Coverage for tests / unit / no_torch / test_zanj_edge_cases.py: 99%
147 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-22 19:31 -0700
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-22 19:31 -0700
1from __future__ import annotations
3import os
4import zipfile
5from pathlib import Path
7import numpy as np
8import pytest
9from muutils.errormode import ErrorMode
11from zanj import ZANJ
13TEST_DATA_PATH: Path = Path("tests/junk_data")
16def test_zanj_with_different_configs():
17 """Test ZANJ with different configuration options"""
18 # Create data to save
19 data = {
20 "name": "test_config",
21 "array": np.random.rand(50, 50), # Just below default threshold
22 }
24 # Test with default config (external_array_threshold=256)
25 z1 = ZANJ()
26 path1 = TEST_DATA_PATH / "test_default_config.zanj"
27 z1.save(data, path1)
29 # Test with low threshold to force external storage
30 z2 = ZANJ(external_array_threshold=10)
31 path2 = TEST_DATA_PATH / "test_low_threshold.zanj"
32 z2.save(data, path2)
34 # Test with high threshold to force internal storage
35 z3 = ZANJ(external_array_threshold=10000)
36 path3 = TEST_DATA_PATH / "test_high_threshold.zanj"
37 z3.save(data, path3)
39 # Check that the files exist
40 assert path1.exists()
41 assert path2.exists()
42 assert path3.exists()
44 # Check that all three files can be loaded correctly
45 data1 = z1.read(path1)
46 data2 = z2.read(path2)
47 data3 = z3.read(path3)
49 assert data1["name"] == data["name"]
50 assert data2["name"] == data["name"]
51 assert data3["name"] == data["name"]
53 assert np.allclose(data1["array"], data["array"])
54 assert np.allclose(data2["array"], data["array"])
55 assert np.allclose(data3["array"], data["array"])
58def test_zanj_compression_options():
59 """Test different compression settings"""
60 data = {
61 "name": "compression_test",
62 "array": np.random.rand(100, 100),
63 }
65 # Test with default compression (True -> ZIP_DEFLATED)
66 z1 = ZANJ(compress=True)
67 path1 = TEST_DATA_PATH / "test_default_compression.zanj"
68 z1.save(data, path1)
70 # Test with no compression
71 z2 = ZANJ(compress=False)
72 path2 = TEST_DATA_PATH / "test_no_compression.zanj"
73 z2.save(data, path2)
75 # Test with explicit compression level
76 z3 = ZANJ(compress=zipfile.ZIP_DEFLATED)
77 path3 = TEST_DATA_PATH / "test_explicit_compression.zanj"
78 z3.save(data, path3)
80 # Check files exist
81 assert path1.exists()
82 assert path2.exists()
83 assert path3.exists()
85 # Both should load correctly
86 data1 = z1.read(path1)
87 data2 = z2.read(path2)
88 data3 = z3.read(path3)
90 assert data1["name"] == data["name"]
91 assert data2["name"] == data["name"]
92 assert data3["name"] == data["name"]
94 assert np.allclose(data1["array"], data["array"])
95 assert np.allclose(data2["array"], data["array"])
96 assert np.allclose(data3["array"], data["array"])
99def test_zanj_error_modes():
100 """Test different error modes"""
102 # Create a class with __repr__ that will cause an error during serialization
103 class ForceExceptionOnSerialize:
104 def __repr__(self):
105 raise Exception("Forced exception during serialization")
107 # Create data with a problematic object
108 data = {
109 "name": "error_test",
110 "unserializable": ForceExceptionOnSerialize(),
111 }
113 # Create a subclass of ZANJ to force an exception
114 class ExceptionForcingZANJ(ZANJ):
115 def json_serialize(self, obj):
116 if isinstance(obj, dict) and "unserializable" in obj:
117 raise Exception("Forced exception")
118 return super().json_serialize(obj)
120 # Test with EXCEPT mode (should raise)
121 z3 = ExceptionForcingZANJ(error_mode=ErrorMode.EXCEPT)
122 path3 = TEST_DATA_PATH / "test_error_except.zanj"
123 with pytest.raises(Exception):
124 z3.save(data, path3) # This should fail
127def test_zanj_array_modes():
128 """Test different array modes"""
129 data = {
130 "name": "array_mode_test",
131 "array": np.random.rand(5, 5),
132 }
134 # Test with list mode (use the string value, not the enum attribute)
135 z1 = ZANJ(internal_array_mode="list")
136 path1 = TEST_DATA_PATH / "test_array_mode_list.zanj"
137 z1.save(data, path1)
139 # Test with array_list_meta mode
140 z3 = ZANJ(internal_array_mode="array_list_meta")
141 path3 = TEST_DATA_PATH / "test_array_mode_array_list_meta.zanj"
142 z3.save(data, path3)
144 # Check that all files can be loaded correctly
145 data1 = z1.read(path1)
146 data3 = z3.read(path3)
148 assert data1["name"] == data["name"]
149 assert data3["name"] == data["name"]
151 assert np.allclose(data1["array"], data["array"])
152 assert np.allclose(data3["array"], data["array"])
155def test_zanj_meta():
156 """Test the meta method of ZANJ"""
157 # Create a ZANJ instance
158 z = ZANJ()
160 # Call the meta method
161 meta = z.meta()
163 # Check that it contains the expected fields
164 assert "zanj_cfg" in meta
165 assert "sysinfo" in meta
166 assert "externals_info" in meta
167 assert "timestamp" in meta
169 # Check that zanj_cfg contains configuration information
170 assert "error_mode" in meta["zanj_cfg"]
171 assert "array_mode" in meta["zanj_cfg"]
172 assert "external_array_threshold" in meta["zanj_cfg"]
173 assert "external_list_threshold" in meta["zanj_cfg"]
174 assert "compress" in meta["zanj_cfg"]
175 assert "serialization_handlers" in meta["zanj_cfg"]
176 assert "load_handlers" in meta["zanj_cfg"]
179def test_zanj_externals_info():
180 """Test the externals_info method of ZANJ"""
181 # Create a ZANJ instance with a low threshold
182 z = ZANJ(external_array_threshold=10)
184 # Create data with an array that will be stored externally
185 data = {
186 "name": "externals_test",
187 "array": np.random.rand(20, 20),
188 }
190 # Save the data
191 path = TEST_DATA_PATH / "test_externals_info.zanj"
192 z.save(data, path)
194 # The externals should be empty after saving
195 assert len(z._externals) == 0
197 # Load the data to populate externals
198 loaded_data = z.read(path)
200 # Check that the data was loaded correctly
201 assert loaded_data["name"] == data["name"]
202 assert np.allclose(loaded_data["array"], data["array"])
205def test_zanj_save_extension():
206 """Test that ZANJ adds the .zanj extension if not provided"""
207 data = {"name": "extension_test"}
209 # Save without extension
210 z = ZANJ()
211 path_str = str(TEST_DATA_PATH / "test_no_extension")
212 actual_path = z.save(data, path_str)
214 # Check that .zanj extension was added
215 assert actual_path.endswith(".zanj")
216 assert actual_path == path_str + ".zanj"
218 # Check that the file exists
219 assert os.path.exists(actual_path)
221 # Check that we can load it
222 loaded_data = z.read(actual_path)
223 assert loaded_data["name"] == data["name"]
225 # Save with extension already provided
226 path_with_ext = str(TEST_DATA_PATH / "test_with_extension.zanj")
227 actual_path2 = z.save(data, path_with_ext)
229 # Check that the extension was not added again
230 assert actual_path2 == path_with_ext
231 assert not actual_path2.endswith(".zanj.zanj")
233 # Check that the file exists
234 assert os.path.exists(actual_path2)
236 # Check that we can load it
237 loaded_data2 = z.read(actual_path2)
238 assert loaded_data2["name"] == data["name"]
241def test_zanj_file_not_found():
242 """Test behavior when trying to read a non-existent file"""
243 z = ZANJ()
245 # Try to read a non-existent file
246 non_existent_path = TEST_DATA_PATH / "non_existent_file.zanj"
248 # Should raise FileNotFoundError
249 with pytest.raises(FileNotFoundError):
250 z.read(non_existent_path)
252 # Try to read a directory (not a file)
253 # First ensure the directory exists
254 dir_path = TEST_DATA_PATH / "test_dir"
255 dir_path.mkdir(exist_ok=True)
257 # Should raise FileNotFoundError with "not a file" message
258 with pytest.raises(FileNotFoundError):
259 z.read(dir_path)
262def test_zanj_create_directory():
263 """Test that ZANJ creates the directory structure if needed"""
264 data = {"name": "dir_test"}
266 # Use a nested directory structure that doesn't exist yet
267 nested_dir = TEST_DATA_PATH / "new_dir" / "nested" / "structure"
268 nested_path = nested_dir / "test_file.zanj"
270 # Make sure the directory doesn't exist
271 import shutil
273 if (TEST_DATA_PATH / "new_dir").exists():
274 shutil.rmtree(TEST_DATA_PATH / "new_dir")
276 # Save should create all necessary directories
277 z = ZANJ()
278 z.save(data, nested_path)
280 # Check that directories were created
281 assert nested_dir.exists()
282 assert nested_dir.is_dir()
284 # Check that the file exists
285 assert nested_path.exists()
286 assert nested_path.is_file()
288 # Check that we can load it
289 loaded_data = z.read(nested_path)
290 assert loaded_data["name"] == data["name"]