@@ -253,6 +253,120 @@ def test_library_schema_header_attributes(self):
253253 # Version number might be different for unmerged (without library prefix)
254254 self .assertEqual (schema .with_standard , schema_unmerged .with_standard )
255255
256+ def test_json_empty_list_attributes_omitted (self ):
257+ """Test that empty list attributes (suggestedTag, relatedTag, etc.) are omitted from JSON."""
258+ import json
259+
260+ schema = load_schema_version ("8.4.0" )
261+ json_path = os .path .join (self .temp_dir , "empty_lists.json" )
262+ schema .save_as_json (json_path )
263+
264+ # Read the JSON file and check for empty list attributes
265+ with open (json_path , 'r' , encoding = 'utf-8' ) as f :
266+ json_data = json .load (f )
267+
268+ # Check ALL tags for empty lists
269+ tags_with_empty_lists = []
270+
271+ for tag_name , tag_data in json_data .get ("tags" , {}).items ():
272+ # Check attributes dict
273+ attrs = tag_data .get ("attributes" , {})
274+ for list_attr in ["suggestedTag" , "relatedTag" , "valueClass" , "unitClass" ]:
275+ if list_attr in attrs and attrs [list_attr ] == []:
276+ tags_with_empty_lists .append (f"{ tag_name } .attributes.{ list_attr } " )
277+
278+ # Check explicitAttributes dict
279+ explicit_attrs = tag_data .get ("explicitAttributes" , {})
280+ for list_attr in ["suggestedTag" , "relatedTag" , "valueClass" , "unitClass" ]:
281+ if list_attr in explicit_attrs and explicit_attrs [list_attr ] == []:
282+ tags_with_empty_lists .append (f"{ tag_name } .explicitAttributes.{ list_attr } " )
283+
284+ self .assertEqual (len (tags_with_empty_lists ), 0 ,
285+ f"Found { len (tags_with_empty_lists )} empty list attributes: { tags_with_empty_lists [:5 ]} " )
286+
287+ # Verify that tags WITH these attributes have non-empty lists
288+ if "Sensory-event" in json_data .get ("tags" , {}):
289+ sensory_attrs = json_data ["tags" ]["Sensory-event" ].get ("attributes" , {})
290+ if "suggestedTag" in sensory_attrs :
291+ self .assertTrue (len (sensory_attrs ["suggestedTag" ]) > 0 ,
292+ "Sensory-event suggestedTag should be non-empty if present" )
293+
294+ def test_extras_sections_roundtrip (self ):
295+ """Test that extras sections (Sources, Prefixes, AnnotationPropertyExternal) roundtrip correctly."""
296+ schema = load_schema_version ("8.4.0" )
297+
298+ # Check that original has extras
299+ orig_extras = getattr (schema , 'extras' , {}) or {}
300+ self .assertGreater (len (orig_extras ), 0 , "Schema should have extras sections" )
301+
302+ # Save and reload
303+ json_path = os .path .join (self .temp_dir , "with_extras.json" )
304+ schema .save_as_json (json_path )
305+ reloaded = load_schema (json_path )
306+
307+ # Check reloaded has extras
308+ reloaded_extras = getattr (reloaded , 'extras' , {}) or {}
309+
310+ # Compare each extras section
311+ self .assertEqual (set (orig_extras .keys ()), set (reloaded_extras .keys ()),
312+ "Extras sections should match" )
313+
314+ for key in orig_extras .keys ():
315+ orig_df = orig_extras [key ]
316+ reloaded_df = reloaded_extras [key ]
317+ self .assertTrue (orig_df .equals (reloaded_df ),
318+ f"Extras section '{ key } ' should match after roundtrip" )
319+
320+ def test_library_schema_extras_roundtrip (self ):
321+ """Test that library schema extras (external annotations, etc.) roundtrip correctly."""
322+ schema = load_schema_version ("score_2.1.0" )
323+
324+ # Check that library schema has extras
325+ orig_extras = getattr (schema , 'extras' , {}) or {}
326+ self .assertGreater (len (orig_extras ), 0 , "Library schema should have extras sections" )
327+
328+ # Check for external annotations specifically
329+ self .assertIn ("AnnotationPropertyExternal" , orig_extras ,
330+ "Library schema should have external annotations" )
331+
332+ # Save and reload
333+ json_path = os .path .join (self .temp_dir , "library_with_extras.json" )
334+ schema .save_as_json (json_path , save_merged = False )
335+ reloaded = load_schema (json_path )
336+
337+ # Check reloaded has all extras
338+ reloaded_extras = getattr (reloaded , 'extras' , {}) or {}
339+ self .assertEqual (set (orig_extras .keys ()), set (reloaded_extras .keys ()),
340+ "Library schema extras sections should match" )
341+
342+ # Verify each extras dataframe matches
343+ for key in orig_extras .keys ():
344+ orig_df = orig_extras [key ]
345+ reloaded_df = reloaded_extras [key ]
346+ self .assertTrue (orig_df .equals (reloaded_df ),
347+ f"Library schema extras '{ key } ' should match after roundtrip" )
348+
349+ def test_library_schema_score (self ):
350+ """Test score library schema roundtrip specifically."""
351+ schema = load_schema_version ("score_2.1.0" )
352+
353+ # Test unmerged format
354+ json_path = os .path .join (self .temp_dir , "score_unmerged.json" )
355+ schema .save_as_json (json_path , save_merged = False )
356+ reloaded = load_schema (json_path )
357+
358+ # Verify library attributes
359+ self .assertEqual (schema .library , reloaded .library )
360+ self .assertEqual (schema .version , reloaded .version )
361+ self .assertEqual (schema .with_standard , reloaded .with_standard )
362+
363+ # Verify tag counts match
364+ self .assertEqual (len (schema .tags .all_entries ), len (reloaded .tags .all_entries ))
365+
366+ # Verify prologue and epilogue
367+ self .assertEqual (schema .prologue , reloaded .prologue )
368+ self .assertEqual (schema .epilogue , reloaded .epilogue )
369+
256370
257371if __name__ == "__main__" :
258372 unittest .main ()
0 commit comments