Skip to content

Commit

Permalink
Merge pull request coreos#2 from kinvolk/krnowak/regexp-matching-fixes
Browse files Browse the repository at this point in the history
Put excess characters from regexp matching back into the buffer
  • Loading branch information
jonboulle committed Jan 14, 2016
2 parents 5173270 + 3bc350a commit aefa734
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 0 deletions.
9 changes: 9 additions & 0 deletions gexpect.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,15 @@ func (expect *ExpectSubprocess) expectRegexFind(regex string, output bool) ([]st

if len(result) == 0 {
err = fmt.Errorf("ExpectRegex didn't find regex '%v'.", regex)
} else {
// The number in pairs[1] is an index of a first
// character outside the whole match
putBackIdx := pairs[1]
if len(stringIndexedInto) > putBackIdx {
stringToPutBack := stringIndexedInto[putBackIdx:]
stringIndexedInto = stringIndexedInto[:putBackIdx]
expect.buf.PutBack([]byte(stringToPutBack))
}
}
return result, stringIndexedInto, err
}
Expand Down
85 changes: 85 additions & 0 deletions gexpect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,88 @@ func TestRegexTimeoutWithOutput(t *testing.T) {
t.Fatalf("Didn't find %v in output: %v", searchPattern, out)
}
}

func TestRegexFindNoExcessBytes(t *testing.T) {
t.Logf("Testing Regular Expressions returning output with no excess strings")
repeats := 100
tests := []struct {
desc string
loopBody string
searchPattern string
expectFullTmpl string
unmatchedData string
}{
{
desc: `matching lines line by line with $ at the end of the regexp`,
loopBody: `echo "prefix: ${i} line"`,
searchPattern: `(?m)^prefix:\s+(\d+) line\s??$`,
expectFullTmpl: `prefix: %d line`,
unmatchedData: "\n",
// the "$" char at the end of regexp does not
// match the \n, so it is left as an unmatched
// data
},
{
desc: `matching lines line by line with \n at the end of the regexp`,
loopBody: `echo "prefix: ${i} line"`,
searchPattern: `(?m)^prefix:\s+(\d+) line\s??\n`,
expectFullTmpl: `prefix: %d line`,
unmatchedData: "",
},
{
desc: `matching chunks in single line chunk by chunk`,
loopBody: `echo -n "a ${i} b"`,
searchPattern: `a\s+(\d+)\s+b`,
expectFullTmpl: `a %d b`,
unmatchedData: "",
},
}
seqCmd := fmt.Sprintf("`seq 1 %d`", repeats)
shCmdTmpl := fmt.Sprintf(`sh -c 'for i in %s; do %%s; done'`, seqCmd)
for _, tt := range tests {
t.Logf("Test: %s", tt.desc)
shCmd := fmt.Sprintf(shCmdTmpl, tt.loopBody)
t.Logf("Running command: %s", shCmd)
p, err := Spawn(shCmd)
if err != nil {
t.Fatalf("Cannot exec shell script: %v", err)
}
defer func() {
if err := p.Wait(); err != nil {
t.Fatalf("shell script didn't terminate correctly: %v", err)
}
}()
for i := 1; i <= repeats; i++ {
matches, output, err := p.ExpectRegexFindWithOutput(tt.searchPattern)
if err != nil {
t.Fatalf("Failed to get the match number %d: %v", i, err)
}
if len(matches) != 2 {
t.Fatalf("Expected only 2 matches, got %d", len(matches))
}
full := strings.TrimSpace(matches[0])
expFull := fmt.Sprintf(tt.expectFullTmpl, i)
partial := matches[1]
expPartial := fmt.Sprintf("%d", i)
if full != expFull {
t.Fatalf("Did not the expected full match %q, got %q", expFull, full)
}
if partial != expPartial {
t.Fatalf("Did not the expected partial match %q, got %q", expPartial, partial)
}
// The output variable usually contains the
// unmatched data followed by the whole match.
// The first line is special as it has no data
// preceding it.
var expectedOutput string
if i == 1 || tt.unmatchedData == "" {
expectedOutput = matches[0]
} else {
expectedOutput = fmt.Sprintf("%s%s", tt.unmatchedData, matches[0])
}
if output != expectedOutput {
t.Fatalf("The collected output %q should be the same as the whole match %q", output, expectedOutput)
}
}
}
}

0 comments on commit aefa734

Please sign in to comment.