This commit is contained in:
@@ -0,0 +1,260 @@
|
||||
package rext
|
||||
|
||||
import (
|
||||
"git.blackforestbytes.com/BlackForestBytes/goext/tst"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestW(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`\d+`))
|
||||
tst.AssertTrue(t, r != nil)
|
||||
tst.AssertEqual(t, r.String(), `\d+`)
|
||||
}
|
||||
|
||||
func TestIsMatchTrue(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`\d+`))
|
||||
tst.AssertTrue(t, r.IsMatch("abc 123 def"))
|
||||
}
|
||||
|
||||
func TestIsMatchFalse(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`\d+`))
|
||||
tst.AssertFalse(t, r.IsMatch("abc def"))
|
||||
}
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`^foo(bar)?$`))
|
||||
tst.AssertEqual(t, r.String(), `^foo(bar)?$`)
|
||||
}
|
||||
|
||||
func TestGroupCountWrapper(t *testing.T) {
|
||||
r0 := W(regexp.MustCompile(`abc`))
|
||||
tst.AssertEqual(t, r0.GroupCount(), 0)
|
||||
|
||||
r1 := W(regexp.MustCompile(`(a)(b)(c)`))
|
||||
tst.AssertEqual(t, r1.GroupCount(), 3)
|
||||
|
||||
r2 := W(regexp.MustCompile(`(?P<x>\d+)-(?P<y>\d+)`))
|
||||
tst.AssertEqual(t, r2.GroupCount(), 2)
|
||||
}
|
||||
|
||||
func TestMatchFirstFound(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`(\d+)-(\d+)`))
|
||||
m, ok := r.MatchFirst("a 12-34 b 56-78 c")
|
||||
tst.AssertTrue(t, ok)
|
||||
tst.AssertEqual(t, m.FullMatch().Value(), "12-34")
|
||||
tst.AssertEqual(t, m.GroupByIndex(1).Value(), "12")
|
||||
tst.AssertEqual(t, m.GroupByIndex(2).Value(), "34")
|
||||
}
|
||||
|
||||
func TestMatchFirstNotFound(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`\d+`))
|
||||
m, ok := r.MatchFirst("nothing here")
|
||||
tst.AssertFalse(t, ok)
|
||||
// zero-value match should be returned
|
||||
tst.AssertEqual(t, len(m.submatchesIndex), 0)
|
||||
}
|
||||
|
||||
func TestMatchAllMultiple(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`\d+`))
|
||||
matches := r.MatchAll("a 1 b 22 c 333")
|
||||
tst.AssertEqual(t, len(matches), 3)
|
||||
tst.AssertEqual(t, matches[0].FullMatch().Value(), "1")
|
||||
tst.AssertEqual(t, matches[1].FullMatch().Value(), "22")
|
||||
tst.AssertEqual(t, matches[2].FullMatch().Value(), "333")
|
||||
}
|
||||
|
||||
func TestMatchAllNone(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`\d+`))
|
||||
matches := r.MatchAll("abc")
|
||||
tst.AssertEqual(t, len(matches), 0)
|
||||
}
|
||||
|
||||
func TestMatchAllSingle(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`(?P<num>\d+)`))
|
||||
matches := r.MatchAll("only 42 here")
|
||||
tst.AssertEqual(t, len(matches), 1)
|
||||
tst.AssertEqual(t, matches[0].GroupByName("num").Value(), "42")
|
||||
}
|
||||
|
||||
func TestReplaceAllNonLiteralExpansion(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`(\w+)@(\w+)`))
|
||||
out := r.ReplaceAll("hi alice@example, hi bob@example", "$2/$1", false)
|
||||
tst.AssertEqual(t, out, "hi example/alice, hi example/bob")
|
||||
}
|
||||
|
||||
func TestReplaceAllLiteralNoExpansion(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`(\w+)@(\w+)`))
|
||||
out := r.ReplaceAll("hi alice@example", "$2/$1", true)
|
||||
tst.AssertEqual(t, out, "hi $2/$1")
|
||||
}
|
||||
|
||||
func TestReplaceAllFunc(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`\d+`))
|
||||
out := r.ReplaceAllFunc("a1 b22 c333", func(s string) string {
|
||||
return strings.Repeat("x", len(s))
|
||||
})
|
||||
tst.AssertEqual(t, out, "ax bxx cxxx")
|
||||
}
|
||||
|
||||
func TestRemoveAll(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`\s+`))
|
||||
out := r.RemoveAll(" hello world ")
|
||||
tst.AssertEqual(t, out, "helloworld")
|
||||
}
|
||||
|
||||
func TestRemoveAllNoMatch(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`\d+`))
|
||||
out := r.RemoveAll("no digits here")
|
||||
tst.AssertEqual(t, out, "no digits here")
|
||||
}
|
||||
|
||||
func TestRemoveAllDoesNotExpandPlaceholders(t *testing.T) {
|
||||
// removal uses literal replacement, so no expansion happens
|
||||
r := W(regexp.MustCompile(`(\w+)`))
|
||||
out := r.RemoveAll("abc")
|
||||
tst.AssertEqual(t, out, "")
|
||||
}
|
||||
|
||||
// --- RegexMatch ---
|
||||
|
||||
func TestRegexMatchFullMatch(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`b\w+d`))
|
||||
m, ok := r.MatchFirst("aa beard cc")
|
||||
tst.AssertTrue(t, ok)
|
||||
fm := m.FullMatch()
|
||||
tst.AssertEqual(t, fm.Value(), "beard")
|
||||
tst.AssertEqual(t, fm.Start(), 3)
|
||||
tst.AssertEqual(t, fm.End(), 8)
|
||||
}
|
||||
|
||||
func TestRegexMatchGroupCount(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`(a)(b)(c)`))
|
||||
m, ok := r.MatchFirst("abc")
|
||||
tst.AssertTrue(t, ok)
|
||||
tst.AssertEqual(t, m.GroupCount(), 3)
|
||||
}
|
||||
|
||||
func TestRegexMatchGroupByIndex(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`(\w+)-(\w+)-(\w+)`))
|
||||
m, ok := r.MatchFirst("foo-bar-baz")
|
||||
tst.AssertTrue(t, ok)
|
||||
tst.AssertEqual(t, m.GroupByIndex(0).Value(), "foo-bar-baz")
|
||||
tst.AssertEqual(t, m.GroupByIndex(1).Value(), "foo")
|
||||
tst.AssertEqual(t, m.GroupByIndex(2).Value(), "bar")
|
||||
tst.AssertEqual(t, m.GroupByIndex(3).Value(), "baz")
|
||||
}
|
||||
|
||||
func TestRegexMatchGroupByName(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`(?P<first>\w+)\s+(?P<last>\w+)`))
|
||||
m, ok := r.MatchFirst("John Doe")
|
||||
tst.AssertTrue(t, ok)
|
||||
tst.AssertEqual(t, m.GroupByName("first").Value(), "John")
|
||||
tst.AssertEqual(t, m.GroupByName("last").Value(), "Doe")
|
||||
}
|
||||
|
||||
func TestRegexMatchGroupByNamePanics(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`(?P<x>\d+)`))
|
||||
m, ok := r.MatchFirst("99")
|
||||
tst.AssertTrue(t, ok)
|
||||
|
||||
defer func() {
|
||||
rec := recover()
|
||||
tst.AssertTrue(t, rec != nil)
|
||||
}()
|
||||
|
||||
_ = m.GroupByName("nonexistent")
|
||||
t.Fatal("expected panic")
|
||||
}
|
||||
|
||||
func TestGroupByNameOrEmptyMissingName(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`(?P<x>\d+)`))
|
||||
m, ok := r.MatchFirst("99")
|
||||
tst.AssertTrue(t, ok)
|
||||
|
||||
g := m.GroupByNameOrEmpty("not-present")
|
||||
tst.AssertTrue(t, g.IsEmpty())
|
||||
tst.AssertFalse(t, g.Exists())
|
||||
tst.AssertEqual(t, g.ValueOrEmpty(), "")
|
||||
tst.AssertPtrEqual(t, g.ValueOrNil(), nil)
|
||||
}
|
||||
|
||||
// --- RegexMatchGroup ---
|
||||
|
||||
func TestRegexMatchGroupAccessors(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`(\w+)`))
|
||||
m, ok := r.MatchFirst(" hello ")
|
||||
tst.AssertTrue(t, ok)
|
||||
|
||||
g := m.GroupByIndex(1)
|
||||
tst.AssertEqual(t, g.Value(), "hello")
|
||||
tst.AssertEqual(t, g.Start(), 2)
|
||||
tst.AssertEqual(t, g.End(), 7)
|
||||
s, e := g.Range()
|
||||
tst.AssertEqual(t, s, 2)
|
||||
tst.AssertEqual(t, e, 7)
|
||||
tst.AssertEqual(t, g.Length(), 5)
|
||||
}
|
||||
|
||||
// --- OptRegexMatchGroup ---
|
||||
|
||||
func TestOptRegexMatchGroupExisting(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`(?P<word>\w+)`))
|
||||
m, ok := r.MatchFirst(" hello ")
|
||||
tst.AssertTrue(t, ok)
|
||||
|
||||
g := m.GroupByNameOrEmpty("word")
|
||||
tst.AssertTrue(t, g.Exists())
|
||||
tst.AssertFalse(t, g.IsEmpty())
|
||||
tst.AssertEqual(t, g.Value(), "hello")
|
||||
tst.AssertEqual(t, g.ValueOrEmpty(), "hello")
|
||||
tst.AssertEqual(t, *g.ValueOrNil(), "hello")
|
||||
tst.AssertEqual(t, g.Start(), 2)
|
||||
tst.AssertEqual(t, g.End(), 7)
|
||||
s, e := g.Range()
|
||||
tst.AssertEqual(t, s, 2)
|
||||
tst.AssertEqual(t, e, 7)
|
||||
tst.AssertEqual(t, g.Length(), 5)
|
||||
}
|
||||
|
||||
func TestOptRegexMatchGroupOptionalNotMatched(t *testing.T) {
|
||||
// group2 is optional and won't match; group1 will
|
||||
r := W(regexp.MustCompile(`(?P<group1>A+)(?P<group2>B+)?`))
|
||||
m, ok := r.MatchFirst("AAA")
|
||||
tst.AssertTrue(t, ok)
|
||||
|
||||
g1 := m.GroupByNameOrEmpty("group1")
|
||||
tst.AssertTrue(t, g1.Exists())
|
||||
tst.AssertEqual(t, g1.ValueOrEmpty(), "AAA")
|
||||
|
||||
g2 := m.GroupByNameOrEmpty("group2")
|
||||
tst.AssertTrue(t, g2.IsEmpty())
|
||||
tst.AssertFalse(t, g2.Exists())
|
||||
tst.AssertEqual(t, g2.ValueOrEmpty(), "")
|
||||
tst.AssertPtrEqual(t, g2.ValueOrNil(), nil)
|
||||
}
|
||||
|
||||
// --- Misc combined behavior ---
|
||||
|
||||
func TestMultipleNamedGroupsAcrossMatches(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`(?P<k>\w+)=(?P<v>\d+)`))
|
||||
matches := r.MatchAll("a=1 b=22 c=333")
|
||||
tst.AssertEqual(t, len(matches), 3)
|
||||
|
||||
tst.AssertEqual(t, matches[0].GroupByName("k").Value(), "a")
|
||||
tst.AssertEqual(t, matches[0].GroupByName("v").Value(), "1")
|
||||
tst.AssertEqual(t, matches[1].GroupByName("k").Value(), "b")
|
||||
tst.AssertEqual(t, matches[1].GroupByName("v").Value(), "22")
|
||||
tst.AssertEqual(t, matches[2].GroupByName("k").Value(), "c")
|
||||
tst.AssertEqual(t, matches[2].GroupByName("v").Value(), "333")
|
||||
}
|
||||
|
||||
func TestEmptyMatchHaystack(t *testing.T) {
|
||||
r := W(regexp.MustCompile(`.*`))
|
||||
tst.AssertTrue(t, r.IsMatch(""))
|
||||
m, ok := r.MatchFirst("")
|
||||
tst.AssertTrue(t, ok)
|
||||
tst.AssertEqual(t, m.FullMatch().Value(), "")
|
||||
tst.AssertEqual(t, m.FullMatch().Length(), 0)
|
||||
}
|
||||
Reference in New Issue
Block a user