#!/usr/bin/perl

# Copyright (c) 2011 Joe Leslie-Hurd, distributed under the MIT license

use strict;
use warnings;
use Pod::Usage;
use Getopt::Std;
use Cwd 'realpath';

use vars qw($opt_h $opt_d);

###############################################################################
# Process options.
###############################################################################

getopts('hd:');

if ($opt_h or scalar @ARGV != 0)
{
    pod2usage({-exitval => 2,
	       -verbose => 2});
}

# Autoflush STDIN
$|++;

my $program = "tool-test";

my $opentheory = "opentheory";
if ($opt_d) { $opentheory = "$opt_d/$opentheory"; }
[ -x $opentheory ] or die "$program: $opentheory not an executable";

my $repo_dir = "repos";
[ -d $repo_dir ] or die "$program: $repo_dir not a directory";

my $repo = "$repo_dir/repo";
my $opentheory_repo = "$opentheory -d $repo";

my $upstream = "$repo_dir/upstream";
my $upstream_realpath = realpath($upstream);
my $opentheory_upstream = "$opentheory -d $upstream/opentheory";

###############################################################################
# Execute commands.
###############################################################################

sub test_section {
    (scalar @_ == 1) or die;
    my $title = shift @_;

    print STDOUT "==========================================================================\n$title\n";
}

sub execute_command {
    (scalar @_ == 1) or die;
    my $cmd = shift @_;

    my $cmd_text = $cmd;
    if ($cmd_text =~ s%^[[:alnum:]./]*opentheory%opentheory%) {
      print STDOUT "--------------------------------------------------------------------------\n$cmd_text\n\n";
    }

    return system("$cmd 2>&1");
}

sub test_passing {
    (scalar @_ == 1) or die;
    my $cmd = shift @_;

    my $result = execute_command($cmd);

    if ($result != 0) {
        die "$program: this command should have succeeded, but returned error code $result."
    }
}

###############################################################################
# Execute test cases.
###############################################################################

test_section "Check the opentheory tool is alive";
test_passing "$opentheory --help";

test_section "Initialize upstream";
test_passing "rm -rf $upstream";
test_passing "mkdir $upstream";
test_passing "$opentheory_upstream init --remote";
test_passing "tail -n +6 < $upstream/opentheory/config > $upstream/opentheory/config.new";
test_passing "mv $upstream/opentheory/config.new $upstream/opentheory/config";
test_passing "$opentheory_upstream install theories/bool-true-def/bool-true-def.thy";
test_passing "$opentheory_upstream install theories/bool-true-thm/bool-true-thm.thy";
test_passing "$opentheory_upstream install theories/bool-true/bool-true.thy";
test_passing "$opentheory_upstream install theories/bool-forall-def/bool-forall-def.thy";
test_passing "$opentheory_upstream install theories/bool-forall-thm/bool-forall-thm.thy";
test_passing "$opentheory_upstream install theories/bool-forall/bool-forall.thy";
test_passing "$opentheory_upstream install theories/bool-and-def/bool-and-def.thy";
test_passing "$opentheory_upstream install theories/bool-and-thm/bool-and-thm.thy";
test_passing "$opentheory_upstream install theories/bool-and/bool-and.thy";
test_passing "$opentheory_upstream list";

test_section "Simulate user initializing repo and updating config file";
test_passing "rm -rf $repo";
test_passing "$opentheory_repo init";
test_passing "echo '[author]' > $repo/config.new";
test_passing "echo 'name = Joe Programmer' >> $repo/config.new";
test_passing "echo 'email = joe\@gilith.com' >> $repo/config.new";
test_passing "echo >> $repo/config.new";
test_passing "echo '[repo]' >> $repo/config.new";
test_passing "echo 'name = upstream' >> $repo/config.new";
test_passing "echo 'url = file://$upstream_realpath/' >> $repo/config.new";
test_passing "tail -n +4 < $repo/config >> $repo/config.new";
test_passing "mv $repo/config.new $repo/config";

test_section "Simulate user installing packages";
test_passing "$opentheory_repo list";
test_passing "$opentheory_repo install bool-true";
test_passing "$opentheory_repo install bool-and";
test_passing "$opentheory_repo list";
test_passing "$opentheory_repo list ~UpToDate";
test_passing "$opentheory_repo info --theory bool-and";
test_passing "$opentheory_repo install bool-forall";
test_passing "$opentheory_repo list";
test_passing "$opentheory_repo list ~UpToDate";

test_section "Simulate user developing own theory package";
test_passing "$opentheory_repo list";
test_passing "$opentheory_repo install theories/bool-implies-def/bool-implies-def.thy";
test_passing "$opentheory_repo install theories/bool-implies-thm/bool-implies-thm.thy";
test_passing "$opentheory_repo install theories/bool-implies/bool-implies.thy";
test_passing "$opentheory_repo list";
test_passing "$opentheory_repo list ~UpToDate";
test_passing "$opentheory_repo list Mine";

test_section "Simulate user uploading own theory package";
test_passing "$opentheory_repo list Uploadable";
test_passing "$opentheory_upstream install --stage --manual --name bool-implies-def-1.0 tarball:$repo/packages/bool-implies-def-1.0/bool-implies-def-1.0.tgz";
test_passing "$opentheory_upstream install --stage --manual --name bool-implies-thm-1.0 tarball:$repo/packages/bool-implies-thm-1.0/bool-implies-thm-1.0.tgz";
test_passing "$opentheory_upstream install --stage --manual --name bool-implies-1.0 tarball:$repo/packages/bool-implies-1.0/bool-implies-1.0.tgz";
test_passing "$opentheory_upstream install staged:bool-implies-def-1.0";
test_passing "$opentheory_upstream install staged:bool-implies-thm-1.0";
test_passing "$opentheory_upstream install staged:bool-implies-1.0";
test_passing "$opentheory_repo update";
test_passing "$opentheory_repo list Uploadable";

test_section "Simulate user upgrading theory packages";
test_passing "$opentheory_repo list Upgradable";
test_passing "$opentheory_upstream install theories/bool-and-thm-1.1/bool-and-thm.thy";
test_passing "$opentheory_upstream install theories/bool-and-1.1/bool-and.thy";
test_passing "$opentheory_repo list Upgradable";
test_passing "$opentheory_repo update";
test_passing "$opentheory_repo list Upgradable";
test_passing "$opentheory_repo upgrade";
test_passing "$opentheory_repo list";
test_passing "$opentheory_repo list Upgradable";
test_passing "$opentheory_repo list Obsolete";
test_passing "$opentheory_repo uninstall Obsolete";

test_section "Check the package checksums are consistent";
test_passing "$opentheory_upstream list --format 'NAME-VERSION CHECKSUM' All";
test_passing "$opentheory_repo list --format 'NAME-VERSION CHECKSUM' All";
test_passing "$opentheory_repo info --theory-source --show-checksums bool-implies";

test_section "Simulate user updating own theory package";
test_passing "$opentheory_repo list";
test_passing "$opentheory_repo list ~UpToDate";
test_passing "$opentheory_repo list Deprecated";
test_passing "$opentheory_repo list Obsolete";
test_passing "$opentheory_repo list Upgradable";
test_passing "$opentheory_repo install theories/bool-implies-thm-1.1/bool-implies-thm.thy";
test_passing "$opentheory_repo info --format 'NAME-VERSION CHECKSUM' bool-implies-thm";
test_passing "$opentheory_repo list";
test_passing "$opentheory_repo list ~UpToDate";
test_passing "$opentheory_repo list Deprecated";
test_passing "$opentheory_repo list Obsolete";
test_passing "$opentheory_repo list Upgradable";
test_passing "$opentheory_repo info --upgrade-theory --theory-source --show-checksums bool-implies";
test_passing "$opentheory_repo install theories/bool-implies-1.1/bool-implies.thy";
test_passing "$opentheory_repo list";
test_passing "$opentheory_repo list ~UpToDate";
test_passing "$opentheory_repo list Deprecated";
test_passing "$opentheory_repo list Obsolete";
test_passing "$opentheory_repo list Upgradable";
test_passing "$opentheory_repo uninstall Obsolete";
test_passing "$opentheory_repo list Uploadable";

test_section "Completed opentheory tool test";

__END__

=pod

=head1 NAME

tool-test - test the opentheory tool

=head1 SYNOPSIS

tool-test [-h] [-d DIR]

=head1 ARGUMENTS

The recognized flags are described below:

=over 2

=item B<-h>

Produce this documentation.

=item B<-d DIR>

Set the path to the opentheory executable to be DIR.

=back

=head1 DESCRIPTION

Tests the opentheory tool.

=head1 BUGS

Waiting to rear their ugly heads.

=head1 AUTHORS

Joe Leslie-Hurd <joe@gilith.com>

=head1 SEE ALSO

Perl(1).

=cut
