1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
|
// SPDX-License-Identifier: MIT
// Copyright (c) 2026 Paul Buetow
package rpn
import (
"strings"
"testing"
)
// customCleanup undefines a custom metric and verifies the cleanup.
// Must be deferred at the start of each test that defines a custom metric.
func customCleanup(t *testing.T, rpn *RPN, name string) {
_, err := rpn.ParseAndEvaluate("custom undefine " + name)
if err != nil {
t.Logf("cleanup: failed to undefine %s: %v", name, err)
}
}
// TestCustomDefineFactorZero tests defining a custom metric with factor=0
func TestCustomDefineFactorZero(t *testing.T) {
vars := NewVariables()
rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "zero")
result, err := rpn.ParseAndEvaluate("custom define zero 0 Custom")
if err != nil {
t.Fatalf("unexpected error defining metric with factor=0: %v", err)
}
if !strings.Contains(result, "defined") {
t.Errorf("expected 'defined' in result, got: %s", result)
}
// Verify it works (factor=0 means any value in this metric = 0 in base)
result, err = rpn.ParseAndEvaluate("5zero 3 +")
if err != nil {
t.Fatalf("arithmetic with factor=0 metric failed: %v", err)
}
t.Logf("5zero + 3 = %s", result)
}
// TestCustomDefineNegativeFactor tests defining a custom metric with negative factor
func TestCustomDefineNegativeFactor(t *testing.T) {
vars := NewVariables()
rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "negtest")
result, err := rpn.ParseAndEvaluate("custom define negtest -5 Custom")
if err != nil {
t.Fatalf("unexpected error defining metric with negative factor: %v", err)
}
if !strings.Contains(result, "defined") {
t.Errorf("expected 'defined' in result, got: %s", result)
}
// Verify it works with negative factor
result, err = rpn.ParseAndEvaluate("2negtest 1 +")
if err != nil {
t.Fatalf("arithmetic with negative factor metric failed: %v", err)
}
t.Logf("2negtest + 1 = %s", result)
}
// TestCustomDefineMalformedInput tests that malformed custom define input
func TestCustomDefineMalformedInput(t *testing.T) {
vars := NewVariables()
rpn := NewRPN(vars, nil)
_, err := rpn.ParseAndEvaluate("custom define 1 Custom")
// Double-space collapses: fields = ["custom", "define", "1", "Custom"] (metric "" already exists as alias or empty check)
if err == nil {
t.Log("custom define with empty name succeeded")
}
// Either way, it shouldn't panic
}
// TestCustomDefineConflictingAlias tests defining a custom metric with a name
// that conflicts with an existing metric
func TestCustomDefineConflictingAlias(t *testing.T) {
vars := NewVariables()
rpn := NewRPN(vars, nil)
// Try to define a metric with a name that matches an existing one
_, err := rpn.ParseAndEvaluate("custom define Mbps 1000 DataRate")
if err == nil {
t.Error("expected error defining metric with existing name 'Mbps'")
}
}
// TestCustomMetricArithmetic tests using a custom metric in arithmetic operations
func TestCustomMetricArithmetic(t *testing.T) {
vars := NewVariables()
rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "arithmetic_test")
_, err := rpn.ParseAndEvaluate("custom define arithmetic_test 42 Custom")
if err != nil {
t.Fatalf("failed to define custom metric: %v", err)
}
// Use in addition: 10arithmetic_test + 5arithmetic_test = 15arithmetic_test
result, err := rpn.ParseAndEvaluate("10arithmetic_test 5arithmetic_test +")
if err != nil {
t.Fatalf("arithmetic with custom metric failed: %v", err)
}
t.Logf("10arithmetic_test + 5arithmetic_test = %s", result)
}
// TestCustomMetricHyperOperations tests using a custom metric in hyper operations
func TestCustomMetricHyperOperations(t *testing.T) {
vars := NewVariables()
rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "hyper_test")
_, err := rpn.ParseAndEvaluate("custom define hyper_test 100 Custom")
if err != nil {
t.Fatalf("failed to define custom metric: %v", err)
}
// Use in hyper add
result, err := rpn.ParseAndEvaluate("10hyper_test 5hyper_test 3hyper_test [+]")
if err != nil {
t.Fatalf("hyper operation with custom metric failed: %v", err)
}
t.Logf("10hyper_test 5hyper_test 3hyper_test [+] = %s", result)
}
// TestCustomMetricSubtraction tests subtraction with custom metrics
func TestCustomMetricSubtraction(t *testing.T) {
vars := NewVariables()
rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "sub_test")
_, err := rpn.ParseAndEvaluate("custom define sub_test 10 Custom")
if err != nil {
t.Fatalf("failed to define custom metric: %v", err)
}
result, err := rpn.ParseAndEvaluate("5sub_test 3sub_test -")
if err != nil {
t.Fatalf("subtraction with custom metric failed: %v", err)
}
t.Logf("5sub_test - 3sub_test = %s", result)
}
// TestCustomMetricMultiplication tests multiplication with custom metrics
func TestCustomMetricMultiplication(t *testing.T) {
vars := NewVariables()
rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "mul_test")
_, err := rpn.ParseAndEvaluate("custom define mul_test 5 Custom")
if err != nil {
t.Fatalf("failed to define custom metric: %v", err)
}
result, err := rpn.ParseAndEvaluate("3mul_test 2 *")
if err != nil {
t.Fatalf("multiplication with custom metric failed: %v", err)
}
t.Logf("3mul_test * 2 = %s", result)
}
// TestCustomMetricDivision tests division with custom metrics
func TestCustomMetricDivision(t *testing.T) {
vars := NewVariables()
rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "div_test")
_, err := rpn.ParseAndEvaluate("custom define div_test 10 Custom")
if err != nil {
t.Fatalf("failed to define custom metric: %v", err)
}
result, err := rpn.ParseAndEvaluate("20div_test 4div_test /")
if err != nil {
t.Fatalf("division with custom metric failed: %v", err)
}
t.Logf("20div_test / 4div_test = %s", result)
}
// TestCustomMetricConversionFail tests that custom metrics can't be converted
// between different categories
func TestCustomMetricConversionFail(t *testing.T) {
vars := NewVariables()
rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "conv_test")
_, err := rpn.ParseAndEvaluate("custom define conv_test 10 Custom")
if err != nil {
t.Fatalf("failed to define custom metric: %v", err)
}
// Converting Custom to DataRate should fail
_, err = rpn.ParseAndEvaluate("10conv_test @Mbps convert")
if err == nil {
t.Error("expected error converting Custom to DataRate")
}
}
// TestCustomMetricCrossCategory tests that custom metrics in different categories
// can't be mixed in operations
func TestCustomMetricCrossCategory(t *testing.T) {
vars := NewVariables()
rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "cat_test1")
defer customCleanup(t, rpn, "cat_test2")
_, _ = rpn.ParseAndEvaluate("custom define cat_test1 10 Time")
_, _ = rpn.ParseAndEvaluate("custom define cat_test2 5 Distance")
// Mixing Time and Distance should fail
_, err := rpn.ParseAndEvaluate("10cat_test1 5cat_test2 +")
if err == nil {
t.Error("expected error mixing Time and Distance categories")
}
}
// TestCustomMetricShow tests that custom metrics display correctly in Show
func TestCustomMetricShow(t *testing.T) {
vars := NewVariables()
rpn := NewRPN(vars, nil)
defer customCleanup(t, rpn, "show_test")
_, err := rpn.ParseAndEvaluate("custom define show_test 100 Custom")
if err != nil {
t.Fatalf("failed to define custom metric: %v", err)
}
result, err := rpn.ParseAndEvaluate("42show_test show")
if err != nil {
t.Fatalf("show with custom metric failed: %v", err)
}
t.Logf("42show_test show = %s", result)
}
|