veyron/lib/expect: return matching groups from ExpectSet(Eventually)?RE
This CL allows users to capture matching groups from their regular
expressions which can be helpful in certain circumstances.
Change-Id: I92813d4c9c0aa72d8dbf0bd1017f6e2813863a6f
diff --git a/lib/expect/expect.go b/lib/expect/expect.go
index 2c6c70a..01e9e35 100644
--- a/lib/expect/expect.go
+++ b/lib/expect/expect.go
@@ -27,7 +27,7 @@
// buffer.WriteString("foo\n")
// buffer.WriteString("bar\n")
// buffer.WriteString("baz\n")
-// s := expect.New(t, bufio.NewReader(buffer), time.Second)
+// s := expect.NewSession(t, bufio.NewReader(buffer), time.Second)
// s.Expect("foo")
// s.Expect("bars)
// if got, want := s.ReadLine(), "baz"; got != want {
@@ -67,6 +67,7 @@
type Testing interface {
Error(args ...interface{})
+ Errorf(format string, args ...interface{})
Log(args ...interface{})
}
@@ -277,38 +278,54 @@
// lines of input. Each line is read and matched against the supplied
// patterns in the order that they are supplied as parameters. Consequently
// the set may contain repetitions if the same pattern is expected multiple
-// times.
-func (s *Session) ExpectSetRE(expected ...string) {
+// times. The value returned is either:
+// * nil in the case of an error or no match, or
+// * an array of length len(expected), whose ith element contains the result
+// of FindStringSubmatch of expected[i] on the matching string (never
+// nil). If there are no capturing groups in expected[i], the return
+// value's [i][0] element will be the entire matching string
+func (s *Session) ExpectSetRE(expected ...string) [][]string {
if s.Failed() {
- return
+ return nil
}
- if err := s.expectSetRE(len(expected), expected...); err != nil {
+ if match, err := s.expectSetRE(len(expected), expected...); err != nil {
s.error(err)
+ return nil
+ } else {
+ return match
}
}
// ExpectSetEventuallyRE is like ExpectSetRE except that it reads
// all remaining output rather than just the next n lines and thus
// can be used to look for a set of patterns that occur within that
-// output.
-func (s *Session) ExpectSetEventuallyRE(expected ...string) {
+// output. The value returned is either:
+// * nil in the case of an error or no match, or
+// * an array of length len(expected), whose ith element contains the result
+// of FindStringSubmatch of expected[i] on the matching string (never
+// nil). If there are no capturing groups in expected[i], the return
+// value's [i][0] will contain the entire matching string
+func (s *Session) ExpectSetEventuallyRE(expected ...string) [][]string {
if s.Failed() {
- return
+ return nil
}
- if err := s.expectSetRE(-1, expected...); err != nil {
+ if matches, err := s.expectSetRE(-1, expected...); err != nil {
s.error(err)
+ return nil
+ } else {
+ return matches
}
}
// expectSetRE will look for the expected set of patterns in the next
// numLines of output or in all remaining output.
-func (s *Session) expectSetRE(numLines int, expected ...string) error {
+func (s *Session) expectSetRE(numLines int, expected ...string) ([][]string, error) {
regexps := make([]*regexp.Regexp, len(expected))
for i, expRE := range expected {
re, err := regexp.Compile(expRE)
if err != nil {
- return err
+ return nil, err
}
regexps[i] = re
}
@@ -320,7 +337,7 @@
s.log(err, "ExpectSetRE: %s", line)
if err != nil {
if numLines >= 0 {
- return err
+ return nil, err
}
break
}
@@ -331,6 +348,7 @@
}
}
+ matches := make([][]string, len(expected))
// Match each line against all regexp's and remove each regexp
// that matches.
for _, l := range actual {
@@ -338,8 +356,10 @@
if re == nil {
continue
}
- if re.MatchString(l) {
+ match := re.FindStringSubmatch(l)
+ if match != nil {
regexps[i] = nil
+ matches[i] = match
break
}
}
@@ -347,10 +367,10 @@
// It's an error if there are any unmatched regexps.
for _, re := range regexps {
if re != nil {
- return fmt.Errorf("found no match for %q", re)
+ return nil, fmt.Errorf("found no match for %q", re)
}
}
- return nil
+ return matches, nil
}
// ReadLine reads the next line, if any, from the input stream. It will set
diff --git a/lib/expect/expect_test.go b/lib/expect/expect_test.go
index 44422fa..b0fc48b 100644
--- a/lib/expect/expect_test.go
+++ b/lib/expect/expect_test.go
@@ -95,17 +95,31 @@
buffer.WriteString("def\n")
buffer.WriteString("abc\n")
s := expect.NewSession(nil, bufio.NewReader(buffer), time.Minute)
- s.ExpectSetRE("^bar=.*$", "def$", "^abc$", "^a..$")
+ got := s.ExpectSetRE("^bar=.*$", "def$", "^abc$", "^a..$")
if s.Error() != nil {
t.Errorf("unexpected error: %s", s.Error())
}
+ want := [][]string{{"bar=baz"}, {"def"}, {"abc"}, {"abc"}}
+ if !reflect.DeepEqual(got, want) {
+ t.Error("unexpected result from ExpectSetRE, got %v, want %v", got, want)
+ }
buffer.WriteString("ooh\n")
buffer.WriteString("aah\n")
s.ExpectSetRE("bar=.*", "def")
- if got, want := s.Error(), "expect_test.go:104: found no match for \"bar=.*\""; got == nil || got.Error() != want {
+ if got, want := s.Error(), "expect_test.go:108: found no match for \"bar=.*\""; got == nil || got.Error() != want {
t.Errorf("got %v, want %q", got, want)
}
s.ExpectEOF()
+
+ buf = []byte{}
+ buffer = bytes.NewBuffer(buf)
+ s = expect.NewSession(nil, bufio.NewReader(buffer), time.Minute)
+ buffer.WriteString("hello world\n")
+ buffer.WriteString("this is a test\n")
+ matches := s.ExpectSetRE("hello (world)", "this (is) (a|b) test")
+ if want := [][]string{{"hello world", "world"}, {"this is a test", "is", "a"}}; !reflect.DeepEqual(want, matches) {
+ t.Errorf("unexpected result from ExpectSetRE, got %v, want %v", matches, want)
+ }
}
func TestExpectSetEventuallyRE(t *testing.T) {
@@ -122,7 +136,7 @@
t.Errorf("unexpected error: %s", s.Error())
}
s.ExpectSetEventuallyRE("abc")
- if got, want := s.Error(), "expect_test.go:124: found no match for \"abc\""; got == nil || got.Error() != want {
+ if got, want := s.Error(), "expect_test.go:138: found no match for \"abc\""; got == nil || got.Error() != want {
t.Errorf("got %q, want %q", got, want)
}
// Need to clear the EOF from the previous ExpectSetEventuallyRE call
@@ -132,10 +146,21 @@
buffer.WriteString("ooh\n")
buffer.WriteString("aah\n")
s.ExpectSetEventuallyRE("zzz")
- if got, want := s.Error(), "expect_test.go:134: found no match for \"zzz\""; got == nil || got.Error() != want {
+ if got, want := s.Error(), "expect_test.go:148: found no match for \"zzz\""; got == nil || got.Error() != want {
t.Errorf("got %q, want %q", got, want)
}
s.ExpectEOF()
+
+ buf = []byte{}
+ buffer = bytes.NewBuffer(buf)
+ s = expect.NewSession(nil, bufio.NewReader(buffer), time.Minute)
+ buffer.WriteString("not expected\n")
+ buffer.WriteString("hello world\n")
+ buffer.WriteString("this is a test\n")
+ matches := s.ExpectSetEventuallyRE("hello (world)", "this (is) (a|b) test")
+ if want := [][]string{{"hello world", "world"}, {"this is a test", "is", "a"}}; !reflect.DeepEqual(want, matches) {
+ t.Errorf("unexpected result from ExpectSetRE, got %v, want %v", matches, want)
+ }
}
func TestRead(t *testing.T) {