261 lines
7.4 KiB
Go
261 lines
7.4 KiB
Go
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)
|
|
}
|