diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-22 11:00:49 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-22 11:00:49 +0300 |
| commit | 0364480eb4d99142c1f2d79ebc25692809acb094 (patch) | |
| tree | da6b37c14dc4ae24831c96d47ed3cc0ce624feff | |
| parent | 9c0f60456a279d69abea17075ebaad1c7194a9bc (diff) | |
test(rpn): add table-driven unit tests for metric-aware arithmetic
Test with NewOperations and direct stack manipulation:
- Same-category addition (1000bps + 1Kbps = 2000bps)
- Cool absorbing metric (5 + 100Mbps = 100.000005Mbps)
- Incompatible categories error (100bps + 2hr)
- Cross-category multiplication (100Mbps * 2hr → bits)
- Cross-category division (10GB / 2hr → bps)
| -rw-r--r-- | internal/rpn/metric_test.go | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/internal/rpn/metric_test.go b/internal/rpn/metric_test.go index ab9c215..71da7dc 100644 --- a/internal/rpn/metric_test.go +++ b/internal/rpn/metric_test.go @@ -899,3 +899,110 @@ func TestMetricAwareArithmetic(t *testing.T) { }) } } + +func TestMetricOperationsUnit(t *testing.T) { + reg := GetMetricRegistry() + tolerance := 0.001 + + cases := []struct { + name string + setup func(s *Stack) + op func(*Operations, *Stack) error + wantVal float64 + wantMet string + wantErr bool + }{ + { + name: "same-category addition 1000bps+1Kbps", + setup: func(s *Stack) { + kbps, _ := reg.Find("Kbps") + bps, _ := reg.Find("bps") + s.Push(NewFloatWithMetric(1000, bps)) + s.Push(NewFloatWithMetric(1, kbps)) + }, + op: func(o *Operations, s *Stack) error { return o.Add(s) }, + wantVal: 2000, + wantMet: "bps", // result in left operand's metric (bps) + }, + { + name: "Cool absorbing metric 5+100Mbps", + setup: func(s *Stack) { + mbps, _ := reg.Find("Mbps") + s.Push(NewFloatWithMetric(5, GetCoolMetric())) + s.Push(NewFloatWithMetric(100, mbps)) + }, + op: func(o *Operations, s *Stack) error { return o.Add(s) }, + wantVal: 100.000005, + wantMet: "Mbps", + }, + { + name: "incompatible categories 100bps+2hr", + setup: func(s *Stack) { + bps, _ := reg.Find("bps") + hr, _ := reg.Find("hr") + s.Push(NewFloatWithMetric(100, bps)) + s.Push(NewFloatWithMetric(2, hr)) + }, + op: func(o *Operations, s *Stack) error { return o.Add(s) }, + wantErr: true, + }, + { + name: "cross-category mul 100Mbps*2hr", + setup: func(s *Stack) { + mbps, _ := reg.Find("Mbps") + hr, _ := reg.Find("hr") + s.Push(NewFloatWithMetric(100, mbps)) + s.Push(NewFloatWithMetric(2, hr)) + }, + op: func(o *Operations, s *Stack) error { return o.Multiply(s) }, + wantVal: 720000000000, + wantMet: "bits", + }, + { + name: "cross-category div 10GB/2hr", + setup: func(s *Stack) { + gb, _ := reg.Find("GB") + hr, _ := reg.Find("hr") + s.Push(NewFloatWithMetric(10, gb)) + s.Push(NewFloatWithMetric(2, hr)) + }, + op: func(o *Operations, s *Stack) error { return o.Divide(s) }, + wantVal: 11111111.111, + wantMet: "bps", + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + vars := NewVariables() + ops := NewOperations(vars) + s := NewStack() + tc.setup(s) + + err := tc.op(ops, s) + if tc.wantErr { + if err == nil { + t.Fatal("expected error, got nil") + } + return + } + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if s.Len() != 1 { + t.Fatalf("expected 1 item on stack, got %d", s.Len()) + } + result, _ := s.Pop() + val, _ := result.Float64() + if val < tc.wantVal-tolerance || val > tc.wantVal+tolerance { + t.Errorf("val = %g, want %g (tolerance %g)", val, tc.wantVal, tolerance) + } + m := result.Metric() + expected, _ := reg.Find(tc.wantMet) + if m != expected { + t.Errorf("metric = %v, want %v", m, expected) + } + }) + } +} |
