Coverage for tests/test_diff.py: 100.00%

24 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-08-15 16:47 +0200

1"""Tests for the `diff` module.""" 

2 

3from __future__ import annotations 

4 

5import pytest 

6 

7from griffe import Breakage, BreakageKind, find_breaking_changes, temporary_visited_module, temporary_visited_package 

8 

9 

10@pytest.mark.parametrize( 

11 ("old_code", "new_code", "expected_breakages"), 

12 [ 

13 ( 

14 "a = True", 

15 "a = False", 

16 [BreakageKind.ATTRIBUTE_CHANGED_VALUE], 

17 ), 

18 ( 

19 "class a(int, str): ...", 

20 "class a(int): ...", 

21 [BreakageKind.CLASS_REMOVED_BASE], 

22 ), 

23 ( 

24 "a = 0", 

25 "class a: ...", 

26 [BreakageKind.OBJECT_CHANGED_KIND], 

27 ), 

28 ( 

29 "a = True", 

30 "", 

31 [BreakageKind.OBJECT_REMOVED], 

32 ), 

33 ( 

34 "def a(): ...", 

35 "def a(x): ...", 

36 [BreakageKind.PARAMETER_ADDED_REQUIRED], 

37 ), 

38 ( 

39 "def a(x=0): ...", 

40 "def a(x=1): ...", 

41 [BreakageKind.PARAMETER_CHANGED_DEFAULT], 

42 ), 

43 ( 

44 # positional-only to keyword-only 

45 "def a(x, /): ...", 

46 "def a(*, x): ...", 

47 [BreakageKind.PARAMETER_CHANGED_KIND], 

48 ), 

49 ( 

50 # keyword-only to positional-only 

51 "def a(*, x): ...", 

52 "def a(x, /): ...", 

53 [BreakageKind.PARAMETER_CHANGED_KIND], 

54 ), 

55 ( 

56 # positional or keyword to positional-only 

57 "def a(x): ...", 

58 "def a(x, /): ...", 

59 [BreakageKind.PARAMETER_CHANGED_KIND], 

60 ), 

61 ( 

62 # positional or keyword to keyword-only 

63 "def a(x): ...", 

64 "def a(*, x): ...", 

65 [BreakageKind.PARAMETER_CHANGED_KIND], 

66 ), 

67 # to variadic positional 

68 ( 

69 # positional-only to variadic positional 

70 "def a(x, /): ...", 

71 "def a(*x): ...", 

72 [], 

73 ), 

74 ( 

75 # positional or keyword to variadic positional 

76 "def a(x): ...", 

77 "def a(*x): ...", 

78 [BreakageKind.PARAMETER_CHANGED_KIND], 

79 ), 

80 ( 

81 # keyword-only to variadic positional 

82 "def a(*, x): ...", 

83 "def a(*x): ...", 

84 [BreakageKind.PARAMETER_CHANGED_KIND], 

85 ), 

86 ( 

87 # variadic keyword to variadic positional 

88 "def a(**x): ...", 

89 "def a(*x): ...", 

90 [BreakageKind.PARAMETER_CHANGED_KIND], 

91 ), 

92 ( 

93 # positional or keyword to variadic positional, with variadic keyword 

94 "def a(x): ...", 

95 "def a(*x, **y): ...", 

96 [], 

97 ), 

98 ( 

99 # keyword-only to variadic positional, with variadic keyword 

100 "def a(*, x): ...", 

101 "def a(*x, **y): ...", 

102 [], 

103 ), 

104 # to variadic keyword 

105 ( 

106 # positional-only to variadic keyword 

107 "def a(x, /): ...", 

108 "def a(**x): ...", 

109 [BreakageKind.PARAMETER_CHANGED_KIND], 

110 ), 

111 ( 

112 # positional or keyword to variadic keyword 

113 "def a(x): ...", 

114 "def a(**x): ...", 

115 [BreakageKind.PARAMETER_CHANGED_KIND], 

116 ), 

117 ( 

118 # keyword-only to variadic keyword 

119 "def a(*, x): ...", 

120 "def a(**x): ...", 

121 [], 

122 ), 

123 ( 

124 # variadic positional to variadic keyword 

125 "def a(*x): ...", 

126 "def a(**x): ...", 

127 [BreakageKind.PARAMETER_CHANGED_KIND], 

128 ), 

129 ( 

130 # positional-only to variadic keyword, with variadic positional 

131 "def a(x, /): ...", 

132 "def a(*y, **x): ...", 

133 [], 

134 ), 

135 ( 

136 # positional or keyword to variadic keyword, with variadic positional 

137 "def a(x): ...", 

138 "def a(*y, **x): ...", 

139 [], 

140 ), 

141 ( 

142 "def a(x=1): ...", 

143 "def a(x): ...", 

144 [BreakageKind.PARAMETER_CHANGED_REQUIRED], 

145 ), 

146 ( 

147 "def a(x, y): ...", 

148 "def a(y, x): ...", 

149 [BreakageKind.PARAMETER_MOVED, BreakageKind.PARAMETER_MOVED], 

150 ), 

151 ( 

152 "def a(x, y): ...", 

153 "def a(x): ...", 

154 [BreakageKind.PARAMETER_REMOVED], 

155 ), 

156 ( 

157 "class a:\n\tb: int | None = None", 

158 "class a:\n\tb: int", 

159 [BreakageKind.ATTRIBUTE_CHANGED_VALUE], 

160 ), 

161 ( 

162 "def a() -> int: ...", 

163 "def a() -> str: ...", 

164 [], # not supported yet: BreakageKind.RETURN_CHANGED_TYPE 

165 ), 

166 ], 

167) 

168def test_diff_griffe(old_code: str, new_code: str, expected_breakages: list[Breakage]) -> None: 

169 """Test the different incompatibility finders. 

170 

171 Parameters: 

172 old_code: Parametrized code of the old module version. 

173 new_code: Parametrized code of the new module version. 

174 expected_breakages: A list of breakage kinds to expect. 

175 """ 

176 # check without any alias 

177 with temporary_visited_module(old_code) as old_package, temporary_visited_module(new_code) as new_package: 

178 breaking = list(find_breaking_changes(old_package, new_package)) 

179 assert len(breaking) == len(expected_breakages) 

180 for breakage, expected_kind in zip(breaking, expected_breakages): 

181 assert breakage.kind is expected_kind 

182 # check with aliases 

183 import_a = "from ._mod_a import a\n__all__ = ['a']" 

184 old_modules = {"__init__.py": import_a, "_mod_a.py": old_code} 

185 new_modules = {"__init__.py": new_code and import_a, "_mod_a.py": new_code} 

186 with temporary_visited_package("package_old", old_modules) as old_package: # noqa: SIM117 

187 with temporary_visited_package("package_new", new_modules) as new_package: 

188 breaking = list(find_breaking_changes(old_package, new_package)) 

189 assert len(breaking) == len(expected_breakages) 

190 for breakage, expected_kind in zip(breaking, expected_breakages): 

191 assert breakage.kind is expected_kind 

192 

193 

194def test_moving_members_in_parent_classes() -> None: 

195 """Test that moving an object from a base class to a parent class doesn't trigger a breakage.""" 

196 old_code = """ 

197 class Parent: 

198 ... 

199 

200 class Base(Parent): 

201 def method(self): 

202 ... 

203 """ 

204 new_code = """ 

205 class Parent: 

206 def method(self): 

207 ... 

208 

209 class Base(Parent): 

210 ... 

211 """ 

212 with temporary_visited_module(old_code) as old_package, temporary_visited_module(new_code) as new_package: 

213 assert not list(find_breaking_changes(old_package, new_package))