Browse files

[6model/c] many small build and testing changes

  • Loading branch information...
1 parent d50b8cb commit 816dda0e81c28a9126806e576125df4f00934694 @mberends mberends committed Aug 21, 2011
View
6 c/t/01-toolchain/01a-cc.c → c/t/01-toolchain/01a-cc.t.c
@@ -181,7 +181,11 @@ create_lib()
#else
status = system("gcc -c -fPIC -o testlib.o testlib.c"); /* Unix */
if (status==0) {
- status = system("cc -shared -s -o testlib.so testlib.o");
+ #if defined( __APPLE__ )
+ status = system("cc -shared -o testlib.so testlib.o");
+ #else
+ status = system("cc -shared -s -o testlib.so testlib.o");
+ #endif
}
if (status==0) {
status = system("rm testlib.o");
View
10 c/t/01-toolchain/01b-timing.c → c/t/01-toolchain/01b-timing.t.c
@@ -1,5 +1,9 @@
/* 01b-timing.c */
+/* TODO: try these functions on Win32 for better precision: */
+/* _ftime usleep QueryPerformanceCounter QueryPerformanceFrequency */
+
+
#include <stdio.h> /* sprintf */
#ifdef _WIN32
#include <windows.h>
@@ -18,13 +22,13 @@ seconds_microseconds_sleep()
int microseconds1, microseconds2, microseconds3, microseconds4, microseconds5;
char message[80];
- /* Read the clock twice in quick succession, sleep for 1 second, */
- /* then read the clock a third time. Report the differences */
- /* between the times and verify that the sleep was about 1 sec. */
+ /* Read the clock multiple times with various delays in between. */
+ /* Check that the time differences are within reason */
#ifdef _WIN32
FILETIME time1, time2, time3, time4, time5;
GetSystemTimeAsFileTime(&time1); /* * 100ns since 1601-01-01 */
GetSystemTimeAsFileTime(&time2);
+ _ftime(); // TODO
Sleep(0); /* 0 milliseconds */
GetSystemTimeAsFileTime(&time3);
Sleep(1); /* 1 millisecond */
View
0 c/t/01-toolchain/01c-osthreads.c → c/t/01-toolchain/01c-osthreads.t.c
File renamed without changes.
View
0 c/t/02-components/02a-threads.c → c/t/02-components/02a-threads.t.c
File renamed without changes.
View
0 c/t/02-components/02b-hashtable.c → c/t/02-components/02b-hashtable.t.c
File renamed without changes.
View
23 c/t/Test.h
@@ -35,27 +35,40 @@ int _test_number=0; /* yes, namespace pollution. patches welcome ;-) */
#define \
ok(flag,desc) \
printf("%sok %d - %s\n", \
- flag?"":"not ",++_test_number,desc)
+ flag?"":"not ",++_test_number,desc); \
+ fflush(stdout)
#define \
is_ii(got,expected,desc) \
printf("%sok %d - %s\n", \
got==expected?"":"not ",++_test_number,desc); \
if(got!=expected) \
- printf("# got : %d\n# expected : %d\n", got, expected)
+ printf("# got : %d\n# expected : %d\n", got, expected); \
+ fflush(stdout)
+
+#define \
+is_ll(got,expected,desc) \
+ printf("%sok %d - %s\n", \
+ got==expected?"":"not ",++_test_number,desc); \
+ if(got!=expected) \
+ printf("# got : %ld\n# expected : %ld\n", got, expected); \
+ fflush(stdout)
#define \
is_ss(got,expected,desc) \
printf("%sok %d - %s\n", \
- strcmp(got,expected)?"not ":"",++_test_number,desc)
+ strcmp(got,expected)?"not ":"",++_test_number,desc); \
+ fflush(stdout)
#define \
isnt_pp(got,expected,desc) \
printf("%sok %d - %s\n", \
- (got!=expected)?"":"not ", ++_test_number, desc)
+ (got!=expected)?"":"not ", ++_test_number, desc); \
+ fflush(stdout)
#define \
diag(message) \
- printf("# %s\n", message)
+ printf("# %s\n", message); \
+ fflush(stdout)
/* end of Test.h */
View
39 c/tools/build/Configure.c
@@ -1,27 +1,28 @@
/* Configure.c */
-/* Compiled and run by 6model/c/Configure.(sh|bat) */
+/* Compiled and run by 6model/c/Configure.{sh,bat} */
/* This program (Configure) uses environment variables and C macros */
/* to autodetect the operating system, compiler and other utilities */
/* that can be used to build your software. It then creates your */
-/* Makefile based on a template (Makefile.in). To work also with */
-/* non-GNU systems such as Microsoft Visual C++, it follows the */
-/* style of Automake and Autoconf, but is written in only C and does */
-/* not rely on other tools such as M4. */
-
-/* This work will never be finished. Reliable autodetection is hard. */
-/* There are always newer environments and tools to try out. */
-/* Systems usually predefine some variables and macros. Users might */
-/* make the same definitions. */
-
-/* Currently works with:
+/* Makefile based on a template (Makefile.in). To also work with */
+/* non-GNU systems such as Microsoft C/C++, it follows the style of */
+/* Automake and Autoconf, but is written only in C and does not rely */
+/* on other tools such as M4. */
+
+/* This work will never be complete, because autodetection is hard. */
+/* New software emerges, environments and tools evolve, users make */
+/* unforeseen choices. Monitor the changes through regular testing. */
+
+/* Currently verified to work with:
+ * GNU C compiler on Linux, OS X and Windows (as MinGW).
+ *
* MinGW
* http://mingw.org/
* Currently based on GCC 4.5.2, 85MB disk.
* Targets Win32 libraries, no Posix emulation or dlopen.
* (older version bundled with Git full install)
- * Microsoft Visual C++ Express Edition 1-2GB RAM, 3GB disk
+ * Microsoft Visual C++ Express Edition 1-2GB RAM
* Registration required to avoid de-activation after 30 days. Downloads a 3.2MB web installer.
* http://www.microsoft.com/express/vc/ do not need optional SQL express.
* Also installs Windows Installer 4.5, .NET Framework 4, SQL Server Compact 3.5, Help Viewer 1.0
@@ -66,7 +67,7 @@ void
detection(void)
{
int processors = 0;
- #if defined( _WIN32 )
+ #if defined( _WIN32 ) && ! defined( _OPENMP )
SYSTEM_INFO sysinfo; /* declare up here because MSC hates it lower */
#endif
printf("Configure detects the following:\n");
@@ -224,7 +225,7 @@ makefile_convert(char * programfilename, char * templatefilename,
trans(&makefiletext, "t/02-components", "t\\02-components");
#endif
#if defined( _MSC_VER )
- trans(&makefiletext, "$(O) ", "$(O)");
+ trans(&makefiletext, "$(OUTFILE) ", "$(OUTFILE)");
#endif
printf(" %s: writing to %s\n", programfilename, outputfilename);
squirt(makefiletext, outputfilename);
@@ -341,16 +342,16 @@ main(int argc, char * argv[])
/*
* TODO
-
- * Explore more Win32 C compilers and toolchains
+ *
+ * Explore more C compilers and toolchains
* http://www.thefreecountry.com/compilers/cpp.shtml
* lcc-win32 http://www.cs.virginia.edu/~lcc-win32/
* Borland (Registration required)
* Tiny C Compiler http://bellard.org/tcc/
* OpenWatcom http://www.openwatcom.org/index.php/Download
* Digital Mars http://www.digitalmars.com/download/freecompiler.html
-
-*/
+ *
+ */
/* See also: */
View
48 c/tools/build/Makefile.in
@@ -20,32 +20,32 @@ OPENMP = @openmp@
all: test
# Recipes to build executables
-t/01-toolchain/01a-cc.exe: t/01-toolchain/01a-cc.c t/Test.h
- $(CC) $(OUTFILE) t/01-toolchain/01a-cc.exe t/01-toolchain/01a-cc.c
- -$(RM_RF) 01a-cc.obj
+t/01-toolchain/01a-cc.t.exe: t/01-toolchain/01a-cc.t.c t/Test.h
+ $(CC) $(OUTFILE) t/01-toolchain/01a-cc.t.exe t/01-toolchain/01a-cc.t.c
+ -$(RM_RF) 01a-cc.t.obj
-t/01-toolchain/01b-timing.exe: t/01-toolchain/01b-timing.c t/Test.h
- $(CC) $(OUTFILE) t/01-toolchain/01b-timing.exe t/01-toolchain/01b-timing.c
- -$(RM_RF) 01b-timing.obj
+t/01-toolchain/01b-timing.t.exe: t/01-toolchain/01b-timing.t.c t/Test.h
+ $(CC) $(OUTFILE) t/01-toolchain/01b-timing.t.exe t/01-toolchain/01b-timing.t.c
+ -$(RM_RF) 01b-timing.t.obj
-t/01-toolchain/01c-osthreads.exe: t/01-toolchain/01c-osthreads.c t/Test.h
- $(CC) $(THREADS) $(OPENMP) $(OUTFILE) t/01-toolchain/01c-osthreads.exe t/01-toolchain/01c-osthreads.c
- -$(RM_RF) 01c-osthreads.obj
+t/01-toolchain/01c-osthreads.t.exe: t/01-toolchain/01c-osthreads.t.c t/Test.h
+ $(CC) $(THREADS) $(OPENMP) $(OUTFILE) t/01-toolchain/01c-osthreads.t.exe t/01-toolchain/01c-osthreads.t.c
+ -$(RM_RF) 01c-osthreads.t.obj
-t/02-components/02a-threads.exe: t/02-components/02a-threads.c \
+t/02-components/02a-threads.t.exe: t/02-components/02a-threads.t.c \
src/threads.h src/threads.c src/timing.c src/timing.h t/Test.h
- $(CC) $(THREADS) $(OUTFILE) t/02-components/02a-threads.exe src/threads.c src/timing.c t/02-components/02a-threads.c
- -$(RM_RF) threads.obj 02a-threads.obj
+ $(CC) $(THREADS) $(OUTFILE) t/02-components/02a-threads.t.exe src/threads.c src/timing.c t/02-components/02a-threads.t.c
+ -$(RM_RF) threads.obj 02a-threads.t.obj
-t/02-components/02b-hashtable.exe: t/02-components/02b-hashtable.c \
+t/02-components/02b-hashtable.t.exe: t/02-components/02b-hashtable.t.c \
src/hashtable.h src/hashtable.c t/Test.h
- $(CC) $(OUTFILE) t/02-components/02b-hashtable.exe src/hashtable.c t/02-components/02b-hashtable.c
- -$(RM_RF) hashtable.obj 02b-hashtable.obj
+ $(CC) $(OUTFILE) t/02-components/02b-hashtable.t.exe src/hashtable.c t/02-components/02b-hashtable.t.c
+ -$(RM_RF) hashtable.obj 02b-hashtable.t.obj
-t/02-components/02c-heapmanager.exe: t/02-components/02c-heapmanager.c \
- src/heapmanager.h src/heapmanager.c t/Test.h
- $(CC) $(OUTFILE) t/02-components/02c-heapmanager.exe src/heapmanager.c t/02-components/02c-heapmanager.c
- -$(RM_RF) heapmanager.obj 02b-heapmanager.obj
+t/02-components/02c-mem.t.exe: t/02-components/02c-mem.t.c \
+ src/mem.h src/mem.c t/Test.h
+ $(CC) $(OUTFILE) t/02-components/02c-mem.t.exe src/mem.c t/02-components/02c-mem.t.c
+ -$(RM_RF) mem.obj 02b-mem.t.obj
tools/build/prove$(EXE): tools/build/prove.c
$(CC) $(OUTFILE) tools/build/prove$(EXE) tools/build/prove.c
@@ -58,13 +58,13 @@ test: test01 test02
# The test01 target checks that the C compiler and so on perform the
# functions needed by the rest of the code. It is generally unnecessary
# to run this test, but is useful when troubleshooting.
-test01: t/01-toolchain/01a-cc.exe t/01-toolchain/01b-timing.exe \
- t/01-toolchain/01c-osthreads.exe tools/build/prove$(EXE)
+test01: t/01-toolchain/01a-cc.t.exe t/01-toolchain/01b-timing.t.exe \
+ t/01-toolchain/01c-osthreads.t.exe tools/build/prove$(EXE)
tools/build/prove -e "" --ext ".exe" t/01-toolchain
# The test02 target validates the internal libraries of 6model/c
-test02: t/02-components/02a-threads.exe \
- t/02-components/02b-hashtable.exe tools/build/prove$(EXE)
+test02: t/02-components/02a-threads.t.exe t/02-components/02b-hashtable.t.exe \
+ tools/build/prove$(EXE)
tools/build/prove -e "" --ext ".exe" t/02-components
# Miscellaneous targets
@@ -81,7 +81,7 @@ help:
@echo In this 6model/c directory you can make the following targets:
@echo "test - general test as far as 6model has been developed"
@echo "test01 - test the toolchain, eg C compiler, threads, ICU etc"
- @echo "test02 - test 6model components, eg hashtable, heapmanager etc"
+ @echo "test02 - test 6model components, eg hashtable, mem etc"
@echo "clean - remove all generated files except this Makefile"
@echo "realclean - remove all generated files including this Makefile"
@echo "help - you already found this"
View
195 c/tools/build/prove.c
@@ -1,26 +1,34 @@
/* prove.c */
-/* Lightweight TAP (Test Anything Protocol) harness */
+/* Lightweight C version of a TAP (Test Anything Protocol) harness */
-/* TODO: parse the test script output looking for 'ok', 'not ok' etc */
-/* and output a summary instead of every test result. */
+/* TODO: support for TODO tests (that are expected to fail) */
+/* TODO: ensure the '1..n' (plan) output is either first or last line */
+/* TODO: check exit status from child process */
+
+/* Functions are placed in this file at the point just before they */
+/* are needed, but all global variables are declared at the start. */
#include <assert.h> /* assert */
#include <stdio.h> /* FILE fprintf printf stderr */
-#include <stdlib.h> /* exit free malloc qsort realloc */
+#include <stdlib.h> /* atoi exit free malloc qsort realloc */
#include <string.h> /* strcat strcpy strlen */
#if defined( _WIN32 )
#include <windows.h>
#define pclose _pclose
#define popen _popen
+ #define DIRECTORY_SEPARATOR "\\"
#else
- #include <dirent.h> /* opendir readdir */
+ #include <dirent.h> /* opendir readdir */
+ #define DIRECTORY_SEPARATOR "/"
#endif
#define LINEBUFFERSIZE 128
+/* Global variables */
char * program_name;
char * executable_program;
char * filename_extension;
+int tests_passed=0, tests_failed=0, todos_passed=0, total_files=0;
/* options */
@@ -35,7 +43,10 @@ options(int argc, char * argv[])
executable_program = NULL; /* should be "perl6" ;-) */
filename_extension = NULL; /* should be ".t" */
if (argc < 2) {
- fprintf(stderr, "Usage: %s test_directory\n", argv[0]);
+ fprintf(stderr,
+ "Usage: %s [-e \"cmd\"] [--ext \"extension\"] test_directory\n",
+ argv[0]
+ );
exit(1);
}
scanning_args = 1;
@@ -85,6 +96,51 @@ qx(char * command)
}
+/* split_str */
+int
+split_str(char * str, char * delim, char *** substrings)
+{
+ int substringcount = 0, substringlen, delimiterlen;
+ char * p1, * p2, * substr;
+ delimiterlen = strlen(delim);
+ assert( delimiterlen>0 );
+ p1 = str;
+ while ((p2=strstr(p1, delim)) != NULL) {
+ substringlen = p2 - p1;
+ /* Create or extend the list of pointers to strings */
+ if (substringcount++ == 0) {
+ * substrings = (char **) malloc(sizeof(char **));
+ }
+ else {
+ * substrings = (char **) realloc(* substrings, substringcount * sizeof(char **));
+ }
+ /* Push the substring onto the end of the list */
+ substr = (char *) malloc(substringlen+1);
+ strncpy(substr, p1, substringlen);
+ substr[substringlen] = '\0';
+ (* substrings)[substringcount-1] = substr;
+ /* Move the search pointer past the delimiter */
+ p1 += substringlen + delimiterlen;
+ }
+ /* There is often another substring after the last delimiter */
+ if ((substringlen=strlen(p1))>0) {
+ /* Create or extend the list of pointers to strings */
+ if (substringcount++ == 0) {
+ * substrings = (char **) malloc(sizeof(char **));
+ }
+ else {
+ * substrings = (char **) realloc(* substrings, substringcount * sizeof(char **));
+ }
+ /* Push the substring onto the end of the list */
+ substr = (char *) malloc(substringlen+1);
+ strncpy(substr, p1, substringlen);
+ substr[substringlen] = '\0';
+ (* substrings)[substringcount-1] = substr;
+ }
+ return substringcount;
+}
+
+
#if ! defined( _WIN32 )
/* scandirectory_comparenames */
int
@@ -122,7 +178,6 @@ scandirectory(char * dirname, char *** filenamelist) /* yes, triple pointer */
strcat(filename, "\\*");
if (filename_extension != NULL)
strcat(filename, filename_extension);
- printf("%s\n", filename);
hFind = FindFirstFile(filename, &dir);
found_a_file = (hFind != INVALID_HANDLE_VALUE);
#else
@@ -134,7 +189,6 @@ scandirectory(char * dirname, char *** filenamelist) /* yes, triple pointer */
}
direntry = readdir(dir);
found_a_file = (direntry != NULL);
- printf("scandirectory %s\n", dirname);
#endif
while (found_a_file) {
#if defined( _WIN32 )
@@ -184,7 +238,8 @@ scandirectory(char * dirname, char *** filenamelist) /* yes, triple pointer */
}
-/* filecollection - a list of directory names containing file names */
+/* filecollection */
+/* a list of directory names containing file names */
struct filecollection {
int dircount;
struct filecollection_dir {
@@ -196,15 +251,14 @@ struct filecollection {
/* filecollection_free */
+/* Frees all the memory allocated to a filecollection */
void
filecollection_free(struct filecollection * coll)
{
int i, j;
for (i=0; i<coll->dircount; ++i) {
-// printf("Freeing %s has %d files\n", coll->dirs[i].dirname, coll->dirs[i].filecount);
free(coll->dirs[i].dirname);
for (j=0; j<coll->dirs[i].filecount; ++j) {
-// printf(" Freeing %s\n", coll->dirs[i].filenames[j]);
free(coll->dirs[i].filenames[j]);
}
free(coll->dirs[i].filenames);
@@ -213,7 +267,11 @@ filecollection_free(struct filecollection * coll)
free(coll);
}
+
/* scandirectories */
+/* Takes a list of directory names and returns a filecollection which */
+/* is a list of those directory names and also either all the files */
+/* in each directory or those that have a specified extension. */
struct filecollection *
scandirectories(int argc, char * argv[])
{
@@ -266,7 +324,6 @@ scandirectories(int argc, char * argv[])
filedir->filenames[filedir->filecount-1] =
(char *) malloc(strlen(filenamelist[j])+1);
strcpy(filedir->filenames[filedir->filecount-1], filenamelist[j]);
-// printf(" %s\n", filenamelist[j]);
free(filenamelist[j]);
}
}
@@ -276,15 +333,94 @@ scandirectories(int argc, char * argv[])
}
-/* runtests */
+/* TAP_Parser */
void
-runtests(struct filecollection * coll)
+TAP_Parser(FILE * program_output)
+{
+ int planned=0, passed=0, failed=0, testnumber, testnumber_expected;
+ int len;
+ char line[LINEBUFFERSIZE];
+
+ testnumber_expected = 1;
+ while (fgets(line, LINEBUFFERSIZE, program_output)) {
+ if (strncmp(line, "1..", 3)==0) { /* plan() output */
+ planned = atoi(line+3);
+ }
+ else {
+ if (strncmp(line, "ok ", 3)==0) { /* passed test */
+ testnumber = atoi(line+3);
+ if (testnumber == testnumber_expected) {
+ ++testnumber_expected;
+ }
+ else {
+ fprintf(stderr,
+ "tap_parser expected test number %d but got %d\n",
+ testnumber_expected, testnumber );
+ testnumber_expected = testnumber + 1;
+ }
+ ++passed;
+ }
+ else {
+ if (strncmp(line, "not ok ", 7)==0) { /* failed test */
+ testnumber = atoi(line+7);
+ if (testnumber == testnumber_expected) {
+ ++testnumber_expected;
+ }
+ else {
+ fprintf(stderr,
+ "tap_parser expected test number %d but got %d\n",
+ testnumber_expected, testnumber );
+ testnumber_expected = testnumber + 1;
+ }
+ ++failed;
+ }
+ else {
+ if (strncmp(line, "#", 1)==0) { /* comment */
+ ;
+ }
+ else {
+ fprintf(stderr, "tap_parser: unexpected line: %s\n", line);
+ }
+ }
+ }
+ }
+ /* Display a running X/Y count of results as they arrive */
+ len = printf(" %d/%d", passed, planned ? planned : passed+failed);
+ while (len--)
+ printf("\b");
+ fflush(stdout);
+ }
+ printf("%d/%d %sok", passed, passed+failed,
+ (passed!=planned || failed!=0) ? "*NOT* " : "");
+ if (planned != passed + failed ) {
+ printf(" (%d planned)", planned);
+ }
+}
+
+
+/* runtest */
+void
+runtest(char * command)
+{
+ FILE * childprocess;
+
+ /* Run the test and capture its standard output */
+ childprocess = popen(command, "r");
+ /* Analyze the output for planned number of tests, passes and fails */
+ TAP_Parser(childprocess);
+ /* Clean up */
+ pclose(childprocess);
+}
+
+
+/* runtestdirs */
+void
+runtestdirs(struct filecollection * coll)
{
int i, j, commandlen;
char * command, * tap_output;
for (i=0; i<coll->dircount; ++i) {
for (j=0; j<coll->dirs[i].filecount; ++j) {
- printf("runtest %s / %s\n", coll->dirs[i].dirname, coll->dirs[i].filenames[j]);
commandlen = (executable_program ? strlen(executable_program) + 1 : 0)
+ strlen(coll->dirs[i].dirname) + 1
+ strlen(coll->dirs[i].filenames[j]) + 1;
@@ -295,41 +431,44 @@ runtests(struct filecollection * coll)
strcat(command, " ");
}
strcat(command, coll->dirs[i].dirname);
- #if defined( _WIN32 )
- strcat(command, "\\");
- #else
- strcat(command, "/");
- #endif
+ strcat(command, DIRECTORY_SEPARATOR );
strcat(command, coll->dirs[i].filenames[j]);
-
- tap_output = qx(command);
- printf("%s\n", tap_output);
+ printf("%s%s%s ", coll->dirs[i].dirname,
+ DIRECTORY_SEPARATOR, coll->dirs[i].filenames[j]);
+ fflush(stdout);
+ /* Run each test and parse its output */
+ runtest(command);
+ printf("\n");
free(command);
- free(tap_output);
}
}
}
+
/* main */
int
main(int argc, char * argv[])
{
int argi;
- struct filecollection * files;
+ struct filecollection * dirs_and_files;
/* Get command line options and process them */
argi = options(argc, argv);
/* Scan the remaining non-option arguments as directory names */
- files = scandirectories(argc-argi, argv+argi); /* argi hides what options() saw */
+ dirs_and_files = scandirectories(argc-argi, argv+argi);
+ /* argi hides what options() took from argv */
/* Perform each test and parse its TAP output */
- runtests(files);
+ runtestdirs(dirs_and_files);
/* Clean up when finished */
- filecollection_free(files);
+ filecollection_free(dirs_and_files);
return 0;
}
+/* See also: */
+/* perldoc prove, TAP::Harness, TAP::Parser::Aggregator */
+/* TAP::Parser::Grammar, TAP::Formatter::Console */
/* end of prove.c */

0 comments on commit 816dda0

Please sign in to comment.