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_tests(CFCTest *test) { CFCParser *parser = CFCParser_new(); { CFCCBlock *block = CFCCBlock_new("int foo;"); STR_EQ(test, CFCCBlock_get_contents(block), "int foo;", "get_contents"); CFCBase_decref((CFCBase*)block); } { const char *cblock_string = " __C__\n" "#define FOO_BAR 1\n" "__END_C__ "; CFCBase *result = CFCParser_parse(parser, cblock_string); OK(test, result != NULL, "parse cblock"); STR_EQ(test, CFCBase_get_cfc_class(result), "Clownfish::CFC::Model::CBlock", "result class of cblock"); CFCCBlock *block = (CFCCBlock*)result; STR_EQ(test, CFCCBlock_get_contents(block), "#define FOO_BAR 1\n", "parse embed_c"); CFCBase_decref((CFCBase*)block); } CFCBase_decref((CFCBase*)parser); }
static void S_run_void_tests(CFCTest *test) { CFCParser *parser = CFCParser_new(); { CFCType *type = CFCType_new_void(false); STR_EQ(test, CFCType_get_specifier(type), "void", "get_specifier"); STR_EQ(test, CFCType_to_c(type), "void", "to_c"); OK(test, CFCType_is_void(type), "is_void"); CFCBase_decref((CFCBase*)type); } { CFCType *type = CFCType_new_void(true); STR_EQ(test, CFCType_to_c(type), "const void", "'const' in C representation"); CFCBase_decref((CFCBase*)type); } { CFCType *type = CFCTest_parse_type(test, parser, "void"); OK(test, CFCType_is_void(type), "void is_void"); CFCBase_decref((CFCBase*)type); } { CFCType *type = CFCTest_parse_type(test, parser, "const void"); OK(test, CFCType_is_void(type), "const void is_void"); OK(test, CFCType_const(type), "const void is const"); CFCBase_decref((CFCBase*)type); } CFCBase_decref((CFCBase*)parser); }
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_integer_tests(CFCTest *test) { { CFCType *type = CFCType_new_integer(CFCTYPE_CONST, "int32_t"); OK(test, CFCType_const(type), "const"); STR_EQ(test, CFCType_get_specifier(type), "int32_t", "get_specifier"); STR_EQ(test, CFCType_to_c(type), "const int32_t", "'const' in C representation"); CFCBase_decref((CFCBase*)type); } { CFCParser *parser = CFCParser_new(); static const char *specifiers[14] = { "bool", "char", "short", "int", "long", "size_t", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t" }; for (int i = 0; i < 14; ++i) { const char *specifier = specifiers[i]; CFCType *type; type = CFCTest_parse_type(test, parser, specifier); OK(test, CFCType_is_integer(type), "%s is_integer", specifier); CFCBase_decref((CFCBase*)type); char *const_specifier = CFCUtil_sprintf("const %s", specifier); type = CFCTest_parse_type(test, parser, const_specifier); OK(test, CFCType_is_integer(type), "%s is_integer", const_specifier); OK(test, CFCType_const(type), "%s is const", const_specifier); FREEMEM(const_specifier); CFCBase_decref((CFCBase*)type); } CFCBase_decref((CFCBase*)parser); } }
static void S_run_va_list_tests(CFCTest *test) { { CFCType *type = CFCType_new_va_list(); STR_EQ(test, CFCType_get_specifier(type), "va_list", "specifier defaults to 'va_list'"); STR_EQ(test, CFCType_to_c(type), "va_list", "to_c"); CFCBase_decref((CFCBase*)type); } { CFCParser *parser = CFCParser_new(); CFCType *type = CFCTest_parse_type(test, parser, "va_list"); OK(test, CFCType_is_va_list(type), "is_va_list"); CFCBase_decref((CFCBase*)type); CFCBase_decref((CFCBase*)parser); } }
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(); }
CFCHierarchy* CFCHierarchy_init(CFCHierarchy *self, const char *dest) { if (!dest || !strlen(dest)) { CFCUtil_die("'dest' is required"); } self->sources = (char**)CALLOCATE(1, sizeof(char*)); self->num_sources = 0; self->includes = (char**)CALLOCATE(1, sizeof(char*)); self->num_includes = 0; self->prereqs = (char**)CALLOCATE(1, sizeof(char*)); self->num_prereqs = 0; self->dest = CFCUtil_strdup(dest); self->trees = (CFCClass**)CALLOCATE(1, sizeof(CFCClass*)); self->num_trees = 0; self->files = (CFCFile**)CALLOCATE(1, sizeof(CFCFile*)); self->num_files = 0; self->parser = CFCParser_new(); self->inc_dest = CFCUtil_sprintf("%s" CHY_DIR_SEP "include", self->dest); self->src_dest = CFCUtil_sprintf("%s" CHY_DIR_SEP "source", self->dest); return self; }
static void S_run_float_tests(CFCTest *test) { { CFCType *type = CFCType_new_float(CFCTYPE_CONST, "float"); OK(test, CFCType_const(type), "const"); STR_EQ(test, CFCType_get_specifier(type), "float", "get_specifier"); STR_EQ(test, CFCType_to_c(type), "const float", "'const' in C representation"); CFCBase_decref((CFCBase*)type); } { CFCParser *parser = CFCParser_new(); static const char *specifiers[2] = { "float", "double" }; for (int i = 0; i < 2; ++i) { const char *specifier = specifiers[i]; CFCType *type; type = CFCTest_parse_type(test, parser, specifier); OK(test, CFCType_is_floating(type), "%s is_floating", specifier); CFCBase_decref((CFCBase*)type); char *const_specifier = CFCUtil_sprintf("const %s", specifier); type = CFCTest_parse_type(test, parser, const_specifier); OK(test, CFCType_is_floating(type), "%s is_floating", const_specifier); OK(test, CFCType_const(type), "%s is const", const_specifier); FREEMEM(const_specifier); CFCBase_decref((CFCBase*)type); } CFCBase_decref((CFCBase*)parser); } }
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(); }
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_composite_tests(CFCTest *test) { CFCParser *parser = CFCParser_new(); CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL, NULL); CFCParser_set_parcel(parser, neato_parcel); { static const char *type_strings[14] = { "char*", "char**", "char***", "int32_t*", "Obj**", "int8_t[]", "int8_t[1]", "neato_method_t[]", "neato_method_t[1]", "multi_dimensional_t[1][10]", "char * * ", "const Obj**", "const void*", "int8_t[ 3 ]" }; for (int i = 0; i < 14; ++i) { const char *type_string = type_strings[i]; CFCType *type = CFCTest_parse_type(test, parser, type_string); OK(test, CFCType_is_composite(type), "composite type %s", type_string); CFCBase_decref((CFCBase*)type); } } { CFCType *foo = CFCType_new_object(0, neato_parcel, "Foo", 1); CFCType *const_foo = CFCType_new_object(CFCTYPE_CONST, neato_parcel, "Foo", 1); CFCType *composite = CFCType_new_composite(0, foo, 1, NULL); OK(test, CFCType_is_composite(composite), "is_composite"); STR_EQ(test, CFCType_get_specifier(composite), "Foo", "get_specifier delegates to child" ); CFCType *twin = CFCType_new_composite(0, foo, 1, NULL); OK(test, CFCType_equals(composite, twin), "equals"); CFCBase_decref((CFCBase*)twin); CFCType *const_composite = CFCType_new_composite(0, const_foo, 1, NULL); OK(test, !CFCType_equals(composite, const_composite), "equals spoiled by different child"); CFCBase_decref((CFCBase*)const_composite); CFCBase_decref((CFCBase*)composite); CFCBase_decref((CFCBase*)foo); CFCBase_decref((CFCBase*)const_foo); } { CFCType *foo_array = CFCTest_parse_type(test, parser, "foo_t[]"); CFCType_resolve(foo_array); STR_EQ(test, CFCType_get_array(foo_array), "[]", "get_array"); STR_EQ(test, CFCType_to_c(foo_array), "foo_t", "array subscripts not included by to_c"); CFCType *foo_array_array = CFCTest_parse_type(test, parser, "foo_t[][]"); OK(test, !CFCType_equals(foo_array, foo_array_array), "equals spoiled by different array postfixes"); CFCBase_decref((CFCBase*)foo_array); CFCBase_decref((CFCBase*)foo_array_array); } { CFCType *foo_star = CFCTest_parse_type(test, parser, "foo_t*"); CFCType *foo_star_star = CFCTest_parse_type(test, parser, "foo_t**"); OK(test, !CFCType_equals(foo_star, foo_star_star), "equals spoiled by different levels of indirection"); INT_EQ(test, CFCType_get_indirection(foo_star), 1, "foo_t* indirection"); INT_EQ(test, CFCType_get_indirection(foo_star_star), 2, "foo_t** indirection"); CFCBase_decref((CFCBase*)foo_star); CFCBase_decref((CFCBase*)foo_star_star); } CFCBase_decref((CFCBase*)neato_parcel); CFCBase_decref((CFCBase*)parser); }
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) { 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) { 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(); }