Update vendor dir and Godeps.json with new Godep

This commit is contained in:
saadali
2016-05-11 16:59:55 -07:00
parent b83af3d481
commit c708e2cc82
2053 changed files with 955 additions and 140589 deletions

View File

@@ -1,98 +0,0 @@
/*
Table provides a simple DSL for Ginkgo-native Table-Driven Tests
The godoc documentation describes Table's API. More comprehensive documentation (with examples!) is available at http://onsi.github.io/ginkgo#table-driven-tests
*/
package table
import (
"fmt"
"reflect"
"github.com/onsi/ginkgo"
)
/*
DescribeTable describes a table-driven test.
For example:
DescribeTable("a simple table",
func(x int, y int, expected bool) {
Ω(x > y).Should(Equal(expected))
},
Entry("x > y", 1, 0, true),
Entry("x == y", 0, 0, false),
Entry("x < y", 0, 1, false),
)
The first argument to `DescribeTable` is a string description.
The second argument is a function that will be run for each table entry. Your assertions go here - the function is equivalent to a Ginkgo It.
The subsequent arguments must be of type `TableEntry`. We recommend using the `Entry` convenience constructors.
The `Entry` constructor takes a string description followed by an arbitrary set of parameters. These parameters are passed into your function.
Under the hood, `DescribeTable` simply generates a new Ginkgo `Describe`. Each `Entry` is turned into an `It` within the `Describe`.
It's important to understand that the `Describe`s and `It`s are generated at evaluation time (i.e. when Ginkgo constructs the tree of tests and before the tests run).
Individual Entries can be focused (with FEntry) or marked pending (with PEntry or XEntry). In addition, the entire table can be focused or marked pending with FDescribeTable and PDescribeTable/XDescribeTable.
*/
func DescribeTable(description string, itBody interface{}, entries ...TableEntry) bool {
describeTable(description, itBody, entries, false, false)
return true
}
/*
You can focus a table with `FDescribeTable`. This is equivalent to `FDescribe`.
*/
func FDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool {
describeTable(description, itBody, entries, false, true)
return true
}
/*
You can mark a table as pending with `PDescribeTable`. This is equivalent to `PDescribe`.
*/
func PDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool {
describeTable(description, itBody, entries, true, false)
return true
}
/*
You can mark a table as pending with `XDescribeTable`. This is equivalent to `XDescribe`.
*/
func XDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool {
describeTable(description, itBody, entries, true, false)
return true
}
func describeTable(description string, itBody interface{}, entries []TableEntry, pending bool, focused bool) {
itBodyValue := reflect.ValueOf(itBody)
if itBodyValue.Kind() != reflect.Func {
panic(fmt.Sprintf("DescribeTable expects a function, got %#v", itBody))
}
if pending {
ginkgo.PDescribe(description, func() {
for _, entry := range entries {
entry.generateIt(itBodyValue)
}
})
} else if focused {
ginkgo.FDescribe(description, func() {
for _, entry := range entries {
entry.generateIt(itBodyValue)
}
})
} else {
ginkgo.Describe(description, func() {
for _, entry := range entries {
entry.generateIt(itBodyValue)
}
})
}
}

View File

@@ -1,81 +0,0 @@
package table
import (
"reflect"
"github.com/onsi/ginkgo"
)
/*
TableEntry represents an entry in a table test. You generally use the `Entry` constructor.
*/
type TableEntry struct {
Description string
Parameters []interface{}
Pending bool
Focused bool
}
func (t TableEntry) generateIt(itBody reflect.Value) {
if t.Pending {
ginkgo.PIt(t.Description)
return
}
values := []reflect.Value{}
for i, param := range t.Parameters {
var value reflect.Value
if param == nil {
inType := itBody.Type().In(i)
value = reflect.Zero(inType)
} else {
value = reflect.ValueOf(param)
}
values = append(values, value)
}
body := func() {
itBody.Call(values)
}
if t.Focused {
ginkgo.FIt(t.Description, body)
} else {
ginkgo.It(t.Description, body)
}
}
/*
Entry constructs a TableEntry.
The first argument is a required description (this becomes the content of the generated Ginkgo `It`).
Subsequent parameters are saved off and sent to the callback passed in to `DescribeTable`.
Each Entry ends up generating an individual Ginkgo It.
*/
func Entry(description string, parameters ...interface{}) TableEntry {
return TableEntry{description, parameters, false, false}
}
/*
You can focus a particular entry with FEntry. This is equivalent to FIt.
*/
func FEntry(description string, parameters ...interface{}) TableEntry {
return TableEntry{description, parameters, false, true}
}
/*
You can mark a particular entry as pending with PEntry. This is equivalent to PIt.
*/
func PEntry(description string, parameters ...interface{}) TableEntry {
return TableEntry{description, parameters, true, false}
}
/*
You can mark a particular entry as pending with XEntry. This is equivalent to XIt.
*/
func XEntry(description string, parameters ...interface{}) TableEntry {
return TableEntry{description, parameters, true, false}
}

View File

@@ -1 +0,0 @@
package integration

View File

@@ -1,229 +0,0 @@
/*
Package gbytes provides a buffer that supports incrementally detecting input.
You use gbytes.Buffer with the gbytes.Say matcher. When Say finds a match, it fastforwards the buffer's read cursor to the end of that match.
Subsequent matches against the buffer will only operate against data that appears *after* the read cursor.
The read cursor is an opaque implementation detail that you cannot access. You should use the Say matcher to sift through the buffer. You can always
access the entire buffer's contents with Contents().
*/
package gbytes
import (
"errors"
"fmt"
"io"
"regexp"
"sync"
"time"
)
/*
gbytes.Buffer implements an io.Writer and can be used with the gbytes.Say matcher.
You should only use a gbytes.Buffer in test code. It stores all writes in an in-memory buffer - behavior that is inappropriate for production code!
*/
type Buffer struct {
contents []byte
readCursor uint64
lock *sync.Mutex
detectCloser chan interface{}
closed bool
}
/*
NewBuffer returns a new gbytes.Buffer
*/
func NewBuffer() *Buffer {
return &Buffer{
lock: &sync.Mutex{},
}
}
/*
BufferWithBytes returns a new gbytes.Buffer seeded with the passed in bytes
*/
func BufferWithBytes(bytes []byte) *Buffer {
return &Buffer{
lock: &sync.Mutex{},
contents: bytes,
}
}
/*
Write implements the io.Writer interface
*/
func (b *Buffer) Write(p []byte) (n int, err error) {
b.lock.Lock()
defer b.lock.Unlock()
if b.closed {
return 0, errors.New("attempt to write to closed buffer")
}
b.contents = append(b.contents, p...)
return len(p), nil
}
/*
Read implements the io.Reader interface. It advances the
cursor as it reads.
Returns an error if called after Close.
*/
func (b *Buffer) Read(d []byte) (int, error) {
b.lock.Lock()
defer b.lock.Unlock()
if b.closed {
return 0, errors.New("attempt to read from closed buffer")
}
if uint64(len(b.contents)) <= b.readCursor {
return 0, io.EOF
}
n := copy(d, b.contents[b.readCursor:])
b.readCursor += uint64(n)
return n, nil
}
/*
Close signifies that the buffer will no longer be written to
*/
func (b *Buffer) Close() error {
b.lock.Lock()
defer b.lock.Unlock()
b.closed = true
return nil
}
/*
Closed returns true if the buffer has been closed
*/
func (b *Buffer) Closed() bool {
b.lock.Lock()
defer b.lock.Unlock()
return b.closed
}
/*
Contents returns all data ever written to the buffer.
*/
func (b *Buffer) Contents() []byte {
b.lock.Lock()
defer b.lock.Unlock()
contents := make([]byte, len(b.contents))
copy(contents, b.contents)
return contents
}
/*
Detect takes a regular expression and returns a channel.
The channel will receive true the first time data matching the regular expression is written to the buffer.
The channel is subsequently closed and the buffer's read-cursor is fast-forwarded to just after the matching region.
You typically don't need to use Detect and should use the ghttp.Say matcher instead. Detect is useful, however, in cases where your code must
be branch and handle different outputs written to the buffer.
For example, consider a buffer hooked up to the stdout of a client library. You may (or may not, depending on state outside of your control) need to authenticate the client library.
You could do something like:
select {
case <-buffer.Detect("You are not logged in"):
//log in
case <-buffer.Detect("Success"):
//carry on
case <-time.After(time.Second):
//welp
}
buffer.CancelDetects()
You should always call CancelDetects after using Detect. This will close any channels that have not detected and clean up the goroutines that were spawned to support them.
Finally, you can pass detect a format string followed by variadic arguments. This will construct the regexp using fmt.Sprintf.
*/
func (b *Buffer) Detect(desired string, args ...interface{}) chan bool {
formattedRegexp := desired
if len(args) > 0 {
formattedRegexp = fmt.Sprintf(desired, args...)
}
re := regexp.MustCompile(formattedRegexp)
b.lock.Lock()
defer b.lock.Unlock()
if b.detectCloser == nil {
b.detectCloser = make(chan interface{})
}
closer := b.detectCloser
response := make(chan bool)
go func() {
ticker := time.NewTicker(10 * time.Millisecond)
defer ticker.Stop()
defer close(response)
for {
select {
case <-ticker.C:
b.lock.Lock()
data, cursor := b.contents[b.readCursor:], b.readCursor
loc := re.FindIndex(data)
b.lock.Unlock()
if loc != nil {
response <- true
b.lock.Lock()
newCursorPosition := cursor + uint64(loc[1])
if newCursorPosition >= b.readCursor {
b.readCursor = newCursorPosition
}
b.lock.Unlock()
return
}
case <-closer:
return
}
}
}()
return response
}
/*
CancelDetects cancels any pending detects and cleans up their goroutines. You should always call this when you're done with a set of Detect channels.
*/
func (b *Buffer) CancelDetects() {
b.lock.Lock()
defer b.lock.Unlock()
close(b.detectCloser)
b.detectCloser = nil
}
func (b *Buffer) didSay(re *regexp.Regexp) (bool, []byte) {
b.lock.Lock()
defer b.lock.Unlock()
unreadBytes := b.contents[b.readCursor:]
copyOfUnreadBytes := make([]byte, len(unreadBytes))
copy(copyOfUnreadBytes, unreadBytes)
loc := re.FindIndex(unreadBytes)
if loc != nil {
b.readCursor += uint64(loc[1])
return true, copyOfUnreadBytes
} else {
return false, copyOfUnreadBytes
}
}

View File

@@ -1,105 +0,0 @@
package gbytes
import (
"fmt"
"regexp"
"github.com/onsi/gomega/format"
)
//Objects satisfying the BufferProvider can be used with the Say matcher.
type BufferProvider interface {
Buffer() *Buffer
}
/*
Say is a Gomega matcher that operates on gbytes.Buffers:
Ω(buffer).Should(Say("something"))
will succeed if the unread portion of the buffer matches the regular expression "something".
When Say succeeds, it fast forwards the gbytes.Buffer's read cursor to just after the succesful match.
Thus, subsequent calls to Say will only match against the unread portion of the buffer
Say pairs very well with Eventually. To asser that a buffer eventually receives data matching "[123]-star" within 3 seconds you can:
Eventually(buffer, 3).Should(Say("[123]-star"))
Ditto with consistently. To assert that a buffer does not receive data matching "never-see-this" for 1 second you can:
Consistently(buffer, 1).ShouldNot(Say("never-see-this"))
In addition to bytes.Buffers, Say can operate on objects that implement the gbytes.BufferProvider interface.
In such cases, Say simply operates on the *gbytes.Buffer returned by Buffer()
If the buffer is closed, the Say matcher will tell Eventually to abort.
*/
func Say(expected string, args ...interface{}) *sayMatcher {
formattedRegexp := expected
if len(args) > 0 {
formattedRegexp = fmt.Sprintf(expected, args...)
}
return &sayMatcher{
re: regexp.MustCompile(formattedRegexp),
}
}
type sayMatcher struct {
re *regexp.Regexp
receivedSayings []byte
}
func (m *sayMatcher) buffer(actual interface{}) (*Buffer, bool) {
var buffer *Buffer
switch x := actual.(type) {
case *Buffer:
buffer = x
case BufferProvider:
buffer = x.Buffer()
default:
return nil, false
}
return buffer, true
}
func (m *sayMatcher) Match(actual interface{}) (success bool, err error) {
buffer, ok := m.buffer(actual)
if !ok {
return false, fmt.Errorf("Say must be passed a *gbytes.Buffer or BufferProvider. Got:\n%s", format.Object(actual, 1))
}
didSay, sayings := buffer.didSay(m.re)
m.receivedSayings = sayings
return didSay, nil
}
func (m *sayMatcher) FailureMessage(actual interface{}) (message string) {
return fmt.Sprintf(
"Got stuck at:\n%s\nWaiting for:\n%s",
format.IndentString(string(m.receivedSayings), 1),
format.IndentString(m.re.String(), 1),
)
}
func (m *sayMatcher) NegatedFailureMessage(actual interface{}) (message string) {
return fmt.Sprintf(
"Saw:\n%s\nWhich matches the unexpected:\n%s",
format.IndentString(string(m.receivedSayings), 1),
format.IndentString(m.re.String(), 1),
)
}
func (m *sayMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
switch x := actual.(type) {
case *Buffer:
return !x.Closed()
case BufferProvider:
return !x.Buffer().Closed()
default:
return true
}
}

View File

@@ -1,78 +0,0 @@
package gexec
import (
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"runtime"
)
var tmpDir string
/*
Build uses go build to compile the package at packagePath. The resulting binary is saved off in a temporary directory.
A path pointing to this binary is returned.
Build uses the $GOPATH set in your environment. It passes the variadic args on to `go build`.
*/
func Build(packagePath string, args ...string) (compiledPath string, err error) {
return BuildIn(os.Getenv("GOPATH"), packagePath, args...)
}
/*
BuildIn is identical to Build but allows you to specify a custom $GOPATH (the first argument).
*/
func BuildIn(gopath string, packagePath string, args ...string) (compiledPath string, err error) {
tmpDir, err := temporaryDirectory()
if err != nil {
return "", err
}
if len(gopath) == 0 {
return "", errors.New("$GOPATH not provided when building " + packagePath)
}
executable := filepath.Join(tmpDir, path.Base(packagePath))
if runtime.GOOS == "windows" {
executable = executable + ".exe"
}
cmdArgs := append([]string{"build"}, args...)
cmdArgs = append(cmdArgs, "-o", executable, packagePath)
build := exec.Command("go", cmdArgs...)
build.Env = append([]string{"GOPATH=" + gopath}, os.Environ()...)
output, err := build.CombinedOutput()
if err != nil {
return "", fmt.Errorf("Failed to build %s:\n\nError:\n%s\n\nOutput:\n%s", packagePath, err, string(output))
}
return executable, nil
}
/*
You should call CleanupBuildArtifacts before your test ends to clean up any temporary artifacts generated by
gexec. In Ginkgo this is typically done in an AfterSuite callback.
*/
func CleanupBuildArtifacts() {
if tmpDir != "" {
os.RemoveAll(tmpDir)
}
}
func temporaryDirectory() (string, error) {
var err error
if tmpDir == "" {
tmpDir, err = ioutil.TempDir("", "gexec_artifacts")
if err != nil {
return "", err
}
}
return ioutil.TempDir(tmpDir, "g")
}

View File

@@ -1,88 +0,0 @@
package gexec
import (
"fmt"
"github.com/onsi/gomega/format"
)
/*
The Exit matcher operates on a session:
Ω(session).Should(Exit(<optional status code>))
Exit passes if the session has already exited.
If no status code is provided, then Exit will succeed if the session has exited regardless of exit code.
Otherwise, Exit will only succeed if the process has exited with the provided status code.
Note that the process must have already exited. To wait for a process to exit, use Eventually:
Eventually(session, 3).Should(Exit(0))
*/
func Exit(optionalExitCode ...int) *exitMatcher {
exitCode := -1
if len(optionalExitCode) > 0 {
exitCode = optionalExitCode[0]
}
return &exitMatcher{
exitCode: exitCode,
}
}
type exitMatcher struct {
exitCode int
didExit bool
actualExitCode int
}
type Exiter interface {
ExitCode() int
}
func (m *exitMatcher) Match(actual interface{}) (success bool, err error) {
exiter, ok := actual.(Exiter)
if !ok {
return false, fmt.Errorf("Exit must be passed a gexec.Exiter (Missing method ExitCode() int) Got:\n%s", format.Object(actual, 1))
}
m.actualExitCode = exiter.ExitCode()
if m.actualExitCode == -1 {
return false, nil
}
if m.exitCode == -1 {
return true, nil
}
return m.exitCode == m.actualExitCode, nil
}
func (m *exitMatcher) FailureMessage(actual interface{}) (message string) {
if m.actualExitCode == -1 {
return "Expected process to exit. It did not."
} else {
return format.Message(m.actualExitCode, "to match exit code:", m.exitCode)
}
}
func (m *exitMatcher) NegatedFailureMessage(actual interface{}) (message string) {
if m.actualExitCode == -1 {
return "you really shouldn't be able to see this!"
} else {
if m.exitCode == -1 {
return "Expected process not to exit. It did."
} else {
return format.Message(m.actualExitCode, "not to match exit code:", m.exitCode)
}
}
}
func (m *exitMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
session, ok := actual.(*Session)
if ok {
return session.ExitCode() == -1
}
return true
}

View File

@@ -1,53 +0,0 @@
package gexec
import (
"io"
"sync"
)
/*
PrefixedWriter wraps an io.Writer, emiting the passed in prefix at the beginning of each new line.
This can be useful when running multiple gexec.Sessions concurrently - you can prefix the log output of each
session by passing in a PrefixedWriter:
gexec.Start(cmd, NewPrefixedWriter("[my-cmd] ", GinkgoWriter), NewPrefixedWriter("[my-cmd] ", GinkgoWriter))
*/
type PrefixedWriter struct {
prefix []byte
writer io.Writer
lock *sync.Mutex
atStartOfLine bool
}
func NewPrefixedWriter(prefix string, writer io.Writer) *PrefixedWriter {
return &PrefixedWriter{
prefix: []byte(prefix),
writer: writer,
lock: &sync.Mutex{},
atStartOfLine: true,
}
}
func (w *PrefixedWriter) Write(b []byte) (int, error) {
w.lock.Lock()
defer w.lock.Unlock()
toWrite := []byte{}
for _, c := range b {
if w.atStartOfLine {
toWrite = append(toWrite, w.prefix...)
}
toWrite = append(toWrite, c)
w.atStartOfLine = c == '\n'
}
_, err := w.writer.Write(toWrite)
if err != nil {
return 0, err
}
return len(b), nil
}

View File

@@ -1,214 +0,0 @@
/*
Package gexec provides support for testing external processes.
*/
package gexec
import (
"io"
"os"
"os/exec"
"reflect"
"sync"
"syscall"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gbytes"
)
const INVALID_EXIT_CODE = 254
type Session struct {
//The wrapped command
Command *exec.Cmd
//A *gbytes.Buffer connected to the command's stdout
Out *gbytes.Buffer
//A *gbytes.Buffer connected to the command's stderr
Err *gbytes.Buffer
//A channel that will close when the command exits
Exited <-chan struct{}
lock *sync.Mutex
exitCode int
}
/*
Start starts the passed-in *exec.Cmd command. It wraps the command in a *gexec.Session.
The session pipes the command's stdout and stderr to two *gbytes.Buffers available as properties on the session: session.Out and session.Err.
These buffers can be used with the gbytes.Say matcher to match against unread output:
Ω(session.Out).Should(gbytes.Say("foo-out"))
Ω(session.Err).Should(gbytes.Say("foo-err"))
In addition, Session satisfies the gbytes.BufferProvider interface and provides the stdout *gbytes.Buffer. This allows you to replace the first line, above, with:
Ω(session).Should(gbytes.Say("foo-out"))
When outWriter and/or errWriter are non-nil, the session will pipe stdout and/or stderr output both into the session *gybtes.Buffers and to the passed-in outWriter/errWriter.
This is useful for capturing the process's output or logging it to screen. In particular, when using Ginkgo it can be convenient to direct output to the GinkgoWriter:
session, err := Start(command, GinkgoWriter, GinkgoWriter)
This will log output when running tests in verbose mode, but - otherwise - will only log output when a test fails.
The session wrapper is responsible for waiting on the *exec.Cmd command. You *should not* call command.Wait() yourself.
Instead, to assert that the command has exited you can use the gexec.Exit matcher:
Ω(session).Should(gexec.Exit())
When the session exits it closes the stdout and stderr gbytes buffers. This will short circuit any
Eventuallys waiting fo the buffers to Say something.
*/
func Start(command *exec.Cmd, outWriter io.Writer, errWriter io.Writer) (*Session, error) {
exited := make(chan struct{})
session := &Session{
Command: command,
Out: gbytes.NewBuffer(),
Err: gbytes.NewBuffer(),
Exited: exited,
lock: &sync.Mutex{},
exitCode: -1,
}
var commandOut, commandErr io.Writer
commandOut, commandErr = session.Out, session.Err
if outWriter != nil && !reflect.ValueOf(outWriter).IsNil() {
commandOut = io.MultiWriter(commandOut, outWriter)
}
if errWriter != nil && !reflect.ValueOf(errWriter).IsNil() {
commandErr = io.MultiWriter(commandErr, errWriter)
}
command.Stdout = commandOut
command.Stderr = commandErr
err := command.Start()
if err == nil {
go session.monitorForExit(exited)
}
return session, err
}
/*
Buffer implements the gbytes.BufferProvider interface and returns s.Out
This allows you to make gbytes.Say matcher assertions against stdout without having to reference .Out:
Eventually(session).Should(gbytes.Say("foo"))
*/
func (s *Session) Buffer() *gbytes.Buffer {
return s.Out
}
/*
ExitCode returns the wrapped command's exit code. If the command hasn't exited yet, ExitCode returns -1.
To assert that the command has exited it is more convenient to use the Exit matcher:
Eventually(s).Should(gexec.Exit())
When the process exits because it has received a particular signal, the exit code will be 128+signal-value
(See http://www.tldp.org/LDP/abs/html/exitcodes.html and http://man7.org/linux/man-pages/man7/signal.7.html)
*/
func (s *Session) ExitCode() int {
s.lock.Lock()
defer s.lock.Unlock()
return s.exitCode
}
/*
Wait waits until the wrapped command exits. It can be passed an optional timeout.
If the command does not exit within the timeout, Wait will trigger a test failure.
Wait returns the session, making it possible to chain:
session.Wait().Out.Contents()
will wait for the command to exit then return the entirety of Out's contents.
Wait uses eventually under the hood and accepts the same timeout/polling intervals that eventually does.
*/
func (s *Session) Wait(timeout ...interface{}) *Session {
EventuallyWithOffset(1, s, timeout...).Should(Exit())
return s
}
/*
Kill sends the running command a SIGKILL signal. It does not wait for the process to exit.
If the command has already exited, Kill returns silently.
The session is returned to enable chaining.
*/
func (s *Session) Kill() *Session {
if s.ExitCode() != -1 {
return s
}
s.Command.Process.Kill()
return s
}
/*
Interrupt sends the running command a SIGINT signal. It does not wait for the process to exit.
If the command has already exited, Interrupt returns silently.
The session is returned to enable chaining.
*/
func (s *Session) Interrupt() *Session {
return s.Signal(syscall.SIGINT)
}
/*
Terminate sends the running command a SIGTERM signal. It does not wait for the process to exit.
If the command has already exited, Terminate returns silently.
The session is returned to enable chaining.
*/
func (s *Session) Terminate() *Session {
return s.Signal(syscall.SIGTERM)
}
/*
Terminate sends the running command the passed in signal. It does not wait for the process to exit.
If the command has already exited, Signal returns silently.
The session is returned to enable chaining.
*/
func (s *Session) Signal(signal os.Signal) *Session {
if s.ExitCode() != -1 {
return s
}
s.Command.Process.Signal(signal)
return s
}
func (s *Session) monitorForExit(exited chan<- struct{}) {
err := s.Command.Wait()
s.lock.Lock()
s.Out.Close()
s.Err.Close()
status := s.Command.ProcessState.Sys().(syscall.WaitStatus)
if status.Signaled() {
s.exitCode = 128 + int(status.Signal())
} else {
exitStatus := status.ExitStatus()
if exitStatus == -1 && err != nil {
s.exitCode = INVALID_EXIT_CODE
}
s.exitCode = exitStatus
}
s.lock.Unlock()
close(exited)
}

View File

@@ -1,313 +0,0 @@
package ghttp
import (
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"reflect"
"github.com/golang/protobuf/proto"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/types"
)
//CombineHandler takes variadic list of handlers and produces one handler
//that calls each handler in order.
func CombineHandlers(handlers ...http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
for _, handler := range handlers {
handler(w, req)
}
}
}
//VerifyRequest returns a handler that verifies that a request uses the specified method to connect to the specified path
//You may also pass in an optional rawQuery string which is tested against the request's `req.URL.RawQuery`
//
//For path, you may pass in a string, in which case strict equality will be applied
//Alternatively you can pass in a matcher (ContainSubstring("/foo") and MatchRegexp("/foo/[a-f0-9]+") for example)
func VerifyRequest(method string, path interface{}, rawQuery ...string) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
Ω(req.Method).Should(Equal(method), "Method mismatch")
switch p := path.(type) {
case types.GomegaMatcher:
Ω(req.URL.Path).Should(p, "Path mismatch")
default:
Ω(req.URL.Path).Should(Equal(path), "Path mismatch")
}
if len(rawQuery) > 0 {
values, err := url.ParseQuery(rawQuery[0])
Ω(err).ShouldNot(HaveOccurred(), "Expected RawQuery is malformed")
Ω(req.URL.Query()).Should(Equal(values), "RawQuery mismatch")
}
}
}
//VerifyContentType returns a handler that verifies that a request has a Content-Type header set to the
//specified value
func VerifyContentType(contentType string) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
Ω(req.Header.Get("Content-Type")).Should(Equal(contentType))
}
}
//VerifyBasicAuth returns a handler that verifies the request contains a BasicAuth Authorization header
//matching the passed in username and password
func VerifyBasicAuth(username string, password string) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
auth := req.Header.Get("Authorization")
Ω(auth).ShouldNot(Equal(""), "Authorization header must be specified")
decoded, err := base64.StdEncoding.DecodeString(auth[6:])
Ω(err).ShouldNot(HaveOccurred())
Ω(string(decoded)).Should(Equal(fmt.Sprintf("%s:%s", username, password)), "Authorization mismatch")
}
}
//VerifyHeader returns a handler that verifies the request contains the passed in headers.
//The passed in header keys are first canonicalized via http.CanonicalHeaderKey.
//
//The request must contain *all* the passed in headers, but it is allowed to have additional headers
//beyond the passed in set.
func VerifyHeader(header http.Header) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
for key, values := range header {
key = http.CanonicalHeaderKey(key)
Ω(req.Header[key]).Should(Equal(values), "Header mismatch for key: %s", key)
}
}
}
//VerifyHeaderKV returns a handler that verifies the request contains a header matching the passed in key and values
//(recall that a `http.Header` is a mapping from string (key) to []string (values))
//It is a convenience wrapper around `VerifyHeader` that allows you to avoid having to create an `http.Header` object.
func VerifyHeaderKV(key string, values ...string) http.HandlerFunc {
return VerifyHeader(http.Header{key: values})
}
//VerifyBody returns a handler that verifies that the body of the request matches the passed in byte array.
//It does this using Equal().
func VerifyBody(expectedBody []byte) http.HandlerFunc {
return CombineHandlers(
func(w http.ResponseWriter, req *http.Request) {
body, err := ioutil.ReadAll(req.Body)
req.Body.Close()
Ω(err).ShouldNot(HaveOccurred())
Ω(body).Should(Equal(expectedBody), "Body Mismatch")
},
)
}
//VerifyJSON returns a handler that verifies that the body of the request is a valid JSON representation
//matching the passed in JSON string. It does this using Gomega's MatchJSON method
//
//VerifyJSON also verifies that the request's content type is application/json
func VerifyJSON(expectedJSON string) http.HandlerFunc {
return CombineHandlers(
VerifyContentType("application/json"),
func(w http.ResponseWriter, req *http.Request) {
body, err := ioutil.ReadAll(req.Body)
req.Body.Close()
Ω(err).ShouldNot(HaveOccurred())
Ω(body).Should(MatchJSON(expectedJSON), "JSON Mismatch")
},
)
}
//VerifyJSONRepresenting is similar to VerifyJSON. Instead of taking a JSON string, however, it
//takes an arbitrary JSON-encodable object and verifies that the requests's body is a JSON representation
//that matches the object
func VerifyJSONRepresenting(object interface{}) http.HandlerFunc {
data, err := json.Marshal(object)
Ω(err).ShouldNot(HaveOccurred())
return CombineHandlers(
VerifyContentType("application/json"),
VerifyJSON(string(data)),
)
}
//VerifyForm returns a handler that verifies a request contains the specified form values.
//
//The request must contain *all* of the specified values, but it is allowed to have additional
//form values beyond the passed in set.
func VerifyForm(values url.Values) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
Ω(err).ShouldNot(HaveOccurred())
for key, vals := range values {
Ω(r.Form[key]).Should(Equal(vals), "Form mismatch for key: %s", key)
}
}
}
//VerifyFormKV returns a handler that verifies a request contains a form key with the specified values.
//
//It is a convenience wrapper around `VerifyForm` that lets you avoid having to create a `url.Values` object.
func VerifyFormKV(key string, values ...string) http.HandlerFunc {
return VerifyForm(url.Values{key: values})
}
//VerifyProtoRepresenting returns a handler that verifies that the body of the request is a valid protobuf
//representation of the passed message.
//
//VerifyProtoRepresenting also verifies that the request's content type is application/x-protobuf
func VerifyProtoRepresenting(expected proto.Message) http.HandlerFunc {
return CombineHandlers(
VerifyContentType("application/x-protobuf"),
func(w http.ResponseWriter, req *http.Request) {
body, err := ioutil.ReadAll(req.Body)
Ω(err).ShouldNot(HaveOccurred())
req.Body.Close()
expectedType := reflect.TypeOf(expected)
actualValuePtr := reflect.New(expectedType.Elem())
actual, ok := actualValuePtr.Interface().(proto.Message)
Ω(ok).Should(BeTrue(), "Message value is not a proto.Message")
err = proto.Unmarshal(body, actual)
Ω(err).ShouldNot(HaveOccurred(), "Failed to unmarshal protobuf")
Ω(actual).Should(Equal(expected), "ProtoBuf Mismatch")
},
)
}
func copyHeader(src http.Header, dst http.Header) {
for key, value := range src {
dst[key] = value
}
}
/*
RespondWith returns a handler that responds to a request with the specified status code and body
Body may be a string or []byte
Also, RespondWith can be given an optional http.Header. The headers defined therein will be added to the response headers.
*/
func RespondWith(statusCode int, body interface{}, optionalHeader ...http.Header) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
if len(optionalHeader) == 1 {
copyHeader(optionalHeader[0], w.Header())
}
w.WriteHeader(statusCode)
switch x := body.(type) {
case string:
w.Write([]byte(x))
case []byte:
w.Write(x)
default:
Ω(body).Should(BeNil(), "Invalid type for body. Should be string or []byte.")
}
}
}
/*
RespondWithPtr returns a handler that responds to a request with the specified status code and body
Unlike RespondWith, you pass RepondWithPtr a pointer to the status code and body allowing different tests
to share the same setup but specify different status codes and bodies.
Also, RespondWithPtr can be given an optional http.Header. The headers defined therein will be added to the response headers.
Since the http.Header can be mutated after the fact you don't need to pass in a pointer.
*/
func RespondWithPtr(statusCode *int, body interface{}, optionalHeader ...http.Header) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
if len(optionalHeader) == 1 {
copyHeader(optionalHeader[0], w.Header())
}
w.WriteHeader(*statusCode)
if body != nil {
switch x := (body).(type) {
case *string:
w.Write([]byte(*x))
case *[]byte:
w.Write(*x)
default:
Ω(body).Should(BeNil(), "Invalid type for body. Should be string or []byte.")
}
}
}
}
/*
RespondWithJSONEncoded returns a handler that responds to a request with the specified status code and a body
containing the JSON-encoding of the passed in object
Also, RespondWithJSONEncoded can be given an optional http.Header. The headers defined therein will be added to the response headers.
*/
func RespondWithJSONEncoded(statusCode int, object interface{}, optionalHeader ...http.Header) http.HandlerFunc {
data, err := json.Marshal(object)
Ω(err).ShouldNot(HaveOccurred())
var headers http.Header
if len(optionalHeader) == 1 {
headers = optionalHeader[0]
} else {
headers = make(http.Header)
}
if _, found := headers["Content-Type"]; !found {
headers["Content-Type"] = []string{"application/json"}
}
return RespondWith(statusCode, string(data), headers)
}
/*
RespondWithJSONEncodedPtr behaves like RespondWithJSONEncoded but takes a pointer
to a status code and object.
This allows different tests to share the same setup but specify different status codes and JSON-encoded
objects.
Also, RespondWithJSONEncodedPtr can be given an optional http.Header. The headers defined therein will be added to the response headers.
Since the http.Header can be mutated after the fact you don't need to pass in a pointer.
*/
func RespondWithJSONEncodedPtr(statusCode *int, object interface{}, optionalHeader ...http.Header) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
data, err := json.Marshal(object)
Ω(err).ShouldNot(HaveOccurred())
var headers http.Header
if len(optionalHeader) == 1 {
headers = optionalHeader[0]
} else {
headers = make(http.Header)
}
if _, found := headers["Content-Type"]; !found {
headers["Content-Type"] = []string{"application/json"}
}
copyHeader(headers, w.Header())
w.WriteHeader(*statusCode)
w.Write(data)
}
}
//RespondWithProto returns a handler that responds to a request with the specified status code and a body
//containing the protobuf serialization of the provided message.
//
//Also, RespondWithProto can be given an optional http.Header. The headers defined therein will be added to the response headers.
func RespondWithProto(statusCode int, message proto.Message, optionalHeader ...http.Header) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
data, err := proto.Marshal(message)
Ω(err).ShouldNot(HaveOccurred())
var headers http.Header
if len(optionalHeader) == 1 {
headers = optionalHeader[0]
} else {
headers = make(http.Header)
}
if _, found := headers["Content-Type"]; !found {
headers["Content-Type"] = []string{"application/x-protobuf"}
}
copyHeader(headers, w.Header())
w.WriteHeader(statusCode)
w.Write(data)
}
}

View File

@@ -1,3 +0,0 @@
package protobuf
//go:generate protoc --go_out=. simple_message.proto

View File

@@ -1,55 +0,0 @@
// Code generated by protoc-gen-go.
// source: simple_message.proto
// DO NOT EDIT!
/*
Package protobuf is a generated protocol buffer package.
It is generated from these files:
simple_message.proto
It has these top-level messages:
SimpleMessage
*/
package protobuf
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
type SimpleMessage struct {
Description *string `protobuf:"bytes,1,req,name=description" json:"description,omitempty"`
Id *int32 `protobuf:"varint,2,req,name=id" json:"id,omitempty"`
Metadata *string `protobuf:"bytes,3,opt,name=metadata" json:"metadata,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *SimpleMessage) Reset() { *m = SimpleMessage{} }
func (m *SimpleMessage) String() string { return proto.CompactTextString(m) }
func (*SimpleMessage) ProtoMessage() {}
func (m *SimpleMessage) GetDescription() string {
if m != nil && m.Description != nil {
return *m.Description
}
return ""
}
func (m *SimpleMessage) GetId() int32 {
if m != nil && m.Id != nil {
return *m.Id
}
return 0
}
func (m *SimpleMessage) GetMetadata() string {
if m != nil && m.Metadata != nil {
return *m.Metadata
}
return ""
}

View File

@@ -1,9 +0,0 @@
syntax = "proto2";
package protobuf;
message SimpleMessage {
required string description = 1;
required int32 id = 2;
optional string metadata = 3;
}

View File

@@ -1,379 +0,0 @@
/*
Package ghttp supports testing HTTP clients by providing a test server (simply a thin wrapper around httptest's server) that supports
registering multiple handlers. Incoming requests are not routed between the different handlers
- rather it is merely the order of the handlers that matters. The first request is handled by the first
registered handler, the second request by the second handler, etc.
The intent here is to have each handler *verify* that the incoming request is valid. To accomplish, ghttp
also provides a collection of bite-size handlers that each perform one aspect of request verification. These can
be composed together and registered with a ghttp server. The result is an expressive language for describing
the requests generated by the client under test.
Here's a simple example, note that the server handler is only defined in one BeforeEach and then modified, as required, by the nested BeforeEaches.
A more comprehensive example is available at https://onsi.github.io/gomega/#_testing_http_clients
var _ = Describe("A Sprockets Client", func() {
var server *ghttp.Server
var client *SprocketClient
BeforeEach(func() {
server = ghttp.NewServer()
client = NewSprocketClient(server.URL(), "skywalker", "tk427")
})
AfterEach(func() {
server.Close()
})
Describe("fetching sprockets", func() {
var statusCode int
var sprockets []Sprocket
BeforeEach(func() {
statusCode = http.StatusOK
sprockets = []Sprocket{}
server.AppendHandlers(ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/sprockets"),
ghttp.VerifyBasicAuth("skywalker", "tk427"),
ghttp.RespondWithJSONEncodedPtr(&statusCode, &sprockets),
))
})
Context("when requesting all sprockets", func() {
Context("when the response is succesful", func() {
BeforeEach(func() {
sprockets = []Sprocket{
NewSprocket("Alfalfa"),
NewSprocket("Banana"),
}
})
It("should return the returned sprockets", func() {
Ω(client.Sprockets()).Should(Equal(sprockets))
})
})
Context("when the response is missing", func() {
BeforeEach(func() {
statusCode = http.StatusNotFound
})
It("should return an empty list of sprockets", func() {
Ω(client.Sprockets()).Should(BeEmpty())
})
})
Context("when the response fails to authenticate", func() {
BeforeEach(func() {
statusCode = http.StatusUnauthorized
})
It("should return an AuthenticationError error", func() {
sprockets, err := client.Sprockets()
Ω(sprockets).Should(BeEmpty())
Ω(err).Should(MatchError(AuthenticationError))
})
})
Context("when the response is a server failure", func() {
BeforeEach(func() {
statusCode = http.StatusInternalServerError
})
It("should return an InternalError error", func() {
sprockets, err := client.Sprockets()
Ω(sprockets).Should(BeEmpty())
Ω(err).Should(MatchError(InternalError))
})
})
})
Context("when requesting some sprockets", func() {
BeforeEach(func() {
sprockets = []Sprocket{
NewSprocket("Alfalfa"),
NewSprocket("Banana"),
}
server.WrapHandler(0, ghttp.VerifyRequest("GET", "/sprockets", "filter=FOOD"))
})
It("should make the request with a filter", func() {
Ω(client.Sprockets("food")).Should(Equal(sprockets))
})
})
})
})
*/
package ghttp
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"reflect"
"regexp"
"strings"
"sync"
. "github.com/onsi/gomega"
)
func new() *Server {
return &Server{
AllowUnhandledRequests: false,
UnhandledRequestStatusCode: http.StatusInternalServerError,
writeLock: &sync.Mutex{},
}
}
type routedHandler struct {
method string
pathRegexp *regexp.Regexp
path string
handler http.HandlerFunc
}
// NewServer returns a new `*ghttp.Server` that wraps an `httptest` server. The server is started automatically.
func NewServer() *Server {
s := new()
s.HTTPTestServer = httptest.NewServer(s)
return s
}
// NewUnstartedServer return a new, unstarted, `*ghttp.Server`. Useful for specifying a custom listener on `server.HTTPTestServer`.
func NewUnstartedServer() *Server {
s := new()
s.HTTPTestServer = httptest.NewUnstartedServer(s)
return s
}
// NewTLSServer returns a new `*ghttp.Server` that wraps an `httptest` TLS server. The server is started automatically.
func NewTLSServer() *Server {
s := new()
s.HTTPTestServer = httptest.NewTLSServer(s)
return s
}
type Server struct {
//The underlying httptest server
HTTPTestServer *httptest.Server
//Defaults to false. If set to true, the Server will allow more requests than there are registered handlers.
AllowUnhandledRequests bool
//The status code returned when receiving an unhandled request.
//Defaults to http.StatusInternalServerError.
//Only applies if AllowUnhandledRequests is true
UnhandledRequestStatusCode int
//If provided, ghttp will log about each request received to the provided io.Writer
//Defaults to nil
//If you're using Ginkgo, set this to GinkgoWriter to get improved output during failures
Writer io.Writer
receivedRequests []*http.Request
requestHandlers []http.HandlerFunc
routedHandlers []routedHandler
writeLock *sync.Mutex
calls int
}
//Start() starts an unstarted ghttp server. It is a catastrophic error to call Start more than once (thanks, httptest).
func (s *Server) Start() {
s.HTTPTestServer.Start()
}
//URL() returns a url that will hit the server
func (s *Server) URL() string {
return s.HTTPTestServer.URL
}
//Addr() returns the address on which the server is listening.
func (s *Server) Addr() string {
return s.HTTPTestServer.Listener.Addr().String()
}
//Close() should be called at the end of each test. It spins down and cleans up the test server.
func (s *Server) Close() {
s.writeLock.Lock()
defer s.writeLock.Unlock()
server := s.HTTPTestServer
s.HTTPTestServer = nil
server.Close()
}
//ServeHTTP() makes Server an http.Handler
//When the server receives a request it handles the request in the following order:
//
//1. If the request matches a handler registered with RouteToHandler, that handler is called.
//2. Otherwise, if there are handlers registered via AppendHandlers, those handlers are called in order.
//3. If all registered handlers have been called then:
// a) If AllowUnhandledRequests is true, the request will be handled with response code of UnhandledRequestStatusCode
// b) If AllowUnhandledRequests is false, the request will not be handled and the current test will be marked as failed.
func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
s.writeLock.Lock()
defer func() {
e := recover()
if e != nil {
w.WriteHeader(http.StatusInternalServerError)
}
//If the handler panics GHTTP will silently succeed. This is bad™.
//To catch this case we need to fail the test if the handler has panicked.
//However, if the handler is panicking because Ginkgo's causing it to panic (i.e. an asswertion failed)
//then we shouldn't double-report the error as this will confuse people.
//So: step 1, if this is a Ginkgo panic - do nothing, Ginkgo's aware of the failure
eAsString, ok := e.(string)
if ok && strings.Contains(eAsString, "defer GinkgoRecover()") {
return
}
//If we're here, we have to do step 2: assert that the error is nil. This assertion will
//allow us to fail the test suite (note: we can't call Fail since Gomega is not allowed to import Ginkgo).
//Since a failed assertion throws a panic, and we are likely in a goroutine, we need to defer within our defer!
defer func() {
recover()
}()
Ω(e).Should(BeNil(), "Handler Panicked")
}()
if s.Writer != nil {
s.Writer.Write([]byte(fmt.Sprintf("GHTTP Received Request: %s - %s\n", req.Method, req.URL)))
}
s.receivedRequests = append(s.receivedRequests, req)
if routedHandler, ok := s.handlerForRoute(req.Method, req.URL.Path); ok {
s.writeLock.Unlock()
routedHandler(w, req)
} else if s.calls < len(s.requestHandlers) {
h := s.requestHandlers[s.calls]
s.calls++
s.writeLock.Unlock()
h(w, req)
} else {
s.writeLock.Unlock()
if s.AllowUnhandledRequests {
ioutil.ReadAll(req.Body)
req.Body.Close()
w.WriteHeader(s.UnhandledRequestStatusCode)
} else {
Ω(req).Should(BeNil(), "Received Unhandled Request")
}
}
}
//ReceivedRequests is an array containing all requests received by the server (both handled and unhandled requests)
func (s *Server) ReceivedRequests() []*http.Request {
s.writeLock.Lock()
defer s.writeLock.Unlock()
return s.receivedRequests
}
//RouteToHandler can be used to register handlers that will always handle requests that match
//the passed in method and path.
//
//The path may be either a string object or a *regexp.Regexp.
func (s *Server) RouteToHandler(method string, path interface{}, handler http.HandlerFunc) {
s.writeLock.Lock()
defer s.writeLock.Unlock()
rh := routedHandler{
method: method,
handler: handler,
}
switch p := path.(type) {
case *regexp.Regexp:
rh.pathRegexp = p
case string:
rh.path = p
default:
panic("path must be a string or a regular expression")
}
for i, existingRH := range s.routedHandlers {
if existingRH.method == method &&
reflect.DeepEqual(existingRH.pathRegexp, rh.pathRegexp) &&
existingRH.path == rh.path {
s.routedHandlers[i] = rh
return
}
}
s.routedHandlers = append(s.routedHandlers, rh)
}
func (s *Server) handlerForRoute(method string, path string) (http.HandlerFunc, bool) {
for _, rh := range s.routedHandlers {
if rh.method == method {
if rh.pathRegexp != nil {
if rh.pathRegexp.Match([]byte(path)) {
return rh.handler, true
}
} else if rh.path == path {
return rh.handler, true
}
}
}
return nil, false
}
//AppendHandlers will appends http.HandlerFuncs to the server's list of registered handlers. The first incoming request is handled by the first handler, the second by the second, etc...
func (s *Server) AppendHandlers(handlers ...http.HandlerFunc) {
s.writeLock.Lock()
defer s.writeLock.Unlock()
s.requestHandlers = append(s.requestHandlers, handlers...)
}
//SetHandler overrides the registered handler at the passed in index with the passed in handler
//This is useful, for example, when a server has been set up in a shared context, but must be tweaked
//for a particular test.
func (s *Server) SetHandler(index int, handler http.HandlerFunc) {
s.writeLock.Lock()
defer s.writeLock.Unlock()
s.requestHandlers[index] = handler
}
//GetHandler returns the handler registered at the passed in index.
func (s *Server) GetHandler(index int) http.HandlerFunc {
s.writeLock.Lock()
defer s.writeLock.Unlock()
return s.requestHandlers[index]
}
func (s *Server) Reset() {
s.writeLock.Lock()
defer s.writeLock.Unlock()
s.HTTPTestServer.CloseClientConnections()
s.calls = 0
s.receivedRequests = nil
s.requestHandlers = nil
s.routedHandlers = nil
}
//WrapHandler combines the passed in handler with the handler registered at the passed in index.
//This is useful, for example, when a server has been set up in a shared context but must be tweaked
//for a particular test.
//
//If the currently registered handler is A, and the new passed in handler is B then
//WrapHandler will generate a new handler that first calls A, then calls B, and assign it to index
func (s *Server) WrapHandler(index int, handler http.HandlerFunc) {
existingHandler := s.GetHandler(index)
s.SetHandler(index, CombineHandlers(existingHandler, handler))
}
func (s *Server) CloseClientConnections() {
s.writeLock.Lock()
defer s.writeLock.Unlock()
s.HTTPTestServer.CloseClientConnections()
}

View File

@@ -1,23 +0,0 @@
package fakematcher
import "fmt"
type FakeMatcher struct {
ReceivedActual interface{}
MatchesToReturn bool
ErrToReturn error
}
func (matcher *FakeMatcher) Match(actual interface{}) (bool, error) {
matcher.ReceivedActual = actual
return matcher.MatchesToReturn, matcher.ErrToReturn
}
func (matcher *FakeMatcher) FailureMessage(actual interface{}) string {
return fmt.Sprintf("positive: %v", actual)
}
func (matcher *FakeMatcher) NegatedFailureMessage(actual interface{}) string {
return fmt.Sprintf("negative: %v", actual)
}

View File

@@ -1,20 +0,0 @@
Copyright (c) 2014 Amit Kumar Gupta
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.