generate-test-runner.pl (5458B)
1#!/usr/bin/env perl 2# 3# Licensed to the Apache Software Foundation (ASF) under one 4# or more contributor license agreements. See the NOTICE file 5# distributed with this work for additional information 6# regarding copyright ownership. The ASF licenses this file 7# to you under the Apache License, Version 2.0 (the 8# "License"); you may not use this file except in compliance 9# with the License. You may obtain a copy of the License at 10# 11# http://www.apache.org/licenses/LICENSE-2.0 12# 13# Unless required by applicable law or agreed to in writing, 14# software distributed under the License is distributed on an 15# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16# KIND, either express or implied. See the License for the 17# specific language governing permissions and limitations 18# under the License. 19# 20 21# 22# generate-test-runner.pl 23# 24# Generates a test runner for the .c files given on the command line. Each .c 25# file may declare any number of tests so long as each test uses CUnit and is 26# declared with the following convention: 27# 28# void test_SUITENAME__TESTNAME() { 29# ... 30# } 31# 32# where TESTNAME is the arbitrary name of the test and SUITENAME is the 33# arbitrary name of the test suite that this test belongs to. 34# 35# Absolutely all tests MUST follow the above convention if they are to be 36# picked up by this script. Functions which are not tests MUST NOT follow 37# the above convention. 38# 39 40use strict; 41 42my $num_tests = 0; 43my %test_suites = (); 44 45# Parse all test declarations from given file 46while (<>) { 47 if ((my $suite_name, my $test_name) = m/^void\s+test_(\w+)__(\w+)/) { 48 $num_tests++; 49 $test_suites{$suite_name} //= (); 50 push @{$test_suites{$suite_name}}, $test_name; 51 } 52} 53 54# Bail out if there's nothing to write 55if ($num_tests == 0) { 56 die "No unit tests... :(\n"; 57} 58 59# 60# Common test runner header 61# 62 63print <<'END'; 64/* 65 * Licensed to the Apache Software Foundation (ASF) under one 66 * or more contributor license agreements. See the NOTICE file 67 * distributed with this work for additional information 68 * regarding copyright ownership. The ASF licenses this file 69 * to you under the Apache License, Version 2.0 (the 70 * "License"); you may not use this file except in compliance 71 * with the License. You may obtain a copy of the License at 72 * 73 * http://www.apache.org/licenses/LICENSE-2.0 74 * 75 * Unless required by applicable law or agreed to in writing, 76 * software distributed under the License is distributed on an 77 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 78 * KIND, either express or implied. See the License for the 79 * specific language governing permissions and limitations 80 * under the License. 81 */ 82 83#include <stdlib.h> 84#include <CUnit/TestRun.h> 85 86/** 87 * The current test number, as required by the TAP format. This value is 88 * automatically incremented by tap_log_test_completed() after each test is 89 * run. 90 */ 91int tap_test_number = 1; 92 93/** 94 * Logs the status of a CUnit test which just completed. This implementation 95 * logs test completion in TAP format. 96 * 97 * @param test 98 * The CUnit test which just completed. 99 * 100 * @param suite 101 * The CUnit test suite associated with the test. 102 * 103 * @param failure 104 * The head element of the test failure list, or NULL if the test passed. 105 */ 106static void tap_log_test_completed(const CU_pTest test, 107 const CU_pSuite suite, const CU_pFailureRecord failure) { 108 109 /* Log success/failure in TAP format */ 110 if (failure == NULL) 111 printf("ok %i - [%s] %s: OK\n", 112 tap_test_number, suite->pName, test->pName); 113 else 114 printf("not ok %i - [%s] %s: Assertion failed on %s:%i: %s\n", 115 tap_test_number, suite->pName, test->pName, 116 failure->strFileName, failure->uiLineNumber, 117 failure->strCondition); 118 119 tap_test_number++; 120 121} 122END 123 124# 125# Prototypes for all test functions 126# 127 128while ((my $suite_name, my $test_names) = each (%test_suites)) { 129 print "\n/* Automatically-generated prototypes for the $suite_name suite */\n"; 130 foreach my $test_name (@{ $test_names }) { 131 print "void test_${suite_name}__${test_name}();\n"; 132 } 133} 134 135# 136# Beginning of main() function body for test runner 137# 138 139print <<"END"; 140 141/* Automatically-generated test runner */ 142int main() { 143 144 /* Init CUnit test registry */ 145 if (CU_initialize_registry() != CUE_SUCCESS) 146 return CU_get_error(); 147END 148 149# 150# Within main(), register each test and its corresponding test suite 151# 152 153while ((my $suite_name, my $test_names) = each (%test_suites)) { 154 155 print <<" END"; 156 157 /* Create and register all tests for the $suite_name suite */ 158 CU_pSuite $suite_name = CU_add_suite("$suite_name", NULL, NULL); 159 if ($suite_name == NULL 160 END 161 162 foreach my $test_name (@{ $test_names }) { 163 print <<" END"; 164 || CU_add_test($suite_name, "$test_name", test_${suite_name}__${test_name}) == NULL 165 END 166 } 167 168 print <<" END"; 169 ) goto cleanup; 170 END 171 172} 173 174# 175# End of main() function 176# 177 178print <<"END"; 179 180 /* Force line-buffered output to ensure log messages are visible even if 181 * a test crashes */ 182 setvbuf(stdout, NULL, _IOLBF, 0); 183 setvbuf(stderr, NULL, _IOLBF, 0); 184 185 /* Write TAP header */ 186 printf("1..$num_tests\\n"); 187 188 /* Run all tests in all suites */ 189 CU_set_test_complete_handler(tap_log_test_completed); 190 CU_run_all_tests(); 191 192cleanup: 193 /* Tests complete */ 194 CU_cleanup_registry(); 195 return CU_get_error(); 196 197} 198END 199