3636TEST_OBSOLETE_ZAP_FILE = SCRIPT_DIR / "test_obsolete.zap"
3737APP_TEMPLATES_FILE = MATTER_BASE / DEFAULT_APP_TEMPLATES_RELATIVE_PATH
3838VERSION_FILE = MATTER_BASE / DEFAULT_ZAP_VERSION_RELATIVE_PATH
39+ TEST_SAMPLES_FILE = SCRIPT_DIR / "zap_samples.yml"
3940
4041
4142class TestWestZap (unittest .TestCase ):
@@ -55,8 +56,10 @@ def setUpClass(cls):
5556 cls .zap_output_dir = cls .test_dir / "zap-generated"
5657 cls .zap_output_dir_full = cls .test_dir / "zap-generated-full"
5758 cls .zap_output_dir_synced = cls .test_dir / "zap-generated-synced"
59+ cls .zap_output_dir_samples_yml = cls .test_dir / "zap-generated-samples-yml"
5860 cls .test_obsolete_zap_file = cls .test_dir / "test_obsolete.zap"
5961 cls .test_obsolete_zcl_file = cls .test_dir / "zcl_test_obsolete.json"
62+ cls .test_samples_file = cls .test_dir / "zap_samples.yml"
6063
6164 cls .cluster_names = [cluster .stem for cluster in cls .test_clusters ]
6265
@@ -74,10 +77,14 @@ def setUpClass(cls):
7477 shutil .copy (TEST_ZCL_FILE , cls .zcl_json_file_with_new_items )
7578 shutil .copy (TEST_ZAP_FILE , cls .test_zap_file )
7679 shutil .copy (VERSION_FILE , cls .version_file )
80+ shutil .copy (TEST_SAMPLES_FILE , cls .test_samples_file )
7781
7882 with open (cls .version_file , 'r' ) as f :
7983 cls .recommended_version = f .read ().strip ()
8084
85+ # Initialize common zap installer
86+ cls .zap_installer = ZapInstaller (cls .test_dir )
87+
8188 @classmethod
8289 def tearDownClass (cls ):
8390 if cls .test_dir .exists ():
@@ -155,18 +162,30 @@ def test_post_process_generated_files(self):
155162 with open (test_file , 'w' ) as f :
156163 f .write ("test content" )
157164
158- post_process_generated_files (self .test_dir )
165+ post_process_generated_files (self .test_dir , "manufacturer_specific" )
159166
160167 with open (test_file , 'r' ) as f :
161168 content = f .read ()
162169 self .assertTrue (content .endswith ('\n ' ))
163170 self .assertEqual (content , "test content\n " )
164171
172+ with open (test_file , 'w' ) as f :
173+ f .write ("# Cluster generated code for constants and metadata based on /home/xxx/ncs/nrf/samples/matter/manufacturer_specific/src/default_zap/manufacturer_specific.matter\n " )
174+ f .write ("// based on /home/xxx/ncs/nrf/samples/matter/manufacturer_specific/src/default_zap/manufacturer_specific.matter\n " )
175+
176+ post_process_generated_files (self .test_dir , "manufacturer_specific" )
177+ with open (test_file , 'r' ) as f :
178+ content = f .readlines ()
179+ self .assertEqual (
180+ content [0 ], "# Cluster generated code for constants and metadata based on manufacturer_specific/src/default_zap/manufacturer_specific.matter\n " )
181+ self .assertEqual (
182+ content [1 ], "// based on manufacturer_specific/src/default_zap/manufacturer_specific.matter\n " )
183+
165184 # Test file with multiple newlines
166185 with open (test_file , 'w' ) as f :
167186 f .write ("test content\n \n \n " )
168187
169- post_process_generated_files (self .test_dir )
188+ post_process_generated_files (self .test_dir , "manufacturer_specific" )
170189
171190 with open (test_file , 'r' ) as f :
172191 content = f .read ()
@@ -215,17 +234,17 @@ def test_get_paths(self):
215234 - The zap CLI path is returned correctly.
216235 """
217236 # Install path
218- installer = ZapInstaller ( self .test_dir )
237+ installer = self .zap_installer
219238 expected = self .test_dir / '.zap-install'
220239 self .assertEqual (installer .get_install_path (), expected )
221240
222241 # Zap path
223- installer = ZapInstaller ( self .test_dir )
242+ installer = self .zap_installer
224243 expected = self .test_dir / '.zap-install' / installer .zap_exe
225244 self .assertEqual (installer .get_zap_path (), expected )
226245
227246 # Zap CLI path
228- installer = ZapInstaller ( self .test_dir )
247+ installer = self .zap_installer
229248 expected = self .test_dir / '.zap-install' / installer .zap_cli_exe
230249 self .assertEqual (installer .get_zap_cli_path (), expected )
231250
@@ -238,11 +257,11 @@ def test_version(self):
238257 - The current version is returned correctly.
239258 """
240259
241- installer = ZapInstaller ( self .test_dir )
260+ installer = self .zap_installer
242261 version = installer .get_recommended_version ()
243262 self .assertEqual (version , self .recommended_version )
244263
245- installer = ZapInstaller ( self .test_dir )
264+ installer = self .zap_installer
246265
247266 with patch ('subprocess.check_output' , side_effect = Exception ()):
248267 version = installer .get_current_version ()
@@ -277,7 +296,7 @@ def test_install_zap(self):
277296 - The ZAP package is not installed if the current ver sion is the same as the recommended version.
278297 - The ZAP package is installed.
279298 """
280- zap_installer = ZapInstaller ( self .test_dir )
299+ zap_installer = self .zap_installer
281300
282301 # Test when the current version is the same as the recommended version
283302 with patch .object (zap_installer , 'get_current_version' , return_value = self .recommended_version ):
@@ -314,19 +333,20 @@ def test_zap_generate(self):
314333 - Zap files are generated correctly.
315334 - The data model is re-generated for --full argument and all zap files for new clusters are generated.
316335 """
317- zap_installer = ZapInstaller ( self .test_dir )
336+ zap_installer = self .zap_installer
318337 self .assertTrue (zap_installer .get_current_version () != "" )
319338
320339 # Run zap-generate command for simple generation
321340 with patch ('zap_generate.get_zap_generate_path' , return_value = MATTER_BASE / DEFAULT_ZAP_GENERATE_RELATIVE_PATH ):
322341 with patch ('zap_generate.get_app_templates_path' , return_value = MATTER_BASE / DEFAULT_APP_TEMPLATES_RELATIVE_PATH ):
323- ZapGenerate ().do_run (Namespace (zap_file = self .test_zap_file ,
324- output = self .zap_output_dir ,
325- matter_path = self .test_dir ,
326- full = False ,
327- keep_previous = False ,
328- zcl = None ,
329- yaml = None ), [])
342+ with patch ('zap_generate.ZapInstaller' , return_value = zap_installer ):
343+ ZapGenerate ().do_run (Namespace (zap_file = self .test_zap_file ,
344+ output = self .zap_output_dir ,
345+ matter_path = self .test_dir ,
346+ full = False ,
347+ keep_previous = False ,
348+ zcl = None ,
349+ yaml = None ), [])
330350
331351 self .assertTrue (self .zap_output_dir .exists ())
332352 self .assertTrue ((self .zap_output_dir .parent / "test.matter" ).exists ())
@@ -375,61 +395,157 @@ def test_zap_generate_full(self):
375395 # Use the full zap file to generate the full data model.
376396 with patch ('zap_generate.get_zap_generate_path' , return_value = MATTER_BASE / DEFAULT_ZAP_GENERATE_RELATIVE_PATH ):
377397 with patch ('zap_generate.get_app_templates_path' , return_value = MATTER_BASE / DEFAULT_APP_TEMPLATES_RELATIVE_PATH ):
378- ZapGenerate ().do_run (Namespace (zap_file = self .test_zap_file_full ,
379- output = self .zap_output_dir_full ,
380- matter_path = MATTER_BASE ,
381- full = True ,
382- keep_previous = False ,
383- zcl = self .zcl_json_appended ,
384- yaml = None ), [])
398+ with patch ('zap_generate.ZapInstaller' , return_value = self .zap_installer ):
399+ ZapGenerate ().do_run (Namespace (zap_file = self .test_zap_file_full ,
400+ output = self .zap_output_dir_full ,
401+ matter_path = MATTER_BASE ,
402+ full = True ,
403+ keep_previous = False ,
404+ zcl = self .zcl_json_appended ,
405+ yaml = None ), [])
385406
386407 # Check full generation
387408 self ._check_full_generation (self .zap_output_dir_full , self .cluster_names )
388409
389- def test_zap_synchronize (self ):
410+ def test_generate_from_yaml (self ):
390411 """
391- Checks whether the zap_sync function synchronizes the ZAP file correctly.
392-
393- We expect:
394- - The ZAP file still contains the custom clusters after synchronization.
395- - The zcl.json file is synchronized with the Matter SDK, so contains the new items from the Matter SDK, but also contains the custom clusters.
396- - West zap-generate still works without any errors.
412+ Checks whether the zap_generate function generates the ZAP package correctly from a yaml file.
397413 """
398414
399- # Input files should exist.
400- self .assertTrue (self .zcl_json_appended .exists ())
401- shutil .copy (TEST_ZAP_FILE_FULL , self .test_zap_file_full )
402- # self.assertTrue(self.test_zap_file_full.exists())
403-
404- # Copy the obsolete zcl.json file to the test directory.
405- shutil .copy (TEST_OBSOLETE_ZCL_FILE , self .test_obsolete_zcl_file )
406- # Copy the obsolete zap file to the test directory.
407- shutil .copy (TEST_OBSOLETE_ZAP_FILE , self .test_obsolete_zap_file )
408-
409- # Run zap-sync command
410- with patch ('zap_common.get_rules_path' , return_value = MATTER_BASE / DEFAULT_RULES_RELATIVE_PATH ):
411- ZapSync ().do_run (Namespace (zap_file = self .test_obsolete_zap_file , zcl_json = self .test_obsolete_zcl_file ,
412- matter_path = MATTER_BASE , clusters = self .test_clusters ), [])
413-
414- # Check whether the custom clusters are still present in the ZAP file.
415- with open (self .test_obsolete_zap_file , 'r' ) as f :
416- content = f .read ()
417- self .assertIn ("Cluster 1" , content )
418- self .assertIn ("Cluster 2" , content )
419- # Check whether the custom clusters are still present in the zcl.json file.
420- with open (self .test_obsolete_zcl_file , 'r' ) as f :
421- content = f .read ()
422- self .assertIn ("Cluster1" , content )
423- self .assertIn ("Cluster2" , content )
424-
425- # Run zap-generate command
415+ # Copy the zap file and zcl to compare later.
416+ zap_to_compare = self .test_dir / "zap_to_comapre.zap"
417+ zcl_to_compare = self .test_dir / "zcl_to_compare.json"
418+ shutil .copy (self .test_zap_file_full , zap_to_compare )
419+ shutil .copy (self .zcl_json_appended , zcl_to_compare )
420+
421+ # Replace the base_dir relative to the ZEPHYR_BASE directory.
422+ with open (self .test_samples_file , 'r' ) as f :
423+ ZEPHYR_BASE = os .environ .get ('ZEPHYR_BASE' , "" )
424+ samples_yml_content = f .read ()
425+ samples_yml_content = samples_yml_content .replace (
426+ "base_dir: ../modules/lib/matter/test_dir" , f"base_dir: { self .test_dir .relative_to (Path (ZEPHYR_BASE ), walk_up = True )} " )
427+ print (f"\n \n samples_yml_content: { samples_yml_content } \n \n " )
428+ with open (self .test_samples_file , 'w' ) as f :
429+ f .write (samples_yml_content )
430+
431+ # Run generate using the yaml file
426432 with patch ('zap_generate.get_zap_generate_path' , return_value = MATTER_BASE / DEFAULT_ZAP_GENERATE_RELATIVE_PATH ):
427433 with patch ('zap_generate.get_app_templates_path' , return_value = MATTER_BASE / DEFAULT_APP_TEMPLATES_RELATIVE_PATH ):
428- ZapGenerate ().do_run (Namespace (zap_file = self .test_obsolete_zap_file , output = self .zap_output_dir_synced ,
429- matter_path = MATTER_BASE , full = True , keep_previous = False , zcl = self .test_obsolete_zcl_file , yaml = None ), [])
434+ with patch ('zap_generate.ZapInstaller' , return_value = self .zap_installer ):
435+ ZapGenerate ().do_run (Namespace (zap_file = None , output = self .zap_output_dir_samples_yml ,
436+ matter_path = MATTER_BASE , full = None , keep_previous = False , zcl = None , yaml = self .test_samples_file ), [])
430437
431438 # Check full generation
432- self ._check_full_generation (self .zap_output_dir_synced , self .cluster_names )
439+ self ._check_full_generation (self .zap_output_dir_samples_yml , self .cluster_names )
440+
441+ # Check whether all generated files are the same as the ones generated from the zap_generate_full test.
442+ failures = []
443+
444+ # Recursively collect all files from both directories
445+ def collect_files (directory ):
446+ """Recursively collect all files in a directory."""
447+ files = {}
448+ for file_path in directory .rglob ("*" ):
449+ if file_path .is_file ():
450+ # Get relative path from the directory root
451+ rel_path = file_path .relative_to (directory )
452+ files [rel_path ] = file_path
453+ return files
454+
455+ full_files = collect_files (self .zap_output_dir_full )
456+ samples_yml_files = collect_files (self .zap_output_dir_samples_yml )
457+
458+ # Check all files from zap_output_dir_full
459+ for rel_path , full_file in full_files .items ():
460+ samples_yml_file = self .zap_output_dir_samples_yml / rel_path
461+
462+ if rel_path not in samples_yml_files :
463+ failures .append (f"File missing in samples_yml: { rel_path } " )
464+ else :
465+ try :
466+ with open (full_file , 'r' , encoding = 'utf-8' , errors = 'ignore' ) as f :
467+ full_content = f .read ()
468+ with open (samples_yml_file , 'r' , encoding = 'utf-8' , errors = 'ignore' ) as f :
469+ samples_yml_content = f .read ()
470+
471+ if full_content != samples_yml_content :
472+ failures .append (f"File content differs: { rel_path } " )
473+ except Exception as e :
474+ failures .append (f"Error comparing file { rel_path } : { str (e )} " )
475+
476+ # Check for files in samples_yml that are not in full
477+ for rel_path in samples_yml_files :
478+ if rel_path not in full_files :
479+ failures .append (f"Extra file in samples_yml: { rel_path } " )
480+
481+ # Print all failures
482+ if failures :
483+ print ("\n " + "=" * 80 )
484+ print (f"Found { len (failures )} file comparison failure(s):" )
485+ print ("=" * 80 )
486+ for failure in failures :
487+ print (f" - { failure } " )
488+ print ("=" * 80 + "\n " )
489+
490+ # Assert that there are no failures
491+ self .assertEqual (len (failures ), 0 , f"Found { len (failures )} file comparison failure(s). See output above for details." )
492+
493+ # Compare zap_from_yml.zap with self.test_zap_file_full
494+ with open (zap_to_compare , "rb" ) as f1 , open (self .test_zap_file_full , "rb" ) as f2 :
495+ zap_to_compare_content = f1 .read ()
496+ zap_full_content = f2 .read ()
497+ self .assertEqual (zap_to_compare_content , zap_full_content , "zap_to_compare.zap and test_zap_file_full differ" )
498+
499+ # Compare zcl_from_yml.json with zcl_json_appended
500+ with open (zcl_to_compare , "rb" ) as f1 , open (self .zcl_json_appended , "rb" ) as f2 :
501+ zcl_to_compare_content = f1 .read ()
502+ zcl_appended_content = f2 .read ()
503+ self .assertEqual (zcl_to_compare_content , zcl_appended_content , "zcl_to_compare.json and zcl_json_appended differ" )
504+
505+ # def test_zap_synchronize(self):
506+ # """
507+ # Checks whether the zap_sync function synchronizes the ZAP file correctly.
508+
509+ # We expect:
510+ # - The ZAP file still contains the custom clusters after synchronization.
511+ # - The zcl.json file is synchronized with the Matter SDK, so contains the new items from the Matter SDK, but also contains the custom clusters.
512+ # - West zap-generate still works without any errors.
513+ # """
514+
515+ # # Input files should exist.
516+ # self.assertTrue(self.zcl_json_appended.exists())
517+ # shutil.copy(TEST_ZAP_FILE_FULL, self.test_zap_file_full)
518+
519+ # # Copy the obsolete zcl.json file to the test directory.
520+ # shutil.copy(TEST_OBSOLETE_ZCL_FILE, self.test_obsolete_zcl_file)
521+ # # Copy the obsolete zap file to the test directory.
522+ # shutil.copy(TEST_OBSOLETE_ZAP_FILE, self.test_obsolete_zap_file)
523+
524+ # # Run zap-sync command
525+ # with patch('zap_common.get_rules_path', return_value=MATTER_BASE / DEFAULT_RULES_RELATIVE_PATH):
526+ # ZapSync().do_run(Namespace(zap_file=self.test_obsolete_zap_file, zcl_json=self.test_obsolete_zcl_file,
527+ # matter_path=MATTER_BASE, clusters=self.test_clusters), [])
528+
529+ # # Check whether the custom clusters are still present in the ZAP file.
530+ # with open(self.test_obsolete_zap_file, 'r') as f:
531+ # content = f.read()
532+ # self.assertIn("Cluster 1", content)
533+ # self.assertIn("Cluster 2", content)
534+ # # Check whether the custom clusters are still present in the zcl.json file.
535+ # with open(self.test_obsolete_zcl_file, 'r') as f:
536+ # content = f.read()
537+ # self.assertIn("Cluster1", content)
538+ # self.assertIn("Cluster2", content)
539+
540+ # # Run zap-generate command
541+ # with patch('zap_generate.get_zap_generate_path', return_value=MATTER_BASE / DEFAULT_ZAP_GENERATE_RELATIVE_PATH):
542+ # with patch('zap_generate.get_app_templates_path', return_value=MATTER_BASE / DEFAULT_APP_TEMPLATES_RELATIVE_PATH):
543+ # with patch('zap_generate.ZapInstaller', return_value=self.zap_installer):
544+ # ZapGenerate().do_run(Namespace(zap_file=self.test_obsolete_zap_file, output=self.zap_output_dir_synced,
545+ # matter_path=MATTER_BASE, full=True, keep_previous=False, zcl=self.test_obsolete_zcl_file, yaml=None), [])
546+
547+ # # Check full generation
548+ # self._check_full_generation(self.zap_output_dir_synced, self.cluster_names)
433549
434550 def _check_full_generation (self , output_dir , clusters ):
435551 self .assertTrue (output_dir .exists ())
@@ -521,7 +637,8 @@ def suite():
521637 'test_zap_generate' ,
522638 'test_zap_append' ,
523639 'test_zap_generate_full' ,
524- 'test_zap_synchronize'
640+ 'test_generate_from_yaml' ,
641+ # 'test_zap_synchronize',
525642 ]
526643
527644 loader = unittest .TestLoader ()
0 commit comments