#!/usr/bin/perl
# Test how mood calls methods of various sorts.
use Mooix::Thing;
use Mooix::Root;
use Test::More import => ['!fail'];
			
# The perl binding does not currently provide a way
# to call a method passing args on the command line.
sub call {
	my $test=shift;
	my $pid=open(CALL, "-|");
	if (! $pid) {
		exec("./".$test, @_);
		exit 100;
	}
	else {
		my @ret;
		while (<CALL>) {
			chomp;
			s/^"//;
			s/"$//;
			push @ret, $_;
		}
		close CALL;
		return @ret;
	}
}
			
run sub {
	my $this=shift;
	
	my @environs=$this->environ_tests;
	
	my @nums=qw(0 1 42 255);
	# Testing the environment mood provides to methods of various
	# kinds.
	plan tests => @environs * (15 + 2 * int(@nums)) + 1,
	     import => ['!fail'];
	ok(@environs > 0, "make sure there are some..");
	
	foreach my $env (@environs) {
		SKIP: {
			# Parameter passing. Methods return their inputs.
			my $test="params_$env";
			skip "unimplemented methods", 5
				unless $this->implements($test);
			foreach my $params (
				[],
				[1,2,3,4],
				[1,$this,3,$this->parent],
				["this is a long\nmulti-line string\nend"]
			) {
				my @ret=$this->$test(@$params);
				my @expected=(int(@$params), @$params);
				if (eq_array(\@ret, \@expected)) {
					ok(1, "passed ".join(", ",@$params));
				}
				else {
					ok(0, "passed ".join(", ",@$params));
					diag("expected: ".join(", ", @expected)."  (test is $test)");
					diag("got:      ".join(", ", @ret));
				}
			}
			is($?, 0, "check exit status")
		}
		SKIP: {
			# Exit code returning. Methods exit with code from
			# parameter (and output "ran");
			my $test="exitcode_$env";
			skip "unimplemented methods", 2 * int(@nums)
				unless $this->implements($test);
			for my $num (@nums) {
				my $ret=$this->$test(code => $num);
				is($ret, "ran", "call with $num");
				if ($ret ne 'ran') {
					diag("failed test for $env with num: $num");
				}
				is($? >> 8, $num, "returned $num");
				if ($? >> 8 != $num) {
					diag("failed test for $env with num: $num");
				}
			}
		}
		SKIP: {
			# Command-line argument passing. Methods return $0,
			# argc, and all of argv.
			my $test="argv_$env";
			skip "unimplemented methods", 4
				unless $this->implements($test);

			foreach my $set (
				[],
				["hi mom", "bye mom"],
				[1,2,3,4],
			) {
				my @ret = call($test, @$set);
				if (eq_array(\@ret, ["./".$test, int(@$set), @$set])) {
					ok(1, "passed $#set");
				}
				else {
					ok(0, "passed $#set");
					diag("got: ".join(", ", @ret)." ".
					     "expected: ".join(", ", "./".$test, int(@$set), @$set));
				}
			}		
			is($? >> 8, 0, "check exit status")
		}
		SKIP: {
			# Basic environment. Methods return METHOD,
			# MOOSOCK, LD_PRELOAD, THIS.
			my $test="environ_$env";
			skip "unimplemented methods", 4
				unless $this->implements($test);
			my @ret=$this->$test;
			is($ret[0], "./".$test);
			like($ret[1], qr/.*\/.*.sock$/);
			like($ret[2], qr/.*\/libmooproxy.so$/);
			is($ret[3], $this->id);
		}
		SKIP: {
			# MOOIX_DEBUG support. Methods call other methods,
			# with it unset, and set, and return their return
			# codes, which say whether it was set or not.
			# 
			# Note that this test will fail if mood was started
			# with MOOIX_DEBUG set.
			my $test="debug_$env";
			skip "unimplemented methods", 2
				unless $this->implements($test);
			my @ret=$this->$test;
			is($ret[0], "", "w/o debug on");
			is($ret[1], $Mooix::Root->abstract->debug."", "with debug on");
		}
	}
}
