Coverage for tests/test_dtd/test_python.py: 100%

1"""Tests for Data Transformation Density (Python)."""

2

3 from analyzers.python import analyze_source

4

5

6 def _dtd(code: str) -> int:

7 """Return DTD 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].dtd

11

12

13 def _dtds(code: str) -> dict[str, int]:

14 """Return {name: dtd} for all functions in code."""

15 result = analyze_source(code)

16 return {f.name: f.dtd for f in result.functions}

17

18

19# --- Empty / no data ---

20

21 def test_empty_function():

22 assert _dtd("def f(): pass") == 0

23

24

25 def test_no_data_structures():

26 code = """

27 def f(x):

28 return x + 1

29"""

30 assert _dtd(code) == 0

31

32

33# --- Flat structures ---

34

35 def test_flat_dict():

36 code = """

37 def f():

38 return {"a": 1, "b": 2, "c": 3}

39"""

40 # dict at depth 1, 3 pairs x 1 = 3

41 assert _dtd(code) == 3

42

43

44 def test_flat_list():

45 code = """

46 def f():

47 return [1, 2, 3]

48"""

49 # list at depth 1, 3 elements x 1 = 3

50 assert _dtd(code) == 3

51

52

53# --- Nested structures ---

54

55 def test_nested_dict_in_list():

56 code = """

57 def f():

58 return [{"a": 1}, {"b": 2}]

59"""

60 # list at depth 1: 2 elements x 1 = 2

61 # each dict at depth 2: 1 pair x 2 = 2 each -> 4

62 # total = 2 + 4 = 6

63 assert _dtd(code) == 6

64

65

66 def test_deeply_nested():

67 code = """

68 def f():

69 return {"outer": {"inner": [1, 2]}}

70"""

71 # outer dict depth 1: 1 pair x 1 = 1

72 # inner dict depth 2: 1 pair x 2 = 2

73 # list depth 3: 2 elements x 3 = 6

74 # total = 1 + 2 + 6 = 9

75 assert _dtd(code) == 9

76

77

78# --- Nested function skipped ---

79

80 def test_nested_function_skipped():

81 code = """

82 def outer():

83 x = {"a": 1}

84 def inner():

85 y = {"b": 2, "c": 3}

86 return x

87"""

88 dtds = _dtds(code)

89 assert dtds["outer"] == 1 # only {"a": 1}

90 assert dtds["inner"] == 2 # {"b": 2, "c": 3} -> 2 pairs x 1

91

92

93# --- Comprehensions ---

94

95 def test_dict_comprehension():

96 code = """

97 def f(items):

98 return {k: v for k, v in items}

99"""

100 # dict_comprehension is a container at depth 1

101 # pair inside at depth 1: 1 pair x 1 = 1

102 assert _dtd(code) == 1

103

104

105 def test_list_comprehension():

106 code = """

107 def f(items):

108 return [x for x in items]

109"""

110 # list_comprehension is a container at depth 1

111 # no explicit payload children (the inner expression isn't a pair/keyword_arg)

112 assert _dtd(code) == 0