From a7eeaa0001d4c12a1df6df17de2cb437dbab7423 Mon Sep 17 00:00:00 2001 From: Modestas Vainius Date: Thu, 11 Jun 2009 03:01:58 +0300 Subject: [PATCH] Add a test suite for build systems. * Tests for core Buildsystem API (mostly path API). * Tests for check_auto_configure() for each buildsystem. * Build system autoselection tests under "typical" conditions for each buildsystem. * DH_AUTO_OPTIONS and command line argument parsing tests. * Real dh_auto_* tests for autoconf/makefile build systems with emulated. autoconf behaviour under in both in source and out of source tree scenarios. Signed-off-by: Modestas Vainius --- t/buildsystems/autoconf/configure | 74 +++++ t/buildsystems/buildsystem_tests | 430 ++++++++++++++++++++++++++++++ t/buildsystems/debian/changelog | 5 + t/buildsystems/debian/compat | 1 + t/buildsystems/debian/control | 10 + 5 files changed, 520 insertions(+) create mode 100755 t/buildsystems/autoconf/configure create mode 100755 t/buildsystems/buildsystem_tests create mode 100644 t/buildsystems/debian/changelog create mode 100644 t/buildsystems/debian/compat create mode 100644 t/buildsystems/debian/control diff --git a/t/buildsystems/autoconf/configure b/t/buildsystems/autoconf/configure new file mode 100755 index 0000000..adea14e --- /dev/null +++ b/t/buildsystems/autoconf/configure @@ -0,0 +1,74 @@ +#!/usr/bin/perl + +# Emulate autoconf behaviour and do some checks + +use strict; +use warnings; + +my @OPTIONS=qw( + ^--build=.*$ + ^--prefix=/usr$ + ^--includedir=\$\{prefix\}/include$ + ^--mandir=\$\{prefix\}/share/man$ + ^--infodir=\$\{prefix\}/share/info$ + ^--sysconfdir=/etc$ + ^--localstatedir=/var$ + ^--libexecdir=\$\{prefix\}/lib/.*$ + ^--disable-maintainer-mode$ + ^--disable-dependency-tracking$ +); + +# Verify if all command line arguments were passed +my @options = map { { regex => qr/$_/, + str => $_, + found => 0 } } @OPTIONS; +my @extra_args; +ARGV_LOOP: foreach my $arg (@ARGV) { + foreach my $opt (@options) { + if ($arg =~ $opt->{regex}) { + $opt->{found} = 1; + next ARGV_LOOP; + } + } + # Extra / unrecognized argument + push @extra_args, $arg; +} + +my @notfound = grep { ! $_->{found} and $_ } @options; +if (@notfound) { + print STDERR "Error: the following default options were NOT passed\n"; + print STDERR " ", $_->{str}, "\n" foreach (@notfound); + exit 1; +} + +# Create a simple Makefile +open(MAKEFILE, ">", "Makefile"); +print MAKEFILE < stamp_build + +# Tests if dh_auto_test executes 'check' target if 'test' does not exist +check: \$(CONFIGURE) stamp_build + \@echo Tested > stamp_test + +install: stamp_build + \@echo DESTDIR=\$(DESTDIR) > stamp_install + +# Tests whether dh_auto_clean executes distclean but does not touch +# this target +clean: + echo "This should not have been executed" >&2 && exit 1 + +distclean: + \@rm -f stamp_* Makefile + +.PHONY: all check install clean distclean +EOF +close MAKEFILE; + +open(STAMP, ">", "stamp_configure"); +print STAMP $_, "\n" foreach (@extra_args); +close STAMP; + +exit 0; diff --git a/t/buildsystems/buildsystem_tests b/t/buildsystems/buildsystem_tests new file mode 100755 index 0000000..a2b451a --- /dev/null +++ b/t/buildsystems/buildsystem_tests @@ -0,0 +1,430 @@ +#!/usr/bin/perl + +use Test::More tests => 224; + +use strict; +use warnings; +use IPC::Open2; +use Cwd (); +use File::Temp qw(tempfile tempdir); +use File::Basename (); + +# Let the tests to be run from anywhere but currect directory +# is expected to be the one where this test lives in. +chdir File::Basename::dirname($0) or die "Unable to chdir to ".File::Basename::dirname($0); + +use_ok( 'Debian::Debhelper::Dh_Lib' ); +use_ok( 'Debian::Debhelper::Buildsystem' ); +use_ok( 'Debian::Debhelper::Dh_Buildsystems' ); + +my $TOPDIR = "../.."; +my @STEPS = qw(configure build test install clean); +my @BUILDSYSTEMS = qw(autoconf perl_makemaker makefile python_distutils perl_build cmake); +my $BS_CLASS = 'Debian::Debhelper::Buildsystem'; + +my ($bs, @bs, %bs); +my ($tmp, @tmp, %tmp); +my ($tmpdir, $builddir, $default_builddir); + +### Common subs #### +sub touch { + my $file=shift; + my $chmod=shift; + open FILE, ">", $file and close FILE or die "Unable to touch $file"; + chmod $chmod, $file if defined $chmod; +} + +sub cleandir { + my $dir=shift; + system ("find", $dir, "-type", "f", "-delete"); +} +sub readlines { + my $h=shift; + my @lines = <$h>; + close $h; + chop @lines; + return \@lines; +} + +sub process_stdout { + my ($cmdline, $stdin) = @_; + my ($reader, $writer); + + open2($reader, $writer, $cmdline) or die "Unable to exec $cmdline"; + print $writer $stdin if $stdin; + close $writer; + return readlines($reader); +} + +### Test Buildsystem class API methods +is( $BS_CLASS->_canonpath("path/to/the/./nowhere/../../somewhere"), + "path/to/somewhere", "_canonpath no1" ); +is( $BS_CLASS->_canonpath("path/to/../forward/../../somewhere"), + "somewhere","_canonpath no2" ); +is( $BS_CLASS->_canonpath("path/to/../../../somewhere"), + "../somewhere","_canonpath no3" ); +is( $BS_CLASS->_rel2rel("path/my/file", "path/my"), + "file", "_rel2rel no1" ); +is( $BS_CLASS->_rel2rel("path/dir/file", "path/my"), + "../dir/file", "_rel2rel no2" ); +is( $BS_CLASS->_rel2rel("file", "/root/path/my", "/root"), + "../../file", "_rel2rel no3" ); + +### Test Buildsystem class path API methods under different configurations +sub test_buildsystem_paths_api { + my ($bs, $config, $expected)=@_; + + my $api_is = sub { + my ($got, $name)=@_; + is( $got, $expected->{$name}, "paths API ($config): $name") + }; + + &$api_is( $bs->get_sourcedir(), 'get_sourcedir()' ); + &$api_is( $bs->get_sourcepath("a/b"), 'get_sourcepath(a/b)' ); + &$api_is( $bs->get_builddir(), 'get_builddir()' ); + &$api_is( $bs->get_buildpath(), 'get_buildpath()' ); + &$api_is( $bs->get_buildpath("a/b"), 'get_buildpath(a/b)' ); + &$api_is( $bs->get_source_rel2builddir(), 'get_source_rel2builddir()' ); + &$api_is( $bs->get_source_rel2builddir("a/b"), 'get_source_rel2builddir(a/b)' ); + &$api_is( $bs->get_build_rel2sourcedir(), 'get_build_rel2sourcedir()' ); + &$api_is( $bs->get_build_rel2sourcedir("a/b"), 'get_build_rel2sourcedir(a/b)' ); +} + +# Defaults +$bs = $BS_CLASS->new(); +$default_builddir = $bs->DEFAULT_BUILD_DIRECTORY(); +%tmp = ( + "get_sourcedir()" => ".", + "get_sourcepath(a/b)" => "./a/b", + "get_builddir()" => undef, + "get_buildpath()" => ".", + "get_buildpath(a/b)" => "./a/b", + "get_source_rel2builddir()" => ".", + "get_source_rel2builddir(a/b)" => "./a/b", + "get_build_rel2sourcedir()" => ".", + "get_build_rel2sourcedir(a/b)" => "./a/b", +); +test_buildsystem_paths_api($bs, "no builddir, no sourcedir", \%tmp); + +# builddir=bld/dir +$bs = $BS_CLASS->new(builddir => "bld/dir"); +%tmp = ( + "get_sourcedir()" => ".", + "get_sourcepath(a/b)" => "./a/b", + "get_builddir()" => "bld/dir", + "get_buildpath()" => "bld/dir", + "get_buildpath(a/b)" => "bld/dir/a/b", + "get_source_rel2builddir()" => "../..", + "get_source_rel2builddir(a/b)" => "../../a/b", + "get_build_rel2sourcedir()" => "bld/dir", + "get_build_rel2sourcedir(a/b)" => "bld/dir/a/b", +); +test_buildsystem_paths_api($bs, "builddir=bld/dir, no sourcedir", \%tmp); + +# Default builddir, sourcedir=autoconf +$bs = $BS_CLASS->new(builddir => undef, sourcedir => "autoconf"); +%tmp = ( + "get_sourcedir()" => "autoconf", + "get_sourcepath(a/b)" => "autoconf/a/b", + "get_builddir()" => "autoconf/$default_builddir", + "get_buildpath()" => "autoconf/$default_builddir", + "get_buildpath(a/b)" => "autoconf/$default_builddir/a/b", + "get_source_rel2builddir()" => "..", + "get_source_rel2builddir(a/b)" => "../a/b", + "get_build_rel2sourcedir()" => "$default_builddir", + "get_build_rel2sourcedir(a/b)" => "$default_builddir/a/b", +); +test_buildsystem_paths_api($bs, "default builddir, sourcedir=autoconf", \%tmp); + +# Enforced out of source tree building +# sourcedir=builddir=autoconf hence default builddir is implied +$bs = $BS_CLASS->new(builddir => "./autoconf", sourcedir => "autoconf/"); +$bs->enforce_out_of_source_building(); +test_buildsystem_paths_api($bs, "out of source enforced, sourcedir=autoconf/", \%tmp); + +# sourcedir=autoconf (builddir should be dropped) +$bs = $BS_CLASS->new(builddir => ".", sourcedir => "autoconf"); +%tmp = ( + "get_sourcedir()" => "autoconf", + "get_sourcepath(a/b)" => "autoconf/a/b", + "get_builddir()" => undef, + "get_buildpath()" => "autoconf", + "get_buildpath(a/b)" => "autoconf/a/b", + "get_source_rel2builddir()" => ".", + "get_source_rel2builddir(a/b)" => "./a/b", + "get_build_rel2sourcedir()" => ".", + "get_build_rel2sourcedir(a/b)" => "./a/b", +); +test_buildsystem_paths_api($bs, "no builddir, sourcedir=autoconf", \%tmp); + +# builddir=bld/dir, sourcedir=autoconf. Should be the same as sourcedir=autoconf. +$bs = $BS_CLASS->new(builddir => "bld/dir", sourcedir => "autoconf"); +$bs->enforce_in_source_building(); +test_buildsystem_paths_api($bs, "in source enforced, sourcedir=autoconf", \%tmp); + +# builddir=../bld/dir (relative to the sourcedir) +$bs = $BS_CLASS->new(builddir => "../bld/dir/", sourcedir => "autoconf"); +%tmp = ( + "get_sourcedir()" => "autoconf", + "get_sourcepath(a/b)" => "autoconf/a/b", + "get_builddir()" => "bld/dir", + "get_buildpath()" => "bld/dir", + "get_buildpath(a/b)" => "bld/dir/a/b", + "get_source_rel2builddir()" => "../../autoconf", + "get_source_rel2builddir(a/b)" => "../../autoconf/a/b", + "get_build_rel2sourcedir()" => "../bld/dir", + "get_build_rel2sourcedir(a/b)" => "../bld/dir/a/b", +); +test_buildsystem_paths_api($bs, "builddir=../bld/dir, sourcedir=autoconf", \%tmp); + +# Builddir relative to the pwd (same path as above). +$bs = $BS_CLASS->new(builddir => "./bld/dir", sourcedir => "autoconf"); +test_buildsystem_paths_api($bs, "builddir=./bld/dir, sourcedir=autoconf", \%tmp); + +### Test if all buildsystems can be loaded +@bs = load_all_buildsystems([ $INC[0] ]); +@tmp = map { $_->NAME() } @bs; +is_deeply( \@tmp, \@BUILDSYSTEMS, "load_all_buildsystems() loads all built-in buildsystems" ); + +### Test check_auto_buildable() of each buildsystem +sub test_check_auto_buildable { + my $bs=shift; + my $config=shift; + my $expected=shift; + my @steps=@_ || @STEPS; + + if (! ref $expected) { + my %all_steps; + $all_steps{$_} = $expected foreach (@steps); + $expected = \%all_steps; + } + for my $step (@steps) { + my $e = 0; + if (exists $expected->{$step}) { + $e = $expected->{$step}; + } elsif (exists $expected->{default}) { + $e = $expected->{default}; + } + if ($e) { + ok( $bs->check_auto_buildable($step), + $bs->NAME() . "($config): check_auto_buildable($step)" ); + } + else { + ok( ! $bs->check_auto_buildable($step), + $bs->NAME() . "($config): ! check_auto_buildable($step)" ); + } + } +} + +$tmpdir = tempdir("tmp.XXXXXX"); +$builddir = "$tmpdir/builddir"; +mkdir $builddir; +%tmp = ( + builddir => 'builddir', + sourcedir => $tmpdir +); + +$bs{autoconf} = load_buildsystem("autoconf", undef, %tmp); +$bs{cmake} = load_buildsystem("cmake", undef, %tmp); +$bs{perl_mm} = load_buildsystem("perl_makemaker", undef, %tmp); +$bs = load_buildsystem("makefile", undef, %tmp); + +test_check_auto_buildable($bs{autoconf}, "no configure", 0); +test_check_auto_buildable($bs{cmake}, "no CMakeLists.txt", 0); +test_check_auto_buildable($bs{perl_mm}, "no Makefile.PL", 0); +test_check_auto_buildable($bs, "no Makefile", 0); + +touch "$tmpdir/configure", 0755; +test_check_auto_buildable($bs{autoconf}, "configure", { configure => 1 }); + +touch "$tmpdir/CMakeLists.txt"; +test_check_auto_buildable($bs{cmake}, "CMakeLists.txt", { configure => 1 }); + +touch "$tmpdir/Makefile.PL"; +test_check_auto_buildable($bs{perl_mm}, "Makefile.PL", + { configure => 1, install => 1 }); + +# With Makefile +touch "$builddir/Makefile"; +test_check_auto_buildable($bs, "Makefile", { configure => 0, default => 1 }); +test_check_auto_buildable($bs{autoconf}, "configure+Makefile", { configure => 1 }); +test_check_auto_buildable($bs{cmake}, "CMakeLists.txt+Makefile", 1); + +# Makefile.PL forces in-source +#(see note in check_auto_buildable() why always 1 here) +unlink "$builddir/Makefile"; +touch "$tmpdir/Makefile"; +test_check_auto_buildable($bs{perl_mm}, "Makefile.PL+Makefile", 1); + +# Perl Build.PL - handles always +$bs = load_buildsystem("perl_build", undef, %tmp); +test_check_auto_buildable($bs, "no Build.PL", 0); +touch "$tmpdir/Build.PL"; +test_check_auto_buildable($bs, "Build.PL", { configure => 1 }); +touch "$tmpdir/Build"; # forced in source +test_check_auto_buildable($bs, "Build.PL+Build", 1); + +# Python Distutils +$bs = load_buildsystem("python_distutils", undef, %tmp); +test_check_auto_buildable($bs, "no setup.py", 0); +touch "$tmpdir/setup.py"; +test_check_auto_buildable($bs, "setup.py", 1); + +cleandir($tmpdir); + +### Now test if it can autoselect a proper buildsystem for a typical package +sub test_autoselection { + my $system=shift; + my $expected=shift; + for my $step (@STEPS) { + my $bs = load_buildsystem(undef, $step, @_); + my $e = $expected; + $e = $expected->{$step} if ref $expected; + if (defined $bs) { + is( $bs->NAME(), $e, "autoselection($system): $step=".((defined $e)?$e:'undef') ); + } + else { + is ( undef, $e, "autoselection($system): $step=".((defined $e)?$e:'undef') ); + } + } +} + +# Autoconf +touch "$tmpdir/configure", 0755; +touch "$builddir/Makefile"; +test_autoselection("autoconf", + { configure => "autoconf", build => "makefile", + test => "makefile", install => "makefile", clean => "makefile" }, %tmp); +cleandir $tmpdir; + +# Perl Makemaker (build, test, clean fail with builddir set [not supported]) +touch "$tmpdir/Makefile.PL"; +touch "$tmpdir/Makefile"; +test_autoselection("perl_makemaker", "perl_makemaker", %tmp); +cleandir $tmpdir; + +# Makefile +touch "$builddir/Makefile"; +test_autoselection("makefile", { build => "makefile", test => "makefile", + install => "makefile", clean => "makefile" }, %tmp); +cleandir $tmpdir; + +# Python Distutils +touch "$tmpdir/setup.py"; +test_autoselection("python_distutils", "python_distutils", %tmp); +cleandir $tmpdir; + +# Perl Build +touch "$tmpdir/Build.PL"; +touch "$tmpdir/Build"; +test_autoselection("perl_build", "perl_build", %tmp); +cleandir $tmpdir; + +# CMake +touch "$tmpdir/CMakeLists.txt"; +touch "$builddir/Makefile"; +test_autoselection("cmake", + { configure => "cmake", build => "makefile", + test => "makefile", install => "makefile", clean => "makefile" }, %tmp); +cleandir $tmpdir; + +### Test buildsystems_init() and commandline/env argument handling +sub get_load_bs_source { + my ($system, $step)=@_; + $step = (defined $step) ? "'$step'" : 'undef'; + $system = (defined $system) ? "'$system'" : 'undef'; + +return < [ "--extra-autoconf-configure-arg" ]); +ok ( ! -e 'autoconf/bld', "autoconf/bld got deleted too" ); + +END { + system("rm", "-rf", $tmpdir); + system("$TOPDIR/dh_clean"); +} diff --git a/t/buildsystems/debian/changelog b/t/buildsystems/debian/changelog new file mode 100644 index 0000000..f902d89 --- /dev/null +++ b/t/buildsystems/debian/changelog @@ -0,0 +1,5 @@ +testpackage (1.0-1) unstable; urgency=low + + * Initial release. (Closes: #XXXXXX) + + -- Test Tue, 09 Jun 2009 15:35:32 +0300 diff --git a/t/buildsystems/debian/compat b/t/buildsystems/debian/compat new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/t/buildsystems/debian/compat @@ -0,0 +1 @@ +7 diff --git a/t/buildsystems/debian/control b/t/buildsystems/debian/control new file mode 100644 index 0000000..7edd806 --- /dev/null +++ b/t/buildsystems/debian/control @@ -0,0 +1,10 @@ +Source: testsrcpackage +Section: devel +Priority: optional +Maintainer: Test +Standards-Version: 3.8.1 + +Package: testpackage +Architecture: all +Description: short description + Long description -- 2.39.2