Coverage for tests/unit/misc/test_freeze.py: 100%

121 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2025-04-04 03:33 -0600

1from __future__ import annotations 

2 

3import pytest 

4 

5from muutils.misc import freeze 

6 

7# TODO: there are a bunch of 'type: ignore' comments here which it would be nice to get rid of 

8 

9 

10def test_freeze_basic_types(): 

11 freeze(True) 

12 freeze(123) 

13 freeze(45.67) 

14 freeze("hello") 

15 freeze(b"bytes") 

16 

17 assert True # No exceptions should be raised 

18 

19 

20def test_freeze_list(): 

21 lst = [1, 2, 3] 

22 lst = freeze(lst) 

23 

24 with pytest.raises(AttributeError): 

25 lst[0] = 4 

26 

27 with pytest.raises(AttributeError): 

28 lst.append(4) 

29 

30 with pytest.raises(AttributeError): 

31 lst.extend([4, 5]) 

32 

33 with pytest.raises(AttributeError): 

34 lst.pop() 

35 

36 with pytest.raises(AttributeError): 

37 lst.clear() 

38 

39 

40def test_freeze_tuple(): 

41 tpl = (1, 2, 3) 

42 frozen_tpl = freeze(tpl) 

43 

44 assert frozen_tpl == (1, 2, 3) 

45 assert isinstance(frozen_tpl, tuple) 

46 

47 

48def test_freeze_set(): 

49 st = {1, 2, 3} 

50 frozen_st = freeze(st) 

51 

52 assert frozen_st == frozenset({1, 2, 3}) 

53 assert isinstance(frozen_st, frozenset) 

54 

55 

56def test_freeze_dict(): 

57 dct = {"key1": 1, "key2": 2} 

58 dct = freeze(dct) 

59 

60 with pytest.raises(AttributeError): 

61 dct["key1"] = 3 

62 

63 with pytest.raises(AttributeError): 

64 del dct["key2"] 

65 

66 

67def test_freeze_nested_structures(): 

68 nested = {"key1": [1, 2, 3], "key2": {"subkey": 4}} 

69 freeze(nested) 

70 

71 with pytest.raises(AttributeError): 

72 nested["key1"][0] = 4 # type: ignore[index] 

73 

74 with pytest.raises(AttributeError): 

75 nested["key2"]["subkey"] = 5 # type: ignore[index] 

76 

77 

78def test_freeze_custom_class(): 

79 class CustomClass: 

80 def __init__(self, value): 

81 self.value = value 

82 

83 obj = CustomClass(10) 

84 freeze(obj) 

85 

86 with pytest.raises(AttributeError): 

87 obj.value = 20 

88 

89 

90class CustomClass: 

91 def __init__(self, value): 

92 self.value = value 

93 

94 

95def test_freeze_class_with_nested_structures(): 

96 class NestedClass: 

97 def __init__(self): 

98 self.lst = [1, 2, {"key": 3}, (4, 5)] 

99 self.dct = {"key1": {1, 2, 3}, "key2": [6, 7, 8]} 

100 self.st = {frozenset((9, 10)), (11, 12)} 

101 self.tpl = (CustomClass(13), [14, 15], {"key3": 16}) 

102 

103 obj_orig = NestedClass() 

104 obj = freeze(obj_orig) 

105 

106 with pytest.raises(AttributeError): 

107 obj.lst[0] = 10 

108 

109 with pytest.raises(AttributeError): 

110 obj.lst[2]["key"] = 30 # type: ignore[index] 

111 

112 with pytest.raises(AttributeError): 

113 obj.lst[3] = (40, 50) 

114 

115 with pytest.raises(AttributeError): 

116 obj.dct["key1"] = {100, 200} 

117 

118 with pytest.raises(AttributeError): 

119 obj.dct["key2"][1] = 70 # type: ignore[index] 

120 

121 with pytest.raises(AttributeError): 

122 obj.st.add((13, 14)) 

123 

124 with pytest.raises(AttributeError): 

125 obj.tpl[1][0] = 140 

126 

127 with pytest.raises(AttributeError): 

128 obj.tpl[2]["key3"] = 160 

129 

130 

131def test_freeze_lists_with_classes_and_nested_structures(): 

132 lst = [CustomClass(1), [2, 3], {"key": (4, 5)}] 

133 freeze(lst) 

134 

135 with pytest.raises(AttributeError): 

136 lst[0].value = 10 # type: ignore[attr-defined] 

137 

138 with pytest.raises(AttributeError): 

139 lst[1][1] = 30 # type: ignore[index] 

140 

141 with pytest.raises(AttributeError): 

142 lst[2]["key"] = (40, 50) # type: ignore[index] 

143 

144 

145def test_freeze_dicts_with_classes_and_nested_structures(): 

146 dct = {"class": CustomClass(6), "lst": [7, 8], "set": {9, (10, 11)}} 

147 freeze(dct) 

148 

149 with pytest.raises(AttributeError): 

150 dct["class"].value = 60 # type: ignore[attr-defined] 

151 

152 with pytest.raises(AttributeError): 

153 dct["lst"][0] = 70 # type: ignore[index] 

154 

155 with pytest.raises(AttributeError): 

156 dct["set"].add(12) # type: ignore[attr-defined] 

157 

158 

159def test_freeze_sets_with_classes_and_nested_structures(): 

160 st = {CustomClass(1), frozenset({2, 3}), (4, 5)} 

161 freeze(st) 

162 

163 for item in st: 

164 if isinstance(item, CustomClass): 

165 with pytest.raises(AttributeError): 

166 item.value = 10 

167 

168 

169def test_freeze_tuples_with_classes_and_nested_structures(): 

170 tpl = (CustomClass(1), [2, 3], {"key": 4}) 

171 frozen_tpl = freeze(tpl) 

172 

173 for item in frozen_tpl: 

174 if isinstance(item, CustomClass): 

175 with pytest.raises(AttributeError): 

176 item.value = 10 

177 elif isinstance(item, list): 

178 with pytest.raises(AttributeError): 

179 item[0] = 20 

180 elif isinstance(item, dict): 

181 with pytest.raises(AttributeError): 

182 item["key"] = 40