package pcre_test import ( "strings" "sync" "testing" "go.elara.ws/pcre" ) func TestCompileError(t *testing.T) { r, err := pcre.Compile("(") if err == nil { t.Error("expected error, got nil") } defer r.Close() } func TestMatch(t *testing.T) { r := pcre.MustCompile(`\d+ (?=USD)`) defer r.Close() matches := r.MatchString("9000 USD") if !matches { t.Error("expected 9000 USD to match") } matches = r.MatchString("9000 RUB") if matches { t.Error("expected 9000 RUB not to match") } matches = r.MatchString("800 USD") if !matches { t.Error("expected 800 USD to match") } matches = r.MatchString("700 CAD") if matches { t.Error("expected 700 CAD not to match") } matches = r.Match([]byte("8 USD")) if !matches { t.Error("expected 8 USD to match") } } func TestMatchUngreedy(t *testing.T) { r := pcre.MustCompileOpts(`Hello, (.+)\.`, pcre.Ungreedy) defer r.Close() submatches := r.FindAllStringSubmatch("Hello, World. Hello, pcre2.", 1) if submatches[0][1] != "World" { t.Errorf("expected World, got %s", submatches[0][1]) } matches := r.MatchString("hello, world.") if matches { t.Error("expected lowercase 'hello, world' not to match") } } func TestReplace(t *testing.T) { r := pcre.MustCompile(`(\d+)\.\d+`) defer r.Close() testStr := "123.54321 Test" newStr := r.ReplaceAllString(testStr, "${1}.12345") if newStr != "123.12345 Test" { t.Errorf(`expected "123.12345 Test", got "%s"`, newStr) } newStr = r.ReplaceAllString(testStr, "${9}.12345") if newStr != ".12345 Test" { t.Errorf(`expected ".12345 Test", got "%s"`, newStr) } newStr = r.ReplaceAllString(testStr, "${hi}.12345") if newStr != ".12345 Test" { t.Errorf(`expected ".12345 Test", got "%s"`, newStr) } newStr = r.ReplaceAllLiteralString(testStr, "${1}.12345") if newStr != "${1}.12345 Test" { t.Errorf(`expected "${1}.12345 Test", got "%s"`, newStr) } newStr = r.ReplaceAllStringFunc(testStr, func(s string) string { return strings.Replace(s, ".", ",", -1) }) if newStr != "123,54321 Test" { t.Errorf(`expected "123,54321 Test", got "%s"`, newStr) } } func TestSplit(t *testing.T) { r := pcre.MustCompile("a*") defer r.Close() split := r.Split("abaabaccadaaae", 5) expected := [5]string{"", "b", "b", "c", "cadaaae"} if *(*[5]string)(split) != expected { t.Errorf("expected %v, got %v", expected, split) } split = r.Split("", 0) if split != nil { t.Errorf("expected nil, got %v", split) } split = r.Split("", 5) if split[0] != "" { t.Errorf(`expected []string{""}, got %v`, split) } } func TestFind(t *testing.T) { r := pcre.MustCompile(`(\d+)`) defer r.Close() testStr := "3 times 4 is 12" matches := r.FindAllString(testStr, -1) if len(matches) != 3 { t.Errorf("expected length 3, got %d", len(matches)) } matches = r.FindAllString(testStr, 2) if len(matches) != 2 { t.Errorf("expected length 2, got %d", len(matches)) } if matches[0] != "3" || matches[1] != "4" { t.Errorf("expected [3 4], got %v", matches) } index := r.FindStringIndex(testStr) if index[0] != 0 || index[1] != 1 { t.Errorf("expected [0 1], got %v", index) } submatch := r.FindStringSubmatch(testStr) if submatch[0] != "3" { t.Errorf("expected 3, got %s", submatch[0]) } index = r.FindStringSubmatchIndex(testStr) if *(*[4]int)(index) != [4]int{0, 1, 0, 1} { t.Errorf("expected [0 1 0 1], got %v", index) } submatches := r.FindAllStringSubmatchIndex(testStr, 2) if len(submatches) != 2 { t.Errorf("expected length 2, got %d", len(submatches)) } expected := [2][4]int{{0, 1, 0, 1}, {8, 9, 8, 9}} if *(*[4]int)(submatches[0]) != expected[0] { t.Errorf("expected %v, got %v", expected[0], submatches[0]) } if *(*[4]int)(submatches[1]) != expected[1] { t.Errorf("expected %v, got %v", expected[0], submatches[0]) } } func TestSubexpIndex(t *testing.T) { r := pcre.MustCompile(`(?P\d)`) defer r.Close() index := r.SubexpIndex("number") if index != 1 { t.Errorf("expected 1, got %d", index) } index = r.SubexpIndex("string") if index != -1 { t.Errorf("expected -1, got %d", index) } num := r.NumSubexp() if num != 1 { t.Errorf("expected 1, got %d", num) } } func TestConcurrency(t *testing.T) { r := pcre.MustCompile(`\d*`) defer r.Close() wg := &sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() found := r.FindString("Test string 12345") if found != "12345" { t.Errorf("expected 12345, got %s", found) } }() wg.Add(1) go func() { defer wg.Done() matched := r.MatchString("Hello") if matched { t.Errorf("Expected Hello not to match") } }() wg.Add(1) go func() { defer wg.Done() matched := r.MatchString("54321") if !matched { t.Errorf("expected 54321 to match") } }() wg.Wait() } func TestString(t *testing.T) { const expr = `()` r := pcre.MustCompile(expr) defer r.Close() if r.String() != expr { t.Errorf("expected %s, got %s", expr, r.String()) } } func TestCallout(t *testing.T) { const expr = `(https?)://([.\w\d]+\.[\w\d]{2,4}[\w\d?&=%/.-]*)(?C2)` subject := "https://www.elara.ws/" r := pcre.MustCompile(expr) defer r.Close() executed := false r.SetCallout(func(cb *pcre.CalloutBlock) int32 { executed = true if cb.CalloutNumber != 2 { t.Errorf("[CalloutNumber] expected %d, got %d", 2, cb.CalloutNumber) } if cb.CaptureTop != 3 { t.Errorf("[CaptureTop] expected %d, got %d", 3, cb.CaptureTop) } if cb.CaptureLast != 2 { t.Errorf("[CaptureLast] expected %d, got %d", 2, cb.CaptureLast) } if cb.Subject != subject { t.Errorf("[Subject] expected %q, got %q", subject, cb.Subject) } if cb.StartMatch != 0 { t.Errorf("[StartMatch] expected %d, got %d", 0, cb.StartMatch) } if cb.CurrentPosition != 21 { t.Errorf("[CurrentPosition] expected %d, got %d", 0, cb.CurrentPosition) } if cb.PatternPosition != 53 { t.Errorf("[PatternPosition] expected %d, got %d", 53, cb.PatternPosition) } if cb.NextItemLength != 0 { t.Errorf("[NextItemLength] expected %d, got %d", 0, cb.NextItemLength) } return 0 }) m := r.MatchString(subject) if !executed { t.Error("expected callout to be executed") } else if !m { t.Error("expected regular expression to match the string") } }