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_primitive_tests(CFCTest *test) { CFCParcel *parcel = CFCParcel_new("Parcel", NULL, NULL, NULL); CFCType *type = CFCType_new(CFCTYPE_PRIMITIVE, parcel, "hump_t", 0); OK(test, CFCType_is_primitive(type), "is_primitive"); { CFCType *twin = CFCType_new(CFCTYPE_PRIMITIVE, parcel, "hump_t", 0); OK(test, CFCType_equals(type, twin), "equals"); CFCBase_decref((CFCBase*)twin); } { CFCType *other = CFCType_new(CFCTYPE_PRIMITIVE, parcel, "dump_t", 0); OK(test, !CFCType_equals(type, other), "equals spoiled by specifier"); CFCBase_decref((CFCBase*)other); } { CFCType *other = CFCType_new(CFCTYPE_PRIMITIVE|CFCTYPE_CONST, parcel, "hump_t", 0); OK(test, !CFCType_equals(type, other), "equals spoiled by const"); CFCBase_decref((CFCBase*)other); } CFCBase_decref((CFCBase*)type); CFCBase_decref((CFCBase*)parcel); }
CFCParcel* CFCParcel_default_parcel(void) { if (default_parcel == NULL) { default_parcel = CFCParcel_new("", "", NULL); } return default_parcel; }
CFCParcel* CFCParcel_clownfish_parcel(void) { CFCParcel *parcel = CFCParcel_fetch("Lucy"); if (!parcel) { CFCVersion *version = CFCVersion_new("v0.3.0"); parcel = CFCParcel_new("Lucy", "Lucy", version); CFCParcel_register(parcel); CFCBase_decref((CFCBase*)version); CFCBase_decref((CFCBase*)parcel); } return parcel; }
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_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 CFCParcel* S_new_from_json(const char *json, const char *path) { JSONNode *parsed = S_parse_json_for_parcel(json); if (!parsed) { CFCUtil_die("Invalid JSON parcel definition in '%s'", path); } const char *name = NULL; const char *nickname = NULL; CFCVersion *version = NULL; for (size_t i = 0, max = parsed->num_kids; i < max; i += 2) { JSONNode *key = parsed->kids[i]; JSONNode *value = parsed->kids[i + 1]; if (key->type != JSON_STRING) { CFCUtil_die("JSON parsing error (filepath '%s')", path); } if (strcmp(key->string, "name") == 0) { if (value->type != JSON_STRING) { CFCUtil_die("'name' must be a string (filepath %s)", path); } name = value->string; } else if (strcmp(key->string, "nickname") == 0) { if (value->type != JSON_STRING) { CFCUtil_die("'nickname' must be a string (filepath %s)", path); } nickname = value->string; } else if (strcmp(key->string, "version") == 0) { if (value->type != JSON_STRING) { CFCUtil_die("'version' must be a string (filepath %s)", path); } version = CFCVersion_new(value->string); } } if (!name) { CFCUtil_die("Missing required key 'name' (filepath '%s')", path); } if (!version) { CFCUtil_die("Missing required key 'version' (filepath '%s')", path); } CFCParcel *self = CFCParcel_new(name, nickname, version); CFCBase_decref((CFCBase*)version); for (size_t i = 0, max = parsed->num_kids; i < max; i += 2) { JSONNode *key = parsed->kids[i]; JSONNode *value = parsed->kids[i + 1]; if (strcmp(key->string, "name") == 0 || strcmp(key->string, "nickname") == 0 || strcmp(key->string, "version") == 0 ) { ; } else { CFCUtil_die("Unrecognized key: '%s' (filepath '%s')", key->string, path); } } S_destroy_json(parsed); return self; }
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 CFCParcel* S_new_from_json(const char *json, CFCFileSpec *file_spec) { const char *path = file_spec ? CFCFileSpec_get_path(file_spec) : "[NULL]"; CFCJson *parsed = CFCJson_parse(json); if (!parsed) { CFCUtil_die("Invalid JSON parcel definition in '%s'", path); } if (CFCJson_get_type(parsed) != CFCJSON_HASH) { CFCUtil_die("Parcel definition must be a hash in '%s'", path); } const char *name = NULL; const char *nickname = NULL; int installed = true; CFCVersion *version = NULL; CFCVersion *major_version = NULL; CFCJson *prereqs = NULL; CFCJson **children = CFCJson_get_children(parsed); for (size_t i = 0; children[i]; i += 2) { const char *key = CFCJson_get_string(children[i]); CFCJson *value = children[i + 1]; int value_type = CFCJson_get_type(value); if (strcmp(key, "name") == 0) { if (value_type != CFCJSON_STRING) { CFCUtil_die("'name' must be a string (filepath %s)", path); } name = CFCJson_get_string(value); } else if (strcmp(key, "nickname") == 0) { if (value_type != CFCJSON_STRING) { CFCUtil_die("'nickname' must be a string (filepath %s)", path); } nickname = CFCJson_get_string(value); } else if (strcmp(key, "installed") == 0) { if (value_type != CFCJSON_BOOL) { CFCUtil_die("'installed' must be a boolean (filepath %s)", path); } installed = CFCJson_get_bool(value); } else if (strcmp(key, "version") == 0) { if (value_type != CFCJSON_STRING) { CFCUtil_die("'version' must be a string (filepath %s)", path); } version = CFCVersion_new(CFCJson_get_string(value)); } else if (strcmp(key, "major_version") == 0) { if (value_type != CFCJSON_STRING) { CFCUtil_die("'major_version' must be a string (filepath %s)", path); } major_version = CFCVersion_new(CFCJson_get_string(value)); } else if (strcmp(key, "prerequisites") == 0) { if (value_type != CFCJSON_HASH) { CFCUtil_die("'prerequisites' must be a hash (filepath %s)", path); } prereqs = value; } else { CFCUtil_die("Unrecognized key: '%s' (filepath '%s')", key, path); } } if (!name) { CFCUtil_die("Missing required key 'name' (filepath '%s')", path); } if (!version) { CFCUtil_die("Missing required key 'version' (filepath '%s')", path); } CFCParcel *self = CFCParcel_new(name, nickname, version, major_version, file_spec); if (!file_spec || !CFCFileSpec_included(file_spec)) { self->is_installed = installed; } if (prereqs) { S_set_prereqs(self, prereqs, path); } CFCBase_decref((CFCBase*)version); CFCBase_decref((CFCBase*)major_version); CFCJson_destroy(parsed); return self; }
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(); }