From caa03388bcccc64f444f9b4ef664ec5039d5bf72 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 20 Feb 2002 19:03:59 +0000 Subject: [PATCH] Preliminary version of the C unit tests run-time environment. Added make rules for building and running C unit tests. --- Make.rules.in | 37 ++++++++-- dlls/Makedll.rules.in | 1 - include/wine/test.h | 22 ++++++ programs/winetest/make_ctests | 28 ++++++++ programs/winetest/runtest | 46 +++++++----- programs/winetest/wtmain.c | 129 ++++++++++++++++++++++++++++++++++ 6 files changed, 238 insertions(+), 25 deletions(-) create mode 100644 include/wine/test.h create mode 100755 programs/winetest/make_ctests create mode 100644 programs/winetest/wtmain.c diff --git a/Make.rules.in b/Make.rules.in index 91b061bf1b5..0eb61c7fbb6 100644 --- a/Make.rules.in +++ b/Make.rules.in @@ -59,10 +59,6 @@ LINT = @LINT@ LINTFLAGS = @LINTFLAGS@ ALLLINTFLAGS = $(LINTFLAGS) $(DEFS) $(OPTIONS) $(DIVINCL) WINAPI_CHECK = $(TOPSRCDIR)/tools/winapi_check/winapi_check -WINETEST = $(TOPOBJDIR)/programs/winetest/winetest -RUNTEST = $(TOPSRCDIR)/programs/winetest/runtest -RUNTESTFLAGS = -q -P wine -M $(MODULE) -T $(TOPOBJDIR) -TESTRESULTS = $(PLTESTS:.pl=.ok) $(CTESTS:.c=.ok) WINEBUILD = $(TOPOBJDIR)/tools/winebuild/winebuild MAKEDEP = $(TOPOBJDIR)/tools/makedep WRC = $(TOPOBJDIR)/tools/wrc/wrc @@ -74,6 +70,15 @@ LIBTSX11 = -L$(TOPOBJDIR)/tsx11 -lwine_tsx11 LIBUNICODE= -L$(TOPOBJDIR)/unicode -lwine_unicode LIBUUID = -L$(TOPOBJDIR)/ole -lwine_uuid +WINETEST = $(TOPOBJDIR)/programs/winetest/winetest +RUNTEST = $(TOPSRCDIR)/programs/winetest/runtest +RUNTESTFLAGS = -q -P wine -M $(MODULE) -T $(TOPOBJDIR) +TESTRESULTS = $(PLTESTS:.pl=.ok) $(CTESTS:.c=.ok) +TESTPROGRAM = tests/$(MODULE)_test +TESTLIST = tests/testlist.c +TESTOBJS = $(TESTMAIN) $(TESTLIST:.c=.o) $(CTESTS:.c=.o) +TESTMAIN = $(TOPOBJDIR)/programs/winetest/wtmain.o + @SET_MAKE@ # Installation infos @@ -130,6 +135,9 @@ LINTS = $(C_SRCS:.c=.ln) .c.ln: $(LINT) -c $(ALLLINTFLAGS) $< || ( $(RM) $@ && exit 1 ) +.c.ok: + $(RUNTEST) $(RUNTESTFLAGS) -p $(TESTPROGRAM) $< && touch $@ + .pl.ok: $(RUNTEST) $(RUNTESTFLAGS) $< && touch $@ @@ -217,7 +225,7 @@ $(SUBDIRS:%=%/__depend__): $(MAKEDEP) dummy cd `dirname $@` && $(MAKE) depend depend: $(MAKEDEP) $(GEN_C_SRCS) $(SUBDIRS:%=%/__depend__) - $(MAKEDEP) $(DIVINCL) -C$(SRCDIR) $(C_SRCS) $(RC_SRCS) $(RC_SRCS16) $(MC_SRCS) $(EXTRA_SRCS) -C. $(GEN_C_SRCS) + $(MAKEDEP) $(DIVINCL) -C$(SRCDIR) $(C_SRCS) $(RC_SRCS) $(RC_SRCS16) $(MC_SRCS) $(EXTRA_SRCS) $(CTESTS) -C. $(GEN_C_SRCS) # Rules for cleaning @@ -248,11 +256,28 @@ $(SUBDIRS:%=%/__uninstall__): dummy test:: $(TESTRESULTS) -$(TESTRESULTS): $(WINETEST) +$(PLTESTS:.c=.ok): $(WINETEST) +$(CTESTS:.c=.ok): $(TESTPROGRAM).so $(WINETEST): cd $(TOPOBJDIR)/programs/winetest && $(MAKE) winetest +$(TESTMAIN): + cd $(TOPOBJDIR)/programs/winetest && $(MAKE) wtmain.o + +$(TESTLIST): Makefile.in + $(TOPSRCDIR)/programs/winetest/make_ctests $(CTESTS) >$(TESTLIST) || $(RM) $(TESTLIST) + +$(TESTPROGRAM).so: $(TESTPROGRAM).spec.o $(TESTOBJS) + $(LDSHARED) $(LDDLLFLAGS) $(TESTPROGRAM).spec.o $(TESTOBJS) -o $@ $(LIBWINE) $(LIBS) + +$(TESTPROGRAM).tmp.o: $(TESTOBJS) + $(LDCOMBINE) $(TESTOBJS) -o $@ + -strip --strip-unneeded $@ + +$(TESTPROGRAM).spec.c: $(TESTPROGRAM).spec $(TESTPROGRAM).tmp.o $(WINEBUILD) + $(LDPATH) $(WINEBUILD) @DLLFLAGS@ -L$(DLLDIR) -sym $(TESTPROGRAM).tmp.o -o $@ -spec $(SRCDIR)/$(TESTPROGRAM).spec + # Misc. rules $(SPEC_SRCS:.spec=.spec.c): $(WINEBUILD) diff --git a/dlls/Makedll.rules.in b/dlls/Makedll.rules.in index 1f95477671d..beba9757efb 100644 --- a/dlls/Makedll.rules.in +++ b/dlls/Makedll.rules.in @@ -11,7 +11,6 @@ DEFS = @DLLFLAGS@ -D__WINE__ $(EXTRADEFS) LIBEXT = @LIBEXT@ -SONAME = lib$(MODULE).so IMPORTLIBS = $(IMPORTS:%=$(DLLDIR)/lib%.$(LIBEXT)) SPEC_SRCS = $(ALTNAMES:%=%.spec) ALL_OBJS = $(MODULE).spec.o $(OBJS) diff --git a/include/wine/test.h b/include/wine/test.h new file mode 100644 index 00000000000..7ce654390e3 --- /dev/null +++ b/include/wine/test.h @@ -0,0 +1,22 @@ +/* + * Definitions for Wine C unit tests. + * + * Copyright (C) 2002 Alexandre Julliard + */ + +#ifndef __WINE_TEST_H +#define __WINE_TEST_H + +/* debug level */ +extern int winetest_debug; + +/* current platform */ +extern const char *winetest_platform; + +extern void winetest_ok( int condition, const char *msg, const char *file, int line ); + +#define START_TEST(name) void func_##name(void) + +#define ok(test,msg) winetest_ok( (test), (msg), __FILE__, __LINE__ ) + +#endif /* __WINE_TEST_H */ diff --git a/programs/winetest/make_ctests b/programs/winetest/make_ctests new file mode 100755 index 00000000000..ddda0674119 --- /dev/null +++ b/programs/winetest/make_ctests @@ -0,0 +1,28 @@ +#!/usr/bin/perl + +use strict; + +print "/* Automatically generated file; DO NOT EDIT!! */\n\n"; + +my @testlist = @ARGV; +foreach (@testlist) +{ + s!.*/([^/]+)\.c$!$1!; + printf "extern void func_%s(void);\n", $_; +} + +print <= 0) { my $arg = shift @ARGV; if ($arg eq "-h") { usage; } + if ($arg eq "-p") { $program = shift @ARGV; next; } if ($arg eq "-q") { $ENV{WINETEST_DEBUG} = 0; next; } if ($arg eq "-v") { $ENV{WINETEST_DEBUG}++; next; } if ($arg eq "-P") { $platform = shift @ARGV; next; } @@ -57,6 +60,12 @@ while ($#ARGV >= 0) # we must have found an input file usage unless defined($infile); +if ($infile =~ /\.c$/ && !defined($program)) +{ + # set program to the .c file base name if not specified otherwise + ($program = $infile) =~ s/\.c$//; +} + # check/detect topobjdir if (defined($topobjdir)) { @@ -74,20 +83,6 @@ else # try to detect it automatically elsif (-f "../../../server/wineserver") { $topobjdir = "../../.."; } } -# set environment variables needed for Wine -if (defined($topobjdir)) -{ - chop($topobjdir = `cd $topobjdir && pwd`); - $ENV{LD_LIBRARY_PATH} = $topobjdir . "/dlls:" . $topobjdir . ":" . $ENV{LD_LIBRARY_PATH}; - $ENV{WINESERVER} ||= $topobjdir . "/server/wineserver"; - $ENV{WINELOADER} ||= $topobjdir . "/wine"; - $ENV{WINETEST_PLATFORM} = $platform || "wine"; -} -else -{ - $ENV{WINETEST_PLATFORM} = $platform || "windows"; -} - # check for include/ dir in script source directory and append it to search path my $basedir = $0; if ($basedir =~ /\//) { $basedir =~ s!/[^/]+$!!; } @@ -101,10 +96,25 @@ if (@modules) $ENV{WINEOPTIONS} .= "--dll " . join(',',@modules) . "=b"; } -# and now exec winetest +# set environment variables needed for Wine if (defined($topobjdir)) { - exec $topobjdir . "/programs/winetest/winetest", $infile, @ARGV; + chop($topobjdir = `cd $topobjdir && pwd`); + $ENV{LD_LIBRARY_PATH} = $topobjdir . "/dlls:" . $topobjdir . ":" . $ENV{LD_LIBRARY_PATH}; + $ENV{WINESERVER} ||= $topobjdir . "/server/wineserver"; + $ENV{WINELOADER} ||= $topobjdir . "/wine"; + $ENV{WINETEST_PLATFORM} = $platform || "wine"; + $ENV{WINEPRELOAD}=($program || ($topobjdir . "/programs/winetest/winetest")) . ".so"; + # try to exec the wine loader directly; if it fails continue on to normal exec + exec $ENV{WINELOADER}, $infile, @ARGV; } -exec "winetest", $infile, @ARGV; -print STDERR "Could not exec winetest\n"; +else +{ + $ENV{WINETEST_PLATFORM} = $platform || "windows"; +} + +# and now exec the program +$program ||= "winetest"; +exec $program, $infile, @ARGV; +print STDERR "Could not exec $program\n"; +exit 1; diff --git a/programs/winetest/wtmain.c b/programs/winetest/wtmain.c new file mode 100644 index 00000000000..52898e80966 --- /dev/null +++ b/programs/winetest/wtmain.c @@ -0,0 +1,129 @@ +/* + * Main routine for Wine C unit tests. + * + * Copyright 2002 Alexandre Julliard + * Copyright 2002 Andriy Palamarchuk + */ + +#include +#include +#include + +/* debug level */ +int winetest_debug = 1; + +/* current platform */ +const char *winetest_platform = "windows"; + +struct test +{ + const char *name; + void (*func)(void); +}; + +extern const struct test winetest_testlist[]; +static const struct test *current_test; /* test currently being run */ + +static int successes; /* number of successful tests */ +static int failures; /* number of failures */ +static int todo_successes; /* number of successful tests inside todo block */ +static int todo_failures; /* number of failures inside todo block */ +static int todo_level; /* current todo nesting level */ + +/* + * Checks condition. + * Parameters: + * - condition - condition to check; + * - msg test description; + * - file - test application source code file name of the check + * - line - test application source code file line number of the check + */ +void winetest_ok( int condition, const char *msg, const char *file, int line ) +{ + if (todo_level) + { + if (condition) + { + fprintf( stderr, "%s:%d: Test succeeded inside todo block", file, line ); + if (msg && msg[0]) fprintf( stderr, ": %s", msg ); + fputc( '\n', stderr ); + todo_failures++; + } + else todo_successes++; + } + else + { + if (!condition) + { + fprintf( stderr, "%s:%d: Test failed", file, line ); + if (msg && msg[0]) fprintf( stderr, ": %s", msg ); + fputc( '\n', stderr ); + failures++; + } + else successes++; + } +} + + +/* Find a test by name */ +static const struct test *find_test( const char *name ) +{ + const struct test *test; + const char *p; + int len; + + if ((p = strrchr( name, '/' ))) name = p + 1; + if ((p = strrchr( name, '\\' ))) name = p + 1; + len = strlen(name); + if (len > 2 && !strcmp( name + len - 2, ".c" )) len -= 2; + + for (test = winetest_testlist; test->name; test++) + { + if (!strncmp( test->name, name, len ) && !test->name[len]) break; + } + return test->name ? test : NULL; +} + + +/* Run a named test, and return exit status */ +static int run_test( const char *name ) +{ + const struct test *test; + int status; + + if (!(test = find_test( name ))) + { + fprintf( stderr, "Fatal: test '%s' does not exist.\n", name ); + exit(1); + } + successes = failures = todo_successes = todo_failures = 0; + todo_level = 0; + current_test = test; + test->func(); + + if (winetest_debug) + { + fprintf( stderr, "%s: %d tests executed, %d marked as todo, %d %s.\n", + name, successes + failures + todo_successes + todo_failures, + todo_successes, failures + todo_failures, + (failures + todo_failures != 1) ? "failures" : "failure" ); + } + status = (failures + todo_failures < 255) ? failures + todo_failures : 255; + return status; +} + + +/* main function */ +int main( int argc, char **argv ) +{ + char *p; + + if ((p = getenv( "WINETEST_PLATFORM" ))) winetest_platform = p; + if ((p = getenv( "WINETEST_DEBUG" ))) winetest_debug = atoi(p); + if (!argv[1]) + { + fprintf( stderr, "Usage: %s test_name\n", argv[0] ); + exit(1); + } + exit( run_test(argv[1]) ); +}