Location: PHPKode > projects > phc > test/framework/lib/test.php
<?php
/*
 * phc -- the open source PHP compiler
 * See doc/license/README.license for licensing information
 *
 * Base class for tests
 */

require_once ("labels.php");
abstract class Test
{
	function __construct ()
	{
		$this->successes = 0;
		$this->failures = 0;
		$this->skipped = 0;
		$this->timeouts = 0;
		$this->max_time = 20;
		$this->total = 0;
		$this->solo_tests = 0;
		$this->missing_dependencies = array ();
	}

	function get_name ()
	{
		return get_class($this);
	}

	function ready_progress_bar ($num_files)
	{
		global $opt_no_progress_bar;
		$this->num_files = $num_files;
		if (!$opt_no_progress_bar)
		{
			// this line is irrelevent, since it's reset below 
			$this->progress_bar = new Console_ProgressBar (
				$this->get_name()."%bar% Testing (%fraction%)",
				"#", "-", 80, $num_files); 
		}
		$this->update_count(0);
	}

	function homogenize_output ($string)
	{
		return $string;
	}

	function check_global_prerequisites ()
	{
		global $php;
		return check_for_program ($php);
	}

	function check_prerequisites ()
	{
		return true;
	}

	function check_test_prerequisites ($subject)
	{
		return true;
	}

	function get_dependent_test_names ()
	{
		return array ();
	}

	// we dont want this to be overridden
	function get_builtin_dependent_test_names ()
	{
		if (!isset($this->dependencies))
			return array ();

		return (array) ($this->dependencies);
	}

	function calculate_all_dependencies ()
	{
		global $tests;
		$dependencies = $this->get_builtin_dependent_test_names () 
				+ $this->get_dependent_test_names ();

		# we want deep dependencies here, so get the parent dependencies too
		$all_dependencies = array ();
		foreach ($dependencies as $dependency)
		{
			$all_dependencies[] = $dependency;
			foreach ($tests as $test) # find it in the set of tests
			{
				if ($test->get_name () == $dependency)
				{
					foreach ($test->get_all_dependencies() as $new_dependency)
						$all_dependencies[] = $new_dependency;
					break;
				}
			}
		}
		$this->all_dependencies = $all_dependencies;
	}

	function get_all_dependencies ()
	{
		if (isset($this->all_dependencies))
			return $this->all_dependencies;

		$this->calculate_all_dependencies ();
		return $this->all_dependencies;
	}

	function passed_test_dependencies ($subject)
	{
		$shallow_dependencies = $this->get_all_dependencies ();

		# we want deep dependencies here, so get the parent dependencies too
		$dependencies = array ();
		global $tests;
		while ($shallow_dependencies)
		{
			$dependency = array_pop ($shallow_dependencies);
			if (in_array ($dependency, $dependencies))
				continue;

			$dependencies[] = $dependency;
			foreach ($tests as $test) # find it in the set of tests
			{
				if ($test->get_name () == $dependency)
				{
					foreach ($test->get_all_dependencies() as $new_dependency)
						$shallow_dependencies[] = $new_dependency;
					break;
				}
			}
		}

		foreach ($dependencies as $dependency)
		{
			$depend = read_dependency ($dependency, $subject);
			if ($depend == "Fail")
				return false;
			elseif ($depend == "missing")
				$this->missing_dependencies[$subject] = $dependency;
		}
		return true;
	}

	abstract function run_test ($subject);
	abstract function get_test_subjects ();

	function print_numbered ()
	{
		$files = $this->get_test_subjects();
		$i = 1;
		foreach ($files as $file)
		{
			print "$i. $file\n";
			$i++;
		}
	}

	function run()
	{
		// do this first so that the progress bar is ready
		$files = $this->get_test_subjects ();
		$this->ready_progress_bar (count ($files));


		if (!$this->check_prerequisites () || !$this->check_global_prerequisites ())
		{
			$this->mark_skipped ("All", "Test prerequisties failed");
			$this->finish_test ();
			return false;
		}

		// end early if specified
		global $opt_quick;
		$count = 0;

		foreach ($files as $subject)
		{
			if (!$this->check_test_prerequisites ($subject))
			{
				$this->mark_skipped ($subject, "Individual prerequsite failed");
			}
			elseif (!$this->passed_test_dependencies ($subject))
			{
				$this->mark_skipped ($subject, "Test failed dependency");
			}
			elseif ($this->check_exception ($subject))
			{
				$this->mark_skipped ($subject, "Test excepted");
			}
			else
			{
				$this->run_test ($subject);
			}
			$count ++;

			if ($opt_quick && $count >= 10)
				break;
		}

		$this->finish_test ();
	}

	function mark_success ($subject)
	{
		write_dependencies ($this->get_name (), $subject, true);

		$this->successes++;
		$this->total++;
		$this->update_count ();
		log_status ("success", $this->get_name(), $subject, "");
	}

	function mark_timeout ($subject, $commands, $outs, $errs, $exits)
	{
		$this->timeouts++;
		$this->total++;
		$this->update_count ();
		log_status ("timeout", $this->get_name(), $subject, "");
	}

	function mark_skipped ($subject, $reason)
	{
		if ($subject == "All")
		{
			$this->skipped += count($this->get_test_subjects ());
			$this->total = $this->skipped;
		}
		else
		{
			$this->skipped++;
			$this->total++;
		}
		write_dependencies ($this->get_name (), $subject, false);
		log_status ("skipped", $this->get_name(), $subject, $reason);
		$this->update_count ();
	}

	function mark_failure ($subject, $commands, $outs = "Not relevent", $errs = "Not relevent", $exits = "Not relevent", $reason = "TODO - no reason given")
	{
		write_dependencies ($this->get_name (), $subject, false);

		log_failure ($this->get_name(), $subject, $commands, $outs, $errs, $exits, isset ($this->missing_dependencies[$subject]) ? $this->missing_dependencies[$subject] : NULL, $reason);
		log_status ("failure", $this->get_name(), $subject, $reason);
		$this->erase_progress_bar();

		$this->display_progress_bar ();

		$this->failures++;
		$this->total++;
		$this->update_count ();
	}

	function is_successful ()
	{
		return ($this->failures == 0);
	}

	function is_completely_skipped ()
	{
		return ($this->failures == 0 and $this->successes == 0 and $this->timeouts == 0 and $this->skipped >= 0);
	}

	function get_appropriate_colour ()
	{
		if ($this->is_completely_skipped ())
			return blue_string ();
		elseif ($this->is_successful ())
			return green_string ();
		else
			return red_string ();
	}

	function get_appropriate_phrase ()
	{
		if ($this->is_completely_skipped ())
			return "Skipped";
		elseif ($this->is_successful ())
			return "Success";
		else
			return "Failure";
	}

	function get_triple_string ($finished = false)
	{
		$reset = reset_string ();
		$passed = sprintf ("%5s", $this->successes." P");
		$failed = sprintf ("%5s", $this->failures." F");
		$timedout = sprintf ("%5s", $this->timeouts ." T");
		$skipped = sprintf ("%5s", $this->skipped." S");
		if ($finished)
		{
			$colour = $this->get_appropriate_colour ();
			return "$colour$passed, $failed, $timedout, $skipped$reset";
		}
		else
		{
			$blue = blue_string ();
			$green = green_string ();
			$red = red_string ();
			$reset = reset_string ();
			return "$green$passed$reset, $red$failed$reset, $blue$timedout$reset, $blue$skipped$reset";
		}
	}

	function update_count ()
	{
		global $opt_no_progress_bar;
		if (! $opt_no_progress_bar)
		{
			# check for divide by zero
			$target_num = $this->num_files;
			if ($target_num == 0) $target_num = 1;

			$this->erase_progress_bar ();
			$this->progress_bar->reset(
					"{$this->get_name()} %bar% %fraction%: {$this->get_triple_string ()}", 
					"#", "-", 112, $target_num); # i dont understand how this number works, but it includes control chars
			$this->progress_bar->update($this->total);
		}
	}

	function erase_progress_bar ()
	{
		global $opt_no_progress_bar;
		if (! $opt_no_progress_bar)
		{
			$this->progress_bar->erase();
		}
	}

	function display_progress_bar ()
	{
		global $opt_no_progress_bar;
		if (! $opt_no_progress_bar)
		{
			$this->progress_bar->display($this->total);
		}
	}

	function finish_test ()
	{
		$this->erase_progress_bar();

		$red = red_string ();
		$blue = blue_string ();
		$green = green_string ();
		$reset = reset_string ();

		$test = $this->get_name();
		$triple = $this->get_triple_string (true);

		$phrase = $this->get_appropriate_phrase ();
		$colour = $this->get_appropriate_colour ();
		$word = "$colour$phrase:$reset";

		// a color or a reset involves 6 characters, but gets displayed as zero.
		// Those 6 need to be taken into account for sprintf
		$string = sprintf("%-27s %20s %41s\n", $test, $word, $triple);
		print "$string";
		write_status ("results", strip_colour ($string));
	}

	// return true if the subject is marked as an exception
	function check_exception ($subject)
	{
		global $exceptions;
		if (!isset($exceptions{$this->get_name()})) return false;
		$array = $exceptions{$this->get_name()};
		assert (is_array ($array));
		return (in_array ($subject, $array));
	}
}


?>
Return current item: phc