ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
AbstractFactoryTest.php
Go to the documentation of this file.
1<?php
2
3require_once("libs/composer/vendor/autoload.php");
4
7
18{
19 const COMPONENT = 1;
20 const FACTORY = 2;
21
22 /* kitchensink info test configuration:
23 * true = should be there, check
24 * false = may be there, don't check
25 * Notice, some properties (MUST/MUST NOT) will always be checked.
26 */
28 = array('description'
29 => true
30 ,'background'
31 => false
32 ,'context'
33 => true
34 ,'featurewiki'
35 => false
36 ,'javascript'
37 => false
38 ,'rules'
39 => true);
40
41 /* You can overwrite these settings per factory method when using this test
42 * by writing $kitchensink_info_settings. See GlyphFactoryTest for an example.
43 */
44
45
46 // Definitions and Helpers:
47
49 array('purpose', 'composition', 'effect', 'rival');
50
52 array('usage', 'interaction', 'wording', 'style', 'ordering', 'responsiveness',
53 'composition','accessibility');
54
55 final protected function returnsFactory($docstring_data)
56 {
57 return $this->isFactoryName($docstring_data["namespace"]);
58 }
59
60 final protected function returnsComponent($docstring_data)
61 {
62 $reflection = new ReflectionClass($docstring_data["namespace"]);
63 return in_array("ILIAS\\UI\\Component\\Component", $reflection->getInterfaceNames());
64 }
65
66 final protected function isFactoryName($name)
67 {
68 return preg_match("#^(\\\\)?ILIAS\\\\UI\\\\Component\\\\([a-zA-Z]+\\\\)*Factory$#", $name) === 1;
69 }
70
71 final public function buildFactoryReflection()
72 {
73 return new ReflectionClass($this->factory_title);
74 }
75
76 final public function methods_provider()
77 {
78 $reflection = $this->buildFactoryReflection();
79 return array_map(function ($element) {
80 return array($element, $element->getName());
81 }, $reflection->getMethods());
82 }
83
84 // Setup
85
86 public function setUp()
87 {
88 $this->yaml_parser = new Crawler\EntriesYamlParser();
89 $this->reflection = $this->buildFactoryReflection();
90 }
91
92 public function test_proper_namespace()
93 {
94 $message = "TODO: Put your factory into the proper namespace.";
95 $this->assertRegExp(
96 "#^ILIAS\\\\UI\\\\Component.#",
97 $this->reflection->getNamespaceName(),
99 );
100 }
101
102 public function test_proper_name()
103 {
104 $name = $this->reflection->getName();
105 $message = "TODO: Give your factory a proper name.";
106 $this->assertTrue(
107 $this->isFactoryName($name),
109 );
110 }
111
117 final public function test_check_yaml_extraction($method_reflection, $name)
118 {
119 try {
120 //Todo (TA) this is not pretty. We should think about using only reflection in the parser as well.
121 $function_name_string = "\n public function " . $method_reflection->getName() . "()";
122 $docstring_data = $this->yaml_parser->parseArrayFromString(
123 $method_reflection->getDocComment() . $function_name_string
124 );
125 $this->assertTrue(true);
127 $message = "TODO ($name): fix parse error in kitchen sink yaml: " . $e->getMessage();
128 $this->assertTrue(false, $message);
129 }
130 $this->assertCount(1, $docstring_data);
131 return $docstring_data[0];
132 }
133
139 final public function test_return_type($method_reflection, $name)
140 {
141 $message = "TODO ($name): fix return type, it must be a factory or a component.";
142 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
143 if ($this->returnsFactory($docstring_data)) {
144 $this->assertTrue(true);
145 } elseif ($this->returnsComponent($docstring_data)) {
146 $this->assertTrue(true);
147 } else {
148 $this->assertTrue(false, $message);
149 }
150 }
151
157 final public function test_factory_method_name_compatible_docstring($method_reflection, $name)
158 {
159 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
160 $this->test_return_type($method_reflection, $name);
161
162 $return_doc = $docstring_data["namespace"];
163 $name_uppercase = ucwords($name);
164 $regex_factory_namespace = $this->get_regex_factory_namespace();
165 $regex_head = "#^(\\\\?)$regex_factory_namespace";
166
167 $message = "TODO ($name): fix @return, it does not match the method name.";
168 if ($this->returnsFactory($docstring_data)) {
169 $this->assertRegExp(
170 "$regex_head\\\\$name_uppercase\\\\Factory$#",
171 $return_doc,
173 );
174 } else { // returnsComponent
175 // Every component MUST be described by a single interface, where the name of
176 // the interface corresponds to the name of the component.
177 $standard_pattern = "$regex_head\\\\$name_uppercase#";
178 $standard_case = preg_match($standard_pattern, $return_doc);
179
180 // unless they only differ in a type and share a common prefix to their pathes.
181 $namespace_parts = explode("\\", $this->reflection->getNamespaceName());
182 $typediff_only_pattern = "$regex_head\\\\" . array_pop($namespace_parts) . "#";
183 $typediff_only_case = preg_match($typediff_only_pattern, $return_doc);
184
185 $this->assertTrue($standard_case || $typediff_only_case, $message);
186 }
187 }
188
189 protected function get_regex_factory_namespace()
190 {
191 return str_replace("\\", "\\\\", $this->reflection->getNamespaceName());
192 }
193
199 final public function test_method_params($method_reflection, $name)
200 {
201 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
202 if ($this->returnsFactory($docstring_data)) {
203 $message = "TODO ($name): remove params from method that returns Factory.";
204 $this->assertEquals(0, $method_reflection->getNumberOfParameters(), $message);
205 }
206 }
207
208 // Common rules for all factory methods, regardless whether they return other
209 // factories or components.
210
214 final public function test_kitchensink_info_description($method_reflection, $name)
215 {
216 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
217 $kitchensink_info_settings = $this->kitchensink_info_settings_merged_with_defaults($name);
218
219 if ($kitchensink_info_settings['description']) {
220 $message = "TODO ($name): add a description.";
221 $this->assertArrayHasKey('description', $docstring_data, $message);
222
223 $desc_fields = implode(", ", $this->description_categories);
224 $message = "TODO ($name): the description field should at least contain one of these: $desc_fields.";
225 $existing_keys = array_keys($docstring_data["description"]);
226 $existing_expected_keys = array_intersect($this->description_categories, $existing_keys);
227 $this->assertGreaterThanOrEqual(
228 1,
229 $existing_expected_keys,
231 );
232 }
233 }
234
238 final public function test_kitchensink_info_rivals($method_reflection, $name)
239 {
240 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
241 if (isset($docstring_data["description"]) && isset($docstring_data["description"]["rivals"])) {
242 $rules = $docstring_data["description"]["rivals"];
243 $message = "TODO ($name): The Rivals field has a non-string index. Format like 'rival_name': 'description'";
244 $this->assertTrue(array_unique(array_map("is_string", array_keys($rules))) === array(true), $message);
245 }
246 $this->assertTrue(true);
247 }
248
252 final public function test_kitchensink_info_background($method_reflection, $name)
253 {
254 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
255 $kitchensink_info_settings = $this->kitchensink_info_settings_merged_with_defaults($name);
256
257 if ($kitchensink_info_settings['background']) {
258 $message = "TODO ($name): add a background field.";
259 $this->assertArrayHasKey('background', $docstring_data, $message);
260 }
261 }
262
266 final public function test_kitchensink_info_featurewiki($method_reflection, $name)
267 {
268 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
269 $kitchensink_info_settings = $this->kitchensink_info_settings_merged_with_defaults($name);
270
271 if ($kitchensink_info_settings['featurewiki']) {
272 $message = "TODO ($name): add a featurewiki field.";
273 $this->assertArrayHasKey('featurewiki', $docstring_data, $message);
274 }
275 }
276
280 final public function test_kitchensink_info_javascript($method_reflection, $name)
281 {
282 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
283 $kitchensink_info_settings = $this->kitchensink_info_settings_merged_with_defaults($name);
284
285 if ($kitchensink_info_settings['javascript']) {
286 $message = "TODO ($name): add a javascript field.";
287 $this->assertArrayHasKey('javascript', $docstring_data, $message);
288 }
289 }
290
294 final public function test_kitchensink_info_rules($method_reflection, $name)
295 {
296 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
297 $kitchensink_info_settings = $this->kitchensink_info_settings_merged_with_defaults($name);
298
299 if ($kitchensink_info_settings['rules']) {
300 $message = "TODO ($name): add a rules field.";
301 $this->assertArrayHasKey('rules', $docstring_data, $message);
302
303 $rules_fields = implode(", ", $this->rules_categories);
304 $message = "TODO ($name): the rules field should at least contain one of these: $rules_fields.";
305 $existing_keys = array_keys($docstring_data["rules"]);
306 $existing_expected_keys = array_intersect($this->rules_categories, $existing_keys);
307 $this->assertGreaterThanOrEqual(
308 1,
309 $existing_expected_keys,
311 );
312 }
313 }
314
318 final public function test_kitchensink_info_context($method_reflection, $name)
319 {
320 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
321 $kitchensink_info_settings = $this->kitchensink_info_settings_merged_with_defaults($name);
322
323 // Special rules for factory methods:
324 if ($this->returnsFactory($docstring_data)) {
325 $message = "TODO ($name): remove 'context' field, method returns a factory.";
326 $this->assertArrayNotHasKey("context", $docstring_data, $message);
327 } else { // returnsComponent
328 if ($kitchensink_info_settings["context"]) {
329 $message = "TODO ($name): factory method returning component should have context field. Add it.";
330 $this->assertArrayHasKey("context", $docstring_data, $message);
331 }
332 }
333 }
334
336 {
337 if (array_key_exists($name, $this->kitchensink_info_settings)) {
338 return array_merge(
339 $this->kitchensink_info_settings_default,
340 $this->kitchensink_info_settings[$name]
341 );
342 } else {
344 }
345 }
346}
Defines tests every SHOULD pass UI-factory.
test_kitchensink_info_javascript($method_reflection, $name)
@dataProvider methods_provider
test_return_type($method_reflection, $name)
Tests whether the method either returns a factory or a component.
test_kitchensink_info_background($method_reflection, $name)
@dataProvider methods_provider
returnsFactory($docstring_data)
test_factory_method_name_compatible_docstring($method_reflection, $name)
Tests whether the method name matches the.
test_kitchensink_info_context($method_reflection, $name)
@dataProvider methods_provider
test_check_yaml_extraction($method_reflection, $name)
Tests whether the YAML Kitchen Sink info can be parsed.
test_kitchensink_info_rules($method_reflection, $name)
@dataProvider methods_provider
test_kitchensink_info_featurewiki($method_reflection, $name)
@dataProvider methods_provider
kitchensink_info_settings_merged_with_defaults($name)
returnsComponent($docstring_data)
test_kitchensink_info_rivals($method_reflection, $name)
@dataProvider methods_provider
test_kitchensink_info_description($method_reflection, $name)
@dataProvider methods_provider
test_method_params($method_reflection, $name)
Tests whether methods returning factories have no parameters.
An exception for terminatinating execution or to throw for unit testing.
catch(Exception $e) $message