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