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

36 statements  

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

1"""Tests for Maintainability Index (TypeScript).""" 

2 

3from analyzers.typescript import analyze_source 

4 

5 

6def _mi(code: str) -> float: 

7 """Return MI 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].mi 

11 

12 

13# --- Trivial function (high MI) --- 

14 

15def test_trivial_function(): 

16 code = """ 

17function f() { 

18 return 1; 

19} 

20""" 

21 mi = _mi(code) 

22 assert mi > 50, f"Trivial function should have high MI, got {mi}" 

23 

24 

25def test_simple_add(): 

26 code = """ 

27function add(a: number, b: number): number { 

28 return a + b; 

29} 

30""" 

31 mi = _mi(code) 

32 assert mi > 50, f"Simple function should have high MI, got {mi}" 

33 

34 

35# --- Complex function (low MI) --- 

36 

37def test_complex_function(): 

38 code = """ 

39function process(data: any[], flag: boolean, mode: boolean, opt: boolean, extra: boolean) { 

40 let result: any[] = []; 

41 let total = 0; 

42 let count = 0; 

43 for (let item of data) { 

44 if (flag && mode) { 

45 if (item > 0) { 

46 for (let sub of item) { 

47 if (sub < 100) { 

48 if (opt || extra) { 

49 result.push(sub * 2 + total); 

50 count += 1; 

51 } else { 

52 result.push(sub - 1); 

53 } 

54 } else if (sub > 200) { 

55 total += sub; 

56 count -= 1; 

57 } 

58 } 

59 } else if (item < 0) { 

60 try { 

61 const val = parseInt(item); 

62 if (val > 0 && val < 50) { 

63 result.push(val); 

64 } else if (val >= 50 || val === 0) { 

65 result.push(-val); 

66 } 

67 } catch (e) { 

68 result.push(0); 

69 } 

70 } 

71 } else if (mode || opt) { 

72 for (let sub of data) { 

73 if (sub !== item) { 

74 result.push(sub + item); 

75 total += sub; 

76 } 

77 } 

78 } 

79 } 

80 if (count > 0) { 

81 return result.slice(0, count); 

82 } 

83 return result; 

84} 

85""" 

86 mi = _mi(code) 

87 assert mi < 50, f"Complex function should have low MI, got {mi}" 

88 

89 

90# --- Edge case: empty body --- 

91 

92def test_empty_body(): 

93 code = """ 

94function noop() {} 

95""" 

96 mi = _mi(code) 

97 # With empty/minimal body, MI should be high 

98 assert mi > 50, f"Empty body function should have high MI, got {mi}" 

99 

100 

101# --- Edge case: no operators --- 

102 

103def test_no_operators(): 

104 code = """ 

105function f() { 

106 const x = 1; 

107} 

108""" 

109 mi = _mi(code) 

110 assert mi > 50, f"No-operator function should have high MI, got {mi}" 

111 

112 

113# --- MI is in valid range --- 

114 

115def test_mi_range(): 

116 code = """ 

117function f(x: boolean) { 

118 if (x) { 

119 return 1; 

120 } 

121 return 0; 

122} 

123""" 

124 mi = _mi(code) 

125 assert 0 <= mi <= 100, f"MI should be in [0, 100], got {mi}" 

126 

127 

128# --- Multiple functions --- 

129 

130def test_multiple_functions(): 

131 code = """ 

132function simple() { 

133 return 42; 

134} 

135 

136function moderate(x: number, y: number) { 

137 if (x > y) { 

138 return x; 

139 } else if (x < y) { 

140 return y; 

141 } else { 

142 return x + y; 

143 } 

144} 

145""" 

146 result = analyze_source(code) 

147 assert len(result.functions) == 2 

148 mi_simple = result.functions[0].mi 

149 mi_moderate = result.functions[1].mi 

150 assert mi_simple > mi_moderate, f"Simple function should have higher MI: {mi_simple} vs {mi_moderate}"