Sfoglia il codice sorgente

Moved test suites into custom linker section

This simplifies the interaction between code generation and the
test-runner.

In theory it also reduces compilation dependencies, but internal tests
make this difficult.
Christopher Haster 3 anni fa
parent
commit
4a42326797
3 ha cambiato i file con 96 aggiunte e 115 eliminazioni
  1. 68 61
      runners/test_runner.c
  2. 1 4
      runners/test_runner.h
  3. 27 50
      scripts/test.py

+ 68 - 61
runners/test_runner.c

@@ -7,6 +7,14 @@
 #include <errno.h>
 
 
+// test suites in a custom ld section
+extern struct test_suite __start__test_suites;
+extern struct test_suite __stop__test_suites;
+
+const struct test_suite *test_suites = &__start__test_suites;
+#define TEST_SUITE_COUNT \
+    ((size_t)(&__stop__test_suites - &__start__test_suites))
+
 // test geometries
 struct test_geometry {
     const char *name;
@@ -212,24 +220,24 @@ static void summary(void) {
     test_types_t types = 0;
     size_t perms = 0;
     size_t filtered = 0;
-    for (size_t i = 0; i < test_suite_count; i++) {
-        if (test_suite_skip(test_suites[i])) {
+    for (size_t i = 0; i < TEST_SUITE_COUNT; i++) {
+        if (test_suite_skip(&test_suites[i])) {
             continue;
         }
 
-        test_define_suite(test_suites[i]);
+        test_define_suite(&test_suites[i]);
 
-        for (size_t j = 0; j < test_suites[i]->case_count; j++) {
-            if (test_case_skip(test_suites[i]->cases[j])) {
+        for (size_t j = 0; j < test_suites[i].case_count; j++) {
+            if (test_case_skip(&test_suites[i].cases[j])) {
                 continue;
             }
 
-            test_case_permcount(test_suites[i], test_suites[i]->cases[j],
+            test_case_permcount(&test_suites[i], &test_suites[i].cases[j],
                     &perms, &filtered);
         }
 
-        cases += test_suites[i]->case_count;
-        types |= test_suites[i]->types;
+        cases += test_suites[i].case_count;
+        types |= test_suites[i].types;
     }
 
     char perm_buf[64];
@@ -241,28 +249,28 @@ static void summary(void) {
     printf("%-36s %7s %7zu %7zu %11s\n",
             "TOTAL",
             type_buf,
-            test_suite_count,
+            TEST_SUITE_COUNT,
             cases,
             perm_buf);
 }
 
 static void list_suites(void) {
     printf("%-36s %7s %7s %11s\n", "suite", "types", "cases", "perms");
-    for (size_t i = 0; i < test_suite_count; i++) {
-        if (test_suite_skip(test_suites[i])) {
+    for (size_t i = 0; i < TEST_SUITE_COUNT; i++) {
+        if (test_suite_skip(&test_suites[i])) {
             continue;
         }
 
-        test_define_suite(test_suites[i]);
+        test_define_suite(&test_suites[i]);
 
         size_t perms = 0;
         size_t filtered = 0;
-        for (size_t j = 0; j < test_suites[i]->case_count; j++) {
-            if (test_case_skip(test_suites[i]->cases[j])) {
+        for (size_t j = 0; j < test_suites[i].case_count; j++) {
+            if (test_case_skip(&test_suites[i].cases[j])) {
                 continue;
             }
 
-            test_case_permcount(test_suites[i], test_suites[i]->cases[j],
+            test_case_permcount(&test_suites[i], &test_suites[i].cases[j],
                     &perms, &filtered);
         }
 
@@ -270,35 +278,35 @@ static void list_suites(void) {
         sprintf(perm_buf, "%zu/%zu", filtered, perms);
         char type_buf[64];
         sprintf(type_buf, "%s%s",
-                (test_suites[i]->types & TEST_NORMAL)    ? "n" : "",
-                (test_suites[i]->types & TEST_REENTRANT) ? "r" : "");
+                (test_suites[i].types & TEST_NORMAL)    ? "n" : "",
+                (test_suites[i].types & TEST_REENTRANT) ? "r" : "");
         printf("%-36s %7s %7zu %11s\n",
-                test_suites[i]->id,
+                test_suites[i].id,
                 type_buf,
-                test_suites[i]->case_count,
+                test_suites[i].case_count,
                 perm_buf);
     }
 }
 
 static void list_cases(void) {
     printf("%-36s %7s %11s\n", "case", "types", "perms");
-    for (size_t i = 0; i < test_suite_count; i++) {
-        if (test_suite_skip(test_suites[i])) {
+    for (size_t i = 0; i < TEST_SUITE_COUNT; i++) {
+        if (test_suite_skip(&test_suites[i])) {
             continue;
         }
 
-        test_define_suite(test_suites[i]);
+        test_define_suite(&test_suites[i]);
 
-        for (size_t j = 0; j < test_suites[i]->case_count; j++) {
-            if (test_case_skip(test_suites[i]->cases[j])) {
+        for (size_t j = 0; j < test_suites[i].case_count; j++) {
+            if (test_case_skip(&test_suites[i].cases[j])) {
                 continue;
             }
 
             size_t perms = 0;
             size_t filtered = 0;
-            test_case_permcount(test_suites[i], test_suites[i]->cases[j],
+            test_case_permcount(&test_suites[i], &test_suites[i].cases[j],
                     &perms, &filtered);
-            test_types_t types = test_suites[i]->cases[j]->types;
+            test_types_t types = test_suites[i].cases[j].types;
 
             char perm_buf[64];
             sprintf(perm_buf, "%zu/%zu", filtered, perms);
@@ -307,7 +315,7 @@ static void list_cases(void) {
                     (types & TEST_NORMAL)    ? "n" : "",
                     (types & TEST_REENTRANT) ? "r" : "");
             printf("%-36s %7s %11s\n",
-                    test_suites[i]->cases[j]->id,
+                    test_suites[i].cases[j].id,
                     type_buf,
                     perm_buf);
         }
@@ -315,39 +323,39 @@ static void list_cases(void) {
 }
 
 static void list_paths(void) {
-    for (size_t i = 0; i < test_suite_count; i++) {
-        if (test_suite_skip(test_suites[i])) {
+    for (size_t i = 0; i < TEST_SUITE_COUNT; i++) {
+        if (test_suite_skip(&test_suites[i])) {
             continue;
         }
 
-        for (size_t j = 0; j < test_suites[i]->case_count; j++) {
-            if (test_case_skip(test_suites[i]->cases[j])) {
+        for (size_t j = 0; j < test_suites[i].case_count; j++) {
+            if (test_case_skip(&test_suites[i].cases[j])) {
                 continue;
             }
 
             printf("%-36s %-36s\n",
-                    test_suites[i]->cases[j]->id,
-                    test_suites[i]->cases[j]->path);
+                    test_suites[i].cases[j].id,
+                    test_suites[i].cases[j].path);
         }
     }
 }
 
 static void list_defines(void) {
-    for (size_t i = 0; i < test_suite_count; i++) {
-        if (test_suite_skip(test_suites[i])) {
+    for (size_t i = 0; i < TEST_SUITE_COUNT; i++) {
+        if (test_suite_skip(&test_suites[i])) {
             continue;
         }
 
-        test_define_suite(test_suites[i]);
+        test_define_suite(&test_suites[i]);
 
-        for (size_t j = 0; j < test_suites[i]->case_count; j++) {
-            if (test_case_skip(test_suites[i]->cases[j])) {
+        for (size_t j = 0; j < test_suites[i].case_count; j++) {
+            if (test_case_skip(&test_suites[i].cases[j])) {
                 continue;
             }
 
             for (size_t perm = 0;
                     perm < TEST_GEOMETRY_COUNT
-                        * test_suites[i]->cases[j]->permutations;
+                        * test_suites[i].cases[j].permutations;
                     perm++) {
                 if (test_perm_skip(perm)) {
                     continue;
@@ -356,25 +364,24 @@ static void list_defines(void) {
                 // setup defines
                 size_t case_perm = perm / TEST_GEOMETRY_COUNT;
                 size_t geom_perm = perm % TEST_GEOMETRY_COUNT;
-                test_define_perm(test_suites[i],
-                        test_suites[i]->cases[j], case_perm);
+                test_define_perm(&test_suites[i],
+                        &test_suites[i].cases[j], case_perm);
                 test_define_geometry(&test_geometries[geom_perm]);
 
                 // print the case
                 char id_buf[256];
-                sprintf(id_buf, "%s#%zu", test_suites[i]->cases[j]->id, perm);
+                sprintf(id_buf, "%s#%zu", test_suites[i].cases[j].id, perm);
                 printf("%-36s ", id_buf);
 
                 // special case for the current geometry
                 printf("GEOMETRY=%s ", test_geometries[geom_perm].name);
 
                 // print each define
-                for (size_t k = 0; k < test_suites[i]->define_count; k++) {
-                    if (test_suites[i]->cases[j]->defines
-                            && test_suites[i]->cases[j]
-                                ->defines[case_perm][k]) {
+                for (size_t k = 0; k < test_suites[i].define_count; k++) {
+                    if (test_suites[i].cases[j].defines
+                            && test_suites[i].cases[j].defines[case_perm][k]) {
                         printf("%s=%jd ",
-                                test_suites[i]->define_names[k],
+                                test_suites[i].define_names[k],
                                 test_define(k));
                     }
                 }
@@ -419,21 +426,21 @@ static void list_defaults(void) {
 
 static void run(void) {
     size_t step = 0;
-    for (size_t i = 0; i < test_suite_count; i++) {
-        if (test_suite_skip(test_suites[i])) {
+    for (size_t i = 0; i < TEST_SUITE_COUNT; i++) {
+        if (test_suite_skip(&test_suites[i])) {
             continue;
         }
 
-        test_define_suite(test_suites[i]);
+        test_define_suite(&test_suites[i]);
 
-        for (size_t j = 0; j < test_suites[i]->case_count; j++) {
-            if (test_case_skip(test_suites[i]->cases[j])) {
+        for (size_t j = 0; j < test_suites[i].case_count; j++) {
+            if (test_case_skip(&test_suites[i].cases[j])) {
                 continue;
             }
 
             for (size_t perm = 0;
                     perm < TEST_GEOMETRY_COUNT
-                        * test_suites[i]->cases[j]->permutations;
+                        * test_suites[i].cases[j].permutations;
                     perm++) {
                 if (test_perm_skip(perm)) {
                     continue;
@@ -447,15 +454,15 @@ static void run(void) {
                 // setup defines
                 size_t case_perm = perm / TEST_GEOMETRY_COUNT;
                 size_t geom_perm = perm % TEST_GEOMETRY_COUNT;
-                test_define_perm(test_suites[i],
-                        test_suites[i]->cases[j], case_perm);
+                test_define_perm(&test_suites[i],
+                        &test_suites[i].cases[j], case_perm);
                 test_define_geometry(&test_geometries[geom_perm]);
 
                 // filter?
-                if (test_suites[i]->cases[j]->filter) {
-                    if (!test_suites[i]->cases[j]->filter()) {
+                if (test_suites[i].cases[j].filter) {
+                    if (!test_suites[i].cases[j].filter()) {
                         printf("skipped %s#%zu\n",
-                                test_suites[i]->cases[j]->id,
+                                test_suites[i].cases[j].id,
                                 perm);
                         continue;
                     }
@@ -494,11 +501,11 @@ static void run(void) {
                 }
 
                 // run the test
-                printf("running %s#%zu\n", test_suites[i]->cases[j]->id, perm);
+                printf("running %s#%zu\n", test_suites[i].cases[j].id, perm);
 
-                test_suites[i]->cases[j]->run(&cfg);
+                test_suites[i].cases[j].run(&cfg);
 
-                printf("finished %s#%zu\n", test_suites[i]->cases[j]->id, perm);
+                printf("finished %s#%zu\n", test_suites[i].cases[j].id, perm);
 
                 // cleanup
                 err = lfs_testbd_destroy(&cfg);

+ 1 - 4
runners/test_runner.h

@@ -34,13 +34,10 @@ struct test_suite {
     const char *const *define_names;
     size_t define_count;
 
-    const struct test_case *const *cases;
+    const struct test_case *cases;
     size_t case_count;
 };
 
-extern const struct test_suite *test_suites[];
-extern const size_t test_suite_count;
-
 
 // access generated test defines
 intmax_t test_predefine(size_t define);

+ 27 - 50
scripts/test.py

@@ -342,8 +342,8 @@ def compile(**args):
                         f.writeln('#endif')
                     f.writeln()
 
+                # create case functions
                 for case in suite.cases:
-                    # create case functions
                     if case.in_ is None:
                         write_case_functions(f, suite, case)
                     else:
@@ -360,39 +360,8 @@ def compile(**args):
                             % (suite.name, case.name))
                         f.writeln()
 
-                    # create case struct
-                    f.writeln('const struct test_case __test__%s__%s__case = {'
-                        % (suite.name, case.name))
-                    f.writeln(4*' '+'.id = "%s",' % case.id())
-                    f.writeln(4*' '+'.name = "%s",' % case.name)
-                    f.writeln(4*' '+'.path = "%s",' % case.path)
-                    f.writeln(4*' '+'.types = %s,'
-                        % ' | '.join(filter(None, [
-                            'TEST_NORMAL' if case.normal else None,
-                            'TEST_REENTRANT' if case.reentrant else None])))
-                    f.writeln(4*' '+'.permutations = %d,'
-                        % len(case.permutations))
-                    if case.defines:
-                        f.writeln(4*' '+'.defines = __test__%s__%s__defines,'
-                            % (suite.name, case.name))
-                    if suite.if_ is not None or case.if_ is not None:
-                        f.writeln(4*' '+'.filter = __test__%s__%s__filter,'
-                            % (suite.name, case.name))
-                    f.writeln(4*' '+'.run = __test__%s__%s__run,'
-                        % (suite.name, case.name))
-                    f.writeln('};')
-                    f.writeln()
-
-                # create suite define names
-                if suite.defines:
-                    f.writeln('const char *const __test__%s__define_names[] = {'
-                        % suite.name)
-                    for k in sorted(suite.defines):
-                        f.writeln(4*' '+'"%s",' % k)
-                    f.writeln('};')
-                    f.writeln()
-
                 # create suite struct
+                f.writeln('__attribute__((section("_test_suites")))')
                 f.writeln('const struct test_suite __test__%s__suite = {'
                     % suite.name)
                 f.writeln(4*' '+'.id = "%s",' % suite.id())
@@ -403,13 +372,34 @@ def compile(**args):
                         'TEST_NORMAL' if suite.normal else None,
                         'TEST_REENTRANT' if suite.reentrant else None])))
                 if suite.defines:
-                    f.writeln(4*' '+'.define_names = __test__%s__define_names,'
-                        % suite.name)
+                    # create suite define names
+                    f.writeln(4*' '+'.define_names = (const char *const[]){')
+                    for k in sorted(suite.defines):
+                        f.writeln(8*' '+'"%s",' % k)
+                    f.writeln(4*' '+'},')
                 f.writeln(4*' '+'.define_count = %d,' % len(suite.defines))
-                f.writeln(4*' '+'.cases = (const struct test_case *const []){')
+                f.writeln(4*' '+'.cases = (const struct test_case[]){')
                 for case in suite.cases:
-                    f.writeln(8*' '+'&__test__%s__%s__case,'
+                    # create case structs
+                    f.writeln(8*' '+'{')
+                    f.writeln(12*' '+'.id = "%s",' % case.id())
+                    f.writeln(12*' '+'.name = "%s",' % case.name)
+                    f.writeln(12*' '+'.path = "%s",' % case.path)
+                    f.writeln(12*' '+'.types = %s,'
+                        % ' | '.join(filter(None, [
+                            'TEST_NORMAL' if case.normal else None,
+                            'TEST_REENTRANT' if case.reentrant else None])))
+                    f.writeln(12*' '+'.permutations = %d,'
+                        % len(case.permutations))
+                    if case.defines:
+                        f.writeln(12*' '+'.defines = __test__%s__%s__defines,'
+                            % (suite.name, case.name))
+                    if suite.if_ is not None or case.if_ is not None:
+                        f.writeln(12*' '+'.filter = __test__%s__%s__filter,'
+                            % (suite.name, case.name))
+                    f.writeln(12*' '+'.run = __test__%s__%s__run,'
                         % (suite.name, case.name))
+                    f.writeln(8*' '+'},')
                 f.writeln(4*' '+'},')
                 f.writeln(4*' '+'.case_count = %d,' % len(suite.cases))
                 f.writeln('};')
@@ -456,19 +446,6 @@ def compile(**args):
                                     f.writeln('#endif')
                                 f.writeln()
 
-                # add suite info to test_runner.c
-                if args['source'] == 'runners/test_runner.c':
-                    f.writeln()
-                    for suite in suites:
-                        f.writeln('extern const struct test_suite '
-                            '__test__%s__suite;' % suite.name)
-                    f.writeln('const struct test_suite *test_suites[] = {')
-                    for suite in suites:
-                        f.writeln(4*' '+'&__test__%s__suite,' % suite.name)
-                    f.writeln('};')
-                    f.writeln('const size_t test_suite_count = %d;'
-                        % len(suites))
-
 def runner(**args):
     cmd = args['runner'].copy()
     cmd.extend(args.get('test_ids'))