benchmark unstructuredToVal

This commit is contained in:
cici37 2022-01-25 09:54:25 -08:00
parent 33a2c50bce
commit 62394b8ab8
3 changed files with 138 additions and 0 deletions

View File

@ -619,3 +619,47 @@ func TestMapper(t *testing.T) {
})
}
}
func BenchmarkUnstructuredToVal(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for n := 0; n < b.N; n++ {
if val := UnstructuredToVal([]interface{}{
map[string]interface{}{
"key": "a",
"val": 1,
},
map[string]interface{}{
"key": "b",
"val": 2,
},
map[string]interface{}{
"key": "@b",
"val": 2,
},
}, &mapListSchema); val == nil {
b.Fatal(val)
}
}
}
func BenchmarkUnstructuredToValWithEscape(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for n := 0; n < b.N; n++ {
if val := UnstructuredToVal([]interface{}{
map[string]interface{}{
"key": "a.1",
"val": "__i.1",
},
map[string]interface{}{
"key": "b.1",
"val": 2,
},
}, &mapListSchema); val == nil {
b.Fatal(val)
}
}
}

View File

@ -36,6 +36,57 @@ var celReservedSymbols = sets.NewString(
// expandMatcher matches the escape sequence, characters that are escaped, and characters that are unsupported
var expandMatcher = regexp.MustCompile(`(__|[-./]|[^a-zA-Z0-9-./_])`)
// newCharacterFilter returns a boolean array to indicate the allowed characters
func newCharacterFilter(characters string) []bool {
maxChar := 0
for _, c := range characters {
if maxChar < int(c) {
maxChar = int(c)
}
}
filter := make([]bool, maxChar+1)
for _, c := range characters {
filter[int(c)] = true
}
return filter
}
type escapeCheck struct {
canSkipRegex bool
invalidCharFound bool
}
// skipRegexCheck checks if escape would be skipped.
// if invalidCharFound is true, it must have invalid character; if invalidCharFound is false, not sure if it has invalid character or not
func skipRegexCheck(ident string) escapeCheck {
escapeCheck := escapeCheck{canSkipRegex: true, invalidCharFound: false}
// skip escape if possible
previous_underscore := false
for _, c := range ident {
if c == '/' || c == '-' || c == '.' {
escapeCheck.canSkipRegex = false
return escapeCheck
}
intc := int(c)
if intc < 0 || intc >= len(validCharacterFilter) || !validCharacterFilter[intc] {
escapeCheck.invalidCharFound = true
return escapeCheck
}
if c == '_' && previous_underscore {
escapeCheck.canSkipRegex = false
return escapeCheck
}
previous_underscore = c == '_'
}
return escapeCheck
}
// validCharacterFilter indicates the allowed characters.
var validCharacterFilter = newCharacterFilter("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_")
// Escape escapes ident and returns a CEL identifier (of the form '[a-zA-Z_][a-zA-Z0-9_]*'), or returns
// false if the ident does not match the supported input format of `[a-zA-Z_.-/][a-zA-Z0-9_.-/]*`.
// Escaping Rules:
@ -53,6 +104,15 @@ func Escape(ident string) (string, bool) {
if celReservedSymbols.Has(ident) {
return "__" + ident + "__", true
}
escapeCheck := skipRegexCheck(ident)
if escapeCheck.invalidCharFound {
return "", false
}
if escapeCheck.canSkipRegex {
return ident, true
}
ok := true
ident = expandMatcher.ReplaceAllStringFunc(ident, func(s string) string {
switch s {

View File

@ -170,3 +170,37 @@ func TestEscapingFuzz(t *testing.T) {
}
var validCelIdent = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)
func TestCanSkipRegex(t *testing.T) {
cases := []struct {
unescaped string
canSkip bool
invalidCharFound bool
}{
{unescaped: "a.a", canSkip: false},
{unescaped: "a-a", canSkip: false},
{unescaped: "a__a", canSkip: false},
{unescaped: "a.-/__a", canSkip: false},
{unescaped: "a_a", canSkip: true},
{unescaped: "a_a_a", canSkip: true},
{unescaped: "@", invalidCharFound: true},
{unescaped: "👑", invalidCharFound: true},
// if escape keyword is detected before invalid character, invalidCharFound
{unescaped: "/👑", canSkip: false},
}
for _, tc := range cases {
t.Run(tc.unescaped, func(t *testing.T) {
escapeCheck := skipRegexCheck(tc.unescaped)
if escapeCheck.invalidCharFound {
if escapeCheck.invalidCharFound != tc.invalidCharFound {
t.Errorf("Expected input validation to be %v, but got %t", tc.invalidCharFound, escapeCheck.invalidCharFound)
}
} else {
if escapeCheck.canSkipRegex != tc.canSkip {
t.Errorf("Expected %v, but got %t", tc.canSkip, escapeCheck.canSkipRegex)
}
}
})
}
}