|
4 | 4 | """Tests for the FormulaFormatter.""" |
5 | 5 |
|
6 | 6 |
|
7 | | -from contextlib import AsyncExitStack |
8 | | - |
9 | 7 | from frequenz.channels import Broadcast |
10 | 8 | from frequenz.quantities import Quantity |
11 | | -from pytest_mock import MockerFixture |
12 | 9 |
|
13 | | -from frequenz.sdk import microgrid |
14 | 10 | from frequenz.sdk.timeseries import Sample |
15 | | -from frequenz.sdk.timeseries.formula_engine._formula_engine import FormulaBuilder |
| 11 | +from frequenz.sdk.timeseries.formula_engine._formula_engine import ( |
| 12 | + FormulaBuilder, |
| 13 | +) |
16 | 14 | from frequenz.sdk.timeseries.formula_engine._formula_formatter import format_formula |
17 | 15 | from frequenz.sdk.timeseries.formula_engine._formula_steps import ( |
18 | 16 | Clipper, |
|
22 | 20 | Minimizer, |
23 | 21 | ) |
24 | 22 | from frequenz.sdk.timeseries.formula_engine._tokenizer import Tokenizer, TokenType |
25 | | -from tests.timeseries.mock_microgrid import MockMicrogrid |
26 | 23 |
|
27 | 24 |
|
28 | 25 | def build_formula(formula: str) -> list[FormulaStep]: |
@@ -112,27 +109,34 @@ def test_functions(self) -> None: |
112 | 109 | # flake8: enable |
113 | 110 | # fmt: on |
114 | 111 |
|
115 | | - async def test_higher_order_formula(self, mocker: MockerFixture) -> None: |
116 | | - """Test that the formula is formatted correctly for a higher-order formula.""" |
117 | | - mockgrid = MockMicrogrid(grid_meter=False, mocker=mocker) |
118 | | - mockgrid.add_batteries(3) |
119 | | - mockgrid.add_ev_chargers(1) |
120 | | - mockgrid.add_solar_inverters(2) |
121 | | - |
122 | | - async with mockgrid, AsyncExitStack() as stack: |
123 | | - logical_meter = microgrid.logical_meter() |
124 | | - stack.push_async_callback(logical_meter.stop) |
125 | | - |
126 | | - pv_pool = microgrid.new_pv_pool(priority=5) |
127 | | - stack.push_async_callback(pv_pool.stop) |
128 | | - |
129 | | - grid = microgrid.grid() |
130 | | - stack.push_async_callback(grid.stop) |
131 | | - |
132 | | - assert str(grid.power) == "#36 + #7 + #47 + #17 + #57 + #27" |
133 | | - |
134 | | - composed_formula = (grid.power - pv_pool.power).build("grid_minus_pv") |
135 | | - assert ( |
136 | | - str(composed_formula) |
137 | | - == "[grid-power](#36 + #7 + #47 + #17 + #57 + #27) - [pv-power](#47 + #57)" |
138 | | - ) |
| 112 | + async def test_higher_order_formula(self) -> None: |
| 113 | + """Test that higher-order formulas (formulas combining other formulas) are formatted correctly.""" |
| 114 | + # Create two base formulas |
| 115 | + builder1 = FormulaBuilder("test_formula1", Quantity) |
| 116 | + builder2 = FormulaBuilder("test_formula2", Quantity) |
| 117 | + |
| 118 | + # Push metrics directly to the builders |
| 119 | + channel1 = Broadcast[Sample[Quantity]](name="channel1") |
| 120 | + channel2 = Broadcast[Sample[Quantity]](name="channel2") |
| 121 | + builder1.push_metric("#1", channel1.new_receiver(), nones_are_zeros=True) |
| 122 | + builder1.push_oper("+") |
| 123 | + builder1.push_metric("#2", channel2.new_receiver(), nones_are_zeros=True) |
| 124 | + |
| 125 | + channel3 = Broadcast[Sample[Quantity]](name="channel3") |
| 126 | + channel4 = Broadcast[Sample[Quantity]](name="channel4") |
| 127 | + builder2.push_metric("#3", channel3.new_receiver(), nones_are_zeros=True) |
| 128 | + builder2.push_oper("+") |
| 129 | + builder2.push_metric("#4", channel4.new_receiver(), nones_are_zeros=True) |
| 130 | + |
| 131 | + # Build individual formula engines first |
| 132 | + engine1 = builder1.build() |
| 133 | + engine2 = builder2.build() |
| 134 | + |
| 135 | + # Combine them into a higher-order formula |
| 136 | + composed_formula = (engine1 - engine2).build("higher_order_formula") |
| 137 | + |
| 138 | + # Check the string representation |
| 139 | + assert ( |
| 140 | + str(composed_formula) |
| 141 | + == "[test_formula1](#1 + #2) - [test_formula2](#3 + #4)" |
| 142 | + ) |
0 commit comments