1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <assert.h> 18 #include <stdlib.h> 19 #include <stdio.h> 20 #include <sys/types.h> 21 #include <sys/wait.h> 22 #include <unistd.h> 23 #include <ctest/ctest.h> 24 25 #define MAX_TESTS 255 26 27 /** Semi-random number used to identify assertion errors. */ 28 #define ASSERTION_ERROR 42 29 30 typedef void TestCase(); 31 32 /** A suite of tests. */ 33 typedef struct { 34 int size; 35 const char* testNames[MAX_TESTS]; 36 TestCase* tests[MAX_TESTS]; 37 int currentTest; 38 FILE* out; 39 } TestSuite; 40 41 /** Gets the test suite. Creates it if necessary. */ 42 static TestSuite* getTestSuite() { 43 static TestSuite* suite = NULL; 44 45 if (suite != NULL) { 46 return suite; 47 } 48 49 suite = calloc(1, sizeof(TestSuite)); 50 assert(suite != NULL); 51 52 suite->out = tmpfile(); 53 assert(suite->out != NULL); 54 55 return suite; 56 } 57 58 void addNamedTest(const char* name, TestCase* test) { 59 TestSuite* testSuite = getTestSuite(); 60 assert(testSuite->size <= MAX_TESTS); 61 62 int index = testSuite->size; 63 testSuite->testNames[index] = name; 64 testSuite->tests[index] = test; 65 66 testSuite->size++; 67 } 68 69 /** Prints failures to stderr. */ 70 static void printFailures(int failures) { 71 TestSuite* suite = getTestSuite(); 72 73 fprintf(stderr, "FAILURE! %d of %d tests failed. Failures:\n", 74 failures, suite->size); 75 76 // Copy test output to stdout. 77 rewind(suite->out); 78 char buffer[512]; 79 size_t read; 80 while ((read = fread(buffer, sizeof(char), 512, suite->out)) > 0) { 81 // TODO: Make sure we actually wrote 'read' bytes. 82 fwrite(buffer, sizeof(char), read, stderr); 83 } 84 } 85 86 /** Runs a single test case. */ 87 static int runCurrentTest() { 88 TestSuite* suite = getTestSuite(); 89 90 pid_t pid = fork(); 91 if (pid == 0) { 92 // Child process. Runs test case. 93 suite->tests[suite->currentTest](); 94 95 // Exit successfully. 96 exit(0); 97 } else if (pid < 0) { 98 fprintf(stderr, "Fork failed."); 99 exit(1); 100 } else { 101 // Parent process. Wait for child. 102 int status; 103 waitpid(pid, &status, 0); 104 105 if (!WIFEXITED(status)) { 106 return -1; 107 } 108 109 return WEXITSTATUS(status); 110 } 111 } 112 113 void runTests() { 114 TestSuite* suite = getTestSuite(); 115 116 int failures = 0; 117 for (suite->currentTest = 0; suite->currentTest < suite->size; 118 suite->currentTest++) { 119 // Flush stdout before forking. 120 fflush(stdout); 121 122 int result = runCurrentTest(); 123 124 if (result != 0) { 125 printf("X"); 126 127 failures++; 128 129 // Handle errors other than assertions. 130 if (result != ASSERTION_ERROR) { 131 // TODO: Report file name. 132 fprintf(suite->out, "Process failed: [%s] status: %d\n", 133 suite->testNames[suite->currentTest], result); 134 fflush(suite->out); 135 } 136 } else { 137 printf("."); 138 } 139 } 140 141 printf("\n"); 142 143 if (failures > 0) { 144 printFailures(failures); 145 } else { 146 printf("SUCCESS! %d tests ran successfully.\n", suite->size); 147 } 148 } 149 150 void assertTrueWithSource(int value, const char* file, int line, char* message) { 151 if (!value) { 152 TestSuite* suite = getTestSuite(); 153 154 fprintf(suite->out, "Assertion failed: [%s:%d] %s: %s\n", file, line, 155 suite->testNames[suite->currentTest], message); 156 fflush(suite->out); 157 158 // Exit the process for this test case. 159 exit(ASSERTION_ERROR); 160 } 161 } 162