OSDN Git Service

4a7cf29bf57671b7cc57432c99042ed518c0c783
[ethna/ethna.git] / class / Ethna_UnitTestManager.php
1 <?php
2 /**
3  *  Ethna_UnitTestManager.php
4  *
5  *  @author     Takuya Ookubo <sfio@sakura.ai.to>
6  *  @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
7  *  @package    Ethna
8  *  @version    $Id$
9  */
10
11 require_once('simpletest/unit_tester.php');
12 require_once('Ethna_UnitTestCase.php');
13 require_once('Ethna_UnitTestReporter.php');
14
15 /**
16  *  Ethnaユニットテストマネージャクラス
17  *
18  *  @author     Takuya Ookubo <sfio@sakura.ai.to>
19  *  @access     public
20  *  @package    Ethna
21  */
22 class Ethna_UnitTestManager extends Ethna_AppManager
23 {
24     /** @var    object  Ethna_Controller    コントローラオブジェクト */
25     var $ctl;
26
27     /** @var    array                       一般テストケース定義 */
28     var $testcase = array();
29
30     /**
31      *  Ethna_UnitTestManagerのコンストラクタ
32      *
33      *  @access public
34      *  @param  object  Ethna_Backend   &$backend   Ethna_Backendオブジェクト
35      */
36     function Ethna_UnitTestManager(&$backend)
37     {
38         parent::Ethna_AppManager($backend);
39         $this->ctl =& Ethna_Controller::getInstance();
40         $this->class_factory =& $this->ctl->getClassFactory();
41     }
42
43     /**
44      *  定義済みアクション一覧を取得する
45      *
46      *  @access public
47      *  @return array   アクション一覧
48      */
49     function _getActionList()
50     {
51         $im =& new Ethna_InfoManager($this->backend);
52         return $im->getActionList();
53     }
54
55     /**
56      *  クラス名からビュー名を取得する
57      *
58      *  @access public
59      *  @param  string  $class_name     ビュークラス名
60      *  @return string  アクション名
61      */
62     function viewClassToName($class_name)
63     {
64         $prefix = sprintf("%s_View_", $this->ctl->getAppId());
65         if (preg_match("/$prefix(.*)/", $class_name, $match) == 0) {
66             // 不明なクラス名
67             return null;
68         }
69         $target = $match[1];
70
71         $action_name = substr(preg_replace('/([A-Z])/e', "'_' . strtolower('\$1')", $target), 1);
72
73         return $action_name;
74     }
75
76     /**
77      *  指定されたクラス名を継承しているかどうかを返す
78      *
79      *  @access private
80      *  @param  string  $class_name     チェック対象のクラス名
81      *  @param  string  $parent_name    親クラス名
82      *  @return bool    true:継承している false:いない
83      */
84     function _isSubclassOf($class_name, $parent_name)
85     {
86         while ($tmp = get_parent_class($class_name)) {
87             if (strcasecmp($tmp, $parent_name) == 0) {
88                 return true;
89             }
90             $class_name = $tmp;
91         }
92         return false;
93     }
94
95     /**
96      *  ビュースクリプトを解析する
97      *
98      *  @access private
99      *  @param  string  $script ファイル名
100      *  @return array   ビュークラス定義一覧
101      */
102     function __analyzeViewScript($script)
103     {
104         $class_list = array();
105
106         $source = "";
107         $fp = fopen($script, 'r');
108         if ($fp == false) {
109             return null;
110         }
111         while (feof($fp) == false) {
112             $source .= fgets($fp, 8192);
113         }
114         fclose($fp);
115
116         // トークンに分割してクラス定義情報を取得
117         $token_list = token_get_all($source);
118         for ($i = 0; $i < count($token_list); $i++) {
119             $token = $token_list[$i];
120
121             if ($token[0] == T_CLASS) {
122                 // クラス定義開始
123                 $i += 2;
124                 $class_name = $token_list[$i][1];       // should be T_STRING
125                 if ($this->_isSubclassOf($class_name, 'Ethna_ViewClass')) {
126                     $view_name = $this->viewClassToName($class_name);
127                     $class_list[$view_name] = array(
128                         'template_file' => $this->ctl->_getForwardPath($view_name),
129                         'view_class' => $class_name,
130                         'view_class_file' => $this->ctl->getDefaultViewPath($view_name),
131                     );
132                 }
133             }
134         }
135
136         if (count($class_list) == 0) {
137             return null;
138         }
139         return $class_list;
140     }
141
142     /**
143      *  ディレクトリ以下のビュースクリプトを解析する
144      *
145      *  @access private
146      *  @param  string  $action_dir     解析対象のディレクトリ
147      *  @return array   ビュークラス定義一覧
148      */
149     function __analyzeViewList($view_dir = null)
150     {
151         $r = array();
152
153         if (is_null($view_dir)) {
154             $view_dir = $this->ctl->getViewdir();
155         }
156         $prefix_len = strlen($this->ctl->getViewdir());
157
158         $ext = '.' . $this->ctl->getExt('php');
159         $ext_len = strlen($ext);
160
161         $dh = opendir($view_dir);
162         if ($dh) {
163             while (($file = readdir($dh)) !== false) {
164                 $path = "$view_dir/$file";
165                 if ($file != '.' && $file != '..' && is_dir($path)) {
166                     $tmp = $this->__analyzeViewList($path);
167                     $r = array_merge($r, $tmp);
168                     continue;
169                 }
170                 if (substr($file, -$ext_len, $ext_len) != $ext) {
171                     continue;
172                 }
173
174                 include_once($path);
175                 $class_list = $this->__analyzeViewScript($path);
176                 if (is_null($class_list) == false) {
177                     $r = array_merge($r, $class_list);
178                 }
179             }
180         }
181         closedir($dh);
182
183         return $r;
184     }
185
186     /**
187      *  定義済みビュー一覧を取得する
188      *
189      *  @access public
190      *  @return array   ビュー一覧
191      */
192     function _getViewList()
193     {
194         $im =& new Ethna_InfoManager($this->backend);
195 //        $view_class_list = array_keys($im->getForwardList());
196
197         $r = array();
198
199         // テンプレート/ビュースクリプトを解析する
200         $forward_list = $im->_analyzeForwardList();
201         $view_list = $this->__analyzeViewList();
202
203         // ビュー定義エントリ一覧
204         $manifest_forward_list = $im->_getForwardList_Manifest($forward_list);
205
206         // ビュー定義省略エントリ一覧
207         $implicit_forward_list = $im->_getForwardList_Implicit($forward_list, $manifest_forward_list);
208
209         $r = array_merge($view_list, $manifest_forward_list, $implicit_forward_list);
210         ksort($r);
211
212         return $r;
213     }
214
215     /**
216      *  アクションテストクラスを取得する
217      *
218      *  @access private
219      *  @return array
220      */
221     function _getTestAction()
222     {
223         $action_class_list = array_keys($this->_getActionList());
224
225         // テストの存在するアクション
226         foreach ($action_class_list as $key => $action_name) {
227             $action_class = $this->ctl->getDefaultActionClass($action_name, false).'_TestCase';
228             if (!class_exists($action_class)) {
229                 unset($action_class_list[$key]);
230             }
231         }
232
233         return $action_class_list;
234     }
235
236     /**
237      *  ビューテストクラスを取得する
238      *
239      *  @access private
240      *  @return array
241      */
242     function _getTestView()
243     {
244         $view_class_list = array_keys($this->_getViewList());
245
246         // テストの存在するビュー
247         foreach ($view_class_list as $key => $view_name) {
248             $view_class = $this->ctl->getDefaultViewClass($view_name, false).'_TestCase';
249             if (!class_exists($view_class)) {
250                 unset($view_class_list[$key]);
251             }
252         }
253
254         return $view_class_list;
255     }
256
257     /**
258      *  ユニットテストを実行する
259      *
260      *  @access private
261      *  @return mixed   0:正常終了 Ethna_Error:エラー
262      */
263     function run()
264     {
265         $action_class_list = $this->_getTestAction();
266         $view_class_list = $this->_getTestView();
267
268         $test =& new GroupTest("Ethna UnitTest");
269
270         // アクション
271         foreach ($action_class_list as $action_name) {
272             $action_class = $this->ctl->getDefaultActionClass($action_name, false).'_TestCase';
273             $action_form = $this->ctl->getDefaultFormClass($action_name, false).'_TestCase';
274
275             $test->addTestCase(new $action_class($this->ctl));
276             $test->addTestCase(new $action_form($this->ctl));
277         }
278
279         // ビュー
280         foreach ($view_class_list as $view_name) {
281             $view_class = $this->ctl->getDefaultViewClass($view_name, false).'_TestCase';
282
283             $test->addTestCase(new $view_class($this->ctl));
284         }
285
286         // 一般
287         foreach ($this->testcase as $class_name => $file_name) {
288             $dir = $this->ctl->getBasedir().'/';
289             include_once $dir . $file_name;
290             $testcase_name = $class_name.'_TestCase';
291             $test->addTestCase(new $testcase_name($this->ctl));
292         }
293
294         // ActionFormのバックアップ
295         $af =& $this->ctl->getActionForm();
296
297         //出力したい形式にあわせて切り替える
298         $reporter = new Ethna_UnitTestReporter();
299         $test->run($reporter);
300
301         // ActionFormのリストア
302         $this->ctl->action_form =& $af;
303         $this->backend->action_form =& $af;
304         $this->backend->af =& $af;
305
306         return array($reporter->report, $reporter->result);
307     }
308 }
309 ?>