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

73 statements  

« prev     ^ index     » next       coverage.py v7.13.3, created at 2026-02-08 15:04 -0800

1"""Tests for NPath complexity (Go).""" 

2 

3from analyzers.go import analyze_source 

4 

5 

6def _npath(code: str) -> int: 

7 """Return NPath of the first function in code.""" 

8 result = analyze_source(code) 

9 assert result.functions, f"No functions found in:\n{code}" 

10 return result.functions[0].npath 

11 

12 

13def _npaths(code: str) -> dict[str, int]: 

14 """Return {name: npath} for all functions in code.""" 

15 result = analyze_source(code) 

16 return {f.name: f.npath for f in result.functions} 

17 

18 

19# --- Simple --- 

20 

21def test_simple_function(): 

22 code = "package main\nfunc f() {}" 

23 assert _npath(code) == 1 

24 

25 

26def test_empty_source(): 

27 result = analyze_source("package main") 

28 assert len(result.functions) == 0 

29 

30 

31# --- If statements --- 

32 

33def test_if_only(): 

34 code = """ 

35package main 

36func f(x bool) { 

37 if x { 

38 return 

39 } 

40} 

41""" 

42 assert _npath(code) == 2 

43 

44 

45def test_if_else(): 

46 code = """ 

47package main 

48func f(x bool) { 

49 if x { 

50 return 

51 } else { 

52 return 

53 } 

54} 

55""" 

56 assert _npath(code) == 2 

57 

58 

59def test_if_elif_else(): 

60 code = """ 

61package main 

62func f(x int) { 

63 if x > 0 { 

64 return 

65 } else if x < 0 { 

66 return 

67 } else { 

68 return 

69 } 

70} 

71""" 

72 assert _npath(code) == 3 

73 

74 

75def test_if_elif_no_else(): 

76 code = """ 

77package main 

78func f(x int) { 

79 if x > 0 { 

80 return 

81 } else if x < 0 { 

82 return 

83 } 

84} 

85""" 

86 assert _npath(code) == 3 # +1 for no terminal else 

87 

88 

89# --- Bool ops --- 

90 

91def test_bool_ops_in_if(): 

92 code = """ 

93package main 

94func f(a, b bool) { 

95 if a && b { 

96 return 

97 } 

98} 

99""" 

100 assert _npath(code) == 3 

101 

102 

103def test_two_bool_ops(): 

104 code = """ 

105package main 

106func f(a, b, c bool) { 

107 if a && b || c { 

108 return 

109 } 

110} 

111""" 

112 assert _npath(code) == 4 

113 

114 

115# --- Loops --- 

116 

117def test_for_loop(): 

118 code = """ 

119package main 

120func f() { 

121 for i := 0; i < 10; i++ { 

122 _ = i 

123 } 

124} 

125""" 

126 assert _npath(code) == 2 

127 

128 

129def test_for_range(): 

130 code = """ 

131package main 

132func f(items []int) { 

133 for _, v := range items { 

134 _ = v 

135 } 

136} 

137""" 

138 assert _npath(code) == 2 

139 

140 

141def test_infinite_for(): 

142 code = """ 

143package main 

144func f() { 

145 for { 

146 break 

147 } 

148} 

149""" 

150 assert _npath(code) == 2 

151 

152 

153# --- Switch --- 

154 

155def test_switch_three_cases(): 

156 code = """ 

157package main 

158func f(x int) { 

159 switch x { 

160 case 1: 

161 return 

162 case 2: 

163 return 

164 case 3: 

165 return 

166 } 

167} 

168""" 

169 assert _npath(code) == 4 # 1+1+1 + 1 (no default) 

170 

171 

172def test_switch_with_default(): 

173 code = """ 

174package main 

175func f(x int) { 

176 switch x { 

177 case 1: 

178 return 

179 case 2: 

180 return 

181 default: 

182 return 

183 } 

184} 

185""" 

186 assert _npath(code) == 3 

187 

188 

189def test_type_switch(): 

190 code = """ 

191package main 

192func f(x interface{}) { 

193 switch x.(type) { 

194 case int: 

195 return 

196 case string: 

197 return 

198 } 

199} 

200""" 

201 assert _npath(code) == 3 # 1+1 + 1 (no default) 

202 

203 

204# --- Select --- 

205 

206def test_select(): 

207 code = """ 

208package main 

209func f(ch1, ch2 chan int) { 

210 select { 

211 case v := <-ch1: 

212 _ = v 

213 case v := <-ch2: 

214 _ = v 

215 } 

216} 

217""" 

218 assert _npath(code) == 3 # 1+1 + 1 (no default) 

219 

220 

221def test_select_with_default(): 

222 code = """ 

223package main 

224func f(ch chan int) { 

225 select { 

226 case v := <-ch: 

227 _ = v 

228 default: 

229 return 

230 } 

231} 

232""" 

233 assert _npath(code) == 2 

234 

235 

236# --- Sequential ifs --- 

237 

238def test_sequential_ifs(): 

239 code = """ 

240package main 

241func f(a, b bool) { 

242 if a { 

243 return 

244 } 

245 if b { 

246 return 

247 } 

248} 

249""" 

250 assert _npath(code) == 4 

251 

252 

253# --- Nested if --- 

254 

255def test_nested_if(): 

256 code = """ 

257package main 

258func f(a, b bool) { 

259 if a { 

260 if b { 

261 return 

262 } 

263 } 

264} 

265""" 

266 assert _npath(code) == 3 

267 

268 

269# --- Nested named func_literal --- 

270 

271def test_nested_named_func_literal(): 

272 code = """ 

273package main 

274func outer(x bool) { 

275 if x { 

276 return 

277 } 

278 inner := func(y bool) { 

279 if y { 

280 return 

281 } 

282 } 

283 _ = inner 

284} 

285""" 

286 npaths = _npaths(code) 

287 assert npaths["outer"] == 2 # inner counts as 1 

288 assert npaths["inner"] == 2 

289 

290 

291# --- Goroutine with inline closure --- 

292 

293def test_goroutine_inline_closure(): 

294 code = """ 

295package main 

296func f(x bool) { 

297 go func() { 

298 if x { 

299 return 

300 } 

301 }() 

302} 

303""" 

304 assert _npath(code) == 2 

305 

306 

307# --- Method declaration --- 

308 

309def test_method_declaration(): 

310 code = """ 

311package main 

312type Foo struct{} 

313func (f Foo) bar(x bool) { 

314 if x { 

315 return 

316 } 

317} 

318""" 

319 assert _npath(code) == 2