1+ <?php
2+ /**
3+ * Copyright © Magento, Inc. All rights reserved.
4+ * See COPYING.txt for license details.
5+ */
6+ namespace Magento \FunctionalTestingFramework \Suite \Handlers ;
7+
8+ use Exception ;
9+ use Magento \FunctionalTestingFramework \ObjectManager \ObjectHandlerInterface ;
10+ use Magento \FunctionalTestingFramework \ObjectManagerFactory ;
11+ use Magento \FunctionalTestingFramework \Suite \Objects \SuiteObject ;
12+ use Magento \FunctionalTestingFramework \Suite \Parsers \SuiteDataParser ;
13+ use Magento \FunctionalTestingFramework \Test \Handlers \CestObjectHandler ;
14+ use Magento \FunctionalTestingFramework \Test \Objects \CestObject ;
15+ use Magento \Ui \Test \Unit \Component \PagingTest ;
16+
17+ /**
18+ * Class SuiteObjectHandler
19+ */
20+ class SuiteObjectHandler implements ObjectHandlerInterface
21+ {
22+ const SUITE_TAG_NAME = 'suite ' ;
23+ const INCLUDE_TAG_NAME = 'include ' ;
24+ const EXCLUDE_TAG_NAME = 'exclude ' ;
25+ const MODULE_TAG_NAME = 'module ' ;
26+ const MODULE_TAG_FILE_ATTRIBUTE = 'file ' ;
27+ const CEST_TAG_NAME = 'cest ' ;
28+ const CEST_TAG_NAME_ATTRIBUTE = 'name ' ;
29+ const CEST_TAG_TEST_ATTRIBUTE = 'test ' ;
30+ const GROUP_TAG_NAME = 'group ' ;
31+
32+ /**
33+ * Singleton instance of suite object handler.
34+ *
35+ * @var SuiteObjectHandler
36+ */
37+ private static $ SUITE_OBJECT_HANLDER_INSTANCE ;
38+
39+ /**
40+ * Array of suite objects keyed by suite name.
41+ *
42+ * @var array
43+ */
44+ private $ suiteObjects ;
45+
46+ private function __construct ()
47+ {
48+ // empty constructor
49+ }
50+
51+ /**
52+ * Function to enforce singleton design pattern
53+ *
54+ * @return ObjectHandlerInterface
55+ */
56+ public static function getInstance ()
57+ {
58+ if (self ::$ SUITE_OBJECT_HANLDER_INSTANCE == null ) {
59+ self ::$ SUITE_OBJECT_HANLDER_INSTANCE = new SuiteObjectHandler ();
60+ self ::$ SUITE_OBJECT_HANLDER_INSTANCE ->initSuiteData ();
61+ }
62+
63+ return self ::$ SUITE_OBJECT_HANLDER_INSTANCE ;
64+ }
65+
66+ /**
67+ * Function to return a single suite object by name
68+ *
69+ * @param string $objectName
70+ * @return SuiteObject
71+ */
72+ public function getObject ($ objectName )
73+ {
74+ if (!array_key_exists ($ objectName , $ this ->suiteObjects )) {
75+ trigger_error ("Suite $ {objectName} is not defined. " , E_USER_ERROR );
76+ }
77+ return $ this ->suiteObjects [$ objectName ];
78+ }
79+
80+ /**
81+ * Function to return all objects the handler is responsible for
82+ *
83+ * @return array
84+ */
85+ public function getAllObjects ()
86+ {
87+ return $ this ->suiteObjects ;
88+ }
89+
90+ private function initSuiteData ()
91+ {
92+ $ suiteDataParser = ObjectManagerFactory::getObjectManager ()->create (SuiteDataParser::class);
93+ $ this ->suiteObjects = $ this ->parseSuiteDataIntoObjects ($ suiteDataParser ->readSuiteData ());
94+ }
95+
96+ private function parseSuiteDataIntoObjects ($ parsedSuiteData )
97+ {
98+ $ suiteObjects = [];
99+ foreach ($ parsedSuiteData [self ::SUITE_TAG_NAME ] as $ parsedSuiteName => $ parsedSuite ) {
100+ $ includeCests = [];
101+ $ excludeCests = [];
102+
103+ $ groupCestsToInclude = $ parsedSuite [self ::INCLUDE_TAG_NAME ][0 ] ?? [];
104+ $ groupCestsToExclude = $ parsedSuite [self ::EXCLUDE_TAG_NAME ][0 ] ?? [];
105+
106+ if (array_key_exists (self ::CEST_TAG_NAME , $ groupCestsToInclude )) {
107+ $ includeCests = $ includeCests + $ this ->extractRelevantTests ($ groupCestsToInclude [self ::CEST_TAG_NAME ]);
108+ }
109+
110+ if (array_key_exists (self ::CEST_TAG_NAME , $ groupCestsToExclude )) {
111+ $ excludeCests = $ excludeCests + $ this ->extractRelevantTests ($ groupCestsToExclude [self ::CEST_TAG_NAME ]);
112+ }
113+
114+ $ includeCests = $ includeCests + $ this ->extractGroups ($ groupCestsToInclude );
115+ $ excludeCests = $ excludeCests + $ this ->extractGroups ($ groupCestsToExclude );
116+
117+
118+ // get tests by path (dir or file)
119+ if (array_key_exists (self ::MODULE_TAG_NAME , $ groupCestsToInclude )) {
120+ $ includeCests = array_merge (
121+ $ includeCests ,
122+ $ this ->extractModuleAndFiles ($ groupCestsToInclude [self ::MODULE_TAG_NAME ])
123+ );
124+ }
125+
126+ if (array_key_exists (self ::MODULE_TAG_NAME , $ groupCestsToExclude )) {
127+ $ excludeCests = array_merge (
128+ $ excludeCests ,
129+ $ this ->extractModuleAndFiles ($ groupCestsToExclude [self ::MODULE_TAG_NAME ])
130+ );
131+ }
132+
133+ // add all cests if include cests is completely empty
134+ if (empty ($ includeCests )) {
135+ $ includeCests = CestObjectHandler::getInstance ()->getAllObjects ();
136+ }
137+
138+ $ suiteObjects [$ parsedSuiteName ] = new SuiteObject ($ parsedSuiteName , $ includeCests , $ excludeCests );
139+ }
140+
141+ return $ suiteObjects ;
142+ }
143+
144+ private function extractRelevantTests ($ suiteTestData )
145+ {
146+ $ relevantCests = [];
147+ foreach ($ suiteTestData as $ cestName => $ cestInfo ) {
148+ $ relevantCest = CestObjectHandler::getInstance ()->getObject ($ cestName );
149+
150+ if (array_key_exists (self ::CEST_TAG_TEST_ATTRIBUTE , $ cestInfo )) {
151+ $ relevantTest = $ relevantCest ->getTests ()[$ cestInfo [self ::CEST_TAG_TEST_ATTRIBUTE ]] ?? null ;
152+
153+ if (!$ relevantTest ) {
154+ trigger_error (
155+ "Test " .
156+ $ cestInfo [self ::CEST_TAG_NAME_ATTRIBUTE ] .
157+ " does not exist. " ,
158+ E_USER_NOTICE
159+ );
160+ continue ;
161+ }
162+
163+ $ relevantCests [$ cestName ] = new CestObject (
164+ $ relevantCest ->getName (),
165+ $ relevantCest ->getAnnotations (),
166+ [$ relevantTest ->getName () => $ relevantTest ],
167+ $ relevantCest ->getHooks ()
168+ );
169+ } else {
170+ $ relevantCests [$ cestName ] = $ relevantCest ;
171+ }
172+ }
173+
174+ return $ relevantCests ;
175+ }
176+
177+ private function extractGroups ($ suiteData )
178+ {
179+ $ cestsByGroup = [];
180+ // get tests by group
181+ if (array_key_exists (self ::GROUP_TAG_NAME , $ suiteData )) {
182+ //loop groups and add to the groupCests
183+ foreach ($ suiteData [self ::GROUP_TAG_NAME ] as $ groupName => $ groupVal ) {
184+ $ cestsByGroup = $ cestsByGroup + CestObjectHandler::getInstance ()->getCestsByGroup ($ groupName );
185+ }
186+ }
187+
188+ return $ cestsByGroup ;
189+ }
190+
191+ private function extractModuleAndFiles ($ suitePathData )
192+ {
193+ $ cestsByModule = [];
194+ foreach ($ suitePathData as $ moduleName => $ fileInfo ) {
195+ if (empty ($ fileInfo )) {
196+ $ cestsByModule = array_merge ($ cestsByModule , $ this ->resolveModulePathCestNames ($ moduleName ));
197+ } else {
198+ $ cestObj = $ this ->resolveFilePathCestName ($ fileInfo [self ::MODULE_TAG_FILE_ATTRIBUTE ], $ moduleName );
199+ $ cestsByModule [$ cestObj ->getName ()] = $ cestObj ;
200+ }
201+ }
202+
203+ return $ cestsByModule ;
204+ }
205+
206+ private function resolveFilePathCestName ($ filename , $ moduleName = null )
207+ {
208+ $ filepath = $ filename ;
209+ if (!strstr ($ filepath , DIRECTORY_SEPARATOR )) {
210+ $ filepath = TESTS_MODULE_PATH .
211+ DIRECTORY_SEPARATOR .
212+ $ moduleName .
213+ DIRECTORY_SEPARATOR .
214+ 'Cest ' .
215+ DIRECTORY_SEPARATOR .
216+ $ filename ;
217+ }
218+
219+ if (!file_exists ($ filepath )) {
220+ throw new Exception ("Could not find file $ {filename}" );
221+ }
222+ $ xml = simplexml_load_file ($ filepath );
223+ $ cestName = (string )$ xml ->cest ->attributes ()->name ;
224+
225+ return CestObjectHandler::getInstance ()->getObject ($ cestName );
226+ }
227+
228+ private function resolveModulePathCestNames ($ moduleName )
229+ {
230+ $ cestObjects = [];
231+ $ xmlFiles = glob (
232+ TESTS_MODULE_PATH .
233+ DIRECTORY_SEPARATOR .
234+ $ moduleName .
235+ DIRECTORY_SEPARATOR .
236+ 'Cest ' .
237+ DIRECTORY_SEPARATOR .
238+ '*.xml '
239+ );
240+
241+ foreach ($ xmlFiles as $ xmlFile ) {
242+ $ cestObj = $ this ->resolveFilePathCestName ($ xmlFile );
243+ $ cestObjects [$ cestObj ->getName ()] = $ cestObj ;
244+ }
245+
246+ return $ cestObjects ;
247+ }
248+ }
0 commit comments