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

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

2

3 from analyzers.go import analyze_source

4

5

6 def _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

13 def _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

21 def test_simple_function():

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

23 assert _npath(code) == 1

24

25

26 def test_empty_source():

27 result = analyze_source("package main")

28 assert len(result.functions) == 0

29

30

31# --- If statements ---

32

33 def test_if_only():

34 code = """

35 package main

36 func f(x bool) {

37 if x {

38 return

39 }

40}

41"""

42 assert _npath(code) == 2

43

44

45 def test_if_else():

46 code = """

47 package main

48 func f(x bool) {

49 if x {

50 return

51 } else {

52 return

53 }

54}

55"""

56 assert _npath(code) == 2

57

58

59 def test_if_elif_else():

60 code = """

61 package main

62 func 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

75 def test_if_elif_no_else():

76 code = """

77 package main

78 func 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

91 def test_bool_ops_in_if():

92 code = """

93 package main

94 func f(a, b bool) {

95 if a && b {

96 return

97 }

98}

99"""

100 assert _npath(code) == 3

101

102

103 def test_two_bool_ops():

104 code = """

105 package main

106 func 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

117 def test_for_loop():

118 code = """

119 package main

120 func f() {

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

122 _ = i

123 }

124}

125"""

126 assert _npath(code) == 2

127

128

129 def test_for_range():

130 code = """

131 package main

132 func f(items []int) {

133 for _, v := range items {

134 _ = v

135 }

136}

137"""

138 assert _npath(code) == 2

139

140

141 def test_infinite_for():

142 code = """

143 package main

144 func f() {

145 for {

146 break

147 }

148}

149"""

150 assert _npath(code) == 2

151

152

153# --- Switch ---

154

155 def test_switch_three_cases():

156 code = """

157 package main

158 func 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

172 def test_switch_with_default():

173 code = """

174 package main

175 func 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

189 def test_type_switch():

190 code = """

191 package main

192 func 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

206 def test_select():

207 code = """

208 package main

209 func 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

221 def test_select_with_default():

222 code = """

223 package main

224 func 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

238 def test_sequential_ifs():

239 code = """

240 package main

241 func 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

255 def test_nested_if():

256 code = """

257 package main

258 func 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

271 def test_nested_named_func_literal():

272 code = """

273 package main

274 func 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

293 def test_goroutine_inline_closure():

294 code = """

295 package main

296 func 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

309 def test_method_declaration():

310 code = """

311 package main

312 type Foo struct{}

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

314 if x {

315 return

316 }

317}

318"""

319 assert _npath(code) == 2