Coverage for tests/test_circular_deps/test_go.py: 100%

1 from __future__ import annotations

2

3 import os

4 import shutil

5 import sys

6 import tempfile

7 from pathlib import Path

8

9 sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

10

11 from circular_deps import find_cycles

12 from circular_deps.parsers.go import GoImportParser

13 from circular_deps.resolvers.go import GoPathResolver

14

15

16 def test_go_parser_extract_import():

17 parser = GoImportParser()

18 source = """

19 import (

20 "fmt"

21 "os"

22 "mymodule/sub"

23)

24"""

25 imports = parser.extract_imports(source, "test.go")

26 assert len(imports) == 3

27 assert imports[0].raw_module == "fmt"

28 assert imports[1].raw_module == "os"

29 assert imports[2].raw_module == "mymodule/sub"

30

31

32 def test_go_stdlib_filtering():

33 from circular_deps.resolvers.go import GoPathResolver

34

35 tmpdir = Path(tempfile.mkdtemp())

36 try:

37 resolver = GoPathResolver()

38

39 path = resolver.resolve("fmt", "a.go", str(tmpdir))

40 assert path is None

41

42 path = resolver.resolve("encoding/json", "a.go", str(tmpdir))

43 assert path is None

44

45 sub_dir = tmpdir / "subdir"

46 go_dir = sub_dir / "pkg"

47 go_dir.mkdir(parents=True)

48 go_file = go_dir / "pkg.go"

49 go_file.write_text("")

50

51 path = resolver.resolve("subdir/pkg", str(tmpdir), str(tmpdir))

52 assert path == str(go_file)

53 finally:

54 shutil.rmtree(tmpdir)

55

56

57 def test_go_cycle_detection_simple():

58 tmpdir = Path(tempfile.mkdtemp())

59 try:

60 a_go = tmpdir / "a.go"

61 b_dir = tmpdir / "module" / "b"

62 b_go = b_dir / "b.go"

63

64 a_go.write_text('package main\nimport "mymodule/b"\n')

65 b_dir.mkdir(parents=True, exist_ok=True)

66 b_go.write_text('package b\nimport ".."\n')

67

68 files = [a_go, b_go]

69 cycles = find_cycles(files)

70

71 assert isinstance(cycles, list)

72 finally:

73 shutil.rmtree(tmpdir)

74

75

76 def test_go_resolver_package_resolution():

77 from circular_deps.resolvers.go import GoPathResolver

78

79 tmpdir = Path(tempfile.mkdtemp())

80 try:

81 resolver = GoPathResolver()

82

83 package_dir = tmpdir / "mypackage" / "subdir"

84 package_dir.mkdir(parents=True)

85 go_file = package_dir / "file.go"

86 go_file.write_text("")

87

88 path = resolver.resolve("mypackage/subdir", str(tmpdir), str(tmpdir))

89 assert path == str(go_file)

90

91 go_file2 = package_dir / "other.go"

92 go_file2.write_text("")

93 path = resolver.resolve("mypackage/subdir", str(tmpdir), str(tmpdir))

94 assert path is not None and path.endswith(".go")

95 finally:

96 shutil.rmtree(tmpdir)

97

98

99 def test_go_resolver_finds_go_file():

100 from circular_deps.resolvers.go import GoPathResolver

101

102 tmpdir = Path(tempfile.mkdtemp())

103 try:

104 resolver = GoPathResolver()

105

106 pkg_dir = tmpdir / "pkg"

107 pkg_dir.mkdir()

108 go_file = pkg_dir / "main.go"

109 go_file.write_text("")

110

111 path = resolver.resolve("pkg", str(tmpdir), str(tmpdir))

112 assert path == str(go_file)

113

114 direct_go = tmpdir / "direct.go"

115 direct_go.write_text("")

116 path = resolver.resolve("direct.go", str(tmpdir), str(tmpdir))

117 assert path == str(direct_go)

118 finally:

119 shutil.rmtree(tmpdir)

120

121

122 def test_go_cycle_detection_in_src_subdirectory():

123 """Test circular dependency detection with files in ./src subdirectory."""

124 tmpdir = Path(tempfile.mkdtemp())

125 try:

126 src_dir = tmpdir / "src"

127 src_dir.mkdir(parents=True, exist_ok=True)

128

129 afet_dir = src_dir / "afet"

130 bfet_dir = src_dir / "bfet"

131 afet_dir.mkdir(parents=True, exist_ok=True)

132 bfet_dir.mkdir(parents=True, exist_ok=True)

133

134 a_go = afet_dir / "a.go"

135 b_go = bfet_dir / "b.go"

136

137 a_go.write_text('package afet\nimport "bfet"\n')

138 b_go.write_text('package bfet\nimport "afet"\n')

139

140 files = [a_go, b_go]

141 cycles = find_cycles(files)

142

143 assert len(cycles) == 1

144 assert cycles[0].depth == 2

145 assert cycles[0].severity == "warning"

146 finally:

147 shutil.rmtree(tmpdir)

148

149

150 def test_go_cycle_transitive_three_files():

151 """Test transitive circular dependency with 3 files."""

152 tmpdir = Path(tempfile.mkdtemp())

153 try:

154 a_dir = tmpdir / "a"

155 b_dir = tmpdir / "b"

156 c_dir = tmpdir / "c"

157

158 a_dir.mkdir(parents=True, exist_ok=True)

159 b_dir.mkdir(parents=True, exist_ok=True)

160 c_dir.mkdir(parents=True, exist_ok=True)

161

162 a_go = a_dir / "a.go"

163 b_go = b_dir / "b.go"

164 c_go = c_dir / "c.go"

165

166 a_go.write_text('package a\nimport "b"\n')

167 b_go.write_text('package b\nimport "c"\n')

168 c_go.write_text('package c\nimport "a"\n')

169

170 files = [a_go, b_go, c_go]

171 cycles = find_cycles(files)

172

173 assert len(cycles) == 1

174 assert cycles[0].depth == 3

175 finally:

176 shutil.rmtree(tmpdir)

177

178

179 def test_go_cycle_nested_to_root():

180 """Test circular dependency with nested package importing root."""

181 tmpdir = Path(tempfile.mkdtemp())

182 try:

183 analysis_dir = tmpdir / "analysis"

184 analysis_dir.mkdir(parents=True, exist_ok=True)

185

186 verticality_go = analysis_dir / "verticality.go"

187 index_go = tmpdir / "index.go"

188

189 verticality_go.write_text('package analysis\nimport "."\n')

190 index_go.write_text('package main\nimport "analysis"\n')

191

192 files = [verticality_go, index_go]

193 cycles = find_cycles(files)

194

195 assert len(cycles) == 1

196 assert cycles[0].depth == 2

197 finally:

198 shutil.rmtree(tmpdir)

199

200

201 def test_go_no_cycles_linear_chain():

202 """Test linear import chain with no circular dependencies."""

203 tmpdir = Path(tempfile.mkdtemp())

204 try:

205 a_dir = tmpdir / "a"

206 b_dir = tmpdir / "b"

207 c_dir = tmpdir / "c"

208

209 a_dir.mkdir(parents=True, exist_ok=True)

210 b_dir.mkdir(parents=True, exist_ok=True)

211 c_dir.mkdir(parents=True, exist_ok=True)

212

213 a_go = a_dir / "a.go"

214 b_go = b_dir / "b.go"

215 c_go = c_dir / "c.go"

216

217 a_go.write_text('package a\nimport "b"\n')

218 b_go.write_text('package b\nimport (\n\t"fmt"\n)\n')

219 c_go.write_text('package c\nimport (\n\t"os"\n)\n')

220

221 files = [a_go, b_go, c_go]

222 cycles = find_cycles(files)

223

224 assert len(cycles) == 0

225 finally:

226 shutil.rmtree(tmpdir)