Merge pull request #17 from davidgiven/dtrg-tests

Refactor the tests so they run for several plats.
This commit is contained in:
David Given 2016-11-26 12:59:13 +01:00 committed by GitHub
commit 9641801455
41 changed files with 312 additions and 151 deletions

View file

@ -1,13 +1,13 @@
matrix:
include:
- os: linux
- os: osx
addons:
apt:
packages:
- ed
- openbios-ppc
- qemu-user
git:
depth: 10

View file

@ -14,7 +14,10 @@ vars.plats = {
"rpi",
}
vars.plats_with_tests = {
"linux386",
"linuxppc",
"qemuppc",
"pc86",
}
local plat_packages = {}

View file

@ -26,7 +26,6 @@ void* sbrk(int increment)
{
char* old;
char* new;
char* actual;
if (!current)
current = (char*) _syscall(__NR_brk, 0, 0, 0);
@ -35,15 +34,21 @@ void* sbrk(int increment)
return current;
old = current;
new = old + increment;
actual = (char*) _syscall(__NR_brk, (quad) new, 0, 0);
if (actual < new)
{
errno = ENOMEM;
return OUT_OF_MEMORY;
}
if ((increment > 0) && (new <= old))
goto out_of_memory;
else if ((increment < 0) && (new >= old))
goto out_of_memory;
if (brk(new) < 0)
goto out_of_memory;
current = actual;
return old;
out_of_memory:
errno = ENOMEM;
return OUT_OF_MEMORY;
}

View file

@ -16,6 +16,7 @@ return installable {
["$(PLATDEP)/linux386/as"] = "+as",
["$(PLATDEP)/linux386/ncg"] = "+ncg",
["$(PLATIND)/descr/linux386"] = "./descr",
"util/amisc+aelflod-pkg",
"util/opt+pkg",
}
}

View file

@ -0,0 +1,7 @@
include("tests/plat/build.lua")
plat_testsuite {
name = "tests",
plat = "linux386",
method = "qemu-i386"
}

View file

@ -16,6 +16,7 @@ return installable {
["$(PLATDEP)/linux68k/as"] = "+as",
["$(PLATDEP)/linux68k/ncg"] = "+ncg",
["$(PLATIND)/descr/linux68k"] = "./descr",
"util/amisc+aelflod-pkg",
"util/opt+pkg",
}
}

View file

@ -28,6 +28,7 @@ return installable {
["$(PLATDEP)/linuxppc/mcg"] = "+mcg",
["$(PLATDEP)/linuxppc/top"] = "+top",
["$(PLATIND)/descr/linuxppc"] = "./descr",
"util/amisc+aelflod-pkg",
"util/opt+pkg",
}
}

View file

@ -0,0 +1,7 @@
include("tests/plat/build.lua")
plat_testsuite {
name = "tests",
plat = "linuxppc",
method = "qemu-ppc"
}

View file

@ -23,6 +23,9 @@ are stubs required to make the demo apps link. File descriptors 0, 1 and 2
represent the console. All reads block. There's enough TTY emulation to allow
\n conversion and local echo (but it can't be turned off).
Console output is echoed to the serial port (without any setup). This is used
by qemu for running tests.
Example command line
====================

View file

@ -23,7 +23,7 @@
! If you ever need to change the boot code, this needs adjusting. I recommend
! a hex editor.
PADDING = 0xB7
PADDING = 0xB3
! Some definitions.
@ -271,9 +271,12 @@ finished:
! Push standard parameters onto the stack and go.
push envp ! envp
push argv ! argv
push 1 ! argc
mov ax, envp
push ax
mov ax, argv
push ax
mov ax, 1
push ax
call __m_a_i_n
! fall through into the exit routine.

View file

@ -37,6 +37,7 @@ extern char** environ;
extern void _exit(int);
extern pid_t getpid(void);
extern int brk(void* addr);
extern void* sbrk(int increment);
extern int isatty(int d);
extern off_t lseek(int fildes, off_t offset, int whence);

View file

@ -21,9 +21,18 @@ __sys_rawwrite:
push bp
mov bp, sp
! Write to the BIOS console.
movb al, 4(bp)
movb ah, 0x0E
mov bx, 0x0007
int 0x10
! Also write to the serial port (used by the test suite).
movb ah, 0x01
xor dx, dx
int 0x14
jmp .cret

View file

@ -22,7 +22,10 @@ int brk(void* newend)
if ((p > (&dummy - STACK_BUFFER)) ||
(p < _end))
{
errno = ENOMEM;
return -1;
}
current = p;
return 0;
@ -31,13 +34,26 @@ int brk(void* newend)
void* sbrk(int increment)
{
char* old;
char* new;
if (increment == 0)
return current;
old = current;
if (brk(old + increment) < 0)
return OUT_OF_MEMORY;
new = old + increment;
if ((increment > 0) && (new <= old))
goto out_of_memory;
else if ((increment < 0) && (new >= old))
goto out_of_memory;
if (brk(new) < 0)
goto out_of_memory;
return old;
out_of_memory:
errno = ENOMEM;
return OUT_OF_MEMORY;
}

View file

@ -0,0 +1,7 @@
include("tests/plat/build.lua")
plat_testsuite {
name = "tests",
plat = "pc86",
method = "qemu-system-i386"
}

View file

@ -34,13 +34,26 @@ int brk(void* newend)
void* sbrk(int increment)
{
char* old;
char* new;
if (increment == 0)
return current;
old = current;
if (brk(old + increment) < 0)
return OUT_OF_MEMORY;
new = old + increment;
if ((increment > 0) && (new <= old))
goto out_of_memory;
else if ((increment < 0) && (new >= old))
goto out_of_memory;
if (brk(new) < 0)
goto out_of_memory;
return old;
out_of_memory:
errno = ENOMEM;
return OUT_OF_MEMORY;
}

View file

@ -1,28 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include "test.h"
int main(int argc, const char* argv[])
{
void* p;
ASSERT(-1 == (intptr_t)brk((void*)0xffffffff));
ASSERT(ENOMEM == errno);
p = sbrk(0);
ASSERT(p == sbrk(0));
ASSERT(p == sbrk(8));
ASSERT(p != sbrk(0));
ASSERT(p != sbrk(-8));
ASSERT(p == sbrk(0));
/* We assume the test environment has less than 2GB of RAM. */
ASSERT(-1 == (intptr_t)sbrk(INT_MAX));
ASSERT(-1 == (intptr_t)sbrk(INT_MIN));
finished();
}

View file

@ -1,49 +1,7 @@
include("plat/build.lua")
include("tests/plat/build.lua")
local qemu = "qemu-system-ppc"
local tests = {}
if os.execute("which "..qemu.." > /dev/null") ~= 0 then
print("warning: skipping tests which require ", qemu)
else
local testcases = filenamesof("./*.c", "./*.s", "./*.e", "./*.p")
for _, f in ipairs(testcases) do
local fs = replace(basename(f), "%..$", "")
local _, _, lang = fs:find("_(.)$")
if not lang then
lang = "e"
end
local bin = ackprogram {
name = fs.."_bin",
srcs = { f },
deps = { "plat/qemuppc/tests/lib+lib" },
vars = {
plat = "qemuppc",
lang = lang,
ackcflags = "-O0"
}
}
tests[#tests+1] = normalrule {
name = fs,
outleaves = { "stamp" },
ins = {
bin,
"./testdriver.sh"
},
commands = {
"%{ins[2]} "..qemu.." %{ins[1]} 5",
"touch %{outs}"
}
}
end
end
normalrule {
name = "tests",
outleaves = { "stamp" },
ins = tests,
commands = { "touch %{outs}" }
plat_testsuite {
name = "tests",
plat = "qemuppc",
method = "qemu-system-ppc"
}

View file

@ -1,22 +0,0 @@
#!/bin/sh
qemu=$1
img=$2
timeout=$3
pipe=/tmp/$$.testdriver.pipe
mknod $pipe p
trap "rm -f $pipe" EXIT
result=/tmp/$$.testdriver.result
trap "rm -f $result" EXIT
pidfile=/tmp/$$.testdriver.pid
trap "rm -f $pidfile" EXIT
( $qemu -nographic -kernel $img 2>&1 & echo $! > $pidfile ) \
| tee $result \
| ( timeout $timeout grep -l -q @@FINISHED ; echo ) \
| ( read dummy && kill $(cat $pidfile) )
( grep -q @@FAIL $result || ! grep -q @@FINISHED $result ) && cat $result && exit 1
exit 0

View file

@ -6,3 +6,4 @@ void _m_a_i_n(void)
ASSERT(0 == 0);
finished();
}

46
tests/plat/brk_c.c Normal file
View file

@ -0,0 +1,46 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include "test.h"
int main(int argc, const char* argv[])
{
char* o;
char* p;
p = sbrk(0);
ASSERT(p == sbrk(0));
ASSERT(p == sbrk(8));
ASSERT(p != sbrk(0));
ASSERT(p != sbrk(-8));
ASSERT(p == sbrk(0));
errno = 0;
o = sbrk(INT_MAX);
if (o == (char*)-1)
ASSERT(ENOMEM == errno);
else
{
ASSERT(0 == errno);
p = sbrk(0);
ASSERT(p > o);
brk(o);
}
errno = 0;
o = sbrk(INT_MIN);
if (o == (char*)-1)
ASSERT(ENOMEM == errno);
else
{
ASSERT(0 == errno);
p = sbrk(0);
ASSERT(p < o);
brk(o);
}
finished();
}

64
tests/plat/build.lua Normal file
View file

@ -0,0 +1,64 @@
include("plat/build.lua")
definerule("plat_testsuite",
{
plat = { type="string" },
method = { type="string" },
},
function(e)
-- Remember this is executed from the caller's directory; local
-- target names will resolve there.
local testfiles = filenamesof(
"tests/plat/*.c",
"tests/plat/*.e",
"tests/plat/*.p"
)
acklibrary {
name = "lib",
srcs = { "tests/plat/lib/test.c" },
hdrs = { "tests/plat/lib/test.h" },
vars = { plat = e.plat },
}
local tests = {}
for _, f in ipairs(testfiles) do
local fs = replace(basename(f), "%..$", "")
local _, _, lang = fs:find("_(.)$")
if not lang then
lang = "e"
end
local bin = ackprogram {
name = fs.."_bin",
srcs = { f },
deps = { "+lib" },
vars = {
plat = e.plat,
lang = lang,
ackcflags = "-O0"
}
}
tests[#tests+1] = normalrule {
name = fs,
outleaves = { "stamp" },
ins = {
bin,
"tests/plat/testdriver.sh"
},
commands = {
"%{ins[2]} "..e.method.." %{ins[1]} 5",
"touch %{outs}"
}
}
end
return normalrule {
name = e.name,
outleaves = { "stamp" },
ins = tests,
commands = { "touch %{outs}" }
}
end
)

View file

@ -1,11 +1,12 @@
#include <limits.h>
#include "test.h"
/* Constants in globals to defeat constant folding. */
double one = 1.0;
double zero = 0.0;
double minusone = -1.0;
double big = 2147483647.0;
double minusbig = -2147483648.0;
double big = (double)INT_MAX;
double minusbig = (double)INT_MIN;
/* Bypasses the CRT, so there's no stdio or BSS initialisation. */
void _m_a_i_n(void)
@ -13,8 +14,8 @@ void _m_a_i_n(void)
ASSERT((int)zero == 0);
ASSERT((int)one == 1);
ASSERT((int)minusone == -1);
ASSERT((int)big == 2147483647);
ASSERT((int)minusbig == -2147483648);
ASSERT((int)big == INT_MAX);
ASSERT((int)minusbig == INT_MIN);
finished();
}

View file

@ -1,16 +1,17 @@
#include <limits.h>
#include "test.h"
/* Constants in globals to defeat constant folding. */
double one = 1.0;
double zero = 0.0;
double big = 4294967295.0;
double big = (double)UINT_MAX;
/* Bypasses the CRT, so there's no stdio or BSS initialisation. */
void _m_a_i_n(void)
{
ASSERT((unsigned int)zero == 0);
ASSERT((unsigned int)one == 1);
ASSERT((unsigned int)big == 4294967295);
ASSERT((unsigned int)big == UINT_MAX);
finished();
}

View file

@ -1,11 +1,12 @@
#include <limits.h>
#include "test.h"
/* Constants in globals to defeat constant folding. */
int one = 1;
int zero = 0;
int minusone = -1;
int big = 0x7fffffff;
int minusbig = -0x8000000;
int big = INT_MAX;
int minusbig = INT_MIN;
/* Bypasses the CRT, so there's no stdio or BSS initialisation. */
void _m_a_i_n(void)
@ -13,8 +14,8 @@ void _m_a_i_n(void)
ASSERT((double)zero == 0.0);
ASSERT((double)one == 1.0);
ASSERT((double)minusone == -1.0);
ASSERT((double)big == 2147483647.0);
/* ASSERT((double)minusbig == -2147483648.0); FIXME: fails for now */
ASSERT((double)big == (double)INT_MAX);
/* ASSERT((double)minusbig == (double)INT_MIN); FIXME: fails for now */
finished();
}

View file

@ -1,16 +1,17 @@
#include <limits.h>
#include "test.h"
/* Constants in globals to defeat constant folding. */
unsigned int one_u = 1;
unsigned int zero_u = 0;
unsigned int big_u = 0xffffffff;
unsigned int big_u = UINT_MAX;
/* Bypasses the CRT, so there's no stdio or BSS initialisation. */
void _m_a_i_n(void)
{
ASSERT((double)zero_u == 0.0);
ASSERT((double)one_u == 1.0);
ASSERT((double)big_u == 4294967295.0);
ASSERT((double)big_u == (double)UINT_MAX);
finished();
}

View file

@ -1,5 +1,5 @@
#
mes 2, 4, 4
mes 2, EM_WSIZE, EM_PSIZE
exp $_m_a_i_n
pro $_m_a_i_n, 0
@ -10,12 +10,12 @@
rom 0I1, 0I1, 0I1, 0I1
loe .1
loc 1 /* bit number */
inn 4
inn EM_WSIZE
zeq *1
loc __LINE__
cal $fail
ass 4
ass EM_WSIZE
1
/* Test existent bit */
@ -24,12 +24,12 @@
rom 2I1, 0I1, 0I1, 0I1
loe .2
loc 1 /* bit number */
inn 4
inn EM_WSIZE
zne *2
loc __LINE__
cal $fail
ass 4
ass EM_WSIZE
2
/* Test non-existent high bit */
@ -38,36 +38,44 @@
rom 0I1, 0I1, 0I1, 0I1
rom 0I1, 0I1, 0I1, 0I1
.31
rom 33 /* to defeat constant folding */
rom (EM_WSIZE*8)+1 /* to defeat constant folding */
lae .3
loi 8
loi EM_WSIZE*2
loe .31 /* bit number */
inn 8
inn EM_WSIZE*2
zeq *3
loc __LINE__
cal $fail
ass 4
ass EM_WSIZE
3
/* Test existent high bit */
.4
#if EM_WSIZE == 2
rom 0I1, 0I1
rom 2I1, 0I1
#elif EM_WSIZE == 4
rom 0I1, 0I1, 0I1, 0I1
rom 2I1, 0I1, 0I1, 0I1
#else
#error Unknown word size
#endif
.41
rom 33 /* to defeat constant folding */
rom (EM_WSIZE*8)+1 /* to defeat constant folding */
lae .4
loi 8
loi EM_WSIZE*2
loe .41 /* bit number */
inn 8
inn EM_WSIZE*2
zne *4
loc __LINE__
cal $fail
ass 4
ass EM_WSIZE
4
cal $finished

View file

@ -1,3 +1,4 @@
#include <limits.h>
#include "test.h"
/* Constants in globals to defeat constant folding. */
@ -25,8 +26,8 @@ void _m_a_i_n(void)
ASSERT(((unsigned int)one >>(unsigned int)zero) == 1);
ASSERT(((unsigned int)one >>(unsigned int)one) == 0);
ASSERT(((unsigned int)minusone>>(unsigned int)zero) == 0xffffffff);
ASSERT(((unsigned int)minusone>>(unsigned int)one) == 0x7fffffff);
ASSERT(((unsigned int)minusone>>(unsigned int)zero) == UINT_MAX);
ASSERT(((unsigned int)minusone>>(unsigned int)one) == (UINT_MAX>>1));
ASSERT((one <<0) == 1);
ASSERT((one <<1) == 2);
@ -45,8 +46,8 @@ void _m_a_i_n(void)
ASSERT(((unsigned int)one >>(unsigned int)0) == 1);
ASSERT(((unsigned int)one >>(unsigned int)1) == 0);
ASSERT(((unsigned int)minusone>>(unsigned int)0) == 0xffffffff);
ASSERT(((unsigned int)minusone>>(unsigned int)1) == 0x7fffffff);
ASSERT(((unsigned int)minusone>>(unsigned int)0) == UINT_MAX);
ASSERT(((unsigned int)minusone>>(unsigned int)1) == (UINT_MAX>>1));
finished();
}

View file

@ -1,3 +1,4 @@
#include <limits.h>
#include "test.h"
/* Constants in globals to defeat constant folding. */
@ -19,13 +20,13 @@ void _m_a_i_n(void)
ASSERT((1 - two) == -1);
ASSERT(((unsigned int)two - (unsigned int)one) == 1);
ASSERT(((unsigned int)one - (unsigned int)two) == 0xffffffff);
ASSERT(((unsigned int)one - (unsigned int)two) == UINT_MAX);
ASSERT(((unsigned int)two - (unsigned int)1) == 1);
ASSERT(((unsigned int)one - (unsigned int)2) == 0xffffffff);
ASSERT(((unsigned int)one - (unsigned int)2) == UINT_MAX);
ASSERT(((unsigned int)2 - (unsigned int)one) == 1);
ASSERT(((unsigned int)1 - (unsigned int)two) == 0xffffffff);
ASSERT(((unsigned int)1 - (unsigned int)two) == UINT_MAX);
finished();
}

View file

@ -4,5 +4,4 @@ acklibrary {
name = "lib",
srcs = { "./test.c" },
hdrs = { "./test.h" },
vars = { plat = "qemuppc" }
}

View file

@ -6,6 +6,7 @@ void finished(void)
{
static const char s[] = "@@FINISHED\n";
write(1, s, sizeof(s));
_exit(0);
}
void writehex(uint32_t code)
@ -25,7 +26,7 @@ void writehex(uint32_t code)
void fail(uint32_t code)
{
write(1, "@@FAIL on line 0x", 7);
write(1, "@@FAIL 0x", 10);
writehex(code);
write(1, "\n", 1);
}

View file

@ -9,6 +9,6 @@ extern void writehex(uint32_t code);
extern void fail(uint32_t code);
#define ASSERT(condition) \
if (!(condition)) fail(__LINE__)
do { if (!(condition)) fail(__LINE__); } while(0)
#endif

51
tests/plat/testdriver.sh Executable file
View file

@ -0,0 +1,51 @@
#!/bin/sh
method=$1
img=$2
timeout=$3
pipe=/tmp/$$.testdriver.pipe
mknod $pipe p
trap "rm -f $pipe" EXIT
result=/tmp/$$.testdriver.result
trap "rm -f $result" EXIT
pidfile=/tmp/$$.testdriver.pid
trap "rm -f $pidfile" EXIT
case $method in
qemu-system-*)
if ! command -v $method 2>/dev/null; then
echo "Warning: $method not installed, skipping test"
exit 0
fi
case $method in
qemu-system-i386) img="-drive file=$img,if=floppy,format=raw" ;;
qemu-system-ppc) img="-kernel $img" ;;
esac
( $method -nographic $img 2>&1 & echo $! > $pidfile ) \
| tee $result \
| ( timeout $timeout grep -l -q @@FINISHED ; echo ) \
| ( read dummy && kill $(cat $pidfile) )
;;
qemu-*)
if ! command -v $method 2>/dev/null; then
echo "Warning: $method not installed, skipping test"
exit 0
fi
$method $img > $result
;;
*)
echo "Error: $method not known by testdriver"
exit 1
;;
esac
( grep -q @@FAIL $result || ! grep -q @@FINISHED $result ) && cat $result && exit 1
exit 0