Coverage for tests / test_mi / test_python.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 (Python).""" 

2 

3from analyzers.python 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 = """ 

17def f(): 

18 return 1 

19""" 

20 mi = _mi(code) 

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

22 

23 

24def test_simple_add(): 

25 code = """ 

26def add(a, b): 

27 return a + b 

28""" 

29 mi = _mi(code) 

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

31 

32 

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

34 

35def test_complex_function(): 

36 code = """ 

37def process(data, flag, mode, opt, extra): 

38 result = [] 

39 total = 0 

40 count = 0 

41 for item in data: 

42 if flag and mode: 

43 if item > 0: 

44 for sub in item: 

45 if sub < 100: 

46 if opt or extra: 

47 result.append(sub * 2 + total) 

48 count += 1 

49 else: 

50 result.append(sub - 1) 

51 elif sub > 200: 

52 total += sub 

53 count -= 1 

54 elif item < 0: 

55 try: 

56 val = int(item) 

57 if val > 0 and val < 50: 

58 result.append(val) 

59 elif val >= 50 or val == 0: 

60 result.append(-val) 

61 except Exception: 

62 result.append(0) 

63 elif mode or opt: 

64 for sub in data: 

65 if sub != item: 

66 result.append(sub + item) 

67 total += sub 

68 if count > 0: 

69 return result[:count] 

70 return result 

71""" 

72 mi = _mi(code) 

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

74 

75 

76# --- Edge case: empty body --- 

77 

78def test_empty_body(): 

79 code = """ 

80def noop(): 

81 pass 

82""" 

83 mi = _mi(code) 

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

85 

86 

87# --- Edge case: no operators --- 

88 

89def test_no_operators(): 

90 code = """ 

91def f(): 

92 x = 1 

93""" 

94 mi = _mi(code) 

95 # With minimal halstead volume, MI should be high 

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

97 

98 

99# --- MI is in valid range --- 

100 

101def test_mi_range(): 

102 code = """ 

103def f(x): 

104 if x: 

105 return 1 

106 return 0 

107""" 

108 mi = _mi(code) 

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

110 

111 

112# --- Multiple functions --- 

113 

114def test_multiple_functions(): 

115 code = """ 

116def simple(): 

117 return 42 

118 

119def moderate(x, y): 

120 if x > y: 

121 return x 

122 elif x < y: 

123 return y 

124 else: 

125 return x + y 

126""" 

127 result = analyze_source(code) 

128 assert len(result.functions) == 2 

129 mi_simple = result.functions[0].mi 

130 mi_moderate = result.functions[1].mi 

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