| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 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 | } |