mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-22 03:10:42 +08:00
338 lines
9.8 KiB
Go
338 lines
9.8 KiB
Go
package lib
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/google/cel-go/common/types"
|
|
"github.com/google/cel-go/common/types/ref"
|
|
)
|
|
|
|
func TestRegisterStringImplementations(t *testing.T) {
|
|
overloads := registerStringImplementations()
|
|
|
|
idx := make(map[string]int, len(overloads))
|
|
for i, o := range overloads {
|
|
idx[o.Operator] = i
|
|
}
|
|
|
|
t.Run("bytes_bcontains_bytes", func(t *testing.T) {
|
|
binary := overloads[idx["bytes_bcontains_bytes"]].Binary
|
|
|
|
tests := []struct {
|
|
name string
|
|
lhs types.Bytes
|
|
rhs types.Bytes
|
|
want types.Bool
|
|
}{
|
|
{"contains", types.Bytes([]byte("hello world")), types.Bytes([]byte("world")), true},
|
|
{"not_contains", types.Bytes([]byte("hello world")), types.Bytes([]byte("xyz")), false},
|
|
{"empty_needle", types.Bytes([]byte("hello")), types.Bytes([]byte{}), true},
|
|
{"both_empty", types.Bytes([]byte{}), types.Bytes([]byte{}), true},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
result := binary(tc.lhs, tc.rhs)
|
|
if types.IsError(result) {
|
|
t.Fatalf("unexpected error: %v", result)
|
|
}
|
|
got, ok := result.(types.Bool)
|
|
if !ok {
|
|
t.Fatalf("expected types.Bool, got %T", result)
|
|
}
|
|
if got != tc.want {
|
|
t.Errorf("bcontains = %v, want %v", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("bytes_bcontains_bytes_wrong_lhs", func(t *testing.T) {
|
|
result := overloads[idx["bytes_bcontains_bytes"]].Binary(types.String("hello"), types.Bytes([]byte("x")))
|
|
if !types.IsError(result) {
|
|
t.Error("expected error for non-Bytes lhs")
|
|
}
|
|
})
|
|
|
|
t.Run("bytes_bcontains_bytes_wrong_rhs", func(t *testing.T) {
|
|
result := overloads[idx["bytes_bcontains_bytes"]].Binary(types.Bytes([]byte("hello")), types.String("x"))
|
|
if !types.IsError(result) {
|
|
t.Error("expected error for non-Bytes rhs")
|
|
}
|
|
})
|
|
|
|
t.Run("string_bmatches_bytes", func(t *testing.T) {
|
|
binary := overloads[idx["string_bmatches_bytes"]].Binary
|
|
|
|
tests := []struct {
|
|
name string
|
|
pattern types.String
|
|
input types.Bytes
|
|
want types.Bool
|
|
}{
|
|
{"digits_match", `\d+`, types.Bytes([]byte("abc123")), true},
|
|
{"digits_no_match", `\d+`, types.Bytes([]byte("abc")), false},
|
|
{"any", `.*`, types.Bytes([]byte("hello")), true},
|
|
{"empty_pattern", ``, types.Bytes([]byte("hello")), true},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
result := binary(tc.pattern, tc.input)
|
|
if types.IsError(result) {
|
|
t.Fatalf("unexpected error: %v", result)
|
|
}
|
|
got, ok := result.(types.Bool)
|
|
if !ok {
|
|
t.Fatalf("expected types.Bool, got %T", result)
|
|
}
|
|
if got != tc.want {
|
|
t.Errorf("bmatches(%q, %q) = %v, want %v", tc.pattern, tc.input, got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("string_bmatches_bytes_invalid_regex", func(t *testing.T) {
|
|
result := overloads[idx["string_bmatches_bytes"]].Binary(types.String(`[invalid`), types.Bytes([]byte("hello")))
|
|
if !types.IsError(result) {
|
|
t.Error("expected error for invalid regex pattern")
|
|
}
|
|
})
|
|
|
|
t.Run("string_bmatches_bytes_wrong_lhs", func(t *testing.T) {
|
|
result := overloads[idx["string_bmatches_bytes"]].Binary(types.Int(0), types.Bytes([]byte("hello")))
|
|
if !types.IsError(result) {
|
|
t.Error("expected error for non-String lhs")
|
|
}
|
|
})
|
|
|
|
t.Run("string_bmatches_bytes_wrong_rhs", func(t *testing.T) {
|
|
result := overloads[idx["string_bmatches_bytes"]].Binary(types.String(`\d+`), types.String("123"))
|
|
if !types.IsError(result) {
|
|
t.Error("expected error for non-Bytes rhs")
|
|
}
|
|
})
|
|
|
|
t.Run("icontains_string", func(t *testing.T) {
|
|
binary := overloads[idx["icontains_string"]].Binary
|
|
|
|
tests := []struct {
|
|
name string
|
|
lhs types.String
|
|
rhs types.String
|
|
want types.Bool
|
|
}{
|
|
{"case_insensitive_match", "Hello World", "hello", true},
|
|
{"exact_match", "Hello World", "Hello", true},
|
|
{"upper_needle", "hello world", "WORLD", true},
|
|
{"not_contains", "hello world", "xyz", false},
|
|
{"empty_needle", "hello", "", true},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
result := binary(tc.lhs, tc.rhs)
|
|
if types.IsError(result) {
|
|
t.Fatalf("unexpected error: %v", result)
|
|
}
|
|
got, ok := result.(types.Bool)
|
|
if !ok {
|
|
t.Fatalf("expected types.Bool, got %T", result)
|
|
}
|
|
if got != tc.want {
|
|
t.Errorf("icontains(%q, %q) = %v, want %v", tc.lhs, tc.rhs, got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("icontains_string_wrong_lhs", func(t *testing.T) {
|
|
result := overloads[idx["icontains_string"]].Binary(types.Bool(true), types.String("x"))
|
|
if !types.IsError(result) {
|
|
t.Error("expected error for non-String lhs")
|
|
}
|
|
})
|
|
|
|
t.Run("icontains_string_wrong_rhs", func(t *testing.T) {
|
|
result := overloads[idx["icontains_string"]].Binary(types.String("hello"), types.Int(1))
|
|
if !types.IsError(result) {
|
|
t.Error("expected error for non-String rhs")
|
|
}
|
|
})
|
|
|
|
t.Run("substr_string_int_int", func(t *testing.T) {
|
|
fn := overloads[idx["substr_string_int_int"]].Function
|
|
|
|
tests := []struct {
|
|
name string
|
|
str types.String
|
|
start types.Int
|
|
length types.Int
|
|
want types.String
|
|
}{
|
|
{"basic", "hello world", 0, 5, "hello"},
|
|
{"middle", "hello world", 6, 5, "world"},
|
|
{"single_char", "hello", 1, 1, "e"},
|
|
{"full", "hello", 0, 5, "hello"},
|
|
{"zero_length", "hello", 2, 0, ""},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
result := fn(tc.str, tc.start, tc.length)
|
|
if types.IsError(result) {
|
|
t.Fatalf("substr(%q, %d, %d): unexpected error %v", tc.str, tc.start, tc.length, result)
|
|
}
|
|
got, ok := result.(types.String)
|
|
if !ok {
|
|
t.Fatalf("expected types.String, got %T", result)
|
|
}
|
|
if got != tc.want {
|
|
t.Errorf("substr(%q, %d, %d) = %q, want %q", tc.str, tc.start, tc.length, got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("substr_out_of_bounds", func(t *testing.T) {
|
|
fn := overloads[idx["substr_string_int_int"]].Function
|
|
|
|
oob := []struct {
|
|
name string
|
|
str types.String
|
|
start types.Int
|
|
length types.Int
|
|
}{
|
|
{"negative_start", "hello", -1, 2},
|
|
{"negative_length", "hello", 0, -1},
|
|
{"start_too_large", "hello", 10, 1},
|
|
{"length_overflow", "hello", 3, 10},
|
|
}
|
|
for _, tc := range oob {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
result := fn(tc.str, tc.start, tc.length)
|
|
if !types.IsError(result) {
|
|
t.Errorf("expected error for substr(%q, %d, %d), got %v", tc.str, tc.start, tc.length, result)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("substr_wrong_arg_count", func(t *testing.T) {
|
|
fn := overloads[idx["substr_string_int_int"]].Function
|
|
result := fn(types.String("hello"), types.Int(0))
|
|
if !types.IsError(result) {
|
|
t.Error("expected error for wrong argument count")
|
|
}
|
|
})
|
|
|
|
t.Run("substr_wrong_types", func(t *testing.T) {
|
|
fn := overloads[idx["substr_string_int_int"]].Function
|
|
|
|
cases := []struct {
|
|
name string
|
|
args []ref.Val
|
|
}{
|
|
{"wrong_str", []ref.Val{types.Int(0), types.Int(0), types.Int(1)}},
|
|
{"wrong_start", []ref.Val{types.String("hello"), types.String("x"), types.Int(1)}},
|
|
{"wrong_length", []ref.Val{types.String("hello"), types.Int(0), types.String("x")}},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
result := fn(tc.args...)
|
|
if !types.IsError(result) {
|
|
t.Errorf("expected error, got %v", result)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("startsWith_bytes", func(t *testing.T) {
|
|
binary := overloads[idx["startsWith_bytes"]].Binary
|
|
|
|
tests := []struct {
|
|
name string
|
|
lhs types.Bytes
|
|
rhs types.Bytes
|
|
want types.Bool
|
|
}{
|
|
{"match", types.Bytes([]byte("hello world")), types.Bytes([]byte("hello")), true},
|
|
{"no_match", types.Bytes([]byte("hello world")), types.Bytes([]byte("world")), false},
|
|
{"empty_prefix", types.Bytes([]byte("hello")), types.Bytes([]byte{}), true},
|
|
{"exact", types.Bytes([]byte("hello")), types.Bytes([]byte("hello")), true},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
result := binary(tc.lhs, tc.rhs)
|
|
if types.IsError(result) {
|
|
t.Fatalf("unexpected error: %v", result)
|
|
}
|
|
got, ok := result.(types.Bool)
|
|
if !ok {
|
|
t.Fatalf("expected types.Bool, got %T", result)
|
|
}
|
|
if got != tc.want {
|
|
t.Errorf("startsWith_bytes = %v, want %v", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("startsWith_bytes_wrong_lhs", func(t *testing.T) {
|
|
result := overloads[idx["startsWith_bytes"]].Binary(types.String("hello"), types.Bytes([]byte("h")))
|
|
if !types.IsError(result) {
|
|
t.Error("expected error for non-Bytes lhs")
|
|
}
|
|
})
|
|
|
|
t.Run("startsWith_bytes_wrong_rhs", func(t *testing.T) {
|
|
result := overloads[idx["startsWith_bytes"]].Binary(types.Bytes([]byte("hello")), types.String("h"))
|
|
if !types.IsError(result) {
|
|
t.Error("expected error for non-Bytes rhs")
|
|
}
|
|
})
|
|
|
|
t.Run("startsWith_string", func(t *testing.T) {
|
|
binary := overloads[idx["startsWith_string"]].Binary
|
|
|
|
tests := []struct {
|
|
name string
|
|
lhs types.String
|
|
rhs types.String
|
|
want types.Bool
|
|
}{
|
|
{"case_insensitive_match", "Hello World", "hello", true},
|
|
{"upper_prefix", "hello world", "HELLO", true},
|
|
{"no_match", "hello world", "world", false},
|
|
{"empty_prefix", "hello", "", true},
|
|
{"exact", "Hello", "Hello", true},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
result := binary(tc.lhs, tc.rhs)
|
|
if types.IsError(result) {
|
|
t.Fatalf("unexpected error: %v", result)
|
|
}
|
|
got, ok := result.(types.Bool)
|
|
if !ok {
|
|
t.Fatalf("expected types.Bool, got %T", result)
|
|
}
|
|
if got != tc.want {
|
|
t.Errorf("startsWith_string(%q, %q) = %v, want %v", tc.lhs, tc.rhs, got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("startsWith_string_wrong_lhs", func(t *testing.T) {
|
|
result := overloads[idx["startsWith_string"]].Binary(types.Int(0), types.String("h"))
|
|
if !types.IsError(result) {
|
|
t.Error("expected error for non-String lhs")
|
|
}
|
|
})
|
|
|
|
t.Run("startsWith_string_wrong_rhs", func(t *testing.T) {
|
|
result := overloads[idx["startsWith_string"]].Binary(types.String("hello"), types.Bool(true))
|
|
if !types.IsError(result) {
|
|
t.Error("expected error for non-String rhs")
|
|
}
|
|
})
|
|
}
|