-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfilter_test.go
More file actions
168 lines (139 loc) · 5.02 KB
/
Copy pathfilter_test.go
File metadata and controls
168 lines (139 loc) · 5.02 KB
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
package n2k
import (
"testing"
"github.com/open-ships/n2k/pgn"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestFilterCompilation(t *testing.T) {
f, err := compileFilter("pgn == 127250")
require.NoError(t, err)
assert.NotNil(t, f)
}
func TestFilterPreOnly(t *testing.T) {
f, err := compileFilter("pgn == 127250 && source == 3")
require.NoError(t, err)
assert.True(t, f.preOnly, "expression with only metadata vars should be pre-only")
assert.False(t, f.hasPost, "should not have post filter")
assert.NotNil(t, f.preProg, "should have pre program")
assert.Nil(t, f.postProg, "should not have post program")
// Passes.
assert.True(t, f.evalPre(pgn.MessageInfo{PGN: 127250, SourceId: 3}))
// Fails on PGN.
assert.False(t, f.evalPre(pgn.MessageInfo{PGN: 99999, SourceId: 3}))
// Fails on source.
assert.False(t, f.evalPre(pgn.MessageInfo{PGN: 127250, SourceId: 7}))
}
func TestFilterPostOnly(t *testing.T) {
f, err := compileFilter("msg.Heading > 3.14")
require.NoError(t, err)
assert.False(t, f.preOnly, "should not be pre-only")
assert.True(t, f.hasPost, "should have post filter")
assert.Nil(t, f.preProg, "should not have pre program")
assert.NotNil(t, f.postProg, "should have post program")
// Passes.
info := pgn.MessageInfo{PGN: 127250}
assert.True(t, f.evalPostWithInfo(info, map[string]any{"Heading": 4.0}))
// Fails.
assert.False(t, f.evalPostWithInfo(info, map[string]any{"Heading": 1.0}))
}
func TestFilterSplit(t *testing.T) {
f, err := compileFilter("pgn == 127250 && msg.Heading > 3.14")
require.NoError(t, err)
assert.False(t, f.preOnly, "should not be pre-only since msg is referenced")
assert.True(t, f.hasPost, "should have post filter")
assert.NotNil(t, f.preProg, "should have pre program for pgn check")
assert.NotNil(t, f.postProg, "should have post program for msg check")
info := pgn.MessageInfo{PGN: 127250}
wrongInfo := pgn.MessageInfo{PGN: 99999}
// Pre-filter passes, post-filter passes.
assert.True(t, f.evalPre(info))
assert.True(t, f.evalPostWithInfo(info, map[string]any{"Heading": 4.0}))
// Pre-filter fails (wrong PGN) — no need to decode.
assert.False(t, f.evalPre(wrongInfo))
// Pre passes but post fails.
assert.True(t, f.evalPre(info))
assert.False(t, f.evalPostWithInfo(info, map[string]any{"Heading": 1.0}))
}
func TestFilterOrCannotSplit(t *testing.T) {
f, err := compileFilter("source == 3 || msg.Heading > 1.0")
require.NoError(t, err)
// OR cannot be split: the whole expression references msg, so it all goes to post.
assert.False(t, f.preOnly)
assert.True(t, f.hasPost)
assert.Nil(t, f.preProg, "OR expression cannot be split, no pre program")
assert.NotNil(t, f.postProg)
}
func TestFilterCaseInsensitive(t *testing.T) {
f, err := compileFilter("msg.heading > 1.0")
require.NoError(t, err)
assert.True(t, f.hasPost)
info := pgn.MessageInfo{PGN: 127250}
fields := map[string]any{"heading": 2.0, "Heading": 2.0}
assert.True(t, f.evalPostWithInfo(info, fields))
}
func TestFilterInvalidExpression(t *testing.T) {
_, err := compileFilter("this is not valid CEL !!!")
assert.Error(t, err)
}
func TestFilterDestination(t *testing.T) {
f, err := compileFilter("destination == 255")
require.NoError(t, err)
assert.True(t, f.preOnly)
assert.True(t, f.evalPre(pgn.MessageInfo{TargetId: ptrU8(255)}))
assert.False(t, f.evalPre(pgn.MessageInfo{TargetId: ptrU8(0)}))
}
func TestFilterPriority(t *testing.T) {
f, err := compileFilter("priority < 4")
require.NoError(t, err)
assert.True(t, f.preOnly)
assert.True(t, f.evalPre(pgn.MessageInfo{Priority: ptrU8(2)}))
assert.False(t, f.evalPre(pgn.MessageInfo{Priority: ptrU8(5)}))
}
func ptrU8(v uint8) *uint8 { return &v }
func TestStructToFilterMap(t *testing.T) {
type testStruct struct {
info pgn.MessageInfo // unexported, like real PGN structs
Heading *float32
Deviation *float32
Sid *uint8
Reference string
}
heading := float32(1.57)
sid := uint8(42)
s := testStruct{
info: pgn.MessageInfo{PGN: 127250},
Heading: &heading,
Deviation: nil, // nil pointer, should be skipped
Sid: &sid,
Reference: "Magnetic",
}
m := structToFilterMap(s)
// info (unexported) should be skipped.
_, hasInfo := m["info"]
assert.False(t, hasInfo, "unexported info field should be skipped")
// Heading should be present with both cases.
assert.InDelta(t, 1.57, m["Heading"], 0.01)
assert.InDelta(t, 1.57, m["heading"], 0.01)
// Deviation (nil pointer) should be absent.
_, hasDev := m["Deviation"]
assert.False(t, hasDev, "nil pointer field should be skipped")
// Sid should be present as int64.
assert.Equal(t, int64(42), m["Sid"])
assert.Equal(t, int64(42), m["sid"])
// Reference should be present.
assert.Equal(t, "Magnetic", m["Reference"])
assert.Equal(t, "Magnetic", m["reference"])
}
func TestStructToFilterMapPointer(t *testing.T) {
type simple struct {
Value *float64
}
v := 3.14
m := structToFilterMap(&simple{Value: &v})
assert.Equal(t, 3.14, m["Value"])
}
func TestStructToFilterMapNonStruct(t *testing.T) {
m := structToFilterMap(42)
assert.Nil(t, m)
}