• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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. */
getTestSuite()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 
addNamedTest(const char * name,TestCase * test)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. */
printFailures(int failures)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. */
runCurrentTest()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 
runTests()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 
assertTrueWithSource(int value,const char * file,int line,char * message)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