2022-08-24 14:54:26 +00:00
|
|
|
package regexutil
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
2024-05-24 01:06:55 +00:00
|
|
|
func TestGetOrValuesRegex(t *testing.T) {
|
2022-08-24 14:54:26 +00:00
|
|
|
f := func(s string, valuesExpected []string) {
|
|
|
|
t.Helper()
|
2024-05-24 01:06:55 +00:00
|
|
|
values := GetOrValuesRegex(s)
|
|
|
|
if !reflect.DeepEqual(values, valuesExpected) {
|
|
|
|
t.Fatalf("unexpected values for s=%q; got %q; want %q", s, values, valuesExpected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
f("", []string{""})
|
|
|
|
f("foo", []string{"foo"})
|
|
|
|
f("^foo$", nil)
|
|
|
|
f("|foo", []string{"", "foo"})
|
|
|
|
f("|foo|", []string{"", "", "foo"})
|
|
|
|
f("foo.+", nil)
|
|
|
|
f("foo.*", nil)
|
|
|
|
f(".*", nil)
|
|
|
|
f("foo|.*", nil)
|
|
|
|
f("(fo((o)))|(bar)", []string{"bar", "foo"})
|
|
|
|
f("foobar", []string{"foobar"})
|
|
|
|
f("z|x|c", []string{"c", "x", "z"})
|
|
|
|
f("foo|bar", []string{"bar", "foo"})
|
|
|
|
f("(foo|bar)", []string{"bar", "foo"})
|
|
|
|
f("(foo|bar)baz", []string{"barbaz", "foobaz"})
|
|
|
|
f("[a-z][a-z]", nil)
|
|
|
|
f("[a-d]", []string{"a", "b", "c", "d"})
|
|
|
|
f("x[a-d]we", []string{"xawe", "xbwe", "xcwe", "xdwe"})
|
|
|
|
f("foo(bar|baz)", []string{"foobar", "foobaz"})
|
|
|
|
f("foo(ba[rz]|(xx|o))", []string{"foobar", "foobaz", "fooo", "fooxx"})
|
|
|
|
f("foo(?:bar|baz)x(qwe|rt)", []string{"foobarxqwe", "foobarxrt", "foobazxqwe", "foobazxrt"})
|
|
|
|
f("foo(bar||baz)", []string{"foo", "foobar", "foobaz"})
|
|
|
|
f("(a|b|c)(d|e|f|0|1|2)(g|h|k|x|y|z)", nil)
|
|
|
|
f("(?i)foo", nil)
|
|
|
|
f("(?i)(foo|bar)", nil)
|
|
|
|
f("^foo|bar$", nil)
|
|
|
|
f("^(foo|bar)$", nil)
|
|
|
|
f("^a(foo|b(?:a|r))$", nil)
|
|
|
|
f("^a(foo$|b(?:a$|r))$", nil)
|
|
|
|
f("^a(^foo|bar$)z$", nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetOrValuesPromRegex(t *testing.T) {
|
|
|
|
f := func(s string, valuesExpected []string) {
|
|
|
|
t.Helper()
|
|
|
|
values := GetOrValuesPromRegex(s)
|
2022-08-24 14:54:26 +00:00
|
|
|
if !reflect.DeepEqual(values, valuesExpected) {
|
|
|
|
t.Fatalf("unexpected values for s=%q; got %q; want %q", s, values, valuesExpected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
f("", []string{""})
|
|
|
|
f("foo", []string{"foo"})
|
|
|
|
f("^foo$", []string{"foo"})
|
|
|
|
f("|foo", []string{"", "foo"})
|
|
|
|
f("|foo|", []string{"", "", "foo"})
|
|
|
|
f("foo.+", nil)
|
|
|
|
f("foo.*", nil)
|
|
|
|
f(".*", nil)
|
|
|
|
f("foo|.*", nil)
|
2022-08-26 08:57:12 +00:00
|
|
|
f("(fo((o)))|(bar)", []string{"bar", "foo"})
|
2022-08-24 14:54:26 +00:00
|
|
|
f("foobar", []string{"foobar"})
|
|
|
|
f("z|x|c", []string{"c", "x", "z"})
|
|
|
|
f("foo|bar", []string{"bar", "foo"})
|
|
|
|
f("(foo|bar)", []string{"bar", "foo"})
|
|
|
|
f("(foo|bar)baz", []string{"barbaz", "foobaz"})
|
|
|
|
f("[a-z][a-z]", nil)
|
|
|
|
f("[a-d]", []string{"a", "b", "c", "d"})
|
|
|
|
f("x[a-d]we", []string{"xawe", "xbwe", "xcwe", "xdwe"})
|
|
|
|
f("foo(bar|baz)", []string{"foobar", "foobaz"})
|
|
|
|
f("foo(ba[rz]|(xx|o))", []string{"foobar", "foobaz", "fooo", "fooxx"})
|
|
|
|
f("foo(?:bar|baz)x(qwe|rt)", []string{"foobarxqwe", "foobarxrt", "foobazxqwe", "foobazxrt"})
|
|
|
|
f("foo(bar||baz)", []string{"foo", "foobar", "foobaz"})
|
|
|
|
f("(a|b|c)(d|e|f|0|1|2)(g|h|k|x|y|z)", nil)
|
|
|
|
f("(?i)foo", nil)
|
|
|
|
f("(?i)(foo|bar)", nil)
|
|
|
|
f("^foo|bar$", []string{"bar", "foo"})
|
|
|
|
f("^(foo|bar)$", []string{"bar", "foo"})
|
|
|
|
f("^a(foo|b(?:a|r))$", []string{"aba", "abr", "afoo"})
|
2022-08-26 08:57:12 +00:00
|
|
|
f("^a(foo$|b(?:a$|r))$", []string{"aba", "abr", "afoo"})
|
|
|
|
f("^a(^foo|bar$)z$", nil)
|
|
|
|
}
|
|
|
|
|
2024-05-24 01:06:55 +00:00
|
|
|
func TestSimplifyRegex(t *testing.T) {
|
|
|
|
f := func(s, expectedPrefix, expectedSuffix string) {
|
|
|
|
t.Helper()
|
|
|
|
prefix, suffix := SimplifyRegex(s)
|
|
|
|
if prefix != expectedPrefix {
|
|
|
|
t.Fatalf("unexpected prefix for s=%q; got %q; want %q", s, prefix, expectedPrefix)
|
|
|
|
}
|
|
|
|
if suffix != expectedSuffix {
|
|
|
|
t.Fatalf("unexpected suffix for s=%q; got %q; want %q", s, suffix, expectedSuffix)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
f("", "", "")
|
|
|
|
f(".*", "", "")
|
|
|
|
f(".*(.*).*", "", "")
|
|
|
|
f("foo.*", "foo", "")
|
|
|
|
f(".*foo.*", "", "foo")
|
|
|
|
f("^", "", "\\A")
|
|
|
|
f("$", "", "(?-m:$)")
|
|
|
|
f("^()$", "", "(?-m:\\A$)")
|
|
|
|
f("^(?:)$", "", "(?-m:\\A$)")
|
|
|
|
f("^foo|^bar$|baz", "", "(?-m:\\Afoo|\\Abar$|baz)")
|
|
|
|
f("^(foo$|^bar)$", "", "(?-m:\\A(?:foo$|\\Abar)$)")
|
|
|
|
f("^a(foo$|bar)$", "", "(?-m:\\Aa(?:foo$|bar)$)")
|
|
|
|
f("^a(^foo|bar$)z$", "", "(?-m:\\Aa(?:\\Afoo|bar$)z$)")
|
|
|
|
f("foobar", "foobar", "")
|
|
|
|
f("foo$|^foobar", "", "(?-m:foo$|\\Afoobar)")
|
|
|
|
f("^(foo$|^foobar)$", "", "(?-m:\\A(?:foo$|\\Afoobar)$)")
|
|
|
|
f("foobar|foobaz", "fooba", "[rz]")
|
|
|
|
f("(fo|(zar|bazz)|x)", "", "fo|zar|bazz|x")
|
|
|
|
f("(тестЧЧ|тест)", "тест", "ЧЧ|")
|
|
|
|
f("foo(bar|baz|bana)", "fooba", "[rz]|na")
|
|
|
|
f("^foobar|foobaz", "", "\\Afoobar|foobaz")
|
|
|
|
f("^foobar|^foobaz$", "", "(?-m:\\Afoobar|\\Afoobaz$)")
|
|
|
|
f("foobar|foobaz", "fooba", "[rz]")
|
|
|
|
f("(?:^foobar|^foobaz)aa.*", "", "(?:\\Afoobar|\\Afoobaz)aa")
|
|
|
|
f("foo[bar]+", "foo", "[abr]+")
|
|
|
|
f("foo[a-z]+", "foo", "[a-z]+")
|
|
|
|
f("foo[bar]*", "foo", "[abr]*")
|
|
|
|
f("foo[a-z]*", "foo", "[a-z]*")
|
|
|
|
f("foo[x]+", "foo", "x+")
|
|
|
|
f("foo[^x]+", "foo", "[^x]+")
|
|
|
|
f("foo[x]*", "foo", "x*")
|
|
|
|
f("foo[^x]*", "foo", "[^x]*")
|
|
|
|
f("foo[x]*bar", "foo", "x*bar")
|
|
|
|
f("fo\\Bo[x]*bar?", "fo", "\\Box*bar?")
|
|
|
|
f("foo.+bar", "foo", "(?s:.+bar)")
|
|
|
|
f("a(b|c.*).+", "a", "(?s:(?:b|c.*).+)")
|
|
|
|
f("ab|ac", "a", "[bc]")
|
|
|
|
f("(?i)xyz", "", "(?i:XYZ)")
|
|
|
|
f("(?i)foo|bar", "", "(?i:FOO|BAR)")
|
|
|
|
f("(?i)up.+x", "", "(?is:UP.+X)")
|
|
|
|
f("(?smi)xy.*z$", "", "(?ims:XY.*Z$)")
|
|
|
|
|
|
|
|
// test invalid regexps
|
|
|
|
f("a(", "a(", "")
|
|
|
|
f("a[", "a[", "")
|
|
|
|
f("a[]", "a[]", "")
|
|
|
|
f("a{", "a{", "")
|
|
|
|
f("a{}", "a{}", "")
|
|
|
|
f("invalid(regexp", "invalid(regexp", "")
|
|
|
|
|
|
|
|
// The transformed regexp mustn't match aba
|
|
|
|
f("a?(^ba|c)", "", "a?(?:\\Aba|c)")
|
|
|
|
|
|
|
|
// The transformed regexp mustn't match barx
|
|
|
|
f("(foo|bar$)x*", "", "(?-m:(?:foo|bar$)x*)")
|
|
|
|
|
|
|
|
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5297
|
|
|
|
f(".+;|;.+", "", "(?s:.+;|;.+)")
|
|
|
|
f("^(.+);|;(.+)$", "", "(?s-m:\\A.+;|;.+$)")
|
|
|
|
f("^(.+);$|^;(.+)$", "", "(?s-m:\\A.+;$|\\A;.+$)")
|
|
|
|
f(".*;|;.*", "", "(?s:.*;|;.*)")
|
|
|
|
f("^(.*);|;(.*)$", "", "(?s-m:\\A.*;|;.*$)")
|
|
|
|
f("^(.*);$|^;(.*)$", "", "(?s-m:\\A.*;$|\\A;.*$)")
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSimplifyPromRegex(t *testing.T) {
|
2022-08-26 08:57:12 +00:00
|
|
|
f := func(s, expectedPrefix, expectedSuffix string) {
|
|
|
|
t.Helper()
|
2024-05-24 01:06:55 +00:00
|
|
|
prefix, suffix := SimplifyPromRegex(s)
|
2022-08-26 08:57:12 +00:00
|
|
|
if prefix != expectedPrefix {
|
|
|
|
t.Fatalf("unexpected prefix for s=%q; got %q; want %q", s, prefix, expectedPrefix)
|
|
|
|
}
|
|
|
|
if suffix != expectedSuffix {
|
|
|
|
t.Fatalf("unexpected suffix for s=%q; got %q; want %q", s, suffix, expectedSuffix)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
f("", "", "")
|
|
|
|
f("^", "", "")
|
|
|
|
f("$", "", "")
|
|
|
|
f("^()$", "", "")
|
|
|
|
f("^(?:)$", "", "")
|
|
|
|
f("^foo|^bar$|baz", "", "foo|ba[rz]")
|
|
|
|
f("^(foo$|^bar)$", "", "foo|bar")
|
|
|
|
f("^a(foo$|bar)$", "a", "foo|bar")
|
2024-02-12 19:59:41 +00:00
|
|
|
f("^a(^foo|bar$)z$", "a", "(?-m:(?:\\Afoo|bar$)z)")
|
2022-08-26 08:57:12 +00:00
|
|
|
f("foobar", "foobar", "")
|
|
|
|
f("foo$|^foobar", "foo", "|bar")
|
|
|
|
f("^(foo$|^foobar)$", "foo", "|bar")
|
|
|
|
f("foobar|foobaz", "fooba", "[rz]")
|
|
|
|
f("(fo|(zar|bazz)|x)", "", "fo|zar|bazz|x")
|
|
|
|
f("(тестЧЧ|тест)", "тест", "ЧЧ|")
|
|
|
|
f("foo(bar|baz|bana)", "fooba", "[rz]|na")
|
|
|
|
f("^foobar|foobaz", "fooba", "[rz]")
|
|
|
|
f("^foobar|^foobaz$", "fooba", "[rz]")
|
|
|
|
f("foobar|foobaz", "fooba", "[rz]")
|
2024-05-24 01:06:55 +00:00
|
|
|
f("(?:^foobar|^foobaz)aa.*", "fooba", "(?s:[rz]aa.*)")
|
2024-02-12 19:59:41 +00:00
|
|
|
f("foo[bar]+", "foo", "[abr]+")
|
2022-08-26 08:57:12 +00:00
|
|
|
f("foo[a-z]+", "foo", "[a-z]+")
|
2024-02-12 19:59:41 +00:00
|
|
|
f("foo[bar]*", "foo", "[abr]*")
|
2022-08-26 08:57:12 +00:00
|
|
|
f("foo[a-z]*", "foo", "[a-z]*")
|
|
|
|
f("foo[x]+", "foo", "x+")
|
|
|
|
f("foo[^x]+", "foo", "[^x]+")
|
|
|
|
f("foo[x]*", "foo", "x*")
|
|
|
|
f("foo[^x]*", "foo", "[^x]*")
|
|
|
|
f("foo[x]*bar", "foo", "x*bar")
|
|
|
|
f("fo\\Bo[x]*bar?", "fo", "\\Box*bar?")
|
2024-05-24 01:06:55 +00:00
|
|
|
f("foo.+bar", "foo", "(?s:.+bar)")
|
|
|
|
f("a(b|c.*).+", "a", "(?s:(?:b|c.*).+)")
|
2024-02-12 19:59:41 +00:00
|
|
|
f("ab|ac", "a", "[bc]")
|
2022-08-26 08:57:12 +00:00
|
|
|
f("(?i)xyz", "", "(?i:XYZ)")
|
2024-02-12 19:59:41 +00:00
|
|
|
f("(?i)foo|bar", "", "(?i:FOO|BAR)")
|
2024-05-24 01:06:55 +00:00
|
|
|
f("(?i)up.+x", "", "(?is:UP.+X)")
|
2024-02-12 19:59:41 +00:00
|
|
|
f("(?smi)xy.*z$", "", "(?ims:XY.*Z$)")
|
2022-08-26 08:57:12 +00:00
|
|
|
|
|
|
|
// test invalid regexps
|
|
|
|
f("a(", "a(", "")
|
|
|
|
f("a[", "a[", "")
|
|
|
|
f("a[]", "a[]", "")
|
|
|
|
f("a{", "a{", "")
|
|
|
|
f("a{}", "a{}", "")
|
|
|
|
f("invalid(regexp", "invalid(regexp", "")
|
|
|
|
|
|
|
|
// The transformed regexp mustn't match aba
|
|
|
|
f("a?(^ba|c)", "", "a?(?:\\Aba|c)")
|
|
|
|
|
|
|
|
// The transformed regexp mustn't match barx
|
2024-02-12 19:59:41 +00:00
|
|
|
f("(foo|bar$)x*", "", "(?-m:(?:foo|bar$)x*)")
|
2023-11-13 17:23:36 +00:00
|
|
|
|
|
|
|
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5297
|
2024-05-24 01:06:55 +00:00
|
|
|
f(".+;|;.+", "", "(?s:.+;|;.+)")
|
|
|
|
f("^(.+);|;(.+)$", "", "(?s:.+;|;.+)")
|
|
|
|
f("^(.+);$|^;(.+)$", "", "(?s:.+;|;.+)")
|
|
|
|
f(".*;|;.*", "", "(?s:.*;|;.*)")
|
|
|
|
f("^(.*);|;(.*)$", "", "(?s:.*;|;.*)")
|
|
|
|
f("^(.*);$|^;(.*)$", "", "(?s:.*;|;.*)")
|
2022-08-24 14:54:26 +00:00
|
|
|
}
|
2022-09-30 05:13:56 +00:00
|
|
|
|
|
|
|
func TestRemoveStartEndAnchors(t *testing.T) {
|
|
|
|
f := func(s, resultExpected string) {
|
|
|
|
t.Helper()
|
|
|
|
result := RemoveStartEndAnchors(s)
|
|
|
|
if result != resultExpected {
|
|
|
|
t.Fatalf("unexpected result for RemoveStartEndAnchors(%q); got %q; want %q", s, result, resultExpected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f("", "")
|
|
|
|
f("a", "a")
|
|
|
|
f("^^abc", "abc")
|
|
|
|
f("a^b$c", "a^b$c")
|
|
|
|
f("$$abc^", "$$abc^")
|
|
|
|
f("^abc|de$", "abc|de")
|
|
|
|
f("abc\\$", "abc\\$")
|
|
|
|
f("^abc\\$$$", "abc\\$")
|
|
|
|
f("^a\\$b\\$$", "a\\$b\\$")
|
|
|
|
}
|