| package engine |
| |
| import ( |
| "bufio" |
| "bytes" |
| "fmt" |
| "io" |
| "io/ioutil" |
| "strings" |
| "testing" |
| ) |
| |
| type sentinelWriteCloser struct { |
| calledWrite bool |
| calledClose bool |
| } |
| |
| func (w *sentinelWriteCloser) Write(p []byte) (int, error) { |
| w.calledWrite = true |
| return len(p), nil |
| } |
| |
| func (w *sentinelWriteCloser) Close() error { |
| w.calledClose = true |
| return nil |
| } |
| |
| func TestOutputAddEnv(t *testing.T) { |
| input := "{\"foo\": \"bar\", \"answer_to_life_the_universe_and_everything\": 42}" |
| o := NewOutput() |
| result, err := o.AddEnv() |
| if err != nil { |
| t.Fatal(err) |
| } |
| o.Write([]byte(input)) |
| o.Close() |
| if v := result.Get("foo"); v != "bar" { |
| t.Errorf("Expected %v, got %v", "bar", v) |
| } |
| if v := result.GetInt("answer_to_life_the_universe_and_everything"); v != 42 { |
| t.Errorf("Expected %v, got %v", 42, v) |
| } |
| if v := result.Get("this-value-doesnt-exist"); v != "" { |
| t.Errorf("Expected %v, got %v", "", v) |
| } |
| } |
| |
| func TestOutputAddClose(t *testing.T) { |
| o := NewOutput() |
| var s sentinelWriteCloser |
| o.Add(&s) |
| if err := o.Close(); err != nil { |
| t.Fatal(err) |
| } |
| // Write data after the output is closed. |
| // Write should succeed, but no destination should receive it. |
| if _, err := o.Write([]byte("foo bar")); err != nil { |
| t.Fatal(err) |
| } |
| if !s.calledClose { |
| t.Fatal("Output.Close() didn't close the destination") |
| } |
| } |
| |
| func TestOutputAddPipe(t *testing.T) { |
| var testInputs = []string{ |
| "hello, world!", |
| "One\nTwo\nThree", |
| "", |
| "A line\nThen another nl-terminated line\n", |
| "A line followed by an empty line\n\n", |
| } |
| for _, input := range testInputs { |
| expectedOutput := input |
| o := NewOutput() |
| r, err := o.AddPipe() |
| if err != nil { |
| t.Fatal(err) |
| } |
| go func(o *Output) { |
| if n, err := o.Write([]byte(input)); err != nil { |
| t.Error(err) |
| } else if n != len(input) { |
| t.Errorf("Expected %d, got %d", len(input), n) |
| } |
| if err := o.Close(); err != nil { |
| t.Error(err) |
| } |
| }(o) |
| output, err := ioutil.ReadAll(r) |
| if err != nil { |
| t.Fatal(err) |
| } |
| if string(output) != expectedOutput { |
| t.Errorf("Last line is not stored as return string.\nExpected: '%s'\nGot: '%s'", expectedOutput, output) |
| } |
| } |
| } |
| |
| func TestTail(t *testing.T) { |
| var tests = make(map[string][]string) |
| tests["hello, world!"] = []string{ |
| "", |
| "hello, world!", |
| "hello, world!", |
| "hello, world!", |
| } |
| tests["One\nTwo\nThree"] = []string{ |
| "", |
| "Three", |
| "Two\nThree", |
| "One\nTwo\nThree", |
| } |
| tests["One\nTwo\n\n\n"] = []string{ |
| "", |
| "Two", |
| "One\nTwo", |
| } |
| for input, outputs := range tests { |
| for n, expectedOutput := range outputs { |
| output := Tail(bytes.NewBufferString(input), n) |
| if output != expectedOutput { |
| t.Errorf("Tail n=%d returned wrong result.\nExpected: '%s'\nGot : '%s'", n, expectedOutput, output) |
| } |
| } |
| } |
| } |
| |
| func lastLine(txt string) string { |
| scanner := bufio.NewScanner(strings.NewReader(txt)) |
| var lastLine string |
| for scanner.Scan() { |
| lastLine = scanner.Text() |
| } |
| return lastLine |
| } |
| |
| func TestOutputAdd(t *testing.T) { |
| o := NewOutput() |
| b := &bytes.Buffer{} |
| o.Add(b) |
| input := "hello, world!" |
| if n, err := o.Write([]byte(input)); err != nil { |
| t.Fatal(err) |
| } else if n != len(input) { |
| t.Fatalf("Expected %d, got %d", len(input), n) |
| } |
| if output := b.String(); output != input { |
| t.Fatalf("Received wrong data from Add.\nExpected: '%s'\nGot: '%s'", input, output) |
| } |
| } |
| |
| func TestOutputWriteError(t *testing.T) { |
| o := NewOutput() |
| buf := &bytes.Buffer{} |
| o.Add(buf) |
| r, w := io.Pipe() |
| input := "Hello there" |
| expectedErr := fmt.Errorf("This is an error") |
| r.CloseWithError(expectedErr) |
| o.Add(w) |
| n, err := o.Write([]byte(input)) |
| if err != expectedErr { |
| t.Fatalf("Output.Write() should return the first error encountered, if any") |
| } |
| if buf.String() != input { |
| t.Fatalf("Output.Write() should attempt write on all destinations, even after encountering an error") |
| } |
| if n != len(input) { |
| t.Fatalf("Output.Write() should return the size of the input if it successfully writes to at least one destination") |
| } |
| } |
| |
| func TestInputAddEmpty(t *testing.T) { |
| i := NewInput() |
| var b bytes.Buffer |
| if err := i.Add(&b); err != nil { |
| t.Fatal(err) |
| } |
| data, err := ioutil.ReadAll(i) |
| if err != nil { |
| t.Fatal(err) |
| } |
| if len(data) > 0 { |
| t.Fatalf("Read from empty input shoul yield no data") |
| } |
| } |
| |
| func TestInputAddTwo(t *testing.T) { |
| i := NewInput() |
| var b1 bytes.Buffer |
| // First add should succeed |
| if err := i.Add(&b1); err != nil { |
| t.Fatal(err) |
| } |
| var b2 bytes.Buffer |
| // Second add should fail |
| if err := i.Add(&b2); err == nil { |
| t.Fatalf("Adding a second source should return an error") |
| } |
| } |
| |
| func TestInputAddNotEmpty(t *testing.T) { |
| i := NewInput() |
| b := bytes.NewBufferString("hello world\nabc") |
| expectedResult := b.String() |
| i.Add(b) |
| result, err := ioutil.ReadAll(i) |
| if err != nil { |
| t.Fatal(err) |
| } |
| if string(result) != expectedResult { |
| t.Fatalf("Expected: %v\nReceived: %v", expectedResult, result) |
| } |
| } |