M1: pure normalization engine + default seed
Infrastructure-free normalization engine in Core dispatching on MeterMode: - Cumulative/Generation counters: register deltas, first-reading baseline (Haus 411, Auto 3755), meter swaps (water …861→2 reconciles to 12 via boundary registers OR an explicit amount override), counter resets, anomaly-guarded decreases. - RuntimeCounter: Δhours × rate (fixed/empirical). - ConsumableBalance: tank level-Δ + deliveries → consumption, cm→litre calibration; delivery-only rows before the first dipstick emit nothing. - DirectDelta, and Virtual meters via a small safe arithmetic evaluator (Netz Einsparung = Haus − Netz, Eigenverbrauch = Erzeugung − Einsparung) — data-driven, not hardcoded. - DatabaseSeeder: default energy types, cost categories, base settings (idempotent). 24 Core unit tests + 4 integration tests green. Claude-Session: https://claude.ai/code/session_01WujdMtMJPbxDpDnMeK22rr
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
using MeterVault.Core.Domain;
|
||||
using MeterVault.Core.Normalization;
|
||||
using static MeterVault.Core.Tests.TestData;
|
||||
|
||||
namespace MeterVault.Core.Tests;
|
||||
|
||||
public sealed class CumulativeCounterNormalizerTests
|
||||
{
|
||||
private readonly INormalizationEngine _engine = NormalizationEngine.CreateDefault();
|
||||
|
||||
[Fact]
|
||||
public void Straight_deltas_match_the_electricity_house_meter()
|
||||
{
|
||||
// Zähler Haus: Sept 0 → Okt 411 → Nov 1153 → Dez 1968 (SDD reference data).
|
||||
var ctx = new NormalizationContext
|
||||
{
|
||||
Meter = new MeterConfig { MeterId = 1, Mode = MeterMode.CumulativeCounter, Unit = "kWh" },
|
||||
Readings =
|
||||
[
|
||||
Reading(1, Month(2022, 9), 0),
|
||||
Reading(1, Month(2022, 10), 411),
|
||||
Reading(1, Month(2022, 11), 1153),
|
||||
Reading(1, Month(2022, 12), 1968),
|
||||
],
|
||||
};
|
||||
|
||||
var result = _engine.Normalize(ctx);
|
||||
|
||||
Assert.Equal([0d, 411d, 742d, 815d], result.Select(c => c.Amount));
|
||||
Assert.All(result, c => Assert.Equal(ConsumptionKind.Consumption, c.Kind));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void First_reading_books_the_full_register_against_a_zero_baseline()
|
||||
{
|
||||
// Zähler Auto appears mid-series: first reading 3755 → month-one consumption 3755.
|
||||
var ctx = new NormalizationContext
|
||||
{
|
||||
Meter = new MeterConfig { MeterId = 3, Mode = MeterMode.CumulativeCounter, Unit = "kWh" },
|
||||
Readings = [Reading(3, Month(2023, 5), 3755), Reading(3, Month(2023, 6), 3960)],
|
||||
};
|
||||
|
||||
var result = _engine.Normalize(ctx);
|
||||
|
||||
Assert.Equal([3755d, 205d], result.Select(c => c.Amount));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Counter_reset_rebaselines_at_new_value()
|
||||
{
|
||||
var ctx = new NormalizationContext
|
||||
{
|
||||
Meter = new MeterConfig
|
||||
{
|
||||
MeterId = 1,
|
||||
Mode = MeterMode.CumulativeCounter,
|
||||
Unit = "kWh",
|
||||
InitialBaseline = 90,
|
||||
},
|
||||
Readings =
|
||||
[
|
||||
Reading(1, Month(2023, 1), 100),
|
||||
Reading(1, Month(2023, 2), 150),
|
||||
Reading(1, Month(2023, 3), 30),
|
||||
Reading(1, Month(2023, 4), 80),
|
||||
],
|
||||
Events = [Reset(1, Month(2023, 3), newValue: 0)],
|
||||
};
|
||||
|
||||
var result = _engine.Normalize(ctx);
|
||||
|
||||
Assert.Equal([10d, 50d, 30d, 50d], result.Select(c => c.Amount));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Unexplained_decrease_yields_zero_and_marks_quality()
|
||||
{
|
||||
var ctx = new NormalizationContext
|
||||
{
|
||||
Meter = new MeterConfig { MeterId = 1, Mode = MeterMode.CumulativeCounter, Unit = "kWh" },
|
||||
Readings = [Reading(1, Month(2023, 1), 100), Reading(1, Month(2023, 2), 60)],
|
||||
};
|
||||
|
||||
var result = _engine.Normalize(ctx);
|
||||
|
||||
Assert.Equal(0d, result[1].Amount);
|
||||
Assert.Equal(ReadingQuality.Estimated, result[1].Quality);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generation_meter_emits_generation_kind()
|
||||
{
|
||||
// Solar 2: Okt 0 → Nov 0 → ... → first real reading 7 in Feb.
|
||||
var ctx = new NormalizationContext
|
||||
{
|
||||
Meter = new MeterConfig { MeterId = 5, Mode = MeterMode.GenerationCounter, Unit = "kWh" },
|
||||
Readings = [Reading(5, Month(2023, 1), 0), Reading(5, Month(2023, 2), 7)],
|
||||
};
|
||||
|
||||
var result = _engine.Normalize(ctx);
|
||||
|
||||
Assert.Equal([0d, 7d], result.Select(c => c.Amount));
|
||||
Assert.All(result, c => Assert.Equal(ConsumptionKind.Generation, c.Kind));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user