Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
baee123
Add function ExpectRegexFindWithOutput
steveej Jul 27, 2015
2879eb1
Split std anad non-std imports
steveej Jul 31, 2015
42d1f7f
Add function ExpectTimeoutRegexFindWithOutput
steveej Jul 27, 2015
f1c747f
Rewrite imports due to fork
steveej Jul 31, 2015
d65e778
Merge branch 'RegexWithOutput'
steveej Jul 31, 2015
17b0753
tests: minor fixes
steveej Jul 31, 2015
cbae588
Increased error message detail
steveej Aug 1, 2015
d56b2c6
tests: fix typo in error message
steveej Aug 1, 2015
b96dabc
include output in the error when a timeout occurs
alban Nov 12, 2015
24c1b4c
Merge pull request #1 from alban/alban/print-output-timeout
steveej Nov 25, 2015
730eeb6
examples: fix import references
jonboulle Nov 25, 2015
5173270
Merge pull request #1 from jonboulle/master
jonboulle Nov 25, 2015
59e31a7
Put the excess unmatched characters back into the buffer
krnowak Jan 13, 2016
3bc350a
Add a test for putting the excess characters back into the buffer
krnowak Jan 13, 2016
aefa734
Merge pull request #2 from kinvolk/krnowak/regexp-matching-fixes
jonboulle Jan 14, 2016
f09c623
Merge remote-tracking branch 'upstream/master'
krnowak Jan 14, 2016
0b5620b
Merge pull request #3 from kinvolk/krnowak/merge-upstream-changes
jonboulle Jan 15, 2016
17aee1a
fix buffer.ReadRune for multibyte unicode characters
ppalucki Feb 18, 2016
9dddc9f
Merge pull request #4 from ppalucki/fix-regex-runes
jonboulle Feb 23, 2016
2ea7406
Merge remote-tracking branch 'upstream/master'
krnowak Mar 30, 2016
ca42424
Merge pull request #5 from kinvolk/krnowak/merge-upstream-changes2
jonboulle Mar 31, 2016
6e01750
expect: do not prematurely return error on last read
lucab Dec 8, 2016
8d6e05e
Merge pull request #6 from lucab/to-upstream/eof-fix
jonboulle Dec 8, 2016
24be02b
Fixes to let me copy&paste examples
SvenDowideit Dec 26, 2016
a54f389
Merge pull request #7 from SvenDowideit/small-example-update-coreos
jonboulle Jan 2, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ It makes it simpler to create and control other terminal applications.

`ReadLine`, `ReadUntil` and `SendLine` send strings from/to `stdout/stdin` respectively

child := gexpect.Spawn("cat")
child, _ := gexpect.Spawn("cat")
child.SendLine("echoing process_stdin") // SendLine(command string) (error)
msg, _ := child.ReadLine() // msg = echoing process_stdin

Expand All @@ -34,24 +34,24 @@ It makes it simpler to create and control other terminal applications.

`AsyncInteractChannels` spawns two go routines to pipe into and from `stdout`/`stdin`, allowing for some usecases to be a little simpler.

child := gexpect.spawn("sh")
child, _ := gexpect.Spawn("sh")
sender, receiver := child.AsyncInteractChannels()
sender <- "echo Hello World\n" // Send to stdin
line, open := <- receiver // Recieve a line from stdout/stderr
// When the subprocess stops (e.g. with child.Close()) , receiver is closed
if open {
fmt.Printf("Received %s", line)]
fmt.Printf("Received %s", line)
}

`ExpectRegex` uses golang's internal regex engine to wait until a match from the process with the given regular expression (or an error on process termination with no match).

child := gexpect.Spawn("echo accb")
child, _ := gexpect.Spawn("echo accb")
match, _ := child.ExpectRegex("a..b")
// (match=true)

`ExpectRegexFind` allows for groups to be extracted from process stdout. The first element is an array of containing the total matched text, followed by each subexpression group match.

child := gexpect.Spawn("echo 123 456 789")
child, _ := gexpect.Spawn("echo 123 456 789")
result, _ := child.ExpectRegexFind("\d+ (\d+) (\d+)")
// result = []string{"123 456 789", "456", "789"}

Expand All @@ -61,4 +61,4 @@ See `gexpect_test.go` and the `examples` folder for full syntax

github.com/kballard/go-shellquote
github.com/kr/pty
KMP Algorithm: "http://blog.databigbang.com/searching-for-substrings-in-streams-a-slight-modification-of-the-knuth-morris-pratt-algorithm-in-haxe/"
KMP Algorithm: "http://blog.databigbang.com/searching-for-substrings-in-streams-a-slight-modification-of-the-knuth-morris-pratt-algorithm-in-haxe/"
2 changes: 1 addition & 1 deletion examples/ftp.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package main

import gexpect "github.com/ThomasRooney/gexpect"
import gexpect "github.com/coreos/gexpect"
import "log"

func main() {
Expand Down
2 changes: 1 addition & 1 deletion examples/ping.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package main

import gexpect "github.com/ThomasRooney/gexpect"
import gexpect "github.com/coreos/gexpect"
import "log"

func main() {
Expand Down
2 changes: 1 addition & 1 deletion examples/python.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package main

import "github.com/ThomasRooney/gexpect"
import "github.com/coreos/gexpect"
import "fmt"

func main() {
Expand Down
2 changes: 1 addition & 1 deletion examples/screen.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package main

import "github.com/ThomasRooney/gexpect"
import "github.com/coreos/gexpect"
import "fmt"
import "strings"

Expand Down
7 changes: 3 additions & 4 deletions gexpect.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (

var (
ErrEmptySearch = errors.New("empty search string")
ErrTimeout = errors.New("expect timed out")
)

type ExpectSubprocess struct {
Expand Down Expand Up @@ -72,7 +71,7 @@ func (buf *buffer) ReadRune() (r rune, size int, err error) {
if err != nil {
return 0, 0, err
}
if utf8.FullRune(chunk) {
if utf8.FullRune(chunk[:n]) {
r, rL := utf8.DecodeRune(chunk)
if n > rL {
buf.PutBack(chunk[rL:n])
Expand All @@ -91,7 +90,7 @@ func (buf *buffer) ReadRune() (r rune, size int, err error) {
}
l = l + fn

if utf8.FullRune(chunk) {
if utf8.FullRune(chunk[:l]) {
r, rL := utf8.DecodeRune(chunk)
if buf.collect {
buf.collection.WriteRune(r)
Expand Down Expand Up @@ -319,7 +318,7 @@ func (expect *ExpectSubprocess) Expect(searchString string) (e error) {

for {
n, err := expect.buf.Read(chunk)
if err != nil {
if n == 0 && err != nil {
return err
}
if expect.outputBuffer != nil {
Expand Down
57 changes: 57 additions & 0 deletions gexpect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
package gexpect

import (
"bytes"
"fmt"
"io/ioutil"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -117,6 +119,7 @@ var regexMatchTests = []struct {
{`a+hello`, `aaaahello`, `bhello`},
{`(hello|world)`, `hello`, `unknown`},
{`(hello|world)`, `world`, `unknown`},
{"\u00a9", "\u00a9", `unknown`}, // 2 bytes long unicode character "copyright sign"
}

func TestRegexMatch(t *testing.T) {
Expand Down Expand Up @@ -153,6 +156,7 @@ var regexFindTests = []struct {
{`so.. (hello|world)`, `so.. hello`, []string{"so.. hello", "hello"}},
{`(a+)hello`, `aaaahello`, []string{"aaaahello", "aaaa"}},
{`\d+ (\d+) (\d+)`, `123 456 789`, []string{"123 456 789", "456", "789"}},
{`\d+ (\d+) (\d+)`, "\u00a9 123 456 789 \u00a9", []string{"123 456 789", "456", "789"}}, // check unicode characters
}

func TestRegexFind(t *testing.T) {
Expand Down Expand Up @@ -360,3 +364,56 @@ func TestRegexFindNoExcessBytes(t *testing.T) {
}
}
}

func TestBufferReadRune(t *testing.T) {
tests := []struct {
bufferContent []byte
fileContent []byte
expectedRune rune
}{
// unicode "copyright char" is \u00a9 is encoded as two bytes in utf8 0xc2 0xa9
{[]byte{0xc2, 0xa9}, []byte{}, '\u00a9'}, // whole rune is already in buffer.b
{[]byte{0xc2}, []byte{0xa9}, '\u00a9'}, // half of is in the buffer.b and another half still in buffer.f (file)
{[]byte{}, []byte{0xc2, 0xa9}, '\u00a9'}, // whole rune is the file
// some random noise in the end of file
{[]byte{0xc2, 0xa9}, []byte{0x20, 0x20, 0x20, 0x20}, '\u00a9'},
{[]byte{0xc2}, []byte{0xa9, 0x20, 0x20, 0x20, 0x20}, '\u00a9'},
{[]byte{}, []byte{0xc2, 0xa9, 0x20, 0x20, 0x20, 0x20}, '\u00a9'},
}

for i, tt := range tests {

// prepare tmp file with fileContent
f, err := ioutil.TempFile("", "")
if err != nil {
t.Fatal(err)
}
n, err := f.Write(tt.fileContent)
if err != nil {
t.Fatal(err)
}
if n != len(tt.fileContent) {
t.Fatal("expected fileContent written to temp file")
}
_, err = f.Seek(0, 0)
if err != nil {
t.Fatal(err)
}

// new buffer
buf := buffer{f: f, b: *bytes.NewBuffer(tt.bufferContent)}

// call ReadRune
r, size, err := buf.ReadRune()

if r != tt.expectedRune {
t.Fatalf("#%d: expected rune %+q but go is %+q", i, tt.expectedRune, r)
}

if size != len(string(tt.expectedRune)) {
t.Fatalf("#%d: expected rune %d bytes long but got just %d bytes long", i, len(string(tt.expectedRune)), size)
}

}

}