/* Unit tests of mhparse.c Copyright © 2021-2024 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. */ #include "../mhparse.c" #define MHPARSE #include "parsecommon.h" #include "unittest.h" #include "alltests.h" #include #include #define BASE_ASSERT_DEP(_dep, _name, _flags) do { \ tassert((_dep) != NULL); \ tsoftassert((_dep)->node.length == sizeof(_name)-1); \ tassert(node_nameptr(&(_dep)->node) != NULL); \ tsoftassert(!memcmp(node_nameptr(&(_dep)->node), (_name), sizeof(_name)-1)); \ tsoftassert((_dep)->flags == (_flags)); \ } while (0) /* These are separate macros to avoid "NULL argument" warnings from GCC depending on compiler version and flags. */ #define ASSERT_DEP(_dep, _name, _ver, _flags) do { \ BASE_ASSERT_DEP(_dep, _name, _flags); \ tsoftassert((_dep)->minverlen == sizeof(_ver)-1); \ tassert((_dep)->min_version != NULL); \ tsoftassert(!memcmp((_dep)->min_version, (_ver), sizeof(_ver)-1)); \ } while (0) #define ASSERT_DEP_NOVERSION(_dep, _name, _flags) do { \ BASE_ASSERT_DEP(_dep, _name, _flags); \ tsoftassert((_dep)->minverlen == 0); \ tsoftassert((_dep)->min_version == NULL); \ } while (0) #define ASSERT_IDEP(_idep, _dep, _modname, _minver, _sincever) do { \ tassert((_idep) != NULL); \ if (tsoftassert((_idep)->minverlen == sizeof(_minver)-1)) { \ tassert((_idep)->min_version != NULL); \ tsoftassert(!memcmp((_idep)->min_version, _minver, sizeof(_minver)-1)); \ } \ if (tsoftassert((_idep)->node.length == sizeof(_sincever)-1)) { \ tassert(node_nameptr(&(_idep)->node) != NULL); \ tsoftassert(!memcmp(node_nameptr(&(_idep)->node), _sincever, sizeof(_sincever)-1)); \ } \ tsoftassert((_idep)->dep == (_dep)); \ } while (0) #define ASSERT_APIDEF_WITHOUT_HASH(_apidef, _ind, _verstr, _flags) do { \ tassert(_apidef != NULL); \ tsoftassert((_apidef)->index == (_ind)); \ if (tsoftassert((_apidef)->verstr.length == sizeof(_verstr)-1)) { \ tassert(node_nameptr(&(_apidef)->verstr) != NULL); \ tsoftassert(!memcmp(node_nameptr(&(_apidef)->verstr), _verstr, sizeof(_verstr)-1)); \ } \ tsoftassert((_apidef)->flags == (_flags)); \ } while (0) #define ASSERT_APIDEF_WITH_HASH(_apidef, _ind, _verstr, _apihash, _flags) do { \ ASSERT_APIDEF_WITHOUT_HASH(_apidef, _ind, _verstr, _flags); \ tsoftassert(!memcmp((_apidef)->apihash, (_apihash), CSLUL_APIHASHBYTES)); \ } while (0) /** Runs before each test case */ static void before_test(void) { set_mhparse(1); /* Set mode. */ } /** Runs after each test case */ static void after_test(void) { verify_errors(); } static void test_mh_attrs_matchattr_attr2str(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); size_t left = (sizeof(attr2str)/sizeof(attr2str[0])); size_t i = 1; while (--left) { const char *attrname = attr2str[i]; cslul_ll_set_input_buffer(ctx, attrname, strlen(attrname), 0); sourceline = __LINE__; tsoftassert(cslul_ll_next_mh_token(ctx) == CSLUL_MHT_NEEDDATA); cslul_ll_set_input_buffer(ctx, "\n", 1, 0); sourceline = __LINE__; tsoftassert(cslul_ll_next_mh_token(ctx) == CSLUL_MHT_AttrName); tsoftassert(cslul_ll_next_mh_token(ctx) == CSLUL_MHT_NEEDDATA); tsoftassert(match_attr(ctx) == i); i++; } ctx->tokval = "notfound"; ctx->toklen = 8; tsoftassert(match_attr(ctx) == MANone); free_ctx(ctx); } static void check_mh_values(struct CSlul *ctx) { tsoftassert(ctx->module.min_langver == LANGVER_0_0_0); tsoftassert(ctx->module.max_langver == 0); tsoftassert(ctx->module.type == CSLUL_MT_LIBRARY); /* TODO implement and check the other fields */ } static void test_mh_attrs_good(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); TEST_SOURCE("\\slul 0.0.0\n" "\\name x\n" "\\type library\n" "\\version 0.1\n" "\\repo git://example/test\n" "\\repo.mirror http://example2/git\n" "\\website https://example/\n" "\\license MIT\n" "\\license.text LICENSE.txt\n" "\\license.list doc/licenses.txt\n" "\\api_def 0.1\n", 0); tsoftassert(ctx->parser.mh.attr == MAApiDef); check_mh_values(ctx); free_ctx(ctx); } static void test_mh_attrs_good_splitted(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); TEST_SOURCE("\\slul 0.0.0\n\\name x\n\\", 0); tsoftassert(ctx->parser.mh.attr == MAName); TEST_SOURCE("type library\n\\version 0.1", 0); tsoftassert(ctx->parser.mh.attr == MAVersion); TEST_SOURCE("\n\\repo git://example/test\n\\repo.mirror", 0); tsoftassert(ctx->parser.mh.attr == MARepo); TEST_SOURCE(" http://example2/git\n\\website https://example/\n", 0); tsoftassert(ctx->parser.mh.attr == MAWebsite); TEST_SOURCE("\\license MIT\n\\license.text LICENSE.txt\n\\license.list ", 0); tsoftassert(ctx->parser.mh.attr == MALicenseList); TEST_SOURCE("doc/licenses.txt\n\\api", 0); tsoftassert(ctx->parser.mh.attr == MALicenseList); TEST_SOURCE("_def ", 0); tsoftassert(ctx->parser.mh.attr == MAApiDef); check_mh_values(ctx); free_ctx(ctx); } static void test_mh_attrs_unknown1(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_BADATTRNAME, 2, 1); TEST_SOURCE("\\slul 0.0.0\n\\namee\n", 0); free_ctx(ctx); } static void test_mh_attrs_unknown2(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_BADATTRNAME, 2, 1); TEST_SOURCE("\\slul 0.0.0\n\\namee test 123\n", 0); free_ctx(ctx); } static void test_mh_attrs_wrongorder(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_WRONGATTRORDER, 3, 1); TEST_SOURCE("\\slul 0.0.0\n\\type app\n\\name x\n", 0); tsoftassert(ctx->parser.mh.attr == MAName); free_ctx(ctx); } static void test_mh_attrs_duplicate(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_DUPLICATEATTR, 3, 1); TEST_SOURCE("\\slul 0.0.0\n\\name x\n\\name x\n", 0); tsoftassert(ctx->parser.mh.attr == MAName); free_ctx(ctx); } static void test_mh_attrs_novalue(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_MISSINGATTRVALUE, 2, 6); TEST_SOURCE("\\slul 0.0.0\n\\name\n\\type ", 0); free_ctx(ctx); } static void test_mh_attrs_badchars(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_VERSTRCHAR, 4, 10); expect_error(CSLUL_E_INVALIDCHAR, 4, 12); expect_error(CSLUL_E_BADMODULETYPE, 3, 7); expect_error(CSLUL_E_INVALIDCHAR, 3, 7); expect_error(CSLUL_E_MODNAMECHAR, 2, 7); expect_error(CSLUL_E_INVALIDCHAR, 2, 8); TEST_SOURCE("\\slul 0.0.0\n" "\\name x\x01\n" "\\type \x1Fx\n" "\\version 0.\x7F\n", 0); free_ctx(ctx); } static void test_mh_eof_newline(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_NOEOFNEWLINE, 2, 11); TEST_SOURCE("\\slul 0.0.0\n\\name test", 1); tsoftassert(ctx->module.type == CSLUL_MT_APP); tsoftassert(!ctx->in_moduleheader); free_ctx(ctx); } static void test_mh_eof_early(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); /* check mandatory attributes for libraries */ expect_error(CSLUL_E_MISSINGSOURCE, 0, 0); expect_error(CSLUL_E_MISSINGATTR, 0, 0); TEST_SOURCE("\\slul 0.0.0\n" "\\type library\n", 1); tsoftassert(!ctx->in_moduleheader); free_ctx(ctx); } #define GOODVERSTR(s) tsoftassert(check_verstr(ctx, (s), strlen(s))) #define BADVERSTR(s, err) do { \ ctx->tokline = 123; \ ctx->tokcolumn = 45; \ ctx->tokval = "dummy"; \ ctx->toklen = 5; \ expect_error((err), 123, 45); \ tsoftassert(!check_verstr(ctx, (s), strlen(s))); \ } while (0) static void test_mh_verstr(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); GOODVERSTR("0"); GOODVERSTR("0.1"); GOODVERSTR("1.23"); GOODVERSTR("1.23.0"); GOODVERSTR("1.23.0a"); GOODVERSTR("1.23.b"); GOODVERSTR("1.23~alpha1"); GOODVERSTR("1.23.git20211218"); GOODVERSTR("1.20003"); GOODVERSTR("2021.01.02"); BADVERSTR("", CSLUL_E_VERSTRLENGTH); BADVERSTR("a", CSLUL_E_VERSTRSTART); BADVERSTR("_", CSLUL_E_VERSTRSTART); BADVERSTR(".1", CSLUL_E_VERSTRSTART); BADVERSTR("~1", CSLUL_E_VERSTRSTART); BADVERSTR("0.", CSLUL_E_VERSTRDOTEND); BADVERSTR("0~", CSLUL_E_VERSTRDOTEND); BADVERSTR("1..0", CSLUL_E_VERSTRDOTDOT); BADVERSTR("1.2_3", CSLUL_E_VERSTRCHAR); BADVERSTR("01.2", CSLUL_E_VERSTRZEROPREFIXED); free_ctx(ctx); } static void test_mh_langver_good1(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); TEST_SOURCE("\\slul 0.0.0\n", 0); tsoftassert(ctx->module.min_langver == LANGVER_0_0_0); tsoftassert(ctx->module.max_langver == 0); free_ctx(ctx); } static void test_mh_langver_good2(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); TEST_SOURCE("\\slul 0.0.0 upto 0.0.0\n" "\\name test\n", 0); tsoftassert(ctx->module.min_langver == LANGVER_0_0_0); tsoftassert(ctx->module.impl_minlangver == LANGVER_UNSET); tsoftassert(ctx->module.max_langver == LANGVER_0_0_0); tassert(ctx->module.name != NULL); tsoftassert(!strcmp(ctx->module.name, "test")); free_ctx(ctx); } static void test_mh_langver_good3(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); TEST_SOURCE("\\slul 0.0.0 upto 999.999.999\n" "\\name test\n", 0); tsoftassert(ctx->module.min_langver == LANGVER_0_0_0); tsoftassert(ctx->module.impl_minlangver == LANGVER_UNSET); tsoftassert(ctx->module.max_langver == LANGVER_BAD); tassert(ctx->module.name != NULL); tsoftassert(!strcmp(ctx->module.name, "test")); free_ctx(ctx); } static void test_mh_langver_good4(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); TEST_SOURCE("\\slul 0.0.0 impl 0.0.0\n" "\\name test\n", 0); tsoftassert(ctx->module.min_langver == LANGVER_0_0_0); tsoftassert(ctx->module.impl_minlangver == LANGVER_0_0_0); tsoftassert(ctx->module.max_langver == LANGVER_UNSET); tassert(ctx->module.name != NULL); tsoftassert(!strcmp(ctx->module.name, "test")); free_ctx(ctx); } static void test_mh_langver_good5(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); TEST_SOURCE("\\slul 0.0.0 impl 0.0.0 upto 999.999.999\n" "\\name test\n", 0); tsoftassert(ctx->module.min_langver == LANGVER_0_0_0); tsoftassert(ctx->module.impl_minlangver == LANGVER_0_0_0); tsoftassert(ctx->module.max_langver == LANGVER_BAD); tassert(ctx->module.name != NULL); tsoftassert(!strcmp(ctx->module.name, "test")); free_ctx(ctx); } static void test_mh_langver_good6(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); TEST_SOURCE("\\slul 0.0.0 impl 999.999.999 upto 999.999.999\n" "\\name test\n" "\\type library\n" "\\version 1.0 unstable_api\n" "\\source someimpl.slul\n" "\n" "func ", 1); tsoftassert(ctx->module.min_langver == LANGVER_0_0_0); tsoftassert(ctx->module.impl_minlangver == LANGVER_BAD); tsoftassert(ctx->module.max_langver == LANGVER_BAD); if (!ctx->has_fatal_errors) { /* skip when testing out-of-memory */ tsoftassert(ctx->module.effective_minlangver == LANGVER_0_0_0); tsoftassert(ctx->module.effective_maxlangver == LANGVER_0_0_0); } tassert(ctx->module.name != NULL); tsoftassert(!strcmp(ctx->module.name, "test")); free_ctx(ctx); } static void test_mh_langver_unsupported(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_UNSUPPORTEDLANGVER, 1, 7); TEST_SOURCE("\\slul 999.999.999\n" "\\name test\n", 0); tsoftassert(ctx->module.min_langver == LANGVER_BAD); tsoftassert(ctx->module.max_langver == 0); tassert(ctx->module.name == NULL); /* parsing stops */ free_ctx(ctx); } static void test_mh_langver_older(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_SLULMAXVEROLDER, 1, 35); TEST_SOURCE("\\slul 0.0.0 impl 999.999.999 upto 0.0.0\n" "\\name test\n" "\\type library\n" "\\version 1.0 unstable_api\n" "\\source impl.slul\n" "\n" "func ", 0); tsoftassert(ctx->module.min_langver == LANGVER_0_0_0); tsoftassert(ctx->module.impl_minlangver == LANGVER_BAD); tsoftassert(ctx->module.max_langver == LANGVER_0_0_0); free_ctx(ctx); } static void test_mh_langver_malformed_upto(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_VERSTRDOTDOT, 1, 18); TEST_SOURCE("\\slul 0.0.0 upto 0.0..1\n" "\\name test\n" "\\type library\n" "\\version 1.0 unstable_api\n" "\\source impl.slul\n" "\n" "func ", 0); tsoftassert(ctx->module.min_langver == LANGVER_0_0_0); tsoftassert(ctx->module.max_langver == LANGVER_BAD); free_ctx(ctx); } static void test_mh_langver_badsyntax1(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_MISSINGATTRVALUE, 1, 6); TEST_SOURCE("\\slul\n" "\\name test\n", 0); tsoftassert(ctx->module.min_langver == LANGVER_BAD); tsoftassert(ctx->module.max_langver == 0); tassert(ctx->module.name != NULL); tsoftassert(!strcmp(ctx->module.name, "test")); free_ctx(ctx); } static void test_mh_langver_badsyntax2(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_BADLANGVERSYNTAX, 1, 13); TEST_SOURCE("\\slul 0.0.0 xxx\n" "\\name test\n", 0); tsoftassert(ctx->module.min_langver == LANGVER_0_0_0); tsoftassert(ctx->module.max_langver == 0); tassert(ctx->module.name != NULL); tsoftassert(!strcmp(ctx->module.name, "test")); free_ctx(ctx); } static void test_mh_langver_badsyntax3(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_BADLANGVERSYNTAX, 1, 17); TEST_SOURCE("\\slul 0.0.0 upto\n" "\\name test\n", 0); tsoftassert(ctx->module.min_langver == LANGVER_0_0_0); tsoftassert(ctx->module.max_langver == 0); tassert(ctx->module.name != NULL); tsoftassert(!strcmp(ctx->module.name, "test")); free_ctx(ctx); } static void test_mh_sources_good(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); TEST_SOURCE("\\slul 0.0.0\n" "\\name someapp\n" "\\source file1.slul\n" "\\source file2.slul\n" "\\source src/file2.slul\n", 0); free_ctx(ctx); } static void test_mh_sources_bad_pattern(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_BADDIRNAME, 7, 10); expect_error(CSLUL_E_FILENAMEDOTDOT, 6, 18); expect_error(CSLUL_E_FILENAMEDOUBLESLASH, 5, 13); expect_error(CSLUL_E_FILENAMEROOT, 4, 9); expect_error(CSLUL_E_FILENAMEDOT, 3, 9); TEST_SOURCE("\\slul 0.0.0\n" "\\name someapp\n" "\\source .hidden.slul\n" "\\source /root.slul\n" "\\source src//doubleslash.slul\n" "\\source doubledot..slul\n" "\\source d.slul/stuff.slul\n", 0); expect_error(CSLUL_E_DIRTRAILINGDOT, 11, 12); expect_error(CSLUL_E_FILENAMEDOTDOT, 10, 22); expect_error(CSLUL_E_FILENAMEDOUBLESLASH, 9, 17); expect_error(CSLUL_E_FILENAMEDOT, 8, 13); TEST_SOURCE("\\source dir/.hidden.slul\n" "\\source dir/src//doubleslash.slul\n" "\\source dir/doubledot..slul\n" "\\source dir./trailingdot.slul\n", 0); expect_error(CSLUL_E_DIRTRAILINGDOT, 15, 12); expect_error(CSLUL_E_NONSLULFILE, 14, 9); expect_error(CSLUL_E_FILENAMEDOUBLESLASH, 13, 15); expect_error(CSLUL_E_FILENAMEDOT, 12, 15); TEST_SOURCE("\\source x/y/z/.slul\n" "\\source x/y/z//.slul\n" "\\source .slul\n" "\\source x/x./y.slul\n", 0); expect_error(CSLUL_E_BADFILENAMECHAR, 21, 9); expect_error(CSLUL_E_BADFILENAMECHAR, 20, 10); expect_error(CSLUL_E_BADFILENAMECHAR, 19, 11); expect_error(CSLUL_E_BADFILENAMECHAR, 18, 12); expect_error(CSLUL_E_BADFILENAMECHAR, 17, 10); expect_error(CSLUL_E_BADFILENAMECHAR, 16, 9); TEST_SOURCE("\\source å.slul\n" "\\source xå.slul\n" "\\source xxxåxx.slul\n" "\\source x/å.slul\n" "\\source x-x.slul\n" "\\source \\.slul\n", 0); { const char *windev = "\\source con.slul\n" "\\source lpt1.slul\n" "\\source com9.slul\n" "\\source nul/src.slul\n" "\\source dir/aux.slul\n" "\\source dir/lpt9.slul\n" "\\source dir/com1.slul\n" "\\source dir/prn/src.slul\n"; int line = 22; while (*windev) { size_t len; int has_dir = memcmp(windev+8, "dir/", 4)==0; expect_error(CSLUL_E_DEVICEFILENAME, line++, has_dir ? 13 : 9); len = strcspn(windev, "\n")+1; sourceline = __LINE__; test_source(ctx, windev, len, 0); windev += len; } } free_ctx(ctx); } static void test_mh_sources_bad_fileext(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_NONSLULFILE, 3, 9); TEST_SOURCE("\\slul 0.0.0\n" "\\name someapp\n" "\\source somefile.c\n", 0); free_ctx(ctx); } static void test_mh_sources_mainslul1(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_SOURCEMAINSLUL, 3, 9); TEST_SOURCE("\\slul 0.0.0\n" "\\name someapp\n" "\\source main.slul\n", 0); free_ctx(ctx); } static void test_mh_sources_mainslul2(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_SOURCEMAINSLUL, 3, 9); TEST_SOURCE("\\slul 0.0.0\n" "\\name someapp\n" "\\source a/main.slul\n", 0); free_ctx(ctx); } static void test_mh_sources_duplicate_samecase(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_DUPLICATEFILE, 4, 9); TEST_SOURCE("\\slul 0.0.0\n" "\\name someapp\n" "\\source dupfile.slul\n" "\\source dupfile.slul\n", 0); free_ctx(ctx); } static void test_mh_sources_duplicate_casediff(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_SOURCECASEDUP, 4, 9); TEST_SOURCE("\\slul 0.0.0\n" "\\name someapp\n" "\\source dUpfIle.slul\n" "\\source DuPfiLE.slul\n", 0); free_ctx(ctx); } static void test_mh_sources_duplicate_short(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_SOURCECASEDUP, 4, 9); TEST_SOURCE("\\slul 0.0.0\n" "\\name someapp\n" "\\source a.slul\n" "\\source A.slul\n", 0); free_ctx(ctx); } static void test_mh_sources_toomany(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); TEST_SOURCE("\\slul 0.0.0\n" "\\name someapp\n" "\\source file1.slul\n", 0); ctx->num_sourcefiles = MAX_SOURCEFILES; expect_error(CSLUL_E_MAXSOURCEFILES, 4, 1); TEST_SOURCE("\\source file2.slul\n", 0); free_ctx(ctx); } static void test_mh_sources_toolong(void) { static const char part1[] = "\\slul 0.0.0\n" "\\name someapp\n" "\\source "; static const char part2[] = "\n\\source file.slul\n"; struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); char buff[sizeof(part1)-1+101+sizeof(part2)]; char *sp = buff; memcpy(sp, part1, sizeof(part1)-1); sp += sizeof(part1)-1; memset(sp, 'a', 101); sp += 101; memcpy(sp, part2, sizeof(part2)); expect_error(CSLUL_E_NONSLULFILE, 3, 9); /* FIXME fix error message. should say attribute value, not identifier */ expect_error(CSLUL_E_IDENTTOOLONG, 3, 109); TEST_SOURCE(buff, 0); free_ctx(ctx); } static void test_mh_sources_toolong_eof(void) { static const char part1[] = "\\slul 0.0.0\n" "\\name someapp\n" "\\source "; struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); char buff[sizeof(part1)+101]; char *sp = buff; memcpy(sp, part1, sizeof(part1)-1); sp += sizeof(part1)-1; memset(sp, 'a', 101); sp += 101; *sp = '\0'; expect_error(CSLUL_E_NOEOFNEWLINE, 3, 110); expect_error(CSLUL_E_NONSLULFILE, 3, 9); /* FIXME fix error message. should say attribute value, not identifier */ expect_error(CSLUL_E_IDENTTOOLONG, 3, 109); TEST_SOURCE(buff, 1); free_ctx(ctx); } static void test_mh_deps_single(void) { struct CSlulDependency *dep; struct Module *mod; struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); ctx->parser.mh.seen_explicit_slulrt_dep = 1; /* skip implicit slulrt dep */ TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\version 0.1.23\n" "\\depends a 1.23.4\n" "\\source file1.slul\n", 1); tassert((mod = ctx->parsed_module) != NULL); tassert(mod->deps_root != NULL); tassert(mod->first_dep != NULL); tassert(mod->last_dep == mod->first_dep); dep = mod->first_dep; tassert(mod->deps_root == &dep->node); ASSERT_DEP(dep, "a", "1.23.4", 0); free_ctx(ctx); } static void test_mh_deps_several(void) { struct CSlulDependency *dep; struct Module *mod; struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); ctx->parser.mh.seen_explicit_slulrt_dep = 1; /* skip implicit slulrt dep */ TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\version 0.1.23\n" "\\depends optdep 12.3.4 optional\n" "\\depends onlynested 5.789bugfix nestedonly\n" "\\depends multiflags 9.87a unstable_api optional nestedonly\n" "\\depends noversion bundled\n" "\\depends noflags 1.23.4\n" "\\source file1.slul\n", 1); tassert((mod = ctx->parsed_module) != NULL); tassert(mod->deps_root != NULL); tassert(mod->first_dep != NULL); tassert(mod->last_dep != mod->first_dep); dep = mod->first_dep; ASSERT_DEP(dep, "optdep", "12.3.4", CSLUL_DF_OPTIONAL); dep = dep->next; ASSERT_DEP(dep, "onlynested", "5.789bugfix", CSLUL_DF_NESTEDONLY); dep = dep->next; ASSERT_DEP(dep, "multiflags", "9.87a", CSLUL_DF_UNSTABLE_API|CSLUL_DF_OPTIONAL|CSLUL_DF_NESTEDONLY); dep = dep->next; ASSERT_DEP_NOVERSION(dep, "noversion", CSLUL_DF_BUNDLED); dep = dep->next; ASSERT_DEP(dep, "noflags", "1.23.4", 0); tsoftassert(dep == mod->last_dep); tsoftassert(dep->next == NULL); free_ctx(ctx); } static void test_mh_deps_selfdepend(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_SELFDEPEND, 5, 10); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" /* case insensitive check */ "\\version 1.0\n" "\n" "\\depends test 1.0\n", 0); free_ctx(ctx); } static void test_mh_deps_dup(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_DUPLICATEDEP, 4, 10); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\depends module 1.0\n" "\\depends module 1.0\n", 0); free_ctx(ctx); } static void test_mh_deps_flag_unknown(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_BADDEPFLAG, 3, 21); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\depends module 1.0 bad\n", 0); free_ctx(ctx); } static void test_mh_deps_flag_dup(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_DUPLDEPFLAG, 4, 42); expect_error(CSLUL_E_DUPLDEPFLAG, 3, 30); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\depends module 1.0 optional optional\n" "\\depends module2 1.0 optional nestedonly optional\n", 0); free_ctx(ctx); } static void test_mh_deps_flag_tab(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_TAB, 3, 20); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\depends module 1.0\tnestedonly\n", 0); free_ctx(ctx); } static void test_mh_deps_flag_wrongorder(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_DEPFLAGSORDER, 3, 32); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\depends module 1.0 nestedonly optional\n", 0); free_ctx(ctx); } static void test_mh_ifacedeps(void) { struct CSlulDependency *dep; struct CSlulInterfaceDep *idep; struct Module *mod; struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); ctx->parser.mh.seen_explicit_slulrt_dep = 1; /* skip implicit slulrt dep */ TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\type library\n" "\\version 0.1.23\n" "\\depends optdep 12.3.4 optional\n" "\\depends onlynested 5.789bugfix nestedonly\n" "\\interface_depends optdep 0.9.34b since 0.1.17\n" "\\interface_depends optdep 11.3 since 0.1.20\n" "\\interface_depends onlynested 5.789bugfix nestedonly since 0.1.23\n" "\\interface_depends ifaceonly 0.98.7 since 0.1.23\n" "\\api_def 0.1.17 00101700101700101700101700101700\n" "\\api_def 0.1.20 00102000102000102000102000102000\n" "\\api_def 0.1.23 00102300102300102300102300102300\n" "\\source file1.slul\n", 1); tassert((mod = ctx->parsed_module) != NULL); tassert(mod->deps_root != NULL); tassert(mod->first_dep != NULL); tassert(mod->last_dep != mod->first_dep); dep = mod->first_dep; ASSERT_DEP(dep, "optdep", "12.3.4", CSLUL_DF_OPTIONAL); tassert((idep = dep->first_ifacever) != NULL); tsoftassert(dep->last_ifacever != NULL); ASSERT_IDEP(idep, dep, "optdep", "0.9.34b", "0.1.17"); idep = idep->sincever_next; ASSERT_IDEP(idep, dep, "optdep", "11.3", "0.1.20"); dep = dep->next; ASSERT_DEP(dep, "onlynested", "5.789bugfix", CSLUL_DF_NESTEDONLY); dep = dep->next; ASSERT_DEP(dep, "ifaceonly", "0.98.7", CSLUL_DF_IFACEONLY); tsoftassert(dep == mod->last_dep); tsoftassert(dep->next == NULL); free_ctx(ctx); } static void test_mh_ifacedeps_bundled(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_IFACEDEPENDBUNDLED, 6, 20); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\type library\n" "\\version 1.2.3\n" "\\depends somemodule bundled\n" "\\interface_depends somemodule 1.0 since 1.2.2\n" "\\interface_depends ", 0); free_ctx(ctx); } static void test_mh_ifacedeps_selfdepend(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_SELFDEPEND, 5, 20); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\type library\n" "\\version 1.2.3\n" "\\interface_depends test 1.0 since 1.2.2\n" "\\interface_depends ", 0); free_ctx(ctx); } static void test_mh_ifacedeps_missingversion(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_NOIFACEDEPVERSION, 5, 26); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\type library\n" "\\version 1.2.3\n" "\\interface_depends module\n" "\\interface_depends ", 0); free_ctx(ctx); } static void test_mh_ifacedeps_missingsinceversion(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_NOSINCEVERSION, 5, 36); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\type library\n" "\\version 1.2.3\n" "\\interface_depends module 1.0 since\n" "\\interface_depends ", 0); free_ctx(ctx); } static void test_mh_ifacedeps_badsinceversion(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_VERSTRSTART, 5, 37); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\type library\n" "\\version 1.2.3\n" "\\interface_depends module 1.0 since x\n" "\\interface_depends ", 0); free_ctx(ctx); } static void test_mh_ifacedeps_app(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_APPWITHIFACEDEP, 4, 1); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\version 1.2.3\n" "\\interface_depends module 1.0 since 1.2.2\n" "\\interface_depends ", 0); free_ctx(ctx); } static void test_mh_ifacedeps_dup(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_DUPLICATEIFACEDEP, 6, 37); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\type library\n" "\\version 1.2.3\n" "\\interface_depends module 1.0 since 1.2.2~rc1\n" "\\interface_depends module 1.0 since 1.2.2~rc1\n" "\\interface_depends ", 0); free_ctx(ctx); } static void test_mh_apidef(void) { struct ApiDef *apidef; struct Module *mod; struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\type library\n" "\\version 1.1.23\n" "\\api_def 0.1.0\n" "\\api_def 0.1.1 retracted\n" "\\api_def 0.2.0 VGVzdAABAgMwMTIzNDU2Nzg5YWJjZGVm retracted\n" "\\api_def 0.2.1 T3RoZXKqu8wwMDExMjIzMzQ0NTU2Njc3\n" "\\api_def 0.2.2 X/x+x//x/+x+/x++x+++XxXxXxXxXxX/\n" "\\source file1.slul\n", 1); tassert((mod = ctx->parsed_module) != NULL); tassert(mod->apidefs_root != NULL); tassert(mod->first_apidef != NULL); tassert(mod->last_apidef != mod->first_apidef); apidef = mod->first_apidef; ASSERT_APIDEF_WITHOUT_HASH(apidef, 0, "0.1.0", 0); apidef = apidef->next; ASSERT_APIDEF_WITHOUT_HASH(apidef, 1, "0.1.1", APIDEF_RETRACTED); apidef = apidef->next; /* Bogus data for testing. This would normally be a random binary value */ ASSERT_APIDEF_WITH_HASH(apidef, 2, "0.2.0", "Test\0\x01\x02\x03" "0123456789abcdef", APIDEF_HAS_HASH|APIDEF_RETRACTED); apidef = apidef->next; ASSERT_APIDEF_WITH_HASH(apidef, 3, "0.2.1", "Other\xaa\xbb\xcc" "0011223344556677", APIDEF_HAS_HASH); apidef = apidef->next; ASSERT_APIDEF_WITH_HASH(apidef, 4, "0.2.2", "_\xfc~\xc7\xff\xf1\xff\xec" "\x7e\xff\x1f\xbe\xc7\xef\xbe\x5f\x15\xf1_\x15\xf1_\x15\xff", APIDEF_HAS_HASH); tsoftassert(apidef == mod->last_apidef); tsoftassert(apidef->next == NULL); free_ctx(ctx); } /* static void test_mh_apidef_hash(void) { } */ static void test_mh_apidef_badversion(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_VERSTRSTART, 5, 10); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\type library\n" "\\version 1.2\n" "\\api_def x1.2\n" "\\source file1.slul\n", 1); free_ctx(ctx); } static void test_mh_apidef_badflag(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_BADAPIDEFFLAG, 6, 47); expect_error(CSLUL_E_BADAPIDEFFLAG, 5, 14); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\type library\n" "\\version 1.2\n" "\\api_def 1.1 badflag\n" "\\api_def 1.2 VGVzdAABAgMwMTIzNDU2Nzg5YWJjZGVm badflag\n" "\\source file1.slul\n", 1); free_ctx(ctx); } static void test_mh_apidef_dup(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_DUPLICATEAPIDEF, 6, 1); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\type library\n" "\\version 1.2\n" "\\api_def 1.2\n" "\\api_def 1.2\n" "\\source file1.slul\n", 1); free_ctx(ctx); } static void test_mh_apidef_badhashlength(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_BADAPIHASHLEN, 5, 14); /* last character is missing in hash */ TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\type library\n" "\\version 1.0\n" "\\api_def 1.0 TWlzc2luZyBvbmUgc2luZ2xlIGJ5dGU\n" "\\source file1.slul\n", 1); free_ctx(ctx); } static void test_mh_apidef_badhashchar(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_BADAPIHASH, 5, 14); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\type library\n" "\\version 1.0\n" "\\api_def 1.0 VGVzdAABAgMwMTIzNDU2Nzg5YWJjZGV!\n" "\\source file1.slul\n", 1); free_ctx(ctx); } static void test_mh_apidef_toomany(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); TEST_SOURCE("\\slul 0.0.0\n" "\\name someapp\n" "\\type library\n" "\\version 1.1\n" "\\api_def 1.0 VGVzdAABAgMwMTIzNDU2Nzg5YWJjZGVm\n", 0); ctx->parsed_module->num_apidefs = MAX_APIDEFS; expect_error(CSLUL_E_MAXAPIDEFS, 6, 1); TEST_SOURCE("\\api_def 0.2.1 T3RoZXKqu8wwMDExMjIzMzQ0NTU2Njc3\n", 0); free_ctx(ctx); } static void test_mh_apidef_withapp(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_APPWITHAPI, 4, 1); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\version 1.0\n" "\\api_def 1.0 VGVzdAABAgMwMTIzNDU2Nzg5YWJjZGVm\n" "\\source file1.slul\n", 1); free_ctx(ctx); } static void test_mh_apidef_withoutversion(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_APIDEFWITHOUTMODVER, 4, 1); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\type library\n" "\\api_def 1.0 VGVzdAABAgMwMTIzNDU2Nzg5YWJjZGVm\n" "\\source file1.slul\n", 1); free_ctx(ctx); } static void test_mh_moduletype_good(void) { static const char *const types[] = { "internal", "library", "plugin", "libraryspec", "pluginspec", "app", NULL }; char buffer[200]; const char *const *type = types; for (; *type; type++) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); sprintf(buffer, "\\slul 0.0.0\n\\name test\n\\type %s\n", *type); sourceline = __LINE__; test_source(ctx, buffer, strlen(buffer), 0); free_ctx(ctx); } } static void test_mh_moduletype_bad(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_BADMODULETYPE, 3, 7); TEST_SOURCE("\\slul 0.0.0\n" "\\name test\n" "\\type internzl\n", 0); free_ctx(ctx); } static void test_mh_nameversion_good(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); TEST_SOURCE("\\slul 0.0.0\n" "\\name a0123456789bcdefghijklmnopqrstuvwxy_z\n" "\\version 0.1.999923456789abcdefghijkl~m\n", 0); free_ctx(ctx); } static void test_mh_name_bad(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); char buffer[52]; memset(buffer, 'z', sizeof(buffer)-1); buffer[51] ='\0'; TEST_SOURCE("\\slul 0.0.0\n\\name ", 0); TEST_SOURCE(buffer, 0); expect_error(CSLUL_E_MODNAMELENGTH, 2, 7); TEST_SOURCE("\n", 0); expect_error(CSLUL_E_MODNAMESTART, 3, 7); expect_error(CSLUL_E_DUPLICATEATTR, 3, 1); TEST_SOURCE("\\name 0\n", 0); expect_error(CSLUL_E_MODNAMECHAR, 4, 7); expect_error(CSLUL_E_DUPLICATEATTR, 4, 1); TEST_SOURCE("\\name a?\n", 0); free_ctx(ctx); } static void test_mh_version_bad(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); char buffer[52]; memset(buffer, '1', sizeof(buffer)-1); buffer[51] = '\0'; TEST_SOURCE("\\slul 0.0.0\n\\name test\n\\version ", 0); TEST_SOURCE(buffer, 0); expect_error(CSLUL_E_VERSTRLENGTH, 3, 10); TEST_SOURCE("\n", 0); expect_error(CSLUL_E_VERSTRSTART, 4, 10); expect_error(CSLUL_E_DUPLICATEATTR, 4, 1); TEST_SOURCE("\\version x\n", 0); expect_error(CSLUL_E_VERSTRCHAR, 5, 10); expect_error(CSLUL_E_DUPLICATEATTR, 5, 1); TEST_SOURCE("\\version 0?\n", 0); expect_error(CSLUL_E_VERSTRDOTDOT, 6, 10); expect_error(CSLUL_E_DUPLICATEATTR, 6, 1); TEST_SOURCE("\\version 0..1\n", 0); expect_error(CSLUL_E_VERSTRDOTEND, 7, 10); expect_error(CSLUL_E_DUPLICATEATTR, 7, 1); TEST_SOURCE("\\version 0.\n", 0); expect_error(CSLUL_E_BADVERSIONFLAG, 8, 14); expect_error(CSLUL_E_DUPLICATEATTR, 8, 1); TEST_SOURCE("\\version 0.1 unstablx\n", 0); free_ctx(ctx); } static void test_mh_specwithsource(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_SPECWITHSOURCE, 4, 1); TEST_SOURCE("\\slul 0.0.0\n\\name x\n\\type libraryspec\n\\source x.slul\n", 1); free_ctx(ctx); } static void test_mh_missingsource(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_MISSINGSOURCE, 0, 0); TEST_SOURCE("\\slul 0.0.0\n\\name x\n\\type library\n", 1); free_ctx(ctx); } static void test_mh_missingattr(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_MISSINGATTR, 0, 0); /* missing 'name' */ TEST_SOURCE("\\slul 0.0.0\n\\type library\n\\source x.slul\n", 1); free_ctx(ctx); } static void test_mh_withsource_good(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); TEST_SOURCE("\\slul 0.0.0\n\\name x\n\\source x.slul\n", 1); free_ctx(ctx); } static void test_mh_withoutsource_good(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); TEST_SOURCE("\\slul 0.0.0\n\\name x\n\\type libraryspec\n", 1); free_ctx(ctx); } /** Module headers end when a line starts with a keyword without a leading. backslash. This test checks that the transition works correctly. */ static void test_mh_with_end(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); TEST_SOURCE("\\slul 0.0.0\n\\name x\n\ntype ", 0); tsoftassert(ctx->parser.mh.state == MHPDone); tsoftassert(ctx->line == 4); tsoftassert(ctx->tokline == 4); tsoftassert(ctx->tokcolumn == 1); tassert(!ctx->has_fatal_errors); /* stop if testing out-of-memory */ /* Poke the normal (non module header) parser */ TEST_SOURCE("", 0); tsoftassert(ctx->parser.slul.state == PTypeIdent); tsoftassert(ctx->line == 4); tsoftassert(ctx->tokline == 4); tsoftassert(ctx->tokcolumn == 1); tassert(!ctx->has_fatal_errors); /* stop if testing out-of-memory */ tsoftassert(ctx->typedepth == -1); tsoftassert(ctx->blockdepth == -1); tsoftassert(ctx->exprdepth == -1); tsoftassert(ctx->current_block == NULL); free_ctx(ctx); } /* TODO enforce a blank line between the module header and main source? */ /** Tests parsing an attribute with a missing \\ */ static void test_mh_nobackslash(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_MHNOBACKSLASH, 2, 1); TEST_SOURCE("\\slul 0.0.0\nname abc\n\\type app\n", 0); /* Should recover from error */ tassert(ctx->parsed_module != NULL); tassert(ctx->parsed_module->namelen == 3); tassert(ctx->parsed_module->name != NULL); tsoftassert(!memcmp(ctx->parsed_module->name, "abc", 3)); tsoftassert(ctx->parsed_module->type == CSLUL_MT_APP); free_ctx(ctx); } /** Tests parsing a file with a missing module header */ static void test_mh_missingheader(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); expect_error(CSLUL_E_MISSINGMODULEHEADER, 1, 1); TEST_SOURCE("type ", 0); free_ctx(ctx); } static void test_mh_toolong(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); char buff[103]; memset(buff+1, 'x', 100); buff[0] = '\\'; buff[1] = 'a'; buff[99] = 'b'; buff[100] = 'c'; buff[101] = 'd'; TEST_SOURCE("\\slul 0.0.0\n\\name x\n", 0); expect_error(CSLUL_E_IDENTTOOLONG, 3, 102); TEST_SOURCE(buff, 0); tsoftassert(ctx->toklen == 100); tsoftassert(!memcmp(ctx->tokval, buff+1, 100)); expect_error(CSLUL_E_BADATTRNAME, 3, 1); TEST_SOURCE(" ", 0); expect_error(CSLUL_E_IDENTTOOLONG, 3, 204); buff[0] = 'e'; buff[99] = 'f'; TEST_SOURCE(buff, 0); tsoftassert(ctx->toklen == 100); tsoftassert(!memcmp(ctx->tokval, buff, 100)); TEST_SOURCE("\n\\source a.slul\n", 1); free_ctx(ctx); } static void test_mh_toolong_utf8(void) { struct CSlul *ctx = create_ctx(CSLUL_P_MODULEHEADER); char buff[102]; memset(buff, 'x', 100); TEST_SOURCE("\\slul 0.0.0\n\\name x\n\\version 1.23.4\n\\repo ", 0); expect_error(CSLUL_E_IDENTTOOLONG, 4, 107); buff[0] = 'y'; buff[99] = '\xe2'; buff[100] = '\x8c'; buff[101] = '\xa8'; TEST_SOURCE(buff, 0); tsoftassert(ctx->toklen == 100); tsoftassert(!memcmp(ctx->tokval, buff, 100)); TEST_SOURCE("\n\\source a.slul\n", 1); free_ctx(ctx); } const TestFunctionInfo tests_mhparse[] = { TEST_BEFORE(before_test) TEST_AFTER(after_test) TEST_INFO(test_mh_attrs_matchattr_attr2str) TEST_INFO(test_mh_attrs_good) TEST_INFO(test_mh_attrs_good_splitted) TEST_INFO(test_mh_attrs_unknown1) TEST_INFO(test_mh_attrs_unknown2) TEST_INFO(test_mh_attrs_wrongorder) TEST_INFO(test_mh_attrs_duplicate) TEST_INFO(test_mh_attrs_novalue) TEST_INFO(test_mh_attrs_badchars) TEST_INFO(test_mh_eof_newline) TEST_INFO(test_mh_eof_early) TEST_INFO(test_mh_verstr) TEST_INFO(test_mh_langver_good1) TEST_INFO(test_mh_langver_good2) TEST_INFO(test_mh_langver_good3) TEST_INFO(test_mh_langver_good4) TEST_INFO(test_mh_langver_good5) TEST_INFO(test_mh_langver_good6) TEST_INFO(test_mh_langver_unsupported) TEST_INFO(test_mh_langver_older) TEST_INFO(test_mh_langver_malformed_upto) TEST_INFO(test_mh_langver_badsyntax1) TEST_INFO(test_mh_langver_badsyntax2) TEST_INFO(test_mh_langver_badsyntax3) TEST_INFO(test_mh_sources_good) TEST_INFO(test_mh_sources_bad_pattern) TEST_INFO(test_mh_sources_bad_fileext) TEST_INFO(test_mh_sources_mainslul1) TEST_INFO(test_mh_sources_mainslul2) TEST_INFO(test_mh_sources_duplicate_samecase) TEST_INFO(test_mh_sources_duplicate_casediff) TEST_INFO(test_mh_sources_duplicate_short) TEST_INFO(test_mh_sources_toomany) TEST_INFO(test_mh_sources_toolong) TEST_INFO(test_mh_sources_toolong_eof) TEST_INFO(test_mh_deps_single) TEST_INFO(test_mh_deps_several) TEST_INFO(test_mh_deps_selfdepend) TEST_INFO(test_mh_deps_dup) TEST_INFO(test_mh_deps_flag_unknown) TEST_INFO(test_mh_deps_flag_dup) TEST_INFO(test_mh_deps_flag_tab) TEST_INFO(test_mh_deps_flag_wrongorder) TEST_INFO(test_mh_ifacedeps) TEST_INFO(test_mh_ifacedeps_bundled) TEST_INFO(test_mh_ifacedeps_selfdepend) TEST_INFO(test_mh_ifacedeps_missingversion) TEST_INFO(test_mh_ifacedeps_missingsinceversion) TEST_INFO(test_mh_ifacedeps_badsinceversion) TEST_INFO(test_mh_ifacedeps_app) TEST_INFO(test_mh_ifacedeps_dup) TEST_INFO(test_mh_apidef) TEST_INFO(test_mh_apidef_badversion) TEST_INFO(test_mh_apidef_badflag) TEST_INFO(test_mh_apidef_dup) TEST_INFO(test_mh_apidef_badhashlength) TEST_INFO(test_mh_apidef_badhashchar) TEST_INFO(test_mh_apidef_toomany) TEST_INFO(test_mh_apidef_withapp) TEST_INFO(test_mh_apidef_withoutversion) TEST_INFO(test_mh_moduletype_good) TEST_INFO(test_mh_moduletype_bad) TEST_INFO(test_mh_nameversion_good) TEST_INFO(test_mh_name_bad) TEST_INFO(test_mh_version_bad) TEST_INFO(test_mh_specwithsource) TEST_INFO(test_mh_missingsource) TEST_INFO(test_mh_missingattr) TEST_INFO(test_mh_withsource_good) TEST_INFO(test_mh_withoutsource_good) TEST_INFO(test_mh_with_end) TEST_INFO(test_mh_nobackslash) TEST_INFO(test_mh_missingheader) TEST_INFO(test_mh_toolong) TEST_INFO(test_mh_toolong_utf8) TEST_END };