1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Tester;
9:
10:
11: 12: 13: 14: 15:
16: class TestCase
17: {
18:
19: const LIST_METHODS = 'nette-tester-list-methods',
20: METHOD_PATTERN = '#^test[A-Z0-9_]#';
21:
22:
23: 24: 25: 26:
27: public function run($method = NULL)
28: {
29: if (($method === NULL || $method === self::LIST_METHODS) && isset($_SERVER['argv'][1])) {
30: if ($_SERVER['argv'][1] === self::LIST_METHODS) {
31: echo json_encode(array_values(preg_grep(self::METHOD_PATTERN, get_class_methods($this))));
32: return;
33: }
34: $method = $_SERVER['argv'][1];
35: }
36:
37: $methods = preg_grep(self::METHOD_PATTERN, $method ? array($method) : get_class_methods($this));
38: foreach ($methods as $method) {
39: $this->runMethod($method);
40: }
41: }
42:
43:
44: 45: 46: 47:
48: private function runMethod($method)
49: {
50: $method = new \ReflectionMethod($this, $method);
51: if (!$method->isPublic()) {
52: throw new TestCaseException("Method {$method->getName()} is not public. Make it public or rename it.");
53: }
54:
55: $data = array();
56: $info = Helpers::parseDocComment($method->getDocComment()) + array('dataprovider' => NULL, 'throws' => NULL);
57:
58: if ($info['throws'] === '') {
59: throw new TestCaseException("Missing class name in @throws annotation for {$method->getName()}().");
60: } elseif (is_array($info['throws'])) {
61: throw new TestCaseException("Annotation @throws for {$method->getName()}() can be specified only once.");
62: } else {
63: $throws = preg_split('#\s+#', $info['throws'], 2) + array(NULL, NULL);
64: }
65:
66: foreach ((array) $info['dataprovider'] as $provider) {
67: $res = $this->getData($provider);
68: if (!is_array($res)) {
69: throw new TestCaseException("Data provider $provider() doesn't return array.");
70: }
71: $data = array_merge($data, $res);
72: }
73: if (!$info['dataprovider']) {
74: if ($method->getNumberOfRequiredParameters()) {
75: throw new TestCaseException("Method {$method->getName()}() has arguments, but @dataProvider is missing.");
76: }
77: $data[] = array();
78: }
79:
80: foreach ($data as $args) {
81: try {
82: if ($info['throws']) {
83: $tmp = $this;
84: $e = Assert::error(function() use ($tmp, $method, $args) {
85: $tmp->runTest($method->getName(), $args);
86: }, $throws[0], $throws[1]);
87: if ($e instanceof AssertException) {
88: throw $e;
89: }
90: } else {
91: $this->runTest($method->getName(), $args);
92: }
93: } catch (AssertException $e) {
94: $e->message .= " in {$method->getName()}" . (substr(Dumper::toLine($args), 5));
95: throw $e;
96: }
97: }
98: }
99:
100:
101: 102: 103: 104:
105: public function runTest($name, array $args = array())
106: {
107: $this->setUp();
108: try {
109: call_user_func_array(array($this, $name), $args);
110: } catch (\Exception $e) {
111: }
112: try {
113: $this->tearDown();
114: } catch (\Exception $tearDownEx) {
115: throw isset($e) ? $e : $tearDownEx;
116: }
117: if (isset($e)) {
118: throw $e;
119: }
120: }
121:
122:
123: 124: 125:
126: protected function getData($provider)
127: {
128: if (strpos($provider, '.')) {
129: $rc = new \ReflectionClass($this);
130: list($file, $query) = DataProvider::parseAnnotation($provider, $rc->getFileName());
131: return DataProvider::load($file, $query);
132: } else {
133: return $this->$provider();
134: }
135: }
136:
137:
138: 139: 140: 141:
142: protected function setUp()
143: {
144: }
145:
146:
147: 148: 149: 150:
151: protected function tearDown()
152: {
153: }
154:
155: }
156:
157:
158: class TestCaseException extends \Exception
159: {
160: }
161: