@@ -18,30 +18,31 @@ def test_add_and_read_json(self):
1818 tc .add_json ("data.json" , json_obj )
1919
2020 loaded = tc .read_json ("data.json" )
21+ assert loaded is not None
2122 assert loaded == json_obj
2223
2324 def test_read_json_optional_missing (self ):
2425 """Test reading missing optional JSON file returns None."""
2526 tc = TarCoder ()
26- result = tc .read_json ("missing.json" , required = False )
27+ result = tc .read_json ("missing.json" , optional = True )
2728 assert result is None
2829
2930 def test_read_json_required_missing (self ):
3031 """Test reading missing required JSON file raises error."""
3132 tc = TarCoder ()
3233 with pytest .raises (KeyError ):
33- tc .read_json ("missing.json" , required = True )
34+ tc .read_json ("missing.json" )
3435
3536 def test_add_json_required_none (self ):
3637 """Test that adding None for required JSON raises error."""
3738 tc = TarCoder ()
3839 with pytest .raises (ValueError ):
39- tc .add_json ("data.json" , None , required = True )
40+ tc .add_json ("data.json" , None )
4041
4142 def test_add_json_optional_none (self ):
4243 """Test that adding None for optional JSON does nothing."""
4344 tc = TarCoder ()
44- tc .add_json ("data.json" , None , required = False )
45+ tc .add_json ("data.json" , None , optional = True )
4546 assert not tc .has_file ("data.json" )
4647
4748 def test_complex_json (self ):
@@ -51,6 +52,7 @@ def test_complex_json(self):
5152
5253 tc .add_json ("complex.json" , json_obj )
5354 loaded = tc .read_json ("complex.json" )
55+ assert loaded is not None
5456 assert loaded == json_obj
5557
5658
@@ -66,14 +68,15 @@ def test_add_and_read_vector(self):
6668 tc .add_vector ("values.bin" , sized_type , values )
6769
6870 loaded = tc .read_vector ("values.bin" , sized_type )
71+ assert loaded is not None
6972 assert loaded == values
7073
7174 def test_read_vector_optional_missing (self ):
7275 """Test reading missing optional vector returns None."""
7376 tc = TarCoder ()
7477 sized_type = SizedType (NumericPrimitiveType .UINT , 32 )
7578
76- result = tc .read_vector ("missing.bin" , sized_type , required = False )
79+ result = tc .read_vector ("missing.bin" , sized_type , optional = True )
7780 assert result is None
7881
7982 def test_read_vector_required_missing (self ):
@@ -82,15 +85,15 @@ def test_read_vector_required_missing(self):
8285 sized_type = SizedType (NumericPrimitiveType .UINT , 32 )
8386
8487 with pytest .raises (KeyError ):
85- tc .read_vector ("missing.bin" , sized_type , required = True )
88+ tc .read_vector ("missing.bin" , sized_type )
8689
8790 def test_add_vector_required_none (self ):
8891 """Test that adding None for required vector raises error."""
8992 tc = TarCoder ()
9093 sized_type = SizedType (NumericPrimitiveType .UINT , 32 )
9194
9295 with pytest .raises (ValueError ):
93- tc .add_vector ("values.bin" , sized_type , None , required = True )
96+ tc .add_vector ("values.bin" , sized_type , None )
9497
9598 def test_vector_roundtrip (self ):
9699 """Test vector round-trip conversion."""
@@ -101,6 +104,7 @@ def test_vector_roundtrip(self):
101104 tc1 .add_vector ("data.bin" , sized_type , original )
102105
103106 loaded = tc1 .read_vector ("data.bin" , sized_type )
107+ assert loaded is not None
104108 assert loaded == original
105109
106110
@@ -115,6 +119,7 @@ def test_add_and_read_bitvector(self):
115119 tc .add_bitvector ("bits.bin" , bitvector )
116120
117121 loaded = tc .read_bitvector ("bits.bin" , num_entries = 5 )
122+ assert loaded is not None
118123 # May be padded, so check the first 5 elements
119124 assert loaded [:5 ] == bitvector
120125
@@ -127,6 +132,7 @@ def test_bitvector_padding(self):
127132 tc .add_bitvector ("bits.bin" , bitvector , pad_to_8_bytes = True )
128133
129134 loaded = tc .read_bitvector ("bits.bin" , num_entries = 5 )
135+ assert loaded is not None
130136 assert loaded [:5 ] == bitvector
131137 # Remaining should be False (padding)
132138 assert all (not bit for bit in loaded [5 :])
@@ -139,6 +145,7 @@ def test_bitvector_no_padding(self):
139145 tc .add_bitvector ("bits.bin" , bitvector , pad_to_8_bytes = False )
140146
141147 loaded = tc .read_bitvector ("bits.bin" , num_entries = 8 )
148+ assert loaded is not None
142149 assert loaded == bitvector
143150
144151 def test_bitvector_truncation (self ):
@@ -151,10 +158,159 @@ def test_bitvector_truncation(self):
151158
152159 # Read only 8 entries
153160 loaded = tc .read_bitvector ("bits.bin" , num_entries = 8 )
161+ assert loaded is not None
154162 assert len (loaded ) == 8
155163 assert loaded == bitvector [:8 ]
156164
157165
166+ class TestTarCoderVectorWithRanges :
167+ """Test vector with CSR ranges reading and writing."""
168+
169+ def test_add_and_read_vector_with_ranges (self ):
170+ """Test adding and reading a vector with CSR ranges."""
171+ tc = TarCoder ()
172+ vector = [1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ]
173+ sized_type = SizedType (NumericPrimitiveType .UINT , 32 )
174+
175+ tc .add_vector_with_ranges ("data.bin" , sized_type , vector , "ranges.bin" )
176+
177+ loaded = tc .read_vector_with_ranges ("data.bin" , NumericPrimitiveType .UINT , filename_csr = "ranges.bin" )
178+ assert loaded is not None
179+ assert loaded == vector
180+
181+ def test_read_vector_with_ranges_optional_missing (self ):
182+ """Test reading missing optional vector with ranges returns None."""
183+ tc = TarCoder ()
184+ result = tc .read_vector_with_ranges (
185+ "missing.bin" , NumericPrimitiveType .UINT , optional = True , filename_csr = "ranges.bin"
186+ )
187+ assert result is None
188+
189+ def test_read_vector_with_ranges_required_missing (self ):
190+ """Test reading missing required vector with ranges raises error."""
191+ tc = TarCoder ()
192+ with pytest .raises (KeyError ):
193+ tc .read_vector_with_ranges ("missing.bin" , NumericPrimitiveType .UINT , filename_csr = "ranges.bin" )
194+
195+ def test_read_vector_with_ranges_missing_csr (self ):
196+ """Test that missing CSR file raises error even if main file exists."""
197+ tc = TarCoder ()
198+ vector = [1 , 2 , 3 , 4 , 5 ]
199+ sized_type = SizedType (NumericPrimitiveType .UINT , 32 )
200+
201+ tc .add_vector_with_ranges ("data.bin" , sized_type , vector , "ranges.bin" )
202+ # Remove the CSR file using dict interface
203+ tc .pop ("ranges.bin" , None )
204+
205+ with pytest .raises (KeyError ):
206+ tc .read_vector_with_ranges ("data.bin" , NumericPrimitiveType .UINT , filename_csr = "ranges.bin" )
207+
208+ def test_add_vector_with_ranges_required_none (self ):
209+ """Test that adding None for required vector with ranges raises error."""
210+ tc = TarCoder ()
211+ sized_type = SizedType (NumericPrimitiveType .UINT , 32 )
212+
213+ with pytest .raises (ValueError ):
214+ tc .add_vector_with_ranges ("data.bin" , sized_type , None , "ranges.bin" )
215+
216+ def test_add_vector_with_ranges_optional_none (self ):
217+ """Test that adding None for optional vector with ranges does nothing."""
218+ tc = TarCoder ()
219+ sized_type = SizedType (NumericPrimitiveType .UINT , 32 )
220+
221+ tc .add_vector_with_ranges ("data.bin" , sized_type , None , "ranges.bin" , optional = True )
222+ assert not tc .has_file ("data.bin" )
223+ assert not tc .has_file ("ranges.bin" )
224+
225+ def test_vector_with_ranges_roundtrip (self ):
226+ """Test vector with ranges round-trip conversion."""
227+ original = [100 , 200 , 300 , 400 , 500 , 600 ]
228+ sized_type = SizedType (NumericPrimitiveType .UINT , 64 )
229+
230+ tc1 = TarCoder ()
231+ tc1 .add_vector_with_ranges ("data.bin" , sized_type , original , "ranges.bin" )
232+
233+ loaded = tc1 .read_vector_with_ranges ("data.bin" , NumericPrimitiveType .UINT , filename_csr = "ranges.bin" )
234+ assert loaded is not None
235+ assert loaded == original
236+
237+
238+ class TestTarCoderStrings :
239+ """Test string vector reading and writing with CSR."""
240+
241+ def test_add_and_read_strings (self ):
242+ """Test adding and reading strings with CSR."""
243+ tc = TarCoder ()
244+ strings = ["hello" , "world" , "test" , "data" ]
245+
246+ tc .add_strings ("strings.bin" , strings , "strings_csr.bin" )
247+
248+ loaded = tc .read_strings ("strings.bin" , filename_csr = "strings_csr.bin" )
249+ assert loaded is not None
250+ assert loaded == strings
251+
252+ def test_read_strings_optional_missing (self ):
253+ """Test reading missing optional strings returns None."""
254+ tc = TarCoder ()
255+ result = tc .read_strings ("missing.bin" , optional = True , filename_csr = "strings_csr.bin" )
256+ assert result is None
257+
258+ def test_read_strings_required_missing (self ):
259+ """Test reading missing required strings raises error."""
260+ tc = TarCoder ()
261+ with pytest .raises (KeyError ):
262+ tc .read_strings ("missing.bin" , filename_csr = "strings_csr.bin" )
263+
264+ def test_read_strings_missing_csr (self ):
265+ """Test that missing CSR file raises error even if main file exists."""
266+ tc = TarCoder ()
267+ strings = ["a" , "b" , "c" ]
268+
269+ tc .add_strings ("strings.bin" , strings , "strings_csr.bin" )
270+ # Remove the CSR file using dict interface
271+ tc .pop ("strings_csr.bin" , None )
272+
273+ with pytest .raises (KeyError ):
274+ tc .read_strings ("strings.bin" , filename_csr = "strings_csr.bin" )
275+
276+ def test_add_strings_required_none (self ):
277+ """Test that adding None for required strings raises error."""
278+ tc = TarCoder ()
279+
280+ with pytest .raises (ValueError ):
281+ tc .add_strings ("strings.bin" , None , "strings_csr.bin" )
282+
283+ def test_add_strings_optional_none (self ):
284+ """Test that adding None for optional strings does nothing."""
285+ tc = TarCoder ()
286+
287+ tc .add_strings ("strings.bin" , None , "strings_csr.bin" , optional = True )
288+ assert not tc .has_file ("strings.bin" )
289+ assert not tc .has_file ("strings_csr.bin" )
290+
291+ def test_strings_roundtrip (self ):
292+ """Test strings round-trip conversion."""
293+ original = ["foo" , "bar" , "baz" , "qux" , "long string with spaces" ]
294+
295+ tc1 = TarCoder ()
296+ tc1 .add_strings ("strings.bin" , original , "strings_csr.bin" )
297+
298+ loaded = tc1 .read_strings ("strings.bin" , filename_csr = "strings_csr.bin" )
299+ assert loaded is not None
300+ assert loaded == original
301+
302+ def test_strings_single_empty_string (self ):
303+ """Test handling of empty strings in list."""
304+ tc = TarCoder ()
305+ strings = ["" , "non-empty" , "" ]
306+
307+ tc .add_strings ("strings.bin" , strings , "strings_csr.bin" )
308+
309+ loaded = tc .read_strings ("strings.bin" , filename_csr = "strings_csr.bin" )
310+ assert loaded is not None
311+ assert loaded == strings
312+
313+
158314class TestTarCoderIntegration :
159315 """Integration tests for TarCoder."""
160316
@@ -168,17 +324,23 @@ def test_multiple_files(self):
168324 tc .add_bitvector ("flags.bin" , [True , False , True , False ])
169325
170326 # Verify all files exist and can be read
171- assert tc .read_json ("metadata.json" ) == {"version" : 1 }
172- assert tc .read_vector ("values.bin" , SizedType (NumericPrimitiveType .UINT , 32 )) == [1 , 2 , 3 ]
173- assert tc .read_bitvector ("flags.bin" , num_entries = 4 )[:4 ] == [True , False , True , False ]
327+ json_data = tc .read_json ("metadata.json" )
328+ assert json_data is not None
329+ assert json_data == {"version" : 1 }
330+ vector_data = tc .read_vector ("values.bin" , SizedType (NumericPrimitiveType .UINT , 32 ))
331+ assert vector_data is not None
332+ assert vector_data == [1 , 2 , 3 ]
333+ bits_data = tc .read_bitvector ("flags.bin" , num_entries = 4 )
334+ assert bits_data is not None
335+ assert bits_data [:4 ] == [True , False , True , False ]
174336
175337 def test_tar_coder_inherits_tarfile (self ):
176338 """Test that TarCoder has all TarFile functionality."""
177339 tc = TarCoder ()
178340
179341 # Test dict interface
180342 tc ["raw.bin" ] = b"raw data"
181- assert tc .get_file ("raw.bin" ) == b"raw data"
343+ assert tc .read_file ("raw.bin" ) == b"raw data"
182344
183345 # Test add_file
184346 tc .add_file ("file.bin" , b"content" )
0 commit comments