END_TEST START_TEST (test_FormulaTokenizer_empty) { FormulaTokenizer_t *ft = FormulaTokenizer_createFromFormula(""); Token_t *t; t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_END ); fail_unless( t->value.ch == '\0' ); Token_free(t); /** * Subsequent calls to FormulaTokenizer_nextToken() should continue to * return TT_END. */ t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_END ); fail_unless( t->value.ch == '\0' ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_END ); fail_unless( t->value.ch == '\0' ); Token_free(t); FormulaTokenizer_free(ft); }
END_TEST START_TEST (test_FormulaTokenizer_numbers_nan_inf) { FormulaTokenizer_t *ft = FormulaTokenizer_createFromFormula("NaN Inf"); Token_t *t; t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_REAL ); fail_unless( t->value.real != t->value.real ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_REAL ); fail_unless( util_isInf(t->value.real) == 1 ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_END ); Token_free(t); FormulaTokenizer_free(ft); }
END_TEST START_TEST (test_FormulaTokenizer_names) { FormulaTokenizer_t *ft = FormulaTokenizer_createFromFormula("foobar Foo2Bar _Foo_Bar"); Token_t *t; t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_NAME ); fail_unless( !strcmp(t->value.name, "foobar") ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_NAME ); fail_unless( !strcmp(t->value.name, "Foo2Bar") ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_NAME ); fail_unless( !strcmp(t->value.name, "_Foo_Bar") ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_END ); Token_free(t); FormulaTokenizer_free(ft); }
END_TEST START_TEST (test_FormulaTokenizer_numbers_exp_bug) { /* we were failing to correctly parse an exponentional followed * by a sign with no space */ const char *formula = "12.3e1+.314E1"; FormulaTokenizer_t *ft = FormulaTokenizer_createFromFormula(formula); Token_t *t; t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_REAL_E ); fail_unless( t->value.real == 12.3 ); fail_unless( t->exponent == 1 ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_PLUS ); fail_unless( t->value.ch == '+' ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_REAL_E ); fail_unless( t->value.real == .314 ); fail_unless( t->exponent == 1 ); Token_free(t); FormulaTokenizer_free(ft); }
END_TEST START_TEST (test_FormulaTokenizer_operators) { FormulaTokenizer_t *ft = FormulaTokenizer_createFromFormula("+-*/^(),"); Token_t *t; t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_PLUS ); fail_unless( t->value.ch == '+' ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_MINUS ); fail_unless( t->value.ch == '-' ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_TIMES ); fail_unless( t->value.ch == '*' ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_DIVIDE ); fail_unless( t->value.ch == '/' ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_POWER ); fail_unless( t->value.ch == '^' ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_LPAREN ); fail_unless( t->value.ch == '(' ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_RPAREN ); fail_unless( t->value.ch == ')' ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_COMMA ); fail_unless( t->value.ch == ',' ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless(t->type == TT_END ); fail_unless( t->value.ch == '\0' ); Token_free(t); FormulaTokenizer_free(ft); }
END_TEST START_TEST (test_Token_free_NULL) { Token_free(NULL); }
END_TEST START_TEST (test_Token_free) { Token_t *t = Token_create(); t->type = TT_NAME; t->value.name = safe_strdup("foo"); Token_free(t); }
END_TEST START_TEST (test_FormulaTokenizer_numbers_locale) { FormulaTokenizer_t *ft = FormulaTokenizer_createFromFormula("2.72"); Token_t *t; setlocale(LC_NUMERIC, "de_DE"); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_REAL ); fail_unless( t->value.real == 2.72 ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_END ); Token_free(t); setlocale(LC_NUMERIC, "C"); FormulaTokenizer_free(ft); }
END_TEST START_TEST (test_Token_create) { Token_t *t = Token_create(); fail_unless( t->type == TT_UNKNOWN ); fail_unless( t->value.ch == '\0' ); fail_unless( t->value.name == NULL ); fail_unless( t->value.integer == 0 ); fail_unless( t->value.real == 0.0 ); fail_unless( t->exponent == 0 ); Token_free(t); }
END_TEST START_TEST (test_FormulaTokenizer_whitespace) { FormulaTokenizer_t *ft = FormulaTokenizer_createFromFormula(" \t \n "); Token_t *t; t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_END ); fail_unless( t->value.ch == '\0' ); Token_free(t); FormulaTokenizer_free(ft); }
END_TEST START_TEST (test_FormulaTokenizer_unknown) { FormulaTokenizer_t *ft = FormulaTokenizer_createFromFormula("*****@*****.**"); Token_t *t; t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_NAME ); fail_unless( !strcmp(t->value.name, "bbornstein") ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_UNKNOWN ); fail_unless( t->value.ch == '@' ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_NAME ); fail_unless( !strcmp(t->value.name, "acm") ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_UNKNOWN ); fail_unless( t->value.ch == '.' ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_NAME ); fail_unless( !strcmp(t->value.name, "org") ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_END ); Token_free(t); FormulaTokenizer_free(ft); }
END_TEST START_TEST (test_FormulaTokenizer_numbers) { FormulaTokenizer_t *ft = FormulaTokenizer_createFromFormula("123 3.14 .007 6.7 5."); Token_t *t; t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_INTEGER ); fail_unless( t->value.integer == 123 ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_REAL ); fail_unless( t->value.real == 3.14 ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_REAL ); fail_unless( t->value.real == .007 ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_REAL ); fail_unless( t->value.real == 6.7 ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_REAL ); fail_unless( t->value.real == 5.0 ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_END ); Token_free(t); FormulaTokenizer_free(ft); }
CK_CPPSTART #endif /** * The following are private and used only within FormulaParser.c; however, * I don't know how else to make them "public" only for testing than to put * them here */ #define START_STATE 0 #define ACCEPT_STATE 0 #define ERROR_STATE 27 #define NUM_STATES 27 /** * The Action[] table contains 144 entries. To test them all would be * laborious and silly. Instead, for a few token type, test the first, * last and middle entry in each token "run". Also, test some error * states. */ START_TEST (test_FormulaParser_getAction) { int i; Token_t *t = Token_create(); t->type = TT_NAME; fail_unless( FormulaParser_getAction( 0, t) == 6, NULL ); fail_unless( FormulaParser_getAction(10, t) == 6, NULL ); fail_unless( FormulaParser_getAction(25, t) == 6, NULL ); fail_unless( FormulaParser_getAction( 1, t) == ERROR_STATE, NULL ); t->type = TT_INTEGER; fail_unless( FormulaParser_getAction( 0, t) == 1, NULL ); fail_unless( FormulaParser_getAction(10, t) == 1, NULL ); fail_unless( FormulaParser_getAction(25, t) == 1, NULL ); fail_unless( FormulaParser_getAction( 1, t) == ERROR_STATE, NULL ); t->type = TT_PLUS; fail_unless( FormulaParser_getAction( 1, t) == -9, NULL ); fail_unless( FormulaParser_getAction(16, t) == -2, NULL ); fail_unless( FormulaParser_getAction(24, t) == -11, NULL ); fail_unless( FormulaParser_getAction( 2, t) == ERROR_STATE, NULL ); t->type = TT_MINUS; fail_unless( FormulaParser_getAction( 0, t) == 5, NULL ); fail_unless( FormulaParser_getAction(16, t) == -2, NULL ); fail_unless( FormulaParser_getAction(25, t) == 5, NULL ); fail_unless( FormulaParser_getAction( 2, t) == ERROR_STATE, NULL ); t->type = TT_END; fail_unless( FormulaParser_getAction( 1, t) == -9, NULL ); fail_unless( FormulaParser_getAction(17, t) == -5, NULL ); fail_unless( FormulaParser_getAction(24, t) == -11, NULL ); fail_unless( FormulaParser_getAction( 3, t) == ERROR_STATE, NULL ); /** * TT_UNKNOWN should always yield an error state. */ t->type = TT_UNKNOWN; for (i = 0; i < NUM_STATES; i++) { fail_unless( FormulaParser_getAction(i, t) == ERROR_STATE, NULL ); } Token_free(t); }
END_TEST START_TEST (test_FormulaTokenizer_numbers_exp) { const char *formula = "12.3e1 .314E1 7e-3 .067e2 5E0 2e+12 3e 4"; FormulaTokenizer_t *ft = FormulaTokenizer_createFromFormula(formula); Token_t *t; t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_REAL_E ); fail_unless( t->value.real == 12.3 ); fail_unless( t->exponent == 1 ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_REAL_E ); fail_unless( t->value.real == .314 ); fail_unless( t->exponent == 1 ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_REAL_E ); fail_unless( t->value.real == 7 ); fail_unless( t->exponent == -3 ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_REAL_E ); fail_unless( t->value.real == .067 ); fail_unless( t->exponent == 2 ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_REAL_E ); fail_unless( t->value.real == 5.0 ); fail_unless( t->exponent == 0 ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_REAL_E ); fail_unless( t->value.real == 2 ); fail_unless( t->exponent == 12 ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_REAL_E ); fail_unless( t->value.real == 3.0 ); fail_unless( t->exponent == 0 ); Token_free(t); /** * Gobble-up the '4'. This last token is here as a test to ensure the * previous token is not interpreted as 3e4. */ t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_INTEGER ); fail_unless( t->value.integer == 4 ); Token_free(t); t = FormulaTokenizer_nextToken(ft); fail_unless( t->type == TT_END ); Token_free(t); FormulaTokenizer_free(ft); }
/** * @if conly * @memberof ASTNode_t * @endif */ LIBSBML_EXTERN ASTNode_t * SBML_parseFormula (const char *formula) { long rule, state, action; ASTNode_t *node = NULL; FormulaTokenizer_t *tokenizer = NULL; Stack_t *stack = NULL; Token_t *token = NULL; if (formula == NULL) return NULL; tokenizer = FormulaTokenizer_createFromFormula(formula); token = FormulaTokenizer_nextToken(tokenizer); stack = Stack_create(20); Stack_push(stack, (void *) START_STATE); while (1) { state = (long) Stack_peek(stack); action = FormulaParser_getAction(state, token); if (action == ACCEPT_STATE) { node = Stack_peekAt(stack, 1); break; } else if (action == ERROR_STATE) { /** * Free ASTNodes on the Stack, skip the states. */ while (Stack_size(stack) > 1) { Stack_pop(stack); ASTNode_free( Stack_pop(stack) ); } node = NULL; break; } /** * Shift */ else if (action > 0) { Stack_push( stack, ASTNode_createFromToken(token) ); Stack_push( stack, (void *) action ); Token_free(token); token = FormulaTokenizer_nextToken(tokenizer); } /** * Reduce */ else if (action < 0) { rule = -action; node = FormulaParser_reduceStackByRule(stack, rule); state = (long) Stack_peek(stack); Stack_push( stack, node ); Stack_push( stack, (void *) FormulaParser_getGoto(state, rule) ); } } FormulaTokenizer_free(tokenizer); Stack_free(stack); Token_free(token); return node; }