static void S_run_parser_tests(CFCTest *test) { CFCParser *parser = CFCParser_new(); CFCParcel *neato_parcel = CFCTest_parse_parcel(test, parser, "parcel Neato;"); CFCParser_set_class_name(parser, "Neato::Obj"); CFCParser_set_class_nickname(parser, "Obj"); { static const char *method_strings[4] = { "public int Do_Foo(Obj *self);", "Obj* Gimme_An_Obj(Obj *self);", "void Do_Whatever(Obj *self, uint32_t a_num, float real);", "Foo* Fetch_Foo(Obj *self, int num);", }; for (int i = 0; i < 4; ++i) { CFCMethod *method = CFCTest_parse_method(test, parser, method_strings[i]); CFCBase_decref((CFCBase*)method); } } { CFCMethod *method = CFCTest_parse_method(test, parser, "public final void The_End(Obj *self);"); OK(test, CFCMethod_final(method), "final"); CFCBase_decref((CFCBase*)method); } CFCBase_decref((CFCBase*)neato_parcel); CFCBase_decref((CFCBase*)parser); CFCParcel_reap_singletons(); }
static void S_run_overridden_tests(CFCTest *test) { CFCParser *parser = CFCParser_new(); CFCParcel *neato_parcel = CFCTest_parse_parcel(test, parser, "parcel Neato;"); CFCType *return_type = CFCTest_parse_type(test, parser, "Obj*"); CFCParamList *param_list = CFCTest_parse_param_list(test, parser, "(Foo *self)"); CFCMethod *orig = CFCMethod_new(neato_parcel, NULL, "Neato::Foo", "Foo", "Return_An_Obj", return_type, param_list, NULL, 0, 0); CFCParamList *overrider_param_list = CFCTest_parse_param_list(test, parser, "(FooJr *self)"); CFCMethod *overrider = CFCMethod_new(neato_parcel, NULL, "Neato::Foo::FooJr", "FooJr", "Return_An_Obj", return_type, overrider_param_list, NULL, 0, 0); CFCMethod_override(overrider, orig); OK(test, !CFCMethod_novel(overrider), "A Method which overrides another is not 'novel'"); CFCBase_decref((CFCBase*)parser); CFCBase_decref((CFCBase*)neato_parcel); CFCBase_decref((CFCBase*)return_type); CFCBase_decref((CFCBase*)param_list); CFCBase_decref((CFCBase*)orig); CFCBase_decref((CFCBase*)overrider_param_list); CFCBase_decref((CFCBase*)overrider); CFCParcel_reap_singletons(); }
static void S_run_basic_tests(CFCTest *test) { CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL, NULL); CFCParcel_register(neato_parcel); CFCType *type = CFCType_new(0, neato_parcel, "mytype_t", 0); OK(test, CFCType_get_parcel(type) == neato_parcel, "get_parcel"); STR_EQ(test, CFCType_to_c(type), "mytype_t", "to_c"); STR_EQ(test, CFCType_get_specifier(type), "mytype_t", "get_specifier"); #define TEST_BOOL_ACCESSOR(type, name) \ OK(test, !CFCType_ ## name(type), #name " false by default"); TEST_BOOL_ACCESSOR(type, const); TEST_BOOL_ACCESSOR(type, nullable); TEST_BOOL_ACCESSOR(type, incremented); TEST_BOOL_ACCESSOR(type, decremented); TEST_BOOL_ACCESSOR(type, is_void); TEST_BOOL_ACCESSOR(type, is_object); TEST_BOOL_ACCESSOR(type, is_primitive); TEST_BOOL_ACCESSOR(type, is_integer); TEST_BOOL_ACCESSOR(type, is_floating); TEST_BOOL_ACCESSOR(type, is_string_type); TEST_BOOL_ACCESSOR(type, is_va_list); TEST_BOOL_ACCESSOR(type, is_arbitrary); TEST_BOOL_ACCESSOR(type, is_composite); CFCBase_decref((CFCBase*)neato_parcel); CFCBase_decref((CFCBase*)type); CFCParcel_reap_singletons(); }
static void S_run_tests(CFCTest *test) { CFCParser *parser = CFCParser_new(); CFCParcel *neato_parcel = CFCTest_parse_parcel(test, parser, "parcel Neato;"); CFCType *return_type = CFCTest_parse_type(test, parser, "Obj*"); CFCParamList *param_list = CFCTest_parse_param_list(test, parser, "(int32_t some_num)"); { CFCFunction *func = CFCFunction_new(NULL, "return_an_obj", return_type, param_list, NULL, 0); OK(test, func != NULL, "new"); CFCBase_decref((CFCBase*)func); } { CFCFunction *func = NULL; char *error; CFCUTIL_TRY { func = CFCFunction_new(NULL, "Uh_Oh", return_type, param_list, NULL, 0); } CFCUTIL_CATCH(error); OK(test, error && strstr(error, "Uh_Oh"), "invalid name kills constructor"); FREEMEM(error); CFCBase_decref((CFCBase*)func); } { CFCClass *neato_obj = CFCClass_create(neato_parcel, NULL, "Neato::Obj", NULL, NULL, NULL, NULL, false, false, false); CFCParser_set_class(parser, neato_obj); static const char *func_strings[2] = { "inert int running_count(int biscuit);", "public inert Hash* init_fave_hash(int32_t num_buckets," " bool o_rly);" }; for (int i = 0; i < 2; ++i) { CFCFunction *func = CFCTest_parse_function(test, parser, func_strings[i]); CFCBase_decref((CFCBase*)func); } CFCBase_decref((CFCBase*)neato_obj); } CFCBase_decref((CFCBase*)return_type); CFCBase_decref((CFCBase*)param_list); CFCBase_decref((CFCBase*)neato_parcel); CFCBase_decref((CFCBase*)parser); CFCParcel_reap_singletons(); }
static void S_run_tests(CFCTest *test) { CFCParser *parser = CFCParser_new(); CFCParcel *neato_parcel = CFCTest_parse_parcel(test, parser, "parcel Neato;"); { CFCType *return_type = CFCTest_parse_type(test, parser, "Obj*"); CFCParamList *param_list = CFCTest_parse_param_list(test, parser, "(int32_t some_num)"); CFCFunction *func = CFCFunction_new(neato_parcel, NULL, "Neato::Foo", "Foo", "return_an_obj", return_type, param_list, NULL, 0); OK(test, func != NULL, "new"); CFCBase_decref((CFCBase*)return_type); CFCBase_decref((CFCBase*)param_list); CFCBase_decref((CFCBase*)func); } { CFCParser_set_class_name(parser, "Neato::Obj"); CFCParser_set_class_cnick(parser, "Obj"); static const char *func_strings[2] = { "inert int running_count(int biscuit);", "public inert Hash* init_fave_hash(int32_t num_buckets," " bool o_rly);" }; for (int i = 0; i < 2; ++i) { CFCFunction *func = CFCTest_parse_function(test, parser, func_strings[i]); CFCBase_decref((CFCBase*)func); } } CFCBase_decref((CFCBase*)neato_parcel); CFCBase_decref((CFCBase*)parser); CFCParcel_reap_singletons(); }
static void S_run_arbitrary_tests(CFCTest *test) { { CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL, NULL); CFCParcel_register(neato_parcel); CFCType *foo = CFCType_new_arbitrary(neato_parcel, "foo_t"); STR_EQ(test, CFCType_get_specifier(foo), "foo_t", "get_specifier"); STR_EQ(test, CFCType_to_c(foo), "foo_t", "to_c"); CFCType *twin = CFCType_new_arbitrary(neato_parcel, "foo_t"); OK(test, CFCType_equals(foo, twin), "equals"); CFCType *compare_t = CFCType_new_arbitrary(neato_parcel, "Sort_compare_t"); OK(test, !CFCType_equals(foo, compare_t), "equals spoiled by different specifier"); CFCBase_decref((CFCBase*)neato_parcel); CFCBase_decref((CFCBase*)foo); CFCBase_decref((CFCBase*)compare_t); CFCBase_decref((CFCBase*)twin); } { CFCParser *parser = CFCParser_new(); static const char *specifiers[2] = { "foo_t", "Sort_compare_t" }; for (int i = 0; i < 2; ++i) { const char *specifier = specifiers[i]; CFCType *type = CFCTest_parse_type(test, parser, specifier); OK(test, CFCType_is_arbitrary(type), "arbitrary type %s", specifier); CFCBase_decref((CFCBase*)type); } CFCBase_decref((CFCBase*)parser); } CFCParcel_reap_singletons(); }
static void S_run_final_tests(CFCTest *test) { CFCParser *parser = CFCParser_new(); CFCParcel *neato_parcel = CFCTest_parse_parcel(test, parser, "parcel Neato;"); CFCClass *obj_class = CFCTest_parse_class(test, parser, "class Obj {}"); CFCClass *foo_class = CFCTest_parse_class(test, parser, "class Neato::Foo {}"); CFCType *return_type = CFCTest_parse_type(test, parser, "Obj*"); CFCParamList *param_list = CFCTest_parse_param_list(test, parser, "(Foo *self)"); CFCMethod *not_final = CFCMethod_new(neato_parcel, NULL, "Neato::Foo", "Foo", "Return_An_Obj", return_type, param_list, NULL, 0, 0); CFCMethod_resolve_types(not_final); CFCMethod *final = CFCMethod_finalize(not_final); OK(test, CFCMethod_compatible(not_final, final), "finalize clones properly"); OK(test, !CFCMethod_final(not_final), "not final by default"); OK(test, CFCMethod_final(final), "finalize"); CFCBase_decref((CFCBase*)parser); CFCBase_decref((CFCBase*)neato_parcel); CFCBase_decref((CFCBase*)obj_class); CFCBase_decref((CFCBase*)foo_class); CFCBase_decref((CFCBase*)return_type); CFCBase_decref((CFCBase*)param_list); CFCBase_decref((CFCBase*)not_final); CFCBase_decref((CFCBase*)final); CFCClass_clear_registry(); CFCParcel_reap_singletons(); }
int main(int argc, char **argv) { int i; size_t file_len; CFCArgs args; CFCHierarchy *hierarchy; CFCBindCore *core_binding; CFCC *c_binding; char *header = NULL; char *footer = NULL; const char *include_env; S_parse_arguments(argc, argv, &args); hierarchy = CFCHierarchy_new(args.dest); for (i = 0; args.source_dirs[i]; ++i) { CFCHierarchy_add_source_dir(hierarchy, args.source_dirs[i]); } for (i = 0; args.include_dirs[i]; ++i) { CFCHierarchy_add_include_dir(hierarchy, args.include_dirs[i]); } /* Add include dirs from environment variable CLOWNFISH_INCLUDE. */ include_env = getenv("CLOWNFISH_INCLUDE"); if (include_env != NULL) { char *include_env_copy = CFCUtil_strdup(include_env); const char *include_dir; for (include_dir = strtok(include_env_copy, ":"); include_dir != NULL; include_dir = strtok(NULL, ":") ) { if (include_dir[0] != '\0') { CFCHierarchy_add_include_dir(hierarchy, include_dir); } } FREEMEM(include_env_copy); } else if (UNIX_FILESYSTEM) { /* * Only add system include dirs if CLOWNFISH_INCLUDE is unset to * avoid errors when a parcel is found in multiple locations. */ CFCHierarchy_add_include_dir(hierarchy, "/usr/local/" SYS_INCLUDE_DIR); CFCHierarchy_add_include_dir(hierarchy, "/usr/" SYS_INCLUDE_DIR); } for (i = 0; args.parcels[i]; ++i) { CFCHierarchy_add_prereq(hierarchy, args.parcels[i]); } CFCHierarchy_build(hierarchy); if (args.header_filename) { header = CFCUtil_slurp_text(args.header_filename, &file_len); } else { header = CFCUtil_strdup(""); } if (args.footer_filename) { footer = CFCUtil_slurp_text(args.footer_filename, &file_len); } else { footer = CFCUtil_strdup(""); } core_binding = CFCBindCore_new(hierarchy, header, footer); CFCBindCore_write_all_modified(core_binding, 0); c_binding = CFCC_new(hierarchy, header, footer); CFCC_write_hostdefs(c_binding); if (args.num_source_dirs != 0) { CFCC_write_html_docs(c_binding); CFCC_write_man_pages(c_binding); } CFCHierarchy_write_log(hierarchy); CFCBase_decref((CFCBase*)c_binding); CFCBase_decref((CFCBase*)core_binding); CFCBase_decref((CFCBase*)hierarchy); FREEMEM(header); FREEMEM(footer); CFCClass_clear_registry(); CFCParcel_reap_singletons(); S_free_arguments(&args); return EXIT_SUCCESS; }
static void S_run_basic_tests(CFCTest *test) { CFCParser *parser = CFCParser_new(); CFCParcel *neato_parcel = CFCTest_parse_parcel(test, parser, "parcel Neato;"); CFCType *return_type = CFCTest_parse_type(test, parser, "Obj*"); CFCParamList *param_list = CFCTest_parse_param_list(test, parser, "(Foo *self, int32_t count = 0)"); CFCMethod *method = CFCMethod_new(neato_parcel, NULL, "Neato::Foo", "Foo", "Return_An_Obj", return_type, param_list, NULL, 0, 0); OK(test, method != NULL, "new"); OK(test, CFCSymbol_parcel((CFCSymbol*)method), "parcel exposure by default"); { CFCMethod *dupe = CFCMethod_new(neato_parcel, NULL, "Neato::Foo", "Foo", "Return_An_Obj", return_type, param_list, NULL, 0, 0); OK(test, CFCMethod_compatible(method, dupe), "compatible"); CFCBase_decref((CFCBase*)dupe); } { CFCMethod *macro_sym_differs = CFCMethod_new(neato_parcel, NULL, "Neato::Foo", "Foo", "Eat", return_type, param_list, NULL, 0, 0); OK(test, !CFCMethod_compatible(method, macro_sym_differs), "different macro_sym spoils compatible"); OK(test, !CFCMethod_compatible(macro_sym_differs, method), "... reversed"); CFCBase_decref((CFCBase*)macro_sym_differs); } { static const char *param_strings[5] = { "(Foo *self, int32_t count = 0, int b)", "(Foo *self, int32_t count = 1)", "(Foo *self, int32_t count)", "(Foo *self, int32_t countess = 0)", "(Foo *self, uint32_t count = 0)" }; static const char *test_names[5] = { "extra param", "different initial_value", "missing initial_value", "different param name", "different param type" }; for (int i = 0; i < 5; ++i) { CFCParamList *other_param_list = CFCTest_parse_param_list(test, parser, param_strings[i]); CFCMethod *other = CFCMethod_new(neato_parcel, NULL, "Neato::Foo", "Foo", "Return_An_Obj", return_type, other_param_list, NULL, 0, 0); OK(test, !CFCMethod_compatible(method, other), "%s spoils compatible", test_names[i]); OK(test, !CFCMethod_compatible(other, method), "... reversed"); CFCBase_decref((CFCBase*)other_param_list); CFCBase_decref((CFCBase*)other); } } { CFCParamList *self_differs_list = CFCTest_parse_param_list(test, parser, "(Bar *self, int32_t count = 0)"); CFCMethod *self_differs = CFCMethod_new(neato_parcel, NULL, "Neato::Bar", "Bar", "Return_An_Obj", return_type, self_differs_list, NULL, 0, 0); OK(test, CFCMethod_compatible(method, self_differs), "different self type still compatible()," " since can't test inheritance"); OK(test, CFCMethod_compatible(self_differs, method), "... reversed"); CFCBase_decref((CFCBase*)self_differs_list); CFCBase_decref((CFCBase*)self_differs); } { CFCMethod *aliased = CFCMethod_new(neato_parcel, NULL, "Neato::Foo", "Foo", "Aliased", return_type, param_list, NULL, 0, 0); OK(test, !CFCMethod_get_host_alias(aliased), "no host alias by default"); CFCMethod_set_host_alias(aliased, "Host_Alias"); STR_EQ(test, CFCMethod_get_host_alias(aliased), "Host_Alias", "set/get host alias"); CFCBase_decref((CFCBase*)aliased); } { CFCMethod *excluded = CFCMethod_new(neato_parcel, NULL, "Neato::Foo", "Foo", "Excluded", return_type, param_list, NULL, 0, 0); OK(test, !CFCMethod_excluded_from_host(excluded), "not excluded by default"); CFCMethod_exclude_from_host(excluded); OK(test, CFCMethod_excluded_from_host(excluded), "exclude from host"); CFCBase_decref((CFCBase*)excluded); } CFCBase_decref((CFCBase*)parser); CFCBase_decref((CFCBase*)neato_parcel); CFCBase_decref((CFCBase*)return_type); CFCBase_decref((CFCBase*)param_list); CFCBase_decref((CFCBase*)method); CFCParcel_reap_singletons(); }
static void S_run_tests(CFCTest *test) { #define STUFF_THING "Stuff" CHY_DIR_SEP "Thing" CFCParser *parser = CFCParser_new(); CFCFileSpec *file_spec = CFCFileSpec_new(".", STUFF_THING, 0); { const char *string = "parcel Stuff;\n" "class Stuff::Thing {\n" " Foo *foo;\n" " Bar *bar;\n" "}\n" "class Foo {}\n" "class Bar {}\n" "__C__\n" "int foo;\n" "__END_C__\n"; CFCFile *file = CFCParser_parse_file(parser, string, file_spec); STR_EQ(test, CFCFile_get_source_dir(file), ".", "get_source_dir"); STR_EQ(test, CFCFile_get_path_part(file), STUFF_THING, "get_path_part"); OK(test, !CFCFile_included(file), "included"); STR_EQ(test, CFCFile_guard_name(file), "H_STUFF_THING", "guard_name"); STR_EQ(test, CFCFile_guard_start(file), "#ifndef H_STUFF_THING\n#define H_STUFF_THING 1\n", "guard_start"); STR_EQ(test, CFCFile_guard_close(file), "#endif /* H_STUFF_THING */\n", "guard_close"); OK(test, !CFCFile_get_modified(file), "modified false at start"); CFCFile_set_modified(file, 1); OK(test, CFCFile_get_modified(file), "set_modified, get_modified"); #define PATH_TO_STUFF_THING \ "path" CHY_DIR_SEP \ "to" CHY_DIR_SEP \ "Stuff" CHY_DIR_SEP \ "Thing" char *cfh_path = CFCFile_cfh_path(file, "path/to"); STR_EQ(test, cfh_path, PATH_TO_STUFF_THING ".cfh", "cfh_path"); FREEMEM(cfh_path); char *c_path = CFCFile_c_path(file, "path/to"); STR_EQ(test, c_path, PATH_TO_STUFF_THING ".c", "c_path"); FREEMEM(c_path); char *h_path = CFCFile_h_path(file, "path/to"); STR_EQ(test, h_path, PATH_TO_STUFF_THING ".h", "h_path"); FREEMEM(h_path); CFCClass **classes = CFCFile_classes(file); OK(test, classes[0] != NULL && classes[1] != NULL && classes[2] != NULL && classes[3] == NULL, "classes() filters blocks"); CFCVariable **member_vars = CFCClass_fresh_member_vars(classes[0]); CFCType *foo_type = CFCVariable_get_type(member_vars[0]); CFCType_resolve(foo_type); STR_EQ(test, CFCType_get_specifier(foo_type), "stuff_Foo", "file production picked up parcel def"); CFCType *bar_type = CFCVariable_get_type(member_vars[1]); CFCType_resolve(bar_type); STR_EQ(test, CFCType_get_specifier(bar_type), "stuff_Bar", "parcel def is sticky"); CFCParcel *parcel = CFCFile_get_parcel(file); STR_EQ(test, CFCParcel_get_name(parcel), "Stuff", "get_parcel"); CFCBase **blocks = CFCFile_blocks(file); STR_EQ(test, CFCBase_get_cfc_class(blocks[0]), "Clownfish::CFC::Model::Class", "blocks[0]"); STR_EQ(test, CFCBase_get_cfc_class(blocks[1]), "Clownfish::CFC::Model::Class", "blocks[1]"); STR_EQ(test, CFCBase_get_cfc_class(blocks[2]), "Clownfish::CFC::Model::Class", "blocks[2]"); STR_EQ(test, CFCBase_get_cfc_class(blocks[3]), "Clownfish::CFC::Model::CBlock", "blocks[3]"); OK(test, blocks[4] == NULL, "blocks[4]"); CFCBase_decref((CFCBase*)file); CFCClass_clear_registry(); } CFCBase_decref((CFCBase*)file_spec); CFCBase_decref((CFCBase*)parser); CFCParcel_reap_singletons(); }
static void S_run_object_tests(CFCTest *test) { static const char *modifiers[4] = { "const", "incremented", "decremented", "nullable" }; static int flags[4] = { CFCTYPE_CONST, CFCTYPE_INCREMENTED, CFCTYPE_DECREMENTED, CFCTYPE_NULLABLE }; static int (*accessors[4])(CFCType *type) = { CFCType_const, CFCType_incremented, CFCType_decremented, CFCType_nullable }; { CFCParser *parser = CFCParser_new(); CFCParcel *neato_parcel = CFCTest_parse_parcel(test, parser, "parcel Neato;"); static const char *specifiers[4] = { "Foo", "FooJr", "FooIII", "Foo4th" }; for (int i = 0; i < 4; ++i) { const char *specifier = specifiers[i]; char *class_code = CFCUtil_sprintf("class %s {}", specifier); CFCClass *klass = CFCTest_parse_class(test, parser, class_code); FREEMEM(class_code); static const char *prefixes[2] = { "", "neato_" }; char *expect = CFCUtil_sprintf("neato_%s", specifier); for (int j = 0; j < 2; ++j) { char *src = CFCUtil_sprintf("%s%s*", prefixes[j], specifier); CFCType *type = CFCTest_parse_type(test, parser, src); CFCType_resolve(type); STR_EQ(test, CFCType_get_specifier(type), expect, "object_type_specifier: %s", src); OK(test, CFCType_is_object(type), "%s is_object", src); INT_EQ(test, CFCType_get_indirection(type), 1, "%s indirection", src); FREEMEM(src); CFCBase_decref((CFCBase*)type); } FREEMEM(expect); for (int j = 0; j < 4; ++j) { char *src = CFCUtil_sprintf("%s %s*", modifiers[j], specifier); CFCType *type = CFCTest_parse_type(test, parser, src); OK(test, CFCType_is_object(type), "%s is_object", src); OK(test, accessors[j](type), "%s accessor", src); FREEMEM(src); CFCBase_decref((CFCBase*)type); } CFCBase_decref((CFCBase*)klass); CFCClass_clear_registry(); } CFCBase_decref((CFCBase*)neato_parcel); CFCBase_decref((CFCBase*)parser); } CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL, NULL); CFCClass *foo_class = CFCClass_create(neato_parcel, NULL, "Foo", NULL, NULL, NULL, NULL, NULL, false, false, false); CFCType *foo = CFCType_new_object(0, neato_parcel, "Foo", 1); CFCType_resolve(foo); { CFCType *another_foo = CFCType_new_object(0, neato_parcel, "Foo", 1); CFCType_resolve(another_foo); OK(test, CFCType_equals(foo, another_foo), "equals"); CFCBase_decref((CFCBase*)another_foo); } { CFCClass *bar_class = CFCClass_create(neato_parcel, NULL, "Bar", NULL, NULL, NULL, NULL, NULL, false, false, false); CFCType *bar = CFCType_new_object(0, neato_parcel, "Bar", 1); CFCType_resolve(bar); OK(test, !CFCType_equals(foo, bar), "different specifier spoils equals"); CFCBase_decref((CFCBase*)bar); CFCBase_decref((CFCBase*)bar_class); } { CFCParcel *foreign_parcel = CFCParcel_new("Foreign", NULL, NULL, NULL); CFCClass *foreign_foo_class = CFCClass_create(foreign_parcel, NULL, "Foreign::Foo", NULL, NULL, NULL, NULL, NULL, false, false, false); CFCType *foreign_foo = CFCType_new_object(0, foreign_parcel, "Foo", 1); CFCType_resolve(foreign_foo); OK(test, !CFCType_equals(foo, foreign_foo), "different parcel spoils equals"); STR_EQ(test, CFCType_get_specifier(foreign_foo), "foreign_Foo", "prepend parcel prefix to specifier"); CFCBase_decref((CFCBase*)foreign_parcel); CFCBase_decref((CFCBase*)foreign_foo_class); CFCBase_decref((CFCBase*)foreign_foo); } { for (int i = 0; i < 4; ++i) { CFCType *modified_foo = CFCType_new_object(flags[i], neato_parcel, "Foo", 1); CFCType_resolve(modified_foo); OK(test, accessors[i](modified_foo), "%s", modifiers[i]); OK(test, !accessors[i](foo), "not %s", modifiers[i]); OK(test, !CFCType_equals(foo, modified_foo), "different %s spoils equals", modifiers[i]); OK(test, !CFCType_similar(foo, modified_foo), "different %s spoils similar", modifiers[i]); CFCBase_decref((CFCBase*)modified_foo); } } { CFCType *string_type = CFCType_new_object(0, neato_parcel, "String", 1); OK(test, CFCType_is_string_type(string_type), "%s", "is_string_type"); OK(test, !CFCType_is_string_type(foo), "not %s", "not is_string_type"); CFCBase_decref((CFCBase*)string_type); } CFCBase_decref((CFCBase*)neato_parcel); CFCBase_decref((CFCBase*)foo_class); CFCBase_decref((CFCBase*)foo); CFCClass_clear_registry(); CFCParcel_reap_singletons(); }
static void S_run_basic_tests(CFCTest *test) { CFCHierarchy *hierarchy = CFCHierarchy_new(T_CFDEST); STR_EQ(test, CFCHierarchy_get_dest(hierarchy), T_CFDEST, "get_dest"); STR_EQ(test, CFCHierarchy_get_include_dest(hierarchy), T_CFDEST_INCLUDE, "get_include_dest"); STR_EQ(test, CFCHierarchy_get_source_dest(hierarchy), T_CFDEST_SOURCE, "get_source_dest"); CFCHierarchy_add_source_dir(hierarchy, T_CFBASE); const char **source_dirs = CFCHierarchy_get_source_dirs(hierarchy); STR_EQ(test, source_dirs[0], T_CFBASE, "source_dirs[0]"); OK(test, source_dirs[1] == NULL, "source_dirs[1]"); CFCHierarchy_build(hierarchy); CFCFile **files = CFCHierarchy_files(hierarchy); CFCFile *animal = NULL; CFCFile *dog = NULL; CFCFile *util = NULL; for (int i = 0; i < 3; ++i) { CFCFile *file = files[i]; OK(test, file != NULL, "files[%d]", i); OK(test, !CFCFile_get_modified(file), "start off not modified"); CFCBase **blocks = CFCFile_blocks(file); for (int j = 0; blocks[j]; ++j) { CFCBase *block = blocks[j]; const char *cfc_class_name = CFCBase_get_cfc_class(block); if (strcmp(cfc_class_name, "Clownfish::CFC::Model::Class") == 0) { CFCClass *klass = (CFCClass*)block; const char *class_name = CFCClass_get_name(klass); if (strcmp(class_name, "Animal") == 0) { animal = file; } else if (strcmp(class_name, "Animal::Dog") == 0) { dog = file; } else if (strcmp(class_name, "Animal::Util") == 0) { util = file; } } } } OK(test, files[3] == NULL, "recursed and found all three files"); { CFCClass **ordered_classes = CFCHierarchy_ordered_classes(hierarchy); OK(test, ordered_classes[0] != NULL, "ordered_classes[0]"); OK(test, ordered_classes[1] != NULL, "ordered_classes[1]"); OK(test, ordered_classes[2] != NULL, "ordered_classes[2]"); OK(test, ordered_classes[3] != NULL, "ordered_classes[3]"); OK(test, ordered_classes[4] == NULL, "all classes"); FREEMEM(ordered_classes); } // Generate fake C files, with times set to two seconds ago. time_t now = time(NULL); time_t past_time = now - 2; static const char *const h_paths[] = { T_CFDEST_INCLUDE CHY_DIR_SEP "Animal.h", T_CFDEST_INCLUDE CHY_DIR_SEP "Animal" CHY_DIR_SEP "Dog.h", T_CFDEST_INCLUDE CHY_DIR_SEP "Animal" CHY_DIR_SEP "Util.h" }; OK(test, CFCUtil_make_path(T_CFDEST_INCLUDE CHY_DIR_SEP "Animal"), "make_path"); for (int i = 0; i < 3; ++i) { const char *h_path = h_paths[i]; const char *content = "#include <stdio.h>\n"; CFCUtil_write_file(h_path, content, strlen(content)); CFCTest_set_file_times(h_path, past_time); } char *cfh_path = CFCFile_cfh_path(animal, T_CFBASE); CFCTest_set_file_times(cfh_path, now); FREEMEM(cfh_path); CFCHierarchy_propagate_modified(hierarchy, 0); OK(test, CFCFile_get_modified(animal), "Animal modified"); OK(test, CFCFile_get_modified(dog), "Parent's modification propagates to child's file"); OK(test, !CFCFile_get_modified(util), "Modification doesn't propagate to inert class"); for (int i = 0; i < 3; ++i) { remove(h_paths[i]); } rmdir(T_CFDEST_INCLUDE CHY_DIR_SEP "Animal"); rmdir(T_CFDEST_INCLUDE); rmdir(T_CFDEST_SOURCE); rmdir(T_CFDEST); CFCBase_decref((CFCBase*)hierarchy); CFCClass_clear_registry(); CFCParcel_reap_singletons(); }
static void S_run_include_tests(CFCTest *test) { { CFCHierarchy *hierarchy = CFCHierarchy_new(T_CFDEST); CFCHierarchy_add_source_dir(hierarchy, T_CFEXT); CFCHierarchy_add_include_dir(hierarchy, T_CFBASE); const char **include_dirs = CFCHierarchy_get_include_dirs(hierarchy); STR_EQ(test, include_dirs[0], T_CFBASE, "include_dirs[0]"); OK(test, include_dirs[1] == NULL, "include_dirs[1]"); CFCHierarchy_build(hierarchy); CFCClass **classes = CFCHierarchy_ordered_classes(hierarchy); CFCClass *rottweiler = NULL;; int num_classes; int num_source_classes = 0; for (num_classes = 0; classes[num_classes]; ++num_classes) { CFCClass *klass = classes[num_classes]; int expect_included = 1; const char *class_name = CFCClass_get_name(klass); if (strcmp(class_name, "Animal::Rottweiler") == 0) { rottweiler = klass; expect_included = 0; ++num_source_classes; } INT_EQ(test, CFCClass_included(klass), expect_included, "included"); } INT_EQ(test, num_classes, 5, "class count"); INT_EQ(test, num_source_classes, 1, "source class count"); STR_EQ(test, CFCClass_get_name(CFCClass_get_parent(rottweiler)), "Animal::Dog", "parent of included class"); FREEMEM(classes); CFCBase_decref((CFCBase*)hierarchy); CFCClass_clear_registry(); CFCParcel_reap_singletons(); } { CFCHierarchy *hierarchy = CFCHierarchy_new(T_CFDEST); CFCHierarchy_add_source_dir(hierarchy, T_CFBASE); CFCHierarchy_add_source_dir(hierarchy, T_CFEXT); CFCHierarchy_build(hierarchy); CFCClass **classes = CFCHierarchy_ordered_classes(hierarchy); CFCClass *rottweiler = NULL;; int num_classes; for (num_classes = 0; classes[num_classes]; ++num_classes) { CFCClass *klass = classes[num_classes]; const char *class_name = CFCClass_get_name(klass); if (strcmp(class_name, "Animal::Rottweiler") == 0) { rottweiler = klass; } OK(test, !CFCClass_included(klass), "not included"); } INT_EQ(test, num_classes, 5, "class count"); OK(test, rottweiler != NULL, "found rottweiler"); STR_EQ(test, CFCClass_get_name(CFCClass_get_parent(rottweiler)), "Animal::Dog", "parent of class from second source"); FREEMEM(classes); CFCBase_decref((CFCBase*)hierarchy); CFCClass_clear_registry(); CFCParcel_reap_singletons(); } { CFCHierarchy *hierarchy = CFCHierarchy_new(T_CFDEST); CFCHierarchy_add_include_dir(hierarchy, T_CFBASE); CFCHierarchy_add_include_dir(hierarchy, T_CFEXT); CFCHierarchy_add_prereq(hierarchy, "AnimalExtension"); CFCHierarchy_build(hierarchy); CFCParcel *animal = CFCParcel_fetch("Animal"); OK(test, animal != NULL, "parcel Animal registered"); OK(test, CFCParcel_required(animal), "parcel Animal required"); CFCParcel *animal_ext = CFCParcel_fetch("AnimalExtension"); OK(test, animal_ext != NULL, "parcel AnimalExtension registered"); OK(test, CFCParcel_required(animal_ext), "parcel AnimalExtension required"); CFCClass **classes = CFCHierarchy_ordered_classes(hierarchy); int num_classes = 0; while (classes[num_classes]) { ++num_classes; } INT_EQ(test, num_classes, 5, "class count"); FREEMEM(classes); CFCBase_decref((CFCBase*)hierarchy); CFCClass_clear_registry(); CFCParcel_reap_singletons(); } rmdir(T_CFDEST_INCLUDE); rmdir(T_CFDEST_SOURCE); rmdir(T_CFDEST); }
static void S_run_parcel_tests(CFCTest *test) { { CFCParcel *parcel = CFCParcel_new("Foo", NULL, NULL, NULL); OK(test, parcel != NULL, "new"); OK(test, !CFCParcel_included(parcel), "not included"); CFCBase_decref((CFCBase*)parcel); } { CFCFileSpec *file_spec = CFCFileSpec_new(".", "Parcel", true); CFCParcel *parcel = CFCParcel_new("Foo", NULL, NULL, file_spec); OK(test, CFCParcel_included(parcel), "included"); CFCBase_decref((CFCBase*)parcel); CFCBase_decref((CFCBase*)file_spec); } { const char *json = " {\n" " \"name\": \"Crustacean\",\n" " \"nickname\": \"Crust\",\n" " \"version\": \"v0.1.0\"\n" " }\n"; CFCParcel *parcel = CFCParcel_new_from_json(json, NULL); OK(test, parcel != NULL, "new_from_json"); CFCBase_decref((CFCBase*)parcel); } { const char *path = "t" CHY_DIR_SEP "cfbase" CHY_DIR_SEP "Animal.cfp"; CFCParcel *parcel = CFCParcel_new_from_file(path, NULL); OK(test, parcel != NULL, "new_from_file"); CFCBase_decref((CFCBase*)parcel); } { CFCParcel *parcel = CFCParcel_new("Crustacean", "Crust", NULL, NULL); CFCParcel_register(parcel); STR_EQ(test, CFCVersion_get_vstring(CFCParcel_get_version(parcel)), "v0", "get_version"); CFCBase_decref((CFCBase*)parcel); CFCParcel_reap_singletons(); } { const char *json = " {\n" " \"name\": \"Crustacean\",\n" " \"version\": \"v0.1.0\",\n" " \"prerequisites\": {\n" " \"Clownfish\": null,\n" " \"Arthropod\": \"v30.104.5\"\n" " }\n" " }\n"; CFCParcel *parcel = CFCParcel_new_from_json(json, NULL); CFCPrereq **prereqs = CFCParcel_get_prereqs(parcel); OK(test, prereqs != NULL, "prereqs"); CFCPrereq *cfish = prereqs[0]; OK(test, cfish != NULL, "prereqs[0]"); const char *cfish_name = CFCPrereq_get_name(cfish); STR_EQ(test, cfish_name, "Clownfish", "prereqs[0] name"); CFCVersion *v0 = CFCVersion_new("v0"); CFCVersion *cfish_version = CFCPrereq_get_version(cfish); INT_EQ(test, CFCVersion_compare_to(cfish_version, v0), 0, "prereqs[0] version"); CFCPrereq *apod = prereqs[1]; OK(test, apod != NULL, "prereqs[1]"); const char *apod_name = CFCPrereq_get_name(apod); STR_EQ(test, apod_name, "Arthropod", "prereqs[1] name"); CFCVersion *v30_104_5 = CFCVersion_new("v30.104.5"); CFCVersion *apod_version = CFCPrereq_get_version(apod); INT_EQ(test, CFCVersion_compare_to(apod_version, v30_104_5), 0, "prereqs[1] version"); OK(test, prereqs[2] == NULL, "prereqs[2]"); CFCBase_decref((CFCBase*)v30_104_5); CFCBase_decref((CFCBase*)v0); CFCBase_decref((CFCBase*)parcel); } { CFCFileSpec *foo_file_spec = CFCFileSpec_new(".", "Foo", true); CFCParcel *foo = CFCParcel_new("Foo", NULL, NULL, foo_file_spec); CFCParcel_register(foo); CFCVersion *cfish_version = CFCVersion_new("v0.8.7"); CFCFileSpec *cfish_file_spec = CFCFileSpec_new(".", "Clownfish", true); CFCParcel *cfish = CFCParcel_new("Clownfish", NULL, cfish_version, cfish_file_spec); CFCParcel_register(cfish); const char *crust_json = " {\n" " \"name\": \"Crustacean\",\n" " \"version\": \"v0.1.0\",\n" " \"prerequisites\": {\n" " \"Clownfish\": \"v0.8.5\",\n" " }\n" " }\n"; CFCParcel *crust = CFCParcel_new_from_json(crust_json, NULL); CFCParcel_register(crust); CFCParcel_check_prereqs(crust); INT_EQ(test, CFCParcel_required(foo), false, "parcel not required"); INT_EQ(test, CFCParcel_required(cfish), true, "prereq required"); INT_EQ(test, CFCParcel_required(crust), true, "self required"); CFCParcel **prereq_parcels = CFCParcel_prereq_parcels(crust); OK(test, prereq_parcels[0] != NULL, "prereq_parcels[0]"); const char *name = CFCParcel_get_name(prereq_parcels[0]); STR_EQ(test, name, "Clownfish", "prereq_parcels[0] name"); OK(test, prereq_parcels[1] == NULL, "prereq_parcels[0]"); OK(test, CFCParcel_has_prereq(crust, cfish), "has_prereq"); OK(test, CFCParcel_has_prereq(crust, crust), "has_prereq self"); OK(test, !CFCParcel_has_prereq(crust, foo), "has_prereq false"); CFCParcel_add_struct_sym(cfish, "Swim"); CFCParcel_add_struct_sym(crust, "Pinch"); CFCParcel_add_struct_sym(foo, "Bar"); CFCParcel *found; found = CFCParcel_lookup_struct_sym(crust, "Swim"); OK(test, found == cfish, "lookup_struct_sym prereq"); found = CFCParcel_lookup_struct_sym(crust, "Pinch"); OK(test, found == crust, "lookup_struct_sym self"); found = CFCParcel_lookup_struct_sym(crust, "Bar"); OK(test, found == NULL, "lookup_struct_sym other"); FREEMEM(prereq_parcels); CFCBase_decref((CFCBase*)crust); CFCBase_decref((CFCBase*)cfish_version); CFCBase_decref((CFCBase*)cfish_file_spec); CFCBase_decref((CFCBase*)cfish); CFCBase_decref((CFCBase*)foo_file_spec); CFCBase_decref((CFCBase*)foo); CFCParcel_reap_singletons(); } }
static void S_run_tests(CFCTest *test) { CFCParcel *parcel = CFCParcel_default_parcel(); { static const char *exposures[4] = { "public", "private", "parcel", "local" }; static int (*accessors[4])(CFCSymbol *sym) = { CFCSymbol_public, CFCSymbol_private, CFCSymbol_parcel, CFCSymbol_local }; for (int i = 0; i < 4; ++i) { CFCSymbol *symbol = CFCSymbol_new(parcel, exposures[i], NULL, NULL, "sym"); for (int j = 0; j < 4; ++j) { int has_exposure = accessors[j](symbol); if (i == j) { OK(test, has_exposure, "exposure %s", exposures[i]); } else { OK(test, !has_exposure, "%s means not %s", exposures[i], exposures[j]); } } CFCBase_decref((CFCBase*)symbol); } } { CFCSymbol *foo = CFCSymbol_new(parcel, "parcel", "Foo", NULL, "sym"); CFCSymbol *foo_jr = CFCSymbol_new(parcel, "parcel", "Foo::FooJr", NULL, "sym"); int equal = CFCSymbol_equals(foo, foo_jr); OK(test, !equal, "different class_name spoils equals"); const char *foo_jr_name = CFCSymbol_get_class_name(foo_jr); STR_EQ(test, foo_jr_name, "Foo::FooJr", "get_class_name"); const char *foo_jr_cnick = CFCSymbol_get_class_cnick(foo_jr); STR_EQ(test, foo_jr_cnick, "FooJr", "derive class_cnick from class_name"); CFCBase_decref((CFCBase*)foo); CFCBase_decref((CFCBase*)foo_jr); } { CFCSymbol *public_exposure = CFCSymbol_new(parcel, "public", NULL, NULL, "sym"); CFCSymbol *parcel_exposure = CFCSymbol_new(parcel, "parcel", NULL, NULL, "sym"); int equal = CFCSymbol_equals(public_exposure, parcel_exposure); OK(test, !equal, "different exposure spoils equals"); CFCBase_decref((CFCBase*)public_exposure); CFCBase_decref((CFCBase*)parcel_exposure); } { CFCParcel *lucifer_parcel = CFCParcel_new("Lucifer", NULL, NULL, false); CFCParcel_register(lucifer_parcel); CFCSymbol *lucifer = CFCSymbol_new(lucifer_parcel, "parcel", NULL, NULL, "sym"); CFCParcel *symbol_parcel = CFCSymbol_get_parcel(lucifer); OK(test, symbol_parcel == lucifer_parcel, "derive parcel"); const char *prefix = CFCSymbol_get_prefix(lucifer); STR_EQ(test, prefix, "lucifer_", "get_prefix"); const char *Prefix = CFCSymbol_get_Prefix(lucifer); STR_EQ(test, Prefix, "Lucifer_", "get_Prefix"); const char *PREFIX = CFCSymbol_get_PREFIX(lucifer); STR_EQ(test, PREFIX, "LUCIFER_", "get_PREFIX"); CFCParcel *luser_parcel = CFCParcel_new("Luser", NULL, NULL, false); CFCParcel_register(luser_parcel); CFCSymbol *luser = CFCSymbol_new(luser_parcel, "parcel", NULL, NULL, "sym"); int equal = CFCSymbol_equals(lucifer, luser); OK(test, !equal, "different exposure spoils equals"); CFCBase_decref((CFCBase*)lucifer_parcel); CFCBase_decref((CFCBase*)lucifer); CFCBase_decref((CFCBase*)luser_parcel); CFCBase_decref((CFCBase*)luser); } { CFCSymbol *ooga = CFCSymbol_new(parcel, "parcel", NULL, NULL, "ooga"); CFCSymbol *booga = CFCSymbol_new(parcel, "parcel", NULL, NULL, "booga"); int equal = CFCSymbol_equals(ooga, booga); OK(test, !equal, "different micro_sym spoils equals"); CFCBase_decref((CFCBase*)ooga); CFCBase_decref((CFCBase*)booga); } { CFCParcel *eep_parcel = CFCParcel_new("Eep", NULL, NULL, false); CFCParcel_register(eep_parcel); CFCSymbol *eep = CFCSymbol_new(eep_parcel, "parcel", "Op::Ork", NULL, "ah_ah"); const char *short_sym = CFCSymbol_short_sym(eep); STR_EQ(test, short_sym, "Ork_ah_ah", "short_sym"); const char *full_sym = CFCSymbol_full_sym(eep); STR_EQ(test, full_sym, "eep_Ork_ah_ah", "full_sym"); CFCBase_decref((CFCBase*)eep_parcel); CFCBase_decref((CFCBase*)eep); } CFCParcel_reap_singletons(); }
static void S_run_tests(CFCTest *test) { CFCParser *parser = CFCParser_new(); OK(test, parser != NULL, "new"); { CFCParcel *fish = CFCTest_parse_parcel(test, parser, "parcel Fish;"); CFCParcel *registered = CFCParcel_new("Crustacean", "Crust", NULL, false); CFCParcel_register(registered); CFCParcel *parcel = CFCTest_parse_parcel(test, parser, "parcel Crustacean;"); OK(test, parcel == registered, "Fetch registered parcel"); OK(test, CFCParser_get_parcel(parser) == parcel, "parcel_definition sets internal var"); CFCBase_decref((CFCBase*)fish); CFCBase_decref((CFCBase*)registered); CFCBase_decref((CFCBase*)parcel); } { static const char *const specifiers[8] = { "foo", "_foo", "foo_yoo", "FOO", "Foo", "fOO", "f00", "foo_foo_foo" }; for (int i = 0; i < 8; ++i) { const char *specifier = specifiers[i]; char *src = CFCUtil_sprintf("int32_t %s;", specifier); CFCVariable *var = CFCTest_parse_variable(test, parser, src); STR_EQ(test, CFCVariable_micro_sym(var), specifier, "identifier/declarator: %s", specifier); FREEMEM(src); CFCBase_decref((CFCBase*)var); } } { static const char *const specifiers[6] = { "void", "float", "uint32_t", "int64_t", "uint8_t", "bool" }; for (int i = 0; i < 6; ++i) { const char *specifier = specifiers[i]; char *src = CFCUtil_sprintf("int32_t %s;", specifier); CFCBase *result = CFCParser_parse(parser, src); OK(test, result == NULL, "reserved word not parsed as identifier: %s", specifier); FREEMEM(src); CFCBase_decref(result); } } { static const char *const type_strings[7] = { "bool", "const char *", "Obj*", "i32_t", "char[]", "long[1]", "i64_t[30]" }; for (int i = 0; i < 7; ++i) { const char *type_string = type_strings[i]; CFCType *type = CFCTest_parse_type(test, parser, type_string); CFCBase_decref((CFCBase*)type); } } { static const char *const class_names[7] = { "ByteBuf", "Obj", "ANDMatcher", "Foo", "FooJr", "FooIII", "Foo4th" }; CFCClass *class_list[8]; for (int i = 0; i < 7; ++i) { char *class_code = CFCUtil_sprintf("class %s {}", class_names[i]); CFCClass *klass = CFCTest_parse_class(test, parser, class_code); class_list[i] = klass; FREEMEM(class_code); } class_list[7] = NULL; for (int i = 0; i < 7; ++i) { const char *class_name = class_names[i]; char *src = CFCUtil_sprintf("%s*", class_name); char *expected = CFCUtil_sprintf("crust_%s", class_name); CFCType *type = CFCTest_parse_type(test, parser, src); CFCType_resolve(type, class_list); STR_EQ(test, CFCType_get_specifier(type), expected, "object_type_specifier: %s", class_name); FREEMEM(src); FREEMEM(expected); CFCBase_decref((CFCBase*)type); } for (int i = 0; i < 7; ++i) { CFCBase_decref((CFCBase*)class_list[i]); } CFCClass_clear_registry(); } { CFCType *type = CFCTest_parse_type(test, parser, "const char"); OK(test, CFCType_const(type), "type_qualifier const"); CFCBase_decref((CFCBase*)type); } { static const char *const exposures[2] = { "public", "" }; static int (*const accessors[2])(CFCSymbol *sym) = { CFCSymbol_public, CFCSymbol_parcel }; for (int i = 0; i < 2; ++i) { const char *exposure = exposures[i]; char *src = CFCUtil_sprintf("%s inert int32_t foo;", exposure); CFCVariable *var = CFCTest_parse_variable(test, parser, src); OK(test, accessors[i]((CFCSymbol*)var), "exposure_specifier %s", exposure); FREEMEM(src); CFCBase_decref((CFCBase*)var); } } { static const char *const hex_constants[] = { "0x1", "0x0a", "0xFFFFFFFF", "-0xFC", NULL }; S_test_initial_value(test, parser, hex_constants, "int32_t", "hex_constant:"); } { static const char *const integer_constants[] = { "1", "-9999", "0", "10000", NULL }; S_test_initial_value(test, parser, integer_constants, "int32_t", "integer_constant:"); } { static const char *const float_constants[] = { "1.0", "-9999.999", "0.1", "0.0", NULL }; S_test_initial_value(test, parser, float_constants, "double", "float_constant:"); } { static const char *const string_literals[] = { "\"blah\"", "\"blah blah\"", "\"\\\"blah\\\" \\\"blah\\\"\"", NULL }; S_test_initial_value(test, parser, string_literals, "String*", "string_literal:"); } { static const char *const composites[5] = { "int[]", "i32_t **", "Foo **", "Foo ***", "const void *" }; for (int i = 0; i < 5; ++i) { const char *composite = composites[i]; CFCType *type = CFCTest_parse_type(test, parser, composite); OK(test, CFCType_is_composite(type), "composite_type: %s", composite); CFCBase_decref((CFCBase*)type); } } { static const char *const object_types[5] = { "Obj *", "incremented Foo*", "decremented String *" }; for (int i = 0; i < 3; ++i) { const char *object_type = object_types[i]; CFCType *type = CFCTest_parse_type(test, parser, object_type); OK(test, CFCType_is_object(type), "object_type: %s", object_type); CFCBase_decref((CFCBase*)type); } } { static const char *const param_list_strings[3] = { "()", "(int foo)", "(Obj *foo, Foo **foo_ptr)" }; for (int i = 0; i < 3; ++i) { const char *param_list_string = param_list_strings[i]; CFCParamList *param_list = CFCTest_parse_param_list(test, parser, param_list_string); INT_EQ(test, CFCParamList_num_vars(param_list), i, "param list num_vars: %d", i); CFCBase_decref((CFCBase*)param_list); } } { CFCParamList *param_list = CFCTest_parse_param_list(test, parser, "(int foo, ...)"); OK(test, CFCParamList_variadic(param_list), "variadic param list"); CFCBase_decref((CFCBase*)param_list); } { const char *param_list_string = "(int foo = 0xFF, char *bar =\"blah\")"; CFCParamList *param_list = CFCTest_parse_param_list(test, parser, param_list_string); const char **initial_values = CFCParamList_get_initial_values(param_list); STR_EQ(test, initial_values[0], "0xFF", "param list initial_values[0]"); STR_EQ(test, initial_values[1], "\"blah\"", "param list initial_values[1]"); OK(test, initial_values[2] == NULL, "param list initial_values[2]"); CFCBase_decref((CFCBase*)param_list); } { CFCParser_set_class_name(parser, "Stuff::Obj"); CFCParser_set_class_cnick(parser, "Obj"); const char *method_string = "public Foo* Spew_Foo(Obj *self, uint32_t *how_many);"; CFCMethod *method = CFCTest_parse_method(test, parser, method_string); CFCBase_decref((CFCBase*)method); const char *var_string = "public inert Hash *hash;"; CFCVariable *var = CFCTest_parse_variable(test, parser, var_string); CFCBase_decref((CFCBase*)var); } { static const char *const class_names[4] = { "Foo", "Foo::FooJr", "Foo::FooJr::FooIII", "Foo::FooJr::FooIII::Foo4th" }; for (int i = 0; i < 4; ++i) { const char *class_name = class_names[i]; char *class_string = CFCUtil_sprintf("class %s { }", class_name); CFCClass *klass = CFCTest_parse_class(test, parser, class_string); STR_EQ(test, CFCClass_get_class_name(klass), class_name, "class_name: %s", class_name); FREEMEM(class_string); CFCBase_decref((CFCBase*)klass); } } { static const char *const cnicks[2] = { "Food", "FF" }; for (int i = 0; i < 2; ++i) { const char *cnick = cnicks[i]; char *class_string = CFCUtil_sprintf("class Foodie%s cnick %s { }", cnick, cnick); CFCClass *klass = CFCTest_parse_class(test, parser, class_string); STR_EQ(test, CFCClass_get_cnick(klass), cnick, "cnick: %s", cnick); FREEMEM(class_string); CFCBase_decref((CFCBase*)klass); } } CFCBase_decref((CFCBase*)parser); CFCClass_clear_registry(); CFCParcel_reap_singletons(); }