Coverage for tests/unit/no_torch/test_serializing_edge_cases.py: 100%

1"""Edge case tests for zanj/serializing.py to improve coverage."""

2

3 from __future__ import annotations

4

5 import numpy as np

6 import pytest

7

8 from zanj import ZANJ

9 from zanj.serializing import zanj_external_serialize

10

11

12 class TestZanjExternalSerialize:

13 """Tests for zanj_external_serialize function edge cases."""

14

15 def test_duplicate_external_path(self):

16 """Lines 124-127: Duplicate external path should raise ValueError."""

17 z = ZANJ()

18 array1 = np.random.rand(10, 10)

19 array2 = np.random.rand(5, 5)

20

21 # First call with path ('data',) should succeed

22 zanj_external_serialize(

23 z, array1, path=("data",), item_type="npy", _format="numpy.ndarray:external"

24 )

25

26 # Second call with same path should raise ValueError

27 with pytest.raises(ValueError, match="already exists"):

28 zanj_external_serialize(

29 z,

30 array2,

31 path=("data",),

32 item_type="npy",

33 _format="numpy.ndarray:external",

34 )

35

36 def test_path_prefix_conflict_child_first(self):

37 """Lines 137-142: Path prefix conflict where new path is parent of existing."""

38 z = ZANJ()

39 array1 = np.random.rand(10, 10)

40 array2 = np.random.rand(5, 5)

41

42 # First: add child path 'layer/1/weight'

43 zanj_external_serialize(

44 z,

45 array1,

46 path=("layer", "1", "weight"),

47 item_type="npy",

48 _format="numpy.ndarray:external",

49 )

50

51 # Second: try to add parent path 'layer/1' - should conflict

52 with pytest.raises(ValueError, match="is a prefix of another path"):

53 zanj_external_serialize(

54 z,

55 array2,

56 path=("layer", "1"),

57 item_type="npy",

58 _format="numpy.ndarray:external",

59 )

60

61 def test_path_prefix_conflict_parent_first(self):

62 """Lines 134-136: Path prefix conflict where new path is child of existing."""

63 z = ZANJ()

64 array1 = np.random.rand(10, 10)

65 array2 = np.random.rand(5, 5)

66

67 # First: add parent path 'layer/1'

68 zanj_external_serialize(

69 z,

70 array1,

71 path=("layer", "1"),

72 item_type="npy",

73 _format="numpy.ndarray:external",

74 )

75

76 # Second: try to add child path 'layer/1/weight' - should conflict

77 with pytest.raises(ValueError, match="is a prefix of another path"):

78 zanj_external_serialize(

79 z,

80 array2,

81 path=("layer", "1", "weight"),

82 item_type="npy",

83 _format="numpy.ndarray:external",

84 )

85

86 def test_invalid_npy_data_type(self):

87 """Line 160: Invalid data type for NPY serialization should raise TypeError."""

88 z = ZANJ()

89

90 # Pass a string instead of array - should fail

91 with pytest.raises(TypeError, match="expected numpy.ndarray"):

92 zanj_external_serialize(

93 z,

94 data="not an array",

95 path=("test",),

96 item_type="npy",

97 _format="numpy.ndarray:external",

98 )

99

100 def test_invalid_jsonl_data_type(self):

101 """Line 184: Invalid data type for JSONL serialization should raise TypeError."""

102 z = ZANJ()

103

104 # Create a custom class that is not iterable/sequence/dataframe

105 class NotSerializableAsJsonl:

106 pass

107

108 obj = NotSerializableAsJsonl()

109

110 with pytest.raises(TypeError, match="expected list or pandas.DataFrame"):

111 zanj_external_serialize(

112 z,

113 data=obj,

114 path=("test",),

115 item_type="jsonl",

116 _format="list:external",

117 )

118

119 def test_valid_npy_serialization(self):

120 """Verify valid NPY serialization works correctly."""

121 z = ZANJ()

122 array = np.random.rand(10, 10)

123

124 result = zanj_external_serialize(

125 z,

126 array,

127 path=("valid_array",),

128 item_type="npy",

129 _format="numpy.ndarray:external",

130 )

131

132 assert "__muutils_format__" in result

133 assert result["__muutils_format__"] == "numpy.ndarray:external"

134 assert "valid_array.npy" in z._externals

135

136 def test_valid_jsonl_list_serialization(self):

137 """Verify valid JSONL list serialization works correctly."""

138 z = ZANJ()

139 data = [{"a": 1}, {"b": 2}, {"c": 3}]

140

141 result = zanj_external_serialize(

142 z,

143 data,

144 path=("valid_list",),

145 item_type="jsonl",

146 _format="list:external",

147 )

148

149 assert "__muutils_format__" in result

150 assert result["__muutils_format__"] == "list:external"

151 assert "valid_list.jsonl" in z._externals

152

153 def test_non_overlapping_paths_allowed(self):

154 """Verify that non-overlapping paths with similar prefixes are allowed."""

155 z = ZANJ()

156 array1 = np.random.rand(10, 10)

157 array2 = np.random.rand(5, 5)

158

159 # These should NOT conflict: 'layer.1' and 'layer.1.weight' as strings

160 # but 'layer/1' and 'layer/10' should be fine

161 zanj_external_serialize(

162 z,

163 array1,

164 path=("layer", "1"),

165 item_type="npy",

166 _format="numpy.ndarray:external",

167 )

168

169 # 'layer/10' is NOT a prefix of 'layer/1' or vice versa

170 zanj_external_serialize(

171 z,

172 array2,

173 path=("layer", "10"),

174 item_type="npy",

175 _format="numpy.ndarray:external",

176 )

177

178 assert "layer/1.npy" in z._externals

179 assert "layer/10.npy" in z._externals