Updated Branches:
  refs/heads/cfc-tests 7c4d3f5e0 -> e47ccd4cd

Port more CFC tests to C


Project: http://git-wip-us.apache.org/repos/asf/lucy/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/e47ccd4c
Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/e47ccd4c
Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/e47ccd4c

Branch: refs/heads/cfc-tests
Commit: e47ccd4cd8828283bd3ea7e8cc1dc256ebbfd800
Parents: 5ee2fed
Author: Nick Wellnhofer <[email protected]>
Authored: Wed Jan 30 20:27:57 2013 +0100
Committer: Nick Wellnhofer <[email protected]>
Committed: Thu Jan 31 22:28:05 2013 +0100

----------------------------------------------------------------------
 clownfish/compiler/perl/t/core/402-c_block.t   |   25 ++++
 clownfish/compiler/perl/t/core/403-parcel.t    |   25 ++++
 clownfish/compiler/perl/t/core/404-file.t      |   25 ++++
 clownfish/compiler/perl/t/core/500-hierarchy.t |   25 ++++
 clownfish/compiler/src/CFCTest.c               |   59 ++++++++
 clownfish/compiler/src/CFCTest.h               |   12 ++
 clownfish/compiler/src/CFCTestCBlock.c         |   60 ++++++++
 clownfish/compiler/src/CFCTestFile.c           |  126 +++++++++++++++++
 clownfish/compiler/src/CFCTestHierarchy.c      |  141 +++++++++++++++++++
 clownfish/compiler/src/CFCTestParcel.c         |   92 ++++++++++++
 clownfish/compiler/src/CFCTestUtil.c           |   67 +--------
 11 files changed, 594 insertions(+), 63 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/e47ccd4c/clownfish/compiler/perl/t/core/402-c_block.t
----------------------------------------------------------------------
diff --git a/clownfish/compiler/perl/t/core/402-c_block.t 
b/clownfish/compiler/perl/t/core/402-c_block.t
new file mode 100644
index 0000000..f993aa4
--- /dev/null
+++ b/clownfish/compiler/perl/t/core/402-c_block.t
@@ -0,0 +1,25 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+use strict;
+use warnings;
+
+use Clownfish::CFC::Test;
+
+my $test   = Clownfish::CFC::Test->new;
+my $passed = $test->run_batch('Clownfish::CFC::Model::CBlock');
+
+exit($passed ? 0 : 1);
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/e47ccd4c/clownfish/compiler/perl/t/core/403-parcel.t
----------------------------------------------------------------------
diff --git a/clownfish/compiler/perl/t/core/403-parcel.t 
b/clownfish/compiler/perl/t/core/403-parcel.t
new file mode 100644
index 0000000..1258f6d
--- /dev/null
+++ b/clownfish/compiler/perl/t/core/403-parcel.t
@@ -0,0 +1,25 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+use strict;
+use warnings;
+
+use Clownfish::CFC::Test;
+
+my $test   = Clownfish::CFC::Test->new;
+my $passed = $test->run_batch('Clownfish::CFC::Model::Parcel');
+
+exit($passed ? 0 : 1);
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/e47ccd4c/clownfish/compiler/perl/t/core/404-file.t
----------------------------------------------------------------------
diff --git a/clownfish/compiler/perl/t/core/404-file.t 
b/clownfish/compiler/perl/t/core/404-file.t
new file mode 100644
index 0000000..69c112e
--- /dev/null
+++ b/clownfish/compiler/perl/t/core/404-file.t
@@ -0,0 +1,25 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+use strict;
+use warnings;
+
+use Clownfish::CFC::Test;
+
+my $test   = Clownfish::CFC::Test->new;
+my $passed = $test->run_batch('Clownfish::CFC::Model::File');
+
+exit($passed ? 0 : 1);
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/e47ccd4c/clownfish/compiler/perl/t/core/500-hierarchy.t
----------------------------------------------------------------------
diff --git a/clownfish/compiler/perl/t/core/500-hierarchy.t 
b/clownfish/compiler/perl/t/core/500-hierarchy.t
new file mode 100644
index 0000000..5b60568
--- /dev/null
+++ b/clownfish/compiler/perl/t/core/500-hierarchy.t
@@ -0,0 +1,25 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+use strict;
+use warnings;
+
+use Clownfish::CFC::Test;
+
+my $test   = Clownfish::CFC::Test->new;
+my $passed = $test->run_batch('Clownfish::CFC::Model::Hierarchy');
+
+exit($passed ? 0 : 1);
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/e47ccd4c/clownfish/compiler/src/CFCTest.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTest.c b/clownfish/compiler/src/CFCTest.c
index e4f6e4c..5e4f930 100644
--- a/clownfish/compiler/src/CFCTest.c
+++ b/clownfish/compiler/src/CFCTest.c
@@ -14,9 +14,14 @@
  * limitations under the License.
  */
 
+#include "charmony.h"
+
+#include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #define CFC_NEED_BASE_STRUCT_DEF
 #define CFC_USE_TEST_MACROS
@@ -117,6 +122,10 @@ static const CFCTestBatch *const S_batches[] = {
     &CFCTEST_BATCH_PARAM_LIST,
     &CFCTEST_BATCH_FILE_SPEC,
     &CFCTEST_BATCH_CLASS,
+    &CFCTEST_BATCH_C_BLOCK,
+    &CFCTEST_BATCH_PARCEL,
+    &CFCTEST_BATCH_FILE,
+    &CFCTEST_BATCH_HIERARCHY,
     NULL
 };
 
@@ -428,3 +437,53 @@ CFCTest_parse_class(CFCTest *test, CFCParser *parser, 
const char *src) {
     return (struct CFCClass*)result;
 }
 
+time_t
+CFCTest_get_file_mtime(const char *path) {
+    struct stat buf;
+    if (stat(path, &buf)) {
+        CFCUtil_die("Can't stat '%s': %s", path, strerror(errno));
+    }
+    return buf.st_mtime;
+}
+
+#if defined(CHY_HAS_UTIME_H)
+
+#include <utime.h>
+
+void
+CFCTest_set_file_times(const char *path, time_t time) {
+    struct utimbuf buf;
+    buf.actime  = time;
+    buf.modtime = time;
+    if (utime(path, &buf)) {
+        CFCUtil_die("Can't set file time of '%s': %s", path, strerror(errno));
+    }
+}
+
+#elif defined(CHY_HAS_WINDOWS_H)
+
+#include <windows.h>
+
+void
+CFCTest_set_file_times(const char *path, time_t time) {
+    HANDLE handle = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ, NULL,
+                               OPEN_EXISTING, 0, NULL);
+    if (handle == INVALID_HANDLE_VALUE) {
+        CFCUtil_die("Can't open '%s': %u", path, GetLastError());
+    }
+    uint64_t ticks = 10000000 * (UINT64_C(11644473600) + time);
+    FILETIME time;
+    time.dwLowDateTime  = (DWORD)ticks;
+    time.dwHighDateTime = (DWORD)(ticks >> 32);
+    if (!SetFileTime(handle, time, time, time)) {
+        CFCUtil_die("Can't set file time of '%s': %u", path, GetLastError());
+    }
+    CloseHandle(handle);
+}
+
+#else
+
+#error Need either utime.h or windows.h
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/e47ccd4c/clownfish/compiler/src/CFCTest.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTest.h b/clownfish/compiler/src/CFCTest.h
index 8b87b3c..ac80b92 100644
--- a/clownfish/compiler/src/CFCTest.h
+++ b/clownfish/compiler/src/CFCTest.h
@@ -17,6 +17,8 @@
 #ifndef H_TEST_CFC
 #define H_TEST_CFC
 
+#include <time.h>
+
 #ifdef CFC_USE_TEST_MACROS
   #define OK      CFCTest_test_true
   #define STR_EQ  CFCTest_test_string_equals
@@ -96,12 +98,22 @@ CFCTest_parse_method(CFCTest *test, struct CFCParser 
*parser, const char *src);
 struct CFCClass*
 CFCTest_parse_class(CFCTest *test, struct CFCParser *parser, const char *src);
 
+time_t
+CFCTest_get_file_mtime(const char *path);
+
+void
+CFCTest_set_file_times(const char *path, time_t time);
+
 extern const CFCTestBatch CFCTEST_BATCH_CLASS;
+extern const CFCTestBatch CFCTEST_BATCH_C_BLOCK;
 extern const CFCTestBatch CFCTEST_BATCH_DOCU_COMMENT;
+extern const CFCTestBatch CFCTEST_BATCH_FILE;
 extern const CFCTestBatch CFCTEST_BATCH_FILE_SPEC;
 extern const CFCTestBatch CFCTEST_BATCH_FUNCTION;
+extern const CFCTestBatch CFCTEST_BATCH_HIERARCHY;
 extern const CFCTestBatch CFCTEST_BATCH_METHOD;
 extern const CFCTestBatch CFCTEST_BATCH_PARAM_LIST;
+extern const CFCTestBatch CFCTEST_BATCH_PARCEL;
 extern const CFCTestBatch CFCTEST_BATCH_SYMBOL;
 extern const CFCTestBatch CFCTEST_BATCH_TYPE;
 extern const CFCTestBatch CFCTEST_BATCH_UTIL;

http://git-wip-us.apache.org/repos/asf/lucy/blob/e47ccd4c/clownfish/compiler/src/CFCTestCBlock.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestCBlock.c 
b/clownfish/compiler/src/CFCTestCBlock.c
new file mode 100644
index 0000000..6061d44
--- /dev/null
+++ b/clownfish/compiler/src/CFCTestCBlock.c
@@ -0,0 +1,60 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define CFC_USE_TEST_MACROS
+#include "CFCBase.h"
+#include "CFCCBlock.h"
+#include "CFCParser.h"
+#include "CFCTest.h"
+
+static void
+S_run_tests(CFCTest *test);
+
+const CFCTestBatch CFCTEST_BATCH_C_BLOCK = {
+    "Clownfish::CFC::Model::CBlock",
+    4,
+    S_run_tests
+};
+
+static void
+S_run_tests(CFCTest *test) {
+    CFCParser *parser = CFCParser_new();
+
+    {
+        CFCCBlock *block = CFCCBlock_new("int foo;");
+        STR_EQ(test, CFCCBlock_get_contents(block), "int foo;",
+               "get_contents");
+        CFCBase_decref((CFCBase*)block);
+    }
+
+    {
+        const char *cblock_string =
+            " __C__\n"
+            "#define FOO_BAR 1\n"
+            "__END_C__  ";
+        CFCBase *result = CFCParser_parse(parser, cblock_string);
+        OK(test, result != NULL, "parse cblock");
+        STR_EQ(test, CFCBase_get_cfc_class(result),
+               "Clownfish::CFC::Model::CBlock", "result class of cblock");
+        CFCCBlock *block = (CFCCBlock*)result;
+        STR_EQ(test, CFCCBlock_get_contents(block), "#define FOO_BAR 1\n",
+               "parse embed_c");
+        CFCBase_decref((CFCBase*)block);
+    }
+
+    CFCBase_decref((CFCBase*)parser);
+}
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/e47ccd4c/clownfish/compiler/src/CFCTestFile.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestFile.c 
b/clownfish/compiler/src/CFCTestFile.c
new file mode 100644
index 0000000..dbd2c89
--- /dev/null
+++ b/clownfish/compiler/src/CFCTestFile.c
@@ -0,0 +1,126 @@
+/* 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.
+ */
+
+#include "charmony.h"
+
+#define CFC_USE_TEST_MACROS
+#include "CFCBase.h"
+#include "CFCClass.h"
+#include "CFCFile.h"
+#include "CFCFileSpec.h"
+#include "CFCParser.h"
+#include "CFCTest.h"
+#include "CFCType.h"
+#include "CFCVariable.h"
+
+static void
+S_run_tests(CFCTest *test);
+
+const CFCTestBatch CFCTEST_BATCH_FILE = {
+    "Clownfish::CFC::Model::File",
+    19,
+    S_run_tests
+};
+
+static void
+S_run_tests(CFCTest *test) {
+    CFCParser *parser = CFCParser_new();
+    CFCFileSpec *file_spec = CFCFileSpec_new(".", "Stuff/Thing", 0);
+
+    {
+        const char *string =
+            "parcel Stuff;\n"
+            "class Stuff::Thing {\n"
+            "    Foo *foo;\n"
+            "    Bar *bar;\n"
+            "}\n"
+            "__C__\n"
+            "int foo;\n"
+            "__END_C__\n";
+        CFCFile *file = CFCParser_parse_file(parser, string, file_spec);
+
+        STR_EQ(test, CFCFile_get_source_dir(file), ".", "get_source_dir");
+        STR_EQ(test, CFCFile_get_path_part(file), "Stuff/Thing",
+               "get_path_part");
+        OK(test, !CFCFile_included(file), "included");
+
+        STR_EQ(test, CFCFile_guard_name(file), "H_STUFF_THING", "guard_name");
+        STR_EQ(test, CFCFile_guard_start(file),
+               "#ifndef H_STUFF_THING\n#define H_STUFF_THING 1\n",
+               "guard_start");
+        STR_EQ(test, CFCFile_guard_close(file), "#endif /* H_STUFF_THING */\n",
+               "guard_close");
+
+        OK(test, !CFCFile_get_modified(file), "modified false at start");
+        CFCFile_set_modified(file, 1);
+        OK(test, CFCFile_get_modified(file), "set_modified, get_modified");
+
+#define PATH_TO_STUFF_THING \
+    "path" CHY_DIR_SEP \
+    "to" CHY_DIR_SEP \
+    "Stuff" CHY_DIR_SEP \
+    "Thing"
+
+        STR_EQ(test, CFCFile_cfh_path(file, "path/to"),
+               PATH_TO_STUFF_THING ".cfh", "cfh_path" );
+        STR_EQ(test, CFCFile_c_path(file, "path/to"),
+               PATH_TO_STUFF_THING ".c", "c_path" );
+        STR_EQ(test, CFCFile_h_path(file, "path/to"),
+               PATH_TO_STUFF_THING ".h", "h_path" );
+
+        CFCClass **classes = CFCFile_classes(file);
+        OK(test, classes[0] != NULL && classes[1] == NULL,
+           "classes() filters blocks");
+        CFCVariable **member_vars = CFCClass_member_vars(classes[0]);
+        CFCType *foo_type = CFCVariable_get_type(member_vars[0]);
+        STR_EQ(test, CFCType_get_specifier(foo_type), "stuff_Foo",
+               "file production picked up parcel def");
+        CFCType *bar_type = CFCVariable_get_type(member_vars[1]);
+        STR_EQ(test, CFCType_get_specifier(bar_type), "stuff_Bar",
+               "parcel def is sticky");
+
+        CFCBase **blocks = CFCFile_blocks(file);
+        STR_EQ(test, CFCBase_get_cfc_class(blocks[0]),
+               "Clownfish::CFC::Model::Parcel", "blocks[0]");
+        STR_EQ(test, CFCBase_get_cfc_class(blocks[1]),
+               "Clownfish::CFC::Model::Class", "blocks[1]");
+        STR_EQ(test, CFCBase_get_cfc_class(blocks[2]),
+               "Clownfish::CFC::Model::CBlock", "blocks[2]");
+        OK(test, blocks[3] == NULL, "blocks[3]");
+
+        CFCBase_decref((CFCBase*)file);
+    }
+
+    {
+        const char *string =
+            "class Stuff::Thing {\n"
+            "    Foo *foo;\n"
+            "    Bar *bar;\n"
+            "}\n";
+        CFCFile *file = CFCParser_parse_file(parser, string, file_spec);
+        CFCClass **classes = CFCFile_classes(file);
+        CFCVariable **member_vars = CFCClass_member_vars(classes[0]);
+        CFCType *foo_type = CFCVariable_get_type(member_vars[0]);
+        STR_EQ(test, CFCType_get_specifier(foo_type), "Foo",
+               "file production resets parcel");
+
+        CFCBase_decref((CFCBase*)file);
+    }
+
+    CFCBase_decref((CFCBase*)file_spec);
+    CFCBase_decref((CFCBase*)parser);
+}
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/e47ccd4c/clownfish/compiler/src/CFCTestHierarchy.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestHierarchy.c 
b/clownfish/compiler/src/CFCTestHierarchy.c
new file mode 100644
index 0000000..10bd4e2
--- /dev/null
+++ b/clownfish/compiler/src/CFCTestHierarchy.c
@@ -0,0 +1,141 @@
+/* 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.
+ */
+
+#include "charmony.h"
+
+#include <stdio.h>
+#include <string.h>
+
+/* For rmdir */
+#ifdef CHY_HAS_UNISTD_H
+  #include <unistd.h>
+#endif
+#ifdef CHY_HAS_DIRECT_H
+  #include <direct.h>
+#endif
+
+#define CFC_USE_TEST_MACROS
+#include "CFCBase.h"
+#include "CFCClass.h"
+#include "CFCFile.h"
+#include "CFCHierarchy.h"
+#include "CFCTest.h"
+#include "CFCUtil.h"
+
+static void
+S_run_tests(CFCTest *test);
+
+const CFCTestBatch CFCTEST_BATCH_HIERARCHY = {
+    "Clownfish::CFC::Model::Hierarchy",
+    20,
+    S_run_tests
+};
+
+static void
+S_run_tests(CFCTest *test) {
+#define T_CFSOURCE        "t" CHY_DIR_SEP "cfsource"
+#define T_CFDEST          "t" CHY_DIR_SEP "cfdest"
+#define T_CFDEST_INCLUDE  T_CFDEST CHY_DIR_SEP "include"
+#define T_CFDEST_SOURCE   T_CFDEST CHY_DIR_SEP "source"
+
+    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,
+           "get_include_dest");
+    STR_EQ(test, CFCHierarchy_get_source_dest(hierarchy), T_CFDEST_SOURCE,
+           "get_source_dest");
+
+    CFCHierarchy_add_source_dir(hierarchy, T_CFSOURCE);
+    const char **source_dirs = CFCHierarchy_get_source_dirs(hierarchy);
+    STR_EQ(test, source_dirs[0], T_CFSOURCE, "source_dirs[0]");
+    OK(test, source_dirs[1] == NULL, "source_dirs[1]");
+
+    CFCHierarchy_build(hierarchy);
+
+    CFCFile **files = CFCHierarchy_files(hierarchy);
+    CFCFile *animal;
+    CFCFile *dog;
+    CFCFile *util;
+    for (int i = 0; i < 3; ++i) {
+        CFCFile *file = files[i];
+        OK(test, file != NULL, "files[%d]", i);
+        OK(test, !CFCFile_get_modified(file), "start off not modified");
+
+        CFCBase **blocks = CFCFile_blocks(file);
+        for (int j = 0; blocks[j]; ++j) {
+            CFCBase *block = blocks[j];
+            const char *cfc_class_name = CFCBase_get_cfc_class(block);
+            if (strcmp(cfc_class_name, "Clownfish::CFC::Model::Class") == 0) {
+                CFCClass *klass = (CFCClass*)block;
+                const char *class_name = CFCClass_get_class_name(klass);
+                if (strcmp(class_name, "Animal") == 0) {
+                    animal = file;
+                }
+                else if (strcmp(class_name, "Animal::Dog") == 0) {
+                    dog = file;
+                }
+                else if (strcmp(class_name, "Animal::Util") == 0) {
+                    util = file;
+                }
+            }
+        }
+    }
+    OK(test, files[3] == NULL, "recursed and found all three files");
+
+    CFCClass **ordered_classes = CFCHierarchy_ordered_classes(hierarchy);
+    OK(test, ordered_classes[0] != NULL, "ordered_classes[0]");
+    OK(test, ordered_classes[1] != NULL, "ordered_classes[1]");
+    OK(test, ordered_classes[2] != NULL, "ordered_classes[2]");
+    OK(test, ordered_classes[3] == NULL, "all classes");
+
+    // Generate fake C files, with times set to two seconds ago.
+    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"
+    };
+    OK(test, CFCUtil_make_path(T_CFDEST_INCLUDE CHY_DIR_SEP "Animal"),
+       "make_path");
+    for (int i = 0; i < 3; ++i) {
+        const char *h_path  = h_paths[i];
+        const char *content = "#include <stdio.h>\n";
+        CFCUtil_write_file(h_path, content, strlen(content));
+        CFCTest_set_file_times(h_path, past_time);
+    }
+
+    CFCTest_set_file_times(CFCFile_cfh_path(animal, T_CFSOURCE), now);
+
+    CFCHierarchy_propagate_modified(hierarchy, 0);
+
+    OK(test, CFCFile_get_modified(animal), "Animal modified");
+    OK(test, CFCFile_get_modified(dog),
+       "Parent's modification propagates to child's file");
+    OK(test, !CFCFile_get_modified(util),
+       "Modification doesn't propagate to inert class");
+
+    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);
+
+    CFCBase_decref((CFCBase*)hierarchy);
+}
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/e47ccd4c/clownfish/compiler/src/CFCTestParcel.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestParcel.c 
b/clownfish/compiler/src/CFCTestParcel.c
new file mode 100644
index 0000000..c48d5d5
--- /dev/null
+++ b/clownfish/compiler/src/CFCTestParcel.c
@@ -0,0 +1,92 @@
+/* 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.
+ */
+
+#include "charmony.h"
+
+#define CFC_USE_TEST_MACROS
+#include "CFCBase.h"
+#include "CFCParcel.h"
+#include "CFCSymbol.h"
+#include "CFCVersion.h"
+#include "CFCTest.h"
+
+static void
+S_run_tests(CFCTest *test);
+
+const CFCTestBatch CFCTEST_BATCH_PARCEL = {
+    "Clownfish::CFC::Model::Parcel",
+    10,
+    S_run_tests
+};
+
+static void
+S_run_tests(CFCTest *test) {
+    {
+        CFCParcel *parcel = CFCParcel_new("Foo", NULL, NULL);
+        OK(test, parcel != NULL, "new");
+        CFCBase_decref((CFCBase*)parcel);
+    }
+
+    {
+        const char *json =
+            "        {\n"
+            "            \"name\": \"Crustacean\",\n"
+            "            \"nickname\": \"Crust\",\n"
+            "            \"version\": \"v0.1.0\"\n"
+            "        }\n";
+        CFCParcel *parcel = CFCParcel_new_from_json(json);
+        OK(test, parcel != NULL, "new_from_json");
+        CFCBase_decref((CFCBase*)parcel);
+    }
+
+    {
+        const char *path = "t" CHY_DIR_SEP "cfsource" CHY_DIR_SEP "Animal.cfp";
+        CFCParcel *parcel = CFCParcel_new_from_file(path);
+        OK(test, parcel != NULL, "new_from_file");
+        CFCBase_decref((CFCBase*)parcel);
+    }
+
+    {
+        CFCParcel *parcel = CFCParcel_default_parcel();
+        CFCSymbol *thing = CFCSymbol_new(parcel, "parcel", NULL, NULL, "sym");
+        STR_EQ(test, CFCSymbol_get_prefix(thing), "",
+               "get_prefix with no parcel");
+        STR_EQ(test, CFCSymbol_get_Prefix(thing), "",
+               "get_Prefix with no parcel");
+        STR_EQ(test, CFCSymbol_get_PREFIX(thing), "",
+               "get_PREFIX with no parcel");
+        CFCBase_decref((CFCBase*)thing);
+    }
+
+    {
+        CFCParcel *parcel = CFCParcel_new("Crustacean", "Crust", NULL);
+        CFCParcel_register(parcel);
+        STR_EQ(test, CFCVersion_get_vstring(CFCParcel_get_version(parcel)),
+               "v0", "get_version");
+
+        CFCSymbol *thing = CFCSymbol_new(parcel, "parcel", NULL, NULL, "sym");
+        STR_EQ(test, CFCSymbol_get_prefix(thing), "crust_",
+               "get_prefix with parcel");
+        STR_EQ(test, CFCSymbol_get_Prefix(thing), "Crust_",
+               "get_Prefix with parcel");
+        STR_EQ(test, CFCSymbol_get_PREFIX(thing), "CRUST_",
+               "get_PREFIX with parcel");
+
+        CFCBase_decref((CFCBase*)thing);
+        CFCBase_decref((CFCBase*)parcel);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/e47ccd4c/clownfish/compiler/src/CFCTestUtil.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestUtil.c 
b/clownfish/compiler/src/CFCTestUtil.c
index 27fbeec..f985d0d 100644
--- a/clownfish/compiler/src/CFCTestUtil.c
+++ b/clownfish/compiler/src/CFCTestUtil.c
@@ -14,12 +14,9 @@
  * limitations under the License.
  */
 
-#include <errno.h>
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 
 #define CFC_USE_TEST_MACROS
 #include "CFCUtil.h"
@@ -34,12 +31,6 @@ S_run_string_tests(CFCTest *test);
 static void
 S_run_file_tests(CFCTest *test);
 
-static time_t
-S_get_file_mtime(const char *path);
-
-static void
-S_set_file_times(const char *path, time_t time);
-
 const CFCTestBatch CFCTEST_BATCH_UTIL = {
     "Clownfish::CFC::Util",
     15,
@@ -109,15 +100,15 @@ S_run_file_tests(CFCTest *test) {
 
     {
         time_t past_time = time(NULL) - 10;
-        S_set_file_times(foo_txt, past_time);
-        past_time = S_get_file_mtime(foo_txt);
+        CFCTest_set_file_times(foo_txt, past_time);
+        past_time = CFCTest_get_file_mtime(foo_txt);
         time_t mtime;
         CFCUtil_write_if_changed(foo_txt, "foo", 3);
-        mtime = S_get_file_mtime(foo_txt);
+        mtime = CFCTest_get_file_mtime(foo_txt);
         OK(test, mtime == past_time,
            "write_if_changed does nothing if contents not changed");
         CFCUtil_write_if_changed(foo_txt, "foofoo", 6);
-        mtime = S_get_file_mtime(foo_txt);
+        mtime = CFCTest_get_file_mtime(foo_txt);
         OK(test, mtime != past_time,
            "write_if_changed writes if contents changed");
     }
@@ -125,53 +116,3 @@ S_run_file_tests(CFCTest *test) {
     remove(foo_txt);
 }
 
-static time_t
-S_get_file_mtime(const char *path) {
-    struct stat buf;
-    if (stat(path, &buf)) {
-        CFCUtil_die("Can't stat '%s': %s", path, strerror(errno));
-    }
-    return buf.st_mtime;
-}
-
-#if 1 || defined(HAS_UTIME_H)
-
-#include <utime.h>
-
-static void
-S_set_file_times(const char *path, time_t time) {
-    struct utimbuf buf;
-    buf.actime  = time;
-    buf.modtime = time;
-    if (utime(path, &buf)) {
-        CFCUtil_die("Can't set file time of '%s': %s", path, strerror(errno));
-    }
-}
-
-#elif defined(HAS_WINDOWS_H)
-
-#include <windows.h>
-
-static void
-S_set_file_times(const char *path, time_t time) {
-    HANDLE handle = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ, NULL,
-                               OPEN_EXISTING, 0, NULL);
-    if (handle == INVALID_HANDLE_VALUE) {
-        CFCUtil_die("Can't open '%s': %u", path, GetLastError());
-    }
-    uint64_t ticks = 10000000 * (UINT64_C(11644473600) + time);
-    FILETIME time;
-    time.dwLowDateTime  = (DWORD)ticks;
-    time.dwHighDateTime = (DWORD)(ticks >> 32);
-    if (!SetFileTime(handle, time, time, time)) {
-        CFCUtil_die("Can't set file time of '%s': %u", path, GetLastError());
-    }
-    CloseHandle(handle);
-}
-
-#else
-
-#error Need either utime.h or windows.h
-
-#endif
-

Reply via email to