Coverage for tests / test_cognitive / test_typescript.py: 100%
107 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 TypeScript cognitive complexity."""
3from analyzers.typescript import analyze_source
6def _score(code: str, tsx: bool = False) -> int:
7 """Helper: return total complexity of the first function in code."""
8 result = analyze_source(code, tsx=tsx)
9 assert result.functions, f"No functions found in:\n{code}"
10 return result.functions[0].complexity
13def _scores(code: str, tsx: bool = False) -> dict[str, int]:
14 """Helper: return {name: complexity} for all functions in code."""
15 result = analyze_source(code, tsx=tsx)
16 return {f.name: f.complexity for f in result.functions}
19# --- Basic control flow ---
22def test_empty_function():
23 assert _score("function f() {}") == 0
26def test_single_if():
27 code = """
28function f(x) {
29 if (x) { // +1
30 }
31}
32"""
33 assert _score(code) == 1
36def test_if_else():
37 code = """
38function f(x) {
39 if (x) { // +1
40 } else { // +1
41 }
42}
43"""
44 assert _score(code) == 2
47def test_if_else_if_else():
48 code = """
49function f(x) {
50 if (x > 0) { // +1
51 } else if (x < 0) { // +1
52 } else { // +1
53 }
54}
55"""
56 assert _score(code) == 3
59# --- Loops ---
62def test_for_loop():
63 code = """
64function f(items) {
65 for (let i = 0; i < items.length; i++) { // +1
66 }
67}
68"""
69 assert _score(code) == 1
72def test_for_in_loop():
73 code = """
74function f(obj) {
75 for (const key in obj) { // +1
76 }
77}
78"""
79 assert _score(code) == 1
82def test_while_loop():
83 code = """
84function f(x) {
85 while (x > 0) { // +1
86 x--;
87 }
88}
89"""
90 assert _score(code) == 1
93def test_do_while_loop():
94 code = """
95function f(x) {
96 do { // +1
97 x--;
98 } while (x > 0);
99}
100"""
101 assert _score(code) == 1
104# --- Nesting ---
107def test_nested_if():
108 code = """
109function f(a, b) {
110 if (a) { // +1 (nesting 0)
111 if (b) { // +1 + 1 (nesting 1)
112 }
113 }
114}
115"""
116 assert _score(code) == 3
119def test_deeply_nested():
120 code = """
121function f(a, b, c) {
122 if (a) { // +1 (nesting 0)
123 for (let x of b) { // +1 + 1 (nesting 1)
124 if (c) { // +1 + 2 (nesting 2)
125 }
126 }
127 }
128}
129"""
130 assert _score(code) == 6
133def test_if_else_nesting():
134 code = """
135function f(a, b) {
136 if (a) { // +1 (nesting 0)
137 } else { // +1 (no nesting bonus)
138 if (b) { // +1 + 1 (nesting 1, inside else body)
139 }
140 }
141}
142"""
143 assert _score(code) == 4
146# --- Try/Catch ---
149def test_try_catch():
150 code = """
151function f() {
152 try {
153 } catch (e) { // +1
154 }
155}
156"""
157 assert _score(code) == 1
160def test_try_catch_nested():
161 code = """
162function f(x) {
163 if (x) { // +1 (nesting 0)
164 try {
165 } catch (e) { // +1 + 1 (nesting 1)
166 }
167 }
168}
169"""
170 assert _score(code) == 3
173# --- Boolean operators ---
176def test_single_and():
177 code = """
178function f(a, b) {
179 if (a && b) { // +1 (if) + 1 (boolean)
180 }
181}
182"""
183 assert _score(code) == 2
186def test_chained_same_op():
187 code = """
188function f(a, b, c) {
189 if (a && b && c) { // +1 (if) + 1 (boolean chain, same op)
190 }
191}
192"""
193 assert _score(code) == 2
196def test_mixed_boolean():
197 code = """
198function f(a, b, c) {
199 if (a && b || c) { // +1 (if) + 2 (&&->|| switch)
200 }
201}
202"""
203 assert _score(code) == 3
206def test_complex_boolean():
207 code = """
208function f(a, b, c, d) {
209 if (a || b || (c && d)) { // +1 (if) + 2 (|| sequence, then && subtree)
210 }
211}
212"""
213 assert _score(code) == 3
216# --- Ternary ---
219def test_ternary():
220 code = """
221function f(x) {
222 return x > 0 ? x : -x; // +1 (ternary, nesting 0)
223}
224"""
225 assert _score(code) == 1
228def test_ternary_nested_in_if():
229 code = """
230function f(x) {
231 if (x) { // +1 (nesting 0)
232 return x > 0 ? x : -x; // +1 + 1 (ternary, nesting 1)
233 }
234}
235"""
236 assert _score(code) == 3
239# --- Recursion ---
242def test_recursion():
243 code = """
244function factorial(n) {
245 if (n <= 1) { // +1
246 return 1;
247 }
248 return n * factorial(n - 1); // +1 (recursion)
249}
250"""
251 assert _score(code) == 2
254def test_no_false_recursion():
255 code = """
256function f(x) {
257 return g(x);
258}
259"""
260 assert _score(code) == 0
263# --- Nested functions ---
266def test_nested_function_separate_scoring():
267 code = """
268function outer(x) {
269 if (x) {} // +1 for outer
270 function inner(y) {
271 if (y) {} // +1 for inner
272 }
273}
274"""
275 scores = _scores(code)
276 assert scores["outer"] == 1
277 assert scores["inner"] == 1
280def test_nested_function_nesting_reset():
281 code = """
282function outer(x) {
283 if (x) { // +1 for outer
284 function inner(y) {
285 if (y) {} // +1 for inner (nesting 0, not 1)
286 }
287 }
288}
289"""
290 scores = _scores(code)
291 assert scores["outer"] == 1
292 assert scores["inner"] == 1
295# --- Arrow functions ---
298def test_inline_arrow_increases_nesting():
299 code = """
300function f(items) {
301 return items.map(x => x > 0 ? x : 0);
302}
303"""
304 assert _score(code) == 2
307def test_named_arrow_scored_separately():
308 code = """
309const f = (x) => {
310 if (x) {} // +1
311};
312const g = (a, b) => {
313 if (a) { // +1
314 if (b) {} // +1 + 1
315 }
316};
317"""
318 scores = _scores(code)
319 assert scores["f"] == 1
320 assert scores["g"] == 3
323# --- Switch ---
326def test_switch_statement():
327 code = """
328function f(x) {
329 switch (x) { // +1 (nesting 0)
330 case 1:
331 break;
332 case 2:
333 break;
334 default:
335 break;
336 }
337}
338"""
339 assert _score(code) == 1
342# --- Method definition ---
345def test_method_definition():
346 code = """
347class Foo {
348 bar(x) {
349 if (x) {} // +1
350 }
351}
352"""
353 scores = _scores(code)
354 assert scores["bar"] == 1
357# --- Comprehensive example ---
360def test_comprehensive():
361 code = """
362function process(items, flag) {
363 if (flag) { // +1 (nesting 0)
364 for (let i = 0; i < items.length; i++) { // +1 +1 (nesting 1)
365 if (items[i] > 0) { // +1 +2 (nesting 2)
366 } else if (items[i] < 0) { // +1 (no nesting bonus)
367 } else { // +1 (no nesting bonus)
368 try {
369 } catch (e) { // +1 +3 (nesting 3)
370 }
371 }
372 }
373 } else { // +1 (no nesting bonus)
374 }
375}
376"""
377 assert _score(code) == 13
380# --- Edge cases ---
383def test_not_operator_no_increment():
384 code = """
385function f(x) {
386 if (!x) { // +1 (if only)
387 }
388}
389"""
390 assert _score(code) == 1
393def test_async_function():
394 code = """
395async function f(x) {
396 if (x) {} // +1
397}
398"""
399 assert _score(code) == 1
402def test_generator_function():
403 code = """
404function* gen(items) {
405 for (const item of items) { // +1
406 if (item) { // +1 + 1
407 yield item;
408 }
409 }
410}
411"""
412 assert _score(code) == 3