diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..1413350
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Beginning build for ${product.name} ${product.version}
+ ${TIMESTAMP}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/properties/build.properties b/properties/build.properties
new file mode 100644
index 0000000..c487882
--- /dev/null
+++ b/properties/build.properties
@@ -0,0 +1 @@
+base=./build
\ No newline at end of file
diff --git a/properties/dir.properties b/properties/dir.properties
new file mode 100644
index 0000000..7143df7
--- /dev/null
+++ b/properties/dir.properties
@@ -0,0 +1,2 @@
+tools=tools
+src=src
\ No newline at end of file
diff --git a/properties/product.properties b/properties/product.properties
new file mode 100644
index 0000000..d08264a
--- /dev/null
+++ b/properties/product.properties
@@ -0,0 +1,4 @@
+name=TUnit
+version=0.1.0
+author=Tommy Montgomery
+website=http://tommymontgomery.com/
\ No newline at end of file
diff --git a/src/TUnit/bootstrap.php b/src/TUnit/bootstrap.php
new file mode 100644
index 0000000..62d850b
--- /dev/null
+++ b/src/TUnit/bootstrap.php
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/src/TUnit/manifest.php b/src/TUnit/manifest.php
new file mode 100644
index 0000000..9edc797
--- /dev/null
+++ b/src/TUnit/manifest.php
@@ -0,0 +1,34 @@
+ 'TUnit/framework/Assert.php',
+ 'Autoloader' => 'TUnit/util/Autoloader.php',
+ 'CombinedCaseResult' => 'TUnit/framework/CombinedTestResult.php',
+ 'ErredTest' => 'TUnit/framework/FailedTest.php',
+ 'FailedTest' => 'TUnit/framework/FailedTest.php',
+ 'FailedTestResult' => 'TUnit/framework/FailedTestResult.php',
+ 'IgnoredTest' => 'TUnit/framework/FailedTest.php',
+ 'IgnoredTestResult' => 'TUnit/framework/IgnoredTestResult.php',
+ 'PassedTestResult' => 'TUnit/framework/PassedTestResult.php',
+ 'TestCase' => 'TUnit/framework/TestCase.php',
+ 'TestFailure' => 'TUnit/framework/FailedTest.php',
+ 'TestListener' => 'TUnit/framework/TestListener.php',
+ 'TestMethod' => 'TUnit/framework/TestMethod.php',
+ 'TestReporter' => 'TUnit/framework/TestReporter.php',
+ 'TestResult' => 'TUnit/framework/TestResult.php',
+ 'TestRunner' => 'TUnit/framework/TestRunner.php',
+ 'TestSuite' => 'TUnit/framework/TestSuite.php',
+ 'Testable' => 'TUnit/framework/Testable.php'
+ );
+
+?>
\ No newline at end of file
diff --git a/src/TUnit/util/Autoloader.php b/src/TUnit/util/Autoloader.php
new file mode 100644
index 0000000..a848118
--- /dev/null
+++ b/src/TUnit/util/Autoloader.php
@@ -0,0 +1,98 @@
+ path map
+ *
+ * @version 1.0
+ * @since 1.0
+ *
+ * @return array
+ */
+ public static function getClassMap() {
+ return self::$classMap;
+ }
+
+ /**
+ * Loads a class map from an array
+ *
+ * @version 1.0
+ * @since 1.0
+ * @see loadClassMapFromFile()
+ *
+ * @param array $classMap Array of classes and the paths they map to
+ * @param string $override Whether to override previously existing classes
+ */
+ public static function loadClassMap(array $classMap, $override = true) {
+ if ((bool)$override) {
+ self::$classMap = array_merge(self::$classMap, $classMap);
+ } else {
+ self::$classMap += $classMap;
+ }
+ }
+
+ /**
+ * Loads a class map from a file
+ *
+ * @version 1.0
+ * @since 1.0
+ * @uses loadClassMap()
+ *
+ * @param string $file The manifest file to load
+ * @param string $override Whether to override previously existing classes
+ * @throws InvalidArgumentException
+ */
+ public static function loadClassMapFromFile($file, $override = true) {
+ if (!is_string($file) || !is_file($file)) {
+ throw new InvalidArgumentException('1st argument must be an existing file');
+ }
+
+ self::loadClassMap((array)include $file, $override);
+ }
+
+ /**
+ * Autoload function used by spl_autoload_call()
+ * @ignore
+ */
+ public static function autoload($className) {
+ if (isset(self::$classMap[$className])) {
+ require_once self::$classMap[$className];
+ }
+ }
+
+ }
+
+?>
\ No newline at end of file
diff --git a/tools/cli.php b/tools/cli.php
new file mode 100644
index 0000000..d2e2b71
--- /dev/null
+++ b/tools/cli.php
@@ -0,0 +1,214 @@
+ array(),
+ 'args' => array()
+ );
+
+ $last = null;
+ foreach ($args as $arg) {
+ if (strpos($arg, '-') === 0) {
+ $last = (substr($arg, 0, 2) === '--') ? substr($arg, 2) : substr($arg, 1);
+ $switch = $switches->getSwitch($last);
+ if ($switch !== null) {
+ $parsed['switches'][$switch->longName] = true;
+ }
+ } else if ($switch !== null) {
+ if ($switch->value !== null) {
+ $parsed['switches'][$switch->longName] = $arg;
+ } else {
+ $parsed['args'][] = $arg;
+ }
+
+ $switch = null;
+ } else {
+ $parsed['args'][] = $arg;
+ }
+ }
+
+ return $parsed;
+ }
+
+ }
+
+ class CliSwitch {
+ public $longName;
+ public $shortName;
+ public $required;
+ public $value;
+ public $description;
+
+ public function __construct($longName, $shortName = '', $required = true, $value = null, $description = '') {
+ $this->longName = $longName;
+ $this->shortName = $shortName;
+ $this->required = $required;
+ $this->value = $value;
+ $this->description = $description;
+ }
+ }
+
+ class CliSwitchCollection implements IteratorAggregate {
+
+ private $switches;
+
+ public function __construct() {
+ $this->switches = array();
+ }
+
+ public function addSwitch(CliSwitch $switch) {
+ $this->switches[] = $switch;
+ return $this;
+ }
+
+ public function getSwitch($longOrShortName) {
+ foreach ($this->switches as $switch) {
+ if ($switch->longName == $longOrShortName || $switch->shortName == $longOrShortName) {
+ return $switch;
+ }
+ }
+
+ return null;
+ }
+
+ public function segregateSwitches() {
+ $switches = array(
+ 'required' => array(),
+ 'optional' => array()
+ );
+ foreach ($this->switches as $switch) {
+ if ($switch->required) {
+ $switches['required'][] = $switch;
+ } else {
+ $switches['optional'][] = $switch;
+ }
+ }
+
+ return $switches;
+ }
+
+ public function getIterator() {
+ return new ArrayIterator($this->switches);
+ }
+
+ }
+
+ class Usage {
+
+ private $switches;
+ private $name;
+ private $script;
+ private $description;
+ private $copyright;
+ private $maxSwitchLength;
+
+ const LINE_LENGTH = 80;
+
+ public function __construct($name, $script, $description, $author = null, $date = null) {
+ $this->switches = array(array(), array());
+ $this->maxSwitchLength = 0;
+ $this->script = $script;
+ $this->name = $name;
+ $this->description = $description;
+ $this->copyright =
+ ($date !== null)
+ ? 'Copyright (c) ' . $date . (($author !== null) ? " $author" : '')
+ : (($author !== null) ? "by $author" : '');
+ }
+
+ public function __get($key) {
+ if ($key === 'switches') {
+ return $this->switches;
+ }
+
+ throw new InvalidArgumentException('Invalid property');
+ }
+
+ public function setSwitches(CliSwitchCollection $switches) {
+ $this->switches = $switches;
+
+ $this->maxSwitchLength = 0;
+ foreach ($switches->getIterator() as $switch) {
+ // + 2 for left padding
+ // + 2 for double-hyphen
+ $length = 2 + strlen($switch->longName) + 2;
+
+ // + 1 for left padding
+ // + 1 for hyphen
+ // + 1 for openening parenthesis
+ // + 1 for closing parenthesis
+ $length += (strlen($switch->shortName) > 0) ? 1 + 1 + 1 + strlen($switch->shortName) + 1 : 0;
+ //echo $length . "\n";
+ $this->maxSwitchLength = max($this->maxSwitchLength, $length);
+ }
+
+ //echo $this->maxSwitchLength; exit;
+ }
+
+ public function __toString() {
+ $this->maxSwitchLength += 2;
+ $usage = $this->name . "\n";
+ $usage .= (!empty($this->copyright)) ? ' ' . $this->copyright . "\n" : '';
+ $usage .= "\n";
+
+ $usage .= "USAGE\n";
+ $usageData = ' php ' . $this->script;
+
+ $switchData = "REQUIRED\n";
+
+ $switches = $this->switches->segregateSwitches();
+
+ foreach ($switches['required'] as $switch) {
+ $usageData .= ' --' . $switch->longName;
+ if ($switch->value !== null) {
+ $usageData .= ' ' . $switch->value;
+ }
+
+ $x = ' --' . $switch->longName;
+ if (!empty($switch->shortName)) {
+ $x .= str_repeat(' ', $this->maxSwitchLength - 5 - strlen($x)) . '(-' . $switch->shortName . ')';
+ }
+
+ $x .= str_repeat(' ' , $this->maxSwitchLength - strlen($x));
+ $x .= wordwrap($switch->description, self::LINE_LENGTH - strlen($x), "\n" . str_repeat(' ', strlen($x))) . "\n";
+ $switchData .= $x;
+ }
+
+ $switchData .= "\nOPTIONAL\n";
+ foreach ($switches['optional'] as $switch) {
+ $usageData .= ' [--' . $switch->longName;
+ if ($switch->value !== null) {
+ $usageData .= ' ' . $switch->value;
+ }
+ $usageData .= ']';
+
+ $x = ' --' . $switch->longName;
+ if (!empty($switch->shortName)) {
+ $x .= str_repeat(' ', $this->maxSwitchLength - 5 - strlen($x)) . '(-' . $switch->shortName . ')';
+ }
+
+ $x .= str_repeat(' ' , $this->maxSwitchLength - strlen($x));
+ $x .= wordwrap($switch->description, self::LINE_LENGTH - strlen($x), "\n" . str_repeat(' ', strlen($x))) . "\n";
+ $switchData .= $x;
+ }
+
+ $usage .= wordwrap($usageData, self::LINE_LENGTH - 2, "\n ");
+
+ $usage .= "\n\n" . $switchData . "\n";
+
+ return $usage;
+ }
+
+ }
+
+?>
\ No newline at end of file
diff --git a/tools/manifester.php b/tools/manifester.php
new file mode 100644
index 0000000..096518f
--- /dev/null
+++ b/tools/manifester.php
@@ -0,0 +1,167 @@
+setSwitches($switches);
+
+ echo $usage;
+ }
+
+ if (!extension_loaded('tokenizer')) {
+ throw new Exception('The "tokenizer" extension must be loaded to use this script');
+ }
+
+ global $switches;
+ $switches = new CliSwitchCollection();
+ $switches->addSwitch(new CliSwitch('directory', 'd', true, 'dir1,dir2,...', 'Comma-delimited list of directories'))
+ ->addSwitch(new CliSwitch('version', 'v', true, 'version_number', 'Version number for use in @version tag'))
+ ->addSwitch(new CliSwitch('package', 'p', true, 'package_name ', 'Name of the package for use in @package tag'))
+ ->addSwitch(new CliSwitch('output', 'o', false, 'file', 'Name of the output file, defaults to stdout if empty and this is really really really really long'))
+ ->addSwitch(new CliSwitch('quiet', 'q', false, null, 'Do not print progress messages'))
+ ->addSwitch(new CliSwitch('recursive', 'r', false, null, 'Recursively walk the directories'))
+ ->addSwitch(new CliSwitch('base-dir', 'b', true, 'dir', 'Base directory'));
+
+ array_shift($argv);
+ $args = Cli::parseArgs($argv, $switches);
+ $args = $args['switches']; //don't care about non-switch stuff
+
+ if (!isset($args['directory'], $args['version'], $args['package'], $args['base-dir'])) {
+ usage();
+ fwrite(STDERR, "Missing a required argument\n");
+ exit(1);
+ }
+
+ $dirs = explode(',', $args['directory']);
+
+ if (!is_dir($args['base-dir'])) {
+ fwrite(STDERR, $args['base-dir'] . ' is not a directory');
+ exit(1);
+ }
+
+ $args['recursive'] = array_key_exists('recursive', $args);
+ $args['quiet'] = array_key_exists('quiet', $args);
+
+ $date = date('Y-m-d H:i:s');
+ $self = basename(__FILE__);
+ $data = <<isFile() && strpos($file->getPathName(), DIRECTORY_SEPARATOR . '.') === false && substr($file->getFileName(), -4) === '.php') {
+ if (!$args['quiet']) {
+ echo 'Processing ' . $file->getPathName() . "\n";
+ }
+
+ $tokens = token_get_all(file_get_contents($file->getPathName()));
+ $count = count($tokens);
+ for ($i = 0; $i < $count; $i++) {
+ if (is_array($tokens[$i])) {
+ if ($tokens[$i][0] === T_CLASS || $tokens[$i][0] === T_INTERFACE) {
+ //get class name
+ if (isset($tokens[$i + 2]) && is_array($tokens[$i + 2]) && $tokens[$i + 2][0] === T_STRING) {
+ $className = $tokens[$i + 2][1];
+ if (isset($classes[$className]) && !$args['quiet']) {
+ fwrite(STDERR, '******WARNING: FOUND DUPLICATE CLASS (' . $className . ')******' . "\n");
+ }
+
+ $classes[$className] = ltrim(str_replace(array($args['base-dir'], DIRECTORY_SEPARATOR), array('', '/'), $file->getPathName()), '/');
+ $maxClassNameLength = max($maxClassNameLength, strlen($className));
+ $i += 2; //loop unroll FTW!
+
+ if (!$args['quiet']) {
+ echo 'Added class/interface ' . $className . "\n";
+ }
+ }
+ }
+ }
+ }
+
+ unset($tokens);
+ }
+ }
+ }
+
+ echo "\n" . '# of classes: ' . count($classes) . "\n\n";
+
+ $func = create_function(
+ '&$value, $key',
+ '$value = "\t\t\'$key\'" . str_repeat(\' \', ' . $maxClassNameLength . ' - strlen($key)) . " => \'$value\'";'
+ );
+
+ ksort($classes);
+ array_walk($classes, $func);
+
+ $data .= implode(",\n", $classes) . "\n\t);\n\n?>";
+ if (isset($args['output']) && !is_dir(dirname($args['output'])) && !mkdir(dirname($args['output']), 0777, true)) {
+ fwrite(STDERR, 'Unable to mkdir(): ' . dirname($args['output']));
+ exit(1);
+ } else if (!isset($args['output'])) {
+ $args['output'] = 'php://stdout';
+ }
+
+ if (is_dir($args['output'])) {
+ $args['output'] .= DIRECTORY_SEPARATOR . 'manifest.php';
+ }
+
+ $fp = fopen($args['output'], 'w');
+ if (!$fp) {
+ fwrite(STDERR, 'Unable to open ' . $args['output'] . ' for writing');
+ exit(1);
+ }
+
+ fwrite($fp, $data);
+ fclose($fp);
+ echo 'Wrote data to ' . $args['output'] . ' (' . strlen($data) . ' bytes)' . "\n";
+
+ exit(0);
+
+?>
\ No newline at end of file