OSDN Git Service

- add ethna command(add-action-test,add-view-test)
authorhalt1983 <halt1983@2ef88817-412d-0410-a32c-8029a115e976>
Thu, 9 Mar 2006 13:47:43 +0000 (13:47 +0000)
committerhalt1983 <halt1983@2ef88817-412d-0410-a32c-8029a115e976>
Thu, 9 Mar 2006 13:47:43 +0000 (13:47 +0000)
- add unittest.php(unittest info)
- fixed check parameter of the return value of session_id in Ethna_Session

15 files changed:
class/Action/Ethna_Action_UnitTest.php [new file with mode: 0644]
class/Ethna_Controller.php
class/Ethna_Session.php
class/Ethna_SkeltonGenerator.php
class/Ethna_UnitTestCase.php [new file with mode: 0644]
class/Ethna_UnitTestManager.php [new file with mode: 0644]
class/Ethna_UnitTestReporter.php [new file with mode: 0644]
class/Handle/Ethna_Handle_AddActionTest.php [new file with mode: 0644]
class/Handle/Ethna_Handle_AddViewTest.php [new file with mode: 0644]
class/View/Ethna_View_UnitTest.php [new file with mode: 0644]
skel/app.unittest.php [new file with mode: 0644]
skel/skel.action_test.php [new file with mode: 0644]
skel/skel.view_test.php [new file with mode: 0644]
skel/www.unittest.php [new file with mode: 0644]
tpl/unittest.tpl [new file with mode: 0644]

diff --git a/class/Action/Ethna_Action_UnitTest.php b/class/Action/Ethna_Action_UnitTest.php
new file mode 100644 (file)
index 0000000..3879a94
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+/**
+ *  Ethna_Action_UnitTest.php
+ *
+ *  @author     Takuya Ookubo <sfio@sakura.ai.to>
+ *  @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
+ *  @package    Ethna
+ *  @version    $Id$
+ */
+
+/**
+ *  __ethna_unittest__¥Õ¥©¡¼¥à¤Î¼ÂÁõ
+ *
+ *  @author     Takuya Ookubo <sfio@sakura.ai.to>
+ *  @access     public
+ *  @package    Ethna
+ */
+class Ethna_Form_UnitTest extends Ethna_ActionForm
+{
+    /**
+     *  @access private
+     *  @var    array   ¥Õ¥©¡¼¥àÃÍÄêµÁ
+     */
+    var $form = array(
+    );
+}
+
+/**
+ *  __ethna_unittest__¥¢¥¯¥·¥ç¥ó¤Î¼ÂÁõ
+ *
+ *  @author     Takuya Ookubo <sfio@sakura.ai.to>
+ *  @access     public
+ *  @package    Ethna
+ */
+class Ethna_Action_UnitTest extends Ethna_ActionClass
+{
+    /**
+     *  __ethna_unittest__¥¢¥¯¥·¥ç¥ó¤ÎÁ°½èÍý
+     *
+     *  @access public
+     *  @return string      ForwardÀè(Àµ¾ï½ªÎ»¤Ê¤énull)
+     */
+    function prepare()
+    {
+        return null;
+    }
+
+    /**
+     *  __ethna_unittest__¥¢¥¯¥·¥ç¥ó¤Î¼ÂÁõ
+     *
+     *  @access public
+     *  @return string  Á«°Ü̾
+     */
+    function perform()
+    {
+        return '__ethna_unittest__';
+    }
+}
+?>
index f2b8f29..2ad49b8 100644 (file)
@@ -828,7 +828,8 @@ class Ethna_Controller
                $this->logger->log(LOG_DEBUG, 'form_action_name[%s]', $form_action_name);
 
                // Ethna¥Þ¥Í¡¼¥¸¥ã¤Ø¤Î¥Õ¥©¡¼¥à¤«¤é¤Î¥ê¥¯¥¨¥¹¥È¤ÏµñÈÝ
-               if ($form_action_name == "__ethna_info__") {
+               if ($form_action_name == "__ethna_info__" ||
+                       $form_action_name == "__ethna_unittest__") {
                        $form_action_name = "";
                }
 
@@ -1669,6 +1670,7 @@ class Ethna_Controller
                }
 
                include_once(ETHNA_BASE . '/class/Ethna_InfoManager.php');
+               include_once(ETHNA_BASE . '/class/Ethna_UnitTestManager.php');
 
                // actionÀßÄê
                $this->action['__ethna_info__'] = array(
@@ -1684,6 +1686,23 @@ class Ethna_Controller
                        'view_name'             => 'Ethna_View_Info',
                        'view_path'             => sprintf('%s/class/View/Ethna_View_Info.php', ETHNA_BASE),
                );
+        
+        
+               // actionÀßÄê
+               $this->action['__ethna_unittest__'] = array(
+                       'form_name' =>  'Ethna_Form_UnitTest',
+                       'form_path' =>  sprintf('%s/class/Action/Ethna_Action_UnitTest.php', ETHNA_BASE),
+                       'class_name' => 'Ethna_Action_UnitTest',
+                       'class_path' => sprintf('%s/class/Action/Ethna_Action_UnitTest.php', ETHNA_BASE),
+               );
+
+               // forwardÀßÄê
+               $this->forward['__ethna_unittest__'] = array(
+                       'forward_path'  => sprintf('%s/tpl/unittest.tpl', ETHNA_BASE),
+                       'view_name'             => 'Ethna_View_UnitTest',
+                       'view_path'             => sprintf('%s/class/View/Ethna_View_UnitTest.php', ETHNA_BASE),
+               );
+
        }
 
        /**
index 060a6aa..6816ef8 100644 (file)
@@ -82,7 +82,7 @@ class Ethna_Session
         */
        function restore()
        {
-               if (!empty($_COOKIE[$this->session_name]) || session_id() != null) {
+               if (!empty($_COOKIE[$this->session_name]) || session_id() != "") {
                        session_start();
                        $this->session_start = true;
 
index 7c957ff..d4457a3 100644 (file)
@@ -116,6 +116,10 @@ class Ethna_SkeltonGenerator
                        $this->_generateFile("skel.app_object.php", sprintf("$basedir/skel/skel.app_object.php"), $macro) == false ||
                        $this->_generateFile("skel.view.php", sprintf("$basedir/skel/skel.view.php"), $macro) == false ||
                        $this->_generateFile("skel.template.tpl", sprintf("$basedir/skel/skel.template.tpl"), $macro) == false ||
+                       $this->_generateFile("app.unittest.php", sprintf("$basedir/app/%s_UnitTestManager.php", $macro['project_id']), $macro) == false ||
+                       $this->_generateFile("www.unittest.php", "$basedir/www/unittest.php", $macro) == false ||
+                       $this->_generateFile("skel.action_test.php", sprintf("$basedir/skel/skel.action_test.php"), $macro) == false ||
+                       $this->_generateFile("skel.view_test.php", sprintf("$basedir/skel/skel.view_test.php"), $macro) == false ||
                        $this->_generateFile("template.index.tpl", sprintf("$basedir/template/ja/index.tpl"), $macro) == false) {
                        return Ethna::raiseError('generating files failed');
                }
@@ -295,6 +299,93 @@ class Ethna_SkeltonGenerator
        }
 
        /**
+        *      ¥¢¥¯¥·¥ç¥óÍѥƥ¹¥È¤Î¥¹¥±¥ë¥È¥ó¤òÀ¸À®¤¹¤ë
+        *
+        *      @access public
+        *      @param  string  $action_name    ¥¢¥¯¥·¥ç¥ó̾
+     *  @param  string  $app_dir        ¥×¥í¥¸¥§¥¯¥È¥Ç¥£¥ì¥¯¥È¥ê
+        *      @return bool    true:À®¸ù false:¼ºÇÔ
+        */
+       function generateActionTestSkelton($action_name, $app_dir)
+       {
+        // discover controller
+        $controller_class = $this->_discoverController($app_dir);
+        if (Ethna::isError($controller_class)) {
+            return $controller_class;
+        }
+
+        $c =& new $controller_class;
+        $c->setGateway(GATEWAY_CLI);
+
+               $action_dir = $c->getActiondir();
+               $action_class = $c->getDefaultActionClass($action_name, false);
+               $action_form = $c->getDefaultFormClass($action_name, false);
+               $action_path = $c->getDefaultActionPath($action_name . "Test", false);
+
+               $macro = array();
+               $macro['project_id'] = $c->getAppId();
+               $macro['action_name'] = $action_name;
+               $macro['action_class'] = $action_class;
+               $macro['action_form'] = $action_form;
+               $macro['action_path'] = $action_path;
+
+               $user_macro = $this->_getUserMacro();
+               $macro = array_merge($macro, $user_macro);
+
+               $this->_mkdir(dirname("$action_dir$action_path"), 0755);
+
+               if (file_exists("$action_dir$action_path")) {
+                       printf("file [%s] aleady exists -> skip\n", "$action_dir$action_path");
+               } else if ($this->_generateFile("skel.action_test.php", "$action_dir$action_path", $macro) == false) {
+                       printf("[warning] file creation failed [%s]\n", "$action_dir$action_path");
+               } else {
+                       printf("action test(s) successfully created [%s]\n", "$action_dir$action_path");
+               }
+       }
+
+       /**
+        *      ¥Ó¥å¡¼Íѥƥ¹¥È¤Î¥¹¥±¥ë¥È¥ó¤òÀ¸À®¤¹¤ë
+        *
+        *      @access public
+        *      @param  string  $forward_name   ¥¢¥¯¥·¥ç¥ó̾
+        *      @return bool    true:À®¸ù false:¼ºÇÔ
+        */
+       function generateViewTestSkelton($forward_name, $app_dir)
+       {
+        // discover controller
+        $controller_class = $this->_discoverController($app_dir);
+        if (Ethna::isError($controller_class)) {
+            return $controller_class;
+        }
+
+        $c =& new $controller_class;
+        $c->setGateway(GATEWAY_CLI);
+
+               $view_dir = $c->getViewdir();
+               $view_class = $c->getDefaultViewClass($forward_name, false);
+               $view_path = $c->getDefaultViewPath($forward_name . "Test", false);
+
+               $macro = array();
+               $macro['project_id'] = $c->getAppId();
+               $macro['forward_name'] = $forward_name;
+               $macro['view_class'] = $view_class;
+               $macro['view_path'] = $view_path;
+
+               $user_macro = $this->_getUserMacro();
+               $macro = array_merge($macro, $user_macro);
+
+               $this->_mkdir(dirname("$view_dir/$view_path"), 0755);
+
+               if (file_exists("$view_dir$view_path")) {
+                       printf("file [%s] aleady exists -> skip\n", "$view_dir$view_path");
+               } else if ($this->_generateFile("skel.view_test.php", "$view_dir$view_path", $macro) == false) {
+                       printf("[warning] file creation failed [%s]\n", "$view_dir$view_path");
+               } else {
+                       printf("view test(s) successfully created [%s]\n", "$view_dir$view_path");
+               }
+       }
+
+       /**
         *      mkdir -p
         *
         *      @access private
diff --git a/class/Ethna_UnitTestCase.php b/class/Ethna_UnitTestCase.php
new file mode 100644 (file)
index 0000000..78824a7
--- /dev/null
@@ -0,0 +1,155 @@
+<?php
+/**
+ *  Ethna_UnitTestCase.php
+ *
+ *  @author     Takuya Ookubo <sfio@sakura.ai.to>
+ *  @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
+ *  @package    Ethna
+ *  @version    $Id$
+ */
+
+/**
+ *  UnitTestCase¼Â¹Ô¥¯¥é¥¹
+ *
+ *  @author     Takuya Ookubo <sfio@sakura.ai.to>
+ *  @access     public
+ *  @package    Ethna
+ */
+class Ethna_UnitTestCase extends UnitTestCase
+{
+    /** @var    object  Ethna_Backend       backend¥ª¥Ö¥¸¥§¥¯¥È */
+    var $backend;
+
+    /** @var    object  Ethna_Controller    controller¥ª¥Ö¥¸¥§¥¯¥È */
+    var $controller;
+
+    /** @var    object  Ethna_Controller    controller¥ª¥Ö¥¸¥§¥¯¥È($controller¤Î¾Êά·Á) */
+    var $ctl;
+
+    /** @var    object  Ethna_Session       ¥»¥Ã¥·¥ç¥ó¥ª¥Ö¥¸¥§¥¯¥È */
+    var $session;
+
+    /** @var    string                      ¥¢¥¯¥·¥ç¥ó̾ */
+    var $action_name;
+
+    /** @var    object  Ethna_ActionForm    ¥¢¥¯¥·¥ç¥ó¥Õ¥©¡¼¥à¥ª¥Ö¥¸¥§¥¯¥È */
+    var $action_form;
+
+    /** @var    object  Ethna_ActionForm    ¥¢¥¯¥·¥ç¥ó¥Õ¥©¡¼¥à¥ª¥Ö¥¸¥§¥¯¥È($action_form¤Î¾Êά·Á) */
+    var $af;
+
+    /** @var    object  Ethna_ActionClass   ¥¢¥¯¥·¥ç¥ó¥¯¥é¥¹¥ª¥Ö¥¸¥§¥¯¥È */
+    var $action_class;
+
+    /** @var    object  Ethna_ActionClass   ¥¢¥¯¥·¥ç¥ó¥¯¥é¥¹¥ª¥Ö¥¸¥§¥¯¥È($action_class¤Î¾Êά·Á) */
+    var $ac;
+
+    /** @var    string                      ¥Ó¥å¡¼Ì¾ */
+    var $forward_name;
+
+    /** @var    object  Ethna_ViewClass     view¥¯¥é¥¹¥ª¥Ö¥¸¥§¥¯¥È */
+    var $view_class;
+
+    /** @var    object  Ethna_ViewClass     view¥¯¥é¥¹¥ª¥Ö¥¸¥§¥¯¥È($view_class¤Î¾Êά·Á) */
+    var $vc;
+
+    /**
+     *  Ethna_UnitTestCase¤Î¥³¥ó¥¹¥È¥é¥¯¥¿
+     *
+     *  @access public
+     *  @param  object  Ethna_Controller    &$controller    ¥³¥ó¥È¥í¡¼¥é¥ª¥Ö¥¸¥§¥¯¥È
+     */
+    function Ethna_UnitTestCase(&$controller)
+    {
+        parent::UnitTestCase();
+
+        // ¥ª¥Ö¥¸¥§¥¯¥È¤ÎÀßÄê
+        $this->controller =& $controller;
+        $this->ctl =& $this->controller;
+        $this->backend =& $this->ctl->getBackend();
+        $this->session =& $this->backend->getSession();
+
+        // ÊÑ¿ô¤Î½é´ü²½
+        $this->action_form = $this->af = null;
+        $this->action_class = $this->ac = null;
+        $this->view_class = $this->vc = null;
+    }
+
+    /**
+     *  ¥¢¥¯¥·¥ç¥ó¥Õ¥©¡¼¥à¤ÎºîÀ®¤È´ØÏ¢ÉÕ¤±
+     *
+     *  @access public
+     */
+    function _createActionForm($form_name)
+    {
+        $this->action_form =& new $form_name($this->ctl);
+        $this->af =& $this->action_form;
+
+        // controler&backend¤Ëaf¤ò´ØÏ¢ÉÕ¤±
+        $this->ctl->action_name = $this->action_name;
+        $this->ctl->action_form =& $this->af;
+        $this->backend->action_form =& $this->af;
+        $this->backend->af =& $this->af;
+    }
+
+    /**
+     *  ¥¢¥¯¥·¥ç¥ó¥Õ¥©¡¼¥à¤ÎºîÀ®
+     *
+     *  @access public
+     */
+    function createActionForm()
+    {
+        $form_name = $this->ctl->getActionFormName($this->action_name);
+        $this->_createActionForm($form_name);
+    }
+
+    /**
+     *  Ã±½ã¤Ê¥¢¥¯¥·¥ç¥ó¥Õ¥©¡¼¥à¤ÎºîÀ®
+     *
+     *  @access public
+     */
+    function createPlainActionForm()
+    {
+        $form_name = 'Ethna_ActionForm';
+        $this->_createActionForm($form_name);
+    }
+
+    /**
+     *  ¥¢¥¯¥·¥ç¥ó¤ÎºîÀ®
+     *
+     *  @access public
+     */
+    function createActionClass()
+    {
+        if ($this->af == null) {
+            $this->createActionForm();
+        }
+
+        // ¥ª¥Ö¥¸¥§¥¯¥ÈÀ¸À®
+        $action_class_name = $this->ctl->getActionClassName($this->action_name);
+        $this->action_class =& new $action_class_name($this->backend);
+        $this->ac =& $this->action_class;
+
+        // backend¤Ëac¤ò´ØÏ¢ÉÕ¤±
+        $this->backend->action_class =& $this->ac;
+        $this->backend->ac =& $this->ac;
+    }
+
+    /**
+     *  ¥Ó¥å¡¼¤ÎºîÀ®
+     *
+     *  @access public
+     */
+    function createViewClass()
+    {
+        if ($this->af == null) {
+            $this->createPlainActionForm();
+        }
+
+        // ¥ª¥Ö¥¸¥§¥¯¥ÈÀ¸À®
+        $view_class_name = $this->ctl->getViewClassName($this->forward_name);
+        $this->view_class =& new $view_class_name($this->backend, $this->forward_name, $this->ctl->_getForwardPath($this->forward_name));
+        $this->vc =& $this->view_class;
+    }
+}
+?>
diff --git a/class/Ethna_UnitTestManager.php b/class/Ethna_UnitTestManager.php
new file mode 100644 (file)
index 0000000..cf530b2
--- /dev/null
@@ -0,0 +1,155 @@
+<?php
+/**
+ *  Ethna_UnitTestManager.php
+ *
+ *  @author     Takuya Ookubo <sfio@sakura.ai.to>
+ *  @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
+ *  @package    Ethna
+ *  @version    $Id$
+ */
+
+require_once 'simpletest/unit_tester.php';
+require_once 'Ethna_UnitTestCase.php';
+require_once 'Ethna_UnitTestReporter.php';
+
+/**
+ *  Ethna¥æ¥Ë¥Ã¥È¥Æ¥¹¥È¥Þ¥Í¡¼¥¸¥ã¥¯¥é¥¹
+ *
+ *  @author     Takuya Ookubo <sfio@sakura.ai.to>
+ *  @access     public
+ *  @package    Ethna
+ */
+class Ethna_UnitTestManager extends Ethna_AppManager
+{
+    /** @var    object  Ethna_Controller    ¥³¥ó¥È¥í¡¼¥é¥ª¥Ö¥¸¥§¥¯¥È */
+    var $ctl;
+
+    /** @var    array                       °ìÈ̥ƥ¹¥È¥±¡¼¥¹ÄêµÁ */
+    var $testcase = array();
+
+    /**
+     *  Ethna_UnitTestManager¤Î¥³¥ó¥¹¥È¥é¥¯¥¿
+     *
+     *  @access public
+     *  @param  object  Ethna_Backend   &$backend   Ethna_Backend¥ª¥Ö¥¸¥§¥¯¥È
+     */
+    function Ethna_UnitTestManager(&$backend)
+    {
+        parent::Ethna_AppManager($backend);
+        $this->ctl =& Ethna_Controller::getInstance();
+        $this->class_factory =& $this->ctl->getClassFactory();
+    }
+
+    /**
+     *  ¥¢¥¯¥·¥ç¥ó¥Æ¥¹¥È¥¯¥é¥¹¤ò¼èÆÀ¤¹¤ë
+     *
+     *  @access private
+     *  @return array
+     */
+    function _getTestAction()
+    {
+        $em =& new Ethna_InfoManager($this->backend);
+        $action_class_list = array_keys($em->getActionList());
+
+        // ¥Æ¥¹¥È¤Î¸ºß¤¹¤ë¥¢¥¯¥·¥ç¥ó
+        $action_dir = $this->ctl->getActiondir();
+        foreach ($action_class_list as $key => $action_name) {
+            
+            $action_path = $this->ctl->getDefaultActionPath($action_name, false);
+            if (!file_exists("$action_dir$action_path")) {
+                unset($action_class_list[$key]);
+                continue;
+            }
+            @include_once "$action_dir$action_path";
+            $action_class = $this->ctl->getDefaultActionClass($action_name, false).'_TestCase';
+            if (!class_exists($action_class)) {
+                unset($action_class_list[$key]);
+            }
+        }
+
+        return $action_class_list;
+    }
+
+    /**
+     *  ¥Ó¥å¡¼¥Æ¥¹¥È¥¯¥é¥¹¤ò¼èÆÀ¤¹¤ë
+     *
+     *  @access private
+     *  @return array
+     */
+    function _getTestView()
+    {
+        $em =& new Ethna_InfoManager($this->backend);
+        $view_class_list = array_keys($em->getForwardList());
+
+        // ¥Æ¥¹¥È¤Î¸ºß¤¹¤ë¥Ó¥å¡¼
+        $view_dir = $this->ctl->getViewdir();
+        foreach ($view_class_list as $key => $view_name) {
+
+            $view_path = $this->ctl->getDefaultViewPath($view_name, false);
+            if (!file_exists("$view_dir$view_path")) {
+                unset($view_class_list[$key]);
+                continue;
+            }
+            @include_once "$view_dir$view_path";
+            $view_class = $this->ctl->getDefaultViewClass($view_name, false).'_TestCase';
+            if (!class_exists($view_class)) {
+                unset($view_class_list[$key]);
+            }
+        }
+
+        return $view_class_list;
+    }
+
+    /**
+     *  ¥æ¥Ë¥Ã¥È¥Æ¥¹¥È¤ò¼Â¹Ô¤¹¤ë
+     *
+     *  @access private
+     *  @return mixed   0:Àµ¾ï½ªÎ» Ethna_Error:¥¨¥é¡¼
+     */
+    function run()
+    {
+        $action_class_list = $this->_getTestAction();
+        $view_class_list = $this->_getTestView();
+        
+        $test =& new GroupTest("Ethna UnitTest");
+
+        // ¥¢¥¯¥·¥ç¥ó
+        foreach ($action_class_list as $action_name) {
+            $action_class = $this->ctl->getDefaultActionClass($action_name, false).'_TestCase';
+            $action_form = $this->ctl->getDefaultFormClass($action_name, false).'_TestCase';
+
+            $test->addTestCase(new $action_class($this->ctl));
+            $test->addTestCase(new $action_form($this->ctl));
+        }
+
+        // ¥Ó¥å¡¼
+        foreach ($view_class_list as $view_name) {
+            $view_class = $this->ctl->getDefaultViewClass($view_name, false).'_TestCase';
+
+            $test->addTestCase(new $view_class($this->ctl));
+        }
+
+        // °ìÈÌ
+        foreach ($this->testcase as $class_name => $file_name) {
+            $dir = $this->ctl->getBasedir().'/';
+            require_once "$dir$file_name";
+            $testcase_name = $class_name.'_TestCase';
+            $test->addTestCase(new $testcase_name($this->ctl));
+        }
+
+        // ActionForm¤Î¥Ð¥Ã¥¯¥¢¥Ã¥×
+        $af =& $this->ctl->getActionForm();
+        
+        //½ÐÎϤ·¤¿¤¤·Á¼°¤Ë¤¢¤ï¤»¤ÆÀÚ¤êÂؤ¨¤ë
+        $reporter = new Ethna_UnitTestReporter();
+        $test->run($reporter);
+
+        // ActionForm¤Î¥ê¥¹¥È¥¢
+        $this->ctl->action_form =& $af;
+        $this->backend->action_form =& $af;
+        $this->backend->af =& $af;
+
+        return array($reporter->report, $reporter->result);
+    }
+}
+?>
diff --git a/class/Ethna_UnitTestReporter.php b/class/Ethna_UnitTestReporter.php
new file mode 100644 (file)
index 0000000..9943727
--- /dev/null
@@ -0,0 +1,167 @@
+<?php
+/**
+ *  Ethna_UnitTestReporter.php
+ *
+ *  @author     Takuya Ookubo <sfio@sakura.ai.to>
+ *  @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
+ *  @package    Ethna
+ *  @version    $Id$
+ */
+
+require_once ('simpletest/scorer.php');
+
+/**
+ *  Ethna¥Þ¥Í¡¼¥¸¥ã¥¯¥é¥¹
+ *
+ *  @author     Takuya Ookubo <sfio@sakura.ai.to>
+ *  @access     public
+ *  @package    Ethna
+ */
+class Ethna_UnitTestReporter extends SimpleReporter {
+    
+    var $_character_set;
+
+    var $report;
+    var $result;
+
+    /**
+     *  Ethna_UnitTestReporter¤Î¥³¥ó¥¹¥È¥é¥¯¥¿
+     *
+     *  @access public
+     *  @param  string  $character_set  ¥­¥ã¥é¥¯¥¿¥»¥Ã¥È
+     */
+    function Ethna_UnitTestReporter($character_set = 'EUC-JP') {
+        $this->SimpleReporter();
+        $this->_character_set = $character_set;
+        $this->report= array();
+        $this->result= array();
+    }
+
+    /**
+     *  ·ë²Ì
+     *
+     *  @access public
+     *  @param string   $test_name  ¥Æ¥¹¥È̾¾Î
+     */
+    function paintFooter($test_name) {
+        $colour = ($this->getFailCount() + $this->getExceptionCount() > 0 ? "red" : "green");
+        $this->result = array(
+            'TestCaseProgress' => $this->getTestCaseProgress(),
+            'TestCaseCount' => $this->getTestCaseCount(),
+            'PassCount' => $this->getPassCount(),
+            'FailCount' => $this->getFailCount(),
+            'ExceptionCount' => $this->getExceptionCount(),
+        );
+    }
+
+    /**
+     *  ¥Ñ¥¹
+     *
+     *  @access public
+     *¡¡@param string   $message    ¥á¥Ã¥»¡¼¥¸
+     */
+    function paintPass($message)
+    {
+        parent::paintPass($message);
+            
+        $test_list = $this->getTestList();
+        $this->report[] = array(
+            'type' => 'Pass',
+            'test' => $test_list[2],
+            'message' => $message,
+        );
+    }
+
+    /**
+     *  ¼ºÇÔ
+     *
+     *  @access public
+     *¡¡@param string   $message    ¥á¥Ã¥»¡¼¥¸
+     */
+    function paintFail($message) {
+        parent::paintFail($message);
+
+        $test_list = $this->getTestList();
+        $this->report[] = array(
+            'type' => 'Fail',
+            'test' => $test_list[2],
+            'message' => $message,
+        );
+    }
+
+    /**
+     *  Îã³°
+     *
+     *  @access public
+     *¡¡@param string   $message    ¥á¥Ã¥»¡¼¥¸
+     */
+    function paintException($message) {
+        parent::paintException($message);
+
+        $breadcrumb = $this->getTestList();
+        $test = $breadcrumb[2];
+        array_shift($breadcrumb);
+        $this->report[] = array(
+            'type' => 'Exception',
+            'test' => $test,
+            'breadcrumb' => $breadcrumb,
+            'message' => $message,
+        );
+    }
+
+    /**
+     *  ¥Æ¥¹¥È¥±¡¼¥¹³«»Ï
+     *
+     *  @access public
+     *  @param string   $test_name  ¥Æ¥¹¥È̾¾Î
+     */
+    function paintCaseStart($test_name)
+    {
+        parent::paintCaseStart($test_name);
+
+        $this->report[] = array(
+            'type' => 'CaseStart',
+            'test_name' => $test_name,
+        );
+    }
+
+    /**
+     *  ¥Æ¥¹¥È¥±¡¼¥¹½ªÎ»
+     *
+     *  @access public
+     *  @param string   $test_name  ¥Æ¥¹¥È̾¾Î
+     */
+    function paintCaseEnd($test_name)
+    {
+        parent::paintCaseEnd($test_name);
+
+        $this->report[] = array(
+            'type' => 'CaseEnd',
+        );
+    }
+
+    /**
+     *  ¥Õ¥©¡¼¥Þ¥Ã¥ÈºÑ¤ß¥á¥Ã¥»¡¼¥¸
+     *
+     *  @access public
+     *¡¡@param string   $message    ¥á¥Ã¥»¡¼¥¸
+     */
+    function paintFormattedMessage($message) {
+        $this->report[] = array(
+            'type' => 'FormattedMessage',
+            'message' => $this->_htmlEntities($message),
+        );
+    }
+
+    /**
+     *  HTML¥¨¥ó¥Æ¥£¥Æ¥£ÊÑ´¹
+     *
+     *¡¡@access protected
+     *¡¡@param string   $message    ¥×¥ì¡¼¥ó¥Æ¥­¥¹¥È
+     *¡¡@return string              HTML¥¨¥ó¥Æ¥£¥Æ¥£ÊÑ´¹ºÑ¤ß¥á¥Ã¥»¡¼¥¸
+     */
+    function _htmlEntities($message) {
+        return htmlentities($message, ENT_COMPAT, $this->_character_set);
+    }
+}
+?>
diff --git a/class/Handle/Ethna_Handle_AddActionTest.php b/class/Handle/Ethna_Handle_AddActionTest.php
new file mode 100644 (file)
index 0000000..ca33244
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+/**
+ *  Ethna_Handle_AddActionTest.php
+ *
+ *  @author     halt feits <halt.feits@gmail.com>
+ *  @package    Ethna
+ *  @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
+ *  @version    $Id$
+ */
+
+/**
+ *  add-action-test handler
+ *
+ *  @author     halt feits <halt.feits@gmail.com>
+ *  @access     public
+ *  @package    Ethna
+ */
+class Ethna_Handle_AddActionTest extends Ethna_Handle
+{
+    
+    /**
+     *  get handler's description
+     *
+     *  @access public
+     */
+    function getDescription()
+    {
+        return "add new action test to project:\n    {$this->id} [action] ([project-base-dir])\n";
+    }
+
+    /**
+     *  add action test
+     *
+     *  @access public
+     */
+    function perform()
+    {
+        $r = $this->_validateArgList();
+        if (Ethna::isError($r)) {
+            return $r;
+        }
+        list($action_name, $app_dir) = $r;
+
+        $sg =& new Ethna_SkeltonGenerator();
+        $r = $sg->generateActionTestSkelton($action_name, $app_dir);
+        if (Ethna::isError($r)) {
+            printf("error occurred while generating skelton. please see also following error message(s)\n\n");
+            return $r;
+        }
+
+        return true;
+    }
+
+    /**
+     *  show usage
+     *
+     *  @access public
+     */
+    function usage()
+    {
+        printf("usage:\nethna %s [action] ([project-base-dir])\n\n", $this->id);
+    }
+
+    /**
+     *  check arguments
+     *
+     *  @access private
+     */
+    function _validateArgList()
+    {
+        $arg_list = array();
+        if (count($this->arg_list) < 1) {
+            return Ethna::raiseError('too few argments', 'usage');
+        } else if (count($this->arg_list) > 2) {
+            return Ethna::raiseError('too many argments', 'usage');
+        } else if (count($this->arg_list) == 1) {
+            $arg_list[] = $this->arg_list[0];
+            $arg_list[] = getcwd();
+        } else {
+            $arg_list = $this->arg_list;
+        }
+
+        // TODO: check action name(?) - how it would be easy and pluggable
+        if (is_dir($arg_list[1]) == false) {
+            return Ethna::raiseError("no such directory [{$arg_list[1]}]");
+        }
+
+        return $arg_list;
+    }
+    
+}
+?>
diff --git a/class/Handle/Ethna_Handle_AddViewTest.php b/class/Handle/Ethna_Handle_AddViewTest.php
new file mode 100644 (file)
index 0000000..2c0c646
--- /dev/null
@@ -0,0 +1,93 @@
+<?php
+/**
+ *  Ethna_Handle_AddViewTest.php
+ *
+ *  @author     halt feits <halt.feits@gmail.com>
+ *  @package    Ethna
+ *  @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
+ *  @version    $Id$
+ */
+
+/**
+ *  add-view-test handler
+ *
+ *  @author     halt feits <halt.feits@gmail.com>
+ *  @access     public
+ *  @package    Ethna
+ */
+class Ethna_Handle_AddViewTest extends Ethna_Handle
+{
+    
+    /**
+     *  get handler's description
+     *
+     *  @access public
+     */
+    function getDescription()
+    {
+        return "add new view test to project:\n    {$this->id} [view] ([project-base-dir])\n";
+    }
+
+    /**
+     *  add view test
+     *
+     *  @access public
+     */
+    function perform()
+    {
+        $r = $this->_validateArgList();
+        if (Ethna::isError($r)) {
+            return $r;
+        }
+        list($view_name, $app_dir) = $r;
+
+        $sg =& new Ethna_SkeltonGenerator();
+        $r = $sg->generateViewTestSkelton($view_name, $app_dir);
+        if (Ethna::isError($r)) {
+            printf("error occurred while generating skelton. please see also following error message(s)\n\n");
+            return $r;
+        }
+
+        return true;
+    }
+
+    /**
+     *  show usage
+     *
+     *  @access public
+     */
+    function usage()
+    {
+        printf("usage:\nethna %s [view] ([project-base-dir])\n\n", $this->id);
+    }
+
+    /**
+     *  check arguments
+     *
+     *  @access private
+     */
+    function _validateArgList()
+    {
+        $arg_list = array();
+        if (count($this->arg_list) < 1) {
+            return Ethna::raiseError('too few argments', 'usage');
+        } else if (count($this->arg_list) > 2) {
+            return Ethna::raiseError('too many argments', 'usage');
+        } else if (count($this->arg_list) == 1) {
+            $arg_list[] = $this->arg_list[0];
+            $arg_list[] = getcwd();
+        } else {
+            $arg_list = $this->arg_list;
+        }
+
+        // TODO: check view name(?) - how it would be easy and pluggable
+        if (is_dir($arg_list[1]) == false) {
+            return Ethna::raiseError("no such directory [{$arg_list[1]}]");
+        }
+
+        return $arg_list;
+    }
+    
+}
+
+?>
diff --git a/class/View/Ethna_View_UnitTest.php b/class/View/Ethna_View_UnitTest.php
new file mode 100644 (file)
index 0000000..370e60d
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+/**
+ *  Ethna_View_UnitTest.php
+ *
+ *  @author     Takuya Ookubo <sfio@sakura.ai.to>
+ *  @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
+ *  @package    Ethna
+ *  @version    $Id$
+ */
+
+/**
+ *  __ethna_unittest__¥Ó¥å¡¼¤Î¼ÂÁõ
+ *
+ *  @author     Takuya Ookubo <sfio@sakura.ai.to>
+ *  @access     public
+ *  @package    Ethna
+ */
+class Ethna_View_UnitTest extends Ethna_ViewClass
+{
+    /**
+     *  Á«°ÜÁ°½èÍý
+     *
+     *  @access public
+     */
+    function preforward()
+    {
+        // ¥¿¥¤¥à¥¢¥¦¥È¤·¤Ê¤¤¤è¤¦¤ËÊѹ¹
+        $max_execution_time = ini_get('max_execution_time');
+        set_time_limit(0);
+
+        if (!headers_sent()) {
+            // ¥­¥ã¥Ã¥·¥å¤·¤Ê¤¤
+            header("Expires: Thu, 01 Jan 1970 00:00:00 GMT");
+            header("Last-Modified: " . gmdate("D, d M Y H:i:s \G\M\T"));
+            header("Cache-Control: no-store, no-cache, must-revalidate");
+            header("Cache-Control: post-check=0, pre-check=0", false);
+            header("Pragma: no-cache");
+        }
+
+        $ctl =& Ethna_Controller::getInstance();
+
+        // cores
+        $this->af->setApp('app_id', $ctl->getAppId());
+        $this->af->setApp('ethna_version', ETHNA_VERSION);
+
+        // unittest
+        $r = sprintf("%s_UnitTestManager", $ctl->getAppId());
+        $ut =& new $r($this->backend);
+        list($report, $result) = $ut->run();
+        $this->af->setApp('report', $report);
+        $this->af->setApp('result', $result);
+
+        // ¥¿¥¤¥à¥¢¥¦¥È¤ò¸µ¤ËÌ᤹
+        set_time_limit($max_execution_time);
+    }
+}
+?>
diff --git a/skel/app.unittest.php b/skel/app.unittest.php
new file mode 100644 (file)
index 0000000..1357b9a
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+/**
+ *     {$project_id}_UnitTestManager.php
+ *
+ *     @author         your name
+ *     @package        {$project_id}
+ *     @version        $Id$
+ */
+
+/**
+ *     {$project_id}¥æ¥Ë¥Ã¥È¥Æ¥¹¥È¥Þ¥Í¡¼¥¸¥ã¥¯¥é¥¹
+ *
+ *     @author         your name
+ *     @access         public
+ *     @package        {$project_id}
+ */
+class {$project_id}_UnitTestManager extends Ethna_UnitTestManager
+{
+       /**
+        *      @var    array   °ìÈ̥ƥ¹¥È¥±¡¼¥¹ÄêµÁ
+        */
+       var $testcase = array(
+               /*
+                *      TODO: ¤³¤³¤Ë°ìÈ̥ƥ¹¥È¥±¡¼¥¹ÄêµÁ¤òµ­½Ò¤·¤Æ¤¯¤À¤µ¤¤
+                *
+                *      µ­½ÒÎ㡧
+                *
+                *      'util' => 'app/UtilTest.php',
+                */
+       );
+}
+?>
diff --git a/skel/skel.action_test.php b/skel/skel.action_test.php
new file mode 100644 (file)
index 0000000..11b6093
--- /dev/null
@@ -0,0 +1,124 @@
+<?php
+/**
+ *  {$action_path}
+ *
+ *  @author     your name
+ *  @package    {$project_id}
+ *  @version    $Id$
+ */
+
+/**
+ *  {$action_name}¥Õ¥©¡¼¥à¤Î¥Æ¥¹¥È¥±¡¼¥¹
+ *
+ *  @author     your name
+ *  @access     public
+ *  @package    {$project_id}
+ */
+class {$action_form}_TestCase extends Ethna_UnitTestCase
+{
+    /**
+     *  @access private
+     *  @var    string  ¥¢¥¯¥·¥ç¥ó̾
+     */
+    var $action_name = '{$action_name}';
+
+    /**
+     *    ¥Æ¥¹¥È¤Î½é´ü²½
+     *
+     *    @access public
+     */
+    function setUp()
+    {
+        $this->createActionForm();  // ¥¢¥¯¥·¥ç¥ó¥Õ¥©¡¼¥à¤ÎºîÀ®
+    }
+
+    /**
+     *    ¥Æ¥¹¥È¤Î¸å»ÏËö
+     *
+     *    @access public
+     */
+    function tearDown()
+    {
+    }
+
+    /**
+     *  {$action_name}¥¢¥¯¥·¥ç¥ó¥Õ¥©¡¼¥à¤Î¥µ¥ó¥×¥ë¥Æ¥¹¥È¥±¡¼¥¹
+     *
+     *  @access public
+     */
+    /*
+    function test_formSample()
+    {
+        // ¥Õ¥©¡¼¥à¤ÎÀßÄê
+        $this->af->set('id', 1);
+
+        // {$action_name}¥¢¥¯¥·¥ç¥ó¥Õ¥©¡¼¥àÃ͸¡¾Ú
+        $this->assertEqual($this->af->validate(), 0);
+    }
+    */
+}
+
+/**
+ *  {$action_name}¥¢¥¯¥·¥ç¥ó¤Î¥Æ¥¹¥È¥±¡¼¥¹
+ *
+ *  @author     your name
+ *  @access     public
+ *  @package    {$project_id}
+ */
+class {$action_class}_TestCase extends Ethna_UnitTestCase
+{
+    /**
+     *  @access private
+     *  @var    string  ¥¢¥¯¥·¥ç¥ó̾
+     */
+    var $action_name = '{$action_name}';
+
+    /**
+     *    ¥Æ¥¹¥È¤Î½é´ü²½
+     *
+     *    @access public
+     */
+    function setUp()
+    {
+        $this->createActionForm();  // ¥¢¥¯¥·¥ç¥ó¥Õ¥©¡¼¥à¤ÎºîÀ®
+        $this->createActionClass(); // ¥¢¥¯¥·¥ç¥ó¥¯¥é¥¹¤ÎºîÀ®
+
+        $this->session->start();            // ¥»¥Ã¥·¥ç¥ó¤Î³«»Ï
+    }
+
+    /**
+     *    ¥Æ¥¹¥È¤Î¸å»ÏËö
+     *
+     *    @access public
+     */
+    function tearDown()
+    {
+        $this->session->destroy();      // ¥»¥Ã¥·¥ç¥ó¤ÎÇË´þ
+    }
+
+    /**
+     *  {$action_name}¥¢¥¯¥·¥ç¥ó¥¯¥é¥¹¤Î¥µ¥ó¥×¥ë¥Æ¥¹¥È¥±¡¼¥¹
+     *
+     *  @access public
+     */
+    /*
+    function test_actionSample()
+    {
+        // ¥Õ¥©¡¼¥à¤ÎÀßÄê
+        $this->af->set('id', 1);
+
+        // {$action_name}¥¢¥¯¥·¥ç¥ó¼Â¹ÔÁ°¤Îǧ¾Ú½èÍý
+        $forward_name = $this->ac->authenticate();
+        $this->assertNull($forward_name);
+
+        // {$action_name}¥¢¥¯¥·¥ç¥ó¤ÎÁ°½èÍý
+        $forward_name = $this->ac->prepare();
+        $this->assertNull($forward_name);
+
+        // {$action_name}¥¢¥¯¥·¥ç¥ó¤Î¼ÂÁõ
+        $forward_name = $this->ac->perform();
+        $this->assertEqual($forward_name, '{$action_name}');
+    }
+    */
+}
+?>
diff --git a/skel/skel.view_test.php b/skel/skel.view_test.php
new file mode 100644 (file)
index 0000000..e700c38
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+/**
+ *  {$view_path}
+ *
+ *  @author     your name
+ *  @package    {$project_id}
+ *  @version    $Id$
+ */
+
+/**
+ *  {$forward_name}¥Ó¥å¡¼¤Î¼ÂÁõ
+ *
+ *  @author     your name
+ *  @access     public
+ *  @package    {$project_id}
+ */
+class {$view_class}_TestCase extends Ethna_UnitTestCase
+{
+    /**
+     *  @access private
+     *  @var    string  ¥Ó¥å¡¼Ì¾
+     */
+    var $forward_name = '{$forward_name}';
+
+    /**
+     *    ¥Æ¥¹¥È¤Î½é´ü²½
+     *
+     *    @access public
+     */
+    function setUp()
+    {
+        $this->createPlainActionForm(); // ¥¢¥¯¥·¥ç¥ó¥Õ¥©¡¼¥à¤ÎºîÀ®
+        $this->createViewClass();       // ¥Ó¥å¡¼¤ÎºîÀ®
+    }
+
+    /**
+     *    ¥Æ¥¹¥È¤Î¸å»ÏËö
+     *
+     *    @access public
+     */
+    function tearDown()
+    {
+    }
+
+    /**
+     *  {$forward_name}Á«°ÜÁ°½èÍý¤Î¥µ¥ó¥×¥ë¥Æ¥¹¥È¥±¡¼¥¹
+     *
+     *  @access public
+     */
+    /*
+    function test_viewSample()
+    {
+        // ¥Õ¥©¡¼¥à¤ÎÀßÄê
+        $this->af->set('id', 1);
+
+        // {$forward_name}Á«°ÜÁ°½èÍý
+        $this->vc->preforward();
+        $this->assertNull($this->af->get('data'));
+    }
+    */
+}
+?>
diff --git a/skel/www.unittest.php b/skel/www.unittest.php
new file mode 100644 (file)
index 0000000..79b2985
--- /dev/null
@@ -0,0 +1,9 @@
+<?php
+error_reporting(E_ALL);
+include_once(dirname(__FILE__) . '/../app/{$project_id}_Controller.php');
+
+{$project_id}_Controller::main('{$project_id}_Controller', array(
+    '__ethna_unittest__',
+    )
+);
+?>
diff --git a/tpl/unittest.tpl b/tpl/unittest.tpl
new file mode 100644 (file)
index 0000000..aeb3b3e
--- /dev/null
@@ -0,0 +1,93 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html lang="ja">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=EUC-JP">
+  <meta http-equiv="Content-Style-Type" content="text/css">
+    <title>{$app.app_id} - Ethna UnitTest</title>
+    <style type="text/css">
+        <!--
+        {literal}
+            body {
+                margin: auto;
+                background-color: #ffffff;
+                color: #000000;
+            }
+            body, td, th, h1, h2 {font-family: sans-serif;}
+            pre {margin: 0px; font-family: monospace;}
+            a:link {color: #000099; text-decoration: none; background-color: #ffffff;}
+            a:hover {text-decoration: underline;}
+            table { margin: auto; border-collapse: collapse;}
+            .center {text-align: center;}
+            .center table { text-align: left;}
+            .center th { text-align: center !important; }
+            td, th { border: 1px solid #000000; font-size: 75%; vertical-align: top;}
+            h1 {font-size: 150%;}
+            h2 {font-size: 125%;}
+            .p {text-align: left;}
+            .e {background-color: #ccccff; font-weight: bold; color: #000000;}
+            .h {background-color: #9999cc; font-weight: bold; color: #000000;}
+            .v {background-color: #cccccc; color: #000000;}
+            .vf {background-color: #cccccc; color: red;}
+            i {color: #666666; background-color: #cccccc;}
+            img {float: right; border: 0px;}
+            hr {width: 600px; background-color: #cccccc; border: 0px; height: 1px; color: #000000;}
+            .header {
+                margin: auto;
+                width:600px;
+                background-color: #9999cc;
+                padding:0.2em;
+                border:solid 1px black;
+            }
+        {/literal}
+        //-->
+        </style>
+</head>
+  <body>
+    <div class="center">
+      <div class="header"><h1>{$app.app_id}</h1></div>
+      <h2>Report</h2>
+      <table border="0" cellpadding="2" width="600">
+      {foreach from=$app.report key="key" item="item"}
+        {if $item.type=='Pass'}
+          <tr>
+            <th class="e">{$item.test}</th>
+            <td class="v">{$item.message}</td>
+          </tr>
+        {elseif $item.type=='CaseEnd'}
+        {elseif $item.type=='CaseStart'}
+          <tr class="h">
+            <th colspan="2">{$item.test_name}</th>
+          </tr>
+        {elseif $item.type=='Exception'}
+          <tr>
+            <th class="e">{$item.test}</th>
+            <td class="vf">Exception 
+              <ul>{foreach from=$item.breadcrumb item="crumb"}<li>{$crumb}</li>{/foreach}</ul><strong>{$message|escape:"html"}</strong><br />
+            </td>
+          </tr>
+        {elseif $item.type=='Fail'}
+          <tr>
+            <th class="e">{$item.test}</th>
+            <td class="vf"><strong>Fail</strong> {$item.message}</td>
+          </tr>
+        {else}
+          <tr class="v">
+            <td colspan="2">{$item.message}</td>
+          </tr>
+        {/if} 
+      {/foreach}
+      </table>
+      <h2>Result</h2>
+      <p>
+        {$app.result.TestCaseProgress}/{$app.result.TestCaseCount} test cases complete:
+        <strong>{$app.result.PassCount}</strong> passes, 
+        <strong>{$app.result.FailCount}</strong> fails and 
+        <strong>{$app.result.ExceptionCount}</strong> exceptions.
+      </p>
+      <br />
+      <hr />
+      powered by <a href="http://ethna.jp/">Ethna {$app.ethna_version}</a> (experimental)
+      <hr />
+    </div>
+  </body>
+</html>