@@ -84,10 +84,10 @@ def test_equality(self):
8484class TestAnnotationHandling (unittest .TestCase ):
8585 def test_get_annotations_with_index (self ):
8686 """Test that only annotations containing index are returned from get_annotations()"""
87- smf = SigMFFile (copy .deepcopy (TEST_METADATA ))
88- smf .add_annotation (start_index = 1 )
89- smf .add_annotation (start_index = 4 , length = 4 )
90- annotations_idx10 = smf .get_annotations (index = 10 )
87+ meta = SigMFFile (copy .deepcopy (TEST_METADATA ))
88+ meta .add_annotation (start_index = 1 )
89+ meta .add_annotation (start_index = 4 , length = 4 )
90+ annotations_idx10 = meta .get_annotations (index = 10 )
9191 self .assertListEqual (
9292 annotations_idx10 ,
9393 [
@@ -96,26 +96,26 @@ def test_get_annotations_with_index(self):
9696 ],
9797 )
9898
99- def test__count_samples_from_annotation (self ):
99+ def test_sample_count_from_annotations (self ):
100100 """Make sure sample count from annotations use correct end index"""
101- smf = SigMFFile (copy .deepcopy (TEST_METADATA ))
102- smf .add_annotation (start_index = 0 , length = 32 )
103- smf .add_annotation (start_index = 4 , length = 4 )
104- sample_count = smf ._count_samples ()
101+ meta = SigMFFile (copy .deepcopy (TEST_METADATA ))
102+ meta .add_annotation (start_index = 0 , length = 32 )
103+ meta .add_annotation (start_index = 4 , length = 4 )
104+ sample_count = meta ._count_samples ()
105105 self .assertEqual (sample_count , 32 )
106106
107107 def test_set_data_file_without_annotations (self ):
108108 """
109109 Make sure setting data_file with no annotations registered does not
110110 raise any errors
111111 """
112- smf = SigMFFile (copy .deepcopy (TEST_METADATA ))
113- smf ._metadata [SigMFFile .ANNOTATION_KEY ].clear ()
112+ meta = SigMFFile (copy .deepcopy (TEST_METADATA ))
113+ meta ._metadata [SigMFFile .ANNOTATION_KEY ].clear ()
114114 with tempfile .TemporaryDirectory () as tmpdir :
115115 temp_path_data = Path (tmpdir ) / "datafile"
116116 TEST_FLOAT32_DATA .tofile (temp_path_data )
117- smf .set_data_file (temp_path_data )
118- samples = smf .read_samples ()
117+ meta .set_data_file (temp_path_data )
118+ samples = meta .read_samples ()
119119 self .assertTrue (len (samples ) == 16 )
120120
121121 def test_set_data_file_with_annotations (self ):
@@ -124,15 +124,15 @@ def test_set_data_file_with_annotations(self):
124124 count from data_file and issue a warning if annotations have end
125125 indices bigger than file end index
126126 """
127- smf = SigMFFile (copy .deepcopy (TEST_METADATA ))
128- smf .add_annotation (start_index = 0 , length = 32 )
127+ meta = SigMFFile (copy .deepcopy (TEST_METADATA ))
128+ meta .add_annotation (start_index = 0 , length = 32 )
129129 with tempfile .TemporaryDirectory () as tmpdir :
130130 temp_path_data = Path (tmpdir ) / "datafile"
131131 TEST_FLOAT32_DATA .tofile (temp_path_data )
132132 with self .assertWarns (Warning ):
133133 # Issues warning since file ends before the final annotatio
134- smf .set_data_file (temp_path_data )
135- samples = smf .read_samples ()
134+ meta .set_data_file (temp_path_data )
135+ samples = meta .read_samples ()
136136 self .assertTrue (len (samples ) == 16 )
137137
138138
@@ -222,9 +222,9 @@ def test_key_validity():
222222
223223def test_ordered_metadata ():
224224 """check to make sure the metadata is sorted as expected"""
225- sigf = SigMFFile ()
225+ meta = SigMFFile ()
226226 top_sort_order = ["global" , "captures" , "annotations" ]
227- for kdx , key in enumerate (sigf .ordered_metadata ()):
227+ for kdx , key in enumerate (meta .ordered_metadata ()):
228228 assert kdx == top_sort_order .index (key )
229229
230230
@@ -249,7 +249,7 @@ def prepare(self, data: list, meta: dict, dtype: type, autoscale: bool = True) -
249249 meta = sigmf .fromfile (self .temp_path_meta , skip_checksum = True , autoscale = autoscale )
250250 return meta
251251
252- def test_000 (self ) -> None :
252+ def test_compliant_two_capture_recording (self ) -> None :
253253 """compliant two-capture recording"""
254254 meta = self .prepare (TEST_U8_DATA0 , TEST_U8_META0 , np .uint8 , autoscale = False )
255255 self .assertEqual (256 , meta ._count_samples ())
@@ -260,7 +260,7 @@ def test_000(self) -> None:
260260 self .assertTrue (np .array_equal (np .array ([]), meta .read_samples_in_capture (0 )))
261261 self .assertTrue (np .array_equal (TEST_U8_DATA0 , meta .read_samples_in_capture (1 )))
262262
263- def test_001 (self ) -> None :
263+ def test_two_capture_with_header_trailing_bytes (self ) -> None :
264264 """two capture recording with header_bytes and trailing_bytes set"""
265265 meta = self .prepare (TEST_U8_DATA1 , TEST_U8_META1 , np .uint8 , autoscale = False )
266266 self .assertEqual (192 , meta ._count_samples ())
@@ -270,7 +270,7 @@ def test_001(self) -> None:
270270 self .assertTrue (np .array_equal (np .arange (128 ), meta .read_samples_in_capture (0 )))
271271 self .assertTrue (np .array_equal (np .arange (128 , 192 ), meta .read_samples_in_capture (1 )))
272272
273- def test_002 (self ) -> None :
273+ def test_two_capture_with_multiple_header_bytes (self ) -> None :
274274 """two capture recording with multiple header_bytes set"""
275275 meta = self .prepare (TEST_U8_DATA2 , TEST_U8_META2 , np .uint8 , autoscale = False )
276276 self .assertEqual (192 , meta ._count_samples ())
@@ -280,7 +280,7 @@ def test_002(self) -> None:
280280 self .assertTrue (np .array_equal (np .arange (128 ), meta .read_samples_in_capture (0 )))
281281 self .assertTrue (np .array_equal (np .arange (128 , 192 ), meta .read_samples_in_capture (1 )))
282282
283- def test_003 (self ) -> None :
283+ def test_three_capture_with_multiple_header_bytes (self ) -> None :
284284 """three capture recording with multiple header_bytes set"""
285285 meta = self .prepare (TEST_U8_DATA3 , TEST_U8_META3 , np .uint8 , autoscale = False )
286286 self .assertEqual (192 , meta ._count_samples ())
@@ -292,8 +292,8 @@ def test_003(self) -> None:
292292 self .assertTrue (np .array_equal (np .arange (32 , 128 ), meta .read_samples_in_capture (1 )))
293293 self .assertTrue (np .array_equal (np .arange (128 , 192 ), meta .read_samples_in_capture (2 )))
294294
295- def test_004 (self ) -> None :
296- """two channel version of 000 """
295+ def test_two_channel_capture_recording (self ) -> None :
296+ """two channel version of compliant capture recording """
297297 meta = self .prepare (TEST_U8_DATA4 , TEST_U8_META4 , np .uint8 , autoscale = False )
298298 self .assertEqual (96 , meta ._count_samples ())
299299 self .assertFalse (meta ._is_conforming_dataset ())
@@ -302,20 +302,20 @@ def test_004(self) -> None:
302302 self .assertTrue (np .array_equal (np .arange (64 ).repeat (2 ).reshape (- 1 , 2 ), meta .read_samples_in_capture (0 )))
303303 self .assertTrue (np .array_equal (np .arange (64 , 96 ).repeat (2 ).reshape (- 1 , 2 ), meta .read_samples_in_capture (1 )))
304304
305- def test_slicing_ru8 (self ) -> None :
305+ def test_slice_real_uint8 (self ) -> None :
306306 """slice real uint8"""
307307 meta = self .prepare (TEST_U8_DATA0 , TEST_U8_META0 , np .uint8 , autoscale = False )
308308 self .assertTrue (np .array_equal (meta [:], TEST_U8_DATA0 ))
309309 self .assertTrue (np .array_equal (meta [6 ], TEST_U8_DATA0 [6 ]))
310310 self .assertTrue (np .array_equal (meta [1 :- 1 ], TEST_U8_DATA0 [1 :- 1 ]))
311311
312- def test_slicing_rf32 (self ) -> None :
312+ def test_slice_real_float32 (self ) -> None :
313313 """slice real float32"""
314314 meta = self .prepare (TEST_FLOAT32_DATA , TEST_METADATA , np .float32 )
315315 self .assertTrue (np .array_equal (meta [:], TEST_FLOAT32_DATA ))
316316 self .assertTrue (np .array_equal (meta [9 ], TEST_FLOAT32_DATA [9 ]))
317317
318- def test_slicing_multiple_channels (self ) -> None :
318+ def test_slice_multiple_channels (self ) -> None :
319319 """slice multiple channels"""
320320
321321 meta = self .prepare (TEST_U8_DATA4 , TEST_U8_META4 , np .uint8 , autoscale = False )
@@ -325,7 +325,7 @@ def test_slicing_multiple_channels(self) -> None:
325325 self .assertTrue (np .array_equal (meta [0 ], channelized [0 ]))
326326 self .assertTrue (np .array_equal (meta [1 , :], channelized [1 ]))
327327
328- def test_boundaries (self ) -> None :
328+ def test_capture_byte_boundaries (self ) -> None :
329329 """capture byte boundaries from pairs & archives"""
330330 # get a meta pair and archive
331331 meta = self .prepare (TEST_U8_DATA3 , TEST_U8_META3 , np .uint8 )
@@ -336,6 +336,41 @@ def test_boundaries(self) -> None:
336336 self .assertEqual (meta .get_capture_byte_boundaries (bdx ), arc .get_capture_byte_boundaries (bdx ))
337337 self .assertTrue (np .array_equal (meta .read_samples_in_capture (bdx ), arc .read_samples_in_capture (bdx )))
338338
339+ def test_add_capture (self ):
340+ """test basic capture addition"""
341+ meta = SigMFFile ()
342+ meta .add_capture (start_index = 0 , metadata = {})
343+
344+ def test_add_capture_metadata_merge (self ):
345+ """test that adding capture with existing start_index properly merges metadata"""
346+ meta = SigMFFile ()
347+
348+ # add initial capture with some metadata
349+ initial_meta = {"core:frequency" : 915e6 , "core:sample_rate" : 1e6 }
350+ meta .add_capture (start_index = 0 , metadata = initial_meta )
351+
352+ # add capture with same start_index but additional metadata
353+ additional_meta = {"core:datetime" : "2026-03-17T10:00:00Z" , "custom:gain" : 30 }
354+ meta .add_capture (start_index = 0 , metadata = additional_meta )
355+
356+ # verify metadata was merged properly
357+ captures = meta .get_captures ()
358+ self .assertEqual (len (captures ), 1 , "should have exactly one capture" )
359+
360+ merged_capture = captures [0 ]
361+ # original metadata should be preserved
362+ self .assertEqual (merged_capture ["core:frequency" ], 915e6 )
363+ self .assertEqual (merged_capture ["core:sample_rate" ], 1e6 )
364+ # new metadata should be added
365+ self .assertEqual (merged_capture ["core:datetime" ], "2026-03-17T10:00:00Z" )
366+ self .assertEqual (merged_capture ["custom:gain" ], 30 )
367+
368+ def test_add_multiple_captures_and_annotations (self ):
369+ """test adding multiple captures with annotations"""
370+ meta = SigMFFile ()
371+ for idx in range (3 ):
372+ simulate_capture (meta , idx , 1024 )
373+
339374
340375def simulate_capture (sigmf_md , n , capture_len ):
341376 start_index = capture_len * n
@@ -352,38 +387,35 @@ def simulate_capture(sigmf_md, n, capture_len):
352387 sigmf_md .add_annotation (start_index = start_index , length = capture_len , metadata = annotation_md )
353388
354389
355- def test_default_constructor ():
356- SigMFFile ()
357-
358-
359- def test_set_non_required_global_field ():
360- sigf = SigMFFile ()
361- sigf .set_global_field ("this_is:not_in_the_schema" , None )
362-
363-
364- def test_add_capture ():
365- sigf = SigMFFile ()
366- sigf .add_capture (start_index = 0 , metadata = {})
367-
368-
369- def test_add_annotation ():
370- sigf = SigMFFile ()
371- sigf .add_capture (start_index = 0 )
372- meta = {"latitude" : 40.0 , "longitude" : - 105.0 }
373- sigf .add_annotation (start_index = 0 , length = 128 , metadata = meta )
374-
375-
376- def test_fromarchive (test_sigmffile ):
377- with tempfile .NamedTemporaryFile (suffix = ".sigmf" ) as temp_file :
378- archive_path = test_sigmffile .archive (name = temp_file .name , overwrite = True )
379- result = sigmf .fromarchive (archive_path = archive_path )
380- assert result ._metadata == test_sigmffile ._metadata == TEST_METADATA
381-
382-
383- def test_add_multiple_captures_and_annotations ():
384- sigf = SigMFFile ()
385- for idx in range (3 ):
386- simulate_capture (sigf , idx , 1024 )
390+ class TestBasicFunctionality (unittest .TestCase ):
391+ """test basic SigMFFile functionality"""
392+
393+ def test_default_constructor (self ):
394+ """test default constructor"""
395+ SigMFFile ()
396+
397+ def test_set_non_required_global_field (self ):
398+ """test setting field not in schema"""
399+ meta = SigMFFile ()
400+ meta .set_global_field ("this_is:not_in_the_schema" , None )
401+
402+ def test_add_annotation (self ):
403+ """test basic annotation addition"""
404+ meta = SigMFFile ()
405+ meta .add_capture (start_index = 0 )
406+ annot = {"latitude" : 40.0 , "longitude" : - 105.0 }
407+ meta .add_annotation (start_index = 0 , length = 128 , metadata = annot )
408+
409+ def test_load_from_archive (self ):
410+ """test loading from archive"""
411+ with tempfile .NamedTemporaryFile (suffix = ".sigmf" ) as temp_file :
412+ # create temporary data file
413+ with tempfile .NamedTemporaryFile (suffix = ".sigmf-data" , delete = False ) as data_file :
414+ TEST_FLOAT32_DATA .tofile (data_file .name )
415+ meta = SigMFFile (TEST_METADATA , data_file = data_file .name )
416+ archive_path = meta .archive (name = temp_file .name , overwrite = True )
417+ loopback = sigmf .fromarchive (archive_path = archive_path )
418+ self .assertEqual (loopback ._metadata , meta ._metadata )
387419
388420
389421class TestOverwrite (unittest .TestCase ):
0 commit comments