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

81 statements  

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

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

2 

3from analyzers.typescript 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 assert _npath("function f() {}") == 1 

23 

24 

25def test_empty_source(): 

26 result = analyze_source("") 

27 assert len(result.functions) == 0 

28 

29 

30# --- If statements --- 

31 

32def test_if_only(): 

33 code = """ 

34function f(x: boolean) { 

35 if (x) { 

36 return 1; 

37 } 

38} 

39""" 

40 assert _npath(code) == 2 

41 

42 

43def test_if_else(): 

44 code = """ 

45function f(x: boolean) { 

46 if (x) { 

47 return 1; 

48 } else { 

49 return 2; 

50 } 

51} 

52""" 

53 assert _npath(code) == 2 

54 

55 

56def test_if_elif_else(): 

57 code = """ 

58function f(x: number) { 

59 if (x > 0) { 

60 return 1; 

61 } else if (x < 0) { 

62 return -1; 

63 } else { 

64 return 0; 

65 } 

66} 

67""" 

68 assert _npath(code) == 3 

69 

70 

71def test_if_elif_no_else(): 

72 code = """ 

73function f(x: number) { 

74 if (x > 0) { 

75 return 1; 

76 } else if (x < 0) { 

77 return -1; 

78 } 

79} 

80""" 

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

82 

83 

84# --- Bool ops --- 

85 

86def test_bool_ops_in_if(): 

87 code = """ 

88function f(a: boolean, b: boolean) { 

89 if (a && b) { 

90 return 1; 

91 } 

92} 

93""" 

94 assert _npath(code) == 3 # 1 + 1 + 1 bool op 

95 

96 

97def test_two_bool_ops(): 

98 code = """ 

99function f(a: boolean, b: boolean, c: boolean) { 

100 if (a && b || c) { 

101 return 1; 

102 } 

103} 

104""" 

105 assert _npath(code) == 4 # 1 + 1 + 2 bool ops 

106 

107 

108# --- Loops --- 

109 

110def test_for_loop(): 

111 code = """ 

112function f() { 

113 for (let i = 0; i < 10; i++) { 

114 console.log(i); 

115 } 

116} 

117""" 

118 assert _npath(code) == 2 

119 

120 

121def test_while_loop(): 

122 code = """ 

123function f(x: boolean) { 

124 while (x) { 

125 break; 

126 } 

127} 

128""" 

129 assert _npath(code) == 2 

130 

131 

132def test_while_with_bool_cond(): 

133 code = """ 

134function f(a: boolean, b: boolean) { 

135 while (a && b) { 

136 break; 

137 } 

138} 

139""" 

140 assert _npath(code) == 3 

141 

142 

143def test_do_while(): 

144 code = """ 

145function f(x: boolean) { 

146 do { 

147 break; 

148 } while (x); 

149} 

150""" 

151 assert _npath(code) == 2 

152 

153 

154def test_do_while_with_bool_cond(): 

155 code = """ 

156function f(a: boolean, b: boolean) { 

157 do { 

158 break; 

159 } while (a || b); 

160} 

161""" 

162 assert _npath(code) == 3 

163 

164 

165# --- Try/catch --- 

166 

167def test_try_catch(): 

168 code = """ 

169function f() { 

170 try { 

171 foo(); 

172 } catch (e) { 

173 bar(); 

174 } 

175} 

176""" 

177 assert _npath(code) == 2 

178 

179 

180# --- Switch --- 

181 

182def test_switch_three_cases(): 

183 code = """ 

184function f(x: number) { 

185 switch (x) { 

186 case 1: break; 

187 case 2: break; 

188 case 3: break; 

189 } 

190} 

191""" 

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

193 

194 

195def test_switch_with_default(): 

196 code = """ 

197function f(x: number) { 

198 switch (x) { 

199 case 1: break; 

200 case 2: break; 

201 default: break; 

202 } 

203} 

204""" 

205 assert _npath(code) == 3 # 1+1+1, has default 

206 

207 

208# --- Ternary --- 

209 

210def test_ternary(): 

211 code = """ 

212function f(c: boolean, x: number, y: number) { 

213 return c ? x : y; 

214} 

215""" 

216 assert _npath(code) == 2 

217 

218 

219def test_nested_ternary(): 

220 code = """ 

221function f(c1: boolean, c2: boolean) { 

222 return c1 ? 1 : (c2 ? 2 : 3); 

223} 

224""" 

225 assert _npath(code) == 3 

226 

227 

228# --- Sequential ifs (multiplicative) --- 

229 

230def test_sequential_ifs(): 

231 code = """ 

232function f(a: boolean, b: boolean) { 

233 if (a) { foo(); } 

234 if (b) { bar(); } 

235} 

236""" 

237 assert _npath(code) == 4 

238 

239 

240# --- Nested if --- 

241 

242def test_nested_if(): 

243 code = """ 

244function f(a: boolean, b: boolean) { 

245 if (a) { 

246 if (b) { 

247 foo(); 

248 } 

249 } 

250} 

251""" 

252 assert _npath(code) == 3 

253 

254 

255# --- Arrow functions --- 

256 

257def test_named_arrow(): 

258 code = """ 

259const f = (x: boolean) => { 

260 if (x) { 

261 return 1; 

262 } 

263 return 0; 

264}; 

265""" 

266 assert _npath(code) == 2 

267 

268 

269def test_nested_named_arrow(): 

270 code = """ 

271function outer(x: boolean) { 

272 if (x) { foo(); } 

273 const inner = (y: boolean) => { 

274 if (y) { bar(); } 

275 }; 

276} 

277""" 

278 npaths = _npaths(code) 

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

280 assert npaths["inner"] == 2 

281 

282 

283# --- Method definition --- 

284 

285def test_method_definition(): 

286 code = """ 

287class Foo { 

288 bar(x: boolean) { 

289 if (x) { 

290 return 1; 

291 } 

292 } 

293} 

294""" 

295 assert _npath(code) == 2 

296 

297 

298# --- For-in loop --- 

299 

300def test_for_in_loop(): 

301 code = """ 

302function f(obj: any) { 

303 for (const key in obj) { 

304 console.log(key); 

305 } 

306} 

307""" 

308 assert _npath(code) == 2