#!/usr/bin/env perl # # 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. # # # generate-test-runner.pl # # Generates a test runner for the .c files given on the command line. Each .c # file may declare any number of tests so long as each test uses CUnit and is # declared with the following convention: # # void test_SUITENAME__TESTNAME() { # ... # } # # where TESTNAME is the arbitrary name of the test and SUITENAME is the # arbitrary name of the test suite that this test belongs to. # # Absolutely all tests MUST follow the above convention if they are to be # picked up by this script. Functions which are not tests MUST NOT follow # the above convention. # use strict; my $num_tests = 0; my %test_suites = (); # Parse all test declarations from given file while (<>) { if ((my $suite_name, my $test_name) = m/^void\s+test_(\w+)__(\w+)/) { $num_tests++; $test_suites{$suite_name} //= (); push @{$test_suites{$suite_name}}, $test_name; } } # Bail out if there's nothing to write if ($num_tests == 0) { die "No unit tests... :(\n"; } # # Common test runner header # print <<'END'; /* * 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 #include /** * The current test number, as required by the TAP format. This value is * automatically incremented by tap_log_test_completed() after each test is * run. */ int tap_test_number = 1; /** * Logs the status of a CUnit test which just completed. This implementation * logs test completion in TAP format. * * @param test * The CUnit test which just completed. * * @param suite * The CUnit test suite associated with the test. * * @param failure * The head element of the test failure list, or NULL if the test passed. */ static void tap_log_test_completed(const CU_pTest test, const CU_pSuite suite, const CU_pFailureRecord failure) { /* Log success/failure in TAP format */ if (failure == NULL) printf("ok %i - [%s] %s: OK\n", tap_test_number, suite->pName, test->pName); else printf("not ok %i - [%s] %s: Assertion failed on %s:%i: %s\n", tap_test_number, suite->pName, test->pName, failure->strFileName, failure->uiLineNumber, failure->strCondition); tap_test_number++; } END # # Prototypes for all test functions # while ((my $suite_name, my $test_names) = each (%test_suites)) { print "\n/* Automatically-generated prototypes for the $suite_name suite */\n"; foreach my $test_name (@{ $test_names }) { print "void test_${suite_name}__${test_name}();\n"; } } # # Beginning of main() function body for test runner # print <<"END"; /* Automatically-generated test runner */ int main() { /* Init CUnit test registry */ if (CU_initialize_registry() != CUE_SUCCESS) return CU_get_error(); END # # Within main(), register each test and its corresponding test suite # while ((my $suite_name, my $test_names) = each (%test_suites)) { print <<" END"; /* Create and register all tests for the $suite_name suite */ CU_pSuite $suite_name = CU_add_suite("$suite_name", NULL, NULL); if ($suite_name == NULL END foreach my $test_name (@{ $test_names }) { print <<" END"; || CU_add_test($suite_name, "$test_name", test_${suite_name}__${test_name}) == NULL END } print <<" END"; ) goto cleanup; END } # # End of main() function # print <<"END"; /* Force line-buffered output to ensure log messages are visible even if * a test crashes */ setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(stderr, NULL, _IOLBF, 0); /* Write TAP header */ printf("1..$num_tests\\n"); /* Run all tests in all suites */ CU_set_test_complete_handler(tap_log_test_completed); CU_run_all_tests(); cleanup: /* Tests complete */ CU_cleanup_registry(); return CU_get_error(); } END