machine-dialect 0.1.0a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. machine_dialect/__main__.py +667 -0
  2. machine_dialect/agent/__init__.py +5 -0
  3. machine_dialect/agent/agent.py +360 -0
  4. machine_dialect/ast/__init__.py +95 -0
  5. machine_dialect/ast/ast_node.py +35 -0
  6. machine_dialect/ast/call_expression.py +82 -0
  7. machine_dialect/ast/dict_extraction.py +60 -0
  8. machine_dialect/ast/expressions.py +439 -0
  9. machine_dialect/ast/literals.py +309 -0
  10. machine_dialect/ast/program.py +35 -0
  11. machine_dialect/ast/statements.py +1433 -0
  12. machine_dialect/ast/tests/test_ast_string_representation.py +62 -0
  13. machine_dialect/ast/tests/test_boolean_literal.py +29 -0
  14. machine_dialect/ast/tests/test_collection_hir.py +138 -0
  15. machine_dialect/ast/tests/test_define_statement.py +142 -0
  16. machine_dialect/ast/tests/test_desugar.py +541 -0
  17. machine_dialect/ast/tests/test_foreach_desugar.py +245 -0
  18. machine_dialect/cfg/__init__.py +6 -0
  19. machine_dialect/cfg/config.py +156 -0
  20. machine_dialect/cfg/examples.py +221 -0
  21. machine_dialect/cfg/generate_with_ai.py +187 -0
  22. machine_dialect/cfg/openai_generation.py +200 -0
  23. machine_dialect/cfg/parser.py +94 -0
  24. machine_dialect/cfg/tests/__init__.py +1 -0
  25. machine_dialect/cfg/tests/test_cfg_parser.py +252 -0
  26. machine_dialect/cfg/tests/test_config.py +188 -0
  27. machine_dialect/cfg/tests/test_examples.py +391 -0
  28. machine_dialect/cfg/tests/test_generate_with_ai.py +354 -0
  29. machine_dialect/cfg/tests/test_openai_generation.py +256 -0
  30. machine_dialect/codegen/__init__.py +5 -0
  31. machine_dialect/codegen/bytecode_module.py +89 -0
  32. machine_dialect/codegen/bytecode_serializer.py +300 -0
  33. machine_dialect/codegen/opcodes.py +101 -0
  34. machine_dialect/codegen/register_codegen.py +1996 -0
  35. machine_dialect/codegen/symtab.py +208 -0
  36. machine_dialect/codegen/tests/__init__.py +1 -0
  37. machine_dialect/codegen/tests/test_array_operations_codegen.py +295 -0
  38. machine_dialect/codegen/tests/test_bytecode_serializer.py +185 -0
  39. machine_dialect/codegen/tests/test_register_codegen_ssa.py +324 -0
  40. machine_dialect/codegen/tests/test_symtab.py +418 -0
  41. machine_dialect/codegen/vm_serializer.py +621 -0
  42. machine_dialect/compiler/__init__.py +18 -0
  43. machine_dialect/compiler/compiler.py +197 -0
  44. machine_dialect/compiler/config.py +149 -0
  45. machine_dialect/compiler/context.py +149 -0
  46. machine_dialect/compiler/phases/__init__.py +19 -0
  47. machine_dialect/compiler/phases/bytecode_optimization.py +90 -0
  48. machine_dialect/compiler/phases/codegen.py +40 -0
  49. machine_dialect/compiler/phases/hir_generation.py +39 -0
  50. machine_dialect/compiler/phases/mir_generation.py +86 -0
  51. machine_dialect/compiler/phases/optimization.py +110 -0
  52. machine_dialect/compiler/phases/parsing.py +39 -0
  53. machine_dialect/compiler/pipeline.py +143 -0
  54. machine_dialect/compiler/tests/__init__.py +1 -0
  55. machine_dialect/compiler/tests/test_compiler.py +568 -0
  56. machine_dialect/compiler/vm_runner.py +173 -0
  57. machine_dialect/errors/__init__.py +32 -0
  58. machine_dialect/errors/exceptions.py +369 -0
  59. machine_dialect/errors/messages.py +82 -0
  60. machine_dialect/errors/tests/__init__.py +0 -0
  61. machine_dialect/errors/tests/test_expected_token_errors.py +188 -0
  62. machine_dialect/errors/tests/test_name_errors.py +118 -0
  63. machine_dialect/helpers/__init__.py +0 -0
  64. machine_dialect/helpers/stopwords.py +225 -0
  65. machine_dialect/helpers/validators.py +30 -0
  66. machine_dialect/lexer/__init__.py +9 -0
  67. machine_dialect/lexer/constants.py +23 -0
  68. machine_dialect/lexer/lexer.py +907 -0
  69. machine_dialect/lexer/tests/__init__.py +0 -0
  70. machine_dialect/lexer/tests/helpers.py +86 -0
  71. machine_dialect/lexer/tests/test_apostrophe_identifiers.py +122 -0
  72. machine_dialect/lexer/tests/test_backtick_identifiers.py +140 -0
  73. machine_dialect/lexer/tests/test_boolean_literals.py +108 -0
  74. machine_dialect/lexer/tests/test_case_insensitive_keywords.py +188 -0
  75. machine_dialect/lexer/tests/test_comments.py +200 -0
  76. machine_dialect/lexer/tests/test_double_asterisk_keywords.py +127 -0
  77. machine_dialect/lexer/tests/test_lexer_position.py +113 -0
  78. machine_dialect/lexer/tests/test_list_tokens.py +282 -0
  79. machine_dialect/lexer/tests/test_stopwords.py +80 -0
  80. machine_dialect/lexer/tests/test_strict_equality.py +129 -0
  81. machine_dialect/lexer/tests/test_token.py +41 -0
  82. machine_dialect/lexer/tests/test_tokenization.py +294 -0
  83. machine_dialect/lexer/tests/test_underscore_literals.py +343 -0
  84. machine_dialect/lexer/tests/test_url_literals.py +169 -0
  85. machine_dialect/lexer/tokens.py +487 -0
  86. machine_dialect/linter/__init__.py +10 -0
  87. machine_dialect/linter/__main__.py +144 -0
  88. machine_dialect/linter/linter.py +154 -0
  89. machine_dialect/linter/rules/__init__.py +8 -0
  90. machine_dialect/linter/rules/base.py +112 -0
  91. machine_dialect/linter/rules/statement_termination.py +99 -0
  92. machine_dialect/linter/tests/__init__.py +1 -0
  93. machine_dialect/linter/tests/mdrules/__init__.py +0 -0
  94. machine_dialect/linter/tests/mdrules/test_md101_statement_termination.py +181 -0
  95. machine_dialect/linter/tests/test_linter.py +81 -0
  96. machine_dialect/linter/tests/test_rules.py +110 -0
  97. machine_dialect/linter/tests/test_violations.py +71 -0
  98. machine_dialect/linter/violations.py +51 -0
  99. machine_dialect/mir/__init__.py +69 -0
  100. machine_dialect/mir/analyses/__init__.py +20 -0
  101. machine_dialect/mir/analyses/alias_analysis.py +315 -0
  102. machine_dialect/mir/analyses/dominance_analysis.py +49 -0
  103. machine_dialect/mir/analyses/escape_analysis.py +286 -0
  104. machine_dialect/mir/analyses/loop_analysis.py +272 -0
  105. machine_dialect/mir/analyses/tests/test_type_analysis.py +736 -0
  106. machine_dialect/mir/analyses/type_analysis.py +448 -0
  107. machine_dialect/mir/analyses/use_def_chains.py +232 -0
  108. machine_dialect/mir/basic_block.py +385 -0
  109. machine_dialect/mir/dataflow.py +445 -0
  110. machine_dialect/mir/debug_info.py +208 -0
  111. machine_dialect/mir/hir_to_mir.py +1738 -0
  112. machine_dialect/mir/mir_dumper.py +366 -0
  113. machine_dialect/mir/mir_function.py +167 -0
  114. machine_dialect/mir/mir_instructions.py +1877 -0
  115. machine_dialect/mir/mir_interpreter.py +556 -0
  116. machine_dialect/mir/mir_module.py +225 -0
  117. machine_dialect/mir/mir_printer.py +480 -0
  118. machine_dialect/mir/mir_transformer.py +410 -0
  119. machine_dialect/mir/mir_types.py +367 -0
  120. machine_dialect/mir/mir_validation.py +455 -0
  121. machine_dialect/mir/mir_values.py +268 -0
  122. machine_dialect/mir/optimization_config.py +233 -0
  123. machine_dialect/mir/optimization_pass.py +251 -0
  124. machine_dialect/mir/optimization_pipeline.py +355 -0
  125. machine_dialect/mir/optimizations/__init__.py +84 -0
  126. machine_dialect/mir/optimizations/algebraic_simplification.py +733 -0
  127. machine_dialect/mir/optimizations/branch_prediction.py +372 -0
  128. machine_dialect/mir/optimizations/constant_propagation.py +634 -0
  129. machine_dialect/mir/optimizations/cse.py +398 -0
  130. machine_dialect/mir/optimizations/dce.py +288 -0
  131. machine_dialect/mir/optimizations/inlining.py +551 -0
  132. machine_dialect/mir/optimizations/jump_threading.py +487 -0
  133. machine_dialect/mir/optimizations/licm.py +405 -0
  134. machine_dialect/mir/optimizations/loop_unrolling.py +366 -0
  135. machine_dialect/mir/optimizations/strength_reduction.py +422 -0
  136. machine_dialect/mir/optimizations/tail_call.py +207 -0
  137. machine_dialect/mir/optimizations/tests/test_loop_unrolling.py +483 -0
  138. machine_dialect/mir/optimizations/type_narrowing.py +397 -0
  139. machine_dialect/mir/optimizations/type_specialization.py +447 -0
  140. machine_dialect/mir/optimizations/type_specific.py +906 -0
  141. machine_dialect/mir/optimize_mir.py +89 -0
  142. machine_dialect/mir/pass_manager.py +391 -0
  143. machine_dialect/mir/profiling/__init__.py +26 -0
  144. machine_dialect/mir/profiling/profile_collector.py +318 -0
  145. machine_dialect/mir/profiling/profile_data.py +372 -0
  146. machine_dialect/mir/profiling/profile_reader.py +272 -0
  147. machine_dialect/mir/profiling/profile_writer.py +226 -0
  148. machine_dialect/mir/register_allocation.py +302 -0
  149. machine_dialect/mir/reporting/__init__.py +17 -0
  150. machine_dialect/mir/reporting/optimization_reporter.py +314 -0
  151. machine_dialect/mir/reporting/report_formatter.py +289 -0
  152. machine_dialect/mir/ssa_construction.py +342 -0
  153. machine_dialect/mir/tests/__init__.py +1 -0
  154. machine_dialect/mir/tests/test_algebraic_associativity.py +204 -0
  155. machine_dialect/mir/tests/test_algebraic_complex_patterns.py +221 -0
  156. machine_dialect/mir/tests/test_algebraic_division.py +126 -0
  157. machine_dialect/mir/tests/test_algebraic_simplification.py +863 -0
  158. machine_dialect/mir/tests/test_basic_block.py +425 -0
  159. machine_dialect/mir/tests/test_branch_prediction.py +459 -0
  160. machine_dialect/mir/tests/test_call_lowering.py +168 -0
  161. machine_dialect/mir/tests/test_collection_lowering.py +604 -0
  162. machine_dialect/mir/tests/test_cross_block_constant_propagation.py +255 -0
  163. machine_dialect/mir/tests/test_custom_passes.py +166 -0
  164. machine_dialect/mir/tests/test_debug_info.py +285 -0
  165. machine_dialect/mir/tests/test_dict_extraction_lowering.py +192 -0
  166. machine_dialect/mir/tests/test_dictionary_lowering.py +299 -0
  167. machine_dialect/mir/tests/test_double_negation.py +231 -0
  168. machine_dialect/mir/tests/test_escape_analysis.py +233 -0
  169. machine_dialect/mir/tests/test_hir_to_mir.py +465 -0
  170. machine_dialect/mir/tests/test_hir_to_mir_complete.py +389 -0
  171. machine_dialect/mir/tests/test_hir_to_mir_simple.py +130 -0
  172. machine_dialect/mir/tests/test_inlining.py +435 -0
  173. machine_dialect/mir/tests/test_licm.py +472 -0
  174. machine_dialect/mir/tests/test_mir_dumper.py +313 -0
  175. machine_dialect/mir/tests/test_mir_instructions.py +445 -0
  176. machine_dialect/mir/tests/test_mir_module.py +860 -0
  177. machine_dialect/mir/tests/test_mir_printer.py +387 -0
  178. machine_dialect/mir/tests/test_mir_types.py +123 -0
  179. machine_dialect/mir/tests/test_mir_types_enhanced.py +132 -0
  180. machine_dialect/mir/tests/test_mir_validation.py +378 -0
  181. machine_dialect/mir/tests/test_mir_values.py +168 -0
  182. machine_dialect/mir/tests/test_one_based_indexing.py +202 -0
  183. machine_dialect/mir/tests/test_optimization_helpers.py +60 -0
  184. machine_dialect/mir/tests/test_optimization_pipeline.py +554 -0
  185. machine_dialect/mir/tests/test_optimization_reporter.py +318 -0
  186. machine_dialect/mir/tests/test_pass_manager.py +294 -0
  187. machine_dialect/mir/tests/test_pass_registration.py +64 -0
  188. machine_dialect/mir/tests/test_profiling.py +356 -0
  189. machine_dialect/mir/tests/test_register_allocation.py +307 -0
  190. machine_dialect/mir/tests/test_report_formatters.py +372 -0
  191. machine_dialect/mir/tests/test_ssa_construction.py +433 -0
  192. machine_dialect/mir/tests/test_tail_call.py +236 -0
  193. machine_dialect/mir/tests/test_type_annotated_instructions.py +192 -0
  194. machine_dialect/mir/tests/test_type_narrowing.py +277 -0
  195. machine_dialect/mir/tests/test_type_specialization.py +421 -0
  196. machine_dialect/mir/tests/test_type_specific_optimization.py +545 -0
  197. machine_dialect/mir/tests/test_type_specific_optimization_advanced.py +382 -0
  198. machine_dialect/mir/type_inference.py +368 -0
  199. machine_dialect/parser/__init__.py +12 -0
  200. machine_dialect/parser/enums.py +45 -0
  201. machine_dialect/parser/parser.py +3655 -0
  202. machine_dialect/parser/protocols.py +11 -0
  203. machine_dialect/parser/symbol_table.py +169 -0
  204. machine_dialect/parser/tests/__init__.py +0 -0
  205. machine_dialect/parser/tests/helper_functions.py +193 -0
  206. machine_dialect/parser/tests/test_action_statements.py +334 -0
  207. machine_dialect/parser/tests/test_boolean_literal_expressions.py +152 -0
  208. machine_dialect/parser/tests/test_call_statements.py +154 -0
  209. machine_dialect/parser/tests/test_call_statements_errors.py +187 -0
  210. machine_dialect/parser/tests/test_collection_mutations.py +264 -0
  211. machine_dialect/parser/tests/test_conditional_expressions.py +343 -0
  212. machine_dialect/parser/tests/test_define_integration.py +468 -0
  213. machine_dialect/parser/tests/test_define_statements.py +311 -0
  214. machine_dialect/parser/tests/test_dict_extraction.py +115 -0
  215. machine_dialect/parser/tests/test_empty_literal.py +155 -0
  216. machine_dialect/parser/tests/test_float_literal_expressions.py +163 -0
  217. machine_dialect/parser/tests/test_identifier_expressions.py +57 -0
  218. machine_dialect/parser/tests/test_if_empty_block.py +61 -0
  219. machine_dialect/parser/tests/test_if_statements.py +299 -0
  220. machine_dialect/parser/tests/test_illegal_tokens.py +86 -0
  221. machine_dialect/parser/tests/test_infix_expressions.py +680 -0
  222. machine_dialect/parser/tests/test_integer_literal_expressions.py +137 -0
  223. machine_dialect/parser/tests/test_interaction_statements.py +269 -0
  224. machine_dialect/parser/tests/test_list_literals.py +277 -0
  225. machine_dialect/parser/tests/test_no_none_in_ast.py +94 -0
  226. machine_dialect/parser/tests/test_panic_mode_recovery.py +171 -0
  227. machine_dialect/parser/tests/test_parse_errors.py +114 -0
  228. machine_dialect/parser/tests/test_possessive_syntax.py +182 -0
  229. machine_dialect/parser/tests/test_prefix_expressions.py +415 -0
  230. machine_dialect/parser/tests/test_program.py +13 -0
  231. machine_dialect/parser/tests/test_return_statements.py +89 -0
  232. machine_dialect/parser/tests/test_set_statements.py +152 -0
  233. machine_dialect/parser/tests/test_strict_equality.py +258 -0
  234. machine_dialect/parser/tests/test_symbol_table.py +217 -0
  235. machine_dialect/parser/tests/test_url_literal_expressions.py +209 -0
  236. machine_dialect/parser/tests/test_utility_statements.py +423 -0
  237. machine_dialect/parser/token_buffer.py +159 -0
  238. machine_dialect/repl/__init__.py +3 -0
  239. machine_dialect/repl/repl.py +426 -0
  240. machine_dialect/repl/tests/__init__.py +0 -0
  241. machine_dialect/repl/tests/test_repl.py +606 -0
  242. machine_dialect/semantic/__init__.py +12 -0
  243. machine_dialect/semantic/analyzer.py +906 -0
  244. machine_dialect/semantic/error_messages.py +189 -0
  245. machine_dialect/semantic/tests/__init__.py +1 -0
  246. machine_dialect/semantic/tests/test_analyzer.py +364 -0
  247. machine_dialect/semantic/tests/test_error_messages.py +104 -0
  248. machine_dialect/tests/edge_cases/__init__.py +10 -0
  249. machine_dialect/tests/edge_cases/test_boundary_access.py +256 -0
  250. machine_dialect/tests/edge_cases/test_empty_collections.py +166 -0
  251. machine_dialect/tests/edge_cases/test_invalid_operations.py +243 -0
  252. machine_dialect/tests/edge_cases/test_named_list_edge_cases.py +295 -0
  253. machine_dialect/tests/edge_cases/test_nested_structures.py +313 -0
  254. machine_dialect/tests/edge_cases/test_type_mixing.py +277 -0
  255. machine_dialect/tests/integration/test_array_operations_emulation.py +248 -0
  256. machine_dialect/tests/integration/test_list_compilation.py +395 -0
  257. machine_dialect/tests/integration/test_lists_and_dictionaries.py +322 -0
  258. machine_dialect/type_checking/__init__.py +21 -0
  259. machine_dialect/type_checking/tests/__init__.py +1 -0
  260. machine_dialect/type_checking/tests/test_type_system.py +230 -0
  261. machine_dialect/type_checking/type_system.py +270 -0
  262. machine_dialect-0.1.0a1.dist-info/METADATA +128 -0
  263. machine_dialect-0.1.0a1.dist-info/RECORD +268 -0
  264. machine_dialect-0.1.0a1.dist-info/WHEEL +5 -0
  265. machine_dialect-0.1.0a1.dist-info/entry_points.txt +3 -0
  266. machine_dialect-0.1.0a1.dist-info/licenses/LICENSE +201 -0
  267. machine_dialect-0.1.0a1.dist-info/top_level.txt +2 -0
  268. machine_dialect_vm/__init__.pyi +15 -0
@@ -0,0 +1,372 @@
1
+ """Tests for report formatters."""
2
+
3
+ import json
4
+
5
+ import pytest
6
+
7
+ from machine_dialect.mir.reporting.optimization_reporter import (
8
+ ModuleMetrics,
9
+ PassMetrics,
10
+ )
11
+ from machine_dialect.mir.reporting.report_formatter import (
12
+ HTMLReportFormatter,
13
+ JSONReportFormatter,
14
+ TextReportFormatter,
15
+ )
16
+
17
+
18
+ def create_test_metrics() -> ModuleMetrics:
19
+ """Create test module metrics."""
20
+ metrics = ModuleMetrics(
21
+ module_name="test_module",
22
+ optimization_level=2,
23
+ )
24
+
25
+ # Add pass metrics
26
+ pass1 = PassMetrics(
27
+ pass_name="constant-propagation",
28
+ phase="early",
29
+ metrics={"constants_propagated": 15, "expressions_folded": 5},
30
+ before_stats={"instructions": 100, "blocks": 10},
31
+ after_stats={"instructions": 85, "blocks": 8},
32
+ time_ms=3.5,
33
+ )
34
+
35
+ pass2 = PassMetrics(
36
+ pass_name="dead-code-elimination",
37
+ phase="main",
38
+ metrics={"dead_removed": 10, "blocks_removed": 2},
39
+ before_stats={"instructions": 85, "blocks": 8},
40
+ after_stats={"instructions": 75, "blocks": 6},
41
+ time_ms=2.0,
42
+ )
43
+
44
+ metrics.add_pass_metrics(pass1)
45
+ metrics.add_pass_metrics(pass2)
46
+
47
+ # Add function metrics
48
+ metrics.function_metrics["main"] = {
49
+ "instructions": 50,
50
+ "blocks": 4,
51
+ "loops": 1,
52
+ }
53
+
54
+ metrics.function_metrics["helper"] = {
55
+ "instructions": 25,
56
+ "blocks": 2,
57
+ "loops": 0,
58
+ }
59
+
60
+ return metrics
61
+
62
+
63
+ class TestTextReportFormatter:
64
+ """Test text report formatter."""
65
+
66
+ def test_basic_formatting(self) -> None:
67
+ """Test basic text formatting."""
68
+ formatter = TextReportFormatter(detailed=False)
69
+ metrics = create_test_metrics()
70
+
71
+ report = formatter.format(metrics)
72
+
73
+ assert "OPTIMIZATION REPORT - test_module" in report
74
+ assert "Optimization Level: 2" in report
75
+ assert "Total Passes Run: 2" in report
76
+ assert "Total Time: 5.50ms" in report
77
+ assert "constant-propagation" in report
78
+ assert "dead-code-elimination" in report
79
+
80
+ def test_detailed_formatting(self) -> None:
81
+ """Test detailed text formatting."""
82
+ formatter = TextReportFormatter(detailed=True)
83
+ metrics = create_test_metrics()
84
+
85
+ report = formatter.format(metrics)
86
+
87
+ assert "DETAILED PASS STATISTICS" in report
88
+ assert "[1] constant-propagation" in report
89
+ assert "[2] dead-code-elimination" in report
90
+ assert "Phase: early" in report
91
+ assert "Phase: main" in report
92
+ assert "Time: 3.50ms" in report
93
+ assert "Time: 2.00ms" in report
94
+
95
+ def test_improvements_section(self) -> None:
96
+ """Test that improvements are calculated and shown."""
97
+ formatter = TextReportFormatter(detailed=True)
98
+ metrics = create_test_metrics()
99
+
100
+ report = formatter.format(metrics)
101
+
102
+ assert "OVERALL IMPROVEMENTS" in report
103
+ # Instructions reduced from 100 to 75 (25% reduction)
104
+ assert "instructions" in report
105
+ assert "reduction" in report
106
+
107
+ def test_total_optimizations(self) -> None:
108
+ """Test total optimizations section."""
109
+ formatter = TextReportFormatter()
110
+ metrics = create_test_metrics()
111
+
112
+ report = formatter.format(metrics)
113
+
114
+ assert "TOTAL OPTIMIZATIONS" in report
115
+ assert "constants_propagated" in report
116
+ assert "15" in report
117
+ assert "dead_removed" in report
118
+ assert "10" in report
119
+
120
+ def test_function_metrics_section(self) -> None:
121
+ """Test function-level statistics."""
122
+ formatter = TextReportFormatter(detailed=True)
123
+ metrics = create_test_metrics()
124
+
125
+ report = formatter.format(metrics)
126
+
127
+ assert "FUNCTION-LEVEL STATISTICS" in report
128
+ assert "Function: main" in report
129
+ assert "Function: helper" in report
130
+ assert "instructions" in report
131
+ assert "blocks" in report
132
+ assert "loops" in report
133
+
134
+ def test_empty_metrics(self) -> None:
135
+ """Test formatting empty metrics."""
136
+ formatter = TextReportFormatter()
137
+ metrics = ModuleMetrics("empty", optimization_level=0)
138
+
139
+ report = formatter.format(metrics)
140
+
141
+ assert "OPTIMIZATION REPORT - empty" in report
142
+ assert "Total Passes Run: 0" in report
143
+ assert "Total Time: 0.00ms" in report
144
+
145
+ def test_passes_applied_list(self) -> None:
146
+ """Test passes applied list formatting."""
147
+ formatter = TextReportFormatter()
148
+ metrics = create_test_metrics()
149
+
150
+ report = formatter.format(metrics)
151
+
152
+ assert "PASSES APPLIED" in report
153
+ assert "1. constant-propagation" in report
154
+ assert "2. dead-code-elimination" in report
155
+
156
+ def test_average_pass_time(self) -> None:
157
+ """Test average pass time calculation."""
158
+ formatter = TextReportFormatter()
159
+ metrics = create_test_metrics()
160
+
161
+ report = formatter.format(metrics)
162
+
163
+ assert "Average Pass Time:" in report
164
+ # (3.5 + 2.0) / 2 = 2.75ms
165
+ assert "2.75ms" in report
166
+
167
+
168
+ class TestHTMLReportFormatter:
169
+ """Test HTML report formatter."""
170
+
171
+ def test_basic_html_structure(self) -> None:
172
+ """Test basic HTML structure."""
173
+ formatter = HTMLReportFormatter()
174
+ metrics = create_test_metrics()
175
+
176
+ report = formatter.format(metrics)
177
+
178
+ assert "<!DOCTYPE html>" in report
179
+ assert "<html>" in report
180
+ assert "</html>" in report
181
+ assert "<head>" in report
182
+ assert "<body>" in report
183
+ assert "<title>Optimization Report</title>" in report
184
+
185
+ def test_html_content(self) -> None:
186
+ """Test HTML content."""
187
+ formatter = HTMLReportFormatter()
188
+ metrics = create_test_metrics()
189
+
190
+ report = formatter.format(metrics)
191
+
192
+ assert "<h1>Optimization Report - test_module</h1>" in report
193
+ assert "<h2>Summary</h2>" in report
194
+ assert "Optimization Level" in report
195
+ assert "Total Passes" in report
196
+ assert "constant-propagation" in report
197
+ assert "dead-code-elimination" in report
198
+
199
+ def test_html_tables(self) -> None:
200
+ """Test HTML tables."""
201
+ formatter = HTMLReportFormatter()
202
+ metrics = create_test_metrics()
203
+
204
+ report = formatter.format(metrics)
205
+
206
+ assert "<table>" in report
207
+ assert "<tr>" in report
208
+ assert "<td>" in report
209
+ assert "<th>" in report
210
+
211
+ def test_html_styling(self) -> None:
212
+ """Test HTML styling."""
213
+ formatter = HTMLReportFormatter()
214
+ metrics = create_test_metrics()
215
+
216
+ report = formatter.format(metrics)
217
+
218
+ assert "<style>" in report
219
+ assert "font-family: monospace" in report
220
+ assert ".improvement" in report
221
+ assert ".regression" in report
222
+
223
+ def test_html_improvements(self) -> None:
224
+ """Test HTML improvements section."""
225
+ formatter = HTMLReportFormatter()
226
+ metrics = create_test_metrics()
227
+
228
+ report = formatter.format(metrics)
229
+
230
+ assert "<h2>Overall Improvements</h2>" in report
231
+ assert "class='improvement'" in report
232
+
233
+ def test_html_detailed_stats(self) -> None:
234
+ """Test HTML detailed statistics."""
235
+ formatter = HTMLReportFormatter()
236
+ metrics = create_test_metrics()
237
+
238
+ report = formatter.format(metrics)
239
+
240
+ assert "<h2>Detailed Pass Statistics</h2>" in report
241
+ assert "constant-propagation" in report
242
+ assert "3.50" in report # Time
243
+
244
+ def test_empty_html_report(self) -> None:
245
+ """Test empty HTML report."""
246
+ formatter = HTMLReportFormatter()
247
+ metrics = ModuleMetrics("empty")
248
+
249
+ report = formatter.format(metrics)
250
+
251
+ assert "<!DOCTYPE html>" in report
252
+ assert "Optimization Report - empty" in report
253
+
254
+
255
+ class TestJSONReportFormatter:
256
+ """Test JSON report formatter."""
257
+
258
+ def test_json_structure(self) -> None:
259
+ """Test JSON structure."""
260
+ formatter = JSONReportFormatter()
261
+ metrics = create_test_metrics()
262
+
263
+ report = formatter.format(metrics)
264
+ data = json.loads(report)
265
+
266
+ assert data["module_name"] == "test_module"
267
+ assert data["optimization_level"] == 2
268
+ assert data["total_time_ms"] == 5.5
269
+ assert "summary" in data
270
+ assert "passes" in data
271
+ assert "functions" in data
272
+
273
+ def test_json_passes(self) -> None:
274
+ """Test JSON passes data."""
275
+ formatter = JSONReportFormatter()
276
+ metrics = create_test_metrics()
277
+
278
+ report = formatter.format(metrics)
279
+ data = json.loads(report)
280
+
281
+ assert len(data["passes"]) == 2
282
+
283
+ pass1 = data["passes"][0]
284
+ assert pass1["name"] == "constant-propagation"
285
+ assert pass1["phase"] == "early"
286
+ assert pass1["time_ms"] == 3.5
287
+ assert pass1["metrics"]["constants_propagated"] == 15
288
+
289
+ def test_json_improvements(self) -> None:
290
+ """Test JSON improvements calculation."""
291
+ formatter = JSONReportFormatter()
292
+ metrics = create_test_metrics()
293
+
294
+ report = formatter.format(metrics)
295
+ data = json.loads(report)
296
+
297
+ pass1 = data["passes"][0]
298
+ assert "improvements" in pass1
299
+ assert "instructions" in pass1["improvements"]
300
+ # 100 -> 85 is 15% improvement
301
+ assert pass1["improvements"]["instructions"] == 15.0
302
+
303
+ def test_json_function_metrics(self) -> None:
304
+ """Test JSON function metrics."""
305
+ formatter = JSONReportFormatter()
306
+ metrics = create_test_metrics()
307
+
308
+ report = formatter.format(metrics)
309
+ data = json.loads(report)
310
+
311
+ assert "main" in data["functions"]
312
+ assert data["functions"]["main"]["instructions"] == 50
313
+ assert data["functions"]["main"]["loops"] == 1
314
+
315
+ assert "helper" in data["functions"]
316
+ assert data["functions"]["helper"]["instructions"] == 25
317
+
318
+ def test_json_summary(self) -> None:
319
+ """Test JSON summary data."""
320
+ formatter = JSONReportFormatter()
321
+ metrics = create_test_metrics()
322
+
323
+ report = formatter.format(metrics)
324
+ data = json.loads(report)
325
+
326
+ summary = data["summary"]
327
+ assert summary["module_name"] == "test_module"
328
+ assert summary["total_passes"] == 2
329
+ assert "passes_applied" in summary
330
+ assert len(summary["passes_applied"]) == 2
331
+
332
+ def test_json_formatting(self) -> None:
333
+ """Test JSON is properly formatted."""
334
+ formatter = JSONReportFormatter()
335
+ metrics = create_test_metrics()
336
+
337
+ report = formatter.format(metrics)
338
+
339
+ # Should be indented
340
+ assert "\n " in report
341
+
342
+ # Should be valid JSON
343
+ try:
344
+ json.loads(report)
345
+ except json.JSONDecodeError:
346
+ pytest.fail("Invalid JSON generated")
347
+
348
+ def test_empty_json_report(self) -> None:
349
+ """Test empty JSON report."""
350
+ formatter = JSONReportFormatter()
351
+ metrics = ModuleMetrics("empty")
352
+
353
+ report = formatter.format(metrics)
354
+ data = json.loads(report)
355
+
356
+ assert data["module_name"] == "empty"
357
+ assert len(data["passes"]) == 0
358
+ assert len(data["functions"]) == 0
359
+
360
+ def test_json_before_after_stats(self) -> None:
361
+ """Test JSON before/after statistics."""
362
+ formatter = JSONReportFormatter()
363
+ metrics = create_test_metrics()
364
+
365
+ report = formatter.format(metrics)
366
+ data = json.loads(report)
367
+
368
+ pass1 = data["passes"][0]
369
+ assert pass1["before_stats"]["instructions"] == 100
370
+ assert pass1["after_stats"]["instructions"] == 85
371
+ assert pass1["before_stats"]["blocks"] == 10
372
+ assert pass1["after_stats"]["blocks"] == 8