[Solar-svn] Revision 2684
pmjones at solarphp.com
pmjones at solarphp.com
Thu Aug 9 16:36:04 CDT 2007
Branch: Solar_Cli_MakeTests: [NEW] New CLI command to make Solar_Test stub files
Added: branches/orm/Solar/Cli/MakeTests/Data/classAbstract.php
===================================================================
--- branches/orm/Solar/Cli/MakeTests/Data/classAbstract.php (rev 0)
+++ branches/orm/Solar/Cli/MakeTests/Data/classAbstract.php 2007-08-09 21:36:04 UTC (rev 2684)
@@ -0,0 +1,86 @@
+<?php
+/**
+ *
+ * Abstract class test.
+ *
+ */
+class Test_:class extends :extends {
+
+ /**
+ *
+ * Configuration values.
+ *
+ * @var array
+ *
+ */
+ protected $_Test_:class = array(
+ );
+
+ // -----------------------------------------------------------------
+ //
+ // Support methods.
+ //
+ // -----------------------------------------------------------------
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param array $config User-defined configuration parameters.
+ *
+ */
+ public function __construct($config)
+ {
+ $this->skip('abstract class');
+ parent::__construct($config);
+ }
+
+ /**
+ *
+ * Destructor; runs after all methods are complete.
+ *
+ * @param array $config User-defined configuration parameters.
+ *
+ */
+ public function __destruct()
+ {
+ parent::__destruct();
+ }
+
+ /**
+ *
+ * Setup; runs before each test method.
+ *
+ */
+ public function setup()
+ {
+ parent::setup();
+ }
+
+ /**
+ *
+ * Setup; runs after each test method.
+ *
+ */
+ public function teardown()
+ {
+ parent::teardown();
+ }
+
+ // -----------------------------------------------------------------
+ //
+ // Test methods.
+ //
+ // -----------------------------------------------------------------
+
+ /**
+ *
+ * Test -- Constructor.
+ *
+ */
+ public function test__construct()
+ {
+ $obj = Solar::factory(':class');
+ $this->assertInstance($obj, ':class');
+ }
+}
\ No newline at end of file
Added: branches/orm/Solar/Cli/MakeTests/Data/classAdapter.php
===================================================================
--- branches/orm/Solar/Cli/MakeTests/Data/classAdapter.php (rev 0)
+++ branches/orm/Solar/Cli/MakeTests/Data/classAdapter.php 2007-08-09 21:36:04 UTC (rev 2684)
@@ -0,0 +1,90 @@
+<?php
+/**
+ * Parent test.
+ */
+require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'Adapter.php';
+
+/**
+ *
+ * Adapter class test.
+ *
+ */
+class Test_:class extends :extends {
+
+ /**
+ *
+ * Configuration values.
+ *
+ * @var array
+ *
+ */
+ protected $_Test_:class = array(
+ );
+
+ // -----------------------------------------------------------------
+ //
+ // Support methods.
+ //
+ // -----------------------------------------------------------------
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param array $config User-defined configuration parameters.
+ *
+ */
+ public function __construct($config)
+ {
+ $this->todo('need adapter-specific config');
+ }
+
+ /**
+ *
+ * Destructor; runs after all methods are complete.
+ *
+ * @param array $config User-defined configuration parameters.
+ *
+ */
+ public function __destruct()
+ {
+ parent::__destruct();
+ }
+
+ /**
+ *
+ * Setup; runs before each test method.
+ *
+ */
+ public function setup()
+ {
+ parent::setup();
+ }
+
+ /**
+ *
+ * Setup; runs after each test method.
+ *
+ */
+ public function teardown()
+ {
+ parent::teardown();
+ }
+
+ // -----------------------------------------------------------------
+ //
+ // Test methods.
+ //
+ // -----------------------------------------------------------------
+
+ /**
+ *
+ * Test -- Constructor.
+ *
+ */
+ public function test__construct()
+ {
+ $obj = Solar::factory(':class');
+ $this->assertInstance($obj, ':class');
+ }
+}
\ No newline at end of file
Added: branches/orm/Solar/Cli/MakeTests/Data/classConcrete.php
===================================================================
--- branches/orm/Solar/Cli/MakeTests/Data/classConcrete.php (rev 0)
+++ branches/orm/Solar/Cli/MakeTests/Data/classConcrete.php 2007-08-09 21:36:04 UTC (rev 2684)
@@ -0,0 +1,85 @@
+<?php
+/**
+ *
+ * Concrete class test.
+ *
+ */
+class Test_:class extends :extends {
+
+ /**
+ *
+ * Configuration values.
+ *
+ * @var array
+ *
+ */
+ protected $_Test_:class = array(
+ );
+
+ // -----------------------------------------------------------------
+ //
+ // Support methods.
+ //
+ // -----------------------------------------------------------------
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param array $config User-defined configuration parameters.
+ *
+ */
+ public function __construct($config)
+ {
+ parent::__construct($config);
+ }
+
+ /**
+ *
+ * Destructor; runs after all methods are complete.
+ *
+ * @param array $config User-defined configuration parameters.
+ *
+ */
+ public function __destruct()
+ {
+ parent::__destruct();
+ }
+
+ /**
+ *
+ * Setup; runs before each test method.
+ *
+ */
+ public function setup()
+ {
+ parent::setup();
+ }
+
+ /**
+ *
+ * Setup; runs after each test method.
+ *
+ */
+ public function teardown()
+ {
+ parent::teardown();
+ }
+
+ // -----------------------------------------------------------------
+ //
+ // Test methods.
+ //
+ // -----------------------------------------------------------------
+
+ /**
+ *
+ * Test -- Constructor.
+ *
+ */
+ public function test__construct()
+ {
+ $obj = Solar::factory(':class');
+ $this->assertInstance($obj, ':class');
+ }
+}
\ No newline at end of file
Added: branches/orm/Solar/Cli/MakeTests/Data/classFactory.php
===================================================================
--- branches/orm/Solar/Cli/MakeTests/Data/classFactory.php (rev 0)
+++ branches/orm/Solar/Cli/MakeTests/Data/classFactory.php 2007-08-09 21:36:04 UTC (rev 2684)
@@ -0,0 +1,85 @@
+<?php
+/**
+ *
+ * Factory class test.
+ *
+ */
+class Test_:class extends :extends {
+
+ /**
+ *
+ * Configuration values.
+ *
+ * @var array
+ *
+ */
+ protected $_Test_:class = array(
+ );
+
+ // -----------------------------------------------------------------
+ //
+ // Support methods.
+ //
+ // -----------------------------------------------------------------
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param array $config User-defined configuration parameters.
+ *
+ */
+ public function __construct($config)
+ {
+ parent::__construct($config);
+ }
+
+ /**
+ *
+ * Destructor; runs after all methods are complete.
+ *
+ * @param array $config User-defined configuration parameters.
+ *
+ */
+ public function __destruct()
+ {
+ parent::__destruct();
+ }
+
+ /**
+ *
+ * Setup; runs before each test method.
+ *
+ */
+ public function setup()
+ {
+ parent::setup();
+ }
+
+ /**
+ *
+ * Setup; runs after each test method.
+ *
+ */
+ public function teardown()
+ {
+ parent::teardown();
+ }
+
+ // -----------------------------------------------------------------
+ //
+ // Test methods.
+ //
+ // -----------------------------------------------------------------
+
+ /**
+ *
+ * Test -- Constructor.
+ *
+ */
+ public function test__construct()
+ {
+ $obj = Solar::factory(':class');
+ $this->assertInstance($obj, ':class_Adapter');
+ }
+}
\ No newline at end of file
Added: branches/orm/Solar/Cli/MakeTests/Data/methodAbstract.php
===================================================================
--- branches/orm/Solar/Cli/MakeTests/Data/methodAbstract.php (rev 0)
+++ branches/orm/Solar/Cli/MakeTests/Data/methodAbstract.php 2007-08-09 21:36:04 UTC (rev 2684)
@@ -0,0 +1,10 @@
+
+ /**
+ *
+ * Test -- :summ
+ *
+ */
+ public function :name()
+ {
+ $this->skip('abstract method');
+ }
Added: branches/orm/Solar/Cli/MakeTests/Data/methodConcrete.php
===================================================================
--- branches/orm/Solar/Cli/MakeTests/Data/methodConcrete.php (rev 0)
+++ branches/orm/Solar/Cli/MakeTests/Data/methodConcrete.php 2007-08-09 21:36:04 UTC (rev 2684)
@@ -0,0 +1,10 @@
+
+ /**
+ *
+ * Test -- :summ
+ *
+ */
+ public function :name()
+ {
+ $this->todo('stub');
+ }
Added: branches/orm/Solar/Cli/MakeTests/Info/options.php
===================================================================
--- branches/orm/Solar/Cli/MakeTests/Info/options.php (rev 0)
+++ branches/orm/Solar/Cli/MakeTests/Info/options.php 2007-08-09 21:36:04 UTC (rev 2684)
@@ -0,0 +1,13 @@
+<?php
+return array(
+ 'target' => array(
+ 'long' => 'target',
+ 'descr' => 'Where the tests will be written to.',
+ ),
+ 'only' => array(
+ 'long' => 'only',
+ 'param' => null,
+ 'value' => false,
+ 'descr' => 'Make tests only for the named class; do not descend into subdirectories.',
+ ),
+);
\ No newline at end of file
Added: branches/orm/Solar/Cli/MakeTests.php
===================================================================
--- branches/orm/Solar/Cli/MakeTests.php (rev 0)
+++ branches/orm/Solar/Cli/MakeTests.php 2007-08-09 21:36:04 UTC (rev 2684)
@@ -0,0 +1,282 @@
+<?php
+/**
+ *
+ * Command to make a test class (or set of classes) from a named class.
+ *
+ * @category Solar
+ *
+ * @package Solar_Cli
+ *
+ * @author Paul M. Jones <pmjones at solarphp.com>
+ *
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ *
+ * @version $Id: Base.php 2498 2007-06-01 19:36:45Z pmjones $
+ *
+ */
+
+/**
+ *
+ * Command to make a test class (or set of classes) from a given class.
+ *
+ * The class should be in the include_path.
+ *
+ * Synopsis
+ * ========
+ *
+ * `**solar make-tests** [options] CLASS`
+ *
+ * Options
+ * =======
+ *
+ * `--config FILE`
+ * : Path to the Solar.config.php file. Default false.
+ *
+ * `--target _arg_`
+ * : Directory where the test classes should be written to. Default is the
+ * current working directory.
+ *
+ * `--only`
+ * : Make only the test for the given class, do not recurse into subdirectories.
+ *
+ * Examples
+ * ========
+ *
+ * Make test files for a class and its subdirectories.
+ *
+ * $ cd /path/to/tests/
+ * $ solar make-tests Vendor_Example
+ *
+ * Make "remotely":
+ *
+ * $ solar make-tests --dir /path/to/tests Vendor_Example
+ *
+ * Make only the Vendor_Example test (no subdirectories):
+ *
+ * $ solar make-tests --only Vendor_Example
+ *
+ * @category Solar
+ *
+ * @package Solar_Cli
+ *
+ */
+class Solar_Cli_MakeTests extends Solar_Cli_Base {
+
+ protected $_tpl; // templates for classes and methods
+
+ protected $_class; // the source class to work with
+
+ protected $_target; // the target directory for writing tests
+
+ protected $_file; // name of the test file to work with
+
+ protected $_code; // the code in the test file
+
+ protected function _exec($class = null)
+ {
+ $this->_println("Making tests.");
+
+ // make sure we have a class to work with
+ if (! $class) {
+ throw $this->_exception('ERR_NO_CLASS_SPECIFIED');
+ }
+
+ // make sure we have a target directory
+ $this->_setTarget();
+
+ // get all the class and method templates
+ $this->_loadTemplates();
+
+ // build a class-to-file map object for later use
+ $map = Solar::factory('Solar_Class_Map');
+
+ // tell the user where the source and targets are
+ $this->_println("Source: " . $map->getBase());
+ $this->_println("Target: $this->_target");
+
+ // get the class and file locations
+ $class_file = $map->fetch($class);
+ foreach ($class_file as $class => $file) {
+
+ // tell the user what class we're on
+ $this->_print("$class: ");
+
+ // if this is an exception class, skip it
+ if (strpos($class, '_Exception')) {
+ $this->_println("skip (exception class)");
+ continue;
+ }
+
+ // load the class and get its API reference
+ Solar::loadClass($class);
+ $apiref = Solar::factory('Solar_Docs_Apiref');
+ $apiref->addClass($class);
+ $api = $apiref->api[$class];
+
+ // set the file name, creating if needed
+ $this->_setFile($class, $api);
+
+ // get the code currently in the file
+ $this->_code = file_get_contents($this->_file);
+
+ // add new test methods
+ $this->_addTestMethods($api);
+
+ // write the file back out again
+ file_put_contents($this->_file, $this->_code);
+
+ // done with this class
+ $this->_println(' ;');
+ }
+
+ // done with all classes.
+ $this->_println('Done.');
+ }
+
+ protected function _loadTemplates()
+ {
+ $this->_tpl = array();
+ $dir = Solar::fixdir(dirname(__FILE__) . '/MakeTests/Data');
+ $list = glob($dir . '*.php');
+ foreach ($list as $file) {
+ $key = substr(basename($file), 0, -4);
+ $this->_tpl[$key] = file_get_contents($file);
+ }
+ }
+
+ protected function _setTarget()
+ {
+ // look for a test directory, otherwise assume that the tests are
+ // in the same dir
+ $this->_target = $this->_options['target'];
+ if (! $this->_target) {
+ $this->_target = getcwd();
+ }
+
+ // make sure it matches the OS.
+ $this->_target = Solar::fixdir($this->_target);
+
+ // make sure it exists
+ if (! is_dir($this->_target)) {
+ throw $this->_exception('ERR_TARGET_NOT_EXIST');
+ }
+ }
+
+ protected function _setFile($class, $api)
+ {
+ $this->_file = $this->_target
+ . str_replace('_', DIRECTORY_SEPARATOR, "Test_$class")
+ . '.php';
+
+ // create the file if needed
+ if (file_exists($this->_file)) {
+ return;
+ }
+
+ // create the directory if needed
+ $dir = dirname($this->_file);
+ if (! is_dir($dir)) {
+ mkdir($dir, 0777, true);
+ }
+
+ // use the right code template
+ if ($api['abstract']) {
+ $code = $this->_tpl['classAbstract'];
+ } elseif (! empty($api['methods']['solarFactory'])) {
+ $code = $this->_tpl['classFactory'];
+ } else {
+ $code = $this->_tpl['classConcrete'];
+ }
+
+ // use the right "extends" for adapter classes.
+ // extends this to helpers and abstracts?
+ // note that this still writes the new methods, when they should
+ // be inherited from the parent test instead.
+ $pos = strrpos($class, '_Adapter_');
+ if ($pos) {
+ $code = $this->_tpl['classAdapter'];
+ $extends = 'Test_' . substr($class, 0, $pos + 8);
+ } else {
+ $extends = 'Solar_Test';
+ }
+
+ // do replacements
+ $code = str_replace(
+ array(':class', ':extends'),
+ array($class, $extends),
+ $code
+ );
+
+ // write the file
+ file_put_contents($this->_file, $code);
+ }
+
+ protected function _addTestMethods($api)
+ {
+ // prepare the testing code for appending new methods.
+ $this->_code = trim($this->_code);
+
+ // the last char should be a brace.
+ $last = substr($this->_code, -1);
+ if ($last != '}') {
+ throw $this->_exception('ERR_LAST_BRACE', array(
+ 'file' => $this->_file
+ ));
+ }
+
+ // strip the last brace
+ $this->_code = substr($this->_code, 0, -1);
+
+ // ignore these methods
+ $ignore = array('__construct', '__destruct', 'apiVersion', 'dump',
+ 'locale');
+
+ // look for methods and add them if needed
+ foreach ($api['methods'] as $name => $info) {
+
+ // is this an ignored method?
+ if (in_array($name, $ignore)) {
+ $this->_print('.');
+ continue;
+ }
+
+ // is this a public method?
+ if ($info['access'] != 'public') {
+ $this->_print('.');
+ continue;
+ };
+
+ // the test-method name
+ $test_name = 'test' . ucfirst($name);
+
+ // does the test-method definition already exist?
+ $def = "public function {$test_name}()";
+ $pos = strpos($this->_code, $def);
+ if ($pos) {
+ $this->_print('.');
+ continue;
+ }
+
+ // use the right code template
+ if ($info['abstract']) {
+ $test_code = $this->_tpl['methodAbstract'];
+ } else {
+ $test_code = $this->_tpl['methodConcrete'];
+ }
+
+ // do replacements
+ $test_code = str_replace(
+ array(':name', ':summ'),
+ array($test_name, $info['summ']),
+ $test_code
+ );
+
+ // append to the test code
+ $this->_code .= $test_code;
+ $this->_print('+');
+ }
+
+ // append the last brace
+ $this->_code .= "\n}\n";
+ }
+}
More information about the Solar-svn
mailing list