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