You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by nw...@apache.org on 2016/03/10 14:35:22 UTC
[05/12] lucy-clownfish git commit: Test CFC exceptions in C test suite
Test CFC exceptions in C test suite
Catching exceptions sometimes requires a separate function because
stack variables might be clobbered by longjmp. See
http://stackoverflow.com/q/2024933
Also add some other parcel tests from the Perl test suite.
Fixes CLOWNFISH-14.
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/e3ecf10d
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/e3ecf10d
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/e3ecf10d
Branch: refs/heads/master
Commit: e3ecf10da6a3314c31e60133041ed3578357387b
Parents: 6fdf098
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Fri Mar 4 18:00:49 2016 +0100
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Sat Mar 5 18:15:14 2016 +0100
----------------------------------------------------------------------
compiler/c/t/cfclash/bar/Bar.cfh | 25 +++++
compiler/c/t/cfclash/bar/Bar.cfp | 4 +
compiler/c/t/cfclash/bar/Baz.cfh | 25 +++++
compiler/c/t/cfclash/class/Animal/DogClash.cfh | 28 ++++++
compiler/c/t/cfclash/class/AnimalExtension.cfp | 5 +
compiler/c/t/cfclash/file/Animal/Dog.cfh | 28 ++++++
compiler/c/t/cfclash/foo/Foo.cfh | 25 +++++
compiler/c/t/cfclash/foo/Foo.cfp | 4 +
compiler/src/CFCTestCBlock.c | 19 +++-
compiler/src/CFCTestClass.c | 105 +++++++++++++++++++-
compiler/src/CFCTestFunction.c | 30 ++++--
compiler/src/CFCTestHierarchy.c | 99 +++++++++++++++++-
compiler/src/CFCTestMethod.c | 67 ++++++++++++-
compiler/src/CFCTestParcel.c | 87 +++++++++++++---
compiler/src/CFCTestSymbol.c | 29 +++++-
compiler/src/CFCTestType.c | 59 ++++++++++-
compiler/src/CFCTestVariable.c | 32 +++++-
17 files changed, 645 insertions(+), 26 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/e3ecf10d/compiler/c/t/cfclash/bar/Bar.cfh
----------------------------------------------------------------------
diff --git a/compiler/c/t/cfclash/bar/Bar.cfh b/compiler/c/t/cfclash/bar/Bar.cfh
new file mode 100644
index 0000000..89e798e
--- /dev/null
+++ b/compiler/c/t/cfclash/bar/Bar.cfh
@@ -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.
+ */
+
+parcel Bar;
+
+public class Bar inherits Clownfish::Obj {
+ int var;
+
+ public void
+ Method(Bar *self);
+}
+
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/e3ecf10d/compiler/c/t/cfclash/bar/Bar.cfp
----------------------------------------------------------------------
diff --git a/compiler/c/t/cfclash/bar/Bar.cfp b/compiler/c/t/cfclash/bar/Bar.cfp
new file mode 100644
index 0000000..e5868f6
--- /dev/null
+++ b/compiler/c/t/cfclash/bar/Bar.cfp
@@ -0,0 +1,4 @@
+{
+ "name": "Bar",
+ "version": "v1.0.0"
+}
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/e3ecf10d/compiler/c/t/cfclash/bar/Baz.cfh
----------------------------------------------------------------------
diff --git a/compiler/c/t/cfclash/bar/Baz.cfh b/compiler/c/t/cfclash/bar/Baz.cfh
new file mode 100644
index 0000000..00e4033
--- /dev/null
+++ b/compiler/c/t/cfclash/bar/Baz.cfh
@@ -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.
+ */
+
+parcel Foo;
+
+public class Baz inherits Clownfish::Obj {
+ int var;
+
+ public void
+ Method(Baz *self);
+}
+
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/e3ecf10d/compiler/c/t/cfclash/class/Animal/DogClash.cfh
----------------------------------------------------------------------
diff --git a/compiler/c/t/cfclash/class/Animal/DogClash.cfh b/compiler/c/t/cfclash/class/Animal/DogClash.cfh
new file mode 100644
index 0000000..3eba020
--- /dev/null
+++ b/compiler/c/t/cfclash/class/Animal/DogClash.cfh
@@ -0,0 +1,28 @@
+/* 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.
+ */
+
+parcel AnimalExtension;
+
+class Animal::Dog inherits Clownfish::Obj {
+ public inert incremented Dog*
+ new();
+
+ public inert Dog*
+ init(Dog *self);
+
+ public void
+ Bark(Dog *self);
+}
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/e3ecf10d/compiler/c/t/cfclash/class/AnimalExtension.cfp
----------------------------------------------------------------------
diff --git a/compiler/c/t/cfclash/class/AnimalExtension.cfp b/compiler/c/t/cfclash/class/AnimalExtension.cfp
new file mode 100644
index 0000000..76f31d3
--- /dev/null
+++ b/compiler/c/t/cfclash/class/AnimalExtension.cfp
@@ -0,0 +1,5 @@
+{
+ "name": "AnimalExtension",
+ "nickname": "AniExt",
+ "version": "v0.1.0"
+}
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/e3ecf10d/compiler/c/t/cfclash/file/Animal/Dog.cfh
----------------------------------------------------------------------
diff --git a/compiler/c/t/cfclash/file/Animal/Dog.cfh b/compiler/c/t/cfclash/file/Animal/Dog.cfh
new file mode 100644
index 0000000..1357109
--- /dev/null
+++ b/compiler/c/t/cfclash/file/Animal/Dog.cfh
@@ -0,0 +1,28 @@
+/* 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.
+ */
+
+parcel Animal;
+
+class Animal::AnotherDog inherits Animal {
+ public inert incremented AnotherDog*
+ new();
+
+ public inert AnotherDog*
+ init(AnotherDog *self);
+
+ public void
+ Bark(AnotherDog *self);
+}
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/e3ecf10d/compiler/c/t/cfclash/foo/Foo.cfh
----------------------------------------------------------------------
diff --git a/compiler/c/t/cfclash/foo/Foo.cfh b/compiler/c/t/cfclash/foo/Foo.cfh
new file mode 100644
index 0000000..b770d8a
--- /dev/null
+++ b/compiler/c/t/cfclash/foo/Foo.cfh
@@ -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.
+ */
+
+parcel Foo;
+
+public class Foo inherits Clownfish::Obj {
+ int var;
+
+ public void
+ Method(Foo *self);
+}
+
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/e3ecf10d/compiler/c/t/cfclash/foo/Foo.cfp
----------------------------------------------------------------------
diff --git a/compiler/c/t/cfclash/foo/Foo.cfp b/compiler/c/t/cfclash/foo/Foo.cfp
new file mode 100644
index 0000000..2995169
--- /dev/null
+++ b/compiler/c/t/cfclash/foo/Foo.cfp
@@ -0,0 +1,4 @@
+{
+ "name": "Foo",
+ "version": "v1.0.0"
+}
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/e3ecf10d/compiler/src/CFCTestCBlock.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCTestCBlock.c b/compiler/src/CFCTestCBlock.c
index 6061d44..650a3eb 100644
--- a/compiler/src/CFCTestCBlock.c
+++ b/compiler/src/CFCTestCBlock.c
@@ -14,18 +14,21 @@
* limitations under the License.
*/
+#include <string.h>
+
#define CFC_USE_TEST_MACROS
#include "CFCBase.h"
#include "CFCCBlock.h"
#include "CFCParser.h"
#include "CFCTest.h"
+#include "CFCUtil.h"
static void
S_run_tests(CFCTest *test);
const CFCTestBatch CFCTEST_BATCH_C_BLOCK = {
"Clownfish::CFC::Model::CBlock",
- 4,
+ 5,
S_run_tests
};
@@ -41,6 +44,20 @@ S_run_tests(CFCTest *test) {
}
{
+ CFCCBlock *block = NULL;
+ char *error;
+
+ CFCUTIL_TRY {
+ block = CFCCBlock_new(NULL);
+ }
+ CFCUTIL_CATCH(error);
+ OK(test, error && strstr(error, "contents"), "content required");
+
+ FREEMEM(error);
+ CFCBase_decref((CFCBase*)block);
+ }
+
+ {
const char *cblock_string =
" __C__\n"
"#define FOO_BAR 1\n"
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/e3ecf10d/compiler/src/CFCTestClass.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCTestClass.c b/compiler/src/CFCTestClass.c
index a91e3b9..8acb300 100644
--- a/compiler/src/CFCTestClass.c
+++ b/compiler/src/CFCTestClass.c
@@ -44,10 +44,25 @@ S_has_symbol(CFCSymbol **symbols, const char *name);
const CFCTestBatch CFCTEST_BATCH_CLASS = {
"Clownfish::CFC::Model::Class",
- 86,
+ 96,
S_run_tests
};
+static char*
+S_try_create(CFCParcel *parcel, const char *name, const char *nickname) {
+ CFCClass *klass = NULL;
+ char *error;
+
+ CFCUTIL_TRY {
+ klass = CFCClass_create(parcel, NULL, name, nickname, NULL, NULL, NULL,
+ false, false, false);
+ }
+ CFCUTIL_CATCH(error);
+
+ CFCBase_decref((CFCBase*)klass);
+ return error;
+}
+
static void
S_run_tests(CFCTest *test) {
CFCParser *parser = CFCParser_new();
@@ -94,6 +109,27 @@ S_run_tests(CFCTest *test) {
OK(test, should_be_foo == foo, "fetch_singleton");
}
+ {
+ char *error = S_try_create(neato, "Foo", NULL);
+ OK(test, error && strstr(error, "Two classes with name"),
+ "Can't call create for the same class more than once");
+ FREEMEM(error);
+ }
+
+ {
+ char *error = S_try_create(neato, "Other::Foo", NULL);
+ OK(test, error && strstr(error, "Class name conflict"),
+ "Can't create classes wth the same final component");
+ FREEMEM(error);
+ }
+
+ {
+ char *error = S_try_create(neato, "Bar", "Foo");
+ OK(test, error && strstr(error, "Class nickname conflict"),
+ "Can't create classes wth the same nickname");
+ FREEMEM(error);
+ }
+
CFCClass *foo_jr
= CFCClass_create(neato, NULL, "Foo::FooJr", NULL, NULL, NULL, "Foo",
false, false, false);
@@ -125,6 +161,50 @@ S_run_tests(CFCTest *test) {
= CFCTest_parse_method(test, parser, "void Do_Stuff(Foo *self);");
CFCClass_add_method(foo, do_stuff);
+ CFCClass *inert_foo
+ = CFCClass_create(neato, NULL, "InertFoo", NULL, NULL, NULL, NULL,
+ false, true, false);
+
+ {
+ CFCParser_set_class_name(parser, "InertFoo");
+ CFCMethod *inert_do_stuff
+ = CFCTest_parse_method(test, parser,
+ "void Do_Stuff(InertFoo *self);");
+ char *error;
+
+ CFCUTIL_TRY {
+ CFCClass_add_method(inert_foo, inert_do_stuff);
+ }
+ CFCUTIL_CATCH(error);
+ OK(test, error && strstr(error, "inert class"),
+ "Error out on conflict between inert attribute and object method");
+
+ FREEMEM(error);
+ CFCBase_decref((CFCBase*)inert_do_stuff);
+ }
+
+ {
+ char *error;
+ CFCUTIL_TRY {
+ CFCClass_add_child(foo, inert_foo);
+ }
+ CFCUTIL_CATCH(error);
+ OK(test, error && strstr(error, "Inert class"),
+ "inert class can't inherit");
+ FREEMEM(error);
+ }
+
+ {
+ char *error;
+ CFCUTIL_TRY {
+ CFCClass_add_child(inert_foo, foo);
+ }
+ CFCUTIL_CATCH(error);
+ OK(test, error && strstr(error, "from inert class"),
+ "can't inherit from inert class");
+ FREEMEM(error);
+ }
+
CFCClass_resolve_types(foo);
CFCClass_resolve_types(foo_jr);
CFCClass_resolve_types(final_foo);
@@ -133,6 +213,28 @@ S_run_tests(CFCTest *test) {
CFCClass_add_child(foo_jr, final_foo);
CFCClass_grow_tree(foo);
+ {
+ char *error;
+ CFCUTIL_TRY {
+ CFCClass_grow_tree(foo);
+ }
+ CFCUTIL_CATCH(error);
+ OK(test, error && strstr(error, "grow_tree"),
+ "call grow_tree only once.");
+ FREEMEM(error);
+ }
+
+ {
+ char *error;
+ CFCUTIL_TRY {
+ CFCClass_add_method(foo_jr, do_stuff);
+ }
+ CFCUTIL_CATCH(error);
+ OK(test, error && strstr(error, "grow_tree"),
+ "Forbid add_method after grow_tree.");
+ FREEMEM(error);
+ }
+
OK(test, CFCClass_get_parent(foo_jr) == foo, "grow_tree, one level" );
OK(test, CFCClass_get_parent(final_foo) == foo_jr,
"grow_tree, two levels");
@@ -334,6 +436,7 @@ S_run_tests(CFCTest *test) {
CFCBase_decref((CFCBase*)foo);
CFCBase_decref((CFCBase*)foo_jr);
CFCBase_decref((CFCBase*)final_foo);
+ CFCBase_decref((CFCBase*)inert_foo);
CFCBase_decref((CFCBase*)do_stuff);
CFCClass_clear_registry();
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/e3ecf10d/compiler/src/CFCTestFunction.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCTestFunction.c b/compiler/src/CFCTestFunction.c
index 22dd487..459fea1 100644
--- a/compiler/src/CFCTestFunction.c
+++ b/compiler/src/CFCTestFunction.c
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <string.h>
+
#define CFC_USE_TEST_MACROS
#include "CFCBase.h"
#include "CFCFunction.h"
@@ -22,13 +24,14 @@
#include "CFCParser.h"
#include "CFCTest.h"
#include "CFCType.h"
+#include "CFCUtil.h"
static void
S_run_tests(CFCTest *test);
const CFCTestBatch CFCTEST_BATCH_FUNCTION = {
"Clownfish::CFC::Model::Function",
- 11,
+ 12,
S_run_tests
};
@@ -37,17 +40,30 @@ 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)");
{
- 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");
- CFCBase_decref((CFCBase*)return_type);
- CFCBase_decref((CFCBase*)param_list);
+ FREEMEM(error);
CFCBase_decref((CFCBase*)func);
}
@@ -65,6 +81,8 @@ S_run_tests(CFCTest *test) {
}
}
+ CFCBase_decref((CFCBase*)return_type);
+ CFCBase_decref((CFCBase*)param_list);
CFCBase_decref((CFCBase*)neato_parcel);
CFCBase_decref((CFCBase*)parser);
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/e3ecf10d/compiler/src/CFCTestHierarchy.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCTestHierarchy.c b/compiler/src/CFCTestHierarchy.c
index fa005aa..670f872 100644
--- a/compiler/src/CFCTestHierarchy.c
+++ b/compiler/src/CFCTestHierarchy.c
@@ -17,6 +17,7 @@
#include "charmony.h"
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
/* For rmdir */
@@ -41,6 +42,10 @@
#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"
+#define T_CFCLASH_CLASS "t" CHY_DIR_SEP "cfclash" CHY_DIR_SEP "class"
+#define T_CFCLASH_FILE "t" CHY_DIR_SEP "cfclash" CHY_DIR_SEP "file"
+#define T_CFCLASH_FOO "t" CHY_DIR_SEP "cfclash" CHY_DIR_SEP "foo"
+#define T_CFCLASH_BAR "t" CHY_DIR_SEP "cfclash" CHY_DIR_SEP "bar"
static void
S_run_tests(CFCTest *test);
@@ -51,9 +56,12 @@ S_run_basic_tests(CFCTest *test);
static void
S_run_include_tests(CFCTest *test);
+static void
+S_run_clash_tests(CFCTest *test);
+
const CFCTestBatch CFCTEST_BATCH_HIERARCHY = {
"Clownfish::CFC::Model::Hierarchy",
- 44,
+ 48,
S_run_tests
};
@@ -61,6 +69,7 @@ static void
S_run_tests(CFCTest *test) {
S_run_basic_tests(test);
S_run_include_tests(test);
+ S_run_clash_tests(test);
}
static void
@@ -263,3 +272,91 @@ S_run_include_tests(CFCTest *test) {
rmdir(T_CFDEST);
}
+static void
+S_run_clash_tests(CFCTest *test) {
+ if (getenv("LUCY_VALGRIND")) {
+ SKIP(test, 1, "Exceptions leak");
+ }
+ else {
+ CFCHierarchy *hierarchy = CFCHierarchy_new(T_CFDEST);
+ CFCHierarchy_add_source_dir(hierarchy, T_CFBASE);
+ CFCHierarchy_add_source_dir(hierarchy, T_CFCLASH_FILE);
+ char *error;
+
+ CFCUTIL_TRY {
+ CFCHierarchy_build(hierarchy);
+ }
+ CFCUTIL_CATCH(error);
+ OK(test, error && strstr(error, "found twice"),
+ "source/source filename clash");
+
+ CFCBase_decref((CFCBase*)hierarchy);
+ CFCClass_clear_registry();
+ CFCParcel_reap_singletons();
+ }
+
+ if (getenv("LUCY_VALGRIND")) {
+ SKIP(test, 1, "Exceptions leak");
+ }
+ else {
+ CFCHierarchy *hierarchy = CFCHierarchy_new(T_CFDEST);
+ CFCHierarchy_add_source_dir(hierarchy, T_CFCLASH_CLASS);
+ CFCHierarchy_add_include_dir(hierarchy, T_CFBASE);
+ char *error;
+
+ CFCUTIL_TRY {
+ CFCHierarchy_build(hierarchy);
+ }
+ CFCUTIL_CATCH(error);
+ OK(test, error && strstr(error, "Two classes with name"),
+ "source/include class name clash");
+
+ 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_include_dir(hierarchy, T_CFCLASH_FILE);
+
+ CFCHierarchy_build(hierarchy);
+ CFCClass **ordered = CFCHierarchy_ordered_classes(hierarchy);
+ int count = 0;
+ while (ordered[count]) { count++; }
+ INT_EQ(test, count, 4, "source/include filename clash");
+
+ FREEMEM(ordered);
+ CFCBase_decref((CFCBase*)hierarchy);
+ CFCClass_clear_registry();
+ CFCParcel_reap_singletons();
+ }
+
+ if (getenv("LUCY_VALGRIND")) {
+ SKIP(test, 1, "Exceptions leak");
+ }
+ else {
+ CFCHierarchy *hierarchy = CFCHierarchy_new(T_CFDEST);
+ CFCHierarchy_add_source_dir(hierarchy, T_CFCLASH_BAR);
+ CFCHierarchy_add_include_dir(hierarchy, T_CFCLASH_FOO);
+ CFCHierarchy_add_include_dir(hierarchy, T_CFBASE);
+ char *error;
+
+ CFCUTIL_TRY {
+ CFCHierarchy_build(hierarchy);
+ }
+ CFCUTIL_CATCH(error);
+ OK(test, error && strstr(error, "from source dir found"),
+ "source class with included parcel");
+
+ CFCBase_decref((CFCBase*)hierarchy);
+ CFCClass_clear_registry();
+ CFCParcel_reap_singletons();
+ }
+
+ rmdir(T_CFDEST_INCLUDE);
+ rmdir(T_CFDEST_SOURCE);
+ rmdir(T_CFDEST);
+}
+
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/e3ecf10d/compiler/src/CFCTestMethod.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCTestMethod.c b/compiler/src/CFCTestMethod.c
index 3fc5d57..d92bbdc 100644
--- a/compiler/src/CFCTestMethod.c
+++ b/compiler/src/CFCTestMethod.c
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <string.h>
+
#define CFC_USE_TEST_MACROS
#include "CFCBase.h"
#include "CFCClass.h"
@@ -24,6 +26,7 @@
#include "CFCSymbol.h"
#include "CFCTest.h"
#include "CFCType.h"
+#include "CFCUtil.h"
static void
S_run_tests(CFCTest *test);
@@ -42,7 +45,7 @@ S_run_final_tests(CFCTest *test);
const CFCTestBatch CFCTEST_BATCH_METHOD = {
"Clownfish::CFC::Model::Method",
- 74,
+ 84,
S_run_tests
};
@@ -54,6 +57,22 @@ S_run_tests(CFCTest *test) {
S_run_final_tests(test);
}
+static char*
+S_try_new_method(const char *name, CFCType *return_type,
+ CFCParamList *param_list, const char *class_name) {
+ CFCMethod *method = NULL;
+ char *error;
+
+ CFCUTIL_TRY {
+ method = CFCMethod_new(NULL, name, return_type, param_list, NULL,
+ class_name, 0, 0);
+ }
+ CFCUTIL_CATCH(error);
+
+ CFCBase_decref((CFCBase*)method);
+ return error;
+}
+
static void
S_run_basic_tests(CFCTest *test) {
CFCParser *parser = CFCParser_new();
@@ -72,6 +91,39 @@ S_run_basic_tests(CFCTest *test) {
"parcel exposure by default");
{
+ char *error = S_try_new_method("return_an_obj", return_type,
+ param_list, "Neato::Foo");
+ OK(test, error && strstr(error, "name"),
+ "invalid name kills constructor");
+ FREEMEM(error);
+ }
+
+ {
+ static const char *bad_class_names[4] = {
+ "foo", "1Foo", "Foo_Bar", "1FOOBAR"
+ };
+ for (int i = 0; i < 4; i++) {
+ const char *bad_class_name = bad_class_names[i];
+ char *error;
+
+ error = S_try_new_method("Return_An_Obj", return_type,
+ param_list, bad_class_name);
+ OK(test, error && strstr(error, "class_name"),
+ "Reject invalid class name %s", bad_class_name);
+ FREEMEM(error);
+
+ char *bogus_middle
+ = CFCUtil_sprintf("Foo::%s::Bar", bad_class_name);
+ error = S_try_new_method("Return_An_Obj", return_type,
+ param_list, bogus_middle);
+ OK(test, error && strstr(error, "class_name"),
+ "Reject invalid class name %s", bogus_middle);
+ FREEMEM(error);
+ FREEMEM(bogus_middle);
+ }
+ }
+
+ {
CFCMethod *dupe
= CFCMethod_new(NULL, "Return_An_Obj", return_type, param_list,
NULL, "Neato::Foo", 0, 0);
@@ -260,6 +312,19 @@ S_run_final_tests(CFCTest *test) {
OK(test, !CFCMethod_final(not_final), "not final by default");
OK(test, CFCMethod_final(final), "finalize");
+ {
+ char *error;
+
+ CFCUTIL_TRY {
+ CFCMethod_override(not_final, final);
+ }
+ CFCUTIL_CATCH(error);
+ OK(test, error && strstr(error, "final"),
+ "Can't override final method");
+
+ FREEMEM(error);
+ }
+
CFCBase_decref((CFCBase*)parser);
CFCBase_decref((CFCBase*)neato_parcel);
CFCBase_decref((CFCBase*)obj_class);
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/e3ecf10d/compiler/src/CFCTestParcel.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCTestParcel.c b/compiler/src/CFCTestParcel.c
index eec782a..263c60e 100644
--- a/compiler/src/CFCTestParcel.c
+++ b/compiler/src/CFCTestParcel.c
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <string.h>
+
#include "charmony.h"
#define CFC_USE_TEST_MACROS
@@ -37,18 +39,22 @@ static void
S_run_prereq_tests(CFCTest *test);
static void
-S_run_parcel_tests(CFCTest *test);
+S_run_basic_tests(CFCTest *test);
+
+static void
+S_run_extended_tests(CFCTest *test);
const CFCTestBatch CFCTEST_BATCH_PARCEL = {
"Clownfish::CFC::Model::Parcel",
- 29,
+ 36,
S_run_tests
};
static void
S_run_tests(CFCTest *test) {
S_run_prereq_tests(test);
- S_run_parcel_tests(test);
+ S_run_basic_tests(test);
+ S_run_extended_tests(test);
}
static void
@@ -77,22 +83,77 @@ S_run_prereq_tests(CFCTest *test) {
}
static void
-S_run_parcel_tests(CFCTest *test) {
+S_run_basic_tests(CFCTest *test) {
+ CFCParcel *foo = CFCParcel_new("Foo", NULL, NULL, NULL);
+ OK(test, foo != NULL, "new");
+ OK(test, !CFCParcel_included(foo), "not included");
+ CFCParcel_register(foo);
+
{
- CFCParcel *parcel = CFCParcel_new("Foo", NULL, NULL, NULL);
- OK(test, parcel != NULL, "new");
- OK(test, !CFCParcel_included(parcel), "not included");
- CFCBase_decref((CFCBase*)parcel);
+ CFCParcel *same_name = CFCParcel_new("Foo", NULL, NULL, NULL);
+ char *error;
+
+ CFCUTIL_TRY {
+ CFCParcel_register(same_name);
+ }
+ CFCUTIL_CATCH(error);
+ OK(test, error && strstr(error, "already registered"),
+ "can't register two parcels with the same name");
+
+ FREEMEM(error);
+ CFCBase_decref((CFCBase*)same_name);
}
{
- 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);
+ CFCParcel *same_nick
+ = CFCParcel_new("OtherFoo", "Foo", NULL, NULL);
+ char *error;
+
+ CFCUTIL_TRY {
+ CFCParcel_register(same_nick);
+ }
+ CFCUTIL_CATCH(error);
+ OK(test, error && strstr(error, "already registered"),
+ "can't register two parcels with the same nickname");
+
+ FREEMEM(error);
+ CFCBase_decref((CFCBase*)same_nick);
}
+ CFCFileSpec *file_spec = CFCFileSpec_new(".", "Parcel", true);
+ CFCParcel *included_foo
+ = CFCParcel_new("IncludedFoo", NULL, NULL, file_spec);
+ OK(test, CFCParcel_included(included_foo), "included");
+ CFCParcel_register(included_foo);
+
+ {
+ CFCParcel **all_parcels = CFCParcel_all_parcels();
+ OK(test, all_parcels[0] && all_parcels[1] && !all_parcels[2],
+ "all_parcels returns two parcels");
+ STR_EQ(test, CFCParcel_get_name(all_parcels[0]), "Foo",
+ "all_parcels returns parcel Foo");
+ STR_EQ(test, CFCParcel_get_name(all_parcels[1]), "IncludedFoo",
+ "all_parcels returns parcel IncludedFoo");
+ }
+
+ {
+ CFCParcel_add_inherited_parcel(foo, included_foo);
+ CFCParcel **inh_parcels = CFCParcel_inherited_parcels(foo);
+ OK(test, inh_parcels[0] && !inh_parcels[1],
+ "inherited_parcels returns one parcel");
+ STR_EQ(test, CFCParcel_get_name(inh_parcels[0]), "IncludedFoo",
+ "inh_parcels returns parcel IncludedFoo");
+ FREEMEM(inh_parcels);
+ }
+
+ CFCBase_decref((CFCBase*)included_foo);
+ CFCBase_decref((CFCBase*)file_spec);
+ CFCBase_decref((CFCBase*)foo);
+ CFCParcel_reap_singletons();
+}
+
+static void
+S_run_extended_tests(CFCTest *test) {
{
const char *json =
" {\n"
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/e3ecf10d/compiler/src/CFCTestSymbol.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCTestSymbol.c b/compiler/src/CFCTestSymbol.c
index 690e55c..e177d50 100644
--- a/compiler/src/CFCTestSymbol.c
+++ b/compiler/src/CFCTestSymbol.c
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <string.h>
+
#define CFC_USE_TEST_MACROS
#include "CFCBase.h"
#include "CFCClass.h"
@@ -32,10 +34,24 @@ S_run_tests(CFCTest *test);
const CFCTestBatch CFCTEST_BATCH_SYMBOL = {
"Clownfish::CFC::Model::Symbol",
- 20,
+ 24,
S_run_tests
};
+static char*
+S_try_new_symbol(const char *name) {
+ CFCSymbol *symbol = NULL;
+ char *error;
+
+ CFCUTIL_TRY {
+ symbol = CFCSymbol_new("parcel", name);
+ }
+ CFCUTIL_CATCH(error);
+
+ CFCBase_decref((CFCBase*)symbol);
+ return error;
+}
+
static void
S_run_tests(CFCTest *test) {
CFCParcel *parcel = CFCParcel_new("Parcel", NULL, NULL, NULL);
@@ -76,6 +92,17 @@ S_run_tests(CFCTest *test) {
}
{
+ static const char *names[4] = {
+ "1foo", "*", "0", "\xE2\x98\xBA"
+ };
+ for (int i = 0; i < 4; i++) {
+ char *error = S_try_new_symbol(names[i]);
+ OK(test, error && strstr(error, "name"), "reject bad name");
+ FREEMEM(error);
+ }
+ }
+
+ {
CFCSymbol *ooga = CFCSymbol_new("parcel", "ooga");
CFCSymbol *booga = CFCSymbol_new("parcel", "booga");
int equal = CFCSymbol_equals(ooga, booga);
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/e3ecf10d/compiler/src/CFCTestType.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCTestType.c b/compiler/src/CFCTestType.c
index 5e0d6df..ea61fa0 100644
--- a/compiler/src/CFCTestType.c
+++ b/compiler/src/CFCTestType.c
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <string.h>
+
#define CFC_USE_TEST_MACROS
#include "CFCBase.h"
#include "CFCClass.h"
@@ -60,7 +62,7 @@ S_run_composite_tests(CFCTest *test);
const CFCTestBatch CFCTEST_BATCH_TYPE = {
"Clownfish::CFC::Model::Type",
- 360,
+ 369,
S_run_tests
};
@@ -260,6 +262,20 @@ S_run_void_tests(CFCTest *test) {
CFCBase_decref((CFCBase*)parser);
}
+static char*
+S_try_new_object(CFCParcel *parcel, const char *specifier, int indirection) {
+ CFCType *type = NULL;
+ char *error;
+
+ CFCUTIL_TRY {
+ type = CFCType_new_object(0, parcel, specifier, indirection);
+ }
+ CFCUTIL_CATCH(error);
+
+ CFCBase_decref((CFCBase*)type);
+ return error;
+}
+
static void
S_run_object_tests(CFCTest *test) {
static const char *modifiers[4] = {
@@ -336,6 +352,33 @@ S_run_object_tests(CFCTest *test) {
CFCType_resolve(foo);
{
+ static const char *bad_specifiers[5] = {
+ "foo", "Foo_Bar", "FOOBAR", "1Foo", "1FOO"
+ };
+ for (int i = 0; i < 5; i++) {
+ char *error = S_try_new_object(neato_parcel, bad_specifiers[i], 1);
+ OK(test, error && strstr(error, "specifier"),
+ "constructor rejects bad specifier");
+ FREEMEM(error);
+ }
+ }
+
+ {
+ char *error = S_try_new_object(neato_parcel, NULL, 1);
+ OK(test, error && strstr(error, "specifier"), "specifier required");
+ FREEMEM(error);
+ }
+
+ {
+ for (int indirection = 0; indirection <= 2; indirection += 2) {
+ char *error = S_try_new_object(neato_parcel, "Foo", indirection);
+ OK(test, error && strstr(error, "indirection"),
+ "invalid indirection of %d", indirection);
+ FREEMEM(error);
+ }
+ }
+
+ {
CFCType *another_foo = CFCType_new_object(0, neato_parcel, "Foo", 1);
CFCType_resolve(another_foo);
OK(test, CFCType_equals(foo, another_foo), "equals");
@@ -494,6 +537,20 @@ S_run_composite_tests(CFCTest *test) {
}
{
+ CFCType *type = NULL;
+ char *error;
+
+ CFCUTIL_TRY {
+ type = CFCType_new_composite(0, NULL, 0, NULL);
+ }
+ CFCUTIL_CATCH(error);
+ OK(test, error && strstr(error, "child"), "child required");
+
+ FREEMEM(error);
+ 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);
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/e3ecf10d/compiler/src/CFCTestVariable.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCTestVariable.c b/compiler/src/CFCTestVariable.c
index d256c01..617bf15 100644
--- a/compiler/src/CFCTestVariable.c
+++ b/compiler/src/CFCTestVariable.c
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <string.h>
+
#define CFC_USE_TEST_MACROS
#include "CFCBase.h"
#include "CFCClass.h"
@@ -35,10 +37,24 @@ S_run_tests(CFCTest *test);
const CFCTestBatch CFCTEST_BATCH_VARIABLE = {
"Clownfish::CFC::Model::Variable",
- 29,
+ 33,
S_run_tests
};
+static char*
+S_try_new_variable(const char *name, CFCType *type) {
+ CFCVariable *var = NULL;
+ char *error;
+
+ CFCUTIL_TRY {
+ var = CFCVariable_new(NULL, name, type, 0);
+ }
+ CFCUTIL_CATCH(error);
+
+ CFCBase_decref((CFCBase*)var);
+ return error;
+}
+
static void
S_run_tests(CFCTest *test) {
CFCParser *parser = CFCParser_new();
@@ -47,6 +63,20 @@ S_run_tests(CFCTest *test) {
CFCClass *foo_class = CFCTest_parse_class(test, parser, "class Foo {}");
{
+ char *error = S_try_new_variable("foo", NULL);
+ OK(test, error && strstr(error, "type"), "type is required");
+ FREEMEM(error);
+ }
+
+ {
+ CFCType *type = CFCTest_parse_type(test, parser, "int32_t");
+ char *error = S_try_new_variable(NULL, type);
+ OK(test, error && strstr(error, "name"), "name is required");
+ FREEMEM(error);
+ CFCBase_decref((CFCBase*)type);
+ }
+
+ {
CFCType *type = CFCTest_parse_type(test, parser, "float*");
CFCVariable *var = CFCVariable_new(NULL, "foo", type, 0);
CFCVariable_resolve_type(var);