From 466c0e3f0dd2b3c5b9cb4da2bca424b1bb45fcdb Mon Sep 17 00:00:00 2001 From: Daniel Collins Date: Fri, 30 Nov 2012 20:21:10 +0000 Subject: [PATCH] Implemented basic testing framework and tests for bind behaviour. --- Makefile | 13 ++++- tests/bind.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++ tests/bind.pl | 98 ++++++++++++++++++++++++++++++++++++ tests/ipxtest.pm | 81 ++++++++++++++++++++++++++++++ 4 files changed, 317 insertions(+), 1 deletion(-) create mode 100644 tests/bind.c create mode 100644 tests/bind.pl create mode 100644 tests/ipxtest.pm diff --git a/Makefile b/Makefile index e3764a3..75458b8 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,10 @@ SRC_FILES := changes.txt license.txt Makefile mkstubs.pl readme.txt src/config.h include/dplay.h include/dplaysp.h include/dplobby.h include/wsnwlink.h directplay-win32.reg \ directplay-win64.reg +# DLLs to copy to the tests directory before running the test suite. + +TEST_DLLS := ipxwrapper.dll wsock32.dll mswsock.dll dpwsockx.dll + all: ipxwrapper.dll wsock32.dll mswsock.dll ipxconfig.exe dpwsockx.dll clean: @@ -64,8 +68,15 @@ dist: all zip -r ipxwrapper-$(VERSION)-src.zip ipxwrapper-$(VERSION)-src/ rm -r ipxwrapper-$(VERSION)-src/ +test: $(TEST_DLLS) tests/bind.exe + cp $(TEST_DLLS) tests/ + cd tests; perl bind.pl + +tests/%.exe: tests/%.c + $(CC) $(CFLAGS) -o $@ $< -lwsock32 + .SECONDARY: -.PHONY: all clean dist depend +.PHONY: all clean dist depend test depend: Makefile.dep diff --git a/tests/bind.c b/tests/bind.c new file mode 100644 index 0000000..9a261ab --- /dev/null +++ b/tests/bind.c @@ -0,0 +1,126 @@ +/* IPXWrapper - C utility for testing bind behaviour + * Copyright (C) 2012 Daniel Collins + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include +#include + +int main(int argc, const char **argv) +{ + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + if(argc < 3) + { + USAGE: + + fprintf(stderr, "Usage: %s [--reuse] , ...\n", argv[0]); + return 1; + } + + WSADATA wsdata; + int err = WSAStartup(MAKEWORD(1,1), &wsdata); + if(err) + { + printf("FAIL\n"); + return 1; + } + + int init_sock = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX); + if(init_sock == -1) + { + printf("FAIL\n"); + return 1; + } + + struct sockaddr_ipx addr; + + memset(&addr, 0, sizeof(addr)); + addr.sa_family = AF_IPX; + + if(bind(init_sock, (struct sockaddr*)(&addr), sizeof(addr)) == -1) + { + printf("FAIL\n"); + return 1; + } + + int i, req = 2; + BOOL reuse = FALSE; + + for(i = 1; i < argc; i++) + { + if(strcmp(argv[i], "--reuse") == 0 && req == 2) + { + reuse = TRUE; + continue; + } + + if(i + req > argc || argv[i][strspn(argv[i], "1234567890")] != '\0') + { + goto USAGE; + } + + if(--req == 0) + { + int iface_num = atoi(argv[i - 1]); + int sock_num = atoi(argv[i]); + + IPX_ADDRESS_DATA iface_info; + iface_info.adapternum = iface_num; + + int optlen = sizeof(iface_info); + + if(getsockopt(init_sock, NSPROTO_IPX, IPX_ADDRESS, (char*)&iface_info, &optlen) == -1) + { + printf("FAIL\n"); + return 1; + } + + memcpy(addr.sa_netnum, iface_info.netnum, 4); + memcpy(addr.sa_nodenum, iface_info.nodenum, 6); + addr.sa_socket = htons(sock_num); + + int sock = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX); + if(sock == -1) + { + printf("FAIL\n"); + return 1; + } + + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&reuse, sizeof(reuse)); + + if(bind(sock, (struct sockaddr*)(&addr), sizeof(addr)) == -1) + { + printf("FAIL\n"); + return 1; + } + + reuse = FALSE; + req = 2; + } + } + + /* Wait for input on stdin. */ + + printf("OK\n"); + getchar(); + + return 0; +} diff --git a/tests/bind.pl b/tests/bind.pl new file mode 100644 index 0000000..1fe5d47 --- /dev/null +++ b/tests/bind.pl @@ -0,0 +1,98 @@ +# IPXWrapper - Tests for bind +# Copyright (C) 2012 Daniel Collins +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 as published by +# the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., 51 +# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +use strict; +use warnings; + +use ipxtest; + +my @tests = ( + # Single process, unique socket numbers. + + [ "bind.exe 0 1234 0 1235" => "OK" ], + [ "bind.exe 0 1234 1 1235" => "OK" ], + + # Two processes, unique socket numbers. + + [ + "bind.exe 0 1234" => "OK", + "bind.exe 0 1235" => "OK", + ], + + [ + "bind.exe 0 1234" => "OK", + "bind.exe 1 1235" => "OK", + ], + + # Single process, bind to two random sockets. + + [ "bind.exe 0 0 0 0" => "OK" ], + [ "bind.exe 0 0 1 0" => "OK" ], + + # Two processes, bind to random sockets. + + [ + "bind.exe 0 0" => "OK", + "bind.exe 0 0" => "OK", + ], + + [ + "bind.exe 0 0" => "OK", + "bind.exe 1 0" => "OK", + ], + + # Single process, conflicting addresses. + + [ "bind.exe 0 1234 0 1234" => "FAIL" ], + [ "bind.exe 0 1234 1 1234" => "FAIL" ], + + # Two processes, conflicting addresses. + + [ + "bind.exe 0 1234" => "OK", + "bind.exe 0 1234" => "FAIL" + ], + + [ + "bind.exe 0 1234" => "OK", + "bind.exe 1 1234" => "FAIL" + ], + + # SO_REUSEADDR within one process + + [ "bind.exe --reuse 0 1234 --reuse 0 1234" => "OK" ], + [ "bind.exe --reuse 0 1234 0 1234" => "FAIL" ], + [ "bind.exe 0 1234 --reuse 0 1234" => "FAIL" ], + + # SO_REUSEADDR between processes + + [ + "bind.exe --reuse 0 1234" => "OK", + "bind.exe --reuse 0 1234" => "OK", + ], + + [ + "bind.exe --reuse 0 1234" => "OK", + "bind.exe 0 1234" => "FAIL", + ], + + [ + "bind.exe 0 1234" => "OK", + "bind.exe --reuse 0 1234" => "FAIL", + ], +); + +IPXWrapper::Testing::run_tests(@tests); diff --git a/tests/ipxtest.pm b/tests/ipxtest.pm new file mode 100644 index 0000000..6479723 --- /dev/null +++ b/tests/ipxtest.pm @@ -0,0 +1,81 @@ +# IPXWrapper - Test helpers +# Copyright (C) 2012 Daniel Collins +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 as published by +# the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., 51 +# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +package IPXWrapper::Testing; + +use strict; +use warnings; + +use IPC::Open2; + +sub run_tests +{ + my (@tests) = @_; + + my $total_tests = 0; + my $passed_tests = 0; + + my $test_n = 1; + + foreach my $test(@tests) + { + my @procs = (); + + for(my $i = 0, my $subtest = 1; $i < scalar @$test; $i += 2, $subtest++) + { + my $command = $test->[$i]; + my $expect = $test->[$i + 1]; + + my $pid = open2(my $stdout, my $stdin, $command); + + push(@procs, $stdin); + + (my $result = <$stdout>) =~ s/[\r\n]//g; + + print "Test $test_n-$subtest: "; + + if($result eq $expect) + { + print "PASSED\n"; + + $passed_tests++; + } + else{ + print "FAILED\n"; + print "\tCommand: $command\n"; + print "\tResult: $result\n"; + print "\tExpected: $expect\n"; + } + + $total_tests++; + } + + # Tell any remaining processes to exit. + + foreach my $stdin(@procs) + { + print {$stdin} "\n"; + } + + $test_n++; + } + + print "\n-- Passed $passed_tests/$total_tests tests\n"; + + exit($total_tests == $passed_tests ? 0 : 1); +} + +1;