From 65387c4fe5f0088fe89c90a9d0a1e8829fabb0f3 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Fri, 4 Mar 2016 17:54:20 +0100 Subject: [PATCH 1/8] Implement CFCUtil_vsprintf Drop support for Microsoft compilers without _vscprintf. This function is supported at least since Visual Studio .NET 2003 (MSVC 7.1). I think it was only MSVC 6 that didn't support it. Also use va_copy when iterating va_lists twice. --- compiler/src/CFCUtil.c | 46 +++++++++++++++++------------------------- compiler/src/CFCUtil.h | 4 ++++ 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/compiler/src/CFCUtil.c b/compiler/src/CFCUtil.c index 6fe62fa0..da546aff 100644 --- a/compiler/src/CFCUtil.c +++ b/compiler/src/CFCUtil.c @@ -59,51 +59,41 @@ CFCUtil_strndup(const char *string, size_t len) { return copy; } -#if defined(CHY_HAS_C99_SNPRINTF) || defined(CHY_HAS__SCPRINTF) - char* CFCUtil_sprintf(const char *fmt, ...) { va_list args; va_start(args, fmt); + char *string = CFCUtil_vsprintf(fmt, args); + va_end(args); + + return string; +} + +#if !defined(CHY_HAS_C99_SNPRINTF) && !defined(CHY_HAS__SCPRINTF) + #error "snprintf or replacement not available." +#endif + +char* +CFCUtil_vsprintf(const char *fmt, va_list args) { + va_list args_copy; + + va_copy(args_copy, args); #if defined(CHY_HAS_C99_SNPRINTF) - int size = vsnprintf(NULL, 0, fmt, args); + int size = vsnprintf(NULL, 0, fmt, args_copy); if (size < 0) { CFCUtil_die("snprintf failed"); } #else - int size = _vscprintf(fmt, args); + int size = _vscprintf(fmt, args_copy); if (size < 0) { CFCUtil_die("_scprintf failed"); } #endif - va_end(args); + va_end(args_copy); char *string = (char*)MALLOCATE((size_t)size + 1); - va_start(args, fmt); vsprintf(string, fmt, args); - va_end(args); return string; } -#elif defined(CHY_HAS__SNPRINTF) - -char* -CFCUtil_sprintf(const char *fmt, ...) { - for (size_t size = 32; size * 2 > size; size *= 2) { - char *string = (char*)MALLOCATE(size); - va_list args; - va_start(args, fmt); - int result = _vsnprintf(string, size, fmt, args); - va_end(args); - if (result >= 0 && (size_t)result < size) { return string; } - FREEMEM(string); - } - CFCUtil_die("_snprintf failed"); - return NULL; -} - -#else - #error "snprintf or replacement not available." -#endif - char* CFCUtil_cat(char *string, ...) { va_list args; diff --git a/compiler/src/CFCUtil.h b/compiler/src/CFCUtil.h index 15f45a9e..3e06b030 100644 --- a/compiler/src/CFCUtil.h +++ b/compiler/src/CFCUtil.h @@ -27,6 +27,7 @@ extern "C" { #endif +#include #include /** Create an inner Perl object with a refcount of 1. For use in actual @@ -58,6 +59,9 @@ CFCUtil_strndup(const char *string, size_t len); char* CFCUtil_sprintf(const char *fmt, ...); +char* +CFCUtil_vsprintf(const char *fmt, va_list args); + /** Concatenate a NULL-terminated list of strings onto the first, reallocating * with each argument. */ From 5d0a3efefc68ae1ea81564a0184d70273db75623 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Fri, 4 Mar 2016 17:58:28 +0100 Subject: [PATCH 2/8] Support catching CFC exceptions from C Needed to fix CLOWNFISH-14. --- compiler/src/CFCUtil.c | 71 ++++++++++++++++++++++++++++++++++++++---- compiler/src/CFCUtil.h | 23 ++++++++++++++ 2 files changed, 88 insertions(+), 6 deletions(-) diff --git a/compiler/src/CFCUtil.c b/compiler/src/CFCUtil.c index da546aff..a2a0993b 100644 --- a/compiler/src/CFCUtil.c +++ b/compiler/src/CFCUtil.c @@ -23,6 +23,7 @@ #include #include #include +#include // For mkdir. #ifdef CHY_HAS_DIRECT_H @@ -36,6 +37,9 @@ #include "CFCUtil.h" +static char *thrown_error; +static jmp_buf *current_env; + void CFCUtil_null_check(const void *arg, const char *name, const char *file, int line) { @@ -594,6 +598,21 @@ CFCUtil_closedir(void *dirhandle, const char *dir) { /***************************************************************************/ +jmp_buf* +CFCUtil_try_start(jmp_buf *env) { + jmp_buf *prev_env = current_env; + current_env = env; + return prev_env; +} + +char* +CFCUtil_try_end(jmp_buf *prev_env) { + current_env = prev_env; + char *error = thrown_error; + thrown_error = NULL; + return error; +} + #ifdef CFCPERL #include "EXTERN.h" @@ -605,8 +624,27 @@ void CFCUtil_die(const char* format, ...) { va_list args; va_start(args, format); - vcroak(format, &args); - va_end(args); + + if (current_env) { + thrown_error = CFCUtil_vsprintf(format, args); + va_end(args); + longjmp(*current_env, 1); + } + else { + vcroak(format, &args); + va_end(args); + } +} + +void +CFCUtil_rethrow(char *error) { + if (current_env) { + thrown_error = error; + longjmp(*current_env, 1); + } + else { + croak("%s", error); + } } void @@ -623,10 +661,31 @@ void CFCUtil_die(const char* format, ...) { va_list args; va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); - fprintf(stderr, "\n"); - exit(1); + + if (current_env) { + thrown_error = CFCUtil_vsprintf(format, args); + va_end(args); + longjmp(*current_env, 1); + } + else { + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + abort(); + } +} + +void +CFCUtil_rethrow(char *error) { + if (current_env) { + thrown_error = error; + longjmp(*current_env, 1); + } + else { + fprintf(stderr, "%s\n", error); + FREEMEM(error); + abort(); + } } void diff --git a/compiler/src/CFCUtil.h b/compiler/src/CFCUtil.h index 3e06b030..73286efe 100644 --- a/compiler/src/CFCUtil.h +++ b/compiler/src/CFCUtil.h @@ -29,6 +29,18 @@ extern "C" { #include #include +#include + +#define CFCUTIL_TRY \ + do { \ + jmp_buf env; \ + jmp_buf *prev_env = CFCUtil_try_start(&env); \ + if (!setjmp(env)) + +#define CFCUTIL_CATCH(error) \ + error = CFCUtil_try_end(prev_env); \ + } while (0) + /** Create an inner Perl object with a refcount of 1. For use in actual * Perl-space, it is necessary to wrap this inner object in an RV. @@ -223,11 +235,22 @@ CFCUtil_free_string_array(char **strings); void CFCUtil_die(const char *format, ...); +/* Rethrow an error. + */ +void +CFCUtil_rethrow(char *error); + /* Print an error message to stderr. */ void CFCUtil_warn(const char *format, ...); +jmp_buf* +CFCUtil_try_start(jmp_buf *env); + +char* +CFCUtil_try_end(jmp_buf *prev_env); + #ifdef __cplusplus } #endif From ce0dfbb5a77b55ca59f97eb9cdd6a5de7f59ad86 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Sat, 5 Mar 2016 17:50:13 +0100 Subject: [PATCH 3/8] Fix a couple of leaking exceptions --- compiler/perl/t/401-class.t | 45 +++++++++++++++++-------------------- compiler/src/CFCCBlock.c | 5 ++++- compiler/src/CFCClass.c | 14 ++++++++++-- compiler/src/CFCVariable.c | 5 ++++- 4 files changed, 40 insertions(+), 29 deletions(-) diff --git a/compiler/perl/t/401-class.t b/compiler/perl/t/401-class.t index f4564715..5e0fcba5 100644 --- a/compiler/perl/t/401-class.t +++ b/compiler/perl/t/401-class.t @@ -51,32 +51,27 @@ my $should_be_foo = Clownfish::CFC::Model::Class->fetch_singleton( ); is( $$foo, $$should_be_foo, "fetch_singleton" ); -SKIP: { - skip( 'Exceptions leak', 3 ) - if $ENV{LUCY_VALGRIND}; +eval { Clownfish::CFC::Model::Class->create(%foo_create_args) }; +like( $@, qr/two classes with name/i, + "Can't call create for the same class more than once" ); - eval { Clownfish::CFC::Model::Class->create(%foo_create_args) }; - like( $@, qr/two classes with name/i, - "Can't call create for the same class more than once" ); - - eval { - Clownfish::CFC::Model::Class->create( - parcel => 'Neato', - class_name => 'Other::Foo', - ); - }; - like( $@, qr/class name conflict/i, - "Can't create classes wth the same final component" ); - eval { - Clownfish::CFC::Model::Class->create( - parcel => 'Neato', - class_name => 'Bar', - nickname => 'Foo', - ); - }; - like( $@, qr/class nickname conflict/i, - "Can't create classes wth the same nickname" ); -} +eval { + Clownfish::CFC::Model::Class->create( + parcel => 'Neato', + class_name => 'Other::Foo', + ); +}; +like( $@, qr/class name conflict/i, + "Can't create classes wth the same final component" ); +eval { + Clownfish::CFC::Model::Class->create( + parcel => 'Neato', + class_name => 'Bar', + nickname => 'Foo', + ); +}; +like( $@, qr/class nickname conflict/i, + "Can't create classes wth the same nickname" ); my $foo_jr = Clownfish::CFC::Model::Class->create( parcel => 'Neato', diff --git a/compiler/src/CFCCBlock.c b/compiler/src/CFCCBlock.c index 0231877b..01d0b42d 100644 --- a/compiler/src/CFCCBlock.c +++ b/compiler/src/CFCCBlock.c @@ -38,7 +38,10 @@ CFCCBlock_new(const char *contents) { CFCCBlock* CFCCBlock_init(CFCCBlock *self, const char *contents) { - CFCUTIL_NULL_CHECK(contents); + if (!contents) { + CFCBase_decref((CFCBase*)self); + CFCUtil_die("contents cannot be NULL"); + } self->contents = CFCUtil_strdup(contents); return self; } diff --git a/compiler/src/CFCClass.c b/compiler/src/CFCClass.c index 7ed3167c..5e1f795b 100644 --- a/compiler/src/CFCClass.c +++ b/compiler/src/CFCClass.c @@ -310,8 +310,18 @@ CFCClass_do_create(CFCClass *self, struct CFCParcel *parcel, || !parcel_source_dir || strcmp(class_source_dir, parcel_source_dir) == 0 ) { - // Store in registry. - S_register(self); + char *error; + + CFCUTIL_TRY { + // Store in registry. + S_register(self); + } + CFCUTIL_CATCH(error); + + if (error) { + CFCBase_decref((CFCBase*)self); + CFCUtil_rethrow(error); + } CFCParcel_add_struct_sym(parcel, self->struct_sym); } diff --git a/compiler/src/CFCVariable.c b/compiler/src/CFCVariable.c index c2802fc7..6636ba69 100644 --- a/compiler/src/CFCVariable.c +++ b/compiler/src/CFCVariable.c @@ -59,7 +59,10 @@ CFCVariable* CFCVariable_init(CFCVariable *self, const char *exposure, const char *name, struct CFCType *type, int inert) { // Validate params. - CFCUTIL_NULL_CHECK(type); + if (!type) { + CFCBase_decref((CFCBase*)self); + CFCUtil_die("type cannot be NULL"); + } // Default exposure to "local". const char *real_exposure = exposure ? exposure : "local"; From 6fdf098cef2a360218df6fc666e52d9af5b87152 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Sat, 5 Mar 2016 18:09:27 +0100 Subject: [PATCH 4/8] Finish support for skipping CFC tests --- compiler/src/CFCTest.c | 37 ++++++++++++++++++++++++++++++++++++- compiler/src/CFCTest.h | 3 ++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/compiler/src/CFCTest.c b/compiler/src/CFCTest.c index c62f3b5d..0f61745f 100644 --- a/compiler/src/CFCTest.c +++ b/compiler/src/CFCTest.c @@ -37,6 +37,7 @@ typedef struct CFCTestFormatter { va_list args); void (*test_comment)(const char *fmt, ...); void (*batch_comment)(const char *fmt, ...); + void (*skip)(int test_num, int num_skipped, const char *fmt, va_list args); void (*summary)(const CFCTest *test); } CFCTestFormatter; @@ -70,6 +71,10 @@ S_format_cfish_test_comment(const char *fmt, ...); static void S_format_cfish_batch_comment(const char *fmt, ...); +static void +S_format_cfish_skip(int test_num, int num_skipped, const char *fmt, + va_list args); + static void S_format_cfish_summary(const CFCTest *test); @@ -86,6 +91,10 @@ S_format_tap_test_comment(const char *fmt, ...); static void S_format_tap_batch_comment(const char *fmt, ...); +static void +S_format_tap_skip(int test_num, int num_skipped, const char *fmt, + va_list args); + static void S_format_tap_summary(const CFCTest *test); @@ -100,6 +109,7 @@ static const CFCTestFormatter S_formatter_cfish = { S_format_cfish_vtest_result, S_format_cfish_test_comment, S_format_cfish_batch_comment, + S_format_cfish_skip, S_format_cfish_summary }; @@ -108,6 +118,7 @@ static const CFCTestFormatter S_formatter_tap = { S_format_tap_vtest_result, S_format_tap_test_comment, S_format_tap_batch_comment, + S_format_tap_skip, S_format_tap_summary }; @@ -261,7 +272,12 @@ CFCTest_test_int_equals(CFCTest *self, uint64_t result, uint64_t expected, } void -CFCTest_skip(CFCTest *self, int num) { +CFCTest_skip(CFCTest *self, int num, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + self->formatter->skip(self->num_tests + 1, num, fmt, args); + va_end(args); + self->num_tests += num; self->num_tests_in_batch += num; } @@ -326,6 +342,15 @@ S_format_cfish_batch_comment(const char *fmt, ...) { va_end(args); } +static void +S_format_cfish_skip(int test_num, int num_skipped, const char *fmt, + va_list args) { + CHY_UNUSED_VAR(test_num); + CHY_UNUSED_VAR(num_skipped); + CHY_UNUSED_VAR(fmt); + CHY_UNUSED_VAR(args); +} + static void S_format_cfish_summary(const CFCTest *test) { if (test->num_batches == 0) { @@ -378,6 +403,16 @@ S_format_tap_batch_comment(const char *fmt, ...) { va_end(args); } +static void +S_format_tap_skip(int test_num, int num_skipped, const char *fmt, + va_list args) { + for (int i = 0; i < num_skipped; ++i) { + printf("ok %d # SKIP ", test_num + i); + vprintf(fmt, args); + printf("\n"); + } +} + static void S_format_tap_summary(const CFCTest *test) { (void)test; // unused diff --git a/compiler/src/CFCTest.h b/compiler/src/CFCTest.h index 93d11eba..41cf73dd 100644 --- a/compiler/src/CFCTest.h +++ b/compiler/src/CFCTest.h @@ -29,6 +29,7 @@ #define OK CFCTest_test_true #define STR_EQ CFCTest_test_string_equals #define INT_EQ CFCTest_test_int_equals + #define SKIP CFCTest_skip #endif typedef struct CFCTest CFCTest; @@ -112,7 +113,7 @@ CFCTest_test_int_equals(CFCTest *self, uint64_t result, uint64_t expected, * @param num Number of tests to skip. */ void -CFCTest_skip(CFCTest *self, int num); +CFCTest_skip(CFCTest *self, int num, const char *fmt, ...); /* Finish testing. * From e3ecf10da6a3314c31e60133041ed3578357387b Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Fri, 4 Mar 2016 18:00:49 +0100 Subject: [PATCH 5/8] 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. --- compiler/c/t/cfclash/bar/Bar.cfh | 25 +++++ compiler/c/t/cfclash/bar/Bar.cfp | 4 + compiler/c/t/cfclash/bar/Baz.cfh | 25 +++++ .../c/t/cfclash/class/Animal/DogClash.cfh | 28 +++++ .../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(-) create mode 100644 compiler/c/t/cfclash/bar/Bar.cfh create mode 100644 compiler/c/t/cfclash/bar/Bar.cfp create mode 100644 compiler/c/t/cfclash/bar/Baz.cfh create mode 100644 compiler/c/t/cfclash/class/Animal/DogClash.cfh create mode 100644 compiler/c/t/cfclash/class/AnimalExtension.cfp create mode 100644 compiler/c/t/cfclash/file/Animal/Dog.cfh create mode 100644 compiler/c/t/cfclash/foo/Foo.cfh create mode 100644 compiler/c/t/cfclash/foo/Foo.cfp diff --git a/compiler/c/t/cfclash/bar/Bar.cfh b/compiler/c/t/cfclash/bar/Bar.cfh new file mode 100644 index 00000000..89e798eb --- /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); +} + diff --git a/compiler/c/t/cfclash/bar/Bar.cfp b/compiler/c/t/cfclash/bar/Bar.cfp new file mode 100644 index 00000000..e5868f6f --- /dev/null +++ b/compiler/c/t/cfclash/bar/Bar.cfp @@ -0,0 +1,4 @@ +{ + "name": "Bar", + "version": "v1.0.0" +} diff --git a/compiler/c/t/cfclash/bar/Baz.cfh b/compiler/c/t/cfclash/bar/Baz.cfh new file mode 100644 index 00000000..00e4033b --- /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); +} + 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 00000000..3eba020d --- /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); +} diff --git a/compiler/c/t/cfclash/class/AnimalExtension.cfp b/compiler/c/t/cfclash/class/AnimalExtension.cfp new file mode 100644 index 00000000..76f31d34 --- /dev/null +++ b/compiler/c/t/cfclash/class/AnimalExtension.cfp @@ -0,0 +1,5 @@ +{ + "name": "AnimalExtension", + "nickname": "AniExt", + "version": "v0.1.0" +} 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 00000000..13571093 --- /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); +} diff --git a/compiler/c/t/cfclash/foo/Foo.cfh b/compiler/c/t/cfclash/foo/Foo.cfh new file mode 100644 index 00000000..b770d8a8 --- /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); +} + diff --git a/compiler/c/t/cfclash/foo/Foo.cfp b/compiler/c/t/cfclash/foo/Foo.cfp new file mode 100644 index 00000000..29951692 --- /dev/null +++ b/compiler/c/t/cfclash/foo/Foo.cfp @@ -0,0 +1,4 @@ +{ + "name": "Foo", + "version": "v1.0.0" +} diff --git a/compiler/src/CFCTestCBlock.c b/compiler/src/CFCTestCBlock.c index 6061d44f..650a3eb8 100644 --- a/compiler/src/CFCTestCBlock.c +++ b/compiler/src/CFCTestCBlock.c @@ -14,18 +14,21 @@ * limitations under the License. */ +#include + #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 }; @@ -40,6 +43,20 @@ S_run_tests(CFCTest *test) { CFCBase_decref((CFCBase*)block); } + { + 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" diff --git a/compiler/src/CFCTestClass.c b/compiler/src/CFCTestClass.c index a91e3b9e..8acb300d 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(); diff --git a/compiler/src/CFCTestFunction.c b/compiler/src/CFCTestFunction.c index 22dd487f..459fea10 100644 --- a/compiler/src/CFCTestFunction.c +++ b/compiler/src/CFCTestFunction.c @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #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); diff --git a/compiler/src/CFCTestHierarchy.c b/compiler/src/CFCTestHierarchy.c index fa005aaa..670f8727 100644 --- a/compiler/src/CFCTestHierarchy.c +++ b/compiler/src/CFCTestHierarchy.c @@ -17,6 +17,7 @@ #include "charmony.h" #include +#include #include /* 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); +} + diff --git a/compiler/src/CFCTestMethod.c b/compiler/src/CFCTestMethod.c index 3fc5d578..d92bbdca 100644 --- a/compiler/src/CFCTestMethod.c +++ b/compiler/src/CFCTestMethod.c @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #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(); @@ -71,6 +90,39 @@ S_run_basic_tests(CFCTest *test) { OK(test, CFCSymbol_parcel((CFCSymbol*)method), "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, @@ -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); diff --git a/compiler/src/CFCTestParcel.c b/compiler/src/CFCTestParcel.c index eec782ac..263c60e4 100644 --- a/compiler/src/CFCTestParcel.c +++ b/compiler/src/CFCTestParcel.c @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #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" diff --git a/compiler/src/CFCTestSymbol.c b/compiler/src/CFCTestSymbol.c index 690e55c7..e177d50a 100644 --- a/compiler/src/CFCTestSymbol.c +++ b/compiler/src/CFCTestSymbol.c @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #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); @@ -75,6 +91,17 @@ S_run_tests(CFCTest *test) { CFCBase_decref((CFCBase*)parcel_exposure); } + { + 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"); diff --git a/compiler/src/CFCTestType.c b/compiler/src/CFCTestType.c index 5e0d6dfe..ea61fa08 100644 --- a/compiler/src/CFCTestType.c +++ b/compiler/src/CFCTestType.c @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #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] = { @@ -335,6 +351,33 @@ S_run_object_tests(CFCTest *test) { CFCType *foo = CFCType_new_object(0, neato_parcel, "Foo", 1); 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); @@ -493,6 +536,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 diff --git a/compiler/src/CFCTestVariable.c b/compiler/src/CFCTestVariable.c index d256c01f..617bf150 100644 --- a/compiler/src/CFCTestVariable.c +++ b/compiler/src/CFCTestVariable.c @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #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(); @@ -46,6 +62,20 @@ S_run_tests(CFCTest *test) { = CFCTest_parse_parcel(test, parser, "parcel Neato;"); 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); From df605b501d441251871450f9f46ab11b601781f4 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Sat, 5 Mar 2016 18:17:00 +0100 Subject: [PATCH 6/8] Remove Perl test t/502-clash.t This test is part of C test suite now. --- compiler/perl/t/502-clash.t | 108 ------------------ compiler/perl/t/cfclash/bar/Bar.cfh | 25 ---- compiler/perl/t/cfclash/bar/Bar.cfp | 4 - compiler/perl/t/cfclash/bar/Baz.cfh | 25 ---- .../perl/t/cfclash/class/Animal/DogClash.cfh | 28 ----- .../perl/t/cfclash/class/AnimalExtension.cfp | 5 - compiler/perl/t/cfclash/file/Animal/Dog.cfh | 28 ----- compiler/perl/t/cfclash/foo/Foo.cfh | 25 ---- compiler/perl/t/cfclash/foo/Foo.cfp | 4 - 9 files changed, 252 deletions(-) delete mode 100644 compiler/perl/t/502-clash.t delete mode 100644 compiler/perl/t/cfclash/bar/Bar.cfh delete mode 100644 compiler/perl/t/cfclash/bar/Bar.cfp delete mode 100644 compiler/perl/t/cfclash/bar/Baz.cfh delete mode 100644 compiler/perl/t/cfclash/class/Animal/DogClash.cfh delete mode 100644 compiler/perl/t/cfclash/class/AnimalExtension.cfp delete mode 100644 compiler/perl/t/cfclash/file/Animal/Dog.cfh delete mode 100644 compiler/perl/t/cfclash/foo/Foo.cfh delete mode 100644 compiler/perl/t/cfclash/foo/Foo.cfp diff --git a/compiler/perl/t/502-clash.t b/compiler/perl/t/502-clash.t deleted file mode 100644 index 4cf870bd..00000000 --- a/compiler/perl/t/502-clash.t +++ /dev/null @@ -1,108 +0,0 @@ -# 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 Test::More tests => 4; - -use Clownfish::CFC::Model::Hierarchy; -use File::Spec::Functions qw( catdir catfile splitpath ); -use File::Path qw( rmtree ); - -my $base_dir = catdir(qw( t cfbase )); -my $ext_dir = catdir(qw( t cfext )); -my $dest_dir = catdir(qw( t cfdest )); -my $class_clash_dir = catdir(qw( t cfclash class )); -my $file_clash_dir = catdir(qw( t cfclash file )); - -SKIP: { - skip( 'Exceptions leak', 1 ) - if $ENV{LUCY_VALGRIND}; - - my $hierarchy = Clownfish::CFC::Model::Hierarchy->new(dest => $dest_dir); - - $hierarchy->add_source_dir($base_dir); - $hierarchy->add_source_dir($file_clash_dir); - - eval { $hierarchy->build; }; - - my $filename = catfile(qw( Animal Dog.cfh )); - like( $@, qr|\Q$filename\E .* \Q$base_dir\E .* \Q$file_clash_dir\E|, - "source/source filename clash" ); - - Clownfish::CFC::Model::Class->_clear_registry(); - Clownfish::CFC::Model::Parcel->reap_singletons(); -} - -SKIP: { - skip( 'Exceptions leak', 1 ) - if $ENV{LUCY_VALGRIND}; - - my $hierarchy = Clownfish::CFC::Model::Hierarchy->new(dest => $dest_dir); - - $hierarchy->add_source_dir($class_clash_dir); - $hierarchy->add_include_dir($base_dir); - - eval { $hierarchy->build; }; - - like( $@, qr/Two classes with name/, "source/include class name clash" ); - - Clownfish::CFC::Model::Class->_clear_registry(); - Clownfish::CFC::Model::Parcel->reap_singletons(); -} - -{ - my $hierarchy = Clownfish::CFC::Model::Hierarchy->new(dest => $dest_dir); - - $hierarchy->add_source_dir($base_dir); - $hierarchy->add_include_dir($file_clash_dir); - - $hierarchy->build; - - my $classes = $hierarchy->ordered_classes; - is( scalar @$classes, 4, "source/include filename clash" ); - - Clownfish::CFC::Model::Class->_clear_registry(); - Clownfish::CFC::Model::Parcel->reap_singletons(); -} - -# Parcel/class include mismatch - -my $foo_dir = catdir(qw( t cfclash foo )); -my $bar_dir = catdir(qw( t cfclash bar )); - -SKIP: { - skip( 'Exceptions leak', 1 ) - if $ENV{LUCY_VALGRIND}; - - my $hierarchy = Clownfish::CFC::Model::Hierarchy->new(dest => $dest_dir); - - $hierarchy->add_source_dir($bar_dir); - $hierarchy->add_include_dir($foo_dir); - $hierarchy->add_include_dir($base_dir); - - eval { $hierarchy->build; }; - - like( $@, qr/Class .* from source dir .* parcel .* from include dir/, - "source class with included parcel" ); - - Clownfish::CFC::Model::Class->_clear_registry(); - Clownfish::CFC::Model::Parcel->reap_singletons(); -} - -# Clean up. -rmtree($dest_dir); - diff --git a/compiler/perl/t/cfclash/bar/Bar.cfh b/compiler/perl/t/cfclash/bar/Bar.cfh deleted file mode 100644 index 89e798eb..00000000 --- a/compiler/perl/t/cfclash/bar/Bar.cfh +++ /dev/null @@ -1,25 +0,0 @@ -/* 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); -} - diff --git a/compiler/perl/t/cfclash/bar/Bar.cfp b/compiler/perl/t/cfclash/bar/Bar.cfp deleted file mode 100644 index e5868f6f..00000000 --- a/compiler/perl/t/cfclash/bar/Bar.cfp +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "Bar", - "version": "v1.0.0" -} diff --git a/compiler/perl/t/cfclash/bar/Baz.cfh b/compiler/perl/t/cfclash/bar/Baz.cfh deleted file mode 100644 index 00e4033b..00000000 --- a/compiler/perl/t/cfclash/bar/Baz.cfh +++ /dev/null @@ -1,25 +0,0 @@ -/* 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); -} - diff --git a/compiler/perl/t/cfclash/class/Animal/DogClash.cfh b/compiler/perl/t/cfclash/class/Animal/DogClash.cfh deleted file mode 100644 index 3eba020d..00000000 --- a/compiler/perl/t/cfclash/class/Animal/DogClash.cfh +++ /dev/null @@ -1,28 +0,0 @@ -/* 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); -} diff --git a/compiler/perl/t/cfclash/class/AnimalExtension.cfp b/compiler/perl/t/cfclash/class/AnimalExtension.cfp deleted file mode 100644 index 76f31d34..00000000 --- a/compiler/perl/t/cfclash/class/AnimalExtension.cfp +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "AnimalExtension", - "nickname": "AniExt", - "version": "v0.1.0" -} diff --git a/compiler/perl/t/cfclash/file/Animal/Dog.cfh b/compiler/perl/t/cfclash/file/Animal/Dog.cfh deleted file mode 100644 index 13571093..00000000 --- a/compiler/perl/t/cfclash/file/Animal/Dog.cfh +++ /dev/null @@ -1,28 +0,0 @@ -/* 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); -} diff --git a/compiler/perl/t/cfclash/foo/Foo.cfh b/compiler/perl/t/cfclash/foo/Foo.cfh deleted file mode 100644 index b770d8a8..00000000 --- a/compiler/perl/t/cfclash/foo/Foo.cfh +++ /dev/null @@ -1,25 +0,0 @@ -/* 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); -} - diff --git a/compiler/perl/t/cfclash/foo/Foo.cfp b/compiler/perl/t/cfclash/foo/Foo.cfp deleted file mode 100644 index 29951692..00000000 --- a/compiler/perl/t/cfclash/foo/Foo.cfp +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "Foo", - "version": "v1.0.0" -} From 82ad28953d9d1e2e66fded8ef8ffab85be18f124 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Sat, 5 Mar 2016 19:46:12 +0100 Subject: [PATCH 7/8] Move CFC test files into "common" directory --- compiler/c/t/test_cfc.c | 2 +- .../{c/t => common/test}/cfbase/Animal.cfh | 0 .../{c/t => common/test}/cfbase/Animal.cfp | 0 .../t => common/test}/cfbase/Animal/Dog.cfh | 0 .../t => common/test}/cfbase/Animal/Util.cfh | 0 .../{c/t => common/test}/cfclash/bar/Bar.cfh | 0 .../{c/t => common/test}/cfclash/bar/Bar.cfp | 0 .../{c/t => common/test}/cfclash/bar/Baz.cfh | 0 .../test}/cfclash/class/Animal/DogClash.cfh | 0 .../test}/cfclash/class/AnimalExtension.cfp | 0 .../test}/cfclash/file/Animal/Dog.cfh | 0 .../{c/t => common/test}/cfclash/foo/Foo.cfh | 0 .../{c/t => common/test}/cfclash/foo/Foo.cfp | 0 .../test}/cfext/Animal/Rottweiler.cfh | 0 .../test}/cfext/AnimalExtension.cfp | 0 compiler/perl/buildlib/Clownfish/CFC/Build.pm | 21 +-- .../buildlib/Clownfish/CFC/Test/TestUtils.pm | 44 +++++++ compiler/perl/lib/Clownfish/CFC.xs | 5 +- compiler/perl/t/403-parcel.t | 3 +- compiler/perl/t/500-hierarchy.t | 7 +- compiler/perl/t/501-include_dir.t | 7 +- compiler/perl/t/cfbase/Animal.cfh | 21 --- compiler/perl/t/cfbase/Animal.cfp | 4 - compiler/perl/t/cfbase/Animal/Dog.cfh | 28 ---- compiler/perl/t/cfbase/Animal/Util.cfh | 23 ---- compiler/perl/t/cfext/Animal/Rottweiler.cfh | 31 ----- compiler/perl/t/cfext/AnimalExtension.cfp | 8 -- compiler/perl/t/core/403-parcel.t | 6 +- compiler/perl/t/core/500-hierarchy.t | 6 +- compiler/src/CFCTest.c | 20 ++- compiler/src/CFCTest.h | 9 +- compiler/src/CFCTestHierarchy.c | 121 ++++++++++-------- compiler/src/CFCTestParcel.c | 3 +- 33 files changed, 174 insertions(+), 195 deletions(-) rename compiler/{c/t => common/test}/cfbase/Animal.cfh (100%) rename compiler/{c/t => common/test}/cfbase/Animal.cfp (100%) rename compiler/{c/t => common/test}/cfbase/Animal/Dog.cfh (100%) rename compiler/{c/t => common/test}/cfbase/Animal/Util.cfh (100%) rename compiler/{c/t => common/test}/cfclash/bar/Bar.cfh (100%) rename compiler/{c/t => common/test}/cfclash/bar/Bar.cfp (100%) rename compiler/{c/t => common/test}/cfclash/bar/Baz.cfh (100%) rename compiler/{c/t => common/test}/cfclash/class/Animal/DogClash.cfh (100%) rename compiler/{c/t => common/test}/cfclash/class/AnimalExtension.cfp (100%) rename compiler/{c/t => common/test}/cfclash/file/Animal/Dog.cfh (100%) rename compiler/{c/t => common/test}/cfclash/foo/Foo.cfh (100%) rename compiler/{c/t => common/test}/cfclash/foo/Foo.cfp (100%) rename compiler/{c/t => common/test}/cfext/Animal/Rottweiler.cfh (100%) rename compiler/{c/t => common/test}/cfext/AnimalExtension.cfp (100%) create mode 100644 compiler/perl/buildlib/Clownfish/CFC/Test/TestUtils.pm delete mode 100644 compiler/perl/t/cfbase/Animal.cfh delete mode 100644 compiler/perl/t/cfbase/Animal.cfp delete mode 100644 compiler/perl/t/cfbase/Animal/Dog.cfh delete mode 100644 compiler/perl/t/cfbase/Animal/Util.cfh delete mode 100644 compiler/perl/t/cfext/Animal/Rottweiler.cfh delete mode 100644 compiler/perl/t/cfext/AnimalExtension.cfp diff --git a/compiler/c/t/test_cfc.c b/compiler/c/t/test_cfc.c index 66fa90ae..cb55d451 100644 --- a/compiler/c/t/test_cfc.c +++ b/compiler/c/t/test_cfc.c @@ -22,7 +22,7 @@ int main() { CFCTest *test = CFCTest_new("clownfish"); - CFCTest_run_all(test); + CFCTest_run_all(test, NULL); int pass = CFCTest_finish(test); CFCBase_decref((CFCBase*)test); diff --git a/compiler/c/t/cfbase/Animal.cfh b/compiler/common/test/cfbase/Animal.cfh similarity index 100% rename from compiler/c/t/cfbase/Animal.cfh rename to compiler/common/test/cfbase/Animal.cfh diff --git a/compiler/c/t/cfbase/Animal.cfp b/compiler/common/test/cfbase/Animal.cfp similarity index 100% rename from compiler/c/t/cfbase/Animal.cfp rename to compiler/common/test/cfbase/Animal.cfp diff --git a/compiler/c/t/cfbase/Animal/Dog.cfh b/compiler/common/test/cfbase/Animal/Dog.cfh similarity index 100% rename from compiler/c/t/cfbase/Animal/Dog.cfh rename to compiler/common/test/cfbase/Animal/Dog.cfh diff --git a/compiler/c/t/cfbase/Animal/Util.cfh b/compiler/common/test/cfbase/Animal/Util.cfh similarity index 100% rename from compiler/c/t/cfbase/Animal/Util.cfh rename to compiler/common/test/cfbase/Animal/Util.cfh diff --git a/compiler/c/t/cfclash/bar/Bar.cfh b/compiler/common/test/cfclash/bar/Bar.cfh similarity index 100% rename from compiler/c/t/cfclash/bar/Bar.cfh rename to compiler/common/test/cfclash/bar/Bar.cfh diff --git a/compiler/c/t/cfclash/bar/Bar.cfp b/compiler/common/test/cfclash/bar/Bar.cfp similarity index 100% rename from compiler/c/t/cfclash/bar/Bar.cfp rename to compiler/common/test/cfclash/bar/Bar.cfp diff --git a/compiler/c/t/cfclash/bar/Baz.cfh b/compiler/common/test/cfclash/bar/Baz.cfh similarity index 100% rename from compiler/c/t/cfclash/bar/Baz.cfh rename to compiler/common/test/cfclash/bar/Baz.cfh diff --git a/compiler/c/t/cfclash/class/Animal/DogClash.cfh b/compiler/common/test/cfclash/class/Animal/DogClash.cfh similarity index 100% rename from compiler/c/t/cfclash/class/Animal/DogClash.cfh rename to compiler/common/test/cfclash/class/Animal/DogClash.cfh diff --git a/compiler/c/t/cfclash/class/AnimalExtension.cfp b/compiler/common/test/cfclash/class/AnimalExtension.cfp similarity index 100% rename from compiler/c/t/cfclash/class/AnimalExtension.cfp rename to compiler/common/test/cfclash/class/AnimalExtension.cfp diff --git a/compiler/c/t/cfclash/file/Animal/Dog.cfh b/compiler/common/test/cfclash/file/Animal/Dog.cfh similarity index 100% rename from compiler/c/t/cfclash/file/Animal/Dog.cfh rename to compiler/common/test/cfclash/file/Animal/Dog.cfh diff --git a/compiler/c/t/cfclash/foo/Foo.cfh b/compiler/common/test/cfclash/foo/Foo.cfh similarity index 100% rename from compiler/c/t/cfclash/foo/Foo.cfh rename to compiler/common/test/cfclash/foo/Foo.cfh diff --git a/compiler/c/t/cfclash/foo/Foo.cfp b/compiler/common/test/cfclash/foo/Foo.cfp similarity index 100% rename from compiler/c/t/cfclash/foo/Foo.cfp rename to compiler/common/test/cfclash/foo/Foo.cfp diff --git a/compiler/c/t/cfext/Animal/Rottweiler.cfh b/compiler/common/test/cfext/Animal/Rottweiler.cfh similarity index 100% rename from compiler/c/t/cfext/Animal/Rottweiler.cfh rename to compiler/common/test/cfext/Animal/Rottweiler.cfh diff --git a/compiler/c/t/cfext/AnimalExtension.cfp b/compiler/common/test/cfext/AnimalExtension.cfp similarity index 100% rename from compiler/c/t/cfext/AnimalExtension.cfp rename to compiler/common/test/cfext/AnimalExtension.cfp diff --git a/compiler/perl/buildlib/Clownfish/CFC/Build.pm b/compiler/perl/buildlib/Clownfish/CFC/Build.pm index dd67a0bc..0637b712 100644 --- a/compiler/perl/buildlib/Clownfish/CFC/Build.pm +++ b/compiler/perl/buildlib/Clownfish/CFC/Build.pm @@ -265,15 +265,18 @@ sub ACTION_dist { # the top-level $REPOS_ROOT. Because some assets we need are outside this # directory, we need to copy them in. my %to_copy = ( - '../../CONTRIBUTING.md' => 'CONTRIBUTING.md', - '../../LICENSE' => 'LICENSE', - '../../NOTICE' => 'NOTICE', - '../../README.md' => 'README.md', - '../../lemon' => 'lemon', - '../src' => 'src', - '../include' => 'include', - '../modules' => 'modules', - $CHARMONIZER_C => 'charmonizer.c', + '../../CONTRIBUTING.md' => 'CONTRIBUTING.md', + '../../LICENSE' => 'LICENSE', + '../../NOTICE' => 'NOTICE', + '../../README.md' => 'README.md', + '../../lemon' => 'lemon', + '../src' => 'src', + '../include' => 'include', + '../modules' => 'modules', + '../common/test/cfbase' => 't/cfbase', + '../common/test/cfclash' => 't/cfclash', + '../common/test/cfext' => 't/cfext', + $CHARMONIZER_C => 'charmonizer.c', ); print "Copying files...\n"; while (my ($from, $to) = each %to_copy) { diff --git a/compiler/perl/buildlib/Clownfish/CFC/Test/TestUtils.pm b/compiler/perl/buildlib/Clownfish/CFC/Test/TestUtils.pm new file mode 100644 index 00000000..2df524d8 --- /dev/null +++ b/compiler/perl/buildlib/Clownfish/CFC/Test/TestUtils.pm @@ -0,0 +1,44 @@ +# 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; + +package Clownfish::CFC::Test::TestUtils; + +our $VERSION = '0.005000'; +$VERSION = eval $VERSION; + +use Exporter 'import'; +our @EXPORT_OK = qw( test_files_dir ); + +use File::Spec::Functions qw( catdir updir ); + +sub test_files_dir { + my @dirs = ( + 't', + catdir( updir(), 'common', 'test' ), + ); + + for my $dir (@dirs) { + my $cfbase = catdir( $dir, 'cfbase' ); + return $dir if -d $cfbase; + } + + die("test files dir not found"); +} + +1; + diff --git a/compiler/perl/lib/Clownfish/CFC.xs b/compiler/perl/lib/Clownfish/CFC.xs index 20f889ff..368043c5 100644 --- a/compiler/perl/lib/Clownfish/CFC.xs +++ b/compiler/perl/lib/Clownfish/CFC.xs @@ -2484,10 +2484,11 @@ CODE: OUTPUT: RETVAL int -run_batch(self, klass) +run_batch(self, klass, test_files_dir = NULL) CFCTest *self; const char *klass; + const char *test_files_dir; CODE: - RETVAL = CFCTest_run_batch(self, klass); + RETVAL = CFCTest_run_batch(self, klass, test_files_dir); OUTPUT: RETVAL diff --git a/compiler/perl/t/403-parcel.t b/compiler/perl/t/403-parcel.t index 263e6025..fec23e34 100644 --- a/compiler/perl/t/403-parcel.t +++ b/compiler/perl/t/403-parcel.t @@ -16,6 +16,7 @@ use strict; use warnings; +use Clownfish::CFC::Test::TestUtils qw( test_files_dir ); use Test::More tests => 35; use File::Spec::Functions qw( catfile ); @@ -87,7 +88,7 @@ isa_ok( isa_ok( Clownfish::CFC::Model::Parcel->new_from_file( - path => catfile(qw( t cfbase Animal.cfp )), + path => catfile( test_files_dir(), qw( cfbase Animal.cfp ) ), ), "Clownfish::CFC::Model::Parcel", "new_from_file" diff --git a/compiler/perl/t/500-hierarchy.t b/compiler/perl/t/500-hierarchy.t index 62ac046b..44b0b6a9 100644 --- a/compiler/perl/t/500-hierarchy.t +++ b/compiler/perl/t/500-hierarchy.t @@ -20,14 +20,13 @@ use Test::More tests => 21; use Clownfish::CFC::Model::Hierarchy; use Clownfish::CFC::Util qw( a_isa_b ); +use Clownfish::CFC::Test::TestUtils qw( test_files_dir ); use File::Spec::Functions qw( catdir catfile splitpath ); use Fcntl; use File::Path qw( rmtree mkpath ); -my $base_dir = catdir(qw( t cfbase )); -my %args = ( - dest => catdir(qw( t cfdest )), -); +my $base_dir = catdir( test_files_dir(), 'cfbase' ); +my %args = ( dest => 'autogen' ); # Clean up. rmtree( $args{dest} ); diff --git a/compiler/perl/t/501-include_dir.t b/compiler/perl/t/501-include_dir.t index 13dccfa5..0e4d24ed 100644 --- a/compiler/perl/t/501-include_dir.t +++ b/compiler/perl/t/501-include_dir.t @@ -19,12 +19,13 @@ use warnings; use Test::More tests => 24; use Clownfish::CFC::Model::Hierarchy; +use Clownfish::CFC::Test::TestUtils qw( test_files_dir ); use File::Spec::Functions qw( catdir catfile splitpath ); use File::Path qw( rmtree ); -my $base_dir = catdir(qw( t cfbase )); -my $ext_dir = catdir(qw( t cfext )); -my $dest_dir = catdir(qw( t cfdest )); +my $base_dir = catdir( test_files_dir(), 'cfbase' ); +my $ext_dir = catdir( test_files_dir(), 'cfext' ); +my $dest_dir = 'autogen'; # One source, one include diff --git a/compiler/perl/t/cfbase/Animal.cfh b/compiler/perl/t/cfbase/Animal.cfh deleted file mode 100644 index 46130b72..00000000 --- a/compiler/perl/t/cfbase/Animal.cfh +++ /dev/null @@ -1,21 +0,0 @@ -/* 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 Clownfish::Obj { } - -abstract class Animal { } diff --git a/compiler/perl/t/cfbase/Animal.cfp b/compiler/perl/t/cfbase/Animal.cfp deleted file mode 100644 index e2b5ab58..00000000 --- a/compiler/perl/t/cfbase/Animal.cfp +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "Animal", - "version": "v0.1.0" -} diff --git a/compiler/perl/t/cfbase/Animal/Dog.cfh b/compiler/perl/t/cfbase/Animal/Dog.cfh deleted file mode 100644 index 6d54baa1..00000000 --- a/compiler/perl/t/cfbase/Animal/Dog.cfh +++ /dev/null @@ -1,28 +0,0 @@ -/* 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::Dog inherits Animal { - public inert incremented Dog* - new(); - - public inert Dog* - init(Dog *self); - - public void - Bark(Dog *self); -} diff --git a/compiler/perl/t/cfbase/Animal/Util.cfh b/compiler/perl/t/cfbase/Animal/Util.cfh deleted file mode 100644 index f5688a5e..00000000 --- a/compiler/perl/t/cfbase/Animal/Util.cfh +++ /dev/null @@ -1,23 +0,0 @@ -/* 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; - -inert class Animal::Util { - inert void - groom(Animal *animal); -} - diff --git a/compiler/perl/t/cfext/Animal/Rottweiler.cfh b/compiler/perl/t/cfext/Animal/Rottweiler.cfh deleted file mode 100644 index 9e78b585..00000000 --- a/compiler/perl/t/cfext/Animal/Rottweiler.cfh +++ /dev/null @@ -1,31 +0,0 @@ -/* 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::Rottweiler inherits Animal::Dog { - public inert incremented Rottweiler* - new(); - - public inert Rottweiler* - init(Rottweiler *self); - - public void - Bark(Rottweiler *self); - - public void - Bite(Rottweiler *self); -} diff --git a/compiler/perl/t/cfext/AnimalExtension.cfp b/compiler/perl/t/cfext/AnimalExtension.cfp deleted file mode 100644 index 8b8e75b5..00000000 --- a/compiler/perl/t/cfext/AnimalExtension.cfp +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "AnimalExtension", - "nickname": "AniExt", - "version": "v0.1.0", - "prerequisites": { - "Animal": null - } -} diff --git a/compiler/perl/t/core/403-parcel.t b/compiler/perl/t/core/403-parcel.t index 1258f6d9..13a176d5 100644 --- a/compiler/perl/t/core/403-parcel.t +++ b/compiler/perl/t/core/403-parcel.t @@ -17,9 +17,13 @@ use strict; use warnings; use Clownfish::CFC::Test; +use Clownfish::CFC::Test::TestUtils qw( test_files_dir ); my $test = Clownfish::CFC::Test->new; -my $passed = $test->run_batch('Clownfish::CFC::Model::Parcel'); +my $passed = $test->run_batch( + 'Clownfish::CFC::Model::Parcel', + test_files_dir(), +); exit($passed ? 0 : 1); diff --git a/compiler/perl/t/core/500-hierarchy.t b/compiler/perl/t/core/500-hierarchy.t index 5b60568d..1121369e 100644 --- a/compiler/perl/t/core/500-hierarchy.t +++ b/compiler/perl/t/core/500-hierarchy.t @@ -17,9 +17,13 @@ use strict; use warnings; use Clownfish::CFC::Test; +use Clownfish::CFC::Test::TestUtils qw( test_files_dir ); my $test = Clownfish::CFC::Test->new; -my $passed = $test->run_batch('Clownfish::CFC::Model::Hierarchy'); +my $passed = $test->run_batch( + 'Clownfish::CFC::Model::Hierarchy', + test_files_dir(), +); exit($passed ? 0 : 1); diff --git a/compiler/src/CFCTest.c b/compiler/src/CFCTest.c index 0f61745f..a542c323 100644 --- a/compiler/src/CFCTest.c +++ b/compiler/src/CFCTest.c @@ -104,6 +104,8 @@ static const CFCMeta CFCTEST_META = { (CFCBase_destroy_t)CFCTest_destroy }; +static const char *S_test_files_dir; + static const CFCTestFormatter S_formatter_cfish = { S_format_cfish_batch_prologue, S_format_cfish_vtest_result, @@ -176,9 +178,11 @@ CFCTest_destroy(CFCTest *self) { } int -CFCTest_run_all(CFCTest *self) { +CFCTest_run_all(CFCTest *self, const char *test_files_dir) { int failed = 0; + S_test_files_dir = test_files_dir; + for (int i = 0; S_batches[i]; ++i) { if (!S_do_run_batch(self, S_batches[i])) { failed = 1; } } @@ -187,7 +191,10 @@ CFCTest_run_all(CFCTest *self) { } int -CFCTest_run_batch(CFCTest *self, const char *name) { +CFCTest_run_batch(CFCTest *self, const char *name, + const char *test_files_dir) { + S_test_files_dir = test_files_dir; + for (int i = 0; S_batches[i]; ++i) { const CFCTestBatch *batch = S_batches[i]; if (strcmp(batch->name, name) == 0) { @@ -230,6 +237,15 @@ S_do_run_batch(CFCTest *self, const CFCTestBatch *batch) { return !failed; } +char* +CFCTest_path(const char *path) { + const char *dir = S_test_files_dir + ? S_test_files_dir + : ".." CHY_DIR_SEP "common" CHY_DIR_SEP "test"; + + return CFCUtil_sprintf("%s" CHY_DIR_SEP "%s", dir, path); +} + void CFCTest_test_true(CFCTest *self, int cond, const char *fmt, ...) { va_list args; diff --git a/compiler/src/CFCTest.h b/compiler/src/CFCTest.h index 41cf73dd..fd8bd30d 100644 --- a/compiler/src/CFCTest.h +++ b/compiler/src/CFCTest.h @@ -70,7 +70,7 @@ CFCTest_destroy(CFCTest *self); * @return true if all tests were successful. */ int -CFCTest_run_all(CFCTest *self); +CFCTest_run_all(CFCTest *self, const char *test_files_dir); /** Run a test batch by name. * @@ -78,7 +78,12 @@ CFCTest_run_all(CFCTest *self); * @return true if all tests in the batch were successful. */ int -CFCTest_run_batch(CFCTest *self, const char *name); +CFCTest_run_batch(CFCTest *self, const char *name, const char *test_files_dir); + +/** Return the full path for a test file or directory. + */ +char* +CFCTest_path(const char *path); /* Collect result of a test. * diff --git a/compiler/src/CFCTestHierarchy.c b/compiler/src/CFCTestHierarchy.c index 670f8727..75c63937 100644 --- a/compiler/src/CFCTestHierarchy.c +++ b/compiler/src/CFCTestHierarchy.c @@ -37,15 +37,9 @@ #include "CFCTest.h" #include "CFCUtil.h" -#define T_CFBASE "t" CHY_DIR_SEP "cfbase" -#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" -#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" +#define AUTOGEN "autogen" +#define AUTOGEN_INCLUDE AUTOGEN CHY_DIR_SEP "include" +#define AUTOGEN_SOURCE AUTOGEN CHY_DIR_SEP "source" static void S_run_tests(CFCTest *test); @@ -74,16 +68,18 @@ S_run_tests(CFCTest *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, + char *cfbase_path = CFCTest_path("cfbase"); + + CFCHierarchy *hierarchy = CFCHierarchy_new(AUTOGEN); + STR_EQ(test, CFCHierarchy_get_dest(hierarchy), AUTOGEN, "get_dest"); + STR_EQ(test, CFCHierarchy_get_include_dest(hierarchy), AUTOGEN_INCLUDE, "get_include_dest"); - STR_EQ(test, CFCHierarchy_get_source_dest(hierarchy), T_CFDEST_SOURCE, + STR_EQ(test, CFCHierarchy_get_source_dest(hierarchy), AUTOGEN_SOURCE, "get_source_dest"); - CFCHierarchy_add_source_dir(hierarchy, T_CFBASE); + CFCHierarchy_add_source_dir(hierarchy, cfbase_path); const char **source_dirs = CFCHierarchy_get_source_dirs(hierarchy); - STR_EQ(test, source_dirs[0], T_CFBASE, "source_dirs[0]"); + STR_EQ(test, source_dirs[0], cfbase_path, "source_dirs[0]"); OK(test, source_dirs[1] == NULL, "source_dirs[1]"); CFCHierarchy_build(hierarchy); @@ -132,11 +128,11 @@ S_run_basic_tests(CFCTest *test) { time_t now = time(NULL); time_t past_time = now - 2; static const char *const h_paths[] = { - T_CFDEST_INCLUDE CHY_DIR_SEP "Animal.h", - T_CFDEST_INCLUDE CHY_DIR_SEP "Animal" CHY_DIR_SEP "Dog.h", - T_CFDEST_INCLUDE CHY_DIR_SEP "Animal" CHY_DIR_SEP "Util.h" + AUTOGEN_INCLUDE CHY_DIR_SEP "Animal.h", + AUTOGEN_INCLUDE CHY_DIR_SEP "Animal" CHY_DIR_SEP "Dog.h", + AUTOGEN_INCLUDE CHY_DIR_SEP "Animal" CHY_DIR_SEP "Util.h" }; - OK(test, CFCUtil_make_path(T_CFDEST_INCLUDE CHY_DIR_SEP "Animal"), + OK(test, CFCUtil_make_path(AUTOGEN_INCLUDE CHY_DIR_SEP "Animal"), "make_path"); for (int i = 0; i < 3; ++i) { const char *h_path = h_paths[i]; @@ -145,7 +141,7 @@ S_run_basic_tests(CFCTest *test) { CFCTest_set_file_times(h_path, past_time); } - char *cfh_path = CFCFile_cfh_path(animal, T_CFBASE); + char *cfh_path = CFCFile_cfh_path(animal, cfbase_path); CFCTest_set_file_times(cfh_path, now); FREEMEM(cfh_path); @@ -160,24 +156,28 @@ S_run_basic_tests(CFCTest *test) { for (int i = 0; i < 3; ++i) { remove(h_paths[i]); } - rmdir(T_CFDEST_INCLUDE CHY_DIR_SEP "Animal"); - rmdir(T_CFDEST_INCLUDE); - rmdir(T_CFDEST_SOURCE); - rmdir(T_CFDEST); + rmdir(AUTOGEN_INCLUDE CHY_DIR_SEP "Animal"); + rmdir(AUTOGEN_INCLUDE); + rmdir(AUTOGEN_SOURCE); + rmdir(AUTOGEN); CFCBase_decref((CFCBase*)hierarchy); + FREEMEM(cfbase_path); CFCClass_clear_registry(); CFCParcel_reap_singletons(); } static void S_run_include_tests(CFCTest *test) { + char *cfbase_path = CFCTest_path("cfbase"); + char *cfext_path = CFCTest_path("cfext"); + { - CFCHierarchy *hierarchy = CFCHierarchy_new(T_CFDEST); - CFCHierarchy_add_source_dir(hierarchy, T_CFEXT); - CFCHierarchy_add_include_dir(hierarchy, T_CFBASE); + CFCHierarchy *hierarchy = CFCHierarchy_new(AUTOGEN); + CFCHierarchy_add_source_dir(hierarchy, cfext_path); + CFCHierarchy_add_include_dir(hierarchy, cfbase_path); const char **include_dirs = CFCHierarchy_get_include_dirs(hierarchy); - STR_EQ(test, include_dirs[0], T_CFBASE, "include_dirs[0]"); + STR_EQ(test, include_dirs[0], cfbase_path, "include_dirs[0]"); OK(test, include_dirs[1] == NULL, "include_dirs[1]"); CFCHierarchy_build(hierarchy); @@ -210,9 +210,9 @@ S_run_include_tests(CFCTest *test) { } { - CFCHierarchy *hierarchy = CFCHierarchy_new(T_CFDEST); - CFCHierarchy_add_source_dir(hierarchy, T_CFBASE); - CFCHierarchy_add_source_dir(hierarchy, T_CFEXT); + CFCHierarchy *hierarchy = CFCHierarchy_new(AUTOGEN); + CFCHierarchy_add_source_dir(hierarchy, cfbase_path); + CFCHierarchy_add_source_dir(hierarchy, cfext_path); CFCHierarchy_build(hierarchy); @@ -239,9 +239,9 @@ S_run_include_tests(CFCTest *test) { } { - CFCHierarchy *hierarchy = CFCHierarchy_new(T_CFDEST); - CFCHierarchy_add_include_dir(hierarchy, T_CFBASE); - CFCHierarchy_add_include_dir(hierarchy, T_CFEXT); + CFCHierarchy *hierarchy = CFCHierarchy_new(AUTOGEN); + CFCHierarchy_add_include_dir(hierarchy, cfbase_path); + CFCHierarchy_add_include_dir(hierarchy, cfext_path); CFCHierarchy_add_prereq(hierarchy, "AnimalExtension"); CFCHierarchy_build(hierarchy); @@ -267,20 +267,29 @@ S_run_include_tests(CFCTest *test) { CFCParcel_reap_singletons(); } - rmdir(T_CFDEST_INCLUDE); - rmdir(T_CFDEST_SOURCE); - rmdir(T_CFDEST); + rmdir(AUTOGEN_INCLUDE); + rmdir(AUTOGEN_SOURCE); + rmdir(AUTOGEN); + + FREEMEM(cfbase_path); + FREEMEM(cfext_path); } static void S_run_clash_tests(CFCTest *test) { + char *cfbase_path = CFCTest_path("cfbase"); + char *cfclash_file_path = CFCTest_path("cfclash" CHY_DIR_SEP "file"); + char *cfclash_class_path = CFCTest_path("cfclash" CHY_DIR_SEP "class"); + char *cfclash_foo_path = CFCTest_path("cfclash" CHY_DIR_SEP "foo"); + char *cfclash_bar_path = CFCTest_path("cfclash" CHY_DIR_SEP "bar"); + 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); + CFCHierarchy *hierarchy = CFCHierarchy_new(AUTOGEN); + CFCHierarchy_add_source_dir(hierarchy, cfbase_path); + CFCHierarchy_add_source_dir(hierarchy, cfclash_file_path); char *error; CFCUTIL_TRY { @@ -299,9 +308,9 @@ S_run_clash_tests(CFCTest *test) { 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); + CFCHierarchy *hierarchy = CFCHierarchy_new(AUTOGEN); + CFCHierarchy_add_source_dir(hierarchy, cfclash_class_path); + CFCHierarchy_add_include_dir(hierarchy, cfbase_path); char *error; CFCUTIL_TRY { @@ -317,9 +326,9 @@ S_run_clash_tests(CFCTest *test) { } { - CFCHierarchy *hierarchy = CFCHierarchy_new(T_CFDEST); - CFCHierarchy_add_source_dir(hierarchy, T_CFBASE); - CFCHierarchy_add_include_dir(hierarchy, T_CFCLASH_FILE); + CFCHierarchy *hierarchy = CFCHierarchy_new(AUTOGEN); + CFCHierarchy_add_source_dir(hierarchy, cfbase_path); + CFCHierarchy_add_include_dir(hierarchy, cfclash_file_path); CFCHierarchy_build(hierarchy); CFCClass **ordered = CFCHierarchy_ordered_classes(hierarchy); @@ -337,10 +346,10 @@ S_run_clash_tests(CFCTest *test) { 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); + CFCHierarchy *hierarchy = CFCHierarchy_new(AUTOGEN); + CFCHierarchy_add_source_dir(hierarchy, cfclash_bar_path); + CFCHierarchy_add_include_dir(hierarchy, cfclash_foo_path); + CFCHierarchy_add_include_dir(hierarchy, cfbase_path); char *error; CFCUTIL_TRY { @@ -355,8 +364,14 @@ S_run_clash_tests(CFCTest *test) { CFCParcel_reap_singletons(); } - rmdir(T_CFDEST_INCLUDE); - rmdir(T_CFDEST_SOURCE); - rmdir(T_CFDEST); + rmdir(AUTOGEN_INCLUDE); + rmdir(AUTOGEN_SOURCE); + rmdir(AUTOGEN); + + FREEMEM(cfbase_path); + FREEMEM(cfclash_file_path); + FREEMEM(cfclash_class_path); + FREEMEM(cfclash_foo_path); + FREEMEM(cfclash_bar_path); } diff --git a/compiler/src/CFCTestParcel.c b/compiler/src/CFCTestParcel.c index 263c60e4..c4f90851 100644 --- a/compiler/src/CFCTestParcel.c +++ b/compiler/src/CFCTestParcel.c @@ -167,10 +167,11 @@ S_run_extended_tests(CFCTest *test) { } { - const char *path = "t" CHY_DIR_SEP "cfbase" CHY_DIR_SEP "Animal.cfp"; + char *path = CFCTest_path("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); + FREEMEM(path); } { From 25e6ff33d3df646d1bf5adc887b8bd5cd6f59023 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Sat, 5 Mar 2016 19:54:54 +0100 Subject: [PATCH 8/8] Add check for va_copy --- compiler/src/CFCUtil.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/src/CFCUtil.c b/compiler/src/CFCUtil.c index a2a0993b..7470c04c 100644 --- a/compiler/src/CFCUtil.c +++ b/compiler/src/CFCUtil.c @@ -30,6 +30,17 @@ #include #endif +#if !defined(CHY_HAS_C99_SNPRINTF) && !defined(CHY_HAS__SCPRINTF) + #error "snprintf or replacement not available." +#endif + +/* va_copy is not part of C89. Assume that simple assignment works if it + * isn't defined. + */ +#ifndef va_copy + #define va_copy(dst, src) ((dst) = (src)) +#endif + #ifndef true #define true 1 #define false 0 @@ -74,10 +85,6 @@ CFCUtil_sprintf(const char *fmt, ...) { return string; } -#if !defined(CHY_HAS_C99_SNPRINTF) && !defined(CHY_HAS__SCPRINTF) - #error "snprintf or replacement not available." -#endif - char* CFCUtil_vsprintf(const char *fmt, va_list args) { va_list args_copy;