summaryrefslogtreecommitdiffstats
path: root/test/t
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xtest/t/common.t106
-rw-r--r--test/t/config112
-rw-r--r--test/t/config21
-rw-r--r--test/t/json-cache.t25
-rw-r--r--test/t/salsa-config.t18
-rw-r--r--test/t/salsa.conf4
-rw-r--r--test/t/salsa.pm226
-rw-r--r--test/t/salsa.t108
-rw-r--r--test/t/uscan-config.t20
-rwxr-xr-xtest/test_annotate-output47
-rwxr-xr-xtest/test_checkbashisms221
-rwxr-xr-xtest/test_dd-list47
-rwxr-xr-xtest/test_debchange251
-rwxr-xr-xtest/test_debdiff35
-rwxr-xr-xtest/test_debi285
-rwxr-xr-xtest/test_debrepro46
-rwxr-xr-xtest/test_debsign114
-rw-r--r--test/test_helper.sh26
-rwxr-xr-xtest/test_mass_bug161
-rwxr-xr-xtest/test_mergechanges551
-rwxr-xr-xtest/test_mk-origtargz750
-rwxr-xr-xtest/test_package_lifecycle386
-rwxr-xr-xtest/test_perl12
-rwxr-xr-xtest/test_perltidy39
-rwxr-xr-xtest/test_sadt100
-rwxr-xr-xtest/test_salsa106
-rwxr-xr-xtest/test_uscan548
-rwxr-xr-xtest/test_uscan_ftp489
-rwxr-xr-xtest/test_uscan_git207
-rwxr-xr-xtest/test_uscan_group210
-rwxr-xr-xtest/test_uscan_mangle1543
-rwxr-xr-xtest/test_uscan_online50
-rwxr-xr-xtest/test_uscan_svn201
-rwxr-xr-xtest/test_wrap-and-sort50
34 files changed, 6995 insertions, 0 deletions
diff --git a/test/t/common.t b/test/t/common.t
new file mode 100755
index 0000000..82e9b53
--- /dev/null
+++ b/test/t/common.t
@@ -0,0 +1,106 @@
+#!/usr/bin/perl
+
+package Config::Test;
+
+use Moo;
+
+extends 'Devscripts::Config';
+
+use constant keys => [
+ ['test!', 'TEST', 'bool', 1],
+ ['str=s', 'STR', qr/^a/, 'ab'],
+ ['str2=s', 'STR2', qr/^a/, 'bb'],
+ ['array=s', 'ARRAY', undef, sub { [] }],
+];
+
+package main;
+
+use Test::More tests => 39;
+
+BEGIN {
+ use_ok('Devscripts::Config');
+}
+
+my $conf;
+$Devscripts::Output::die_on_error = 0;
+
+@Devscripts::Config::config_files = ();
+
+ok($conf = Config::Test->new->parse, 'No conf files, no args');
+ok($conf->{test} == 1, ' test=1');
+ok($conf->{str} eq 'ab', ' str=ab');
+ok($conf->{str2} eq 'bb', ' str2=bb');
+
+@Devscripts::Config::config_files = ('t/config1');
+
+ok($conf = Config::Test->new->parse, 'Conf files, no args');
+ok($conf->{test} == 0, ' test=0');
+ok($conf->{str} eq 'az', ' str=az');
+ok($conf->{str2} eq 'a1', ' str2=a1');
+if (ok(ref $conf->{array}, ' array')) {
+ ok($conf->{array}->[0] eq "b c", ' "b c" found');
+ ok($conf->{array}->[1] eq "a", ' "a" found');
+ ok($conf->{array}->[2] eq "d", ' "d" found');
+ ok(scalar @{ $conf->{array} } == 3, ' 3 elements');
+}
+
+@ARGV = ('--noconf');
+
+ok($conf = Config::Test->new->parse, '--noconf');
+ok($conf->{test} == 1, ' test=1');
+ok($conf->{str} eq 'ab', ' str=ab');
+ok($conf->{str2} eq 'bb', ' str2=bb');
+
+@ARGV = ('--conffile', 't/config2');
+
+ok($conf = Config::Test->new->parse, '--conffile t/config2');
+ok($conf->{test} == 1, ' test=1');
+ok($conf->{str} eq 'ab', ' str=ab');
+ok($conf->{str2} eq 'axzx', ' str2=axzx');
+
+@ARGV = ('--conffile', '+t/config2');
+
+ok($conf = Config::Test->new->parse, '--conffile +t/config2');
+ok($conf->{test} == 0, ' test=0');
+ok($conf->{str} eq 'az', ' str=az');
+ok($conf->{str2} eq 'axzx', ' str2=axzx');
+
+@ARGV = ('--test', '--str2=ac');
+
+ok($conf = Config::Test->new->parse, '--test --str2=ac');
+ok($conf->{test} == 1, ' test=1');
+ok($conf->{str} eq 'az', ' str=az');
+ok($conf->{str2} eq 'ac', ' str2=ac');
+
+@ARGV = ('--noconf', '--str2', 'ac', '--notest');
+
+ok($conf = Config::Test->new->parse, '--noconf --no-test --str2=ac');
+ok($conf->{test} == 0, ' test=0');
+ok($conf->{str} eq 'ab', ' str=ab');
+ok($conf->{str2} eq 'ac', ' str2=ac');
+
+@ARGV = ('--noconf', '--array', 'a', '--array=b');
+ok($conf = Config::Test->new->parse, '--noconf --array a --array=b');
+ok(ref $conf->{array}, 'Multiple options are allowed');
+ok($conf->{array}->[0] eq 'a', ' first value is a');
+ok($conf->{array}->[1] eq 'b', ' second value is b');
+
+# Redirect STDERR to $out;
+my $out;
+{
+ no warnings;
+ open F, ">&STDERR";
+}
+close STDERR;
+open STDERR, '>', \$out;
+eval {
+ @ARGV = ('--noconf', '--str2', 'bc');
+ $conf = Config::Test->new->parse;
+};
+
+# Restore STDERR
+close STDERR;
+open STDERR, ">&F";
+fail($@) if ($@);
+ok($out =~ /Bad str2 value/, '--str2=bc is rejected');
+
diff --git a/test/t/config1 b/test/t/config1
new file mode 100644
index 0000000..829becc
--- /dev/null
+++ b/test/t/config1
@@ -0,0 +1,12 @@
+TEST=no
+STR=az
+STR2=a1
+ARRAY='a "b c" d'
+USCAN_SYMLINK=rename
+USCAN_VERBOSE=yes
+SALSA_TOKEN=xx
+SALSA_KGB=yes
+SALSA_ENABLE_ISSUES=no
+SALSA_EMAIL=ignore
+SALSA_ENABLE_MR=yes
+SALSA_IRKER=no
diff --git a/test/t/config2 b/test/t/config2
new file mode 100644
index 0000000..32d1629
--- /dev/null
+++ b/test/t/config2
@@ -0,0 +1 @@
+STR2=axzx
diff --git a/test/t/json-cache.t b/test/t/json-cache.t
new file mode 100644
index 0000000..a9d8918
--- /dev/null
+++ b/test/t/json-cache.t
@@ -0,0 +1,25 @@
+use Test::More;
+
+use strict;
+
+SKIP: {
+ eval "use JSON";
+ skip "JSON isn't available" if ($@);
+ use_ok('Devscripts::JSONCache');
+
+ my %c;
+
+ ok(tie(%c, 'Devscripts::JSONCache', 'test.json'), 'No file');
+ $c{a} = 1;
+ untie %c;
+ ok(-r 'test.json', 'Cache created');
+ ok(tie(%c, 'Devscripts::JSONCache', 'test.json'), 'Reuse file');
+ ok($c{a} == 1, 'Value saved');
+ untie %c;
+ unlink 'test.json';
+
+ my %c2;
+ eval { tie(%c2, 'Devscripts::JSONCache', 'zzz/test.json') };
+ ok($@, "Build refused if write isn't possible");
+}
+done_testing();
diff --git a/test/t/salsa-config.t b/test/t/salsa-config.t
new file mode 100644
index 0000000..1ee644a
--- /dev/null
+++ b/test/t/salsa-config.t
@@ -0,0 +1,18 @@
+use Test::More tests => 8;
+
+BEGIN {
+ use_ok('Devscripts::Salsa::Config');
+}
+
+@Devscripts::Config::config_files = ('t/config1');
+@ARGV = ('push_repo', '--disable-kgb', '--tagpending', '--irker');
+
+ok($conf = Devscripts::Salsa::Config->new->parse, 'Parse');
+
+ok(($conf->kgb == 0 and $conf->disable_kgb), 'KGB disabled');
+ok(($conf->tagpending and $conf->disable_tagpending == 0),
+ 'Tagpending enabled');
+ok(($conf->issues == 'disabled'), 'Enable-issues disabled');
+ok(($conf->email == 0 and $conf->disable_email == 0), 'Email ignored');
+ok(($conf->mr == 'enabled'), 'MR enabled');
+ok(($conf->irker == 1 and $conf->disable_irker == 0), 'Irker enabled');
diff --git a/test/t/salsa.conf b/test/t/salsa.conf
new file mode 100644
index 0000000..d14fa84
--- /dev/null
+++ b/test/t/salsa.conf
@@ -0,0 +1,4 @@
+SALSA_TOKEN=abc
+SALSA_API_URL=http://no-exist.xxx/api/v4
+SALSA_KGB_SERVER_URL=http://no-exist.xxx:9418/webhook/?channel=
+SALSA_TAGPENDING_SERVER_URL=http://no-exist.xxx:9418/tagpending/
diff --git a/test/t/salsa.pm b/test/t/salsa.pm
new file mode 100644
index 0000000..800d1e5
--- /dev/null
+++ b/test/t/salsa.pm
@@ -0,0 +1,226 @@
+{
+
+ package MockRESTClient;
+ use URI;
+ use Moo;
+ extends 'GitLab::API::v4::RESTClient';
+
+ has _mocks => (
+ is => 'ro',
+ default => sub { [] },
+ init_arg => undef,
+ );
+
+ sub mock_endpoints {
+ my $self = shift;
+
+ while (@_) {
+ my $method = shift;
+ my $path_re = shift;
+ my $sub = shift;
+
+ push @{ $self->_mocks() }, [$method, $path_re, $sub];
+ }
+
+ return;
+ }
+
+ sub _http_tiny_request {
+ my ($self, $req_method, $req) = @_;
+
+ die "req_method may only be 'request' at this time"
+ if $req_method ne 'request';
+
+ my ($method, $url, $options) = @$req;
+
+ my $path = URI->new($url)->path();
+ $path =~ s{^.*api/v4/}{};
+
+ foreach my $mock (@{ $self->_mocks() }) {
+ my ($handler_method, $path_re, $sub) = @$mock;
+
+ next if $method ne $handler_method;
+
+ my @captures = ($path =~ $path_re);
+ next if !@captures; # No captures still returns a 1.
+
+ my ($status, $content)
+ = $sub->([$method, $url, $options], @captures);
+ $content = JSON::to_json($content) if ref $content;
+
+ return {
+ status => $status,
+ success => ($status =~ m{^2\d\d$}) ? 1 : 0,
+ defined($content) ? (content => $content) : (),
+ };
+ }
+
+ die "No mock endpoint matched the $method '$path' endpoint";
+ }
+}
+
+sub api {
+ my ($gitdir) = @_;
+ my @users = ({
+ id => 11,
+ username => 'me',
+ name => 'Me',
+ email => 'me@debian.org',
+ state => 'active'
+ });
+ my @teams = ({
+ id => 2099,
+ name => 'Debian JavaScript Maintainers',
+ full_name => 'Debian JavaScript Maintainers',
+ full_path => 'js-team',
+ });
+ my @projects;
+ my $next_id = 1;
+
+ my $api = GitLab::API::v4->new(
+ url => 'https://example.com/api/v4',
+ rest_client_class => 'MockRESTClient',
+ );
+
+ $api->rest_client->mock_endpoints(
+ GET => qr{^user$} => sub { 200, $users[0] },
+ GET => qr{^users$} => sub { 200, \@users },
+ POST => qr{^users$} => sub {
+ my ($req) = @_;
+ my $user = decode_json($req->[2]->{content});
+ $user->{id} = $next_id;
+ $next_id++;
+ push @users, $user;
+ return 204;
+ },
+ GET => qr{^users?/(\d+)$} => sub {
+ my ($req, $id) = @_;
+ foreach my $user (@users) {
+ next if $user->{id} != $id;
+ return 200, $user;
+ }
+ return 404;
+ },
+ GET => qr{^users/(\D+)$} => sub {
+ my ($req, $id) = @_;
+ foreach my $user (@users) {
+ next if $user->{username} != $id;
+ return 200, $user;
+ }
+ return 404;
+ },
+ GET => qr{^groups$} => sub {
+ 200, \@teams;
+ },
+ GET => qr{^groups/([^/]+)$} => sub {
+ my ($req, $name) = @_;
+ foreach my $team (@teams) {
+ next if $team->{full_path} ne $name;
+ return 200, $team;
+ }
+ return 404;
+ },
+ PUT => qr{^users/(\d+)$} => sub {
+ my ($req, $id) = @_;
+ my $data = decode_json($req->[2]->{content});
+ foreach my $user (@users) {
+ next if $user->{id} != $id;
+ %$user = (%$user, %$data,);
+ return 204;
+ }
+ return 404;
+ },
+ DELETE => qr{^users/(\d+)$} => sub {
+ my ($req, $id) = @_;
+ my @new;
+ foreach my $user (@users) {
+ next if $user->{id} == $id;
+ push @new, $user;
+ }
+ return 404 if @new == @users;
+ @users = @new;
+ return 204;
+ },
+ # Projects
+ POST => qr{^projects$} => sub {
+ my $content = JSON::from_json($_[0]->[2]->{content});
+ mkdir "$gitdir/me/$content->{path}";
+ $ENV{"GIT_CONFIG_NOGLOBAL"} = 1;
+ print
+`cd $gitdir/me/$content->{path};git init;git config receive.denyCurrentBranch ignore;cd -`;
+ $content->{id} = scalar @projects + 1;
+ $content->{hooks} = [];
+ $content->{namespace} = {
+ kind => 'user',
+ id => 11,
+ name => 'me',
+ };
+ $content->{path_with_namespace} = 'me/' . $content->{path};
+ $content->{web_url} = 'http://no.org/me/' . $content->{path};
+ push @projects, $content;
+ return 200, $content;
+ },
+ GET => qr{^projects/(\d+)/hooks} => sub {
+ my ($req, $id) = @_;
+ my $res = eval { $projects[$id - 1]->{hooks} };
+ return ($res ? (200, $res) : (404));
+ },
+ GET => qr{^projects/(\d+)/services/(\w+)} => sub {
+ my ($req, $id, $service) = @_;
+ return 404;
+ },
+ GET => qr{^projects$} => sub {
+ my ($req) = @_;
+ return (200, \@projects) unless ($req->[1] =~ /search=([^&]+)/);
+ my $str = $1;
+ my @res;
+ foreach (@projects) {
+ if ($_->{name} =~ /\Q$str\E/) {
+ push @res, $_;
+ }
+ }
+ return 200, \@res;
+ },
+ GET => qr{^projects/([a-z]+)(?:%2F(\w+))*$} => sub {
+ my ($req, @path) = @_;
+ my $repo = pop @path;
+ my $path = join '/', @path;
+ foreach (@projects) {
+ if ($_->{namespace}->{name} eq $path and $_->{path} eq $repo) {
+ return 200, $_;
+ }
+ }
+ return 404;
+ },
+ GET => qr{^projects/(\d+)$} => sub {
+ my ($req, $id) = @_;
+ return 404 unless ($_ = $projects[$id - 1]);
+ return 200, $_;
+ },
+ PUT => qr{^projects/(\d+)} => sub {
+ my ($req, $id) = @_;
+ return 404 unless ($_ = $projects[$id - 1]);
+ my $content = JSON::from_json($req->[2]->{content});
+ foreach my $k (keys %$content) {
+ $_->{$k} = $content->{$k};
+ }
+ return 200, {};
+ },
+ POST => qr{^projects/(\d+)/hooks} => sub {
+ my ($req, $id) = @_;
+ return 404 unless ($_ = $projects[$id - 1]);
+ my $content = JSON::from_json($req->[2]->{content});
+ push @{ $_->{hooks} }, $content;
+ return 200, {};
+ },
+ POST => qr{^projects/(\d+)/repository/branches} => sub {
+ return 200, {};
+ },
+ DELETE => qr{^projects/(\d+)/repository/branches/([\w\-\.]+)$} => sub {
+ return 200, {};
+ },
+ );
+ return $api;
+}
+
+1;
diff --git a/test/t/salsa.t b/test/t/salsa.t
new file mode 100644
index 0000000..d80978a
--- /dev/null
+++ b/test/t/salsa.t
@@ -0,0 +1,108 @@
+#!/usr/bin/env perl
+
+my $skip;
+use File::Temp 'tempdir';
+use Test::More;
+use strict;
+
+BEGIN {
+ eval "use Test::Output;use GitLab::API::v4;";
+ $skip = $@ ? 1 : 0;
+}
+
+my $pwd = `pwd`;
+chomp $pwd;
+my ($api, $gitdir);
+
+sub mkDebianDir {
+ my $tmpdir = tempdir(CLEANUP => 1);
+ chdir $tmpdir;
+ $ENV{"GIT_CONFIG_NOGLOBAL"} = 1;
+ $ENV{"HOME"} = "";
+ system "git init";
+ system "git config user.name 'Joe Developer'";
+ system 'git config user.email "jd@debian.org"';
+ mkdir 'debian';
+ open F, ">debian/changelog";
+ print F <<EOF;
+foobar (0-1) unstable; urgency=low
+
+ * Initial release
+
+ -- Joe Developer <jd\@debian.org> Mon, 02 Nov 2013 22:21:31 -0100
+EOF
+ close F;
+ open F, ">README.md";
+ print F <<EOF;
+# Salsa test
+EOF
+ system "git add *";
+ system "git commit -a -m 'Salsa test'";
+ system "git checkout -q -b dev";
+ chdir $pwd;
+ return $tmpdir;
+}
+
+sub run {
+ my ($result, $out, @list) = @_;
+ @ARGV = ('--no-cache', @list);
+ my ($res, $salsa);
+ combined_like(
+ sub {
+ $salsa = Devscripts::Salsa->new({ api => $api });
+ $salsa->config->git_server_url($gitdir . '/');
+ $res = $salsa->run;
+ },
+ $out,
+ "command: " . join(' ', @list));
+ ok($res =~ /^$result$/i, " result is $result");
+}
+
+sub run_debug {
+ my ($result, $out, @list) = @_;
+ @ARGV = ('--no-cache', @list);
+ my ($res, $salsa);
+ $salsa = Devscripts::Salsa->new({ api => $api });
+ $salsa->config->git_server_url($gitdir . '/');
+ $res = $salsa->run;
+}
+
+SKIP: {
+ skip "Missing dependencies" if ($skip);
+ require './t/salsa.pm';
+ $gitdir = tempdir(CLEANUP => 1);
+ sleep 1;
+ mkdir "$gitdir/me" or die "$gitdir/me: $!";
+
+ $api = api($gitdir);
+
+ use_ok 'Devscripts::Salsa';
+ $Devscripts::Output::die_on_error = 0;
+ @Devscripts::Config::config_files = ('t/salsa.conf');
+
+ # Search methods
+ run(0, qr/Id\s*:\s*11\nUsername\s*:\s*me/s, 'whoami');
+ run(0, qr/Id\s*:\s*2099\nName/s, 'search_group', 'js-team');
+ run(0, qr/Id\s*:\s*2099\nName/s, 'search_group', 2099);
+ run(0, qr/Id.*\nUsername\s*: me/s, 'search_user', 'me');
+ run(0, qr/Id.*\nUsername\s*: me/s, 'search_user', 'm');
+ run(0, qr/Id.*\nUsername\s*: me/s, 'search_user', 11);
+
+ # Project methods
+ my $repo = mkDebianDir;
+ run(0, qr/Project .*created/s, '-C', $repo, '--verbose', 'push_repo', '.');
+ chdir $pwd;
+ $repo = tempdir(CLEANUP => 1);
+ run(0, qr/KGB hook added.*Tagpending hook added/s,
+ 'update_repo', '--kgb', '--irc=debian', '--tagpending', 'foobar');
+ run(0, qr/foobar\s*:\s*OK/s,
+ 'update_safe', '--kgb', '--irc=debian', '--tagpending', 'foobar');
+ run(0, qr{Full path\s*:\s*me/foobar}, 'search', 'foobar');
+ run(0, qr{Configuring foobar},
+ 'rename_branch', 'foobar', '--source-branch=dev',
+ '--dest-branch=dev2');
+}
+
+done_testing;
+
+1;
diff --git a/test/t/uscan-config.t b/test/t/uscan-config.t
new file mode 100644
index 0000000..5209924
--- /dev/null
+++ b/test/t/uscan-config.t
@@ -0,0 +1,20 @@
+use Test::More tests => 8;
+
+BEGIN {
+ use_ok('Devscripts::Uscan::Config');
+ use_ok('Devscripts::Uscan::Output');
+}
+
+@Devscripts::Config::config_files = ('t/config1');
+@ARGV = ( '--download-version', '1.0', '-dd', '--no-verbose' );
+
+ok(
+ $conf = Devscripts::Uscan::Config->new->parse,
+ 'USCAN_SYMLINK=rename + --download-version'
+);
+
+ok($conf->symlink eq 'rename', ' symlink=rename');
+ok($conf->download_version eq '1.0',' download_version=1.0');
+ok($conf->user_agent =~ /^Debian uscan/, qq' user agent starts with "Debian uscan" ($conf->{user_agent})');
+ok($conf->download == 2, 'Force download');
+ok($verbose == 0, 'Verbose is disabled');
diff --git a/test/test_annotate-output b/test/test_annotate-output
new file mode 100755
index 0000000..ca367be
--- /dev/null
+++ b/test/test_annotate-output
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+# Copyright (C) 2012, James McCoy <jamessan@debian.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+set -u
+
+if test "${1:-}" = --installed; then
+ COMMAND=annotate-output
+ shift
+else
+ COMMAND="../scripts/annotate-output.sh"
+fi
+
+WORKDIR="$(readlink -f "${0%/*}")"
+
+testSwallowedNewline() {
+ expected="% O: foo% I: Finished with exitcode 0"
+ actual="$($COMMAND +%% echo -n foo | grep O:)"
+ assertEquals 'incomplete line found' "${expected}" "${actual}"
+}
+
+testBackslashes() {
+ expected='% O: \f\o\o'
+ actual="$($COMMAND +%% printf '%s\n' '\f\o\o' | grep O:)"
+ assertEquals 'backslashes echoed' "${expected}" "${actual}"
+}
+
+testLeadingWhitespace() {
+ expected='% O: foo'
+ actual="$($COMMAND +%% printf '%s\n' ' foo' | grep O:)"
+ assertEquals 'leading whitespace preserved' "${expected}" "${actual}"
+}
+
+. shunit2
diff --git a/test/test_checkbashisms b/test/test_checkbashisms
new file mode 100755
index 0000000..38d4c4a
--- /dev/null
+++ b/test/test_checkbashisms
@@ -0,0 +1,221 @@
+#!/bin/sh
+
+# Copyright (C) 2012, Benjamin Drung <bdrung@debian.org>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+set -u
+
+if test "${1:-}" = --installed; then
+ COMMAND=checkbashisms
+ shift
+else
+ # shellcheck disable=SC2034
+ COMMAND="../scripts/checkbashisms.pl"
+fi
+
+WORKDIR="$(readlink -f "${0%/*}")"
+
+. "${0%/*}/shunit2-helper-functions.sh"
+
+clean() {
+ cd "$WORKDIR"
+ runCommand "$1" "" "" 0
+}
+
+found() {
+ cd "$WORKDIR"
+ runCommand "$1" "" "$2" 1
+}
+
+test_531327() {
+ clean "bashisms/531327.sh"
+}
+
+test_535368() {
+ clean "-f bashisms/535368.mk"
+}
+
+test_808271() {
+ found "bashisms/808271.sh" "$(cat bashisms/808271.sh.out)"
+}
+
+test_arith() {
+ found "bashisms/arith.sh" "$(cat bashisms/arith.sh.out)"
+}
+
+test_array_expansion() {
+ found "bashisms/array-expansion.sh" "$(cat bashisms/array-expansion.sh.out)"
+}
+
+test_ash_setvar() {
+ found "bashisms/ash-setvar.sh" "$(cat bashisms/ash-setvar.sh.out)"
+}
+
+test_basic() {
+ found "-f bashisms/basic.mk" "$(cat bashisms/basic.mk.out)"
+}
+
+test_basic_bash() {
+ clean "-f bashisms/basic-bash.mk"
+}
+
+test_brace_expansion() {
+ found "-f bashisms/brace-expansion.sh" "$(cat bashisms/brace-expansion.sh.out)"
+}
+
+test_basic_bash_override() {
+ clean "-f bashisms/basic-bash-override.mk"
+}
+
+test_case_modification() {
+ found "-f bashisms/case-modification.sh" "$(cat bashisms/case-modification.sh.out)"
+}
+
+test_comments_in_quoted_strings1() {
+ clean "bashisms/comments-in-quoted-strings1.sh"
+}
+
+test_comments_in_quoted_strings2() {
+ clean "bashisms/comments-in-quoted-strings2.sh"
+}
+
+test_command() {
+ found "bashisms/command.sh" "$(cat bashisms/command.sh.out)"
+}
+
+test_comments_parsing_fns() {
+ found "bashisms/comments-parsing-fns.sh" "$(cat bashisms/comments-parsing-fns.sh.out)"
+}
+
+test_coproc() {
+ found "bashisms/coproc.sh" "$(cat bashisms/coproc.sh.out)"
+}
+
+test_dynamic_length() {
+ found "bashisms/dynamic-length.sh" "$(cat bashisms/dynamic-length.sh.out)"
+}
+
+test_exit_code() {
+ found "bashisms/exit-code.sh" "$(cat bashisms/exit-code.sh.out)"
+}
+
+test_fail2ban() {
+ clean "bashisms/fail2ban.sh"
+}
+
+test_fps() {
+ found "bashisms/fps.sh" "$(cat bashisms/fps.sh.out)"
+}
+
+test_functions() {
+ found "bashisms/functions.sh" "$(cat bashisms/functions.sh.out)"
+}
+
+test_gettext() {
+ found "bashisms/gettext.sh" "$(cat bashisms/gettext.sh.out)"
+}
+
+test_glob_ignore() {
+ found "bashisms/glob-ignore.sh" "$(cat bashisms/glob-ignore.sh.out)"
+}
+
+test_hash() {
+ found "bashisms/hash.sh" "$(cat bashisms/hash.sh.out)"
+}
+
+test_heredocs() {
+ found "bashisms/heredocs.sh" "$(cat bashisms/heredocs.sh.out)"
+}
+
+test_heredoc_with_dash() {
+ clean "bashisms/heredoc-with-dash.sh"
+}
+
+test_heredoc_with_others() {
+ clean "bashisms/heredoc-with-others.sh"
+}
+
+test_jobs() {
+ found "bashisms/jobs.sh" "$(cat bashisms/jobs.sh.out)"
+}
+
+test_line_continuation() {
+ found "bashisms/line-continuation.sh" "$(cat bashisms/line-continuation.sh.out)"
+}
+
+test_negations() {
+ found "bashisms/negations.sh" "$(cat bashisms/negations.sh.out)"
+}
+
+test_other_vars() {
+ found "bashisms/other-vars.sh" "$(cat bashisms/other-vars.sh.out)"
+}
+
+test_printf() {
+ found "bashisms/printf.sh" "$(cat bashisms/printf.sh.out)"
+}
+
+test_quoted_strings() {
+ found "bashisms/quoted-strings.sh" "$(cat bashisms/quoted-strings.sh.out)"
+}
+
+test_return() {
+ found "bashisms/return.sh" "$(cat bashisms/return.sh.out)"
+}
+
+test_shell_vars() {
+ clean "-f bashisms/shell-vars.mk"
+}
+
+test_source() {
+ found "bashisms/source" "$(cat bashisms/source.out)"
+}
+
+test_special_case() {
+ found "bashisms/special-case.sh" "$(cat bashisms/special-case.sh.out)"
+}
+
+test_special_expansions() {
+ found "bashisms/special-expansions.sh" "$(cat bashisms/special-expansions.sh.out)"
+}
+
+test_subshell_no_arith() {
+ clean "bashisms/subshell-no-arith.sh"
+}
+
+test_tilde_expansion() {
+ found "bashisms/tilde-expansion.sh" "$(cat bashisms/tilde-expansion.sh.out)"
+}
+
+test_traps() {
+ found "bashisms/traps.sh" "$(cat bashisms/traps.sh.out)"
+}
+
+test_underscore_var() {
+ found "bashisms/underscore-var.sh" "$(cat bashisms/underscore-var.sh.out)"
+}
+
+test_unknown_fns() {
+ found "bashisms/unknown-fns.sh" "$(cat bashisms/unknown-fns.sh.out)"
+}
+
+test_unterminated_string() {
+ clean "bashisms/unterminated-string.sh"
+}
+
+test_unterminated_string2() {
+ clean "bashisms/unterminated-string2.sh"
+}
+
+. shunit2
diff --git a/test/test_dd-list b/test/test_dd-list
new file mode 100755
index 0000000..5d741d2
--- /dev/null
+++ b/test/test_dd-list
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+# Copyright (C) 2012, James McCoy <jamessan@debian.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+set -u
+
+WORKDIR="$(readlink -f "${0%/*}")"
+
+if test "${1:-}" = --installed; then
+ COMMAND=dd-list
+ shift
+else
+ COMMAND="$WORKDIR/../scripts/dd-list.pl"
+fi
+
+testBinariesFromSameSource() {
+ $COMMAND -s ${WORKDIR}/dd-list/sources vim-gtk vim-nox 2>&1 >/dev/null
+ rc=$?
+ assertEquals 'packages found' 0 $rc
+}
+
+testExtraSourceOnlyIgnored() {
+ $COMMAND -s ${WORKDIR}/dd-list/sources bzip2 >$SHUNIT_TMPDIR/extra-source.out
+
+ assertFalse 'Jorge listed as uploader' "grep -q Jorge $SHUNIT_TMPDIR/extra-source.out"
+}
+
+testUseOnlyLatestVersion() {
+ $COMMAND -s ${WORKDIR}/dd-list/sources subversion >$SHUNIT_TMPDIR/latest-version.out
+
+ assertFalse 'Troy Heber listed as uploader' "grep -q Troy $SHUNIT_TMPDIR/latest-version.out"
+}
+
+. shunit2
diff --git a/test/test_debchange b/test/test_debchange
new file mode 100755
index 0000000..f4bca26
--- /dev/null
+++ b/test/test_debchange
@@ -0,0 +1,251 @@
+#!/bin/bash
+
+# Copyright (C) 2012, Benjamin Drung <bdrung@debian.org>
+# © 2017 Mattia Rizzolo <mattia@debian.org>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+set -u
+
+if test "${1:-}" = --installed; then
+ COMMAND="dch --no-conf"
+ shift
+else
+ COMMAND="perl -I ${0%/*}/../lib ${0%/*}/../scripts/debchange.pl --no-conf"
+fi
+
+. "${0%/*}/shunit2-helper-functions.sh"
+
+setUp() {
+ CHANGELOG="${SHUNIT_TMPDIR}/changelog"
+ DEBFULLNAME="Raphaël Hertzog"
+ DEBEMAIL="hertzog@debian.org"
+ export DEBFULLNAME DEBEMAIL
+}
+
+tearDown() {
+ unset CHANGELOG DEBFULLNAME DEBEMAIL
+}
+
+runCommand2() {
+ local param="$1"
+ local exp_stdout="$2"
+ local exp_stderr="$3"
+ local exp_retval=$4
+ local stdoutF="${SHUNIT_TMPDIR}/stdout"
+ local stderrF="${SHUNIT_TMPDIR}/stderr"
+ eval "${COMMAND} $param" > ${stdoutF} 2> ${stderrF}
+ # Strip distribution data outdated warnings (caused by outdate distro-info-data).
+ cat $stderrF | \
+ grep -v "^Distribution data outdated. Please check for an update for distro-info-data. See /usr/share/doc/distro-info-data/README.Debian for details." | \
+ grep -v '^debchange[^ ]* warning: Unable to determine the current Ubuntu development release. Using UNRELEASED instead.$' > ${stderrF}.tmp
+ mv ${stderrF}.tmp ${stderrF}
+ retval=$?
+ assertEquals "standard output of ${COMMAND} $param\n" "$exp_stdout" "$(cat ${stdoutF})"
+ assertEquals "error output of ${COMMAND} $param\n" "$exp_stderr" "$(cat ${stderrF})"
+ assertEquals "return value of ${COMMAND} $param\n" $exp_retval $retval
+}
+
+success() {
+ runCommand2 "-c \"$CHANGELOG\" $1" "" "" 0
+}
+
+checkUbuntuDevelAvailable() {
+ if ubuntu-distro-info --devel 2>/dev/null >&2; then
+ # distro-info-data knows of the current devel release
+ true
+ else
+ # distro-info-data doesn't know of the current devel release
+ false
+ fi
+}
+
+checkVersion() {
+ local start_param="$1"
+ local param="$2"
+ local start_version="$3"
+ local expected_version="$4"
+ rm -f "$CHANGELOG"
+ success "--create $start_param --package test-package -v $start_version \"Devscripts Test Suite.\""
+ success "$param \"Version test.\""
+ local version=$(dpkg-parsechangelog -l"$CHANGELOG" -SVersion)
+ assertEquals "\"dch $param\" from version $start_version" "$expected_version" "$version"
+}
+
+checkDebianDistribution() {
+ checkVersion "--vendor Debian -D unstable" "--vendor Debian -i -D $1" "1.0-1" "1.0-2"
+}
+
+checkDebianVersion() {
+ checkVersion "--vendor Debian -D unstable" "--vendor Debian $1" "$2" "$3"
+}
+
+checkUbuntuVersion() {
+ checkVersion "--vendor Debian -D unstable" "--vendor Ubuntu $1" "$2" "$3"
+}
+
+testDebianDistributions() {
+ checkDebianDistribution "trixie"
+ checkDebianDistribution "trixie-security"
+ checkDebianDistribution "bookworm"
+ checkDebianDistribution "bookworm-proposed-updates"
+ checkDebianDistribution "bookworm-security"
+ checkDebianDistribution "bullseye"
+ checkDebianDistribution "bullseye-security"
+ checkDebianDistribution "buster"
+ checkDebianDistribution "buster-security"
+ checkDebianDistribution "experimental"
+ checkDebianDistribution "oldstable"
+ checkDebianDistribution "oldstable-proposed-updates"
+ checkDebianDistribution "oldoldstable"
+ checkDebianDistribution "oldoldstable-proposed-updates"
+ checkDebianDistribution "proposed-updates"
+ checkDebianDistribution "stable"
+ checkDebianDistribution "stable-proposed-updates"
+ checkDebianDistribution "testing"
+ checkDebianDistribution "testing-proposed-updates"
+ checkDebianDistribution "UNRELEASED"
+}
+
+testDebianIncrement() {
+ checkDebianVersion "-i" "1.0-1" "1.0-2"
+ checkDebianVersion "-i" "12" "13"
+}
+
+testUbuntuIncrement() {
+ if ! checkUbuntuDevelAvailable; then
+ echo "No known Ubuntu devel release known, skipping related tests"
+ startSkipping
+ fi
+ checkUbuntuVersion "-i" "12" "12ubuntu1"
+ checkUbuntuVersion "-i" "3.4" "3.4ubuntu1"
+ checkUbuntuVersion "-i" "3.4.5" "3.4.5ubuntu1"
+ checkUbuntuVersion "-i" "5.6-7" "5.6-7ubuntu1"
+ checkUbuntuVersion "-i" "5.6-7.1" "5.6-7.1ubuntu1"
+ checkUbuntuVersion "-i" "5.6-7.1.8" "5.6-7.1.8ubuntu1"
+ checkUbuntuVersion "-i" "2.13-14build5" "2.13-14ubuntu1"
+ checkUbuntuVersion "-i" "0.45-2ubuntu3" "0.45-2ubuntu4"
+ checkUbuntuVersion "-i" "0.45-2ubuntu3.1" "0.45-2ubuntu3.2"
+ checkUbuntuVersion "-i" "0.45-2ubuntu3.1.0" "0.45-2ubuntu3.1.1"
+}
+
+testUbuntuRebuild() {
+ if ! checkUbuntuDevelAvailable; then
+ echo "No known Ubuntu devel release known, skipping related tests"
+ startSkipping
+ fi
+ checkUbuntuVersion "-R" "3.4" "3.4build1"
+ checkUbuntuVersion "-R" "2.0-4" "2.0-4build1"
+ checkUbuntuVersion "-R" "1.42-4ubuntu5" "1.42-4ubuntu6"
+ checkUbuntuVersion "-R" "0.1-2build3" "0.1-2build4"
+}
+
+verifyMaintainer() {
+ local maintainer="$(dpkg-parsechangelog -l"$CHANGELOG" -SMaintainer)"
+ assertEquals "\"$1\"" "$DEBFULLNAME <$DEBEMAIL>" "$maintainer"
+}
+
+testEncoding() {
+ rm -f "$CHANGELOG"
+ success "--create -D unstable --package test-package -v 1.0-1 \"First upload\""
+ verifyMaintainer "dch --create"
+
+ success "-a \"Some change\""
+ verifyMaintainer "dch -a"
+
+ success "-i \"Second upload\""
+ verifyMaintainer "dch -i"
+
+ success "-e \"Another change\""
+ verifyMaintainer "dch -e"
+
+ success "-n NMU"
+ verifyMaintainer "dch -n"
+
+ success "-v 1.1-1 \"New upstream\""
+ verifyMaintainer "dch -v"
+
+ success "--bin-nmu \"Rebuild against libfoo\""
+ verifyMaintainer "dch --bin-nmu"
+
+ success "-q \"QA upload\""
+ verifyMaintainer "dch -q"
+
+ success "-s \"Security upload\""
+ verifyMaintainer "dch -s"
+
+ success "-s \"LTS Security upload\""
+ verifyMaintainer "dch --lts"
+
+ success "--bpo \"Backports upload\""
+ verifyMaintainer "dch --bpo"
+
+ success "--stable \"Stable upload\""
+ verifyMaintainer "dch --stable"
+}
+
+verifyEntryLines() {
+ success "--vendor Debian $1"
+ local changes="$(dpkg-parsechangelog -l"$CHANGELOG" -SChanges | grep -F '*')"
+ assertEquals "\"$changes\"" 1 "$(echo "$changes" | wc -l)"
+}
+
+# Any options which automatically add their own entry to the changelog should
+# elide an empty entry if the user passes an empty string as the entry.
+testEmptyMessage() {
+ rm -f "$CHANGELOG"
+ success "--create -D unstable --package test-package -v 1.0-1 'First upload'"
+
+ verifyEntryLines "--nmu ''"
+
+ verifyEntryLines "--bin-nmu ''"
+
+ verifyEntryLines "--qa ''"
+
+ verifyEntryLines "--security ''"
+
+ verifyEntryLines "--bpo ''"
+
+ verifyEntryLines "--team ''"
+}
+
+verifyGuessedDistribution() {
+ # $1 → initial suite
+ # $2 → action
+ # $3 → expected suite after the action
+ rm -f "$CHANGELOG"
+ vdeb="--vendor Debian"
+ success "$vdeb --create -D $1 --package test-package -v 1.0-1 'First upload'"
+ success "$vdeb $2 'Second Upload'"
+ success "$vdeb -r ''"
+ local dist="$(dpkg-parsechangelog -l"$CHANGELOG" -SDistribution)"
+ assertEquals "$3" "$dist"
+}
+
+testGuessedDistribution() {
+ verifyGuessedDistribution unstable -i unstable
+ verifyGuessedDistribution experimental -i experimental
+ verifyGuessedDistribution bookworm-backports -i bookworm-backports
+ verifyGuessedDistribution trixie -i trixie
+ verifyGuessedDistribution unstable --bpo bookworm-backports
+ verifyGuessedDistribution unstable --stable bookworm
+}
+
+testSpecialCharacterMaintainer() {
+ rm -f "$CHANGELOG"
+ export DEBFULLNAME='\k'
+ success "--create -D unstable --package test-package -v 1.0-1 \"First upload\""
+ success "-a \"Some change\""
+}
+
+. shunit2
diff --git a/test/test_debdiff b/test/test_debdiff
new file mode 100755
index 0000000..8043574
--- /dev/null
+++ b/test/test_debdiff
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+# Copyright (C) 2013, James McCoy <jamessan@debian.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+set -u
+
+if test "${1:-}" = --installed; then
+ COMMAND="debdiff --no-conf"
+ shift
+else
+ COMMAND="perl -I ${0%/*}/../lib ${0%/*}/../scripts/debdiff.pl --no-conf"
+fi
+
+WORKDIR="$(readlink -f "${0%/*}")"
+
+test() {
+ $COMMAND ${WORKDIR}/debdiff/devscripts_2.13.0_any.deb ${WORKDIR}/debdiff/devscripts_2.13.1_any.deb >/dev/null 2>/dev/null
+ rc=$?
+ assertEquals 'difference found, no errors' 1 $rc
+}
+
+. shunit2
diff --git a/test/test_debi b/test/test_debi
new file mode 100755
index 0000000..f3206f5
--- /dev/null
+++ b/test/test_debi
@@ -0,0 +1,285 @@
+#!/usr/bin/perl
+
+# Copyright 2019 Simon McVittie
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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, see <https://www.gnu.org/licenses/>.
+
+=head1 NAME
+
+test_debi - unit test for debi
+
+=head1 WARNING
+
+This test requires root privileges, and installs and removes packages.
+Please run it in an expendable environment, such as via
+one of the B<autopkgtest-virt-*> autopkgtest backends.
+
+=head1 DESCRIPTION
+
+This test verifies that debi's B<--with-depends> and B<--upgrade> interact
+as expected.
+
+=cut
+
+use autodie;
+use strict;
+use warnings;
+
+use Cwd qw(getcwd);
+use Digest::MD5;
+use Digest::SHA;
+use File::Temp qw(tempdir);
+use IPC::Run qw(run);
+use Test::More;
+
+use Dpkg::Control;
+
+my $srcdir = getcwd;
+my $top_srcdir = getcwd . '/..';
+my @debi = ("$top_srcdir/scripts/debi.pl", '--no-conf');
+my $tmp;
+
+if (defined $ARGV[0] && $ARGV[0] eq '--installed') {
+ $debi[0] = 'debi';
+}
+else {
+ $ENV{PATH} = "$top_srcdir/scripts:$ENV{PATH}";
+}
+
+sub verbose_run {
+ my $argv = shift;
+ diag("Running: @{$argv}");
+ my $ret = run($argv, @_);
+ if ($ret) {
+ diag("=> success");
+ } else {
+ diag("=> exit status $?");
+ }
+ return $ret;
+}
+
+sub capture {
+ my $output;
+ my $argv = shift;
+ ok(verbose_run($argv, '>', \$output), "@{$argv}");
+ chomp $output;
+ return $output;
+}
+
+sub make_deb {
+ my ($name, $version, $depends) = @_;
+ mkdir "$tmp/deb" unless -d "$tmp/deb";
+ mkdir "$tmp/deb/DEBIAN" unless -d "$tmp/deb/DEBIAN";
+ open my $fh, '>', "$tmp/deb/DEBIAN/control";
+ print {$fh} "Package: devscripts-test-$name\n";
+ print {$fh} "Section: misc\n";
+ print {$fh} "Priority: optional\n";
+ print {$fh} "Maintainer: nobody\n";
+ print {$fh} "Version: $version\n";
+ print {$fh} "Architecture: all\n";
+ print {$fh} "Depends: $depends\n";
+ print {$fh} "Description: a package\n";
+ close $fh;
+
+ my $deb = "$tmp/devscripts-test-${name}_${version}_all.deb";
+ if (!run(['dpkg-deb', '-b', "$tmp/deb", $deb])) {
+ BAIL_OUT("Failed to build $name package from $tmp/deb");
+ }
+}
+
+sub make_changes {
+ my @packages = @_;
+ my $changes = "$tmp/foo.changes";
+ my $ctrl = Dpkg::Control->new(type => CTRL_FILE_CHANGES);
+ $ctrl->{Format} = '1.8';
+ $ctrl->{Source} = 'devscripts-test';
+ $ctrl->{Files} = "\n";
+ $ctrl->{'Checksums-Sha256'} = "\n";
+
+ foreach my $name (@packages) {
+ my $md5 = Digest::MD5->new;
+ my $sha256 = Digest::SHA->new(256);
+ open my $fh, '<', "$tmp/devscripts-test-${name}_1_all.deb";
+ binmode $fh;
+ $md5->addfile($fh);
+ seek $fh, 0, 0;
+ $sha256->addfile(*$fh);
+ close $fh;
+ my $hash = $md5->hexdigest;
+ my @stat = stat "$tmp/devscripts-test-${name}_1_all.deb";
+ my $size = $stat[7];
+
+ $ctrl->{Files}
+ .= "$hash $size misc optional devscripts-test-${name}_1_all.deb\n";
+ $hash = $sha256->hexdigest;
+ $ctrl->{'Checksums-Sha256'}
+ .= "$hash $size devscripts-test-${name}_1_all.deb\n";
+ }
+ diag $ctrl;
+ $ctrl->save($changes);
+}
+
+sub purge_packages {
+ ok(
+ verbose_run([
+ 'dpkg',
+ '--purge',
+ 'devscripts-test-already-installed',
+ 'devscripts-test-dependency',
+ 'devscripts-test-gains-dependency',
+ 'devscripts-test-gains-local-dependency',
+ 'devscripts-test-not-installed',
+ 'hello',
+ ]));
+}
+
+sub version_of {
+ my $output;
+ my $ignored;
+ run(['dpkg-query', '-W', '-f', '${Version}', shift],
+ '>', \$output, '2>', \$ignored);
+ chomp $output;
+ return $output;
+}
+
+sub status_of {
+ my $output;
+ my $ignored;
+ run(['dpkg-query', '-W', '-f', '${Status}', shift],
+ '>', \$output, '2>', \$ignored);
+ chomp $output;
+ return $output;
+}
+
+plan skip_all => 'not root' unless $< == 0 && $> == 0;
+
+$tmp = tempdir(CLEANUP => 1);
+open my $fh, '>', "$tmp/yes.conf";
+print {$fh} qq{Apt::Get::Assume-Yes "true";\n};
+print {$fh} qq{Apt::Get::allow-downgrades "true";\n};
+close $fh;
+$ENV{APT_CONFIG} = "$tmp/yes.conf";
+
+make_deb('already-installed', '0', 'base-files');
+make_deb('already-installed', '1', 'base-files');
+make_deb('already-installed', '2', 'base-files');
+make_deb('not-installed', '1', 'base-files');
+make_deb('gains-local-dependency', '0', 'base-files');
+make_deb('gains-local-dependency', '1', 'devscripts-test-dependency');
+make_deb('dependency', '1', 'base-files');
+make_deb('gains-dependency', '0', 'base-files');
+make_deb('gains-dependency', '1', 'hello');
+
+diag('debi foo.changes will upgrade existing packages and install new ones');
+purge_packages();
+ok(
+ verbose_run(
+ ['dpkg', '-i', "$tmp/devscripts-test-already-installed_0_all.deb",]));
+make_changes(qw(already-installed not-installed));
+ok(verbose_run([@debi, "$tmp/foo.changes",]), 'plain debi succeeds');
+is(version_of('devscripts-test-already-installed'),
+ '1', 'already installed package was upgraded');
+is(version_of('devscripts-test-not-installed'),
+ '1', 'not-installed package was installed (regressed in #932640)');
+
+diag('debi foo.changes will also downgrade existing packages');
+purge_packages();
+ok(
+ verbose_run(
+ ['dpkg', '-i', "$tmp/devscripts-test-already-installed_2_all.deb",]));
+make_changes(qw(already-installed));
+ok(verbose_run([@debi, "$tmp/foo.changes",]), 'plain debi succeeds');
+is(version_of('devscripts-test-already-installed'),
+ '1', 'already installed package was downgraded');
+
+diag('debi --upgrade will upgrade/downgrade existing packages, only');
+purge_packages();
+ok(
+ verbose_run(
+ ['dpkg', '-i', "$tmp/devscripts-test-already-installed_2_all.deb",]));
+make_changes(qw(already-installed not-installed));
+ok(verbose_run([@debi, '--upgrade', "$tmp/foo.changes",]),
+ 'debi --upgrade succeeds');
+is(version_of('devscripts-test-already-installed'),
+ '1', 'already installed package was downgraded');
+is(version_of('devscripts-test-not-installed'),
+ '', 'not-installed package was not installed');
+
+diag('it is OK if debi --upgrade does nothing');
+purge_packages();
+make_changes(qw(not-installed));
+ok(verbose_run([@debi, '--upgrade', "$tmp/foo.changes",]),
+ 'debi --upgrade succeeds');
+is(version_of('devscripts-test-not-installed'),
+ '', 'not-installed package was not installed');
+
+diag('debi without --with-depends does not try to satisfy dependencies');
+purge_packages();
+ok(
+ verbose_run(
+ ['dpkg', '-i', "$tmp/devscripts-test-gains-dependency_0_all.deb",]));
+make_changes(qw(gains-dependency));
+ok(!verbose_run([@debi, "$tmp/foo.changes",]),
+ 'debi without --with-depends does not install dependency');
+# It's OK for it to either be unpacked but fail to configure, or be
+# left at version 0.
+isnt(
+ version_of('devscripts-test-gains-dependency') . "::"
+ . status_of('devscripts-test-gains-dependency'),
+ '1::install ok installed',
+ 'package with a dependency was not installed'
+);
+is(version_of('hello'), '', 'third party dependency was not installed');
+
+diag('debi --with-depends does satisfy dependencies');
+purge_packages();
+make_changes(qw(gains-dependency));
+ok(verbose_run([@debi, '--with-depends', "$tmp/foo.changes",]),
+ 'debi --with-depends succeeds');
+is(version_of('devscripts-test-gains-dependency'),
+ '1', 'package with a dependency was installed');
+isnt(version_of('hello'), '', 'third party dependency was installed');
+
+diag('debi --upgrade --with-depends does satisfy new dependencies');
+purge_packages();
+ok(
+ verbose_run(
+ ['dpkg', '-i', "$tmp/devscripts-test-gains-dependency_0_all.deb",]));
+make_changes(qw(gains-dependency not-installed));
+ok(verbose_run([@debi, '--with-depends', '--upgrade', "$tmp/foo.changes",]),
+ 'debi --with-depends --upgrade succeeds');
+is(version_of('devscripts-test-gains-dependency'),
+ '1', 'package with a dependency was installed');
+isnt(version_of('hello'), '', 'third party dependency was installed');
+is(version_of('devscripts-test-not-installed'),
+ '', 'not-installed package was not installed (#932963)');
+
+purge_packages();
+verbose_run(
+ ['dpkg', '-i', "$tmp/devscripts-test-gains-local-dependency_0_all.deb",]);
+make_changes(qw(dependency gains-local-dependency));
+ok(
+ verbose_run([@debi, '--upgrade', '--with-depends', "$tmp/foo.changes",]),
+ 'corner case from #932963: debi --upgrade --with-depends can cope with '
+ . 'a new dependency on a binary from the same source'
+);
+is(version_of('devscripts-test-gains-local-dependency'),
+ '1', 'the package we wanted to upgrade is upgraded');
+is(version_of('devscripts-test-dependency'),
+ '1',
+ 'the new dependency of the package we wanted to upgrade is installed');
+
+purge_packages();
+done_testing;
diff --git a/test/test_debrepro b/test/test_debrepro
new file mode 100755
index 0000000..077be1e
--- /dev/null
+++ b/test/test_debrepro
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+# Copyright (C) 2018, Antonio Terceiro <terceiro@debian.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+set -u
+
+DEB_HOST_OS="$(dpkg-architecture -qDEB_HOST_ARCH_OS)"
+if [ "$DEB_HOST_OS" = "kfreebsd" ]; then
+ # kbsd has a non-working semaphore, that is needed here.
+ echo "This test is not supported on $(dpkg-architecture -qDEB_HOST_ARCH), skipping"
+ exit 0
+fi
+
+if test "${1:-}" = --installed; then
+ debrepro="debrepro --skip filesystem-ordering"
+ shift
+else
+ debrepro="${0%/*}/../scripts/debrepro.sh --skip filesystem-ordering"
+fi
+
+samples="${0%/*}/debrepro"
+
+. "${0%/*}/test_helper.sh"
+
+test_reproducible() {
+ assertPasses $debrepro $samples/reproducible
+}
+
+test_unreproducible() {
+ assertFails $debrepro $samples/unreproducible
+}
+
+. shunit2
diff --git a/test/test_debsign b/test/test_debsign
new file mode 100755
index 0000000..9c7ccf5
--- /dev/null
+++ b/test/test_debsign
@@ -0,0 +1,114 @@
+#!/bin/sh
+
+# Copyright (C) 2018, Chris Lamb <lamby@debian.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+set -u
+
+WORKDIR="$(readlink -f "${0%/*}")"
+
+if test "${1:-}" = --installed; then
+ COMMAND="debsign --no-conf"
+ shift
+else
+ COMMAND="$WORKDIR/../scripts/debsign.sh --no-conf"
+fi
+
+GPG=gpg
+GPGHOME=$(mktemp -d -p /tmp gpg.XXXXX)
+if ! command -v $GPG >/dev/null 2>&1; then
+ echo "$GPG missing"
+ GPG=gpg2
+ if ! command -v $GPG >/dev/null 2>&1; then
+ echo "$GPG missing"
+ exit 1
+ fi
+fi
+
+oneTimeSetUp () {
+ $GPG -v --homedir "$GPGHOME" --no-options -q --batch --no-default-keyring \
+ --output $GPGHOME/secring.gpg --dearmor $WORKDIR/debsign/private_key.asc
+
+ $GPG -v --homedir "$GPGHOME" --no-options -q --batch --no-default-keyring \
+ --output $GPGHOME/pubring.gpg --dearmor $WORKDIR/debsign/public_key.asc
+
+ export GNUPGHOME=$GPGHOME
+}
+
+oneTimeTearDown () {
+ gpgconf --homedir "$GPGHOME" --verbose --kill gpg-agent
+ rm -rf "$GPGHOME"
+}
+
+setUp() {
+ TEMPDIR=$(mktemp -d -p /tmp debsign.XXXXX)
+ cp $WORKDIR/debsign/* $TEMPDIR
+ CHANGES=$(echo $TEMPDIR/*changes)
+}
+
+tearDown() {
+ rm -rf $TEMPDIR
+}
+
+assertSigned() {
+ expected=$1
+ shift
+ $COMMAND "$@" $CHANGES >$TEMPDIR/stdout 2>$TEMPDIR/stderr
+ rc=$?
+ assertEquals 'error code' $expected $rc
+}
+
+testEmailKeyID () {
+ assertSigned 0 -k none@debian.org
+}
+
+testShortKeyID () {
+ assertSigned 1 -k 72543FAF
+ assertTrue 'error not seen' "grep -q 'short key ID' $TEMPDIR/stderr"
+}
+
+testPrefixedShortKeyID () {
+ assertSigned 1 -k 0x72543FAF
+ assertTrue 'error not seen' "grep -q 'short key ID' $TEMPDIR/stderr"
+}
+
+testLongKeyID() {
+ assertSigned 0 -k C77E2D6872543FAF
+ assertTrue 'not signed' "grep -q 'BEGIN PGP SIGNATURE' $CHANGES"
+}
+
+testPrefixedLongKeyID() {
+ assertSigned 0 -k 0xC77E2D6872543FAF
+ assertTrue 'not signed' "grep -q 'BEGIN PGP SIGNATURE' $CHANGES"
+}
+
+testFingerprintKeyID () {
+ assertSigned 0 -k CF218F0E7EABF584B7E20402C77E2D6872543FAF
+}
+
+testUnknownKeyID () {
+ assertSigned 2 -k AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ assertTrue 'warning not seen' "grep -q 'No secret key' $TEMPDIR/stderr"
+}
+
+testNameKeyID () {
+ assertSigned 0 -k 'uscan test key (no secret)'
+}
+
+testFullNameAsKeyID () {
+ assertSigned 0 -k 'uscan test key (no secret) <none@debian.org>'
+}
+
+. shunit2
diff --git a/test/test_helper.sh b/test/test_helper.sh
new file mode 100644
index 0000000..579780c
--- /dev/null
+++ b/test/test_helper.sh
@@ -0,0 +1,26 @@
+setUp() {
+ tmpdir=$(mktemp -d)
+ log="$tmpdir/log"
+}
+
+tearDown() {
+ rm -rf "$tmpdir"
+}
+
+assertPasses() {
+ local rc=0
+ "$@" > "$log" 2>&1 || rc=$?
+ if [ "$rc" -ne 0 ]; then
+ cat "$log"
+ fail "command failed: «$*» (expected pass)"
+ fi
+}
+
+assertFails() {
+ local rc=0
+ "$@" > "$log" 2>&1 || rc=$?
+ if [ "$rc" -eq 0 ]; then
+ cat "$log"
+ fail "command passed: «$*» (expected fail)"
+ fi
+}
diff --git a/test/test_mass_bug b/test/test_mass_bug
new file mode 100755
index 0000000..b75386c
--- /dev/null
+++ b/test/test_mass_bug
@@ -0,0 +1,161 @@
+#!/usr/bin/perl
+
+# Copyright 2020 Simon McVittie
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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, see <https://www.gnu.org/licenses/>.
+
+use strict;
+use warnings;
+
+use Cwd qw(getcwd);
+use File::Temp qw(tempdir);
+use IPC::Run qw(run);
+use Test::More;
+
+# Disable l10n: we look for specific messages
+$ENV{LC_ALL} = 'C.UTF-8';
+
+my $srcdir = getcwd;
+my $top_srcdir = getcwd . '/..';
+my $mass_bug = "$top_srcdir/scripts/mass-bug.pl";
+
+if (defined $ARGV[0] && $ARGV[0] eq '--installed') {
+ $mass_bug = 'mass-bug';
+}
+
+my $tmp = tempdir(CLEANUP => 1);
+
+sub verbose_run {
+ my $argv = shift;
+ diag("Running: @{$argv}");
+ return run($argv, @_);
+}
+
+sub capture {
+ my $output;
+ my $argv = shift;
+ ok(verbose_run($argv, '>', \$output), "@{$argv}");
+ chomp $output;
+ return $output;
+}
+
+my $stdout;
+my $stderr;
+
+diag('Help');
+$stdout = capture([
+ $mass_bug,
+ '--help',
+]);
+like($stdout, qr{Usage:});
+
+diag('Version');
+$stdout = capture([
+ $mass_bug,
+ '--version',
+]);
+like($stdout, qr{devscripts package});
+
+diag('Basic use');
+$stdout = capture([
+ $mass_bug,
+ '--no-conf',
+ '--subject=Is broken',
+ "$srcdir/mass-bug/template",
+ "$srcdir/mass-bug/one-package",
+]);
+like($stdout, qr{^Subject: test-package: Is broken$}m);
+like($stdout, qr{^Package: test-package$}m);
+like($stdout, qr{^Version: 1\.2-3$}m);
+like($stdout, qr{^test-package has a bug\. Please fix\.$}m);
+like($stdout, qr{^This long line gets word-wrapped because}m);
+unlike($stdout, qr{text/plain; format=flowed never really took off\.$}m);
+like($stdout, qr{^These short lines also get wrapped\.$}m);
+like($stdout, qr{^test-package version=1\.2-3$}m);
+like($stdout, qr{^test-package epoch=$}m);
+like($stdout, qr{^test-package upstream=1\.2$}m);
+like($stdout, qr{^test-package revision=-3$}m);
+like($stdout, qr{^test-package reassembled=1\.2-3$}m);
+like($stdout, qr{^-- $}m);
+like($stdout, qr{^This signature does not get word-wrapped because it is a signature, even though it is longer than a line ought to be\.$}m);
+
+diag('Subject is mandatory');
+ok(! verbose_run([
+ $mass_bug,
+ '--no-conf',
+ "$srcdir/mass-bug/template",
+ "$srcdir/mass-bug/one-package",
+], '>', \$stdout, '2>', \$stderr));
+isnt($?, 0);
+like($stderr, qr{You must specify a subject}m);
+is($stdout, '');
+
+diag('Various options');
+$stdout = capture([
+ $mass_bug,
+ '--no-conf',
+ '--subject=Is broken',
+ '--source',
+ '--tags=ftbfs sid',
+ '--user=me@example.com',
+ '--usertags=bad wrong',
+ '--control=block 123456 by -1',
+ '--control=block -1 by 789012',
+ '--no-wrap',
+ "$srcdir/mass-bug/template",
+ "$srcdir/mass-bug/one-package",
+]);
+like($stdout, qr{^Subject: test-package: Is broken$}m);
+like($stdout, qr{^Source: test-package$}m);
+unlike($stdout, qr{^Package: test-package$}m);
+like($stdout, qr{^test-package has a bug\. Please fix\.$}m);
+like($stdout, qr{^Tags: ftbfs sid$}m);
+like($stdout, qr{^User: me\@example\.com$}m);
+like($stdout, qr{^Usertags: bad wrong$}m);
+like($stdout, qr{^Control: block 123456 by -1$}m);
+like($stdout, qr{^Control: block -1 by 789012$}m);
+like($stdout, qr{^This long line gets word-wrapped because text/plain; format=flowed never really took off\.$}m);
+unlike($stdout, qr{^These short lines also get wrapped\.$}m);
+
+diag('Version numbers');
+$stdout = capture([
+ $mass_bug,
+ '--no-conf',
+ '--subject=Is broken',
+ "$srcdir/mass-bug/template",
+ "$srcdir/mass-bug/packages",
+]);
+like($stdout, qr{^native-package version=1\.0$}m);
+like($stdout, qr{^native-package epoch=$}m);
+like($stdout, qr{^native-package upstream=1\.0$}m);
+like($stdout, qr{^native-package revision=$}m);
+like($stdout, qr{^native-package reassembled=1\.0$}m);
+like($stdout, qr{^upstream-package version=1\.2-3$}m);
+like($stdout, qr{^upstream-package epoch=$}m);
+like($stdout, qr{^upstream-package upstream=1\.2$}m);
+like($stdout, qr{^upstream-package revision=-3$}m);
+like($stdout, qr{^upstream-package reassembled=1\.2-3$}m);
+like($stdout, qr{^epoch-native-package version=1:2\.3$}m);
+like($stdout, qr{^epoch-native-package epoch=1:$}m);
+like($stdout, qr{^epoch-native-package upstream=2\.3$}m);
+like($stdout, qr{^epoch-native-package revision=$}m);
+like($stdout, qr{^epoch-native-package reassembled=1:2\.3$}m);
+like($stdout, qr{^epoch-package version=1:2\.3-4\.5$}m);
+like($stdout, qr{^epoch-package epoch=1:$}m);
+like($stdout, qr{^epoch-package upstream=2\.3$}m);
+like($stdout, qr{^epoch-package revision=-4\.5$}m);
+like($stdout, qr{^epoch-package reassembled=1:2\.3-4\.5$}m);
+
+done_testing;
diff --git a/test/test_mergechanges b/test/test_mergechanges
new file mode 100755
index 0000000..e689cd7
--- /dev/null
+++ b/test/test_mergechanges
@@ -0,0 +1,551 @@
+#!/usr/bin/perl
+
+# Copyright 2019 Simon McVittie
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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, see <https://www.gnu.org/licenses/>.
+
+use strict;
+use warnings;
+
+use Cwd qw(getcwd);
+use Data::Dumper;
+use File::Temp qw(tempdir);
+use IPC::Run qw(run);
+use Test::More;
+
+use Dpkg::Control;
+
+my $srcdir = getcwd;
+my $top_srcdir = getcwd . '/..';
+my $mergechanges = "$top_srcdir/scripts/mergechanges.sh";
+
+if (defined $ARGV[0] && $ARGV[0] eq '--installed') {
+ $mergechanges = 'mergechanges';
+}
+
+my $tmp = tempdir(CLEANUP => 1);
+my $stdout;
+my $stderr;
+my $fh;
+my $merged;
+my $all = 'xdg-desktop-portal_1.2.0-1_all.changes';
+my $amd64 = 'xdg-desktop-portal_1.2.0-1_amd64.changes';
+my $source = 'xdg-desktop-portal_1.2.0-1_source.changes';
+my %controls;
+my @words;
+my @lines;
+my $orig;
+
+sub verbose_run {
+ my $argv = shift;
+ diag("Running: @{$argv}");
+ return run($argv, @_);
+}
+
+sub capture {
+ my $output;
+ my $argv = shift;
+ ok(verbose_run($argv, '>', \$output), "@{$argv}");
+ chomp $output;
+ return $output;
+}
+
+sub uniq {
+ my %seen;
+ my @ret;
+ foreach my $member (@_) {
+ push @ret, $member unless defined $seen{$member};
+ $seen{$member} = 1;
+ }
+ return @ret;
+}
+
+sub verbose_is_deeply {
+ diag Dumper($_[0], $_[1]);
+ is_deeply(@_);
+}
+
+foreach my $name ($all, $amd64, $source) {
+ $controls{$name} = Dpkg::Control->new(type => CTRL_FILE_CHANGES);
+ $controls{$name}->load("mergechanges/$name");
+}
+
+diag('Help');
+$stdout = capture([
+ $mergechanges,
+ '--help',
+]);
+like($stdout, qr{Usage:});
+
+diag('Version');
+$stdout = capture([
+ $mergechanges,
+ '--version',
+]);
+like($stdout, qr{devscripts package});
+
+diag('Simple merge');
+$stdout = capture([
+ $mergechanges,
+ "mergechanges/$all",
+ "mergechanges/$amd64",
+ "mergechanges/$source",
+]);
+#diag $stdout;
+unlike($stdout, qr/BEGIN PGP/);
+unlike($stdout, qr/END PGP/);
+$merged = Dpkg::Control->new(type => CTRL_FILE_CHANGES);
+open($fh, '<', \$stdout);
+$merged->parse($fh, 'stdout of mergechanges');
+close($fh);
+is($merged->{Format}, $controls{$source}->{Format});
+is($merged->{Date}, $controls{$source}->{Date});
+is($merged->{Source}, $controls{$source}->{Source});
+@words = sort split / /, $merged->{Binary};
+is_deeply(\@words, [sort qw(
+ xdg-desktop-portal
+ xdg-desktop-portal-dbgsym
+ xdg-desktop-portal-dev
+ xdg-desktop-portal-tests
+ xdg-desktop-portal-tests-dbgsym
+)]);
+@words = sort split / /, $merged->{Architecture};
+is_deeply(\@words, [sort qw(amd64 all source)]);
+is($merged->{Version}, $controls{$source}->{Version});
+is($merged->{Distribution}, $controls{$source}->{Distribution});
+is($merged->{Urgency}, $controls{$source}->{Urgency});
+is($merged->{Maintainer}, $controls{$source}->{Maintainer});
+is($merged->{'Changed-By'}, $controls{$source}->{'Changed-By'});
+isnt($merged->{Description}, undef);
+@lines = sort split /\n/, $merged->{Description};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$all}->{Description}),
+ (split /\n/, $controls{$amd64}->{Description}),
+))]);
+is($merged->{Changes}, $controls{$source}->{Changes});
+@lines = sort split /\n/, $merged->{Files};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$all}->{Files}),
+ (split /\n/, $controls{$amd64}->{Files}),
+ (split /\n/, $controls{$source}->{Files}),
+))]);
+@lines = sort split /\n/, $merged->{'Checksums-Sha1'};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$all}->{'Checksums-Sha1'}),
+ (split /\n/, $controls{$amd64}->{'Checksums-Sha1'}),
+ (split /\n/, $controls{$source}->{'Checksums-Sha1'}),
+))]);
+@lines = sort split /\n/, $merged->{'Checksums-Sha256'};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$all}->{'Checksums-Sha256'}),
+ (split /\n/, $controls{$amd64}->{'Checksums-Sha256'}),
+ (split /\n/, $controls{$source}->{'Checksums-Sha256'}),
+))]);
+
+diag('Source only');
+$stdout = capture([
+ $mergechanges,
+ '-S',
+ "mergechanges/$all",
+ "mergechanges/$amd64",
+ "mergechanges/$source",
+]);
+#diag $stdout;
+unlike($stdout, qr/BEGIN PGP/);
+unlike($stdout, qr/END PGP/);
+$merged = Dpkg::Control->new(type => CTRL_FILE_CHANGES);
+open($fh, '<', \$stdout);
+$merged->parse($fh, 'stdout of mergechanges');
+close($fh);
+is($merged->{Format}, $controls{$source}->{Format});
+is($merged->{Date}, $controls{$source}->{Date});
+is($merged->{Source}, $controls{$source}->{Source});
+is($merged->{Binary}, undef);
+@words = sort split / /, $merged->{Architecture};
+is_deeply(\@words, [sort qw(source)]);
+is($merged->{Version}, $controls{$source}->{Version});
+is($merged->{Distribution}, $controls{$source}->{Distribution});
+is($merged->{Urgency}, $controls{$source}->{Urgency});
+is($merged->{Maintainer}, $controls{$source}->{Maintainer});
+is($merged->{'Changed-By'}, $controls{$source}->{'Changed-By'});
+is($merged->{Description}, undef);
+is($merged->{Changes}, $controls{$source}->{Changes});
+@lines = sort split /\n/, $merged->{Files};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$source}->{Files}),
+))]);
+@lines = sort split /\n/, $merged->{'Checksums-Sha1'};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$source}->{'Checksums-Sha1'}),
+))]);
+@lines = sort split /\n/, $merged->{'Checksums-Sha256'};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$source}->{'Checksums-Sha256'}),
+))]);
+
+diag('Indep only');
+$stdout = capture([
+ $mergechanges,
+ '-i',
+ "mergechanges/$all",
+ "mergechanges/$amd64",
+ "mergechanges/$source",
+]);
+#diag $stdout;
+unlike($stdout, qr/BEGIN PGP/);
+unlike($stdout, qr/END PGP/);
+$merged = Dpkg::Control->new(type => CTRL_FILE_CHANGES);
+open($fh, '<', \$stdout);
+$merged->parse($fh, 'stdout of mergechanges');
+close($fh);
+is($merged->{Format}, $controls{$source}->{Format});
+is($merged->{Date}, $controls{$source}->{Date});
+is($merged->{Source}, $controls{$source}->{Source});
+is($merged->{Binary}, 'xdg-desktop-portal-dev');
+@words = sort split / /, $merged->{Architecture};
+is_deeply(\@words, [sort qw(all source)]);
+is($merged->{Version}, $controls{$source}->{Version});
+is($merged->{Distribution}, $controls{$source}->{Distribution});
+is($merged->{Urgency}, $controls{$source}->{Urgency});
+is($merged->{Maintainer}, $controls{$source}->{Maintainer});
+is($merged->{'Changed-By'}, $controls{$source}->{'Changed-By'});
+isnt($merged->{Description}, undef);
+@lines = sort split /\n/, $merged->{Description};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$all}->{Description}),
+))]);
+is($merged->{Changes}, $controls{$source}->{Changes});
+@lines = sort split /\n/, $merged->{Files};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$source}->{Files}),
+ (split /\n/, $controls{$all}->{Files}),
+))]);
+@lines = sort split /\n/, $merged->{'Checksums-Sha1'};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$source}->{'Checksums-Sha1'}),
+ (split /\n/, $controls{$all}->{'Checksums-Sha1'}),
+))]);
+@lines = sort split /\n/, $merged->{'Checksums-Sha256'};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$source}->{'Checksums-Sha256'}),
+ (split /\n/, $controls{$all}->{'Checksums-Sha256'}),
+))]);
+
+diag('To file');
+ok(run(['cp', "mergechanges/$source", "$tmp/source.changes"]));
+$stdout = capture([
+ $mergechanges,
+ '-f',
+ "$tmp/source.changes",
+ "mergechanges/$all",
+]);
+ok(-e "$tmp/source.changes");
+is($stdout, '');
+#system("cat", "$tmp/xdg-desktop-portal_1.2.0-1_multi.changes");
+$merged = Dpkg::Control->new(type => CTRL_FILE_CHANGES);
+$merged->load("$tmp/xdg-desktop-portal_1.2.0-1_multi.changes");
+is($merged->{Format}, $controls{$source}->{Format});
+is($merged->{Date}, $controls{$source}->{Date});
+is($merged->{Source}, $controls{$source}->{Source});
+is($merged->{Binary}, 'xdg-desktop-portal-dev');
+@words = sort split / /, $merged->{Architecture};
+is_deeply(\@words, [sort qw(all source)]);
+is($merged->{Version}, $controls{$source}->{Version});
+is($merged->{Distribution}, $controls{$source}->{Distribution});
+is($merged->{Urgency}, $controls{$source}->{Urgency});
+is($merged->{Maintainer}, $controls{$source}->{Maintainer});
+is($merged->{'Changed-By'}, $controls{$source}->{'Changed-By'});
+isnt($merged->{Description}, undef);
+@lines = sort split /\n/, $merged->{Description};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$all}->{Description}),
+))]);
+is($merged->{Changes}, $controls{$source}->{Changes});
+@lines = sort split /\n/, $merged->{Files};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$source}->{Files}),
+ (split /\n/, $controls{$all}->{Files}),
+))]);
+@lines = sort split /\n/, $merged->{'Checksums-Sha1'};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$source}->{'Checksums-Sha1'}),
+ (split /\n/, $controls{$all}->{'Checksums-Sha1'}),
+))]);
+@lines = sort split /\n/, $merged->{'Checksums-Sha256'};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$source}->{'Checksums-Sha256'}),
+ (split /\n/, $controls{$all}->{'Checksums-Sha256'}),
+))]);
+
+diag('Deleting');
+ok(run(['cp', "mergechanges/$source", "$tmp/source.changes"]));
+ok(run(['cp', "mergechanges/$all", "$tmp/all.changes"]));
+$stdout = capture([
+ $mergechanges,
+ '-d',
+ '-f',
+ "$tmp/source.changes",
+ "$tmp/all.changes",
+]);
+ok(! -e "$tmp/source.changes");
+ok(! -e "$tmp/all.changes");
+is($stdout, '');
+#system("cat", "$tmp/xdg-desktop-portal_1.2.0-1_multi.changes");
+$merged = Dpkg::Control->new(type => CTRL_FILE_CHANGES);
+$merged->load("$tmp/xdg-desktop-portal_1.2.0-1_multi.changes");
+is($merged->{Format}, $controls{$source}->{Format});
+is($merged->{Date}, $controls{$source}->{Date});
+is($merged->{Source}, $controls{$source}->{Source});
+is($merged->{Binary}, 'xdg-desktop-portal-dev');
+@words = sort split / /, $merged->{Architecture};
+is_deeply(\@words, [sort qw(all source)]);
+is($merged->{Version}, $controls{$source}->{Version});
+is($merged->{Distribution}, $controls{$source}->{Distribution});
+is($merged->{Urgency}, $controls{$source}->{Urgency});
+is($merged->{Maintainer}, $controls{$source}->{Maintainer});
+is($merged->{'Changed-By'}, $controls{$source}->{'Changed-By'});
+isnt($merged->{Description}, undef);
+@lines = sort split /\n/, $merged->{Description};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$all}->{Description}),
+))]);
+is($merged->{Changes}, $controls{$source}->{Changes});
+@lines = sort split /\n/, $merged->{Files};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$source}->{Files}),
+ (split /\n/, $controls{$all}->{Files}),
+))]);
+@lines = sort split /\n/, $merged->{'Checksums-Sha1'};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$source}->{'Checksums-Sha1'}),
+ (split /\n/, $controls{$all}->{'Checksums-Sha1'}),
+))]);
+@lines = sort split /\n/, $merged->{'Checksums-Sha256'};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$source}->{'Checksums-Sha256'}),
+ (split /\n/, $controls{$all}->{'Checksums-Sha256'}),
+))]);
+
+diag('Merge with itself');
+$stdout = capture([
+ $mergechanges,
+ '--indep',
+ "mergechanges/$all",
+ "mergechanges/$all",
+]);
+#diag $stdout;
+unlike($stdout, qr/BEGIN PGP/);
+unlike($stdout, qr/END PGP/);
+$merged = Dpkg::Control->new(type => CTRL_FILE_CHANGES);
+open($fh, '<', \$stdout);
+$merged->parse($fh, 'stdout of mergechanges');
+close($fh);
+is($merged->{Format}, $controls{$source}->{Format});
+is($merged->{Date}, $controls{$source}->{Date});
+is($merged->{Source}, $controls{$source}->{Source});
+is($merged->{Binary}, 'xdg-desktop-portal-dev');
+@words = sort split / /, $merged->{Architecture};
+is_deeply(\@words, [sort qw(all)]);
+is($merged->{Version}, $controls{$source}->{Version});
+is($merged->{Distribution}, $controls{$source}->{Distribution});
+is($merged->{Urgency}, $controls{$source}->{Urgency});
+is($merged->{Maintainer}, $controls{$source}->{Maintainer});
+is($merged->{'Changed-By'}, $controls{$source}->{'Changed-By'});
+isnt($merged->{Description}, undef);
+@lines = sort split /\n/, $merged->{Description};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$all}->{Description}),
+))]);
+is($merged->{Changes}, $controls{$source}->{Changes});
+@lines = sort split /\n/, $merged->{Files};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$all}->{Files}),
+))]);
+@lines = sort split /\n/, $merged->{'Checksums-Sha1'};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$all}->{'Checksums-Sha1'}),
+))]);
+@lines = sort split /\n/, $merged->{'Checksums-Sha256'};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$all}->{'Checksums-Sha256'}),
+))]);
+
+diag('Format 1.7 and 1.8 are compatible');
+$stdout = capture([
+ $mergechanges,
+ '--indep',
+ "mergechanges/$all",
+ "mergechanges/format-1.7.changes",
+]);
+diag $stdout;
+unlike($stdout, qr/BEGIN PGP/);
+unlike($stdout, qr/END PGP/);
+$merged = Dpkg::Control->new(type => CTRL_FILE_CHANGES);
+open($fh, '<', \$stdout);
+$merged->parse($fh, 'stdout of mergechanges');
+close($fh);
+# Formats 1.8 and 1.7 merge to 1.7
+is($merged->{Format}, '1.7');
+is($merged->{Date}, $controls{$source}->{Date});
+is($merged->{Source}, $controls{$source}->{Source});
+is($merged->{Binary}, 'xdg-desktop-portal-dev');
+@words = sort split / /, $merged->{Architecture};
+is_deeply(\@words, [sort qw(all)]);
+is($merged->{Version}, $controls{$source}->{Version});
+is($merged->{Distribution}, $controls{$source}->{Distribution});
+is($merged->{Urgency}, $controls{$source}->{Urgency});
+is($merged->{Maintainer}, $controls{$source}->{Maintainer});
+is($merged->{'Changed-By'}, $controls{$source}->{'Changed-By'});
+isnt($merged->{Description}, undef);
+@lines = sort split /\n/, $merged->{Description};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$all}->{Description}),
+))]);
+is($merged->{Changes}, $controls{$source}->{Changes});
+@lines = sort split /\n/, $merged->{Files};
+is_deeply(\@lines, [sort(uniq(
+ (split /\n/, $controls{$all}->{Files}),
+))]);
+# Format 1.7 didn't have Checksums-*
+is($merged->{'Checksums-Sha1'}, undef);
+is($merged->{'Checksums-Sha256'}, undef);
+
+diag('Only one');
+ok(! verbose_run([
+ $mergechanges,
+ "mergechanges/$source",
+], '>', \$stdout, '2>', \$stderr));
+is($stdout, '');
+like($stderr, qr{Not enough parameters});
+
+diag('ENOENT');
+ok(! verbose_run([
+ $mergechanges,
+ "mergechanges/$source",
+ "mergechanges/does-not-exist.changes",
+], '>', \$stdout, '2>', \$stderr));
+is($stdout, '');
+like($stderr, qr{ERROR: Cannot read mergechanges/does-not-exist\.changes});
+
+diag('Different description');
+ok(! verbose_run([
+ $mergechanges,
+ "mergechanges/$all",
+ "mergechanges/different-description.changes",
+], '>', \$stdout, '2>', \$stderr));
+is($stdout, '');
+like($stderr, qr{Error: Descriptions do not match});
+
+diag('Different format');
+ok(! verbose_run([
+ $mergechanges,
+ "mergechanges/$all",
+ "mergechanges/unsupported-format.changes",
+], '>', \$stdout, '2>', \$stderr));
+is($stdout, '');
+like($stderr, qr{Error: Changes files have different Format fields});
+
+diag('Different source package');
+ok(! verbose_run([
+ $mergechanges,
+ "mergechanges/$all",
+ "mergechanges/different-source.changes",
+], '>', \$stdout, '2>', \$stderr));
+is($stdout, '');
+like($stderr, qr{Error: Source packages do not match});
+
+diag('Different version');
+ok(! verbose_run([
+ $mergechanges,
+ "mergechanges/$all",
+ "mergechanges/different-version.changes",
+], '>', \$stdout, '2>', \$stderr));
+is($stdout, '');
+like($stderr, qr{ERROR: Version numbers do not match});
+
+diag('Unsupported checksums');
+ok(! verbose_run([
+ $mergechanges,
+ "mergechanges/$all",
+ "mergechanges/unsupported-checksum.changes",
+], '>', \$stdout, '2>', \$stderr));
+is($stdout, '');
+like($stderr, qr{Error: Unsupported checksum fields});
+
+diag('Unsupported format');
+ok(! verbose_run([
+ $mergechanges,
+ "mergechanges/unsupported-format.changes",
+ "mergechanges/unsupported-format.changes",
+], '>', \$stdout, '2>', \$stderr));
+is($stdout, '');
+like($stderr, qr{Error: Changes files use unknown Format});
+
+diag('Multi-line Binary');
+$stdout = capture([
+ $mergechanges,
+ '--indep',
+ 'mergechanges/linux_4.9.161-1_amd64.changes',
+ 'mergechanges/linux_4.9.161-1_amd64.changes',
+]);
+unlike($stdout, qr/BEGIN PGP/);
+unlike($stdout, qr/END PGP/);
+$merged = Dpkg::Control->new(type => CTRL_FILE_CHANGES);
+open($fh, '<', \$stdout);
+$merged->parse($fh, 'stdout of mergechanges');
+close($fh);
+$orig = Dpkg::Control->new(type => CTRL_FILE_CHANGES);
+$orig->load('mergechanges/linux_4.9.161-1_amd64.changes');
+is($merged->{Format}, $orig->{Format});
+is($merged->{Date}, $orig->{Date});
+is($merged->{Source}, $orig->{Source});
+@words = sort split / /, $merged->{Binary};
+is_deeply(\@words, [sort qw(
+ linux-doc-4.9
+ linux-headers-4.9.0-9-common
+ linux-headers-4.9.0-9-common-rt
+ linux-manual-4.9
+ linux-source-4.9
+ linux-support-4.9.0-9
+)]);
+@words = sort split / /, $merged->{Architecture};
+is_deeply(\@words, [sort qw(all source)]);
+is($merged->{Version}, $orig->{Version});
+is($merged->{Distribution}, $orig->{Distribution});
+is($merged->{Urgency}, $orig->{Urgency});
+is($merged->{Maintainer}, $orig->{Maintainer});
+is($merged->{'Changed-By'}, $orig->{'Changed-By'});
+isnt($merged->{Description}, undef);
+@lines = sort split /\n/, $merged->{Description};
+is_deeply(\@lines, [sort(uniq(
+ grep({m/^$/ || m/^(linux-doc-4.9|linux-headers-4.9.0-9-common|linux-headers-4.9.0-9-common-rt|linux-manual-4.9|linux-source-4.9|linux-support-4.9.0-9) - /} (split /\n/, $orig->{Description})),
+))]);
+is($merged->{Changes}, $orig->{Changes});
+@lines = sort split /\n/, $merged->{Files};
+is_deeply(\@lines, [sort(uniq(
+ grep({! /_amd64\./} (split /\n/, $orig->{Files})),
+))]);
+@lines = sort split /\n/, $merged->{'Checksums-Sha1'};
+is_deeply(\@lines, [sort(uniq(
+ grep({! /_amd64\./} (split /\n/, $orig->{'Checksums-Sha1'})),
+))]);
+@lines = sort split /\n/, $merged->{'Checksums-Sha256'};
+is_deeply(\@lines, [sort(uniq(
+ grep({! /_amd64\./} (split /\n/, $orig->{'Checksums-Sha256'})),
+))]);
+
+done_testing;
+
+# vim:set sts=4 sw=4 et:
diff --git a/test/test_mk-origtargz b/test/test_mk-origtargz
new file mode 100755
index 0000000..1aa8f1e
--- /dev/null
+++ b/test/test_mk-origtargz
@@ -0,0 +1,750 @@
+#!/bin/bash
+
+# Copyright 2014, Rafael Laboissiere <rafael@laboissiere.net>
+# Copyright 2015, James McCoy <jamessan@debian.org>
+
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at your
+# option) any later version.
+#
+# 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.
+#
+# On Debian systems, the complete text of the GNU General Public License
+# version 3 can be found in the /usr/share/common-licenses/GPL-3 file.
+
+set -u
+
+# Load GPG
+TESTTYPE=MkOrigTarGz
+. ./lib_test_uscan
+
+if test "${1:-}" = --installed; then
+ MK_ORIGTARGZ="mk-origtargz"
+ shift
+else
+ top_srcdir=$(readlink -f "${0%/*}/..")
+ make -C "$top_srcdir/scripts" mk-origtargz
+ MK_ORIGTARGZ="perl -I $top_srcdir/lib $top_srcdir/scripts/mk-origtargz"
+ PATH="$top_srcdir/scripts:$PATH"
+ export PATH
+ PERL5LIB="$top_srcdir/lib"
+ export PERL5LIB
+fi
+PROGNAME="mk-origtargz"
+
+LC_ALL=C
+export LC_ALL
+
+setUp () {
+ TMPDIR=$(mktemp -d -p "$SHUNIT_TMPDIR" test_mk-origtargz.XXXX)
+}
+
+
+makeSubDir () {
+ dir=$1
+ shift
+
+ mkdir -p "$TMPDIR/foo-0.1/$dir"
+ touch "$TMPDIR/foo-0.1/$dir/a-file"
+ mkdir "$TMPDIR/foo-0.1/$dir/a-subdir"
+ touch "$TMPDIR/foo-0.1/$dir/a-subdir/a-file"
+}
+
+
+makeUpstreamFiles () {
+ mkdir -p "$TMPDIR/foo-0.1"
+ touch "$TMPDIR/foo-0.1/include-this-file"
+ touch "$TMPDIR/foo-0.1/exclude-this-file"
+ touch "$TMPDIR/foo-0.1/.include-this-hidden-file"
+ touch "$TMPDIR/foo-0.1/.exclude-this-hidden-file"
+
+ makeSubDir "include-this-dir"
+ makeSubDir "exclude-this-dir"
+ makeSubDir "exclude-dir1"
+ makeSubDir "exclude-dir2"
+ makeSubDir ".include-this-hidden-dir"
+ makeSubDir ".exclude-this-hidden-dir"
+ makeSubDir "a-dir/include-this-subdir"
+ # Expected not to be removed since exclusion is anchored to top-level
+ makeSubDir "a-dir/exclude-this-subdir"
+
+ touch "$TMPDIR/foo-0.1/; echo strange-file; #"
+
+}
+
+makeGolangLikeVendorFiles() {
+ makeSubDir "vendor"
+
+ mkdir -p "$TMPDIR/foo-0.1/vendor/includeme"
+ touch "$TMPDIR/foo-0.1/vendor/includeme/important.go"
+}
+
+makeTarBall () {
+ comp="$1"
+ mkgpg="${2:-none}"
+ makeUpstreamFiles
+ COMP="--auto-compress"
+ if [ "$comp" = "zst" ]; then
+ COMP=--zstd
+ fi
+ tar --create $COMP --file "$TMPDIR/foo-0.1.tar.$comp" --directory "$TMPDIR" foo-0.1
+ local gpgopts=(
+ chronic_sh $GPG
+ --homedir "$GPGHOME"
+ --no-options -q --batch --no-default-keyring
+ --secret-keyring "$PRIVATE_KEYRING"
+ --default-key 72544FAF
+ --detach-sign
+ )
+ case "$mkgpg" in
+ sig)
+ "${gpgopts[@]}" "$TMPDIR/foo-0.1.tar.$comp"
+ ;;
+ asc)
+ "${gpgopts[@]}" --armor "$TMPDIR/foo-0.1.tar.$comp"
+ ;;
+ none)
+ ;;
+ *)
+ fail "unknown parameter in makeTarBall()"
+ ;;
+ esac
+ rm -rf "$TMPDIR/foo-0.1"
+}
+makeSimpleTar () {
+ makeUpstreamFiles
+ tar --create --file "$TMPDIR/foo-0.1.tar" --directory "$TMPDIR" foo-0.1
+ rm -rf "$TMPDIR/foo-0.1"
+}
+makeBrokenTarBall () {
+ echo foo > foo.txt
+ tar cf - foo.txt | sed -e 's/^/foo/' | gzip > "$TMPDIR/foo-0.1.tar.gz"
+ rm -f foo.txt
+}
+
+makeZipFile () {
+ makeUpstreamFiles
+ (cd $TMPDIR >/dev/null; zip -q -r "foo-0.1.zip" foo-0.1 )
+ rm -rf "$TMPDIR/foo-0.1"
+}
+
+makeJarFile () {
+ makeUpstreamFiles
+ cat > "$TMPDIR/MANIFEST.MF" <<END
+Manifest-Version: 1.0
+Main-Class: foo.bar
+END
+ (cd $TMPDIR >/dev/null; jar cf "foo-0.1.jar" MANIFEST.MF foo-0.1 )
+ rm -rf "$TMPDIR/foo-0.1" "$TMPDIR/MANIFEST.MF"
+}
+
+makeDebianChangelog() {
+ mkdir -p $TMPDIR/foo/debian
+ cat <<END > $TMPDIR/foo/debian/changelog
+foo (0.1-1) unstable; urgency=low
+
+ * Initial release
+
+ -- Joe Developer <jd@debian.org> Mon, 02 Nov 2013 22:21:31 -0100
+END
+}
+
+makeDebianOldDir() {
+ makeDebianChangelog
+}
+
+makeDebianDir() {
+ makeDebianChangelog
+ mkdir -p $TMPDIR/foo/debian/source
+ echo -n "3.0 (quilt)" > $TMPDIR/foo/debian/source/format
+}
+
+makeDebianCopyright() {
+ cat <<'END' > $TMPDIR/foo/debian/copyright
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Files-Excluded: exclude-this*
+ .exclude-this*
+ exclude-dir1
+ exclude-dir2/
+ ;?echo?strange-file;?#
+END
+
+}
+
+makeWrongDebianCopyright() {
+ cat <<'END' > $TMPDIR/foo/debian/copyright
+Format: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=174
+Files-Excluded: exclude-this*
+ .exclude-this*
+ exclude-dir1
+ exclude-dir2/
+ ;?echo?strange-file;?#
+END
+
+}
+
+makeUnmatchedExcludeCopyright() {
+ cat <<'END' > $TMPDIR/foo/debian/copyright
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Files-Excluded: exclude-this*
+ .exclude-this*
+ exclude-dir1
+ exclude-dir2
+ ;?echo?strange-file;?#
+ nomatch
+END
+}
+
+
+makeDuplicatePatternCopyright() {
+ cat <<'END' > $TMPDIR/foo/debian/copyright
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Files-Excluded: exclude-this*
+ .exclude-this*
+ exclude-dir1
+ exclude-dir*
+ ;?echo?strange-file;?#
+END
+}
+
+expected_stderr_after_removal="mk-origtargz warn: Files-Excluded pattern (exclude-dir2/) should not have a trailing /"
+
+expected_files_after_removal=$(LC_ALL=C sort <<END
+foo-0.1/
+foo-0.1/a-dir/
+foo-0.1/a-dir/exclude-this-subdir/
+foo-0.1/a-dir/exclude-this-subdir/a-file
+foo-0.1/a-dir/exclude-this-subdir/a-subdir/
+foo-0.1/a-dir/exclude-this-subdir/a-subdir/a-file
+foo-0.1/a-dir/include-this-subdir/
+foo-0.1/a-dir/include-this-subdir/a-file
+foo-0.1/a-dir/include-this-subdir/a-subdir/
+foo-0.1/a-dir/include-this-subdir/a-subdir/a-file
+foo-0.1/include-this-dir/
+foo-0.1/include-this-dir/a-file
+foo-0.1/include-this-dir/a-subdir/
+foo-0.1/include-this-dir/a-subdir/a-file
+foo-0.1/include-this-file
+foo-0.1/.include-this-hidden-dir/
+foo-0.1/.include-this-hidden-dir/a-file
+foo-0.1/.include-this-hidden-dir/a-subdir/
+foo-0.1/.include-this-hidden-dir/a-subdir/a-file
+foo-0.1/.include-this-hidden-file
+END
+)
+
+run_mk_origtargz() {
+ local dir="$1"
+ local exp_stderr="$2"
+ local exp_stdout="$3"
+ local stderrF="${SHUNIT_TMPDIR}/stderr"
+ shift
+ shift
+ shift
+ output="$( cd $TMPDIR/$dir >/dev/null; LC_ALL=C $MK_ORIGTARGZ "$@" 2> $stderrF )"
+ stderr="$(cat $stderrF)"
+ retval=$?
+ assertEquals "standard output of mk-origtargz $*\n" "$exp_stdout" "$output"
+ assertEquals "error output of mk-origtargz $*\n" "$exp_stderr" "$stderr"
+ assertEquals "return valueof mk-origtargz $*\n" "0" "$retval"
+}
+
+assertType () {
+ mime="$1"
+ file="$2"
+ actual="$(file --brief --mime-type "$file" | sed -e 's,/x-,/,')"
+ assertEquals "filetype for $(basename "$file")" "$mime" "$actual"
+}
+
+
+testSymlink() {
+ makeTarBall gz
+ makeDebianDir
+ run_mk_origtargz foo "" \
+ "Successfully symlinked ../foo-0.1.tar.gz to ../foo_0.1.orig.tar.gz." \
+ ../foo-0.1.tar.gz
+ assertTrue "original tarball does not exist" "[ -e $TMPDIR/foo-0.1.tar.gz ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertTrue "result is not a symlink" "[ -L $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertTrue "result is not readable" "[ -r $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertEquals "final symlink" foo-0.1.tar.gz "$(readlink $TMPDIR/foo_0.1.orig.tar.gz)"
+}
+
+testSymlinkWithConvertedSig() {
+ makeTarBall gz sig
+ makeDebianDir
+ run_mk_origtargz foo "" \
+ "Successfully symlinked ../foo-0.1.tar.gz to ../foo_0.1.orig.tar.gz." \
+ --signature 1 --signature-file=../foo-0.1.tar.gz.sig \
+ ../foo-0.1.tar.gz
+ assertTrue "original tarball does not exist" "[ -e $TMPDIR/foo-0.1.tar.gz ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertTrue "result is not a symlink" "[ -L $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertTrue "result is not readable" "[ -r $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertEquals "final symlink" foo-0.1.tar.gz "$(readlink $TMPDIR/foo_0.1.orig.tar.gz)"
+ assertTrue "signature isn't valid" "$GPG --homedir '$GPGHOME' --verify $TMPDIR/foo_0.1.orig.tar.gz.asc"
+}
+
+testSymlinkWithArmoredSig() {
+ # MR for https://lists.debian.org/debian-devel/2019/04/msg00459.html
+ makeTarBall gz asc
+ # an armored signature, but with the wrong extension.
+ mv $TMPDIR/foo-0.1.tar.gz.asc $TMPDIR/foo-0.1.tar.gz.sig
+ makeDebianDir
+ run_mk_origtargz foo "" \
+ "Successfully symlinked ../foo-0.1.tar.gz to ../foo_0.1.orig.tar.gz." \
+ --signature 1 --signature-file=../foo-0.1.tar.gz.sig \
+ ../foo-0.1.tar.gz
+ assertTrue "original tarball does not exist" "[ -e $TMPDIR/foo-0.1.tar.gz ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertTrue "result is not a symlink" "[ -L $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertTrue "result is not readable" "[ -r $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertEquals "final symlink" foo-0.1.tar.gz "$(readlink $TMPDIR/foo_0.1.orig.tar.gz)"
+ assertTrue "signature isn't valid" "$GPG --homedir '$GPGHOME' --verify $TMPDIR/foo_0.1.orig.tar.gz.asc"
+}
+
+testCopy() {
+ makeTarBall gz
+ makeDebianDir
+ run_mk_origtargz foo "" \
+ "Successfully copied ../foo-0.1.tar.gz to ../foo_0.1.orig.tar.gz." \
+ --copy ../foo-0.1.tar.gz
+ assertTrue "original tarball does not exist" "[ -e $TMPDIR/foo-0.1.tar.gz ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertFalse "result is a symlink" "[ -L $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertTrue "result is not readable" "[ -r $TMPDIR/foo_0.1.orig.tar.gz ]"
+}
+
+testRename() {
+ makeTarBall gz
+ makeDebianDir
+ run_mk_origtargz foo "" \
+ "Successfully renamed ../foo-0.1.tar.gz to ../foo_0.1.orig.tar.gz." \
+ --rename ../foo-0.1.tar.gz
+ assertFalse "original tarball does exist" "[ -e $TMPDIR/foo-0.1.tar.gz ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertFalse "result is a symlink" "[ -L $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertTrue "result is not readable" "[ -r $TMPDIR/foo_0.1.orig.tar.gz ]"
+}
+
+testSymlinkExplicit() {
+ makeTarBall gz
+ run_mk_origtargz "" "" \
+ "Successfully symlinked foo-0.1.tar.gz to foo_0.1.orig.tar.gz." \
+ --package foo --version 0.1 foo-0.1.tar.gz
+ assertTrue "original tarball does not exist" "[ -e $TMPDIR/foo-0.1.tar.gz ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertTrue "result is not a symlink" "[ -L $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertTrue "result is not readable" "[ -r $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertEquals "final symlink" foo-0.1.tar.gz "$(readlink $TMPDIR/foo_0.1.orig.tar.gz)"
+}
+
+testCopyExplicit() {
+ makeTarBall gz
+ run_mk_origtargz "" "" \
+ "Successfully copied foo-0.1.tar.gz to foo_0.1.orig.tar.gz." \
+ --package foo --version 0.1 --copy foo-0.1.tar.gz
+ assertTrue "original tarball does not exist" "[ -e $TMPDIR/foo-0.1.tar.gz ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertFalse "result is a symlink" "[ -L $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertTrue "result is not readable" "[ -r $TMPDIR/foo_0.1.orig.tar.gz ]"
+}
+
+testRenameExplicit() {
+ makeTarBall gz
+ run_mk_origtargz "" "" \
+ "Successfully renamed foo-0.1.tar.gz to foo_0.1.orig.tar.gz." \
+ --package foo --version 0.1 --rename foo-0.1.tar.gz
+ assertFalse "original tarball does exist" "[ -e $TMPDIR/foo-0.1.tar.gz ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertFalse "result is a symlink" "[ -L $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertTrue "result is not readable" "[ -r $TMPDIR/foo_0.1.orig.tar.gz ]"
+}
+
+testSymlinkExplicitSubdir() {
+ makeTarBall gz
+ mkdir -p $TMPDIR/destdir
+ run_mk_origtargz "" "" \
+ "Successfully symlinked foo-0.1.tar.gz to destdir/foo_0.1.orig.tar.gz." \
+ --package foo --version 0.1 -C destdir foo-0.1.tar.gz
+ assertTrue "original tarball does not exist" "[ -e $TMPDIR/foo-0.1.tar.gz ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/destdir/foo_0.1.orig.tar.gz ]"
+ assertTrue "result is not a symlink" "[ -L $TMPDIR/destdir/foo_0.1.orig.tar.gz ]"
+ assertTrue "result is not readable" "[ -r $TMPDIR/destdir/foo_0.1.orig.tar.gz ]"
+ assertEquals "final symlink" ../foo-0.1.tar.gz "$(readlink $TMPDIR/destdir/foo_0.1.orig.tar.gz)"
+}
+
+testRepackGZ2GZ() {
+ makeTarBall gz
+ run_mk_origtargz "" "" \
+ "Successfully copied foo-0.1.tar.gz to foo_0.1.orig.tar.gz." \
+ --package foo --version 0.1 --copy foo-0.1.tar.gz --repack --compression gzip
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertType application/gzip $TMPDIR/foo_0.1.orig.tar.gz
+}
+
+testForceRepackGZ2XZ() {
+ makeTarBall gz
+ makeDebianDir
+ run_mk_origtargz foo "" \
+ "Successfully repacked ../foo-0.1.tar.gz as ../foo_0.1.orig.tar.gz." \
+ --force-repack ../foo-0.1.tar.gz --compression gzip
+ assertTrue "original tarball does not exist" "[ -e $TMPDIR/foo-0.1.tar.gz ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertTrue "result is not a file" "[ -f $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertTrue "result is not readable" "[ -r $TMPDIR/foo_0.1.orig.tar.gz ]"
+}
+
+testRepackGZ2XZ() {
+ makeTarBall gz
+ run_mk_origtargz "" ""\
+ "Successfully repacked foo-0.1.tar.gz as foo_0.1.orig.tar.xz." \
+ --package foo --version 0.1 --copy foo-0.1.tar.gz --repack
+ assertFalse "wrong result does exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.xz ]"
+ assertType application/xz $TMPDIR/foo_0.1.orig.tar.xz
+}
+
+testRepackXZ2GZ() {
+ makeTarBall xz
+ run_mk_origtargz "" "" \
+ "Successfully repacked foo-0.1.tar.xz as foo_0.1.orig.tar.gz." \
+ --package foo --version 0.1 --copy foo-0.1.tar.xz --repack --compression gzip
+ assertFalse "wrong result does exist" "[ -e $TMPDIR/foo_0.1.orig.tar.xz ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertType application/gzip $TMPDIR/foo_0.1.orig.tar.gz
+}
+
+testRepackZST2XZRepackOpt() {
+ makeTarBall zst
+ run_mk_origtargz "" ""\
+ "Successfully repacked foo-0.1.tar.zst as foo_0.1.orig.tar.xz." \
+ --package foo --version 0.1 --copy foo-0.1.tar.zst --repack
+ assertFalse "wrong result does exist" "[ -e $TMPDIR/foo_0.1.orig.tar.zst ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.xz ]"
+ assertType application/xz $TMPDIR/foo_0.1.orig.tar.xz
+}
+
+testRepackZST2XZNoRepackOpt() {
+ makeTarBall zst
+ run_mk_origtargz "" ""\
+ "Successfully repacked foo-0.1.tar.zst as foo_0.1.orig.tar.xz." \
+ --package foo --version 0.1 --copy foo-0.1.tar.zst
+ assertFalse "wrong result does exist" "[ -e $TMPDIR/foo_0.1.orig.tar.zst ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.xz ]"
+ assertType application/xz $TMPDIR/foo_0.1.orig.tar.xz
+}
+
+testRepackZST2ZSTFail() {
+ makeTarBall zst
+ run_mk_origtargz "" "mk-origtargz error: Bad value for compression: Unknown compression scheme zst"\
+ "" \
+ --package foo --version 0.1 --copy foo-0.1.tar.zst --compression zst
+ assertFalse "wrong result does exist" "[ -e $TMPDIR/foo_0.1.orig.tar.zst ]"
+ assertFalse "result does exist" "[ -e $TMPDIR/foo_0.1.orig.tar.xz ]"
+}
+
+testRepackZip2GZ() {
+ makeZipFile
+ run_mk_origtargz "" "" \
+ "Successfully repacked foo-0.1.zip as foo_0.1.orig.tar.gz." \
+ --package foo --version 0.1 --copy foo-0.1.zip --compression gzip
+ assertTrue "original zip file does not exist" "[ -e $TMPDIR/foo-0.1.zip ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertType application/gzip $TMPDIR/foo_0.1.orig.tar.gz
+}
+
+testRepackJar2GZ() {
+ if ! command -v jar >/dev/null
+ then
+ # skip to avoid dependency on java-jdk
+ return
+ fi
+ makeJarFile
+ run_mk_origtargz "" "" \
+ "Successfully repacked foo-0.1.jar as foo_0.1.orig.tar.gz." \
+ --package foo --version 0.1 --copy foo-0.1.jar --compression gzip
+ assertTrue "original zip file does not exist" "[ -e $TMPDIR/foo-0.1.jar ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertType application/gzip $TMPDIR/foo_0.1.orig.tar.gz
+}
+
+testRepackZip2GZRename() {
+ makeZipFile
+ run_mk_origtargz "" "" \
+ "Successfully repacked foo-0.1.zip as foo_0.1.orig.tar.gz, and removed the original file." \
+ --package foo --version 0.1 --rename foo-0.1.zip --compression gzip
+ assertFalse "original zip file does exist" "[ -e $TMPDIR/foo-0.1.zip ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertType application/gzip $TMPDIR/foo_0.1.orig.tar.gz
+}
+
+testRepackZip2XZ() {
+ makeZipFile
+ run_mk_origtargz "" "" \
+ "Successfully repacked foo-0.1.zip as foo_0.1.orig.tar.xz." \
+ --package foo --version 0.1 foo-0.1.zip
+ assertTrue "original zip file does not exist" "[ -e $TMPDIR/foo-0.1.zip ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.xz ]"
+ assertType application/xz $TMPDIR/foo_0.1.orig.tar.xz
+}
+
+testRepackXpi2XZ() {
+ makeZipFile
+ mv $TMPDIR/foo-0.1.zip $TMPDIR/foo-0.1.xpi
+ run_mk_origtargz "" "" \
+ "Successfully repacked foo-0.1.xpi as foo_0.1.orig.tar.xz." \
+ --package foo --version 0.1 foo-0.1.xpi
+ assertTrue "original xpi file does not exist" "[ -e $TMPDIR/foo-0.1.xpi ]"
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.xz ]"
+ assertType application/xz $TMPDIR/foo_0.1.orig.tar.xz
+}
+
+testRepackTAR2XZ() {
+ makeSimpleTar
+ run_mk_origtargz "" "" \
+ "Successfully repacked foo-0.1.tar as foo_0.1.orig.tar.xz." \
+ --package foo --version 0.1 --copy foo-0.1.tar --repack
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.xz ]"
+ assertType application/xz $TMPDIR/foo_0.1.orig.tar.xz
+}
+testOldFormat() {
+ makeTarBall xz
+ makeDebianOldDir
+ makeDebianCopyright
+ run_mk_origtargz foo "mk-origtargz warn: Missing debian/source/format, switch compression to gzip
+$expected_stderr_after_removal" \
+ "Successfully repacked ../foo-0.1.tar.xz as ../foo_0.1.orig.tar.gz, deleting 19 files from it." \
+ ../foo-0.1.tar.xz
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertType application/gzip $TMPDIR/foo_0.1.orig.tar.gz
+ assertEquals "file contents" "$expected_files_after_removal" "$(tar taf $TMPDIR/foo_0.1.orig.tar.gz | sort)"
+}
+
+testExclude() {
+ makeTarBall gz
+ makeDebianDir
+ makeDebianCopyright
+ run_mk_origtargz foo "$expected_stderr_after_removal" \
+ "Successfully repacked ../foo-0.1.tar.gz as ../foo_0.1.orig.tar.xz, deleting 19 files from it." \
+ ../foo-0.1.tar.gz
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.xz ]"
+ assertType application/xz $TMPDIR/foo_0.1.orig.tar.xz
+ assertEquals "file contents" "$expected_files_after_removal" "$(tar taf $TMPDIR/foo_0.1.orig.tar.xz | sort)"
+}
+
+testGoVendorIncludeIgnore () {
+ makeGolangLikeVendorFiles
+ makeTarBall gz
+ makeDebianDir
+ makeDebianCopyright
+
+ # adjust existing test cases slightly
+ cat <<'END' >> $TMPDIR/foo/debian/copyright
+ vendor
+Files-Included:
+ vendor/includeme
+END
+
+ expected_files=$(LC_ALL=C sort <<END
+$expected_files_after_removal
+foo-0.1/vendor/
+foo-0.1/vendor/a-subdir/
+foo-0.1/vendor/includeme/
+foo-0.1/vendor/includeme/important.go
+END
+)
+
+ run_mk_origtargz foo "$expected_stderr_after_removal" \
+ "Successfully repacked ../foo-0.1.tar.gz as ../foo_0.1.orig.tar.xz, deleting 21 files from it." \
+ ../foo-0.1.tar.gz
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.xz ]"
+ assertType application/xz $TMPDIR/foo_0.1.orig.tar.xz
+ assertEquals "file contents" "$expected_files" "$(tar taf $TMPDIR/foo_0.1.orig.tar.xz | sort)"
+}
+
+testExcludeXZ() {
+ makeTarBall xz
+ makeDebianDir
+ makeDebianCopyright
+ run_mk_origtargz foo "$expected_stderr_after_removal" \
+ "Successfully repacked ../foo-0.1.tar.xz as ../foo_0.1.orig.tar.xz, deleting 19 files from it." \
+ ../foo-0.1.tar.xz
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.xz ]"
+ assertType application/xz $TMPDIR/foo_0.1.orig.tar.xz
+ assertEquals "file contents" "$expected_files_after_removal" "$(tar taf $TMPDIR/foo_0.1.orig.tar.xz | sort)"
+}
+
+testExcludeZip() {
+ makeZipFile
+ makeDebianDir
+ makeDebianCopyright
+ run_mk_origtargz foo "$expected_stderr_after_removal" \
+ "Successfully repacked ../foo-0.1.zip as ../foo_0.1.orig.tar.xz, deleting 19 files from it." \
+ ../foo-0.1.zip
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.xz ]"
+ assertType application/xz $TMPDIR/foo_0.1.orig.tar.xz
+ assertEquals "file contents" "$expected_files_after_removal" "$(tar taf $TMPDIR/foo_0.1.orig.tar.xz | sort)"
+}
+
+testSuffix() {
+ makeTarBall gz
+ makeDebianDir
+ makeDebianCopyright
+ run_mk_origtargz foo "$expected_stderr_after_removal" \
+ "Successfully repacked ../foo-0.1.tar.gz as ../foo_0.1+dfsg1.orig.tar.xz, deleting 19 files from it." \
+ ../foo-0.1.tar.gz --repack-suffix +dfsg1
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1+dfsg1.orig.tar.xz ]"
+ assertType application/xz $TMPDIR/foo_0.1+dfsg1.orig.tar.xz
+ assertEquals "file contents" "$expected_files_after_removal" "$(tar taf $TMPDIR/foo_0.1+dfsg1.orig.tar.xz | sort)"
+}
+
+testSuffixXZ() {
+ makeTarBall xz
+ makeDebianDir
+ makeDebianCopyright
+ run_mk_origtargz foo "$expected_stderr_after_removal" \
+ "Successfully repacked ../foo-0.1.tar.xz as ../foo_0.1+dfsg1.orig.tar.xz, deleting 19 files from it." \
+ ../foo-0.1.tar.xz --repack-suffix +dfsg1
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1+dfsg1.orig.tar.xz ]"
+ assertType application/xz $TMPDIR/foo_0.1+dfsg1.orig.tar.xz
+ assertEquals "file contents" "$expected_files_after_removal" "$(tar taf $TMPDIR/foo_0.1+dfsg1.orig.tar.xz | sort)"
+}
+
+testSuffixZip() {
+ makeZipFile
+ makeDebianDir
+ makeDebianCopyright
+ run_mk_origtargz foo "$expected_stderr_after_removal" \
+ "Successfully repacked ../foo-0.1.zip as ../foo_0.1+dfsg1.orig.tar.xz, deleting 19 files from it." \
+ ../foo-0.1.zip --repack-suffix +dfsg1
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1+dfsg1.orig.tar.xz ]"
+ assertType application/xz $TMPDIR/foo_0.1+dfsg1.orig.tar.xz
+ assertEquals "file contents" "$expected_files_after_removal" "$(tar taf $TMPDIR/foo_0.1+dfsg1.orig.tar.xz | sort)"
+}
+
+testSuffixNoExclusions() {
+ makeTarBall gz
+ makeDebianDir
+ run_mk_origtargz foo "" \
+ "Successfully renamed ../foo-0.1.tar.gz to ../foo_0.1.orig.tar.gz." \
+ ../foo-0.1.tar.gz --rename --repack-suffix +dfsg1
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+}
+
+testSameNameSymlink() {
+ makeTarBall gz
+ mv $TMPDIR/foo-0.1.tar.gz $TMPDIR/foo_0.1.orig.tar.gz
+ makeDebianDir
+ run_mk_origtargz foo "" \
+ "Leaving ../foo_0.1.orig.tar.gz where it is." \
+ --symlink ../foo_0.1.orig.tar.gz
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertFalse "result is a symlink" "[ -L $TMPDIR/foo_0.1.orig.tar.gz ]"
+}
+
+testSameNameCopy() {
+ makeTarBall gz
+ mv $TMPDIR/foo-0.1.tar.gz $TMPDIR/foo_0.1.orig.tar.gz
+ makeDebianDir
+ run_mk_origtargz foo "" \
+ "Leaving ../foo_0.1.orig.tar.gz where it is." \
+ --copy ../foo_0.1.orig.tar.gz
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertFalse "result is a symlink" "[ -L $TMPDIR/foo_0.1.orig.tar.gz ]"
+}
+
+testSameNameRename() {
+ makeTarBall gz
+ mv $TMPDIR/foo-0.1.tar.gz $TMPDIR/foo_0.1.orig.tar.gz
+ makeDebianDir
+ run_mk_origtargz foo "" \
+ "Leaving ../foo_0.1.orig.tar.gz where it is." \
+ --rename ../foo_0.1.orig.tar.gz
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertFalse "result is a symlink" "[ -L $TMPDIR/foo_0.1.orig.tar.gz ]"
+}
+
+testSameNameExclude() {
+ makeTarBall gz
+ mv $TMPDIR/foo-0.1.tar.gz $TMPDIR/foo_0.1.orig.tar.gz
+ makeDebianDir
+ makeDebianCopyright
+ run_mk_origtargz foo "$expected_stderr_after_removal" \
+ "Leaving ../foo_0.1.orig.tar.gz where it is, deleting 19 files from it." \
+ ../foo_0.1.orig.tar.gz --compression=gzip
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertFalse "result is a symlink" "[ -L $TMPDIR/foo_0.1.orig.tar.gz ]"
+ assertEquals "file contents" "$expected_files_after_removal" "$(tar taf $TMPDIR/foo_0.1.orig.tar.gz | sort)"
+}
+
+testSameNameExcludeSymlink() {
+ makeTarBall xz
+ ln -s foo-0.1.tar.xz $TMPDIR/foo_0.1.orig.tar.xz
+ makeDebianDir
+ makeDebianCopyright
+ run_mk_origtargz foo "$expected_stderr_after_removal" \
+ "Leaving ../foo_0.1.orig.tar.xz where it is, deleting 19 files from it." \
+ ../foo_0.1.orig.tar.xz
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.xz ]"
+ assertTrue "result is not a symlink" "[ -L $TMPDIR/foo_0.1.orig.tar.xz ]"
+ assertEquals "file contents" "$expected_files_after_removal" "$(tar taf $TMPDIR/foo_0.1.orig.tar.xz | sort)"
+}
+
+testCopyrightFormatWarning() {
+ makeTarBall gz
+ makeDebianDir
+ makeWrongDebianCopyright
+ run_mk_origtargz foo \
+ "mk-origtargz warn: The file debian/copyright mentions Files-Excluded, but its format is not recognized. Specify Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ in order to remove files from the tarball with mk-origtargz." \
+ "Successfully symlinked ../foo-0.1.tar.gz to ../foo_0.1.orig.tar.gz." \
+ ../foo-0.1.tar.gz
+
+}
+
+testBrokenTarWarning() {
+ makeBrokenTarBall
+ makeDebianDir
+ if dpkg --compare-versions $(dpkg-query -W -f='${Version}' libdpkg-perl) lt 1.19.0~; then
+ local SUBPROCESS_ERROR="gave error exit status 2"
+ else
+ local SUBPROCESS_ERROR="subprocess returned exit status 2"
+ fi
+ run_mk_origtargz foo \
+ "tar: This does not look like a tar archive
+tar: Skipping to next header
+tar: Exiting with failure status due to previous errors
+$PROGNAME: error: tar --list --auto-compress --file ../foo_0.1.orig.tar.xz $SUBPROCESS_ERROR" \
+ "" \
+ ../foo-0.1.tar.gz --repack
+}
+
+testUnmatchedExclusion() {
+ makeTarBall gz
+ makeDebianDir
+ makeUnmatchedExcludeCopyright
+ run_mk_origtargz foo "mk-origtargz warn: No files matched excluded pattern as the last matching glob: nomatch" \
+ "Successfully repacked ../foo-0.1.tar.gz as ../foo_0.1.orig.tar.xz, deleting 19 files from it." \
+ ../foo-0.1.tar.gz
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.xz ]"
+ assertType application/xz $TMPDIR/foo_0.1.orig.tar.xz
+ assertEquals "file contents" "$expected_files_after_removal" "$(tar taf $TMPDIR/foo_0.1.orig.tar.xz | sort)"
+}
+
+testDuplicatePattern() {
+ makeTarBall gz
+ makeDebianDir
+ makeDuplicatePatternCopyright
+ run_mk_origtargz foo "mk-origtargz warn: No files matched excluded pattern as the last matching glob: exclude-dir1" \
+ "Successfully repacked ../foo-0.1.tar.gz as ../foo_0.1.orig.tar.xz, deleting 19 files from it." \
+ ../foo-0.1.tar.gz
+ assertTrue "result does not exist" "[ -e $TMPDIR/foo_0.1.orig.tar.xz ]"
+ assertType application/xz $TMPDIR/foo_0.1.orig.tar.xz
+ assertEquals "file contents" "$expected_files_after_removal" "$(tar taf $TMPDIR/foo_0.1.orig.tar.xz | sort)"
+}
+
+. shunit2
diff --git a/test/test_package_lifecycle b/test/test_package_lifecycle
new file mode 100755
index 0000000..9ed7485
--- /dev/null
+++ b/test/test_package_lifecycle
@@ -0,0 +1,386 @@
+#!/bin/bash
+
+# Copyright (C) 2015, Nicholas Bamber <nicholas@periapt.co.uk>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+set -u
+
+WORKDIR=$(readlink -f "${0%/*}")
+_ARCH=$(dpkg-architecture -qDEB_BUILD_ARCH)
+declare -r _ARCH
+if dpkg --compare-versions "$(dpkg-query -W -f='${Version}' dpkg-dev )" lt "1.19.1~"; then
+ echo "This test requires dpkg-dev >= 1.19.1." >&2
+ exit 1
+fi
+if dpkg --compare-versions "$(dpkg-query -W -f='${Version}' dpkg-dev )" lt "1.21.0~"; then
+ _dpkg_genchanges="dpkg-genchanges >"
+elif dpkg --compare-versions "$(dpkg-query -W -f='${Version}' dpkg-dev )" eq "1.21.0"; then
+ echo "This version of dpkg produces incorrect output, not supported" >&2
+ exit 1
+else
+ _dpkg_genchanges="dpkg-genchanges -O"
+fi
+declare -r _dpkg_genchanges
+
+if test "${1:-}" = --installed; then
+ shift
+else
+ PATH=${WORKDIR}/../scripts:${PATH}
+ PERL5LIB=${WORKDIR}/../lib:${PERL5LIB:-}
+ export PATH PERL5LIB
+fi
+
+. "${0%/*}/shunit2-helper-functions.sh"
+
+GPGHOME=$(mktemp -d -p /tmp gpg.XXXXX)
+
+oneTimeSetUp () {
+ GPG=gpg
+ if ! command -v $GPG >/dev/null 2>&1;then
+ echo "$GPG missing"
+ GPG=gpg2
+ if ! command -v $GPG >/dev/null 2>&1;then
+ echo "$GPG missing"
+ exit 1
+ fi
+ fi
+
+ PRIVATE_KEY=${WORKDIR}/uscan/PRIVATE_KEY.asc
+ PUBLIC_KEY=${WORKDIR}/uscan/PUBLIC_KEY.asc
+
+ PRIVATE_KEYRING=$GPGHOME/secring.gpg
+ PUBLIC_KEYRING=$GPGHOME/pubring.gpg
+
+ $GPG -v --homedir "$GPGHOME" --no-options -q --batch --no-default-keyring \
+ --output $PRIVATE_KEYRING --dearmor $PRIVATE_KEY
+
+ $GPG -v --homedir "$GPGHOME" --no-options -q --batch --no-default-keyring \
+ --output $PUBLIC_KEYRING --dearmor $PUBLIC_KEY
+
+ $GPG --homedir "$GPGHOME" --no-options -q --batch --no-default-keyring \
+ --secret-keyring $PRIVATE_KEYRING --default-key 72543FAF \
+ --list-keys --verbose
+
+ mkdir -p ${WORKDIR}/package_lifecycle/test/debian/source
+ cat > ${WORKDIR}/package_lifecycle/test/debian/control <<-EOS
+ Source: test
+ Section: devel
+ Priority: optional
+ Maintainer: Devscripts Devel Team <devscripts-devel@lists.alioth.debian.org>
+ Uploaders: Testophilus Testownik <tester@testity.org>
+ Standards-Version: 4.5.0
+ Rules-Requires-Root: no
+
+ Package: test
+ Architecture: all
+ Description: Short description
+ Longer description
+EOS
+ printf '#!/usr/bin/make -f\n%%:\n\tdh $@' > ${WORKDIR}/package_lifecycle/test/debian/rules
+ chmod +x ${WORKDIR}/package_lifecycle/test/debian/rules
+ _DATE=$(LC_ALL=C date '+%a, %d %b %Y %T +0000')
+ cat > ${WORKDIR}/package_lifecycle/test/debian/changelog <<-EOS
+ test (1.0-1) unstable; urgency=low
+
+ * Initial packaging
+
+ -- Testophilus Testownik <tester@testity.org> ${_DATE}
+EOS
+ echo 12 > ${WORKDIR}/package_lifecycle/test/debian/compat
+ echo '3.0 (quilt)' > ${WORKDIR}/package_lifecycle/test/debian/source/format
+ touch ${WORKDIR}/package_lifecycle/test/CONTENTS
+ cd ${WORKDIR}/package_lifecycle/ && tar cvf test_1.0.orig.tar --exclude debian -- test/CONTENTS 2>&1 > /dev/null && xz -f test_1.0.orig.tar
+ cd ${WORKDIR}
+}
+
+runCommandOutCmpFile() {
+ local param="$1"
+ local exp_stdoutfile="$2"
+ local exp_stderr="$3"
+ local exp_retval=$4
+ local stdoutF="${SHUNIT_TMPDIR}/stdout"
+ local stderrF="${SHUNIT_TMPDIR}/stderr"
+ eval "${COMMAND} $param" 2> ${stderrF} | \
+ grep -v File::FcntlLock | \
+ grep -v '^ *dh_' | \
+ grep -v '^dh_gencontrol debug symbol wrapper:' | \
+ grep -v '^ *create-stamp debian/debhelper' | \
+ sed -e "s/\`/'/g" | \
+ sed -e "s/^dpkg-buildpackage: info: /dpkg-buildpackage: /g" | \
+ sed -e "s/^dpkg-genchanges: info: /dpkg-genchanges: /g" | \
+ sed -e "/^ dpkg-genbuildinfo/d" | \
+ sed -e "/^gpg: /d" | \
+ sed -e's!^ -- Testophilus Testownik <tester@testity.org>.*! -- Testophilus Testownik <tester@testity.org>!' > ${stdoutF}
+ retval=$?
+ eval "cmp ${stdoutF} ${exp_stdoutfile}" 3>&1 >/dev/null
+ local diffretval=$?
+ assertEquals "standard output of ${COMMAND} $param matches ${exp_stdoutfile}\n" "0" "$diffretval" || diff ${stdoutF} ${exp_stdoutfile}
+ assertEquals "error output of ${COMMAND} $param\n" "$exp_stderr" "$(cat ${stderrF})"
+ assertEquals "return value of ${COMMAND} $param\n" $exp_retval $retval
+}
+
+
+test_debuild() {
+ export GNUPGHOME=$GPGHOME
+ cd ${WORKDIR}/package_lifecycle/test
+ COMMAND='LC_ALL=C debuild --no-conf --no-lintian --preserve-envvar=PATH --preserve-envvar=PERL5LIB --preserve-envvar=DEBFULLNAME --preserve-envvar=DEBEMAIL --preserve-envvar=GNUPGHOME --set-envvar=NO_PKG_MANGLE=1'
+ cat > ${WORKDIR}/package_lifecycle/debuild.txt <<-EOS
+ dpkg-buildpackage -us -uc -ui
+ dpkg-buildpackage: source package test
+ dpkg-buildpackage: source version 1.0-1
+ dpkg-buildpackage: source distribution unstable
+ dpkg-buildpackage: source changed by Testophilus Testownik <tester@testity.org>
+ dpkg-source --before-build .
+ dpkg-buildpackage: host architecture ${_ARCH}
+ debian/rules clean
+ dh clean
+ dpkg-source -b .
+ dpkg-source: info: using source format '3.0 (quilt)'
+ dpkg-source: info: building test using existing ./test_1.0.orig.tar.xz
+ dpkg-source: info: building test in test_1.0-1.debian.tar.xz
+ dpkg-source: info: building test in test_1.0-1.dsc
+ debian/rules binary
+ dh binary
+ dpkg-deb: building package 'test' in '../test_1.0-1_all.deb'.
+ ${_dpkg_genchanges}../test_1.0-1_${_ARCH}.changes
+ dpkg-genchanges: including full source code in upload
+ dpkg-source --after-build .
+ dpkg-buildpackage: full upload (original source is included)
+ Now signing changes and any dsc files...
+EOS
+ if command -v dpkg-genbuildinfo >/dev/null; then
+ cat >> ${WORKDIR}/package_lifecycle/debuild.txt <<-EOS
+ signfile dsc test_1.0-1.dsc uscan test key (no secret) <none@debian.org>
+
+ fixup_buildinfo test_1.0-1.dsc test_1.0-1_${_ARCH}.buildinfo
+ signfile buildinfo test_1.0-1_${_ARCH}.buildinfo uscan test key (no secret) <none@debian.org>
+
+ fixup_changes dsc test_1.0-1.dsc test_1.0-1_${_ARCH}.changes
+ fixup_changes buildinfo test_1.0-1_${_ARCH}.buildinfo test_1.0-1_${_ARCH}.changes
+ signfile changes test_1.0-1_${_ARCH}.changes uscan test key (no secret) <none@debian.org>
+
+ Successfully signed dsc, buildinfo, changes files
+EOS
+ else
+ cat >> ${WORKDIR}/package_lifecycle/debuild.txt <<-EOS
+ signfile dsc test_1.0-1.dsc uscan test key (no secret) <none@debian.org>
+
+ fixup_changes dsc test_1.0-1.dsc test_1.0-1_${_ARCH}.changes
+ signfile changes test_1.0-1_${_ARCH}.changes uscan test key (no secret) <none@debian.org>
+
+ Successfully signed dsc, changes files
+EOS
+ fi
+ runCommandOutCmpFile "-k'uscan test key (no secret) <none@debian.org>'" "${WORKDIR}/package_lifecycle/debuild.txt" "" 0
+ cd ${WORKDIR}
+}
+
+test_dscverify () {
+ cd ${WORKDIR}/package_lifecycle
+ COMMAND='dscverify --no-conf --keyring $GPGHOME/pubring.gpg'
+ cat > ${WORKDIR}/package_lifecycle/dscverify.txt <<-EOS
+ ${WORKDIR}/package_lifecycle/test_1.0-1.dsc:
+ Good signature found
+ validating test_1.0.orig.tar.xz
+ validating test_1.0-1.debian.tar.xz
+ All files validated successfully.
+EOS
+ runCommandOutCmpFile "${WORKDIR}/package_lifecycle/test_1.0-1.dsc" "${WORKDIR}/package_lifecycle/dscverify.txt" "" 0
+ cd ${WORKDIR}
+}
+
+test_dscextractControl () {
+ cd ${WORKDIR}/package_lifecycle
+ COMMAND='dscextract'
+ cat > ${WORKDIR}/package_lifecycle/dscextractControl.txt <<-EOS
+ Source: test
+ Section: devel
+ Priority: optional
+ Maintainer: Devscripts Devel Team <devscripts-devel@lists.alioth.debian.org>
+ Uploaders: Testophilus Testownik <tester@testity.org>
+ Standards-Version: 4.5.0
+ Rules-Requires-Root: no
+
+ Package: test
+ Architecture: all
+ Description: Short description
+ Longer description
+EOS
+ runCommandOutCmpFile "test_1.0-1.dsc debian/control" "dscextractControl.txt" "" 0
+ cd ${WORKDIR}
+}
+
+test_dscextractChangelog () {
+ cd ${WORKDIR}/package_lifecycle
+ COMMAND='dscextract'
+ cat > ${WORKDIR}/package_lifecycle/dscextractChangelog.txt <<-EOS
+ test (1.0-1) unstable; urgency=low
+
+ * Initial packaging
+
+ -- Testophilus Testownik <tester@testity.org>
+EOS
+ runCommandOutCmpFile "test_1.0-1.dsc debian/changelog" "dscextractChangelog.txt" "" 0
+ cd ${WORKDIR}
+}
+
+test_debchange () {
+ cd ${WORKDIR}/package_lifecycle/test
+ COMMAND='debchange'
+ export DEBFULLNAME='Testophilus Testownik'
+ export DEBEMAIL='tester@testity.org'
+ cat > ${WORKDIR}/package_lifecycle/debchange.txt <<-EOS
+ test (1.0-2) UNRELEASED; urgency=medium
+
+ * new killer app functionality
+
+ -- Testophilus Testownik <tester@testity.org>
+
+ test (1.0-1) unstable; urgency=low
+
+ * Initial packaging
+
+ -- Testophilus Testownik <tester@testity.org>
+EOS
+ runCommand "-iU 'new killer app functionality'" "" "" 0
+ COMMAND=cat
+ runCommandOutCmpFile "debian/changelog" "../debchange.txt" "" 0
+ cd ${WORKDIR}
+}
+
+test_list_unreleased () {
+ cd ${WORKDIR}/package_lifecycle/test
+ COMMAND='list-unreleased'
+ cat > ${WORKDIR}/package_lifecycle/list-unreleased.txt <<-EOS
+ test (1.0-2) UNRELEASED; urgency=medium
+
+ * new killer app functionality
+
+ -- Testophilus Testownik <tester@testity.org>
+EOS
+ runCommandOutCmpFile "-c -R" "../list-unreleased.txt" "" 0
+ cd ${WORKDIR}
+}
+
+
+test_debuild2() {
+ export GNUPGHOME=$GPGHOME
+ cd ${WORKDIR}/package_lifecycle/test
+ COMMAND='LC_ALL=C debuild --no-conf --no-lintian --preserve-envvar=PATH --preserve-envvar=PERL5LIB --preserve-envvar=DEBFULLNAME --preserve-envvar=DEBEMAIL --preserve-envvar=GNUPGHOME --set-envvar=NO_PKG_MANGLE=1'
+ cat > ${WORKDIR}/package_lifecycle/debuild.txt <<-EOS
+ dpkg-buildpackage -us -uc -ui
+ dpkg-buildpackage: source package test
+ dpkg-buildpackage: source version 1.0-2
+ dpkg-buildpackage: source distribution UNRELEASED
+ dpkg-buildpackage: source changed by Testophilus Testownik <tester@testity.org>
+ dpkg-source --before-build .
+ dpkg-buildpackage: host architecture ${_ARCH}
+ debian/rules clean
+ dh clean
+ dpkg-source -b .
+ dpkg-source: info: using source format '3.0 (quilt)'
+ dpkg-source: info: building test using existing ./test_1.0.orig.tar.xz
+ dpkg-source: info: building test in test_1.0-2.debian.tar.xz
+ dpkg-source: info: building test in test_1.0-2.dsc
+ debian/rules binary
+ dh binary
+ dpkg-deb: building package 'test' in '../test_1.0-2_all.deb'.
+ ${_dpkg_genchanges}../test_1.0-2_${_ARCH}.changes
+ dpkg-genchanges: not including original source code in upload
+ dpkg-source --after-build .
+ dpkg-buildpackage: binary and diff upload (original source NOT included)
+EOS
+ runCommandOutCmpFile "-k'uscan test key (no secret) <none@debian.org>'" "${WORKDIR}/package_lifecycle/debuild.txt" "" 0
+ cd ${WORKDIR}
+}
+
+test_debuild_forcesign() {
+ export GNUPGHOME=$GPGHOME
+ cd ${WORKDIR}/package_lifecycle/test
+ COMMAND='LC_ALL=C debuild --no-conf --no-lintian --preserve-envvar=PATH --preserve-envvar=PERL5LIB --preserve-envvar=DEBFULLNAME --preserve-envvar=DEBEMAIL --preserve-envvar=GNUPGHOME --set-envvar=NO_PKG_MANGLE=1 --force-sign'
+ cat > ${WORKDIR}/package_lifecycle/debuild.txt <<-EOS
+ dpkg-buildpackage -us -uc -ui
+ dpkg-buildpackage: source package test
+ dpkg-buildpackage: source version 1.0-2
+ dpkg-buildpackage: source distribution UNRELEASED
+ dpkg-buildpackage: source changed by Testophilus Testownik <tester@testity.org>
+ dpkg-source --before-build .
+ dpkg-buildpackage: host architecture ${_ARCH}
+ debian/rules clean
+ dh clean
+ dpkg-source -b .
+ dpkg-source: info: using source format '3.0 (quilt)'
+ dpkg-source: info: building test using existing ./test_1.0.orig.tar.xz
+ dpkg-source: info: building test in test_1.0-2.debian.tar.xz
+ dpkg-source: info: building test in test_1.0-2.dsc
+ debian/rules binary
+ dh binary
+ dpkg-deb: building package 'test' in '../test_1.0-2_all.deb'.
+ ${_dpkg_genchanges}../test_1.0-2_${_ARCH}.changes
+ dpkg-genchanges: not including original source code in upload
+ dpkg-source --after-build .
+ dpkg-buildpackage: binary and diff upload (original source NOT included)
+ Now signing changes and any dsc files...
+EOS
+ if command -v dpkg-genbuildinfo >/dev/null; then
+ cat >> ${WORKDIR}/package_lifecycle/debuild.txt <<-EOS
+ signfile dsc test_1.0-2.dsc uscan test key (no secret) <none@debian.org>
+
+ fixup_buildinfo test_1.0-2.dsc test_1.0-2_${_ARCH}.buildinfo
+ signfile buildinfo test_1.0-2_${_ARCH}.buildinfo uscan test key (no secret) <none@debian.org>
+
+ fixup_changes dsc test_1.0-2.dsc test_1.0-2_${_ARCH}.changes
+ fixup_changes buildinfo test_1.0-2_${_ARCH}.buildinfo test_1.0-2_${_ARCH}.changes
+ signfile changes test_1.0-2_${_ARCH}.changes uscan test key (no secret) <none@debian.org>
+
+ Successfully signed dsc, buildinfo, changes files
+EOS
+ else
+ cat >> ${WORKDIR}/package_lifecycle/debuild.txt <<-EOS
+ signfile dsc test_1.0-2.dsc uscan test key (no secret) <none@debian.org>
+
+ fixup_changes dsc test_1.0-2.dsc test_1.0-2_${_ARCH}.changes
+ signfile changes test_1.0-2_${_ARCH}.changes uscan test key (no secret) <none@debian.org>
+
+ Successfully signed dsc, changes files
+EOS
+ fi
+ runCommandOutCmpFile "-k'uscan test key (no secret) <none@debian.org>'" "${WORKDIR}/package_lifecycle/debuild.txt" "" 0
+ cd ${WORKDIR}
+}
+
+test_debdiff () {
+ cd ${WORKDIR}/package_lifecycle
+ COMMAND='debdiff --no-conf'
+ cat > ${WORKDIR}/package_lifecycle/debdiff.txt <<-EOS
+ File lists identical (after any substitutions)
+
+ Control files: lines which differ (wdiff format)
+ ------------------------------------------------
+ Version: [-1.0-1-] {+1.0-2+}
+EOS
+ runCommandOutCmpFile "test_1.0-1_${_ARCH}.changes test_1.0-2_${_ARCH}.changes" "debdiff.txt" "" 0
+ cd ${WORKDIR}
+}
+
+oneTimeTearDown () {
+ rm -rf ${WORKDIR}/package_lifecycle
+ gpgconf --homedir "$GPGHOME" --kill gpg-agent
+ rm -rf "$GPGHOME"
+}
+
+cd ${WORKDIR}
+. shunit2
+
diff --git a/test/test_perl b/test/test_perl
new file mode 100755
index 0000000..aed1906
--- /dev/null
+++ b/test/test_perl
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+set -e
+
+LIB=-I../lib
+if test "${1:-}" = --installed; then
+ LIB=""
+ shift
+fi
+
+prove --norc $LIB t/*.t
+
diff --git a/test/test_perltidy b/test/test_perltidy
new file mode 100755
index 0000000..af9827c
--- /dev/null
+++ b/test/test_perltidy
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+set -u
+
+base="$(readlink -f "${0%/*}"/..)"
+
+
+# perltidy test is ran only during dev
+if test "$(cd "$base" && dpkg-parsechangelog -c0 -SDistribution)" != UNRELEASED; then
+ echo "SKIP: Not checking a released version with perltidy."
+ exit 0
+fi
+
+# perltidy test isn't ran in autopkgtest environment
+if test "${1:-}" = --installed; then
+ echo "SKIP: Not running perltidy in autopkgtest."
+ exit 0
+fi
+
+# Don't run this test with old Perltidy versions
+if test "$(perl -MPerl::Tidy -le 'print $Perl::Tidy::VERSION')" -lt 20220613; then
+ echo "SKIP: perltidy version too old, skipping this test."
+ exit 0
+fi
+
+
+testPerltidy() {
+ LIST=$(find "$base/lib/" "$base/scripts/" -iname '*.pl' -or -iname '*.pm')
+
+ for file in $LIST; do
+ perltidy --output-path="$SHUNIT_TMPDIR/" --profile="$base/.perltidyrc" "$file"
+ cmp -s "$file" "$SHUNIT_TMPDIR/$(basename "$file").tdy"
+ retval=$?
+ assertEquals "## $file isn't following perltidy" 0 "$retval"
+ done
+
+}
+
+. shunit2
diff --git a/test/test_sadt b/test/test_sadt
new file mode 100755
index 0000000..0292d20
--- /dev/null
+++ b/test/test_sadt
@@ -0,0 +1,100 @@
+#!/bin/sh
+
+# Copyright (C) 2018, Antonio Terceiro <terceiro@debian.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+set -u
+
+. ${0%/*}/test_helper.sh
+
+if test "${1:-}" = --installed; then
+ sadt="sadt"
+ shift
+else
+ sadt="$(readlink -f "${0%/*}/../scripts/sadt")"
+fi
+
+samples="${0%/*}/sadt"
+
+run_sadt() {
+ dir="$1"
+ shift
+ (cd "$samples/$dir" && $sadt "$@")
+}
+
+test_passes() {
+ assertPasses run_sadt passes
+}
+
+test_superficial() {
+ assertPasses run_sadt superficial
+ assertFails run_sadt superficial-fails
+}
+
+test_flaky() {
+ assertPasses run_sadt flaky
+}
+
+test_skippable() {
+ assertPasses run_sadt skippable
+}
+
+test_skippable_fails() {
+ assertFails run_sadt unskippable
+ assertFails run_sadt unskipped
+}
+
+test_fails() {
+ assertFails run_sadt fails
+}
+
+test_space_separated_tests() {
+ assertPasses run_sadt space-separated-tests
+ assertFalse "skipped=1 found in output" "grep -q skipped=1 $log"
+}
+
+test_comma_separated_tests() {
+ assertPasses run_sadt comma-separated-tests
+ assertFalse "skipped=1 found in output" "grep -q skipped=1 $log"
+}
+
+test_space_separated_restrictions() {
+ assertPasses run_sadt space-separated-restrictions
+ assertFalse "skipped=1 found in output" "grep -q skipped=1 $log"
+}
+
+test_comma_separated_restrictions() {
+ assertPasses run_sadt comma-separated-restrictions
+ assertFalse "skipped=1 found in output" "grep -q skipped=1 $log"
+}
+
+test_tests_directory() {
+ assertPasses run_sadt tests-directory
+ assertFalse "skipped=1 found in output" "grep -q skipped=1 $log"
+}
+
+test_test_command() {
+ assertPasses run_sadt test-command --verbose
+ assertTrue "recognizes Test-Command" "grep 'O: Test-Command is supported' $log"
+ assertTrue "recognizes Test-Command" "grep tests=1 $log"
+}
+
+test_run_specific_tests() {
+ assertPasses run_sadt comma-separated-tests --verbose test1
+ assertTrue "runs test1" "grep '^test1:' $log"
+ assertFalse "does not run test2" "grep '^test2:' $log"
+}
+
+. shunit2
diff --git a/test/test_salsa b/test/test_salsa
new file mode 100755
index 0000000..8c21342
--- /dev/null
+++ b/test/test_salsa
@@ -0,0 +1,106 @@
+#!/usr/bin/perl
+
+use strict;
+use lib '../lib';
+use Test::More;
+
+my $skip;
+
+BEGIN {
+ my $cwd = `pwd`;
+ chomp $cwd;
+ eval "use File::Temp 'tempdir';"
+ . "use Test::Output;use GitLab::API::v4;"
+ . "use lib '$cwd/../lib'";
+ $skip = $@ ? 1 : 0;
+}
+
+sub run {
+ my ($result, $out, @list) = @_;
+ @ARGV = @list;
+ my $res;
+ combined_like(
+ sub {
+ $res = Devscripts::Salsa->new->run;
+ },
+ $out,
+ "command: " . join(' ', @list));
+ ok($res =~ /^$result$/i, " result is $result");
+}
+
+sub mkDebianDir {
+ my $tmpdir = tempdir(CLEANUP => 1);
+ chdir $tmpdir;
+ $ENV{"GIT_CONFIG_NOGLOBAL"} = 1;
+ system "git init";
+ mkdir 'debian';
+ open F, ">debian/changelog";
+ print F <<EOF;
+foobar (0-1) unstable; urgency=low
+
+ * Initial release
+
+ -- Joe Developer <jd\@debian.org> Mon, 02 Nov 2013 22:21:31 -0100
+EOF
+ close F;
+ open F, ">README.md";
+ print F <<EOF;
+# Salsa test
+EOF
+ system "git add *";
+ system "git commit -a -m 'Salsa test'";
+}
+
+SKIP: {
+ skip "Missing dependencies" if ($skip);
+ use_ok 'Devscripts::Salsa';
+ $Devscripts::Output::die_on_error = 0;
+
+ # Search methods
+ run(0, qr/Id.*\nUsername.*/s, 'whoami');
+ run(0, qr/Id.*\nName/s, 'search_group', 'js-team');
+ run(0, qr/Id.*\nName/s, 'search_group', '2666');
+ run(0, qr/Id.*\nName/s, 'search_group', 'perl-team/modules');
+ run(0, qr/Id.*\nUsername\s*: yadd/s, 'search_user', 'yadd');
+ run(0, qr/Id.*\nUsername\s*: yadd/s, 'search_user', 'yad');
+ run(0, qr/Id.*\nUsername\s*: yadd/s, 'search_user', '3818');
+ run(0, qr/Id.*\nName\s*: qa/s, 'search_project', 'qa');
+ run(0, qr/Id.*\nName\s*: qa/s, 'search_project', '1417');
+ run(0, qr/Id.*\nName\s*: qa/s, 'search_project', 'qa/qa');
+ run(0, qr/Id.*\nUsername.*/s, '--group', 'perl-team', 'group');
+ run(0, qr/Id.*\nName/s, '--group', 'perl-team', 'list_repos');
+ run(0, qr/Id.*\nName/s, 'list_groups');
+ run(0, qr/Id.*\n\tName/s, 'forks', 'qa/qa');
+ run(0, qr/^debian\/devscripts/m, 'mrs', 'debian/devscripts');
+ run(0, qr/^devscripts/m, 'mrs', 'devscripts', '--group-id', 2);
+ run(0, qr/master.*Maintainer.*Developers/m,
+ 'protected_branches', 'debian/devscripts');
+
+ # checkout
+ {
+ my $tmpdir = tempdir(CLEANUP => 1);
+ run(0, qr/gbp:info/, 'co', '-C', $tmpdir,
+ 'debian/libapache2-mod-fcgid');
+ ok(
+ -d "$tmpdir/libapache2-mod-fcgid/.git",
+ ' libapache2-mod-fcgid cloned'
+ );
+ run(0, qr/gbp:info/, 'checkout', '-C', $tmpdir, '--group=qa', 'qa');
+ ok(-d "$tmpdir/qa/.git", ' qa cloned');
+ }
+
+ # push_repo, update_repo and del_repo
+ if ($ARGV[0] eq '--full') {
+ mkDebianDir;
+ run(0, qr/Project .*created/s,
+ 'push_repo', '.', '--verbose', '--kgb', '--irc=devscripts');
+ diag "Verify that foobar appears in #devscripts channel";
+ run(0, qr/Project .*updated/s,
+ 'update_repo', 'foobar', '--rename-head');
+ run(1, qr/update_repo has failed for foobar/s,
+ 'update_repo', 'foobar', '--rename-head', '--no-fail');
+ run(0, qr/Project .*foobar deleted/s,
+ '--verbose', 'del_repo', 'foobar');
+ }
+}
+done_testing;
diff --git a/test/test_uscan b/test/test_uscan
new file mode 100755
index 0000000..1b66f30
--- /dev/null
+++ b/test/test_uscan
@@ -0,0 +1,548 @@
+#!/bin/bash
+
+# Copyright (C) 2013, Rafael Laboissiere <rafael@laboissiere.net>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at your
+# option) any later version.
+#
+# 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.
+#
+# On Debian systems, the complete text of the GNU General Public License
+# version 3 can be found in the /usr/share/common-licenses/GPL-3 file.
+
+set -u
+
+TESTTYPE=base
+test_dir=$(readlink -f "${0%/*}")
+. "$test_dir/lib_test_uscan"
+
+SUFFIX="1"
+if command -v dpkg-vendor >/dev/null; then
+ VENDER="$(dpkg-vendor --query Vendor 2>/dev/null|tr 'A-Z' 'a-z')"
+ case "$VENDER" in
+ debian) SUFFIX="1" ;;
+ *) SUFFIX="0${VENDER}1" ;;
+ esac
+fi
+
+if test "${1:-}" = --installed; then
+ COMMAND="uscan --no-conf --compression=xz"
+ shift
+else
+ top_srcdir=$(readlink -f "${0%/*}/..")
+ make -C "$top_srcdir/scripts" uscan mk-origtargz uupdate debchange
+ PATH="$top_srcdir/scripts:$PATH"
+ export PATH
+ PERL5LIB="$top_srcdir/lib"
+ export PERL5LIB
+ COMMAND="uscan --no-conf --compression=xz"
+fi
+
+COMMANDDEHS="$COMMAND --dehs"
+
+# comment out for debug
+#COMMAND="$COMMAND --debug"
+
+tearDown(){
+ killHttpServer
+ echo
+}
+
+trap tearDown EXIT
+
+containsName(){
+ echo "$1" | grep -qF "$2"
+ echo $?
+}
+
+validXML(){
+ echo "$1" | perl -ne 's/<[^\/].*?>.*?<\/.*>//g;$open++ if/<[^\/].*?>/;$open-- if/<\/.*>/;if(!$open and /^\s+\w/){$false++}}{exit ($false || $open) ? 1 : 0'
+ echo $?
+}
+
+. "$test_dir/shunit2-helper-functions.sh"
+
+# The following tests do the following: (1) create a minimal Debian package
+# directory, containing minimal files debian/{changelog,watch,copyright},
+# (2) create a minimal repository, containing a tarball (built on the fly),
+# (3) start an HTTP server that works offline, using the SimpleHTTPServer
+# module of Python, and (4) run uscan inside that minimal universe.
+
+
+# The following function tests the --repack feature
+helperTestRepack() {
+ from_ext="$1"
+ to_comp="$2"
+ file_output="$3"
+
+ PKG=foo
+ TEMP_PKG_DIR=$(mktemp -d -p "$SHUNIT_TMPDIR")
+
+ mkdir -p "$TEMP_PKG_DIR"/$PKG/debian/source
+ spawnHttpServer
+ PORT=$(cat "$TEMP_PKG_DIR"/repo/port)
+
+ cat <<END > "$TEMP_PKG_DIR"/$PKG/debian/watch
+version=3
+http://localhost:$PORT/$PKG-(\d).$from_ext
+END
+
+ cat <<END > "$TEMP_PKG_DIR"/$PKG/debian/changelog
+$PKG (0-1) unstable; urgency=low
+
+ * Initial release
+
+ -- Joe Developer <jd@debian.org> Mon, 02 Nov 2013 22:21:31 -0100
+END
+
+ echo -n '3.0 (quilt)' > "$TEMP_PKG_DIR"/$PKG/debian/source/format
+ mkdir -p "$TEMP_PKG_DIR"/repo/foo
+ touch "$TEMP_PKG_DIR"/repo/foo/content
+
+ if [ "$from_ext" = "tar.zstd" ]
+ then
+ ( cd "$TEMP_PKG_DIR"/repo ;
+ tar --zstd -cf $PKG-1.$from_ext $PKG/* )
+ else
+ ( cd "$TEMP_PKG_DIR"/repo ;
+ tar -caf $PKG-1.$from_ext $PKG/* )
+ fi
+
+ OUTPUT=$( cd "$TEMP_PKG_DIR"/$PKG ; $COMMANDDEHS --repack --compression=$to_comp )
+ assertEquals "uscan: exit_code!=0 but exit_code=0" "$?" "0"
+
+ TARBALL=${PKG}_1.orig.tar.$to_comp
+ if [ "$from_ext" != "tar.$to_comp" ]
+ then
+ assertFalse 'unrepacked tarball still present' "[ -f "$TEMP_PKG_DIR"/${PKG}_1.orig.$from_ext ]"
+ fi
+ assertTrue 'pristine tarball is not created' "[ -f "$TEMP_PKG_DIR"/$TARBALL ]"
+ assertNotNull "pristine tarball is not $to_comp-compressed" \
+ "$( file -L "$TEMP_PKG_DIR"/$TARBALL | grep "$file_output" )"
+ CONTENTS="$(tar atf "$TEMP_PKG_DIR"/$TARBALL)"
+ assertTrue 'file contents missing' \
+ $(containsName "$CONTENTS" content)
+ assertTrue "malfored target in dehs output: $OUTPUT" $(validXML "$OUTPUT")
+ assertTrue "malfored target in dehs output: $OUTPUT" \
+ $(containsName "$OUTPUT" "<target>$TARBALL</target>")
+
+}
+
+testRepackGZ_XZ() { helperTestRepack "tar.gz" "xz" "XZ compressed data" ; }
+testRepackGZ_BZ2() { helperTestRepack "tar.gz" "bz2" "bzip2 compressed data" ; }
+testRepackBZ2_GZ() { helperTestRepack "tar.bz2" "gz" "gzip compressed data" ; }
+testRepackGZ_GZ() { helperTestRepack "tar.gz" "gz" "gzip compressed data" ; }
+testRepackXZ_XZ() { helperTestRepack "tar.xz" "xz" "XZ compressed data" ; }
+testRepackTGZ_XZ() { helperTestRepack "tgz" "xz" "XZ compressed data" ; }
+testRepackTGZ_XZ() { helperTestRepack "tgz" "xz" "XZ compressed data" ; }
+testRepackLZ_XZ() { helperTestRepack "tar.lzma" "xz" "XZ compressed data" ; }
+testRepackZST_XZ() { helperTestRepack "tar.zst" "xz" "XZ compressed data" ; }
+testRepackZSTD_XZ() { helperTestRepack "tar.zstd" "xz" "XZ compressed data" ; }
+
+# The following function tests the --repack feature, with a zip file
+testRepackZip_XZ() {
+ to_comp=xz
+ file_output="XZ compressed data"
+
+ PKG=foo
+ TEMP_PKG_DIR=$(mktemp -d -p "$SHUNIT_TMPDIR")
+ spawnHttpServer
+ PORT=$(cat "$TEMP_PKG_DIR"/repo/port)
+
+ mkdir -p "$TEMP_PKG_DIR"/$PKG/debian/source
+
+ cat <<END > "$TEMP_PKG_DIR"/$PKG/debian/watch
+version=3
+http://localhost:$PORT/$PKG-(\d).zip
+END
+
+ cat <<END > "$TEMP_PKG_DIR"/$PKG/debian/changelog
+$PKG (0-1) unstable; urgency=low
+
+ * Initial release
+
+ -- Joe Developer <jd@debian.org> Mon, 02 Nov 2013 22:21:31 -0100
+END
+ echo -n '3.0 (quilt)' > "$TEMP_PKG_DIR"/$PKG/debian/source/format
+
+ mkdir -p "$TEMP_PKG_DIR"/repo/foo
+ touch "$TEMP_PKG_DIR"/repo/foo/content
+
+ ( cd "$TEMP_PKG_DIR"/repo ;
+ zip -q -r $PKG-1.zip * )
+
+ OUTPUT=$( (cd "$TEMP_PKG_DIR"/$PKG ; $COMMANDDEHS --repack --compression=$to_comp) )
+ assertEquals "uscan: exit_code!=0 but exit_code=0" "$?" "0"
+
+ TARBALL=${PKG}_1.orig.tar.$to_comp
+ assertTrue 'unrepacked zipfile present' "[ -f "$TEMP_PKG_DIR"/${PKG}-1.zip ]"
+ assertTrue 'pristine tarball is not created' "[ -f "$TEMP_PKG_DIR"/$TARBALL ]"
+ assertNotNull "pristine tarball is not $to_comp-compressed" \
+ "$( file -L "$TEMP_PKG_DIR"/$TARBALL | grep "$file_output" )"
+ CONTENTS="$(tar atf "$TEMP_PKG_DIR"/$TARBALL)"
+ assertTrue 'file contents missing' \
+ $(containsName "$CONTENTS" content)
+ assertTrue "malfored target in dehs output: $OUTPUT" $(validXML "$OUTPUT")
+ assertTrue "malfored target in dehs output: $OUTPUT" \
+ $(containsName "$OUTPUT" "<target>$TARBALL</target>")
+
+}
+
+
+
+# The following function tests the Files-Excluded feature of uscan, which
+# allows the selective exclusion of files from the upstream tarball before
+# repacking it.
+
+helperCreateRepo () {
+ mkdir -p $PKG/debian
+
+ cat <<END > $PKG/debian/watch
+version=3
+${OPTS:-}http://localhost:$PORT/$PKG-(\d).tar.gz debian ${SCRIPT:-}
+END
+
+ cat <<END > $PKG/debian/changelog
+$PKG (0+dfsg1-$SUFFIX) unstable; urgency=low
+
+ * Initial release
+
+ -- Joe Developer <jd@debian.org> Mon, 02 Nov 2013 22:21:31 -0100
+END
+
+ cat <<'END' > $PKG/debian/copyright
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Files-Excluded: exclude-this
+ exclude-dir
+ .*
+ */js/jquery.js
+ ;?echo?baz;?#
+END
+ if [ -n "${SRCFORMAT:-}" ]; then
+ mkdir -p $PKG/debian/source
+ echo "$SRCFORMAT" > $PKG/debian/source/format
+ fi
+
+ mkdir -p repo
+ touch repo/include-this
+ touch repo/exclude-this
+ touch repo/.hidden
+ mkdir -p "repo/; echo baz; #/"
+ mkdir -p repo/exclude-dir
+ touch repo/exclude-dir/file
+ mkdir -p repo/exclude-dir/subdir
+ touch repo/exclude-dir/subdir/file2
+ mkdir -p repo/docs/html/js/
+ touch repo/docs/html/js/jquery.js
+
+}
+
+helperTestContent() {
+ assertTrue 'file that must be present is excluded in the tarball' \
+ $(containsName "$CONTENTS" include-this)
+ assertFalse 'file that must be excluded is present in the tarball' \
+ $(containsName "$CONTENTS" exclude-this)
+ assertFalse "dir that must be excluded is present in the tarball" \
+ $(containsName "$CONTENTS" exclude-dir)
+ assertFalse "subdir that must be excluded is present in the tarball" \
+ $(containsName "$CONTENTS" subdir)
+ assertFalse "non-root-file that must be excluded is present in the tarball" \
+ $(containsName "$CONTENTS" jquery.js)
+ assertFalse "hidden file that must be excluded is present in the zip file" \
+ $(containsName "$CONTENTS" .hidden)
+ assertFalse "path with whitespace that must be excluded is present" \
+ $(containsName "$CONTENTS" "; echo baz; #/")
+}
+
+testFileExclusion() {
+
+ PKG=foo
+ TEMP_PKG_DIR=$(mktemp -d -p "$SHUNIT_TMPDIR")
+ spawnHttpServer
+ PORT=$(cat "$TEMP_PKG_DIR"/repo/port)
+
+ (
+ cd "$TEMP_PKG_DIR"
+ OPTS="opts=repacksuffix=+dfsg1,dversionmangle=s/@DEB_EXT@// "
+ SCRIPT="uupdate"
+ SRCFORMAT="3.0 (quilt)"
+ helperCreateRepo
+ cd repo
+ tar cfz $PKG-1.tar.gz * .hidden )
+
+ (cd "$TEMP_PKG_DIR"/$PKG ; $COMMAND)
+ assertEquals "uscan: exit_code!=0 but exit_code=0" "$?" "0"
+
+ TARBALL=${PKG}_1+dfsg1.orig.tar.xz
+ assertTrue 'downloaded tarfile not present' "[ -f "$TEMP_PKG_DIR"/${PKG}-1.tar.gz ]"
+ assertTrue 'pristine tarball is not created' "[ -f "$TEMP_PKG_DIR"/$TARBALL ]"
+ assertFalse 'pristine tarball is a symlink (nothing repacked?)' "[ -L "$TEMP_PKG_DIR"/$TARBALL ]"
+ assertNotNull 'pristine tarball is not XZ-compressed' \
+ "$( file "$TEMP_PKG_DIR"/$TARBALL | grep -i 'XZ compressed data' )"
+ CONTENTS="$(tar atf "$TEMP_PKG_DIR"/$TARBALL)"
+
+ helperTestContent
+
+ # check uupdate
+ assertTrue 'pristine tarball is not extracted' "[ -f "$TEMP_PKG_DIR"/${PKG}-1+dfsg1/debian/changelog ]"
+ DVERSION=`dpkg-parsechangelog -l"$TEMP_PKG_DIR"/${PKG}-1+dfsg1/debian/changelog -SVersion`
+ assertEquals "uscan: Version should be 1+dfsg1-$SUFFIX but $DVERSION" "$DVERSION" "1+dfsg1-$SUFFIX"
+
+}
+
+# the same, but run from a separate directory (no way for uupdate, just download)
+testFileExclusionSeparateDir() {
+
+ PKG=foo
+ TEMP_PKG_DIR=$(mktemp -d -p "$SHUNIT_TMPDIR")
+ spawnHttpServer
+ PORT=$(cat "$TEMP_PKG_DIR"/repo/port)
+
+ (
+ cd "$TEMP_PKG_DIR"
+ SCRIPT=""
+ OPTS="opts=repacksuffix=+dfsg1,dversionmangle=auto "
+ helperCreateRepo
+ cd repo
+ tar cfz $PKG-1.tar.gz * .hidden )
+
+ mkdir "$TEMP_PKG_DIR"/otherdir
+ (
+ cd "$TEMP_PKG_DIR"/otherdir;
+ $COMMAND --package $PKG --force-download --upstream-version 1 \
+ --watchfile ../$PKG/debian/watch --copyright-file ../$PKG/debian/copyright
+ )
+ assertEquals "uscan: exit_code!=0 but exit_code=0" "$?" "0"
+
+ TARBALL=${PKG}_1+dfsg1.orig.tar.xz
+ assertTrue 'downloaded tarfile not present' "[ -f "$TEMP_PKG_DIR"/${PKG}-1.tar.gz ]"
+ assertTrue 'pristine tarball is not created' "[ -f "$TEMP_PKG_DIR"/$TARBALL ]"
+ assertFalse 'pristine tarball is a symlink (nothing repacked?)' "[ -L "$TEMP_PKG_DIR"/$TARBALL ]"
+ assertNotNull 'pristine tarball is not XZ-compressed' \
+ "$( file "$TEMP_PKG_DIR"/$TARBALL | grep -i 'XZ compressed data' )"
+ CONTENTS="$(tar atf "$TEMP_PKG_DIR"/$TARBALL)"
+
+ helperTestContent
+
+}
+
+# The same, for a zip file that is being repacked
+
+testFileExclusionZipToTar() {
+
+ PKG=foo
+ TEMP_PKG_DIR=$(mktemp -d -p "$SHUNIT_TMPDIR")
+ spawnHttpServer
+ PORT=$(cat "$TEMP_PKG_DIR"/repo/port)
+
+ (
+ cd "$TEMP_PKG_DIR"
+ SRCFORMAT="3.0 (quilt)"
+ helperCreateRepo
+ cat <<END > $PKG/debian/watch
+version=3
+opts=repacksuffix=+dfsg1,dversionmangle=s/@DEB_EXT@// http://localhost:$PORT/$PKG-(\d).zip debian uupdate
+END
+
+ cd repo
+ zip -q -r $PKG-1.zip * .hidden )
+
+ (cd "$TEMP_PKG_DIR"/$PKG ; $COMMAND --repack)
+ assertEquals "uscan: exit_code!=0 but exit_code=0" "$?" "0"
+
+ TARBALL=${PKG}_1+dfsg1.orig.tar.xz
+ assertTrue 'unrepacked zipfile not present' "[ -f "$TEMP_PKG_DIR"/${PKG}-1.zip ]"
+ assertTrue 'pristine tarball is not created' "[ -f "$TEMP_PKG_DIR"/$TARBALL ]"
+ assertNotNull 'pristine tarball is not xz-compressed' \
+ "$( file "$TEMP_PKG_DIR"/$TARBALL | grep 'XZ compressed data' )"
+ CONTENTS="$(tar atf "$TEMP_PKG_DIR"/$TARBALL)"
+ helperTestContent
+
+ # check uupdate
+ assertTrue 'pristine tarball is not extracted' "[ -f "$TEMP_PKG_DIR"/${PKG}-1+dfsg1/debian/changelog ]"
+ DVERSION=`dpkg-parsechangelog -l"$TEMP_PKG_DIR"/${PKG}-1+dfsg1/debian/changelog -SVersion`
+ assertEquals "uscan: Version should be 1+dfsg1-$SUFFIX but $DVERSION" "$DVERSION" "1+dfsg1-$SUFFIX"
+
+}
+
+testPlainMode() {
+ PKG=foo
+ TEMP_PKG_DIR=$(mktemp -d -p "$SHUNIT_TMPDIR")
+ spawnHttpServer
+ PORT=$(cat "$TEMP_PKG_DIR"/repo/port)
+
+ mkdir -p "$TEMP_PKG_DIR"/$PKG/debian
+
+ cat <<END > "$TEMP_PKG_DIR"/$PKG/debian/watch
+version=4
+opts="searchmode=plain" \
+http://localhost:$PORT/src.json http://localhost:$PORT/foo-(\d).zip
+END
+
+ cat <<END > "$TEMP_PKG_DIR"/$PKG/debian/changelog
+$PKG (0-1) unstable; urgency=low
+
+ * Initial release
+
+ -- Joe Developer <jd@debian.org> Mon, 02 Nov 2013 22:21:31 -0100
+END
+
+ mkdir -p "$TEMP_PKG_DIR"/repo/foo
+ touch "$TEMP_PKG_DIR"/repo/foo/content
+
+ ( cd "$TEMP_PKG_DIR"/repo ;
+ zip -q -r $PKG-1.zip *;
+ cat > src.json <<END
+{"1.0":{"tarball":"http://localhost:$PORT/foo-1.zip"}}
+END
+ )
+
+ OUTPUT=$( (cd "$TEMP_PKG_DIR"/$PKG ; $COMMANDDEHS) )
+ assertEquals "uscan: exit_code!=0 but exit_code=0" "$?" "0"
+
+ TARBALL=${PKG}_1.orig.tar.$to_comp
+ assertTrue 'unrepacked zipfile present' "[ -f "$TEMP_PKG_DIR"/${PKG}-1.zip ]"
+
+}
+
+testLinksWithRelativeBase() {
+ PKG=foo
+ TEMP_PKG_DIR=$(mktemp -d -p "$SHUNIT_TMPDIR")
+ spawnHttpServer
+ PORT=$(cat "$TEMP_PKG_DIR"/repo/port)
+ to_comp=xz
+
+ mkdir -p "$TEMP_PKG_DIR"/$PKG/debian
+
+ cat <<END > "$TEMP_PKG_DIR"/$PKG/debian/watch
+version=4
+http://localhost:$PORT/foo/index.html foo-([\d\.]+).zip
+END
+
+ cat <<END > "$TEMP_PKG_DIR"/$PKG/debian/changelog
+$PKG (0-1) unstable; urgency=low
+
+ * Initial release
+
+ -- Joe Developer <jd@debian.org> Mon, 02 Nov 2013 22:21:31 -0100
+END
+
+ mkdir -p "$TEMP_PKG_DIR"/repo/foo
+ touch "$TEMP_PKG_DIR"/repo/foo/content
+
+ for href in foo-1.zip /foo/foo-1.zip //localhost:$PORT/foo/foo-1.zip ../foo/foo-1.zip x/../../foo/foo-1.zip; do
+ ( cd "$TEMP_PKG_DIR"/repo/foo ;
+ zip -q -r $PKG-1.zip *;
+ zip -q -r $PKG-0.9.zip *;
+ cat > index.html <<END
+<html><body>
+<base href="/foo/" />
+<a href="$href">foo-1.zip</a>
+</body></html>
+END
+ )
+
+ (cd "$TEMP_PKG_DIR"/$PKG ; $COMMAND)
+ assertEquals "uscan: exit_code!=0 but exit_code=0 with $href" "$?" "0"
+ done
+
+ assertTrue 'unrepacked zipfile present' "[ -f "$TEMP_PKG_DIR"/${PKG}-1.zip ]"
+
+}
+
+testComponentDehsOutput() {
+ PKG=foo
+ TEMP_PKG_DIR=$(mktemp -d -p "$SHUNIT_TMPDIR")
+ spawnHttpServer
+ PORT=$(cat "$TEMP_PKG_DIR"/repo/port)
+
+ mkdir -p "$TEMP_PKG_DIR"/$PKG/debian
+
+ cat <<END > "$TEMP_PKG_DIR"/$PKG/debian/watch
+version=4
+http://localhost:$PORT/$PKG-(\d).zip debian
+
+opts="searchmode=plain,component=baz" \
+http://localhost:$PORT/src.json http://localhost:$PORT/foo-(\d).zip
+END
+
+ cat <<END > "$TEMP_PKG_DIR"/$PKG/debian/changelog
+$PKG (0-1) unstable; urgency=low
+
+ * Initial release
+
+ -- Joe Developer <jd@debian.org> Mon, 02 Nov 2013 22:21:31 -0100
+END
+
+ mkdir -p "$TEMP_PKG_DIR"/repo/foo
+ touch "$TEMP_PKG_DIR"/repo/foo/content
+
+ ( cd "$TEMP_PKG_DIR"/repo ;
+ zip -q -r $PKG-1.zip *;
+ cat > src.json <<END
+{"1.0":{"tarball":"http://localhost:$PORT/foo-1.zip"}}
+END
+ )
+
+ OUTPUT=$( (cd "$TEMP_PKG_DIR"/$PKG ; $COMMANDDEHS --report --dehs) )
+ assertEquals "uscan: exit_code!=0 but exit_code=0" "$?" "0"
+ assertTrue "malfored target in dehs output: $OUTPUT" $(validXML "$OUTPUT")
+ assertTrue "malfored target in dehs output: $OUTPUT" \
+ $(containsName "$OUTPUT" '<component id="baz">')
+ assertTrue "malfored target in dehs output: $OUTPUT" \
+ $(containsName "$OUTPUT" "<component-upstream-version>1</component-upstream-version>")
+}
+
+testSimpleHeader() {
+ PKG=foo
+ TEMP_PKG_DIR=$(mktemp -d -p "$SHUNIT_TMPDIR")
+ spawnHttpServer
+ PORT=$(cat "$TEMP_PKG_DIR"/repo/port)
+
+ mkdir -p "$TEMP_PKG_DIR"/$PKG/debian/source
+
+ cat <<END > "$TEMP_PKG_DIR"/$PKG/debian/watch
+version=4
+http://localhost:$PORT/$PKG-(\d).zip debian
+
+opts="searchmode=plain,component=baz,filenamemangle=s/.*-(@ANY_VERSION@@ARCHIVE_EXT@)/baz-\$1/" \
+http://localhost:$PORT/src.json http://localhost:$PORT/foo-(\d).zip
+END
+
+ echo -n '3.0 (quilt)' > "$TEMP_PKG_DIR"/$PKG/debian/source/format
+
+ cat <<END > "$TEMP_PKG_DIR"/$PKG/debian/changelog
+$PKG (0-1) unstable; urgency=low
+
+ * Initial release
+
+ -- Joe Developer <jd@debian.org> Mon, 02 Nov 2013 22:21:31 -0100
+END
+
+ mkdir -p "$TEMP_PKG_DIR"/repo/foo
+ touch "$TEMP_PKG_DIR"/repo/foo/content
+
+ ( cd "$TEMP_PKG_DIR"/repo ;
+ zip -q -r $PKG-1.zip *;
+ cat > src.json <<END
+{"1.0":{"tarball":"http://localhost:$PORT/foo-1.zip"}}
+END
+ )
+
+ OUTPUT=$( (cd "$TEMP_PKG_DIR"/$PKG ; $COMMAND -v \
+ --http-header http://localhost:$PORT@Simple-Token=localtoken \
+ --http-header http://another.com@Ext-Token=exttoken \
+ ) )
+ assertEquals "uscan: exit_code!=0 but exit_code=0" "$?" "0"
+ assertTrue "per-host header not exported: $OUTPUT" \
+ $(containsName "$OUTPUT" "Set per-host custom header Simple-Token for http://localhost:$PORT/foo")
+ assertFalse "ext per-host header is exported: $OUTPUT" \
+ $(containsName "$OUTPUT" "Set per-host custom header Ext-Token")
+}
+
+. shunit2
diff --git a/test/test_uscan_ftp b/test/test_uscan_ftp
new file mode 100755
index 0000000..d35db8c
--- /dev/null
+++ b/test/test_uscan_ftp
@@ -0,0 +1,489 @@
+#!/bin/bash
+# vim: set shiftwidth=4 tabstop=8 noexpandtab:
+
+# Copyright (C) 2018, Osamu Aoki <osamu@debian.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at your
+# option) any later version.
+#
+# 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.
+#
+# On Debian systems, the complete text of the GNU General Public License
+# version 3 can be found in the /usr/share/common-licenses/GPL-3 file.
+
+set -u
+
+TESTTYPE=FTP
+. ./lib_test_uscan
+
+DEB_HOST_OS="$(dpkg-architecture -qDEB_HOST_ARCH_OS)"
+if [ "$DEB_HOST_OS" = "kfreebsd" ]; then
+ # kbsd has a non-working semaphore, that is needed here.
+ echo "This test is not supported on $(dpkg-architecture -qDEB_HOST_ARCH), skipping"
+ exit 0
+fi
+
+COMMAND="uscan --no-conf"
+
+# set safe defaults
+WEBSCRIPT=":"
+DEBUGECHO=":"
+DEBUGLSLR=":"
+DEBUGBASH=":"
+# comment out for debug
+#COMMAND="$COMMAND --debug"
+#COMMAND="$COMMAND --verbose"
+#DEBUGECHO=echo
+#DEBUGLSLR="ls -laR"
+#DEBUGLSLR="ls -la"
+#DEBUGBASH="bash -i"
+
+# Initial Debian revision value is distribution dependent
+SUFFIX="1"
+if command -v dpkg-vendor >/dev/null; then
+ VENDER="$(dpkg-vendor --query Vendor 2>/dev/null|tr 'A-Z' 'a-z')"
+ case "$VENDER" in
+ debian) SUFFIX="1" ;;
+ *) SUFFIX="0${VENDER}1" ;;
+ esac
+fi
+
+cleanup(){
+ kill -9 $(cat $TMPDIR/$REPOPATH/pid)
+ rm -rf $TMPDIR
+ echo ""
+}
+
+spawnFtpServer(){
+ (
+ local USCAN_FTP_SERVER=${USCAN_FTP_SERVER:-ftpserver.py}
+ mkdir -p "$TMPDIR/$REPOPATH"
+ cd "$TMPDIR/$REPOPATH" || exit 1
+ echo "FTP starting ... $TMPDIR/$REPOPATH"
+ local pid
+ python3 "$test_dir/uscan/$USCAN_FTP_SERVER" 2>log &
+ pid=$!
+ echo $pid > pid
+ while ! [ -s port ]; do
+ sleep 2s
+ if ! kill -0 $pid 2> /dev/null ; then
+ echo "The FTP server returned an error:"
+ cat log
+ exit 1
+ fi
+ done
+ )
+}
+
+trap cleanup 1 2 3 13 15
+
+containsName(){
+ echo "$1" | grep -qF "$2"
+ echo $?
+}
+
+. "${0%/*}/shunit2-helper-functions.sh"
+
+# The following tests do the following: (1) create a minimal Debian package
+# directory, containing minimal files debian/{changelog,watch,copyright},
+# (2) create a minimal repository, containing a tarball (built on the fly),
+# (3) start an FTP server that works offline, using the pyftpdlib
+# module of Python, and (4) run uscan inside that minimal universe.
+
+# make debian/ in `pwd`
+# debian/watch contains $WATCHVER and $WATCHLINE with template URL updated
+makeDebianDir() {
+ DEBNAME=${1:-foo} # Debian source package name
+ DEBVER=${2:-1.0} # Debian source package version
+ mkdir -p debian/source
+
+ cat <<END > debian/rules
+%:
+ dh $@
+END
+chmod 755 debian/rules
+
+ cat <<END > debian/changelog
+$DEBNAME ($DEBVER) unstable; urgency=low
+
+ * Release of the $DEBNAME package $DEBVER.
+
+ -- Joe Developer <jd@debian.org> Mon, 02 Nov 2013 22:21:31 -0100
+END
+ # debian/source/format
+ case $DEBVER in
+ *-*) # non-native package
+ echo "3.0 (quilt)" > debian/source/format
+ ;;
+ *) # native package
+ echo "3.0 (native)" > debian/source/format
+ ;;
+ esac
+ # debian/copyright
+ echo "Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/" \
+ > debian/copyright
+ # debian/watch
+ echo "version=$WATCHVER" > debian/watch
+ echo "$WATCHLINE" | sed -e "s,@@@url@@@,ftp://127.0.0.1:${PORT}/,g" - \
+ >> debian/watch
+ # debian/upstream/signing-key.asc
+ mkdir -p debian/upstream
+ cp -f $test_dir/uscan/PUBLIC_KEY.asc debian/upstream/signing-key.asc
+}
+
+
+# make tarball in $REPOPATH/$POOLPATH
+makeUpstreamTar() {
+ UPNAME=${1:-foo} # Upstream package name
+ UPVER=${2:-1.0} # upstream package version
+ COMPRESSION=${3:-gz} # archve compression type
+ TYPE=${4:-non-native} # set this if native-type upstream
+ OLDDIR=`pwd`
+ mkdir -p $TMPDIR/$REPOPATH/$POOLPATH/$UPNAME-$UPVER
+ cd $TMPDIR/$REPOPATH/$POOLPATH
+ touch $UPNAME-$UPVER/FILE.$UPNAME.$UPVER
+ if [ "$TYPE" = "native" ]; then
+ cd $TMPDIR/$REPOPATH/$POOLPATH/$UPNAME-$UPVER
+ makeDebianDir $UPNAME $UPVER
+ cd $TMPDIR/$REPOPATH/$POOLPATH
+ fi
+ case $COMPRESSION in
+ gz|gzip)
+ NEWTAR=$UPNAME-$UPVER.tar
+ tar -cf $NEWTAR $UPNAME-$UPVER
+ NEWTAR=$UPNAME-$UPVER.tar.gz
+ tar -czf $NEWTAR $UPNAME-$UPVER
+ ;;
+ bz2|bzip2)
+ NEWTAR=$UPNAME-$UPVER.tar
+ tar -cf $NEWTAR $UPNAME-$UPVER
+ NEWTAR=$UPNAME-$UPVER.tar.bz2
+ tar --bzip2 -cf $NEWTAR $UPNAME-$UPVER
+ ;;
+ xz)
+ NEWTAR=$UPNAME-$UPVER.tar
+ tar -cf $NEWTAR $UPNAME-$UPVER
+ NEWTAR= $UPNAME-$UPVER.tar.xz
+ tar --xz -cf $NEWTAR $UPNAME-$UPVER
+ ;;
+ zip)
+ NEWTAR=$UPNAME-$UPVER.zip
+ zip -r $NEWTAR $UPNAME-$UPVER
+ ;;
+ *) echo "Wrong compression mode: $COMPRESSION"
+ exit 1
+ ;;
+ esac
+ # make $NEWTAR.asc
+ $GPG --homedir "$GPGHOME" --no-options -q --batch --no-default-keyring \
+ --secret-keyring $PRIVATE_KEYRING --default-key 72543FAF \
+ --armor --detach-sign $NEWTAR
+ if [ "$COMPRESSION" != "zip" ]; then
+ NEWTAR=$UPNAME-$UPVER.tar
+ $GPG --homedir "$GPGHOME" --no-options -q --batch --no-default-keyring \
+ --secret-keyring $PRIVATE_KEYRING --default-key 72543FAF \
+ --armor --detach-sign $NEWTAR
+
+ fi
+ cd $OLDDIR
+}
+
+# setup a common watch file test environment
+helperWatch() {
+ local SITESCRIPT=${1:-siteWebNonNative}
+ local VEROLD=${2:-1.0}
+ local VERNEW=${3:-2.0}
+ local PREFIX="${4:-}"
+ local TMPDIR=$(mktemp -d)
+ ORIGDIR=`pwd`
+ PKG=${PKG:-foo}
+ REPOPATH=${REPOPATH:-repo}
+ POOLPATH=${POOLPATH:-pool}
+ GZREPACK=${GZREPACK:-gz}
+ XCOMMAND=${XCOMMAND:-$COMMAND}
+ WATCHVER="${WATCHVER:-3}"
+ WATCHLINE0="@@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate"
+ WATCHLINE="${WATCHLINE:-$WATCHLINE0}"
+ cd $TMPDIR
+ # start FTP server with its root at $TMPDIR/$REPOPATH
+ spawnFtpServer || exit 1
+ PORT=$(cat $TMPDIR/$REPOPATH/port)
+ $DEBUGECHO " ***** ftp://localhost:$PORT started showing $TMPDIR/$REPOPATH *****"
+ # make web site
+ $SITESCRIPT
+ # make local $VEROLD source tree
+ tar -xzf $TMPDIR/$REPOPATH/$POOLPATH/${PKG}-${VEROLD}.tar.gz
+ if [ -n "${PREFIX}" ]; then
+ mv $TMPDIR/${PKG}-${VEROLD} $TMPDIR/${PKG}-${PREFIX}${VEROLD}
+ fi
+ mv $TMPDIR/${PKG}-${PREFIX}${VEROLD} $TMPDIR/${PKG}
+ cd $TMPDIR/${PKG}
+ if [ ! -d debian ]; then
+ makeDebianDir $PKG ${PREFIX}${VEROLD}-$SUFFIX
+ fi
+ local UUPDATE=""
+ if grep -q "uupdate" $TMPDIR/${PKG}/debian/watch ; then
+ UUPDATE=uupdate
+ fi
+ local PGP=""
+ if grep -q "pgpurlmangle" $TMPDIR/${PKG}/debian/watch ; then
+ PGP=pgp
+ fi
+ if grep -q "pgpmode *= *auto" $TMPDIR/${PKG}/debian/watch ; then
+ PGP=pgp
+ fi
+ if grep -q "pgpmode *= *previous" $TMPDIR/${PKG}/debian/watch ; then
+ PGP=pgp
+ fi
+ $XCOMMAND
+ assertEquals "uscan: exit_code!=0 but exit_code=0" "$?" "0"
+ cd $TMPDIR
+ $DEBUGLSLR
+ UTARBALL=${PKG}-${VERNEW}.tar.gz
+ STARBALL=${PKG}_${PREFIX}${VERNEW}.orig.tar.$GZREPACK
+ assertTrue "$UTARBALL missing: $WATCHLINE" "[ -f $UTARBALL ]"
+ assertTrue "$STARBALL missing: $WATCHLINE" "[ -f $STARBALL ]"
+ if [ "$PGP" = "pgp" ]; then
+ UTARSIG=${PKG}-${VERNEW}.tar.gz.asc
+ if [ ! -f $UTARSIG ]; then
+ UTARSIG=${PKG}-${VERNEW}.tar.asc
+ fi
+ STARSUG=${PKG}_${PREFIX}${VERNEW}.orig.tar.$GZREPACK.asc
+ assertTrue "$UTARSIG and *.sig missing: $WATCHLINE" "[ -f $UTARSIG ]"
+ assertTrue "$STARSIG missing: $WATCHLINE" "[ -f $STARSIG ]"
+ fi
+ # check uupdate
+ if [ "$UUPDATE" = "uupdate" ]; then
+ cd $TMPDIR/${PKG}-${PREFIX}${VERNEW}
+ assertTrue 'pristine tarball is not extracted' "[ -f debian/changelog ]"
+ DVERSION=`dpkg-parsechangelog -ldebian/changelog -SVersion`
+ assertEquals "uscan: Version should be ${PREFIX}${VERNEW}-$SUFFIX but $DVERSION" "$DVERSION" "${PREFIX}${VERNEW}-$SUFFIX"
+ cd $TMPDIR
+ fi
+ $DEBUGBASH
+ cd $ORIGDIR
+ cleanup
+ unset REPOPATH
+ unset POOLPATH
+ unset GZREPACK
+ unset XCOMMAND
+ unset WATCHVER
+ unset WATCHLINE
+}
+
+# setup a common watch file test environment with Zip upstream
+helperWatchZip() {
+ local SITESCRIPT=${1:-siteWebNonNative}
+ local VEROLD=${2:-1.0}
+ local VERNEW=${3:-2.0}
+ local PREFIX="${4:-}"
+ local TMPDIR=$(mktemp -d)
+ ORIGDIR=`pwd`
+ PKG=${PKG:-foo}
+ REPOPATH=${REPOPATH:-repo}
+ POOLPATH=${POOLPATH:-pool}
+ GZREPACK=${GZREPACK:-xz}
+ XCOMMAND=${XCOMMAND:-$COMMAND}
+ WATCHVER="${WATCHVER:-3}"
+ WATCHLINE0="@@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate"
+ WATCHLINE="${WATCHLINE:-$WATCHLINE0}"
+ cd $TMPDIR
+ # start FTP server with its root at $TMPDIR/$REPOPATH
+ spawnFtpServer || exit 1
+ PORT=$(cat $TMPDIR/$REPOPATH/port)
+ $DEBUGECHO " ***** ftp://localhost:$PORT started showing $TMPDIR/$REPOPATH *****"
+ # make web site
+ $SITESCRIPT
+ # make local $VEROLD source tree
+ unzip $TMPDIR/$REPOPATH/$POOLPATH/${PKG}-${VEROLD}.zip
+ if [ -n "$PREFIX" ]; then
+ mv $TMPDIR/${PKG}-${VEROLD} $TMPDIR/${PKG}-${PREFIX}${VEROLD}
+ fi
+ mv $TMPDIR/${PKG}-${PREFIX}${VEROLD} $TMPDIR/${PKG}
+ cd $TMPDIR/${PKG}
+ if [ ! -d debian ]; then
+ makeDebianDir $PKG ${PREFIX}${VEROLD}-$SUFFIX
+ fi
+ local UUPDATE=""
+ if grep -q "uupdate" $TMPDIR/${PKG}/debian/watch ; then
+ UUPDATE=uupdate
+ fi
+ local PGP=""
+ if grep -q "pgpurlmangle" $TMPDIR/${PKG}/debian/watch ; then
+ PGP=pgp
+ fi
+ if grep -q "pgpmode *= *auto" $TMPDIR/${PKG}/debian/watch ; then
+ PGP=pgp
+ fi
+ if grep -q "pgpmode *= *previous" $TMPDIR/${PKG}/debian/watch ; then
+ PGP=pgp
+ fi
+ $XCOMMAND
+ assertEquals "uscan: exit_code!=0 but exit_code=0" "$?" "0"
+ cd $TMPDIR
+ $DEBUGLSLR
+ UTARBALL=${PKG}-${VERNEW}.zip
+ STARBALL=${PKG}_${PREFIX}${VERNEW}.orig.tar.$GZREPACK
+ assertTrue "$UTARBALL missing: $WATCHLINE" "[ -f $UTARBALL ]"
+ assertTrue "$STARBALL missing: $WATCHLINE" "[ -f $STARBALL ]"
+ if [ "$PGP" = "pgp" ]; then
+ UTARSIG=${PKG}-${VERNEW}.zip.asc
+ STARSUG=${PKG}_${PREFIX}${VERNEW}.orig.tar.$GZREPACK.asc
+ assertTrue "$UTARSIG and *.sig missing: $WATCHLINE" "[ -f $UTARSIG ]"
+ assertTrue "$STARSIG missing: $WATCHLINE" "[ -f $STARSIG ]"
+ fi
+ # check uupdate
+ if [ "$UUPDATE" = "uupdate" ]; then
+ cd $TMPDIR/${PKG}-${PREFIX}${VERNEW}
+ assertTrue 'pristine tarball is not extracted' "[ -f debian/changelog ]"
+ DVERSION=`dpkg-parsechangelog -ldebian/changelog -SVersion`
+ assertEquals "uscan: Version should be ${PREFIX}${VERNEW}-$SUFFIX but $DVERSION" "$DVERSION" "${PREFIX}${VERNEW}-$SUFFIX"
+ cd $TMPDIR
+ fi
+ $DEBUGBASH
+ cd $ORIGDIR
+ cleanup
+ unset REPOPATH
+ unset POOLPATH
+ unset GZREPACK
+ unset XCOMMAND
+ unset WATCHVER
+ unset WATCHLINE
+}
+
+siteNonNative() {
+ local PKG=${1:-foo}
+ local EXTRA=${2:-}
+ makeUpstreamTar $PKG 0.0 gz non-native
+ makeUpstreamTar $PKG 1.0 gz non-native
+ makeUpstreamTar $PKG 2.0 gz non-native
+ mkdir -p $TMPDIR/$REPOPATH/0.0/$PKG/ooo/
+ mkdir -p $TMPDIR/$REPOPATH/1.0/$PKG/ooo/
+ mkdir -p $TMPDIR/$REPOPATH/2.0/$PKG/ooo/
+ if [ -n "$EXTRA" ]; then
+ makeUpstreamTar $PKG 3.0 gz non-native
+ mkdir -p $TMPDIR/$REPOPATH/3.0/$PKG/ooo/
+ fi
+ ln -sf ../../../$POOLPATH/${PKG}-0.0.tar.gz $TMPDIR/$REPOPATH/0.0/$PKG/ooo/${PKG}-0.0.tar.gz
+ ln -sf ../../../$POOLPATH/${PKG}-0.0.tar.gz.asc $TMPDIR/$REPOPATH/0.0/$PKG/ooo/${PKG}-0.0.tar.gz.asc
+ ln -sf ../../../$POOLPATH/${PKG}-0.0.tar.asc $TMPDIR/$REPOPATH/0.0/$PKG/ooo/${PKG}-0.0.tar.asc
+ ln -sf ../../../$POOLPATH/${PKG}-1.0.tar.gz $TMPDIR/$REPOPATH/1.0/$PKG/ooo/${PKG}-1.0.tar.gz
+ ln -sf ../../../$POOLPATH/${PKG}-1.0.tar.gz.asc $TMPDIR/$REPOPATH/1.0/$PKG/ooo/${PKG}-1.0.tar.gz.asc
+ ln -sf ../../../$POOLPATH/${PKG}-1.0.tar.asc $TMPDIR/$REPOPATH/1.0/$PKG/ooo/${PKG}-1.0.tar.asc
+ ln -sf ../../../$POOLPATH/${PKG}-2.0.tar.gz $TMPDIR/$REPOPATH/2.0/$PKG/ooo/${PKG}-2.0.tar.gz
+ ln -sf ../../../$POOLPATH/${PKG}-2.0.tar.gz.asc $TMPDIR/$REPOPATH/2.0/$PKG/ooo/${PKG}-2.0.tar.gz.asc
+ ln -sf ../../../$POOLPATH/${PKG}-2.0.tar.asc $TMPDIR/$REPOPATH/2.0/$PKG/ooo/${PKG}-2.0.tar.asc
+ if [ -n "$EXTRA" ]; then
+ ln -sf ../../../$POOLPATH/${PKG}-3.0.tar.gz $TMPDIR/$REPOPATH/3.0/$PKG/ooo/${PKG}-3.0.tar.gz
+ ln -sf ../../../$POOLPATH/${PKG}-3.0.tar.gz.asc $TMPDIR/$REPOPATH/3.0/$PKG/ooo/${PKG}-3.0.tar.gz.asc
+ ln -sf ../../../$POOLPATH/${PKG}-3.0.tar.asc $TMPDIR/$REPOPATH/3.0/$PKG/ooo/${PKG}-3.0.tar.asc
+ fi
+}
+
+siteNonNativeZip() {
+ local PKG=${1:-foo}
+ local EXTRA=${2:-}
+ makeUpstreamTar $PKG 0.0 zip non-native
+ makeUpstreamTar $PKG 1.0 zip non-native
+ makeUpstreamTar $PKG 2.0 zip non-native
+ mkdir -p $TMPDIR/$REPOPATH/0.0/$PKG/ooo/
+ mkdir -p $TMPDIR/$REPOPATH/1.0/$PKG/ooo/
+ mkdir -p $TMPDIR/$REPOPATH/2.0/$PKG/ooo/
+ if [ -n "$EXTRA" ]; then
+ makeUpstreamTar $PKG 3.0 gz non-native
+ mkdir -p $TMPDIR/$REPOPATH/3.0/$PKG/ooo/
+ fi
+ ln -sf ../../../$POOLPATH/${PKG}-0.0.zip $TMPDIR/$REPOPATH/0.0/$PKG/ooo/${PKG}-0.0.zip
+ ln -sf ../../../$POOLPATH/${PKG}-0.0.zip.asc $TMPDIR/$REPOPATH/0.0/$PKG/ooo/${PKG}-0.0.zip.asc
+ ln -sf ../../../$POOLPATH/${PKG}-1.0.zip $TMPDIR/$REPOPATH/1.0/$PKG/ooo/${PKG}-1.0.zip
+ ln -sf ../../../$POOLPATH/${PKG}-1.0.zip.asc $TMPDIR/$REPOPATH/1.0/$PKG/ooo/${PKG}-1.0.zip.asc
+ ln -sf ../../../$POOLPATH/${PKG}-2.0.zip $TMPDIR/$REPOPATH/2.0/$PKG/ooo/${PKG}-2.0.zip
+ ln -sf ../../../$POOLPATH/${PKG}-2.0.zip.asc $TMPDIR/$REPOPATH/2.0/$PKG/ooo/${PKG}-2.0.zip.asc
+ if [ -n "$EXTRA" ]; then
+ ln -sf ../../../$POOLPATH/${PKG}-3.0.zip $TMPDIR/$REPOPATH/3.0/$PKG/ooo/${PKG}-3.0.zip
+ ln -sf ../../../$POOLPATH/${PKG}-3.0.zip.asc $TMPDIR/$REPOPATH/3.0/$PKG/ooo/${PKG}-3.0.zip.asc
+ fi
+}
+
+siteNonNativeR() {
+ local PKG=${1:-foo}
+ local EXTRA=${2:-}
+ makeUpstreamTar $PKG 0.0 gz non-native
+ makeUpstreamTar $PKG 1.0 gz non-native
+ makeUpstreamTar $PKG 2.0 gz non-native
+ mkdir -p $TMPDIR/$REPOPATH/0.0/$PKG/ooo/
+ mkdir -p $TMPDIR/$REPOPATH/1.0/$PKG/ooo/
+ mkdir -p $TMPDIR/$REPOPATH/2.0/$PKG/ooo/
+ if [ -n "$EXTRA" ]; then
+ makeUpstreamTar $PKG 3.0 gz non-native
+ mkdir -p $TMPDIR/$REPOPATH/3.0/$PKG/ooo/
+ fi
+ ln -sf ../../../$POOLPATH/${PKG}-0.0.tar.gz $TMPDIR/$REPOPATH/3.0/$PKG/ooo/${PKG}-0.0.tar.gz
+ ln -sf ../../../$POOLPATH/${PKG}-0.0.tar.gz.asc $TMPDIR/$REPOPATH/3.0/$PKG/ooo/${PKG}-0.0.tar.gz.asc
+ ln -sf ../../../$POOLPATH/${PKG}-1.0.tar.gz $TMPDIR/$REPOPATH/2.0/$PKG/ooo/${PKG}-1.0.tar.gz
+ ln -sf ../../../$POOLPATH/${PKG}-1.0.tar.gz.asc $TMPDIR/$REPOPATH/2.0/$PKG/ooo/${PKG}-1.0.tar.gz.asc
+ ln -sf ../../../$POOLPATH/${PKG}-2.0.tar.gz $TMPDIR/$REPOPATH/1.0/$PKG/ooo/${PKG}-2.0.tar.gz
+ ln -sf ../../../$POOLPATH/${PKG}-2.0.tar.gz.asc $TMPDIR/$REPOPATH/1.0/$PKG/ooo/${PKG}-2.0.tar.gz.asc
+ if [ -n "$EXTRA" ]; then
+ ln -sf ../../../$POOLPATH/${PKG}-3.0.tar.gz $TMPDIR/$REPOPATH/0.0/$PKG/ooo/${PKG}-3.0.tar.gz
+ ln -sf ../../../$POOLPATH/${PKG}-3.0.tar.gz.asc $TMPDIR/$REPOPATH/0.0/$PKG/ooo/${PKG}-3.0.tar.gz.asc
+ fi
+}
+
+# test a watch files
+
+### VERSION 4 ###
+# standard tests
+
+# test non-native package with uupdate, bare FTP server in normal order
+testWatch4NonNative() {
+ WATCHVER=4
+ WATCHLINE='opts=pgpsigurlmangle=s/$/.asc/ @@@url@@@([\.\d]+)/(.+)/(.+)/ @PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch siteNonNative
+}
+
+# test --download-current-version, bare FTP server in normal order
+testWatch4NonNativeDlCurrent() {
+ WATCHVER=4
+ XCOMMAND="$COMMAND --download-current-version"
+ WATCHLINE='opts=pgpsigurlmangle=s/$/.asc/ @@@url@@@([\.\d]+)/(.+)/(.+)/ @PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch siteNonNative 1.0 1.0
+}
+
+# test --download-version, bare FTP server in normal order
+testWatch4NonNativeDlUversion() {
+ WATCHVER=4
+ XCOMMAND="$COMMAND --download-version 0.0"
+ WATCHLINE='opts=pgpsigurlmangle=s/$/.asc/ @@@url@@@([\.\d]+)/(.+)/(.+)/ @PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch siteNonNative 1.0 0.0
+}
+
+# test non-native package with uupdate, bare FTP server in normal order with upstream ZIP
+testWatch4NonNativeZip() {
+ WATCHVER=4
+ COMPRESSION='zip'
+ WATCHLINE='opts=pgpsigurlmangle=s/$/.asc/ @@@url@@@([\.\d]+)/(.+)/(.+)/ @PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatchZip siteNonNativeZip
+}
+
+# test non-native package with uupdate, bare FTP server in normal order with repack to xz
+testWatch4NonNativeXz() {
+ WATCHVER=4
+ GZREPACK='xz'
+ WATCHLINE='opts=pgpsigurlmangle=s/$/.asc/,compression=xz,repack @@@url@@@([\.\d]+)/(.+)/(.+)/ @PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch siteNonNative
+}
+
+# test non-native package with uupdate, bare FTP server in normal order with ungzsig
+testWatch4NonNativeUngzsig() {
+ WATCHVER=4
+ WATCHLINE='opts=pgpsigurlmangle=s/.gz$/.asc/,decompress @@@url@@@([\.\d]+)/(.+)/(.+)/ @PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch siteNonNative
+}
+
+. shunit2
diff --git a/test/test_uscan_git b/test/test_uscan_git
new file mode 100755
index 0000000..61b5c81
--- /dev/null
+++ b/test/test_uscan_git
@@ -0,0 +1,207 @@
+#!/bin/bash
+
+# Copyright (C) 2018, Xavier <yadd@debian.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at your
+# option) any later version.
+#
+# 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.
+#
+# On Debian systems, the complete text of the GNU General Public License
+# version 3 can be found in the /usr/share/common-licenses/GPL-3 file.
+
+set -u
+#set -x
+
+TESTTYPE=Git
+. ./lib_test_uscan
+
+COMMAND="chronic_sh uscan --no-conf --compression=xz --dehs"
+
+# prevent the local from messing with this test
+export GIT_CONFIG_NOGLOBAL=1
+export HOME=""
+export XDG_CONFIG_HOME=""
+
+# comment out for debug
+#COMMAND="$COMMAND --verbose"
+#COMMAND="$COMMAND --debug"
+
+cleanup(){
+ rm -rf "$TEMP_PKG_DIR"
+}
+
+spawnGitRepo(){
+ mkdir -p "$TEMP_PKG_DIR/repo"
+ (cd "$TEMP_PKG_DIR/repo" || exit 1
+ chronic_sh git init
+ git config user.name "Joe Developer"
+ git config user.email "none@debian.org"
+ touch changelog file.c extra.c
+ echo 'extra.c export-ignore' >.gitattributes
+ chronic_sh git add changelog file.c extra.c .gitattributes
+ chronic_sh git commit -a -m 'Init'
+ for version in 1.0 2.0; do
+ echo "# Version $version" >> file.c
+ cat >> changelog <<END
+Version $version
+
+END
+ chronic_sh git commit -a -m "Releasing $version"
+ chronic_sh git tag -s -u 72543FAF -m "Version $version" "v$version"
+ done)
+}
+
+trap cleanup EXIT
+
+containsName(){
+ echo "$1" | grep -F -q "$2"
+ echo $?
+}
+
+# shellcheck source=shunit2-helper-functions.sh
+. "${0%/*}/shunit2-helper-functions.sh"
+
+PKG=foo
+
+makeDebianDir() {
+ WATCHARGS=$1
+ TEMP_PKG_DIR=$(mktemp -d --tmpdir="$SHUNIT_TMPDIR" uscan_git.XXXXXX)
+ if [ -z "$TEMP_PKG_DIR" ]; then
+ echo "Failed to create temporary directory" >&2
+ exit 1
+ fi
+ mkdir -p "$TEMP_PKG_DIR"/$PKG/debian/upstream
+ mkdir -p "$TEMP_PKG_DIR"/$PKG/debian/source
+ spawnGitRepo
+
+ cat <<END > "$TEMP_PKG_DIR/$PKG/debian/watch"
+version=4
+opts="mode=git,gitmode=shallow,$WATCHARGS" \
+file:///$TEMP_PKG_DIR/repo refs/tags/v([\\d\\.]+) debian
+END
+
+ cat <<END > "$TEMP_PKG_DIR/$PKG/debian/changelog"
+$PKG (0-1) unstable; urgency=low
+
+ * Initial release
+
+ -- Joe Developer <jd@debian.org> Mon, 02 Nov 2013 22:21:31 -0100
+END
+ echo '3.0 (quilt)' > "$TEMP_PKG_DIR/$PKG/debian/source/format"
+ cp -f "$test_dir/uscan/PUBLIC_KEY.asc" "$TEMP_PKG_DIR/$PKG/debian/upstream/signing-key.asc"
+}
+
+makeDebianDirWithUpstream() {
+ WATCHARGS=$1
+ makeDebianDir "$WATCHARGS"
+ cd "$TEMP_PKG_DIR/$PKG" || exit 1
+ chronic_sh git init
+ chronic_sh git remote add upstream "file:///$TEMP_PKG_DIR/repo"
+ chronic_sh git fetch upstream
+ cd - > /dev/null || exit 1
+}
+
+makeDebianDirHead() {
+ WATCHARGS=$1
+ makeDebianDir "$WATCHARGS"
+ cat <<END > "$TEMP_PKG_DIR/$PKG/debian/watch"
+version=4
+opts="mode=git,pretty=0.0+git%cd.%h" \
+file:///$TEMP_PKG_DIR/repo HEAD
+END
+}
+
+helperLaunch() {
+ WATCHARGS=$1
+ ARG="${2:-}"
+ CMD_ARG="${3:-}"
+ if test "$ARG" = "upstream"; then
+ makeDebianDirWithUpstream "$WATCHARGS"
+ elif test "$ARG" = "HEAD"; then
+ makeDebianDirHead "$WATCHARGS"
+ else
+ makeDebianDir "$WATCHARGS"
+ fi
+ ( cd "$TEMP_PKG_DIR/$PKG" || exit 1 ; $COMMAND $CMD_ARG --watchfile=debian/watch )
+ assertEquals "uscan: exit_code!=0 but exit_code=0" "$?" "0"
+}
+
+testGit() {
+ helperLaunch "pgpmode=none"
+ TARBALL=${PKG}_2.0.orig.tar.xz
+ assertTrue 'downloaded tarfile not present' "[ -f '$TEMP_PKG_DIR/${PKG}-2.0.tar.xz' ]"
+ assertTrue 'pristine tarball is not created' "[ -f '$TEMP_PKG_DIR/$TARBALL' ]"
+ assertTrue 'pristine tarball is a symlink' "[ -L '$TEMP_PKG_DIR/$TARBALL' ]"
+ cleanup
+}
+
+testGitHead() {
+ helperLaunch "pgpmode=none" HEAD
+ ORIG=$(find "$TEMP_PKG_DIR" | perl -ne 'print if/\/foo.*\.orig\.tar\.xz$/')
+ UPSTREAM=$(find "$TEMP_PKG_DIR" | perl -ne 'print if/\/foo.*(?<!orig)\.tar\.xz$/')
+ assertTrue 'downloaded tarfile not present' "[ -f '$UPSTREAM' ]"
+ assertTrue 'pristine tarball is not created' "[ -f '$ORIG' ]"
+ assertTrue 'pristine tarball is a symlink' "[ -L '$ORIG' ]"
+ cleanup
+}
+
+testGitSignedTag() {
+ helperLaunch "pgpmode=gittag"
+ TARBALL=${PKG}_2.0.orig.tar.xz
+ assertTrue 'downloaded tarfile not present' "[ -f '$TEMP_PKG_DIR/${PKG}-2.0.tar.xz' ]"
+ assertTrue 'pristine tarball is not created' "[ -f '$TEMP_PKG_DIR/$TARBALL' ]"
+ assertTrue 'pristine tarball is a symlink' "[ -L '$TEMP_PKG_DIR/$TARBALL' ]"
+ cleanup
+}
+
+testGitUpstream() {
+ helperLaunch "pgpmode=none" upstream
+ TARBALL=${PKG}_2.0.orig.tar.xz
+ assertTrue 'downloaded tarfile not present' "[ -f '$TEMP_PKG_DIR/${PKG}-2.0.tar.xz' ]"
+ assertTrue 'pristine tarball is not created' "[ -f '$TEMP_PKG_DIR/$TARBALL' ]"
+ assertTrue 'pristine tarball is a symlink' "[ -L '$TEMP_PKG_DIR/$TARBALL' ]"
+ cleanup
+}
+
+testGitUpstreamSignedTag() {
+ helperLaunch "pgpmode=gittag" upstream
+ TARBALL=${PKG}_2.0.orig.tar.xz
+ assertTrue 'downloaded tarfile not present' "[ -f '$TEMP_PKG_DIR/${PKG}-2.0.tar.xz' ]"
+ assertTrue 'pristine tarball is not created' "[ -f '$TEMP_PKG_DIR/$TARBALL' ]"
+ assertTrue 'pristine tarball is a symlink' "[ -L '$TEMP_PKG_DIR/$TARBALL' ]"
+ cleanup
+}
+
+testGitIgnoreExclusions() {
+ helperLaunch "gitexport=all"
+ assertTrue 'downloaded tarfile is incomplete' \
+ "tar tf '$TEMP_PKG_DIR/${PKG}-2.0.tar.xz' '${PKG}-2.0/extra.c'"
+ cleanup
+}
+
+testGitUpstreamIgnoreExclusions() {
+ helperLaunch "gitexport=all" upstream
+ assertTrue 'downloaded tarfile is incomplete' \
+ "tar tf '$TEMP_PKG_DIR/${PKG}-2.0.tar.xz' '${PKG}-2.0/extra.c'"
+ cleanup
+}
+
+testGitSignedTagWithDestDir() {
+ DESTDIR=$TEMP_PKG_DIR/destdir
+ mkdir -p $DESTDIR
+ helperLaunch "pgpmode=gittag" "" "--destdir $TEMP_PKG_DIR/destdir"
+ TARBALL=${PKG}_2.0.orig.tar.xz
+ assertTrue 'downloaded tarfile not present' "[ -f '$DESTDIR/${PKG}-2.0.tar.xz' ]"
+ assertTrue 'pristine tarball is not created' "[ -f '$DESTDIR/$TARBALL' ]"
+ assertTrue 'pristine tarball is a symlink' "[ -L '$DESTDIR/$TARBALL' ]"
+ cleanup
+}
+
+# shellcheck disable=SC1091
+. shunit2
diff --git a/test/test_uscan_group b/test/test_uscan_group
new file mode 100755
index 0000000..c5e7ef9
--- /dev/null
+++ b/test/test_uscan_group
@@ -0,0 +1,210 @@
+#!/bin/bash
+
+# Copyright (C) 2020, Xavier Guimard <yadd@debian.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at your
+# option) any later version.
+#
+# 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.
+#
+# On Debian systems, the complete text of the GNU General Public License
+# version 3 can be found in the /usr/share/common-licenses/GPL-3 file.
+
+set -u
+
+TESTTYPE=base
+test_dir=$(readlink -f "${0%/*}")
+. "$test_dir/lib_test_uscan"
+
+SUFFIX="1"
+if command -v dpkg-vendor >/dev/null; then
+ VENDER="$(dpkg-vendor --query Vendor 2>/dev/null|tr 'A-Z' 'a-z')"
+ case "$VENDER" in
+ debian) SUFFIX="1" ;;
+ *) SUFFIX="0${VENDER}1" ;;
+ esac
+fi
+
+if test "${1:-}" = --installed; then
+ COMMAND="uscan --no-conf --compression=gz"
+ shift
+else
+ top_srcdir=$(readlink -f "${0%/*}/..")
+ make -C "$top_srcdir/scripts" uscan mk-origtargz uupdate debchange
+ PATH="$top_srcdir/scripts:$PATH"
+ export PATH
+ PERL5LIB="$top_srcdir/lib"
+ export PERL5LIB
+ COMMAND="uscan --no-conf --compression=xz"
+fi
+
+COMMANDDEHS="$COMMAND --dehs"
+
+# comment out for debug
+#COMMAND="$COMMAND --debug"
+
+tearDown(){
+ killHttpServer
+ echo
+}
+
+trap tearDown EXIT
+
+containsName(){
+ echo "$1" | grep -qF "$2"
+ echo $?
+}
+
+makeRepo() {
+ lv="$1"
+ cmpopt1="$2"
+ lv1="$3"
+ cmpopt2="$4"
+ lv2="$5"
+ cmpopt3="$6"
+ lv3="$7"
+ cmpopt4="$8"
+ lv4="$9"
+ prev="${10}"
+ PKG=foo
+ TEMP_PKG_DIR=$(mktemp -d -p "$SHUNIT_TMPDIR")
+
+ mkdir -p "$TEMP_PKG_DIR"/$PKG/debian/source
+ spawnHttpServer
+ PORT=$(cat "$TEMP_PKG_DIR"/repo/port)
+
+ cat <<END > "$TEMP_PKG_DIR"/$PKG/debian/watch
+version=4
+http://localhost:$PORT/ .*$PKG-([\d\.]+).tar.gz $lv
+
+opts="dversionmangle=auto,component=bar1$cmpopt1" http://localhost:$PORT/ .*bar1-([\d\.]+).tar.gz $lv1
+opts="dversionmangle=auto,component=bar2$cmpopt2" http://localhost:$PORT/ .*bar2-([\d\.]+).tar.gz $lv2
+opts="dversionmangle=auto,component=bar3$cmpopt3" http://localhost:$PORT/ .*bar3-([\d\.]+).tar.gz $lv3
+opts="dversionmangle=auto,component=bar4$cmpopt4" http://localhost:$PORT/ .*bar4-([\d\.]+).tar.gz $lv4
+END
+
+ cat <<END > "$TEMP_PKG_DIR"/$PKG/debian/changelog
+$PKG ($prev) unstable; urgency=medium
+
+ * Initial release
+
+ -- Joe Developer <jd@debian.org> Mon, 02 Nov 2013 22:21:31 -0100
+END
+
+ echo -n '3.0 (quilt)' > "$TEMP_PKG_DIR"/$PKG/debian/source/format
+ mkdir -p "$TEMP_PKG_DIR"/repo/foo
+ touch "$TEMP_PKG_DIR"/repo/foo/content
+
+ # Upstream repo
+ ( cd "$TEMP_PKG_DIR"/repo ;
+ tar -czf $PKG-1.0.0.tar.gz $PKG/* )
+
+ for i in 1 2 3 4; do
+ # Upstream repo
+ mkdir -p "$TEMP_PKG_DIR"/repo/bar$i
+ touch "$TEMP_PKG_DIR"/repo/bar$i/content
+ ( cd "$TEMP_PKG_DIR"/repo ;
+ tar -czf bar$i-2.0.$i.tar.gz bar$i/* )
+ # Debian dir
+ mkdir $TEMP_PKG_DIR/$PKG/bar$i
+ echo '{"name":"bar'$i'","version":"'1.0.$i'"}' > $TEMP_PKG_DIR/$PKG/bar$i/package.json
+ done
+}
+
+helperDownload() {
+ next="${11}"
+ makeRepo "$@"
+
+ OUTPUT=$( cd "$TEMP_PKG_DIR"/$PKG ; $COMMANDDEHS --dehs )
+ BASETARBALL=${PKG}_$next.orig
+ assertTrue 'pristine tarball foo is not created' "[ -f "$TEMP_PKG_DIR"/$BASETARBALL.tar.gz ]"
+ assertTrue "malformed target in dehs output: $OUTPUT" \
+ $(containsName "$OUTPUT" "<target>$BASETARBALL.tar.gz</target>")
+ for i in 1 2 3 4; do
+ assertTrue "pristine tarball bar$i is not created" "[ -f "$TEMP_PKG_DIR"/$BASETARBALL-bar$i.tar.gz ]"
+ assertTrue "malformed target in dehs output: $OUTPUT" \
+ $(containsName "$OUTPUT" "<component-target>$BASETARBALL-bar$i.tar.gz</component-target>")
+ done
+ #cat "$TEMP_PKG_DIR"/$PKG/debian/watch
+}
+
+testCmpIgnore() {
+ helperDownload "debian" "" "ignore" "" "ignore" "" "ignore" "" "ignore" "0.0.1" "1.0.0"
+}
+
+testCmpGroup() {
+ helperDownload "group" "" "group" "" "group" "" "group" "" "group" "0.0.1+~1" "1.0.0+~2.0.1+~2.0.2+~2.0.3+~2.0.4"
+}
+
+testCmpGroupOneCmpChanged() {
+ helperDownload "group" "" "group" "" "group" "" "group" "" "group" "1.0.0+~2.0.1+~2.0.2+~2.0.2+~2.0.4" "1.0.0+~2.0.1+~2.0.2+~2.0.3+~2.0.4"
+}
+
+testCmpPartialGroup() {
+ helperDownload "group" "" "group" "" "group" "" "ignore" "" "ignore" "0.0.1+~1" "1.0.0+~2.0.1+~2.0.2"
+}
+
+testCmpPartialGroup2() {
+ helperDownload "group" "" "group" "" "ignore" "" "group" "" "ignore" "0.0.1+~1" "1.0.0+~2.0.1+~2.0.3"
+}
+
+testCmpChecksum() {
+ helperDownload "group" "" "checksum" "" "checksum" "" "checksum" "" "checksum" "0.0.1+~1" "1.0.0+~cs8.0.10"
+}
+
+testCmpChecksumOneCmpChanged() {
+ helperDownload "group" "" "checksum" "" "checksum" "" "checksum" "" "checksum" "1.0.0+~cs8.0.9" "1.0.0+~cs8.0.10"
+}
+
+testCmpGroupAndChecksum() {
+ helperDownload "group" "" "group" "" "checksum" "" "checksum" "" "checksum" "0.0.1+~1" "1.0.0+~2.0.1+~cs6.0.9"
+}
+
+testCmpGroupIgnoreAndChecksum() {
+ helperDownload "group" "" "group" "" "ignore" "" "checksum" "" "checksum" "0.0.1+~1" "1.0.0+~2.0.1+~cs4.0.7"
+}
+
+helperNoDownload() {
+ next="${10}"
+ makeRepo "$@"
+
+ OUTPUT=$( cd "$TEMP_PKG_DIR"/$PKG ; $COMMANDDEHS --dehs 2>&1 )
+ assertTrue "bad change detected: $OUTPUT" \
+ $(containsName "$OUTPUT" "<status>up to date</status>")
+ BASETARBALL=${PKG}_$next.orig
+ assertTrue 'pristine tarball foo is created' "[ ! -f "$TEMP_PKG_DIR"/$BASETARBALL.tar.gz ]"
+}
+
+testCmpIgnoreND() {
+ helperNoDownload "debian" "" "ignore" "" "ignore" "" "ignore" "" "ignore" "1.0.0"
+}
+
+testCmpGroupND() {
+ helperNoDownload "group" "" "group" "" "group" "" "group" "" "group" "1.0.0+~2.0.1+~2.0.2+~2.0.3+~2.0.4"
+}
+
+testCmpGroupRepackND() {
+ helperNoDownload "group" "" "group" "" "group" "" "group" "" "group" "1.0.0+~2.0.1~ds+~2.0.2+~2.0.3+~2.0.4"
+}
+
+testCmpChecksumND() {
+ helperNoDownload "group" "" "checksum" "" "checksum" "" "checksum" "" "checksum" "1.0.0+~cs8.0.10"
+}
+
+# Same test but here Ctype detects change even if previous checksum is wrong
+testCmpChecksumCtype() {
+ helperDownload "group" ",ctype=nodejs" "checksum" ",ctype=nodejs" "checksum" ",ctype=nodejs" "checksum" ",ctype=nodejs" "checksum" "1.0.0+~cs8.0.10" "1.0.0+~cs8.0.10"
+}
+
+testCmpIgnoreCtype() {
+ helperNoDownload "debian" ",ctype=nodejs" "ignore" "" "ignore" "" "ignore" "" "ignore" "1.0.0"
+ assertTrue "Component change is not detected: $OUTPUT" \
+ $(containsName "$OUTPUT" "Newest version of bar1 on remote site is 2.0.1, local version is 1.0.1")
+}
+
+. shunit2
diff --git a/test/test_uscan_mangle b/test/test_uscan_mangle
new file mode 100755
index 0000000..409e16e
--- /dev/null
+++ b/test/test_uscan_mangle
@@ -0,0 +1,1543 @@
+#!/bin/bash
+
+# Copyright (C) 2013, Rafael Laboissiere <rafael@laboissiere.net>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at your
+# option) any later version.
+#
+# 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.
+#
+# On Debian systems, the complete text of the GNU General Public License
+# version 3 can be found in the /usr/share/common-licenses/GPL-3 file.
+
+set -u
+
+TESTTYPE=Mangle
+. ./lib_test_uscan
+
+COMMAND="uscan --no-conf"
+
+# set safe defaults
+WEBSCRIPT=":"
+DEBUGECHO=":"
+DEBUGLSLR=":"
+DEBUGBASH=":"
+# comment out for debug
+#COMMAND="$COMMAND --debug"
+#COMMAND="$COMMAND --verbose"
+#DEBUGECHO=echo
+#DEBUGLSLR="ls -laR"
+#DEBUGLSLR="ls -la"
+#DEBUGBASH="bash -i"
+
+# Initial Debian revision value is distribution dependent
+SUFFIX="1"
+if command -v dpkg-vendor >/dev/null; then
+ VENDER="$(dpkg-vendor --query Vendor 2>/dev/null|tr 'A-Z' 'a-z')"
+ case "$VENDER" in
+ debian) SUFFIX="1" ;;
+ *) SUFFIX="0${VENDER}1" ;;
+ esac
+fi
+
+tearDown(){
+ killHttpServer
+ echo
+}
+
+trap tearDown EXIT
+
+containsName(){
+ echo "$1" | grep -qF "$2"
+ echo $?
+}
+
+. "${0%/*}/shunit2-helper-functions.sh"
+
+# The following tests do the following: (1) create a minimal Debian package
+# directory, containing minimal files debian/{changelog,watch,copyright},
+# (2) create a minimal repository, containing a tarball (built on the fly),
+# (3) start an HTTP server that works offline, using the SimpleHTTPServer
+# module of Python, and (4) run uscan inside that minimal universe.
+
+# make debian/ in `pwd`
+# debian/watch contains $WATCHVER and $WATCHLINE with template URL updated
+makeDebianDir() {
+ DEBNAME=${1:-foo} # Debian source package name
+ DEBVER=${2:-1.0} # Debian source package version
+ mkdir -p debian/source
+
+ cat <<END > debian/rules
+%:
+ dh $@
+END
+chmod 755 debian/rules
+
+ cat <<END > debian/changelog
+$DEBNAME ($DEBVER) unstable; urgency=low
+
+ * Release of the $DEBNAME package $DEBVER.
+
+ -- Joe Developer <jd@debian.org> Mon, 02 Nov 2013 22:21:31 -0100
+END
+ # debian/source/format
+ case $DEBVER in
+ *-*) # non-native package
+ echo "3.0 (quilt)" > debian/source/format
+ ;;
+ *) # native package
+ echo "3.0 (native)" > debian/source/format
+ ;;
+ esac
+ # debian/copyright
+ echo "Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/" \
+ > debian/copyright
+ if [ "${FILEEXCLUDE:-0}" = "1" ]; then
+ # exclude just for main
+ cat <<'END' >> debian/copyright
+Files-Excluded: exclude-this
+ */exclude-dir
+ .*
+ */js/jquery.js
+ ;?echo?baz;?#
+END
+ elif [ "${FILEEXCLUDE:-0}" = "2" ]; then
+ # exclude for main(=foo) bar baz
+ cat <<'END' >> debian/copyright
+Files-Excluded: exclude-this
+ */exclude-dir
+ .*
+ */js/jquery.js
+ ;?echo?baz;?#
+Files-Excluded-bar: exclude-this
+ */exclude-dir
+ .*
+ */js/jquery.js
+ ;?echo?baz;?#
+Files-Excluded-baz: exclude-this
+ */exclude-dir
+ .*
+ */js/jquery.js
+ ;?echo?baz;?#
+END
+ elif [ "${FILEEXCLUDE:-0}" = "3" ]; then
+ # exclude for foo bar baz
+ cat <<'END' >> debian/copyright
+Files-Excluded-foo: exclude-this
+ */exclude-dir
+ .*
+ */js/jquery.js
+ ;?echo?baz;?#
+Files-Excluded-bar: exclude-this
+ */exclude-dir
+ .*
+ */js/jquery.js
+ ;?echo?baz;?#
+Files-Excluded-baz: exclude-this
+ */exclude-dir
+ .*
+ */js/jquery.js
+ ;?echo?baz;?#
+END
+ fi
+ # debian/watch
+ echo "version=$WATCHVER" > debian/watch
+ echo "$WATCHLINE" | sed -e "s,@@@url@@@,http://localhost:${PORT}/,g" - \
+ >> debian/watch
+ # debian/upstream/signing-key.asc
+ mkdir -p debian/upstream
+ if [ "$KEYMODE" = "ASC" ]; then
+ cp -f $test_dir/uscan/PUBLIC_KEY.asc debian/upstream/signing-key.asc
+ else
+ cp -f "$GPGHOME/pubring.gpg" debian/upstream/signing-key.pgp
+ fi
+}
+
+
+# make tarball in $REPOPATH/$POOLPATH
+makeUpstreamTar() {
+ UPNAME=${1:-foo} # Upstream package name
+ UPVER=${2:-1.0} # upstream package version
+ COMPRESSION=${3:-gz} # archve compression type
+ TYPE=${4:-non-native} # set this if native-type upstream
+ OLDDIR=`pwd`
+ mkdir -p "$TEMP_PKG_DIR"/$REPOPATH/$POOLPATH/$UPNAME-$UPVER
+ cd "$TEMP_PKG_DIR"/$REPOPATH/$POOLPATH
+ touch $UPNAME-$UPVER/FILE.$UPNAME.$UPVER
+ touch $UPNAME-$UPVER/include-this
+ touch $UPNAME-$UPVER/exclude-this
+ touch $UPNAME-$UPVER/.hidden
+ mkdir -p "$UPNAME-$UPVER/; echo baz; #/"
+ mkdir -p $UPNAME-$UPVER/exclude-dir
+ touch $UPNAME-$UPVER/exclude-dir/file
+ mkdir -p $UPNAME-$UPVER/subdir/exclude-dir
+ touch $UPNAME-$UPVER/subdir/exclude-dir/file2
+ mkdir -p $UPNAME-$UPVER/docs/html/js/
+ touch $UPNAME-$UPVER/docs/html/js/jquery.js
+ if [ "$TYPE" = "native" ]; then
+ cd "$TEMP_PKG_DIR"/$REPOPATH/$POOLPATH/$UPNAME-$UPVER
+ makeDebianDir $UPNAME $UPVER
+ cd "$TEMP_PKG_DIR"/$REPOPATH/$POOLPATH
+ fi
+ case $COMPRESSION in
+ gz|gzip)
+ NEWTAR=$UPNAME-$UPVER.tar.gz
+ tar -czf $NEWTAR $UPNAME-$UPVER
+ ;;
+ bz2|bzip2)
+ NEWTAR=$UPNAME-$UPVER.tar.bz2
+ tar --bzip2 -cf $NEWTAR $UPNAME-$UPVER
+ ;;
+ xz)
+ NEWTAR= $UPNAME-$UPVER.tar.xz
+ tar --xz -cf $NEWTAR $UPNAME-$UPVER
+ ;;
+ zip)
+ NEWTAR=$UPNAME-$UPVER.zip
+ zip -r $NEWTAR $UPNAME-$UPVER
+ ;;
+ *) echo "Wrong compression mode: $COMPRESSION"
+ exit 1
+ ;;
+ esac
+ case "${SIGMODE:-}" in # undefined SIGMODE → no sig
+ ASC) # make $NEWTAR.asc
+ $GPG --homedir "$GPGHOME" --no-options -q --batch --no-default-keyring \
+ --secret-keyring $PRIVATE_KEYRING --default-key 72543FAF \
+ --armor --detach-sign $NEWTAR
+ ;;
+ BIN) #make $NEWTAR.sig
+ $GPG --homedir "$GPGHOME" --no-options -q --batch --no-default-keyring \
+ --secret-keyring $PRIVATE_KEYRING --default-key 72543FAF \
+ --detach-sign $NEWTAR
+ ;;
+ SELF) #make $NEWTAR.gpg
+ $GPG --homedir "$GPGHOME" --no-options -q --batch --no-default-keyring \
+ --secret-keyring $PRIVATE_KEYRING --default-key 72543FAF \
+ --sign $NEWTAR
+ esac
+
+ cd $OLDDIR
+}
+
+# setup a common watch file test environment
+helperWatch() {
+ local SITESCRIPT=${1:-siteWebNonNative}
+ local VEROLD=${2:-1.0}
+ local VERNEW=${3:-2.0}
+ local PREFIX="${4:-}"
+ TEMP_PKG_DIR=${TEMP_PKG_DIR:-$(mktemp -d -p "$SHUNIT_TMPDIR" uscan_mangle.XXXXXX)}
+ ORIGDIR=`pwd`
+ PKG=${PKG:-foo}
+ REPOPATH=${REPOPATH:-repo}
+ POOLPATH=${POOLPATH:-pool}
+ MGZREPACK=${MGZREPACK:-gz}
+ XCOMMAND=${XCOMMAND:-$COMMAND}
+ WATCHVER="${WATCHVER:-3}"
+ WATCHLINE0="@@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate"
+ WATCHLINE="${WATCHLINE:-$WATCHLINE0}"
+ COMPONENTS=${COMPONENTS:-}
+ FILEEXCLUDE=${FILEEXCLUDE:-0} # no exclude
+ FILENAMEMANGLE=${FILENAMEMANGLE:-}
+ SIGMODE=${SIGMODE:-ASC} # ASC=ASCII or BIN=BINARY or SELF
+ KEYMODE=${KEYMODE:-ASC} # ASC=ASCII AEMORED or BIN=DEARMORED BINARY
+ cd "$TEMP_PKG_DIR"
+ # start HTTP server with its root at "$TEMP_PKG_DIR"/$REPOPATH
+ spawnHttpServer
+ PORT=$(cat "$TEMP_PKG_DIR"/$REPOPATH/port)
+ $DEBUGECHO " ***** http://localhost:$PORT started showing "$TEMP_PKG_DIR"/$REPOPATH *****"
+ # make web site
+ $SITESCRIPT
+ # make local $VEROLD source tree
+ tar -xzf "$TEMP_PKG_DIR"/$REPOPATH/$POOLPATH/${PKG}-${VEROLD}.tar.gz
+ if [ -n "$PREFIX" ]; then
+ mv "$TEMP_PKG_DIR"/${PKG}-${VEROLD} "$TEMP_PKG_DIR"/${PKG}-${PREFIX}${VEROLD}
+ fi
+ mv "$TEMP_PKG_DIR"/${PKG}-${PREFIX}${VEROLD} "$TEMP_PKG_DIR"/${PKG}
+ cd "$TEMP_PKG_DIR"/${PKG}
+ if [ ! -d debian ]; then
+ makeDebianDir $PKG ${PREFIX}${VEROLD}-$SUFFIX
+ fi
+ local UUPDATE=""
+ if grep -q "uupdate" "$TEMP_PKG_DIR"/${PKG}/debian/watch ; then
+ UUPDATE=uupdate
+ fi
+ local PGP=""
+ if grep -q "pgpurlmangle" "$TEMP_PKG_DIR"/${PKG}/debian/watch ; then
+ PGP=pgp
+ fi
+ if grep -q "pgpmode *= *auto" "$TEMP_PKG_DIR"/${PKG}/debian/watch ; then
+ PGP=pgp
+ fi
+ if grep -q "pgpmode *= *previous" "$TEMP_PKG_DIR"/${PKG}/debian/watch ; then
+ PGP=pgp
+ fi
+ $XCOMMAND
+ assertEquals "uscan: exit_code!=0 but exit_code=0" "$?" "0"
+ cd "$TEMP_PKG_DIR"
+ $DEBUGLSLR
+ UTARBALL=${PKG}-${UVERSION:-${VERNEW}}.tar.gz
+ if [[ "$FILENAMEMANGLE" != *"$PKG"* ]]; then
+ UTARBALL=${PKG}-${UVERSION:-${VERNEW}}.tar.gz
+ else
+ UTARBALL=${PKG}-${UVERSION:-${VERNEW}}-filenamemangle.tar.gz
+ fi
+ STARBALL=${PKG}_${PREFIX}${VERNEW}.orig.tar.$MGZREPACK
+ if [ ! -f $STARBALL ]; then
+ # testWatch4WebNonNativeMUT0() only repacks its component tarballs. It does
+ # not repack the main upstream tarball, which is the usual behaviour when
+ # excluding files from the upstream source. This means we need to find the
+ # upstream tarball.
+ STARBALL=${PKG}_${PREFIX}${VERNEW}.orig.tar.gz
+ fi
+ assertTrue "$UTARBALL missing: $WATCHLINE" "[ -f $UTARBALL ]"
+ assertTrue "$STARBALL missing: $WATCHLINE" "[ -f $STARBALL ]"
+ if [ "$PGP" = "pgp" ]; then
+ UTARSIG=${PKG}-${UVERSION:-${VERNEW}}.tar.gz.sig
+ if [ ! -f $UTARSIG ]; then
+ UTARSIG=${PKG}-${UVERSION:-${VERNEW}}.tar.gz.asc
+ fi
+ STARSIG=${PKG}_${PREFIX}${VERNEW}.orig.tar.$MGZREPACK.asc
+ assertTrue "$UTARSIG and *.sig missing: $WATCHLINE" "[ -f $UTARSIG ]"
+ assertTrue "$STARSIG missing: $WATCHLINE" "[ -f $STARSIG ]"
+ fi
+ for cpnt in $COMPONENTS; do
+ if [[ "$FILENAMEMANGLE" != *"$cpnt"* ]]; then
+ UTARBALL=${cpnt}-${CMPVERSION:-${VERNEW}}.tar.gz
+ else
+ UTARBALL=${PKG}-${cpnt}-${CMPVERSION:-${VERNEW}}.tar.gz
+ fi
+ STARBALL=${PKG}_${PREFIX}${VERNEW}.orig-${cpnt}.tar.$MGZREPACK
+ assertTrue "$UTARBALL missing: $WATCHLINE" "[ -f $UTARBALL ]"
+ assertTrue "$STARBALL missing: $WATCHLINE" "[ -f $STARBALL ]"
+ if [ "$PGP" = "pgp" ]; then
+ UTARSIG=${cpnt}-${CMPVERSION:-${VERNEW}}.tar.gz.sig
+ if [ ! -f $UTARSIG ]; then
+ UTARSIG=${cpnt}-${CMPVERSION:-${VERNEW}}.tar.gz.asc
+ fi
+ STARSIG=${PKG}_${PREFIX}${VERNEW}.orig-${cpnt}.tar.$MGZREPACK.asc
+ assertTrue "$UTARSIG and *.sig missing: $WATCHLINE" "[ -f $UTARSIG ]"
+ # Skipping this: signature link skipped when upstream file is repacked
+ #assertTrue "$STARSIG missing: $WATCHLINE" "[ -f $STARSIG ]"
+ fi
+ done
+ # check uupdate
+ if [ "$UUPDATE" = "uupdate" ]; then
+ cd "$TEMP_PKG_DIR"/${PKG}-${PREFIX}${VERNEW}
+ assertTrue 'pristine tarball is not extracted' "[ -f debian/changelog ]"
+ DVERSION=`dpkg-parsechangelog -ldebian/changelog -SVersion`
+ assertEquals "uscan: Version should be ${PREFIX}${VERNEW}-$SUFFIX but $DVERSION" "$DVERSION" "${PREFIX}${VERNEW}-$SUFFIX"
+ if [ "$FILEEXCLUDE" != "3" ]; then
+ # main is dummy
+ assertTrue 'file that must be present is excluded in the tarball' '[ -f include-this ]'
+ fi
+ if [ "$FILEEXCLUDE" = "1" ] || [ "$FILEEXCLUDE" = "2" ]; then
+ assertFalse "file that must be excluded is present in the tarball" '[ -f exclude-this ]'
+ assertFalse "hidden file that must be excluded is present in the tarball" '[ -f .hidden ]'
+ assertFalse "dir that must be excluded is present in the tarball" '[ -d exclude-dir ]'
+ assertFalse "subdir that must be excluded is present in the tarball" '[ -d subdir/exclude-dir ]'
+ CONTENTS=$(ls -R)
+ assertFalse "non-root-file that must be excluded is present in the tarball" \
+ $(containsName "$CONTENTS" jquery.js)
+ assertFalse "path with whitespace that must be excluded is present in the tarball" \
+ $(containsName "$CONTENTS" "; echo baz; #/")
+ fi
+ for c in $COMPONENTS ; do
+ cd "$TEMP_PKG_DIR"/${PKG}-${PREFIX}${VERNEW}/$c
+ assertTrue 'file that must be present is excluded in the tarball' '[ -f include-this ]'
+ if [ "$FILEEXCLUDE" = "1" ] || [ "$FILEEXCLUDE" = "2" ]; then
+ assertFalse "file that must be excluded is present in the orig-$c.tar" '[ -f exclude-this ]'
+ assertFalse "hidden file that must be excluded is present in the orig-$c.tar" '[ -f .hidden ]'
+ assertFalse "dir that must be excluded is present in the orig-$c.tar" '[ -d exclude-dir ]'
+ assertFalse "subdir that must be excluded is present in the orig-$c.tar" '[ -d subdir/exclude-dir ]'
+ CONTENTS=$(ls -R)
+ assertFalse "non-root-file that must be excluded is present in the orig-$c.tar" \
+ $(containsName "$CONTENTS" jquery.js)
+ assertFalse "path with whitespace that must be excluded is present in the orig-$c.tar" \
+ $(containsName "$CONTENTS" "; echo baz; #/")
+ fi
+ done
+ cd "$TEMP_PKG_DIR"
+ fi
+ $DEBUGBASH
+ cd $ORIGDIR
+ unset REPOPATH
+ unset POOLPATH
+ unset MGZREPACK
+ unset XCOMMAND
+ unset WATCHVER
+ unset WATCHLINE
+ unset COMPONENTS
+ unset FILEEXCLUDE
+ unset FILENAMEMANGLE
+ unset SIGMODE
+ unset KEYMODE
+}
+
+# setup a common watch file test environment to see user-agent
+helperWatchUA() {
+ local SITESCRIPT=${1:-siteWebNonNative}
+ TEMP_PKG_DIR=$(mktemp -d -p "$SHUNIT_TMPDIR" uscan_mangle.XXXXXX)
+ ORIGDIR=`pwd`
+ PKG=${PKG:-foo}
+ REPOPATH=${REPOPATH:-repo}
+ POOLPATH=${POOLPATH:-pool}
+ XCOMMAND=${XCOMMAND:-$COMMAND}
+ WATCHVER="${WATCHVER:-3}"
+ WATCHLINE0="@@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate"
+ WATCHLINE="${WATCHLINE:-$WATCHLINE0}"
+ KEYMODE=${KEYMODE:-ASC} # ASC=ASCII AEMORED or BIN=DEARMORED BINARY
+ cd "$TEMP_PKG_DIR"
+ # start HTTP server with its root at "$TEMP_PKG_DIR"/$REPOPATH
+ spawnHttpServer
+ PORT=$(cat "$TEMP_PKG_DIR"/$REPOPATH/port)
+ $DEBUGECHO " ***** http://localhost:$PORT started showing "$TEMP_PKG_DIR"/$REPOPATH *****"
+ # make web site
+ $SITESCRIPT
+ # make local $VEROLD source tree
+ mkdir -p "$TEMP_PKG_DIR"/${PKG}
+ cd "$TEMP_PKG_DIR"/${PKG}
+ if [ ! -d debian ]; then
+ makeDebianDir $PKG 1.0-$SUFFIX
+ fi
+ $XCOMMAND
+ USERAGENTX="$(grep -ie '^User-Agent:' ../repo/log |head -1 | perl -p -e "s/\r//g" )"
+ assertTrue "Bad $USERAGENTX" "[ \"$USERAGENTX\" = \"User-Agent: $USERAGENT\" ]"
+ echo "SENT: \"User-Agent: $USERAGENT\""
+ echo "GOT : \"$USERAGENTX\""
+ $DEBUGBASH
+ cd $ORIGDIR
+ unset REPOPATH
+ unset POOLPATH
+ unset XCOMMAND
+ unset WATCHVER
+ unset WATCHLINE
+ unset KEYMODE
+}
+
+# populate pool directory
+siteNative() {
+ local PKG=${1:-foo}
+ makeUpstreamTar $PKG 0.0 gz native
+ makeUpstreamTar $PKG 1.0 gz native
+ makeUpstreamTar $PKG 2.0 gz native
+ mkdir -p "$TEMP_PKG_DIR"/$REPOPATH/0.0/$PKG/ooo/
+ mkdir -p "$TEMP_PKG_DIR"/$REPOPATH/1.0/$PKG/ooo/
+ mkdir -p "$TEMP_PKG_DIR"/$REPOPATH/2.0/$PKG/ooo/
+ ln -sf ../../../$POOLPATH/${PKG}-0.0.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/0.0/$PKG/ooo/${PKG}-0.0.tar.gz
+ ln -sf ../../../$POOLPATH/${PKG}-1.0.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/1.0/$PKG/ooo/${PKG}-1.0.tar.gz
+ ln -sf ../../../$POOLPATH/${PKG}-2.0.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/2.0/$PKG/ooo/${PKG}-2.0.tar.gz
+}
+
+siteNonNative() {
+ local PKG=${1:-foo}
+ local EXTRA=${2:-}
+ makeUpstreamTar $PKG 0.0 gz non-native
+ makeUpstreamTar $PKG 1.0 gz non-native
+ makeUpstreamTar $PKG 2.0 gz non-native
+ mkdir -p "$TEMP_PKG_DIR"/$REPOPATH/0.0/$PKG/ooo/
+ mkdir -p "$TEMP_PKG_DIR"/$REPOPATH/1.0/$PKG/ooo/
+ mkdir -p "$TEMP_PKG_DIR"/$REPOPATH/2.0/$PKG/ooo/
+ if [ -n "$EXTRA" ]; then
+ makeUpstreamTar $PKG 3.0 gz non-native
+ mkdir -p "$TEMP_PKG_DIR"/$REPOPATH/3.0/$PKG/ooo/
+ fi
+ if [ "${SIGMODE:-}" = "ASC" ]; then
+ ln -sf ../../../$POOLPATH/${PKG}-0.0.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/0.0/$PKG/ooo/${PKG}-0.0.tar.gz
+ ln -sf ../../../$POOLPATH/${PKG}-0.0.tar.gz.asc "$TEMP_PKG_DIR"/$REPOPATH/0.0/$PKG/ooo/${PKG}-0.0.tar.gz.asc
+ ln -sf ../../../$POOLPATH/${PKG}-1.0.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/1.0/$PKG/ooo/${PKG}-1.0.tar.gz
+ ln -sf ../../../$POOLPATH/${PKG}-1.0.tar.gz.asc "$TEMP_PKG_DIR"/$REPOPATH/1.0/$PKG/ooo/${PKG}-1.0.tar.gz.asc
+ ln -sf ../../../$POOLPATH/${PKG}-2.0.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/2.0/$PKG/ooo/${PKG}-2.0.tar.gz
+ ln -sf ../../../$POOLPATH/${PKG}-2.0.tar.gz.asc "$TEMP_PKG_DIR"/$REPOPATH/2.0/$PKG/ooo/${PKG}-2.0.tar.gz.asc
+ if [ -n "$EXTRA" ]; then
+ ln -sf ../../../$POOLPATH/${PKG}-3.0.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/3.0/$PKG/ooo/${PKG}-3.0.tar.gz
+ ln -sf ../../../$POOLPATH/${PKG}-3.0.tar.gz.asc "$TEMP_PKG_DIR"/$REPOPATH/3.0/$PKG/ooo/${PKG}-3.0.tar.gz.asc
+ fi
+ elif [ "${SIGMODE:-}" = "BIN" ]; then
+ ln -sf ../../../$POOLPATH/${PKG}-0.0.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/0.0/$PKG/ooo/${PKG}-0.0.tar.gz
+ ln -sf ../../../$POOLPATH/${PKG}-0.0.tar.gz.sig "$TEMP_PKG_DIR"/$REPOPATH/0.0/$PKG/ooo/${PKG}-0.0.tar.gz.sig
+ ln -sf ../../../$POOLPATH/${PKG}-1.0.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/1.0/$PKG/ooo/${PKG}-1.0.tar.gz
+ ln -sf ../../../$POOLPATH/${PKG}-1.0.tar.gz.sig "$TEMP_PKG_DIR"/$REPOPATH/1.0/$PKG/ooo/${PKG}-1.0.tar.gz.sig
+ ln -sf ../../../$POOLPATH/${PKG}-2.0.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/2.0/$PKG/ooo/${PKG}-2.0.tar.gz
+ ln -sf ../../../$POOLPATH/${PKG}-2.0.tar.gz.sig "$TEMP_PKG_DIR"/$REPOPATH/2.0/$PKG/ooo/${PKG}-2.0.tar.gz.sig
+ if [ -n "$EXTRA" ]; then
+ ln -sf ../../../$POOLPATH/${PKG}-3.0.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/3.0/$PKG/ooo/${PKG}-3.0.tar.gz
+ ln -sf ../../../$POOLPATH/${PKG}-3.0.tar.gz.sig "$TEMP_PKG_DIR"/$REPOPATH/3.0/$PKG/ooo/${PKG}-3.0.tar.gz.sig
+ fi
+ elif [ "${SIGMODE:-}" = "SELF" ]; then
+ ln -sf ../../../$POOLPATH/${PKG}-0.0.tar.gz.gpg "$TEMP_PKG_DIR"/$REPOPATH/0.0/$PKG/ooo/${PKG}-0.0.tar.gz.gpg
+ ln -sf ../../../$POOLPATH/${PKG}-1.0.tar.gz.gpg "$TEMP_PKG_DIR"/$REPOPATH/1.0/$PKG/ooo/${PKG}-1.0.tar.gz.gpg
+ ln -sf ../../../$POOLPATH/${PKG}-2.0.tar.gz.gpg "$TEMP_PKG_DIR"/$REPOPATH/2.0/$PKG/ooo/${PKG}-2.0.tar.gz.gpg
+ if [ -n "$EXTRA" ]; then
+ ln -sf ../../../$POOLPATH/${PKG}-3.0.tar.gz.gpg "$TEMP_PKG_DIR"/$REPOPATH/3.0/$PKG/ooo/${PKG}-3.0.tar.gz.gpg
+ fi
+ fi
+}
+
+# hide siteNative behind a web page
+siteWebNative() {
+ siteNative
+ cat <<END > "$TEMP_PKG_DIR"/$REPOPATH/index.html
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+<a href="/0.0/foo/ooo/foo-0.0.tar.gz">Very old</a> <br/ >
+<a href="/1.0/foo/ooo/foo-1.0.tar.gz">A bit OLD</a> <br />
+<a href="/2.0/foo/ooo/foo-2.0.tar.gz">Latest</a> <br />
+</body>
+<html>
+END
+}
+
+siteWebNonNative() {
+ siteNonNative
+ cat <<END > "$TEMP_PKG_DIR"/$REPOPATH/index.html
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+<a href="/0.0/foo/ooo/foo-0.0.tar.gz">Very old</a> <br/ >
+<a href="/1.0/foo/ooo/foo-1.0.tar.gz">A bit OLD</a> <br />
+<a href="/2.0/foo/ooo/foo-2.0.tar.gz">Latest</a> <br />
+</body>
+<html>
+END
+}
+
+siteWebNonNativeRecWithBase() {
+ siteNonNative "$@"
+ for DIR in "$TEMP_PKG_DIR"/$REPOPATH/[0-9].*; do
+ [ -d "$DIR" ] && cat <<END > "$DIR"/index.html
+<html>
+<head>
+ <meta charset="utf-8">
+<base href="/${DIR##*/}/foo/ooo/x.html"/>
+</head>
+<body>
+<a href="foo-${DIR##*/}.tar.gz">Blah</a> <br/ >
+</body>
+<html>
+END
+ done
+}
+
+siteWebNonNativeR() {
+ makeUpstreamTar foo 0.0 gz non-native
+ makeUpstreamTar foo 1.0 gz non-native
+ makeUpstreamTar foo 2.0 gz non-native
+ mkdir -p "$TEMP_PKG_DIR"/$REPOPATH/123/foo/ooo/
+ mkdir -p "$TEMP_PKG_DIR"/$REPOPATH/124/foo/ooo/
+ mkdir -p "$TEMP_PKG_DIR"/$REPOPATH/125/foo/ooo/
+ mkdir -p "$TEMP_PKG_DIR"/$REPOPATH/325/foo/ooo/
+ mkdir -p "$TEMP_PKG_DIR"/$REPOPATH/424/foo/ooo/
+ mkdir -p "$TEMP_PKG_DIR"/$REPOPATH/523/foo/ooo/
+ if [ "$SIGMODE" = "ASC" ]; then
+ ln -sf ../../../$POOLPATH/foo-0.0.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/125/foo/ooo/foo-0.0.tar.gz
+ ln -sf ../../../$POOLPATH/foo-1.0.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/124/foo/ooo/foo-1.0.tar.gz
+ ln -sf ../../../$POOLPATH/foo-2.0.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/123/foo/ooo/foo-2.0.tar.gz
+ ln -sf ../../../$POOLPATH/foo-0.0.tar.gz.asc "$TEMP_PKG_DIR"/$REPOPATH/325/foo/ooo/foo-0.0.tar.gz.asc
+ ln -sf ../../../$POOLPATH/foo-1.0.tar.gz.asc "$TEMP_PKG_DIR"/$REPOPATH/424/foo/ooo/foo-1.0.tar.gz.asc
+ ln -sf ../../../$POOLPATH/foo-2.0.tar.gz.asc "$TEMP_PKG_DIR"/$REPOPATH/523/foo/ooo/foo-2.0.tar.gz.asc
+ cat <<END > "$TEMP_PKG_DIR"/$REPOPATH/index.html
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+<a href="/125/foo/ooo/foo-0.0.tar.gz">Very old</a> <br/ >
+<a href="/124/foo/ooo/foo-1.0.tar.gz">A bit OLD</a> <br />
+<a href="/123/foo/ooo/foo-2.0.tar.gz">Latest</a> <br />
+<a href="/325/foo/ooo/foo-0.0.tar.gz.asc">Very old sig</a> <br/ >
+<a href="/424/foo/ooo/foo-1.0.tar.gz.asc">A bit OLD sig</a> <br />
+<a href="/523/foo/ooo/foo-2.0.tar.gz.asc">Latest sig</a> <br />
+</body>
+<html>
+END
+ elif [ "$SIGMODE" = "BIN" ]; then
+ ln -sf ../../../$POOLPATH/foo-0.0.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/125/foo/ooo/foo-0.0.tar.gz
+ ln -sf ../../../$POOLPATH/foo-1.0.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/124/foo/ooo/foo-1.0.tar.gz
+ ln -sf ../../../$POOLPATH/foo-2.0.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/123/foo/ooo/foo-2.0.tar.gz
+ ln -sf ../../../$POOLPATH/foo-0.0.tar.gz.sig "$TEMP_PKG_DIR"/$REPOPATH/325/foo/ooo/foo-0.0.tar.gz.sig
+ ln -sf ../../../$POOLPATH/foo-1.0.tar.gz.sig "$TEMP_PKG_DIR"/$REPOPATH/424/foo/ooo/foo-1.0.tar.gz.sig
+ ln -sf ../../../$POOLPATH/foo-2.0.tar.gz.sig "$TEMP_PKG_DIR"/$REPOPATH/523/foo/ooo/foo-2.0.tar.gz.sig
+ cat <<END > "$TEMP_PKG_DIR"/$REPOPATH/index.html
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+<a href="/125/foo/ooo/foo-0.0.tar.gz">Very old</a> <br/ >
+<a href="/124/foo/ooo/foo-1.0.tar.gz">A bit OLD</a> <br />
+<a href="/123/foo/ooo/foo-2.0.tar.gz">Latest</a> <br />
+<a href="/325/foo/ooo/foo-0.0.tar.gz.sig">Very old sig</a> <br/ >
+<a href="/424/foo/ooo/foo-1.0.tar.gz.sig">A bit OLD sig</a> <br />
+<a href="/523/foo/ooo/foo-2.0.tar.gz.sig">Latest sig</a> <br />
+</body>
+<html>
+END
+ elif [ "$SIGMODE" = "SELF" ]; then
+ ln -sf ../../../$POOLPATH/foo-0.0.tar.gz.gpg "$TEMP_PKG_DIR"/$REPOPATH/325/foo/ooo/foo-0.0.tar.gz.gpg
+ ln -sf ../../../$POOLPATH/foo-1.0.tar.gz.gpg "$TEMP_PKG_DIR"/$REPOPATH/424/foo/ooo/foo-1.0.tar.gz.gpg
+ ln -sf ../../../$POOLPATH/foo-2.0.tar.gz.gpg "$TEMP_PKG_DIR"/$REPOPATH/523/foo/ooo/foo-2.0.tar.gz.gpg
+ cat <<END > "$TEMP_PKG_DIR"/$REPOPATH/index.html
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+<a href="/125/foo/ooo/foo-0.0.tar.gz">Very old</a> <br/ >
+<a href="/124/foo/ooo/foo-1.0.tar.gz">A bit OLD</a> <br />
+<a href="/123/foo/ooo/foo-2.0.tar.gz">Latest</a> <br />
+<a href="/325/foo/ooo/foo-0.0.tar.gz.gpg">Very old sig</a> <br/ >
+<a href="/424/foo/ooo/foo-1.0.tar.gz.gpg">A bit OLD sig</a> <br />
+<a href="/523/foo/ooo/foo-2.0.tar.gz.gpg">Latest sig</a> <br />
+</body>
+<html>
+END
+ fi
+}
+
+sitePrWebNonNative() {
+ siteNonNative
+ cat <<END > "$TEMP_PKG_DIR"/$REPOPATH/index.html
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+<a href="/0.0/boo/xxx/boo-0.0.tar.gz">Very old</a> <br/ >
+<a href="/1.0/boo/xxx/boo-1.0.tar.gz">A bit OLD</a> <br />
+<a href="/2.0/boo/xxx/boo-2.0.tar.gz">Latest</a> <br />
+</body>
+<html>
+END
+}
+
+siteWebNonNativeLarge() {
+ makeUpstreamTar foo 19990101 gz non-native
+ makeUpstreamTar foo 20000101 gz non-native
+ makeUpstreamTar foo 20010101 gz non-native
+ mkdir -p $REPOPATH/0.0/foo/ooo/
+ mkdir -p $REPOPATH/1.0/foo/ooo/
+ mkdir -p $REPOPATH/2.0/foo/ooo/
+ ln -sf ../../../$POOLPATH/foo-19990101.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/0.0/foo/ooo/foo-19990101.tar.gz
+ ln -sf ../../../$POOLPATH/foo-20000101.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/1.0/foo/ooo/foo-20000101.tar.gz
+ ln -sf ../../../$POOLPATH/foo-20010101.tar.gz "$TEMP_PKG_DIR"/$REPOPATH/2.0/foo/ooo/foo-20010101.tar.gz
+ cat <<END > "$TEMP_PKG_DIR"/$REPOPATH/index.html
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+<a href="/0.0/foo/ooo/foo-19990101.tar.gz">Very old</a> <br/ >
+<a href="/1.0/foo/ooo/foo-20000101.tar.gz">A bit OLD</a> <br />
+<a href="/2.0/foo/ooo/foo-20010101.tar.gz">Latest</a> <br />
+</body>
+<html>
+END
+}
+
+siteXmlNonNative() {
+ siteNonNative
+ cat <<END > "$TEMP_PKG_DIR"/$REPOPATH/index.html
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+<Key>/0.0/foo/ooo/foo-0.0.tar.gz</Key> <br/ >
+<Key>/1.0/foo/ooo/foo-1.0.tar.gz</Key> <br />
+<Key>/2.0/foo/ooo/foo-2.0.tar.gz</Key> <br />
+</body>
+<html>
+END
+}
+
+siteWebNonNativeMUT() {
+ siteNonNative foo
+ siteNonNative bar EXTRA
+ siteNonNative baz EXTRA
+ cat <<END > "$TEMP_PKG_DIR"/$REPOPATH/index.html
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+<a href="/0.0/foo/ooo/foo-0.0.tar.gz">Very old</a> <br/ >
+<a href="/1.0/foo/ooo/foo-1.0.tar.gz">A bit OLD</a> <br />
+<a href="/2.0/foo/ooo/foo-2.0.tar.gz">Latest</a> <br />
+<a href="/2.0/foo/ooo/foo-2.0.tar.gz.asc">Latest sig</a> <br />
+<a href="/0.0/bar/ooo/bar-0.0.tar.gz">Very old</a> <br/ >
+<a href="/1.0/bar/ooo/bar-1.0.tar.gz">A bit OLD</a> <br />
+<a href="/2.0/bar/ooo/bar-2.0.tar.gz">Latest</a> <br />
+<a href="/3.0/bar/ooo/bar-3.0.tar.gz">OOPS Latest</a> <br />
+<a href="/3.0/bar/ooo/bar-3.0.tar.gz.asc">Latest sig</a> <br />
+<a href="/0.0/baz/ooo/baz-0.0.tar.gz">Very old</a> <br/ >
+<a href="/1.0/baz/ooo/baz-1.0.tar.gz">A bit OLD</a> <br />
+<a href="/2.0/baz/ooo/baz-2.0.tar.gz">Latest</a> <br />
+<a href="/3.0/baz/ooo/baz-3.0.tar.gz">OOPS Latest</a> <br />
+<a href="/3.0/baz/ooo/baz-3.0.tar.gz.asc">Latest sig</a> <br />
+</body>
+<html>
+END
+}
+
+siteWebNonNativeMUT_filenamemangle() {
+ siteNonNative foo
+ siteNonNative bar EXTRA
+ siteNonNative baz EXTRA
+ cat <<END > "$TEMP_PKG_DIR"/$REPOPATH/index.html
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+<a href="/0.0/foo/ooo/foo-0.0.tar.gz">Very old</a> <br/ >
+<a href="/1.0/foo/ooo/foo-1.0.tar.gz">A bit old</a> <br />
+<a href="/2.0/foo/ooo/foo-2.0.tar.gz">Latest</a> <br />
+<a href="/2.0/foo/ooo/foo-2.0.tar.gz.asc">Latest sig</a> <br />
+<a href="/0.0/bar/ooo/bar-0.0.tar.gz">Very old</a> <br/ >
+<a href="/1.0/bar/ooo/bar-1.0.tar.gz">A bit old</a> <br />
+<a href="/2.0/bar/ooo/bar-2.0.tar.gz">Latest</a> <br />
+<a href="/3.0/bar/ooo/bar-2.0.tar.gz.asc">Latest sig</a> <br />
+<a href="/0.0/baz/ooo/baz-0.0.tar.gz">Very old</a> <br/ >
+<a href="/1.0/baz/ooo/baz-1.0.tar.gz">A bit old</a> <br />
+<a href="/2.0/baz/ooo/baz-2.0.tar.gz">Latest</a> <br />
+<a href="/3.0/baz/ooo/baz-2.0.tar.gz.asc">Latest sig</a> <br />
+</body>
+<html>
+END
+}
+
+siteWebNonNativeGetOnlyHref() {
+ siteNonNative foo
+ cat <<END > "$TEMP_PKG_DIR"/$REPOPATH/index.html
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+<a href="/0.0/foo/ooo/foo-0.0.tar.gz">Very old</a> <br/ >
+<a href="/1.0/bar/ooo/foo-1.0.tar.gz">A bit OLD</a> <br />
+<a href="/2.0/foo/ooo/foo-2.0.tar.gz" data-foobar-href="">Latest</a> <br />
+<aueu href="/2.0/foo/ooo/foo-3.0.tar.gz" data-foobar-href="">Nothing here</a> <br />
+</body>
+<html>
+END
+}
+
+# test a watch files
+
+### VERSION3 ###
+# version locking calls suffer changes due to uupdate calling differences
+
+# test --download-current-version
+testWatch3WebNonNativeDlCurrent() {
+ WATCHVER=3
+ XCOMMAND="$COMMAND --download-current-version"
+ WATCHLINE='@@@url@@@/ (?:.*)/foo-([\.\d]+).tar.gz debian uupdate'
+ helperWatch siteWebNonNative 1.0 1.0
+}
+
+# test --download-version
+testWatch3WebNonNativeDlUversion() {
+ WATCHVER=3
+ XCOMMAND="$COMMAND --download-version 0.0"
+ WATCHLINE='@@@url@@@/ (?:.*)/foo-([\.\d]+).tar.gz debian uupdate'
+ helperWatch siteWebNonNative 1.0 0.0
+}
+
+# test --download-debversion uupdate
+testWatch3WebNonNativeDlDversion() {
+ WATCHVER=3
+ XCOMMAND="$COMMAND --download-debversion 0.0-1"
+ WATCHLINE='@@@url@@@/ (?:.*)/foo-([\.\d]+).tar.gz debian uupdate'
+ helperWatch siteWebNonNative 1.0 0.0
+}
+
+### VERSION 4 ###
+# standard tests
+
+# test native package w/o uupdate, bare HTTP server in normal order
+testWatch4Native() {
+ WATCHVER=4
+ WATCHLINE='@@@url@@@/([\.\d]+)/(.+)/(.+)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian'
+ helperWatch siteNative
+}
+
+# test non-native package with uupdate, bare HTTP server in normal order
+testWatch4NonNative() {
+ WATCHVER=4
+ WATCHLINE='@@@url@@@([\.\d]+)/(.+)/(.+)/ @PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch siteNonNative
+}
+
+# test non-native package with uupdate, bare HTTP server with dirversionmangle
+testWatch4NonNativeDMangle() {
+ WATCHVER=4
+ WATCHLINE='opts="dirversionmangle=s/^\d*[13579]\./0~$&/, uversionmangle=s/^\d*[13579]\./0~$&/" @@@url@@@([\.\d]+)/(.+)/(.+)/ @PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch "siteNonNative foo EXTRA"
+}
+
+# ... and without dirversionmangle, should return version 3
+testWatch4NonNativeDMangleWithoutD() {
+ WATCHVER=4
+ WATCHLINE='@@@url@@@([\.\d]+)/(.+)/(.+)/ @PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch "siteNonNative foo EXTRA" 1.0 3.0
+}
+
+# test non-native package with uupdate, bare HTTP server with dirversionmangle and base
+testWatch4NonNativeDMangleB() {
+ WATCHVER=4
+ WATCHLINE='opts="dirversionmangle=s/^\d*[13579]\./0~$&/, uversionmangle=s/^\d*[13579]\./0~$&/" @@@url@@@([\.\d]+)/ @PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch "siteWebNonNativeRecWithBase foo EXTRA"
+}
+
+# ... and without dirversionmangle, should return version 3
+testWatch4NonNativeDMangleBWithoutD() {
+ WATCHVER=4
+ WATCHLINE='@@@url@@@([\.\d]+)/ @PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch "siteWebNonNativeRecWithBase foo EXTRA" 1.0 3.0
+}
+
+# test 3 parameter watch line
+testWatch4WebNative() {
+ WATCHVER=4
+ WATCHLINE='@@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian'
+ helperWatch siteWebNative
+}
+
+# test normal web page
+testWatch4WebNonNative() {
+ WATCHVER=4
+ helperWatch
+}
+
+# test normal web page (Files-exclude)
+testWatch4WebNonNativeFE() {
+ MGZREPACK=xz
+ FILEEXCLUDE=1
+ WATCHVER=4
+ helperWatch
+}
+
+# test normal web page (file path reverse order)
+testWatch4WebNonNativeR() {
+ WATCHVER=4
+ helperWatch siteWebNonNativeR
+}
+
+# test for downloadurlmangle and filenamemangle for tricky web page
+testWatch4PrWebNonNative() {
+ WATCHVER=4
+ WATCHLINE='opts="downloadurlmangle = s%boo/xxx%@PACKAGE@/ooo% ; s%boo-%@PACKAGE@-%, \
+ filenamemangle = s%.*boo-(.*)%@PACKAGE@-$1% " \
+ @@@url@@@/ (?:.*)/boo@ANY_VERSION@@ARCHIVE_EXT@ \
+ debian uupdate'
+ helperWatch sitePrWebNonNative
+}
+
+# test --download-current-version
+testWatch4NonNativeDlCurrent() {
+ WATCHVER=4
+ XCOMMAND="$COMMAND --download-current-version"
+ WATCHLINE='@@@url@@@/([\d\.]+)/@PACKAGE@/ooo/ @PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch siteNonNative 1.0 1.0
+}
+
+# test --download-version
+testWatch4NonNativeDlUversion() {
+ WATCHVER=4
+ XCOMMAND="$COMMAND --download-version 0.0"
+ WATCHLINE='@@@url@@@/([\d\.]+)/@PACKAGE@/ooo/ @PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch siteNonNative 1.0 0.0
+}
+
+# test --download-debversion uupdate
+testWatch4NonNativeDlDversion() {
+ WATCHVER=4
+ XCOMMAND="$COMMAND --download-debversion 0.0-1"
+ WATCHLINE='@@@url@@@/([\d\.]+)/@PACKAGE@/ooo/ @PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch siteNonNative 1.0 0.0
+}
+
+# test --download-current-version
+testWatch4WebNonNativeDlCurrent() {
+ WATCHVER=4
+ XCOMMAND="$COMMAND --download-current-version"
+ WATCHLINE='@@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch siteWebNonNative 1.0 1.0
+}
+
+# test --download-version
+testWatch4WebNonNativeDlUversion() {
+ WATCHVER=4
+ XCOMMAND="$COMMAND --download-version 0.0"
+ WATCHLINE='@@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch siteWebNonNative 1.0 0.0
+}
+
+# test --download-debversion uupdate
+testWatch4WebNonNativeDlDversion() {
+ WATCHVER=4
+ XCOMMAND="$COMMAND --download-debversion 0.0-1"
+ WATCHLINE='@@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch siteWebNonNative 1.0 0.0
+}
+
+# Debian version is 0.19990101 for future proof while upstream is 19990101
+testWatch4WebNonNativeLarge() {
+ WATCHVER=4
+ WATCHLINE='opts=" dversionmangle = s/0\.(.*)/$1/ , \
+ oversionmangle = s/(.*)/0.$1/" \
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch siteWebNonNativeLarge 20000101 20010101 0.
+}
+
+# test for pagemangle
+testWatch4XmlNonNative() {
+ WATCHVER=4
+ WATCHLINE='opts="pagemangle = \
+ s%<Key>([^<]*)</Key>%<Key><a href=\"$1\">$1</a></Key>%g" \
+ @@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch siteXmlNonNative
+}
+
+# test user-agent string setting via opts=
+testWatch4WebNonNativeUA() {
+ WATCHVER=4
+ KEYMODE=BIN
+ USERAGENT="foo/bar; baz:12,3.45"
+ WATCHLINE='opts="useragent= '$USERAGENT' "'" \
+"'@@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatchUA
+ unset USERAGENT
+}
+
+# test repack and compression
+testWatch4WebNonNativeBZ2() {
+ WATCHVER=4
+ WATCHLINE='opts=repack,compression=bz2 @@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ MGZREPACK=bz2
+ helperWatch
+}
+
+# test repack and compression
+testWatch4WebNonNativeXZ() {
+ MGZREPACK=xz
+ WATCHVER=4
+ WATCHLINE='opts=repack,compression=xz @@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch
+}
+
+# test spaces everywhere
+testWatch4PrWebNonNativeXZ() {
+ MGZREPACK=xz
+ WATCHVER=4
+ WATCHLINE='opts = "downloadurlmangle = s%boo/xxx%@PACKAGE@/ooo% ; s%boo-%@PACKAGE@-%, \
+ filenamemangle = s%.*boo-(.*)%@PACKAGE@-$1% , \
+ repack , compression=xz" \
+ @@@url@@@/ (?:.*)/boo@ANY_VERSION@@ARCHIVE_EXT@ \
+ debian uupdate'
+ helperWatch sitePrWebNonNative
+}
+
+# test get strictly href from links and not something like foo-href. See #904578 and MR !25
+testWatchGetOnlyHref() {
+ WATCHVER=4
+ WATCHLINE='@@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch siteWebNonNativeGetOnlyHref 1.0 2.0
+}
+
+### VERSION 4 with sig check ###
+
+# test normal web page with sig(asc)
+testWatch4WebNonNativeSig() {
+ WATCHVER=4
+ WATCHLINE='opts = "pgpsigurlmangle = s%(.*)%$1.asc%" \
+ @@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch
+}
+
+# test normal web page with sig(asc) with < and >
+testWatch4WebNonNativeSigAngleBraket() {
+ WATCHVER=4
+ WATCHLINE='opts = "pgpsigurlmangle = s<(.*)><$1.asc>" \
+ @@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch
+}
+
+# test normal web page with sig(asc) with < and > with space
+testWatch4WebNonNativeSigAngleBraketSpace() {
+ WATCHVER=4
+ WATCHLINE='opts = "pgpsigurlmangle = s<(.*)> <$1.asc>" \
+ @@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch
+}
+
+# test normal web page with sig(asc) with < and > with tab
+testWatch4WebNonNativeSigAngleBraketTab() {
+ WATCHVER=4
+ WATCHLINE='opts = "pgpsigurlmangle = s<(.*)> <$1.asc>" \
+ @@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch
+}
+
+# test normal web page with sig(asc) with [ and ]
+testWatch4WebNonNativeSigSquareBraket() {
+ WATCHVER=4
+ WATCHLINE='opts = "pgpsigurlmangle = s[(.*)][$1.asc]" \
+ @@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch
+}
+
+# test normal web page with sig(asc) with { and }
+testWatch4WebNonNativeSigCurlyBraket() {
+ WATCHVER=4
+ WATCHLINE='opts = "pgpsigurlmangle = s{(.*)}{$1.asc}" \
+ @@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch
+}
+
+# test normal web page with sig(asc) - auto
+testWatch4WebNonNativeSigAuto() {
+ WATCHVER=4
+ WATCHLINE='opts = "pgpmode = auto" \
+ @@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate'
+ helperWatch
+}
+
+# test normal web page with sig(bin) (Files-exclude)
+testWatch4WebNonNativeFESig() {
+ MGZREPACK=xz
+ FILEEXCLUDE=1
+ WATCHVER=4
+ SIGMODE=BIN
+ KEYMODE=BIN
+ WATCHLINE='opts = "pgpsigurlmangle = s%(.*)%$1.sig%" \
+ @@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ \
+ debian uupdate'
+ helperWatch
+}
+
+# test normal web page with sig (different file path for sig and tar; reverse order)
+testWatch4WebNonNativeRSig() {
+ WATCHVER=4
+ WATCHLINE='opts = "pgpmode=next" @@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts = "pgpmode=previous" @@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@.asc previous uupdate'
+ helperWatch siteWebNonNativeR
+}
+
+# test normal web page with sig (different file path for sig and tar; reverse order, BIN)
+testWatch4WebNonNativeRSigBIN() {
+ WATCHVER=4
+ SIGMODE=BIN
+ WATCHLINE='opts = "pgpmode=next" @@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts = "pgpmode=previous" @@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@.sig previous uupdate'
+ helperWatch siteWebNonNativeR
+}
+
+# test normal web page with sig (different file path for sig and tar; reverse order, BIN BIN)
+testWatch4WebNonNativeRSigBINiBIN() {
+ WATCHVER=4
+ SIGMODE=BIN
+ KEYMODE=BIN
+ WATCHLINE='opts = "pgpmode=next" @@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts = "pgpmode=previous" @@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@.sig previous uupdate'
+ helperWatch siteWebNonNativeR
+}
+
+# test normal web page with sig (self)
+testWatch4WebNonNativeSelfSig() {
+ WATCHVER=4
+ SIGMODE=SELF
+ WATCHLINE='opts = "pgpmode = self" \
+ @@@url@@@/ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@.gpg debian uupdate'
+ helperWatch siteWebNonNativeR
+}
+
+### VERSION 4 only ###
+
+# filenamemangle supports two patterns, each causing different behaviour.
+# * The first pattern replaces the existing URL with the new filename.
+# * The second pattern modifies the filename component, creating a new (and invalid) URL.
+
+# test normal web page (filenamemangle on main upstream tarball [pattern 1])
+testWatch4WebNonNative_filenamemangle1a() {
+ WATCHVER=4
+ FILENAMEMANGLE=foo
+ WATCHLINE='
+opts="filenamemangle=s#.+/(@PACKAGE@-\d\S+)(@ARCHIVE_EXT@)#$1-filenamemangle$2#" \
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian'
+ helperWatch siteWebNonNative
+}
+
+# test normal web page (signature and filenamemangle on main upstream tarball [pattern 1])
+testWatch4WebNonNative_filenamemangle1b() {
+ WATCHVER=4
+ FILENAMEMANGLE=foo
+ WATCHLINE='
+opts="filenamemangle=s#.+/(@PACKAGE@-\d\S+)(@ARCHIVE_EXT@)#$1-filenamemangle$2#, \
+ pgpsigurlmangle=s/$/.asc/" \
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian'
+ helperWatch siteWebNonNative
+}
+
+# test normal web page (filenamemangle on main upstream tarball [pattern 2])
+testWatch4WebNonNative_filenamemangle1c() {
+ WATCHVER=4
+ FILENAMEMANGLE=foo
+ WATCHLINE='
+opts="filenamemangle=s/(\d\S+)(@ARCHIVE_EXT@)/$1-filenamemangle$2/" \
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian'
+ helperWatch siteWebNonNative
+}
+
+# test normal web page (signature and filenamemangle on main upstream tarball [pattern 2])
+testWatch4WebNonNative_filenamemangle1d() {
+ WATCHVER=4
+ FILENAMEMANGLE=foo
+ WATCHLINE='
+opts="filenamemangle=s/(\d\S+)(@ARCHIVE_EXT@)/$1-filenamemangle$2/, \
+ pgpsigurlmangle=s/$/.asc/" \
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian'
+ helperWatch siteWebNonNative
+}
+
+# test normal web page (MUT)
+testWatch4WebNonNativeMUT() {
+ MGZREPACK=xz
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ SIGMODE=BIN
+ FILEEXCLUDE=2
+ WATCHLINE='
+opts=" pgpsigurlmangle=s/$/.sig/" @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar,pgpsigurlmangle=s/$/.sig/" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz,pgpsigurlmangle=s/$/.sig/" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same uupdate'
+ helperWatch siteWebNonNativeMUT
+}
+
+# test normal web page (MUT, filenamemangle on main upstream tarball [pattern 1])
+testWatch4WebNonNativeMUT_filenamemangle1a() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE=foo
+ WATCHLINE='
+opts="filenamemangle=s#.+/(@PACKAGE@-\d\S+)(@ARCHIVE_EXT@)#$1-filenamemangle$2#" \
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, signature and filenamemangle on main upstream tarball [pattern 1])
+testWatch4WebNonNativeMUT_filenamemangle1b() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE=foo
+ WATCHLINE='
+opts="filenamemangle=s#.+/(@PACKAGE@-\d\S+)(@ARCHIVE_EXT@)#$1-filenamemangle$2#, \
+ pgpsigurlmangle=s/$/.asc/" \
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, filenamemangle on main upstream tarball [pattern 2])
+testWatch4WebNonNativeMUT_filenamemangle1c() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE=foo
+ WATCHLINE='
+opts="filenamemangle=s/(@PACKAGE@-\d\S+)(@ARCHIVE_EXT@)/$1-filenamemangle$2/" \
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, signature and filenamemangle on main upstream tarball [pattern 2])
+testWatch4WebNonNativeMUT_filenamemangle1d() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE=foo
+ WATCHLINE='
+opts="filenamemangle=s/(@PACKAGE@-\d\S+)(@ARCHIVE_EXT@)/$1-filenamemangle$2/, \
+ pgpsigurlmangle=s/$/.asc/" \
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, filenamemangle on first component tarball [pattern 1])
+testWatch4WebNonNativeMUT_filenamemangle2a() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE=bar
+ WATCHLINE='
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar, filenamemangle=s#.+/(bar-)#@PACKAGE@-$1#" \
+ @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, signature and filenamemangle on first component tarball [pattern 1])
+testWatch4WebNonNativeMUT_filenamemangle2b() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE=bar
+ WATCHLINE='
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar, filenamemangle=s#.+/(bar-)#@PACKAGE@-$1#, pgpsigurlmangle=s/$/.asc/" \
+ @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, filenamemangle on first component tarball [pattern 2])
+testWatch4WebNonNativeMUT_filenamemangle2c() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE=bar
+ WATCHLINE='
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar, filenamemangle=s/(bar-)/@PACKAGE@-$1/" \
+ @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, signature and filenamemangle on first component tarball [pattern 2])
+testWatch4WebNonNativeMUT_filenamemangle2d() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE=bar
+ WATCHLINE='
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar, filenamemangle=s/(bar-)/@PACKAGE@-$1/, pgpsigurlmangle=s/$/.asc/" \
+ @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, filenamemangle on second component tarball [pattern 1])
+testWatch4WebNonNativeMUT_filenamemangle3a() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE=baz
+ WATCHLINE='
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz, filenamemangle=s#.+/(baz-)#@PACKAGE@-$1#" \
+ @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, signature and filenamemangle on second component tarball [pattern 1])
+testWatch4WebNonNativeMUT_filenamemangle3b() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE=baz
+ WATCHLINE='
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz, filenamemangle=s#.+/(baz-)#@PACKAGE@-$1#, pgpsigurlmangle=s/$/.asc/" \
+ @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, filenamemangle on second component tarball [pattern 2])
+testWatch4WebNonNativeMUT_filenamemangle3c() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE=baz
+ WATCHLINE='
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz, filenamemangle=s/(baz-)/@PACKAGE@-$1/" \
+ @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, signature and filenamemangle on second component tarball [pattern 2])
+testWatch4WebNonNativeMUT_filenamemangle3d() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE=baz
+ WATCHLINE='
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz, filenamemangle=s/(baz-)/@PACKAGE@-$1/, pgpsigurlmangle=s/$/.asc/" \
+ @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, filenamemangle on both component tarballs [pattern 1])
+testWatch4WebNonNativeMUT_filenamemangle4a() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE="$COMPONENTS"
+ WATCHLINE='
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar, filenamemangle=s#.+/(bar-)#@PACKAGE@-$1#" \
+ @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz, filenamemangle=s#.+/(baz-)#@PACKAGE@-$1#" \
+ @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, signatures and filenamemangle on both component tarballs [pattern 1])
+testWatch4WebNonNativeMUT_filenamemangle4b() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE="$COMPONENTS"
+ WATCHLINE='
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar, filenamemangle=s#.+/(bar-)#@PACKAGE@-$1#, pgpsigurlmangle=s/$/.asc/" \
+ @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz, filenamemangle=s#.+/(baz-)#@PACKAGE@-$1#, pgpsigurlmangle=s/$/.asc/" \
+ @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, filenamemangle on both component tarballs [pattern 2])
+testWatch4WebNonNativeMUT_filenamemangle4c() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE="$COMPONENTS"
+ WATCHLINE='
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar, filenamemangle=s/(bar-)/@PACKAGE@-$1/" \
+ @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz, filenamemangle=s/(baz-)/@PACKAGE@-$1/" \
+ @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, signatures and filenamemangle on both component tarballs [pattern 2])
+testWatch4WebNonNativeMUT_filenamemangle4d() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE="$COMPONENTS"
+ WATCHLINE='
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar, filenamemangle=s/(bar-)/@PACKAGE@-$1/, pgpsigurlmangle=s/$/.asc/" \
+ @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz, filenamemangle=s/(baz-)/@PACKAGE@-$1/, pgpsigurlmangle=s/$/.asc/" \
+ @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, filenamemangle on all upstream tarballs [pattern 1])
+testWatch4WebNonNativeMUT_filenamemangle5a() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE="foo $COMPONENTS"
+ WATCHLINE='
+opts="filenamemangle=s#.+/(@PACKAGE@-\d\S+)(@ARCHIVE_EXT@)#$1-filenamemangle$2#" \
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar, filenamemangle=s#.+/(bar-)#@PACKAGE@-$1#" \
+ @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz, filenamemangle=s#.+/(baz-)#@PACKAGE@-$1#" \
+ @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, signatures and filenamemangle on all upstream tarballs [pattern 1])
+testWatch4WebNonNativeMUT_filenamemangle5b() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE="foo $COMPONENTS"
+ WATCHLINE='
+opts="filenamemangle=s#.+/(@PACKAGE@-\d\S+)(@ARCHIVE_EXT@)#$1-filenamemangle$2#, \
+ pgpsigurlmangle=s/$/.asc/" \
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar, filenamemangle=s#.+/(bar-)#@PACKAGE@-$1#, pgpsigurlmangle=s/$/.asc/" \
+ @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz, filenamemangle=s#.+/(baz-)#@PACKAGE@-$1#, pgpsigurlmangle=s/$/.asc/" \
+ @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, filenamemangle on all upstream tarballs [pattern 2])
+testWatch4WebNonNativeMUT_filenamemangle5c() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE="foo $COMPONENTS"
+ WATCHLINE='
+opts="filenamemangle=s/(@PACKAGE@-\d\S+)(@ARCHIVE_EXT@)/$1-filenamemangle$2/" \
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar, filenamemangle=s/(bar-)/@PACKAGE@-$1/" \
+ @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz, filenamemangle=s/(baz-)/@PACKAGE@-$1/" \
+ @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT, signatures and filenamemangle on all upstream tarballs [pattern 2])
+testWatch4WebNonNativeMUT_filenamemangle5d() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILENAMEMANGLE="foo $COMPONENTS"
+ WATCHLINE='
+opts="filenamemangle=s/(@PACKAGE@-\d\S+)(@ARCHIVE_EXT@)/$1-filenamemangle$2/, \
+ pgpsigurlmangle=s/$/.asc/" \
+ @@@url@@@ (?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar, filenamemangle=s/(bar-)/@PACKAGE@-$1/, pgpsigurlmangle=s/$/.asc/" \
+ @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz, filenamemangle=s/(baz-)/@PACKAGE@-$1/, pgpsigurlmangle=s/$/.asc/" \
+ @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same'
+ helperWatch siteWebNonNativeMUT_filenamemangle
+}
+
+# test normal web page (MUT with O main)
+testWatch4WebNonNativeMUT0() {
+ WATCHVER=4
+ COMPONENTS="foo bar baz"
+ FILEEXCLUDE=3
+ MGZREPACK=xz
+ WATCHLINE='
+opts="component=foo,pgpsigurlmangle=s/$/.asc/" @@@url@@@ (?:.*)/foo@ANY_VERSION@@ARCHIVE_EXT@ debian
+opts="component=bar,pgpsigurlmangle=s/$/.asc/" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ same
+opts="component=baz,pgpsigurlmangle=s/$/.asc/" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ same uupdate'
+ helperWatch siteWebNonNativeMUT
+}
+
+# Group test without signatures
+testWatch4WebNonNativeGroup() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILEEXCLUDE=3
+ UVERSION=2.0
+ CMPVERSION=3.0
+ WATCHLINE='
+opts="pgpmode=none" @@@url@@@ (?:.*)/foo@ANY_VERSION@@ARCHIVE_EXT@ group
+opts="component=bar,pgpmode=none" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ group
+opts="component=baz,pgpmode=none" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ group'
+ helperWatch siteWebNonNativeMUT 1.0 2.0+~3.0+~3.0
+}
+
+# Group test with repack suffix
+testWatch4WebNonNativeGroupRepackSuffix() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILEEXCLUDE=3
+ UVERSION=2.0
+ CMPVERSION=3.0
+ WATCHLINE='
+opts="pgpmode=none" @@@url@@@ (?:.*)/foo@ANY_VERSION@@ARCHIVE_EXT@ group
+opts="component=bar,repacksuffix=+ds,pgpmode=none" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ group
+opts="component=baz,pgpmode=none" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ group'
+ helperWatch siteWebNonNativeMUT 1.0 2.0+~3.0+ds+~3.0
+}
+
+testWatch4WebNonNativeGroupRepackSuffix2() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILEEXCLUDE=3
+ UVERSION=2.0
+ CMPVERSION=3.0
+ WATCHLINE='
+opts="dversionmangle=auto,pgpmode=none" @@@url@@@ (?:.*)/foo@ANY_VERSION@@ARCHIVE_EXT@ group
+opts="dversionmangle=auto,component=bar,repacksuffix=~ds,pgpmode=none" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ group
+opts="dversionmangle=auto,component=baz,pgpmode=none" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ group'
+ helperWatch siteWebNonNativeMUT 1.0 2.0+~3.0~ds+~3.0
+}
+
+# Group test with pgpsigurlmangle
+testWatch4WebNonNativeGroupSigned() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILEEXCLUDE=3
+ UVERSION=2.0
+ CMPVERSION=3.0
+ WATCHLINE='
+opts="pgpsigurlmangle=s/$/.asc/" @@@url@@@ (?:.*)/foo@ANY_VERSION@@ARCHIVE_EXT@ group
+opts="component=bar,pgpsigurlmangle=s/$/.asc/" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ group
+opts="component=baz,pgpsigurlmangle=s/$/.asc/" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ group'
+ helperWatch siteWebNonNativeMUT 1.0 2.0+~3.0+~3.0
+}
+
+# Group test with pgpmode next/previous
+testWatch4WebNonNativeGroupSignedNext() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILEEXCLUDE=3
+ UVERSION=2.0
+ CMPVERSION=3.0
+ SIGMODE=ASC
+ WATCHLINE='
+opts="pgpmode=next" @@@url@@@ (?:.*)/foo@ANY_VERSION@@ARCHIVE_EXT@ group
+opts="pgpmode=previous" @@@url@@@/ (?:.*)/foo@ANY_VERSION@@ARCHIVE_EXT@.asc previous
+opts="component=bar,pgpmode=next" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ group
+opts="component=bar,pgpmode=previous" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@.asc previous
+opts="component=baz,pgpmode=next" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ group
+opts="component=baz,pgpmode=previous" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@.asc previous'
+ helperWatch siteWebNonNativeMUT 1.0 2.0+~3.0+~3.0
+}
+
+testWatch4WebNonNativeGroupWithCompression() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILEEXCLUDE=3
+ UVERSION=2.0
+ CMPVERSION=3.0
+ WATCHLINE='
+opts="pgpmode=none" @@@url@@@ (?:.*)/foo@ANY_VERSION@@ARCHIVE_EXT@ group
+opts="component=bar,compression=xz,repack,pgpmode=none" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ group
+opts="component=baz,repack,pgpmode=none" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ group'
+ helperWatch siteWebNonNativeMUT 1.0 2.0+~3.0+~3.0
+}
+
+testWatch4WebNonNativeGroupWithChecksum1() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILEEXCLUDE=3
+ UVERSION=2.0
+ CMPVERSION=3.0
+ WATCHLINE='
+opts="pgpmode=none" @@@url@@@ (?:.*)/foo@ANY_VERSION@@ARCHIVE_EXT@ group
+opts="component=bar,compression=xz,repack,pgpmode=none" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ group
+opts="component=baz,repack,pgpmode=none" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ checksum'
+ helperWatch siteWebNonNativeMUT 1.0 2.0+~3.0+~cs3.0
+}
+
+testWatch4WebNonNativeGroupWithChecksum2() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILEEXCLUDE=3
+ UVERSION=2.0
+ CMPVERSION=3.0
+ WATCHLINE='
+opts="pgpmode=none" @@@url@@@ (?:.*)/foo@ANY_VERSION@@ARCHIVE_EXT@ group
+opts="component=bar,compression=xz,repack,pgpmode=none" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ checksum
+opts="component=baz,repack,pgpmode=none" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ checksum'
+ helperWatch siteWebNonNativeMUT 1.0 2.0+~cs6.0
+}
+
+testWatch4WebNonNativeGroupWithChecksumAndIgnore() {
+ WATCHVER=4
+ COMPONENTS="bar baz"
+ FILEEXCLUDE=3
+ UVERSION=2.0
+ CMPVERSION=3.0
+ WATCHLINE='
+opts="pgpmode=none" @@@url@@@ (?:.*)/foo@ANY_VERSION@@ARCHIVE_EXT@ group
+opts="component=bar,compression=xz,repack,pgpmode=none" @@@url@@@ (?:.*)/bar@ANY_VERSION@@ARCHIVE_EXT@ checksum
+opts="component=baz,repack,pgpmode=none" @@@url@@@ (?:.*)/baz@ANY_VERSION@@ARCHIVE_EXT@ ignore'
+ helperWatch siteWebNonNativeMUT 1.0 2.0+~cs3.0
+}
+
+. shunit2
diff --git a/test/test_uscan_online b/test/test_uscan_online
new file mode 100755
index 0000000..47ecda2
--- /dev/null
+++ b/test/test_uscan_online
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+# Copyright (C) 2012, Benjamin Drung <bdrung@debian.org>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+set -u
+
+# Operation mode
+if test "${1:-}" = --installed; then
+ COMMAND="uscan --no-conf"
+ shift
+else
+ top_srcdir=$(readlink -f "${0%/*}/..")
+ make -C "$top_srcdir/scripts" uscan mk-origtargz uupdate debchange
+ PATH="$top_srcdir/scripts:$PATH"
+ export PATH
+ PERL5LIB="$top_srcdir/lib"
+ export PERL5LIB
+ COMMAND="uscan --no-conf"
+fi
+
+. "${0%/*}/shunit2-helper-functions.sh"
+
+found() {
+ runCommand "--report --watchfile ${0%/*}/uscan/$1 --package $2 --upstream-version $3" "$4" "" 0
+}
+
+testS3Bucket() {
+ local latest=$(curl -s http://s3.amazonaws.com/rds-downloads | \
+ sed 's@\(</[A-Za-z]*>\)@\1\n@g' | grep '<Key>RDSCli-' | \
+ sed 's@.*<Key>RDSCli-\([-0-9.]*\)\.zip</Key>.*@\1@g' | \
+ sort -n | tail -n 1)
+ local result="uscan: Newest version of rdscli on remote site is ${latest}, local version is 1.4.007
+uscan: => Newer package available from:
+ => http://s3.amazonaws.com/rds-downloads/RDSCli-${latest}.zip"
+ found "s3bucket" "rdscli" "1.4.007" "$result"
+}
+
+. shunit2
diff --git a/test/test_uscan_svn b/test/test_uscan_svn
new file mode 100755
index 0000000..fdc3c2d
--- /dev/null
+++ b/test/test_uscan_svn
@@ -0,0 +1,201 @@
+#!/bin/bash
+
+# Copyright (C) 2018, Xavier <yadd@debian.org>
+# 2019-2020, Andrius Merkys <merkys@debian.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at your
+# option) any later version.
+#
+# 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.
+#
+# On Debian systems, the complete text of the GNU General Public License
+# version 3 can be found in the /usr/share/common-licenses/GPL-3 file.
+
+set -u
+#set -x
+
+DEB_HOST_OS="$(dpkg-architecture -qDEB_HOST_ARCH_OS)"
+if [ "$DEB_HOST_OS" = "kfreebsd" ]; then
+ # kbsd has a non-working semaphore, that is needed here.
+ echo "This test is not supported on $(dpkg-architecture -qDEB_HOST_ARCH), skipping"
+ exit 0
+fi
+DEB_HOST_ARCH="$(dpkg-architecture -qDEB_HOST_ARCH)"
+if [ "$DEB_HOST_ARCH" = "i386" ]; then
+ echo "To \"help\" Ubuntu that has a fondamentally broken i386 (so that we can't depend on svn), this test is simply skipped on i386."
+ exit 0
+fi
+
+TESTTYPE=Svn
+. ./lib_test_uscan
+
+COMMAND="chronic_sh uscan --no-conf --compression=xz --dehs"
+
+# prevent the local from messing with this test
+export HOME=""
+export XDG_CONFIG_HOME=""
+
+# comment out for debug
+#COMMAND="$COMMAND --verbose"
+#COMMAND="$COMMAND --debug"
+
+cleanup(){
+ rm -rf "$TEMP_PKG_DIR"
+}
+
+spawnSvnRepo(){
+ mkdir -p "$TEMP_PKG_DIR/repo"
+ (cd "$TEMP_PKG_DIR/repo" || exit 1
+ chronic_sh svnadmin create .)
+ mkdir -p "$TEMP_PKG_DIR/working-copy"
+ (cd "$TEMP_PKG_DIR/working-copy" || exit 1
+ chronic_sh svn checkout "file:///$TEMP_PKG_DIR/repo" .
+ chronic_sh mkdir trunk tags
+ touch trunk/changelog trunk/file.c
+ chronic_sh svn add trunk tags
+ chronic_sh svn commit -m 'Init'
+ export TZ=UTC
+ for version in 1.0 2.0; do
+ echo "# Version $version" >> trunk/file.c
+ cat >> trunk/changelog <<END
+Version $version
+
+END
+ chronic_sh faketime -f '2000-01-01 12:34:56' svn commit -m "Releasing $version"
+ chronic_sh faketime -f '2000-01-01 12:34:56' svn copy ^/trunk "^/tags/v$version" -m "Version $version"
+ done)
+}
+
+trap cleanup EXIT
+
+containsName(){
+ echo "$1" | grep -F -q "$2"
+ echo $?
+}
+
+# shellcheck source=shunit2-helper-functions.sh
+. "${0%/*}/shunit2-helper-functions.sh"
+
+PKG=foo
+
+makeDebianDir() {
+ WATCHARGS=$1
+ TEMP_PKG_DIR=$(mktemp -d --tmpdir="$SHUNIT_TMPDIR" uscan_svn.XXXXXX)
+ if [ -z "$TEMP_PKG_DIR" ]; then
+ echo "Failed to create temporary directory" >&2
+ exit 1
+ fi
+ mkdir -p "$TEMP_PKG_DIR/$PKG/debian/source"
+ spawnSvnRepo
+
+ cat <<END > "$TEMP_PKG_DIR/$PKG/debian/watch"
+version=4
+opts="mode=svn,$WATCHARGS" \
+file:///$TEMP_PKG_DIR/repo/tags v([\\d\\.]+)\/ debian
+END
+
+ cat <<END > "$TEMP_PKG_DIR/$PKG/debian/changelog"
+$PKG (0-1) unstable; urgency=low
+
+ * Initial release
+
+ -- Joe Developer <jd@debian.org> Mon, 02 Nov 2013 22:21:31 -0100
+END
+ echo '3.0 (quilt)' > "$TEMP_PKG_DIR/$PKG/debian/source/format"
+}
+
+makeDebianDirHead() {
+ WATCHARGS=$1
+ makeDebianDir "$WATCHARGS"
+ cat <<END > "$TEMP_PKG_DIR/$PKG/debian/watch"
+version=4
+opts="mode=svn,$WATCHARGS" \
+file:///$TEMP_PKG_DIR/repo/trunk HEAD
+END
+}
+
+helperLaunch() {
+ WATCHARGS=$1
+ ARG="${2:-}"
+ if test "$ARG" = "HEAD"; then
+ makeDebianDirHead "$WATCHARGS"
+ else
+ makeDebianDir "$WATCHARGS"
+ fi
+ ( cd "$TEMP_PKG_DIR/$PKG" || exit 1 ; $COMMAND --watchfile=debian/watch )
+ assertEquals "uscan: exit_code!=0 but exit_code=0" "0" "$?"
+}
+
+helperLaunchFail() {
+ WATCHARGS=$1
+ ARG="${2:-}"
+ if test "$ARG" = "HEAD"; then
+ makeDebianDirHead "$WATCHARGS"
+ else
+ makeDebianDir "$WATCHARGS"
+ fi
+ # discard output as it's expected to fail
+ ( cd "$TEMP_PKG_DIR/$PKG" || exit 1 ; $COMMAND --watchfile=debian/watch > /dev/null)
+ assertEquals "uscan: exit_code!=2 but exit_code=2" "2" "$?"
+}
+
+testSvn() {
+ helperLaunch "pgpmode=none"
+ TARBALL="${PKG}_2.0.orig.tar.xz"
+ CHECKSUM=$(sha1sum "$TEMP_PKG_DIR/${PKG}-2.0.tar.xz" | awk '{print $1}')
+ assertTrue 'downloaded tarfile not present' "[ -f '$TEMP_PKG_DIR/${PKG}-2.0.tar.xz' ]"
+ assertTrue 'pristine tarball is not created' "[ -f '$TEMP_PKG_DIR/$TARBALL' ]"
+ assertTrue 'pristine tarball is a symlink' "[ -L '$TEMP_PKG_DIR/$TARBALL' ]"
+ if [ "$CHECKSUM" != 'bd4a60786013848e402bcf20db211fd465afeda5' ]; then
+ set -x
+ echo "Copying the faulty tarball to the artefact directory, if available..."
+ if [ -n "${AUTOPKGTEST_ARTIFACTS:-}" ] && [ -d "$AUTOPKGTEST_ARTIFACTS" ]; then
+ cp -v "$TEMP_PKG_DIR/${PKG}-2.0.tar.xz" "$AUTOPKGTEST_ARTIFACTS"/
+ fi
+ set +x
+ fi
+ assertTrue 'checksums do not match' "[ '${CHECKSUM}' = 'bd4a60786013848e402bcf20db211fd465afeda5' ]"
+ cleanup
+}
+
+testSvnPgpmodeDefault() {
+ helperLaunch "pgpmode=default"
+ TARBALL="${PKG}_2.0.orig.tar.xz"
+ assertTrue 'downloaded tarfile not present' "[ -f '$TEMP_PKG_DIR/${PKG}-2.0.tar.xz' ]"
+ assertTrue 'pristine tarball is not created' "[ -f '$TEMP_PKG_DIR/$TARBALL' ]"
+ assertTrue 'pristine tarball is a symlink' "[ -L '$TEMP_PKG_DIR/$TARBALL' ]"
+ cleanup
+}
+
+testSvnPgpmodeNext() {
+ helperLaunchFail "pgpmode=next"
+ cleanup
+}
+
+testSvnHead() {
+ helperLaunch "pgpmode=none" HEAD
+ ORIG="$TEMP_PKG_DIR/foo_0.0~svn4.orig.tar.xz"
+ UPSTREAM="$TEMP_PKG_DIR/foo-0.0~svn4.tar.xz"
+ assertTrue 'downloaded tarfile not present' "[ -f '$UPSTREAM' ]"
+ assertTrue 'pristine tarball is not created' "[ -f '$ORIG' ]"
+ assertTrue 'pristine tarball is a symlink' "[ -L '$ORIG' ]"
+ cleanup
+}
+
+testSvnHeadMangle() {
+ helperLaunch "pgpmode=none,uversionmangle=s/^[^~]+/1.23.45/" HEAD
+ ORIG="$TEMP_PKG_DIR/foo_1.23.45~svn4.orig.tar.xz"
+ UPSTREAM="$TEMP_PKG_DIR/foo-1.23.45~svn4.tar.xz"
+ assertTrue 'downloaded tarfile not present' "[ -f '$UPSTREAM' ]"
+ assertTrue 'pristine tarball is not created' "[ -f '$ORIG' ]"
+ assertTrue 'pristine tarball is a symlink' "[ -L '$ORIG' ]"
+ cleanup
+}
+
+# shellcheck disable=SC1091
+. shunit2
diff --git a/test/test_wrap-and-sort b/test/test_wrap-and-sort
new file mode 100755
index 0000000..ac6bdab
--- /dev/null
+++ b/test/test_wrap-and-sort
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+# Copyright (C) 2022, Niels Thykier <niels@thykier.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+set -u
+
+
+WORK_DIR="$(readlink -f "${0%/*}")"
+if test "${1:-}" = --installed; then
+ wrap_and_sort="wrap-and-sort "
+ shift
+else
+ wrap_and_sort="${WORK_DIR}/../scripts/wrap-and-sort"
+fi
+
+. "${WORK_DIR}/test_helper.sh"
+
+oneTimeSetUp() {
+ TEMP_DIR=$(mktemp -d -p "$SHUNIT_TMPDIR" wrap-and-sort.XXXXX)
+}
+
+# Run as `prepare_and_run_wrap_and_sort <test-name> [args-for-wrap-and-sort]`
+prepare_and_run_wrap_and_sort() {
+ TEST_NAME="${1}"
+ TEST_DIR="${TEMP_DIR}/${TEST_NAME}"
+
+ mkdir "${TEST_DIR}"
+ cp -a "${WORK_DIR}/wrap-and-sort/${TEST_NAME}/in/"* "$TEST_DIR/" || exit 1
+ assertPasses $wrap_and_sort -d "$TEST_DIR"
+ assertPasses diff -Nuarp "${WORK_DIR}/wrap-and-sort/${TEST_NAME}/out" "${TEST_DIR}"
+}
+
+test_install_comments() {
+ prepare_and_run_wrap_and_sort 'install-comments'
+}
+
+. shunit2