ILIAS  release_8 Revision v8.25-1-g13de6a5eca6
AbstractFactoryTest.php
Go to the documentation of this file.
1<?php
2
3declare(strict_types=1);
4
21require_once("libs/composer/vendor/autoload.php");
22
25use PHPUnit\Framework\TestCase;
26
36abstract class AbstractFactoryTest extends TestCase
37{
38 public const COMPONENT = 1;
39 public const FACTORY = 2;
40
41 /* kitchensink info test configuration:
42 * true = should be there, check
43 * false = may be there, don't check
44 * Notice, some properties (MUST/MUST NOT) will always be checked.
45 */
47 'description' => true,
48 'background' => false,
49 'context' => true,
50 'featurewiki' => false,
51 'javascript' => false,
52 'rules' => true
53 ];
54
55 /* You can overwrite these settings per factory method when using this test
56 * by writing $kitchensink_info_settings. See GlyphFactoryTest for an example.
57 */
58
59
60 // Definitions and Helpers:
61
62 private array $description_categories = ['purpose', 'composition', 'effect', 'rival'];
63
64 private array $rules_categories = [
65 'usage',
66 'interaction',
67 'wording',
68 'style',
69 'ordering',
70 'responsiveness',
71 'composition',
72 'accessibility'
73 ];
74
76 private ReflectionClass $reflection;
77
78 final protected function returnsFactory(array $docstring_data): bool
79 {
80 return $this->isFactoryName($docstring_data["namespace"]);
81 }
82
83 final protected function returnsComponent(array $docstring_data): bool
84 {
85 $reflection = new ReflectionClass($docstring_data["namespace"]);
86 return in_array("ILIAS\\UI\\Component\\Component", $reflection->getInterfaceNames());
87 }
88
89 final protected function isFactoryName(string $name): bool
90 {
91 return preg_match("#^(\\\\)?ILIAS\\\\UI\\\\Component\\\\([a-zA-Z]+\\\\)*Factory$#", $name) === 1;
92 }
93
94 final public function buildFactoryReflection(): ReflectionClass
95 {
96 return new ReflectionClass($this->factory_title);
97 }
98
99 final public function methods_provider(): array
100 {
102 return array_map(function ($element) {
103 return array($element, $element->getName());
104 }, $reflection->getMethods());
105 }
106
107 // Setup
108
109 public function setUp(): void
110 {
111 $this->yaml_parser = new Crawler\EntriesYamlParser();
112 $this->reflection = $this->buildFactoryReflection();
113 }
114
115 public function test_proper_namespace(): void
116 {
117 $message = "TODO: Put your factory into the proper namespace.";
118 $this->assertMatchesRegularExpression(
119 "#^ILIAS\\\\UI\\\\Component.#",
120 $this->reflection->getNamespaceName(),
122 );
123 }
124
125 public function test_proper_name(): void
126 {
127 $name = $this->reflection->getName();
128 $message = "TODO: Give your factory a proper name.";
129 $this->assertTrue($this->isFactoryName($name), $message);
130 }
131
137 final public function test_check_yaml_extraction(ReflectionMethod $method_reflection, string $name): array
138 {
139 try {
140 //Todo (TA) this is not pretty. We should think about using only reflection in the parser as well.
141 $function_name_string = "\n public function " . $method_reflection->getName() . "()";
142 $docstring_data = $this->yaml_parser->parseArrayFromString(
143 $method_reflection->getDocComment() . $function_name_string
144 );
145 $this->assertTrue(true);
147 $message = "TODO ($name): fix parse error in kitchen sink yaml: " . $e->getMessage();
148 $this->assertTrue(false, $message);
149 }
150 $this->assertCount(1, $docstring_data);
151 return $docstring_data[0];
152 }
153
159 final public function test_return_type(ReflectionMethod $method_reflection, string $name): void
160 {
161 $message = "TODO ($name): fix return type, it must be a factory or a component.";
162 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
163 if ($this->returnsFactory($docstring_data)) {
164 $this->assertTrue(true);
165 } elseif ($this->returnsComponent($docstring_data)) {
166 $this->assertTrue(true);
167 } else {
168 $this->assertTrue(false, $message);
169 }
170 }
171
178 ReflectionMethod $method_reflection,
179 string $name
180 ): void {
181 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
182 $this->test_return_type($method_reflection, $name);
183
184 $return_doc = $docstring_data["namespace"];
185 $name_uppercase = ucwords($name);
186 $regex_factory_namespace = $this->get_regex_factory_namespace();
187 $regex_head = "#^(\\\\?)$regex_factory_namespace";
188
189 $message = "TODO ($name): fix @return, it does not match the method name.";
190 if ($this->returnsFactory($docstring_data)) {
191 $this->assertMatchesRegularExpression(
192 "$regex_head\\\\$name_uppercase\\\\Factory$#",
193 $return_doc,
195 );
196 } else { // returnsComponent
197 // Every component MUST be described by a single interface, where the name of
198 // the interface corresponds to the name of the component.
199 $standard_pattern = "$regex_head\\\\$name_uppercase#";
200 $standard_case = preg_match($standard_pattern, $return_doc);
201
202 // unless they only differ in a type and share a common prefix to their pathes.
203 $namespace_parts = explode("\\", $this->reflection->getNamespaceName());
204 $typediff_only_pattern = "$regex_head\\\\" . array_pop($namespace_parts) . "#";
205 $typediff_only_case = preg_match($typediff_only_pattern, $return_doc);
206
207 $this->assertTrue($standard_case || $typediff_only_case, $message);
208 }
209 }
210
211 protected function get_regex_factory_namespace(): string
212 {
213 return str_replace("\\", "\\\\", $this->reflection->getNamespaceName());
214 }
215
221 final public function test_method_params(ReflectionMethod $method_reflection, string $name): void
222 {
223 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
224 if ($this->returnsFactory($docstring_data)) {
225 $message = "TODO ($name): remove params from method that returns Factory.";
226 $this->assertEquals(0, $method_reflection->getNumberOfParameters(), $message);
227 }
228 }
229
230 // Common rules for all factory methods, regardless whether they return other
231 // factories or components.
232
236 final public function test_kitchensink_info_description(ReflectionMethod $method_reflection, string $name): void
237 {
238 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
239 $kitchensink_info_settings = $this->kitchensink_info_settings_merged_with_defaults($name);
240
241 if ($kitchensink_info_settings['description']) {
242 $message = "TODO ($name): add a description.";
243 $this->assertArrayHasKey('description', $docstring_data, $message);
244
245 $desc_fields = implode(", ", $this->description_categories);
246 $message = "TODO ($name): the description field should at least contain one of these: $desc_fields.";
247 $existing_keys = array_keys($docstring_data["description"]);
248 $existing_expected_keys = array_intersect($this->description_categories, $existing_keys);
249 $this->assertGreaterThanOrEqual(
250 1,
251 $existing_expected_keys,
253 );
254 }
255 }
256
260 final public function test_kitchensink_info_rivals(ReflectionMethod $method_reflection, string $name): void
261 {
262 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
263 if (isset($docstring_data["description"]) && isset($docstring_data["description"]["rivals"])) {
264 $rules = $docstring_data["description"]["rivals"];
265 $message = "TODO ($name): The Rivals field has a non-string index. Format like 'rival_name': 'description'";
266 $this->assertTrue(array_unique(array_map("is_string", array_keys($rules))) === array(true), $message);
267 }
268 $this->assertTrue(true);
269 }
270
274 final public function test_kitchensink_info_background(ReflectionMethod $method_reflection, string $name): void
275 {
276 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
277 $kitchensink_info_settings = $this->kitchensink_info_settings_merged_with_defaults($name);
278
279 if ($kitchensink_info_settings['background']) {
280 $message = "TODO ($name): add a background field.";
281 $this->assertArrayHasKey('background', $docstring_data, $message);
282 }
283 }
284
288 final public function test_kitchensink_info_featurewiki(ReflectionMethod $method_reflection, string $name): void
289 {
290 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
291 $kitchensink_info_settings = $this->kitchensink_info_settings_merged_with_defaults($name);
292
293 if ($kitchensink_info_settings['featurewiki']) {
294 $message = "TODO ($name): add a featurewiki field.";
295 $this->assertArrayHasKey('featurewiki', $docstring_data, $message);
296 }
297 }
298
302 final public function test_kitchensink_info_javascript(ReflectionMethod $method_reflection, string $name): void
303 {
304 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
305 $kitchensink_info_settings = $this->kitchensink_info_settings_merged_with_defaults($name);
306
307 if ($kitchensink_info_settings['javascript']) {
308 $message = "TODO ($name): add a javascript field.";
309 $this->assertArrayHasKey('javascript', $docstring_data, $message);
310 }
311 }
312
316 final public function test_kitchensink_info_rules(ReflectionMethod $method_reflection, string $name): void
317 {
318 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
319 $kitchensink_info_settings = $this->kitchensink_info_settings_merged_with_defaults($name);
320
321 if ($kitchensink_info_settings['rules']) {
322 $message = "TODO ($name): add a rules field.";
323 $this->assertArrayHasKey('rules', $docstring_data, $message);
324
325 $rules_fields = implode(", ", $this->rules_categories);
326 $message = "TODO ($name): the rules field should at least contain one of these: $rules_fields.";
327 $existing_keys = array_keys($docstring_data["rules"]);
328 $existing_expected_keys = array_intersect($this->rules_categories, $existing_keys);
329 $this->assertGreaterThanOrEqual(
330 1,
331 $existing_expected_keys,
333 );
334 }
335 }
336
340 final public function test_kitchensink_info_context(ReflectionMethod $method_reflection, string $name): void
341 {
342 $docstring_data = $this->test_check_yaml_extraction($method_reflection, $name);
343 $kitchensink_info_settings = $this->kitchensink_info_settings_merged_with_defaults($name);
344
345 // Special rules for factory methods:
346 if ($this->returnsFactory($docstring_data)) {
347 $message = "TODO ($name): remove 'context' field, method returns a factory.";
348 $this->assertArrayNotHasKey("context", $docstring_data, $message);
349 } else { // returnsComponent
350 if ($kitchensink_info_settings["context"]) {
351 $message = "TODO ($name): factory method returning component should have context field. Add it.";
352 $this->assertArrayHasKey("context", $docstring_data, $message);
353 }
354 }
355 }
356
357 final public function kitchensink_info_settings_merged_with_defaults(string $name): array
358 {
359 if (array_key_exists($name, $this->kitchensink_info_settings)) {
360 return array_merge(
361 $this->kitchensink_info_settings_default,
362 $this->kitchensink_info_settings[$name]
363 );
364 } else {
365 return $this->kitchensink_info_settings_default;
366 }
367 }
368}
Defines tests every SHOULD pass UI-factory.
returnsComponent(array $docstring_data)
test_kitchensink_info_background(ReflectionMethod $method_reflection, string $name)
@dataProvider methods_provider
kitchensink_info_settings_merged_with_defaults(string $name)
test_factory_method_name_compatible_docstring(ReflectionMethod $method_reflection, string $name)
Tests whether the method name matches the return doctring?
test_check_yaml_extraction(ReflectionMethod $method_reflection, string $name)
Tests whether the YAML Kitchen Sink info can be parsed.
test_kitchensink_info_description(ReflectionMethod $method_reflection, string $name)
@dataProvider methods_provider
test_kitchensink_info_context(ReflectionMethod $method_reflection, string $name)
@dataProvider methods_provider
Crawler EntriesYamlParser $yaml_parser
test_return_type(ReflectionMethod $method_reflection, string $name)
Tests whether the method either returns a factory or a component.
ReflectionClass $reflection
test_kitchensink_info_rivals(ReflectionMethod $method_reflection, string $name)
@dataProvider methods_provider
returnsFactory(array $docstring_data)
test_method_params(ReflectionMethod $method_reflection, string $name)
Tests whether methods returning factories have no parameters.
test_kitchensink_info_featurewiki(ReflectionMethod $method_reflection, string $name)
@dataProvider methods_provider
test_kitchensink_info_rules(ReflectionMethod $method_reflection, string $name)
@dataProvider methods_provider
test_kitchensink_info_javascript(ReflectionMethod $method_reflection, string $name)
@dataProvider methods_provider
return true
if($format !==null) $name
Definition: metadata.php:247
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: Crawler.php:21
$message
Definition: xapiexit.php:32