Updated Branches: refs/heads/cfc-tests e47ccd4cd -> 8ef152ae6
Port final CFC tests to C Note that testing exceptions in C is not supported yet. Project: http://git-wip-us.apache.org/repos/asf/lucy/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/8ef152ae Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/8ef152ae Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/8ef152ae Branch: refs/heads/cfc-tests Commit: 8ef152ae68751b99a48c6366caea972787c81d09 Parents: e47ccd4 Author: Nick Wellnhofer <[email protected]> Authored: Sun Feb 3 16:52:36 2013 +0100 Committer: Nick Wellnhofer <[email protected]> Committed: Sun Feb 3 18:36:28 2013 +0100 ---------------------------------------------------------------------- clownfish/compiler/perl/t/core/600-parser.t | 25 ++ clownfish/compiler/src/CFCTest.c | 1 + clownfish/compiler/src/CFCTest.h | 1 + clownfish/compiler/src/CFCTestHierarchy.c | 93 ++++++- clownfish/compiler/src/CFCTestParser.c | 312 ++++++++++++++++++++++ 5 files changed, 427 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy/blob/8ef152ae/clownfish/compiler/perl/t/core/600-parser.t ---------------------------------------------------------------------- diff --git a/clownfish/compiler/perl/t/core/600-parser.t b/clownfish/compiler/perl/t/core/600-parser.t new file mode 100644 index 0000000..0311548 --- /dev/null +++ b/clownfish/compiler/perl/t/core/600-parser.t @@ -0,0 +1,25 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +use strict; +use warnings; + +use Clownfish::CFC::Test; + +my $test = Clownfish::CFC::Test->new; +my $passed = $test->run_batch('Clownfish::CFC::Model::Parser'); + +exit($passed ? 0 : 1); + http://git-wip-us.apache.org/repos/asf/lucy/blob/8ef152ae/clownfish/compiler/src/CFCTest.c ---------------------------------------------------------------------- diff --git a/clownfish/compiler/src/CFCTest.c b/clownfish/compiler/src/CFCTest.c index 5e4f930..309e85f 100644 --- a/clownfish/compiler/src/CFCTest.c +++ b/clownfish/compiler/src/CFCTest.c @@ -126,6 +126,7 @@ static const CFCTestBatch *const S_batches[] = { &CFCTEST_BATCH_PARCEL, &CFCTEST_BATCH_FILE, &CFCTEST_BATCH_HIERARCHY, + &CFCTEST_BATCH_PARSER, NULL }; http://git-wip-us.apache.org/repos/asf/lucy/blob/8ef152ae/clownfish/compiler/src/CFCTest.h ---------------------------------------------------------------------- diff --git a/clownfish/compiler/src/CFCTest.h b/clownfish/compiler/src/CFCTest.h index ac80b92..3846023 100644 --- a/clownfish/compiler/src/CFCTest.h +++ b/clownfish/compiler/src/CFCTest.h @@ -114,6 +114,7 @@ extern const CFCTestBatch CFCTEST_BATCH_HIERARCHY; extern const CFCTestBatch CFCTEST_BATCH_METHOD; extern const CFCTestBatch CFCTEST_BATCH_PARAM_LIST; extern const CFCTestBatch CFCTEST_BATCH_PARCEL; +extern const CFCTestBatch CFCTEST_BATCH_PARSER; extern const CFCTestBatch CFCTEST_BATCH_SYMBOL; extern const CFCTestBatch CFCTEST_BATCH_TYPE; extern const CFCTestBatch CFCTEST_BATCH_UTIL; http://git-wip-us.apache.org/repos/asf/lucy/blob/8ef152ae/clownfish/compiler/src/CFCTestHierarchy.c ---------------------------------------------------------------------- diff --git a/clownfish/compiler/src/CFCTestHierarchy.c b/clownfish/compiler/src/CFCTestHierarchy.c index 10bd4e2..90a586b 100644 --- a/clownfish/compiler/src/CFCTestHierarchy.c +++ b/clownfish/compiler/src/CFCTestHierarchy.c @@ -35,22 +35,35 @@ #include "CFCTest.h" #include "CFCUtil.h" +#define T_CFSOURCE "t" CHY_DIR_SEP "cfsource" +#define T_CFEXT "t" CHY_DIR_SEP "cfext" +#define T_CFDEST "t" CHY_DIR_SEP "cfdest" +#define T_CFDEST_INCLUDE T_CFDEST CHY_DIR_SEP "include" +#define T_CFDEST_SOURCE T_CFDEST CHY_DIR_SEP "source" + static void S_run_tests(CFCTest *test); +static void +S_run_basic_tests(CFCTest *test); + +static void +S_run_include_tests(CFCTest *test); + const CFCTestBatch CFCTEST_BATCH_HIERARCHY = { "Clownfish::CFC::Model::Hierarchy", - 20, + 36, S_run_tests }; static void S_run_tests(CFCTest *test) { -#define T_CFSOURCE "t" CHY_DIR_SEP "cfsource" -#define T_CFDEST "t" CHY_DIR_SEP "cfdest" -#define T_CFDEST_INCLUDE T_CFDEST CHY_DIR_SEP "include" -#define T_CFDEST_SOURCE T_CFDEST CHY_DIR_SEP "source" + S_run_basic_tests(test); + S_run_include_tests(test); +} +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, @@ -137,5 +150,75 @@ S_run_tests(CFCTest *test) { rmdir(T_CFDEST); CFCBase_decref((CFCBase*)hierarchy); + CFCClass_clear_registry(); +} + +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_CFSOURCE); + const char **include_dirs = CFCHierarchy_get_include_dirs(hierarchy); + STR_EQ(test, include_dirs[0], T_CFSOURCE, "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_class_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, 4, "class count"); + INT_EQ(test, num_source_classes, 1, "source class count"); + STR_EQ(test, CFCClass_get_class_name(CFCClass_get_parent(rottweiler)), + "Animal::Dog", "parent of included class"); + + CFCBase_decref((CFCBase*)hierarchy); + CFCClass_clear_registry(); + } + + { + CFCHierarchy *hierarchy = CFCHierarchy_new(T_CFDEST); + CFCHierarchy_add_source_dir(hierarchy, T_CFSOURCE); + 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_class_name(klass); + if (strcmp(class_name, "Animal::Rottweiler") == 0) { + rottweiler = klass; + } + OK(test, !CFCClass_included(klass), "not included"); + } + INT_EQ(test, num_classes, 4, "class count"); + OK(test, rottweiler != NULL, "found rottweiler"); + STR_EQ(test, CFCClass_get_class_name(CFCClass_get_parent(rottweiler)), + "Animal::Dog", "parent of class from second source"); + + CFCBase_decref((CFCBase*)hierarchy); + CFCClass_clear_registry(); + } + + rmdir(T_CFDEST_INCLUDE); + rmdir(T_CFDEST_SOURCE); + rmdir(T_CFDEST); } http://git-wip-us.apache.org/repos/asf/lucy/blob/8ef152ae/clownfish/compiler/src/CFCTestParser.c ---------------------------------------------------------------------- diff --git a/clownfish/compiler/src/CFCTestParser.c b/clownfish/compiler/src/CFCTestParser.c new file mode 100644 index 0000000..f3eb1cd --- /dev/null +++ b/clownfish/compiler/src/CFCTestParser.c @@ -0,0 +1,312 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define CFC_USE_TEST_MACROS +#include "CFCBase.h" +#include "CFCClass.h" +#include "CFCMethod.h" +#include "CFCParamList.h" +#include "CFCParcel.h" +#include "CFCParser.h" +#include "CFCSymbol.h" +#include "CFCTest.h" +#include "CFCType.h" +#include "CFCUtil.h" +#include "CFCVariable.h" + +static void +S_run_tests(CFCTest *test); + +static void +S_test_initial_value(CFCTest *test, CFCParser *parser, + const char *const *values, const char *type, + const char *test_name); + +const CFCTestBatch CFCTEST_BATCH_PARSER = { + "Clownfish::CFC::Model::Parser", + 192, + S_run_tests +}; + +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); + 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" + }; + 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); + STR_EQ(test, CFCType_get_specifier(type), expected, + "object_type_specifier: %s", class_name); + FREEMEM(src); + FREEMEM(expected); + CFCBase_decref((CFCBase*)type); + } + } + + { + 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[3] = { + "public", "private", "parcel" + }; + static int (*const accessors[3])(CFCSymbol *sym) = { + CFCSymbol_public, CFCSymbol_private, CFCSymbol_parcel + }; + for (int i = 0; i < 3; ++i) { + const char *exposure = exposures[i]; + char *src = CFCUtil_sprintf("%s 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, "CharBuf*", + "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 CharBuf *" + }; + 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 = + "private 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] = { "Foo", "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(); +} + +static void +S_test_initial_value(CFCTest *test, CFCParser *parser, + const char *const *values, const char *type, + const char *test_name) { + for (int i = 0; values[i]; ++i) { + const char *value = values[i]; + char *src = CFCUtil_sprintf("(%s foo = %s)", type, value); + CFCParamList *param_list + = CFCTest_parse_param_list(test, parser, src); + const char **initial_values + = CFCParamList_get_initial_values(param_list); + STR_EQ(test, initial_values[0], value, "%s %s", test_name, value); + FREEMEM(src); + CFCBase_decref((CFCBase*)param_list); + } +} +
