Coverage for tests / test_cognitive / test_go.py: 100%
109 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-08 15:04 -0800
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-08 15:04 -0800
1"""Tests for Go cognitive complexity."""
3from analyzers.go import analyze_source
6def _score(code: str) -> int:
7 """Helper: return total complexity 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].complexity
13def _scores(code: str) -> dict[str, int]:
14 """Helper: return {name: complexity} for all functions in code."""
15 result = analyze_source(code)
16 return {f.name: f.complexity for f in result.functions}
19# --- Basic control flow ---
22def test_empty_function():
23 code = """
24package main
26func f() {}
27"""
28 assert _score(code) == 0
31def test_single_if():
32 code = """
33package main
35func f(x int) {
36 if x > 0 { // +1
37 }
38}
39"""
40 assert _score(code) == 1
43def test_if_else():
44 code = """
45package main
47func f(x int) {
48 if x > 0 { // +1
49 } else { // +1
50 }
51}
52"""
53 assert _score(code) == 2
56def test_if_else_if_else():
57 code = """
58package main
60func f(x int) {
61 if x > 0 { // +1
62 } else if x < 0 { // +1
63 } else { // +1
64 }
65}
66"""
67 assert _score(code) == 3
70# --- Loops ---
73def test_for_c_style():
74 code = """
75package main
77func f(n int) {
78 for i := 0; i < n; i++ { // +1
79 }
80}
81"""
82 assert _score(code) == 1
85def test_for_range():
86 code = """
87package main
89func f(items []int) {
90 for _, v := range items { // +1
91 }
92}
93"""
94 assert _score(code) == 1
97def test_for_as_while():
98 code = """
99package main
101func f(x int) {
102 for x > 0 { // +1
103 x--
104 }
105}
106"""
107 assert _score(code) == 1
110def test_infinite_for():
111 code = """
112package main
114func f() {
115 for { // +1
116 break
117 }
118}
119"""
120 assert _score(code) == 1
123# --- Nesting ---
126def test_nested_if():
127 code = """
128package main
130func f(a, b bool) {
131 if a { // +1 (nesting 0)
132 if b { // +1 + 1 (nesting 1)
133 }
134 }
135}
136"""
137 assert _score(code) == 3
140def test_deeply_nested():
141 code = """
142package main
144func f(a bool, items []int, c bool) {
145 if a { // +1 (nesting 0)
146 for _, v := range items { // +1 + 1 (nesting 1)
147 if c { // +1 + 2 (nesting 2)
148 _ = v
149 }
150 }
151 }
152}
153"""
154 assert _score(code) == 6
157def test_if_else_nesting():
158 code = """
159package main
161func f(a, b bool) {
162 if a { // +1 (nesting 0)
163 } else { // +1 (no nesting bonus)
164 if b { // +1 + 1 (nesting 1, inside else body)
165 }
166 }
167}
168"""
169 assert _score(code) == 4
172# --- Switch/Select ---
175def test_expression_switch():
176 code = """
177package main
179func f(x int) {
180 switch x { // +1 (nesting 0)
181 case 1:
182 case 2:
183 default:
184 }
185}
186"""
187 assert _score(code) == 1
190def test_type_switch():
191 code = """
192package main
194func f(x interface{}) {
195 switch x.(type) { // +1 (nesting 0)
196 case int:
197 case string:
198 }
199}
200"""
201 assert _score(code) == 1
204def test_select_statement():
205 code = """
206package main
208func f(ch1, ch2 chan int) {
209 select { // +1 (nesting 0)
210 case v := <-ch1:
211 _ = v
212 case v := <-ch2:
213 _ = v
214 }
215}
216"""
217 assert _score(code) == 1
220def test_switch_nested_in_if():
221 code = """
222package main
224func f(x int, flag bool) {
225 if flag { // +1 (nesting 0)
226 switch x { // +1 + 1 (nesting 1)
227 case 1:
228 case 2:
229 }
230 }
231}
232"""
233 assert _score(code) == 3
236# --- Boolean operators ---
239def test_single_and():
240 code = """
241package main
243func f(a, b bool) {
244 if a && b { // +1 (if) + 1 (boolean)
245 }
246}
247"""
248 assert _score(code) == 2
251def test_chained_same_op():
252 code = """
253package main
255func f(a, b, c bool) {
256 if a && b && c { // +1 (if) + 1 (boolean chain, same op)
257 }
258}
259"""
260 assert _score(code) == 2
263def test_mixed_boolean():
264 code = """
265package main
267func f(a, b, c bool) {
268 if a && b || c { // +1 (if) + 2 (&&->|| switch)
269 }
270}
271"""
272 assert _score(code) == 3
275def test_complex_boolean():
276 code = """
277package main
279func f(a, b, c, d bool) {
280 if a || b || (c && d) { // +1 (if) + 2 (|| sequence, then && subtree)
281 }
282}
283"""
284 assert _score(code) == 3
287# --- Recursion ---
290def test_recursion():
291 code = """
292package main
294func factorial(n int) int {
295 if n <= 1 { // +1
296 return 1
297 }
298 return n * factorial(n - 1) // +1 (recursion)
299}
300"""
301 assert _score(code) == 2
304def test_no_false_recursion():
305 code = """
306package main
308func f(x int) int {
309 return g(x)
310}
311"""
312 assert _score(code) == 0
315# --- Nested named func_literal (separate scoring) ---
318def test_nested_function_separate_scoring():
319 code = """
320package main
322func outer(x bool) {
323 if x {} // +1 for outer
324 inner := func(y bool) {
325 if y {} // +1 for inner
326 }
327 _ = inner
328}
329"""
330 scores = _scores(code)
331 assert scores["outer"] == 1
332 assert scores["inner"] == 1
335# --- Closures ---
338def test_inline_func_literal_increases_nesting():
339 code = """
340package main
342func f(x int) {
343 apply(func(v int) int {
344 if v > 0 { // +1 + 1 (nesting 1, inside inline closure)
345 return v
346 }
347 return 0
348 })
349}
350"""
351 assert _score(code) == 2
354def test_named_func_literal_scored_separately():
355 code = """
356package main
358func outer() {
359 if true {} // +1 for outer
360 handler := func(x bool) {
361 if x { // +1 for handler
362 if true {} // +1 + 1 for handler
363 }
364 }
365 _ = handler
366}
367"""
368 scores = _scores(code)
369 assert scores["outer"] == 1
370 assert scores["handler"] == 3
373# --- Method ---
376def test_method_declaration():
377 code = """
378package main
380type Foo struct{}
382func (f Foo) Bar(x bool) {
383 if x {} // +1
384}
385"""
386 scores = _scores(code)
387 assert scores["Bar"] == 1
390# --- Go-specific ---
393def test_go_statement_no_increment():
394 code = """
395package main
397func f(x bool) {
398 go func() {
399 if x {} // +1 + 1 (nesting 1 from inline closure)
400 }()
401}
402"""
403 assert _score(code) == 2
406def test_defer_no_increment():
407 code = """
408package main
410func f(x bool) {
411 defer func() {
412 if x {} // +1 + 1 (nesting 1 from inline closure)
413 }()
414}
415"""
416 assert _score(code) == 2
419def test_error_handling_pattern():
420 code = """
421package main
423import "errors"
425func f() error {
426 err := doSomething()
427 if err != nil { // +1
428 return err
429 }
430 return nil
431}
432"""
433 assert _score(code) == 1
436def test_if_with_initializer():
437 code = """
438package main
440func f() {
441 if err := doSomething(); err != nil { // +1
442 }
443}
444"""
445 assert _score(code) == 1
448# --- Comprehensive example ---
451def test_comprehensive():
452 code = """
453package main
455func process(items []int, flag bool) {
456 if flag { // +1 (nesting 0)
457 for i := 0; i < len(items); i++ { // +1 +1 (nesting 1)
458 if items[i] > 0 { // +1 +2 (nesting 2)
459 } else if items[i] < 0 { // +1 (no nesting bonus)
460 } else { // +1 (no nesting bonus)
461 switch items[i] { // +1 +3 (nesting 3)
462 case 0:
463 }
464 }
465 }
466 } else { // +1 (no nesting bonus)
467 }
468}
469"""
470 assert _score(code) == 13
473# --- Edge cases ---
476def test_not_operator_no_increment():
477 code = """
478package main
480func f(x bool) {
481 if !x { // +1 (if only)
482 }
483}
484"""
485 assert _score(code) == 1
488def test_multiple_return_values():
489 code = """
490package main
492func f() (int, error) {
493 if true { // +1
494 return 0, nil
495 }
496 return 1, nil
497}
498"""
499 assert _score(code) == 1