/* Common helper functions for parser/mhparser unit tests Copyright © 2021-2023 Samuel Lidén Borell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef CSLUL_PARSECOMMON_H #define CSLUL_PARSECOMMON_H #include "../internal.h" #include "unittest.h" struct ExpectedError { enum CSlulErrorCode errcode; int line; int column; const char *filename; }; #define MAX_EXPECTED_ERRS 10 extern struct ExpectedError expected[MAX_EXPECTED_ERRS]; extern int num_expected; extern int sourceline; void set_mhparse(int value); struct CSlul *create_ctx(enum CSlulPhase initial_phase); struct CSlul *create_ctx_cfg(enum CSlulPhase initial_phase, struct CSlulConfig *cfg); void free_ctx(struct CSlul *ctx); void errors_in(const char *filename); void expect_error(enum CSlulErrorCode errorcode, int line, int column); void verify_errors(void); char *cut0(const char *s); int nexttoken(struct CSlul *ctx); struct TreeNode *lookup(struct CSlul *ctx, struct TreeNode *root, const char *name); struct TypeDecl *lookup_type(struct CSlul *ctx, const char *name); struct TypeDecl *lookup_type_ver(struct CSlul *ctx, const char *name, const char *version); struct IdentDecl *lookup_toplevel(struct CSlul *ctx, const char *name); struct IdentDecl *lookup_toplevel_ver(struct CSlul *ctx, const char *name, const char *version); #if defined(MHPARSE) /* test_mhparse.c */ #define NEXTTOKEN cslul_ll_next_mh_token #define TOKENUM enum CSlulModuleHeaderToken #define PHASE CSLUL_P_MODULEHEADER #define NEEDDATA CSLUL_MHT_NEEDDATA #define UNIONFIELD mh #elif defined(SLULPARSE) /* test_parse.c */ #define NEXTTOKEN cslul_ll_next_slul_token #define TOKENUM enum CSlulToken #define PHASE CSLUL_P_IMPL #define NEEDDATA CSLUL_T_NEEDDATA #define UNIONFIELD slul #else /* parsecommon.c */ #define NEXTTOKEN nexttoken #define TOKENUM enum CSlulToken #define NEEDDATA ((int)0) #define UNIONFIELD mh #endif #define TEST_CONT(expected, ln, col, mb, st) do { \ TOKENUM token; \ sourceline = __LINE__; \ token = NEXTTOKEN(ctx); \ if (!tsoftassert(token == (TOKENUM)(expected)) && !quiet) \ tprintf("- was: %d\n", (int)token); \ if (!tsoftassert(ctx->line == (ln)) && !quiet) \ tprintf("- was: %d\n", ctx->line); \ if (!tsoftassert(ctx->startcolumn == (col)) && !quiet) \ tprintf("- was: %d\n", ctx->startcolumn); \ if (!tsoftassert(ctx->mbtrailerbytes == (mb)) && !quiet) \ tprintf("- was: %d\n", ctx->mbtrailerbytes); \ if (!tsoftassert(ctx->tokstate.UNIONFIELD == (st)) && !quiet) \ tprintf("- was: %d\n", (int)ctx->tokstate.UNIONFIELD); \ } while (0) #define TEST_ONE(buff, len, is_last, expected, ln, col, mb, st) do { \ cslul_ll_set_input_buffer(ctx, (buff), (len), (is_last)); \ TEST_CONT((expected), (ln), (col), (mb), (st)) ; \ } while (0) /* TODO clean up these */ #define TEST_ERROR(buff, len, is_last, expected, ln, col, mb, st, \ errcode, errline, errcol) do { \ expect_error(errcode, errline, errcol); \ TEST_ONE(buff, len, is_last, expected, ln, col, mb, st); \ verify_errors(); \ } while (0) #define TEST_ERROR2(buff, len, is_last, expected, ln, col, mb, st, \ errcode1, errline1, errcol1, \ errcode2, errline2, errcol2) do { \ expect_error(errcode2, errline2, errcol2); \ expect_error(errcode1, errline1, errcol1); \ TEST_ONE(buff, len, is_last, expected, ln, col, mb, st); \ verify_errors(); \ } while (0) #define TEST_ERROR3(buff, len, is_last, expected, ln, col, mb, st, \ errcode1, errline1, errcol1, \ errcode2, errline2, errcol2, \ errcode3, errline3, errcol3) do { \ expect_error(errcode3, errline3, errcol3); \ expect_error(errcode2, errline2, errcol2); \ expect_error(errcode1, errline1, errcol1); \ TEST_ONE(buff, len, is_last, expected, ln, col, mb, st); \ verify_errors(); \ } while (0) #define TEST_ERROR4(buff, len, is_last, expected, ln, col, mb, st, \ errcode1, errline1, errcol1, \ errcode2, errline2, errcol2, \ errcode3, errline3, errcol3, \ errcode4, errline4, errcol4) do { \ expect_error(errcode4, errline4, errcol4); \ expect_error(errcode3, errline3, errcol3); \ expect_error(errcode2, errline2, errcol2); \ expect_error(errcode1, errline1, errcol1); \ TEST_ONE(buff, len, is_last, expected, ln, col, mb, st); \ verify_errors(); \ } while (0) #define TEST_ERROR5(buff, len, is_last, expected, ln, col, mb, st, \ errcode1, errline1, errcol1, \ errcode2, errline2, errcol2, \ errcode3, errline3, errcol3, \ errcode4, errline4, errcol4, \ errcode5, errline5, errcol5) do { \ expect_error(errcode5, errline5, errcol5); \ expect_error(errcode4, errline4, errcol4); \ expect_error(errcode3, errline3, errcol3); \ expect_error(errcode2, errline2, errcol2); \ expect_error(errcode1, errline1, errcol1); \ TEST_ONE(buff, len, is_last, expected, ln, col, mb, st); \ verify_errors(); \ } while (0) #define ASSERT_RAW_VALUE(v, line, col) do { \ const char *name; \ size_t length; \ cslul_ll_current_value(ctx, &name, &length); \ /*fprintf(stderr, "<%lu> <%.*s>\n", length, (int)length, name);*/ \ tsoftassert(length == strlen(v) && !strncmp(name, (v), length)); \ /*fprintf(stderr, "column was %d expected %d\n", ctx->tokcolumn, (col));*/ \ tsoftassert(ctx->tokline == (line)); \ tsoftassert(ctx->tokcolumn == (col)); \ } while (0) #define ASSERT_TOKEN_VALUE(v, line, col) do { \ const char *c; \ HashCode h = 0; \ ASSERT_RAW_VALUE(v, line, col); \ for (c = v; *c; c++) { h = HASH(h, *c); } \ tsoftassert(ctx->tokhash == h); \ } while (0) #define TEST_SOURCE(s, is_last) do { \ sourceline = __LINE__; \ test_source(ctx, s, sizeof(s)-1, is_last); \ } while (0) void test_source(struct CSlul *ctx, const char *s, size_t length, int is_last); void testcommon_empty(void); void testcommon_newline_single(void); void testcommon_newline_splitted(void); void testcommon_newline_eof1(void); void testcommon_newline_eof2(void); void testcommon_null(void); void testcommon_utf8_2min(void); void testcommon_utf8_2max(void); void testcommon_utf8_2split(void); void testcommon_utf8_2overlong(void); void testcommon_utf8_2eof(void); void testcommon_utf8_2badcont(void); void testcommon_utf8_3min(void); void testcommon_utf8_3max(void); void testcommon_utf8_3split(void); void testcommon_utf8_3overlong(void); void testcommon_utf8_3eof2(void); void testcommon_utf8_3nullchar3(void); void testcommon_utf8_4min(void); void testcommon_utf8_4max(void); void testcommon_utf8_4split(void); void testcommon_utf8_4overlong(void); void testcommon_utf8_4overflow(void); void testcommon_utf8_4eof2(void); void testcommon_utf8_4eof3(void); void testcommon_utf8_4nullchar3(void); void testcommon_utf8_4nullchar4(void); void testcommon_utf8_forbidden(void); void testcommon_comment(void); void testcommon_comment_badchar(void); void testcommon_multiline_comment(void); void testcommon_multiline_comment_badstart(void); #endif