diff --git a/CHANGELOG.md b/CHANGELOG.md index ffde1c937fb..0352a2a3f8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,6 @@ * **Graphite**: Fixed issue with mixed data sources and Graphite, fixes [#5617](https://github.com/grafana/grafana/issues/5617) * **Templating**: Fixed issue with template variable query was issued multiple times during dashboard load, fixes [#5637](https://github.com/grafana/grafana/issues/5637) * **Zoom**: Fixed issues with zoom in and out on embedded (iframed) panel, fixes [#4489](https://github.com/grafana/grafana/issues/4489), [#5666](https://github.com/grafana/grafana/issues/5666) -* **Templating**: Row/Panel repeat issue when saving dashboard caused dupes to appear, fixes [#5591](https://github.com/grafana/grafana/issues/5591) # 3.1.0 stable (2016-07-12) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 20b0753f824..7d0d7f15009 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -130,6 +130,10 @@ "Comment": "v1.4.1", "Rev": "f80e7d0182a463dff0c0da6bbed57f21369d4346" }, + { + "ImportPath": "github.com/benbjohnson/clock", + "Rev": "a620c1cc9866f84a2550ad53f4f353ec030fa26b" + }, { "ImportPath": "github.com/bmizerany/assert", "Comment": "release.r60-6-ge17e998", @@ -272,6 +276,14 @@ "Comment": "go.weekly.2011-12-22-27-ge6ac2fc", "Rev": "e6ac2fc51e89a3249e82157fa0bb7a18ef9dd5bb" }, + { + "ImportPath": "github.com/kr/s3", + "Rev": "c070c8f9a8f0032d48f0d2a77d4e382788bd8a1d" + }, + { + "ImportPath": "github.com/kr/s3/s3util", + "Rev": "c070c8f9a8f0032d48f0d2a77d4e382788bd8a1d" + }, { "ImportPath": "github.com/kr/text", "Rev": "bb797dc4fb8320488f47bf11de07a733d7233e1f" diff --git a/Godeps/_workspace/src/github.com/benbjohnson/clock/LICENSE b/Godeps/_workspace/src/github.com/benbjohnson/clock/LICENSE new file mode 100644 index 00000000000..ce212cb1cee --- /dev/null +++ b/Godeps/_workspace/src/github.com/benbjohnson/clock/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Ben Johnson + +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. diff --git a/Godeps/_workspace/src/github.com/benbjohnson/clock/README.md b/Godeps/_workspace/src/github.com/benbjohnson/clock/README.md new file mode 100644 index 00000000000..5d4f4fe72e7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/benbjohnson/clock/README.md @@ -0,0 +1,104 @@ +clock [![Build Status](https://drone.io/github.com/benbjohnson/clock/status.png)](https://drone.io/github.com/benbjohnson/clock/latest) [![Coverage Status](https://coveralls.io/repos/benbjohnson/clock/badge.png?branch=master)](https://coveralls.io/r/benbjohnson/clock?branch=master) [![GoDoc](https://godoc.org/github.com/benbjohnson/clock?status.png)](https://godoc.org/github.com/benbjohnson/clock) ![Project status](http://img.shields.io/status/experimental.png?color=red) +===== + +Clock is a small library for mocking time in Go. It provides an interface +around the standard library's [`time`][time] package so that the application +can use the realtime clock while tests can use the mock clock. + +[time]: http://golang.org/pkg/time/ + + +## Usage + +### Realtime Clock + +Your application can maintain a `Clock` variable that will allow realtime and +mock clocks to be interchangable. For example, if you had an `Application` type: + +```go +import "github.com/benbjohnson/clock" + +type Application struct { + Clock clock.Clock +} +``` + +You could initialize it to use the realtime clock like this: + +```go +var app Application +app.Clock = clock.New() +... +``` + +Then all timers and time-related functionality should be performed from the +`Clock` variable. + + +### Mocking time + +In your tests, you will want to use a `Mock` clock: + +```go +import ( + "testing" + + "github.com/benbjohnson/clock" +) + +func TestApplication_DoSomething(t *testing.T) { + mock := clock.NewMock() + app := Application{Clock: mock} + ... +} +``` + +Now that you've initialized your application to use the mock clock, you can +adjust the time programmatically. The mock clock always starts from the Unix +epoch (midnight, Jan 1, 1970 UTC). + + +### Controlling time + +The mock clock provides the same functions that the standard library's `time` +package provides. For example, to find the current time, you use the `Now()` +function: + +```go +mock := clock.NewMock() + +// Find the current time. +mock.Now().UTC() // 1970-01-01 00:00:00 +0000 UTC + +// Move the clock forward. +mock.Add(2 * time.Hour) + +// Check the time again. It's 2 hours later! +mock.Now().UTC() // 1970-01-01 02:00:00 +0000 UTC +``` + +Timers and Tickers are also controlled by this same mock clock. They will only +execute when the clock is moved forward: + +``` +mock := clock.NewMock() +count := 0 + +// Kick off a timer to increment every 1 mock second. +go func() { + ticker := clock.Ticker(1 * time.Second) + for { + <-ticker.C + count++ + } +}() +runtime.Gosched() + +// Move the clock forward 10 second. +mock.Add(10 * time.Second) + +// This prints 10. +fmt.Println(count) +``` + + diff --git a/Godeps/_workspace/src/github.com/benbjohnson/clock/clock.go b/Godeps/_workspace/src/github.com/benbjohnson/clock/clock.go new file mode 100644 index 00000000000..518178d6dea --- /dev/null +++ b/Godeps/_workspace/src/github.com/benbjohnson/clock/clock.go @@ -0,0 +1,319 @@ +package clock + +import ( + "sort" + "sync" + "time" +) + +// Clock represents an interface to the functions in the standard library time +// package. Two implementations are available in the clock package. The first +// is a real-time clock which simply wraps the time package's functions. The +// second is a mock clock which will only make forward progress when +// programmatically adjusted. +type Clock interface { + After(d time.Duration) <-chan time.Time + AfterFunc(d time.Duration, f func()) *Timer + Now() time.Time + Sleep(d time.Duration) + Tick(d time.Duration) <-chan time.Time + Ticker(d time.Duration) *Ticker + Timer(d time.Duration) *Timer +} + +// New returns an instance of a real-time clock. +func New() Clock { + return &clock{} +} + +// clock implements a real-time clock by simply wrapping the time package functions. +type clock struct{} + +func (c *clock) After(d time.Duration) <-chan time.Time { return time.After(d) } + +func (c *clock) AfterFunc(d time.Duration, f func()) *Timer { + return &Timer{timer: time.AfterFunc(d, f)} +} + +func (c *clock) Now() time.Time { return time.Now() } + +func (c *clock) Sleep(d time.Duration) { time.Sleep(d) } + +func (c *clock) Tick(d time.Duration) <-chan time.Time { return time.Tick(d) } + +func (c *clock) Ticker(d time.Duration) *Ticker { + t := time.NewTicker(d) + return &Ticker{C: t.C, ticker: t} +} + +func (c *clock) Timer(d time.Duration) *Timer { + t := time.NewTimer(d) + return &Timer{C: t.C, timer: t} +} + +// Mock represents a mock clock that only moves forward programmically. +// It can be preferable to a real-time clock when testing time-based functionality. +type Mock struct { + mu sync.Mutex + now time.Time // current time + timers clockTimers // tickers & timers +} + +// NewMock returns an instance of a mock clock. +// The current time of the mock clock on initialization is the Unix epoch. +func NewMock() *Mock { + return &Mock{now: time.Unix(0, 0)} +} + +// Add moves the current time of the mock clock forward by the duration. +// This should only be called from a single goroutine at a time. +func (m *Mock) Add(d time.Duration) { + // Calculate the final current time. + t := m.now.Add(d) + + // Continue to execute timers until there are no more before the new time. + for { + if !m.runNextTimer(t) { + break + } + } + + // Ensure that we end with the new time. + m.mu.Lock() + m.now = t + m.mu.Unlock() + + // Give a small buffer to make sure the other goroutines get handled. + gosched() +} + +// Sets the current time of the mock clock to a specific one. +// This should only be called from a single goroutine at a time. +func (m *Mock) Set(t time.Time) { + // Continue to execute timers until there are no more before the new time. + for { + if !m.runNextTimer(t) { + break + } + } + + // Ensure that we end with the new time. + m.mu.Lock() + m.now = t + m.mu.Unlock() + + // Give a small buffer to make sure the other goroutines get handled. + gosched() +} + +// runNextTimer executes the next timer in chronological order and moves the +// current time to the timer's next tick time. The next time is not executed if +// it's next time if after the max time. Returns true if a timer is executed. +func (m *Mock) runNextTimer(max time.Time) bool { + m.mu.Lock() + + // Sort timers by time. + sort.Sort(m.timers) + + // If we have no more timers then exit. + if len(m.timers) == 0 { + m.mu.Unlock() + return false + } + + // Retrieve next timer. Exit if next tick is after new time. + t := m.timers[0] + if t.Next().After(max) { + m.mu.Unlock() + return false + } + + // Move "now" forward and unlock clock. + m.now = t.Next() + m.mu.Unlock() + + // Execute timer. + t.Tick(m.now) + return true +} + +// After waits for the duration to elapse and then sends the current time on the returned channel. +func (m *Mock) After(d time.Duration) <-chan time.Time { + return m.Timer(d).C +} + +// AfterFunc waits for the duration to elapse and then executes a function. +// A Timer is returned that can be stopped. +func (m *Mock) AfterFunc(d time.Duration, f func()) *Timer { + t := m.Timer(d) + t.C = nil + t.fn = f + return t +} + +// Now returns the current wall time on the mock clock. +func (m *Mock) Now() time.Time { + m.mu.Lock() + defer m.mu.Unlock() + return m.now +} + +// Sleep pauses the goroutine for the given duration on the mock clock. +// The clock must be moved forward in a separate goroutine. +func (m *Mock) Sleep(d time.Duration) { + <-m.After(d) +} + +// Tick is a convenience function for Ticker(). +// It will return a ticker channel that cannot be stopped. +func (m *Mock) Tick(d time.Duration) <-chan time.Time { + return m.Ticker(d).C +} + +// Ticker creates a new instance of Ticker. +func (m *Mock) Ticker(d time.Duration) *Ticker { + m.mu.Lock() + defer m.mu.Unlock() + ch := make(chan time.Time, 1) + t := &Ticker{ + C: ch, + c: ch, + mock: m, + d: d, + next: m.now.Add(d), + } + m.timers = append(m.timers, (*internalTicker)(t)) + return t +} + +// Timer creates a new instance of Timer. +func (m *Mock) Timer(d time.Duration) *Timer { + m.mu.Lock() + defer m.mu.Unlock() + ch := make(chan time.Time, 1) + t := &Timer{ + C: ch, + c: ch, + mock: m, + next: m.now.Add(d), + stopped: false, + } + m.timers = append(m.timers, (*internalTimer)(t)) + return t +} + +func (m *Mock) removeClockTimer(t clockTimer) { + m.mu.Lock() + defer m.mu.Unlock() + for i, timer := range m.timers { + if timer == t { + copy(m.timers[i:], m.timers[i+1:]) + m.timers[len(m.timers)-1] = nil + m.timers = m.timers[:len(m.timers)-1] + break + } + } + sort.Sort(m.timers) +} + +// clockTimer represents an object with an associated start time. +type clockTimer interface { + Next() time.Time + Tick(time.Time) +} + +// clockTimers represents a list of sortable timers. +type clockTimers []clockTimer + +func (a clockTimers) Len() int { return len(a) } +func (a clockTimers) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a clockTimers) Less(i, j int) bool { return a[i].Next().Before(a[j].Next()) } + +// Timer represents a single event. +// The current time will be sent on C, unless the timer was created by AfterFunc. +type Timer struct { + C <-chan time.Time + c chan time.Time + timer *time.Timer // realtime impl, if set + next time.Time // next tick time + mock *Mock // mock clock, if set + fn func() // AfterFunc function, if set + stopped bool // True if stopped, false if running +} + +// Stop turns off the ticker. +func (t *Timer) Stop() bool { + if t.timer != nil { + return t.timer.Stop() + } + + registered := !t.stopped + t.mock.removeClockTimer((*internalTimer)(t)) + t.stopped = true + return registered +} + +// Reset changes the expiry time of the timer +func (t *Timer) Reset(d time.Duration) bool { + if t.timer != nil { + return t.timer.Reset(d) + } + + t.next = t.mock.now.Add(d) + registered := !t.stopped + if t.stopped { + t.mock.mu.Lock() + t.mock.timers = append(t.mock.timers, (*internalTimer)(t)) + t.mock.mu.Unlock() + } + t.stopped = false + return registered +} + +type internalTimer Timer + +func (t *internalTimer) Next() time.Time { return t.next } +func (t *internalTimer) Tick(now time.Time) { + if t.fn != nil { + t.fn() + } else { + t.c <- now + } + t.mock.removeClockTimer((*internalTimer)(t)) + t.stopped = true + gosched() +} + +// Ticker holds a channel that receives "ticks" at regular intervals. +type Ticker struct { + C <-chan time.Time + c chan time.Time + ticker *time.Ticker // realtime impl, if set + next time.Time // next tick time + mock *Mock // mock clock, if set + d time.Duration // time between ticks +} + +// Stop turns off the ticker. +func (t *Ticker) Stop() { + if t.ticker != nil { + t.ticker.Stop() + } else { + t.mock.removeClockTimer((*internalTicker)(t)) + } +} + +type internalTicker Ticker + +func (t *internalTicker) Next() time.Time { return t.next } +func (t *internalTicker) Tick(now time.Time) { + select { + case t.c <- now: + default: + } + t.next = now.Add(t.d) + gosched() +} + +// Sleep momentarily so that other goroutines can process. +func gosched() { time.Sleep(1 * time.Millisecond) } diff --git a/Godeps/_workspace/src/github.com/kr/s3/License b/Godeps/_workspace/src/github.com/kr/s3/License new file mode 100644 index 00000000000..4abc7488905 --- /dev/null +++ b/Godeps/_workspace/src/github.com/kr/s3/License @@ -0,0 +1,19 @@ +Copyright (c) 2012 Keith Rarick. + +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. diff --git a/Godeps/_workspace/src/github.com/kr/s3/Readme b/Godeps/_workspace/src/github.com/kr/s3/Readme new file mode 100644 index 00000000000..93b53595271 --- /dev/null +++ b/Godeps/_workspace/src/github.com/kr/s3/Readme @@ -0,0 +1,4 @@ +Package s3 signs HTTP requests for use with Amazon’s S3 API. + +Documentation: +http://godoc.org/github.com/kr/s3 diff --git a/Godeps/_workspace/src/github.com/kr/s3/s3util/Readme b/Godeps/_workspace/src/github.com/kr/s3/s3util/Readme new file mode 100644 index 00000000000..97c4a9de3d3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/kr/s3/s3util/Readme @@ -0,0 +1,4 @@ +Package s3util provides streaming transfers to and from Amazon S3. + +Full documentation: +http://godoc.org/github.com/kr/s3/s3util diff --git a/Godeps/_workspace/src/github.com/kr/s3/s3util/config.go b/Godeps/_workspace/src/github.com/kr/s3/s3util/config.go new file mode 100644 index 00000000000..aeae14ac4e7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/kr/s3/s3util/config.go @@ -0,0 +1,27 @@ +// Package s3util provides streaming transfers to and from Amazon S3. +// +// To use it, open or create an S3 object, read or write data, +// and close the object. +// +// You must assign valid credentials to DefaultConfig.Keys before using +// DefaultConfig. Be sure to close an io.WriteCloser returned by this package, +// to flush buffers and complete the multipart upload process. +package s3util + +// TODO(kr): parse error responses; return structured data + +import ( + "github.com/kr/s3" + "net/http" +) + +var DefaultConfig = &Config{ + Service: s3.DefaultService, + Keys: new(s3.Keys), +} + +type Config struct { + *s3.Service + *s3.Keys + *http.Client // if nil, uses http.DefaultClient +} diff --git a/Godeps/_workspace/src/github.com/kr/s3/s3util/error.go b/Godeps/_workspace/src/github.com/kr/s3/s3util/error.go new file mode 100644 index 00000000000..8f512f46811 --- /dev/null +++ b/Godeps/_workspace/src/github.com/kr/s3/s3util/error.go @@ -0,0 +1,29 @@ +package s3util + +import ( + "bytes" + "fmt" + "io" + "net/http" +) + +type respError struct { + r *http.Response + b bytes.Buffer +} + +func newRespError(r *http.Response) *respError { + e := new(respError) + e.r = r + io.Copy(&e.b, r.Body) + r.Body.Close() + return e +} + +func (e *respError) Error() string { + return fmt.Sprintf( + "unwanted http status %d: %q", + e.r.StatusCode, + e.b.String(), + ) +} diff --git a/Godeps/_workspace/src/github.com/kr/s3/s3util/open.go b/Godeps/_workspace/src/github.com/kr/s3/s3util/open.go new file mode 100644 index 00000000000..3f6ae9c5d83 --- /dev/null +++ b/Godeps/_workspace/src/github.com/kr/s3/s3util/open.go @@ -0,0 +1,33 @@ +package s3util + +import ( + "io" + "net/http" + "time" +) + +// Open requests the S3 object at url. An HTTP status other than 200 is +// considered an error. +// +// If c is nil, Open uses DefaultConfig. +func Open(url string, c *Config) (io.ReadCloser, error) { + if c == nil { + c = DefaultConfig + } + // TODO(kr): maybe parallel range fetching + r, _ := http.NewRequest("GET", url, nil) + r.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) + c.Sign(r, *c.Keys) + client := c.Client + if client == nil { + client = http.DefaultClient + } + resp, err := client.Do(r) + if err != nil { + return nil, err + } + if resp.StatusCode != 200 { + return nil, newRespError(resp) + } + return resp.Body, nil +} diff --git a/Godeps/_workspace/src/github.com/kr/s3/s3util/readdir.go b/Godeps/_workspace/src/github.com/kr/s3/s3util/readdir.go new file mode 100644 index 00000000000..d14d6002a34 --- /dev/null +++ b/Godeps/_workspace/src/github.com/kr/s3/s3util/readdir.go @@ -0,0 +1,208 @@ +package s3util + +import ( + "bytes" + "encoding/xml" + "errors" + "io" + "net/http" + "net/url" + "os" + "strconv" + "strings" + "time" +) + +// File represents an S3 object or directory. +type File struct { + url string + prefix string + config *Config + result *listObjectsResult +} + +type fileInfo struct { + name string + size int64 + dir bool + modTime time.Time + sys *Stat +} + +// Stat contains information about an S3 object or directory. +// It is the "underlying data source" returned by method Sys +// for each FileInfo produced by this package. +// fi.Sys().(*s3util.Stat) +// For the meaning of these fields, see +// http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGET.html. +type Stat struct { + Key string + LastModified string + ETag string // ETag value, without double quotes. + Size string + StorageClass string + OwnerID string `xml:"Owner>ID"` + OwnerName string `xml:"Owner>DisplayName"` +} + +type listObjectsResult struct { + IsTruncated bool + Contents []Stat + Directories []string `xml:"CommonPrefixes>Prefix"` // Suffix "/" trimmed +} + +func (f *fileInfo) Name() string { return f.name } +func (f *fileInfo) Size() int64 { return f.size } +func (f *fileInfo) Mode() os.FileMode { + if f.dir { + return 0755 | os.ModeDir + } + return 0644 +} +func (f *fileInfo) ModTime() time.Time { + if f.modTime.IsZero() && f.sys != nil { + // we return the zero value if a parse error ever happens. + f.modTime, _ = time.Parse(time.RFC3339Nano, f.sys.LastModified) + } + return f.modTime +} +func (f *fileInfo) IsDir() bool { return f.dir } +func (f *fileInfo) Sys() interface{} { return f.sys } + +// NewFile returns a new File with the given URL and config. +// +// Set rawurl to a directory on S3, such as +// https://mybucket.s3.amazonaws.com/myfolder. +// The URL cannot have query parameters or a fragment. +// If c is nil, DefaultConfig will be used. +func NewFile(rawurl string, c *Config) (*File, error) { + u, err := url.Parse(rawurl) + if err != nil { + return nil, err + } + if u.RawQuery != "" { + return nil, errors.New("url cannot have raw query parameters.") + } + if u.Fragment != "" { + return nil, errors.New("url cannot have a fragment.") + } + + prefix := strings.TrimLeft(u.Path, "/") + if prefix != "" && !strings.HasSuffix(prefix, "/") { + prefix += "/" + } + u.Path = "" + return &File{u.String(), prefix, c, nil}, nil +} + +// Readdir requests a list of entries in the S3 directory +// represented by f and returns a slice of up to n FileInfo +// values, in alphabetical order. Subsequent calls +// on the same File will yield further FileInfos. +// Only direct children are returned, not deeper descendants. +func (f *File) Readdir(n int) ([]os.FileInfo, error) { + if f.result != nil && !f.result.IsTruncated { + return make([]os.FileInfo, 0), io.EOF + } + + reader, err := f.sendRequest(n) + if err != nil { + return nil, err + } + defer reader.Close() + + return f.parseResponse(reader) +} + +func (f *File) sendRequest(count int) (io.ReadCloser, error) { + c := f.config + if c == nil { + c = DefaultConfig + } + var buf bytes.Buffer + buf.WriteString(f.url) + buf.WriteString("?delimiter=%2F") + if f.prefix != "" { + buf.WriteString("&prefix=") + buf.WriteString(url.QueryEscape(f.prefix)) + } + if count > 0 { + buf.WriteString("&max-keys=") + buf.WriteString(strconv.Itoa(count)) + } + if f.result != nil && f.result.IsTruncated { + var lastDir, lastKey, marker string + if len(f.result.Directories) > 0 { + lastDir = f.result.Directories[len(f.result.Directories)-1] + } + if len(f.result.Contents) > 0 { + lastKey = f.result.Contents[len(f.result.Contents)-1].Key + } + + if lastKey > lastDir { + marker = lastKey + } else { + marker = lastDir + } + + if marker != "" { + buf.WriteString("&marker=") + buf.WriteString(url.QueryEscape(marker)) + } + } + u := buf.String() + r, _ := http.NewRequest("GET", u, nil) + r.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) + c.Sign(r, *c.Keys) + resp, err := http.DefaultClient.Do(r) + if err != nil { + return nil, err + } + if resp.StatusCode != 200 { + return nil, newRespError(resp) + } + return resp.Body, nil +} + +func (f *File) parseResponse(reader io.Reader) ([]os.FileInfo, error) { + decoder := xml.NewDecoder(reader) + result := listObjectsResult{} + var err error + err = decoder.Decode(&result) + if err != nil { + return nil, err + } + + infos := make([]os.FileInfo, len(result.Contents)+len(result.Directories)) + var size int64 + var name string + var is_dir bool + for i, content := range result.Contents { + c := content + c.ETag = strings.Trim(c.ETag, `"`) + size, _ = strconv.ParseInt(c.Size, 10, 0) + if size == 0 && strings.HasSuffix(c.Key, "/") { + name = strings.TrimRight(c.Key, "/") + is_dir = true + } else { + name = c.Key + is_dir = false + } + infos[i] = &fileInfo{ + name: name, + size: size, + dir: is_dir, + sys: &c, + } + } + for i, dir := range result.Directories { + infos[len(result.Contents)+i] = &fileInfo{ + name: strings.TrimRight(dir, "/"), + size: 0, + dir: true, + } + } + f.result = &result + + return infos, nil +} diff --git a/Godeps/_workspace/src/github.com/kr/s3/s3util/uploader.go b/Godeps/_workspace/src/github.com/kr/s3/s3util/uploader.go new file mode 100644 index 00000000000..1a21511bd29 --- /dev/null +++ b/Godeps/_workspace/src/github.com/kr/s3/s3util/uploader.go @@ -0,0 +1,267 @@ +package s3util + +import ( + "bytes" + "encoding/xml" + "github.com/kr/s3" + "fmt" + "io" + "net/http" + "net/url" + "strconv" + "sync" + "syscall" + "time" +) + +// defined by amazon +const ( + minPartSize = 5 * 1024 * 1024 + maxPartSize = 1<<31 - 1 // for 32-bit use; amz max is 5GiB + maxObjSize = 5 * 1024 * 1024 * 1024 * 1024 + maxNPart = 10000 +) + +const ( + concurrency = 5 + nTry = 2 +) + +type part struct { + r io.ReadSeeker + len int64 + + // read by xml encoder + PartNumber int + ETag string +} + +type uploader struct { + s3 s3.Service + keys s3.Keys + url string + client *http.Client + UploadId string // written by xml decoder + + bufsz int64 + buf []byte + off int + ch chan *part + part int + closed bool + err error + wg sync.WaitGroup + + xml struct { + XMLName string `xml:"CompleteMultipartUpload"` + Part []*part + } +} + +// Create creates an S3 object at url and sends multipart upload requests as +// data is written. +// +// If h is not nil, each of its entries is added to the HTTP request header. +// If c is nil, Create uses DefaultConfig. +func Create(url string, h http.Header, c *Config) (io.WriteCloser, error) { + if c == nil { + c = DefaultConfig + } + return newUploader(url, h, c) +} + +// Sends an S3 multipart upload initiation request. +// See http://docs.amazonwebservices.com/AmazonS3/latest/dev/mpuoverview.html. +// This initial request returns an UploadId that we use to identify +// subsequent PUT requests. +func newUploader(url string, h http.Header, c *Config) (u *uploader, err error) { + u = new(uploader) + u.s3 = *c.Service + u.url = url + u.keys = *c.Keys + u.client = c.Client + if u.client == nil { + u.client = http.DefaultClient + } + u.bufsz = minPartSize + r, err := http.NewRequest("POST", url+"?uploads", nil) + if err != nil { + return nil, err + } + r.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) + for k := range h { + for _, v := range h[k] { + r.Header.Add(k, v) + } + } + u.s3.Sign(r, u.keys) + resp, err := u.client.Do(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + return nil, newRespError(resp) + } + err = xml.NewDecoder(resp.Body).Decode(u) + if err != nil { + return nil, err + } + u.ch = make(chan *part) + for i := 0; i < concurrency; i++ { + go u.worker() + } + return u, nil +} + +func (u *uploader) Write(p []byte) (n int, err error) { + if u.closed { + return 0, syscall.EINVAL + } + if u.err != nil { + return 0, u.err + } + for n < len(p) { + if cap(u.buf) == 0 { + u.buf = make([]byte, int(u.bufsz)) + // Increase part size (1.001x). + // This lets us reach the max object size (5TiB) while + // still doing minimal buffering for small objects. + u.bufsz = min(u.bufsz+u.bufsz/1000, maxPartSize) + } + r := copy(u.buf[u.off:], p[n:]) + u.off += r + n += r + if u.off == len(u.buf) { + u.flush() + } + } + return n, nil +} + +func (u *uploader) flush() { + u.wg.Add(1) + u.part++ + p := &part{bytes.NewReader(u.buf[:u.off]), int64(u.off), u.part, ""} + u.xml.Part = append(u.xml.Part, p) + u.ch <- p + u.buf, u.off = nil, 0 +} + +func (u *uploader) worker() { + for p := range u.ch { + u.retryUploadPart(p) + } +} + +// Calls putPart up to nTry times to recover from transient errors. +func (u *uploader) retryUploadPart(p *part) { + defer u.wg.Done() + defer func() { p.r = nil }() // free the large buffer + var err error + for i := 0; i < nTry; i++ { + p.r.Seek(0, 0) + err = u.putPart(p) + if err == nil { + return + } + } + u.err = err +} + +// Uploads part p, reading its contents from p.r. +// Stores the ETag in p.ETag. +func (u *uploader) putPart(p *part) error { + v := url.Values{} + v.Set("partNumber", strconv.Itoa(p.PartNumber)) + v.Set("uploadId", u.UploadId) + req, err := http.NewRequest("PUT", u.url+"?"+v.Encode(), p.r) + if err != nil { + return err + } + req.ContentLength = p.len + req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) + u.s3.Sign(req, u.keys) + resp, err := u.client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + return newRespError(resp) + } + s := resp.Header.Get("etag") // includes quote chars for some reason + if len(s) < 2 { + return fmt.Errorf("received invalid etag %q", s) + } + p.ETag = s[1 : len(s)-1] + return nil +} + +func (u *uploader) Close() error { + if u.closed { + return syscall.EINVAL + } + if cap(u.buf) > 0 { + u.flush() + } + u.wg.Wait() + close(u.ch) + u.closed = true + if u.err != nil { + u.abort() + return u.err + } + + body, err := xml.Marshal(u.xml) + if err != nil { + return err + } + b := bytes.NewBuffer(body) + v := url.Values{} + v.Set("uploadId", u.UploadId) + req, err := http.NewRequest("POST", u.url+"?"+v.Encode(), b) + if err != nil { + return err + } + req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) + u.s3.Sign(req, u.keys) + resp, err := u.client.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return newRespError(resp) + } + resp.Body.Close() + return nil +} + +func (u *uploader) abort() { + // TODO(kr): devise a reasonable way to report an error here in addition + // to the error that caused the abort. + v := url.Values{} + v.Set("uploadId", u.UploadId) + s := u.url + "?" + v.Encode() + req, err := http.NewRequest("DELETE", s, nil) + if err != nil { + return + } + req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) + u.s3.Sign(req, u.keys) + resp, err := u.client.Do(req) + if err != nil { + return + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + return + } +} + +func min(a, b int64) int64 { + if a < b { + return a + } + return b +} diff --git a/Godeps/_workspace/src/github.com/kr/s3/sign.go b/Godeps/_workspace/src/github.com/kr/s3/sign.go new file mode 100644 index 00000000000..0ff2d483bb4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/kr/s3/sign.go @@ -0,0 +1,200 @@ +// Package s3 signs HTTP requests for Amazon S3 and compatible services. +package s3 + +// See +// http://docs.amazonwebservices.com/AmazonS3/2006-03-01/dev/RESTAuthentication.html. + +import ( + "crypto/hmac" + "crypto/sha1" + "encoding/base64" + "io" + "net/http" + "sort" + "strings" +) + +var signParams = map[string]bool{ + "acl": true, + "delete": true, + "lifecycle": true, + "location": true, + "logging": true, + "notification": true, + "partNumber": true, + "policy": true, + "requestPayment": true, + "response-cache-control": true, + "response-content-disposition": true, + "response-content-encoding": true, + "response-content-language": true, + "response-content-type": true, + "response-expires": true, + "restore": true, + "torrent": true, + "uploadId": true, + "uploads": true, + "versionId": true, + "versioning": true, + "versions": true, + "website": true, +} + +// Keys holds a set of Amazon Security Credentials. +type Keys struct { + AccessKey string + SecretKey string + + // SecurityToken is used for temporary security credentials. + // If set, it will be added to header field X-Amz-Security-Token + // before signing a request. + SecurityToken string + // See http://docs.aws.amazon.com/AmazonS3/latest/dev/MakingRequests.html#TypesofSecurityCredentials +} + +// IdentityBucket returns subdomain. +// It is designed to be used with S3-compatible services that +// treat the entire subdomain as the bucket name, for example +// storage.io. +func IdentityBucket(subdomain string) string { + return subdomain +} + +// AmazonBucket returns everything up to the last '.' in subdomain. +// It is designed to be used with the Amazon service. +// "johnsmith.s3" becomes "johnsmith" +// "johnsmith.s3-eu-west-1" becomes "johnsmith" +// "www.example.com.s3" becomes "www.example.com" +func AmazonBucket(subdomain string) string { + if i := strings.LastIndex(subdomain, "."); i != -1 { + return subdomain[:i] + } + return "" +} + +// DefaultService is the default Service used by Sign. +var DefaultService = &Service{Domain: "amazonaws.com"} + +// Sign signs an HTTP request with the given S3 keys. +// +// This function is a wrapper around DefaultService.Sign. +func Sign(r *http.Request, k Keys) { + DefaultService.Sign(r, k) +} + +// Service represents an S3-compatible service. +type Service struct { + // Domain is the service's root domain. It is used to extract + // the subdomain from an http.Request before passing the + // subdomain to Bucket. + Domain string + + // Bucket derives the bucket name from a subdomain. + // If nil, AmazonBucket is used. + Bucket func(subdomain string) string +} + +// Sign signs an HTTP request with the given S3 keys for use on service s. +func (s *Service) Sign(r *http.Request, k Keys) { + if k.SecurityToken != "" { + r.Header.Set("X-Amz-Security-Token", k.SecurityToken) + } + h := hmac.New(sha1.New, []byte(k.SecretKey)) + s.writeSigData(h, r) + sig := make([]byte, base64.StdEncoding.EncodedLen(h.Size())) + base64.StdEncoding.Encode(sig, h.Sum(nil)) + r.Header.Set("Authorization", "AWS "+k.AccessKey+":"+string(sig)) +} + +func (s *Service) writeSigData(w io.Writer, r *http.Request) { + w.Write([]byte(r.Method)) + w.Write([]byte{'\n'}) + w.Write([]byte(r.Header.Get("content-md5"))) + w.Write([]byte{'\n'}) + w.Write([]byte(r.Header.Get("content-type"))) + w.Write([]byte{'\n'}) + if _, ok := r.Header["X-Amz-Date"]; !ok { + w.Write([]byte(r.Header.Get("date"))) + } + w.Write([]byte{'\n'}) + writeAmzHeaders(w, r) + s.writeResource(w, r) +} + +func (s *Service) writeResource(w io.Writer, r *http.Request) { + s.writeVhostBucket(w, strings.ToLower(r.Host)) + path := r.URL.RequestURI() + if r.URL.RawQuery != "" { + path = path[:len(path)-len(r.URL.RawQuery)-1] + } + w.Write([]byte(path)) + s.writeSubResource(w, r) +} + +func (s *Service) writeVhostBucket(w io.Writer, host string) { + if i := strings.Index(host, ":"); i != -1 { + host = host[:i] + } + + if host == s.Domain { + // no vhost - do nothing + } else if strings.HasSuffix(host, "."+s.Domain) { + // vhost - bucket may be in prefix + b := s.Bucket + if b == nil { + b = AmazonBucket + } + bucket := b(host[:len(host)-len(s.Domain)-1]) + + if bucket != "" { + w.Write([]byte{'/'}) + w.Write([]byte(bucket)) + } + } else { + // cname - bucket is host + w.Write([]byte{'/'}) + w.Write([]byte(host)) + } +} + +func (s *Service) writeSubResource(w io.Writer, r *http.Request) { + var a []string + for k, vs := range r.URL.Query() { + if signParams[k] { + for _, v := range vs { + if v == "" { + a = append(a, k) + } else { + a = append(a, k+"="+v) + } + } + } + } + sort.Strings(a) + var p byte = '?' + for _, s := range a { + w.Write([]byte{p}) + w.Write([]byte(s)) + p = '&' + } +} + +func writeAmzHeaders(w io.Writer, r *http.Request) { + var keys []string + for k, _ := range r.Header { + if strings.HasPrefix(strings.ToLower(k), "x-amz-") { + keys = append(keys, k) + } + } + + sort.Strings(keys) + var a []string + for _, k := range keys { + v := r.Header[k] + a = append(a, strings.ToLower(k)+":"+strings.Join(v, ",")) + } + for _, h := range a { + w.Write([]byte(h)) + w.Write([]byte{'\n'}) + } +} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/collections_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/collections_test.go deleted file mode 100644 index 25612bd7670..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/collections_test.go +++ /dev/null @@ -1,103 +0,0 @@ -package assertions - -import ( - "fmt" - "testing" - "time" -) - -func TestShouldContain(t *testing.T) { - fail(t, so([]int{}, ShouldContain), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so([]int{}, ShouldContain, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).") - - fail(t, so(Thing1{}, ShouldContain, 1), "You must provide a valid container (was assertions.Thing1)!") - fail(t, so(nil, ShouldContain, 1), "You must provide a valid container (was )!") - fail(t, so([]int{1}, ShouldContain, 2), "Expected the container ([]int) to contain: '2' (but it didn't)!") - - pass(t, so([]int{1}, ShouldContain, 1)) - pass(t, so([]int{1, 2, 3}, ShouldContain, 2)) -} - -func TestShouldNotContain(t *testing.T) { - fail(t, so([]int{}, ShouldNotContain), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so([]int{}, ShouldNotContain, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).") - - fail(t, so(Thing1{}, ShouldNotContain, 1), "You must provide a valid container (was assertions.Thing1)!") - fail(t, so(nil, ShouldNotContain, 1), "You must provide a valid container (was )!") - - fail(t, so([]int{1}, ShouldNotContain, 1), "Expected the container ([]int) NOT to contain: '1' (but it did)!") - fail(t, so([]int{1, 2, 3}, ShouldNotContain, 2), "Expected the container ([]int) NOT to contain: '2' (but it did)!") - - pass(t, so([]int{1}, ShouldNotContain, 2)) -} - -func TestShouldBeIn(t *testing.T) { - fail(t, so(4, ShouldBeIn), shouldHaveProvidedCollectionMembers) - - container := []int{1, 2, 3, 4} - pass(t, so(4, ShouldBeIn, container)) - pass(t, so(4, ShouldBeIn, 1, 2, 3, 4)) - - fail(t, so(4, ShouldBeIn, 1, 2, 3), "Expected '4' to be in the container ([]interface {}, but it wasn't)!") - fail(t, so(4, ShouldBeIn, []int{1, 2, 3}), "Expected '4' to be in the container ([]int, but it wasn't)!") -} - -func TestShouldNotBeIn(t *testing.T) { - fail(t, so(4, ShouldNotBeIn), shouldHaveProvidedCollectionMembers) - - container := []int{1, 2, 3, 4} - pass(t, so(42, ShouldNotBeIn, container)) - pass(t, so(42, ShouldNotBeIn, 1, 2, 3, 4)) - - fail(t, so(2, ShouldNotBeIn, 1, 2, 3), "Expected '2' NOT to be in the container ([]interface {}, but it was)!") - fail(t, so(2, ShouldNotBeIn, []int{1, 2, 3}), "Expected '2' NOT to be in the container ([]int, but it was)!") -} - -func TestShouldBeEmpty(t *testing.T) { - fail(t, so(1, ShouldBeEmpty, 2, 3), "This assertion requires exactly 0 comparison values (you provided 2).") - - pass(t, so([]int{}, ShouldBeEmpty)) // empty slice - pass(t, so([]interface{}{}, ShouldBeEmpty)) // empty slice - pass(t, so(map[string]int{}, ShouldBeEmpty)) // empty map - pass(t, so("", ShouldBeEmpty)) // empty string - pass(t, so(&[]int{}, ShouldBeEmpty)) // pointer to empty slice - pass(t, so(&[0]int{}, ShouldBeEmpty)) // pointer to empty array - pass(t, so(nil, ShouldBeEmpty)) // nil - pass(t, so(make(chan string), ShouldBeEmpty)) // empty channel - - fail(t, so([]int{1}, ShouldBeEmpty), "Expected [1] to be empty (but it wasn't)!") // non-empty slice - fail(t, so([]interface{}{1}, ShouldBeEmpty), "Expected [1] to be empty (but it wasn't)!") // non-empty slice - fail(t, so(map[string]int{"hi": 0}, ShouldBeEmpty), "Expected map[hi:0] to be empty (but it wasn't)!") // non-empty map - fail(t, so("hi", ShouldBeEmpty), "Expected hi to be empty (but it wasn't)!") // non-empty string - fail(t, so(&[]int{1}, ShouldBeEmpty), "Expected &[1] to be empty (but it wasn't)!") // pointer to non-empty slice - fail(t, so(&[1]int{1}, ShouldBeEmpty), "Expected &[1] to be empty (but it wasn't)!") // pointer to non-empty array - c := make(chan int, 1) // non-empty channel - go func() { c <- 1 }() - time.Sleep(time.Millisecond) - fail(t, so(c, ShouldBeEmpty), fmt.Sprintf("Expected %+v to be empty (but it wasn't)!", c)) -} - -func TestShouldNotBeEmpty(t *testing.T) { - fail(t, so(1, ShouldNotBeEmpty, 2, 3), "This assertion requires exactly 0 comparison values (you provided 2).") - - fail(t, so([]int{}, ShouldNotBeEmpty), "Expected [] to NOT be empty (but it was)!") // empty slice - fail(t, so([]interface{}{}, ShouldNotBeEmpty), "Expected [] to NOT be empty (but it was)!") // empty slice - fail(t, so(map[string]int{}, ShouldNotBeEmpty), "Expected map[] to NOT be empty (but it was)!") // empty map - fail(t, so("", ShouldNotBeEmpty), "Expected to NOT be empty (but it was)!") // empty string - fail(t, so(&[]int{}, ShouldNotBeEmpty), "Expected &[] to NOT be empty (but it was)!") // pointer to empty slice - fail(t, so(&[0]int{}, ShouldNotBeEmpty), "Expected &[] to NOT be empty (but it was)!") // pointer to empty array - fail(t, so(nil, ShouldNotBeEmpty), "Expected to NOT be empty (but it was)!") // nil - c := make(chan int, 0) // non-empty channel - fail(t, so(c, ShouldNotBeEmpty), fmt.Sprintf("Expected %+v to NOT be empty (but it was)!", c)) // empty channel - - pass(t, so([]int{1}, ShouldNotBeEmpty)) // non-empty slice - pass(t, so([]interface{}{1}, ShouldNotBeEmpty)) // non-empty slice - pass(t, so(map[string]int{"hi": 0}, ShouldNotBeEmpty)) // non-empty map - pass(t, so("hi", ShouldNotBeEmpty)) // non-empty string - pass(t, so(&[]int{1}, ShouldNotBeEmpty)) // pointer to non-empty slice - pass(t, so(&[1]int{1}, ShouldNotBeEmpty)) // pointer to non-empty array - c = make(chan int, 1) - go func() { c <- 1 }() - time.Sleep(time.Millisecond) - pass(t, so(c, ShouldNotBeEmpty)) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/equality_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/equality_test.go deleted file mode 100644 index ee3939712fc..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/equality_test.go +++ /dev/null @@ -1,267 +0,0 @@ -package assertions - -import ( - "fmt" - "reflect" - "testing" -) - -func TestShouldEqual(t *testing.T) { - serializer = newFakeSerializer() - - fail(t, so(1, ShouldEqual), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(1, ShouldEqual, 1, 2), "This assertion requires exactly 1 comparison values (you provided 2).") - fail(t, so(1, ShouldEqual, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).") - - pass(t, so(1, ShouldEqual, 1)) - fail(t, so(1, ShouldEqual, 2), "2|1|Expected: '2' Actual: '1' (Should be equal)") - - pass(t, so(true, ShouldEqual, true)) - fail(t, so(true, ShouldEqual, false), "false|true|Expected: 'false' Actual: 'true' (Should be equal)") - - pass(t, so("hi", ShouldEqual, "hi")) - fail(t, so("hi", ShouldEqual, "bye"), "bye|hi|Expected: 'bye' Actual: 'hi' (Should be equal)") - - pass(t, so(42, ShouldEqual, uint(42))) - - fail(t, so(Thing1{"hi"}, ShouldEqual, Thing1{}), "{}|{hi}|Expected: '{}' Actual: '{hi}' (Should be equal)") - fail(t, so(Thing1{"hi"}, ShouldEqual, Thing1{"hi"}), "{hi}|{hi}|Expected: '{hi}' Actual: '{hi}' (Should be equal)") - fail(t, so(&Thing1{"hi"}, ShouldEqual, &Thing1{"hi"}), "&{hi}|&{hi}|Expected: '&{hi}' Actual: '&{hi}' (Should be equal)") - - fail(t, so(Thing1{}, ShouldEqual, Thing2{}), "{}|{}|Expected: '{}' Actual: '{}' (Should be equal)") -} - -func TestShouldNotEqual(t *testing.T) { - fail(t, so(1, ShouldNotEqual), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(1, ShouldNotEqual, 1, 2), "This assertion requires exactly 1 comparison values (you provided 2).") - fail(t, so(1, ShouldNotEqual, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).") - - pass(t, so(1, ShouldNotEqual, 2)) - fail(t, so(1, ShouldNotEqual, 1), "Expected '1' to NOT equal '1' (but it did)!") - - pass(t, so(true, ShouldNotEqual, false)) - fail(t, so(true, ShouldNotEqual, true), "Expected 'true' to NOT equal 'true' (but it did)!") - - pass(t, so("hi", ShouldNotEqual, "bye")) - fail(t, so("hi", ShouldNotEqual, "hi"), "Expected 'hi' to NOT equal 'hi' (but it did)!") - - pass(t, so(&Thing1{"hi"}, ShouldNotEqual, &Thing1{"hi"})) - pass(t, so(Thing1{"hi"}, ShouldNotEqual, Thing1{"hi"})) - pass(t, so(Thing1{}, ShouldNotEqual, Thing1{})) - pass(t, so(Thing1{}, ShouldNotEqual, Thing2{})) -} - -func TestShouldAlmostEqual(t *testing.T) { - fail(t, so(1, ShouldAlmostEqual), "This assertion requires exactly one comparison value and an optional delta (you provided neither)") - fail(t, so(1, ShouldAlmostEqual, 1, 2, 3), "This assertion requires exactly one comparison value and an optional delta (you provided more values)") - - // with the default delta - pass(t, so(1, ShouldAlmostEqual, .99999999999999)) - pass(t, so(1.3612499999999996, ShouldAlmostEqual, 1.36125)) - pass(t, so(0.7285312499999999, ShouldAlmostEqual, 0.72853125)) - fail(t, so(1, ShouldAlmostEqual, .99), "Expected '1' to almost equal '0.99' (but it didn't)!") - - // with a different delta - pass(t, so(100.0, ShouldAlmostEqual, 110.0, 10.0)) - fail(t, so(100.0, ShouldAlmostEqual, 111.0, 10.5), "Expected '100' to almost equal '111' (but it didn't)!") - - // ints should work - pass(t, so(100, ShouldAlmostEqual, 100.0)) - fail(t, so(100, ShouldAlmostEqual, 99.0), "Expected '100' to almost equal '99' (but it didn't)!") - - // float32 should work - pass(t, so(float64(100.0), ShouldAlmostEqual, float32(100.0))) - fail(t, so(float32(100.0), ShouldAlmostEqual, 99.0, float32(0.1)), "Expected '100' to almost equal '99' (but it didn't)!") -} - -func TestShouldNotAlmostEqual(t *testing.T) { - fail(t, so(1, ShouldNotAlmostEqual), "This assertion requires exactly one comparison value and an optional delta (you provided neither)") - fail(t, so(1, ShouldNotAlmostEqual, 1, 2, 3), "This assertion requires exactly one comparison value and an optional delta (you provided more values)") - - // with the default delta - fail(t, so(1, ShouldNotAlmostEqual, .99999999999999), "Expected '1' to NOT almost equal '0.99999999999999' (but it did)!") - fail(t, so(1.3612499999999996, ShouldNotAlmostEqual, 1.36125), "Expected '1.3612499999999996' to NOT almost equal '1.36125' (but it did)!") - pass(t, so(1, ShouldNotAlmostEqual, .99)) - - // with a different delta - fail(t, so(100.0, ShouldNotAlmostEqual, 110.0, 10.0), "Expected '100' to NOT almost equal '110' (but it did)!") - pass(t, so(100.0, ShouldNotAlmostEqual, 111.0, 10.5)) - - // ints should work - fail(t, so(100, ShouldNotAlmostEqual, 100.0), "Expected '100' to NOT almost equal '100' (but it did)!") - pass(t, so(100, ShouldNotAlmostEqual, 99.0)) - - // float32 should work - fail(t, so(float64(100.0), ShouldNotAlmostEqual, float32(100.0)), "Expected '100' to NOT almost equal '100' (but it did)!") - pass(t, so(float32(100.0), ShouldNotAlmostEqual, 99.0, float32(0.1))) -} - -func TestShouldResemble(t *testing.T) { - serializer = newFakeSerializer() - - fail(t, so(Thing1{"hi"}, ShouldResemble), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(Thing1{"hi"}, ShouldResemble, Thing1{"hi"}, Thing1{"hi"}), "This assertion requires exactly 1 comparison values (you provided 2).") - - pass(t, so(Thing1{"hi"}, ShouldResemble, Thing1{"hi"})) - fail(t, so(Thing1{"hi"}, ShouldResemble, Thing1{"bye"}), "{bye}|{hi}|Expected: 'assertions.Thing1{a:\"bye\"}' Actual: 'assertions.Thing1{a:\"hi\"}' (Should resemble)!") - - var ( - a []int - b []int = []int{} - ) - - fail(t, so(a, ShouldResemble, b), "[]|[]|Expected: '[]int{}' Actual: '[]int(nil)' (Should resemble)!") - fail(t, so(2, ShouldResemble, 1), "1|2|Expected: '1' Actual: '2' (Should resemble)!") - - fail(t, so(StringStringMapAlias{"hi": "bye"}, ShouldResemble, map[string]string{"hi": "bye"}), - "map[hi:bye]|map[hi:bye]|Expected: 'map[string]string{\"hi\":\"bye\"}' Actual: 'assertions.StringStringMapAlias{\"hi\":\"bye\"}' (Should resemble)!") - fail(t, so(StringSliceAlias{"hi", "bye"}, ShouldResemble, []string{"hi", "bye"}), - "[hi bye]|[hi bye]|Expected: '[]string{\"hi\", \"bye\"}' Actual: 'assertions.StringSliceAlias{\"hi\", \"bye\"}' (Should resemble)!") - - // some types come out looking the same when represented with "%#v" so we show type mismatch info: - fail(t, so(StringAlias("hi"), ShouldResemble, "hi"), "hi|hi|Expected: '\"hi\"' Actual: '\"hi\"' (Type mismatch: 'string' vs 'assertions.StringAlias')!") - fail(t, so(IntAlias(42), ShouldResemble, 42), "42|42|Expected: '42' Actual: '42' (Type mismatch: 'int' vs 'assertions.IntAlias')!") -} - -func TestShouldNotResemble(t *testing.T) { - fail(t, so(Thing1{"hi"}, ShouldNotResemble), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(Thing1{"hi"}, ShouldNotResemble, Thing1{"hi"}, Thing1{"hi"}), "This assertion requires exactly 1 comparison values (you provided 2).") - - pass(t, so(Thing1{"hi"}, ShouldNotResemble, Thing1{"bye"})) - fail(t, so(Thing1{"hi"}, ShouldNotResemble, Thing1{"hi"}), - "Expected 'assertions.Thing1{a:\"hi\"}' to NOT resemble 'assertions.Thing1{a:\"hi\"}' (but it did)!") - - pass(t, so(map[string]string{"hi": "bye"}, ShouldResemble, map[string]string{"hi": "bye"})) - pass(t, so(IntAlias(42), ShouldNotResemble, 42)) - - pass(t, so(StringSliceAlias{"hi", "bye"}, ShouldNotResemble, []string{"hi", "bye"})) -} - -func TestShouldPointTo(t *testing.T) { - serializer = newFakeSerializer() - - t1 := &Thing1{} - t2 := t1 - t3 := &Thing1{} - - pointer1 := reflect.ValueOf(t1).Pointer() - pointer3 := reflect.ValueOf(t3).Pointer() - - fail(t, so(t1, ShouldPointTo), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(t1, ShouldPointTo, t2, t3), "This assertion requires exactly 1 comparison values (you provided 2).") - - pass(t, so(t1, ShouldPointTo, t2)) - fail(t, so(t1, ShouldPointTo, t3), fmt.Sprintf( - "%v|%v|Expected '&{a:}' (address: '%v') and '&{a:}' (address: '%v') to be the same address (but their weren't)!", - pointer3, pointer1, pointer1, pointer3)) - - t4 := Thing1{} - t5 := t4 - - fail(t, so(t4, ShouldPointTo, t5), "Both arguments should be pointers (the first was not)!") - fail(t, so(&t4, ShouldPointTo, t5), "Both arguments should be pointers (the second was not)!") - fail(t, so(nil, ShouldPointTo, nil), "Both arguments should be pointers (the first was nil)!") - fail(t, so(&t4, ShouldPointTo, nil), "Both arguments should be pointers (the second was nil)!") -} - -func TestShouldNotPointTo(t *testing.T) { - t1 := &Thing1{} - t2 := t1 - t3 := &Thing1{} - - pointer1 := reflect.ValueOf(t1).Pointer() - - fail(t, so(t1, ShouldNotPointTo), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(t1, ShouldNotPointTo, t2, t3), "This assertion requires exactly 1 comparison values (you provided 2).") - - pass(t, so(t1, ShouldNotPointTo, t3)) - fail(t, so(t1, ShouldNotPointTo, t2), fmt.Sprintf("Expected '&{a:}' and '&{a:}' to be different references (but they matched: '%v')!", pointer1)) - - t4 := Thing1{} - t5 := t4 - - fail(t, so(t4, ShouldNotPointTo, t5), "Both arguments should be pointers (the first was not)!") - fail(t, so(&t4, ShouldNotPointTo, t5), "Both arguments should be pointers (the second was not)!") - fail(t, so(nil, ShouldNotPointTo, nil), "Both arguments should be pointers (the first was nil)!") - fail(t, so(&t4, ShouldNotPointTo, nil), "Both arguments should be pointers (the second was nil)!") -} - -func TestShouldBeNil(t *testing.T) { - fail(t, so(nil, ShouldBeNil, nil, nil, nil), "This assertion requires exactly 0 comparison values (you provided 3).") - fail(t, so(nil, ShouldBeNil, nil), "This assertion requires exactly 0 comparison values (you provided 1).") - - pass(t, so(nil, ShouldBeNil)) - fail(t, so(1, ShouldBeNil), "Expected: nil Actual: '1'") - - var thing Thinger - pass(t, so(thing, ShouldBeNil)) - thing = &Thing{} - fail(t, so(thing, ShouldBeNil), "Expected: nil Actual: '&{}'") - - var thingOne *Thing1 - pass(t, so(thingOne, ShouldBeNil)) - - var nilSlice []int = nil - pass(t, so(nilSlice, ShouldBeNil)) - - var nilMap map[string]string = nil - pass(t, so(nilMap, ShouldBeNil)) - - var nilChannel chan int = nil - pass(t, so(nilChannel, ShouldBeNil)) - - var nilFunc func() = nil - pass(t, so(nilFunc, ShouldBeNil)) - - var nilInterface interface{} = nil - pass(t, so(nilInterface, ShouldBeNil)) -} - -func TestShouldNotBeNil(t *testing.T) { - fail(t, so(nil, ShouldNotBeNil, nil, nil, nil), "This assertion requires exactly 0 comparison values (you provided 3).") - fail(t, so(nil, ShouldNotBeNil, nil), "This assertion requires exactly 0 comparison values (you provided 1).") - - fail(t, so(nil, ShouldNotBeNil), "Expected '' to NOT be nil (but it was)!") - pass(t, so(1, ShouldNotBeNil)) - - var thing Thinger - fail(t, so(thing, ShouldNotBeNil), "Expected '' to NOT be nil (but it was)!") - thing = &Thing{} - pass(t, so(thing, ShouldNotBeNil)) -} - -func TestShouldBeTrue(t *testing.T) { - fail(t, so(true, ShouldBeTrue, 1, 2, 3), "This assertion requires exactly 0 comparison values (you provided 3).") - fail(t, so(true, ShouldBeTrue, 1), "This assertion requires exactly 0 comparison values (you provided 1).") - - fail(t, so(false, ShouldBeTrue), "Expected: true Actual: false") - fail(t, so(1, ShouldBeTrue), "Expected: true Actual: 1") - pass(t, so(true, ShouldBeTrue)) -} - -func TestShouldBeFalse(t *testing.T) { - fail(t, so(false, ShouldBeFalse, 1, 2, 3), "This assertion requires exactly 0 comparison values (you provided 3).") - fail(t, so(false, ShouldBeFalse, 1), "This assertion requires exactly 0 comparison values (you provided 1).") - - fail(t, so(true, ShouldBeFalse), "Expected: false Actual: true") - fail(t, so(1, ShouldBeFalse), "Expected: false Actual: 1") - pass(t, so(false, ShouldBeFalse)) -} - -func TestShouldBeZeroValue(t *testing.T) { - serializer = newFakeSerializer() - - fail(t, so(0, ShouldBeZeroValue, 1, 2, 3), "This assertion requires exactly 0 comparison values (you provided 3).") - fail(t, so(false, ShouldBeZeroValue, true), "This assertion requires exactly 0 comparison values (you provided 1).") - - fail(t, so(1, ShouldBeZeroValue), "0|1|'1' should have been the zero value") //"Expected: (zero value) Actual: 1") - fail(t, so(true, ShouldBeZeroValue), "false|true|'true' should have been the zero value") //"Expected: (zero value) Actual: true") - fail(t, so("123", ShouldBeZeroValue), "|123|'123' should have been the zero value") //"Expected: (zero value) Actual: 123") - fail(t, so(" ", ShouldBeZeroValue), "| |' ' should have been the zero value") //"Expected: (zero value) Actual: ") - fail(t, so([]string{"Nonempty"}, ShouldBeZeroValue), "[]|[Nonempty]|'[Nonempty]' should have been the zero value") //"Expected: (zero value) Actual: [Nonempty]") - fail(t, so(struct{ a string }{a: "asdf"}, ShouldBeZeroValue), "{}|{asdf}|'{a:asdf}' should have been the zero value") - pass(t, so(0, ShouldBeZeroValue)) - pass(t, so(false, ShouldBeZeroValue)) - pass(t, so("", ShouldBeZeroValue)) - pass(t, so(struct{}{}, ShouldBeZeroValue)) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/all_of_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/all_of_test.go deleted file mode 100644 index 4655f2e7389..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/all_of_test.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "errors" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type allOfFakeMatcher struct { - desc string - err error -} - -func (m *allOfFakeMatcher) Matches(c interface{}) error { - return m.err -} - -func (m *allOfFakeMatcher) Description() string { - return m.desc -} - -type AllOfTest struct { -} - -func init() { RegisterTestSuite(&AllOfTest{}) } - -//////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////// - -func (t *AllOfTest) DescriptionWithEmptySet() { - m := AllOf() - ExpectEq("is anything", m.Description()) -} - -func (t *AllOfTest) DescriptionWithOneMatcher() { - m := AllOf(&allOfFakeMatcher{"taco", errors.New("")}) - ExpectEq("taco", m.Description()) -} - -func (t *AllOfTest) DescriptionWithMultipleMatchers() { - m := AllOf( - &allOfFakeMatcher{"taco", errors.New("")}, - &allOfFakeMatcher{"burrito", errors.New("")}, - &allOfFakeMatcher{"enchilada", errors.New("")}) - - ExpectEq("taco, and burrito, and enchilada", m.Description()) -} - -func (t *AllOfTest) EmptySet() { - m := AllOf() - err := m.Matches(17) - - ExpectEq(nil, err) -} - -func (t *AllOfTest) OneMatcherReturnsFatalErrorAndSomeOthersFail() { - m := AllOf( - &allOfFakeMatcher{"", errors.New("")}, - &allOfFakeMatcher{"", NewFatalError("taco")}, - &allOfFakeMatcher{"", errors.New("")}, - &allOfFakeMatcher{"", nil}) - - err := m.Matches(17) - - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("taco"))) -} - -func (t *AllOfTest) OneMatcherReturnsNonFatalAndOthersSayTrue() { - m := AllOf( - &allOfFakeMatcher{"", nil}, - &allOfFakeMatcher{"", errors.New("taco")}, - &allOfFakeMatcher{"", nil}) - - err := m.Matches(17) - - ExpectFalse(isFatal(err)) - ExpectThat(err, Error(Equals("taco"))) -} - -func (t *AllOfTest) AllMatchersSayTrue() { - m := AllOf( - &allOfFakeMatcher{"", nil}, - &allOfFakeMatcher{"", nil}, - &allOfFakeMatcher{"", nil}) - - err := m.Matches(17) - - ExpectEq(nil, err) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/any_of_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/any_of_test.go deleted file mode 100644 index b73e101285a..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/any_of_test.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "errors" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type fakeAnyOfMatcher struct { - desc string - err error -} - -func (m *fakeAnyOfMatcher) Matches(c interface{}) error { - return m.err -} - -func (m *fakeAnyOfMatcher) Description() string { - return m.desc -} - -type AnyOfTest struct { -} - -func init() { RegisterTestSuite(&AnyOfTest{}) } - -//////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////// - -func (t *AnyOfTest) EmptySet() { - matcher := AnyOf() - - err := matcher.Matches(0) - ExpectThat(err, Error(Equals(""))) -} - -func (t *AnyOfTest) OneTrue() { - matcher := AnyOf( - &fakeAnyOfMatcher{"", NewFatalError("foo")}, - 17, - &fakeAnyOfMatcher{"", errors.New("foo")}, - &fakeAnyOfMatcher{"", nil}, - &fakeAnyOfMatcher{"", errors.New("foo")}, - ) - - err := matcher.Matches(0) - ExpectEq(nil, err) -} - -func (t *AnyOfTest) OneEqual() { - matcher := AnyOf( - &fakeAnyOfMatcher{"", NewFatalError("foo")}, - &fakeAnyOfMatcher{"", errors.New("foo")}, - 13, - "taco", - 19, - &fakeAnyOfMatcher{"", errors.New("foo")}, - ) - - err := matcher.Matches("taco") - ExpectEq(nil, err) -} - -func (t *AnyOfTest) OneFatal() { - matcher := AnyOf( - &fakeAnyOfMatcher{"", errors.New("foo")}, - 17, - &fakeAnyOfMatcher{"", NewFatalError("taco")}, - &fakeAnyOfMatcher{"", errors.New("foo")}, - ) - - err := matcher.Matches(0) - ExpectThat(err, Error(Equals("taco"))) -} - -func (t *AnyOfTest) AllFalseAndNotEqual() { - matcher := AnyOf( - &fakeAnyOfMatcher{"", errors.New("foo")}, - 17, - &fakeAnyOfMatcher{"", errors.New("foo")}, - 19, - ) - - err := matcher.Matches(0) - ExpectThat(err, Error(Equals(""))) -} - -func (t *AnyOfTest) DescriptionForEmptySet() { - matcher := AnyOf() - ExpectEq("or()", matcher.Description()) -} - -func (t *AnyOfTest) DescriptionForNonEmptySet() { - matcher := AnyOf( - &fakeAnyOfMatcher{"taco", nil}, - "burrito", - &fakeAnyOfMatcher{"enchilada", nil}, - ) - - ExpectEq("or(taco, burrito, enchilada)", matcher.Description()) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/any_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/any_test.go deleted file mode 100644 index e0492b82773..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/any_test.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type AnyTest struct { -} - -func init() { RegisterTestSuite(&AnyTest{}) } - -//////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////// - -func (t *AnyTest) Description() { - m := Any() - ExpectEq("is anything", m.Description()) -} - -func (t *AnyTest) Matches() { - var err error - m := Any() - - err = m.Matches(nil) - ExpectEq(nil, err) - - err = m.Matches(17) - ExpectEq(nil, err) - - err = m.Matches("taco") - ExpectEq(nil, err) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/contains_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/contains_test.go deleted file mode 100644 index c61cd886c6c..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/contains_test.go +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type ContainsTest struct{} - -func init() { RegisterTestSuite(&ContainsTest{}) } - -//////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////// - -func (t *ContainsTest) WrongTypeCandidates() { - m := Contains("") - ExpectEq("contains: ", m.Description()) - - var err error - - // Nil candidate - err = m.Matches(nil) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("array"))) - ExpectThat(err, Error(HasSubstr("slice"))) - - // String candidate - err = m.Matches("") - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("array"))) - ExpectThat(err, Error(HasSubstr("slice"))) - - // Map candidate - err = m.Matches(make(map[string]string)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("array"))) - ExpectThat(err, Error(HasSubstr("slice"))) -} - -func (t *ContainsTest) NilArgument() { - m := Contains(nil) - ExpectEq("contains: is nil", m.Description()) - - var c interface{} - var err error - - // Empty array of pointers - c = [...]*int{} - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) - - // Empty slice of pointers - c = []*int{} - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) - - // Non-empty array of integers - c = [...]int{17, 0, 19} - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) - - // Non-empty slice of integers - c = []int{17, 0, 19} - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) - - // Non-matching array of pointers - c = [...]*int{new(int), new(int)} - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) - - // Non-matching slice of pointers - c = []*int{new(int), new(int)} - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) - - // Matching array of pointers - c = [...]*int{new(int), nil, new(int)} - err = m.Matches(c) - ExpectEq(nil, err) - - // Matching slice of pointers - c = []*int{new(int), nil, new(int)} - err = m.Matches(c) - ExpectEq(nil, err) - - // Non-matching slice of pointers from matching array - someArray := [...]*int{new(int), nil, new(int)} - c = someArray[0:1] - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) -} - -func (t *ContainsTest) StringArgument() { - m := Contains("taco") - ExpectEq("contains: taco", m.Description()) - - var c interface{} - var err error - - // Non-matching array of strings - c = [...]string{"burrito", "enchilada"} - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) - - // Non-matching slice of strings - c = []string{"burrito", "enchilada"} - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) - - // Matching array of strings - c = [...]string{"burrito", "taco", "enchilada"} - err = m.Matches(c) - ExpectEq(nil, err) - - // Matching slice of strings - c = []string{"burrito", "taco", "enchilada"} - err = m.Matches(c) - ExpectEq(nil, err) - - // Non-matching slice of strings from matching array - someArray := [...]string{"burrito", "taco", "enchilada"} - c = someArray[0:1] - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) -} - -func (t *ContainsTest) IntegerArgument() { - m := Contains(int(17)) - ExpectEq("contains: 17", m.Description()) - - var c interface{} - var err error - - // Non-matching array of integers - c = [...]int{13, 19} - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) - - // Non-matching slice of integers - c = []int{13, 19} - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) - - // Matching array of integers - c = [...]int{13, 17, 19} - err = m.Matches(c) - ExpectEq(nil, err) - - // Matching slice of integers - c = []int{13, 17, 19} - err = m.Matches(c) - ExpectEq(nil, err) - - // Non-matching slice of integers from matching array - someArray := [...]int{13, 17, 19} - c = someArray[0:1] - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) - - // Non-matching array of floats - c = [...]float32{13, 17.5, 19} - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) - - // Non-matching slice of floats - c = []float32{13, 17.5, 19} - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) - - // Matching array of floats - c = [...]float32{13, 17, 19} - err = m.Matches(c) - ExpectEq(nil, err) - - // Matching slice of floats - c = []float32{13, 17, 19} - err = m.Matches(c) - ExpectEq(nil, err) -} - -func (t *ContainsTest) MatcherArgument() { - m := Contains(HasSubstr("ac")) - ExpectEq("contains: has substring \"ac\"", m.Description()) - - var c interface{} - var err error - - // Non-matching array of strings - c = [...]string{"burrito", "enchilada"} - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) - - // Non-matching slice of strings - c = []string{"burrito", "enchilada"} - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) - - // Matching array of strings - c = [...]string{"burrito", "taco", "enchilada"} - err = m.Matches(c) - ExpectEq(nil, err) - - // Matching slice of strings - c = []string{"burrito", "taco", "enchilada"} - err = m.Matches(c) - ExpectEq(nil, err) - - // Non-matching slice of strings from matching array - someArray := [...]string{"burrito", "taco", "enchilada"} - c = someArray[0:1] - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/deep_equals_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/deep_equals_test.go deleted file mode 100644 index 640bb0e19d1..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/deep_equals_test.go +++ /dev/null @@ -1,344 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "bytes" - "testing" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type DeepEqualsTest struct{} - -func init() { RegisterTestSuite(&DeepEqualsTest{}) } - -//////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////// - -func (t *DeepEqualsTest) WrongTypeCandidateWithScalarValue() { - var x int = 17 - m := DeepEquals(x) - - var err error - - // Nil candidate. - err = m.Matches(nil) - AssertNe(nil, err) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("type"))) - ExpectThat(err, Error(HasSubstr(""))) - - // Int alias candidate. - type intAlias int - err = m.Matches(intAlias(x)) - AssertNe(nil, err) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("type"))) - ExpectThat(err, Error(HasSubstr("intAlias"))) - - // String candidate. - err = m.Matches("taco") - AssertNe(nil, err) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("type"))) - ExpectThat(err, Error(HasSubstr("string"))) - - // Byte slice candidate. - err = m.Matches([]byte{}) - AssertNe(nil, err) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("type"))) - ExpectThat(err, Error(HasSubstr("[]uint8"))) - - // Other slice candidate. - err = m.Matches([]uint16{}) - AssertNe(nil, err) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("type"))) - ExpectThat(err, Error(HasSubstr("[]uint16"))) - - // Unsigned int candidate. - err = m.Matches(uint(17)) - AssertNe(nil, err) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("type"))) - ExpectThat(err, Error(HasSubstr("uint"))) -} - -func (t *DeepEqualsTest) WrongTypeCandidateWithByteSliceValue() { - x := []byte{} - m := DeepEquals(x) - - var err error - - // Nil candidate. - err = m.Matches(nil) - AssertNe(nil, err) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("type"))) - ExpectThat(err, Error(HasSubstr(""))) - - // String candidate. - err = m.Matches("taco") - AssertNe(nil, err) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("type"))) - ExpectThat(err, Error(HasSubstr("string"))) - - // Slice candidate with wrong value type. - err = m.Matches([]uint16{}) - AssertNe(nil, err) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("type"))) - ExpectThat(err, Error(HasSubstr("[]uint16"))) -} - -func (t *DeepEqualsTest) WrongTypeCandidateWithOtherSliceValue() { - x := []uint16{} - m := DeepEquals(x) - - var err error - - // Nil candidate. - err = m.Matches(nil) - AssertNe(nil, err) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("type"))) - ExpectThat(err, Error(HasSubstr(""))) - - // String candidate. - err = m.Matches("taco") - AssertNe(nil, err) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("type"))) - ExpectThat(err, Error(HasSubstr("string"))) - - // Byte slice candidate with wrong value type. - err = m.Matches([]byte{}) - AssertNe(nil, err) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("type"))) - ExpectThat(err, Error(HasSubstr("[]uint8"))) - - // Other slice candidate with wrong value type. - err = m.Matches([]uint32{}) - AssertNe(nil, err) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("type"))) - ExpectThat(err, Error(HasSubstr("[]uint32"))) -} - -func (t *DeepEqualsTest) WrongTypeCandidateWithNilLiteralValue() { - m := DeepEquals(nil) - - var err error - - // String candidate. - err = m.Matches("taco") - AssertNe(nil, err) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("type"))) - ExpectThat(err, Error(HasSubstr("string"))) - - // Nil byte slice candidate. - err = m.Matches([]byte(nil)) - AssertNe(nil, err) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("type"))) - ExpectThat(err, Error(HasSubstr("[]uint8"))) - - // Nil other slice candidate. - err = m.Matches([]uint16(nil)) - AssertNe(nil, err) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("type"))) - ExpectThat(err, Error(HasSubstr("[]uint16"))) -} - -func (t *DeepEqualsTest) NilLiteralValue() { - m := DeepEquals(nil) - ExpectEq("deep equals: ", m.Description()) - - var c interface{} - var err error - - // Nil literal candidate. - c = nil - err = m.Matches(c) - ExpectEq(nil, err) -} - -func (t *DeepEqualsTest) IntValue() { - m := DeepEquals(int(17)) - ExpectEq("deep equals: 17", m.Description()) - - var c interface{} - var err error - - // Matching int. - c = int(17) - err = m.Matches(c) - ExpectEq(nil, err) - - // Non-matching int. - c = int(18) - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) -} - -func (t *DeepEqualsTest) ByteSliceValue() { - x := []byte{17, 19} - m := DeepEquals(x) - ExpectEq("deep equals: [17 19]", m.Description()) - - var c []byte - var err error - - // Matching. - c = make([]byte, len(x)) - AssertEq(len(x), copy(c, x)) - - err = m.Matches(c) - ExpectEq(nil, err) - - // Nil slice. - c = []byte(nil) - err = m.Matches(c) - ExpectThat(err, Error(Equals("which is nil"))) - - // Prefix. - AssertGt(len(x), 1) - c = make([]byte, len(x)-1) - AssertEq(len(x)-1, copy(c, x)) - - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) - - // Suffix. - c = make([]byte, len(x)+1) - AssertEq(len(x), copy(c, x)) - - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) -} - -func (t *DeepEqualsTest) OtherSliceValue() { - x := []uint16{17, 19} - m := DeepEquals(x) - ExpectEq("deep equals: [17 19]", m.Description()) - - var c []uint16 - var err error - - // Matching. - c = make([]uint16, len(x)) - AssertEq(len(x), copy(c, x)) - - err = m.Matches(c) - ExpectEq(nil, err) - - // Nil slice. - c = []uint16(nil) - err = m.Matches(c) - ExpectThat(err, Error(Equals("which is nil"))) - - // Prefix. - AssertGt(len(x), 1) - c = make([]uint16, len(x)-1) - AssertEq(len(x)-1, copy(c, x)) - - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) - - // Suffix. - c = make([]uint16, len(x)+1) - AssertEq(len(x), copy(c, x)) - - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) -} - -func (t *DeepEqualsTest) NilByteSliceValue() { - x := []byte(nil) - m := DeepEquals(x) - ExpectEq("deep equals: ", m.Description()) - - var c []byte - var err error - - // Nil slice. - c = []byte(nil) - err = m.Matches(c) - ExpectEq(nil, err) - - // Non-nil slice. - c = []byte{} - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) -} - -func (t *DeepEqualsTest) NilOtherSliceValue() { - x := []uint16(nil) - m := DeepEquals(x) - ExpectEq("deep equals: ", m.Description()) - - var c []uint16 - var err error - - // Nil slice. - c = []uint16(nil) - err = m.Matches(c) - ExpectEq(nil, err) - - // Non-nil slice. - c = []uint16{} - err = m.Matches(c) - ExpectThat(err, Error(Equals(""))) -} - -//////////////////////////////////////////////////////////////////////// -// Benchmarks -//////////////////////////////////////////////////////////////////////// - -func benchmarkWithSize(b *testing.B, size int) { - b.StopTimer() - buf := bytes.Repeat([]byte{0x01}, size) - bufCopy := make([]byte, size) - copy(bufCopy, buf) - - matcher := DeepEquals(buf) - b.StartTimer() - - for i := 0; i < b.N; i++ { - matcher.Matches(bufCopy) - } - - b.SetBytes(int64(size)) -} - -func BenchmarkShortByteSlice(b *testing.B) { - benchmarkWithSize(b, 256) -} - -func BenchmarkLongByteSlice(b *testing.B) { - benchmarkWithSize(b, 1<<24) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/elements_are_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/elements_are_test.go deleted file mode 100644 index cfc645489cd..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/elements_are_test.go +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type ElementsAreTest struct { -} - -func init() { RegisterTestSuite(&ElementsAreTest{}) } - -//////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////// - -func (t *ElementsAreTest) EmptySet() { - m := ElementsAre() - ExpectEq("elements are: []", m.Description()) - - var c []interface{} - var err error - - // No candidates. - c = []interface{}{} - err = m.Matches(c) - ExpectEq(nil, err) - - // One candidate. - c = []interface{}{17} - err = m.Matches(c) - ExpectThat(err, Error(HasSubstr("length 1"))) -} - -func (t *ElementsAreTest) OneMatcher() { - m := ElementsAre(LessThan(17)) - ExpectEq("elements are: [less than 17]", m.Description()) - - var c []interface{} - var err error - - // No candidates. - c = []interface{}{} - err = m.Matches(c) - ExpectThat(err, Error(HasSubstr("length 0"))) - - // Matching candidate. - c = []interface{}{16} - err = m.Matches(c) - ExpectEq(nil, err) - - // Non-matching candidate. - c = []interface{}{19} - err = m.Matches(c) - ExpectNe(nil, err) - - // Two candidates. - c = []interface{}{17, 19} - err = m.Matches(c) - ExpectThat(err, Error(HasSubstr("length 2"))) -} - -func (t *ElementsAreTest) OneValue() { - m := ElementsAre(17) - ExpectEq("elements are: [17]", m.Description()) - - var c []interface{} - var err error - - // No candidates. - c = []interface{}{} - err = m.Matches(c) - ExpectThat(err, Error(HasSubstr("length 0"))) - - // Matching int. - c = []interface{}{int(17)} - err = m.Matches(c) - ExpectEq(nil, err) - - // Matching float. - c = []interface{}{float32(17)} - err = m.Matches(c) - ExpectEq(nil, err) - - // Non-matching candidate. - c = []interface{}{19} - err = m.Matches(c) - ExpectNe(nil, err) - - // Two candidates. - c = []interface{}{17, 19} - err = m.Matches(c) - ExpectThat(err, Error(HasSubstr("length 2"))) -} - -func (t *ElementsAreTest) MultipleElements() { - m := ElementsAre("taco", LessThan(17)) - ExpectEq("elements are: [taco, less than 17]", m.Description()) - - var c []interface{} - var err error - - // One candidate. - c = []interface{}{17} - err = m.Matches(c) - ExpectThat(err, Error(HasSubstr("length 1"))) - - // Both matching. - c = []interface{}{"taco", 16} - err = m.Matches(c) - ExpectEq(nil, err) - - // First non-matching. - c = []interface{}{"burrito", 16} - err = m.Matches(c) - ExpectThat(err, Error(Equals("whose element 0 doesn't match"))) - - // Second non-matching. - c = []interface{}{"taco", 17} - err = m.Matches(c) - ExpectThat(err, Error(Equals("whose element 1 doesn't match"))) - - // Three candidates. - c = []interface{}{"taco", 17, 19} - err = m.Matches(c) - ExpectThat(err, Error(HasSubstr("length 3"))) -} - -func (t *ElementsAreTest) ArrayCandidates() { - m := ElementsAre("taco", LessThan(17)) - - var err error - - // One candidate. - err = m.Matches([1]interface{}{"taco"}) - ExpectThat(err, Error(HasSubstr("length 1"))) - - // Both matching. - err = m.Matches([2]interface{}{"taco", 16}) - ExpectEq(nil, err) - - // First non-matching. - err = m.Matches([2]interface{}{"burrito", 16}) - ExpectThat(err, Error(Equals("whose element 0 doesn't match"))) -} - -func (t *ElementsAreTest) WrongTypeCandidate() { - m := ElementsAre("taco") - - var err error - - // String candidate. - err = m.Matches("taco") - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("array"))) - ExpectThat(err, Error(HasSubstr("slice"))) - - // Map candidate. - err = m.Matches(map[string]string{}) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("array"))) - ExpectThat(err, Error(HasSubstr("slice"))) - - // Nil candidate. - err = m.Matches(nil) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("array"))) - ExpectThat(err, Error(HasSubstr("slice"))) -} - -func (t *ElementsAreTest) PropagatesFatality() { - m := ElementsAre(LessThan(17)) - ExpectEq("elements are: [less than 17]", m.Description()) - - var c []interface{} - var err error - - // Non-fatal error. - c = []interface{}{19} - err = m.Matches(c) - AssertNe(nil, err) - ExpectFalse(isFatal(err)) - - // Fatal error. - c = []interface{}{"taco"} - err = m.Matches(c) - AssertNe(nil, err) - ExpectTrue(isFatal(err)) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/equals_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/equals_test.go deleted file mode 100644 index 1b2b66ec57d..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/equals_test.go +++ /dev/null @@ -1,3785 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "fmt" - "math" - "unsafe" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -var someInt int = -17 - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type EqualsTest struct { -} - -func init() { RegisterTestSuite(&EqualsTest{}) } - -type equalsTestCase struct { - candidate interface{} - expectedResult bool - shouldBeFatal bool - expectedError string -} - -func (t *EqualsTest) checkTestCases(matcher Matcher, cases []equalsTestCase) { - for i, c := range cases { - err := matcher.Matches(c.candidate) - ExpectEq(c.expectedResult, (err == nil), "Result for case %d: %v", i, c) - - if err == nil { - continue - } - - _, isFatal := err.(*FatalError) - ExpectEq(c.shouldBeFatal, isFatal, "Fatality for case %d: %v", i, c) - - ExpectThat(err, Error(Equals(c.expectedError)), "Case %d: %v", i, c) - } -} - -//////////////////////////////////////////////////////////////////////// -// nil -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) EqualsNil() { - matcher := Equals(nil) - ExpectEq("is nil", matcher.Description()) - - cases := []equalsTestCase{ - // Legal types - equalsTestCase{nil, true, false, ""}, - equalsTestCase{chan int(nil), true, false, ""}, - equalsTestCase{(func())(nil), true, false, ""}, - equalsTestCase{interface{}(nil), true, false, ""}, - equalsTestCase{map[int]int(nil), true, false, ""}, - equalsTestCase{(*int)(nil), true, false, ""}, - equalsTestCase{[]int(nil), true, false, ""}, - - equalsTestCase{make(chan int), false, false, ""}, - equalsTestCase{func() {}, false, false, ""}, - equalsTestCase{map[int]int{}, false, false, ""}, - equalsTestCase{&someInt, false, false, ""}, - equalsTestCase{[]int{}, false, false, ""}, - - // Illegal types - equalsTestCase{17, false, true, "which cannot be compared to nil"}, - equalsTestCase{int8(17), false, true, "which cannot be compared to nil"}, - equalsTestCase{uintptr(17), false, true, "which cannot be compared to nil"}, - equalsTestCase{[...]int{}, false, true, "which cannot be compared to nil"}, - equalsTestCase{"taco", false, true, "which cannot be compared to nil"}, - equalsTestCase{equalsTestCase{}, false, true, "which cannot be compared to nil"}, - equalsTestCase{unsafe.Pointer(&someInt), false, true, "which cannot be compared to nil"}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// Integer literals -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) NegativeIntegerLiteral() { - // -2^30 - matcher := Equals(-1073741824) - ExpectEq("-1073741824", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of -1073741824. - equalsTestCase{-1073741824, true, false, ""}, - equalsTestCase{-1073741824.0, true, false, ""}, - equalsTestCase{-1073741824 + 0i, true, false, ""}, - equalsTestCase{int(-1073741824), true, false, ""}, - equalsTestCase{int32(-1073741824), true, false, ""}, - equalsTestCase{int64(-1073741824), true, false, ""}, - equalsTestCase{float32(-1073741824), true, false, ""}, - equalsTestCase{float64(-1073741824), true, false, ""}, - equalsTestCase{complex64(-1073741824), true, false, ""}, - equalsTestCase{complex128(-1073741824), true, false, ""}, - equalsTestCase{interface{}(int(-1073741824)), true, false, ""}, - - // Values that would be -1073741824 in two's complement. - equalsTestCase{uint((1 << 32) - 1073741824), false, false, ""}, - equalsTestCase{uint32((1 << 32) - 1073741824), false, false, ""}, - equalsTestCase{uint64((1 << 64) - 1073741824), false, false, ""}, - - // Non-equal values of signed integer type. - equalsTestCase{int(-1073741823), false, false, ""}, - equalsTestCase{int32(-1073741823), false, false, ""}, - equalsTestCase{int64(-1073741823), false, false, ""}, - - // Non-equal values of other numeric types. - equalsTestCase{float64(-1073741824.1), false, false, ""}, - equalsTestCase{float64(-1073741823.9), false, false, ""}, - equalsTestCase{complex128(-1073741823), false, false, ""}, - equalsTestCase{complex128(-1073741824 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) PositiveIntegerLiteral() { - // 2^30 - matcher := Equals(1073741824) - ExpectEq("1073741824", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of 1073741824. - equalsTestCase{1073741824, true, false, ""}, - equalsTestCase{1073741824.0, true, false, ""}, - equalsTestCase{1073741824 + 0i, true, false, ""}, - equalsTestCase{int(1073741824), true, false, ""}, - equalsTestCase{uint(1073741824), true, false, ""}, - equalsTestCase{int32(1073741824), true, false, ""}, - equalsTestCase{int64(1073741824), true, false, ""}, - equalsTestCase{uint32(1073741824), true, false, ""}, - equalsTestCase{uint64(1073741824), true, false, ""}, - equalsTestCase{float32(1073741824), true, false, ""}, - equalsTestCase{float64(1073741824), true, false, ""}, - equalsTestCase{complex64(1073741824), true, false, ""}, - equalsTestCase{complex128(1073741824), true, false, ""}, - equalsTestCase{interface{}(int(1073741824)), true, false, ""}, - equalsTestCase{interface{}(uint(1073741824)), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int(1073741823), false, false, ""}, - equalsTestCase{int32(1073741823), false, false, ""}, - equalsTestCase{int64(1073741823), false, false, ""}, - equalsTestCase{float64(1073741824.1), false, false, ""}, - equalsTestCase{float64(1073741823.9), false, false, ""}, - equalsTestCase{complex128(1073741823), false, false, ""}, - equalsTestCase{complex128(1073741824 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// Floating point literals -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) NegativeIntegralFloatingPointLiteral() { - // -2^30 - matcher := Equals(-1073741824.0) - ExpectEq("-1.073741824e+09", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of -1073741824. - equalsTestCase{-1073741824, true, false, ""}, - equalsTestCase{-1073741824.0, true, false, ""}, - equalsTestCase{-1073741824 + 0i, true, false, ""}, - equalsTestCase{int(-1073741824), true, false, ""}, - equalsTestCase{int32(-1073741824), true, false, ""}, - equalsTestCase{int64(-1073741824), true, false, ""}, - equalsTestCase{float32(-1073741824), true, false, ""}, - equalsTestCase{float64(-1073741824), true, false, ""}, - equalsTestCase{complex64(-1073741824), true, false, ""}, - equalsTestCase{complex128(-1073741824), true, false, ""}, - equalsTestCase{interface{}(int(-1073741824)), true, false, ""}, - equalsTestCase{interface{}(float64(-1073741824)), true, false, ""}, - - // Values that would be -1073741824 in two's complement. - equalsTestCase{uint((1 << 32) - 1073741824), false, false, ""}, - equalsTestCase{uint32((1 << 32) - 1073741824), false, false, ""}, - equalsTestCase{uint64((1 << 64) - 1073741824), false, false, ""}, - - // Non-equal values of signed integer type. - equalsTestCase{int(-1073741823), false, false, ""}, - equalsTestCase{int32(-1073741823), false, false, ""}, - equalsTestCase{int64(-1073741823), false, false, ""}, - - // Non-equal values of other numeric types. - equalsTestCase{float64(-1073741824.1), false, false, ""}, - equalsTestCase{float64(-1073741823.9), false, false, ""}, - equalsTestCase{complex128(-1073741823), false, false, ""}, - equalsTestCase{complex128(-1073741824 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) PositiveIntegralFloatingPointLiteral() { - // 2^30 - matcher := Equals(1073741824.0) - ExpectEq("1.073741824e+09", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of 1073741824. - equalsTestCase{1073741824, true, false, ""}, - equalsTestCase{1073741824.0, true, false, ""}, - equalsTestCase{1073741824 + 0i, true, false, ""}, - equalsTestCase{int(1073741824), true, false, ""}, - equalsTestCase{int32(1073741824), true, false, ""}, - equalsTestCase{int64(1073741824), true, false, ""}, - equalsTestCase{uint(1073741824), true, false, ""}, - equalsTestCase{uint32(1073741824), true, false, ""}, - equalsTestCase{uint64(1073741824), true, false, ""}, - equalsTestCase{float32(1073741824), true, false, ""}, - equalsTestCase{float64(1073741824), true, false, ""}, - equalsTestCase{complex64(1073741824), true, false, ""}, - equalsTestCase{complex128(1073741824), true, false, ""}, - equalsTestCase{interface{}(int(1073741824)), true, false, ""}, - equalsTestCase{interface{}(float64(1073741824)), true, false, ""}, - - // Values that would be 1073741824 in two's complement. - equalsTestCase{uint((1 << 32) - 1073741824), false, false, ""}, - equalsTestCase{uint32((1 << 32) - 1073741824), false, false, ""}, - equalsTestCase{uint64((1 << 64) - 1073741824), false, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int(1073741823), false, false, ""}, - equalsTestCase{int32(1073741823), false, false, ""}, - equalsTestCase{int64(1073741823), false, false, ""}, - equalsTestCase{uint(1073741823), false, false, ""}, - equalsTestCase{uint32(1073741823), false, false, ""}, - equalsTestCase{uint64(1073741823), false, false, ""}, - equalsTestCase{float64(1073741824.1), false, false, ""}, - equalsTestCase{float64(1073741823.9), false, false, ""}, - equalsTestCase{complex128(1073741823), false, false, ""}, - equalsTestCase{complex128(1073741824 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) NonIntegralFloatingPointLiteral() { - matcher := Equals(17.1) - ExpectEq("17.1", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of 17.1. - equalsTestCase{17.1, true, false, ""}, - equalsTestCase{17.1, true, false, ""}, - equalsTestCase{17.1 + 0i, true, false, ""}, - equalsTestCase{float32(17.1), true, false, ""}, - equalsTestCase{float64(17.1), true, false, ""}, - equalsTestCase{complex64(17.1), true, false, ""}, - equalsTestCase{complex128(17.1), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{17, false, false, ""}, - equalsTestCase{17.2, false, false, ""}, - equalsTestCase{18, false, false, ""}, - equalsTestCase{int(17), false, false, ""}, - equalsTestCase{int(18), false, false, ""}, - equalsTestCase{int32(17), false, false, ""}, - equalsTestCase{int64(17), false, false, ""}, - equalsTestCase{uint(17), false, false, ""}, - equalsTestCase{uint32(17), false, false, ""}, - equalsTestCase{uint64(17), false, false, ""}, - equalsTestCase{complex128(17.1 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// bool -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) False() { - matcher := Equals(false) - ExpectEq("false", matcher.Description()) - - cases := []equalsTestCase{ - // bools - equalsTestCase{false, true, false, ""}, - equalsTestCase{bool(false), true, false, ""}, - - equalsTestCase{true, false, false, ""}, - equalsTestCase{bool(true), false, false, ""}, - - // Other types. - equalsTestCase{int(0), false, true, "which is not a bool"}, - equalsTestCase{int8(0), false, true, "which is not a bool"}, - equalsTestCase{int16(0), false, true, "which is not a bool"}, - equalsTestCase{int32(0), false, true, "which is not a bool"}, - equalsTestCase{int64(0), false, true, "which is not a bool"}, - equalsTestCase{uint(0), false, true, "which is not a bool"}, - equalsTestCase{uint8(0), false, true, "which is not a bool"}, - equalsTestCase{uint16(0), false, true, "which is not a bool"}, - equalsTestCase{uint32(0), false, true, "which is not a bool"}, - equalsTestCase{uint64(0), false, true, "which is not a bool"}, - equalsTestCase{uintptr(0), false, true, "which is not a bool"}, - equalsTestCase{[...]int{}, false, true, "which is not a bool"}, - equalsTestCase{make(chan int), false, true, "which is not a bool"}, - equalsTestCase{func() {}, false, true, "which is not a bool"}, - equalsTestCase{map[int]int{}, false, true, "which is not a bool"}, - equalsTestCase{&someInt, false, true, "which is not a bool"}, - equalsTestCase{[]int{}, false, true, "which is not a bool"}, - equalsTestCase{"taco", false, true, "which is not a bool"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not a bool"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) True() { - matcher := Equals(true) - ExpectEq("true", matcher.Description()) - - cases := []equalsTestCase{ - // bools - equalsTestCase{true, true, false, ""}, - equalsTestCase{bool(true), true, false, ""}, - - equalsTestCase{false, false, false, ""}, - equalsTestCase{bool(false), false, false, ""}, - - // Other types. - equalsTestCase{int(1), false, true, "which is not a bool"}, - equalsTestCase{int8(1), false, true, "which is not a bool"}, - equalsTestCase{int16(1), false, true, "which is not a bool"}, - equalsTestCase{int32(1), false, true, "which is not a bool"}, - equalsTestCase{int64(1), false, true, "which is not a bool"}, - equalsTestCase{uint(1), false, true, "which is not a bool"}, - equalsTestCase{uint8(1), false, true, "which is not a bool"}, - equalsTestCase{uint16(1), false, true, "which is not a bool"}, - equalsTestCase{uint32(1), false, true, "which is not a bool"}, - equalsTestCase{uint64(1), false, true, "which is not a bool"}, - equalsTestCase{uintptr(1), false, true, "which is not a bool"}, - equalsTestCase{[...]int{}, false, true, "which is not a bool"}, - equalsTestCase{make(chan int), false, true, "which is not a bool"}, - equalsTestCase{func() {}, false, true, "which is not a bool"}, - equalsTestCase{map[int]int{}, false, true, "which is not a bool"}, - equalsTestCase{&someInt, false, true, "which is not a bool"}, - equalsTestCase{[]int{}, false, true, "which is not a bool"}, - equalsTestCase{"taco", false, true, "which is not a bool"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not a bool"}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// int -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) NegativeInt() { - // -2^30 - matcher := Equals(int(-1073741824)) - ExpectEq("-1073741824", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of -1073741824. - equalsTestCase{-1073741824, true, false, ""}, - equalsTestCase{-1073741824.0, true, false, ""}, - equalsTestCase{-1073741824 + 0i, true, false, ""}, - equalsTestCase{int(-1073741824), true, false, ""}, - equalsTestCase{int32(-1073741824), true, false, ""}, - equalsTestCase{int64(-1073741824), true, false, ""}, - equalsTestCase{float32(-1073741824), true, false, ""}, - equalsTestCase{float64(-1073741824), true, false, ""}, - equalsTestCase{complex64(-1073741824), true, false, ""}, - equalsTestCase{complex128(-1073741824), true, false, ""}, - equalsTestCase{interface{}(int(-1073741824)), true, false, ""}, - - // Values that would be -1073741824 in two's complement. - equalsTestCase{uint((1 << 32) - 1073741824), false, false, ""}, - equalsTestCase{uint32((1 << 32) - 1073741824), false, false, ""}, - equalsTestCase{uint64((1 << 64) - 1073741824), false, false, ""}, - - // Non-equal values of signed integer type. - equalsTestCase{int(-1073741823), false, false, ""}, - equalsTestCase{int32(-1073741823), false, false, ""}, - equalsTestCase{int64(-1073741823), false, false, ""}, - - // Non-equal values of other numeric types. - equalsTestCase{float64(-1073741824.1), false, false, ""}, - equalsTestCase{float64(-1073741823.9), false, false, ""}, - equalsTestCase{complex128(-1073741823), false, false, ""}, - equalsTestCase{complex128(-1073741824 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) PositiveInt() { - // 2^30 - matcher := Equals(int(1073741824)) - ExpectEq("1073741824", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of 1073741824. - equalsTestCase{1073741824, true, false, ""}, - equalsTestCase{1073741824.0, true, false, ""}, - equalsTestCase{1073741824 + 0i, true, false, ""}, - equalsTestCase{int(1073741824), true, false, ""}, - equalsTestCase{uint(1073741824), true, false, ""}, - equalsTestCase{int32(1073741824), true, false, ""}, - equalsTestCase{int64(1073741824), true, false, ""}, - equalsTestCase{uint32(1073741824), true, false, ""}, - equalsTestCase{uint64(1073741824), true, false, ""}, - equalsTestCase{float32(1073741824), true, false, ""}, - equalsTestCase{float64(1073741824), true, false, ""}, - equalsTestCase{complex64(1073741824), true, false, ""}, - equalsTestCase{complex128(1073741824), true, false, ""}, - equalsTestCase{interface{}(int(1073741824)), true, false, ""}, - equalsTestCase{interface{}(uint(1073741824)), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int(1073741823), false, false, ""}, - equalsTestCase{int32(1073741823), false, false, ""}, - equalsTestCase{int64(1073741823), false, false, ""}, - equalsTestCase{float64(1073741824.1), false, false, ""}, - equalsTestCase{float64(1073741823.9), false, false, ""}, - equalsTestCase{complex128(1073741823), false, false, ""}, - equalsTestCase{complex128(1073741824 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// int8 -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) NegativeInt8() { - matcher := Equals(int8(-17)) - ExpectEq("-17", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of -17. - equalsTestCase{-17, true, false, ""}, - equalsTestCase{-17.0, true, false, ""}, - equalsTestCase{-17 + 0i, true, false, ""}, - equalsTestCase{int(-17), true, false, ""}, - equalsTestCase{int8(-17), true, false, ""}, - equalsTestCase{int16(-17), true, false, ""}, - equalsTestCase{int32(-17), true, false, ""}, - equalsTestCase{int64(-17), true, false, ""}, - equalsTestCase{float32(-17), true, false, ""}, - equalsTestCase{float64(-17), true, false, ""}, - equalsTestCase{complex64(-17), true, false, ""}, - equalsTestCase{complex128(-17), true, false, ""}, - equalsTestCase{interface{}(int(-17)), true, false, ""}, - - // Values that would be -17 in two's complement. - equalsTestCase{uint((1 << 32) - 17), false, false, ""}, - equalsTestCase{uint8((1 << 8) - 17), false, false, ""}, - equalsTestCase{uint16((1 << 16) - 17), false, false, ""}, - equalsTestCase{uint32((1 << 32) - 17), false, false, ""}, - equalsTestCase{uint64((1 << 64) - 17), false, false, ""}, - - // Non-equal values of signed integer type. - equalsTestCase{int(-16), false, false, ""}, - equalsTestCase{int8(-16), false, false, ""}, - equalsTestCase{int16(-16), false, false, ""}, - equalsTestCase{int32(-16), false, false, ""}, - equalsTestCase{int64(-16), false, false, ""}, - - // Non-equal values of other numeric types. - equalsTestCase{float32(-17.1), false, false, ""}, - equalsTestCase{float32(-16.9), false, false, ""}, - equalsTestCase{complex64(-16), false, false, ""}, - equalsTestCase{complex64(-17 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr((1 << 32) - 17), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{-17}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{-17}, false, true, "which is not numeric"}, - equalsTestCase{"-17", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) ZeroInt8() { - matcher := Equals(int8(0)) - ExpectEq("0", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of 0. - equalsTestCase{0, true, false, ""}, - equalsTestCase{0.0, true, false, ""}, - equalsTestCase{0 + 0i, true, false, ""}, - equalsTestCase{int(0), true, false, ""}, - equalsTestCase{int8(0), true, false, ""}, - equalsTestCase{int16(0), true, false, ""}, - equalsTestCase{int32(0), true, false, ""}, - equalsTestCase{int64(0), true, false, ""}, - equalsTestCase{float32(0), true, false, ""}, - equalsTestCase{float64(0), true, false, ""}, - equalsTestCase{complex64(0), true, false, ""}, - equalsTestCase{complex128(0), true, false, ""}, - equalsTestCase{interface{}(int(0)), true, false, ""}, - equalsTestCase{uint(0), true, false, ""}, - equalsTestCase{uint8(0), true, false, ""}, - equalsTestCase{uint16(0), true, false, ""}, - equalsTestCase{uint32(0), true, false, ""}, - equalsTestCase{uint64(0), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int(1), false, false, ""}, - equalsTestCase{int8(1), false, false, ""}, - equalsTestCase{int16(1), false, false, ""}, - equalsTestCase{int32(1), false, false, ""}, - equalsTestCase{int64(1), false, false, ""}, - equalsTestCase{float32(-0.1), false, false, ""}, - equalsTestCase{float32(0.1), false, false, ""}, - equalsTestCase{complex64(1), false, false, ""}, - equalsTestCase{complex64(0 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{0}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{0}, false, true, "which is not numeric"}, - equalsTestCase{"0", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) PositiveInt8() { - matcher := Equals(int8(17)) - ExpectEq("17", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of 17. - equalsTestCase{17, true, false, ""}, - equalsTestCase{17.0, true, false, ""}, - equalsTestCase{17 + 0i, true, false, ""}, - equalsTestCase{int(17), true, false, ""}, - equalsTestCase{int8(17), true, false, ""}, - equalsTestCase{int16(17), true, false, ""}, - equalsTestCase{int32(17), true, false, ""}, - equalsTestCase{int64(17), true, false, ""}, - equalsTestCase{float32(17), true, false, ""}, - equalsTestCase{float64(17), true, false, ""}, - equalsTestCase{complex64(17), true, false, ""}, - equalsTestCase{complex128(17), true, false, ""}, - equalsTestCase{interface{}(int(17)), true, false, ""}, - equalsTestCase{uint(17), true, false, ""}, - equalsTestCase{uint8(17), true, false, ""}, - equalsTestCase{uint16(17), true, false, ""}, - equalsTestCase{uint32(17), true, false, ""}, - equalsTestCase{uint64(17), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int(16), false, false, ""}, - equalsTestCase{int8(16), false, false, ""}, - equalsTestCase{int16(16), false, false, ""}, - equalsTestCase{int32(16), false, false, ""}, - equalsTestCase{int64(16), false, false, ""}, - equalsTestCase{float32(16.9), false, false, ""}, - equalsTestCase{float32(17.1), false, false, ""}, - equalsTestCase{complex64(16), false, false, ""}, - equalsTestCase{complex64(17 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(17), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{17}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{17}, false, true, "which is not numeric"}, - equalsTestCase{"17", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// int16 -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) NegativeInt16() { - matcher := Equals(int16(-32766)) - ExpectEq("-32766", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of -32766. - equalsTestCase{-32766, true, false, ""}, - equalsTestCase{-32766.0, true, false, ""}, - equalsTestCase{-32766 + 0i, true, false, ""}, - equalsTestCase{int(-32766), true, false, ""}, - equalsTestCase{int16(-32766), true, false, ""}, - equalsTestCase{int32(-32766), true, false, ""}, - equalsTestCase{int64(-32766), true, false, ""}, - equalsTestCase{float32(-32766), true, false, ""}, - equalsTestCase{float64(-32766), true, false, ""}, - equalsTestCase{complex64(-32766), true, false, ""}, - equalsTestCase{complex128(-32766), true, false, ""}, - equalsTestCase{interface{}(int(-32766)), true, false, ""}, - - // Values that would be -32766 in two's complement. - equalsTestCase{uint((1 << 32) - 32766), false, false, ""}, - equalsTestCase{uint16((1 << 16) - 32766), false, false, ""}, - equalsTestCase{uint32((1 << 32) - 32766), false, false, ""}, - equalsTestCase{uint64((1 << 64) - 32766), false, false, ""}, - - // Non-equal values of signed integer type. - equalsTestCase{int(-16), false, false, ""}, - equalsTestCase{int8(-16), false, false, ""}, - equalsTestCase{int16(-16), false, false, ""}, - equalsTestCase{int32(-16), false, false, ""}, - equalsTestCase{int64(-16), false, false, ""}, - - // Non-equal values of other numeric types. - equalsTestCase{float32(-32766.1), false, false, ""}, - equalsTestCase{float32(-32765.9), false, false, ""}, - equalsTestCase{complex64(-32766.1), false, false, ""}, - equalsTestCase{complex64(-32766 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr((1 << 32) - 32766), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{-32766}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{-32766}, false, true, "which is not numeric"}, - equalsTestCase{"-32766", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) ZeroInt16() { - matcher := Equals(int16(0)) - ExpectEq("0", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of 0. - equalsTestCase{0, true, false, ""}, - equalsTestCase{0.0, true, false, ""}, - equalsTestCase{0 + 0i, true, false, ""}, - equalsTestCase{int(0), true, false, ""}, - equalsTestCase{int8(0), true, false, ""}, - equalsTestCase{int16(0), true, false, ""}, - equalsTestCase{int32(0), true, false, ""}, - equalsTestCase{int64(0), true, false, ""}, - equalsTestCase{float32(0), true, false, ""}, - equalsTestCase{float64(0), true, false, ""}, - equalsTestCase{complex64(0), true, false, ""}, - equalsTestCase{complex128(0), true, false, ""}, - equalsTestCase{interface{}(int(0)), true, false, ""}, - equalsTestCase{uint(0), true, false, ""}, - equalsTestCase{uint8(0), true, false, ""}, - equalsTestCase{uint16(0), true, false, ""}, - equalsTestCase{uint32(0), true, false, ""}, - equalsTestCase{uint64(0), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int(1), false, false, ""}, - equalsTestCase{int8(1), false, false, ""}, - equalsTestCase{int16(1), false, false, ""}, - equalsTestCase{int32(1), false, false, ""}, - equalsTestCase{int64(1), false, false, ""}, - equalsTestCase{float32(-0.1), false, false, ""}, - equalsTestCase{float32(0.1), false, false, ""}, - equalsTestCase{complex64(1), false, false, ""}, - equalsTestCase{complex64(0 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{0}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{0}, false, true, "which is not numeric"}, - equalsTestCase{"0", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) PositiveInt16() { - matcher := Equals(int16(32765)) - ExpectEq("32765", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of 32765. - equalsTestCase{32765, true, false, ""}, - equalsTestCase{32765.0, true, false, ""}, - equalsTestCase{32765 + 0i, true, false, ""}, - equalsTestCase{int(32765), true, false, ""}, - equalsTestCase{int16(32765), true, false, ""}, - equalsTestCase{int32(32765), true, false, ""}, - equalsTestCase{int64(32765), true, false, ""}, - equalsTestCase{float32(32765), true, false, ""}, - equalsTestCase{float64(32765), true, false, ""}, - equalsTestCase{complex64(32765), true, false, ""}, - equalsTestCase{complex128(32765), true, false, ""}, - equalsTestCase{interface{}(int(32765)), true, false, ""}, - equalsTestCase{uint(32765), true, false, ""}, - equalsTestCase{uint16(32765), true, false, ""}, - equalsTestCase{uint32(32765), true, false, ""}, - equalsTestCase{uint64(32765), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int(32764), false, false, ""}, - equalsTestCase{int16(32764), false, false, ""}, - equalsTestCase{int32(32764), false, false, ""}, - equalsTestCase{int64(32764), false, false, ""}, - equalsTestCase{float32(32764.9), false, false, ""}, - equalsTestCase{float32(32765.1), false, false, ""}, - equalsTestCase{complex64(32765.9), false, false, ""}, - equalsTestCase{complex64(32765 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(32765), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{32765}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{32765}, false, true, "which is not numeric"}, - equalsTestCase{"32765", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// int32 -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) NegativeInt32() { - // -2^30 - matcher := Equals(int32(-1073741824)) - ExpectEq("-1073741824", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of -1073741824. - equalsTestCase{-1073741824, true, false, ""}, - equalsTestCase{-1073741824.0, true, false, ""}, - equalsTestCase{-1073741824 + 0i, true, false, ""}, - equalsTestCase{int(-1073741824), true, false, ""}, - equalsTestCase{int32(-1073741824), true, false, ""}, - equalsTestCase{int64(-1073741824), true, false, ""}, - equalsTestCase{float32(-1073741824), true, false, ""}, - equalsTestCase{float64(-1073741824), true, false, ""}, - equalsTestCase{complex64(-1073741824), true, false, ""}, - equalsTestCase{complex128(-1073741824), true, false, ""}, - equalsTestCase{interface{}(int(-1073741824)), true, false, ""}, - - // Values that would be -1073741824 in two's complement. - equalsTestCase{uint((1 << 32) - 1073741824), false, false, ""}, - equalsTestCase{uint32((1 << 32) - 1073741824), false, false, ""}, - equalsTestCase{uint64((1 << 64) - 1073741824), false, false, ""}, - - // Non-equal values of signed integer type. - equalsTestCase{int(-1073741823), false, false, ""}, - equalsTestCase{int32(-1073741823), false, false, ""}, - equalsTestCase{int64(-1073741823), false, false, ""}, - - // Non-equal values of other numeric types. - equalsTestCase{float64(-1073741824.1), false, false, ""}, - equalsTestCase{float64(-1073741823.9), false, false, ""}, - equalsTestCase{complex128(-1073741823), false, false, ""}, - equalsTestCase{complex128(-1073741824 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) PositiveInt32() { - // 2^30 - matcher := Equals(int32(1073741824)) - ExpectEq("1073741824", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of 1073741824. - equalsTestCase{1073741824, true, false, ""}, - equalsTestCase{1073741824.0, true, false, ""}, - equalsTestCase{1073741824 + 0i, true, false, ""}, - equalsTestCase{int(1073741824), true, false, ""}, - equalsTestCase{uint(1073741824), true, false, ""}, - equalsTestCase{int32(1073741824), true, false, ""}, - equalsTestCase{int64(1073741824), true, false, ""}, - equalsTestCase{uint32(1073741824), true, false, ""}, - equalsTestCase{uint64(1073741824), true, false, ""}, - equalsTestCase{float32(1073741824), true, false, ""}, - equalsTestCase{float64(1073741824), true, false, ""}, - equalsTestCase{complex64(1073741824), true, false, ""}, - equalsTestCase{complex128(1073741824), true, false, ""}, - equalsTestCase{interface{}(int(1073741824)), true, false, ""}, - equalsTestCase{interface{}(uint(1073741824)), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int(1073741823), false, false, ""}, - equalsTestCase{int32(1073741823), false, false, ""}, - equalsTestCase{int64(1073741823), false, false, ""}, - equalsTestCase{float64(1073741824.1), false, false, ""}, - equalsTestCase{float64(1073741823.9), false, false, ""}, - equalsTestCase{complex128(1073741823), false, false, ""}, - equalsTestCase{complex128(1073741824 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// int64 -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) NegativeInt64() { - // -2^40 - matcher := Equals(int64(-1099511627776)) - ExpectEq("-1099511627776", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of -1099511627776. - equalsTestCase{-1099511627776.0, true, false, ""}, - equalsTestCase{-1099511627776 + 0i, true, false, ""}, - equalsTestCase{int64(-1099511627776), true, false, ""}, - equalsTestCase{float32(-1099511627776), true, false, ""}, - equalsTestCase{float64(-1099511627776), true, false, ""}, - equalsTestCase{complex64(-1099511627776), true, false, ""}, - equalsTestCase{complex128(-1099511627776), true, false, ""}, - equalsTestCase{interface{}(int64(-1099511627776)), true, false, ""}, - - // Values that would be -1099511627776 in two's complement. - equalsTestCase{uint64((1 << 64) - 1099511627776), false, false, ""}, - - // Non-equal values of signed integer type. - equalsTestCase{int64(-1099511627775), false, false, ""}, - - // Non-equal values of other numeric types. - equalsTestCase{float64(-1099511627776.1), false, false, ""}, - equalsTestCase{float64(-1099511627775.9), false, false, ""}, - equalsTestCase{complex128(-1099511627775), false, false, ""}, - equalsTestCase{complex128(-1099511627776 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) PositiveInt64() { - // 2^40 - matcher := Equals(int64(1099511627776)) - ExpectEq("1099511627776", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of 1099511627776. - equalsTestCase{1099511627776.0, true, false, ""}, - equalsTestCase{1099511627776 + 0i, true, false, ""}, - equalsTestCase{int64(1099511627776), true, false, ""}, - equalsTestCase{uint64(1099511627776), true, false, ""}, - equalsTestCase{float32(1099511627776), true, false, ""}, - equalsTestCase{float64(1099511627776), true, false, ""}, - equalsTestCase{complex64(1099511627776), true, false, ""}, - equalsTestCase{complex128(1099511627776), true, false, ""}, - equalsTestCase{interface{}(int64(1099511627776)), true, false, ""}, - equalsTestCase{interface{}(uint64(1099511627776)), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int64(1099511627775), false, false, ""}, - equalsTestCase{uint64(1099511627775), false, false, ""}, - equalsTestCase{float64(1099511627776.1), false, false, ""}, - equalsTestCase{float64(1099511627775.9), false, false, ""}, - equalsTestCase{complex128(1099511627775), false, false, ""}, - equalsTestCase{complex128(1099511627776 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) Int64NotExactlyRepresentableBySinglePrecision() { - // Single-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^25-1, 2^25+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo25 = 1 << 25 - matcher := Equals(int64(kTwoTo25 + 1)) - ExpectEq("33554433", matcher.Description()) - - cases := []equalsTestCase{ - // Integers. - equalsTestCase{int64(kTwoTo25 + 0), false, false, ""}, - equalsTestCase{int64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{int64(kTwoTo25 + 2), false, false, ""}, - - equalsTestCase{uint64(kTwoTo25 + 0), false, false, ""}, - equalsTestCase{uint64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{uint64(kTwoTo25 + 2), false, false, ""}, - - // Single-precision floating point. - equalsTestCase{float32(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{float32(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 3), false, false, ""}, - - equalsTestCase{complex64(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{complex64(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 3), false, false, ""}, - - // Double-precision floating point. - equalsTestCase{float64(kTwoTo25 + 0), false, false, ""}, - equalsTestCase{float64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{float64(kTwoTo25 + 2), false, false, ""}, - - equalsTestCase{complex128(kTwoTo25 + 0), false, false, ""}, - equalsTestCase{complex128(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{complex128(kTwoTo25 + 2), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) Int64NotExactlyRepresentableByDoublePrecision() { - // Double-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^54-1, 2^54+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo54 = 1 << 54 - matcher := Equals(int64(kTwoTo54 + 1)) - ExpectEq("18014398509481985", matcher.Description()) - - cases := []equalsTestCase{ - // Integers. - equalsTestCase{int64(kTwoTo54 + 0), false, false, ""}, - equalsTestCase{int64(kTwoTo54 + 1), true, false, ""}, - equalsTestCase{int64(kTwoTo54 + 2), false, false, ""}, - - equalsTestCase{uint64(kTwoTo54 + 0), false, false, ""}, - equalsTestCase{uint64(kTwoTo54 + 1), true, false, ""}, - equalsTestCase{uint64(kTwoTo54 + 2), false, false, ""}, - - // Double-precision floating point. - equalsTestCase{float64(kTwoTo54 - 2), false, false, ""}, - equalsTestCase{float64(kTwoTo54 - 1), true, false, ""}, - equalsTestCase{float64(kTwoTo54 + 0), true, false, ""}, - equalsTestCase{float64(kTwoTo54 + 1), true, false, ""}, - equalsTestCase{float64(kTwoTo54 + 2), true, false, ""}, - equalsTestCase{float64(kTwoTo54 + 3), false, false, ""}, - - equalsTestCase{complex128(kTwoTo54 - 2), false, false, ""}, - equalsTestCase{complex128(kTwoTo54 - 1), true, false, ""}, - equalsTestCase{complex128(kTwoTo54 + 0), true, false, ""}, - equalsTestCase{complex128(kTwoTo54 + 1), true, false, ""}, - equalsTestCase{complex128(kTwoTo54 + 2), true, false, ""}, - equalsTestCase{complex128(kTwoTo54 + 3), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// uint -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) SmallUint() { - const kExpected = 17 - matcher := Equals(uint(kExpected)) - ExpectEq("17", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{17, true, false, ""}, - equalsTestCase{17.0, true, false, ""}, - equalsTestCase{17 + 0i, true, false, ""}, - equalsTestCase{int(kExpected), true, false, ""}, - equalsTestCase{int8(kExpected), true, false, ""}, - equalsTestCase{int16(kExpected), true, false, ""}, - equalsTestCase{int32(kExpected), true, false, ""}, - equalsTestCase{int64(kExpected), true, false, ""}, - equalsTestCase{uint(kExpected), true, false, ""}, - equalsTestCase{uint8(kExpected), true, false, ""}, - equalsTestCase{uint16(kExpected), true, false, ""}, - equalsTestCase{uint32(kExpected), true, false, ""}, - equalsTestCase{uint64(kExpected), true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric types. - equalsTestCase{kExpected + 1, false, false, ""}, - equalsTestCase{int(kExpected + 1), false, false, ""}, - equalsTestCase{int8(kExpected + 1), false, false, ""}, - equalsTestCase{int16(kExpected + 1), false, false, ""}, - equalsTestCase{int32(kExpected + 1), false, false, ""}, - equalsTestCase{int64(kExpected + 1), false, false, ""}, - equalsTestCase{uint(kExpected + 1), false, false, ""}, - equalsTestCase{uint8(kExpected + 1), false, false, ""}, - equalsTestCase{uint16(kExpected + 1), false, false, ""}, - equalsTestCase{uint32(kExpected + 1), false, false, ""}, - equalsTestCase{uint64(kExpected + 1), false, false, ""}, - equalsTestCase{float32(kExpected + 1), false, false, ""}, - equalsTestCase{float64(kExpected + 1), false, false, ""}, - equalsTestCase{complex64(kExpected + 2i), false, false, ""}, - equalsTestCase{complex64(kExpected + 1), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - equalsTestCase{complex128(kExpected + 1), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) LargeUint() { - const kExpected = (1 << 16) + 17 - matcher := Equals(uint(kExpected)) - ExpectEq("65553", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{65553, true, false, ""}, - equalsTestCase{65553.0, true, false, ""}, - equalsTestCase{65553 + 0i, true, false, ""}, - equalsTestCase{int32(kExpected), true, false, ""}, - equalsTestCase{int64(kExpected), true, false, ""}, - equalsTestCase{uint32(kExpected), true, false, ""}, - equalsTestCase{uint64(kExpected), true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric types. - equalsTestCase{int16(17), false, false, ""}, - equalsTestCase{int32(kExpected + 1), false, false, ""}, - equalsTestCase{int64(kExpected + 1), false, false, ""}, - equalsTestCase{uint16(17), false, false, ""}, - equalsTestCase{uint32(kExpected + 1), false, false, ""}, - equalsTestCase{uint64(kExpected + 1), false, false, ""}, - equalsTestCase{float64(kExpected + 1), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - equalsTestCase{complex128(kExpected + 1), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) UintNotExactlyRepresentableBySinglePrecision() { - // Single-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^25-1, 2^25+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo25 = 1 << 25 - matcher := Equals(uint(kTwoTo25 + 1)) - ExpectEq("33554433", matcher.Description()) - - cases := []equalsTestCase{ - // Integers. - equalsTestCase{int64(kTwoTo25 + 0), false, false, ""}, - equalsTestCase{int64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{int64(kTwoTo25 + 2), false, false, ""}, - - equalsTestCase{uint64(kTwoTo25 + 0), false, false, ""}, - equalsTestCase{uint64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{uint64(kTwoTo25 + 2), false, false, ""}, - - // Single-precision floating point. - equalsTestCase{float32(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{float32(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 3), false, false, ""}, - - equalsTestCase{complex64(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{complex64(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 3), false, false, ""}, - - // Double-precision floating point. - equalsTestCase{float64(kTwoTo25 + 0), false, false, ""}, - equalsTestCase{float64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{float64(kTwoTo25 + 2), false, false, ""}, - - equalsTestCase{complex128(kTwoTo25 + 0), false, false, ""}, - equalsTestCase{complex128(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{complex128(kTwoTo25 + 2), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// uint8 -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) SmallUint8() { - const kExpected = 17 - matcher := Equals(uint8(kExpected)) - ExpectEq("17", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{17, true, false, ""}, - equalsTestCase{17.0, true, false, ""}, - equalsTestCase{17 + 0i, true, false, ""}, - equalsTestCase{int(kExpected), true, false, ""}, - equalsTestCase{int8(kExpected), true, false, ""}, - equalsTestCase{int16(kExpected), true, false, ""}, - equalsTestCase{int32(kExpected), true, false, ""}, - equalsTestCase{int64(kExpected), true, false, ""}, - equalsTestCase{uint(kExpected), true, false, ""}, - equalsTestCase{uint8(kExpected), true, false, ""}, - equalsTestCase{uint16(kExpected), true, false, ""}, - equalsTestCase{uint32(kExpected), true, false, ""}, - equalsTestCase{uint64(kExpected), true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric types. - equalsTestCase{kExpected + 1, false, false, ""}, - equalsTestCase{int(kExpected + 1), false, false, ""}, - equalsTestCase{int8(kExpected + 1), false, false, ""}, - equalsTestCase{int16(kExpected + 1), false, false, ""}, - equalsTestCase{int32(kExpected + 1), false, false, ""}, - equalsTestCase{int64(kExpected + 1), false, false, ""}, - equalsTestCase{uint(kExpected + 1), false, false, ""}, - equalsTestCase{uint8(kExpected + 1), false, false, ""}, - equalsTestCase{uint16(kExpected + 1), false, false, ""}, - equalsTestCase{uint32(kExpected + 1), false, false, ""}, - equalsTestCase{uint64(kExpected + 1), false, false, ""}, - equalsTestCase{float32(kExpected + 1), false, false, ""}, - equalsTestCase{float64(kExpected + 1), false, false, ""}, - equalsTestCase{complex64(kExpected + 2i), false, false, ""}, - equalsTestCase{complex64(kExpected + 1), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - equalsTestCase{complex128(kExpected + 1), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// uint16 -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) SmallUint16() { - const kExpected = 17 - matcher := Equals(uint16(kExpected)) - ExpectEq("17", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{17, true, false, ""}, - equalsTestCase{17.0, true, false, ""}, - equalsTestCase{17 + 0i, true, false, ""}, - equalsTestCase{int(kExpected), true, false, ""}, - equalsTestCase{int8(kExpected), true, false, ""}, - equalsTestCase{int16(kExpected), true, false, ""}, - equalsTestCase{int32(kExpected), true, false, ""}, - equalsTestCase{int64(kExpected), true, false, ""}, - equalsTestCase{uint(kExpected), true, false, ""}, - equalsTestCase{uint8(kExpected), true, false, ""}, - equalsTestCase{uint16(kExpected), true, false, ""}, - equalsTestCase{uint32(kExpected), true, false, ""}, - equalsTestCase{uint64(kExpected), true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric types. - equalsTestCase{kExpected + 1, false, false, ""}, - equalsTestCase{int(kExpected + 1), false, false, ""}, - equalsTestCase{int8(kExpected + 1), false, false, ""}, - equalsTestCase{int16(kExpected + 1), false, false, ""}, - equalsTestCase{int32(kExpected + 1), false, false, ""}, - equalsTestCase{int64(kExpected + 1), false, false, ""}, - equalsTestCase{uint(kExpected + 1), false, false, ""}, - equalsTestCase{uint8(kExpected + 1), false, false, ""}, - equalsTestCase{uint16(kExpected + 1), false, false, ""}, - equalsTestCase{uint32(kExpected + 1), false, false, ""}, - equalsTestCase{uint64(kExpected + 1), false, false, ""}, - equalsTestCase{float32(kExpected + 1), false, false, ""}, - equalsTestCase{float64(kExpected + 1), false, false, ""}, - equalsTestCase{complex64(kExpected + 2i), false, false, ""}, - equalsTestCase{complex64(kExpected + 1), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - equalsTestCase{complex128(kExpected + 1), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) LargeUint16() { - const kExpected = (1 << 8) + 17 - matcher := Equals(uint16(kExpected)) - ExpectEq("273", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{273, true, false, ""}, - equalsTestCase{273.0, true, false, ""}, - equalsTestCase{273 + 0i, true, false, ""}, - equalsTestCase{int16(kExpected), true, false, ""}, - equalsTestCase{int32(kExpected), true, false, ""}, - equalsTestCase{int64(kExpected), true, false, ""}, - equalsTestCase{uint16(kExpected), true, false, ""}, - equalsTestCase{uint32(kExpected), true, false, ""}, - equalsTestCase{uint64(kExpected), true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric types. - equalsTestCase{int8(17), false, false, ""}, - equalsTestCase{int16(kExpected + 1), false, false, ""}, - equalsTestCase{int32(kExpected + 1), false, false, ""}, - equalsTestCase{int64(kExpected + 1), false, false, ""}, - equalsTestCase{uint8(17), false, false, ""}, - equalsTestCase{uint16(kExpected + 1), false, false, ""}, - equalsTestCase{uint32(kExpected + 1), false, false, ""}, - equalsTestCase{uint64(kExpected + 1), false, false, ""}, - equalsTestCase{float64(kExpected + 1), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - equalsTestCase{complex128(kExpected + 1), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// uint32 -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) SmallUint32() { - const kExpected = 17 - matcher := Equals(uint32(kExpected)) - ExpectEq("17", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{17, true, false, ""}, - equalsTestCase{17.0, true, false, ""}, - equalsTestCase{17 + 0i, true, false, ""}, - equalsTestCase{int(kExpected), true, false, ""}, - equalsTestCase{int8(kExpected), true, false, ""}, - equalsTestCase{int16(kExpected), true, false, ""}, - equalsTestCase{int32(kExpected), true, false, ""}, - equalsTestCase{int64(kExpected), true, false, ""}, - equalsTestCase{uint(kExpected), true, false, ""}, - equalsTestCase{uint8(kExpected), true, false, ""}, - equalsTestCase{uint16(kExpected), true, false, ""}, - equalsTestCase{uint32(kExpected), true, false, ""}, - equalsTestCase{uint64(kExpected), true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric types. - equalsTestCase{kExpected + 1, false, false, ""}, - equalsTestCase{int(kExpected + 1), false, false, ""}, - equalsTestCase{int8(kExpected + 1), false, false, ""}, - equalsTestCase{int16(kExpected + 1), false, false, ""}, - equalsTestCase{int32(kExpected + 1), false, false, ""}, - equalsTestCase{int64(kExpected + 1), false, false, ""}, - equalsTestCase{uint(kExpected + 1), false, false, ""}, - equalsTestCase{uint8(kExpected + 1), false, false, ""}, - equalsTestCase{uint16(kExpected + 1), false, false, ""}, - equalsTestCase{uint32(kExpected + 1), false, false, ""}, - equalsTestCase{uint64(kExpected + 1), false, false, ""}, - equalsTestCase{float32(kExpected + 1), false, false, ""}, - equalsTestCase{float64(kExpected + 1), false, false, ""}, - equalsTestCase{complex64(kExpected + 2i), false, false, ""}, - equalsTestCase{complex64(kExpected + 1), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - equalsTestCase{complex128(kExpected + 1), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) LargeUint32() { - const kExpected = (1 << 16) + 17 - matcher := Equals(uint32(kExpected)) - ExpectEq("65553", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{65553, true, false, ""}, - equalsTestCase{65553.0, true, false, ""}, - equalsTestCase{65553 + 0i, true, false, ""}, - equalsTestCase{int32(kExpected), true, false, ""}, - equalsTestCase{int64(kExpected), true, false, ""}, - equalsTestCase{uint32(kExpected), true, false, ""}, - equalsTestCase{uint64(kExpected), true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric types. - equalsTestCase{int16(17), false, false, ""}, - equalsTestCase{int32(kExpected + 1), false, false, ""}, - equalsTestCase{int64(kExpected + 1), false, false, ""}, - equalsTestCase{uint16(17), false, false, ""}, - equalsTestCase{uint32(kExpected + 1), false, false, ""}, - equalsTestCase{uint64(kExpected + 1), false, false, ""}, - equalsTestCase{float64(kExpected + 1), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - equalsTestCase{complex128(kExpected + 1), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) Uint32NotExactlyRepresentableBySinglePrecision() { - // Single-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^25-1, 2^25+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo25 = 1 << 25 - matcher := Equals(uint32(kTwoTo25 + 1)) - ExpectEq("33554433", matcher.Description()) - - cases := []equalsTestCase{ - // Integers. - equalsTestCase{int64(kTwoTo25 + 0), false, false, ""}, - equalsTestCase{int64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{int64(kTwoTo25 + 2), false, false, ""}, - - equalsTestCase{uint64(kTwoTo25 + 0), false, false, ""}, - equalsTestCase{uint64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{uint64(kTwoTo25 + 2), false, false, ""}, - - // Single-precision floating point. - equalsTestCase{float32(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{float32(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 3), false, false, ""}, - - equalsTestCase{complex64(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{complex64(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 3), false, false, ""}, - - // Double-precision floating point. - equalsTestCase{float64(kTwoTo25 + 0), false, false, ""}, - equalsTestCase{float64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{float64(kTwoTo25 + 2), false, false, ""}, - - equalsTestCase{complex128(kTwoTo25 + 0), false, false, ""}, - equalsTestCase{complex128(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{complex128(kTwoTo25 + 2), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// uint64 -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) SmallUint64() { - const kExpected = 17 - matcher := Equals(uint64(kExpected)) - ExpectEq("17", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{17, true, false, ""}, - equalsTestCase{17.0, true, false, ""}, - equalsTestCase{17 + 0i, true, false, ""}, - equalsTestCase{int(kExpected), true, false, ""}, - equalsTestCase{int8(kExpected), true, false, ""}, - equalsTestCase{int16(kExpected), true, false, ""}, - equalsTestCase{int32(kExpected), true, false, ""}, - equalsTestCase{int64(kExpected), true, false, ""}, - equalsTestCase{uint(kExpected), true, false, ""}, - equalsTestCase{uint8(kExpected), true, false, ""}, - equalsTestCase{uint16(kExpected), true, false, ""}, - equalsTestCase{uint32(kExpected), true, false, ""}, - equalsTestCase{uint64(kExpected), true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric types. - equalsTestCase{kExpected + 1, false, false, ""}, - equalsTestCase{int(kExpected + 1), false, false, ""}, - equalsTestCase{int8(kExpected + 1), false, false, ""}, - equalsTestCase{int16(kExpected + 1), false, false, ""}, - equalsTestCase{int32(kExpected + 1), false, false, ""}, - equalsTestCase{int64(kExpected + 1), false, false, ""}, - equalsTestCase{uint(kExpected + 1), false, false, ""}, - equalsTestCase{uint8(kExpected + 1), false, false, ""}, - equalsTestCase{uint16(kExpected + 1), false, false, ""}, - equalsTestCase{uint32(kExpected + 1), false, false, ""}, - equalsTestCase{uint64(kExpected + 1), false, false, ""}, - equalsTestCase{float32(kExpected + 1), false, false, ""}, - equalsTestCase{float64(kExpected + 1), false, false, ""}, - equalsTestCase{complex64(kExpected + 2i), false, false, ""}, - equalsTestCase{complex64(kExpected + 1), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - equalsTestCase{complex128(kExpected + 1), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) LargeUint64() { - const kExpected = (1 << 32) + 17 - matcher := Equals(uint64(kExpected)) - ExpectEq("4294967313", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{4294967313.0, true, false, ""}, - equalsTestCase{4294967313 + 0i, true, false, ""}, - equalsTestCase{int64(kExpected), true, false, ""}, - equalsTestCase{uint64(kExpected), true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric types. - equalsTestCase{int(17), false, false, ""}, - equalsTestCase{int32(17), false, false, ""}, - equalsTestCase{int64(kExpected + 1), false, false, ""}, - equalsTestCase{uint(17), false, false, ""}, - equalsTestCase{uint32(17), false, false, ""}, - equalsTestCase{uint64(kExpected + 1), false, false, ""}, - equalsTestCase{float64(kExpected + 1), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - equalsTestCase{complex128(kExpected + 1), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) Uint64NotExactlyRepresentableBySinglePrecision() { - // Single-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^25-1, 2^25+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo25 = 1 << 25 - matcher := Equals(uint64(kTwoTo25 + 1)) - ExpectEq("33554433", matcher.Description()) - - cases := []equalsTestCase{ - // Integers. - equalsTestCase{int64(kTwoTo25 + 0), false, false, ""}, - equalsTestCase{int64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{int64(kTwoTo25 + 2), false, false, ""}, - - equalsTestCase{uint64(kTwoTo25 + 0), false, false, ""}, - equalsTestCase{uint64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{uint64(kTwoTo25 + 2), false, false, ""}, - - // Single-precision floating point. - equalsTestCase{float32(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{float32(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 3), false, false, ""}, - - equalsTestCase{complex64(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{complex64(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 3), false, false, ""}, - - // Double-precision floating point. - equalsTestCase{float64(kTwoTo25 + 0), false, false, ""}, - equalsTestCase{float64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{float64(kTwoTo25 + 2), false, false, ""}, - - equalsTestCase{complex128(kTwoTo25 + 0), false, false, ""}, - equalsTestCase{complex128(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{complex128(kTwoTo25 + 2), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) Uint64NotExactlyRepresentableByDoublePrecision() { - // Double-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^54-1, 2^54+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo54 = 1 << 54 - matcher := Equals(uint64(kTwoTo54 + 1)) - ExpectEq("18014398509481985", matcher.Description()) - - cases := []equalsTestCase{ - // Integers. - equalsTestCase{int64(kTwoTo54 + 0), false, false, ""}, - equalsTestCase{int64(kTwoTo54 + 1), true, false, ""}, - equalsTestCase{int64(kTwoTo54 + 2), false, false, ""}, - - equalsTestCase{uint64(kTwoTo54 + 0), false, false, ""}, - equalsTestCase{uint64(kTwoTo54 + 1), true, false, ""}, - equalsTestCase{uint64(kTwoTo54 + 2), false, false, ""}, - - // Double-precision floating point. - equalsTestCase{float64(kTwoTo54 - 2), false, false, ""}, - equalsTestCase{float64(kTwoTo54 - 1), true, false, ""}, - equalsTestCase{float64(kTwoTo54 + 0), true, false, ""}, - equalsTestCase{float64(kTwoTo54 + 1), true, false, ""}, - equalsTestCase{float64(kTwoTo54 + 2), true, false, ""}, - equalsTestCase{float64(kTwoTo54 + 3), false, false, ""}, - - equalsTestCase{complex128(kTwoTo54 - 2), false, false, ""}, - equalsTestCase{complex128(kTwoTo54 - 1), true, false, ""}, - equalsTestCase{complex128(kTwoTo54 + 0), true, false, ""}, - equalsTestCase{complex128(kTwoTo54 + 1), true, false, ""}, - equalsTestCase{complex128(kTwoTo54 + 2), true, false, ""}, - equalsTestCase{complex128(kTwoTo54 + 3), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// uintptr -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) NilUintptr() { - var ptr1 uintptr - var ptr2 uintptr - - matcher := Equals(ptr1) - ExpectEq("0", matcher.Description()) - - cases := []equalsTestCase{ - // uintptrs - equalsTestCase{ptr1, true, false, ""}, - equalsTestCase{ptr2, true, false, ""}, - equalsTestCase{uintptr(0), true, false, ""}, - equalsTestCase{uintptr(17), false, false, ""}, - - // Other types. - equalsTestCase{0, false, true, "which is not a uintptr"}, - equalsTestCase{bool(false), false, true, "which is not a uintptr"}, - equalsTestCase{int(0), false, true, "which is not a uintptr"}, - equalsTestCase{int8(0), false, true, "which is not a uintptr"}, - equalsTestCase{int16(0), false, true, "which is not a uintptr"}, - equalsTestCase{int32(0), false, true, "which is not a uintptr"}, - equalsTestCase{int64(0), false, true, "which is not a uintptr"}, - equalsTestCase{uint(0), false, true, "which is not a uintptr"}, - equalsTestCase{uint8(0), false, true, "which is not a uintptr"}, - equalsTestCase{uint16(0), false, true, "which is not a uintptr"}, - equalsTestCase{uint32(0), false, true, "which is not a uintptr"}, - equalsTestCase{uint64(0), false, true, "which is not a uintptr"}, - equalsTestCase{true, false, true, "which is not a uintptr"}, - equalsTestCase{[...]int{}, false, true, "which is not a uintptr"}, - equalsTestCase{make(chan int), false, true, "which is not a uintptr"}, - equalsTestCase{func() {}, false, true, "which is not a uintptr"}, - equalsTestCase{map[int]int{}, false, true, "which is not a uintptr"}, - equalsTestCase{&someInt, false, true, "which is not a uintptr"}, - equalsTestCase{[]int{}, false, true, "which is not a uintptr"}, - equalsTestCase{"taco", false, true, "which is not a uintptr"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not a uintptr"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) NonNilUintptr() { - matcher := Equals(uintptr(17)) - ExpectEq("17", matcher.Description()) - - cases := []equalsTestCase{ - // uintptrs - equalsTestCase{uintptr(17), true, false, ""}, - equalsTestCase{uintptr(16), false, false, ""}, - equalsTestCase{uintptr(0), false, false, ""}, - - // Other types. - equalsTestCase{0, false, true, "which is not a uintptr"}, - equalsTestCase{bool(false), false, true, "which is not a uintptr"}, - equalsTestCase{int(0), false, true, "which is not a uintptr"}, - equalsTestCase{int8(0), false, true, "which is not a uintptr"}, - equalsTestCase{int16(0), false, true, "which is not a uintptr"}, - equalsTestCase{int32(0), false, true, "which is not a uintptr"}, - equalsTestCase{int64(0), false, true, "which is not a uintptr"}, - equalsTestCase{uint(0), false, true, "which is not a uintptr"}, - equalsTestCase{uint8(0), false, true, "which is not a uintptr"}, - equalsTestCase{uint16(0), false, true, "which is not a uintptr"}, - equalsTestCase{uint32(0), false, true, "which is not a uintptr"}, - equalsTestCase{uint64(0), false, true, "which is not a uintptr"}, - equalsTestCase{true, false, true, "which is not a uintptr"}, - equalsTestCase{[...]int{}, false, true, "which is not a uintptr"}, - equalsTestCase{make(chan int), false, true, "which is not a uintptr"}, - equalsTestCase{func() {}, false, true, "which is not a uintptr"}, - equalsTestCase{map[int]int{}, false, true, "which is not a uintptr"}, - equalsTestCase{&someInt, false, true, "which is not a uintptr"}, - equalsTestCase{[]int{}, false, true, "which is not a uintptr"}, - equalsTestCase{"taco", false, true, "which is not a uintptr"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not a uintptr"}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// float32 -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) NegativeIntegralFloat32() { - matcher := Equals(float32(-32769)) - ExpectEq("-32769", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of -32769. - equalsTestCase{-32769.0, true, false, ""}, - equalsTestCase{-32769 + 0i, true, false, ""}, - equalsTestCase{int32(-32769), true, false, ""}, - equalsTestCase{int64(-32769), true, false, ""}, - equalsTestCase{float32(-32769), true, false, ""}, - equalsTestCase{float64(-32769), true, false, ""}, - equalsTestCase{complex64(-32769), true, false, ""}, - equalsTestCase{complex128(-32769), true, false, ""}, - equalsTestCase{interface{}(float32(-32769)), true, false, ""}, - equalsTestCase{interface{}(int64(-32769)), true, false, ""}, - - // Values that would be -32769 in two's complement. - equalsTestCase{uint64((1 << 64) - 32769), false, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int64(-32770), false, false, ""}, - equalsTestCase{float32(-32769.1), false, false, ""}, - equalsTestCase{float32(-32768.9), false, false, ""}, - equalsTestCase{float64(-32769.1), false, false, ""}, - equalsTestCase{float64(-32768.9), false, false, ""}, - equalsTestCase{complex128(-32768), false, false, ""}, - equalsTestCase{complex128(-32769 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) NegativeNonIntegralFloat32() { - matcher := Equals(float32(-32769.1)) - ExpectEq("-32769.1", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of -32769.1. - equalsTestCase{-32769.1, true, false, ""}, - equalsTestCase{-32769.1 + 0i, true, false, ""}, - equalsTestCase{float32(-32769.1), true, false, ""}, - equalsTestCase{float64(-32769.1), true, false, ""}, - equalsTestCase{complex64(-32769.1), true, false, ""}, - equalsTestCase{complex128(-32769.1), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int32(-32769), false, false, ""}, - equalsTestCase{int32(-32770), false, false, ""}, - equalsTestCase{int64(-32769), false, false, ""}, - equalsTestCase{int64(-32770), false, false, ""}, - equalsTestCase{float32(-32769.2), false, false, ""}, - equalsTestCase{float32(-32769.0), false, false, ""}, - equalsTestCase{float64(-32769.2), false, false, ""}, - equalsTestCase{complex128(-32769.1 + 2i), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) LargeNegativeFloat32() { - const kExpected = -1 * (1 << 65) - matcher := Equals(float32(kExpected)) - ExpectEq("-3.689349e+19", matcher.Description()) - - floatExpected := float32(kExpected) - castedInt := int64(floatExpected) - - cases := []equalsTestCase{ - // Equal values of numeric type. - equalsTestCase{kExpected + 0i, true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{castedInt, false, false, ""}, - equalsTestCase{int64(0), false, false, ""}, - equalsTestCase{int64(math.MinInt64), false, false, ""}, - equalsTestCase{int64(math.MaxInt64), false, false, ""}, - equalsTestCase{float32(kExpected / 2), false, false, ""}, - equalsTestCase{float64(kExpected / 2), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) ZeroFloat32() { - matcher := Equals(float32(0)) - ExpectEq("0", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of zero. - equalsTestCase{0.0, true, false, ""}, - equalsTestCase{0 + 0i, true, false, ""}, - equalsTestCase{int(0), true, false, ""}, - equalsTestCase{int8(0), true, false, ""}, - equalsTestCase{int16(0), true, false, ""}, - equalsTestCase{int32(0), true, false, ""}, - equalsTestCase{int64(0), true, false, ""}, - equalsTestCase{uint(0), true, false, ""}, - equalsTestCase{uint8(0), true, false, ""}, - equalsTestCase{uint16(0), true, false, ""}, - equalsTestCase{uint32(0), true, false, ""}, - equalsTestCase{uint64(0), true, false, ""}, - equalsTestCase{float32(0), true, false, ""}, - equalsTestCase{float64(0), true, false, ""}, - equalsTestCase{complex64(0), true, false, ""}, - equalsTestCase{complex128(0), true, false, ""}, - equalsTestCase{interface{}(float32(0)), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int64(1), false, false, ""}, - equalsTestCase{int64(-1), false, false, ""}, - equalsTestCase{float32(1), false, false, ""}, - equalsTestCase{float32(-1), false, false, ""}, - equalsTestCase{complex128(0 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) PositiveIntegralFloat32() { - matcher := Equals(float32(32769)) - ExpectEq("32769", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of 32769. - equalsTestCase{32769.0, true, false, ""}, - equalsTestCase{32769 + 0i, true, false, ""}, - equalsTestCase{int(32769), true, false, ""}, - equalsTestCase{int32(32769), true, false, ""}, - equalsTestCase{int64(32769), true, false, ""}, - equalsTestCase{uint(32769), true, false, ""}, - equalsTestCase{uint32(32769), true, false, ""}, - equalsTestCase{uint64(32769), true, false, ""}, - equalsTestCase{float32(32769), true, false, ""}, - equalsTestCase{float64(32769), true, false, ""}, - equalsTestCase{complex64(32769), true, false, ""}, - equalsTestCase{complex128(32769), true, false, ""}, - equalsTestCase{interface{}(float32(32769)), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int64(32770), false, false, ""}, - equalsTestCase{uint64(32770), false, false, ""}, - equalsTestCase{float32(32769.1), false, false, ""}, - equalsTestCase{float32(32768.9), false, false, ""}, - equalsTestCase{float64(32769.1), false, false, ""}, - equalsTestCase{float64(32768.9), false, false, ""}, - equalsTestCase{complex128(32768), false, false, ""}, - equalsTestCase{complex128(32769 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) PositiveNonIntegralFloat32() { - matcher := Equals(float32(32769.1)) - ExpectEq("32769.1", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of 32769.1. - equalsTestCase{32769.1, true, false, ""}, - equalsTestCase{32769.1 + 0i, true, false, ""}, - equalsTestCase{float32(32769.1), true, false, ""}, - equalsTestCase{float64(32769.1), true, false, ""}, - equalsTestCase{complex64(32769.1), true, false, ""}, - equalsTestCase{complex128(32769.1), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int32(32769), false, false, ""}, - equalsTestCase{int32(32770), false, false, ""}, - equalsTestCase{uint64(32769), false, false, ""}, - equalsTestCase{uint64(32770), false, false, ""}, - equalsTestCase{float32(32769.2), false, false, ""}, - equalsTestCase{float32(32769.0), false, false, ""}, - equalsTestCase{float64(32769.2), false, false, ""}, - equalsTestCase{complex128(32769.1 + 2i), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) LargePositiveFloat32() { - const kExpected = 1 << 65 - matcher := Equals(float32(kExpected)) - ExpectEq("3.689349e+19", matcher.Description()) - - floatExpected := float32(kExpected) - castedInt := uint64(floatExpected) - - cases := []equalsTestCase{ - // Equal values of numeric type. - equalsTestCase{kExpected + 0i, true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{castedInt, false, false, ""}, - equalsTestCase{int64(0), false, false, ""}, - equalsTestCase{int64(math.MinInt64), false, false, ""}, - equalsTestCase{int64(math.MaxInt64), false, false, ""}, - equalsTestCase{uint64(0), false, false, ""}, - equalsTestCase{uint64(math.MaxUint64), false, false, ""}, - equalsTestCase{float32(kExpected / 2), false, false, ""}, - equalsTestCase{float64(kExpected / 2), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) Float32AboveExactIntegerRange() { - // Single-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^25-1, 2^25+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo25 = 1 << 25 - matcher := Equals(float32(kTwoTo25 + 1)) - ExpectEq("3.3554432e+07", matcher.Description()) - - cases := []equalsTestCase{ - // Integers. - equalsTestCase{int64(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{int64(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{int64(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{int64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{int64(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{int64(kTwoTo25 + 3), false, false, ""}, - - equalsTestCase{uint64(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{uint64(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{uint64(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{uint64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{uint64(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{uint64(kTwoTo25 + 3), false, false, ""}, - - // Single-precision floating point. - equalsTestCase{float32(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{float32(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 3), false, false, ""}, - - equalsTestCase{complex64(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{complex64(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 3), false, false, ""}, - - // Double-precision floating point. - equalsTestCase{float64(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{float64(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{float64(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{float64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{float64(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{float64(kTwoTo25 + 3), false, false, ""}, - - equalsTestCase{complex128(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{complex128(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{complex128(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{complex128(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{complex128(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{complex128(kTwoTo25 + 3), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// float64 -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) NegativeIntegralFloat64() { - const kExpected = -(1 << 50) - matcher := Equals(float64(kExpected)) - ExpectEq("-1.125899906842624e+15", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{-1125899906842624.0, true, false, ""}, - equalsTestCase{-1125899906842624.0 + 0i, true, false, ""}, - equalsTestCase{int64(kExpected), true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - equalsTestCase{interface{}(float64(kExpected)), true, false, ""}, - - // Values that would be kExpected in two's complement. - equalsTestCase{uint64((1 << 64) + kExpected), false, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int64(kExpected + 1), false, false, ""}, - equalsTestCase{float32(kExpected - (1 << 30)), false, false, ""}, - equalsTestCase{float32(kExpected + (1 << 30)), false, false, ""}, - equalsTestCase{float64(kExpected - 0.5), false, false, ""}, - equalsTestCase{float64(kExpected + 0.5), false, false, ""}, - equalsTestCase{complex128(kExpected - 1), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) NegativeNonIntegralFloat64() { - const kTwoTo50 = 1 << 50 - const kExpected = -kTwoTo50 - 0.25 - - matcher := Equals(float64(kExpected)) - ExpectEq("-1.1258999068426242e+15", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{kExpected, true, false, ""}, - equalsTestCase{kExpected + 0i, true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int64(-kTwoTo50), false, false, ""}, - equalsTestCase{int64(-kTwoTo50 - 1), false, false, ""}, - equalsTestCase{float32(kExpected - (1 << 30)), false, false, ""}, - equalsTestCase{float64(kExpected - 0.25), false, false, ""}, - equalsTestCase{float64(kExpected + 0.25), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) LargeNegativeFloat64() { - const kExpected = -1 * (1 << 65) - matcher := Equals(float64(kExpected)) - ExpectEq("-3.6893488147419103e+19", matcher.Description()) - - floatExpected := float64(kExpected) - castedInt := int64(floatExpected) - - cases := []equalsTestCase{ - // Equal values of numeric type. - equalsTestCase{kExpected + 0i, true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{castedInt, false, false, ""}, - equalsTestCase{int64(0), false, false, ""}, - equalsTestCase{int64(math.MinInt64), false, false, ""}, - equalsTestCase{int64(math.MaxInt64), false, false, ""}, - equalsTestCase{float32(kExpected / 2), false, false, ""}, - equalsTestCase{float64(kExpected / 2), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) ZeroFloat64() { - matcher := Equals(float64(0)) - ExpectEq("0", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of zero. - equalsTestCase{0.0, true, false, ""}, - equalsTestCase{0 + 0i, true, false, ""}, - equalsTestCase{int(0), true, false, ""}, - equalsTestCase{int8(0), true, false, ""}, - equalsTestCase{int16(0), true, false, ""}, - equalsTestCase{int32(0), true, false, ""}, - equalsTestCase{int64(0), true, false, ""}, - equalsTestCase{uint(0), true, false, ""}, - equalsTestCase{uint8(0), true, false, ""}, - equalsTestCase{uint16(0), true, false, ""}, - equalsTestCase{uint32(0), true, false, ""}, - equalsTestCase{uint64(0), true, false, ""}, - equalsTestCase{float32(0), true, false, ""}, - equalsTestCase{float64(0), true, false, ""}, - equalsTestCase{complex64(0), true, false, ""}, - equalsTestCase{complex128(0), true, false, ""}, - equalsTestCase{interface{}(float32(0)), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int64(1), false, false, ""}, - equalsTestCase{int64(-1), false, false, ""}, - equalsTestCase{float32(1), false, false, ""}, - equalsTestCase{float32(-1), false, false, ""}, - equalsTestCase{complex128(0 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) PositiveIntegralFloat64() { - const kExpected = 1 << 50 - matcher := Equals(float64(kExpected)) - ExpectEq("1.125899906842624e+15", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of 32769. - equalsTestCase{1125899906842624.0, true, false, ""}, - equalsTestCase{1125899906842624.0 + 0i, true, false, ""}, - equalsTestCase{int64(kExpected), true, false, ""}, - equalsTestCase{uint64(kExpected), true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - equalsTestCase{interface{}(float64(kExpected)), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int64(kExpected + 1), false, false, ""}, - equalsTestCase{uint64(kExpected + 1), false, false, ""}, - equalsTestCase{float32(kExpected - (1 << 30)), false, false, ""}, - equalsTestCase{float32(kExpected + (1 << 30)), false, false, ""}, - equalsTestCase{float64(kExpected - 0.5), false, false, ""}, - equalsTestCase{float64(kExpected + 0.5), false, false, ""}, - equalsTestCase{complex128(kExpected - 1), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) PositiveNonIntegralFloat64() { - const kTwoTo50 = 1 << 50 - const kExpected = kTwoTo50 + 0.25 - matcher := Equals(float64(kExpected)) - ExpectEq("1.1258999068426242e+15", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{kExpected, true, false, ""}, - equalsTestCase{kExpected + 0i, true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int64(kTwoTo50), false, false, ""}, - equalsTestCase{int64(kTwoTo50 - 1), false, false, ""}, - equalsTestCase{float64(kExpected - 0.25), false, false, ""}, - equalsTestCase{float64(kExpected + 0.25), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) LargePositiveFloat64() { - const kExpected = 1 << 65 - matcher := Equals(float64(kExpected)) - ExpectEq("3.6893488147419103e+19", matcher.Description()) - - floatExpected := float64(kExpected) - castedInt := uint64(floatExpected) - - cases := []equalsTestCase{ - // Equal values of numeric type. - equalsTestCase{kExpected + 0i, true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{castedInt, false, false, ""}, - equalsTestCase{int64(0), false, false, ""}, - equalsTestCase{int64(math.MinInt64), false, false, ""}, - equalsTestCase{int64(math.MaxInt64), false, false, ""}, - equalsTestCase{uint64(0), false, false, ""}, - equalsTestCase{uint64(math.MaxUint64), false, false, ""}, - equalsTestCase{float32(kExpected / 2), false, false, ""}, - equalsTestCase{float64(kExpected / 2), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) Float64AboveExactIntegerRange() { - // Double-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^54-1, 2^54+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo54 = 1 << 54 - matcher := Equals(float64(kTwoTo54 + 1)) - ExpectEq("1.8014398509481984e+16", matcher.Description()) - - cases := []equalsTestCase{ - // Integers. - equalsTestCase{int64(kTwoTo54 - 2), false, false, ""}, - equalsTestCase{int64(kTwoTo54 - 1), true, false, ""}, - equalsTestCase{int64(kTwoTo54 + 0), true, false, ""}, - equalsTestCase{int64(kTwoTo54 + 1), true, false, ""}, - equalsTestCase{int64(kTwoTo54 + 2), true, false, ""}, - equalsTestCase{int64(kTwoTo54 + 3), false, false, ""}, - - equalsTestCase{uint64(kTwoTo54 - 2), false, false, ""}, - equalsTestCase{uint64(kTwoTo54 - 1), true, false, ""}, - equalsTestCase{uint64(kTwoTo54 + 0), true, false, ""}, - equalsTestCase{uint64(kTwoTo54 + 1), true, false, ""}, - equalsTestCase{uint64(kTwoTo54 + 2), true, false, ""}, - equalsTestCase{uint64(kTwoTo54 + 3), false, false, ""}, - - // Double-precision floating point. - equalsTestCase{float64(kTwoTo54 - 2), false, false, ""}, - equalsTestCase{float64(kTwoTo54 - 1), true, false, ""}, - equalsTestCase{float64(kTwoTo54 + 0), true, false, ""}, - equalsTestCase{float64(kTwoTo54 + 1), true, false, ""}, - equalsTestCase{float64(kTwoTo54 + 2), true, false, ""}, - equalsTestCase{float64(kTwoTo54 + 3), false, false, ""}, - - equalsTestCase{complex128(kTwoTo54 - 2), false, false, ""}, - equalsTestCase{complex128(kTwoTo54 - 1), true, false, ""}, - equalsTestCase{complex128(kTwoTo54 + 0), true, false, ""}, - equalsTestCase{complex128(kTwoTo54 + 1), true, false, ""}, - equalsTestCase{complex128(kTwoTo54 + 2), true, false, ""}, - equalsTestCase{complex128(kTwoTo54 + 3), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// complex64 -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) NegativeIntegralComplex64() { - const kExpected = -32769 - matcher := Equals(complex64(kExpected)) - ExpectEq("(-32769+0i)", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{-32769.0, true, false, ""}, - equalsTestCase{-32769.0 + 0i, true, false, ""}, - equalsTestCase{int(kExpected), true, false, ""}, - equalsTestCase{int32(kExpected), true, false, ""}, - equalsTestCase{int64(kExpected), true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - equalsTestCase{interface{}(float64(kExpected)), true, false, ""}, - - // Values that would be kExpected in two's complement. - equalsTestCase{uint32((1 << 32) + kExpected), false, false, ""}, - equalsTestCase{uint64((1 << 64) + kExpected), false, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int64(kExpected + 1), false, false, ""}, - equalsTestCase{float32(kExpected - (1 << 30)), false, false, ""}, - equalsTestCase{float32(kExpected + (1 << 30)), false, false, ""}, - equalsTestCase{float64(kExpected - 0.5), false, false, ""}, - equalsTestCase{float64(kExpected + 0.5), false, false, ""}, - equalsTestCase{complex64(kExpected - 1), false, false, ""}, - equalsTestCase{complex64(kExpected + 2i), false, false, ""}, - equalsTestCase{complex128(kExpected - 1), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) NegativeNonIntegralComplex64() { - const kTwoTo20 = 1 << 20 - const kExpected = -kTwoTo20 - 0.25 - - matcher := Equals(complex64(kExpected)) - ExpectEq("(-1.0485762e+06+0i)", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{kExpected, true, false, ""}, - equalsTestCase{kExpected + 0i, true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int(-kTwoTo20), false, false, ""}, - equalsTestCase{int(-kTwoTo20 - 1), false, false, ""}, - equalsTestCase{int32(-kTwoTo20), false, false, ""}, - equalsTestCase{int32(-kTwoTo20 - 1), false, false, ""}, - equalsTestCase{int64(-kTwoTo20), false, false, ""}, - equalsTestCase{int64(-kTwoTo20 - 1), false, false, ""}, - equalsTestCase{float32(kExpected - (1 << 30)), false, false, ""}, - equalsTestCase{float64(kExpected - 0.25), false, false, ""}, - equalsTestCase{float64(kExpected + 0.25), false, false, ""}, - equalsTestCase{complex64(kExpected - 0.75), false, false, ""}, - equalsTestCase{complex64(kExpected + 2i), false, false, ""}, - equalsTestCase{complex128(kExpected - 0.75), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) LargeNegativeComplex64() { - const kExpected = -1 * (1 << 65) - matcher := Equals(complex64(kExpected)) - ExpectEq("(-3.689349e+19+0i)", matcher.Description()) - - floatExpected := float64(kExpected) - castedInt := int64(floatExpected) - - cases := []equalsTestCase{ - // Equal values of numeric type. - equalsTestCase{kExpected + 0i, true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{castedInt, false, false, ""}, - equalsTestCase{int64(0), false, false, ""}, - equalsTestCase{int64(math.MinInt64), false, false, ""}, - equalsTestCase{int64(math.MaxInt64), false, false, ""}, - equalsTestCase{float32(kExpected / 2), false, false, ""}, - equalsTestCase{float64(kExpected / 2), false, false, ""}, - equalsTestCase{complex64(kExpected + 2i), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) ZeroComplex64() { - matcher := Equals(complex64(0)) - ExpectEq("(0+0i)", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of zero. - equalsTestCase{0.0, true, false, ""}, - equalsTestCase{0 + 0i, true, false, ""}, - equalsTestCase{int(0), true, false, ""}, - equalsTestCase{int8(0), true, false, ""}, - equalsTestCase{int16(0), true, false, ""}, - equalsTestCase{int32(0), true, false, ""}, - equalsTestCase{int64(0), true, false, ""}, - equalsTestCase{uint(0), true, false, ""}, - equalsTestCase{uint8(0), true, false, ""}, - equalsTestCase{uint16(0), true, false, ""}, - equalsTestCase{uint32(0), true, false, ""}, - equalsTestCase{uint64(0), true, false, ""}, - equalsTestCase{float32(0), true, false, ""}, - equalsTestCase{float64(0), true, false, ""}, - equalsTestCase{complex64(0), true, false, ""}, - equalsTestCase{complex128(0), true, false, ""}, - equalsTestCase{interface{}(float32(0)), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int64(1), false, false, ""}, - equalsTestCase{int64(-1), false, false, ""}, - equalsTestCase{float32(1), false, false, ""}, - equalsTestCase{float32(-1), false, false, ""}, - equalsTestCase{float64(1), false, false, ""}, - equalsTestCase{float64(-1), false, false, ""}, - equalsTestCase{complex64(0 + 2i), false, false, ""}, - equalsTestCase{complex128(0 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) PositiveIntegralComplex64() { - const kExpected = 1 << 20 - matcher := Equals(complex64(kExpected)) - ExpectEq("(1.048576e+06+0i)", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of 32769. - equalsTestCase{1048576.0, true, false, ""}, - equalsTestCase{1048576.0 + 0i, true, false, ""}, - equalsTestCase{int(kExpected), true, false, ""}, - equalsTestCase{int32(kExpected), true, false, ""}, - equalsTestCase{int64(kExpected), true, false, ""}, - equalsTestCase{uint(kExpected), true, false, ""}, - equalsTestCase{uint32(kExpected), true, false, ""}, - equalsTestCase{uint64(kExpected), true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - equalsTestCase{interface{}(float64(kExpected)), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int(kExpected + 1), false, false, ""}, - equalsTestCase{int32(kExpected + 1), false, false, ""}, - equalsTestCase{int64(kExpected + 1), false, false, ""}, - equalsTestCase{uint(kExpected + 1), false, false, ""}, - equalsTestCase{uint32(kExpected + 1), false, false, ""}, - equalsTestCase{uint64(kExpected + 1), false, false, ""}, - equalsTestCase{float32(kExpected - (1 << 30)), false, false, ""}, - equalsTestCase{float32(kExpected + (1 << 30)), false, false, ""}, - equalsTestCase{float64(kExpected - 0.5), false, false, ""}, - equalsTestCase{float64(kExpected + 0.5), false, false, ""}, - equalsTestCase{complex128(kExpected - 1), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) PositiveNonIntegralComplex64() { - const kTwoTo20 = 1 << 20 - const kExpected = kTwoTo20 + 0.25 - matcher := Equals(complex64(kExpected)) - ExpectEq("(1.0485762e+06+0i)", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{kExpected, true, false, ""}, - equalsTestCase{kExpected + 0i, true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int64(kTwoTo20), false, false, ""}, - equalsTestCase{int64(kTwoTo20 - 1), false, false, ""}, - equalsTestCase{uint64(kTwoTo20), false, false, ""}, - equalsTestCase{uint64(kTwoTo20 - 1), false, false, ""}, - equalsTestCase{float32(kExpected - 1), false, false, ""}, - equalsTestCase{float32(kExpected + 1), false, false, ""}, - equalsTestCase{float64(kExpected - 0.25), false, false, ""}, - equalsTestCase{float64(kExpected + 0.25), false, false, ""}, - equalsTestCase{complex64(kExpected - 1), false, false, ""}, - equalsTestCase{complex64(kExpected - 1i), false, false, ""}, - equalsTestCase{complex128(kExpected - 1), false, false, ""}, - equalsTestCase{complex128(kExpected - 1i), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) LargePositiveComplex64() { - const kExpected = 1 << 65 - matcher := Equals(complex64(kExpected)) - ExpectEq("(3.689349e+19+0i)", matcher.Description()) - - floatExpected := float64(kExpected) - castedInt := uint64(floatExpected) - - cases := []equalsTestCase{ - // Equal values of numeric type. - equalsTestCase{kExpected + 0i, true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{castedInt, false, false, ""}, - equalsTestCase{int64(0), false, false, ""}, - equalsTestCase{int64(math.MinInt64), false, false, ""}, - equalsTestCase{int64(math.MaxInt64), false, false, ""}, - equalsTestCase{uint64(0), false, false, ""}, - equalsTestCase{uint64(math.MaxUint64), false, false, ""}, - equalsTestCase{float32(kExpected / 2), false, false, ""}, - equalsTestCase{float64(kExpected / 2), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) Complex64AboveExactIntegerRange() { - // Single-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^25-1, 2^25+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo25 = 1 << 25 - matcher := Equals(complex64(kTwoTo25 + 1)) - ExpectEq("(3.3554432e+07+0i)", matcher.Description()) - - cases := []equalsTestCase{ - // Integers. - equalsTestCase{int64(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{int64(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{int64(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{int64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{int64(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{int64(kTwoTo25 + 3), false, false, ""}, - - equalsTestCase{uint64(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{uint64(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{uint64(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{uint64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{uint64(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{uint64(kTwoTo25 + 3), false, false, ""}, - - // Single-precision floating point. - equalsTestCase{float32(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{float32(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{float32(kTwoTo25 + 3), false, false, ""}, - - equalsTestCase{complex64(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{complex64(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{complex64(kTwoTo25 + 3), false, false, ""}, - - // Double-precision floating point. - equalsTestCase{float64(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{float64(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{float64(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{float64(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{float64(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{float64(kTwoTo25 + 3), false, false, ""}, - - equalsTestCase{complex128(kTwoTo25 - 2), false, false, ""}, - equalsTestCase{complex128(kTwoTo25 - 1), true, false, ""}, - equalsTestCase{complex128(kTwoTo25 + 0), true, false, ""}, - equalsTestCase{complex128(kTwoTo25 + 1), true, false, ""}, - equalsTestCase{complex128(kTwoTo25 + 2), true, false, ""}, - equalsTestCase{complex128(kTwoTo25 + 3), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) Complex64WithNonZeroImaginaryPart() { - const kRealPart = 17 - const kImagPart = 0.25i - const kExpected = kRealPart + kImagPart - matcher := Equals(complex64(kExpected)) - ExpectEq("(17+0.25i)", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{kExpected, true, false, ""}, - equalsTestCase{kRealPart + kImagPart, true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int(kRealPart), false, false, ""}, - equalsTestCase{int8(kRealPart), false, false, ""}, - equalsTestCase{int16(kRealPart), false, false, ""}, - equalsTestCase{int32(kRealPart), false, false, ""}, - equalsTestCase{int64(kRealPart), false, false, ""}, - equalsTestCase{uint(kRealPart), false, false, ""}, - equalsTestCase{uint8(kRealPart), false, false, ""}, - equalsTestCase{uint16(kRealPart), false, false, ""}, - equalsTestCase{uint32(kRealPart), false, false, ""}, - equalsTestCase{uint64(kRealPart), false, false, ""}, - equalsTestCase{float32(kRealPart), false, false, ""}, - equalsTestCase{float64(kRealPart), false, false, ""}, - equalsTestCase{complex64(kRealPart), false, false, ""}, - equalsTestCase{complex64(kRealPart + kImagPart + 0.5), false, false, ""}, - equalsTestCase{complex64(kRealPart + kImagPart + 0.5i), false, false, ""}, - equalsTestCase{complex128(kRealPart), false, false, ""}, - equalsTestCase{complex128(kRealPart + kImagPart + 0.5), false, false, ""}, - equalsTestCase{complex128(kRealPart + kImagPart + 0.5i), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// complex128 -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) NegativeIntegralComplex128() { - const kExpected = -32769 - matcher := Equals(complex128(kExpected)) - ExpectEq("(-32769+0i)", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{-32769.0, true, false, ""}, - equalsTestCase{-32769.0 + 0i, true, false, ""}, - equalsTestCase{int(kExpected), true, false, ""}, - equalsTestCase{int32(kExpected), true, false, ""}, - equalsTestCase{int64(kExpected), true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - equalsTestCase{interface{}(float64(kExpected)), true, false, ""}, - - // Values that would be kExpected in two's complement. - equalsTestCase{uint32((1 << 32) + kExpected), false, false, ""}, - equalsTestCase{uint64((1 << 64) + kExpected), false, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int64(kExpected + 1), false, false, ""}, - equalsTestCase{float32(kExpected - (1 << 30)), false, false, ""}, - equalsTestCase{float32(kExpected + (1 << 30)), false, false, ""}, - equalsTestCase{float64(kExpected - 0.5), false, false, ""}, - equalsTestCase{float64(kExpected + 0.5), false, false, ""}, - equalsTestCase{complex64(kExpected - 1), false, false, ""}, - equalsTestCase{complex64(kExpected + 2i), false, false, ""}, - equalsTestCase{complex128(kExpected - 1), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) NegativeNonIntegralComplex128() { - const kTwoTo20 = 1 << 20 - const kExpected = -kTwoTo20 - 0.25 - - matcher := Equals(complex128(kExpected)) - ExpectEq("(-1.04857625e+06+0i)", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{kExpected, true, false, ""}, - equalsTestCase{kExpected + 0i, true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int(-kTwoTo20), false, false, ""}, - equalsTestCase{int(-kTwoTo20 - 1), false, false, ""}, - equalsTestCase{int32(-kTwoTo20), false, false, ""}, - equalsTestCase{int32(-kTwoTo20 - 1), false, false, ""}, - equalsTestCase{int64(-kTwoTo20), false, false, ""}, - equalsTestCase{int64(-kTwoTo20 - 1), false, false, ""}, - equalsTestCase{float32(kExpected - (1 << 30)), false, false, ""}, - equalsTestCase{float64(kExpected - 0.25), false, false, ""}, - equalsTestCase{float64(kExpected + 0.25), false, false, ""}, - equalsTestCase{complex64(kExpected - 0.75), false, false, ""}, - equalsTestCase{complex64(kExpected + 2i), false, false, ""}, - equalsTestCase{complex128(kExpected - 0.75), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) LargeNegativeComplex128() { - const kExpected = -1 * (1 << 65) - matcher := Equals(complex128(kExpected)) - ExpectEq("(-3.6893488147419103e+19+0i)", matcher.Description()) - - floatExpected := float64(kExpected) - castedInt := int64(floatExpected) - - cases := []equalsTestCase{ - // Equal values of numeric type. - equalsTestCase{kExpected + 0i, true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{castedInt, false, false, ""}, - equalsTestCase{int64(0), false, false, ""}, - equalsTestCase{int64(math.MinInt64), false, false, ""}, - equalsTestCase{int64(math.MaxInt64), false, false, ""}, - equalsTestCase{float32(kExpected / 2), false, false, ""}, - equalsTestCase{float64(kExpected / 2), false, false, ""}, - equalsTestCase{complex64(kExpected + 2i), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) ZeroComplex128() { - matcher := Equals(complex128(0)) - ExpectEq("(0+0i)", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of zero. - equalsTestCase{0.0, true, false, ""}, - equalsTestCase{0 + 0i, true, false, ""}, - equalsTestCase{int(0), true, false, ""}, - equalsTestCase{int8(0), true, false, ""}, - equalsTestCase{int16(0), true, false, ""}, - equalsTestCase{int32(0), true, false, ""}, - equalsTestCase{int64(0), true, false, ""}, - equalsTestCase{uint(0), true, false, ""}, - equalsTestCase{uint8(0), true, false, ""}, - equalsTestCase{uint16(0), true, false, ""}, - equalsTestCase{uint32(0), true, false, ""}, - equalsTestCase{uint64(0), true, false, ""}, - equalsTestCase{float32(0), true, false, ""}, - equalsTestCase{float64(0), true, false, ""}, - equalsTestCase{complex64(0), true, false, ""}, - equalsTestCase{complex128(0), true, false, ""}, - equalsTestCase{interface{}(float32(0)), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int64(1), false, false, ""}, - equalsTestCase{int64(-1), false, false, ""}, - equalsTestCase{float32(1), false, false, ""}, - equalsTestCase{float32(-1), false, false, ""}, - equalsTestCase{float64(1), false, false, ""}, - equalsTestCase{float64(-1), false, false, ""}, - equalsTestCase{complex64(0 + 2i), false, false, ""}, - equalsTestCase{complex128(0 + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) PositiveIntegralComplex128() { - const kExpected = 1 << 20 - matcher := Equals(complex128(kExpected)) - ExpectEq("(1.048576e+06+0i)", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of 32769. - equalsTestCase{1048576.0, true, false, ""}, - equalsTestCase{1048576.0 + 0i, true, false, ""}, - equalsTestCase{int(kExpected), true, false, ""}, - equalsTestCase{int32(kExpected), true, false, ""}, - equalsTestCase{int64(kExpected), true, false, ""}, - equalsTestCase{uint(kExpected), true, false, ""}, - equalsTestCase{uint32(kExpected), true, false, ""}, - equalsTestCase{uint64(kExpected), true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - equalsTestCase{interface{}(float64(kExpected)), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int(kExpected + 1), false, false, ""}, - equalsTestCase{int32(kExpected + 1), false, false, ""}, - equalsTestCase{int64(kExpected + 1), false, false, ""}, - equalsTestCase{uint(kExpected + 1), false, false, ""}, - equalsTestCase{uint32(kExpected + 1), false, false, ""}, - equalsTestCase{uint64(kExpected + 1), false, false, ""}, - equalsTestCase{float32(kExpected - (1 << 30)), false, false, ""}, - equalsTestCase{float32(kExpected + (1 << 30)), false, false, ""}, - equalsTestCase{float64(kExpected - 0.5), false, false, ""}, - equalsTestCase{float64(kExpected + 0.5), false, false, ""}, - equalsTestCase{complex128(kExpected - 1), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - - // Non-numeric types. - equalsTestCase{uintptr(0), false, true, "which is not numeric"}, - equalsTestCase{true, false, true, "which is not numeric"}, - equalsTestCase{[...]int{}, false, true, "which is not numeric"}, - equalsTestCase{make(chan int), false, true, "which is not numeric"}, - equalsTestCase{func() {}, false, true, "which is not numeric"}, - equalsTestCase{map[int]int{}, false, true, "which is not numeric"}, - equalsTestCase{&someInt, false, true, "which is not numeric"}, - equalsTestCase{[]int{}, false, true, "which is not numeric"}, - equalsTestCase{"taco", false, true, "which is not numeric"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not numeric"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) PositiveNonIntegralComplex128() { - const kTwoTo20 = 1 << 20 - const kExpected = kTwoTo20 + 0.25 - matcher := Equals(complex128(kExpected)) - ExpectEq("(1.04857625e+06+0i)", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{kExpected, true, false, ""}, - equalsTestCase{kExpected + 0i, true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int64(kTwoTo20), false, false, ""}, - equalsTestCase{int64(kTwoTo20 - 1), false, false, ""}, - equalsTestCase{uint64(kTwoTo20), false, false, ""}, - equalsTestCase{uint64(kTwoTo20 - 1), false, false, ""}, - equalsTestCase{float32(kExpected - 1), false, false, ""}, - equalsTestCase{float32(kExpected + 1), false, false, ""}, - equalsTestCase{float64(kExpected - 0.25), false, false, ""}, - equalsTestCase{float64(kExpected + 0.25), false, false, ""}, - equalsTestCase{complex64(kExpected - 1), false, false, ""}, - equalsTestCase{complex64(kExpected - 1i), false, false, ""}, - equalsTestCase{complex128(kExpected - 1), false, false, ""}, - equalsTestCase{complex128(kExpected - 1i), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) LargePositiveComplex128() { - const kExpected = 1 << 65 - matcher := Equals(complex128(kExpected)) - ExpectEq("(3.6893488147419103e+19+0i)", matcher.Description()) - - floatExpected := float64(kExpected) - castedInt := uint64(floatExpected) - - cases := []equalsTestCase{ - // Equal values of numeric type. - equalsTestCase{kExpected + 0i, true, false, ""}, - equalsTestCase{float32(kExpected), true, false, ""}, - equalsTestCase{float64(kExpected), true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{castedInt, false, false, ""}, - equalsTestCase{int64(0), false, false, ""}, - equalsTestCase{int64(math.MinInt64), false, false, ""}, - equalsTestCase{int64(math.MaxInt64), false, false, ""}, - equalsTestCase{uint64(0), false, false, ""}, - equalsTestCase{uint64(math.MaxUint64), false, false, ""}, - equalsTestCase{float32(kExpected / 2), false, false, ""}, - equalsTestCase{float64(kExpected / 2), false, false, ""}, - equalsTestCase{complex128(kExpected + 2i), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) Complex128AboveExactIntegerRange() { - // Double-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^54-1, 2^54+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo54 = 1 << 54 - matcher := Equals(complex128(kTwoTo54 + 1)) - ExpectEq("(1.8014398509481984e+16+0i)", matcher.Description()) - - cases := []equalsTestCase{ - // Integers. - equalsTestCase{int64(kTwoTo54 - 2), false, false, ""}, - equalsTestCase{int64(kTwoTo54 - 1), true, false, ""}, - equalsTestCase{int64(kTwoTo54 + 0), true, false, ""}, - equalsTestCase{int64(kTwoTo54 + 1), true, false, ""}, - equalsTestCase{int64(kTwoTo54 + 2), true, false, ""}, - equalsTestCase{int64(kTwoTo54 + 3), false, false, ""}, - - equalsTestCase{uint64(kTwoTo54 - 2), false, false, ""}, - equalsTestCase{uint64(kTwoTo54 - 1), true, false, ""}, - equalsTestCase{uint64(kTwoTo54 + 0), true, false, ""}, - equalsTestCase{uint64(kTwoTo54 + 1), true, false, ""}, - equalsTestCase{uint64(kTwoTo54 + 2), true, false, ""}, - equalsTestCase{uint64(kTwoTo54 + 3), false, false, ""}, - - // Double-precision floating point. - equalsTestCase{float64(kTwoTo54 - 2), false, false, ""}, - equalsTestCase{float64(kTwoTo54 - 1), true, false, ""}, - equalsTestCase{float64(kTwoTo54 + 0), true, false, ""}, - equalsTestCase{float64(kTwoTo54 + 1), true, false, ""}, - equalsTestCase{float64(kTwoTo54 + 2), true, false, ""}, - equalsTestCase{float64(kTwoTo54 + 3), false, false, ""}, - - equalsTestCase{complex128(kTwoTo54 - 2), false, false, ""}, - equalsTestCase{complex128(kTwoTo54 - 1), true, false, ""}, - equalsTestCase{complex128(kTwoTo54 + 0), true, false, ""}, - equalsTestCase{complex128(kTwoTo54 + 1), true, false, ""}, - equalsTestCase{complex128(kTwoTo54 + 2), true, false, ""}, - equalsTestCase{complex128(kTwoTo54 + 3), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) Complex128WithNonZeroImaginaryPart() { - const kRealPart = 17 - const kImagPart = 0.25i - const kExpected = kRealPart + kImagPart - matcher := Equals(complex128(kExpected)) - ExpectEq("(17+0.25i)", matcher.Description()) - - cases := []equalsTestCase{ - // Various types of the expected value. - equalsTestCase{kExpected, true, false, ""}, - equalsTestCase{kRealPart + kImagPart, true, false, ""}, - equalsTestCase{complex64(kExpected), true, false, ""}, - equalsTestCase{complex128(kExpected), true, false, ""}, - - // Non-equal values of numeric type. - equalsTestCase{int(kRealPart), false, false, ""}, - equalsTestCase{int8(kRealPart), false, false, ""}, - equalsTestCase{int16(kRealPart), false, false, ""}, - equalsTestCase{int32(kRealPart), false, false, ""}, - equalsTestCase{int64(kRealPart), false, false, ""}, - equalsTestCase{uint(kRealPart), false, false, ""}, - equalsTestCase{uint8(kRealPart), false, false, ""}, - equalsTestCase{uint16(kRealPart), false, false, ""}, - equalsTestCase{uint32(kRealPart), false, false, ""}, - equalsTestCase{uint64(kRealPart), false, false, ""}, - equalsTestCase{float32(kRealPart), false, false, ""}, - equalsTestCase{float64(kRealPart), false, false, ""}, - equalsTestCase{complex64(kRealPart), false, false, ""}, - equalsTestCase{complex64(kRealPart + kImagPart + 0.5), false, false, ""}, - equalsTestCase{complex64(kRealPart + kImagPart + 0.5i), false, false, ""}, - equalsTestCase{complex128(kRealPart), false, false, ""}, - equalsTestCase{complex128(kRealPart + kImagPart + 0.5), false, false, ""}, - equalsTestCase{complex128(kRealPart + kImagPart + 0.5i), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// array -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) Array() { - var someArray [3]int - f := func() { Equals(someArray) } - ExpectThat(f, Panics(HasSubstr("unsupported kind array"))) -} - -//////////////////////////////////////////////////////////////////////// -// chan -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) NilChan() { - var nilChan1 chan int - var nilChan2 chan int - var nilChan3 chan uint - var nonNilChan1 chan int = make(chan int) - var nonNilChan2 chan uint = make(chan uint) - - matcher := Equals(nilChan1) - ExpectEq("", matcher.Description()) - - cases := []equalsTestCase{ - // int channels - equalsTestCase{nilChan1, true, false, ""}, - equalsTestCase{nilChan2, true, false, ""}, - equalsTestCase{nonNilChan1, false, false, ""}, - - // uint channels - equalsTestCase{nilChan3, false, true, "which is not a chan int"}, - equalsTestCase{nonNilChan2, false, true, "which is not a chan int"}, - - // Other types. - equalsTestCase{0, false, true, "which is not a chan int"}, - equalsTestCase{bool(false), false, true, "which is not a chan int"}, - equalsTestCase{int(0), false, true, "which is not a chan int"}, - equalsTestCase{int8(0), false, true, "which is not a chan int"}, - equalsTestCase{int16(0), false, true, "which is not a chan int"}, - equalsTestCase{int32(0), false, true, "which is not a chan int"}, - equalsTestCase{int64(0), false, true, "which is not a chan int"}, - equalsTestCase{uint(0), false, true, "which is not a chan int"}, - equalsTestCase{uint8(0), false, true, "which is not a chan int"}, - equalsTestCase{uint16(0), false, true, "which is not a chan int"}, - equalsTestCase{uint32(0), false, true, "which is not a chan int"}, - equalsTestCase{uint64(0), false, true, "which is not a chan int"}, - equalsTestCase{true, false, true, "which is not a chan int"}, - equalsTestCase{[...]int{}, false, true, "which is not a chan int"}, - equalsTestCase{func() {}, false, true, "which is not a chan int"}, - equalsTestCase{map[int]int{}, false, true, "which is not a chan int"}, - equalsTestCase{&someInt, false, true, "which is not a chan int"}, - equalsTestCase{[]int{}, false, true, "which is not a chan int"}, - equalsTestCase{"taco", false, true, "which is not a chan int"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not a chan int"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) NonNilChan() { - var nilChan1 chan int - var nilChan2 chan uint - var nonNilChan1 chan int = make(chan int) - var nonNilChan2 chan int = make(chan int) - var nonNilChan3 chan uint = make(chan uint) - - matcher := Equals(nonNilChan1) - ExpectEq(fmt.Sprintf("%v", nonNilChan1), matcher.Description()) - - cases := []equalsTestCase{ - // int channels - equalsTestCase{nonNilChan1, true, false, ""}, - equalsTestCase{nonNilChan2, false, false, ""}, - equalsTestCase{nilChan1, false, false, ""}, - - // uint channels - equalsTestCase{nilChan2, false, true, "which is not a chan int"}, - equalsTestCase{nonNilChan3, false, true, "which is not a chan int"}, - - // Other types. - equalsTestCase{0, false, true, "which is not a chan int"}, - equalsTestCase{bool(false), false, true, "which is not a chan int"}, - equalsTestCase{int(0), false, true, "which is not a chan int"}, - equalsTestCase{int8(0), false, true, "which is not a chan int"}, - equalsTestCase{int16(0), false, true, "which is not a chan int"}, - equalsTestCase{int32(0), false, true, "which is not a chan int"}, - equalsTestCase{int64(0), false, true, "which is not a chan int"}, - equalsTestCase{uint(0), false, true, "which is not a chan int"}, - equalsTestCase{uint8(0), false, true, "which is not a chan int"}, - equalsTestCase{uint16(0), false, true, "which is not a chan int"}, - equalsTestCase{uint32(0), false, true, "which is not a chan int"}, - equalsTestCase{uint64(0), false, true, "which is not a chan int"}, - equalsTestCase{true, false, true, "which is not a chan int"}, - equalsTestCase{[...]int{}, false, true, "which is not a chan int"}, - equalsTestCase{func() {}, false, true, "which is not a chan int"}, - equalsTestCase{map[int]int{}, false, true, "which is not a chan int"}, - equalsTestCase{&someInt, false, true, "which is not a chan int"}, - equalsTestCase{[]int{}, false, true, "which is not a chan int"}, - equalsTestCase{"taco", false, true, "which is not a chan int"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not a chan int"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) ChanDirection() { - var chan1 chan<- int - var chan2 <-chan int - var chan3 chan int - - matcher := Equals(chan1) - ExpectEq(fmt.Sprintf("%v", chan1), matcher.Description()) - - cases := []equalsTestCase{ - equalsTestCase{chan1, true, false, ""}, - equalsTestCase{chan2, false, true, "which is not a chan<- int"}, - equalsTestCase{chan3, false, true, "which is not a chan<- int"}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// func -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) Functions() { - func1 := func() {} - func2 := func() {} - func3 := func(x int) {} - - matcher := Equals(func1) - ExpectEq(fmt.Sprintf("%v", func1), matcher.Description()) - - cases := []equalsTestCase{ - // Functions. - equalsTestCase{func1, true, false, ""}, - equalsTestCase{func2, false, false, ""}, - equalsTestCase{func3, false, false, ""}, - - // Other types. - equalsTestCase{0, false, true, "which is not a function"}, - equalsTestCase{bool(false), false, true, "which is not a function"}, - equalsTestCase{int(0), false, true, "which is not a function"}, - equalsTestCase{int8(0), false, true, "which is not a function"}, - equalsTestCase{int16(0), false, true, "which is not a function"}, - equalsTestCase{int32(0), false, true, "which is not a function"}, - equalsTestCase{int64(0), false, true, "which is not a function"}, - equalsTestCase{uint(0), false, true, "which is not a function"}, - equalsTestCase{uint8(0), false, true, "which is not a function"}, - equalsTestCase{uint16(0), false, true, "which is not a function"}, - equalsTestCase{uint32(0), false, true, "which is not a function"}, - equalsTestCase{uint64(0), false, true, "which is not a function"}, - equalsTestCase{true, false, true, "which is not a function"}, - equalsTestCase{[...]int{}, false, true, "which is not a function"}, - equalsTestCase{map[int]int{}, false, true, "which is not a function"}, - equalsTestCase{&someInt, false, true, "which is not a function"}, - equalsTestCase{[]int{}, false, true, "which is not a function"}, - equalsTestCase{"taco", false, true, "which is not a function"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not a function"}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// map -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) NilMap() { - var nilMap1 map[int]int - var nilMap2 map[int]int - var nilMap3 map[int]uint - var nonNilMap1 map[int]int = make(map[int]int) - var nonNilMap2 map[int]uint = make(map[int]uint) - - matcher := Equals(nilMap1) - ExpectEq("map[]", matcher.Description()) - - cases := []equalsTestCase{ - // Correct type. - equalsTestCase{nilMap1, true, false, ""}, - equalsTestCase{nilMap2, true, false, ""}, - equalsTestCase{nilMap3, true, false, ""}, - equalsTestCase{nonNilMap1, false, false, ""}, - equalsTestCase{nonNilMap2, false, false, ""}, - - // Other types. - equalsTestCase{0, false, true, "which is not a map"}, - equalsTestCase{bool(false), false, true, "which is not a map"}, - equalsTestCase{int(0), false, true, "which is not a map"}, - equalsTestCase{int8(0), false, true, "which is not a map"}, - equalsTestCase{int16(0), false, true, "which is not a map"}, - equalsTestCase{int32(0), false, true, "which is not a map"}, - equalsTestCase{int64(0), false, true, "which is not a map"}, - equalsTestCase{uint(0), false, true, "which is not a map"}, - equalsTestCase{uint8(0), false, true, "which is not a map"}, - equalsTestCase{uint16(0), false, true, "which is not a map"}, - equalsTestCase{uint32(0), false, true, "which is not a map"}, - equalsTestCase{uint64(0), false, true, "which is not a map"}, - equalsTestCase{true, false, true, "which is not a map"}, - equalsTestCase{[...]int{}, false, true, "which is not a map"}, - equalsTestCase{func() {}, false, true, "which is not a map"}, - equalsTestCase{&someInt, false, true, "which is not a map"}, - equalsTestCase{[]int{}, false, true, "which is not a map"}, - equalsTestCase{"taco", false, true, "which is not a map"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not a map"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) NonNilMap() { - var nilMap1 map[int]int - var nilMap2 map[int]uint - var nonNilMap1 map[int]int = make(map[int]int) - var nonNilMap2 map[int]int = make(map[int]int) - var nonNilMap3 map[int]uint = make(map[int]uint) - - matcher := Equals(nonNilMap1) - ExpectEq("map[]", matcher.Description()) - - cases := []equalsTestCase{ - // Correct type. - equalsTestCase{nonNilMap1, true, false, ""}, - equalsTestCase{nonNilMap2, false, false, ""}, - equalsTestCase{nonNilMap3, false, false, ""}, - equalsTestCase{nilMap1, false, false, ""}, - equalsTestCase{nilMap2, false, false, ""}, - - // Other types. - equalsTestCase{0, false, true, "which is not a map"}, - equalsTestCase{bool(false), false, true, "which is not a map"}, - equalsTestCase{int(0), false, true, "which is not a map"}, - equalsTestCase{int8(0), false, true, "which is not a map"}, - equalsTestCase{int16(0), false, true, "which is not a map"}, - equalsTestCase{int32(0), false, true, "which is not a map"}, - equalsTestCase{int64(0), false, true, "which is not a map"}, - equalsTestCase{uint(0), false, true, "which is not a map"}, - equalsTestCase{uint8(0), false, true, "which is not a map"}, - equalsTestCase{uint16(0), false, true, "which is not a map"}, - equalsTestCase{uint32(0), false, true, "which is not a map"}, - equalsTestCase{uint64(0), false, true, "which is not a map"}, - equalsTestCase{true, false, true, "which is not a map"}, - equalsTestCase{[...]int{}, false, true, "which is not a map"}, - equalsTestCase{func() {}, false, true, "which is not a map"}, - equalsTestCase{&someInt, false, true, "which is not a map"}, - equalsTestCase{[]int{}, false, true, "which is not a map"}, - equalsTestCase{"taco", false, true, "which is not a map"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not a map"}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// Pointers -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) NilPointer() { - var someInt int = 17 - var someUint uint = 17 - - var nilInt1 *int - var nilInt2 *int - var nilUint *uint - var nonNilInt *int = &someInt - var nonNilUint *uint = &someUint - - matcher := Equals(nilInt1) - ExpectEq("", matcher.Description()) - - cases := []equalsTestCase{ - // Correct type. - equalsTestCase{nilInt1, true, false, ""}, - equalsTestCase{nilInt2, true, false, ""}, - equalsTestCase{nonNilInt, false, false, ""}, - - // Incorrect type. - equalsTestCase{nilUint, false, true, "which is not a *int"}, - equalsTestCase{nonNilUint, false, true, "which is not a *int"}, - - // Other types. - equalsTestCase{0, false, true, "which is not a *int"}, - equalsTestCase{bool(false), false, true, "which is not a *int"}, - equalsTestCase{int(0), false, true, "which is not a *int"}, - equalsTestCase{int8(0), false, true, "which is not a *int"}, - equalsTestCase{int16(0), false, true, "which is not a *int"}, - equalsTestCase{int32(0), false, true, "which is not a *int"}, - equalsTestCase{int64(0), false, true, "which is not a *int"}, - equalsTestCase{uint(0), false, true, "which is not a *int"}, - equalsTestCase{uint8(0), false, true, "which is not a *int"}, - equalsTestCase{uint16(0), false, true, "which is not a *int"}, - equalsTestCase{uint32(0), false, true, "which is not a *int"}, - equalsTestCase{uint64(0), false, true, "which is not a *int"}, - equalsTestCase{true, false, true, "which is not a *int"}, - equalsTestCase{[...]int{}, false, true, "which is not a *int"}, - equalsTestCase{func() {}, false, true, "which is not a *int"}, - equalsTestCase{map[int]int{}, false, true, "which is not a *int"}, - equalsTestCase{[]int{}, false, true, "which is not a *int"}, - equalsTestCase{"taco", false, true, "which is not a *int"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not a *int"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) NonNilPointer() { - var someInt int = 17 - var someOtherInt int = 17 - var someUint uint = 17 - - var nilInt *int - var nilUint *uint - var nonNilInt1 *int = &someInt - var nonNilInt2 *int = &someOtherInt - var nonNilUint *uint = &someUint - - matcher := Equals(nonNilInt1) - ExpectEq(fmt.Sprintf("%v", nonNilInt1), matcher.Description()) - - cases := []equalsTestCase{ - // Correct type. - equalsTestCase{nonNilInt1, true, false, ""}, - equalsTestCase{nonNilInt2, false, false, ""}, - equalsTestCase{nilInt, false, false, ""}, - - // Incorrect type. - equalsTestCase{nilUint, false, true, "which is not a *int"}, - equalsTestCase{nonNilUint, false, true, "which is not a *int"}, - - // Other types. - equalsTestCase{0, false, true, "which is not a *int"}, - equalsTestCase{bool(false), false, true, "which is not a *int"}, - equalsTestCase{int(0), false, true, "which is not a *int"}, - equalsTestCase{int8(0), false, true, "which is not a *int"}, - equalsTestCase{int16(0), false, true, "which is not a *int"}, - equalsTestCase{int32(0), false, true, "which is not a *int"}, - equalsTestCase{int64(0), false, true, "which is not a *int"}, - equalsTestCase{uint(0), false, true, "which is not a *int"}, - equalsTestCase{uint8(0), false, true, "which is not a *int"}, - equalsTestCase{uint16(0), false, true, "which is not a *int"}, - equalsTestCase{uint32(0), false, true, "which is not a *int"}, - equalsTestCase{uint64(0), false, true, "which is not a *int"}, - equalsTestCase{true, false, true, "which is not a *int"}, - equalsTestCase{[...]int{}, false, true, "which is not a *int"}, - equalsTestCase{func() {}, false, true, "which is not a *int"}, - equalsTestCase{map[int]int{}, false, true, "which is not a *int"}, - equalsTestCase{[]int{}, false, true, "which is not a *int"}, - equalsTestCase{"taco", false, true, "which is not a *int"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not a *int"}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// Slices -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) NilSlice() { - var nilInt1 []int - var nilInt2 []int - var nilUint []uint - - var nonNilInt []int = make([]int, 0) - var nonNilUint []uint = make([]uint, 0) - - matcher := Equals(nilInt1) - ExpectEq("[]", matcher.Description()) - - cases := []equalsTestCase{ - // Correct type. - equalsTestCase{nilInt1, true, false, ""}, - equalsTestCase{nilInt2, true, false, ""}, - equalsTestCase{nonNilInt, false, false, ""}, - - // Incorrect type. - equalsTestCase{nilUint, false, true, "which is not a []int"}, - equalsTestCase{nonNilUint, false, true, "which is not a []int"}, - - // Other types. - equalsTestCase{0, false, true, "which is not a []int"}, - equalsTestCase{bool(false), false, true, "which is not a []int"}, - equalsTestCase{int(0), false, true, "which is not a []int"}, - equalsTestCase{int8(0), false, true, "which is not a []int"}, - equalsTestCase{int16(0), false, true, "which is not a []int"}, - equalsTestCase{int32(0), false, true, "which is not a []int"}, - equalsTestCase{int64(0), false, true, "which is not a []int"}, - equalsTestCase{uint(0), false, true, "which is not a []int"}, - equalsTestCase{uint8(0), false, true, "which is not a []int"}, - equalsTestCase{uint16(0), false, true, "which is not a []int"}, - equalsTestCase{uint32(0), false, true, "which is not a []int"}, - equalsTestCase{uint64(0), false, true, "which is not a []int"}, - equalsTestCase{true, false, true, "which is not a []int"}, - equalsTestCase{[...]int{}, false, true, "which is not a []int"}, - equalsTestCase{func() {}, false, true, "which is not a []int"}, - equalsTestCase{map[int]int{}, false, true, "which is not a []int"}, - equalsTestCase{"taco", false, true, "which is not a []int"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not a []int"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) NonNilSlice() { - nonNil := make([]int, 0) - f := func() { Equals(nonNil) } - ExpectThat(f, Panics(HasSubstr("non-nil slice"))) -} - -//////////////////////////////////////////////////////////////////////// -// string -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) String() { - partial := "taco" - expected := fmt.Sprintf("%s%d", partial, 1) - - matcher := Equals(expected) - ExpectEq("taco1", matcher.Description()) - - type stringAlias string - - cases := []equalsTestCase{ - // Correct types. - equalsTestCase{"taco1", true, false, ""}, - equalsTestCase{"taco" + "1", true, false, ""}, - equalsTestCase{expected, true, false, ""}, - equalsTestCase{stringAlias("taco1"), true, false, ""}, - - equalsTestCase{"", false, false, ""}, - equalsTestCase{"taco", false, false, ""}, - equalsTestCase{"taco1\x00", false, false, ""}, - equalsTestCase{"taco2", false, false, ""}, - equalsTestCase{stringAlias("taco2"), false, false, ""}, - - // Other types. - equalsTestCase{0, false, true, "which is not a string"}, - equalsTestCase{bool(false), false, true, "which is not a string"}, - equalsTestCase{int(0), false, true, "which is not a string"}, - equalsTestCase{int8(0), false, true, "which is not a string"}, - equalsTestCase{int16(0), false, true, "which is not a string"}, - equalsTestCase{int32(0), false, true, "which is not a string"}, - equalsTestCase{int64(0), false, true, "which is not a string"}, - equalsTestCase{uint(0), false, true, "which is not a string"}, - equalsTestCase{uint8(0), false, true, "which is not a string"}, - equalsTestCase{uint16(0), false, true, "which is not a string"}, - equalsTestCase{uint32(0), false, true, "which is not a string"}, - equalsTestCase{uint64(0), false, true, "which is not a string"}, - equalsTestCase{true, false, true, "which is not a string"}, - equalsTestCase{[...]int{}, false, true, "which is not a string"}, - equalsTestCase{func() {}, false, true, "which is not a string"}, - equalsTestCase{map[int]int{}, false, true, "which is not a string"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not a string"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) StringAlias() { - type stringAlias string - - matcher := Equals(stringAlias("taco")) - ExpectEq("taco", matcher.Description()) - - cases := []equalsTestCase{ - // Correct types. - equalsTestCase{stringAlias("taco"), true, false, ""}, - equalsTestCase{"taco", true, false, ""}, - - equalsTestCase{"burrito", false, false, ""}, - equalsTestCase{stringAlias("burrito"), false, false, ""}, - - // Other types. - equalsTestCase{0, false, true, "which is not a string"}, - equalsTestCase{bool(false), false, true, "which is not a string"}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// struct -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) Struct() { - type someStruct struct{ foo uint } - f := func() { Equals(someStruct{17}) } - ExpectThat(f, Panics(HasSubstr("unsupported kind struct"))) -} - -//////////////////////////////////////////////////////////////////////// -// unsafe.Pointer -//////////////////////////////////////////////////////////////////////// - -func (t *EqualsTest) NilUnsafePointer() { - someInt := int(17) - - var nilPtr1 unsafe.Pointer - var nilPtr2 unsafe.Pointer - var nonNilPtr unsafe.Pointer = unsafe.Pointer(&someInt) - - matcher := Equals(nilPtr1) - ExpectEq("", matcher.Description()) - - cases := []equalsTestCase{ - // Correct type. - equalsTestCase{nilPtr1, true, false, ""}, - equalsTestCase{nilPtr2, true, false, ""}, - equalsTestCase{nonNilPtr, false, false, ""}, - - // Other types. - equalsTestCase{0, false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{bool(false), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{int(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{int8(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{int16(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{int32(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{int64(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{uint(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{uint8(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{uint16(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{uint32(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{uint64(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{uintptr(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{true, false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{[...]int{}, false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{make(chan int), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{func() {}, false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{map[int]int{}, false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{&someInt, false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{[]int{}, false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{"taco", false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not a unsafe.Pointer"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *EqualsTest) NonNilUnsafePointer() { - someInt := int(17) - someOtherInt := int(17) - - var nilPtr unsafe.Pointer - var nonNilPtr1 unsafe.Pointer = unsafe.Pointer(&someInt) - var nonNilPtr2 unsafe.Pointer = unsafe.Pointer(&someOtherInt) - - matcher := Equals(nonNilPtr1) - ExpectEq(fmt.Sprintf("%v", nonNilPtr1), matcher.Description()) - - cases := []equalsTestCase{ - // Correct type. - equalsTestCase{nonNilPtr1, true, false, ""}, - equalsTestCase{nonNilPtr2, false, false, ""}, - equalsTestCase{nilPtr, false, false, ""}, - - // Other types. - equalsTestCase{0, false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{bool(false), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{int(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{int8(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{int16(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{int32(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{int64(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{uint(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{uint8(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{uint16(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{uint32(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{uint64(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{uintptr(0), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{true, false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{[...]int{}, false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{make(chan int), false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{func() {}, false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{map[int]int{}, false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{&someInt, false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{[]int{}, false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{"taco", false, true, "which is not a unsafe.Pointer"}, - equalsTestCase{equalsTestCase{}, false, true, "which is not a unsafe.Pointer"}, - } - - t.checkTestCases(matcher, cases) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/error_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/error_test.go deleted file mode 100644 index 31eb685e8d6..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/error_test.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "errors" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type ErrorTest struct { - matcherCalled bool - suppliedCandidate interface{} - wrappedError error - - matcher Matcher -} - -func init() { RegisterTestSuite(&ErrorTest{}) } - -func (t *ErrorTest) SetUp(i *TestInfo) { - wrapped := &fakeMatcher{ - func(c interface{}) error { - t.matcherCalled = true - t.suppliedCandidate = c - return t.wrappedError - }, - "is foo", - } - - t.matcher = Error(wrapped) -} - -func isFatal(err error) bool { - _, isFatal := err.(*FatalError) - return isFatal -} - -//////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////// - -func (t *ErrorTest) Description() { - ExpectThat(t.matcher.Description(), Equals("error is foo")) -} - -func (t *ErrorTest) CandidateIsNil() { - err := t.matcher.Matches(nil) - - ExpectThat(t.matcherCalled, Equals(false)) - ExpectThat(err.Error(), Equals("which is not an error")) - ExpectTrue(isFatal(err)) -} - -func (t *ErrorTest) CandidateIsString() { - err := t.matcher.Matches("taco") - - ExpectThat(t.matcherCalled, Equals(false)) - ExpectThat(err.Error(), Equals("which is not an error")) - ExpectTrue(isFatal(err)) -} - -func (t *ErrorTest) CallsWrappedMatcher() { - candidate := errors.New("taco") - t.matcher.Matches(candidate) - - ExpectThat(t.matcherCalled, Equals(true)) - ExpectThat(t.suppliedCandidate, Equals("taco")) -} - -func (t *ErrorTest) ReturnsWrappedMatcherResult() { - t.wrappedError = errors.New("burrito") - err := t.matcher.Matches(errors.New("")) - ExpectThat(err, Equals(t.wrappedError)) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/greater_or_equal_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/greater_or_equal_test.go deleted file mode 100644 index e2fe137f42e..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/greater_or_equal_test.go +++ /dev/null @@ -1,1059 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "math" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type GreaterOrEqualTest struct { -} - -func init() { RegisterTestSuite(&GreaterOrEqualTest{}) } - -type geTestCase struct { - candidate interface{} - expectedResult bool - shouldBeFatal bool - expectedError string -} - -func (t *GreaterOrEqualTest) checkTestCases(matcher Matcher, cases []geTestCase) { - for i, c := range cases { - err := matcher.Matches(c.candidate) - - ExpectThat( - (err == nil), - Equals(c.expectedResult), - "Case %d (candidate %v)", - i, - c.candidate) - - if err == nil { - continue - } - - _, isFatal := err.(*FatalError) - ExpectEq( - c.shouldBeFatal, - isFatal, - "Case %d (candidate %v)", - i, - c.candidate) - - ExpectThat( - err, - Error(Equals(c.expectedError)), - "Case %d (candidate %v)", - i, - c.candidate) - } -} - -//////////////////////////////////////////////////////////////////////// -// Integer literals -//////////////////////////////////////////////////////////////////////// - -func (t *GreaterOrEqualTest) IntegerCandidateBadTypes() { - matcher := GreaterOrEqual(int(-150)) - - cases := []geTestCase{ - geTestCase{true, false, true, "which is not comparable"}, - geTestCase{uintptr(17), false, true, "which is not comparable"}, - geTestCase{complex64(-151), false, true, "which is not comparable"}, - geTestCase{complex128(-151), false, true, "which is not comparable"}, - geTestCase{[...]int{-151}, false, true, "which is not comparable"}, - geTestCase{make(chan int), false, true, "which is not comparable"}, - geTestCase{func() {}, false, true, "which is not comparable"}, - geTestCase{map[int]int{}, false, true, "which is not comparable"}, - geTestCase{&geTestCase{}, false, true, "which is not comparable"}, - geTestCase{make([]int, 0), false, true, "which is not comparable"}, - geTestCase{"-151", false, true, "which is not comparable"}, - geTestCase{geTestCase{}, false, true, "which is not comparable"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterOrEqualTest) FloatCandidateBadTypes() { - matcher := GreaterOrEqual(float32(-150)) - - cases := []geTestCase{ - geTestCase{true, false, true, "which is not comparable"}, - geTestCase{uintptr(17), false, true, "which is not comparable"}, - geTestCase{complex64(-151), false, true, "which is not comparable"}, - geTestCase{complex128(-151), false, true, "which is not comparable"}, - geTestCase{[...]int{-151}, false, true, "which is not comparable"}, - geTestCase{make(chan int), false, true, "which is not comparable"}, - geTestCase{func() {}, false, true, "which is not comparable"}, - geTestCase{map[int]int{}, false, true, "which is not comparable"}, - geTestCase{&geTestCase{}, false, true, "which is not comparable"}, - geTestCase{make([]int, 0), false, true, "which is not comparable"}, - geTestCase{"-151", false, true, "which is not comparable"}, - geTestCase{geTestCase{}, false, true, "which is not comparable"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterOrEqualTest) StringCandidateBadTypes() { - matcher := GreaterOrEqual("17") - - cases := []geTestCase{ - geTestCase{true, false, true, "which is not comparable"}, - geTestCase{int(0), false, true, "which is not comparable"}, - geTestCase{int8(0), false, true, "which is not comparable"}, - geTestCase{int16(0), false, true, "which is not comparable"}, - geTestCase{int32(0), false, true, "which is not comparable"}, - geTestCase{int64(0), false, true, "which is not comparable"}, - geTestCase{uint(0), false, true, "which is not comparable"}, - geTestCase{uint8(0), false, true, "which is not comparable"}, - geTestCase{uint16(0), false, true, "which is not comparable"}, - geTestCase{uint32(0), false, true, "which is not comparable"}, - geTestCase{uint64(0), false, true, "which is not comparable"}, - geTestCase{uintptr(17), false, true, "which is not comparable"}, - geTestCase{float32(0), false, true, "which is not comparable"}, - geTestCase{float64(0), false, true, "which is not comparable"}, - geTestCase{complex64(-151), false, true, "which is not comparable"}, - geTestCase{complex128(-151), false, true, "which is not comparable"}, - geTestCase{[...]int{-151}, false, true, "which is not comparable"}, - geTestCase{make(chan int), false, true, "which is not comparable"}, - geTestCase{func() {}, false, true, "which is not comparable"}, - geTestCase{map[int]int{}, false, true, "which is not comparable"}, - geTestCase{&geTestCase{}, false, true, "which is not comparable"}, - geTestCase{make([]int, 0), false, true, "which is not comparable"}, - geTestCase{geTestCase{}, false, true, "which is not comparable"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterOrEqualTest) BadArgument() { - panicked := false - - defer func() { - ExpectThat(panicked, Equals(true)) - }() - - defer func() { - if r := recover(); r != nil { - panicked = true - } - }() - - GreaterOrEqual(complex128(0)) -} - -//////////////////////////////////////////////////////////////////////// -// Integer literals -//////////////////////////////////////////////////////////////////////// - -func (t *GreaterOrEqualTest) NegativeIntegerLiteral() { - matcher := GreaterOrEqual(-150) - desc := matcher.Description() - expectedDesc := "greater than or equal to -150" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []geTestCase{ - // Signed integers. - geTestCase{-(1 << 30), false, false, ""}, - geTestCase{-151, false, false, ""}, - geTestCase{-150, true, false, ""}, - geTestCase{0, true, false, ""}, - geTestCase{17, true, false, ""}, - - geTestCase{int(-(1 << 30)), false, false, ""}, - geTestCase{int(-151), false, false, ""}, - geTestCase{int(-150), true, false, ""}, - geTestCase{int(0), true, false, ""}, - geTestCase{int(17), true, false, ""}, - - geTestCase{int8(-127), true, false, ""}, - geTestCase{int8(0), true, false, ""}, - geTestCase{int8(17), true, false, ""}, - - geTestCase{int16(-(1 << 14)), false, false, ""}, - geTestCase{int16(-151), false, false, ""}, - geTestCase{int16(-150), true, false, ""}, - geTestCase{int16(0), true, false, ""}, - geTestCase{int16(17), true, false, ""}, - - geTestCase{int32(-(1 << 30)), false, false, ""}, - geTestCase{int32(-151), false, false, ""}, - geTestCase{int32(-150), true, false, ""}, - geTestCase{int32(0), true, false, ""}, - geTestCase{int32(17), true, false, ""}, - - geTestCase{int64(-(1 << 30)), false, false, ""}, - geTestCase{int64(-151), false, false, ""}, - geTestCase{int64(-150), true, false, ""}, - geTestCase{int64(0), true, false, ""}, - geTestCase{int64(17), true, false, ""}, - - // Unsigned integers. - geTestCase{uint((1 << 32) - 151), true, false, ""}, - geTestCase{uint(0), true, false, ""}, - geTestCase{uint(17), true, false, ""}, - - geTestCase{uint8(0), true, false, ""}, - geTestCase{uint8(17), true, false, ""}, - geTestCase{uint8(253), true, false, ""}, - - geTestCase{uint16((1 << 16) - 151), true, false, ""}, - geTestCase{uint16(0), true, false, ""}, - geTestCase{uint16(17), true, false, ""}, - - geTestCase{uint32((1 << 32) - 151), true, false, ""}, - geTestCase{uint32(0), true, false, ""}, - geTestCase{uint32(17), true, false, ""}, - - geTestCase{uint64((1 << 64) - 151), true, false, ""}, - geTestCase{uint64(0), true, false, ""}, - geTestCase{uint64(17), true, false, ""}, - - // Floating point. - geTestCase{float32(-(1 << 30)), false, false, ""}, - geTestCase{float32(-151), false, false, ""}, - geTestCase{float32(-150.1), false, false, ""}, - geTestCase{float32(-150), true, false, ""}, - geTestCase{float32(-149.9), true, false, ""}, - geTestCase{float32(0), true, false, ""}, - geTestCase{float32(17), true, false, ""}, - geTestCase{float32(160), true, false, ""}, - - geTestCase{float64(-(1 << 30)), false, false, ""}, - geTestCase{float64(-151), false, false, ""}, - geTestCase{float64(-150.1), false, false, ""}, - geTestCase{float64(-150), true, false, ""}, - geTestCase{float64(-149.9), true, false, ""}, - geTestCase{float64(0), true, false, ""}, - geTestCase{float64(17), true, false, ""}, - geTestCase{float64(160), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterOrEqualTest) ZeroIntegerLiteral() { - matcher := GreaterOrEqual(0) - desc := matcher.Description() - expectedDesc := "greater than or equal to 0" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []geTestCase{ - // Signed integers. - geTestCase{-(1 << 30), false, false, ""}, - geTestCase{-1, false, false, ""}, - geTestCase{0, true, false, ""}, - geTestCase{1, true, false, ""}, - geTestCase{17, true, false, ""}, - geTestCase{(1 << 30), true, false, ""}, - - geTestCase{int(-(1 << 30)), false, false, ""}, - geTestCase{int(-1), false, false, ""}, - geTestCase{int(0), true, false, ""}, - geTestCase{int(1), true, false, ""}, - geTestCase{int(17), true, false, ""}, - - geTestCase{int8(-1), false, false, ""}, - geTestCase{int8(0), true, false, ""}, - geTestCase{int8(1), true, false, ""}, - - geTestCase{int16(-(1 << 14)), false, false, ""}, - geTestCase{int16(-1), false, false, ""}, - geTestCase{int16(0), true, false, ""}, - geTestCase{int16(1), true, false, ""}, - geTestCase{int16(17), true, false, ""}, - - geTestCase{int32(-(1 << 30)), false, false, ""}, - geTestCase{int32(-1), false, false, ""}, - geTestCase{int32(0), true, false, ""}, - geTestCase{int32(1), true, false, ""}, - geTestCase{int32(17), true, false, ""}, - - geTestCase{int64(-(1 << 30)), false, false, ""}, - geTestCase{int64(-1), false, false, ""}, - geTestCase{int64(0), true, false, ""}, - geTestCase{int64(1), true, false, ""}, - geTestCase{int64(17), true, false, ""}, - - // Unsigned integers. - geTestCase{uint((1 << 32) - 1), true, false, ""}, - geTestCase{uint(0), true, false, ""}, - geTestCase{uint(17), true, false, ""}, - - geTestCase{uint8(0), true, false, ""}, - geTestCase{uint8(17), true, false, ""}, - geTestCase{uint8(253), true, false, ""}, - - geTestCase{uint16((1 << 16) - 1), true, false, ""}, - geTestCase{uint16(0), true, false, ""}, - geTestCase{uint16(17), true, false, ""}, - - geTestCase{uint32((1 << 32) - 1), true, false, ""}, - geTestCase{uint32(0), true, false, ""}, - geTestCase{uint32(17), true, false, ""}, - - geTestCase{uint64((1 << 64) - 1), true, false, ""}, - geTestCase{uint64(0), true, false, ""}, - geTestCase{uint64(17), true, false, ""}, - - // Floating point. - geTestCase{float32(-(1 << 30)), false, false, ""}, - geTestCase{float32(-1), false, false, ""}, - geTestCase{float32(-0.1), false, false, ""}, - geTestCase{float32(-0.0), true, false, ""}, - geTestCase{float32(0), true, false, ""}, - geTestCase{float32(0.1), true, false, ""}, - geTestCase{float32(17), true, false, ""}, - geTestCase{float32(160), true, false, ""}, - - geTestCase{float64(-(1 << 30)), false, false, ""}, - geTestCase{float64(-1), false, false, ""}, - geTestCase{float64(-0.1), false, false, ""}, - geTestCase{float64(-0), true, false, ""}, - geTestCase{float64(0), true, false, ""}, - geTestCase{float64(17), true, false, ""}, - geTestCase{float64(160), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterOrEqualTest) PositiveIntegerLiteral() { - matcher := GreaterOrEqual(150) - desc := matcher.Description() - expectedDesc := "greater than or equal to 150" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []geTestCase{ - // Signed integers. - geTestCase{-1, false, false, ""}, - geTestCase{149, false, false, ""}, - geTestCase{150, true, false, ""}, - geTestCase{151, true, false, ""}, - - geTestCase{int(-1), false, false, ""}, - geTestCase{int(149), false, false, ""}, - geTestCase{int(150), true, false, ""}, - geTestCase{int(151), true, false, ""}, - - geTestCase{int8(-1), false, false, ""}, - geTestCase{int8(0), false, false, ""}, - geTestCase{int8(17), false, false, ""}, - geTestCase{int8(127), false, false, ""}, - - geTestCase{int16(-1), false, false, ""}, - geTestCase{int16(149), false, false, ""}, - geTestCase{int16(150), true, false, ""}, - geTestCase{int16(151), true, false, ""}, - - geTestCase{int32(-1), false, false, ""}, - geTestCase{int32(149), false, false, ""}, - geTestCase{int32(150), true, false, ""}, - geTestCase{int32(151), true, false, ""}, - - geTestCase{int64(-1), false, false, ""}, - geTestCase{int64(149), false, false, ""}, - geTestCase{int64(150), true, false, ""}, - geTestCase{int64(151), true, false, ""}, - - // Unsigned integers. - geTestCase{uint(0), false, false, ""}, - geTestCase{uint(149), false, false, ""}, - geTestCase{uint(150), true, false, ""}, - geTestCase{uint(151), true, false, ""}, - - geTestCase{uint8(0), false, false, ""}, - geTestCase{uint8(127), false, false, ""}, - - geTestCase{uint16(0), false, false, ""}, - geTestCase{uint16(149), false, false, ""}, - geTestCase{uint16(150), true, false, ""}, - geTestCase{uint16(151), true, false, ""}, - - geTestCase{uint32(0), false, false, ""}, - geTestCase{uint32(149), false, false, ""}, - geTestCase{uint32(150), true, false, ""}, - geTestCase{uint32(151), true, false, ""}, - - geTestCase{uint64(0), false, false, ""}, - geTestCase{uint64(149), false, false, ""}, - geTestCase{uint64(150), true, false, ""}, - geTestCase{uint64(151), true, false, ""}, - - // Floating point. - geTestCase{float32(-1), false, false, ""}, - geTestCase{float32(149), false, false, ""}, - geTestCase{float32(149.9), false, false, ""}, - geTestCase{float32(150), true, false, ""}, - geTestCase{float32(150.1), true, false, ""}, - geTestCase{float32(151), true, false, ""}, - - geTestCase{float64(-1), false, false, ""}, - geTestCase{float64(149), false, false, ""}, - geTestCase{float64(149.9), false, false, ""}, - geTestCase{float64(150), true, false, ""}, - geTestCase{float64(150.1), true, false, ""}, - geTestCase{float64(151), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// Float literals -//////////////////////////////////////////////////////////////////////// - -func (t *GreaterOrEqualTest) NegativeFloatLiteral() { - matcher := GreaterOrEqual(-150.1) - desc := matcher.Description() - expectedDesc := "greater than or equal to -150.1" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []geTestCase{ - // Signed integers. - geTestCase{-(1 << 30), false, false, ""}, - geTestCase{-151, false, false, ""}, - geTestCase{-150, true, false, ""}, - geTestCase{0, true, false, ""}, - geTestCase{17, true, false, ""}, - - geTestCase{int(-(1 << 30)), false, false, ""}, - geTestCase{int(-151), false, false, ""}, - geTestCase{int(-150), true, false, ""}, - geTestCase{int(0), true, false, ""}, - geTestCase{int(17), true, false, ""}, - - geTestCase{int8(-127), true, false, ""}, - geTestCase{int8(0), true, false, ""}, - geTestCase{int8(17), true, false, ""}, - - geTestCase{int16(-(1 << 14)), false, false, ""}, - geTestCase{int16(-151), false, false, ""}, - geTestCase{int16(-150), true, false, ""}, - geTestCase{int16(0), true, false, ""}, - geTestCase{int16(17), true, false, ""}, - - geTestCase{int32(-(1 << 30)), false, false, ""}, - geTestCase{int32(-151), false, false, ""}, - geTestCase{int32(-150), true, false, ""}, - geTestCase{int32(0), true, false, ""}, - geTestCase{int32(17), true, false, ""}, - - geTestCase{int64(-(1 << 30)), false, false, ""}, - geTestCase{int64(-151), false, false, ""}, - geTestCase{int64(-150), true, false, ""}, - geTestCase{int64(0), true, false, ""}, - geTestCase{int64(17), true, false, ""}, - - // Unsigned integers. - geTestCase{uint((1 << 32) - 151), true, false, ""}, - geTestCase{uint(0), true, false, ""}, - geTestCase{uint(17), true, false, ""}, - - geTestCase{uint8(0), true, false, ""}, - geTestCase{uint8(17), true, false, ""}, - geTestCase{uint8(253), true, false, ""}, - - geTestCase{uint16((1 << 16) - 151), true, false, ""}, - geTestCase{uint16(0), true, false, ""}, - geTestCase{uint16(17), true, false, ""}, - - geTestCase{uint32((1 << 32) - 151), true, false, ""}, - geTestCase{uint32(0), true, false, ""}, - geTestCase{uint32(17), true, false, ""}, - - geTestCase{uint64((1 << 64) - 151), true, false, ""}, - geTestCase{uint64(0), true, false, ""}, - geTestCase{uint64(17), true, false, ""}, - - // Floating point. - geTestCase{float32(-(1 << 30)), false, false, ""}, - geTestCase{float32(-151), false, false, ""}, - geTestCase{float32(-150.2), false, false, ""}, - geTestCase{float32(-150.1), true, false, ""}, - geTestCase{float32(-150), true, false, ""}, - geTestCase{float32(0), true, false, ""}, - geTestCase{float32(17), true, false, ""}, - geTestCase{float32(160), true, false, ""}, - - geTestCase{float64(-(1 << 30)), false, false, ""}, - geTestCase{float64(-151), false, false, ""}, - geTestCase{float64(-150.2), false, false, ""}, - geTestCase{float64(-150.1), true, false, ""}, - geTestCase{float64(-150), true, false, ""}, - geTestCase{float64(0), true, false, ""}, - geTestCase{float64(17), true, false, ""}, - geTestCase{float64(160), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterOrEqualTest) PositiveFloatLiteral() { - matcher := GreaterOrEqual(149.9) - desc := matcher.Description() - expectedDesc := "greater than or equal to 149.9" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []geTestCase{ - // Signed integers. - geTestCase{-1, false, false, ""}, - geTestCase{149, false, false, ""}, - geTestCase{150, true, false, ""}, - geTestCase{151, true, false, ""}, - - geTestCase{int(-1), false, false, ""}, - geTestCase{int(149), false, false, ""}, - geTestCase{int(150), true, false, ""}, - geTestCase{int(151), true, false, ""}, - - geTestCase{int8(-1), false, false, ""}, - geTestCase{int8(0), false, false, ""}, - geTestCase{int8(17), false, false, ""}, - geTestCase{int8(127), false, false, ""}, - - geTestCase{int16(-1), false, false, ""}, - geTestCase{int16(149), false, false, ""}, - geTestCase{int16(150), true, false, ""}, - geTestCase{int16(151), true, false, ""}, - - geTestCase{int32(-1), false, false, ""}, - geTestCase{int32(149), false, false, ""}, - geTestCase{int32(150), true, false, ""}, - geTestCase{int32(151), true, false, ""}, - - geTestCase{int64(-1), false, false, ""}, - geTestCase{int64(149), false, false, ""}, - geTestCase{int64(150), true, false, ""}, - geTestCase{int64(151), true, false, ""}, - - // Unsigned integers. - geTestCase{uint(0), false, false, ""}, - geTestCase{uint(149), false, false, ""}, - geTestCase{uint(150), true, false, ""}, - geTestCase{uint(151), true, false, ""}, - - geTestCase{uint8(0), false, false, ""}, - geTestCase{uint8(127), false, false, ""}, - - geTestCase{uint16(0), false, false, ""}, - geTestCase{uint16(149), false, false, ""}, - geTestCase{uint16(150), true, false, ""}, - geTestCase{uint16(151), true, false, ""}, - - geTestCase{uint32(0), false, false, ""}, - geTestCase{uint32(149), false, false, ""}, - geTestCase{uint32(150), true, false, ""}, - geTestCase{uint32(151), true, false, ""}, - - geTestCase{uint64(0), false, false, ""}, - geTestCase{uint64(149), false, false, ""}, - geTestCase{uint64(150), true, false, ""}, - geTestCase{uint64(151), true, false, ""}, - - // Floating point. - geTestCase{float32(-1), false, false, ""}, - geTestCase{float32(149), false, false, ""}, - geTestCase{float32(149.8), false, false, ""}, - geTestCase{float32(149.9), true, false, ""}, - geTestCase{float32(150), true, false, ""}, - geTestCase{float32(151), true, false, ""}, - - geTestCase{float64(-1), false, false, ""}, - geTestCase{float64(149), false, false, ""}, - geTestCase{float64(149.8), false, false, ""}, - geTestCase{float64(149.9), true, false, ""}, - geTestCase{float64(150), true, false, ""}, - geTestCase{float64(151), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// Subtle cases -//////////////////////////////////////////////////////////////////////// - -func (t *GreaterOrEqualTest) Int64NotExactlyRepresentableBySinglePrecision() { - // Single-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^25-1, 2^25+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo25 = 1 << 25 - matcher := GreaterOrEqual(int64(kTwoTo25 + 1)) - - desc := matcher.Description() - expectedDesc := "greater than or equal to 33554433" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []geTestCase{ - // Signed integers. - geTestCase{-1, false, false, ""}, - geTestCase{kTwoTo25 + 0, false, false, ""}, - geTestCase{kTwoTo25 + 1, true, false, ""}, - geTestCase{kTwoTo25 + 2, true, false, ""}, - - geTestCase{int(-1), false, false, ""}, - geTestCase{int(kTwoTo25 + 0), false, false, ""}, - geTestCase{int(kTwoTo25 + 1), true, false, ""}, - geTestCase{int(kTwoTo25 + 2), true, false, ""}, - - geTestCase{int8(-1), false, false, ""}, - geTestCase{int8(127), false, false, ""}, - - geTestCase{int16(-1), false, false, ""}, - geTestCase{int16(0), false, false, ""}, - geTestCase{int16(32767), false, false, ""}, - - geTestCase{int32(-1), false, false, ""}, - geTestCase{int32(kTwoTo25 + 0), false, false, ""}, - geTestCase{int32(kTwoTo25 + 1), true, false, ""}, - geTestCase{int32(kTwoTo25 + 2), true, false, ""}, - - geTestCase{int64(-1), false, false, ""}, - geTestCase{int64(kTwoTo25 + 0), false, false, ""}, - geTestCase{int64(kTwoTo25 + 1), true, false, ""}, - geTestCase{int64(kTwoTo25 + 2), true, false, ""}, - - // Unsigned integers. - geTestCase{uint(0), false, false, ""}, - geTestCase{uint(kTwoTo25 + 0), false, false, ""}, - geTestCase{uint(kTwoTo25 + 1), true, false, ""}, - geTestCase{uint(kTwoTo25 + 2), true, false, ""}, - - geTestCase{uint8(0), false, false, ""}, - geTestCase{uint8(255), false, false, ""}, - - geTestCase{uint16(0), false, false, ""}, - geTestCase{uint16(65535), false, false, ""}, - - geTestCase{uint32(0), false, false, ""}, - geTestCase{uint32(kTwoTo25 + 0), false, false, ""}, - geTestCase{uint32(kTwoTo25 + 1), true, false, ""}, - geTestCase{uint32(kTwoTo25 + 2), true, false, ""}, - - geTestCase{uint64(0), false, false, ""}, - geTestCase{uint64(kTwoTo25 + 0), false, false, ""}, - geTestCase{uint64(kTwoTo25 + 1), true, false, ""}, - geTestCase{uint64(kTwoTo25 + 2), true, false, ""}, - - // Floating point. - geTestCase{float32(-1), false, false, ""}, - geTestCase{float32(kTwoTo25 - 2), false, false, ""}, - geTestCase{float32(kTwoTo25 - 1), true, false, ""}, - geTestCase{float32(kTwoTo25 + 0), true, false, ""}, - geTestCase{float32(kTwoTo25 + 1), true, false, ""}, - geTestCase{float32(kTwoTo25 + 2), true, false, ""}, - geTestCase{float32(kTwoTo25 + 3), true, false, ""}, - - geTestCase{float64(-1), false, false, ""}, - geTestCase{float64(kTwoTo25 - 2), false, false, ""}, - geTestCase{float64(kTwoTo25 - 1), false, false, ""}, - geTestCase{float64(kTwoTo25 + 0), false, false, ""}, - geTestCase{float64(kTwoTo25 + 1), true, false, ""}, - geTestCase{float64(kTwoTo25 + 2), true, false, ""}, - geTestCase{float64(kTwoTo25 + 3), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterOrEqualTest) Int64NotExactlyRepresentableByDoublePrecision() { - // Double-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^54-1, 2^54+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo54 = 1 << 54 - matcher := GreaterOrEqual(int64(kTwoTo54 + 1)) - - desc := matcher.Description() - expectedDesc := "greater than or equal to 18014398509481985" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []geTestCase{ - // Signed integers. - geTestCase{-1, false, false, ""}, - geTestCase{1 << 30, false, false, ""}, - - geTestCase{int(-1), false, false, ""}, - geTestCase{int(math.MaxInt32), false, false, ""}, - - geTestCase{int8(-1), false, false, ""}, - geTestCase{int8(127), false, false, ""}, - - geTestCase{int16(-1), false, false, ""}, - geTestCase{int16(0), false, false, ""}, - geTestCase{int16(32767), false, false, ""}, - - geTestCase{int32(-1), false, false, ""}, - geTestCase{int32(math.MaxInt32), false, false, ""}, - - geTestCase{int64(-1), false, false, ""}, - geTestCase{int64(kTwoTo54 - 1), false, false, ""}, - geTestCase{int64(kTwoTo54 + 0), false, false, ""}, - geTestCase{int64(kTwoTo54 + 1), true, false, ""}, - geTestCase{int64(kTwoTo54 + 2), true, false, ""}, - - // Unsigned integers. - geTestCase{uint(0), false, false, ""}, - geTestCase{uint(math.MaxUint32), false, false, ""}, - - geTestCase{uint8(0), false, false, ""}, - geTestCase{uint8(255), false, false, ""}, - - geTestCase{uint16(0), false, false, ""}, - geTestCase{uint16(65535), false, false, ""}, - - geTestCase{uint32(0), false, false, ""}, - geTestCase{uint32(math.MaxUint32), false, false, ""}, - - geTestCase{uint64(0), false, false, ""}, - geTestCase{uint64(kTwoTo54 - 1), false, false, ""}, - geTestCase{uint64(kTwoTo54 + 0), false, false, ""}, - geTestCase{uint64(kTwoTo54 + 1), true, false, ""}, - geTestCase{uint64(kTwoTo54 + 2), true, false, ""}, - - // Floating point. - geTestCase{float64(-1), false, false, ""}, - geTestCase{float64(kTwoTo54 - 2), false, false, ""}, - geTestCase{float64(kTwoTo54 - 1), true, false, ""}, - geTestCase{float64(kTwoTo54 + 0), true, false, ""}, - geTestCase{float64(kTwoTo54 + 1), true, false, ""}, - geTestCase{float64(kTwoTo54 + 2), true, false, ""}, - geTestCase{float64(kTwoTo54 + 3), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterOrEqualTest) Uint64NotExactlyRepresentableBySinglePrecision() { - // Single-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^25-1, 2^25+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo25 = 1 << 25 - matcher := GreaterOrEqual(uint64(kTwoTo25 + 1)) - - desc := matcher.Description() - expectedDesc := "greater than or equal to 33554433" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []geTestCase{ - // Signed integers. - geTestCase{-1, false, false, ""}, - geTestCase{kTwoTo25 + 0, false, false, ""}, - geTestCase{kTwoTo25 + 1, true, false, ""}, - geTestCase{kTwoTo25 + 2, true, false, ""}, - - geTestCase{int(-1), false, false, ""}, - geTestCase{int(kTwoTo25 + 0), false, false, ""}, - geTestCase{int(kTwoTo25 + 1), true, false, ""}, - geTestCase{int(kTwoTo25 + 2), true, false, ""}, - - geTestCase{int8(-1), false, false, ""}, - geTestCase{int8(127), false, false, ""}, - - geTestCase{int16(-1), false, false, ""}, - geTestCase{int16(0), false, false, ""}, - geTestCase{int16(32767), false, false, ""}, - - geTestCase{int32(-1), false, false, ""}, - geTestCase{int32(kTwoTo25 + 0), false, false, ""}, - geTestCase{int32(kTwoTo25 + 1), true, false, ""}, - geTestCase{int32(kTwoTo25 + 2), true, false, ""}, - - geTestCase{int64(-1), false, false, ""}, - geTestCase{int64(kTwoTo25 + 0), false, false, ""}, - geTestCase{int64(kTwoTo25 + 1), true, false, ""}, - geTestCase{int64(kTwoTo25 + 2), true, false, ""}, - - // Unsigned integers. - geTestCase{uint(0), false, false, ""}, - geTestCase{uint(kTwoTo25 + 0), false, false, ""}, - geTestCase{uint(kTwoTo25 + 1), true, false, ""}, - geTestCase{uint(kTwoTo25 + 2), true, false, ""}, - - geTestCase{uint8(0), false, false, ""}, - geTestCase{uint8(255), false, false, ""}, - - geTestCase{uint16(0), false, false, ""}, - geTestCase{uint16(65535), false, false, ""}, - - geTestCase{uint32(0), false, false, ""}, - geTestCase{uint32(kTwoTo25 + 0), false, false, ""}, - geTestCase{uint32(kTwoTo25 + 1), true, false, ""}, - geTestCase{uint32(kTwoTo25 + 2), true, false, ""}, - - geTestCase{uint64(0), false, false, ""}, - geTestCase{uint64(kTwoTo25 + 0), false, false, ""}, - geTestCase{uint64(kTwoTo25 + 1), true, false, ""}, - geTestCase{uint64(kTwoTo25 + 2), true, false, ""}, - - // Floating point. - geTestCase{float32(-1), false, false, ""}, - geTestCase{float32(kTwoTo25 - 2), false, false, ""}, - geTestCase{float32(kTwoTo25 - 1), true, false, ""}, - geTestCase{float32(kTwoTo25 + 0), true, false, ""}, - geTestCase{float32(kTwoTo25 + 1), true, false, ""}, - geTestCase{float32(kTwoTo25 + 2), true, false, ""}, - geTestCase{float32(kTwoTo25 + 3), true, false, ""}, - - geTestCase{float64(-1), false, false, ""}, - geTestCase{float64(kTwoTo25 - 2), false, false, ""}, - geTestCase{float64(kTwoTo25 - 1), false, false, ""}, - geTestCase{float64(kTwoTo25 + 0), false, false, ""}, - geTestCase{float64(kTwoTo25 + 1), true, false, ""}, - geTestCase{float64(kTwoTo25 + 2), true, false, ""}, - geTestCase{float64(kTwoTo25 + 3), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterOrEqualTest) Uint64NotExactlyRepresentableByDoublePrecision() { - // Double-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^54-1, 2^54+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo54 = 1 << 54 - matcher := GreaterOrEqual(uint64(kTwoTo54 + 1)) - - desc := matcher.Description() - expectedDesc := "greater than or equal to 18014398509481985" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []geTestCase{ - // Signed integers. - geTestCase{-1, false, false, ""}, - geTestCase{1 << 30, false, false, ""}, - - geTestCase{int(-1), false, false, ""}, - geTestCase{int(math.MaxInt32), false, false, ""}, - - geTestCase{int8(-1), false, false, ""}, - geTestCase{int8(127), false, false, ""}, - - geTestCase{int16(-1), false, false, ""}, - geTestCase{int16(0), false, false, ""}, - geTestCase{int16(32767), false, false, ""}, - - geTestCase{int32(-1), false, false, ""}, - geTestCase{int32(math.MaxInt32), false, false, ""}, - - geTestCase{int64(-1), false, false, ""}, - geTestCase{int64(kTwoTo54 - 1), false, false, ""}, - geTestCase{int64(kTwoTo54 + 0), false, false, ""}, - geTestCase{int64(kTwoTo54 + 1), true, false, ""}, - geTestCase{int64(kTwoTo54 + 2), true, false, ""}, - - // Unsigned integers. - geTestCase{uint(0), false, false, ""}, - geTestCase{uint(math.MaxUint32), false, false, ""}, - - geTestCase{uint8(0), false, false, ""}, - geTestCase{uint8(255), false, false, ""}, - - geTestCase{uint16(0), false, false, ""}, - geTestCase{uint16(65535), false, false, ""}, - - geTestCase{uint32(0), false, false, ""}, - geTestCase{uint32(math.MaxUint32), false, false, ""}, - - geTestCase{uint64(0), false, false, ""}, - geTestCase{uint64(kTwoTo54 - 1), false, false, ""}, - geTestCase{uint64(kTwoTo54 + 0), false, false, ""}, - geTestCase{uint64(kTwoTo54 + 1), true, false, ""}, - geTestCase{uint64(kTwoTo54 + 2), true, false, ""}, - - // Floating point. - geTestCase{float64(-1), false, false, ""}, - geTestCase{float64(kTwoTo54 - 2), false, false, ""}, - geTestCase{float64(kTwoTo54 - 1), true, false, ""}, - geTestCase{float64(kTwoTo54 + 0), true, false, ""}, - geTestCase{float64(kTwoTo54 + 1), true, false, ""}, - geTestCase{float64(kTwoTo54 + 2), true, false, ""}, - geTestCase{float64(kTwoTo54 + 3), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterOrEqualTest) Float32AboveExactIntegerRange() { - // Single-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^25-1, 2^25+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo25 = 1 << 25 - matcher := GreaterOrEqual(float32(kTwoTo25 + 1)) - - desc := matcher.Description() - expectedDesc := "greater than or equal to 3.3554432e+07" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []geTestCase{ - // Signed integers. - geTestCase{int64(-1), false, false, ""}, - geTestCase{int64(kTwoTo25 - 2), false, false, ""}, - geTestCase{int64(kTwoTo25 - 1), true, false, ""}, - geTestCase{int64(kTwoTo25 + 0), true, false, ""}, - geTestCase{int64(kTwoTo25 + 1), true, false, ""}, - geTestCase{int64(kTwoTo25 + 2), true, false, ""}, - geTestCase{int64(kTwoTo25 + 3), true, false, ""}, - - // Unsigned integers. - geTestCase{uint64(0), false, false, ""}, - geTestCase{uint64(kTwoTo25 - 2), false, false, ""}, - geTestCase{uint64(kTwoTo25 - 1), true, false, ""}, - geTestCase{uint64(kTwoTo25 + 0), true, false, ""}, - geTestCase{uint64(kTwoTo25 + 1), true, false, ""}, - geTestCase{uint64(kTwoTo25 + 2), true, false, ""}, - geTestCase{uint64(kTwoTo25 + 3), true, false, ""}, - - // Floating point. - geTestCase{float32(-1), false, false, ""}, - geTestCase{float32(kTwoTo25 - 2), false, false, ""}, - geTestCase{float32(kTwoTo25 - 1), true, false, ""}, - geTestCase{float32(kTwoTo25 + 0), true, false, ""}, - geTestCase{float32(kTwoTo25 + 1), true, false, ""}, - geTestCase{float32(kTwoTo25 + 2), true, false, ""}, - geTestCase{float32(kTwoTo25 + 3), true, false, ""}, - - geTestCase{float64(-1), false, false, ""}, - geTestCase{float64(kTwoTo25 - 2), false, false, ""}, - geTestCase{float64(kTwoTo25 - 1), true, false, ""}, - geTestCase{float64(kTwoTo25 + 0), true, false, ""}, - geTestCase{float64(kTwoTo25 + 1), true, false, ""}, - geTestCase{float64(kTwoTo25 + 2), true, false, ""}, - geTestCase{float64(kTwoTo25 + 3), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterOrEqualTest) Float64AboveExactIntegerRange() { - // Double-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^54-1, 2^54+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo54 = 1 << 54 - matcher := GreaterOrEqual(float64(kTwoTo54 + 1)) - - desc := matcher.Description() - expectedDesc := "greater than or equal to 1.8014398509481984e+16" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []geTestCase{ - // Signed integers. - geTestCase{int64(-1), false, false, ""}, - geTestCase{int64(kTwoTo54 - 2), false, false, ""}, - geTestCase{int64(kTwoTo54 - 1), true, false, ""}, - geTestCase{int64(kTwoTo54 + 0), true, false, ""}, - geTestCase{int64(kTwoTo54 + 1), true, false, ""}, - geTestCase{int64(kTwoTo54 + 2), true, false, ""}, - geTestCase{int64(kTwoTo54 + 3), true, false, ""}, - - // Unsigned integers. - geTestCase{uint64(0), false, false, ""}, - geTestCase{uint64(kTwoTo54 - 2), false, false, ""}, - geTestCase{uint64(kTwoTo54 - 1), true, false, ""}, - geTestCase{uint64(kTwoTo54 + 0), true, false, ""}, - geTestCase{uint64(kTwoTo54 + 1), true, false, ""}, - geTestCase{uint64(kTwoTo54 + 2), true, false, ""}, - geTestCase{uint64(kTwoTo54 + 3), true, false, ""}, - - // Floating point. - geTestCase{float64(-1), false, false, ""}, - geTestCase{float64(kTwoTo54 - 2), false, false, ""}, - geTestCase{float64(kTwoTo54 - 1), true, false, ""}, - geTestCase{float64(kTwoTo54 + 0), true, false, ""}, - geTestCase{float64(kTwoTo54 + 1), true, false, ""}, - geTestCase{float64(kTwoTo54 + 2), true, false, ""}, - geTestCase{float64(kTwoTo54 + 3), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// String literals -//////////////////////////////////////////////////////////////////////// - -func (t *GreaterOrEqualTest) EmptyString() { - matcher := GreaterOrEqual("") - desc := matcher.Description() - expectedDesc := "greater than or equal to \"\"" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []geTestCase{ - geTestCase{"", true, false, ""}, - geTestCase{"\x00", true, false, ""}, - geTestCase{"a", true, false, ""}, - geTestCase{"foo", true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterOrEqualTest) SingleNullByte() { - matcher := GreaterOrEqual("\x00") - desc := matcher.Description() - expectedDesc := "greater than or equal to \"\x00\"" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []geTestCase{ - geTestCase{"", false, false, ""}, - geTestCase{"\x00", true, false, ""}, - geTestCase{"a", true, false, ""}, - geTestCase{"foo", true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterOrEqualTest) LongerString() { - matcher := GreaterOrEqual("foo\x00") - desc := matcher.Description() - expectedDesc := "greater than or equal to \"foo\x00\"" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []geTestCase{ - geTestCase{"", false, false, ""}, - geTestCase{"\x00", false, false, ""}, - geTestCase{"bar", false, false, ""}, - geTestCase{"foo", false, false, ""}, - geTestCase{"foo\x00", true, false, ""}, - geTestCase{"fooa", true, false, ""}, - geTestCase{"qux", true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/greater_than_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/greater_than_test.go deleted file mode 100644 index 19c7567fd98..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/greater_than_test.go +++ /dev/null @@ -1,1079 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "math" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type GreaterThanTest struct { -} - -func init() { RegisterTestSuite(&GreaterThanTest{}) } - -type gtTestCase struct { - candidate interface{} - expectedResult bool - shouldBeFatal bool - expectedError string -} - -func (t *GreaterThanTest) checkTestCases(matcher Matcher, cases []gtTestCase) { - for i, c := range cases { - err := matcher.Matches(c.candidate) - - ExpectThat( - (err == nil), - Equals(c.expectedResult), - "Case %d (candidate %v)", - i, - c.candidate) - - if err == nil { - continue - } - - _, isFatal := err.(*FatalError) - ExpectEq( - c.shouldBeFatal, - isFatal, - "Case %d (candidate %v)", - i, - c.candidate) - - ExpectThat( - err, - Error(Equals(c.expectedError)), - "Case %d (candidate %v)", - i, - c.candidate) - } -} - -//////////////////////////////////////////////////////////////////////// -// Integer literals -//////////////////////////////////////////////////////////////////////// - -func (t *GreaterThanTest) IntegerCandidateBadTypes() { - matcher := GreaterThan(int(-150)) - - cases := []gtTestCase{ - gtTestCase{true, false, true, "which is not comparable"}, - gtTestCase{uintptr(17), false, true, "which is not comparable"}, - gtTestCase{complex64(-151), false, true, "which is not comparable"}, - gtTestCase{complex128(-151), false, true, "which is not comparable"}, - gtTestCase{[...]int{-151}, false, true, "which is not comparable"}, - gtTestCase{make(chan int), false, true, "which is not comparable"}, - gtTestCase{func() {}, false, true, "which is not comparable"}, - gtTestCase{map[int]int{}, false, true, "which is not comparable"}, - gtTestCase{>TestCase{}, false, true, "which is not comparable"}, - gtTestCase{make([]int, 0), false, true, "which is not comparable"}, - gtTestCase{"-151", false, true, "which is not comparable"}, - gtTestCase{gtTestCase{}, false, true, "which is not comparable"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterThanTest) FloatCandidateBadTypes() { - matcher := GreaterThan(float32(-150)) - - cases := []gtTestCase{ - gtTestCase{true, false, true, "which is not comparable"}, - gtTestCase{uintptr(17), false, true, "which is not comparable"}, - gtTestCase{complex64(-151), false, true, "which is not comparable"}, - gtTestCase{complex128(-151), false, true, "which is not comparable"}, - gtTestCase{[...]int{-151}, false, true, "which is not comparable"}, - gtTestCase{make(chan int), false, true, "which is not comparable"}, - gtTestCase{func() {}, false, true, "which is not comparable"}, - gtTestCase{map[int]int{}, false, true, "which is not comparable"}, - gtTestCase{>TestCase{}, false, true, "which is not comparable"}, - gtTestCase{make([]int, 0), false, true, "which is not comparable"}, - gtTestCase{"-151", false, true, "which is not comparable"}, - gtTestCase{gtTestCase{}, false, true, "which is not comparable"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterThanTest) StringCandidateBadTypes() { - matcher := GreaterThan("17") - - cases := []gtTestCase{ - gtTestCase{true, false, true, "which is not comparable"}, - gtTestCase{int(0), false, true, "which is not comparable"}, - gtTestCase{int8(0), false, true, "which is not comparable"}, - gtTestCase{int16(0), false, true, "which is not comparable"}, - gtTestCase{int32(0), false, true, "which is not comparable"}, - gtTestCase{int64(0), false, true, "which is not comparable"}, - gtTestCase{uint(0), false, true, "which is not comparable"}, - gtTestCase{uint8(0), false, true, "which is not comparable"}, - gtTestCase{uint16(0), false, true, "which is not comparable"}, - gtTestCase{uint32(0), false, true, "which is not comparable"}, - gtTestCase{uint64(0), false, true, "which is not comparable"}, - gtTestCase{uintptr(17), false, true, "which is not comparable"}, - gtTestCase{float32(0), false, true, "which is not comparable"}, - gtTestCase{float64(0), false, true, "which is not comparable"}, - gtTestCase{complex64(-151), false, true, "which is not comparable"}, - gtTestCase{complex128(-151), false, true, "which is not comparable"}, - gtTestCase{[...]int{-151}, false, true, "which is not comparable"}, - gtTestCase{make(chan int), false, true, "which is not comparable"}, - gtTestCase{func() {}, false, true, "which is not comparable"}, - gtTestCase{map[int]int{}, false, true, "which is not comparable"}, - gtTestCase{>TestCase{}, false, true, "which is not comparable"}, - gtTestCase{make([]int, 0), false, true, "which is not comparable"}, - gtTestCase{gtTestCase{}, false, true, "which is not comparable"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterThanTest) BadArgument() { - panicked := false - - defer func() { - ExpectThat(panicked, Equals(true)) - }() - - defer func() { - if r := recover(); r != nil { - panicked = true - } - }() - - GreaterThan(complex128(0)) -} - -//////////////////////////////////////////////////////////////////////// -// Integer literals -//////////////////////////////////////////////////////////////////////// - -func (t *GreaterThanTest) NegativeIntegerLiteral() { - matcher := GreaterThan(-150) - desc := matcher.Description() - expectedDesc := "greater than -150" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []gtTestCase{ - // Signed integers. - gtTestCase{-(1 << 30), false, false, ""}, - gtTestCase{-151, false, false, ""}, - gtTestCase{-150, false, false, ""}, - gtTestCase{-149, true, false, ""}, - gtTestCase{0, true, false, ""}, - gtTestCase{17, true, false, ""}, - - gtTestCase{int(-(1 << 30)), false, false, ""}, - gtTestCase{int(-151), false, false, ""}, - gtTestCase{int(-150), false, false, ""}, - gtTestCase{int(-149), true, false, ""}, - gtTestCase{int(0), true, false, ""}, - gtTestCase{int(17), true, false, ""}, - - gtTestCase{int8(-127), true, false, ""}, - gtTestCase{int8(0), true, false, ""}, - gtTestCase{int8(17), true, false, ""}, - - gtTestCase{int16(-(1 << 14)), false, false, ""}, - gtTestCase{int16(-151), false, false, ""}, - gtTestCase{int16(-150), false, false, ""}, - gtTestCase{int16(-149), true, false, ""}, - gtTestCase{int16(0), true, false, ""}, - gtTestCase{int16(17), true, false, ""}, - - gtTestCase{int32(-(1 << 30)), false, false, ""}, - gtTestCase{int32(-151), false, false, ""}, - gtTestCase{int32(-150), false, false, ""}, - gtTestCase{int32(-149), true, false, ""}, - gtTestCase{int32(0), true, false, ""}, - gtTestCase{int32(17), true, false, ""}, - - gtTestCase{int64(-(1 << 30)), false, false, ""}, - gtTestCase{int64(-151), false, false, ""}, - gtTestCase{int64(-150), false, false, ""}, - gtTestCase{int64(-149), true, false, ""}, - gtTestCase{int64(0), true, false, ""}, - gtTestCase{int64(17), true, false, ""}, - - // Unsigned integers. - gtTestCase{uint((1 << 32) - 151), true, false, ""}, - gtTestCase{uint(0), true, false, ""}, - gtTestCase{uint(17), true, false, ""}, - - gtTestCase{uint8(0), true, false, ""}, - gtTestCase{uint8(17), true, false, ""}, - gtTestCase{uint8(253), true, false, ""}, - - gtTestCase{uint16((1 << 16) - 151), true, false, ""}, - gtTestCase{uint16(0), true, false, ""}, - gtTestCase{uint16(17), true, false, ""}, - - gtTestCase{uint32((1 << 32) - 151), true, false, ""}, - gtTestCase{uint32(0), true, false, ""}, - gtTestCase{uint32(17), true, false, ""}, - - gtTestCase{uint64((1 << 64) - 151), true, false, ""}, - gtTestCase{uint64(0), true, false, ""}, - gtTestCase{uint64(17), true, false, ""}, - - // Floating point. - gtTestCase{float32(-(1 << 30)), false, false, ""}, - gtTestCase{float32(-151), false, false, ""}, - gtTestCase{float32(-150.1), false, false, ""}, - gtTestCase{float32(-150), false, false, ""}, - gtTestCase{float32(-149.9), true, false, ""}, - gtTestCase{float32(0), true, false, ""}, - gtTestCase{float32(17), true, false, ""}, - gtTestCase{float32(160), true, false, ""}, - - gtTestCase{float64(-(1 << 30)), false, false, ""}, - gtTestCase{float64(-151), false, false, ""}, - gtTestCase{float64(-150.1), false, false, ""}, - gtTestCase{float64(-150), false, false, ""}, - gtTestCase{float64(-149.9), true, false, ""}, - gtTestCase{float64(0), true, false, ""}, - gtTestCase{float64(17), true, false, ""}, - gtTestCase{float64(160), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterThanTest) ZeroIntegerLiteral() { - matcher := GreaterThan(0) - desc := matcher.Description() - expectedDesc := "greater than 0" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []gtTestCase{ - // Signed integers. - gtTestCase{-(1 << 30), false, false, ""}, - gtTestCase{-1, false, false, ""}, - gtTestCase{0, false, false, ""}, - gtTestCase{1, true, false, ""}, - gtTestCase{17, true, false, ""}, - gtTestCase{(1 << 30), true, false, ""}, - - gtTestCase{int(-(1 << 30)), false, false, ""}, - gtTestCase{int(-1), false, false, ""}, - gtTestCase{int(0), false, false, ""}, - gtTestCase{int(1), true, false, ""}, - gtTestCase{int(17), true, false, ""}, - - gtTestCase{int8(-1), false, false, ""}, - gtTestCase{int8(0), false, false, ""}, - gtTestCase{int8(1), true, false, ""}, - - gtTestCase{int16(-(1 << 14)), false, false, ""}, - gtTestCase{int16(-1), false, false, ""}, - gtTestCase{int16(0), false, false, ""}, - gtTestCase{int16(1), true, false, ""}, - gtTestCase{int16(17), true, false, ""}, - - gtTestCase{int32(-(1 << 30)), false, false, ""}, - gtTestCase{int32(-1), false, false, ""}, - gtTestCase{int32(0), false, false, ""}, - gtTestCase{int32(1), true, false, ""}, - gtTestCase{int32(17), true, false, ""}, - - gtTestCase{int64(-(1 << 30)), false, false, ""}, - gtTestCase{int64(-1), false, false, ""}, - gtTestCase{int64(0), false, false, ""}, - gtTestCase{int64(1), true, false, ""}, - gtTestCase{int64(17), true, false, ""}, - - // Unsigned integers. - gtTestCase{uint((1 << 32) - 1), true, false, ""}, - gtTestCase{uint(0), false, false, ""}, - gtTestCase{uint(1), true, false, ""}, - gtTestCase{uint(17), true, false, ""}, - - gtTestCase{uint8(0), false, false, ""}, - gtTestCase{uint8(1), true, false, ""}, - gtTestCase{uint8(17), true, false, ""}, - gtTestCase{uint8(253), true, false, ""}, - - gtTestCase{uint16((1 << 16) - 1), true, false, ""}, - gtTestCase{uint16(0), false, false, ""}, - gtTestCase{uint16(1), true, false, ""}, - gtTestCase{uint16(17), true, false, ""}, - - gtTestCase{uint32((1 << 32) - 1), true, false, ""}, - gtTestCase{uint32(0), false, false, ""}, - gtTestCase{uint32(1), true, false, ""}, - gtTestCase{uint32(17), true, false, ""}, - - gtTestCase{uint64((1 << 64) - 1), true, false, ""}, - gtTestCase{uint64(0), false, false, ""}, - gtTestCase{uint64(1), true, false, ""}, - gtTestCase{uint64(17), true, false, ""}, - - // Floating point. - gtTestCase{float32(-(1 << 30)), false, false, ""}, - gtTestCase{float32(-1), false, false, ""}, - gtTestCase{float32(-0.1), false, false, ""}, - gtTestCase{float32(-0.0), false, false, ""}, - gtTestCase{float32(0), false, false, ""}, - gtTestCase{float32(0.1), true, false, ""}, - gtTestCase{float32(17), true, false, ""}, - gtTestCase{float32(160), true, false, ""}, - - gtTestCase{float64(-(1 << 30)), false, false, ""}, - gtTestCase{float64(-1), false, false, ""}, - gtTestCase{float64(-0.1), false, false, ""}, - gtTestCase{float64(-0), false, false, ""}, - gtTestCase{float64(0), false, false, ""}, - gtTestCase{float64(0.1), true, false, ""}, - gtTestCase{float64(17), true, false, ""}, - gtTestCase{float64(160), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterThanTest) PositiveIntegerLiteral() { - matcher := GreaterThan(150) - desc := matcher.Description() - expectedDesc := "greater than 150" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []gtTestCase{ - // Signed integers. - gtTestCase{-1, false, false, ""}, - gtTestCase{149, false, false, ""}, - gtTestCase{150, false, false, ""}, - gtTestCase{151, true, false, ""}, - - gtTestCase{int(-1), false, false, ""}, - gtTestCase{int(149), false, false, ""}, - gtTestCase{int(150), false, false, ""}, - gtTestCase{int(151), true, false, ""}, - - gtTestCase{int8(-1), false, false, ""}, - gtTestCase{int8(0), false, false, ""}, - gtTestCase{int8(17), false, false, ""}, - gtTestCase{int8(127), false, false, ""}, - - gtTestCase{int16(-1), false, false, ""}, - gtTestCase{int16(149), false, false, ""}, - gtTestCase{int16(150), false, false, ""}, - gtTestCase{int16(151), true, false, ""}, - - gtTestCase{int32(-1), false, false, ""}, - gtTestCase{int32(149), false, false, ""}, - gtTestCase{int32(150), false, false, ""}, - gtTestCase{int32(151), true, false, ""}, - - gtTestCase{int64(-1), false, false, ""}, - gtTestCase{int64(149), false, false, ""}, - gtTestCase{int64(150), false, false, ""}, - gtTestCase{int64(151), true, false, ""}, - - // Unsigned integers. - gtTestCase{uint(0), false, false, ""}, - gtTestCase{uint(149), false, false, ""}, - gtTestCase{uint(150), false, false, ""}, - gtTestCase{uint(151), true, false, ""}, - - gtTestCase{uint8(0), false, false, ""}, - gtTestCase{uint8(127), false, false, ""}, - - gtTestCase{uint16(0), false, false, ""}, - gtTestCase{uint16(149), false, false, ""}, - gtTestCase{uint16(150), false, false, ""}, - gtTestCase{uint16(151), true, false, ""}, - - gtTestCase{uint32(0), false, false, ""}, - gtTestCase{uint32(149), false, false, ""}, - gtTestCase{uint32(150), false, false, ""}, - gtTestCase{uint32(151), true, false, ""}, - - gtTestCase{uint64(0), false, false, ""}, - gtTestCase{uint64(149), false, false, ""}, - gtTestCase{uint64(150), false, false, ""}, - gtTestCase{uint64(151), true, false, ""}, - - // Floating point. - gtTestCase{float32(-1), false, false, ""}, - gtTestCase{float32(149), false, false, ""}, - gtTestCase{float32(149.9), false, false, ""}, - gtTestCase{float32(150), false, false, ""}, - gtTestCase{float32(150.1), true, false, ""}, - gtTestCase{float32(151), true, false, ""}, - - gtTestCase{float64(-1), false, false, ""}, - gtTestCase{float64(149), false, false, ""}, - gtTestCase{float64(149.9), false, false, ""}, - gtTestCase{float64(150), false, false, ""}, - gtTestCase{float64(150.1), true, false, ""}, - gtTestCase{float64(151), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// Float literals -//////////////////////////////////////////////////////////////////////// - -func (t *GreaterThanTest) NegativeFloatLiteral() { - matcher := GreaterThan(-150.1) - desc := matcher.Description() - expectedDesc := "greater than -150.1" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []gtTestCase{ - // Signed integers. - gtTestCase{-(1 << 30), false, false, ""}, - gtTestCase{-151, false, false, ""}, - gtTestCase{-150.1, false, false, ""}, - gtTestCase{-150, true, false, ""}, - gtTestCase{-149, true, false, ""}, - gtTestCase{0, true, false, ""}, - gtTestCase{17, true, false, ""}, - - gtTestCase{int(-(1 << 30)), false, false, ""}, - gtTestCase{int(-151), false, false, ""}, - gtTestCase{int(-150), true, false, ""}, - gtTestCase{int(-149), true, false, ""}, - gtTestCase{int(0), true, false, ""}, - gtTestCase{int(17), true, false, ""}, - - gtTestCase{int8(-127), true, false, ""}, - gtTestCase{int8(0), true, false, ""}, - gtTestCase{int8(17), true, false, ""}, - - gtTestCase{int16(-(1 << 14)), false, false, ""}, - gtTestCase{int16(-151), false, false, ""}, - gtTestCase{int16(-150), true, false, ""}, - gtTestCase{int16(-149), true, false, ""}, - gtTestCase{int16(0), true, false, ""}, - gtTestCase{int16(17), true, false, ""}, - - gtTestCase{int32(-(1 << 30)), false, false, ""}, - gtTestCase{int32(-151), false, false, ""}, - gtTestCase{int32(-150), true, false, ""}, - gtTestCase{int32(-149), true, false, ""}, - gtTestCase{int32(0), true, false, ""}, - gtTestCase{int32(17), true, false, ""}, - - gtTestCase{int64(-(1 << 30)), false, false, ""}, - gtTestCase{int64(-151), false, false, ""}, - gtTestCase{int64(-150), true, false, ""}, - gtTestCase{int64(-149), true, false, ""}, - gtTestCase{int64(0), true, false, ""}, - gtTestCase{int64(17), true, false, ""}, - - // Unsigned integers. - gtTestCase{uint((1 << 32) - 151), true, false, ""}, - gtTestCase{uint(0), true, false, ""}, - gtTestCase{uint(17), true, false, ""}, - - gtTestCase{uint8(0), true, false, ""}, - gtTestCase{uint8(17), true, false, ""}, - gtTestCase{uint8(253), true, false, ""}, - - gtTestCase{uint16((1 << 16) - 151), true, false, ""}, - gtTestCase{uint16(0), true, false, ""}, - gtTestCase{uint16(17), true, false, ""}, - - gtTestCase{uint32((1 << 32) - 151), true, false, ""}, - gtTestCase{uint32(0), true, false, ""}, - gtTestCase{uint32(17), true, false, ""}, - - gtTestCase{uint64((1 << 64) - 151), true, false, ""}, - gtTestCase{uint64(0), true, false, ""}, - gtTestCase{uint64(17), true, false, ""}, - - // Floating point. - gtTestCase{float32(-(1 << 30)), false, false, ""}, - gtTestCase{float32(-151), false, false, ""}, - gtTestCase{float32(-150.2), false, false, ""}, - gtTestCase{float32(-150.1), false, false, ""}, - gtTestCase{float32(-150), true, false, ""}, - gtTestCase{float32(0), true, false, ""}, - gtTestCase{float32(17), true, false, ""}, - gtTestCase{float32(160), true, false, ""}, - - gtTestCase{float64(-(1 << 30)), false, false, ""}, - gtTestCase{float64(-151), false, false, ""}, - gtTestCase{float64(-150.2), false, false, ""}, - gtTestCase{float64(-150.1), false, false, ""}, - gtTestCase{float64(-150), true, false, ""}, - gtTestCase{float64(0), true, false, ""}, - gtTestCase{float64(17), true, false, ""}, - gtTestCase{float64(160), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterThanTest) PositiveFloatLiteral() { - matcher := GreaterThan(149.9) - desc := matcher.Description() - expectedDesc := "greater than 149.9" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []gtTestCase{ - // Signed integers. - gtTestCase{-1, false, false, ""}, - gtTestCase{149, false, false, ""}, - gtTestCase{149.9, false, false, ""}, - gtTestCase{150, true, false, ""}, - gtTestCase{151, true, false, ""}, - - gtTestCase{int(-1), false, false, ""}, - gtTestCase{int(149), false, false, ""}, - gtTestCase{int(150), true, false, ""}, - gtTestCase{int(151), true, false, ""}, - - gtTestCase{int8(-1), false, false, ""}, - gtTestCase{int8(0), false, false, ""}, - gtTestCase{int8(17), false, false, ""}, - gtTestCase{int8(127), false, false, ""}, - - gtTestCase{int16(-1), false, false, ""}, - gtTestCase{int16(149), false, false, ""}, - gtTestCase{int16(150), true, false, ""}, - gtTestCase{int16(151), true, false, ""}, - - gtTestCase{int32(-1), false, false, ""}, - gtTestCase{int32(149), false, false, ""}, - gtTestCase{int32(150), true, false, ""}, - gtTestCase{int32(151), true, false, ""}, - - gtTestCase{int64(-1), false, false, ""}, - gtTestCase{int64(149), false, false, ""}, - gtTestCase{int64(150), true, false, ""}, - gtTestCase{int64(151), true, false, ""}, - - // Unsigned integers. - gtTestCase{uint(0), false, false, ""}, - gtTestCase{uint(149), false, false, ""}, - gtTestCase{uint(150), true, false, ""}, - gtTestCase{uint(151), true, false, ""}, - - gtTestCase{uint8(0), false, false, ""}, - gtTestCase{uint8(127), false, false, ""}, - - gtTestCase{uint16(0), false, false, ""}, - gtTestCase{uint16(149), false, false, ""}, - gtTestCase{uint16(150), true, false, ""}, - gtTestCase{uint16(151), true, false, ""}, - - gtTestCase{uint32(0), false, false, ""}, - gtTestCase{uint32(149), false, false, ""}, - gtTestCase{uint32(150), true, false, ""}, - gtTestCase{uint32(151), true, false, ""}, - - gtTestCase{uint64(0), false, false, ""}, - gtTestCase{uint64(149), false, false, ""}, - gtTestCase{uint64(150), true, false, ""}, - gtTestCase{uint64(151), true, false, ""}, - - // Floating point. - gtTestCase{float32(-1), false, false, ""}, - gtTestCase{float32(149), false, false, ""}, - gtTestCase{float32(149.8), false, false, ""}, - gtTestCase{float32(149.9), false, false, ""}, - gtTestCase{float32(150), true, false, ""}, - gtTestCase{float32(151), true, false, ""}, - - gtTestCase{float64(-1), false, false, ""}, - gtTestCase{float64(149), false, false, ""}, - gtTestCase{float64(149.8), false, false, ""}, - gtTestCase{float64(149.9), false, false, ""}, - gtTestCase{float64(150), true, false, ""}, - gtTestCase{float64(151), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// Subtle cases -//////////////////////////////////////////////////////////////////////// - -func (t *GreaterThanTest) Int64NotExactlyRepresentableBySinglePrecision() { - // Single-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^25-1, 2^25+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo25 = 1 << 25 - matcher := GreaterThan(int64(kTwoTo25 + 1)) - - desc := matcher.Description() - expectedDesc := "greater than 33554433" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []gtTestCase{ - // Signed integers. - gtTestCase{-1, false, false, ""}, - gtTestCase{kTwoTo25 + 0, false, false, ""}, - gtTestCase{kTwoTo25 + 1, false, false, ""}, - gtTestCase{kTwoTo25 + 2, true, false, ""}, - - gtTestCase{int(-1), false, false, ""}, - gtTestCase{int(kTwoTo25 + 0), false, false, ""}, - gtTestCase{int(kTwoTo25 + 1), false, false, ""}, - gtTestCase{int(kTwoTo25 + 2), true, false, ""}, - - gtTestCase{int8(-1), false, false, ""}, - gtTestCase{int8(127), false, false, ""}, - - gtTestCase{int16(-1), false, false, ""}, - gtTestCase{int16(0), false, false, ""}, - gtTestCase{int16(32767), false, false, ""}, - - gtTestCase{int32(-1), false, false, ""}, - gtTestCase{int32(kTwoTo25 + 0), false, false, ""}, - gtTestCase{int32(kTwoTo25 + 1), false, false, ""}, - gtTestCase{int32(kTwoTo25 + 2), true, false, ""}, - - gtTestCase{int64(-1), false, false, ""}, - gtTestCase{int64(kTwoTo25 + 0), false, false, ""}, - gtTestCase{int64(kTwoTo25 + 1), false, false, ""}, - gtTestCase{int64(kTwoTo25 + 2), true, false, ""}, - - // Unsigned integers. - gtTestCase{uint(0), false, false, ""}, - gtTestCase{uint(kTwoTo25 + 0), false, false, ""}, - gtTestCase{uint(kTwoTo25 + 1), false, false, ""}, - gtTestCase{uint(kTwoTo25 + 2), true, false, ""}, - - gtTestCase{uint8(0), false, false, ""}, - gtTestCase{uint8(255), false, false, ""}, - - gtTestCase{uint16(0), false, false, ""}, - gtTestCase{uint16(65535), false, false, ""}, - - gtTestCase{uint32(0), false, false, ""}, - gtTestCase{uint32(kTwoTo25 + 0), false, false, ""}, - gtTestCase{uint32(kTwoTo25 + 1), false, false, ""}, - gtTestCase{uint32(kTwoTo25 + 2), true, false, ""}, - - gtTestCase{uint64(0), false, false, ""}, - gtTestCase{uint64(kTwoTo25 + 0), false, false, ""}, - gtTestCase{uint64(kTwoTo25 + 1), false, false, ""}, - gtTestCase{uint64(kTwoTo25 + 2), true, false, ""}, - - // Floating point. - gtTestCase{float32(-1), false, false, ""}, - gtTestCase{float32(kTwoTo25 - 2), false, false, ""}, - gtTestCase{float32(kTwoTo25 - 1), false, false, ""}, - gtTestCase{float32(kTwoTo25 + 0), false, false, ""}, - gtTestCase{float32(kTwoTo25 + 1), false, false, ""}, - gtTestCase{float32(kTwoTo25 + 2), false, false, ""}, - gtTestCase{float32(kTwoTo25 + 3), true, false, ""}, - - gtTestCase{float64(-1), false, false, ""}, - gtTestCase{float64(kTwoTo25 - 2), false, false, ""}, - gtTestCase{float64(kTwoTo25 - 1), false, false, ""}, - gtTestCase{float64(kTwoTo25 + 0), false, false, ""}, - gtTestCase{float64(kTwoTo25 + 1), false, false, ""}, - gtTestCase{float64(kTwoTo25 + 2), true, false, ""}, - gtTestCase{float64(kTwoTo25 + 3), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterThanTest) Int64NotExactlyRepresentableByDoublePrecision() { - // Double-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^54-1, 2^54+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo54 = 1 << 54 - matcher := GreaterThan(int64(kTwoTo54 + 1)) - - desc := matcher.Description() - expectedDesc := "greater than 18014398509481985" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []gtTestCase{ - // Signed integers. - gtTestCase{-1, false, false, ""}, - gtTestCase{1 << 30, false, false, ""}, - - gtTestCase{int(-1), false, false, ""}, - gtTestCase{int(math.MaxInt32), false, false, ""}, - - gtTestCase{int8(-1), false, false, ""}, - gtTestCase{int8(127), false, false, ""}, - - gtTestCase{int16(-1), false, false, ""}, - gtTestCase{int16(0), false, false, ""}, - gtTestCase{int16(32767), false, false, ""}, - - gtTestCase{int32(-1), false, false, ""}, - gtTestCase{int32(math.MaxInt32), false, false, ""}, - - gtTestCase{int64(-1), false, false, ""}, - gtTestCase{int64(kTwoTo54 - 1), false, false, ""}, - gtTestCase{int64(kTwoTo54 + 0), false, false, ""}, - gtTestCase{int64(kTwoTo54 + 1), false, false, ""}, - gtTestCase{int64(kTwoTo54 + 2), true, false, ""}, - - // Unsigned integers. - gtTestCase{uint(0), false, false, ""}, - gtTestCase{uint(math.MaxUint32), false, false, ""}, - - gtTestCase{uint8(0), false, false, ""}, - gtTestCase{uint8(255), false, false, ""}, - - gtTestCase{uint16(0), false, false, ""}, - gtTestCase{uint16(65535), false, false, ""}, - - gtTestCase{uint32(0), false, false, ""}, - gtTestCase{uint32(math.MaxUint32), false, false, ""}, - - gtTestCase{uint64(0), false, false, ""}, - gtTestCase{uint64(kTwoTo54 - 1), false, false, ""}, - gtTestCase{uint64(kTwoTo54 + 0), false, false, ""}, - gtTestCase{uint64(kTwoTo54 + 1), false, false, ""}, - gtTestCase{uint64(kTwoTo54 + 2), true, false, ""}, - - // Floating point. - gtTestCase{float64(-1), false, false, ""}, - gtTestCase{float64(kTwoTo54 - 2), false, false, ""}, - gtTestCase{float64(kTwoTo54 - 1), false, false, ""}, - gtTestCase{float64(kTwoTo54 + 0), false, false, ""}, - gtTestCase{float64(kTwoTo54 + 1), false, false, ""}, - gtTestCase{float64(kTwoTo54 + 2), false, false, ""}, - gtTestCase{float64(kTwoTo54 + 3), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterThanTest) Uint64NotExactlyRepresentableBySinglePrecision() { - // Single-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^25-1, 2^25+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo25 = 1 << 25 - matcher := GreaterThan(uint64(kTwoTo25 + 1)) - - desc := matcher.Description() - expectedDesc := "greater than 33554433" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []gtTestCase{ - // Signed integers. - gtTestCase{-1, false, false, ""}, - gtTestCase{kTwoTo25 + 0, false, false, ""}, - gtTestCase{kTwoTo25 + 1, false, false, ""}, - gtTestCase{kTwoTo25 + 2, true, false, ""}, - - gtTestCase{int(-1), false, false, ""}, - gtTestCase{int(kTwoTo25 + 0), false, false, ""}, - gtTestCase{int(kTwoTo25 + 1), false, false, ""}, - gtTestCase{int(kTwoTo25 + 2), true, false, ""}, - - gtTestCase{int8(-1), false, false, ""}, - gtTestCase{int8(127), false, false, ""}, - - gtTestCase{int16(-1), false, false, ""}, - gtTestCase{int16(0), false, false, ""}, - gtTestCase{int16(32767), false, false, ""}, - - gtTestCase{int32(-1), false, false, ""}, - gtTestCase{int32(kTwoTo25 + 0), false, false, ""}, - gtTestCase{int32(kTwoTo25 + 1), false, false, ""}, - gtTestCase{int32(kTwoTo25 + 2), true, false, ""}, - - gtTestCase{int64(-1), false, false, ""}, - gtTestCase{int64(kTwoTo25 + 0), false, false, ""}, - gtTestCase{int64(kTwoTo25 + 1), false, false, ""}, - gtTestCase{int64(kTwoTo25 + 2), true, false, ""}, - - // Unsigned integers. - gtTestCase{uint(0), false, false, ""}, - gtTestCase{uint(kTwoTo25 + 0), false, false, ""}, - gtTestCase{uint(kTwoTo25 + 1), false, false, ""}, - gtTestCase{uint(kTwoTo25 + 2), true, false, ""}, - - gtTestCase{uint8(0), false, false, ""}, - gtTestCase{uint8(255), false, false, ""}, - - gtTestCase{uint16(0), false, false, ""}, - gtTestCase{uint16(65535), false, false, ""}, - - gtTestCase{uint32(0), false, false, ""}, - gtTestCase{uint32(kTwoTo25 + 0), false, false, ""}, - gtTestCase{uint32(kTwoTo25 + 1), false, false, ""}, - gtTestCase{uint32(kTwoTo25 + 2), true, false, ""}, - - gtTestCase{uint64(0), false, false, ""}, - gtTestCase{uint64(kTwoTo25 + 0), false, false, ""}, - gtTestCase{uint64(kTwoTo25 + 1), false, false, ""}, - gtTestCase{uint64(kTwoTo25 + 2), true, false, ""}, - - // Floating point. - gtTestCase{float32(-1), false, false, ""}, - gtTestCase{float32(kTwoTo25 - 2), false, false, ""}, - gtTestCase{float32(kTwoTo25 - 1), false, false, ""}, - gtTestCase{float32(kTwoTo25 + 0), false, false, ""}, - gtTestCase{float32(kTwoTo25 + 1), false, false, ""}, - gtTestCase{float32(kTwoTo25 + 2), false, false, ""}, - gtTestCase{float32(kTwoTo25 + 3), true, false, ""}, - - gtTestCase{float64(-1), false, false, ""}, - gtTestCase{float64(kTwoTo25 - 2), false, false, ""}, - gtTestCase{float64(kTwoTo25 - 1), false, false, ""}, - gtTestCase{float64(kTwoTo25 + 0), false, false, ""}, - gtTestCase{float64(kTwoTo25 + 1), false, false, ""}, - gtTestCase{float64(kTwoTo25 + 2), true, false, ""}, - gtTestCase{float64(kTwoTo25 + 3), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterThanTest) Uint64NotExactlyRepresentableByDoublePrecision() { - // Double-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^54-1, 2^54+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo54 = 1 << 54 - matcher := GreaterThan(uint64(kTwoTo54 + 1)) - - desc := matcher.Description() - expectedDesc := "greater than 18014398509481985" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []gtTestCase{ - // Signed integers. - gtTestCase{-1, false, false, ""}, - gtTestCase{1 << 30, false, false, ""}, - - gtTestCase{int(-1), false, false, ""}, - gtTestCase{int(math.MaxInt32), false, false, ""}, - - gtTestCase{int8(-1), false, false, ""}, - gtTestCase{int8(127), false, false, ""}, - - gtTestCase{int16(-1), false, false, ""}, - gtTestCase{int16(0), false, false, ""}, - gtTestCase{int16(32767), false, false, ""}, - - gtTestCase{int32(-1), false, false, ""}, - gtTestCase{int32(math.MaxInt32), false, false, ""}, - - gtTestCase{int64(-1), false, false, ""}, - gtTestCase{int64(kTwoTo54 - 1), false, false, ""}, - gtTestCase{int64(kTwoTo54 + 0), false, false, ""}, - gtTestCase{int64(kTwoTo54 + 1), false, false, ""}, - gtTestCase{int64(kTwoTo54 + 2), true, false, ""}, - - // Unsigned integers. - gtTestCase{uint(0), false, false, ""}, - gtTestCase{uint(math.MaxUint32), false, false, ""}, - - gtTestCase{uint8(0), false, false, ""}, - gtTestCase{uint8(255), false, false, ""}, - - gtTestCase{uint16(0), false, false, ""}, - gtTestCase{uint16(65535), false, false, ""}, - - gtTestCase{uint32(0), false, false, ""}, - gtTestCase{uint32(math.MaxUint32), false, false, ""}, - - gtTestCase{uint64(0), false, false, ""}, - gtTestCase{uint64(kTwoTo54 - 1), false, false, ""}, - gtTestCase{uint64(kTwoTo54 + 0), false, false, ""}, - gtTestCase{uint64(kTwoTo54 + 1), false, false, ""}, - gtTestCase{uint64(kTwoTo54 + 2), true, false, ""}, - - // Floating point. - gtTestCase{float64(-1), false, false, ""}, - gtTestCase{float64(kTwoTo54 - 2), false, false, ""}, - gtTestCase{float64(kTwoTo54 - 1), false, false, ""}, - gtTestCase{float64(kTwoTo54 + 0), false, false, ""}, - gtTestCase{float64(kTwoTo54 + 1), false, false, ""}, - gtTestCase{float64(kTwoTo54 + 2), false, false, ""}, - gtTestCase{float64(kTwoTo54 + 3), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterThanTest) Float32AboveExactIntegerRange() { - // Single-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^25-1, 2^25+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo25 = 1 << 25 - matcher := GreaterThan(float32(kTwoTo25 + 1)) - - desc := matcher.Description() - expectedDesc := "greater than 3.3554432e+07" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []gtTestCase{ - // Signed integers. - gtTestCase{int64(-1), false, false, ""}, - gtTestCase{int64(kTwoTo25 - 2), false, false, ""}, - gtTestCase{int64(kTwoTo25 - 1), false, false, ""}, - gtTestCase{int64(kTwoTo25 + 0), false, false, ""}, - gtTestCase{int64(kTwoTo25 + 1), false, false, ""}, - gtTestCase{int64(kTwoTo25 + 2), false, false, ""}, - gtTestCase{int64(kTwoTo25 + 3), true, false, ""}, - - // Unsigned integers. - gtTestCase{uint64(0), false, false, ""}, - gtTestCase{uint64(kTwoTo25 - 2), false, false, ""}, - gtTestCase{uint64(kTwoTo25 - 1), false, false, ""}, - gtTestCase{uint64(kTwoTo25 + 0), false, false, ""}, - gtTestCase{uint64(kTwoTo25 + 1), false, false, ""}, - gtTestCase{uint64(kTwoTo25 + 2), false, false, ""}, - gtTestCase{uint64(kTwoTo25 + 3), true, false, ""}, - - // Floating point. - gtTestCase{float32(-1), false, false, ""}, - gtTestCase{float32(kTwoTo25 - 2), false, false, ""}, - gtTestCase{float32(kTwoTo25 - 1), false, false, ""}, - gtTestCase{float32(kTwoTo25 + 0), false, false, ""}, - gtTestCase{float32(kTwoTo25 + 1), false, false, ""}, - gtTestCase{float32(kTwoTo25 + 2), false, false, ""}, - gtTestCase{float32(kTwoTo25 + 3), true, false, ""}, - - gtTestCase{float64(-1), false, false, ""}, - gtTestCase{float64(kTwoTo25 - 2), false, false, ""}, - gtTestCase{float64(kTwoTo25 - 1), false, false, ""}, - gtTestCase{float64(kTwoTo25 + 0), false, false, ""}, - gtTestCase{float64(kTwoTo25 + 1), false, false, ""}, - gtTestCase{float64(kTwoTo25 + 2), false, false, ""}, - gtTestCase{float64(kTwoTo25 + 3), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterThanTest) Float64AboveExactIntegerRange() { - // Double-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^54-1, 2^54+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo54 = 1 << 54 - matcher := GreaterThan(float64(kTwoTo54 + 1)) - - desc := matcher.Description() - expectedDesc := "greater than 1.8014398509481984e+16" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []gtTestCase{ - // Signed integers. - gtTestCase{int64(-1), false, false, ""}, - gtTestCase{int64(kTwoTo54 - 2), false, false, ""}, - gtTestCase{int64(kTwoTo54 - 1), false, false, ""}, - gtTestCase{int64(kTwoTo54 + 0), false, false, ""}, - gtTestCase{int64(kTwoTo54 + 1), false, false, ""}, - gtTestCase{int64(kTwoTo54 + 2), false, false, ""}, - gtTestCase{int64(kTwoTo54 + 3), true, false, ""}, - - // Unsigned integers. - gtTestCase{uint64(0), false, false, ""}, - gtTestCase{uint64(kTwoTo54 - 2), false, false, ""}, - gtTestCase{uint64(kTwoTo54 - 1), false, false, ""}, - gtTestCase{uint64(kTwoTo54 + 0), false, false, ""}, - gtTestCase{uint64(kTwoTo54 + 1), false, false, ""}, - gtTestCase{uint64(kTwoTo54 + 2), false, false, ""}, - gtTestCase{uint64(kTwoTo54 + 3), true, false, ""}, - - // Floating point. - gtTestCase{float64(-1), false, false, ""}, - gtTestCase{float64(kTwoTo54 - 2), false, false, ""}, - gtTestCase{float64(kTwoTo54 - 1), false, false, ""}, - gtTestCase{float64(kTwoTo54 + 0), false, false, ""}, - gtTestCase{float64(kTwoTo54 + 1), false, false, ""}, - gtTestCase{float64(kTwoTo54 + 2), false, false, ""}, - gtTestCase{float64(kTwoTo54 + 3), true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// String literals -//////////////////////////////////////////////////////////////////////// - -func (t *GreaterThanTest) EmptyString() { - matcher := GreaterThan("") - desc := matcher.Description() - expectedDesc := "greater than \"\"" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []gtTestCase{ - gtTestCase{"", false, false, ""}, - gtTestCase{"\x00", true, false, ""}, - gtTestCase{"a", true, false, ""}, - gtTestCase{"foo", true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterThanTest) SingleNullByte() { - matcher := GreaterThan("\x00") - desc := matcher.Description() - expectedDesc := "greater than \"\x00\"" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []gtTestCase{ - gtTestCase{"", false, false, ""}, - gtTestCase{"\x00", false, false, ""}, - gtTestCase{"\x00\x00", true, false, ""}, - gtTestCase{"a", true, false, ""}, - gtTestCase{"foo", true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *GreaterThanTest) LongerString() { - matcher := GreaterThan("foo\x00") - desc := matcher.Description() - expectedDesc := "greater than \"foo\x00\"" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []gtTestCase{ - gtTestCase{"", false, false, ""}, - gtTestCase{"\x00", false, false, ""}, - gtTestCase{"bar", false, false, ""}, - gtTestCase{"foo", false, false, ""}, - gtTestCase{"foo\x00", false, false, ""}, - gtTestCase{"foo\x00\x00", true, false, ""}, - gtTestCase{"fooa", true, false, ""}, - gtTestCase{"qux", true, false, ""}, - } - - t.checkTestCases(matcher, cases) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/has_substr_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/has_substr_test.go deleted file mode 100644 index be9f317006b..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/has_substr_test.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type HasSubstrTest struct { -} - -func init() { RegisterTestSuite(&HasSubstrTest{}) } - -//////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////// - -func (t *HasSubstrTest) Description() { - matcher := HasSubstr("taco") - ExpectThat(matcher.Description(), Equals("has substring \"taco\"")) -} - -func (t *HasSubstrTest) CandidateIsNil() { - matcher := HasSubstr("") - err := matcher.Matches(nil) - - ExpectThat(err, Error(Equals("which is not a string"))) - ExpectTrue(isFatal(err)) -} - -func (t *HasSubstrTest) CandidateIsInteger() { - matcher := HasSubstr("") - err := matcher.Matches(17) - - ExpectThat(err, Error(Equals("which is not a string"))) - ExpectTrue(isFatal(err)) -} - -func (t *HasSubstrTest) CandidateIsByteSlice() { - matcher := HasSubstr("") - err := matcher.Matches([]byte{17}) - - ExpectThat(err, Error(Equals("which is not a string"))) - ExpectTrue(isFatal(err)) -} - -func (t *HasSubstrTest) CandidateDoesntHaveSubstring() { - matcher := HasSubstr("taco") - err := matcher.Matches("tac") - - ExpectThat(err, Error(Equals(""))) - ExpectFalse(isFatal(err)) -} - -func (t *HasSubstrTest) CandidateEqualsArg() { - matcher := HasSubstr("taco") - err := matcher.Matches("taco") - - ExpectThat(err, Equals(nil)) -} - -func (t *HasSubstrTest) CandidateHasProperSubstring() { - matcher := HasSubstr("taco") - err := matcher.Matches("burritos and tacos") - - ExpectThat(err, Equals(nil)) -} - -func (t *HasSubstrTest) EmptyStringIsAlwaysSubString() { - matcher := HasSubstr("") - err := matcher.Matches("asdf") - - ExpectThat(err, Equals(nil)) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/identical_to_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/identical_to_test.go deleted file mode 100644 index 19236671437..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/identical_to_test.go +++ /dev/null @@ -1,849 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "fmt" - "io" - "unsafe" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type IdenticalToTest struct { -} - -func init() { RegisterTestSuite(&IdenticalToTest{}) } - -//////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////// - -func (t *IdenticalToTest) TypesNotIdentical() { - var m Matcher - var err error - - type intAlias int - - // Type alias expected value - m = IdenticalTo(intAlias(17)) - err = m.Matches(int(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int"))) - - // Type alias candidate - m = IdenticalTo(int(17)) - err = m.Matches(intAlias(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.intAlias"))) - - // int and uint - m = IdenticalTo(int(17)) - err = m.Matches(uint(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type uint"))) -} - -func (t *IdenticalToTest) PredeclaredNilIdentifier() { - var m Matcher - var err error - - // Nil literal - m = IdenticalTo(nil) - err = m.Matches(nil) - ExpectEq(nil, err) - - // Zero interface var (which is the same as above since IdenticalTo takes an - // interface{} as an arg) - var nilReader io.Reader - var nilWriter io.Writer - - m = IdenticalTo(nilReader) - err = m.Matches(nilWriter) - ExpectEq(nil, err) - - // Typed nil value. - m = IdenticalTo(nil) - err = m.Matches((chan int)(nil)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type chan int"))) - - // Non-nil value. - m = IdenticalTo(nil) - err = m.Matches("taco") - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type string"))) -} - -func (t *IdenticalToTest) Slices() { - var m Matcher - var err error - - // Nil expected value - m = IdenticalTo(([]int)(nil)) - ExpectEq("identical to <[]int> []", m.Description()) - - err = m.Matches(([]int)(nil)) - ExpectEq(nil, err) - - err = m.Matches([]int{}) - ExpectThat(err, Error(Equals("which is not an identical reference"))) - - // Non-nil expected value - o1 := make([]int, 1) - o2 := make([]int, 1) - m = IdenticalTo(o1) - ExpectEq(fmt.Sprintf("identical to <[]int> %v", o1), m.Description()) - - err = m.Matches(o1) - ExpectEq(nil, err) - - err = m.Matches(o2) - ExpectThat(err, Error(Equals("which is not an identical reference"))) -} - -func (t *IdenticalToTest) Maps() { - var m Matcher - var err error - - // Nil expected value - m = IdenticalTo((map[int]int)(nil)) - ExpectEq("identical to map[]", m.Description()) - - err = m.Matches((map[int]int)(nil)) - ExpectEq(nil, err) - - err = m.Matches(map[int]int{}) - ExpectThat(err, Error(Equals("which is not an identical reference"))) - - // Non-nil expected value - o1 := map[int]int{} - o2 := map[int]int{} - m = IdenticalTo(o1) - ExpectEq(fmt.Sprintf("identical to %v", o1), m.Description()) - - err = m.Matches(o1) - ExpectEq(nil, err) - - err = m.Matches(o2) - ExpectThat(err, Error(Equals("which is not an identical reference"))) -} - -func (t *IdenticalToTest) Functions() { - var m Matcher - var err error - - // Nil expected value - m = IdenticalTo((func())(nil)) - ExpectEq("identical to ", m.Description()) - - err = m.Matches((func())(nil)) - ExpectEq(nil, err) - - err = m.Matches(func() {}) - ExpectThat(err, Error(Equals("which is not an identical reference"))) - - // Non-nil expected value - o1 := func() {} - o2 := func() {} - m = IdenticalTo(o1) - ExpectEq(fmt.Sprintf("identical to %v", o1), m.Description()) - - err = m.Matches(o1) - ExpectEq(nil, err) - - err = m.Matches(o2) - ExpectThat(err, Error(Equals("which is not an identical reference"))) -} - -func (t *IdenticalToTest) Channels() { - var m Matcher - var err error - - // Nil expected value - m = IdenticalTo((chan int)(nil)) - ExpectEq("identical to ", m.Description()) - - err = m.Matches((chan int)(nil)) - ExpectEq(nil, err) - - err = m.Matches(make(chan int)) - ExpectThat(err, Error(Equals("which is not an identical reference"))) - - // Non-nil expected value - o1 := make(chan int) - o2 := make(chan int) - m = IdenticalTo(o1) - ExpectEq(fmt.Sprintf("identical to %v", o1), m.Description()) - - err = m.Matches(o1) - ExpectEq(nil, err) - - err = m.Matches(o2) - ExpectThat(err, Error(Equals("which is not an identical reference"))) -} - -func (t *IdenticalToTest) Bools() { - var m Matcher - var err error - - // false - m = IdenticalTo(false) - ExpectEq("identical to false", m.Description()) - - err = m.Matches(false) - ExpectEq(nil, err) - - err = m.Matches(true) - ExpectThat(err, Error(Equals(""))) - - // true - m = IdenticalTo(true) - ExpectEq("identical to true", m.Description()) - - err = m.Matches(false) - ExpectThat(err, Error(Equals(""))) - - err = m.Matches(true) - ExpectEq(nil, err) -} - -func (t *IdenticalToTest) Ints() { - var m Matcher - var err error - - m = IdenticalTo(int(17)) - ExpectEq("identical to 17", m.Description()) - - // Identical value - err = m.Matches(int(17)) - ExpectEq(nil, err) - - // Type alias - type myType int - err = m.Matches(myType(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} - -func (t *IdenticalToTest) Int8s() { - var m Matcher - var err error - - m = IdenticalTo(int8(17)) - ExpectEq("identical to 17", m.Description()) - - // Identical value - err = m.Matches(int8(17)) - ExpectEq(nil, err) - - // Type alias - type myType int8 - err = m.Matches(myType(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} - -func (t *IdenticalToTest) Int16s() { - var m Matcher - var err error - - m = IdenticalTo(int16(17)) - ExpectEq("identical to 17", m.Description()) - - // Identical value - err = m.Matches(int16(17)) - ExpectEq(nil, err) - - // Type alias - type myType int16 - err = m.Matches(myType(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} - -func (t *IdenticalToTest) Int32s() { - var m Matcher - var err error - - m = IdenticalTo(int32(17)) - ExpectEq("identical to 17", m.Description()) - - // Identical value - err = m.Matches(int32(17)) - ExpectEq(nil, err) - - // Type alias - type myType int32 - err = m.Matches(myType(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int16(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int16"))) -} - -func (t *IdenticalToTest) Int64s() { - var m Matcher - var err error - - m = IdenticalTo(int64(17)) - ExpectEq("identical to 17", m.Description()) - - // Identical value - err = m.Matches(int64(17)) - ExpectEq(nil, err) - - // Type alias - type myType int64 - err = m.Matches(myType(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} - -func (t *IdenticalToTest) Uints() { - var m Matcher - var err error - - m = IdenticalTo(uint(17)) - ExpectEq("identical to 17", m.Description()) - - // Identical value - err = m.Matches(uint(17)) - ExpectEq(nil, err) - - // Type alias - type myType uint - err = m.Matches(myType(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} - -func (t *IdenticalToTest) Uint8s() { - var m Matcher - var err error - - m = IdenticalTo(uint8(17)) - ExpectEq("identical to 17", m.Description()) - - // Identical value - err = m.Matches(uint8(17)) - ExpectEq(nil, err) - - // Type alias - type myType uint8 - err = m.Matches(myType(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} - -func (t *IdenticalToTest) Uint16s() { - var m Matcher - var err error - - m = IdenticalTo(uint16(17)) - ExpectEq("identical to 17", m.Description()) - - // Identical value - err = m.Matches(uint16(17)) - ExpectEq(nil, err) - - // Type alias - type myType uint16 - err = m.Matches(myType(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} - -func (t *IdenticalToTest) Uint32s() { - var m Matcher - var err error - - m = IdenticalTo(uint32(17)) - ExpectEq("identical to 17", m.Description()) - - // Identical value - err = m.Matches(uint32(17)) - ExpectEq(nil, err) - - // Type alias - type myType uint32 - err = m.Matches(myType(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} - -func (t *IdenticalToTest) Uint64s() { - var m Matcher - var err error - - m = IdenticalTo(uint64(17)) - ExpectEq("identical to 17", m.Description()) - - // Identical value - err = m.Matches(uint64(17)) - ExpectEq(nil, err) - - // Type alias - type myType uint64 - err = m.Matches(myType(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} - -func (t *IdenticalToTest) Uintptrs() { - var m Matcher - var err error - - m = IdenticalTo(uintptr(17)) - ExpectEq("identical to 17", m.Description()) - - // Identical value - err = m.Matches(uintptr(17)) - ExpectEq(nil, err) - - // Type alias - type myType uintptr - err = m.Matches(myType(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} - -func (t *IdenticalToTest) Float32s() { - var m Matcher - var err error - - m = IdenticalTo(float32(17)) - ExpectEq("identical to 17", m.Description()) - - // Identical value - err = m.Matches(float32(17)) - ExpectEq(nil, err) - - // Type alias - type myType float32 - err = m.Matches(myType(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} - -func (t *IdenticalToTest) Float64s() { - var m Matcher - var err error - - m = IdenticalTo(float64(17)) - ExpectEq("identical to 17", m.Description()) - - // Identical value - err = m.Matches(float64(17)) - ExpectEq(nil, err) - - // Type alias - type myType float64 - err = m.Matches(myType(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} - -func (t *IdenticalToTest) Complex64s() { - var m Matcher - var err error - - m = IdenticalTo(complex64(17)) - ExpectEq("identical to (17+0i)", m.Description()) - - // Identical value - err = m.Matches(complex64(17)) - ExpectEq(nil, err) - - // Type alias - type myType complex64 - err = m.Matches(myType(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} - -func (t *IdenticalToTest) Complex128s() { - var m Matcher - var err error - - m = IdenticalTo(complex128(17)) - ExpectEq("identical to (17+0i)", m.Description()) - - // Identical value - err = m.Matches(complex128(17)) - ExpectEq(nil, err) - - // Type alias - type myType complex128 - err = m.Matches(myType(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} - -func (t *IdenticalToTest) EmptyComparableArrays() { - var m Matcher - var err error - - m = IdenticalTo([0]int{}) - ExpectEq("identical to <[0]int> []", m.Description()) - - // Identical value - err = m.Matches([0]int{}) - ExpectEq(nil, err) - - // Length too long - err = m.Matches([1]int{17}) - ExpectThat(err, Error(Equals("which is of type [1]int"))) - - // Element type alias - type myType int - err = m.Matches([0]myType{}) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type [0]oglematchers_test.myType"))) - - // Completely wrong element type - err = m.Matches([0]int32{}) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type [0]int32"))) -} - -func (t *IdenticalToTest) NonEmptyComparableArrays() { - var m Matcher - var err error - - m = IdenticalTo([2]int{17, 19}) - ExpectEq("identical to <[2]int> [17 19]", m.Description()) - - // Identical value - err = m.Matches([2]int{17, 19}) - ExpectEq(nil, err) - - // Length too short - err = m.Matches([1]int{17}) - ExpectThat(err, Error(Equals("which is of type [1]int"))) - - // Length too long - err = m.Matches([3]int{17, 19, 23}) - ExpectThat(err, Error(Equals("which is of type [3]int"))) - - // First element different - err = m.Matches([2]int{13, 19}) - ExpectThat(err, Error(Equals(""))) - - // Second element different - err = m.Matches([2]int{17, 23}) - ExpectThat(err, Error(Equals(""))) - - // Element type alias - type myType int - err = m.Matches([2]myType{17, 19}) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type [2]oglematchers_test.myType"))) - - // Completely wrong element type - err = m.Matches([2]int32{17, 19}) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type [2]int32"))) -} - -func (t *IdenticalToTest) NonEmptyArraysOfComparableArrays() { - var m Matcher - var err error - - x := [2][2]int{ - [2]int{17, 19}, - [2]int{23, 29}, - } - m = IdenticalTo(x) - ExpectEq("identical to <[2][2]int> [[17 19] [23 29]]", m.Description()) - - // Identical value - err = m.Matches([2][2]int{[2]int{17, 19}, [2]int{23, 29}}) - ExpectEq(nil, err) - - // Outer length too short - err = m.Matches([1][2]int{[2]int{17, 19}}) - ExpectThat(err, Error(Equals("which is of type [1][2]int"))) - - // Inner length too short - err = m.Matches([2][1]int{[1]int{17}, [1]int{23}}) - ExpectThat(err, Error(Equals("which is of type [2][1]int"))) - - // First element different - err = m.Matches([2][2]int{[2]int{13, 19}, [2]int{23, 29}}) - ExpectThat(err, Error(Equals(""))) - - // Element type alias - type myType int - err = m.Matches([2][2]myType{[2]myType{17, 19}, [2]myType{23, 29}}) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type [2][2]oglematchers_test.myType"))) -} - -func (t *IdenticalToTest) NonComparableArrays() { - x := [0]func(){} - f := func() { IdenticalTo(x) } - ExpectThat(f, Panics(HasSubstr("is not comparable"))) -} - -func (t *IdenticalToTest) ArraysOfNonComparableArrays() { - x := [0][0]func(){} - f := func() { IdenticalTo(x) } - ExpectThat(f, Panics(HasSubstr("is not comparable"))) -} - -func (t *IdenticalToTest) Strings() { - var m Matcher - var err error - - m = IdenticalTo("taco") - ExpectEq("identical to taco", m.Description()) - - // Identical value - err = m.Matches("ta" + "co") - ExpectEq(nil, err) - - // Type alias - type myType string - err = m.Matches(myType("taco")) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} - -func (t *IdenticalToTest) ComparableStructs() { - var m Matcher - var err error - - type subStruct struct { - i int - } - - type myStruct struct { - u uint - s subStruct - } - - x := myStruct{17, subStruct{19}} - m = IdenticalTo(x) - ExpectEq("identical to {17 {19}}", m.Description()) - - // Identical value - err = m.Matches(myStruct{17, subStruct{19}}) - ExpectEq(nil, err) - - // Wrong outer field - err = m.Matches(myStruct{13, subStruct{19}}) - ExpectThat(err, Error(Equals(""))) - - // Wrong inner field - err = m.Matches(myStruct{17, subStruct{23}}) - ExpectThat(err, Error(Equals(""))) - - // Type alias - type myType myStruct - err = m.Matches(myType{17, subStruct{19}}) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} - -func (t *IdenticalToTest) NonComparableStructs() { - type subStruct struct { - s []int - } - - type myStruct struct { - u uint - s subStruct - } - - x := myStruct{17, subStruct{[]int{19}}} - f := func() { IdenticalTo(x) } - ExpectThat(f, Panics(AllOf(HasSubstr("IdenticalTo"), HasSubstr("comparable")))) -} - -func (t *IdenticalToTest) NilUnsafePointer() { - var m Matcher - var err error - - x := unsafe.Pointer(nil) - m = IdenticalTo(x) - ExpectEq(fmt.Sprintf("identical to %v", x), m.Description()) - - // Identical value - err = m.Matches(unsafe.Pointer(nil)) - ExpectEq(nil, err) - - // Wrong value - j := 17 - err = m.Matches(unsafe.Pointer(&j)) - ExpectThat(err, Error(Equals(""))) - - // Type alias - type myType unsafe.Pointer - err = m.Matches(myType(unsafe.Pointer(nil))) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} - -func (t *IdenticalToTest) NonNilUnsafePointer() { - var m Matcher - var err error - - i := 17 - x := unsafe.Pointer(&i) - m = IdenticalTo(x) - ExpectEq(fmt.Sprintf("identical to %v", x), m.Description()) - - // Identical value - err = m.Matches(unsafe.Pointer(&i)) - ExpectEq(nil, err) - - // Nil value - err = m.Matches(unsafe.Pointer(nil)) - ExpectThat(err, Error(Equals(""))) - - // Wrong value - j := 17 - err = m.Matches(unsafe.Pointer(&j)) - ExpectThat(err, Error(Equals(""))) - - // Type alias - type myType unsafe.Pointer - err = m.Matches(myType(unsafe.Pointer(&i))) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type oglematchers_test.myType"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} - -func (t *IdenticalToTest) IntAlias() { - var m Matcher - var err error - - type intAlias int - - m = IdenticalTo(intAlias(17)) - ExpectEq("identical to 17", m.Description()) - - // Identical value - err = m.Matches(intAlias(17)) - ExpectEq(nil, err) - - // Int - err = m.Matches(int(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int"))) - - // Completely wrong type - err = m.Matches(int32(17)) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("which is of type int32"))) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/less_or_equal_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/less_or_equal_test.go deleted file mode 100644 index 1fb9d128b0a..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/less_or_equal_test.go +++ /dev/null @@ -1,1079 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "math" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type LessOrEqualTest struct { -} - -func init() { RegisterTestSuite(&LessOrEqualTest{}) } - -type leTestCase struct { - candidate interface{} - expectedResult bool - shouldBeFatal bool - expectedError string -} - -func (t *LessOrEqualTest) checkTestCases(matcher Matcher, cases []leTestCase) { - for i, c := range cases { - err := matcher.Matches(c.candidate) - - ExpectThat( - (err == nil), - Equals(c.expectedResult), - "Case %d (candidate %v)", - i, - c.candidate) - - if err == nil { - continue - } - - _, isFatal := err.(*FatalError) - ExpectEq( - c.shouldBeFatal, - isFatal, - "Case %d (candidate %v)", - i, - c.candidate) - - ExpectThat( - err, - Error(Equals(c.expectedError)), - "Case %d (candidate %v)", - i, - c.candidate) - } -} - -//////////////////////////////////////////////////////////////////////// -// Integer literals -//////////////////////////////////////////////////////////////////////// - -func (t *LessOrEqualTest) IntegerCandidateBadTypes() { - matcher := LessOrEqual(int(-150)) - - cases := []leTestCase{ - leTestCase{true, false, true, "which is not comparable"}, - leTestCase{uintptr(17), false, true, "which is not comparable"}, - leTestCase{complex64(-151), false, true, "which is not comparable"}, - leTestCase{complex128(-151), false, true, "which is not comparable"}, - leTestCase{[...]int{-151}, false, true, "which is not comparable"}, - leTestCase{make(chan int), false, true, "which is not comparable"}, - leTestCase{func() {}, false, true, "which is not comparable"}, - leTestCase{map[int]int{}, false, true, "which is not comparable"}, - leTestCase{&leTestCase{}, false, true, "which is not comparable"}, - leTestCase{make([]int, 0), false, true, "which is not comparable"}, - leTestCase{"-151", false, true, "which is not comparable"}, - leTestCase{leTestCase{}, false, true, "which is not comparable"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessOrEqualTest) FloatCandidateBadTypes() { - matcher := LessOrEqual(float32(-150)) - - cases := []leTestCase{ - leTestCase{true, false, true, "which is not comparable"}, - leTestCase{uintptr(17), false, true, "which is not comparable"}, - leTestCase{complex64(-151), false, true, "which is not comparable"}, - leTestCase{complex128(-151), false, true, "which is not comparable"}, - leTestCase{[...]int{-151}, false, true, "which is not comparable"}, - leTestCase{make(chan int), false, true, "which is not comparable"}, - leTestCase{func() {}, false, true, "which is not comparable"}, - leTestCase{map[int]int{}, false, true, "which is not comparable"}, - leTestCase{&leTestCase{}, false, true, "which is not comparable"}, - leTestCase{make([]int, 0), false, true, "which is not comparable"}, - leTestCase{"-151", false, true, "which is not comparable"}, - leTestCase{leTestCase{}, false, true, "which is not comparable"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessOrEqualTest) StringCandidateBadTypes() { - matcher := LessOrEqual("17") - - cases := []leTestCase{ - leTestCase{true, false, true, "which is not comparable"}, - leTestCase{int(0), false, true, "which is not comparable"}, - leTestCase{int8(0), false, true, "which is not comparable"}, - leTestCase{int16(0), false, true, "which is not comparable"}, - leTestCase{int32(0), false, true, "which is not comparable"}, - leTestCase{int64(0), false, true, "which is not comparable"}, - leTestCase{uint(0), false, true, "which is not comparable"}, - leTestCase{uint8(0), false, true, "which is not comparable"}, - leTestCase{uint16(0), false, true, "which is not comparable"}, - leTestCase{uint32(0), false, true, "which is not comparable"}, - leTestCase{uint64(0), false, true, "which is not comparable"}, - leTestCase{uintptr(17), false, true, "which is not comparable"}, - leTestCase{float32(0), false, true, "which is not comparable"}, - leTestCase{float64(0), false, true, "which is not comparable"}, - leTestCase{complex64(-151), false, true, "which is not comparable"}, - leTestCase{complex128(-151), false, true, "which is not comparable"}, - leTestCase{[...]int{-151}, false, true, "which is not comparable"}, - leTestCase{make(chan int), false, true, "which is not comparable"}, - leTestCase{func() {}, false, true, "which is not comparable"}, - leTestCase{map[int]int{}, false, true, "which is not comparable"}, - leTestCase{&leTestCase{}, false, true, "which is not comparable"}, - leTestCase{make([]int, 0), false, true, "which is not comparable"}, - leTestCase{leTestCase{}, false, true, "which is not comparable"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessOrEqualTest) BadArgument() { - panicked := false - - defer func() { - ExpectThat(panicked, Equals(true)) - }() - - defer func() { - if r := recover(); r != nil { - panicked = true - } - }() - - LessOrEqual(complex128(0)) -} - -//////////////////////////////////////////////////////////////////////// -// Integer literals -//////////////////////////////////////////////////////////////////////// - -func (t *LessOrEqualTest) NegativeIntegerLiteral() { - matcher := LessOrEqual(-150) - desc := matcher.Description() - expectedDesc := "less than or equal to -150" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []leTestCase{ - // Signed integers. - leTestCase{-(1 << 30), true, false, ""}, - leTestCase{-151, true, false, ""}, - leTestCase{-150, true, false, ""}, - leTestCase{-149, false, false, ""}, - leTestCase{0, false, false, ""}, - leTestCase{17, false, false, ""}, - - leTestCase{int(-(1 << 30)), true, false, ""}, - leTestCase{int(-151), true, false, ""}, - leTestCase{int(-150), true, false, ""}, - leTestCase{int(-149), false, false, ""}, - leTestCase{int(0), false, false, ""}, - leTestCase{int(17), false, false, ""}, - - leTestCase{int8(-127), false, false, ""}, - leTestCase{int8(0), false, false, ""}, - leTestCase{int8(17), false, false, ""}, - - leTestCase{int16(-(1 << 14)), true, false, ""}, - leTestCase{int16(-151), true, false, ""}, - leTestCase{int16(-150), true, false, ""}, - leTestCase{int16(-149), false, false, ""}, - leTestCase{int16(0), false, false, ""}, - leTestCase{int16(17), false, false, ""}, - - leTestCase{int32(-(1 << 30)), true, false, ""}, - leTestCase{int32(-151), true, false, ""}, - leTestCase{int32(-150), true, false, ""}, - leTestCase{int32(-149), false, false, ""}, - leTestCase{int32(0), false, false, ""}, - leTestCase{int32(17), false, false, ""}, - - leTestCase{int64(-(1 << 30)), true, false, ""}, - leTestCase{int64(-151), true, false, ""}, - leTestCase{int64(-150), true, false, ""}, - leTestCase{int64(-149), false, false, ""}, - leTestCase{int64(0), false, false, ""}, - leTestCase{int64(17), false, false, ""}, - - // Unsigned integers. - leTestCase{uint((1 << 32) - 151), false, false, ""}, - leTestCase{uint(0), false, false, ""}, - leTestCase{uint(17), false, false, ""}, - - leTestCase{uint8(0), false, false, ""}, - leTestCase{uint8(17), false, false, ""}, - leTestCase{uint8(253), false, false, ""}, - - leTestCase{uint16((1 << 16) - 151), false, false, ""}, - leTestCase{uint16(0), false, false, ""}, - leTestCase{uint16(17), false, false, ""}, - - leTestCase{uint32((1 << 32) - 151), false, false, ""}, - leTestCase{uint32(0), false, false, ""}, - leTestCase{uint32(17), false, false, ""}, - - leTestCase{uint64((1 << 64) - 151), false, false, ""}, - leTestCase{uint64(0), false, false, ""}, - leTestCase{uint64(17), false, false, ""}, - - // Floating point. - leTestCase{float32(-(1 << 30)), true, false, ""}, - leTestCase{float32(-151), true, false, ""}, - leTestCase{float32(-150.1), true, false, ""}, - leTestCase{float32(-150), true, false, ""}, - leTestCase{float32(-149.9), false, false, ""}, - leTestCase{float32(0), false, false, ""}, - leTestCase{float32(17), false, false, ""}, - leTestCase{float32(160), false, false, ""}, - - leTestCase{float64(-(1 << 30)), true, false, ""}, - leTestCase{float64(-151), true, false, ""}, - leTestCase{float64(-150.1), true, false, ""}, - leTestCase{float64(-150), true, false, ""}, - leTestCase{float64(-149.9), false, false, ""}, - leTestCase{float64(0), false, false, ""}, - leTestCase{float64(17), false, false, ""}, - leTestCase{float64(160), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessOrEqualTest) ZeroIntegerLiteral() { - matcher := LessOrEqual(0) - desc := matcher.Description() - expectedDesc := "less than or equal to 0" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []leTestCase{ - // Signed integers. - leTestCase{-(1 << 30), true, false, ""}, - leTestCase{-1, true, false, ""}, - leTestCase{0, true, false, ""}, - leTestCase{1, false, false, ""}, - leTestCase{17, false, false, ""}, - leTestCase{(1 << 30), false, false, ""}, - - leTestCase{int(-(1 << 30)), true, false, ""}, - leTestCase{int(-1), true, false, ""}, - leTestCase{int(0), true, false, ""}, - leTestCase{int(1), false, false, ""}, - leTestCase{int(17), false, false, ""}, - - leTestCase{int8(-1), true, false, ""}, - leTestCase{int8(0), true, false, ""}, - leTestCase{int8(1), false, false, ""}, - - leTestCase{int16(-(1 << 14)), true, false, ""}, - leTestCase{int16(-1), true, false, ""}, - leTestCase{int16(0), true, false, ""}, - leTestCase{int16(1), false, false, ""}, - leTestCase{int16(17), false, false, ""}, - - leTestCase{int32(-(1 << 30)), true, false, ""}, - leTestCase{int32(-1), true, false, ""}, - leTestCase{int32(0), true, false, ""}, - leTestCase{int32(1), false, false, ""}, - leTestCase{int32(17), false, false, ""}, - - leTestCase{int64(-(1 << 30)), true, false, ""}, - leTestCase{int64(-1), true, false, ""}, - leTestCase{int64(0), true, false, ""}, - leTestCase{int64(1), false, false, ""}, - leTestCase{int64(17), false, false, ""}, - - // Unsigned integers. - leTestCase{uint((1 << 32) - 1), false, false, ""}, - leTestCase{uint(0), true, false, ""}, - leTestCase{uint(1), false, false, ""}, - leTestCase{uint(17), false, false, ""}, - - leTestCase{uint8(0), true, false, ""}, - leTestCase{uint8(1), false, false, ""}, - leTestCase{uint8(17), false, false, ""}, - leTestCase{uint8(253), false, false, ""}, - - leTestCase{uint16((1 << 16) - 1), false, false, ""}, - leTestCase{uint16(0), true, false, ""}, - leTestCase{uint16(1), false, false, ""}, - leTestCase{uint16(17), false, false, ""}, - - leTestCase{uint32((1 << 32) - 1), false, false, ""}, - leTestCase{uint32(0), true, false, ""}, - leTestCase{uint32(1), false, false, ""}, - leTestCase{uint32(17), false, false, ""}, - - leTestCase{uint64((1 << 64) - 1), false, false, ""}, - leTestCase{uint64(0), true, false, ""}, - leTestCase{uint64(1), false, false, ""}, - leTestCase{uint64(17), false, false, ""}, - - // Floating point. - leTestCase{float32(-(1 << 30)), true, false, ""}, - leTestCase{float32(-1), true, false, ""}, - leTestCase{float32(-0.1), true, false, ""}, - leTestCase{float32(-0.0), true, false, ""}, - leTestCase{float32(0), true, false, ""}, - leTestCase{float32(0.1), false, false, ""}, - leTestCase{float32(17), false, false, ""}, - leTestCase{float32(160), false, false, ""}, - - leTestCase{float64(-(1 << 30)), true, false, ""}, - leTestCase{float64(-1), true, false, ""}, - leTestCase{float64(-0.1), true, false, ""}, - leTestCase{float64(-0), true, false, ""}, - leTestCase{float64(0), true, false, ""}, - leTestCase{float64(0.1), false, false, ""}, - leTestCase{float64(17), false, false, ""}, - leTestCase{float64(160), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessOrEqualTest) PositiveIntegerLiteral() { - matcher := LessOrEqual(150) - desc := matcher.Description() - expectedDesc := "less than or equal to 150" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []leTestCase{ - // Signed integers. - leTestCase{-1, true, false, ""}, - leTestCase{149, true, false, ""}, - leTestCase{150, true, false, ""}, - leTestCase{151, false, false, ""}, - - leTestCase{int(-1), true, false, ""}, - leTestCase{int(149), true, false, ""}, - leTestCase{int(150), true, false, ""}, - leTestCase{int(151), false, false, ""}, - - leTestCase{int8(-1), true, false, ""}, - leTestCase{int8(0), true, false, ""}, - leTestCase{int8(17), true, false, ""}, - leTestCase{int8(127), true, false, ""}, - - leTestCase{int16(-1), true, false, ""}, - leTestCase{int16(149), true, false, ""}, - leTestCase{int16(150), true, false, ""}, - leTestCase{int16(151), false, false, ""}, - - leTestCase{int32(-1), true, false, ""}, - leTestCase{int32(149), true, false, ""}, - leTestCase{int32(150), true, false, ""}, - leTestCase{int32(151), false, false, ""}, - - leTestCase{int64(-1), true, false, ""}, - leTestCase{int64(149), true, false, ""}, - leTestCase{int64(150), true, false, ""}, - leTestCase{int64(151), false, false, ""}, - - // Unsigned integers. - leTestCase{uint(0), true, false, ""}, - leTestCase{uint(149), true, false, ""}, - leTestCase{uint(150), true, false, ""}, - leTestCase{uint(151), false, false, ""}, - - leTestCase{uint8(0), true, false, ""}, - leTestCase{uint8(127), true, false, ""}, - - leTestCase{uint16(0), true, false, ""}, - leTestCase{uint16(149), true, false, ""}, - leTestCase{uint16(150), true, false, ""}, - leTestCase{uint16(151), false, false, ""}, - - leTestCase{uint32(0), true, false, ""}, - leTestCase{uint32(149), true, false, ""}, - leTestCase{uint32(150), true, false, ""}, - leTestCase{uint32(151), false, false, ""}, - - leTestCase{uint64(0), true, false, ""}, - leTestCase{uint64(149), true, false, ""}, - leTestCase{uint64(150), true, false, ""}, - leTestCase{uint64(151), false, false, ""}, - - // Floating point. - leTestCase{float32(-1), true, false, ""}, - leTestCase{float32(149), true, false, ""}, - leTestCase{float32(149.9), true, false, ""}, - leTestCase{float32(150), true, false, ""}, - leTestCase{float32(150.1), false, false, ""}, - leTestCase{float32(151), false, false, ""}, - - leTestCase{float64(-1), true, false, ""}, - leTestCase{float64(149), true, false, ""}, - leTestCase{float64(149.9), true, false, ""}, - leTestCase{float64(150), true, false, ""}, - leTestCase{float64(150.1), false, false, ""}, - leTestCase{float64(151), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// Float literals -//////////////////////////////////////////////////////////////////////// - -func (t *LessOrEqualTest) NegativeFloatLiteral() { - matcher := LessOrEqual(-150.1) - desc := matcher.Description() - expectedDesc := "less than or equal to -150.1" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []leTestCase{ - // Signed integers. - leTestCase{-(1 << 30), true, false, ""}, - leTestCase{-151, true, false, ""}, - leTestCase{-150.1, true, false, ""}, - leTestCase{-150, false, false, ""}, - leTestCase{-149, false, false, ""}, - leTestCase{0, false, false, ""}, - leTestCase{17, false, false, ""}, - - leTestCase{int(-(1 << 30)), true, false, ""}, - leTestCase{int(-151), true, false, ""}, - leTestCase{int(-150), false, false, ""}, - leTestCase{int(-149), false, false, ""}, - leTestCase{int(0), false, false, ""}, - leTestCase{int(17), false, false, ""}, - - leTestCase{int8(-127), false, false, ""}, - leTestCase{int8(0), false, false, ""}, - leTestCase{int8(17), false, false, ""}, - - leTestCase{int16(-(1 << 14)), true, false, ""}, - leTestCase{int16(-151), true, false, ""}, - leTestCase{int16(-150), false, false, ""}, - leTestCase{int16(-149), false, false, ""}, - leTestCase{int16(0), false, false, ""}, - leTestCase{int16(17), false, false, ""}, - - leTestCase{int32(-(1 << 30)), true, false, ""}, - leTestCase{int32(-151), true, false, ""}, - leTestCase{int32(-150), false, false, ""}, - leTestCase{int32(-149), false, false, ""}, - leTestCase{int32(0), false, false, ""}, - leTestCase{int32(17), false, false, ""}, - - leTestCase{int64(-(1 << 30)), true, false, ""}, - leTestCase{int64(-151), true, false, ""}, - leTestCase{int64(-150), false, false, ""}, - leTestCase{int64(-149), false, false, ""}, - leTestCase{int64(0), false, false, ""}, - leTestCase{int64(17), false, false, ""}, - - // Unsigned integers. - leTestCase{uint((1 << 32) - 151), false, false, ""}, - leTestCase{uint(0), false, false, ""}, - leTestCase{uint(17), false, false, ""}, - - leTestCase{uint8(0), false, false, ""}, - leTestCase{uint8(17), false, false, ""}, - leTestCase{uint8(253), false, false, ""}, - - leTestCase{uint16((1 << 16) - 151), false, false, ""}, - leTestCase{uint16(0), false, false, ""}, - leTestCase{uint16(17), false, false, ""}, - - leTestCase{uint32((1 << 32) - 151), false, false, ""}, - leTestCase{uint32(0), false, false, ""}, - leTestCase{uint32(17), false, false, ""}, - - leTestCase{uint64((1 << 64) - 151), false, false, ""}, - leTestCase{uint64(0), false, false, ""}, - leTestCase{uint64(17), false, false, ""}, - - // Floating point. - leTestCase{float32(-(1 << 30)), true, false, ""}, - leTestCase{float32(-151), true, false, ""}, - leTestCase{float32(-150.2), true, false, ""}, - leTestCase{float32(-150.1), true, false, ""}, - leTestCase{float32(-150), false, false, ""}, - leTestCase{float32(0), false, false, ""}, - leTestCase{float32(17), false, false, ""}, - leTestCase{float32(160), false, false, ""}, - - leTestCase{float64(-(1 << 30)), true, false, ""}, - leTestCase{float64(-151), true, false, ""}, - leTestCase{float64(-150.2), true, false, ""}, - leTestCase{float64(-150.1), true, false, ""}, - leTestCase{float64(-150), false, false, ""}, - leTestCase{float64(0), false, false, ""}, - leTestCase{float64(17), false, false, ""}, - leTestCase{float64(160), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessOrEqualTest) PositiveFloatLiteral() { - matcher := LessOrEqual(149.9) - desc := matcher.Description() - expectedDesc := "less than or equal to 149.9" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []leTestCase{ - // Signed integers. - leTestCase{-1, true, false, ""}, - leTestCase{149, true, false, ""}, - leTestCase{149.9, true, false, ""}, - leTestCase{150, false, false, ""}, - leTestCase{151, false, false, ""}, - - leTestCase{int(-1), true, false, ""}, - leTestCase{int(149), true, false, ""}, - leTestCase{int(150), false, false, ""}, - leTestCase{int(151), false, false, ""}, - - leTestCase{int8(-1), true, false, ""}, - leTestCase{int8(0), true, false, ""}, - leTestCase{int8(17), true, false, ""}, - leTestCase{int8(127), true, false, ""}, - - leTestCase{int16(-1), true, false, ""}, - leTestCase{int16(149), true, false, ""}, - leTestCase{int16(150), false, false, ""}, - leTestCase{int16(151), false, false, ""}, - - leTestCase{int32(-1), true, false, ""}, - leTestCase{int32(149), true, false, ""}, - leTestCase{int32(150), false, false, ""}, - leTestCase{int32(151), false, false, ""}, - - leTestCase{int64(-1), true, false, ""}, - leTestCase{int64(149), true, false, ""}, - leTestCase{int64(150), false, false, ""}, - leTestCase{int64(151), false, false, ""}, - - // Unsigned integers. - leTestCase{uint(0), true, false, ""}, - leTestCase{uint(149), true, false, ""}, - leTestCase{uint(150), false, false, ""}, - leTestCase{uint(151), false, false, ""}, - - leTestCase{uint8(0), true, false, ""}, - leTestCase{uint8(127), true, false, ""}, - - leTestCase{uint16(0), true, false, ""}, - leTestCase{uint16(149), true, false, ""}, - leTestCase{uint16(150), false, false, ""}, - leTestCase{uint16(151), false, false, ""}, - - leTestCase{uint32(0), true, false, ""}, - leTestCase{uint32(149), true, false, ""}, - leTestCase{uint32(150), false, false, ""}, - leTestCase{uint32(151), false, false, ""}, - - leTestCase{uint64(0), true, false, ""}, - leTestCase{uint64(149), true, false, ""}, - leTestCase{uint64(150), false, false, ""}, - leTestCase{uint64(151), false, false, ""}, - - // Floating point. - leTestCase{float32(-1), true, false, ""}, - leTestCase{float32(149), true, false, ""}, - leTestCase{float32(149.8), true, false, ""}, - leTestCase{float32(149.9), true, false, ""}, - leTestCase{float32(150), false, false, ""}, - leTestCase{float32(151), false, false, ""}, - - leTestCase{float64(-1), true, false, ""}, - leTestCase{float64(149), true, false, ""}, - leTestCase{float64(149.8), true, false, ""}, - leTestCase{float64(149.9), true, false, ""}, - leTestCase{float64(150), false, false, ""}, - leTestCase{float64(151), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// Subtle cases -//////////////////////////////////////////////////////////////////////// - -func (t *LessOrEqualTest) Int64NotExactlyRepresentableBySinglePrecision() { - // Single-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^25-1, 2^25+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo25 = 1 << 25 - matcher := LessOrEqual(int64(kTwoTo25 + 1)) - - desc := matcher.Description() - expectedDesc := "less than or equal to 33554433" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []leTestCase{ - // Signed integers. - leTestCase{-1, true, false, ""}, - leTestCase{kTwoTo25 + 0, true, false, ""}, - leTestCase{kTwoTo25 + 1, true, false, ""}, - leTestCase{kTwoTo25 + 2, false, false, ""}, - - leTestCase{int(-1), true, false, ""}, - leTestCase{int(kTwoTo25 + 0), true, false, ""}, - leTestCase{int(kTwoTo25 + 1), true, false, ""}, - leTestCase{int(kTwoTo25 + 2), false, false, ""}, - - leTestCase{int8(-1), true, false, ""}, - leTestCase{int8(127), true, false, ""}, - - leTestCase{int16(-1), true, false, ""}, - leTestCase{int16(0), true, false, ""}, - leTestCase{int16(32767), true, false, ""}, - - leTestCase{int32(-1), true, false, ""}, - leTestCase{int32(kTwoTo25 + 0), true, false, ""}, - leTestCase{int32(kTwoTo25 + 1), true, false, ""}, - leTestCase{int32(kTwoTo25 + 2), false, false, ""}, - - leTestCase{int64(-1), true, false, ""}, - leTestCase{int64(kTwoTo25 + 0), true, false, ""}, - leTestCase{int64(kTwoTo25 + 1), true, false, ""}, - leTestCase{int64(kTwoTo25 + 2), false, false, ""}, - - // Unsigned integers. - leTestCase{uint(0), true, false, ""}, - leTestCase{uint(kTwoTo25 + 0), true, false, ""}, - leTestCase{uint(kTwoTo25 + 1), true, false, ""}, - leTestCase{uint(kTwoTo25 + 2), false, false, ""}, - - leTestCase{uint8(0), true, false, ""}, - leTestCase{uint8(255), true, false, ""}, - - leTestCase{uint16(0), true, false, ""}, - leTestCase{uint16(65535), true, false, ""}, - - leTestCase{uint32(0), true, false, ""}, - leTestCase{uint32(kTwoTo25 + 0), true, false, ""}, - leTestCase{uint32(kTwoTo25 + 1), true, false, ""}, - leTestCase{uint32(kTwoTo25 + 2), false, false, ""}, - - leTestCase{uint64(0), true, false, ""}, - leTestCase{uint64(kTwoTo25 + 0), true, false, ""}, - leTestCase{uint64(kTwoTo25 + 1), true, false, ""}, - leTestCase{uint64(kTwoTo25 + 2), false, false, ""}, - - // Floating point. - leTestCase{float32(-1), true, false, ""}, - leTestCase{float32(kTwoTo25 - 2), true, false, ""}, - leTestCase{float32(kTwoTo25 - 1), true, false, ""}, - leTestCase{float32(kTwoTo25 + 0), true, false, ""}, - leTestCase{float32(kTwoTo25 + 1), true, false, ""}, - leTestCase{float32(kTwoTo25 + 2), true, false, ""}, - leTestCase{float32(kTwoTo25 + 3), false, false, ""}, - - leTestCase{float64(-1), true, false, ""}, - leTestCase{float64(kTwoTo25 - 2), true, false, ""}, - leTestCase{float64(kTwoTo25 - 1), true, false, ""}, - leTestCase{float64(kTwoTo25 + 0), true, false, ""}, - leTestCase{float64(kTwoTo25 + 1), true, false, ""}, - leTestCase{float64(kTwoTo25 + 2), false, false, ""}, - leTestCase{float64(kTwoTo25 + 3), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessOrEqualTest) Int64NotExactlyRepresentableByDoublePrecision() { - // Double-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^54-1, 2^54+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo54 = 1 << 54 - matcher := LessOrEqual(int64(kTwoTo54 + 1)) - - desc := matcher.Description() - expectedDesc := "less than or equal to 18014398509481985" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []leTestCase{ - // Signed integers. - leTestCase{-1, true, false, ""}, - leTestCase{1 << 30, true, false, ""}, - - leTestCase{int(-1), true, false, ""}, - leTestCase{int(math.MaxInt32), true, false, ""}, - - leTestCase{int8(-1), true, false, ""}, - leTestCase{int8(127), true, false, ""}, - - leTestCase{int16(-1), true, false, ""}, - leTestCase{int16(0), true, false, ""}, - leTestCase{int16(32767), true, false, ""}, - - leTestCase{int32(-1), true, false, ""}, - leTestCase{int32(math.MaxInt32), true, false, ""}, - - leTestCase{int64(-1), true, false, ""}, - leTestCase{int64(kTwoTo54 - 1), true, false, ""}, - leTestCase{int64(kTwoTo54 + 0), true, false, ""}, - leTestCase{int64(kTwoTo54 + 1), true, false, ""}, - leTestCase{int64(kTwoTo54 + 2), false, false, ""}, - - // Unsigned integers. - leTestCase{uint(0), true, false, ""}, - leTestCase{uint(math.MaxUint32), true, false, ""}, - - leTestCase{uint8(0), true, false, ""}, - leTestCase{uint8(255), true, false, ""}, - - leTestCase{uint16(0), true, false, ""}, - leTestCase{uint16(65535), true, false, ""}, - - leTestCase{uint32(0), true, false, ""}, - leTestCase{uint32(math.MaxUint32), true, false, ""}, - - leTestCase{uint64(0), true, false, ""}, - leTestCase{uint64(kTwoTo54 - 1), true, false, ""}, - leTestCase{uint64(kTwoTo54 + 0), true, false, ""}, - leTestCase{uint64(kTwoTo54 + 1), true, false, ""}, - leTestCase{uint64(kTwoTo54 + 2), false, false, ""}, - - // Floating point. - leTestCase{float64(-1), true, false, ""}, - leTestCase{float64(kTwoTo54 - 2), true, false, ""}, - leTestCase{float64(kTwoTo54 - 1), true, false, ""}, - leTestCase{float64(kTwoTo54 + 0), true, false, ""}, - leTestCase{float64(kTwoTo54 + 1), true, false, ""}, - leTestCase{float64(kTwoTo54 + 2), true, false, ""}, - leTestCase{float64(kTwoTo54 + 3), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessOrEqualTest) Uint64NotExactlyRepresentableBySinglePrecision() { - // Single-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^25-1, 2^25+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo25 = 1 << 25 - matcher := LessOrEqual(uint64(kTwoTo25 + 1)) - - desc := matcher.Description() - expectedDesc := "less than or equal to 33554433" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []leTestCase{ - // Signed integers. - leTestCase{-1, true, false, ""}, - leTestCase{kTwoTo25 + 0, true, false, ""}, - leTestCase{kTwoTo25 + 1, true, false, ""}, - leTestCase{kTwoTo25 + 2, false, false, ""}, - - leTestCase{int(-1), true, false, ""}, - leTestCase{int(kTwoTo25 + 0), true, false, ""}, - leTestCase{int(kTwoTo25 + 1), true, false, ""}, - leTestCase{int(kTwoTo25 + 2), false, false, ""}, - - leTestCase{int8(-1), true, false, ""}, - leTestCase{int8(127), true, false, ""}, - - leTestCase{int16(-1), true, false, ""}, - leTestCase{int16(0), true, false, ""}, - leTestCase{int16(32767), true, false, ""}, - - leTestCase{int32(-1), true, false, ""}, - leTestCase{int32(kTwoTo25 + 0), true, false, ""}, - leTestCase{int32(kTwoTo25 + 1), true, false, ""}, - leTestCase{int32(kTwoTo25 + 2), false, false, ""}, - - leTestCase{int64(-1), true, false, ""}, - leTestCase{int64(kTwoTo25 + 0), true, false, ""}, - leTestCase{int64(kTwoTo25 + 1), true, false, ""}, - leTestCase{int64(kTwoTo25 + 2), false, false, ""}, - - // Unsigned integers. - leTestCase{uint(0), true, false, ""}, - leTestCase{uint(kTwoTo25 + 0), true, false, ""}, - leTestCase{uint(kTwoTo25 + 1), true, false, ""}, - leTestCase{uint(kTwoTo25 + 2), false, false, ""}, - - leTestCase{uint8(0), true, false, ""}, - leTestCase{uint8(255), true, false, ""}, - - leTestCase{uint16(0), true, false, ""}, - leTestCase{uint16(65535), true, false, ""}, - - leTestCase{uint32(0), true, false, ""}, - leTestCase{uint32(kTwoTo25 + 0), true, false, ""}, - leTestCase{uint32(kTwoTo25 + 1), true, false, ""}, - leTestCase{uint32(kTwoTo25 + 2), false, false, ""}, - - leTestCase{uint64(0), true, false, ""}, - leTestCase{uint64(kTwoTo25 + 0), true, false, ""}, - leTestCase{uint64(kTwoTo25 + 1), true, false, ""}, - leTestCase{uint64(kTwoTo25 + 2), false, false, ""}, - - // Floating point. - leTestCase{float32(-1), true, false, ""}, - leTestCase{float32(kTwoTo25 - 2), true, false, ""}, - leTestCase{float32(kTwoTo25 - 1), true, false, ""}, - leTestCase{float32(kTwoTo25 + 0), true, false, ""}, - leTestCase{float32(kTwoTo25 + 1), true, false, ""}, - leTestCase{float32(kTwoTo25 + 2), true, false, ""}, - leTestCase{float32(kTwoTo25 + 3), false, false, ""}, - - leTestCase{float64(-1), true, false, ""}, - leTestCase{float64(kTwoTo25 - 2), true, false, ""}, - leTestCase{float64(kTwoTo25 - 1), true, false, ""}, - leTestCase{float64(kTwoTo25 + 0), true, false, ""}, - leTestCase{float64(kTwoTo25 + 1), true, false, ""}, - leTestCase{float64(kTwoTo25 + 2), false, false, ""}, - leTestCase{float64(kTwoTo25 + 3), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessOrEqualTest) Uint64NotExactlyRepresentableByDoublePrecision() { - // Double-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^54-1, 2^54+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo54 = 1 << 54 - matcher := LessOrEqual(uint64(kTwoTo54 + 1)) - - desc := matcher.Description() - expectedDesc := "less than or equal to 18014398509481985" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []leTestCase{ - // Signed integers. - leTestCase{-1, true, false, ""}, - leTestCase{1 << 30, true, false, ""}, - - leTestCase{int(-1), true, false, ""}, - leTestCase{int(math.MaxInt32), true, false, ""}, - - leTestCase{int8(-1), true, false, ""}, - leTestCase{int8(127), true, false, ""}, - - leTestCase{int16(-1), true, false, ""}, - leTestCase{int16(0), true, false, ""}, - leTestCase{int16(32767), true, false, ""}, - - leTestCase{int32(-1), true, false, ""}, - leTestCase{int32(math.MaxInt32), true, false, ""}, - - leTestCase{int64(-1), true, false, ""}, - leTestCase{int64(kTwoTo54 - 1), true, false, ""}, - leTestCase{int64(kTwoTo54 + 0), true, false, ""}, - leTestCase{int64(kTwoTo54 + 1), true, false, ""}, - leTestCase{int64(kTwoTo54 + 2), false, false, ""}, - - // Unsigned integers. - leTestCase{uint(0), true, false, ""}, - leTestCase{uint(math.MaxUint32), true, false, ""}, - - leTestCase{uint8(0), true, false, ""}, - leTestCase{uint8(255), true, false, ""}, - - leTestCase{uint16(0), true, false, ""}, - leTestCase{uint16(65535), true, false, ""}, - - leTestCase{uint32(0), true, false, ""}, - leTestCase{uint32(math.MaxUint32), true, false, ""}, - - leTestCase{uint64(0), true, false, ""}, - leTestCase{uint64(kTwoTo54 - 1), true, false, ""}, - leTestCase{uint64(kTwoTo54 + 0), true, false, ""}, - leTestCase{uint64(kTwoTo54 + 1), true, false, ""}, - leTestCase{uint64(kTwoTo54 + 2), false, false, ""}, - - // Floating point. - leTestCase{float64(-1), true, false, ""}, - leTestCase{float64(kTwoTo54 - 2), true, false, ""}, - leTestCase{float64(kTwoTo54 - 1), true, false, ""}, - leTestCase{float64(kTwoTo54 + 0), true, false, ""}, - leTestCase{float64(kTwoTo54 + 1), true, false, ""}, - leTestCase{float64(kTwoTo54 + 2), true, false, ""}, - leTestCase{float64(kTwoTo54 + 3), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessOrEqualTest) Float32AboveExactIntegerRange() { - // Single-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^25-1, 2^25+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo25 = 1 << 25 - matcher := LessOrEqual(float32(kTwoTo25 + 1)) - - desc := matcher.Description() - expectedDesc := "less than or equal to 3.3554432e+07" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []leTestCase{ - // Signed integers. - leTestCase{int64(-1), true, false, ""}, - leTestCase{int64(kTwoTo25 - 2), true, false, ""}, - leTestCase{int64(kTwoTo25 - 1), true, false, ""}, - leTestCase{int64(kTwoTo25 + 0), true, false, ""}, - leTestCase{int64(kTwoTo25 + 1), true, false, ""}, - leTestCase{int64(kTwoTo25 + 2), true, false, ""}, - leTestCase{int64(kTwoTo25 + 3), false, false, ""}, - - // Unsigned integers. - leTestCase{uint64(0), true, false, ""}, - leTestCase{uint64(kTwoTo25 - 2), true, false, ""}, - leTestCase{uint64(kTwoTo25 - 1), true, false, ""}, - leTestCase{uint64(kTwoTo25 + 0), true, false, ""}, - leTestCase{uint64(kTwoTo25 + 1), true, false, ""}, - leTestCase{uint64(kTwoTo25 + 2), true, false, ""}, - leTestCase{uint64(kTwoTo25 + 3), false, false, ""}, - - // Floating point. - leTestCase{float32(-1), true, false, ""}, - leTestCase{float32(kTwoTo25 - 2), true, false, ""}, - leTestCase{float32(kTwoTo25 - 1), true, false, ""}, - leTestCase{float32(kTwoTo25 + 0), true, false, ""}, - leTestCase{float32(kTwoTo25 + 1), true, false, ""}, - leTestCase{float32(kTwoTo25 + 2), true, false, ""}, - leTestCase{float32(kTwoTo25 + 3), false, false, ""}, - - leTestCase{float64(-1), true, false, ""}, - leTestCase{float64(kTwoTo25 - 2), true, false, ""}, - leTestCase{float64(kTwoTo25 - 1), true, false, ""}, - leTestCase{float64(kTwoTo25 + 0), true, false, ""}, - leTestCase{float64(kTwoTo25 + 1), true, false, ""}, - leTestCase{float64(kTwoTo25 + 2), true, false, ""}, - leTestCase{float64(kTwoTo25 + 3), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessOrEqualTest) Float64AboveExactIntegerRange() { - // Double-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^54-1, 2^54+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo54 = 1 << 54 - matcher := LessOrEqual(float64(kTwoTo54 + 1)) - - desc := matcher.Description() - expectedDesc := "less than or equal to 1.8014398509481984e+16" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []leTestCase{ - // Signed integers. - leTestCase{int64(-1), true, false, ""}, - leTestCase{int64(kTwoTo54 - 2), true, false, ""}, - leTestCase{int64(kTwoTo54 - 1), true, false, ""}, - leTestCase{int64(kTwoTo54 + 0), true, false, ""}, - leTestCase{int64(kTwoTo54 + 1), true, false, ""}, - leTestCase{int64(kTwoTo54 + 2), true, false, ""}, - leTestCase{int64(kTwoTo54 + 3), false, false, ""}, - - // Unsigned integers. - leTestCase{uint64(0), true, false, ""}, - leTestCase{uint64(kTwoTo54 - 2), true, false, ""}, - leTestCase{uint64(kTwoTo54 - 1), true, false, ""}, - leTestCase{uint64(kTwoTo54 + 0), true, false, ""}, - leTestCase{uint64(kTwoTo54 + 1), true, false, ""}, - leTestCase{uint64(kTwoTo54 + 2), true, false, ""}, - leTestCase{uint64(kTwoTo54 + 3), false, false, ""}, - - // Floating point. - leTestCase{float64(-1), true, false, ""}, - leTestCase{float64(kTwoTo54 - 2), true, false, ""}, - leTestCase{float64(kTwoTo54 - 1), true, false, ""}, - leTestCase{float64(kTwoTo54 + 0), true, false, ""}, - leTestCase{float64(kTwoTo54 + 1), true, false, ""}, - leTestCase{float64(kTwoTo54 + 2), true, false, ""}, - leTestCase{float64(kTwoTo54 + 3), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// String literals -//////////////////////////////////////////////////////////////////////// - -func (t *LessOrEqualTest) EmptyString() { - matcher := LessOrEqual("") - desc := matcher.Description() - expectedDesc := "less than or equal to \"\"" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []leTestCase{ - leTestCase{"", true, false, ""}, - leTestCase{"\x00", false, false, ""}, - leTestCase{"a", false, false, ""}, - leTestCase{"foo", false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessOrEqualTest) SingleNullByte() { - matcher := LessOrEqual("\x00") - desc := matcher.Description() - expectedDesc := "less than or equal to \"\x00\"" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []leTestCase{ - leTestCase{"", true, false, ""}, - leTestCase{"\x00", true, false, ""}, - leTestCase{"\x00\x00", false, false, ""}, - leTestCase{"a", false, false, ""}, - leTestCase{"foo", false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessOrEqualTest) LongerString() { - matcher := LessOrEqual("foo\x00") - desc := matcher.Description() - expectedDesc := "less than or equal to \"foo\x00\"" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []leTestCase{ - leTestCase{"", true, false, ""}, - leTestCase{"\x00", true, false, ""}, - leTestCase{"bar", true, false, ""}, - leTestCase{"foo", true, false, ""}, - leTestCase{"foo\x00", true, false, ""}, - leTestCase{"foo\x00\x00", false, false, ""}, - leTestCase{"fooa", false, false, ""}, - leTestCase{"qux", false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/less_than_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/less_than_test.go deleted file mode 100644 index 63bc7f44f0f..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/less_than_test.go +++ /dev/null @@ -1,1059 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "math" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type LessThanTest struct { -} - -func init() { RegisterTestSuite(&LessThanTest{}) } - -type ltTestCase struct { - candidate interface{} - expectedResult bool - shouldBeFatal bool - expectedError string -} - -func (t *LessThanTest) checkTestCases(matcher Matcher, cases []ltTestCase) { - for i, c := range cases { - err := matcher.Matches(c.candidate) - - ExpectThat( - (err == nil), - Equals(c.expectedResult), - "Case %d (candidate %v)", - i, - c.candidate) - - if err == nil { - continue - } - - _, isFatal := err.(*FatalError) - ExpectEq( - c.shouldBeFatal, - isFatal, - "Case %d (candidate %v)", - i, - c.candidate) - - ExpectThat( - err, - Error(Equals(c.expectedError)), - "Case %d (candidate %v)", - i, - c.candidate) - } -} - -//////////////////////////////////////////////////////////////////////// -// Integer literals -//////////////////////////////////////////////////////////////////////// - -func (t *LessThanTest) IntegerCandidateBadTypes() { - matcher := LessThan(int(-150)) - - cases := []ltTestCase{ - ltTestCase{true, false, true, "which is not comparable"}, - ltTestCase{uintptr(17), false, true, "which is not comparable"}, - ltTestCase{complex64(-151), false, true, "which is not comparable"}, - ltTestCase{complex128(-151), false, true, "which is not comparable"}, - ltTestCase{[...]int{-151}, false, true, "which is not comparable"}, - ltTestCase{make(chan int), false, true, "which is not comparable"}, - ltTestCase{func() {}, false, true, "which is not comparable"}, - ltTestCase{map[int]int{}, false, true, "which is not comparable"}, - ltTestCase{<TestCase{}, false, true, "which is not comparable"}, - ltTestCase{make([]int, 0), false, true, "which is not comparable"}, - ltTestCase{"-151", false, true, "which is not comparable"}, - ltTestCase{ltTestCase{}, false, true, "which is not comparable"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessThanTest) FloatCandidateBadTypes() { - matcher := LessThan(float32(-150)) - - cases := []ltTestCase{ - ltTestCase{true, false, true, "which is not comparable"}, - ltTestCase{uintptr(17), false, true, "which is not comparable"}, - ltTestCase{complex64(-151), false, true, "which is not comparable"}, - ltTestCase{complex128(-151), false, true, "which is not comparable"}, - ltTestCase{[...]int{-151}, false, true, "which is not comparable"}, - ltTestCase{make(chan int), false, true, "which is not comparable"}, - ltTestCase{func() {}, false, true, "which is not comparable"}, - ltTestCase{map[int]int{}, false, true, "which is not comparable"}, - ltTestCase{<TestCase{}, false, true, "which is not comparable"}, - ltTestCase{make([]int, 0), false, true, "which is not comparable"}, - ltTestCase{"-151", false, true, "which is not comparable"}, - ltTestCase{ltTestCase{}, false, true, "which is not comparable"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessThanTest) StringCandidateBadTypes() { - matcher := LessThan("17") - - cases := []ltTestCase{ - ltTestCase{true, false, true, "which is not comparable"}, - ltTestCase{int(0), false, true, "which is not comparable"}, - ltTestCase{int8(0), false, true, "which is not comparable"}, - ltTestCase{int16(0), false, true, "which is not comparable"}, - ltTestCase{int32(0), false, true, "which is not comparable"}, - ltTestCase{int64(0), false, true, "which is not comparable"}, - ltTestCase{uint(0), false, true, "which is not comparable"}, - ltTestCase{uint8(0), false, true, "which is not comparable"}, - ltTestCase{uint16(0), false, true, "which is not comparable"}, - ltTestCase{uint32(0), false, true, "which is not comparable"}, - ltTestCase{uint64(0), false, true, "which is not comparable"}, - ltTestCase{uintptr(17), false, true, "which is not comparable"}, - ltTestCase{float32(0), false, true, "which is not comparable"}, - ltTestCase{float64(0), false, true, "which is not comparable"}, - ltTestCase{complex64(-151), false, true, "which is not comparable"}, - ltTestCase{complex128(-151), false, true, "which is not comparable"}, - ltTestCase{[...]int{-151}, false, true, "which is not comparable"}, - ltTestCase{make(chan int), false, true, "which is not comparable"}, - ltTestCase{func() {}, false, true, "which is not comparable"}, - ltTestCase{map[int]int{}, false, true, "which is not comparable"}, - ltTestCase{<TestCase{}, false, true, "which is not comparable"}, - ltTestCase{make([]int, 0), false, true, "which is not comparable"}, - ltTestCase{ltTestCase{}, false, true, "which is not comparable"}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessThanTest) BadArgument() { - panicked := false - - defer func() { - ExpectThat(panicked, Equals(true)) - }() - - defer func() { - if r := recover(); r != nil { - panicked = true - } - }() - - LessThan(complex128(0)) -} - -//////////////////////////////////////////////////////////////////////// -// Integer literals -//////////////////////////////////////////////////////////////////////// - -func (t *LessThanTest) NegativeIntegerLiteral() { - matcher := LessThan(-150) - desc := matcher.Description() - expectedDesc := "less than -150" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []ltTestCase{ - // Signed integers. - ltTestCase{-(1 << 30), true, false, ""}, - ltTestCase{-151, true, false, ""}, - ltTestCase{-150, false, false, ""}, - ltTestCase{0, false, false, ""}, - ltTestCase{17, false, false, ""}, - - ltTestCase{int(-(1 << 30)), true, false, ""}, - ltTestCase{int(-151), true, false, ""}, - ltTestCase{int(-150), false, false, ""}, - ltTestCase{int(0), false, false, ""}, - ltTestCase{int(17), false, false, ""}, - - ltTestCase{int8(-127), false, false, ""}, - ltTestCase{int8(0), false, false, ""}, - ltTestCase{int8(17), false, false, ""}, - - ltTestCase{int16(-(1 << 14)), true, false, ""}, - ltTestCase{int16(-151), true, false, ""}, - ltTestCase{int16(-150), false, false, ""}, - ltTestCase{int16(0), false, false, ""}, - ltTestCase{int16(17), false, false, ""}, - - ltTestCase{int32(-(1 << 30)), true, false, ""}, - ltTestCase{int32(-151), true, false, ""}, - ltTestCase{int32(-150), false, false, ""}, - ltTestCase{int32(0), false, false, ""}, - ltTestCase{int32(17), false, false, ""}, - - ltTestCase{int64(-(1 << 30)), true, false, ""}, - ltTestCase{int64(-151), true, false, ""}, - ltTestCase{int64(-150), false, false, ""}, - ltTestCase{int64(0), false, false, ""}, - ltTestCase{int64(17), false, false, ""}, - - // Unsigned integers. - ltTestCase{uint((1 << 32) - 151), false, false, ""}, - ltTestCase{uint(0), false, false, ""}, - ltTestCase{uint(17), false, false, ""}, - - ltTestCase{uint8(0), false, false, ""}, - ltTestCase{uint8(17), false, false, ""}, - ltTestCase{uint8(253), false, false, ""}, - - ltTestCase{uint16((1 << 16) - 151), false, false, ""}, - ltTestCase{uint16(0), false, false, ""}, - ltTestCase{uint16(17), false, false, ""}, - - ltTestCase{uint32((1 << 32) - 151), false, false, ""}, - ltTestCase{uint32(0), false, false, ""}, - ltTestCase{uint32(17), false, false, ""}, - - ltTestCase{uint64((1 << 64) - 151), false, false, ""}, - ltTestCase{uint64(0), false, false, ""}, - ltTestCase{uint64(17), false, false, ""}, - - // Floating point. - ltTestCase{float32(-(1 << 30)), true, false, ""}, - ltTestCase{float32(-151), true, false, ""}, - ltTestCase{float32(-150.1), true, false, ""}, - ltTestCase{float32(-150), false, false, ""}, - ltTestCase{float32(-149.9), false, false, ""}, - ltTestCase{float32(0), false, false, ""}, - ltTestCase{float32(17), false, false, ""}, - ltTestCase{float32(160), false, false, ""}, - - ltTestCase{float64(-(1 << 30)), true, false, ""}, - ltTestCase{float64(-151), true, false, ""}, - ltTestCase{float64(-150.1), true, false, ""}, - ltTestCase{float64(-150), false, false, ""}, - ltTestCase{float64(-149.9), false, false, ""}, - ltTestCase{float64(0), false, false, ""}, - ltTestCase{float64(17), false, false, ""}, - ltTestCase{float64(160), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessThanTest) ZeroIntegerLiteral() { - matcher := LessThan(0) - desc := matcher.Description() - expectedDesc := "less than 0" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []ltTestCase{ - // Signed integers. - ltTestCase{-(1 << 30), true, false, ""}, - ltTestCase{-1, true, false, ""}, - ltTestCase{0, false, false, ""}, - ltTestCase{1, false, false, ""}, - ltTestCase{17, false, false, ""}, - ltTestCase{(1 << 30), false, false, ""}, - - ltTestCase{int(-(1 << 30)), true, false, ""}, - ltTestCase{int(-1), true, false, ""}, - ltTestCase{int(0), false, false, ""}, - ltTestCase{int(1), false, false, ""}, - ltTestCase{int(17), false, false, ""}, - - ltTestCase{int8(-1), true, false, ""}, - ltTestCase{int8(0), false, false, ""}, - ltTestCase{int8(1), false, false, ""}, - - ltTestCase{int16(-(1 << 14)), true, false, ""}, - ltTestCase{int16(-1), true, false, ""}, - ltTestCase{int16(0), false, false, ""}, - ltTestCase{int16(1), false, false, ""}, - ltTestCase{int16(17), false, false, ""}, - - ltTestCase{int32(-(1 << 30)), true, false, ""}, - ltTestCase{int32(-1), true, false, ""}, - ltTestCase{int32(0), false, false, ""}, - ltTestCase{int32(1), false, false, ""}, - ltTestCase{int32(17), false, false, ""}, - - ltTestCase{int64(-(1 << 30)), true, false, ""}, - ltTestCase{int64(-1), true, false, ""}, - ltTestCase{int64(0), false, false, ""}, - ltTestCase{int64(1), false, false, ""}, - ltTestCase{int64(17), false, false, ""}, - - // Unsigned integers. - ltTestCase{uint((1 << 32) - 1), false, false, ""}, - ltTestCase{uint(0), false, false, ""}, - ltTestCase{uint(17), false, false, ""}, - - ltTestCase{uint8(0), false, false, ""}, - ltTestCase{uint8(17), false, false, ""}, - ltTestCase{uint8(253), false, false, ""}, - - ltTestCase{uint16((1 << 16) - 1), false, false, ""}, - ltTestCase{uint16(0), false, false, ""}, - ltTestCase{uint16(17), false, false, ""}, - - ltTestCase{uint32((1 << 32) - 1), false, false, ""}, - ltTestCase{uint32(0), false, false, ""}, - ltTestCase{uint32(17), false, false, ""}, - - ltTestCase{uint64((1 << 64) - 1), false, false, ""}, - ltTestCase{uint64(0), false, false, ""}, - ltTestCase{uint64(17), false, false, ""}, - - // Floating point. - ltTestCase{float32(-(1 << 30)), true, false, ""}, - ltTestCase{float32(-1), true, false, ""}, - ltTestCase{float32(-0.1), true, false, ""}, - ltTestCase{float32(-0.0), false, false, ""}, - ltTestCase{float32(0), false, false, ""}, - ltTestCase{float32(0.1), false, false, ""}, - ltTestCase{float32(17), false, false, ""}, - ltTestCase{float32(160), false, false, ""}, - - ltTestCase{float64(-(1 << 30)), true, false, ""}, - ltTestCase{float64(-1), true, false, ""}, - ltTestCase{float64(-0.1), true, false, ""}, - ltTestCase{float64(-0), false, false, ""}, - ltTestCase{float64(0), false, false, ""}, - ltTestCase{float64(17), false, false, ""}, - ltTestCase{float64(160), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessThanTest) PositiveIntegerLiteral() { - matcher := LessThan(150) - desc := matcher.Description() - expectedDesc := "less than 150" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []ltTestCase{ - // Signed integers. - ltTestCase{-1, true, false, ""}, - ltTestCase{149, true, false, ""}, - ltTestCase{150, false, false, ""}, - ltTestCase{151, false, false, ""}, - - ltTestCase{int(-1), true, false, ""}, - ltTestCase{int(149), true, false, ""}, - ltTestCase{int(150), false, false, ""}, - ltTestCase{int(151), false, false, ""}, - - ltTestCase{int8(-1), true, false, ""}, - ltTestCase{int8(0), true, false, ""}, - ltTestCase{int8(17), true, false, ""}, - ltTestCase{int8(127), true, false, ""}, - - ltTestCase{int16(-1), true, false, ""}, - ltTestCase{int16(149), true, false, ""}, - ltTestCase{int16(150), false, false, ""}, - ltTestCase{int16(151), false, false, ""}, - - ltTestCase{int32(-1), true, false, ""}, - ltTestCase{int32(149), true, false, ""}, - ltTestCase{int32(150), false, false, ""}, - ltTestCase{int32(151), false, false, ""}, - - ltTestCase{int64(-1), true, false, ""}, - ltTestCase{int64(149), true, false, ""}, - ltTestCase{int64(150), false, false, ""}, - ltTestCase{int64(151), false, false, ""}, - - // Unsigned integers. - ltTestCase{uint(0), true, false, ""}, - ltTestCase{uint(149), true, false, ""}, - ltTestCase{uint(150), false, false, ""}, - ltTestCase{uint(151), false, false, ""}, - - ltTestCase{uint8(0), true, false, ""}, - ltTestCase{uint8(127), true, false, ""}, - - ltTestCase{uint16(0), true, false, ""}, - ltTestCase{uint16(149), true, false, ""}, - ltTestCase{uint16(150), false, false, ""}, - ltTestCase{uint16(151), false, false, ""}, - - ltTestCase{uint32(0), true, false, ""}, - ltTestCase{uint32(149), true, false, ""}, - ltTestCase{uint32(150), false, false, ""}, - ltTestCase{uint32(151), false, false, ""}, - - ltTestCase{uint64(0), true, false, ""}, - ltTestCase{uint64(149), true, false, ""}, - ltTestCase{uint64(150), false, false, ""}, - ltTestCase{uint64(151), false, false, ""}, - - // Floating point. - ltTestCase{float32(-1), true, false, ""}, - ltTestCase{float32(149), true, false, ""}, - ltTestCase{float32(149.9), true, false, ""}, - ltTestCase{float32(150), false, false, ""}, - ltTestCase{float32(150.1), false, false, ""}, - ltTestCase{float32(151), false, false, ""}, - - ltTestCase{float64(-1), true, false, ""}, - ltTestCase{float64(149), true, false, ""}, - ltTestCase{float64(149.9), true, false, ""}, - ltTestCase{float64(150), false, false, ""}, - ltTestCase{float64(150.1), false, false, ""}, - ltTestCase{float64(151), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// Float literals -//////////////////////////////////////////////////////////////////////// - -func (t *LessThanTest) NegativeFloatLiteral() { - matcher := LessThan(-150.1) - desc := matcher.Description() - expectedDesc := "less than -150.1" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []ltTestCase{ - // Signed integers. - ltTestCase{-(1 << 30), true, false, ""}, - ltTestCase{-151, true, false, ""}, - ltTestCase{-150, false, false, ""}, - ltTestCase{0, false, false, ""}, - ltTestCase{17, false, false, ""}, - - ltTestCase{int(-(1 << 30)), true, false, ""}, - ltTestCase{int(-151), true, false, ""}, - ltTestCase{int(-150), false, false, ""}, - ltTestCase{int(0), false, false, ""}, - ltTestCase{int(17), false, false, ""}, - - ltTestCase{int8(-127), false, false, ""}, - ltTestCase{int8(0), false, false, ""}, - ltTestCase{int8(17), false, false, ""}, - - ltTestCase{int16(-(1 << 14)), true, false, ""}, - ltTestCase{int16(-151), true, false, ""}, - ltTestCase{int16(-150), false, false, ""}, - ltTestCase{int16(0), false, false, ""}, - ltTestCase{int16(17), false, false, ""}, - - ltTestCase{int32(-(1 << 30)), true, false, ""}, - ltTestCase{int32(-151), true, false, ""}, - ltTestCase{int32(-150), false, false, ""}, - ltTestCase{int32(0), false, false, ""}, - ltTestCase{int32(17), false, false, ""}, - - ltTestCase{int64(-(1 << 30)), true, false, ""}, - ltTestCase{int64(-151), true, false, ""}, - ltTestCase{int64(-150), false, false, ""}, - ltTestCase{int64(0), false, false, ""}, - ltTestCase{int64(17), false, false, ""}, - - // Unsigned integers. - ltTestCase{uint((1 << 32) - 151), false, false, ""}, - ltTestCase{uint(0), false, false, ""}, - ltTestCase{uint(17), false, false, ""}, - - ltTestCase{uint8(0), false, false, ""}, - ltTestCase{uint8(17), false, false, ""}, - ltTestCase{uint8(253), false, false, ""}, - - ltTestCase{uint16((1 << 16) - 151), false, false, ""}, - ltTestCase{uint16(0), false, false, ""}, - ltTestCase{uint16(17), false, false, ""}, - - ltTestCase{uint32((1 << 32) - 151), false, false, ""}, - ltTestCase{uint32(0), false, false, ""}, - ltTestCase{uint32(17), false, false, ""}, - - ltTestCase{uint64((1 << 64) - 151), false, false, ""}, - ltTestCase{uint64(0), false, false, ""}, - ltTestCase{uint64(17), false, false, ""}, - - // Floating point. - ltTestCase{float32(-(1 << 30)), true, false, ""}, - ltTestCase{float32(-151), true, false, ""}, - ltTestCase{float32(-150.2), true, false, ""}, - ltTestCase{float32(-150.1), false, false, ""}, - ltTestCase{float32(-150), false, false, ""}, - ltTestCase{float32(0), false, false, ""}, - ltTestCase{float32(17), false, false, ""}, - ltTestCase{float32(160), false, false, ""}, - - ltTestCase{float64(-(1 << 30)), true, false, ""}, - ltTestCase{float64(-151), true, false, ""}, - ltTestCase{float64(-150.2), true, false, ""}, - ltTestCase{float64(-150.1), false, false, ""}, - ltTestCase{float64(-150), false, false, ""}, - ltTestCase{float64(0), false, false, ""}, - ltTestCase{float64(17), false, false, ""}, - ltTestCase{float64(160), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessThanTest) PositiveFloatLiteral() { - matcher := LessThan(149.9) - desc := matcher.Description() - expectedDesc := "less than 149.9" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []ltTestCase{ - // Signed integers. - ltTestCase{-1, true, false, ""}, - ltTestCase{149, true, false, ""}, - ltTestCase{150, false, false, ""}, - ltTestCase{151, false, false, ""}, - - ltTestCase{int(-1), true, false, ""}, - ltTestCase{int(149), true, false, ""}, - ltTestCase{int(150), false, false, ""}, - ltTestCase{int(151), false, false, ""}, - - ltTestCase{int8(-1), true, false, ""}, - ltTestCase{int8(0), true, false, ""}, - ltTestCase{int8(17), true, false, ""}, - ltTestCase{int8(127), true, false, ""}, - - ltTestCase{int16(-1), true, false, ""}, - ltTestCase{int16(149), true, false, ""}, - ltTestCase{int16(150), false, false, ""}, - ltTestCase{int16(151), false, false, ""}, - - ltTestCase{int32(-1), true, false, ""}, - ltTestCase{int32(149), true, false, ""}, - ltTestCase{int32(150), false, false, ""}, - ltTestCase{int32(151), false, false, ""}, - - ltTestCase{int64(-1), true, false, ""}, - ltTestCase{int64(149), true, false, ""}, - ltTestCase{int64(150), false, false, ""}, - ltTestCase{int64(151), false, false, ""}, - - // Unsigned integers. - ltTestCase{uint(0), true, false, ""}, - ltTestCase{uint(149), true, false, ""}, - ltTestCase{uint(150), false, false, ""}, - ltTestCase{uint(151), false, false, ""}, - - ltTestCase{uint8(0), true, false, ""}, - ltTestCase{uint8(127), true, false, ""}, - - ltTestCase{uint16(0), true, false, ""}, - ltTestCase{uint16(149), true, false, ""}, - ltTestCase{uint16(150), false, false, ""}, - ltTestCase{uint16(151), false, false, ""}, - - ltTestCase{uint32(0), true, false, ""}, - ltTestCase{uint32(149), true, false, ""}, - ltTestCase{uint32(150), false, false, ""}, - ltTestCase{uint32(151), false, false, ""}, - - ltTestCase{uint64(0), true, false, ""}, - ltTestCase{uint64(149), true, false, ""}, - ltTestCase{uint64(150), false, false, ""}, - ltTestCase{uint64(151), false, false, ""}, - - // Floating point. - ltTestCase{float32(-1), true, false, ""}, - ltTestCase{float32(149), true, false, ""}, - ltTestCase{float32(149.8), true, false, ""}, - ltTestCase{float32(149.9), false, false, ""}, - ltTestCase{float32(150), false, false, ""}, - ltTestCase{float32(151), false, false, ""}, - - ltTestCase{float64(-1), true, false, ""}, - ltTestCase{float64(149), true, false, ""}, - ltTestCase{float64(149.8), true, false, ""}, - ltTestCase{float64(149.9), false, false, ""}, - ltTestCase{float64(150), false, false, ""}, - ltTestCase{float64(151), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// Subtle cases -//////////////////////////////////////////////////////////////////////// - -func (t *LessThanTest) Int64NotExactlyRepresentableBySinglePrecision() { - // Single-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^25-1, 2^25+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo25 = 1 << 25 - matcher := LessThan(int64(kTwoTo25 + 1)) - - desc := matcher.Description() - expectedDesc := "less than 33554433" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []ltTestCase{ - // Signed integers. - ltTestCase{-1, true, false, ""}, - ltTestCase{kTwoTo25 + 0, true, false, ""}, - ltTestCase{kTwoTo25 + 1, false, false, ""}, - ltTestCase{kTwoTo25 + 2, false, false, ""}, - - ltTestCase{int(-1), true, false, ""}, - ltTestCase{int(kTwoTo25 + 0), true, false, ""}, - ltTestCase{int(kTwoTo25 + 1), false, false, ""}, - ltTestCase{int(kTwoTo25 + 2), false, false, ""}, - - ltTestCase{int8(-1), true, false, ""}, - ltTestCase{int8(127), true, false, ""}, - - ltTestCase{int16(-1), true, false, ""}, - ltTestCase{int16(0), true, false, ""}, - ltTestCase{int16(32767), true, false, ""}, - - ltTestCase{int32(-1), true, false, ""}, - ltTestCase{int32(kTwoTo25 + 0), true, false, ""}, - ltTestCase{int32(kTwoTo25 + 1), false, false, ""}, - ltTestCase{int32(kTwoTo25 + 2), false, false, ""}, - - ltTestCase{int64(-1), true, false, ""}, - ltTestCase{int64(kTwoTo25 + 0), true, false, ""}, - ltTestCase{int64(kTwoTo25 + 1), false, false, ""}, - ltTestCase{int64(kTwoTo25 + 2), false, false, ""}, - - // Unsigned integers. - ltTestCase{uint(0), true, false, ""}, - ltTestCase{uint(kTwoTo25 + 0), true, false, ""}, - ltTestCase{uint(kTwoTo25 + 1), false, false, ""}, - ltTestCase{uint(kTwoTo25 + 2), false, false, ""}, - - ltTestCase{uint8(0), true, false, ""}, - ltTestCase{uint8(255), true, false, ""}, - - ltTestCase{uint16(0), true, false, ""}, - ltTestCase{uint16(65535), true, false, ""}, - - ltTestCase{uint32(0), true, false, ""}, - ltTestCase{uint32(kTwoTo25 + 0), true, false, ""}, - ltTestCase{uint32(kTwoTo25 + 1), false, false, ""}, - ltTestCase{uint32(kTwoTo25 + 2), false, false, ""}, - - ltTestCase{uint64(0), true, false, ""}, - ltTestCase{uint64(kTwoTo25 + 0), true, false, ""}, - ltTestCase{uint64(kTwoTo25 + 1), false, false, ""}, - ltTestCase{uint64(kTwoTo25 + 2), false, false, ""}, - - // Floating point. - ltTestCase{float32(-1), true, false, ""}, - ltTestCase{float32(kTwoTo25 - 2), true, false, ""}, - ltTestCase{float32(kTwoTo25 - 1), false, false, ""}, - ltTestCase{float32(kTwoTo25 + 0), false, false, ""}, - ltTestCase{float32(kTwoTo25 + 1), false, false, ""}, - ltTestCase{float32(kTwoTo25 + 2), false, false, ""}, - ltTestCase{float32(kTwoTo25 + 3), false, false, ""}, - - ltTestCase{float64(-1), true, false, ""}, - ltTestCase{float64(kTwoTo25 - 2), true, false, ""}, - ltTestCase{float64(kTwoTo25 - 1), true, false, ""}, - ltTestCase{float64(kTwoTo25 + 0), true, false, ""}, - ltTestCase{float64(kTwoTo25 + 1), false, false, ""}, - ltTestCase{float64(kTwoTo25 + 2), false, false, ""}, - ltTestCase{float64(kTwoTo25 + 3), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessThanTest) Int64NotExactlyRepresentableByDoublePrecision() { - // Double-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^54-1, 2^54+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo54 = 1 << 54 - matcher := LessThan(int64(kTwoTo54 + 1)) - - desc := matcher.Description() - expectedDesc := "less than 18014398509481985" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []ltTestCase{ - // Signed integers. - ltTestCase{-1, true, false, ""}, - ltTestCase{1 << 30, true, false, ""}, - - ltTestCase{int(-1), true, false, ""}, - ltTestCase{int(math.MaxInt32), true, false, ""}, - - ltTestCase{int8(-1), true, false, ""}, - ltTestCase{int8(127), true, false, ""}, - - ltTestCase{int16(-1), true, false, ""}, - ltTestCase{int16(0), true, false, ""}, - ltTestCase{int16(32767), true, false, ""}, - - ltTestCase{int32(-1), true, false, ""}, - ltTestCase{int32(math.MaxInt32), true, false, ""}, - - ltTestCase{int64(-1), true, false, ""}, - ltTestCase{int64(kTwoTo54 - 1), true, false, ""}, - ltTestCase{int64(kTwoTo54 + 0), true, false, ""}, - ltTestCase{int64(kTwoTo54 + 1), false, false, ""}, - ltTestCase{int64(kTwoTo54 + 2), false, false, ""}, - - // Unsigned integers. - ltTestCase{uint(0), true, false, ""}, - ltTestCase{uint(math.MaxUint32), true, false, ""}, - - ltTestCase{uint8(0), true, false, ""}, - ltTestCase{uint8(255), true, false, ""}, - - ltTestCase{uint16(0), true, false, ""}, - ltTestCase{uint16(65535), true, false, ""}, - - ltTestCase{uint32(0), true, false, ""}, - ltTestCase{uint32(math.MaxUint32), true, false, ""}, - - ltTestCase{uint64(0), true, false, ""}, - ltTestCase{uint64(kTwoTo54 - 1), true, false, ""}, - ltTestCase{uint64(kTwoTo54 + 0), true, false, ""}, - ltTestCase{uint64(kTwoTo54 + 1), false, false, ""}, - ltTestCase{uint64(kTwoTo54 + 2), false, false, ""}, - - // Floating point. - ltTestCase{float64(-1), true, false, ""}, - ltTestCase{float64(kTwoTo54 - 2), true, false, ""}, - ltTestCase{float64(kTwoTo54 - 1), false, false, ""}, - ltTestCase{float64(kTwoTo54 + 0), false, false, ""}, - ltTestCase{float64(kTwoTo54 + 1), false, false, ""}, - ltTestCase{float64(kTwoTo54 + 2), false, false, ""}, - ltTestCase{float64(kTwoTo54 + 3), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessThanTest) Uint64NotExactlyRepresentableBySinglePrecision() { - // Single-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^25-1, 2^25+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo25 = 1 << 25 - matcher := LessThan(uint64(kTwoTo25 + 1)) - - desc := matcher.Description() - expectedDesc := "less than 33554433" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []ltTestCase{ - // Signed integers. - ltTestCase{-1, true, false, ""}, - ltTestCase{kTwoTo25 + 0, true, false, ""}, - ltTestCase{kTwoTo25 + 1, false, false, ""}, - ltTestCase{kTwoTo25 + 2, false, false, ""}, - - ltTestCase{int(-1), true, false, ""}, - ltTestCase{int(kTwoTo25 + 0), true, false, ""}, - ltTestCase{int(kTwoTo25 + 1), false, false, ""}, - ltTestCase{int(kTwoTo25 + 2), false, false, ""}, - - ltTestCase{int8(-1), true, false, ""}, - ltTestCase{int8(127), true, false, ""}, - - ltTestCase{int16(-1), true, false, ""}, - ltTestCase{int16(0), true, false, ""}, - ltTestCase{int16(32767), true, false, ""}, - - ltTestCase{int32(-1), true, false, ""}, - ltTestCase{int32(kTwoTo25 + 0), true, false, ""}, - ltTestCase{int32(kTwoTo25 + 1), false, false, ""}, - ltTestCase{int32(kTwoTo25 + 2), false, false, ""}, - - ltTestCase{int64(-1), true, false, ""}, - ltTestCase{int64(kTwoTo25 + 0), true, false, ""}, - ltTestCase{int64(kTwoTo25 + 1), false, false, ""}, - ltTestCase{int64(kTwoTo25 + 2), false, false, ""}, - - // Unsigned integers. - ltTestCase{uint(0), true, false, ""}, - ltTestCase{uint(kTwoTo25 + 0), true, false, ""}, - ltTestCase{uint(kTwoTo25 + 1), false, false, ""}, - ltTestCase{uint(kTwoTo25 + 2), false, false, ""}, - - ltTestCase{uint8(0), true, false, ""}, - ltTestCase{uint8(255), true, false, ""}, - - ltTestCase{uint16(0), true, false, ""}, - ltTestCase{uint16(65535), true, false, ""}, - - ltTestCase{uint32(0), true, false, ""}, - ltTestCase{uint32(kTwoTo25 + 0), true, false, ""}, - ltTestCase{uint32(kTwoTo25 + 1), false, false, ""}, - ltTestCase{uint32(kTwoTo25 + 2), false, false, ""}, - - ltTestCase{uint64(0), true, false, ""}, - ltTestCase{uint64(kTwoTo25 + 0), true, false, ""}, - ltTestCase{uint64(kTwoTo25 + 1), false, false, ""}, - ltTestCase{uint64(kTwoTo25 + 2), false, false, ""}, - - // Floating point. - ltTestCase{float32(-1), true, false, ""}, - ltTestCase{float32(kTwoTo25 - 2), true, false, ""}, - ltTestCase{float32(kTwoTo25 - 1), false, false, ""}, - ltTestCase{float32(kTwoTo25 + 0), false, false, ""}, - ltTestCase{float32(kTwoTo25 + 1), false, false, ""}, - ltTestCase{float32(kTwoTo25 + 2), false, false, ""}, - ltTestCase{float32(kTwoTo25 + 3), false, false, ""}, - - ltTestCase{float64(-1), true, false, ""}, - ltTestCase{float64(kTwoTo25 - 2), true, false, ""}, - ltTestCase{float64(kTwoTo25 - 1), true, false, ""}, - ltTestCase{float64(kTwoTo25 + 0), true, false, ""}, - ltTestCase{float64(kTwoTo25 + 1), false, false, ""}, - ltTestCase{float64(kTwoTo25 + 2), false, false, ""}, - ltTestCase{float64(kTwoTo25 + 3), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessThanTest) Uint64NotExactlyRepresentableByDoublePrecision() { - // Double-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^54-1, 2^54+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo54 = 1 << 54 - matcher := LessThan(uint64(kTwoTo54 + 1)) - - desc := matcher.Description() - expectedDesc := "less than 18014398509481985" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []ltTestCase{ - // Signed integers. - ltTestCase{-1, true, false, ""}, - ltTestCase{1 << 30, true, false, ""}, - - ltTestCase{int(-1), true, false, ""}, - ltTestCase{int(math.MaxInt32), true, false, ""}, - - ltTestCase{int8(-1), true, false, ""}, - ltTestCase{int8(127), true, false, ""}, - - ltTestCase{int16(-1), true, false, ""}, - ltTestCase{int16(0), true, false, ""}, - ltTestCase{int16(32767), true, false, ""}, - - ltTestCase{int32(-1), true, false, ""}, - ltTestCase{int32(math.MaxInt32), true, false, ""}, - - ltTestCase{int64(-1), true, false, ""}, - ltTestCase{int64(kTwoTo54 - 1), true, false, ""}, - ltTestCase{int64(kTwoTo54 + 0), true, false, ""}, - ltTestCase{int64(kTwoTo54 + 1), false, false, ""}, - ltTestCase{int64(kTwoTo54 + 2), false, false, ""}, - - // Unsigned integers. - ltTestCase{uint(0), true, false, ""}, - ltTestCase{uint(math.MaxUint32), true, false, ""}, - - ltTestCase{uint8(0), true, false, ""}, - ltTestCase{uint8(255), true, false, ""}, - - ltTestCase{uint16(0), true, false, ""}, - ltTestCase{uint16(65535), true, false, ""}, - - ltTestCase{uint32(0), true, false, ""}, - ltTestCase{uint32(math.MaxUint32), true, false, ""}, - - ltTestCase{uint64(0), true, false, ""}, - ltTestCase{uint64(kTwoTo54 - 1), true, false, ""}, - ltTestCase{uint64(kTwoTo54 + 0), true, false, ""}, - ltTestCase{uint64(kTwoTo54 + 1), false, false, ""}, - ltTestCase{uint64(kTwoTo54 + 2), false, false, ""}, - - // Floating point. - ltTestCase{float64(-1), true, false, ""}, - ltTestCase{float64(kTwoTo54 - 2), true, false, ""}, - ltTestCase{float64(kTwoTo54 - 1), false, false, ""}, - ltTestCase{float64(kTwoTo54 + 0), false, false, ""}, - ltTestCase{float64(kTwoTo54 + 1), false, false, ""}, - ltTestCase{float64(kTwoTo54 + 2), false, false, ""}, - ltTestCase{float64(kTwoTo54 + 3), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessThanTest) Float32AboveExactIntegerRange() { - // Single-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^25-1, 2^25+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo25 = 1 << 25 - matcher := LessThan(float32(kTwoTo25 + 1)) - - desc := matcher.Description() - expectedDesc := "less than 3.3554432e+07" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []ltTestCase{ - // Signed integers. - ltTestCase{int64(-1), true, false, ""}, - ltTestCase{int64(kTwoTo25 - 2), true, false, ""}, - ltTestCase{int64(kTwoTo25 - 1), false, false, ""}, - ltTestCase{int64(kTwoTo25 + 0), false, false, ""}, - ltTestCase{int64(kTwoTo25 + 1), false, false, ""}, - ltTestCase{int64(kTwoTo25 + 2), false, false, ""}, - ltTestCase{int64(kTwoTo25 + 3), false, false, ""}, - - // Unsigned integers. - ltTestCase{uint64(0), true, false, ""}, - ltTestCase{uint64(kTwoTo25 - 2), true, false, ""}, - ltTestCase{uint64(kTwoTo25 - 1), false, false, ""}, - ltTestCase{uint64(kTwoTo25 + 0), false, false, ""}, - ltTestCase{uint64(kTwoTo25 + 1), false, false, ""}, - ltTestCase{uint64(kTwoTo25 + 2), false, false, ""}, - ltTestCase{uint64(kTwoTo25 + 3), false, false, ""}, - - // Floating point. - ltTestCase{float32(-1), true, false, ""}, - ltTestCase{float32(kTwoTo25 - 2), true, false, ""}, - ltTestCase{float32(kTwoTo25 - 1), false, false, ""}, - ltTestCase{float32(kTwoTo25 + 0), false, false, ""}, - ltTestCase{float32(kTwoTo25 + 1), false, false, ""}, - ltTestCase{float32(kTwoTo25 + 2), false, false, ""}, - ltTestCase{float32(kTwoTo25 + 3), false, false, ""}, - - ltTestCase{float64(-1), true, false, ""}, - ltTestCase{float64(kTwoTo25 - 2), true, false, ""}, - ltTestCase{float64(kTwoTo25 - 1), false, false, ""}, - ltTestCase{float64(kTwoTo25 + 0), false, false, ""}, - ltTestCase{float64(kTwoTo25 + 1), false, false, ""}, - ltTestCase{float64(kTwoTo25 + 2), false, false, ""}, - ltTestCase{float64(kTwoTo25 + 3), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessThanTest) Float64AboveExactIntegerRange() { - // Double-precision floats don't have enough bits to represent the integers - // near this one distinctly, so [2^54-1, 2^54+2] all receive the same value - // and should be treated as equivalent when floats are in the mix. - const kTwoTo54 = 1 << 54 - matcher := LessThan(float64(kTwoTo54 + 1)) - - desc := matcher.Description() - expectedDesc := "less than 1.8014398509481984e+16" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []ltTestCase{ - // Signed integers. - ltTestCase{int64(-1), true, false, ""}, - ltTestCase{int64(kTwoTo54 - 2), true, false, ""}, - ltTestCase{int64(kTwoTo54 - 1), false, false, ""}, - ltTestCase{int64(kTwoTo54 + 0), false, false, ""}, - ltTestCase{int64(kTwoTo54 + 1), false, false, ""}, - ltTestCase{int64(kTwoTo54 + 2), false, false, ""}, - ltTestCase{int64(kTwoTo54 + 3), false, false, ""}, - - // Unsigned integers. - ltTestCase{uint64(0), true, false, ""}, - ltTestCase{uint64(kTwoTo54 - 2), true, false, ""}, - ltTestCase{uint64(kTwoTo54 - 1), false, false, ""}, - ltTestCase{uint64(kTwoTo54 + 0), false, false, ""}, - ltTestCase{uint64(kTwoTo54 + 1), false, false, ""}, - ltTestCase{uint64(kTwoTo54 + 2), false, false, ""}, - ltTestCase{uint64(kTwoTo54 + 3), false, false, ""}, - - // Floating point. - ltTestCase{float64(-1), true, false, ""}, - ltTestCase{float64(kTwoTo54 - 2), true, false, ""}, - ltTestCase{float64(kTwoTo54 - 1), false, false, ""}, - ltTestCase{float64(kTwoTo54 + 0), false, false, ""}, - ltTestCase{float64(kTwoTo54 + 1), false, false, ""}, - ltTestCase{float64(kTwoTo54 + 2), false, false, ""}, - ltTestCase{float64(kTwoTo54 + 3), false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -//////////////////////////////////////////////////////////////////////// -// String literals -//////////////////////////////////////////////////////////////////////// - -func (t *LessThanTest) EmptyString() { - matcher := LessThan("") - desc := matcher.Description() - expectedDesc := "less than \"\"" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []ltTestCase{ - ltTestCase{"", false, false, ""}, - ltTestCase{"\x00", false, false, ""}, - ltTestCase{"a", false, false, ""}, - ltTestCase{"foo", false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessThanTest) SingleNullByte() { - matcher := LessThan("\x00") - desc := matcher.Description() - expectedDesc := "less than \"\x00\"" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []ltTestCase{ - ltTestCase{"", true, false, ""}, - ltTestCase{"\x00", false, false, ""}, - ltTestCase{"a", false, false, ""}, - ltTestCase{"foo", false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} - -func (t *LessThanTest) LongerString() { - matcher := LessThan("foo\x00") - desc := matcher.Description() - expectedDesc := "less than \"foo\x00\"" - - ExpectThat(desc, Equals(expectedDesc)) - - cases := []ltTestCase{ - ltTestCase{"", true, false, ""}, - ltTestCase{"\x00", true, false, ""}, - ltTestCase{"bar", true, false, ""}, - ltTestCase{"foo", true, false, ""}, - ltTestCase{"foo\x00", false, false, ""}, - ltTestCase{"fooa", false, false, ""}, - ltTestCase{"qux", false, false, ""}, - } - - t.checkTestCases(matcher, cases) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/matches_regexp_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/matches_regexp_test.go deleted file mode 100644 index 35b9cf9ab9b..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/matches_regexp_test.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type MatchesRegexpTest struct { -} - -func init() { RegisterTestSuite(&MatchesRegexpTest{}) } - -//////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////// - -func (t *MatchesRegexpTest) Description() { - m := MatchesRegexp("foo.*bar") - ExpectEq("matches regexp \"foo.*bar\"", m.Description()) -} - -func (t *MatchesRegexpTest) InvalidRegexp() { - ExpectThat( - func() { MatchesRegexp("(foo") }, - Panics(HasSubstr("missing closing )"))) -} - -func (t *MatchesRegexpTest) CandidateIsNil() { - m := MatchesRegexp("") - err := m.Matches(nil) - - ExpectThat(err, Error(Equals("which is not a string or []byte"))) - ExpectTrue(isFatal(err)) -} - -func (t *MatchesRegexpTest) CandidateIsInteger() { - m := MatchesRegexp("") - err := m.Matches(17) - - ExpectThat(err, Error(Equals("which is not a string or []byte"))) - ExpectTrue(isFatal(err)) -} - -func (t *MatchesRegexpTest) NonMatchingCandidates() { - m := MatchesRegexp("fo[op]\\s+x") - var err error - - err = m.Matches("fon x") - ExpectThat(err, Error(Equals(""))) - ExpectFalse(isFatal(err)) - - err = m.Matches("fopx") - ExpectThat(err, Error(Equals(""))) - ExpectFalse(isFatal(err)) - - err = m.Matches("fop ") - ExpectThat(err, Error(Equals(""))) - ExpectFalse(isFatal(err)) -} - -func (t *MatchesRegexpTest) MatchingCandidates() { - m := MatchesRegexp("fo[op]\\s+x") - var err error - - err = m.Matches("foo x") - ExpectEq(nil, err) - - err = m.Matches("fop x") - ExpectEq(nil, err) - - err = m.Matches("blah blah foo x blah blah") - ExpectEq(nil, err) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/not_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/not_test.go deleted file mode 100644 index 7569d687a74..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/not_test.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "errors" - "testing" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type fakeMatcher struct { - matchFunc func(interface{}) error - description string -} - -func (m *fakeMatcher) Matches(c interface{}) error { - return m.matchFunc(c) -} - -func (m *fakeMatcher) Description() string { - return m.description -} - -type NotTest struct { -} - -func init() { RegisterTestSuite(&NotTest{}) } -func TestOgletest(t *testing.T) { RunTests(t) } - -//////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////// - -func (t *NotTest) CallsWrapped() { - var suppliedCandidate interface{} - matchFunc := func(c interface{}) error { - suppliedCandidate = c - return nil - } - - wrapped := &fakeMatcher{matchFunc, ""} - matcher := Not(wrapped) - - matcher.Matches(17) - ExpectThat(suppliedCandidate, Equals(17)) -} - -func (t *NotTest) WrappedReturnsTrue() { - matchFunc := func(c interface{}) error { - return nil - } - - wrapped := &fakeMatcher{matchFunc, ""} - matcher := Not(wrapped) - - err := matcher.Matches(0) - ExpectThat(err, Error(Equals(""))) -} - -func (t *NotTest) WrappedReturnsNonFatalError() { - matchFunc := func(c interface{}) error { - return errors.New("taco") - } - - wrapped := &fakeMatcher{matchFunc, ""} - matcher := Not(wrapped) - - err := matcher.Matches(0) - ExpectEq(nil, err) -} - -func (t *NotTest) WrappedReturnsFatalError() { - matchFunc := func(c interface{}) error { - return NewFatalError("taco") - } - - wrapped := &fakeMatcher{matchFunc, ""} - matcher := Not(wrapped) - - err := matcher.Matches(0) - ExpectThat(err, Error(Equals("taco"))) -} - -func (t *NotTest) Description() { - wrapped := &fakeMatcher{nil, "taco"} - matcher := Not(wrapped) - - ExpectEq("not(taco)", matcher.Description()) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/panics_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/panics_test.go deleted file mode 100644 index dff2eaeff82..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/panics_test.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "errors" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type PanicsTest struct { - matcherCalled bool - suppliedCandidate interface{} - wrappedError error - - matcher Matcher -} - -func init() { RegisterTestSuite(&PanicsTest{}) } - -func (t *PanicsTest) SetUp(i *TestInfo) { - wrapped := &fakeMatcher{ - func(c interface{}) error { - t.matcherCalled = true - t.suppliedCandidate = c - return t.wrappedError - }, - "foo", - } - - t.matcher = Panics(wrapped) -} - -//////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////// - -func (t *PanicsTest) Description() { - ExpectThat(t.matcher.Description(), Equals("panics with: foo")) -} - -func (t *PanicsTest) CandidateIsNil() { - err := t.matcher.Matches(nil) - - ExpectThat(err, Error(Equals("which is not a zero-arg function"))) - ExpectTrue(isFatal(err)) -} - -func (t *PanicsTest) CandidateIsString() { - err := t.matcher.Matches("taco") - - ExpectThat(err, Error(Equals("which is not a zero-arg function"))) - ExpectTrue(isFatal(err)) -} - -func (t *PanicsTest) CandidateTakesArgs() { - err := t.matcher.Matches(func(i int) string { return "" }) - - ExpectThat(err, Error(Equals("which is not a zero-arg function"))) - ExpectTrue(isFatal(err)) -} - -func (t *PanicsTest) CallsFunction() { - callCount := 0 - t.matcher.Matches(func() string { - callCount++ - return "" - }) - - ExpectThat(callCount, Equals(1)) -} - -func (t *PanicsTest) FunctionDoesntPanic() { - err := t.matcher.Matches(func() {}) - - ExpectThat(err, Error(Equals("which didn't panic"))) - ExpectFalse(isFatal(err)) -} - -func (t *PanicsTest) CallsWrappedMatcher() { - expectedErr := 17 - t.wrappedError = errors.New("") - t.matcher.Matches(func() { panic(expectedErr) }) - - ExpectThat(t.suppliedCandidate, Equals(expectedErr)) -} - -func (t *PanicsTest) WrappedReturnsTrue() { - err := t.matcher.Matches(func() { panic("") }) - - ExpectEq(nil, err) -} - -func (t *PanicsTest) WrappedReturnsFatalErrorWithoutText() { - t.wrappedError = NewFatalError("") - err := t.matcher.Matches(func() { panic(17) }) - - ExpectThat(err, Error(Equals("which panicked with: 17"))) - ExpectFalse(isFatal(err)) -} - -func (t *PanicsTest) WrappedReturnsFatalErrorWithText() { - t.wrappedError = NewFatalError("which blah") - err := t.matcher.Matches(func() { panic(17) }) - - ExpectThat(err, Error(Equals("which panicked with: 17, which blah"))) - ExpectFalse(isFatal(err)) -} - -func (t *PanicsTest) WrappedReturnsNonFatalErrorWithoutText() { - t.wrappedError = errors.New("") - err := t.matcher.Matches(func() { panic(17) }) - - ExpectThat(err, Error(Equals("which panicked with: 17"))) - ExpectFalse(isFatal(err)) -} - -func (t *PanicsTest) WrappedReturnsNonFatalErrorWithText() { - t.wrappedError = errors.New("which blah") - err := t.matcher.Matches(func() { panic(17) }) - - ExpectThat(err, Error(Equals("which panicked with: 17, which blah"))) - ExpectFalse(isFatal(err)) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/pointee_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/pointee_test.go deleted file mode 100644 index 0ef31549532..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglematchers/pointee_test.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "errors" - "testing" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type PointeeTest struct{} - -func init() { RegisterTestSuite(&PointeeTest{}) } - -func TestPointee(t *testing.T) { RunTests(t) } - -//////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////// - -func (t *PointeeTest) Description() { - wrapped := &fakeMatcher{nil, "taco"} - matcher := Pointee(wrapped) - - ExpectEq("pointee(taco)", matcher.Description()) -} - -func (t *PointeeTest) CandidateIsNotAPointer() { - matcher := Pointee(HasSubstr("")) - err := matcher.Matches([]byte{}) - - ExpectThat(err, Error(Equals("which is not a pointer"))) - ExpectTrue(isFatal(err)) -} - -func (t *PointeeTest) CandidateIsANilLiteral() { - matcher := Pointee(HasSubstr("")) - err := matcher.Matches(nil) - - ExpectThat(err, Error(Equals("which is not a pointer"))) - ExpectTrue(isFatal(err)) -} - -func (t *PointeeTest) CandidateIsANilPointer() { - matcher := Pointee(HasSubstr("")) - err := matcher.Matches((*int)(nil)) - - ExpectThat(err, Error(Equals(""))) - ExpectTrue(isFatal(err)) -} - -func (t *PointeeTest) CallsWrapped() { - var suppliedCandidate interface{} - matchFunc := func(c interface{}) error { - suppliedCandidate = c - return nil - } - - wrapped := &fakeMatcher{matchFunc, ""} - matcher := Pointee(wrapped) - - someSlice := []byte{} - matcher.Matches(&someSlice) - ExpectThat(suppliedCandidate, IdenticalTo(someSlice)) -} - -func (t *PointeeTest) WrappedReturnsOkay() { - matchFunc := func(c interface{}) error { - return nil - } - - wrapped := &fakeMatcher{matchFunc, ""} - matcher := Pointee(wrapped) - - err := matcher.Matches(new(int)) - ExpectEq(nil, err) -} - -func (t *PointeeTest) WrappedReturnsNonFatalNonEmptyError() { - matchFunc := func(c interface{}) error { - return errors.New("taco") - } - - wrapped := &fakeMatcher{matchFunc, ""} - matcher := Pointee(wrapped) - - i := 17 - err := matcher.Matches(&i) - ExpectFalse(isFatal(err)) - ExpectThat(err, Error(Equals("taco"))) -} - -func (t *PointeeTest) WrappedReturnsNonFatalEmptyError() { - matchFunc := func(c interface{}) error { - return errors.New("") - } - - wrapped := &fakeMatcher{matchFunc, ""} - matcher := Pointee(wrapped) - - i := 17 - err := matcher.Matches(&i) - ExpectFalse(isFatal(err)) - ExpectThat(err, Error(HasSubstr("whose pointee"))) - ExpectThat(err, Error(HasSubstr("17"))) -} - -func (t *PointeeTest) WrappedReturnsFatalNonEmptyError() { - matchFunc := func(c interface{}) error { - return NewFatalError("taco") - } - - wrapped := &fakeMatcher{matchFunc, ""} - matcher := Pointee(wrapped) - - i := 17 - err := matcher.Matches(&i) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(Equals("taco"))) -} - -func (t *PointeeTest) WrappedReturnsFatalEmptyError() { - matchFunc := func(c interface{}) error { - return NewFatalError("") - } - - wrapped := &fakeMatcher{matchFunc, ""} - matcher := Pointee(wrapped) - - i := 17 - err := matcher.Matches(&i) - ExpectTrue(isFatal(err)) - ExpectThat(err, Error(HasSubstr("whose pointee"))) - ExpectThat(err, Error(HasSubstr("17"))) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/.gitignore b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/.gitignore deleted file mode 100644 index dd8fc7468f4..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*.6 -6.out -_obj/ -_test/ -_testmain.go diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/LICENSE b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/LICENSE deleted file mode 100644 index d6456956733..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/README.markdown b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/README.markdown deleted file mode 100644 index f7323af66b1..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/README.markdown +++ /dev/null @@ -1,101 +0,0 @@ -`oglemock` is a mocking framework for the Go programming language with the -following features: - - * An extensive and extensible set of matchers for expressing call - expectations (provided by the [oglematchers][] package). - - * Clean, readable output that tells you exactly what you need to know. - - * Style and semantics similar to [Google Mock][googlemock] and - [Google JS Test][google-js-test]. - - * Seamless integration with the [ogletest][] unit testing framework. - -It can be integrated into any testing framework (including Go's `testing` -package), but out of the box support is built in to [ogletest][] and that is the -easiest place to use it. - - -Installation ------------- - -First, make sure you have installed Go 1.0.2 or newer. See -[here][golang-install] for instructions. - -Use the following command to install `oglemock` and its dependencies, and to -keep them up to date: - - go get -u github.com/smartystreets/goconvey/convey/assertions/oglemock - go get -u github.com/smartystreets/goconvey/convey/assertions/oglemock/createmock - -Those commands will install the `oglemock` package itself, along with the -`createmock` tool that is used to auto-generate mock types. - - -Generating and using mock types -------------------------------- - -Automatically generating a mock implementation of an interface is easy. If you -want to mock interfaces `Bar` and `Baz` from package `foo`, simply run the -following: - - createmock foo Bar Baz - -That will print source code that can be saved to a file and used in your tests. -For example, to create a `mock_io` package containing mock implementations of -`io.Reader` and `io.Writer`: - - mkdir mock_io - createmock io Reader Writer > mock_io/mock_io.go - -The new package will be named `mock_io`, and contain types called `MockReader` -and `MockWriter`, which implement `io.Reader` and `io.Writer` respectively. - -For each generated mock type, there is a corresponding function for creating an -instance of that type given a `Controller` object (see below). For example, to -create a mock reader: - -```go -someController := [...] // See next section. -someReader := mock_io.NewMockReader(someController, "Mock file reader") -``` - -The snippet above creates a mock `io.Reader` that reports failures to -`someController`. The reader can subsequently have expectations set up and be -passed to your code under test that uses an `io.Reader`. - - -Getting ahold of a controller ------------------------------ - -[oglemock.Controller][controller-ref] is used to create mock objects, and to set -up and verify expectations for them. You can create one by calling -`NewController` with an `ErrorReporter`, which is the basic type used to -interface between `oglemock` and the testing framework within which it is being -used. - -If you are using [ogletest][] you don't need to worry about any of this, since -the `TestInfo` struct provided to your test's `SetUp` function already contains -a working `Controller` that you can use to create mock object, and you can use -the built-in `ExpectCall` function for setting expectations. (See the -[ogletest documentation][ogletest-docs] for more info.) Otherwise, you will need -to implement the simple [ErrorReporter interface][reporter-ref] for your test -environment. - - -Documentation -------------- - -For thorough documentation, including information on how to set up expectations, -see [here][oglemock-docs]. - - -[controller-ref]: http://gopkgdoc.appspot.com/pkg/github.com/smartystreets/goconvey/convey/assertions/oglemock#Controller -[reporter-ref]: http://gopkgdoc.appspot.com/pkg/github.com/smartystreets/goconvey/convey/assertions/oglemock#ErrorReporter -[golang-install]: http://golang.org/doc/install.html -[google-js-test]: http://code.google.com/p/google-js-test/ -[googlemock]: http://code.google.com/p/googlemock/ -[oglematchers]: https://github.com/smartystreets/goconvey/convey/assertions/oglematchers -[oglemock-docs]: http://gopkgdoc.appspot.com/pkg/github.com/smartystreets/goconvey/convey/assertions/oglemock -[ogletest]: https://github.com/smartystreets/goconvey/convey/assertions/oglematchers -[ogletest-docs]: http://gopkgdoc.appspot.com/pkg/github.com/smartystreets/goconvey/convey/assertions/ogletest diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/action.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/action.go deleted file mode 100644 index 9fd40d81fe8..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/action.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglemock - -import ( - "reflect" -) - -// Action represents an action to be taken in response to a call to a mock -// method. -type Action interface { - // Set the signature of the function with which this action is being used. - // This must be called before Invoke is called. - SetSignature(signature reflect.Type) error - - // Invoke runs the specified action, given the arguments to the mock method. - // It returns zero or more values that may be treated as the return values of - // the method. If the action doesn't return any values, it may return the nil - // slice. - // - // You must call SetSignature before calling Invoke. - Invoke(methodArgs []interface{}) []interface{} -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/controller.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/controller.go deleted file mode 100644 index 93a1d6239e1..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/controller.go +++ /dev/null @@ -1,480 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglemock - -import ( - "errors" - "fmt" - "log" - "math" - "reflect" - "sync" -) - -// PartialExpecation is a function that should be called exactly once with -// expected arguments or matchers in order to set up an expected method call. -// See Controller.ExpectMethodCall below. It returns an expectation that can be -// further modified (e.g. by calling WillOnce). -// -// If the arguments are of the wrong type, the function reports a fatal error -// and returns nil. -type PartialExpecation func(...interface{}) Expectation - -// Controller represents an object that implements the central logic of -// oglemock: recording and verifying expectations, responding to mock method -// calls, and so on. -type Controller interface { - // ExpectCall expresses an expectation that the method of the given name - // should be called on the supplied mock object. It returns a function that - // should be called with the expected arguments, matchers for the arguments, - // or a mix of both. - // - // fileName and lineNumber should indicate the line on which the expectation - // was made, if known. - // - // For example: - // - // mockWriter := [...] - // controller.ExpectCall(mockWriter, "Write", "foo.go", 17)(ElementsAre(0x1)) - // .WillOnce(Return(1, nil)) - // - // If the mock object doesn't have a method of the supplied name, the - // function reports a fatal error and returns nil. - ExpectCall( - o MockObject, - methodName string, - fileName string, - lineNumber int) PartialExpecation - - // Finish causes the controller to check for any unsatisfied expectations, - // and report them as errors if they exist. - // - // The controller may panic if any of its methods (including this one) are - // called after Finish is called. - Finish() - - // HandleMethodCall looks for a registered expectation matching the call of - // the given method on mock object o, invokes the appropriate action (if - // any), and returns the values returned by that action (if any). - // - // If the action returns nothing, the controller returns zero values. If - // there is no matching expectation, the controller reports an error and - // returns zero values. - // - // If the mock object doesn't have a method of the supplied name, the - // arguments are of the wrong type, or the action returns the wrong types, - // the function reports a fatal error. - // - // HandleMethodCall is exported for the sake of mock implementations, and - // should not be used directly. - HandleMethodCall( - o MockObject, - methodName string, - fileName string, - lineNumber int, - args []interface{}) []interface{} -} - -// methodMap represents a map from method name to set of expectations for that -// method. -type methodMap map[string][]*InternalExpectation - -// objectMap represents a map from mock object ID to a methodMap for that object. -type objectMap map[uintptr]methodMap - -// NewController sets up a fresh controller, without any expectations set, and -// configures the controller to use the supplied error reporter. -func NewController(reporter ErrorReporter) Controller { - return &controllerImpl{reporter, sync.RWMutex{}, objectMap{}} -} - -type controllerImpl struct { - reporter ErrorReporter - - mutex sync.RWMutex - expectationsByObject objectMap // Protected by mutex -} - -// Return the list of registered expectations for the named method of the -// supplied object, or an empty slice if none have been registered. When this -// method returns, it is guaranteed that c.expectationsByObject has an entry -// for the object. -// -// c.mutex must be held for reading. -func (c *controllerImpl) getExpectationsLocked( - o MockObject, - methodName string) []*InternalExpectation { - id := o.Oglemock_Id() - - // Look up the mock object. - expectationsByMethod, ok := c.expectationsByObject[id] - if !ok { - expectationsByMethod = methodMap{} - c.expectationsByObject[id] = expectationsByMethod - } - - result, ok := expectationsByMethod[methodName] - if !ok { - return []*InternalExpectation{} - } - - return result -} - -// Add an expectation to the list registered for the named method of the -// supplied mock object. -// -// c.mutex must be held for writing. -func (c *controllerImpl) addExpectationLocked( - o MockObject, - methodName string, - exp *InternalExpectation) { - // Get the existing list. - existing := c.getExpectationsLocked(o, methodName) - - // Store a modified list. - id := o.Oglemock_Id() - c.expectationsByObject[id][methodName] = append(existing, exp) -} - -func (c *controllerImpl) ExpectCall( - o MockObject, - methodName string, - fileName string, - lineNumber int) PartialExpecation { - // Find the signature for the requested method. - ov := reflect.ValueOf(o) - method := ov.MethodByName(methodName) - if method.Kind() == reflect.Invalid { - c.reporter.ReportFatalError( - fileName, - lineNumber, - errors.New("Unknown method: "+methodName)) - return nil - } - - partialAlreadyCalled := false // Protected by c.mutex - return func(args ...interface{}) Expectation { - c.mutex.Lock() - defer c.mutex.Unlock() - - // This function should only be called once. - if partialAlreadyCalled { - c.reporter.ReportFatalError( - fileName, - lineNumber, - errors.New("Partial expectation called more than once.")) - return nil - } - - partialAlreadyCalled = true - - // Make sure that the number of args is legal. Keep in mind that the - // method's type has an extra receiver arg. - if len(args) != method.Type().NumIn() { - c.reporter.ReportFatalError( - fileName, - lineNumber, - errors.New( - fmt.Sprintf( - "Expectation for %s given wrong number of arguments: "+ - "expected %d, got %d.", - methodName, - method.Type().NumIn(), - len(args)))) - return nil - } - - // Create an expectation and insert it into the controller's map. - exp := InternalNewExpectation( - c.reporter, - method.Type(), - args, - fileName, - lineNumber) - - c.addExpectationLocked(o, methodName, exp) - - // Return the expectation to the user. - return exp - } -} - -func (c *controllerImpl) Finish() { - c.mutex.Lock() - defer c.mutex.Unlock() - - // Check whether the minimum cardinality for each registered expectation has - // been satisfied. - for _, expectationsByMethod := range c.expectationsByObject { - for methodName, expectations := range expectationsByMethod { - for _, exp := range expectations { - exp.mutex.Lock() - defer exp.mutex.Unlock() - - minCardinality, _ := computeCardinalityLocked(exp) - if exp.NumMatches < minCardinality { - c.reporter.ReportError( - exp.FileName, - exp.LineNumber, - errors.New( - fmt.Sprintf( - "Unsatisfied expectation; expected %s to be called "+ - "at least %d times; called %d times.", - methodName, - minCardinality, - exp.NumMatches))) - } - } - } - } -} - -// expectationMatches checks the matchers for the expectation against the -// supplied arguments. -func expectationMatches(exp *InternalExpectation, args []interface{}) bool { - matchers := exp.ArgMatchers - if len(args) != len(matchers) { - panic("expectationMatches: len(args)") - } - - // Check each matcher. - for i, matcher := range matchers { - if err := matcher.Matches(args[i]); err != nil { - return false - } - } - - return true -} - -// Return the expectation that matches the supplied arguments. If there is more -// than one such expectation, the one furthest along in the list for the method -// is returned. If there is no such expectation, nil is returned. -// -// c.mutex must be held for reading. -func (c *controllerImpl) chooseExpectationLocked( - o MockObject, - methodName string, - args []interface{}) *InternalExpectation { - // Do we have any expectations for this method? - expectations := c.getExpectationsLocked(o, methodName) - if len(expectations) == 0 { - return nil - } - - for i := len(expectations) - 1; i >= 0; i-- { - if expectationMatches(expectations[i], args) { - return expectations[i] - } - } - - return nil -} - -// makeZeroReturnValues creates a []interface{} containing appropriate zero -// values for returning from the supplied method type. -func makeZeroReturnValues(signature reflect.Type) []interface{} { - result := make([]interface{}, signature.NumOut()) - - for i, _ := range result { - outType := signature.Out(i) - zeroVal := reflect.Zero(outType) - result[i] = zeroVal.Interface() - } - - return result -} - -// computeCardinality decides on the [min, max] range of the number of expected -// matches for the supplied expectations, according to the rules documented in -// expectation.go. -// -// exp.mutex must be held for reading. -func computeCardinalityLocked(exp *InternalExpectation) (min, max uint) { - // Explicit cardinality. - if exp.ExpectedNumMatches >= 0 { - min = uint(exp.ExpectedNumMatches) - max = min - return - } - - // Implicit count based on one-time actions. - if len(exp.OneTimeActions) != 0 { - min = uint(len(exp.OneTimeActions)) - max = min - - // If there is a fallback action, this is only a lower bound. - if exp.FallbackAction != nil { - max = math.MaxUint32 - } - - return - } - - // Implicit lack of restriction based on a fallback action being configured. - if exp.FallbackAction != nil { - min = 0 - max = math.MaxUint32 - return - } - - // Implicit cardinality of one. - min = 1 - max = 1 - return -} - -// chooseAction returns the action that should be invoked for the i'th match to -// the supplied expectation (counting from zero). If the implicit "return zero -// values" action should be used, it returns nil. -// -// exp.mutex must be held for reading. -func chooseActionLocked(i uint, exp *InternalExpectation) Action { - // Exhaust one-time actions first. - if i < uint(len(exp.OneTimeActions)) { - return exp.OneTimeActions[i] - } - - // Fallback action (or nil if none is configured). - return exp.FallbackAction -} - -// Find an action for the method call, updating expectation match state in the -// process. Return either an action that should be invoked or a set of zero -// values to return immediately. -// -// This is split out from HandleMethodCall in order to more easily avoid -// invoking the action with locks held. -func (c *controllerImpl) chooseActionAndUpdateExpectations( - o MockObject, - methodName string, - fileName string, - lineNumber int, - args []interface{}, -) (action Action, zeroVals []interface{}) { - c.mutex.Lock() - defer c.mutex.Unlock() - - // Find the signature for the requested method. - ov := reflect.ValueOf(o) - method := ov.MethodByName(methodName) - if method.Kind() == reflect.Invalid { - c.reporter.ReportFatalError( - fileName, - lineNumber, - errors.New("Unknown method: "+methodName), - ) - - // Should never get here in real code. - log.Println("ReportFatalError unexpectedly returned.") - return - } - - // HACK(jacobsa): Make sure we got the correct number of arguments. This will - // need to be refined when issue #5 (variadic methods) is handled. - if len(args) != method.Type().NumIn() { - c.reporter.ReportFatalError( - fileName, - lineNumber, - errors.New( - fmt.Sprintf( - "Wrong number of arguments: expected %d; got %d", - method.Type().NumIn(), - len(args), - ), - ), - ) - - // Should never get here in real code. - log.Println("ReportFatalError unexpectedly returned.") - return - } - - // Find an expectation matching this call. - expectation := c.chooseExpectationLocked(o, methodName, args) - if expectation == nil { - c.reporter.ReportError( - fileName, - lineNumber, - errors.New( - fmt.Sprintf("Unexpected call to %s with args: %v", methodName, args), - ), - ) - - zeroVals = makeZeroReturnValues(method.Type()) - return - } - - expectation.mutex.Lock() - defer expectation.mutex.Unlock() - - // Increase the number of matches recorded, and check whether we're over the - // number expected. - expectation.NumMatches++ - _, maxCardinality := computeCardinalityLocked(expectation) - if expectation.NumMatches > maxCardinality { - c.reporter.ReportError( - expectation.FileName, - expectation.LineNumber, - errors.New( - fmt.Sprintf( - "Unexpected call to %s: "+ - "expected to be called at most %d times; called %d times.", - methodName, - maxCardinality, - expectation.NumMatches, - ), - ), - ) - - zeroVals = makeZeroReturnValues(method.Type()) - return - } - - // Choose an action to invoke. If there is none, just return zero values. - action = chooseActionLocked(expectation.NumMatches-1, expectation) - if action == nil { - zeroVals = makeZeroReturnValues(method.Type()) - return - } - - // Let the action take over. - return -} - -func (c *controllerImpl) HandleMethodCall( - o MockObject, - methodName string, - fileName string, - lineNumber int, - args []interface{}, -) []interface{} { - // Figure out whether to invoke an action or return zero values. - action, zeroVals := c.chooseActionAndUpdateExpectations( - o, - methodName, - fileName, - lineNumber, - args, - ) - - if action != nil { - return action.Invoke(args) - } - - return zeroVals -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/createmock/createmock.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/createmock/createmock.go deleted file mode 100644 index 4117dba4f04..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/createmock/createmock.go +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// createmock is used to generate source code for mock versions of interfaces -// from installed packages. -package main - -import ( - "errors" - "flag" - "fmt" - "go/build" - "io/ioutil" - "log" - "os" - "os/exec" - "path" - "regexp" - "text/template" - - // Ensure that the generate package, which is used by the generated code, is - // installed by goinstall. - _ "github.com/smartystreets/goconvey/convey/assertions/oglemock/generate" -) - -// A template for generated code that is used to print the result. -const tmplStr = ` -{{$inputPkg := .InputPkg}} -{{$outputPkg := .OutputPkg}} - -package main - -import ( - {{range $identifier, $import := .Imports}} - {{$identifier}} "{{$import}}" - {{end}} -) - -func getTypeForPtr(ptr interface{}) reflect.Type { - return reflect.TypeOf(ptr).Elem() -} - -func main() { - // Reduce noise in logging output. - log.SetFlags(0) - - interfaces := []reflect.Type{ - {{range $typeName := .TypeNames}} - getTypeForPtr((*{{base $inputPkg}}.{{$typeName}})(nil)), - {{end}} - } - - err := generate.GenerateMockSource(os.Stdout, "{{$outputPkg}}", interfaces) - if err != nil { - log.Fatalf("Error generating mock source: %v", err) - } -} -` - -// A map from import identifier to package to use that identifier for, -// containing elements for each import needed by the generated code. -type importMap map[string]string - -type tmplArg struct { - InputPkg string - OutputPkg string - - // Imports needed by the generated code. - Imports importMap - - // Types to be mocked, relative to their package's name. - TypeNames []string -} - -var unknownPackageRegexp = regexp.MustCompile( - `tool\.go:\d+:\d+: cannot find package "([^"]+)"`) - -var undefinedInterfaceRegexp = regexp.MustCompile(`tool\.go:\d+: undefined: [\pL_0-9]+\.([\pL_0-9]+)`) - -// Does the 'go build' output indicate that a package wasn't found? If so, -// return the name of the package. -func findUnknownPackage(output []byte) *string { - if match := unknownPackageRegexp.FindSubmatch(output); match != nil { - res := string(match[1]) - return &res - } - - return nil -} - -// Does the 'go build' output indicate that an interface wasn't found? If so, -// return the name of the interface. -func findUndefinedInterface(output []byte) *string { - if match := undefinedInterfaceRegexp.FindSubmatch(output); match != nil { - res := string(match[1]) - return &res - } - - return nil -} - -// Split out from main so that deferred calls are executed even in the event of -// an error. -func run() error { - // Reduce noise in logging output. - log.SetFlags(0) - - // Check the command-line arguments. - flag.Parse() - - cmdLineArgs := flag.Args() - if len(cmdLineArgs) < 2 { - return errors.New("Usage: createmock [package] [interface ...]") - } - - // Create a temporary directory inside of $GOPATH to hold generated code. - buildPkg, err := build.Import("github.com/smartystreets/goconvey/convey/assertions/oglemock", "", build.FindOnly) - if err != nil { - return errors.New(fmt.Sprintf("Couldn't find oglemock in $GOPATH: %v", err)) - } - - tmpDir, err := ioutil.TempDir(buildPkg.SrcRoot, "tmp-createmock-") - if err != nil { - return errors.New(fmt.Sprintf("Creating temp dir: %v", err)) - } - - defer os.RemoveAll(tmpDir) - - // Create a file to hold generated code. - codeFile, err := os.Create(path.Join(tmpDir, "tool.go")) - if err != nil { - return errors.New(fmt.Sprintf("Couldn't create a file to hold code: %v", err)) - } - - // Create an appropriate path for the built binary. - binaryPath := path.Join(tmpDir, "tool") - - // Create an appropriate template argument. - var arg tmplArg - arg.InputPkg = cmdLineArgs[0] - arg.OutputPkg = "mock_" + path.Base(arg.InputPkg) - arg.TypeNames = cmdLineArgs[1:] - - arg.Imports = make(importMap) - arg.Imports[path.Base(arg.InputPkg)] = arg.InputPkg - arg.Imports["generate"] = "github.com/smartystreets/goconvey/convey/assertions/oglemock/generate" - arg.Imports["log"] = "log" - arg.Imports["os"] = "os" - arg.Imports["reflect"] = "reflect" - - // Execute the template to generate code that will itself generate the mock - // code. Write the code to the temp file. - tmpl := template.Must( - template.New("code").Funcs( - template.FuncMap{ - "base": path.Base, - }).Parse(tmplStr)) - if err := tmpl.Execute(codeFile, arg); err != nil { - return errors.New(fmt.Sprintf("Error executing template: %v", err)) - } - - codeFile.Close() - - // Attempt to build the code. - cmd := exec.Command("go", "build", "-o", binaryPath) - cmd.Dir = tmpDir - buildOutput, err := cmd.CombinedOutput() - - if err != nil { - // Did the compilation fail due to the user-specified package not being found? - if pkg := findUnknownPackage(buildOutput); pkg != nil && *pkg == arg.InputPkg { - return errors.New(fmt.Sprintf("Unknown package: %s", *pkg)) - } - - // Did the compilation fail due to an unknown interface? - if in := findUndefinedInterface(buildOutput); in != nil { - return errors.New(fmt.Sprintf("Unknown interface: %s", *in)) - } - - // Otherwise return a generic error. - return errors.New(fmt.Sprintf( - "%s\n\nError building generated code:\n\n"+ - " %v\n\nPlease report this oglemock bug.", - buildOutput, - err)) - } - - // Run the binary. - cmd = exec.Command(binaryPath) - binaryOutput, err := cmd.CombinedOutput() - - if err != nil { - return errors.New(fmt.Sprintf( - "%s\n\nError running generated code:\n\n"+ - " %v\n\n Please report this oglemock bug.", - binaryOutput, - err)) - } - - // Copy its output. - _, err = os.Stdout.Write(binaryOutput) - if err != nil { - return errors.New(fmt.Sprintf("Error copying binary output: %v", err)) - } - - return nil -} - -func main() { - if err := run(); err != nil { - fmt.Println(err.Error()) - os.Exit(1) - } -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/createmock/test_cases/golden.no_interfaces b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/createmock/test_cases/golden.no_interfaces deleted file mode 100644 index b70535fae6b..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/createmock/test_cases/golden.no_interfaces +++ /dev/null @@ -1 +0,0 @@ -Usage: createmock [package] [interface ...] diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/createmock/test_cases/golden.no_package b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/createmock/test_cases/golden.no_package deleted file mode 100644 index b70535fae6b..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/createmock/test_cases/golden.no_package +++ /dev/null @@ -1 +0,0 @@ -Usage: createmock [package] [interface ...] diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/createmock/test_cases/golden.unknown_interface b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/createmock/test_cases/golden.unknown_interface deleted file mode 100644 index c32950a1790..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/createmock/test_cases/golden.unknown_interface +++ /dev/null @@ -1 +0,0 @@ -Unknown interface: Frobnicator diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/createmock/test_cases/golden.unknown_package b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/createmock/test_cases/golden.unknown_package deleted file mode 100644 index d07e915d2cf..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/createmock/test_cases/golden.unknown_package +++ /dev/null @@ -1 +0,0 @@ -Unknown package: foo/bar diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/error_reporter.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/error_reporter.go deleted file mode 100644 index 0c3a65ee187..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/error_reporter.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglemock - -// ErrorReporter is an interface that wraps methods for reporting errors that -// should cause test failures. -type ErrorReporter interface { - // Report that some failure (e.g. an unsatisfied expectation) occurred. If - // known, fileName and lineNumber should contain information about where it - // occurred. The test may continue if the test framework supports it. - ReportError(fileName string, lineNumber int, err error) - - // Like ReportError, but the test should be halted immediately. It is assumed - // that this method does not return. - ReportFatalError(fileName string, lineNumber int, err error) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/expectation.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/expectation.go deleted file mode 100644 index d18bfb8bce9..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/expectation.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglemock - -// Expectation is an expectation for zero or more calls to a mock method with -// particular arguments or sets of arguments. -type Expectation interface { - // Times expresses that a matching method call should happen exactly N times. - // Times must not be called more than once, and must not be called after - // WillOnce or WillRepeatedly. - // - // The full rules for the cardinality of an expectation are as follows: - // - // 1. If an explicit cardinality is set with Times(N), then anything other - // than exactly N matching calls will cause a test failure. - // - // 2. Otherwise, if there are any one-time actions set up, then it is - // expected there will be at least that many matching calls. If there is - // not also a fallback action, then it is expected that there will be - // exactly that many. - // - // 3. Otherwise, if there is a fallback action configured, any number of - // matching calls (including zero) is allowed. - // - // 4. Otherwise, the implicit cardinality is one. - // - Times(n uint) Expectation - - // WillOnce configures a "one-time action". WillOnce can be called zero or - // more times, but must be called after any call to Times and before any call - // to WillRepeatedly. - // - // When matching method calls are made on the mock object, one-time actions - // are invoked one per matching call in the order that they were set up until - // they are exhausted. Afterward the fallback action, if any, will be used. - WillOnce(a Action) Expectation - - // WillRepeatedly configures a "fallback action". WillRepeatedly can be - // called zero or one times, and must not be called before Times or WillOnce. - // - // Once all one-time actions are exhausted (see above), the fallback action - // will be invoked for any further method calls. If WillRepeatedly is not - // called, the fallback action is implicitly an action that returns zero - // values for the method's return values. - WillRepeatedly(a Action) Expectation -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/generate.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/generate.go deleted file mode 100644 index 0c383f9f63e..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/generate.go +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package generate implements code generation for mock classes. This is an -// implementation detail of the createmock command, which you probably want to -// use directly instead. -package generate - -import ( - "bytes" - "errors" - "go/ast" - "go/parser" - "go/printer" - "go/token" - "io" - "reflect" - "regexp" - "text/template" -) - -const tmplStr = ` -// This file was auto-generated using createmock. See the following page for -// more information: -// -// https://github.com/smartystreets/goconvey/convey/assertions/oglemock -// - -package {{.Pkg}} - -import ( - {{range $identifier, $import := .Imports}}{{$identifier}} "{{$import}}" - {{end}} -) - -{{range .Interfaces}} - {{$interfaceName := printf "Mock%s" .Name}} - {{$structName := printf "mock%s" .Name}} - - type {{$interfaceName}} interface { - {{getTypeString .}} - oglemock.MockObject - } - - type {{$structName}} struct { - controller oglemock.Controller - description string - } - - func New{{printf "Mock%s" .Name}}( - c oglemock.Controller, - desc string) {{$interfaceName}} { - return &{{$structName}}{ - controller: c, - description: desc, - } - } - - func (m *{{$structName}}) Oglemock_Id() uintptr { - return uintptr(unsafe.Pointer(m)) - } - - func (m *{{$structName}}) Oglemock_Description() string { - return m.description - } - - {{range getMethods .}} - {{$funcType := .Type}} - {{$inputTypes := getInputs $funcType}} - {{$outputTypes := getOutputs $funcType}} - - func (m *{{$structName}}) {{.Name}}({{range $i, $type := $inputTypes}}p{{$i}} {{getInputTypeString $i $funcType}}, {{end}}) ({{range $i, $type := $outputTypes}}o{{$i}} {{getTypeString $type}}, {{end}}) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "{{.Name}}", - file, - line, - []interface{}{ {{range $i, $type := $inputTypes}}p{{$i}}, {{end}} }) - - if len(retVals) != {{len $outputTypes}} { - panic(fmt.Sprintf("{{$structName}}.{{.Name}}: invalid return values: %v", retVals)) - } - - {{range $i, $type := $outputTypes}} - // o{{$i}} {{getTypeString $type}} - if retVals[{{$i}}] != nil { - o{{$i}} = retVals[{{$i}}].({{getTypeString $type}}) - } - {{end}} - - return - } - {{end}} -{{end}} -` - -type tmplArg struct { - // The package of the generated code. - Pkg string - - // Imports needed by the interfaces. - Imports importMap - - // The set of interfaces to mock. - Interfaces []reflect.Type -} - -var tmpl *template.Template - -func init() { - extraFuncs := make(template.FuncMap) - extraFuncs["getMethods"] = getMethods - extraFuncs["getInputs"] = getInputs - extraFuncs["getOutputs"] = getOutputs - extraFuncs["getInputTypeString"] = getInputTypeString - extraFuncs["getTypeString"] = getTypeString - - tmpl = template.New("code") - tmpl.Funcs(extraFuncs) - tmpl.Parse(tmplStr) -} - -func getInputTypeString(i int, ft reflect.Type) string { - numInputs := ft.NumIn() - if i == numInputs-1 && ft.IsVariadic() { - return "..." + getTypeString(ft.In(i).Elem()) - } - - return getTypeString(ft.In(i)) -} - -func getTypeString(t reflect.Type) string { - return t.String() -} - -func getMethods(it reflect.Type) []reflect.Method { - numMethods := it.NumMethod() - methods := make([]reflect.Method, numMethods) - - for i := 0; i < numMethods; i++ { - methods[i] = it.Method(i) - } - - return methods -} - -func getInputs(ft reflect.Type) []reflect.Type { - numIn := ft.NumIn() - inputs := make([]reflect.Type, numIn) - - for i := 0; i < numIn; i++ { - inputs[i] = ft.In(i) - } - - return inputs -} - -func getOutputs(ft reflect.Type) []reflect.Type { - numOut := ft.NumOut() - outputs := make([]reflect.Type, numOut) - - for i := 0; i < numOut; i++ { - outputs[i] = ft.Out(i) - } - - return outputs -} - -// A map from import identifier to package to use that identifier for, -// containing elements for each import needed by a set of mocked interfaces. -type importMap map[string]string - -var typePackageIdentifierRegexp = regexp.MustCompile(`^([\pL_0-9]+)\.[\pL_0-9]+$`) - -// Add an import for the supplied type, without recursing. -func addImportForType(imports importMap, t reflect.Type) { - // If there is no package path, this is a built-in type and we don't need an - // import. - pkgPath := t.PkgPath() - if pkgPath == "" { - return - } - - // Work around a bug in Go: - // - // http://code.google.com/p/go/issues/detail?id=2660 - // - var errorPtr *error - if t == reflect.TypeOf(errorPtr).Elem() { - return - } - - // Use the identifier that's part of the type's string representation as the - // import identifier. This means that we'll do the right thing for package - // "foo/bar" with declaration "package baz". - match := typePackageIdentifierRegexp.FindStringSubmatch(t.String()) - if match == nil { - return - } - - imports[match[1]] = pkgPath -} - -// Add all necessary imports for the type, recursing as appropriate. -func addImportsForType(imports importMap, t reflect.Type) { - // Add any import needed for the type itself. - addImportForType(imports, t) - - // Handle special cases where recursion is needed. - switch t.Kind() { - case reflect.Array, reflect.Chan, reflect.Ptr, reflect.Slice: - addImportsForType(imports, t.Elem()) - - case reflect.Func: - // Input parameters. - for i := 0; i < t.NumIn(); i++ { - addImportsForType(imports, t.In(i)) - } - - // Return values. - for i := 0; i < t.NumOut(); i++ { - addImportsForType(imports, t.Out(i)) - } - - case reflect.Map: - addImportsForType(imports, t.Key()) - addImportsForType(imports, t.Elem()) - } -} - -// Add imports for each of the methods of the interface, but not the interface -// itself. -func addImportsForInterfaceMethods(imports importMap, it reflect.Type) { - // Handle each method. - for i := 0; i < it.NumMethod(); i++ { - m := it.Method(i) - addImportsForType(imports, m.Type) - } -} - -// Given a set of interfaces, return a map from import identifier to package to -// use that identifier for, containing elements for each import needed by the -// mock versions of those interfaces. -func getImports(interfaces []reflect.Type) importMap { - imports := make(importMap) - for _, it := range interfaces { - addImportForType(imports, it) - addImportsForInterfaceMethods(imports, it) - } - - // Make sure there are imports for other types used by the generated code - // itself. - imports["fmt"] = "fmt" - imports["oglemock"] = "github.com/smartystreets/goconvey/convey/assertions/oglemock" - imports["runtime"] = "runtime" - imports["unsafe"] = "unsafe" - - return imports -} - -// Given a set of interfaces to mock, write out source code for a package named -// `pkg` that contains mock implementations of those interfaces. -func GenerateMockSource(w io.Writer, pkg string, interfaces []reflect.Type) error { - // Sanity-check arguments. - if pkg == "" { - return errors.New("Package name must be non-empty.") - } - - if len(interfaces) == 0 { - return errors.New("List of interfaces must be non-empty.") - } - - // Make sure each type is indeed an interface. - for _, it := range interfaces { - if it.Kind() != reflect.Interface { - return errors.New("Invalid type: " + it.String()) - } - } - - // Create an appropriate template arg, then execute the template. Write the - // raw output into a buffer. - var arg tmplArg - arg.Pkg = pkg - arg.Imports = getImports(interfaces) - arg.Interfaces = interfaces - - buf := new(bytes.Buffer) - if err := tmpl.Execute(buf, arg); err != nil { - return err - } - - // Parse the output. - fset := token.NewFileSet() - astFile, err := parser.ParseFile(fset, pkg+".go", buf, parser.ParseComments) - if err != nil { - return errors.New("Error parsing generated code: " + err.Error()) - } - - // Sort the import lines in the AST in the same way that gofmt does. - ast.SortImports(fset, astFile) - - // Pretty-print the AST, using the same options that gofmt does by default. - cfg := &printer.Config{ - Mode: printer.UseSpaces | printer.TabIndent, - Tabwidth: 8, - } - - if err = cfg.Fprint(w, fset, astFile); err != nil { - return errors.New("Error pretty printing: " + err.Error()) - } - - return nil -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/complicated_pkg/complicated_pkg.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/complicated_pkg/complicated_pkg.go deleted file mode 100644 index d86b25de4a4..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/complicated_pkg/complicated_pkg.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package complicated_pkg contains an interface with lots of interesting -// cases, for use in integration testing. -package complicated_pkg - -import ( - "image" - "io" - "net" - - "github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/renamed_pkg" -) - -type Byte uint8 - -type ComplicatedThing interface { - Channels(a chan chan<- <-chan net.Conn) chan int - Pointers(a *int, b *net.Conn, c **io.Reader) (*int, error) - Functions(a func(int, image.Image) int) func(string, int) net.Conn - Maps(a map[string]*int) (map[int]*string, error) - Arrays(a [3]string) ([3]int, error) - Slices(a []string) ([]int, error) - NamedScalarType(a Byte) ([]Byte, error) - EmptyInterface(a interface{}) (interface{}, error) - RenamedPackage(a tony.SomeUint8Alias) - Variadic(a int, b ...net.Conn) int -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/golden.complicated_pkg.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/golden.complicated_pkg.go deleted file mode 100644 index 2a06efb3626..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/golden.complicated_pkg.go +++ /dev/null @@ -1,312 +0,0 @@ -// This file was auto-generated using createmock. See the following page for -// more information: -// -// https://github.com/smartystreets/goconvey/convey/assertions/oglemock -// - -package some_pkg - -import ( - fmt "fmt" - image "image" - io "io" - net "net" - runtime "runtime" - unsafe "unsafe" - - oglemock "github.com/smartystreets/goconvey/convey/assertions/oglemock" - complicated_pkg "github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/complicated_pkg" - tony "github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/renamed_pkg" -) - -type MockComplicatedThing interface { - complicated_pkg.ComplicatedThing - oglemock.MockObject -} - -type mockComplicatedThing struct { - controller oglemock.Controller - description string -} - -func NewMockComplicatedThing( - c oglemock.Controller, - desc string) MockComplicatedThing { - return &mockComplicatedThing{ - controller: c, - description: desc, - } -} - -func (m *mockComplicatedThing) Oglemock_Id() uintptr { - return uintptr(unsafe.Pointer(m)) -} - -func (m *mockComplicatedThing) Oglemock_Description() string { - return m.description -} - -func (m *mockComplicatedThing) Arrays(p0 [3]string) (o0 [3]int, o1 error) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "Arrays", - file, - line, - []interface{}{p0}) - - if len(retVals) != 2 { - panic(fmt.Sprintf("mockComplicatedThing.Arrays: invalid return values: %v", retVals)) - } - - // o0 [3]int - if retVals[0] != nil { - o0 = retVals[0].([3]int) - } - - // o1 error - if retVals[1] != nil { - o1 = retVals[1].(error) - } - - return -} - -func (m *mockComplicatedThing) Channels(p0 chan chan<- <-chan net.Conn) (o0 chan int) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "Channels", - file, - line, - []interface{}{p0}) - - if len(retVals) != 1 { - panic(fmt.Sprintf("mockComplicatedThing.Channels: invalid return values: %v", retVals)) - } - - // o0 chan int - if retVals[0] != nil { - o0 = retVals[0].(chan int) - } - - return -} - -func (m *mockComplicatedThing) EmptyInterface(p0 interface{}) (o0 interface{}, o1 error) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "EmptyInterface", - file, - line, - []interface{}{p0}) - - if len(retVals) != 2 { - panic(fmt.Sprintf("mockComplicatedThing.EmptyInterface: invalid return values: %v", retVals)) - } - - // o0 interface {} - if retVals[0] != nil { - o0 = retVals[0].(interface{}) - } - - // o1 error - if retVals[1] != nil { - o1 = retVals[1].(error) - } - - return -} - -func (m *mockComplicatedThing) Functions(p0 func(int, image.Image) int) (o0 func(string, int) net.Conn) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "Functions", - file, - line, - []interface{}{p0}) - - if len(retVals) != 1 { - panic(fmt.Sprintf("mockComplicatedThing.Functions: invalid return values: %v", retVals)) - } - - // o0 func(string, int) net.Conn - if retVals[0] != nil { - o0 = retVals[0].(func(string, int) net.Conn) - } - - return -} - -func (m *mockComplicatedThing) Maps(p0 map[string]*int) (o0 map[int]*string, o1 error) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "Maps", - file, - line, - []interface{}{p0}) - - if len(retVals) != 2 { - panic(fmt.Sprintf("mockComplicatedThing.Maps: invalid return values: %v", retVals)) - } - - // o0 map[int]*string - if retVals[0] != nil { - o0 = retVals[0].(map[int]*string) - } - - // o1 error - if retVals[1] != nil { - o1 = retVals[1].(error) - } - - return -} - -func (m *mockComplicatedThing) NamedScalarType(p0 complicated_pkg.Byte) (o0 []complicated_pkg.Byte, o1 error) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "NamedScalarType", - file, - line, - []interface{}{p0}) - - if len(retVals) != 2 { - panic(fmt.Sprintf("mockComplicatedThing.NamedScalarType: invalid return values: %v", retVals)) - } - - // o0 []complicated_pkg.Byte - if retVals[0] != nil { - o0 = retVals[0].([]complicated_pkg.Byte) - } - - // o1 error - if retVals[1] != nil { - o1 = retVals[1].(error) - } - - return -} - -func (m *mockComplicatedThing) Pointers(p0 *int, p1 *net.Conn, p2 **io.Reader) (o0 *int, o1 error) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "Pointers", - file, - line, - []interface{}{p0, p1, p2}) - - if len(retVals) != 2 { - panic(fmt.Sprintf("mockComplicatedThing.Pointers: invalid return values: %v", retVals)) - } - - // o0 *int - if retVals[0] != nil { - o0 = retVals[0].(*int) - } - - // o1 error - if retVals[1] != nil { - o1 = retVals[1].(error) - } - - return -} - -func (m *mockComplicatedThing) RenamedPackage(p0 tony.SomeUint8Alias) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "RenamedPackage", - file, - line, - []interface{}{p0}) - - if len(retVals) != 0 { - panic(fmt.Sprintf("mockComplicatedThing.RenamedPackage: invalid return values: %v", retVals)) - } - - return -} - -func (m *mockComplicatedThing) Slices(p0 []string) (o0 []int, o1 error) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "Slices", - file, - line, - []interface{}{p0}) - - if len(retVals) != 2 { - panic(fmt.Sprintf("mockComplicatedThing.Slices: invalid return values: %v", retVals)) - } - - // o0 []int - if retVals[0] != nil { - o0 = retVals[0].([]int) - } - - // o1 error - if retVals[1] != nil { - o1 = retVals[1].(error) - } - - return -} - -func (m *mockComplicatedThing) Variadic(p0 int, p1 ...net.Conn) (o0 int) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "Variadic", - file, - line, - []interface{}{p0, p1}) - - if len(retVals) != 1 { - panic(fmt.Sprintf("mockComplicatedThing.Variadic: invalid return values: %v", retVals)) - } - - // o0 int - if retVals[0] != nil { - o0 = retVals[0].(int) - } - - return -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/golden.image.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/golden.image.go deleted file mode 100644 index 360fbfa5b4a..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/golden.image.go +++ /dev/null @@ -1,239 +0,0 @@ -// This file was auto-generated using createmock. See the following page for -// more information: -// -// https://github.com/smartystreets/goconvey/convey/assertions/oglemock -// - -package some_pkg - -import ( - fmt "fmt" - image "image" - color "image/color" - runtime "runtime" - unsafe "unsafe" - - oglemock "github.com/smartystreets/goconvey/convey/assertions/oglemock" -) - -type MockImage interface { - image.Image - oglemock.MockObject -} - -type mockImage struct { - controller oglemock.Controller - description string -} - -func NewMockImage( - c oglemock.Controller, - desc string) MockImage { - return &mockImage{ - controller: c, - description: desc, - } -} - -func (m *mockImage) Oglemock_Id() uintptr { - return uintptr(unsafe.Pointer(m)) -} - -func (m *mockImage) Oglemock_Description() string { - return m.description -} - -func (m *mockImage) At(p0 int, p1 int) (o0 color.Color) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "At", - file, - line, - []interface{}{p0, p1}) - - if len(retVals) != 1 { - panic(fmt.Sprintf("mockImage.At: invalid return values: %v", retVals)) - } - - // o0 color.Color - if retVals[0] != nil { - o0 = retVals[0].(color.Color) - } - - return -} - -func (m *mockImage) Bounds() (o0 image.Rectangle) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "Bounds", - file, - line, - []interface{}{}) - - if len(retVals) != 1 { - panic(fmt.Sprintf("mockImage.Bounds: invalid return values: %v", retVals)) - } - - // o0 image.Rectangle - if retVals[0] != nil { - o0 = retVals[0].(image.Rectangle) - } - - return -} - -func (m *mockImage) ColorModel() (o0 color.Model) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "ColorModel", - file, - line, - []interface{}{}) - - if len(retVals) != 1 { - panic(fmt.Sprintf("mockImage.ColorModel: invalid return values: %v", retVals)) - } - - // o0 color.Model - if retVals[0] != nil { - o0 = retVals[0].(color.Model) - } - - return -} - -type MockPalettedImage interface { - image.PalettedImage - oglemock.MockObject -} - -type mockPalettedImage struct { - controller oglemock.Controller - description string -} - -func NewMockPalettedImage( - c oglemock.Controller, - desc string) MockPalettedImage { - return &mockPalettedImage{ - controller: c, - description: desc, - } -} - -func (m *mockPalettedImage) Oglemock_Id() uintptr { - return uintptr(unsafe.Pointer(m)) -} - -func (m *mockPalettedImage) Oglemock_Description() string { - return m.description -} - -func (m *mockPalettedImage) At(p0 int, p1 int) (o0 color.Color) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "At", - file, - line, - []interface{}{p0, p1}) - - if len(retVals) != 1 { - panic(fmt.Sprintf("mockPalettedImage.At: invalid return values: %v", retVals)) - } - - // o0 color.Color - if retVals[0] != nil { - o0 = retVals[0].(color.Color) - } - - return -} - -func (m *mockPalettedImage) Bounds() (o0 image.Rectangle) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "Bounds", - file, - line, - []interface{}{}) - - if len(retVals) != 1 { - panic(fmt.Sprintf("mockPalettedImage.Bounds: invalid return values: %v", retVals)) - } - - // o0 image.Rectangle - if retVals[0] != nil { - o0 = retVals[0].(image.Rectangle) - } - - return -} - -func (m *mockPalettedImage) ColorIndexAt(p0 int, p1 int) (o0 uint8) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "ColorIndexAt", - file, - line, - []interface{}{p0, p1}) - - if len(retVals) != 1 { - panic(fmt.Sprintf("mockPalettedImage.ColorIndexAt: invalid return values: %v", retVals)) - } - - // o0 uint8 - if retVals[0] != nil { - o0 = retVals[0].(uint8) - } - - return -} - -func (m *mockPalettedImage) ColorModel() (o0 color.Model) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "ColorModel", - file, - line, - []interface{}{}) - - if len(retVals) != 1 { - panic(fmt.Sprintf("mockPalettedImage.ColorModel: invalid return values: %v", retVals)) - } - - // o0 color.Model - if retVals[0] != nil { - o0 = retVals[0].(color.Model) - } - - return -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/golden.io_reader_writer.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/golden.io_reader_writer.go deleted file mode 100644 index 304dcd48560..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/golden.io_reader_writer.go +++ /dev/null @@ -1,128 +0,0 @@ -// This file was auto-generated using createmock. See the following page for -// more information: -// -// https://github.com/smartystreets/goconvey/convey/assertions/oglemock -// - -package some_pkg - -import ( - fmt "fmt" - io "io" - runtime "runtime" - unsafe "unsafe" - - oglemock "github.com/smartystreets/goconvey/convey/assertions/oglemock" -) - -type MockReader interface { - io.Reader - oglemock.MockObject -} - -type mockReader struct { - controller oglemock.Controller - description string -} - -func NewMockReader( - c oglemock.Controller, - desc string) MockReader { - return &mockReader{ - controller: c, - description: desc, - } -} - -func (m *mockReader) Oglemock_Id() uintptr { - return uintptr(unsafe.Pointer(m)) -} - -func (m *mockReader) Oglemock_Description() string { - return m.description -} - -func (m *mockReader) Read(p0 []uint8) (o0 int, o1 error) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "Read", - file, - line, - []interface{}{p0}) - - if len(retVals) != 2 { - panic(fmt.Sprintf("mockReader.Read: invalid return values: %v", retVals)) - } - - // o0 int - if retVals[0] != nil { - o0 = retVals[0].(int) - } - - // o1 error - if retVals[1] != nil { - o1 = retVals[1].(error) - } - - return -} - -type MockWriter interface { - io.Writer - oglemock.MockObject -} - -type mockWriter struct { - controller oglemock.Controller - description string -} - -func NewMockWriter( - c oglemock.Controller, - desc string) MockWriter { - return &mockWriter{ - controller: c, - description: desc, - } -} - -func (m *mockWriter) Oglemock_Id() uintptr { - return uintptr(unsafe.Pointer(m)) -} - -func (m *mockWriter) Oglemock_Description() string { - return m.description -} - -func (m *mockWriter) Write(p0 []uint8) (o0 int, o1 error) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "Write", - file, - line, - []interface{}{p0}) - - if len(retVals) != 2 { - panic(fmt.Sprintf("mockWriter.Write: invalid return values: %v", retVals)) - } - - // o0 int - if retVals[0] != nil { - o0 = retVals[0].(int) - } - - // o1 error - if retVals[1] != nil { - o1 = retVals[1].(error) - } - - return -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/golden.renamed_pkg.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/golden.renamed_pkg.go deleted file mode 100644 index 03a53da0ac6..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/golden.renamed_pkg.go +++ /dev/null @@ -1,67 +0,0 @@ -// This file was auto-generated using createmock. See the following page for -// more information: -// -// https://github.com/smartystreets/goconvey/convey/assertions/oglemock -// - -package some_pkg - -import ( - fmt "fmt" - runtime "runtime" - unsafe "unsafe" - - oglemock "github.com/smartystreets/goconvey/convey/assertions/oglemock" - tony "github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/renamed_pkg" -) - -type MockSomeInterface interface { - tony.SomeInterface - oglemock.MockObject -} - -type mockSomeInterface struct { - controller oglemock.Controller - description string -} - -func NewMockSomeInterface( - c oglemock.Controller, - desc string) MockSomeInterface { - return &mockSomeInterface{ - controller: c, - description: desc, - } -} - -func (m *mockSomeInterface) Oglemock_Id() uintptr { - return uintptr(unsafe.Pointer(m)) -} - -func (m *mockSomeInterface) Oglemock_Description() string { - return m.description -} - -func (m *mockSomeInterface) DoFoo(p0 int) (o0 int) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "DoFoo", - file, - line, - []interface{}{p0}) - - if len(retVals) != 1 { - panic(fmt.Sprintf("mockSomeInterface.DoFoo: invalid return values: %v", retVals)) - } - - // o0 int - if retVals[0] != nil { - o0 = retVals[0].(int) - } - - return -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/renamed_pkg/renamed_pkg.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/renamed_pkg/renamed_pkg.go deleted file mode 100644 index 1461cd6960d..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/generate/test_cases/renamed_pkg/renamed_pkg.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// A package that calls itself something different than its package path would -// have you believe. -package tony - -type SomeUint8Alias uint8 - -type SomeInterface interface { - DoFoo(a int) int -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/internal_expectation.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/internal_expectation.go deleted file mode 100644 index 070ecb69b08..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/internal_expectation.go +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglemock - -import ( - "errors" - "fmt" - "reflect" - "sync" - - "github.com/smartystreets/goconvey/convey/assertions/oglematchers" -) - -// InternalExpectation is exported for purposes of testing only. You should not -// touch it. -// -// InternalExpectation represents an expectation for zero or more calls to a -// mock method, and a set of actions to be taken when those calls are received. -type InternalExpectation struct { - // The signature of the method to which this expectation is bound, for - // checking action types. - methodSignature reflect.Type - - // An error reporter to use for reporting errors in the way that expectations - // are set. - errorReporter ErrorReporter - - // A mutex protecting mutable fields of the struct. - mutex sync.Mutex - - // Matchers that the arguments to the mock method must satisfy in order to - // match this expectation. - ArgMatchers []oglematchers.Matcher - - // The name of the file in which this expectation was expressed. - FileName string - - // The line number at which this expectation was expressed. - LineNumber int - - // The number of times this expectation should be matched, as explicitly - // listed by the user. If there was no explicit number expressed, this is -1. - ExpectedNumMatches int - - // Actions to be taken for the first N calls, one per call in order, where N - // is the length of this slice. - OneTimeActions []Action - - // An action to be taken when the one-time actions have expired, or nil if - // there is no such action. - FallbackAction Action - - // The number of times this expectation has been matched so far. - NumMatches uint -} - -// InternalNewExpectation is exported for purposes of testing only. You should -// not touch it. -func InternalNewExpectation( - reporter ErrorReporter, - methodSignature reflect.Type, - args []interface{}, - fileName string, - lineNumber int) *InternalExpectation { - result := &InternalExpectation{} - - // Store fields that can be stored directly. - result.methodSignature = methodSignature - result.errorReporter = reporter - result.FileName = fileName - result.LineNumber = lineNumber - - // Set up defaults. - result.ExpectedNumMatches = -1 - result.OneTimeActions = make([]Action, 0) - - // Set up the ArgMatchers slice, using Equals(x) for each x that is not a - // matcher itself. - result.ArgMatchers = make([]oglematchers.Matcher, len(args)) - for i, x := range args { - if matcher, ok := x.(oglematchers.Matcher); ok { - result.ArgMatchers[i] = matcher - } else { - result.ArgMatchers[i] = oglematchers.Equals(x) - } - } - - return result -} - -func (e *InternalExpectation) Times(n uint) Expectation { - e.mutex.Lock() - defer e.mutex.Unlock() - - // It is illegal to call this more than once. - if e.ExpectedNumMatches != -1 { - e.reportFatalError("Times called more than once.") - return nil - } - - // It is illegal to call this after any actions are configured. - if len(e.OneTimeActions) != 0 { - e.reportFatalError("Times called after WillOnce.") - return nil - } - - if e.FallbackAction != nil { - e.reportFatalError("Times called after WillRepeatedly.") - return nil - } - - // Make sure the number is reasonable (and will fit in an int). - if n > 1000 { - e.reportFatalError("Expectation.Times: N must be at most 1000") - return nil - } - - e.ExpectedNumMatches = int(n) - return e -} - -func (e *InternalExpectation) WillOnce(a Action) Expectation { - e.mutex.Lock() - defer e.mutex.Unlock() - - // It is illegal to call this after WillRepeatedly. - if e.FallbackAction != nil { - e.reportFatalError("WillOnce called after WillRepeatedly.") - return nil - } - - // Tell the action about the method's signature. - if err := a.SetSignature(e.methodSignature); err != nil { - e.reportFatalError(fmt.Sprintf("WillOnce given invalid action: %v", err)) - return nil - } - - // Store the action. - e.OneTimeActions = append(e.OneTimeActions, a) - - return e -} - -func (e *InternalExpectation) WillRepeatedly(a Action) Expectation { - e.mutex.Lock() - defer e.mutex.Unlock() - - // It is illegal to call this twice. - if e.FallbackAction != nil { - e.reportFatalError("WillRepeatedly called more than once.") - return nil - } - - // Tell the action about the method's signature. - if err := a.SetSignature(e.methodSignature); err != nil { - e.reportFatalError(fmt.Sprintf("WillRepeatedly given invalid action: %v", err)) - return nil - } - - // Store the action. - e.FallbackAction = a - - return e -} - -func (e *InternalExpectation) reportFatalError(errorText string) { - e.errorReporter.ReportFatalError(e.FileName, e.LineNumber, errors.New(errorText)) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/invoke.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/invoke.go deleted file mode 100644 index 07630cbbb7e..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/invoke.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglemock - -import ( - "errors" - "fmt" - "reflect" -) - -// Create an Action that invokes the supplied function, returning whatever it -// returns. The signature of the function must match that of the mocked method -// exactly. -func Invoke(f interface{}) Action { - // Make sure f is a function. - fv := reflect.ValueOf(f) - fk := fv.Kind() - - if fk != reflect.Func { - desc := "" - if fk != reflect.Invalid { - desc = fv.Type().String() - } - - panic(fmt.Sprintf("Invoke: expected function, got %s", desc)) - } - - return &invokeAction{fv} -} - -type invokeAction struct { - f reflect.Value -} - -func (a *invokeAction) SetSignature(signature reflect.Type) error { - // The signature must match exactly. - ft := a.f.Type() - if ft != signature { - return errors.New(fmt.Sprintf("Invoke: expected %v, got %v", signature, ft)) - } - - return nil -} - -func (a *invokeAction) Invoke(vals []interface{}) []interface{} { - // Create a slice of args for the function. - in := make([]reflect.Value, len(vals)) - for i, x := range vals { - in[i] = reflect.ValueOf(x) - } - - // Call the function and return its return values. - out := a.f.Call(in) - result := make([]interface{}, len(out)) - for i, v := range out { - result[i] = v.Interface() - } - - return result -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/mock_object.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/mock_object.go deleted file mode 100644 index de995efc667..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/mock_object.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglemock - -// MockObject is an interface that mock object implementations must conform to -// in order to register expectations with and hand off calls to a -// MockController. Users should not interact with this interface directly. -type MockObject interface { - // Oglemock_Id returns an identifier for the mock object that is guaranteed - // to be unique within the process at least until the mock object is garbage - // collected. - Oglemock_Id() uintptr - - // Oglemock_Description returns a description of the mock object that may be - // helpful in test failure messages. - Oglemock_Description() string -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/oglemock.goconvey b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/oglemock.goconvey deleted file mode 100644 index 79982854b53..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/oglemock.goconvey +++ /dev/null @@ -1,2 +0,0 @@ -#ignore --timeout=1s diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/return.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/return.go deleted file mode 100644 index c66d248f44a..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/return.go +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglemock - -import ( - "errors" - "fmt" - "math" - "reflect" -) - -var intType = reflect.TypeOf(int(0)) -var float64Type = reflect.TypeOf(float64(0)) -var complex128Type = reflect.TypeOf(complex128(0)) - -// Return creates an Action that returns the values passed to Return as -// arguments, after suitable legal type conversions. The following rules apply. -// Given an argument x to Return and a corresponding type T in the method's -// signature, at least one of the following must hold: -// -// * x is assignable to T. (See "Assignability" in the language spec.) Note -// that this in particular applies that x may be a type that implements an -// interface T. It also implies that the nil literal can be used if T is a -// pointer, function, interface, slice, channel, or map type. -// -// * T is any numeric type, and x is an int that is in-range for that type. -// This facilities using raw integer constants: Return(17). -// -// * T is a floating-point or complex number type, and x is a float64. This -// facilities using raw floating-point constants: Return(17.5). -// -// * T is a complex number type, and x is a complex128. This facilities using -// raw complex constants: Return(17+2i). -// -func Return(vals ...interface{}) Action { - return &returnAction{vals, nil} -} - -type returnAction struct { - returnVals []interface{} - signature reflect.Type -} - -func (a *returnAction) Invoke(vals []interface{}) []interface{} { - if a.signature == nil { - panic("You must first call SetSignature with a valid signature.") - } - - res, err := a.buildInvokeResult(a.signature) - if err != nil { - panic(err) - } - - return res -} - -func (a *returnAction) SetSignature(signature reflect.Type) error { - if _, err := a.buildInvokeResult(signature); err != nil { - return err - } - - a.signature = signature - return nil -} - -// A version of Invoke that does error checking, used by both public methods. -func (a *returnAction) buildInvokeResult( - sig reflect.Type) (res []interface{}, err error) { - // Check the length of the return value. - numOut := sig.NumOut() - numVals := len(a.returnVals) - - if numOut != numVals { - err = errors.New( - fmt.Sprintf("Return given %d vals; expected %d.", numVals, numOut)) - return - } - - // Attempt to coerce each return value. - res = make([]interface{}, numOut) - - for i, val := range a.returnVals { - resType := sig.Out(i) - res[i], err = a.coerce(val, resType) - - if err != nil { - res = nil - err = errors.New(fmt.Sprintf("Return: arg %d: %v", i, err)) - return - } - } - - return -} - -func (a *returnAction) coerce(x interface{}, t reflect.Type) (interface{}, error) { - xv := reflect.ValueOf(x) - rv := reflect.New(t).Elem() - - // Special case: the language spec says that the predeclared identifier nil - // is assignable to pointers, functions, interface, slices, channels, and map - // types. However, reflect.ValueOf(nil) returns an invalid value that will - // not cooperate below. So handle invalid values here, assuming that they - // resulted from Return(nil). - if !xv.IsValid() { - switch t.Kind() { - case reflect.Ptr, reflect.Func, reflect.Interface, reflect.Chan, reflect.Slice, reflect.Map, reflect.UnsafePointer: - return rv.Interface(), nil - } - - return nil, errors.New(fmt.Sprintf("expected %v, given ", t)) - } - - // If x is assignable to type t, let the reflect package do the heavy - // lifting. - if reflect.TypeOf(x).AssignableTo(t) { - rv.Set(xv) - return rv.Interface(), nil - } - - // Handle numeric types as described in the documentation on Return. - switch { - case xv.Type() == intType && a.isNumeric(t): - return a.coerceInt(xv.Int(), t) - - case xv.Type() == float64Type && (a.isFloatingPoint(t) || a.isComplex(t)): - return a.coerceFloat(xv.Float(), t) - - case xv.Type() == complex128Type && a.isComplex(t): - return a.coerceComplex(xv.Complex(), t) - } - - // The value wasn't of a legal type. - return nil, errors.New(fmt.Sprintf("expected %v, given %v", t, xv.Type())) -} - -func (a *returnAction) isNumeric(t reflect.Type) bool { - return (t.Kind() >= reflect.Int && t.Kind() <= reflect.Uint64) || - a.isFloatingPoint(t) || - a.isComplex(t) -} - -func (a *returnAction) isFloatingPoint(t reflect.Type) bool { - return t.Kind() == reflect.Float32 || t.Kind() == reflect.Float64 -} - -func (a *returnAction) isComplex(t reflect.Type) bool { - return t.Kind() == reflect.Complex64 || t.Kind() == reflect.Complex128 -} - -func (a *returnAction) coerceInt(x int64, t reflect.Type) (interface{}, error) { - k := t.Kind() - - // Floating point and complex numbers: promote appropriately. - if a.isFloatingPoint(t) || a.isComplex(t) { - return a.coerceFloat(float64(x), t) - } - - // Integers: range check. - var min, max int64 - unsigned := false - - switch k { - case reflect.Int8: - min = math.MinInt8 - max = math.MaxInt8 - - case reflect.Int16: - min = math.MinInt16 - max = math.MaxInt16 - - case reflect.Int32: - min = math.MinInt32 - max = math.MaxInt32 - - case reflect.Int64: - min = math.MinInt64 - max = math.MaxInt64 - - case reflect.Uint: - unsigned = true - min = 0 - max = math.MaxUint32 - - case reflect.Uint8: - unsigned = true - min = 0 - max = math.MaxUint8 - - case reflect.Uint16: - unsigned = true - min = 0 - max = math.MaxUint16 - - case reflect.Uint32: - unsigned = true - min = 0 - max = math.MaxUint32 - - case reflect.Uint64: - unsigned = true - min = 0 - max = math.MaxInt64 - - default: - panic(fmt.Sprintf("Unexpected type: %v", t)) - } - - if x < min || x > max { - return nil, errors.New("int value out of range") - } - - rv := reflect.New(t).Elem() - if unsigned { - rv.SetUint(uint64(x)) - } else { - rv.SetInt(x) - } - - return rv.Interface(), nil -} - -func (a *returnAction) coerceFloat(x float64, t reflect.Type) (interface{}, error) { - // Promote complex numbers. - if a.isComplex(t) { - return a.coerceComplex(complex(x, 0), t) - } - - rv := reflect.New(t).Elem() - rv.SetFloat(x) - return rv.Interface(), nil -} - -func (a *returnAction) coerceComplex(x complex128, t reflect.Type) (interface{}, error) { - rv := reflect.New(t).Elem() - rv.SetComplex(x) - return rv.Interface(), nil -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/sample/README.markdown b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/sample/README.markdown deleted file mode 100644 index 60d5d2cb1ab..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/sample/README.markdown +++ /dev/null @@ -1,6 +0,0 @@ -This directory contains sample code generated with the `createmock` command. For -example, the file `mock_io.go` can be regenerated with: - - createmock io Reader > sample/mock_io/mock_io.go - -The files are also used by `integration_test.go`. diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/sample/mock_io/mock_io.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/sample/mock_io/mock_io.go deleted file mode 100644 index c6d5ca78d67..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/oglemock/sample/mock_io/mock_io.go +++ /dev/null @@ -1,72 +0,0 @@ -// This file was auto-generated using createmock. See the following page for -// more information: -// -// https://github.com/smartystreets/goconvey/convey/assertions/oglemock -// - -package mock_io - -import ( - fmt "fmt" - io "io" - runtime "runtime" - unsafe "unsafe" - - oglemock "github.com/smartystreets/goconvey/convey/assertions/oglemock" -) - -type MockReader interface { - io.Reader - oglemock.MockObject -} - -type mockReader struct { - controller oglemock.Controller - description string -} - -func NewMockReader( - c oglemock.Controller, - desc string) MockReader { - return &mockReader{ - controller: c, - description: desc, - } -} - -func (m *mockReader) Oglemock_Id() uintptr { - return uintptr(unsafe.Pointer(m)) -} - -func (m *mockReader) Oglemock_Description() string { - return m.description -} - -func (m *mockReader) Read(p0 []uint8) (o0 int, o1 error) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "Read", - file, - line, - []interface{}{p0}) - - if len(retVals) != 2 { - panic(fmt.Sprintf("mockReader.Read: invalid return values: %v", retVals)) - } - - // o0 int - if retVals[0] != nil { - o0 = retVals[0].(int) - } - - // o1 error - if retVals[1] != nil { - o1 = retVals[1].(error) - } - - return -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/.gitignore b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/.gitignore deleted file mode 100644 index dd8fc7468f4..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*.6 -6.out -_obj/ -_test/ -_testmain.go diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/LICENSE b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/LICENSE deleted file mode 100644 index d6456956733..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/README.markdown b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/README.markdown deleted file mode 100644 index 56f12d62462..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/README.markdown +++ /dev/null @@ -1,149 +0,0 @@ -`ogletest` is a unit testing framework for Go with the following features: - - * An extensive and extensible set of matchers for expressing expectations. - * Automatic failure messages; no need to say `t.Errorf("Expected %v, got - %v"...)`. - * Clean, readable output that tells you exactly what you need to know. - * Built-in support for mocking through the [oglemock][] package. - * Style and semantics similar to [Google Test][googletest] and - [Google JS Test][google-js-test]. - -It integrates with Go's built-in `testing` package, so it works with the -`go test` command, and even with other types of test within your package. Unlike -the `testing` package which offers only basic capabilities for signalling -failures, it offers ways to express expectations and get nice failure messages -automatically. - - -Installation ------------- - -First, make sure you have installed Go 1.0.2 or newer. See -[here][golang-install] for instructions. - -Use the following command to install `ogletest` and its dependencies, and to -keep them up to date: - - go get -u github.com/smartystreets/goconvey/convey/assertions/ogletest - - -Documentation -------------- - -See [here][reference] for package documentation hosted on GoPkgDoc containing an -exhaustive list of exported symbols. Alternatively, you can install the package -and then use `go doc`: - - go doc github.com/smartystreets/goconvey/convey/assertions/ogletest - -An important part of `ogletest` is its use of matchers provided by the -[oglematchers][matcher-reference] package. See that package's documentation -for information on the built-in matchers available, and check out the -`oglematchers.Matcher` interface if you want to define your own. - - -Example -------- - -Let's say you have a function in your package `people` with the following -signature: - -```go -// GetRandomPerson returns the name and phone number of Tony, Dennis, or Scott. -func GetRandomPerson() (name, phone string) { - [...] -} -``` - -A silly function, but it will do for an example. You can write a couple of tests -for it as follows: - -```go -package people - -import ( - "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - "github.com/smartystreets/goconvey/convey/assertions/ogletest" - "testing" -) - -// Give ogletest a chance to run your tests when invoked by 'go test'. -func TestOgletest(t *testing.T) { ogletest.RunTests(t) } - -// Create a test suite, which groups together logically related test methods -// (defined below). You can share common setup and teardown code here; see the -// package docs for more info. -type PeopleTest struct {} -func init() { ogletest.RegisterTestSuite(&PeopleTest{}) } - -func (t *PeopleTest) ReturnsCorrectNames() { - // Call the function a few times, and make sure it never strays from the set - // of expected names. - for i := 0; i < 25; i++ { - name, _ := GetRandomPerson() - ogletest.ExpectThat(name, oglematchers.AnyOf("Tony", "Dennis", "Scott")) - } -} - -func (t *PeopleTest) FormatsPhoneNumbersCorrectly() { - // Call the function a few times, and make sure it returns phone numbers in a - // standard US format. - for i := 0; i < 25; i++ { - _, phone := GetRandomPerson() - ogletest.ExpectThat(phone, oglematchers.MatchesRegexp(`^\(\d{3}\) \d{3}-\d{4}$`)) -} -``` - -Note that test control functions (`RunTests`, `ExpectThat`, and so on) are part -of the `ogletest` package, whereas built-in matchers (`AnyOf`, `MatchesRegexp`, -and more) are part of the [oglematchers][matcher-reference] library. You can of -course use dot imports so that you don't need to prefix each function with its -package name: - -```go -import ( - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) -``` - -If you save the test in a file whose name ends in `_test.go`, you can run your -tests by simply invoking the following in your package directory: - - go test - -Here's what the failure output of ogletest looks like, if your function's -implementation is bad. - - [----------] Running tests from PeopleTest - [ RUN ] PeopleTest.FormatsPhoneNumbersCorrectly - people_test.go:32: - Expected: matches regexp "^\(\d{3}\) \d{3}-\d{4}$" - Actual: +1 800 555 5555 - - [ FAILED ] PeopleTest.FormatsPhoneNumbersCorrectly - [ RUN ] PeopleTest.ReturnsCorrectNames - people_test.go:23: - Expected: or(Tony, Dennis, Scott) - Actual: Bart - - [ FAILED ] PeopleTest.ReturnsCorrectNames - [----------] Finished with tests from PeopleTest - -And if the test passes: - - [----------] Running tests from PeopleTest - [ RUN ] PeopleTest.FormatsPhoneNumbersCorrectly - [ OK ] PeopleTest.FormatsPhoneNumbersCorrectly - [ RUN ] PeopleTest.ReturnsCorrectNames - [ OK ] PeopleTest.ReturnsCorrectNames - [----------] Finished with tests from PeopleTest - - -[reference]: http://gopkgdoc.appspot.com/pkg/github.com/smartystreets/goconvey/convey/assertions/ogletest -[matcher-reference]: http://gopkgdoc.appspot.com/pkg/github.com/smartystreets/goconvey/convey/assertions/oglematchers -[golang-install]: http://golang.org/doc/install.html -[googletest]: http://code.google.com/p/googletest/ -[google-js-test]: http://code.google.com/p/google-js-test/ -[howtowrite]: http://golang.org/doc/code.html -[oglemock]: https://github.com/smartystreets/goconvey/convey/assertions/oglemock diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/assert_aliases.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/assert_aliases.go deleted file mode 100644 index a014d544de8..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/assert_aliases.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ogletest - -import ( - "github.com/smartystreets/goconvey/convey/assertions/oglematchers" -) - -// AssertEq(e, a) is equivalent to AssertThat(a, oglematchers.Equals(e)). -func AssertEq(expected, actual interface{}, errorParts ...interface{}) ExpectationResult { - res := ExpectThat(actual, oglematchers.Equals(expected), errorParts...) - res.SetCaller(getCallerForAlias()) - - matcherErr := res.MatchResult() - if matcherErr != nil { - panic(&assertThatError{}) - } - - return res -} - -// AssertNe(e, a) is equivalent to AssertThat(a, oglematchers.Not(oglematchers.Equals(e))). -func AssertNe(expected, actual interface{}, errorParts ...interface{}) ExpectationResult { - res := ExpectThat(actual, oglematchers.Not(oglematchers.Equals(expected)), errorParts...) - res.SetCaller(getCallerForAlias()) - - matcherErr := res.MatchResult() - if matcherErr != nil { - panic(&assertThatError{}) - } - - return res -} - -// AssertLt(x, y) is equivalent to AssertThat(x, oglematchers.LessThan(y)). -func AssertLt(x, y interface{}, errorParts ...interface{}) ExpectationResult { - res := ExpectThat(x, oglematchers.LessThan(y), errorParts...) - res.SetCaller(getCallerForAlias()) - - matcherErr := res.MatchResult() - if matcherErr != nil { - panic(&assertThatError{}) - } - - return res -} - -// AssertLe(x, y) is equivalent to AssertThat(x, oglematchers.LessOrEqual(y)). -func AssertLe(x, y interface{}, errorParts ...interface{}) ExpectationResult { - res := ExpectThat(x, oglematchers.LessOrEqual(y), errorParts...) - res.SetCaller(getCallerForAlias()) - - matcherErr := res.MatchResult() - if matcherErr != nil { - panic(&assertThatError{}) - } - - return res -} - -// AssertGt(x, y) is equivalent to AssertThat(x, oglematchers.GreaterThan(y)). -func AssertGt(x, y interface{}, errorParts ...interface{}) ExpectationResult { - res := ExpectThat(x, oglematchers.GreaterThan(y), errorParts...) - res.SetCaller(getCallerForAlias()) - - matcherErr := res.MatchResult() - if matcherErr != nil { - panic(&assertThatError{}) - } - - return res -} - -// AssertGe(x, y) is equivalent to AssertThat(x, oglematchers.GreaterOrEqual(y)). -func AssertGe(x, y interface{}, errorParts ...interface{}) ExpectationResult { - res := ExpectThat(x, oglematchers.GreaterOrEqual(y), errorParts...) - res.SetCaller(getCallerForAlias()) - - matcherErr := res.MatchResult() - if matcherErr != nil { - panic(&assertThatError{}) - } - - return res -} - -// AssertTrue(b) is equivalent to AssertThat(b, oglematchers.Equals(true)). -func AssertTrue(b interface{}, errorParts ...interface{}) ExpectationResult { - res := ExpectThat(b, oglematchers.Equals(true), errorParts...) - res.SetCaller(getCallerForAlias()) - - matcherErr := res.MatchResult() - if matcherErr != nil { - panic(&assertThatError{}) - } - - return res -} - -// AssertFalse(b) is equivalent to AssertThat(b, oglematchers.Equals(false)). -func AssertFalse(b interface{}, errorParts ...interface{}) ExpectationResult { - res := ExpectThat(b, oglematchers.Equals(false), errorParts...) - res.SetCaller(getCallerForAlias()) - - matcherErr := res.MatchResult() - if matcherErr != nil { - panic(&assertThatError{}) - } - - return res -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/assert_that.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/assert_that.go deleted file mode 100644 index 319abfc7479..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/assert_that.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ogletest - -import ( - "github.com/smartystreets/goconvey/convey/assertions/oglematchers" -) - -// AssertThat is identical to ExpectThat, except that in the event of failure -// it halts the currently running test immediately. It is thus useful for -// things like bounds checking: -// -// someSlice := [...] -// AssertEq(1, len(someSlice)) // Protects next line from panicking. -// ExpectEq("taco", someSlice[0]) -// -func AssertThat( - x interface{}, - m oglematchers.Matcher, - errorParts ...interface{}) ExpectationResult { - res := ExpectThat(x, m, errorParts...) - res.SetCaller(getCallerForAlias()) - - matcherErr := res.MatchResult() - if matcherErr != nil { - panic(&assertThatError{}) - } - - return res -} - -// assertThatError is a sentinel type that is used in a conspiracy between -// AssertThat and runTests. If runTests sees a *assertThatError as the value -// given to a panic() call, it will avoid printing the panic error. -type assertThatError struct { -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/doc.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/doc.go deleted file mode 100644 index bf6507fae4d..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/doc.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package ogletest provides a framework for writing expressive unit tests. It -// integrates with the builtin testing package, so it works with the gotest -// command. Unlike the testing package which offers only basic capabilities for -// signalling failures, it offers ways to express expectations and get nice -// failure messages automatically. -// -// For example: -// -// //////////////////////////////////////////////////////////////////////// -// // testing package test -// //////////////////////////////////////////////////////////////////////// -// -// someStr, err := ComputeSomeString() -// if err != nil { -// t.Errorf("ComputeSomeString: expected nil error, got %v", err) -// } -// -// !strings.Contains(someStr, "foo") { -// t.Errorf("ComputeSomeString: expected substring foo, got %v", someStr) -// } -// -// //////////////////////////////////////////////////////////////////////// -// // ogletest test -// //////////////////////////////////////////////////////////////////////// -// -// someStr, err := ComputeSomeString() -// ExpectEq(nil, err) -// ExpectThat(someStr, HasSubstr("foo") -// -// Failure messages require no work from the user, and look like the following: -// -// foo_test.go:103: -// Expected: has substring "foo" -// Actual: "bar baz" -// -package ogletest diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/expect_aliases.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/expect_aliases.go deleted file mode 100644 index 050ae10466b..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/expect_aliases.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ogletest - -import ( - "path" - "runtime" - - "github.com/smartystreets/goconvey/convey/assertions/oglematchers" -) - -func getCallerForAlias() (fileName string, lineNumber int) { - _, fileName, lineNumber, _ = runtime.Caller(2) - fileName = path.Base(fileName) - return -} - -// ExpectEq(e, a) is equivalent to ExpectThat(a, oglematchers.Equals(e)). -func ExpectEq(expected, actual interface{}, errorParts ...interface{}) ExpectationResult { - res := ExpectThat(actual, oglematchers.Equals(expected), errorParts...) - res.SetCaller(getCallerForAlias()) - return res -} - -// ExpectNe(e, a) is equivalent to ExpectThat(a, oglematchers.Not(oglematchers.Equals(e))). -func ExpectNe(expected, actual interface{}, errorParts ...interface{}) ExpectationResult { - res := ExpectThat(actual, oglematchers.Not(oglematchers.Equals(expected)), errorParts...) - res.SetCaller(getCallerForAlias()) - return res -} - -// ExpectLt(x, y) is equivalent to ExpectThat(x, oglematchers.LessThan(y)). -func ExpectLt(x, y interface{}, errorParts ...interface{}) ExpectationResult { - res := ExpectThat(x, oglematchers.LessThan(y), errorParts...) - res.SetCaller(getCallerForAlias()) - return res -} - -// ExpectLe(x, y) is equivalent to ExpectThat(x, oglematchers.LessOrEqual(y)). -func ExpectLe(x, y interface{}, errorParts ...interface{}) ExpectationResult { - res := ExpectThat(x, oglematchers.LessOrEqual(y), errorParts...) - res.SetCaller(getCallerForAlias()) - return res -} - -// ExpectGt(x, y) is equivalent to ExpectThat(x, oglematchers.GreaterThan(y)). -func ExpectGt(x, y interface{}, errorParts ...interface{}) ExpectationResult { - res := ExpectThat(x, oglematchers.GreaterThan(y), errorParts...) - res.SetCaller(getCallerForAlias()) - return res -} - -// ExpectGe(x, y) is equivalent to ExpectThat(x, oglematchers.GreaterOrEqual(y)). -func ExpectGe(x, y interface{}, errorParts ...interface{}) ExpectationResult { - res := ExpectThat(x, oglematchers.GreaterOrEqual(y), errorParts...) - res.SetCaller(getCallerForAlias()) - return res -} - -// ExpectTrue(b) is equivalent to ExpectThat(b, oglematchers.Equals(true)). -func ExpectTrue(b interface{}, errorParts ...interface{}) ExpectationResult { - res := ExpectThat(b, oglematchers.Equals(true), errorParts...) - res.SetCaller(getCallerForAlias()) - return res -} - -// ExpectFalse(b) is equivalent to ExpectThat(b, oglematchers.Equals(false)). -func ExpectFalse(b interface{}, errorParts ...interface{}) ExpectationResult { - res := ExpectThat(b, oglematchers.Equals(false), errorParts...) - res.SetCaller(getCallerForAlias()) - return res -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/expect_call.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/expect_call.go deleted file mode 100644 index 8bb8101d569..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/expect_call.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ogletest - -import ( - "runtime" - - "github.com/smartystreets/goconvey/convey/assertions/oglemock" -) - -// ExpectCall expresses an expectation that the method of the given name -// should be called on the supplied mock object. It returns a function that -// should be called with the expected arguments, matchers for the arguments, -// or a mix of both. -// -// For example: -// -// mockWriter := [...] -// ogletest.ExpectCall(mockWriter, "Write")(oglematchers.ElementsAre(0x1)) -// .WillOnce(oglemock.Return(1, nil)) -// -// This is a shortcut for calling i.MockController.ExpectCall, where i is the -// TestInfo struct for the currently-running test. Unlike that direct approach, -// this function automatically sets the correct file name and line number for -// the expectation. -func ExpectCall(o oglemock.MockObject, method string) oglemock.PartialExpecation { - // Get information about the call site. - _, file, lineNumber, ok := runtime.Caller(1) - if !ok { - panic("ExpectCall: runtime.Caller") - } - - // Grab the current test info. - info := currentlyRunningTest - if info == nil { - panic("ExpectCall: no test info.") - } - - // Grab the mock controller. - controller := currentlyRunningTest.MockController - if controller == nil { - panic("ExpectCall: no mock controller.") - } - - // Report the expectation. - return controller.ExpectCall(o, method, file, lineNumber) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/expect_that.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/expect_that.go deleted file mode 100644 index c0adc5aa6cf..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/expect_that.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ogletest - -import ( - "fmt" - "path" - "reflect" - "runtime" - - "github.com/smartystreets/goconvey/convey/assertions/oglematchers" -) - -// ExpectationResult is an interface returned by ExpectThat that allows callers -// to get information about the result of the expectation and set their own -// custom information. This is not useful to the average consumer, but may be -// helpful if you're writing widely used test utility functions. -type ExpectationResult interface { - // SetCaller updates the file name and line number associated with the - // expectation. This allows, for example, a utility function to express that - // *its* caller should have its line number printed if the expectation fails, - // instead of the line number of the ExpectThat call within the utility - // function. - SetCaller(fileName string, lineNumber int) - - // MatchResult returns the result returned by the expectation's matcher for - // the supplied candidate. - MatchResult() error -} - -// ExpectThat confirms that the supplied matcher matches the value x, adding a -// failure record to the currently running test if it does not. If additional -// parameters are supplied, the first will be used as a format string for the -// later ones, and the user-supplied error message will be added to the test -// output in the event of a failure. -// -// For example: -// -// ExpectThat(userName, Equals("jacobsa")) -// ExpectThat(users[i], Equals("jacobsa"), "while processing user %d", i) -// -func ExpectThat( - x interface{}, - m oglematchers.Matcher, - errorParts ...interface{}) ExpectationResult { - res := &expectationResultImpl{} - - // Get information about the call site. - _, file, lineNumber, ok := runtime.Caller(1) - if !ok { - panic("ExpectThat: runtime.Caller") - } - - // Assemble the user error, if any. - userError := "" - if len(errorParts) != 0 { - v := reflect.ValueOf(errorParts[0]) - if v.Kind() != reflect.String { - panic(fmt.Sprintf("ExpectThat: invalid format string type %v", v.Kind())) - } - - userError = fmt.Sprintf(v.String(), errorParts[1:]...) - } - - // Grab the current test info. - info := currentlyRunningTest - if info == nil { - panic("ExpectThat: no test info.") - } - - // Check whether the value matches. - matcherErr := m.Matches(x) - res.matchError = matcherErr - - // Return immediately on success. - if matcherErr == nil { - return res - } - - // Form an appropriate failure message. Make sure that the expected and - // actual values align properly. - var record failureRecord - relativeClause := "" - if matcherErr.Error() != "" { - relativeClause = fmt.Sprintf(", %s", matcherErr.Error()) - } - - record.GeneratedError = fmt.Sprintf( - "Expected: %s\nActual: %v%s", - m.Description(), - x, - relativeClause) - - // Record additional failure info. - record.FileName = path.Base(file) - record.LineNumber = lineNumber - record.UserError = userError - - // Store the failure. - info.mutex.Lock() - defer info.mutex.Unlock() - - info.failureRecords = append(info.failureRecords, &record) - res.failureRecord = &record - - return res -} - -type expectationResultImpl struct { - // The failure record created by the expectation, or nil if none. - failureRecord *failureRecord - - // The result of the matcher. - matchError error -} - -func (r *expectationResultImpl) SetCaller(fileName string, lineNumber int) { - if r.failureRecord == nil { - return - } - - r.failureRecord.FileName = fileName - r.failureRecord.LineNumber = lineNumber -} - -func (r *expectationResultImpl) MatchResult() error { - return r.matchError -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/methods.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/methods.go deleted file mode 100644 index ad58dd840d4..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/methods.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ogletest - -import ( - "fmt" - "reflect" - "runtime" - "sort" -) - -func getLine(m reflect.Method) int { - pc := m.Func.Pointer() - - f := runtime.FuncForPC(pc) - if f == nil { - panic(fmt.Sprintf("Couldn't get runtime func for method (pc=%d): %v", pc, m)) - } - - _, line := f.FileLine(pc) - return line -} - -type sortableMethodSet []reflect.Method - -func (s sortableMethodSet) Len() int { - return len(s) -} - -func (s sortableMethodSet) Less(i, j int) bool { - return getLine(s[i]) < getLine(s[j]) -} - -func (s sortableMethodSet) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Given a type t, return all of the methods of t sorted such that source file -// order is preserved. Order across files is undefined. Order within lines is -// undefined. -func getMethodsInSourceOrder(t reflect.Type) []reflect.Method { - // Build the list of methods. - methods := sortableMethodSet{} - for i := 0; i < t.NumMethod(); i++ { - methods = append(methods, t.Method(i)) - } - - // Sort it. - sort.Sort(methods) - - return methods -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/ogletest.goconvey b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/ogletest.goconvey deleted file mode 100644 index 79982854b53..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/ogletest.goconvey +++ /dev/null @@ -1,2 +0,0 @@ -#ignore --timeout=1s diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/register_test_suite.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/register_test_suite.go deleted file mode 100644 index 0e253a2c162..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/register_test_suite.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ogletest - -// RegisterTestSuite tells ogletest about a test suite containing tests that it -// should run. Any exported method on the type pointed to by the supplied -// prototype value will be treated as test methods, with the exception of the -// following methods (which need not be present): -// -// * SetUpTestSuite() -- called exactly once, before the first test method is -// run. The receiver of this method will be a zero value of the test suite -// type, and is not shared with any other methods. Use this method to set -// up any necessary global state shared by all of the test methods. -// -// * TearDownTestSuite() -- called exactly once, after the last test method -// is run. The receiver of this method will be a zero value of the test -// suite type, and is not shared with any other methods. Use this method to -// clean up after any necessary global state shared by all of the test -// methods. -// -// * SetUp(testInfo) -- called before each test method is invoked, with the -// same receiver as that test method, and with a TestInfo arg. At the time -// this method is invoked, the receiver is a zero value for the test suite -// type. Use this method for common setup code that works on data not -// shared across tests. -// -// * TearDown() -- called after each test method is invoked, with the same -// receiver as that test method. Use this method for common cleanup code -// that works on data not shared across tests. -// -// Each test method is invoked on a different receiver, which is initially a -// zero value of the test suite type. -// -// Example: -// -// // Some value that is needed by the tests but is expensive to compute. -// var someExpensiveThing uint -// -// type FooTest struct { -// // Path to a temporary file used by the tests. Each test gets a -// // different temporary file. -// tempFile string -// } -// func init() { ogletest.RegisterTestSuite(&FooTest{}) } -// -// func (t *FooTest) SetUpTestSuite() { -// someExpensiveThing = ComputeSomeExpensiveThing() -// } -// -// func (t *FooTest) SetUp() { -// t.tempFile = CreateTempFile() -// } -// -// func (t *FooTest) TearDown() { -// DeleteTempFile(t.tempFile) -// } -// -// func (t *FooTest) FrobinicatorIsSuccessfullyTweaked() { -// res := DoSomethingWithExpensiveThing(someExpensiveThing, t.tempFile) -// ExpectThat(res, Equals(true)) -// } -// -func RegisterTestSuite(p interface{}) { - if p == nil { - panic("RegisterTestSuite called with nil suite.") - } - - testSuites = append(testSuites, p) -} - -// The set of test suites previously registered. -var testSuites = make([]interface{}, 0) diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/run_tests.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/run_tests.go deleted file mode 100644 index 75e0f0a262b..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/run_tests.go +++ /dev/null @@ -1,336 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ogletest - -import ( - "bytes" - "flag" - "fmt" - "path" - "reflect" - "regexp" - "runtime" - "sync" - "testing" - "time" -) - -var testFilter = flag.String("ogletest.run", "", "Regexp for matching tests to run.") - -// runTestsOnce protects RunTests from executing multiple times. -var runTestsOnce sync.Once - -func isAssertThatError(x interface{}) bool { - _, ok := x.(*assertThatError) - return ok -} - -// runTest runs a single test, returning a slice of failure records for that test. -func runTest(suite interface{}, method reflect.Method) (failures []*failureRecord) { - suiteValue := reflect.ValueOf(suite) - suiteType := suiteValue.Type() - - // Set up a clean slate for this test. Make sure to reset it after everything - // below is finished, so we don't accidentally use it elsewhere. - currentlyRunningTest = newTestInfo() - defer func() { - currentlyRunningTest = nil - }() - - // Create a receiver. - suiteInstance := reflect.New(suiteType.Elem()) - - // Run the SetUp method, paying attention to whether it panics. - setUpPanicked := runWithProtection( - func() { - runMethodIfExists(suiteInstance, "SetUp", currentlyRunningTest) - }, - ) - - // Run the test method itself, but only if the SetUp method didn't panic. - // (This includes AssertThat errors.) - if !setUpPanicked { - runWithProtection( - func() { - runMethodIfExists(suiteInstance, method.Name) - }, - ) - } - - // Run the TearDown method unconditionally. - runWithProtection( - func() { - runMethodIfExists(suiteInstance, "TearDown") - }, - ) - - // Tell the mock controller for the tests to report any errors it's sitting - // on. - currentlyRunningTest.MockController.Finish() - - return currentlyRunningTest.failureRecords -} - -// RunTests runs the test suites registered with ogletest, communicating -// failures to the supplied testing.T object. This is the bridge between -// ogletest and the testing package (and gotest); you should ensure that it's -// called at least once by creating a gotest-compatible test function and -// calling it there. -// -// For example: -// -// import ( -// "github.com/smartystreets/goconvey/convey/assertions/ogletest" -// "testing" -// ) -// -// func TestOgletest(t *testing.T) { -// ogletest.RunTests(t) -// } -// -func RunTests(t *testing.T) { - runTestsOnce.Do(func() { runTestsInternal(t) }) -} - -// runTestsInternal does the real work of RunTests, which simply wraps it in a -// sync.Once. -func runTestsInternal(t *testing.T) { - // Process each registered suite. - for _, suite := range testSuites { - val := reflect.ValueOf(suite) - typ := val.Type() - suiteName := typ.Elem().Name() - - // Grab methods for the suite, filtering them to just the ones that we - // don't need to skip. - testMethods := filterMethods(suiteName, getMethodsInSourceOrder(typ)) - - // Is there anything left to do? - if len(testMethods) == 0 { - continue - } - - fmt.Printf("[----------] Running tests from %s\n", suiteName) - - // Run the SetUpTestSuite method, if any. - runMethodIfExists(val, "SetUpTestSuite") - - // Run each method. - for _, method := range testMethods { - // Print a banner for the start of this test. - fmt.Printf("[ RUN ] %s.%s\n", suiteName, method.Name) - - // Run the test. - startTime := time.Now() - failures := runTest(suite, method) - runDuration := time.Since(startTime) - - // Print any failures, and mark the test as having failed if there are any. - for _, record := range failures { - t.Fail() - userErrorSection := "" - if record.UserError != "" { - userErrorSection = record.UserError + "\n" - } - - fmt.Printf( - "%s:%d:\n%s\n%s\n", - record.FileName, - record.LineNumber, - record.GeneratedError, - userErrorSection) - } - - // Print a banner for the end of the test. - bannerMessage := "[ OK ]" - if len(failures) != 0 { - bannerMessage = "[ FAILED ]" - } - - // Print a summary of the time taken, if long enough. - var timeMessage string - if runDuration >= 25*time.Millisecond { - timeMessage = fmt.Sprintf(" (%s)", runDuration.String()) - } - - fmt.Printf( - "%s %s.%s%s\n", - bannerMessage, - suiteName, - method.Name, - timeMessage) - } - - // Run the TearDownTestSuite method, if any. - runMethodIfExists(val, "TearDownTestSuite") - - fmt.Printf("[----------] Finished with tests from %s\n", suiteName) - } -} - -// Run the supplied function, catching panics (including AssertThat errors) and -// reporting them to the currently-running test as appropriate. Return true iff -// the function panicked. -func runWithProtection(f func()) (panicked bool) { - defer func() { - // If the test didn't panic, we're done. - r := recover() - if r == nil { - return - } - - panicked = true - - // We modify the currently running test below. - currentlyRunningTest.mutex.Lock() - defer currentlyRunningTest.mutex.Unlock() - - // If the function panicked (and the panic was not due to an AssertThat - // failure), add a failure for the panic. - if !isAssertThatError(r) { - // The stack looks like this: - // - // - // panic(r) - // - // - _, fileName, lineNumber, ok := runtime.Caller(2) - var panicRecord failureRecord - if ok { - panicRecord.FileName = path.Base(fileName) - panicRecord.LineNumber = lineNumber - } - - panicRecord.GeneratedError = fmt.Sprintf( - "panic: %v\n\n%s", r, formatPanicStack()) - - currentlyRunningTest.failureRecords = append( - currentlyRunningTest.failureRecords, - &panicRecord) - } - }() - - f() - return -} - -func runMethodIfExists(v reflect.Value, name string, args ...interface{}) { - method := v.MethodByName(name) - if method.Kind() == reflect.Invalid { - return - } - - if method.Type().NumIn() != len(args) { - panic(fmt.Sprintf( - "%s: expected %d args, actually %d.", - name, - len(args), - method.Type().NumIn())) - } - - // Create a slice of reflect.Values to pass to the method. Simultaneously - // check types. - argVals := make([]reflect.Value, len(args)) - for i, arg := range args { - argVal := reflect.ValueOf(arg) - - if argVal.Type() != method.Type().In(i) { - panic(fmt.Sprintf( - "%s: expected arg %d to have type %v.", - name, - i, - argVal.Type())) - } - - argVals[i] = argVal - } - - method.Call(argVals) -} - -func formatPanicStack() string { - buf := new(bytes.Buffer) - - // Walk the stack from top to bottom. - panicPassed := false - for i := 0; ; i++ { - pc, file, line, ok := runtime.Caller(i) - if !ok { - break - } - - // Choose a function name to display. - funcName := "(unknown)" - if f := runtime.FuncForPC(pc); f != nil { - funcName = f.Name() - } - - // Avoid stack frames at panic and above. - if funcName == "runtime.panic" { - panicPassed = true - continue - } - - if !panicPassed { - continue - } - - // Stop if we've gotten as far as the test runner code. - if funcName == "github.com/smartystreets/goconvey/convey/assertions/ogletest.runMethodIfExists" { - break - } - - // Add an entry for this frame. - fmt.Fprintf(buf, "%s\n\t%s:%d\n", funcName, file, line) - } - - return buf.String() -} - -func filterMethods(suiteName string, in []reflect.Method) (out []reflect.Method) { - for _, m := range in { - // Skip set up, tear down, and unexported methods. - if isSpecialMethod(m.Name) || !isExportedMethod(m.Name) { - continue - } - - // Has the user told us to skip this method? - fullName := fmt.Sprintf("%s.%s", suiteName, m.Name) - matched, err := regexp.MatchString(*testFilter, fullName) - if err != nil { - panic("Invalid value for --ogletest.run: " + err.Error()) - } - - if !matched { - continue - } - - out = append(out, m) - } - - return -} - -func isSpecialMethod(name string) bool { - return (name == "SetUpTestSuite") || - (name == "TearDownTestSuite") || - (name == "SetUp") || - (name == "TearDown") -} - -func isExportedMethod(name string) bool { - return len(name) > 0 && name[0] >= 'A' && name[0] <= 'Z' -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/failing.test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/failing.test.go deleted file mode 100644 index 6cfa4d81cc8..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/failing.test.go +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "fmt" - "testing" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -func TestFailingTest(t *testing.T) { RunTests(t) } - -//////////////////////////////////////////////////////////////////////// -// Usual failures -//////////////////////////////////////////////////////////////////////// - -type FailingTest struct { -} - -func init() { RegisterTestSuite(&FailingTest{}) } - -func (t *FailingTest) TearDown() { - fmt.Println("TearDown running.") -} - -func (t *FailingTest) PassingMethod() { -} - -func (t *FailingTest) Equals() { - ExpectThat(17, Equals(17.5)) - ExpectThat(17, Equals("taco")) -} - -func (t *FailingTest) LessThan() { - ExpectThat(18, LessThan(17)) - ExpectThat(18, LessThan("taco")) -} - -func (t *FailingTest) HasSubstr() { - ExpectThat("taco", HasSubstr("ac")) - ExpectThat(17, HasSubstr("ac")) -} - -func (t *FailingTest) ExpectWithUserErrorMessages() { - ExpectThat(17, Equals(19), "foo bar: %d", 112) - ExpectEq(17, 17.5, "foo bar: %d", 112) - ExpectLe(17, 16.9, "foo bar: %d", 112) - ExpectLt(17, 16.9, "foo bar: %d", 112) - ExpectGe(17, 17.1, "foo bar: %d", 112) - ExpectGt(17, "taco", "foo bar: %d", 112) - ExpectNe(17, 17.0, "foo bar: %d", 112) - ExpectFalse(true, "foo bar: %d", 112) - ExpectTrue(false, "foo bar: %d", 112) -} - -func (t *FailingTest) AssertWithUserErrorMessages() { - AssertThat(17, Equals(19), "foo bar: %d", 112) -} - -func (t *FailingTest) ModifiedExpectation() { - ExpectThat(17, HasSubstr("ac")).SetCaller("foo.go", 112) - ExpectEq(17, 19).SetCaller("bar.go", 117) -} - -func (t *FailingTest) ExpectationAliases() { - ExpectEq(17, 17.5) - ExpectEq("taco", 17.5) - - ExpectLe(17, 16.9) - ExpectLt(17, 16.9) - ExpectLt(17, "taco") - - ExpectGe(17, 17.1) - ExpectGt(17, 17.1) - ExpectGt(17, "taco") - - ExpectNe(17, 17.0) - ExpectNe(17, "taco") - - ExpectFalse(true) - ExpectFalse("taco") - - ExpectTrue(false) - ExpectTrue("taco") -} - -func (t *FailingTest) AssertThatFailure() { - AssertThat(17, Equals(19)) - panic("Shouldn't get here.") -} - -func (t *FailingTest) AssertEqFailure() { - AssertEq(19, 17) - panic("Shouldn't get here.") -} - -func (t *FailingTest) AssertNeFailure() { - AssertNe(19, 19) - panic("Shouldn't get here.") -} - -func (t *FailingTest) AssertLeFailure() { - AssertLe(19, 17) - panic("Shouldn't get here.") -} - -func (t *FailingTest) AssertLtFailure() { - AssertLt(19, 17) - panic("Shouldn't get here.") -} - -func (t *FailingTest) AssertGeFailure() { - AssertGe(17, 19) - panic("Shouldn't get here.") -} - -func (t *FailingTest) AssertGtFailure() { - AssertGt(17, 19) - panic("Shouldn't get here.") -} - -func (t *FailingTest) AssertTrueFailure() { - AssertTrue("taco") - panic("Shouldn't get here.") -} - -func (t *FailingTest) AssertFalseFailure() { - AssertFalse("taco") - panic("Shouldn't get here.") -} - -//////////////////////////////////////////////////////////////////////// -// Expectation failure during SetUp -//////////////////////////////////////////////////////////////////////// - -type ExpectFailDuringSetUpTest struct { -} - -func init() { RegisterTestSuite(&ExpectFailDuringSetUpTest{}) } - -func (t *ExpectFailDuringSetUpTest) SetUp(i *TestInfo) { - ExpectFalse(true) -} - -func (t *ExpectFailDuringSetUpTest) TearDown() { - fmt.Println("TearDown running.") -} - -func (t *ExpectFailDuringSetUpTest) PassingMethod() { - fmt.Println("Method running.") -} - -//////////////////////////////////////////////////////////////////////// -// Assertion failure during SetUp -//////////////////////////////////////////////////////////////////////// - -type AssertFailDuringSetUpTest struct { -} - -func init() { RegisterTestSuite(&AssertFailDuringSetUpTest{}) } - -func (t *AssertFailDuringSetUpTest) SetUp(i *TestInfo) { - AssertFalse(true) -} - -func (t *AssertFailDuringSetUpTest) TearDown() { - fmt.Println("TearDown running.") -} - -func (t *AssertFailDuringSetUpTest) PassingMethod() { - fmt.Println("Method running.") -} - -//////////////////////////////////////////////////////////////////////// -// Expectation failure during TearDown -//////////////////////////////////////////////////////////////////////// - -type ExpectFailDuringTearDownTest struct { -} - -func init() { RegisterTestSuite(&ExpectFailDuringTearDownTest{}) } - -func (t *ExpectFailDuringTearDownTest) SetUp(i *TestInfo) { - fmt.Println("SetUp running.") -} - -func (t *ExpectFailDuringTearDownTest) TearDown() { - ExpectFalse(true) -} - -func (t *ExpectFailDuringTearDownTest) PassingMethod() { - fmt.Println("Method running.") -} - -//////////////////////////////////////////////////////////////////////// -// Assertion failure during TearDown -//////////////////////////////////////////////////////////////////////// - -type AssertFailDuringTearDownTest struct { -} - -func init() { RegisterTestSuite(&AssertFailDuringTearDownTest{}) } - -func (t *AssertFailDuringTearDownTest) SetUp(i *TestInfo) { - fmt.Println("SetUp running.") -} - -func (t *AssertFailDuringTearDownTest) TearDown() { - AssertFalse(true) -} - -func (t *AssertFailDuringTearDownTest) PassingMethod() { - fmt.Println("Method running.") -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/filtered.test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/filtered.test.go deleted file mode 100644 index 64e97a5bb8f..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/filtered.test.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "fmt" - "testing" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -func TestFiltered(t *testing.T) { RunTests(t) } - -//////////////////////////////////////////////////////////////////////// -// Partially filtered out -//////////////////////////////////////////////////////////////////////// - -type PartiallyFilteredTest struct { -} - -func init() { RegisterTestSuite(&PartiallyFilteredTest{}) } - -func (t *PartiallyFilteredTest) PassingTestFoo() { - ExpectThat(19, Equals(19)) -} - -func (t *PartiallyFilteredTest) PassingTestBar() { - ExpectThat(17, Equals(17)) -} - -func (t *PartiallyFilteredTest) PartiallyFilteredTestFoo() { - ExpectThat(18, LessThan(17)) -} - -func (t *PartiallyFilteredTest) PartiallyFilteredTestBar() { - ExpectThat("taco", HasSubstr("blah")) -} - -func (t *PartiallyFilteredTest) PartiallyFilteredTestBaz() { - ExpectThat(18, LessThan(17)) -} - -//////////////////////////////////////////////////////////////////////// -// Completely filtered out -//////////////////////////////////////////////////////////////////////// - -type CompletelyFilteredTest struct { -} - -func init() { RegisterTestSuite(&CompletelyFilteredTest{}) } - -func (t *CompletelyFilteredTest) SetUpTestSuite() { - fmt.Println("SetUpTestSuite run!") -} - -func (t *CompletelyFilteredTest) TearDownTestSuite() { - fmt.Println("TearDownTestSuite run!") -} - -func (t *PartiallyFilteredTest) SomePassingTest() { - ExpectThat(19, Equals(19)) -} - -func (t *PartiallyFilteredTest) SomeFailingTest() { - ExpectThat(19, Equals(17)) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.failing_test b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.failing_test deleted file mode 100644 index de89466fb7d..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.failing_test +++ /dev/null @@ -1,266 +0,0 @@ -[----------] Running tests from FailingTest -[ RUN ] FailingTest.PassingMethod -TearDown running. -[ OK ] FailingTest.PassingMethod -[ RUN ] FailingTest.Equals -TearDown running. -failing_test.go:44: -Expected: 17.5 -Actual: 17 - -failing_test.go:45: -Expected: taco -Actual: 17, which is not a string - -[ FAILED ] FailingTest.Equals -[ RUN ] FailingTest.LessThan -TearDown running. -failing_test.go:49: -Expected: less than 17 -Actual: 18 - -failing_test.go:50: -Expected: less than "taco" -Actual: 18, which is not comparable - -[ FAILED ] FailingTest.LessThan -[ RUN ] FailingTest.HasSubstr -TearDown running. -failing_test.go:55: -Expected: has substring "ac" -Actual: 17, which is not a string - -[ FAILED ] FailingTest.HasSubstr -[ RUN ] FailingTest.ExpectWithUserErrorMessages -TearDown running. -failing_test.go:59: -Expected: 19 -Actual: 17 -foo bar: 112 - -failing_test.go:60: -Expected: 17 -Actual: 17.5 -foo bar: 112 - -failing_test.go:61: -Expected: less than or equal to 16.9 -Actual: 17 -foo bar: 112 - -failing_test.go:62: -Expected: less than 16.9 -Actual: 17 -foo bar: 112 - -failing_test.go:63: -Expected: greater than or equal to 17.1 -Actual: 17 -foo bar: 112 - -failing_test.go:64: -Expected: greater than "taco" -Actual: 17, which is not comparable -foo bar: 112 - -failing_test.go:65: -Expected: not(17) -Actual: 17 -foo bar: 112 - -failing_test.go:66: -Expected: false -Actual: true -foo bar: 112 - -failing_test.go:67: -Expected: true -Actual: false -foo bar: 112 - -[ FAILED ] FailingTest.ExpectWithUserErrorMessages -[ RUN ] FailingTest.AssertWithUserErrorMessages -TearDown running. -failing_test.go:71: -Expected: 19 -Actual: 17 -foo bar: 112 - -[ FAILED ] FailingTest.AssertWithUserErrorMessages -[ RUN ] FailingTest.ModifiedExpectation -TearDown running. -foo.go:112: -Expected: has substring "ac" -Actual: 17, which is not a string - -bar.go:117: -Expected: 17 -Actual: 19 - -[ FAILED ] FailingTest.ModifiedExpectation -[ RUN ] FailingTest.ExpectationAliases -TearDown running. -failing_test.go:80: -Expected: 17 -Actual: 17.5 - -failing_test.go:81: -Expected: taco -Actual: 17.5, which is not a string - -failing_test.go:83: -Expected: less than or equal to 16.9 -Actual: 17 - -failing_test.go:84: -Expected: less than 16.9 -Actual: 17 - -failing_test.go:85: -Expected: less than "taco" -Actual: 17, which is not comparable - -failing_test.go:87: -Expected: greater than or equal to 17.1 -Actual: 17 - -failing_test.go:88: -Expected: greater than 17.1 -Actual: 17 - -failing_test.go:89: -Expected: greater than "taco" -Actual: 17, which is not comparable - -failing_test.go:91: -Expected: not(17) -Actual: 17 - -failing_test.go:92: -Expected: not(17) -Actual: taco, which is not numeric - -failing_test.go:94: -Expected: false -Actual: true - -failing_test.go:95: -Expected: false -Actual: taco, which is not a bool - -failing_test.go:97: -Expected: true -Actual: false - -failing_test.go:98: -Expected: true -Actual: taco, which is not a bool - -[ FAILED ] FailingTest.ExpectationAliases -[ RUN ] FailingTest.AssertThatFailure -TearDown running. -failing_test.go:102: -Expected: 19 -Actual: 17 - -[ FAILED ] FailingTest.AssertThatFailure -[ RUN ] FailingTest.AssertEqFailure -TearDown running. -failing_test.go:107: -Expected: 19 -Actual: 17 - -[ FAILED ] FailingTest.AssertEqFailure -[ RUN ] FailingTest.AssertNeFailure -TearDown running. -failing_test.go:112: -Expected: not(19) -Actual: 19 - -[ FAILED ] FailingTest.AssertNeFailure -[ RUN ] FailingTest.AssertLeFailure -TearDown running. -failing_test.go:117: -Expected: less than or equal to 17 -Actual: 19 - -[ FAILED ] FailingTest.AssertLeFailure -[ RUN ] FailingTest.AssertLtFailure -TearDown running. -failing_test.go:122: -Expected: less than 17 -Actual: 19 - -[ FAILED ] FailingTest.AssertLtFailure -[ RUN ] FailingTest.AssertGeFailure -TearDown running. -failing_test.go:127: -Expected: greater than or equal to 19 -Actual: 17 - -[ FAILED ] FailingTest.AssertGeFailure -[ RUN ] FailingTest.AssertGtFailure -TearDown running. -failing_test.go:132: -Expected: greater than 19 -Actual: 17 - -[ FAILED ] FailingTest.AssertGtFailure -[ RUN ] FailingTest.AssertTrueFailure -TearDown running. -failing_test.go:137: -Expected: true -Actual: taco, which is not a bool - -[ FAILED ] FailingTest.AssertTrueFailure -[ RUN ] FailingTest.AssertFalseFailure -TearDown running. -failing_test.go:142: -Expected: false -Actual: taco, which is not a bool - -[ FAILED ] FailingTest.AssertFalseFailure -[----------] Finished with tests from FailingTest -[----------] Running tests from ExpectFailDuringSetUpTest -[ RUN ] ExpectFailDuringSetUpTest.PassingMethod -Method running. -TearDown running. -failing_test.go:156: -Expected: false -Actual: true - -[ FAILED ] ExpectFailDuringSetUpTest.PassingMethod -[----------] Finished with tests from ExpectFailDuringSetUpTest -[----------] Running tests from AssertFailDuringSetUpTest -[ RUN ] AssertFailDuringSetUpTest.PassingMethod -TearDown running. -failing_test.go:177: -Expected: false -Actual: true - -[ FAILED ] AssertFailDuringSetUpTest.PassingMethod -[----------] Finished with tests from AssertFailDuringSetUpTest -[----------] Running tests from ExpectFailDuringTearDownTest -[ RUN ] ExpectFailDuringTearDownTest.PassingMethod -SetUp running. -Method running. -failing_test.go:202: -Expected: false -Actual: true - -[ FAILED ] ExpectFailDuringTearDownTest.PassingMethod -[----------] Finished with tests from ExpectFailDuringTearDownTest -[----------] Running tests from AssertFailDuringTearDownTest -[ RUN ] AssertFailDuringTearDownTest.PassingMethod -SetUp running. -Method running. -failing_test.go:223: -Expected: false -Actual: true - -[ FAILED ] AssertFailDuringTearDownTest.PassingMethod -[----------] Finished with tests from AssertFailDuringTearDownTest ---- FAIL: somepkg (1.23 seconds) -FAIL -exit status 1 -FAIL somepkg 1.234s diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.filtered_test b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.filtered_test deleted file mode 100644 index 9e99dc38d49..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.filtered_test +++ /dev/null @@ -1,20 +0,0 @@ -[----------] Running tests from PartiallyFilteredTest -[ RUN ] PartiallyFilteredTest.PassingTestBar -[ OK ] PartiallyFilteredTest.PassingTestBar -[ RUN ] PartiallyFilteredTest.PartiallyFilteredTestBar -filtered_test.go:49: -Expected: has substring "blah" -Actual: taco - -[ FAILED ] PartiallyFilteredTest.PartiallyFilteredTestBar -[ RUN ] PartiallyFilteredTest.PartiallyFilteredTestBaz -filtered_test.go:53: -Expected: less than 17 -Actual: 18 - -[ FAILED ] PartiallyFilteredTest.PartiallyFilteredTestBaz -[----------] Finished with tests from PartiallyFilteredTest ---- FAIL: somepkg (1.23 seconds) -FAIL -exit status 1 -FAIL somepkg 1.234s diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.mock_test b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.mock_test deleted file mode 100644 index e9f3b11bc13..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.mock_test +++ /dev/null @@ -1,25 +0,0 @@ -[----------] Running tests from MockTest -[ RUN ] MockTest.ExpectationSatisfied -[ OK ] MockTest.ExpectationSatisfied -[ RUN ] MockTest.MockExpectationNotSatisfied -/some/path/mock_test.go:56: -Unsatisfied expectation; expected At to be called at least 1 times; called 0 times. - -[ FAILED ] MockTest.MockExpectationNotSatisfied -[ RUN ] MockTest.ExpectCallForUnknownMethod -/some/path/mock_test.go:61: -Unknown method: FooBar - -[ FAILED ] MockTest.ExpectCallForUnknownMethod -[ RUN ] MockTest.UnexpectedCall -/some/path/mock_test.go:65: -Unexpected call to At with args: [11 23] - -[ FAILED ] MockTest.UnexpectedCall -[ RUN ] MockTest.InvokeFunction -[ OK ] MockTest.InvokeFunction -[----------] Finished with tests from MockTest ---- FAIL: somepkg (1.23 seconds) -FAIL -exit status 1 -FAIL somepkg 1.234s diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.no_cases_test b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.no_cases_test deleted file mode 100644 index f8161adb19a..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.no_cases_test +++ /dev/null @@ -1,2 +0,0 @@ -PASS -ok somepkg 1.234s diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.panicking_test b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.panicking_test deleted file mode 100644 index 7d3ca2f56f5..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.panicking_test +++ /dev/null @@ -1,23 +0,0 @@ -[----------] Running tests from PanickingTest -[ RUN ] PanickingTest.PanickingTest -TearDown running. -panicking_test.go:44: -panic: foobar - -github.com/smartystreets/goconvey/convey/assertions/ogletest/somepkg_test.(*PanickingTest).PanickingTest - some_file.txt:0 -reflect.Value.call - some_file.txt:0 -reflect.Value.Call - some_file.txt:0 - - -[ FAILED ] PanickingTest.PanickingTest -[ RUN ] PanickingTest.ZzzSomeOtherTest -TearDown running. -[ OK ] PanickingTest.ZzzSomeOtherTest -[----------] Finished with tests from PanickingTest ---- FAIL: somepkg (1.23 seconds) -FAIL -exit status 1 -FAIL somepkg 1.234s diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.passing_test b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.passing_test deleted file mode 100644 index 5204c2f07a2..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.passing_test +++ /dev/null @@ -1,14 +0,0 @@ -[----------] Running tests from PassingTest -[ RUN ] PassingTest.EmptyTestMethod -[ OK ] PassingTest.EmptyTestMethod -[ RUN ] PassingTest.SuccessfullMatches -[ OK ] PassingTest.SuccessfullMatches -[ RUN ] PassingTest.ExpectAliases -[ OK ] PassingTest.ExpectAliases -[ RUN ] PassingTest.AssertAliases -[ OK ] PassingTest.AssertAliases -[ RUN ] PassingTest.SlowTest -[ OK ] PassingTest.SlowTest (1234ms) -[----------] Finished with tests from PassingTest -PASS -ok somepkg 1.234s diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.run_twice_test b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.run_twice_test deleted file mode 100644 index db3a1980b46..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.run_twice_test +++ /dev/null @@ -1,14 +0,0 @@ -[----------] Running tests from RunTwiceTest -[ RUN ] RunTwiceTest.PassingMethod -[ OK ] RunTwiceTest.PassingMethod -[ RUN ] RunTwiceTest.FailingMethod -run_twice_test.go:46: -Expected: 17.5 -Actual: 17 - -[ FAILED ] RunTwiceTest.FailingMethod -[----------] Finished with tests from RunTwiceTest ---- FAIL: somepkg (1.23 seconds) -FAIL -exit status 1 -FAIL somepkg 1.234s diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.unexported_test b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.unexported_test deleted file mode 100644 index 765e4377cfc..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/golden.unexported_test +++ /dev/null @@ -1,12 +0,0 @@ -[----------] Running tests from UnexportedTest -[ RUN ] UnexportedTest.SomeTest -unexported_test.go:42: -Expected: 4 -Actual: 3 - -[ FAILED ] UnexportedTest.SomeTest -[----------] Finished with tests from UnexportedTest ---- FAIL: somepkg (1.23 seconds) -FAIL -exit status 1 -FAIL somepkg 1.234s diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/mock.test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/mock.test.go deleted file mode 100644 index 295c37c3762..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/mock.test.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "image/color" - "testing" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - "github.com/smartystreets/goconvey/convey/assertions/oglemock" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" - "github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/mock_image" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type MockTest struct { - controller oglemock.Controller - image mock_image.MockImage -} - -func init() { RegisterTestSuite(&MockTest{}) } -func TestMockTest(t *testing.T) { RunTests(t) } - -func (t *MockTest) SetUp(i *TestInfo) { - t.controller = i.MockController - t.image = mock_image.NewMockImage(t.controller, "some mock image") -} - -//////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////// - -func (t *MockTest) ExpectationSatisfied() { - ExpectCall(t.image, "At")(11, GreaterThan(19)). - WillOnce(oglemock.Return(color.Gray{0})) - - ExpectThat(t.image.At(11, 23), IdenticalTo(color.Gray{0})) -} - -func (t *MockTest) MockExpectationNotSatisfied() { - ExpectCall(t.image, "At")(11, GreaterThan(19)). - WillOnce(oglemock.Return(color.Gray{0})) -} - -func (t *MockTest) ExpectCallForUnknownMethod() { - ExpectCall(t.image, "FooBar")(11) -} - -func (t *MockTest) UnexpectedCall() { - t.image.At(11, 23) -} - -func (t *MockTest) InvokeFunction() { - var suppliedX, suppliedY int - f := func(x, y int) color.Color { - suppliedX = x - suppliedY = y - return color.Gray{17} - } - - ExpectCall(t.image, "At")(Any(), Any()). - WillOnce(oglemock.Invoke(f)) - - ExpectThat(t.image.At(-1, 12), IdenticalTo(color.Gray{17})) - ExpectEq(-1, suppliedX) - ExpectEq(12, suppliedY) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/mock_image/mock_image.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/mock_image/mock_image.go deleted file mode 100644 index dabcba35e1f..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/mock_image/mock_image.go +++ /dev/null @@ -1,116 +0,0 @@ -// This file was auto-generated using createmock. See the following page for -// more information: -// -// https://github.com/smartystreets/goconvey/convey/assertions/oglemock -// - -package mock_image - -import ( - fmt "fmt" - image "image" - color "image/color" - runtime "runtime" - unsafe "unsafe" - - oglemock "github.com/smartystreets/goconvey/convey/assertions/oglemock" -) - -type MockImage interface { - image.Image - oglemock.MockObject -} - -type mockImage struct { - controller oglemock.Controller - description string -} - -func NewMockImage( - c oglemock.Controller, - desc string) MockImage { - return &mockImage{ - controller: c, - description: desc, - } -} - -func (m *mockImage) Oglemock_Id() uintptr { - return uintptr(unsafe.Pointer(m)) -} - -func (m *mockImage) Oglemock_Description() string { - return m.description -} - -func (m *mockImage) At(p0 int, p1 int) (o0 color.Color) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "At", - file, - line, - []interface{}{p0, p1}) - - if len(retVals) != 1 { - panic(fmt.Sprintf("mockImage.At: invalid return values: %v", retVals)) - } - - // o0 color.Color - if retVals[0] != nil { - o0 = retVals[0].(color.Color) - } - - return -} - -func (m *mockImage) Bounds() (o0 image.Rectangle) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "Bounds", - file, - line, - []interface{}{}) - - if len(retVals) != 1 { - panic(fmt.Sprintf("mockImage.Bounds: invalid return values: %v", retVals)) - } - - // o0 image.Rectangle - if retVals[0] != nil { - o0 = retVals[0].(image.Rectangle) - } - - return -} - -func (m *mockImage) ColorModel() (o0 color.Model) { - // Get a file name and line number for the caller. - _, file, line, _ := runtime.Caller(1) - - // Hand the call off to the controller, which does most of the work. - retVals := m.controller.HandleMethodCall( - m, - "ColorModel", - file, - line, - []interface{}{}) - - if len(retVals) != 1 { - panic(fmt.Sprintf("mockImage.ColorModel: invalid return values: %v", retVals)) - } - - // o0 color.Model - if retVals[0] != nil { - o0 = retVals[0].(color.Model) - } - - return -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/no_cases.test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/no_cases.test.go deleted file mode 100644 index 6efb3db95bc..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/no_cases.test.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "fmt" - "testing" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -func TestNoCases(t *testing.T) { RunTests(t) } - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type NoCasesTest struct { -} - -func init() { RegisterTestSuite(&NoCasesTest{}) } - -func (t *NoCasesTest) SetUpTestSuite() { - fmt.Println("SetUpTestSuite run!") -} - -func (t *NoCasesTest) TearDownTestSuite() { - fmt.Println("TearDownTestSuite run!") -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/panicking.test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/panicking.test.go deleted file mode 100644 index 8a32aadec11..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/panicking.test.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "fmt" - "testing" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type PanickingTest struct { -} - -func init() { RegisterTestSuite(&PanickingTest{}) } -func TestPanickingTest(t *testing.T) { RunTests(t) } - -func (t *PanickingTest) TearDown() { - fmt.Println("TearDown running.") -} - -//////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////// - -func (t *PanickingTest) PanickingTest() { - panic("foobar") -} - -func (t *PanickingTest) ZzzSomeOtherTest() { - ExpectThat(17, Equals(17.0)) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/passing.test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/passing.test.go deleted file mode 100644 index 0615e5e1e30..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/passing.test.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "testing" - "time" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type PassingTest struct { -} - -func init() { RegisterTestSuite(&PassingTest{}) } -func TestPassingTest(t *testing.T) { RunTests(t) } - -//////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////// - -func (t *PassingTest) EmptyTestMethod() { -} - -func (t *PassingTest) SuccessfullMatches() { - ExpectThat(17, Equals(17.0)) - ExpectThat(16.9, LessThan(17)) - ExpectThat("taco", HasSubstr("ac")) - - AssertThat(17, Equals(17.0)) - AssertThat(16.9, LessThan(17)) - AssertThat("taco", HasSubstr("ac")) -} - -func (t *PassingTest) ExpectAliases() { - ExpectEq(17, 17.0) - - ExpectLe(17, 17.0) - ExpectLe(17, 18.0) - ExpectLt(17, 18.0) - - ExpectGe(17, 17.0) - ExpectGe(17, 16.0) - ExpectGt(17, 16.0) - - ExpectNe(17, 18.0) - - ExpectTrue(true) - ExpectFalse(false) -} - -func (t *PassingTest) AssertAliases() { - AssertEq(17, 17.0) - - AssertLe(17, 17.0) - AssertLe(17, 18.0) - AssertLt(17, 18.0) - - AssertGe(17, 17.0) - AssertGe(17, 16.0) - AssertGt(17, 16.0) - - AssertNe(17, 18.0) - - AssertTrue(true) - AssertFalse(false) -} - -func (t *PassingTest) SlowTest() { - time.Sleep(37 * time.Millisecond) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/run_twice.test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/run_twice.test.go deleted file mode 100644 index cfa7c80fb3b..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/run_twice.test.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "testing" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type RunTwiceTest struct { -} - -func init() { RegisterTestSuite(&RunTwiceTest{}) } - -// Set up two helpers that call RunTests. The test should still only be run -// once. -func TestOgletest(t *testing.T) { RunTests(t) } -func TestOgletest2(t *testing.T) { RunTests(t) } - -//////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////// - -func (t *RunTwiceTest) PassingMethod() { -} - -func (t *RunTwiceTest) FailingMethod() { - ExpectThat(17, Equals(17.5)) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/unexported.test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/unexported.test.go deleted file mode 100644 index 7fbbd4e8709..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_cases/unexported.test.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers_test - -import ( - "testing" - . "github.com/smartystreets/goconvey/convey/assertions/oglematchers" - . "github.com/smartystreets/goconvey/convey/assertions/ogletest" -) - -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - -type UnexportedTest struct { -} - -func init() { RegisterTestSuite(&UnexportedTest{}) } -func TestUnexportedTest(t *testing.T) { RunTests(t) } - -func (t *UnexportedTest) someUnexportedMethod() { -} - -//////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////// - -func (t *UnexportedTest) SomeTest() { - ExpectThat(3, Equals(4)) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_info.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_info.go deleted file mode 100644 index c7473103e49..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/ogletest/test_info.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ogletest - -import ( - "sync" - - "github.com/smartystreets/goconvey/convey/assertions/oglemock" -) - -// TestInfo represents information about a currently running or previously-run -// test. -type TestInfo struct { - // A mock controller that is set up to report errors to the ogletest test - // runner. This can be used for setting up mock expectations and handling - // mock calls. The Finish method should not be run by the user; ogletest will - // do that automatically after the test's TearDown method is run. - // - // Note that this feature is still experimental, and is subject to change. - MockController oglemock.Controller - - // A mutex protecting shared state. - mutex sync.RWMutex - - // A set of failure records that the test has produced. - failureRecords []*failureRecord // Protected by mutex -} - -// currentlyRunningTest is the state for the currently running test, if any. -var currentlyRunningTest *TestInfo - -// newTestInfo creates a valid but empty TestInfo struct. -func newTestInfo() *TestInfo { - info := &TestInfo{} - info.failureRecords = make([]*failureRecord, 0) - info.MockController = oglemock.NewController(&testInfoErrorReporter{info}) - return info -} - -// failureRecord represents a single failed expectation for a test. -type failureRecord struct { - // The file name within which the expectation failed, e.g. "foo_test.go". - FileName string - - // The line number at which the expectation failed. - LineNumber int - - // The error generated by the testing framework. For example: - // - // Expected: 17 - // Actual: "taco", which is not numeric - // - GeneratedError string - - // A user-specified string to print out with the error, if any. - UserError string -} - -// testInfoErrorReporter is an oglemock.ErrorReporter that writes failure -// records into a test info struct. -type testInfoErrorReporter struct { - testInfo *TestInfo -} - -func (r *testInfoErrorReporter) ReportError( - fileName string, - lineNumber int, - err error) { - r.testInfo.mutex.Lock() - defer r.testInfo.mutex.Unlock() - - record := &failureRecord{ - FileName: fileName, - LineNumber: lineNumber, - GeneratedError: err.Error(), - } - - r.testInfo.failureRecords = append(r.testInfo.failureRecords, record) -} - -func (r *testInfoErrorReporter) ReportFatalError( - fileName string, - lineNumber int, - err error) { - r.ReportError(fileName, lineNumber, err) - panic(&assertThatError{}) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/panic_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/panic_test.go deleted file mode 100644 index 15eafac4fbb..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/panic_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package assertions - -import ( - "fmt" - "testing" -) - -func TestShouldPanic(t *testing.T) { - fail(t, so(func() {}, ShouldPanic, 1), "This assertion requires exactly 0 comparison values (you provided 1).") - fail(t, so(func() {}, ShouldPanic, 1, 2, 3), "This assertion requires exactly 0 comparison values (you provided 3).") - - fail(t, so(1, ShouldPanic), shouldUseVoidNiladicFunction) - fail(t, so(func(i int) {}, ShouldPanic), shouldUseVoidNiladicFunction) - fail(t, so(func() int { panic("hi") }, ShouldPanic), shouldUseVoidNiladicFunction) - - fail(t, so(func() {}, ShouldPanic), shouldHavePanicked) - pass(t, so(func() { panic("hi") }, ShouldPanic)) -} - -func TestShouldNotPanic(t *testing.T) { - fail(t, so(func() {}, ShouldNotPanic, 1), "This assertion requires exactly 0 comparison values (you provided 1).") - fail(t, so(func() {}, ShouldNotPanic, 1, 2, 3), "This assertion requires exactly 0 comparison values (you provided 3).") - - fail(t, so(1, ShouldNotPanic), shouldUseVoidNiladicFunction) - fail(t, so(func(i int) {}, ShouldNotPanic), shouldUseVoidNiladicFunction) - - fail(t, so(func() { panic("hi") }, ShouldNotPanic), fmt.Sprintf(shouldNotHavePanicked, "hi")) - pass(t, so(func() {}, ShouldNotPanic)) -} - -func TestShouldPanicWith(t *testing.T) { - fail(t, so(func() {}, ShouldPanicWith), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(func() {}, ShouldPanicWith, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).") - - fail(t, so(1, ShouldPanicWith, 1), shouldUseVoidNiladicFunction) - fail(t, so(func(i int) {}, ShouldPanicWith, "hi"), shouldUseVoidNiladicFunction) - fail(t, so(func() {}, ShouldPanicWith, "bye"), shouldHavePanicked) - fail(t, so(func() { panic("hi") }, ShouldPanicWith, "bye"), "bye|hi|Expected func() to panic with 'bye' (but it panicked with 'hi')!") - - pass(t, so(func() { panic("hi") }, ShouldPanicWith, "hi")) -} - -func TestShouldNotPanicWith(t *testing.T) { - fail(t, so(func() {}, ShouldNotPanicWith), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(func() {}, ShouldNotPanicWith, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).") - - fail(t, so(1, ShouldNotPanicWith, 1), shouldUseVoidNiladicFunction) - fail(t, so(func(i int) {}, ShouldNotPanicWith, "hi"), shouldUseVoidNiladicFunction) - fail(t, so(func() { panic("hi") }, ShouldNotPanicWith, "hi"), "Expected func() NOT to panic with 'hi' (but it did)!") - - pass(t, so(func() {}, ShouldNotPanicWith, "bye")) - pass(t, so(func() { panic("hi") }, ShouldNotPanicWith, "bye")) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/quantity_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/quantity_test.go deleted file mode 100644 index 7546e7250a8..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/quantity_test.go +++ /dev/null @@ -1,145 +0,0 @@ -package assertions - -import "testing" - -func TestShouldBeGreaterThan(t *testing.T) { - fail(t, so(1, ShouldBeGreaterThan), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(1, ShouldBeGreaterThan, 0, 0), "This assertion requires exactly 1 comparison values (you provided 2).") - - pass(t, so(1, ShouldBeGreaterThan, 0)) - pass(t, so(1.1, ShouldBeGreaterThan, 1)) - pass(t, so(1, ShouldBeGreaterThan, uint(0))) - pass(t, so("b", ShouldBeGreaterThan, "a")) - - fail(t, so(0, ShouldBeGreaterThan, 1), "Expected '0' to be greater than '1' (but it wasn't)!") - fail(t, so(1, ShouldBeGreaterThan, 1.1), "Expected '1' to be greater than '1.1' (but it wasn't)!") - fail(t, so(uint(0), ShouldBeGreaterThan, 1.1), "Expected '0' to be greater than '1.1' (but it wasn't)!") - fail(t, so("a", ShouldBeGreaterThan, "b"), "Expected 'a' to be greater than 'b' (but it wasn't)!") -} - -func TestShouldBeGreaterThanOrEqual(t *testing.T) { - fail(t, so(1, ShouldBeGreaterThanOrEqualTo), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(1, ShouldBeGreaterThanOrEqualTo, 0, 0), "This assertion requires exactly 1 comparison values (you provided 2).") - - pass(t, so(1, ShouldBeGreaterThanOrEqualTo, 1)) - pass(t, so(1.1, ShouldBeGreaterThanOrEqualTo, 1.1)) - pass(t, so(1, ShouldBeGreaterThanOrEqualTo, uint(1))) - pass(t, so("b", ShouldBeGreaterThanOrEqualTo, "b")) - - pass(t, so(1, ShouldBeGreaterThanOrEqualTo, 0)) - pass(t, so(1.1, ShouldBeGreaterThanOrEqualTo, 1)) - pass(t, so(1, ShouldBeGreaterThanOrEqualTo, uint(0))) - pass(t, so("b", ShouldBeGreaterThanOrEqualTo, "a")) - - fail(t, so(0, ShouldBeGreaterThanOrEqualTo, 1), "Expected '0' to be greater than or equal to '1' (but it wasn't)!") - fail(t, so(1, ShouldBeGreaterThanOrEqualTo, 1.1), "Expected '1' to be greater than or equal to '1.1' (but it wasn't)!") - fail(t, so(uint(0), ShouldBeGreaterThanOrEqualTo, 1.1), "Expected '0' to be greater than or equal to '1.1' (but it wasn't)!") - fail(t, so("a", ShouldBeGreaterThanOrEqualTo, "b"), "Expected 'a' to be greater than or equal to 'b' (but it wasn't)!") -} - -func TestShouldBeLessThan(t *testing.T) { - fail(t, so(1, ShouldBeLessThan), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(1, ShouldBeLessThan, 0, 0), "This assertion requires exactly 1 comparison values (you provided 2).") - - pass(t, so(0, ShouldBeLessThan, 1)) - pass(t, so(1, ShouldBeLessThan, 1.1)) - pass(t, so(uint(0), ShouldBeLessThan, 1)) - pass(t, so("a", ShouldBeLessThan, "b")) - - fail(t, so(1, ShouldBeLessThan, 0), "Expected '1' to be less than '0' (but it wasn't)!") - fail(t, so(1.1, ShouldBeLessThan, 1), "Expected '1.1' to be less than '1' (but it wasn't)!") - fail(t, so(1.1, ShouldBeLessThan, uint(0)), "Expected '1.1' to be less than '0' (but it wasn't)!") - fail(t, so("b", ShouldBeLessThan, "a"), "Expected 'b' to be less than 'a' (but it wasn't)!") -} - -func TestShouldBeLessThanOrEqualTo(t *testing.T) { - fail(t, so(1, ShouldBeLessThanOrEqualTo), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(1, ShouldBeLessThanOrEqualTo, 0, 0), "This assertion requires exactly 1 comparison values (you provided 2).") - - pass(t, so(1, ShouldBeLessThanOrEqualTo, 1)) - pass(t, so(1.1, ShouldBeLessThanOrEqualTo, 1.1)) - pass(t, so(uint(1), ShouldBeLessThanOrEqualTo, 1)) - pass(t, so("b", ShouldBeLessThanOrEqualTo, "b")) - - pass(t, so(0, ShouldBeLessThanOrEqualTo, 1)) - pass(t, so(1, ShouldBeLessThanOrEqualTo, 1.1)) - pass(t, so(uint(0), ShouldBeLessThanOrEqualTo, 1)) - pass(t, so("a", ShouldBeLessThanOrEqualTo, "b")) - - fail(t, so(1, ShouldBeLessThanOrEqualTo, 0), "Expected '1' to be less than '0' (but it wasn't)!") - fail(t, so(1.1, ShouldBeLessThanOrEqualTo, 1), "Expected '1.1' to be less than '1' (but it wasn't)!") - fail(t, so(1.1, ShouldBeLessThanOrEqualTo, uint(0)), "Expected '1.1' to be less than '0' (but it wasn't)!") - fail(t, so("b", ShouldBeLessThanOrEqualTo, "a"), "Expected 'b' to be less than 'a' (but it wasn't)!") -} - -func TestShouldBeBetween(t *testing.T) { - fail(t, so(1, ShouldBeBetween), "This assertion requires exactly 2 comparison values (you provided 0).") - fail(t, so(1, ShouldBeBetween, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).") - - fail(t, so(4, ShouldBeBetween, 1, 1), "The lower and upper bounds must be different values (they were both '1').") - - fail(t, so(7, ShouldBeBetween, 8, 12), "Expected '7' to be between '8' and '12' (but it wasn't)!") - fail(t, so(8, ShouldBeBetween, 8, 12), "Expected '8' to be between '8' and '12' (but it wasn't)!") - pass(t, so(9, ShouldBeBetween, 8, 12)) - pass(t, so(10, ShouldBeBetween, 8, 12)) - pass(t, so(11, ShouldBeBetween, 8, 12)) - fail(t, so(12, ShouldBeBetween, 8, 12), "Expected '12' to be between '8' and '12' (but it wasn't)!") - fail(t, so(13, ShouldBeBetween, 8, 12), "Expected '13' to be between '8' and '12' (but it wasn't)!") - - pass(t, so(1, ShouldBeBetween, 2, 0)) - fail(t, so(-1, ShouldBeBetween, 2, 0), "Expected '-1' to be between '0' and '2' (but it wasn't)!") -} - -func TestShouldNotBeBetween(t *testing.T) { - fail(t, so(1, ShouldNotBeBetween), "This assertion requires exactly 2 comparison values (you provided 0).") - fail(t, so(1, ShouldNotBeBetween, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).") - - fail(t, so(4, ShouldNotBeBetween, 1, 1), "The lower and upper bounds must be different values (they were both '1').") - - pass(t, so(7, ShouldNotBeBetween, 8, 12)) - pass(t, so(8, ShouldNotBeBetween, 8, 12)) - fail(t, so(9, ShouldNotBeBetween, 8, 12), "Expected '9' NOT to be between '8' and '12' (but it was)!") - fail(t, so(10, ShouldNotBeBetween, 8, 12), "Expected '10' NOT to be between '8' and '12' (but it was)!") - fail(t, so(11, ShouldNotBeBetween, 8, 12), "Expected '11' NOT to be between '8' and '12' (but it was)!") - pass(t, so(12, ShouldNotBeBetween, 8, 12)) - pass(t, so(13, ShouldNotBeBetween, 8, 12)) - - pass(t, so(-1, ShouldNotBeBetween, 2, 0)) - fail(t, so(1, ShouldNotBeBetween, 2, 0), "Expected '1' NOT to be between '0' and '2' (but it was)!") -} - -func TestShouldBeBetweenOrEqual(t *testing.T) { - fail(t, so(1, ShouldBeBetweenOrEqual), "This assertion requires exactly 2 comparison values (you provided 0).") - fail(t, so(1, ShouldBeBetweenOrEqual, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).") - - fail(t, so(4, ShouldBeBetweenOrEqual, 1, 1), "The lower and upper bounds must be different values (they were both '1').") - - fail(t, so(7, ShouldBeBetweenOrEqual, 8, 12), "Expected '7' to be between '8' and '12' or equal to one of them (but it wasn't)!") - pass(t, so(8, ShouldBeBetweenOrEqual, 8, 12)) - pass(t, so(9, ShouldBeBetweenOrEqual, 8, 12)) - pass(t, so(10, ShouldBeBetweenOrEqual, 8, 12)) - pass(t, so(11, ShouldBeBetweenOrEqual, 8, 12)) - pass(t, so(12, ShouldBeBetweenOrEqual, 8, 12)) - fail(t, so(13, ShouldBeBetweenOrEqual, 8, 12), "Expected '13' to be between '8' and '12' or equal to one of them (but it wasn't)!") - - pass(t, so(1, ShouldBeBetweenOrEqual, 2, 0)) - fail(t, so(-1, ShouldBeBetweenOrEqual, 2, 0), "Expected '-1' to be between '0' and '2' or equal to one of them (but it wasn't)!") -} - -func TestShouldNotBeBetweenOrEqual(t *testing.T) { - fail(t, so(1, ShouldNotBeBetweenOrEqual), "This assertion requires exactly 2 comparison values (you provided 0).") - fail(t, so(1, ShouldNotBeBetweenOrEqual, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).") - - fail(t, so(4, ShouldNotBeBetweenOrEqual, 1, 1), "The lower and upper bounds must be different values (they were both '1').") - - pass(t, so(7, ShouldNotBeBetweenOrEqual, 8, 12)) - fail(t, so(8, ShouldNotBeBetweenOrEqual, 8, 12), "Expected '8' NOT to be between '8' and '12' or equal to one of them (but it was)!") - fail(t, so(9, ShouldNotBeBetweenOrEqual, 8, 12), "Expected '9' NOT to be between '8' and '12' or equal to one of them (but it was)!") - fail(t, so(10, ShouldNotBeBetweenOrEqual, 8, 12), "Expected '10' NOT to be between '8' and '12' or equal to one of them (but it was)!") - fail(t, so(11, ShouldNotBeBetweenOrEqual, 8, 12), "Expected '11' NOT to be between '8' and '12' or equal to one of them (but it was)!") - fail(t, so(12, ShouldNotBeBetweenOrEqual, 8, 12), "Expected '12' NOT to be between '8' and '12' or equal to one of them (but it was)!") - pass(t, so(13, ShouldNotBeBetweenOrEqual, 8, 12)) - - pass(t, so(-1, ShouldNotBeBetweenOrEqual, 2, 0)) - fail(t, so(1, ShouldNotBeBetweenOrEqual, 2, 0), "Expected '1' NOT to be between '0' and '2' or equal to one of them (but it was)!") -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/serializer_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/serializer_test.go deleted file mode 100644 index 798345d6ca6..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/serializer_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package assertions - -import ( - "encoding/json" - "fmt" - "testing" - - "github.com/smartystreets/goconvey/convey/reporting" -) - -func TestSerializerCreatesSerializedVersionOfAssertionResult(t *testing.T) { - thing1 := Thing1{"Hi"} - thing2 := Thing2{"Bye"} - message := "Super-hip failure message." - serializer := newSerializer() - - actualResult := serializer.serialize(thing1, thing2, message) - - expectedResult, _ := json.Marshal(reporting.FailureView{ - Message: message, - Expected: fmt.Sprintf("%+v", thing1), - Actual: fmt.Sprintf("%+v", thing2), - }) - - if actualResult != string(expectedResult) { - t.Errorf("\nExpected: %s\nActual: %s", string(expectedResult), actualResult) - } - - actualResult = serializer.serializeDetailed(thing1, thing2, message) - expectedResult, _ = json.Marshal(reporting.FailureView{ - Message: message, - Expected: fmt.Sprintf("%#v", thing1), - Actual: fmt.Sprintf("%#v", thing2), - }) - if actualResult != string(expectedResult) { - t.Errorf("\nExpected: %s\nActual: %s", string(expectedResult), actualResult) - } -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/strings_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/strings_test.go deleted file mode 100644 index eec9440ed0a..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/strings_test.go +++ /dev/null @@ -1,102 +0,0 @@ -package assertions - -import "testing" - -func TestShouldStartWith(t *testing.T) { - serializer = newFakeSerializer() - - fail(t, so("", ShouldStartWith), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so("", ShouldStartWith, "asdf", "asdf"), "This assertion requires exactly 1 comparison values (you provided 2).") - - pass(t, so("", ShouldStartWith, "")) - fail(t, so("", ShouldStartWith, "x"), "x||Expected '' to start with 'x' (but it didn't)!") - pass(t, so("abc", ShouldStartWith, "abc")) - fail(t, so("abc", ShouldStartWith, "abcd"), "abcd|abc|Expected 'abc' to start with 'abcd' (but it didn't)!") - - pass(t, so("superman", ShouldStartWith, "super")) - fail(t, so("superman", ShouldStartWith, "bat"), "bat|sup...|Expected 'superman' to start with 'bat' (but it didn't)!") - fail(t, so("superman", ShouldStartWith, "man"), "man|sup...|Expected 'superman' to start with 'man' (but it didn't)!") - - fail(t, so(1, ShouldStartWith, 2), "Both arguments to this assertion must be strings (you provided int and int).") -} - -func TestShouldNotStartWith(t *testing.T) { - fail(t, so("", ShouldNotStartWith), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so("", ShouldNotStartWith, "asdf", "asdf"), "This assertion requires exactly 1 comparison values (you provided 2).") - - fail(t, so("", ShouldNotStartWith, ""), "Expected '' NOT to start with '' (but it did)!") - fail(t, so("superman", ShouldNotStartWith, "super"), "Expected 'superman' NOT to start with 'super' (but it did)!") - pass(t, so("superman", ShouldNotStartWith, "bat")) - pass(t, so("superman", ShouldNotStartWith, "man")) - - fail(t, so(1, ShouldNotStartWith, 2), "Both arguments to this assertion must be strings (you provided int and int).") -} - -func TestShouldEndWith(t *testing.T) { - serializer = newFakeSerializer() - - fail(t, so("", ShouldEndWith), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so("", ShouldEndWith, "", ""), "This assertion requires exactly 1 comparison values (you provided 2).") - - pass(t, so("", ShouldEndWith, "")) - fail(t, so("", ShouldEndWith, "z"), "z||Expected '' to end with 'z' (but it didn't)!") - pass(t, so("xyz", ShouldEndWith, "xyz")) - fail(t, so("xyz", ShouldEndWith, "wxyz"), "wxyz|xyz|Expected 'xyz' to end with 'wxyz' (but it didn't)!") - - pass(t, so("superman", ShouldEndWith, "man")) - fail(t, so("superman", ShouldEndWith, "super"), "super|...erman|Expected 'superman' to end with 'super' (but it didn't)!") - fail(t, so("superman", ShouldEndWith, "blah"), "blah|...rman|Expected 'superman' to end with 'blah' (but it didn't)!") - - fail(t, so(1, ShouldEndWith, 2), "Both arguments to this assertion must be strings (you provided int and int).") -} - -func TestShouldNotEndWith(t *testing.T) { - fail(t, so("", ShouldNotEndWith), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so("", ShouldNotEndWith, "", ""), "This assertion requires exactly 1 comparison values (you provided 2).") - - fail(t, so("", ShouldNotEndWith, ""), "Expected '' NOT to end with '' (but it did)!") - fail(t, so("superman", ShouldNotEndWith, "man"), "Expected 'superman' NOT to end with 'man' (but it did)!") - pass(t, so("superman", ShouldNotEndWith, "super")) - - fail(t, so(1, ShouldNotEndWith, 2), "Both arguments to this assertion must be strings (you provided int and int).") -} - -func TestShouldContainSubstring(t *testing.T) { - serializer = newFakeSerializer() - - fail(t, so("asdf", ShouldContainSubstring), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so("asdf", ShouldContainSubstring, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).") - - fail(t, so(123, ShouldContainSubstring, 23), "Both arguments to this assertion must be strings (you provided int and int).") - - pass(t, so("asdf", ShouldContainSubstring, "sd")) - fail(t, so("qwer", ShouldContainSubstring, "sd"), "sd|qwer|Expected 'qwer' to contain substring 'sd' (but it didn't)!") -} - -func TestShouldNotContainSubstring(t *testing.T) { - fail(t, so("asdf", ShouldNotContainSubstring), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so("asdf", ShouldNotContainSubstring, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).") - - fail(t, so(123, ShouldNotContainSubstring, 23), "Both arguments to this assertion must be strings (you provided int and int).") - - pass(t, so("qwer", ShouldNotContainSubstring, "sd")) - fail(t, so("asdf", ShouldNotContainSubstring, "sd"), "Expected 'asdf' NOT to contain substring 'sd' (but it didn't)!") -} - -func TestShouldBeBlank(t *testing.T) { - serializer = newFakeSerializer() - - fail(t, so("", ShouldBeBlank, "adsf"), "This assertion requires exactly 0 comparison values (you provided 1).") - fail(t, so(1, ShouldBeBlank), "The argument to this assertion must be a string (you provided int).") - - fail(t, so("asdf", ShouldBeBlank), "|asdf|Expected 'asdf' to be blank (but it wasn't)!") - pass(t, so("", ShouldBeBlank)) -} - -func TestShouldNotBeBlank(t *testing.T) { - fail(t, so("", ShouldNotBeBlank, "adsf"), "This assertion requires exactly 0 comparison values (you provided 1).") - fail(t, so(1, ShouldNotBeBlank), "The argument to this assertion must be a string (you provided int).") - - fail(t, so("", ShouldNotBeBlank), "Expected value to NOT be blank (but it was)!") - pass(t, so("asdf", ShouldNotBeBlank)) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/time_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/time_test.go deleted file mode 100644 index f9dda8f8f34..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/time_test.go +++ /dev/null @@ -1,159 +0,0 @@ -package assertions - -import ( - "fmt" - "testing" - "time" -) - -func TestShouldHappenBefore(t *testing.T) { - fail(t, so(0, ShouldHappenBefore), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(0, ShouldHappenBefore, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).") - - fail(t, so(0, ShouldHappenBefore, 1), shouldUseTimes) - fail(t, so(0, ShouldHappenBefore, time.Now()), shouldUseTimes) - fail(t, so(time.Now(), ShouldHappenBefore, 0), shouldUseTimes) - - fail(t, so(january3, ShouldHappenBefore, january1), fmt.Sprintf("Expected '%s' to happen before '%s' (it happened '48h0m0s' after)!", pretty(january3), pretty(january1))) - fail(t, so(january3, ShouldHappenBefore, january3), fmt.Sprintf("Expected '%s' to happen before '%s' (it happened '0' after)!", pretty(january3), pretty(january3))) - pass(t, so(january1, ShouldHappenBefore, january3)) -} - -func TestShouldHappenOnOrBefore(t *testing.T) { - fail(t, so(0, ShouldHappenOnOrBefore), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(0, ShouldHappenOnOrBefore, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).") - - fail(t, so(0, ShouldHappenOnOrBefore, 1), shouldUseTimes) - fail(t, so(0, ShouldHappenOnOrBefore, time.Now()), shouldUseTimes) - fail(t, so(time.Now(), ShouldHappenOnOrBefore, 0), shouldUseTimes) - - fail(t, so(january3, ShouldHappenOnOrBefore, january1), fmt.Sprintf("Expected '%s' to happen before '%s' (it happened '48h0m0s' after)!", pretty(january3), pretty(january1))) - pass(t, so(january3, ShouldHappenOnOrBefore, january3)) - pass(t, so(january1, ShouldHappenOnOrBefore, january3)) -} - -func TestShouldHappenAfter(t *testing.T) { - fail(t, so(0, ShouldHappenAfter), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(0, ShouldHappenAfter, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).") - - fail(t, so(0, ShouldHappenAfter, 1), shouldUseTimes) - fail(t, so(0, ShouldHappenAfter, time.Now()), shouldUseTimes) - fail(t, so(time.Now(), ShouldHappenAfter, 0), shouldUseTimes) - - fail(t, so(january1, ShouldHappenAfter, january2), fmt.Sprintf("Expected '%s' to happen after '%s' (it happened '24h0m0s' before)!", pretty(january1), pretty(january2))) - fail(t, so(january1, ShouldHappenAfter, january1), fmt.Sprintf("Expected '%s' to happen after '%s' (it happened '0' before)!", pretty(january1), pretty(january1))) - pass(t, so(january3, ShouldHappenAfter, january1)) -} - -func TestShouldHappenOnOrAfter(t *testing.T) { - fail(t, so(0, ShouldHappenOnOrAfter), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(0, ShouldHappenOnOrAfter, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).") - - fail(t, so(0, ShouldHappenOnOrAfter, 1), shouldUseTimes) - fail(t, so(0, ShouldHappenOnOrAfter, time.Now()), shouldUseTimes) - fail(t, so(time.Now(), ShouldHappenOnOrAfter, 0), shouldUseTimes) - - fail(t, so(january1, ShouldHappenOnOrAfter, january2), fmt.Sprintf("Expected '%s' to happen after '%s' (it happened '24h0m0s' before)!", pretty(january1), pretty(january2))) - pass(t, so(january1, ShouldHappenOnOrAfter, january1)) - pass(t, so(january3, ShouldHappenOnOrAfter, january1)) -} - -func TestShouldHappenBetween(t *testing.T) { - fail(t, so(0, ShouldHappenBetween), "This assertion requires exactly 2 comparison values (you provided 0).") - fail(t, so(0, ShouldHappenBetween, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).") - - fail(t, so(0, ShouldHappenBetween, 1, 2), shouldUseTimes) - fail(t, so(0, ShouldHappenBetween, time.Now(), time.Now()), shouldUseTimes) - fail(t, so(time.Now(), ShouldHappenBetween, 0, time.Now()), shouldUseTimes) - fail(t, so(time.Now(), ShouldHappenBetween, time.Now(), 9), shouldUseTimes) - - fail(t, so(january1, ShouldHappenBetween, january2, january4), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '24h0m0s' outside threshold)!", pretty(january1), pretty(january2), pretty(january4))) - fail(t, so(january2, ShouldHappenBetween, january2, january4), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '0' outside threshold)!", pretty(january2), pretty(january2), pretty(january4))) - pass(t, so(january3, ShouldHappenBetween, january2, january4)) - fail(t, so(january4, ShouldHappenBetween, january2, january4), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '0' outside threshold)!", pretty(january4), pretty(january2), pretty(january4))) - fail(t, so(january5, ShouldHappenBetween, january2, january4), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '24h0m0s' outside threshold)!", pretty(january5), pretty(january2), pretty(january4))) -} - -func TestShouldHappenOnOrBetween(t *testing.T) { - fail(t, so(0, ShouldHappenOnOrBetween), "This assertion requires exactly 2 comparison values (you provided 0).") - fail(t, so(0, ShouldHappenOnOrBetween, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).") - - fail(t, so(0, ShouldHappenOnOrBetween, 1, time.Now()), shouldUseTimes) - fail(t, so(0, ShouldHappenOnOrBetween, time.Now(), 1), shouldUseTimes) - fail(t, so(time.Now(), ShouldHappenOnOrBetween, 0, 1), shouldUseTimes) - - fail(t, so(january1, ShouldHappenOnOrBetween, january2, january4), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '24h0m0s' outside threshold)!", pretty(january1), pretty(january2), pretty(january4))) - pass(t, so(january2, ShouldHappenOnOrBetween, january2, january4)) - pass(t, so(january3, ShouldHappenOnOrBetween, january2, january4)) - pass(t, so(january4, ShouldHappenOnOrBetween, january2, january4)) - fail(t, so(january5, ShouldHappenOnOrBetween, january2, january4), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '24h0m0s' outside threshold)!", pretty(january5), pretty(january2), pretty(january4))) -} - -func TestShouldNotHappenOnOrBetween(t *testing.T) { - fail(t, so(0, ShouldNotHappenOnOrBetween), "This assertion requires exactly 2 comparison values (you provided 0).") - fail(t, so(0, ShouldNotHappenOnOrBetween, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).") - - fail(t, so(0, ShouldNotHappenOnOrBetween, 1, time.Now()), shouldUseTimes) - fail(t, so(0, ShouldNotHappenOnOrBetween, time.Now(), 1), shouldUseTimes) - fail(t, so(time.Now(), ShouldNotHappenOnOrBetween, 0, 1), shouldUseTimes) - - pass(t, so(january1, ShouldNotHappenOnOrBetween, january2, january4)) - fail(t, so(january2, ShouldNotHappenOnOrBetween, january2, january4), fmt.Sprintf("Expected '%s' to NOT happen on or between '%s' and '%s' (but it did)!", pretty(january2), pretty(january2), pretty(january4))) - fail(t, so(january3, ShouldNotHappenOnOrBetween, january2, january4), fmt.Sprintf("Expected '%s' to NOT happen on or between '%s' and '%s' (but it did)!", pretty(january3), pretty(january2), pretty(january4))) - fail(t, so(january4, ShouldNotHappenOnOrBetween, january2, january4), fmt.Sprintf("Expected '%s' to NOT happen on or between '%s' and '%s' (but it did)!", pretty(january4), pretty(january2), pretty(january4))) - pass(t, so(january5, ShouldNotHappenOnOrBetween, january2, january4)) -} - -func TestShouldHappenWithin(t *testing.T) { - fail(t, so(0, ShouldHappenWithin), "This assertion requires exactly 2 comparison values (you provided 0).") - fail(t, so(0, ShouldHappenWithin, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).") - - fail(t, so(0, ShouldHappenWithin, 1, 2), shouldUseDurationAndTime) - fail(t, so(0, ShouldHappenWithin, oneDay, time.Now()), shouldUseDurationAndTime) - fail(t, so(time.Now(), ShouldHappenWithin, 0, time.Now()), shouldUseDurationAndTime) - - fail(t, so(january1, ShouldHappenWithin, oneDay, january3), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '24h0m0s' outside threshold)!", pretty(january1), pretty(january2), pretty(january4))) - pass(t, so(january2, ShouldHappenWithin, oneDay, january3)) - pass(t, so(january3, ShouldHappenWithin, oneDay, january3)) - pass(t, so(january4, ShouldHappenWithin, oneDay, january3)) - fail(t, so(january5, ShouldHappenWithin, oneDay, january3), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '24h0m0s' outside threshold)!", pretty(january5), pretty(january2), pretty(january4))) -} - -func TestShouldNotHappenWithin(t *testing.T) { - fail(t, so(0, ShouldNotHappenWithin), "This assertion requires exactly 2 comparison values (you provided 0).") - fail(t, so(0, ShouldNotHappenWithin, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).") - - fail(t, so(0, ShouldNotHappenWithin, 1, 2), shouldUseDurationAndTime) - fail(t, so(0, ShouldNotHappenWithin, oneDay, time.Now()), shouldUseDurationAndTime) - fail(t, so(time.Now(), ShouldNotHappenWithin, 0, time.Now()), shouldUseDurationAndTime) - - pass(t, so(january1, ShouldNotHappenWithin, oneDay, january3)) - fail(t, so(january2, ShouldNotHappenWithin, oneDay, january3), fmt.Sprintf("Expected '%s' to NOT happen on or between '%s' and '%s' (but it did)!", pretty(january2), pretty(january2), pretty(january4))) - fail(t, so(january3, ShouldNotHappenWithin, oneDay, january3), fmt.Sprintf("Expected '%s' to NOT happen on or between '%s' and '%s' (but it did)!", pretty(january3), pretty(january2), pretty(january4))) - fail(t, so(january4, ShouldNotHappenWithin, oneDay, january3), fmt.Sprintf("Expected '%s' to NOT happen on or between '%s' and '%s' (but it did)!", pretty(january4), pretty(january2), pretty(january4))) - pass(t, so(january5, ShouldNotHappenWithin, oneDay, january3)) -} - -func TestShouldBeChronological(t *testing.T) { - fail(t, so(0, ShouldBeChronological, 1, 2, 3), "This assertion requires exactly 0 comparison values (you provided 3).") - fail(t, so(0, ShouldBeChronological), shouldUseTimeSlice) - fail(t, so([]time.Time{january5, january1}, ShouldBeChronological), - "The 'Time' at index [1] should have happened after the previous one (but it didn't!):\n [0]: 2013-01-05 00:00:00 +0000 UTC\n [1]: 2013-01-01 00:00:00 +0000 UTC (see, it happened before!)") - - pass(t, so([]time.Time{january1, january2, january3, january4, january5}, ShouldBeChronological)) -} - -const layout = "2006-01-02 15:04" - -var january1, _ = time.Parse(layout, "2013-01-01 00:00") -var january2, _ = time.Parse(layout, "2013-01-02 00:00") -var january3, _ = time.Parse(layout, "2013-01-03 00:00") -var january4, _ = time.Parse(layout, "2013-01-04 00:00") -var january5, _ = time.Parse(layout, "2013-01-05 00:00") - -var oneDay, _ = time.ParseDuration("24h0m0s") -var twoDays, _ = time.ParseDuration("48h0m0s") - -func pretty(t time.Time) string { - return fmt.Sprintf("%v", t) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/type_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/type_test.go deleted file mode 100644 index 4b8d1984670..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/type_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package assertions - -import ( - "bytes" - "io" - "net/http" - "testing" -) - -func TestShouldHaveSameTypeAs(t *testing.T) { - serializer = newFakeSerializer() - - fail(t, so(1, ShouldHaveSameTypeAs), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(1, ShouldHaveSameTypeAs, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).") - - fail(t, so(nil, ShouldHaveSameTypeAs, 0), "int||Expected '' to be: 'int' (but was: '')!") - fail(t, so(1, ShouldHaveSameTypeAs, "asdf"), "string|int|Expected '1' to be: 'string' (but was: 'int')!") - - pass(t, so(1, ShouldHaveSameTypeAs, 0)) - pass(t, so(nil, ShouldHaveSameTypeAs, nil)) -} - -func TestShouldNotHaveSameTypeAs(t *testing.T) { - fail(t, so(1, ShouldNotHaveSameTypeAs), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(1, ShouldNotHaveSameTypeAs, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).") - - fail(t, so(1, ShouldNotHaveSameTypeAs, 0), "Expected '1' to NOT be: 'int' (but it was)!") - fail(t, so(nil, ShouldNotHaveSameTypeAs, nil), "Expected '' to NOT be: '' (but it was)!") - - pass(t, so(nil, ShouldNotHaveSameTypeAs, 0)) - pass(t, so(1, ShouldNotHaveSameTypeAs, "asdf")) -} - -func TestShouldImplement(t *testing.T) { - var ioReader *io.Reader = nil - var response http.Response = http.Response{} - var responsePtr *http.Response = new(http.Response) - var reader = bytes.NewBufferString("") - - fail(t, so(reader, ShouldImplement), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(reader, ShouldImplement, ioReader, ioReader), "This assertion requires exactly 1 comparison values (you provided 2).") - fail(t, so(reader, ShouldImplement, ioReader, ioReader, ioReader), "This assertion requires exactly 1 comparison values (you provided 3).") - - fail(t, so(reader, ShouldImplement, "foo"), shouldCompareWithInterfacePointer) - fail(t, so(reader, ShouldImplement, 1), shouldCompareWithInterfacePointer) - fail(t, so(reader, ShouldImplement, nil), shouldCompareWithInterfacePointer) - - fail(t, so(nil, ShouldImplement, ioReader), shouldNotBeNilActual) - fail(t, so(1, ShouldImplement, ioReader), "Expected: 'io.Reader interface support'\nActual: '*int' does not implement the interface!") - - fail(t, so(response, ShouldImplement, ioReader), "Expected: 'io.Reader interface support'\nActual: '*http.Response' does not implement the interface!") - fail(t, so(responsePtr, ShouldImplement, ioReader), "Expected: 'io.Reader interface support'\nActual: '*http.Response' does not implement the interface!") - pass(t, so(reader, ShouldImplement, ioReader)) - pass(t, so(reader, ShouldImplement, (*io.Reader)(nil))) -} - -func TestShouldNotImplement(t *testing.T) { - var ioReader *io.Reader = nil - var response http.Response = http.Response{} - var responsePtr *http.Response = new(http.Response) - var reader io.Reader = bytes.NewBufferString("") - - fail(t, so(reader, ShouldNotImplement), "This assertion requires exactly 1 comparison values (you provided 0).") - fail(t, so(reader, ShouldNotImplement, ioReader, ioReader), "This assertion requires exactly 1 comparison values (you provided 2).") - fail(t, so(reader, ShouldNotImplement, ioReader, ioReader, ioReader), "This assertion requires exactly 1 comparison values (you provided 3).") - - fail(t, so(reader, ShouldNotImplement, "foo"), shouldCompareWithInterfacePointer) - fail(t, so(reader, ShouldNotImplement, 1), shouldCompareWithInterfacePointer) - fail(t, so(reader, ShouldNotImplement, nil), shouldCompareWithInterfacePointer) - - fail(t, so(reader, ShouldNotImplement, ioReader), "Expected '*bytes.Buffer'\nto NOT implement 'io.Reader' (but it did)!") - fail(t, so(nil, ShouldNotImplement, ioReader), shouldNotBeNilActual) - pass(t, so(1, ShouldNotImplement, ioReader)) - pass(t, so(response, ShouldNotImplement, ioReader)) - pass(t, so(responsePtr, ShouldNotImplement, ioReader)) -} diff --git a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/utilities_for_test.go b/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/utilities_for_test.go deleted file mode 100644 index 7243ebcb937..00000000000 --- a/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/utilities_for_test.go +++ /dev/null @@ -1,75 +0,0 @@ -package assertions - -import ( - "fmt" - "path" - "runtime" - "strings" - "testing" -) - -func pass(t *testing.T, result string) { - if result != success { - _, file, line, _ := runtime.Caller(1) - base := path.Base(file) - t.Errorf("Expectation should have passed but failed (see %s: line %d): '%s'", base, line, result) - } -} - -func fail(t *testing.T, actual string, expected string) { - actual = format(actual) - expected = format(expected) - - if actual != expected { - if actual == "" { - actual = "(empty)" - } - _, file, line, _ := runtime.Caller(1) - base := path.Base(file) - t.Errorf("Expectation should have failed but passed (see %s: line %d). \nExpected: %s\nActual: %s\n", - base, line, expected, actual) - } -} -func format(message string) string { - message = strings.Replace(message, "\n", " ", -1) - for strings.Contains(message, " ") { - message = strings.Replace(message, " ", " ", -1) - } - return message -} - -type Thing1 struct { - a string -} -type Thing2 struct { - a string -} - -type Thinger interface { - Hi() -} - -type Thing struct{} - -func (self *Thing) Hi() {} - -type IntAlias int -type StringAlias string -type StringSliceAlias []string -type StringStringMapAlias map[string]string - -/******** FakeSerialzier ********/ - -type fakeSerializer struct{} - -func (self *fakeSerializer) serialize(expected, actual interface{}, message string) string { - return fmt.Sprintf("%v|%v|%s", expected, actual, message) -} - -func (self *fakeSerializer) serializeDetailed(expected, actual interface{}, message string) string { - return fmt.Sprintf("%v|%v|%s", expected, actual, message) -} - -func newFakeSerializer() *fakeSerializer { - return new(fakeSerializer) -} diff --git a/conf/defaults.ini b/conf/defaults.ini index 18b83969b6f..2219b56a77d 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -355,6 +355,25 @@ global_api_key = -1 # global limit on number of logged in users. global_session = -1 +#################################### Alerting ###################################### +# docs about alerting can be found in /docs/sources/alerting/ +# __.-/| +# \`o_O' +# =( )= +----------------------------+ +# U| | Alerting is still in alpha | +# /\ /\ / | +----------------------------+ +# ) /^\) ^\/ _)\ | +# ) /^\/ _) \ | +# ) _ / / _) \___|_ +# /\ )/\/ || | )_)\___,|)) +# < > |(,,) )__) | +# || / \)___)\ +# | \____( )___) )____ +# \______(_______;;;)__;;;) + +[alerting] +enabled = false + #################################### Internal Grafana Metrics ########################## # Metrics available at HTTP API Url /api/metrics [metrics] @@ -369,3 +388,18 @@ prefix = prod.grafana.%(instance_name)s. [grafana_net] url = https://grafana.net + +#################################### External image storage ########################## +[external_image_storage] +# You can choose between (s3, webdav or internal) +provider = s3 + +[external_image_storage.s3] +bucket_url = +access_key = +secret_key = + +[external_image_storage.webdav] +url = +username = +password = diff --git a/conf/sample.ini b/conf/sample.ini index 9e0e34fb8a9..4fcbe5d1157 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -301,6 +301,25 @@ check_for_updates = true ;enabled = false ;path = /var/lib/grafana/dashboards +#################################### Alerting ###################################### +# docs about alerting can be found in /docs/sources/alerting/ +# __.-/| +# \`o_O' +# =( )= +----------------------------+ +# U| | Alerting is still in alpha | +# /\ /\ / | +----------------------------+ +# ) /^\) ^\/ _)\ | +# ) /^\/ _) \ | +# ) _ / / _) \___|_ +# /\ )/\/ || | )_)\___,|)) +# < > |(,,) )__) | +# || / \)___)\ +# | \____( )___) )____ +# \______(_______;;;)__;;;) + +[alerting] +enabled = false + #################################### Internal Grafana Metrics ########################## # Metrics available at HTTP API Url /api/metrics [metrics] @@ -320,3 +339,19 @@ check_for_updates = true # Url used to to import dashboards directly from Grafana.net [grafana_net] ;url = https://grafana.net + +#################################### External image storage ########################## +[external_image_storage] +# Used for uploading images to public servers so they can be included in slack/email messages. +# you can choose between (s3, webdav or internal) +;provider = s3 + +[external_image_storage.s3] +;bucket_url = +;access_key = +;secret_key = + +[external_image_storage.webdav] +;url = +;username = +;password = diff --git a/docker/blocks/collectd/fig b/docker/blocks/collectd/fig index 6c2e7e25893..99f45a66d12 100644 --- a/docker/blocks/collectd/fig +++ b/docker/blocks/collectd/fig @@ -9,4 +9,3 @@ collectd: COLLECT_INTERVAL: 10 links: - graphite - - memcached diff --git a/docs/sources/alerting/alerting.md b/docs/sources/alerting/alerting.md new file mode 100644 index 00000000000..942327c2eac --- /dev/null +++ b/docs/sources/alerting/alerting.md @@ -0,0 +1,28 @@ +--- +page_title: Alerting +page_description: Alerting for Grafana +page_keywords: alerting, grafana, plugins, documentation +--- + +# Alerting + +> Alerting is still in very early development. Please be aware. + +The roadmap for alerting in Grafana have been changing rapidly during last 2-3 months. So make sure you follow the disucssion in the [alerting issue](https://github.com/grafana/grafana/issues/2209). + +## Introduction + +> Alerting is turned off by default and have to be enabled in the config file. + +Grafana lets you define alert rules based on metrics queries on dashboards. Every alert is connected to a panel and when ever the query for the panel is updated the alerting rule is also updated. +So far only the graph panel supports alerting. To enable alerting for a panel go to the alerting tab and press 'Create alert' button. + +## Alert status page + +You can overview all your current alerts on the alert stats page at /alerting + +## Alert notifications + +When an alert is triggered it goes to the notification handler who takes care of sending emails or push data as webhooks. +The alert notifications can be configured on /alerting/notifications + diff --git a/emails/templates/alert_notification.html b/emails/templates/alert_notification.html new file mode 100644 index 00000000000..5adcda1a620 --- /dev/null +++ b/emails/templates/alert_notification.html @@ -0,0 +1,91 @@ +[[Subject .Subject "[[.Title]]"]] + + + + + +
+ + + + +
+

[[.Title]]

+
+
+ + + + + +
+ + + + +
+

[[.Message]]

+
+
+ +[[if ne .State "ok" ]] + + + + +
+
+ + + + + + [[range .EvalMatches]] + + + + + [[end]] +
+ Metric name + + Value +
+ [[.Metric]] + + [[.Value]] +
+
+
+[[end]] + + + + + +
+ + + + +
+ +
+
+ + + + + + +
+ + + + +
+ Alert rule - Alerts page +
+
+ + diff --git a/examples/alerting-dashboard.json b/examples/alerting-dashboard.json new file mode 100644 index 00000000000..744460d7847 --- /dev/null +++ b/examples/alerting-dashboard.json @@ -0,0 +1,800 @@ +{ + "__inputs": [ + { + "name": "DS_GRAPHITE", + "label": "graphite", + "description": "", + "type": "datasource", + "pluginId": "graphite", + "pluginName": "Graphite" + } + ], + "__requires": [ + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "3.1.0" + }, + { + "type": "datasource", + "id": "graphite", + "name": "Graphite", + "version": "1.0.0" + } + ], + "id": null, + "title": "Alerting example", + "tags": [], + "style": "dark", + "timezone": "browser", + "editable": true, + "hideControls": false, + "sharedCrosshair": false, + "rows": [ + { + "collapse": false, + "editable": true, + "height": "250px", + "panels": [ + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 355 + ], + "type": "gt" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "enabled": true, + "frequency": "60s", + "handler": 1, + "name": "Critical alert panel", + "notifications": [], + "severity": "critical" + }, + "alerting": {}, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "id": 1, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + }, + { + "refId": "B", + "target": "aliasByNode(scale(statsd.$apa.counters.session_start.*.count, 10), 4)" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 355 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Critical panel", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 20 + ], + "type": "gt" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "enabled": true, + "frequency": "60s", + "handler": 1, + "name": "Warning panel alert", + "notifications": [], + "severity": "warning" + }, + "alerting": {}, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "id": 2, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "colorMode": "warning", + "fill": true, + "fillColor": "rgba(235, 138, 14, 0.12)", + "line": true, + "lineColor": "rgba(247, 149, 32, 0.60)", + "op": "gt", + "value": 20 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Warning panel", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "count" + }, + "type": "query" + } + ], + "enabled": true, + "frequency": "60s", + "handler": 1, + "name": "No datapoints", + "notifications": [], + "severity": "critical" + }, + "alerting": {}, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "id": 20, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "value": 1, + "op": "lt", + "fill": true, + "line": true, + "colorMode": "critical" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Count datapoints", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "title": "Row" + }, + { + "collapse": false, + "editable": true, + "height": "250px", + "panels": [ + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 20 + ], + "type": "lt" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "enabled": true, + "frequency": "60s", + "handler": 1, + "name": "Alert below value", + "notifications": [], + "severity": "critical" + }, + "alerting": {}, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "id": 17, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.12)", + "line": true, + "lineColor": "rgba(237, 46, 24, 0.60)", + "op": "lt", + "value": 20 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Alert below value", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 10, + 80 + ], + "type": "outside_range" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "enabled": true, + "frequency": "10s", + "handler": 1, + "name": "Alert is outside range", + "notifications": [], + "severity": "critical" + }, + "alerting": {}, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "id": 18, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.12)", + "line": true, + "lineColor": "rgba(237, 46, 24, 0.60)", + "op": "lt", + "value": 10 + }, + { + "colorMode": "critical", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.12)", + "line": true, + "lineColor": "rgba(237, 46, 24, 0.60)", + "op": "gt", + "value": 80 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Alert is outside range", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 60, + 80 + ], + "type": "within_range" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "enabled": true, + "frequency": "10s", + "handler": 1, + "name": "Alert is within range", + "notifications": [], + "severity": "critical" + }, + "alerting": {}, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "id": 19, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.12)", + "line": true, + "lineColor": "rgba(237, 46, 24, 0.60)", + "op": "gt", + "value": 60 + }, + { + "colorMode": "critical", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.12)", + "line": true, + "lineColor": "rgba(237, 46, 24, 0.60)", + "op": "lt", + "value": 80 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Alert is within range", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "title": "New row" + } + ], + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "templating": { + "list": [ + { + "current": { + "text": "fakesite", + "value": "fakesite" + }, + "datasource": null, + "hide": 0, + "includeAll": false, + "multi": false, + "name": "apa", + "options": [ + { + "selected": true, + "text": "fakesite", + "value": "fakesite" + } + ], + "query": "fakesite", + "refresh": 0, + "type": "custom" + } + ] + }, + "annotations": { + "list": [] + }, + "schemaVersion": 13, + "version": 15, + "links": [], + "gnetId": null +} \ No newline at end of file diff --git a/examples/alerting-multiple-alerts.json b/examples/alerting-multiple-alerts.json new file mode 100644 index 00000000000..e6e729ecc06 --- /dev/null +++ b/examples/alerting-multiple-alerts.json @@ -0,0 +1,2216 @@ +{ + "__inputs": [ + { + "name": "DS_GRAPHITE", + "label": "graphite", + "description": "", + "type": "datasource", + "pluginId": "graphite", + "pluginName": "Graphite" + } + ], + "__requires": [ + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "3.1.0" + }, + { + "type": "datasource", + "id": "graphite", + "name": "Graphite", + "version": "1.0.0" + } + ], + "id": null, + "title": "Dashboard with many alerts", + "tags": [], + "style": "dark", + "timezone": "browser", + "editable": true, + "hideControls": false, + "sharedCrosshair": false, + "rows": [ + { + "collapse": false, + "editable": true, + "height": "250px", + "panels": [ + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 30 + ], + "type": "gt" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "sum" + }, + "type": "query" + } + ], + "enabled": true, + "frequency": "60s", + "handler": 1, + "name": "Critical alert panel", + "notifications": [], + "severity": "critical" + }, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "id": 1, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.12)", + "line": true, + "lineColor": "rgba(237, 46, 24, 0.60)", + "op": "gt", + "value": 30 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Critical panel", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 30 + ], + "type": "gt" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "sum" + }, + "type": "query" + } + ], + "enabled": true, + "frequency": "60s", + "handler": 1, + "name": "Critical alert panel", + "notifications": [], + "severity": "critical" + }, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "id": 5, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.12)", + "line": true, + "lineColor": "rgba(237, 46, 24, 0.60)", + "op": "gt", + "value": 30 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Critical panel", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 30 + ], + "type": "gt" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "sum" + }, + "type": "query" + } + ], + "enabled": true, + "frequency": "60s", + "handler": 1, + "name": "Critical alert panel", + "notifications": [], + "severity": "critical" + }, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "id": 6, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.12)", + "line": true, + "lineColor": "rgba(237, 46, 24, 0.60)", + "op": "gt", + "value": 30 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Critical panel", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 30 + ], + "type": "gt" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "sum" + }, + "type": "query" + } + ], + "enabled": true, + "frequency": "60s", + "handler": 1, + "name": "Critical alert panel", + "notifications": [], + "severity": "critical" + }, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "id": 8, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.12)", + "line": true, + "lineColor": "rgba(237, 46, 24, 0.60)", + "op": "gt", + "value": 30 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Critical panel", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "title": "Row" + }, + { + "collapse": false, + "editable": true, + "height": "250px", + "panels": [ + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 20 + ], + "type": "gt" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "enabled": true, + "frequency": "60s", + "handler": 1, + "name": "Warning panel alert", + "notifications": [], + "severity": "warning" + }, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "id": 2, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "colorMode": "warning", + "fill": true, + "fillColor": "rgba(235, 138, 14, 0.12)", + "line": true, + "lineColor": "rgba(247, 149, 32, 0.60)", + "op": "gt", + "value": 20 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Warning panel", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 20 + ], + "type": "gt" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "enabled": true, + "frequency": "60s", + "handler": 1, + "name": "Warning panel alert", + "notifications": [], + "severity": "warning" + }, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "id": 3, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "colorMode": "warning", + "fill": true, + "fillColor": "rgba(235, 138, 14, 0.12)", + "line": true, + "lineColor": "rgba(247, 149, 32, 0.60)", + "op": "gt", + "value": 20 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Warning panel", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 20 + ], + "type": "gt" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "enabled": true, + "frequency": "60s", + "handler": 1, + "name": "Warning panel alert", + "notifications": [], + "severity": "warning" + }, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "id": 4, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "colorMode": "warning", + "fill": true, + "fillColor": "rgba(235, 138, 14, 0.12)", + "line": true, + "lineColor": "rgba(247, 149, 32, 0.60)", + "op": "gt", + "value": 20 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Warning panel", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 20 + ], + "type": "gt" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "enabled": true, + "frequency": "60s", + "handler": 1, + "name": "Warning panel alert", + "notifications": [], + "severity": "warning" + }, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "id": 7, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "colorMode": "warning", + "fill": true, + "fillColor": "rgba(235, 138, 14, 0.12)", + "line": true, + "lineColor": "rgba(247, 149, 32, 0.60)", + "op": "gt", + "value": 20 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Warning panel", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "title": "New row" + }, + { + "collapse": false, + "editable": true, + "height": "250px", + "panels": [ + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 50 + ], + "type": "gt" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "enabled": true, + "frequency": "10s", + "handler": 1, + "name": "Fast Critical panel alert", + "notifications": [], + "severity": "critical" + }, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "id": 9, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.12)", + "line": true, + "lineColor": "rgba(237, 46, 24, 0.60)", + "op": "gt", + "value": 50 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Fast Critical panel", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 50 + ], + "type": "gt" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "enabled": true, + "frequency": "10s", + "handler": 1, + "name": "Fast Critical panel alert", + "notifications": [], + "severity": "critical" + }, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "id": 10, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.12)", + "line": true, + "lineColor": "rgba(237, 46, 24, 0.60)", + "op": "gt", + "value": 50 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Fast Critical panel", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 50 + ], + "type": "gt" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "enabled": true, + "frequency": "10s", + "handler": 1, + "name": "Fast Critical panel alert", + "notifications": [], + "severity": "critical" + }, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "id": 11, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.12)", + "line": true, + "lineColor": "rgba(237, 46, 24, 0.60)", + "op": "gt", + "value": 50 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Fast Critical panel", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 50 + ], + "type": "gt" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "enabled": true, + "frequency": "10s", + "handler": 1, + "name": "Fast Critical panel alert", + "notifications": [], + "severity": "critical" + }, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "id": 12, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.12)", + "line": true, + "lineColor": "rgba(237, 46, 24, 0.60)", + "op": "gt", + "value": 50 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Fast Critical panel", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "title": "New row" + }, + { + "collapse": false, + "editable": true, + "height": "250px", + "panels": [ + { + "alert": { + "enabled": true, + "conditions": [ + { + "type": "query", + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "type": "avg", + "params": [] + }, + "evaluator": { + "type": "gt", + "params": [ + 10 + ] + } + } + ], + "severity": "warning", + "frequency": "1s", + "handler": 1, + "notifications": [], + "name": "Fast Warning panel alert" + }, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "id": 13, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "value": 10, + "op": "gt", + "fill": true, + "line": true, + "colorMode": "warning", + "fillColor": "rgba(235, 138, 14, 0.12)", + "lineColor": "rgba(247, 149, 32, 0.60)" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Fast Warning panel", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "alert": { + "enabled": true, + "conditions": [ + { + "type": "query", + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "type": "avg", + "params": [] + }, + "evaluator": { + "type": "gt", + "params": [ + 10 + ] + } + } + ], + "severity": "warning", + "frequency": "1s", + "handler": 1, + "notifications": [], + "name": "Fast Warning panel alert" + }, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "id": 14, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "value": 10, + "op": "gt", + "fill": true, + "line": true, + "colorMode": "warning", + "fillColor": "rgba(235, 138, 14, 0.12)", + "lineColor": "rgba(247, 149, 32, 0.60)" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Fast Warning panel", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "alert": { + "enabled": true, + "conditions": [ + { + "type": "query", + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "type": "avg", + "params": [] + }, + "evaluator": { + "type": "gt", + "params": [ + 10 + ] + } + } + ], + "severity": "warning", + "frequency": "1s", + "handler": 1, + "notifications": [], + "name": "Fast Warning panel alert" + }, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "id": 15, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "value": 10, + "op": "gt", + "fill": true, + "line": true, + "colorMode": "warning", + "fillColor": "rgba(235, 138, 14, 0.12)", + "lineColor": "rgba(247, 149, 32, 0.60)" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Fast Warning panel", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "alert": { + "enabled": true, + "conditions": [ + { + "type": "query", + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "type": "avg", + "params": [] + }, + "evaluator": { + "type": "gt", + "params": [ + 10 + ] + } + } + ], + "severity": "warning", + "frequency": "1s", + "handler": 1, + "notifications": [], + "name": "Fast Warning panel alert" + }, + "aliasColors": {}, + "bars": false, + "datasource": "${DS_GRAPHITE}", + "editable": true, + "error": false, + "fill": 1, + "id": 16, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" + } + ], + "thresholds": [ + { + "value": 10, + "op": "gt", + "fill": true, + "line": true, + "colorMode": "warning", + "fillColor": "rgba(235, 138, 14, 0.12)", + "lineColor": "rgba(247, 149, 32, 0.60)" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Fast Warning panel", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "show": true + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "title": "New row" + }, + { + "title": "New row", + "height": "250px", + "editable": true, + "collapse": false, + "panels": [ + { + "title": "Alert below value", + "error": false, + "span": 3, + "editable": true, + "type": "graph", + "isNew": true, + "id": 17, + "targets": [ + { + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)", + "refId": "A" + } + ], + "datasource": "${DS_GRAPHITE}", + "renderer": "flot", + "yaxes": [ + { + "label": null, + "show": true, + "logBase": 1, + "min": null, + "max": null, + "format": "short" + }, + { + "label": null, + "show": true, + "logBase": 1, + "min": null, + "max": null, + "format": "short" + } + ], + "xaxis": { + "show": true + }, + "alert": { + "conditions": [ + { + "type": "query", + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "type": "avg", + "params": [] + }, + "evaluator": { + "type": "lt", + "params": [ + 20 + ] + } + } + ], + "severity": "critical", + "frequency": "60s", + "handler": 1, + "notifications": [], + "name": "Alert below value", + "enabled": true + }, + "lines": true, + "fill": 1, + "linewidth": 2, + "points": false, + "pointradius": 5, + "bars": false, + "stack": false, + "percentage": false, + "legend": { + "show": true, + "values": false, + "min": false, + "max": false, + "current": false, + "total": false, + "avg": false + }, + "nullPointMode": "connected", + "steppedLine": false, + "tooltip": { + "value_type": "cumulative", + "shared": true, + "sort": 0, + "msResolution": false + }, + "timeFrom": null, + "timeShift": null, + "aliasColors": {}, + "seriesOverrides": [], + "thresholds": [ + { + "value": 20, + "op": "lt", + "fill": true, + "line": true, + "colorMode": "critical", + "fillColor": "rgba(234, 112, 112, 0.12)", + "lineColor": "rgba(237, 46, 24, 0.60)" + } + ], + "links": [] + }, + { + "title": "Alert is outside range", + "error": false, + "span": 3, + "editable": true, + "type": "graph", + "isNew": true, + "id": 18, + "targets": [ + { + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)", + "refId": "A" + } + ], + "datasource": "${DS_GRAPHITE}", + "renderer": "flot", + "yaxes": [ + { + "label": null, + "show": true, + "logBase": 1, + "min": null, + "max": null, + "format": "short" + }, + { + "label": null, + "show": true, + "logBase": 1, + "min": null, + "max": null, + "format": "short" + } + ], + "xaxis": { + "show": true + }, + "alert": { + "conditions": [ + { + "type": "query", + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "type": "avg", + "params": [] + }, + "evaluator": { + "type": "outside_range", + "params": [ + 10, + 80 + ] + } + } + ], + "severity": "critical", + "frequency": "10s", + "handler": 1, + "notifications": [], + "name": "Alert is outside range", + "enabled": true + }, + "lines": true, + "fill": 1, + "linewidth": 2, + "points": false, + "pointradius": 5, + "bars": false, + "stack": false, + "percentage": false, + "legend": { + "show": true, + "values": false, + "min": false, + "max": false, + "current": false, + "total": false, + "avg": false + }, + "nullPointMode": "connected", + "steppedLine": false, + "tooltip": { + "value_type": "cumulative", + "shared": true, + "sort": 0, + "msResolution": false + }, + "timeFrom": null, + "timeShift": null, + "aliasColors": {}, + "seriesOverrides": [], + "thresholds": [ + { + "value": 10, + "op": "lt", + "fill": true, + "line": true, + "colorMode": "critical", + "fillColor": "rgba(234, 112, 112, 0.12)", + "lineColor": "rgba(237, 46, 24, 0.60)" + }, + { + "value": 80, + "op": "gt", + "fill": true, + "line": true, + "colorMode": "critical", + "fillColor": "rgba(234, 112, 112, 0.12)", + "lineColor": "rgba(237, 46, 24, 0.60)" + } + ], + "links": [] + }, + { + "title": "Alert is within range", + "error": false, + "span": 3, + "editable": true, + "type": "graph", + "isNew": true, + "id": 19, + "targets": [ + { + "target": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)", + "refId": "A" + } + ], + "datasource": "${DS_GRAPHITE}", + "renderer": "flot", + "yaxes": [ + { + "label": null, + "show": true, + "logBase": 1, + "min": null, + "max": null, + "format": "short" + }, + { + "label": null, + "show": true, + "logBase": 1, + "min": null, + "max": null, + "format": "short" + } + ], + "xaxis": { + "show": true + }, + "alert": { + "conditions": [ + { + "type": "query", + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "type": "avg", + "params": [] + }, + "evaluator": { + "type": "within_range", + "params": [ + 60, + 80 + ] + } + } + ], + "severity": "critical", + "frequency": "10s", + "handler": 1, + "notifications": [], + "name": "Alert is within range", + "enabled": true + }, + "lines": true, + "fill": 1, + "linewidth": 2, + "points": false, + "pointradius": 5, + "bars": false, + "stack": false, + "percentage": false, + "legend": { + "show": true, + "values": false, + "min": false, + "max": false, + "current": false, + "total": false, + "avg": false + }, + "nullPointMode": "connected", + "steppedLine": false, + "tooltip": { + "value_type": "cumulative", + "shared": true, + "sort": 0, + "msResolution": false + }, + "timeFrom": null, + "timeShift": null, + "aliasColors": {}, + "seriesOverrides": [], + "thresholds": [ + { + "value": 60, + "op": "gt", + "fill": true, + "line": true, + "colorMode": "critical", + "fillColor": "rgba(234, 112, 112, 0.12)", + "lineColor": "rgba(237, 46, 24, 0.60)" + }, + { + "value": 80, + "op": "lt", + "fill": true, + "line": true, + "colorMode": "critical", + "fillColor": "rgba(234, 112, 112, 0.12)", + "lineColor": "rgba(237, 46, 24, 0.60)" + } + ], + "links": [] + } + ] + } + ], + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "templating": { + "list": [] + }, + "annotations": { + "list": [] + }, + "schemaVersion": 13, + "version": 50, + "links": [], + "gnetId": null +} \ No newline at end of file diff --git a/package.json b/package.json index 5490435309f..bc356554859 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ }, "devDependencies": { "zone.js": "^0.6.6", - "autoprefixer": "^6.3.3", + "autoprefixer": "^6.4.0", "es6-promise": "^3.0.2", "es6-shim": "^0.35.1", "expect.js": "~0.2.0", diff --git a/packaging/release_process.md b/packaging/release_process.md new file mode 100644 index 00000000000..6037a9c499c --- /dev/null +++ b/packaging/release_process.md @@ -0,0 +1,29 @@ +# New Grafana Release Processes + +## Building release packages + +1) Update package.json so that it has the right version. +2) Create a git tag for the release: `git tag -a v3.0.4 -m "3.0.4 release"` +3) Push branch & tag to github! +2) Packages from master a built automatically by circle CI for this repo [grafana/grafana-packer](https://github.com/grafana/grafana-packer) + +### Non master branch + +When building from non master branch create a new branch in repo [grafana/grafana-packer](https://github.com/grafana/grafana-packer) +and configure circle.yml to deploy that branch as well, https://github.com/grafana/grafana-packer/blob/master/circle.yml#L25, +you also need to update https://github.com/grafana/grafana-packer/blob/v3.1.x/deploy.sh#L7. + +### Windows build + +Sign into ci.appveyor.com and the Grafana project's build history page. Builds for windows take a long time (around 20min) +and fail quite often for random reasons so I usually continue with the release process without a windows build already built. + +1) Click on the green build that has the correct version and tag +2) Click on `DEPLOYMENTS` +3) Click on `NEW DEPLOYMENT` +4) Select GrafanaBuildS3 +4) Select the build you want to deploy. + +The deployment should be quick (just uploads the release zip file to S3) + + diff --git a/pkg/Godeps/Godeps.json b/pkg/Godeps/Godeps.json new file mode 100644 index 00000000000..5cff21cdba5 --- /dev/null +++ b/pkg/Godeps/Godeps.json @@ -0,0 +1,9 @@ +{ + "ImportPath": "github.com/grafana/grafana/pkg", + "GoVersion": "go1.6", + "GodepVersion": "v60", + "Packages": [ + "./pkg/..." + ], + "Deps": [] +} diff --git a/pkg/Godeps/Readme b/pkg/Godeps/Readme new file mode 100644 index 00000000000..4cdaa53d56d --- /dev/null +++ b/pkg/Godeps/Readme @@ -0,0 +1,5 @@ +This directory tree is generated automatically by godep. + +Please do not edit. + +See https://github.com/tools/godep for more information. diff --git a/pkg/api/alerting.go b/pkg/api/alerting.go new file mode 100644 index 00000000000..f20e08a5cad --- /dev/null +++ b/pkg/api/alerting.go @@ -0,0 +1,214 @@ +package api + +import ( + "fmt" + + "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/middleware" + "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/alerting" +) + +func ValidateOrgAlert(c *middleware.Context) { + id := c.ParamsInt64(":alertId") + query := models.GetAlertByIdQuery{Id: id} + + if err := bus.Dispatch(&query); err != nil { + c.JsonApiErr(404, "Alert not found", nil) + return + } + + if c.OrgId != query.Result.OrgId { + c.JsonApiErr(403, "You are not allowed to edit/view alert", nil) + return + } +} + +// GET /api/alerts/rules/ +func GetAlerts(c *middleware.Context) Response { + query := models.GetAlertsQuery{ + OrgId: c.OrgId, + State: c.QueryStrings("state"), + DashboardId: c.QueryInt64("dashboardId"), + PanelId: c.QueryInt64("panelId"), + } + + if err := bus.Dispatch(&query); err != nil { + return ApiError(500, "List alerts failed", err) + } + + dashboardIds := make([]int64, 0) + alertDTOs := make([]*dtos.AlertRule, 0) + for _, alert := range query.Result { + dashboardIds = append(dashboardIds, alert.DashboardId) + alertDTOs = append(alertDTOs, &dtos.AlertRule{ + Id: alert.Id, + DashboardId: alert.DashboardId, + PanelId: alert.PanelId, + Name: alert.Name, + Message: alert.Message, + State: alert.State, + Severity: alert.Severity, + EvalDate: alert.EvalDate, + NewStateDate: alert.NewStateDate, + ExecutionError: alert.ExecutionError, + }) + } + + dashboardsQuery := models.GetDashboardsQuery{ + DashboardIds: dashboardIds, + } + + if len(alertDTOs) > 0 { + if err := bus.Dispatch(&dashboardsQuery); err != nil { + return ApiError(500, "List alerts failed", err) + } + } + + //TODO: should be possible to speed this up with lookup table + for _, alert := range alertDTOs { + for _, dash := range dashboardsQuery.Result { + if alert.DashboardId == dash.Id { + alert.DashbboardUri = "db/" + dash.Slug + } + } + } + + return Json(200, alertDTOs) +} + +// POST /api/alerts/test +func AlertTest(c *middleware.Context, dto dtos.AlertTestCommand) Response { + backendCmd := alerting.AlertTestCommand{ + OrgId: c.OrgId, + Dashboard: dto.Dashboard, + PanelId: dto.PanelId, + } + + if err := bus.Dispatch(&backendCmd); err != nil { + if validationErr, ok := err.(alerting.ValidationError); ok { + return ApiError(422, validationErr.Error(), nil) + } + return ApiError(500, "Failed to test rule", err) + } + + res := backendCmd.Result + + dtoRes := &dtos.AlertTestResult{ + Firing: res.Firing, + } + + if res.Error != nil { + dtoRes.Error = res.Error.Error() + } + + for _, log := range res.Logs { + dtoRes.Logs = append(dtoRes.Logs, &dtos.AlertTestResultLog{Message: log.Message, Data: log.Data}) + } + for _, match := range res.EvalMatches { + dtoRes.EvalMatches = append(dtoRes.EvalMatches, &dtos.EvalMatch{Metric: match.Metric, Value: match.Value}) + } + + dtoRes.TimeMs = fmt.Sprintf("%1.3fms", res.GetDurationMs()) + + return Json(200, dtoRes) +} + +// GET /api/alerts/:id +func GetAlert(c *middleware.Context) Response { + id := c.ParamsInt64(":alertId") + query := models.GetAlertByIdQuery{Id: id} + + if err := bus.Dispatch(&query); err != nil { + return ApiError(500, "List alerts failed", err) + } + + return Json(200, &query.Result) +} + +// DEL /api/alerts/:id +func DelAlert(c *middleware.Context) Response { + alertId := c.ParamsInt64(":alertId") + + if alertId == 0 { + return ApiError(401, "Failed to parse alertid", nil) + } + + cmd := models.DeleteAlertCommand{AlertId: alertId} + + if err := bus.Dispatch(&cmd); err != nil { + return ApiError(500, "Failed to delete alert", err) + } + + var resp = map[string]interface{}{"alertId": alertId} + return Json(200, resp) +} + +func GetAlertNotifications(c *middleware.Context) Response { + query := &models.GetAlertNotificationsQuery{OrgId: c.OrgId} + + if err := bus.Dispatch(query); err != nil { + return ApiError(500, "Failed to get alert notifications", err) + } + + var result []dtos.AlertNotification + + for _, notification := range query.Result { + result = append(result, dtos.AlertNotification{ + Id: notification.Id, + Name: notification.Name, + Type: notification.Type, + Created: notification.Created, + Updated: notification.Updated, + }) + } + + return Json(200, result) +} + +func GetAlertNotificationById(c *middleware.Context) Response { + query := &models.GetAlertNotificationsQuery{ + OrgId: c.OrgId, + Id: c.ParamsInt64("notificationId"), + } + + if err := bus.Dispatch(query); err != nil { + return ApiError(500, "Failed to get alert notifications", err) + } + + return Json(200, query.Result[0]) +} + +func CreateAlertNotification(c *middleware.Context, cmd models.CreateAlertNotificationCommand) Response { + cmd.OrgId = c.OrgId + + if err := bus.Dispatch(&cmd); err != nil { + return ApiError(500, "Failed to create alert notification", err) + } + + return Json(200, cmd.Result) +} + +func UpdateAlertNotification(c *middleware.Context, cmd models.UpdateAlertNotificationCommand) Response { + cmd.OrgId = c.OrgId + + if err := bus.Dispatch(&cmd); err != nil { + return ApiError(500, "Failed to update alert notification", err) + } + + return Json(200, cmd.Result) +} + +func DeleteAlertNotification(c *middleware.Context) Response { + cmd := models.DeleteAlertNotificationCommand{ + OrgId: c.OrgId, + Id: c.ParamsInt64("notificationId"), + } + + if err := bus.Dispatch(&cmd); err != nil { + return ApiError(500, "Failed to delete alert notification", err) + } + + return ApiSuccess("Notification deleted") +} diff --git a/pkg/api/api.go b/pkg/api/api.go index 8c45c8e6d8b..b95e7dc5459 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -61,6 +61,8 @@ func Register(r *macaron.Macaron) { r.Get("/playlists/", reqSignedIn, Index) r.Get("/playlists/*", reqSignedIn, Index) + r.Get("/alerting/", reqSignedIn, Index) + r.Get("/alerting/*", reqSignedIn, Index) // sign up r.Get("/signup", Index) @@ -243,6 +245,24 @@ func Register(r *macaron.Macaron) { // metrics r.Get("/metrics", wrap(GetInternalMetrics)) + r.Group("/alerts", func() { + r.Post("/test", bind(dtos.AlertTestCommand{}), wrap(AlertTest)) + //r.Get("/:alertId/states", wrap(GetAlertStates)) + //r.Put("/:alertId/state", bind(m.UpdateAlertStateCommand{}), wrap(PutAlertState)) + r.Get("/:alertId", ValidateOrgAlert, wrap(GetAlert)) + //r.Delete("/:alertId", ValidateOrgAlert, wrap(DelAlert)) disabled until we know how to handle it dashboard updates + r.Get("/", wrap(GetAlerts)) + }) + + r.Get("/alert-notifications", wrap(GetAlertNotifications)) + + r.Group("/alert-notifications", func() { + r.Post("/", bind(m.CreateAlertNotificationCommand{}), wrap(CreateAlertNotification)) + r.Put("/:notificationId", bind(m.UpdateAlertNotificationCommand{}), wrap(UpdateAlertNotification)) + r.Get("/:notificationId", wrap(GetAlertNotificationById)) + r.Delete("/:notificationId", wrap(DeleteAlertNotification)) + }, reqOrgAdmin) + // error test r.Get("/metrics/error", wrap(GenerateError)) diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go index 041f2a7f8cf..1812226aa90 100644 --- a/pkg/api/dashboard.go +++ b/pkg/api/dashboard.go @@ -13,6 +13,7 @@ import ( "github.com/grafana/grafana/pkg/middleware" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/plugins" + "github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/search" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" @@ -152,6 +153,18 @@ func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) Response { return ApiError(500, "Failed to save dashboard", err) } + if setting.AlertingEnabled { + alertCmd := alerting.UpdateDashboardAlertsCommand{ + OrgId: c.OrgId, + UserId: c.UserId, + Dashboard: cmd.Result, + } + + if err := bus.Dispatch(&alertCmd); err != nil { + return ApiError(500, "Failed to save alerts", err) + } + } + c.TimeRequest(metrics.M_Api_Dashboard_Save) return Json(200, util.DynMap{"status": "success", "slug": cmd.Result.Slug, "version": cmd.Result.Version}) } diff --git a/pkg/api/dataproxy.go b/pkg/api/dataproxy.go index b4860fcb1fb..66d654d4d93 100644 --- a/pkg/api/dataproxy.go +++ b/pkg/api/dataproxy.go @@ -77,7 +77,7 @@ func getDatasource(id int64, orgId int64) (*m.DataSource, error) { return nil, err } - return &query.Result, nil + return query.Result, nil } func ProxyDataSourceRequest(c *middleware.Context) { diff --git a/pkg/api/datasources.go b/pkg/api/datasources.go index 63c2ec57b7a..62a83bdaa0b 100644 --- a/pkg/api/datasources.go +++ b/pkg/api/datasources.go @@ -123,9 +123,7 @@ func GetDataSourceByName(c *middleware.Context) Response { return ApiError(500, "Failed to query datasources", err) } - ds := query.Result - dtos := convertModelToDtos(ds) - + dtos := convertModelToDtos(query.Result) return Json(200, &dtos) } @@ -148,7 +146,7 @@ func GetDataSourceIdByName(c *middleware.Context) Response { return Json(200, &dtos) } -func convertModelToDtos(ds m.DataSource) dtos.DataSource { +func convertModelToDtos(ds *m.DataSource) dtos.DataSource { return dtos.DataSource{ Id: ds.Id, OrgId: ds.OrgId, diff --git a/pkg/api/dtos/alerting.go b/pkg/api/dtos/alerting.go new file mode 100644 index 00000000000..0ec0174a949 --- /dev/null +++ b/pkg/api/dtos/alerting.go @@ -0,0 +1,54 @@ +package dtos + +import ( + "time" + + "github.com/grafana/grafana/pkg/components/simplejson" + m "github.com/grafana/grafana/pkg/models" +) + +type AlertRule struct { + Id int64 `json:"id"` + DashboardId int64 `json:"dashboardId"` + PanelId int64 `json:"panelId"` + Name string `json:"name"` + Message string `json:"message"` + State m.AlertStateType `json:"state"` + Severity m.AlertSeverityType `json:"severity"` + NewStateDate time.Time `json:"newStateDate"` + EvalDate time.Time `json:"evalDate"` + ExecutionError string `json:"executionError"` + DashbboardUri string `json:"dashboardUri"` +} + +type AlertNotification struct { + Id int64 `json:"id"` + Name string `json:"name"` + Type string `json:"type"` + Created time.Time `json:"created"` + Updated time.Time `json:"updated"` +} + +type AlertTestCommand struct { + Dashboard *simplejson.Json `json:"dashboard" binding:"Required"` + PanelId int64 `json:"panelId" binding:"Required"` +} + +type AlertTestResult struct { + Firing bool `json:"firing"` + TimeMs string `json:"timeMs"` + Error string `json:"error,omitempty"` + EvalMatches []*EvalMatch `json:"matches,omitempty"` + Logs []*AlertTestResultLog `json:"logs,omitempty"` +} + +type AlertTestResultLog struct { + Message string `json:"message"` + Data interface{} `json:"data"` +} + +type EvalMatch struct { + Tags map[string]string `json:"tags,omitempty"` + Metric string `json:"metric"` + Value float64 `json:"value"` +} diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index 9fcd5e567fb..5a84409d2c1 100644 --- a/pkg/api/frontendsettings.go +++ b/pkg/api/frontendsettings.go @@ -144,6 +144,7 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro "hasUpdate": plugins.GrafanaHasUpdate, "env": setting.Env, }, + "alertingEnabled": setting.AlertingEnabled, } return jsonObj, nil diff --git a/pkg/api/index.go b/pkg/api/index.go index e44e963d82c..e9d784cb652 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -91,6 +91,20 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { Children: dashboardChildNavs, }) + if setting.AlertingEnabled && (c.OrgRole == m.ROLE_ADMIN || c.OrgRole == m.ROLE_EDITOR) { + alertChildNavs := []*dtos.NavLink{ + {Text: "Alert List", Url: setting.AppSubUrl + "/alerting/list"}, + {Text: "Notifications", Url: setting.AppSubUrl + "/alerting/notifications"}, + } + + data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{ + Text: "Alerting", + Icon: "icon-gf icon-gf-alert", + Url: setting.AppSubUrl + "/alerting/list", + Children: alertChildNavs, + }) + } + if c.OrgRole == m.ROLE_ADMIN { data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{ Text: "Data Sources", diff --git a/pkg/api/login_oauth.go b/pkg/api/login_oauth.go index 4244feef664..6512a827341 100644 --- a/pkg/api/login_oauth.go +++ b/pkg/api/login_oauth.go @@ -8,7 +8,6 @@ import ( "golang.org/x/oauth2" "github.com/grafana/grafana/pkg/bus" - "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/metrics" "github.com/grafana/grafana/pkg/middleware" m "github.com/grafana/grafana/pkg/models" @@ -42,7 +41,7 @@ func OAuthLogin(ctx *middleware.Context) { return } - log.Trace("login.OAuthLogin(Got token)") + ctx.Logger.Debug("OAuthLogin Got token") userInfo, err := connect.UserInfo(token) if err != nil { @@ -56,11 +55,11 @@ func OAuthLogin(ctx *middleware.Context) { return } - log.Trace("login.OAuthLogin(social login): %s", userInfo) + ctx.Logger.Debug("OAuthLogin got user info", "userInfo", userInfo) // validate that the email is allowed to login to grafana if !connect.IsEmailAllowed(userInfo.Email) { - log.Info("OAuth login attempt with unallowed email, %s", userInfo.Email) + ctx.Logger.Info("OAuth login attempt with unallowed email", "email", userInfo.Email) ctx.Redirect(setting.AppSubUrl + "/login?failedMsg=" + url.QueryEscape("Required email domain not fulfilled")) return } diff --git a/pkg/cmd/grafana-server/main.go b/pkg/cmd/grafana-server/main.go index 29cb5222e03..d3d291a74bf 100644 --- a/pkg/cmd/grafana-server/main.go +++ b/pkg/cmd/grafana-server/main.go @@ -16,6 +16,7 @@ import ( "github.com/grafana/grafana/pkg/login" "github.com/grafana/grafana/pkg/metrics" "github.com/grafana/grafana/pkg/plugins" + alertingInit "github.com/grafana/grafana/pkg/services/alerting/init" "github.com/grafana/grafana/pkg/services/eventpublisher" "github.com/grafana/grafana/pkg/services/notifications" "github.com/grafana/grafana/pkg/services/search" @@ -67,6 +68,7 @@ func main() { social.NewOAuthService() eventpublisher.Init() plugins.Init() + alertingInit.Init() if err := notifications.Init(); err != nil { log.Fatal(3, "Notification service failed to initialize", err) diff --git a/pkg/components/imguploader/imguploader.go b/pkg/components/imguploader/imguploader.go new file mode 100644 index 00000000000..5b383e69f34 --- /dev/null +++ b/pkg/components/imguploader/imguploader.go @@ -0,0 +1,57 @@ +package imguploader + +import ( + "fmt" + + "github.com/grafana/grafana/pkg/setting" +) + +type ImageUploader interface { + Upload(path string) (string, error) +} + +func NewImageUploader() (ImageUploader, error) { + + switch setting.ImageUploadProvider { + case "s3": + s3sec, err := setting.Cfg.GetSection("external_image_storage.s3") + if err != nil { + return nil, err + } + + bucket := s3sec.Key("secret_key").String() + accessKey := s3sec.Key("access_key").String() + secretKey := s3sec.Key("secret_key").String() + + if bucket == "" { + return nil, fmt.Errorf("Could not find bucket setting for image.uploader.s3") + } + + if accessKey == "" { + return nil, fmt.Errorf("Could not find accessKey setting for image.uploader.s3") + } + + if secretKey == "" { + return nil, fmt.Errorf("Could not find secretKey setting for image.uploader.s3") + } + + return NewS3Uploader(bucket, accessKey, secretKey), nil + case "webdav": + webdavSec, err := setting.Cfg.GetSection("external_image_storage.webdav") + if err != nil { + return nil, err + } + + url := webdavSec.Key("url").String() + if url == "" { + return nil, fmt.Errorf("Could not find url key for image.uploader.webdav") + } + + username := webdavSec.Key("username").String() + password := webdavSec.Key("password").String() + + return NewWebdavImageUploader(url, username, password) + } + + return nil, fmt.Errorf("could not find specified provider") +} diff --git a/pkg/components/imguploader/imguploader_test.go b/pkg/components/imguploader/imguploader_test.go new file mode 100644 index 00000000000..d12464dae69 --- /dev/null +++ b/pkg/components/imguploader/imguploader_test.go @@ -0,0 +1,53 @@ +package imguploader + +import ( + "reflect" + "testing" + + "github.com/grafana/grafana/pkg/setting" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestImageUploaderFactory(t *testing.T) { + Convey("Can create image uploader for ", t, func() { + Convey("S3ImageUploader", func() { + var err error + setting.NewConfigContext(&setting.CommandLineArgs{ + HomePath: "../../../", + }) + + setting.ImageUploadProvider = "s3" + + s3sec, err := setting.Cfg.GetSection("external_image_storage.s3") + s3sec.NewKey("bucket_url", "bucket_url") + s3sec.NewKey("access_key", "access_key") + s3sec.NewKey("secret_key", "secret_key") + + uploader, err := NewImageUploader() + + So(err, ShouldBeNil) + So(reflect.TypeOf(uploader), ShouldEqual, reflect.TypeOf(&S3Uploader{})) + }) + + Convey("Webdav uploader", func() { + var err error + + setting.NewConfigContext(&setting.CommandLineArgs{ + HomePath: "../../../", + }) + + setting.ImageUploadProvider = "webdav" + + webdavSec, err := setting.Cfg.GetSection("external_image_storage.webdav") + webdavSec.NewKey("url", "webdavUrl") + webdavSec.NewKey("username", "username") + webdavSec.NewKey("password", "password") + + uploader, err := NewImageUploader() + + So(err, ShouldBeNil) + So(reflect.TypeOf(uploader), ShouldEqual, reflect.TypeOf(&WebdavUploader{})) + }) + }) +} diff --git a/pkg/components/imguploader/s3uploader.go b/pkg/components/imguploader/s3uploader.go new file mode 100644 index 00000000000..af995d566c1 --- /dev/null +++ b/pkg/components/imguploader/s3uploader.go @@ -0,0 +1,53 @@ +package imguploader + +import ( + "io/ioutil" + "net/http" + + "github.com/grafana/grafana/pkg/util" + "github.com/kr/s3/s3util" +) + +type S3Uploader struct { + bucket string + secretKey string + accessKey string +} + +func NewS3Uploader(bucket, accessKey, secretKey string) *S3Uploader { + return &S3Uploader{ + bucket: bucket, + accessKey: accessKey, + secretKey: secretKey, + } +} + +func (u *S3Uploader) Upload(path string) (string, error) { + + s3util.DefaultConfig.AccessKey = u.accessKey + s3util.DefaultConfig.SecretKey = u.secretKey + + header := make(http.Header) + header.Add("x-amz-acl", "public-read") + header.Add("Content-Type", "image/png") + + fullUrl := u.bucket + util.GetRandomString(20) + ".png" + writer, err := s3util.Create(fullUrl, header, nil) + if err != nil { + return "", err + } + + defer writer.Close() + + imgData, err := ioutil.ReadFile(path) + if err != nil { + return "", err + } + + _, err = writer.Write(imgData) + if err != nil { + return "", err + } + + return fullUrl, nil +} diff --git a/pkg/components/imguploader/webdavuploader.go b/pkg/components/imguploader/webdavuploader.go new file mode 100644 index 00000000000..74444b1b123 --- /dev/null +++ b/pkg/components/imguploader/webdavuploader.go @@ -0,0 +1,51 @@ +package imguploader + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "path" + "time" + + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/util" +) + +type WebdavUploader struct { + url string + username string + password string +} + +func (u *WebdavUploader) Upload(pa string) (string, error) { + log.Error2("Hej") + client := http.Client{Timeout: time.Duration(10 * time.Second)} + + url, _ := url.Parse(u.url) + url.Path = path.Join(url.Path, util.GetRandomString(20)+".png") + + imgData, err := ioutil.ReadFile(pa) + req, err := http.NewRequest("PUT", url.String(), bytes.NewReader(imgData)) + res, err := client.Do(req) + + if err != nil { + return "", err + } + + if res.StatusCode != http.StatusCreated { + body, _ := ioutil.ReadAll(res.Body) + return "", fmt.Errorf("Failed to upload image. Returned statuscode %v body %s", res.StatusCode, body) + } + + return url.String(), nil +} + +func NewWebdavImageUploader(url, username, passwrod string) (*WebdavUploader, error) { + return &WebdavUploader{ + url: url, + username: username, + password: passwrod, + }, nil +} diff --git a/pkg/components/imguploader/webdavuploader_test.go b/pkg/components/imguploader/webdavuploader_test.go new file mode 100644 index 00000000000..273cd1c2a86 --- /dev/null +++ b/pkg/components/imguploader/webdavuploader_test.go @@ -0,0 +1,18 @@ +package imguploader + +import ( + "testing" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestUploadToWebdav(t *testing.T) { + webdavUploader, _ := NewWebdavImageUploader("http://localhost:9998/dav/", "username", "password") + + SkipConvey("[Integration test] for external_image_store.webdav", t, func() { + path, err := webdavUploader.Upload("../../../public/img/logo_transparent_400x.png") + + So(err, ShouldBeNil) + So(path, ShouldNotEqual, "") + }) +} diff --git a/pkg/components/renderer/renderer.go b/pkg/components/renderer/renderer.go index d6091a3cb19..ad8f76e03aa 100644 --- a/pkg/components/renderer/renderer.go +++ b/pkg/components/renderer/renderer.go @@ -9,10 +9,11 @@ import ( "runtime" "time" + "strconv" + "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" - "strconv" ) type RenderOpts struct { @@ -23,8 +24,10 @@ type RenderOpts struct { Timeout string } +var rendererLog log.Logger = log.New("png-renderer") + func RenderToPng(params *RenderOpts) (string, error) { - log.Info("PhantomRenderer::renderToPng url %v", params.Url) + rendererLog.Info("Rendering", "url", params.Url) var executable = "phantomjs" if runtime.GOOS == "windows" { @@ -71,11 +74,12 @@ func RenderToPng(params *RenderOpts) (string, error) { select { case <-time.After(time.Duration(timeout) * time.Second): if err := cmd.Process.Kill(); err != nil { - log.Error(4, "failed to kill: %v", err) + rendererLog.Error("failed to kill", "error", err) } return "", fmt.Errorf("PhantomRenderer::renderToPng timeout (>%vs)", timeout) case <-done: } + rendererLog.Debug("Image rendered", "path", pngPath) return pngPath, nil } diff --git a/pkg/log/log.go b/pkg/log/log.go index 15fa8e0cb74..34a2aed4762 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -12,6 +12,7 @@ import ( "gopkg.in/ini.v1" + "github.com/go-stack/stack" "github.com/inconshreveable/log15" "github.com/inconshreveable/log15/term" ) @@ -115,7 +116,9 @@ func getFilters(filterStrArray []string) map[string]log15.Lvl { for _, filterStr := range filterStrArray { parts := strings.Split(filterStr, ":") - filterMap[parts[0]] = getLogLevelFromString(parts[1]) + if len(parts) > 1 { + filterMap[parts[0]] = getLogLevelFromString(parts[1]) + } } return filterMap @@ -218,3 +221,9 @@ func LogFilterHandler(maxLevel log15.Lvl, filters map[string]log15.Lvl, h log15. return r.Lvl <= maxLevel }, h) } + +func Stack(skip int) string { + call := stack.Caller(skip) + s := stack.Trace().TrimBelow(call).TrimRuntime() + return s.String() +} diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index 9982827d858..9477f2738b5 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -9,29 +9,38 @@ func init() { } var ( - M_Instance_Start Counter - M_Page_Status_200 Counter - M_Page_Status_500 Counter - M_Page_Status_404 Counter - M_Api_Status_500 Counter - M_Api_Status_404 Counter - M_Api_User_SignUpStarted Counter - M_Api_User_SignUpCompleted Counter - M_Api_User_SignUpInvite Counter - M_Api_Dashboard_Save Timer - M_Api_Dashboard_Get Timer - M_Api_Dashboard_Search Timer - M_Api_Admin_User_Create Counter - M_Api_Login_Post Counter - M_Api_Login_OAuth Counter - M_Api_Org_Create Counter - M_Api_Dashboard_Snapshot_Create Counter - M_Api_Dashboard_Snapshot_External Counter - M_Api_Dashboard_Snapshot_Get Counter - M_Models_Dashboard_Insert Counter + M_Instance_Start Counter + M_Page_Status_200 Counter + M_Page_Status_500 Counter + M_Page_Status_404 Counter + M_Api_Status_500 Counter + M_Api_Status_404 Counter + M_Api_User_SignUpStarted Counter + M_Api_User_SignUpCompleted Counter + M_Api_User_SignUpInvite Counter + M_Api_Dashboard_Save Timer + M_Api_Dashboard_Get Timer + M_Api_Dashboard_Search Timer + M_Api_Admin_User_Create Counter + M_Api_Login_Post Counter + M_Api_Login_OAuth Counter + M_Api_Org_Create Counter + M_Api_Dashboard_Snapshot_Create Counter + M_Api_Dashboard_Snapshot_External Counter + M_Api_Dashboard_Snapshot_Get Counter + M_Models_Dashboard_Insert Counter + M_Alerting_Result_Critical Counter + M_Alerting_Result_Warning Counter + M_Alerting_Result_Info Counter + M_Alerting_Result_Ok Counter + M_Alerting_Active_Alerts Counter + M_Alerting_Notification_Sent_Slack Counter + M_Alerting_Notification_Sent_Email Counter + M_Alerting_Notification_Sent_Webhook Counter // Timers M_DataSource_ProxyReq_Timer Timer + M_Alerting_Exeuction_Time Timer ) func initMetricVars(settings *MetricSettings) { @@ -66,6 +75,16 @@ func initMetricVars(settings *MetricSettings) { M_Models_Dashboard_Insert = RegCounter("models.dashboard.insert") + M_Alerting_Result_Critical = RegCounter("alerting.result", "severity", "critical") + M_Alerting_Result_Warning = RegCounter("alerting.result", "severity", "warning") + M_Alerting_Result_Info = RegCounter("alerting.result", "severity", "info") + M_Alerting_Result_Ok = RegCounter("alerting.result", "severity", "ok") + M_Alerting_Active_Alerts = RegCounter("alerting.active_alerts") + M_Alerting_Notification_Sent_Slack = RegCounter("alerting.notifications_sent", "type", "slack") + M_Alerting_Notification_Sent_Email = RegCounter("alerting.notifications_sent", "type", "email") + M_Alerting_Notification_Sent_Webhook = RegCounter("alerting.notifications_sent", "type", "webhook") + // Timers M_DataSource_ProxyReq_Timer = RegTimer("api.dataproxy.request.all") + M_Alerting_Exeuction_Time = RegTimer("alerting.execution_time") } diff --git a/pkg/models/alert.go b/pkg/models/alert.go new file mode 100644 index 00000000000..b7d0c3e0c1c --- /dev/null +++ b/pkg/models/alert.go @@ -0,0 +1,146 @@ +package models + +import ( + "time" + + "github.com/grafana/grafana/pkg/components/simplejson" +) + +type AlertStateType string +type AlertSeverityType string + +const ( + AlertStatePending AlertStateType = "pending" + AlertStateExeuctionError AlertStateType = "execution_error" + AlertStatePaused AlertStateType = "paused" + AlertStateCritical AlertStateType = "critical" + AlertStateWarning AlertStateType = "warning" + AlertStateOK AlertStateType = "ok" +) + +func (s AlertStateType) IsValid() bool { + return s == AlertStateOK || s == AlertStatePending || s == AlertStateExeuctionError || s == AlertStatePaused || s == AlertStateCritical || s == AlertStateWarning +} + +const ( + AlertSeverityCritical AlertSeverityType = "critical" + AlertSeverityWarning AlertSeverityType = "warning" + AlertSeverityInfo AlertSeverityType = "info" + AlertSeverityOK AlertSeverityType = "ok" +) + +func (s AlertSeverityType) IsValid() bool { + return s == AlertSeverityCritical || s == AlertSeverityInfo || s == AlertSeverityWarning +} + +type Alert struct { + Id int64 + Version int64 + OrgId int64 + DashboardId int64 + PanelId int64 + Name string + Message string + Severity AlertSeverityType + State AlertStateType + Handler int64 + Silenced bool + ExecutionError string + Frequency int64 + + EvalData *simplejson.Json + EvalDate time.Time + NewStateDate time.Time + StateChanges int + + Created time.Time + Updated time.Time + + Settings *simplejson.Json +} + +func (alert *Alert) ValidToSave() bool { + return alert.DashboardId != 0 && alert.OrgId != 0 && alert.PanelId != 0 +} + +func (alert *Alert) ShouldUpdateState(newState AlertStateType) bool { + return alert.State != newState +} + +func (this *Alert) ContainsUpdates(other *Alert) bool { + result := false + result = result || this.Name != other.Name + result = result || this.Message != other.Message + + if this.Settings != nil && other.Settings != nil { + json1, err1 := this.Settings.Encode() + json2, err2 := other.Settings.Encode() + + if err1 != nil || err2 != nil { + return false + } + + result = result || string(json1) != string(json2) + } + + //don't compare .State! That would be insane. + return result +} + +type AlertingClusterInfo struct { + ServerId string + ClusterSize int + UptimePosition int +} + +type HeartBeat struct { + Id int64 + ServerId string + Updated time.Time + Created time.Time +} + +type HeartBeatCommand struct { + ServerId string + Result AlertingClusterInfo +} + +type SaveAlertsCommand struct { + DashboardId int64 + UserId int64 + OrgId int64 + + Alerts []*Alert +} + +type SetAlertStateCommand struct { + AlertId int64 + OrgId int64 + State AlertStateType + Error string + Timestamp time.Time +} + +type DeleteAlertCommand struct { + AlertId int64 +} + +//Queries +type GetAlertsQuery struct { + OrgId int64 + State []string + DashboardId int64 + PanelId int64 + + Result []*Alert +} + +type GetAllAlertsQuery struct { + Result []*Alert +} + +type GetAlertByIdQuery struct { + Id int64 + + Result *Alert +} diff --git a/pkg/models/alert_notifications.go b/pkg/models/alert_notifications.go new file mode 100644 index 00000000000..464d6dc88da --- /dev/null +++ b/pkg/models/alert_notifications.go @@ -0,0 +1,50 @@ +package models + +import ( + "time" + + "github.com/grafana/grafana/pkg/components/simplejson" +) + +type AlertNotification struct { + Id int64 `json:"id"` + OrgId int64 `json:"-"` + Name string `json:"name"` + Type string `json:"type"` + Settings *simplejson.Json `json:"settings"` + Created time.Time `json:"created"` + Updated time.Time `json:"updated"` +} + +type CreateAlertNotificationCommand struct { + Name string `json:"name" binding:"Required"` + Type string `json:"type" binding:"Required"` + Settings *simplejson.Json `json:"settings"` + + OrgId int64 `json:"-"` + Result *AlertNotification +} + +type UpdateAlertNotificationCommand struct { + Id int64 `json:"id" binding:"Required"` + Name string `json:"name" binding:"Required"` + Type string `json:"type" binding:"Required"` + Settings *simplejson.Json `json:"settings" binding:"Required"` + + OrgId int64 `json:"-"` + Result *AlertNotification +} + +type DeleteAlertNotificationCommand struct { + Id int64 + OrgId int64 +} + +type GetAlertNotificationsQuery struct { + Name string + Id int64 + Ids []int64 + OrgId int64 + + Result []*AlertNotification +} diff --git a/pkg/models/alert_state.go b/pkg/models/alert_state.go new file mode 100644 index 00000000000..5071efc2171 --- /dev/null +++ b/pkg/models/alert_state.go @@ -0,0 +1,47 @@ +package models + +// type AlertState struct { +// Id int64 `json:"-"` +// OrgId int64 `json:"-"` +// AlertId int64 `json:"alertId"` +// State string `json:"state"` +// Created time.Time `json:"created"` +// Info string `json:"info"` +// TriggeredAlerts *simplejson.Json `json:"triggeredAlerts"` +// } +// +// func (this *UpdateAlertStateCommand) IsValidState() bool { +// for _, v := range alertstates.ValidStates { +// if this.State == v { +// return true +// } +// } +// return false +// } +// +// // Commands +// +// type UpdateAlertStateCommand struct { +// AlertId int64 `json:"alertId" binding:"Required"` +// OrgId int64 `json:"orgId" binding:"Required"` +// State string `json:"state" binding:"Required"` +// Info string `json:"info"` +// +// Result *Alert +// } +// +// // Queries +// +// type GetAlertsStateQuery struct { +// OrgId int64 `json:"orgId" binding:"Required"` +// AlertId int64 `json:"alertId" binding:"Required"` +// +// Result *[]AlertState +// } +// +// type GetLastAlertStateQuery struct { +// AlertId int64 +// OrgId int64 +// +// Result *AlertState +// } diff --git a/pkg/models/alert_test.go b/pkg/models/alert_test.go new file mode 100644 index 00000000000..421b90f1b21 --- /dev/null +++ b/pkg/models/alert_test.go @@ -0,0 +1,39 @@ +package models + +import ( + "testing" + + "github.com/grafana/grafana/pkg/components/simplejson" + . "github.com/smartystreets/goconvey/convey" +) + +func TestAlertingModelTest(t *testing.T) { + Convey("Testing Alerting model", t, func() { + + json1, _ := simplejson.NewJson([]byte(`{ "field": "value" }`)) + json2, _ := simplejson.NewJson([]byte(`{ "field": "value" }`)) + + rule1 := &Alert{ + Settings: json1, + Name: "Namn", + Message: "Message", + } + + rule2 := &Alert{ + Settings: json2, + Name: "Namn", + Message: "Message", + } + + Convey("Testing AlertRule equals", func() { + + So(rule1.ContainsUpdates(rule2), ShouldBeFalse) + }) + + Convey("Changing the expression should contain update", func() { + json2, _ := simplejson.NewJson([]byte(`{ "field": "newValue" }`)) + rule1.Settings = json2 + So(rule1.ContainsUpdates(rule2), ShouldBeTrue) + }) + }) +} diff --git a/pkg/models/datasource.go b/pkg/models/datasource.go index 2e9d98e9700..794266ba71e 100644 --- a/pkg/models/datasource.go +++ b/pkg/models/datasource.go @@ -131,13 +131,13 @@ type GetDataSourcesQuery struct { type GetDataSourceByIdQuery struct { Id int64 OrgId int64 - Result DataSource + Result *DataSource } type GetDataSourceByNameQuery struct { Name string OrgId int64 - Result DataSource + Result *DataSource } // --------------------- diff --git a/pkg/models/emails.go b/pkg/models/notifications.go similarity index 79% rename from pkg/models/emails.go rename to pkg/models/notifications.go index 74da180f7d8..d357b9cf562 100644 --- a/pkg/models/emails.go +++ b/pkg/models/notifications.go @@ -12,6 +12,13 @@ type SendEmailCommand struct { Info string } +type SendWebhook struct { + Url string + User string + Password string + Body string +} + type SendResetPasswordEmailCommand struct { User *User } diff --git a/pkg/services/alerting/commands.go b/pkg/services/alerting/commands.go new file mode 100644 index 00000000000..4e269aca695 --- /dev/null +++ b/pkg/services/alerting/commands.go @@ -0,0 +1,38 @@ +package alerting + +import ( + "github.com/grafana/grafana/pkg/bus" + m "github.com/grafana/grafana/pkg/models" +) + +type UpdateDashboardAlertsCommand struct { + UserId int64 + OrgId int64 + Dashboard *m.Dashboard +} + +func init() { + bus.AddHandler("alerting", updateDashboardAlerts) +} + +func updateDashboardAlerts(cmd *UpdateDashboardAlertsCommand) error { + saveAlerts := m.SaveAlertsCommand{ + OrgId: cmd.OrgId, + UserId: cmd.UserId, + DashboardId: cmd.Dashboard.Id, + } + + extractor := NewDashAlertExtractor(cmd.Dashboard, cmd.OrgId) + + if alerts, err := extractor.GetAlerts(); err != nil { + return err + } else { + saveAlerts.Alerts = alerts + } + + if err := bus.Dispatch(&saveAlerts); err != nil { + return err + } + + return nil +} diff --git a/pkg/services/alerting/conditions/common.go b/pkg/services/alerting/conditions/common.go new file mode 100644 index 00000000000..06702fd1e08 --- /dev/null +++ b/pkg/services/alerting/conditions/common.go @@ -0,0 +1 @@ +package conditions diff --git a/pkg/services/alerting/conditions/evaluator.go b/pkg/services/alerting/conditions/evaluator.go new file mode 100644 index 00000000000..8c28a278d9f --- /dev/null +++ b/pkg/services/alerting/conditions/evaluator.go @@ -0,0 +1,130 @@ +package conditions + +import ( + "encoding/json" + + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/services/alerting" + "github.com/grafana/grafana/pkg/tsdb" +) + +var ( + defaultTypes []string = []string{"gt", "lt"} + rangedTypes []string = []string{"within_range", "outside_range"} + paramlessTypes []string = []string{"no_value"} +) + +type AlertEvaluator interface { + Eval(timeSeries *tsdb.TimeSeries, reducedValue float64) bool +} + +type ParameterlessEvaluator struct { + Type string +} + +func (e *ParameterlessEvaluator) Eval(series *tsdb.TimeSeries, reducedValue float64) bool { + return len(series.Points) == 0 +} + +type ThresholdEvaluator struct { + Type string + Threshold float64 +} + +func newThresholdEvaludator(typ string, model *simplejson.Json) (*ThresholdEvaluator, error) { + params := model.Get("params").MustArray() + if len(params) == 0 { + return nil, alerting.ValidationError{Reason: "Evaluator missing threshold parameter"} + } + + firstParam, ok := params[0].(json.Number) + if !ok { + return nil, alerting.ValidationError{Reason: "Evaluator has invalid parameter"} + } + + defaultEval := &ThresholdEvaluator{Type: typ} + defaultEval.Threshold, _ = firstParam.Float64() + return defaultEval, nil +} + +func (e *ThresholdEvaluator) Eval(series *tsdb.TimeSeries, reducedValue float64) bool { + switch e.Type { + case "gt": + return reducedValue > e.Threshold + case "lt": + return reducedValue < e.Threshold + case "no_value": + return len(series.Points) == 0 + } + + return false +} + +type RangedEvaluator struct { + Type string + Lower float64 + Upper float64 +} + +func newRangedEvaluator(typ string, model *simplejson.Json) (*RangedEvaluator, error) { + params := model.Get("params").MustArray() + if len(params) == 0 { + return nil, alerting.ValidationError{Reason: "Evaluator missing threshold parameter"} + } + + firstParam, ok := params[0].(json.Number) + if !ok { + return nil, alerting.ValidationError{Reason: "Evaluator has invalid parameter"} + } + + secondParam, ok := params[1].(json.Number) + if !ok { + return nil, alerting.ValidationError{Reason: "Evaluator has invalid second parameter"} + } + + rangedEval := &RangedEvaluator{Type: typ} + rangedEval.Lower, _ = firstParam.Float64() + rangedEval.Upper, _ = secondParam.Float64() + return rangedEval, nil +} + +func (e *RangedEvaluator) Eval(series *tsdb.TimeSeries, reducedValue float64) bool { + switch e.Type { + case "within_range": + return (e.Lower < reducedValue && e.Upper > reducedValue) || (e.Upper < reducedValue && e.Lower > reducedValue) + case "outside_range": + return (e.Upper < reducedValue && e.Lower < reducedValue) || (e.Upper > reducedValue && e.Lower > reducedValue) + } + + return false +} + +func NewAlertEvaluator(model *simplejson.Json) (AlertEvaluator, error) { + typ := model.Get("type").MustString() + if typ == "" { + return nil, alerting.ValidationError{Reason: "Evaluator missing type property"} + } + + if inSlice(typ, defaultTypes) { + return newThresholdEvaludator(typ, model) + } + + if inSlice(typ, rangedTypes) { + return newRangedEvaluator(typ, model) + } + + if inSlice(typ, paramlessTypes) { + return &ParameterlessEvaluator{Type: typ}, nil + } + + return nil, alerting.ValidationError{Reason: "Evaludator invalid evaluator type"} +} + +func inSlice(a string, list []string) bool { + for _, b := range list { + if b == a { + return true + } + } + return false +} diff --git a/pkg/services/alerting/conditions/evaluator_test.go b/pkg/services/alerting/conditions/evaluator_test.go new file mode 100644 index 00000000000..8cc6899ff81 --- /dev/null +++ b/pkg/services/alerting/conditions/evaluator_test.go @@ -0,0 +1,62 @@ +package conditions + +import ( + "testing" + + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/tsdb" + . "github.com/smartystreets/goconvey/convey" +) + +func evalutorScenario(json string, reducedValue float64, datapoints ...float64) bool { + jsonModel, err := simplejson.NewJson([]byte(json)) + So(err, ShouldBeNil) + + evaluator, err := NewAlertEvaluator(jsonModel) + So(err, ShouldBeNil) + + var timeserie [][2]float64 + dummieTimestamp := float64(521452145) + + for _, v := range datapoints { + timeserie = append(timeserie, [2]float64{v, dummieTimestamp}) + } + + tsdb := &tsdb.TimeSeries{ + Name: "test time serie", + Points: timeserie, + } + + return evaluator.Eval(tsdb, reducedValue) +} + +func TestEvalutors(t *testing.T) { + Convey("greater then", t, func() { + So(evalutorScenario(`{"type": "gt", "params": [1] }`, 3), ShouldBeTrue) + So(evalutorScenario(`{"type": "gt", "params": [3] }`, 1), ShouldBeFalse) + }) + + Convey("less then", t, func() { + So(evalutorScenario(`{"type": "lt", "params": [1] }`, 3), ShouldBeFalse) + So(evalutorScenario(`{"type": "lt", "params": [3] }`, 1), ShouldBeTrue) + }) + + Convey("within_range", t, func() { + So(evalutorScenario(`{"type": "within_range", "params": [1, 100] }`, 3), ShouldBeTrue) + So(evalutorScenario(`{"type": "within_range", "params": [1, 100] }`, 300), ShouldBeFalse) + So(evalutorScenario(`{"type": "within_range", "params": [100, 1] }`, 3), ShouldBeTrue) + So(evalutorScenario(`{"type": "within_range", "params": [100, 1] }`, 300), ShouldBeFalse) + }) + + Convey("outside_range", t, func() { + So(evalutorScenario(`{"type": "outside_range", "params": [1, 100] }`, 1000), ShouldBeTrue) + So(evalutorScenario(`{"type": "outside_range", "params": [1, 100] }`, 50), ShouldBeFalse) + So(evalutorScenario(`{"type": "outside_range", "params": [100, 1] }`, 1000), ShouldBeTrue) + So(evalutorScenario(`{"type": "outside_range", "params": [100, 1] }`, 50), ShouldBeFalse) + }) + + Convey("no_value", t, func() { + So(evalutorScenario(`{"type": "no_value", "params": [] }`, 1000), ShouldBeTrue) + So(evalutorScenario(`{"type": "no_value", "params": [] }`, 1000, 1, 2), ShouldBeFalse) + }) +} diff --git a/pkg/services/alerting/conditions/query.go b/pkg/services/alerting/conditions/query.go new file mode 100644 index 00000000000..d94c2d468f2 --- /dev/null +++ b/pkg/services/alerting/conditions/query.go @@ -0,0 +1,144 @@ +package conditions + +import ( + "fmt" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/components/simplejson" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/alerting" + "github.com/grafana/grafana/pkg/tsdb" +) + +func init() { + alerting.RegisterCondition("query", func(model *simplejson.Json, index int) (alerting.Condition, error) { + return NewQueryCondition(model, index) + }) +} + +type QueryCondition struct { + Index int + Query AlertQuery + Reducer QueryReducer + Evaluator AlertEvaluator + HandleRequest tsdb.HandleRequestFunc +} + +type AlertQuery struct { + Model *simplejson.Json + DatasourceId int64 + From string + To string +} + +func (c *QueryCondition) Eval(context *alerting.EvalContext) { + seriesList, err := c.executeQuery(context) + if err != nil { + context.Error = err + return + } + + for _, series := range seriesList { + reducedValue := c.Reducer.Reduce(series) + evalMatch := c.Evaluator.Eval(series, reducedValue) + + if context.IsTestRun { + context.Logs = append(context.Logs, &alerting.ResultLogEntry{ + Message: fmt.Sprintf("Condition[%d]: Eval: %v, Metric: %s, Value: %1.3f", c.Index, evalMatch, series.Name, reducedValue), + }) + } + + if evalMatch { + context.EvalMatches = append(context.EvalMatches, &alerting.EvalMatch{ + Metric: series.Name, + Value: reducedValue, + }) + } + + context.Firing = evalMatch + } +} + +func (c *QueryCondition) executeQuery(context *alerting.EvalContext) (tsdb.TimeSeriesSlice, error) { + getDsInfo := &m.GetDataSourceByIdQuery{ + Id: c.Query.DatasourceId, + OrgId: context.Rule.OrgId, + } + + if err := bus.Dispatch(getDsInfo); err != nil { + return nil, fmt.Errorf("Could not find datasource") + } + + req := c.getRequestForAlertRule(getDsInfo.Result) + result := make(tsdb.TimeSeriesSlice, 0) + + resp, err := c.HandleRequest(req) + if err != nil { + return nil, fmt.Errorf("tsdb.HandleRequest() error %v", err) + } + + for _, v := range resp.Results { + if v.Error != nil { + return nil, fmt.Errorf("tsdb.HandleRequest() response error %v", v) + } + + result = append(result, v.Series...) + + if context.IsTestRun { + context.Logs = append(context.Logs, &alerting.ResultLogEntry{ + Message: fmt.Sprintf("Condition[%d]: Query Result", c.Index), + Data: v.Series, + }) + } + } + + return result, nil +} + +func (c *QueryCondition) getRequestForAlertRule(datasource *m.DataSource) *tsdb.Request { + req := &tsdb.Request{ + TimeRange: tsdb.TimeRange{ + From: c.Query.From, + To: c.Query.To, + }, + Queries: []*tsdb.Query{ + { + RefId: "A", + Query: c.Query.Model.Get("target").MustString(), + DataSource: &tsdb.DataSourceInfo{ + Id: datasource.Id, + Name: datasource.Name, + PluginId: datasource.Type, + Url: datasource.Url, + }, + }, + }, + } + + return req +} + +func NewQueryCondition(model *simplejson.Json, index int) (*QueryCondition, error) { + condition := QueryCondition{} + condition.Index = index + condition.HandleRequest = tsdb.HandleRequest + + queryJson := model.Get("query") + + condition.Query.Model = queryJson.Get("model") + condition.Query.From = queryJson.Get("params").MustArray()[1].(string) + condition.Query.To = queryJson.Get("params").MustArray()[2].(string) + condition.Query.DatasourceId = queryJson.Get("datasourceId").MustInt64() + + reducerJson := model.Get("reducer") + condition.Reducer = NewSimpleReducer(reducerJson.Get("type").MustString()) + + evaluatorJson := model.Get("evaluator") + evaluator, err := NewAlertEvaluator(evaluatorJson) + if err != nil { + return nil, err + } + + condition.Evaluator = evaluator + return &condition, nil +} diff --git a/pkg/services/alerting/conditions/query_test.go b/pkg/services/alerting/conditions/query_test.go new file mode 100644 index 00000000000..07cc6871801 --- /dev/null +++ b/pkg/services/alerting/conditions/query_test.go @@ -0,0 +1,116 @@ +package conditions + +import ( + "testing" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/components/simplejson" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/alerting" + "github.com/grafana/grafana/pkg/tsdb" + . "github.com/smartystreets/goconvey/convey" +) + +func TestQueryCondition(t *testing.T) { + + Convey("when evaluating query condition", t, func() { + + queryConditionScenario("Given avg() and > 100", func(ctx *queryConditionTestContext) { + + ctx.reducer = `{"type": "avg"}` + ctx.evaluator = `{"type": "gt", "params": [100]}` + + Convey("Can read query condition from json model", func() { + ctx.exec() + + So(ctx.condition.Query.From, ShouldEqual, "5m") + So(ctx.condition.Query.To, ShouldEqual, "now") + So(ctx.condition.Query.DatasourceId, ShouldEqual, 1) + + Convey("Can read query reducer", func() { + reducer, ok := ctx.condition.Reducer.(*SimpleReducer) + So(ok, ShouldBeTrue) + So(reducer.Type, ShouldEqual, "avg") + }) + + Convey("Can read evaluator", func() { + evaluator, ok := ctx.condition.Evaluator.(*ThresholdEvaluator) + So(ok, ShouldBeTrue) + So(evaluator.Type, ShouldEqual, "gt") + }) + }) + + Convey("should fire when avg is above 100", func() { + ctx.series = tsdb.TimeSeriesSlice{tsdb.NewTimeSeries("test1", [][2]float64{{120, 0}})} + ctx.exec() + + So(ctx.result.Error, ShouldBeNil) + So(ctx.result.Firing, ShouldBeTrue) + }) + + Convey("Should not fire when avg is below 100", func() { + ctx.series = tsdb.TimeSeriesSlice{tsdb.NewTimeSeries("test1", [][2]float64{{90, 0}})} + ctx.exec() + + So(ctx.result.Error, ShouldBeNil) + So(ctx.result.Firing, ShouldBeFalse) + }) + }) + }) +} + +type queryConditionTestContext struct { + reducer string + evaluator string + series tsdb.TimeSeriesSlice + result *alerting.EvalContext + condition *QueryCondition +} + +type queryConditionScenarioFunc func(c *queryConditionTestContext) + +func (ctx *queryConditionTestContext) exec() { + jsonModel, err := simplejson.NewJson([]byte(`{ + "type": "query", + "query": { + "params": ["A", "5m", "now"], + "datasourceId": 1, + "model": {"target": "aliasByNode(statsd.fakesite.counters.session_start.mobile.count, 4)"} + }, + "reducer":` + ctx.reducer + `, + "evaluator":` + ctx.evaluator + ` + }`)) + So(err, ShouldBeNil) + + condition, err := NewQueryCondition(jsonModel, 0) + So(err, ShouldBeNil) + + ctx.condition = condition + + condition.HandleRequest = func(req *tsdb.Request) (*tsdb.Response, error) { + return &tsdb.Response{ + Results: map[string]*tsdb.QueryResult{ + "A": {Series: ctx.series}, + }, + }, nil + } + + condition.Eval(ctx.result) +} + +func queryConditionScenario(desc string, fn queryConditionScenarioFunc) { + Convey(desc, func() { + + bus.AddHandler("test", func(query *m.GetDataSourceByIdQuery) error { + query.Result = &m.DataSource{Id: 1, Type: "graphite"} + return nil + }) + + ctx := &queryConditionTestContext{} + ctx.result = &alerting.EvalContext{ + Rule: &alerting.Rule{}, + } + + fn(ctx) + }) +} diff --git a/pkg/services/alerting/conditions/reducer.go b/pkg/services/alerting/conditions/reducer.go new file mode 100644 index 00000000000..f97ff6a56d7 --- /dev/null +++ b/pkg/services/alerting/conditions/reducer.go @@ -0,0 +1,54 @@ +package conditions + +import "github.com/grafana/grafana/pkg/tsdb" + +type QueryReducer interface { + Reduce(timeSeries *tsdb.TimeSeries) float64 +} + +type SimpleReducer struct { + Type string +} + +func (s *SimpleReducer) Reduce(series *tsdb.TimeSeries) float64 { + var value float64 = 0 + + switch s.Type { + case "avg": + for _, point := range series.Points { + value += point[0] + } + value = value / float64(len(series.Points)) + case "sum": + for _, point := range series.Points { + value += point[0] + } + case "min": + for i, point := range series.Points { + if i == 0 { + value = point[0] + } + + if value > point[0] { + value = point[0] + } + } + case "max": + for _, point := range series.Points { + if value < point[0] { + value = point[0] + } + } + case "mean": + meanPosition := int64(len(series.Points) / 2) + value = series.Points[meanPosition][0] + case "count": + value = float64(len(series.Points)) + } + + return value +} + +func NewSimpleReducer(typ string) *SimpleReducer { + return &SimpleReducer{Type: typ} +} diff --git a/pkg/services/alerting/conditions/reducer_test.go b/pkg/services/alerting/conditions/reducer_test.go new file mode 100644 index 00000000000..af242bbd668 --- /dev/null +++ b/pkg/services/alerting/conditions/reducer_test.go @@ -0,0 +1,58 @@ +package conditions + +import ( + "testing" + + "github.com/grafana/grafana/pkg/tsdb" + . "github.com/smartystreets/goconvey/convey" +) + +func TestSimpleReducer(t *testing.T) { + Convey("Test simple reducer by calculating", t, func() { + Convey("avg", func() { + result := testReducer("avg", 1, 2, 3) + So(result, ShouldEqual, float64(2)) + }) + + Convey("sum", func() { + result := testReducer("sum", 1, 2, 3) + So(result, ShouldEqual, float64(6)) + }) + + Convey("min", func() { + result := testReducer("min", 3, 2, 1) + So(result, ShouldEqual, float64(1)) + }) + + Convey("max", func() { + result := testReducer("max", 1, 2, 3) + So(result, ShouldEqual, float64(3)) + }) + + Convey("mean odd numbers", func() { + result := testReducer("mean", 1, 2, 3000) + So(result, ShouldEqual, float64(2)) + }) + + Convey("count", func() { + result := testReducer("count", 1, 2, 3000) + So(result, ShouldEqual, float64(3)) + }) + }) +} + +func testReducer(typ string, datapoints ...float64) float64 { + reducer := NewSimpleReducer(typ) + var timeserie [][2]float64 + dummieTimestamp := float64(521452145) + + for _, v := range datapoints { + timeserie = append(timeserie, [2]float64{v, dummieTimestamp}) + } + + tsdb := &tsdb.TimeSeries{ + Name: "test time serie", + Points: timeserie, + } + return reducer.Reduce(tsdb) +} diff --git a/pkg/services/alerting/engine.go b/pkg/services/alerting/engine.go new file mode 100644 index 00000000000..7abfe32425c --- /dev/null +++ b/pkg/services/alerting/engine.go @@ -0,0 +1,106 @@ +package alerting + +import ( + "time" + + "github.com/benbjohnson/clock" + "github.com/grafana/grafana/pkg/log" +) + +type Engine struct { + execQueue chan *Job + resultQueue chan *EvalContext + clock clock.Clock + ticker *Ticker + scheduler Scheduler + evalHandler EvalHandler + ruleReader RuleReader + log log.Logger + resultHandler ResultHandler +} + +func NewEngine() *Engine { + e := &Engine{ + ticker: NewTicker(time.Now(), time.Second*0, clock.New()), + execQueue: make(chan *Job, 1000), + resultQueue: make(chan *EvalContext, 1000), + scheduler: NewScheduler(), + evalHandler: NewEvalHandler(), + ruleReader: NewRuleReader(), + log: log.New("alerting.engine"), + resultHandler: NewResultHandler(), + } + + return e +} + +func (e *Engine) Start() { + e.log.Info("Starting Alerting Engine") + + go e.alertingTicker() + go e.execDispatcher() + go e.resultDispatcher() +} + +func (e *Engine) Stop() { + close(e.execQueue) + close(e.resultQueue) +} + +func (e *Engine) alertingTicker() { + defer func() { + if err := recover(); err != nil { + e.log.Error("Scheduler Panic: stopping alertingTicker", "error", err, "stack", log.Stack(1)) + } + }() + + tickIndex := 0 + + for { + select { + case tick := <-e.ticker.C: + // TEMP SOLUTION update rules ever tenth tick + if tickIndex%10 == 0 { + e.scheduler.Update(e.ruleReader.Fetch()) + } + + e.scheduler.Tick(tick, e.execQueue) + tickIndex++ + } + } +} + +func (e *Engine) execDispatcher() { + for job := range e.execQueue { + e.log.Debug("Starting executing alert rule", "alert id", job.Rule.Id) + go e.executeJob(job) + } +} + +func (e *Engine) executeJob(job *Job) { + defer func() { + if err := recover(); err != nil { + e.log.Error("Execute Alert Panic", "error", err, "stack", log.Stack(1)) + } + }() + + job.Running = true + context := NewEvalContext(job.Rule) + e.evalHandler.Eval(context) + job.Running = false + + e.resultQueue <- context +} + +func (e *Engine) resultDispatcher() { + defer func() { + if err := recover(); err != nil { + e.log.Error("Panic in resultDispatcher", "error", err, "stack", log.Stack(1)) + } + }() + + for result := range e.resultQueue { + e.log.Debug("Alert Rule Result", "ruleId", result.Rule.Id, "firing", result.Firing) + e.resultHandler.Handle(result) + } +} diff --git a/pkg/services/alerting/eval_context.go b/pkg/services/alerting/eval_context.go new file mode 100644 index 00000000000..70dc6b17a2f --- /dev/null +++ b/pkg/services/alerting/eval_context.go @@ -0,0 +1,105 @@ +package alerting + +import ( + "fmt" + "time" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/log" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/setting" +) + +type EvalContext struct { + Firing bool + IsTestRun bool + EvalMatches []*EvalMatch + Logs []*ResultLogEntry + Error error + Description string + StartTime time.Time + EndTime time.Time + Rule *Rule + DoneChan chan bool + CancelChan chan bool + log log.Logger + dashboardSlug string + ImagePublicUrl string + ImageOnDiskPath string +} + +func (a *EvalContext) GetDurationMs() float64 { + return float64(a.EndTime.Nanosecond()-a.StartTime.Nanosecond()) / float64(1000000) +} + +func (c *EvalContext) GetColor() string { + if !c.Firing { + return "#36a64f" + } + + if c.Rule.Severity == m.AlertSeverityWarning { + return "#fd821b" + } else { + return "#D63232" + } +} + +func (c *EvalContext) GetStateText() string { + if !c.Firing { + return "OK" + } + + if c.Rule.Severity == m.AlertSeverityWarning { + return "WARNING" + } else { + return "CRITICAL" + } +} + +func (c *EvalContext) GetNotificationTitle() string { + return "[" + c.GetStateText() + "] " + c.Rule.Name +} + +func (c *EvalContext) getDashboardSlug() (string, error) { + if c.dashboardSlug != "" { + return c.dashboardSlug, nil + } + + slugQuery := &m.GetDashboardSlugByIdQuery{Id: c.Rule.DashboardId} + if err := bus.Dispatch(slugQuery); err != nil { + return "", err + } + + c.dashboardSlug = slugQuery.Result + return c.dashboardSlug, nil +} + +func (c *EvalContext) GetRuleUrl() (string, error) { + if slug, err := c.getDashboardSlug(); err != nil { + return "", err + } else { + ruleUrl := fmt.Sprintf("%sdashboard/db/%s?fullscreen&edit&tab=alert&panelId=%d", setting.AppUrl, slug, c.Rule.PanelId) + return ruleUrl, nil + } +} + +func (c *EvalContext) GetImageUrl() (string, error) { + if slug, err := c.getDashboardSlug(); err != nil { + return "", err + } else { + ruleUrl := fmt.Sprintf("%sdashboard-solo/db/%s?&panelId=%d", setting.AppUrl, slug, c.Rule.PanelId) + return ruleUrl, nil + } +} + +func NewEvalContext(rule *Rule) *EvalContext { + return &EvalContext{ + StartTime: time.Now(), + Rule: rule, + Logs: make([]*ResultLogEntry, 0), + EvalMatches: make([]*EvalMatch, 0), + DoneChan: make(chan bool, 1), + CancelChan: make(chan bool, 1), + log: log.New("alerting.evalContext"), + } +} diff --git a/pkg/services/alerting/eval_handler.go b/pkg/services/alerting/eval_handler.go new file mode 100644 index 00000000000..3abcd978064 --- /dev/null +++ b/pkg/services/alerting/eval_handler.go @@ -0,0 +1,58 @@ +package alerting + +import ( + "fmt" + "time" + + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/metrics" +) + +type DefaultEvalHandler struct { + log log.Logger + alertJobTimeout time.Duration +} + +func NewEvalHandler() *DefaultEvalHandler { + return &DefaultEvalHandler{ + log: log.New("alerting.evalHandler"), + alertJobTimeout: time.Second * 5, + } +} + +func (e *DefaultEvalHandler) Eval(context *EvalContext) { + + go e.eval(context) + + select { + case <-time.After(e.alertJobTimeout): + context.Error = fmt.Errorf("Timeout") + context.EndTime = time.Now() + e.log.Debug("Job Execution timeout", "alertId", context.Rule.Id) + case <-context.DoneChan: + e.log.Debug("Job Execution done", "timeMs", context.GetDurationMs(), "alertId", context.Rule.Id, "firing", context.Firing) + } + +} + +func (e *DefaultEvalHandler) eval(context *EvalContext) { + + for _, condition := range context.Rule.Conditions { + condition.Eval(context) + + // break if condition could not be evaluated + if context.Error != nil { + break + } + + // break if result has not triggered yet + if context.Firing == false { + break + } + } + + context.EndTime = time.Now() + elapsedTime := context.EndTime.Sub(context.StartTime) + metrics.M_Alerting_Exeuction_Time.Update(elapsedTime) + context.DoneChan <- true +} diff --git a/pkg/services/alerting/eval_handler_test.go b/pkg/services/alerting/eval_handler_test.go new file mode 100644 index 00000000000..039e9be9a30 --- /dev/null +++ b/pkg/services/alerting/eval_handler_test.go @@ -0,0 +1,45 @@ +package alerting + +import ( + "testing" + + . "github.com/smartystreets/goconvey/convey" +) + +type conditionStub struct { + firing bool +} + +func (c *conditionStub) Eval(context *EvalContext) { + context.Firing = c.firing +} + +func TestAlertingExecutor(t *testing.T) { + Convey("Test alert execution", t, func() { + handler := NewEvalHandler() + + Convey("Show return triggered with single passing condition", func() { + context := NewEvalContext(&Rule{ + Conditions: []Condition{&conditionStub{ + firing: true, + }}, + }) + + handler.eval(context) + So(context.Firing, ShouldEqual, true) + }) + + Convey("Show return false with not passing condition", func() { + context := NewEvalContext(&Rule{ + Conditions: []Condition{ + &conditionStub{firing: true}, + &conditionStub{firing: false}, + }, + }) + + handler.eval(context) + So(context.Firing, ShouldEqual, false) + }) + + }) +} diff --git a/pkg/services/alerting/extractor.go b/pkg/services/alerting/extractor.go new file mode 100644 index 00000000000..7d3b800fb31 --- /dev/null +++ b/pkg/services/alerting/extractor.go @@ -0,0 +1,141 @@ +package alerting + +import ( + "errors" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/log" + m "github.com/grafana/grafana/pkg/models" +) + +type DashAlertExtractor struct { + Dash *m.Dashboard + OrgId int64 + log log.Logger +} + +func NewDashAlertExtractor(dash *m.Dashboard, orgId int64) *DashAlertExtractor { + return &DashAlertExtractor{ + Dash: dash, + OrgId: orgId, + log: log.New("alerting.extractor"), + } +} + +func (e *DashAlertExtractor) lookupDatasourceId(dsName string) (*m.DataSource, error) { + if dsName == "" { + query := &m.GetDataSourcesQuery{OrgId: e.OrgId} + if err := bus.Dispatch(query); err != nil { + return nil, err + } else { + for _, ds := range query.Result { + if ds.IsDefault { + return ds, nil + } + } + } + } else { + query := &m.GetDataSourceByNameQuery{Name: dsName, OrgId: e.OrgId} + if err := bus.Dispatch(query); err != nil { + return nil, err + } else { + return query.Result, nil + } + } + + return nil, errors.New("Could not find datasource id for " + dsName) +} + +func findPanelQueryByRefId(panel *simplejson.Json, refId string) *simplejson.Json { + for _, targetsObj := range panel.Get("targets").MustArray() { + target := simplejson.NewFromAny(targetsObj) + + if target.Get("refId").MustString() == refId { + return target + } + } + return nil +} + +func (e *DashAlertExtractor) GetAlerts() ([]*m.Alert, error) { + e.log.Debug("GetAlerts") + + alerts := make([]*m.Alert, 0) + + for _, rowObj := range e.Dash.Data.Get("rows").MustArray() { + row := simplejson.NewFromAny(rowObj) + + for _, panelObj := range row.Get("panels").MustArray() { + panel := simplejson.NewFromAny(panelObj) + jsonAlert, hasAlert := panel.CheckGet("alert") + + if !hasAlert { + continue + } + + enabled, hasEnabled := jsonAlert.CheckGet("enabled") + + if !hasEnabled || !enabled.MustBool() { + continue + } + + alert := &m.Alert{ + DashboardId: e.Dash.Id, + OrgId: e.OrgId, + PanelId: panel.Get("id").MustInt64(), + Id: jsonAlert.Get("id").MustInt64(), + Name: jsonAlert.Get("name").MustString(), + Handler: jsonAlert.Get("handler").MustInt64(), + Message: jsonAlert.Get("message").MustString(), + Severity: m.AlertSeverityType(jsonAlert.Get("severity").MustString()), + Frequency: getTimeDurationStringToSeconds(jsonAlert.Get("frequency").MustString()), + } + + if !alert.Severity.IsValid() { + return nil, ValidationError{Reason: "Invalid alert Severity"} + } + + for _, condition := range jsonAlert.Get("conditions").MustArray() { + jsonCondition := simplejson.NewFromAny(condition) + + jsonQuery := jsonCondition.Get("query") + queryRefId := jsonQuery.Get("params").MustArray()[0].(string) + panelQuery := findPanelQueryByRefId(panel, queryRefId) + + if panelQuery == nil { + return nil, ValidationError{Reason: "Alert refes to query that cannot be found"} + } + + dsName := "" + if panelQuery.Get("datasource").MustString() != "" { + dsName = panelQuery.Get("datasource").MustString() + } else if panel.Get("datasource").MustString() != "" { + dsName = panel.Get("datasource").MustString() + } + + if datasource, err := e.lookupDatasourceId(dsName); err != nil { + return nil, err + } else { + jsonQuery.SetPath([]string{"datasourceId"}, datasource.Id) + } + + jsonQuery.Set("model", panelQuery.Interface()) + } + + alert.Settings = jsonAlert + + // validate + _, err := NewRuleFromDBAlert(alert) + if err == nil && alert.ValidToSave() { + alerts = append(alerts, alert) + } else { + e.log.Error("Failed to extract alerts from dashboard", "error", err) + return nil, err + } + } + } + + e.log.Debug("Extracted alerts from dashboard", "alertCount", len(alerts)) + return alerts, nil +} diff --git a/pkg/services/alerting/extractor_test.go b/pkg/services/alerting/extractor_test.go new file mode 100644 index 00000000000..e3df5e571d1 --- /dev/null +++ b/pkg/services/alerting/extractor_test.go @@ -0,0 +1,168 @@ +package alerting + +import ( + "testing" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/components/simplejson" + m "github.com/grafana/grafana/pkg/models" + . "github.com/smartystreets/goconvey/convey" +) + +func TestAlertRuleExtraction(t *testing.T) { + + Convey("Parsing alert rules from dashboard json", t, func() { + + RegisterCondition("query", func(model *simplejson.Json, index int) (Condition, error) { + return &FakeCondition{}, nil + }) + + Convey("Parsing and validating alerts from dashboards", func() { + json := `{ + "id": 57, + "title": "Graphite 4", + "originalTitle": "Graphite 4", + "tags": ["graphite"], + "rows": [ + { + "panels": [ + { + "title": "Active desktop users", + "editable": true, + "type": "graph", + "id": 3, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.desktop.count, 4)" + } + ], + "datasource": null, + "alert": { + "name": "name1", + "message": "desc1", + "handler": 1, + "enabled": true, + "frequency": "60s", + "severity": "critical", + "conditions": [ + { + "type": "query", + "query": {"params": ["A", "5m", "now"]}, + "reducer": {"type": "avg", "params": []}, + "evaluator": {"type": ">", "params": [100]} + } + ] + } + }, + { + "title": "Active mobile users", + "id": 4, + "targets": [ + {"refId": "A", "target": ""}, + {"refId": "B", "target": "aliasByNode(statsd.fakesite.counters.session_start.mobile.count, 4)"} + ], + "datasource": "graphite2", + "alert": { + "name": "name2", + "message": "desc2", + "handler": 0, + "enabled": true, + "frequency": "60s", + "severity": "warning", + "conditions": [ + { + "type": "query", + "query": {"params": ["B", "5m", "now"]}, + "reducer": {"type": "avg", "params": []}, + "evaluator": {"type": ">", "params": [100]} + } + ] + } + } + ] + } + ] + }` + dashJson, err := simplejson.NewJson([]byte(json)) + So(err, ShouldBeNil) + + dash := m.NewDashboardFromJson(dashJson) + extractor := NewDashAlertExtractor(dash, 1) + + // mock data + defaultDs := &m.DataSource{Id: 12, OrgId: 2, Name: "I am default", IsDefault: true} + graphite2Ds := &m.DataSource{Id: 15, OrgId: 2, Name: "graphite2"} + + bus.AddHandler("test", func(query *m.GetDataSourcesQuery) error { + query.Result = []*m.DataSource{defaultDs, graphite2Ds} + return nil + }) + + bus.AddHandler("test", func(query *m.GetDataSourceByNameQuery) error { + if query.Name == defaultDs.Name { + query.Result = defaultDs + } + if query.Name == graphite2Ds.Name { + query.Result = graphite2Ds + } + return nil + }) + + alerts, err := extractor.GetAlerts() + + Convey("Get rules without error", func() { + So(err, ShouldBeNil) + }) + + Convey("all properties have been set", func() { + So(len(alerts), ShouldEqual, 2) + + for _, v := range alerts { + So(v.DashboardId, ShouldEqual, 57) + So(v.Name, ShouldNotBeEmpty) + So(v.Message, ShouldNotBeEmpty) + } + + Convey("should extract handler property", func() { + So(alerts[0].Handler, ShouldEqual, 1) + So(alerts[1].Handler, ShouldEqual, 0) + }) + + Convey("should extract Severity property", func() { + So(alerts[0].Severity, ShouldEqual, "critical") + So(alerts[1].Severity, ShouldEqual, "warning") + }) + + Convey("should extract frequency in seconds", func() { + So(alerts[0].Frequency, ShouldEqual, 60) + So(alerts[1].Frequency, ShouldEqual, 60) + }) + + Convey("should extract panel idc", func() { + So(alerts[0].PanelId, ShouldEqual, 3) + So(alerts[1].PanelId, ShouldEqual, 4) + }) + + Convey("should extract name and desc", func() { + So(alerts[0].Name, ShouldEqual, "name1") + So(alerts[0].Message, ShouldEqual, "desc1") + So(alerts[1].Name, ShouldEqual, "name2") + So(alerts[1].Message, ShouldEqual, "desc2") + }) + + Convey("should set datasourceId", func() { + condition := simplejson.NewFromAny(alerts[0].Settings.Get("conditions").MustArray()[0]) + query := condition.Get("query") + So(query.Get("datasourceId").MustInt64(), ShouldEqual, 12) + }) + + Convey("should copy query model to condition", func() { + condition := simplejson.NewFromAny(alerts[0].Settings.Get("conditions").MustArray()[0]) + model := condition.Get("query").Get("model") + So(model.Get("target").MustString(), ShouldEqual, "aliasByNode(statsd.fakesite.counters.session_start.desktop.count, 4)") + }) + }) + }) + }) +} diff --git a/pkg/services/alerting/init/init.go b/pkg/services/alerting/init/init.go new file mode 100644 index 00000000000..b6627a359e6 --- /dev/null +++ b/pkg/services/alerting/init/init.go @@ -0,0 +1,20 @@ +package init + +import ( + "github.com/grafana/grafana/pkg/services/alerting" + _ "github.com/grafana/grafana/pkg/services/alerting/conditions" + _ "github.com/grafana/grafana/pkg/services/alerting/notifiers" + "github.com/grafana/grafana/pkg/setting" + _ "github.com/grafana/grafana/pkg/tsdb/graphite" +) + +var engine *alerting.Engine + +func Init() { + if !setting.AlertingEnabled { + return + } + + engine = alerting.NewEngine() + engine.Start() +} diff --git a/pkg/services/alerting/interfaces.go b/pkg/services/alerting/interfaces.go new file mode 100644 index 00000000000..9688aba153a --- /dev/null +++ b/pkg/services/alerting/interfaces.go @@ -0,0 +1,22 @@ +package alerting + +import "time" + +type EvalHandler interface { + Eval(context *EvalContext) +} + +type Scheduler interface { + Tick(time time.Time, execQueue chan *Job) + Update(rules []*Rule) +} + +type Notifier interface { + Notify(alertResult *EvalContext) + GetType() string + NeedsImage() bool +} + +type Condition interface { + Eval(result *EvalContext) +} diff --git a/pkg/services/alerting/models.go b/pkg/services/alerting/models.go new file mode 100644 index 00000000000..e11e1e1aaaf --- /dev/null +++ b/pkg/services/alerting/models.go @@ -0,0 +1,24 @@ +package alerting + +type Job struct { + Offset int64 + Delay bool + Running bool + Rule *Rule +} + +type ResultLogEntry struct { + Message string + Data interface{} +} + +type EvalMatch struct { + Value float64 + Metric string + Tags map[string]string +} + +type Level struct { + Operator string + Value float64 +} diff --git a/pkg/services/alerting/notifier.go b/pkg/services/alerting/notifier.go new file mode 100644 index 00000000000..826aede2d11 --- /dev/null +++ b/pkg/services/alerting/notifier.go @@ -0,0 +1,125 @@ +package alerting + +import ( + "errors" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/components/imguploader" + "github.com/grafana/grafana/pkg/components/renderer" + "github.com/grafana/grafana/pkg/log" + m "github.com/grafana/grafana/pkg/models" +) + +type RootNotifier struct { + log log.Logger +} + +func NewRootNotifier() *RootNotifier { + return &RootNotifier{ + log: log.New("alerting.notifier"), + } +} + +func (n *RootNotifier) GetType() string { + return "root" +} + +func (n *RootNotifier) NeedsImage() bool { + return false +} + +func (n *RootNotifier) Notify(context *EvalContext) { + n.log.Info("Sending notifications for", "ruleId", context.Rule.Id) + + notifiers, err := n.getNotifiers(context.Rule.OrgId, context.Rule.Notifications) + if err != nil { + n.log.Error("Failed to read notifications", "error", err) + return + } + + if len(notifiers) == 0 { + return + } + + err = n.uploadImage(context) + if err != nil { + n.log.Error("Failed to upload alert panel image", "error", err) + } + + for _, notifier := range notifiers { + n.log.Info("Sending notification", "firing", context.Firing, "type", notifier.GetType()) + + go notifier.Notify(context) + } +} + +func (n *RootNotifier) uploadImage(context *EvalContext) error { + + uploader, _ := imguploader.NewImageUploader() + + imageUrl, err := context.GetImageUrl() + if err != nil { + return err + } + + renderOpts := &renderer.RenderOpts{ + Url: imageUrl, + Width: "800", + Height: "400", + SessionId: "123", + Timeout: "10", + } + + if imagePath, err := renderer.RenderToPng(renderOpts); err != nil { + return err + } else { + context.ImageOnDiskPath = imagePath + } + + context.ImagePublicUrl, err = uploader.Upload(context.ImageOnDiskPath) + if err != nil { + return err + } + + n.log.Info("uploaded", "url", context.ImagePublicUrl) + return nil +} + +func (n *RootNotifier) getNotifiers(orgId int64, notificationIds []int64) ([]Notifier, error) { + if len(notificationIds) == 0 { + return []Notifier{}, nil + } + + query := &m.GetAlertNotificationsQuery{OrgId: orgId, Ids: notificationIds} + if err := bus.Dispatch(query); err != nil { + return nil, err + } + + var result []Notifier + for _, notification := range query.Result { + if not, err := n.getNotifierFor(notification); err != nil { + return nil, err + } else { + result = append(result, not) + } + } + + return result, nil +} + +func (n *RootNotifier) getNotifierFor(model *m.AlertNotification) (Notifier, error) { + factory, found := notifierFactories[model.Type] + if !found { + return nil, errors.New("Unsupported notification type") + } + + return factory(model) +} + +type NotifierFactory func(notification *m.AlertNotification) (Notifier, error) + +var notifierFactories map[string]NotifierFactory = make(map[string]NotifierFactory) + +func RegisterNotifier(typeName string, factory NotifierFactory) { + notifierFactories[typeName] = factory +} diff --git a/pkg/services/alerting/notifier_test.go b/pkg/services/alerting/notifier_test.go new file mode 100644 index 00000000000..ebe305c6174 --- /dev/null +++ b/pkg/services/alerting/notifier_test.go @@ -0,0 +1,114 @@ +package alerting + +// func TestAlertNotificationExtraction(t *testing.T) { +// Convey("Notifier tests", t, func() { +// Convey("rules for sending notifications", func() { +// dummieNotifier := NotifierImpl{} +// +// result := &AlertResult{ +// State: alertstates.Critical, +// } +// +// notifier := &Notification{ +// Name: "Test Notifier", +// Type: "TestType", +// SendCritical: true, +// SendWarning: true, +// } +// +// Convey("Should send notification", func() { +// So(dummieNotifier.ShouldDispath(result, notifier), ShouldBeTrue) +// }) +// +// Convey("warn:false and state:warn should not send", func() { +// result.State = alertstates.Warn +// notifier.SendWarning = false +// So(dummieNotifier.ShouldDispath(result, notifier), ShouldBeFalse) +// }) +// }) +// +// Convey("Parsing alert notification from settings", func() { +// Convey("Parsing email", func() { +// Convey("empty settings should return error", func() { +// json := `{ }` +// +// settingsJSON, _ := simplejson.NewJson([]byte(json)) +// model := &m.AlertNotification{ +// Name: "ops", +// Type: "email", +// Settings: settingsJSON, +// } +// +// _, err := NewNotificationFromDBModel(model) +// So(err, ShouldNotBeNil) +// }) +// +// Convey("from settings", func() { +// json := ` +// { +// "to": "ops@grafana.org" +// }` +// +// settingsJSON, _ := simplejson.NewJson([]byte(json)) +// model := &m.AlertNotification{ +// Name: "ops", +// Type: "email", +// Settings: settingsJSON, +// } +// +// not, err := NewNotificationFromDBModel(model) +// +// So(err, ShouldBeNil) +// So(not.Name, ShouldEqual, "ops") +// So(not.Type, ShouldEqual, "email") +// So(reflect.TypeOf(not.Notifierr).Elem().String(), ShouldEqual, "alerting.EmailNotifier") +// +// email := not.Notifierr.(*EmailNotifier) +// So(email.To, ShouldEqual, "ops@grafana.org") +// }) +// }) +// +// Convey("Parsing webhook", func() { +// Convey("empty settings should return error", func() { +// json := `{ }` +// +// settingsJSON, _ := simplejson.NewJson([]byte(json)) +// model := &m.AlertNotification{ +// Name: "ops", +// Type: "webhook", +// Settings: settingsJSON, +// } +// +// _, err := NewNotificationFromDBModel(model) +// So(err, ShouldNotBeNil) +// }) +// +// Convey("from settings", func() { +// json := ` +// { +// "url": "http://localhost:3000", +// "username": "username", +// "password": "password" +// }` +// +// settingsJSON, _ := simplejson.NewJson([]byte(json)) +// model := &m.AlertNotification{ +// Name: "slack", +// Type: "webhook", +// Settings: settingsJSON, +// } +// +// not, err := NewNotificationFromDBModel(model) +// +// So(err, ShouldBeNil) +// So(not.Name, ShouldEqual, "slack") +// So(not.Type, ShouldEqual, "webhook") +// So(reflect.TypeOf(not.Notifierr).Elem().String(), ShouldEqual, "alerting.WebhookNotifier") +// +// webhook := not.Notifierr.(*WebhookNotifier) +// So(webhook.Url, ShouldEqual, "http://localhost:3000") +// }) +// }) +// }) +// }) +// } diff --git a/pkg/services/alerting/notifiers/base.go b/pkg/services/alerting/notifiers/base.go new file mode 100644 index 00000000000..48fe6c4eaa5 --- /dev/null +++ b/pkg/services/alerting/notifiers/base.go @@ -0,0 +1,14 @@ +package notifiers + +type NotifierBase struct { + Name string + Type string +} + +func (n *NotifierBase) GetType() string { + return n.Type +} + +func (n *NotifierBase) NeedsImage() bool { + return true +} diff --git a/pkg/services/alerting/notifiers/common.go b/pkg/services/alerting/notifiers/common.go new file mode 100644 index 00000000000..48b634c44d7 --- /dev/null +++ b/pkg/services/alerting/notifiers/common.go @@ -0,0 +1 @@ +package notifiers diff --git a/pkg/services/alerting/notifiers/email.go b/pkg/services/alerting/notifiers/email.go new file mode 100644 index 00000000000..20b0bc06463 --- /dev/null +++ b/pkg/services/alerting/notifiers/email.go @@ -0,0 +1,71 @@ +package notifiers + +import ( + "strings" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/metrics" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/alerting" + "github.com/grafana/grafana/pkg/setting" +) + +func init() { + alerting.RegisterNotifier("email", NewEmailNotifier) +} + +type EmailNotifier struct { + NotifierBase + Addresses []string + log log.Logger +} + +func NewEmailNotifier(model *m.AlertNotification) (alerting.Notifier, error) { + addressesString := model.Settings.Get("addresses").MustString() + + if addressesString == "" { + return nil, alerting.ValidationError{Reason: "Could not find addresses in settings"} + } + + return &EmailNotifier{ + NotifierBase: NotifierBase{ + Name: model.Name, + Type: model.Type, + }, + Addresses: strings.Split(addressesString, "\n"), + log: log.New("alerting.notifier.email"), + }, nil +} + +func (this *EmailNotifier) Notify(context *alerting.EvalContext) { + this.log.Info("Sending alert notification to", "addresses", this.Addresses) + metrics.M_Alerting_Notification_Sent_Email.Inc(1) + + ruleUrl, err := context.GetRuleUrl() + if err != nil { + this.log.Error("Failed get rule link", "error", err) + return + } + + cmd := &m.SendEmailCommand{ + Data: map[string]interface{}{ + "Title": context.GetNotificationTitle(), + "State": context.Rule.State, + "Name": context.Rule.Name, + "Severity": context.Rule.Severity, + "SeverityColor": context.GetColor(), + "Message": context.Rule.Message, + "RuleUrl": ruleUrl, + "ImageLink": context.ImagePublicUrl, + "AlertPageUrl": setting.AppUrl + "alerting", + "EvalMatches": context.EvalMatches, + }, + To: this.Addresses, + Template: "alert_notification.html", + } + + if err := bus.Dispatch(cmd); err != nil { + this.log.Error("Failed to send alert notification email", "error", err) + } +} diff --git a/pkg/services/alerting/notifiers/email_test.go b/pkg/services/alerting/notifiers/email_test.go new file mode 100644 index 00000000000..19dcf23c3d2 --- /dev/null +++ b/pkg/services/alerting/notifiers/email_test.go @@ -0,0 +1,52 @@ +package notifiers + +import ( + "testing" + + "github.com/grafana/grafana/pkg/components/simplejson" + m "github.com/grafana/grafana/pkg/models" + . "github.com/smartystreets/goconvey/convey" +) + +func TestEmailNotifier(t *testing.T) { + Convey("Email notifier tests", t, func() { + + Convey("Parsing alert notification from settings", func() { + Convey("empty settings should return error", func() { + json := `{ }` + + settingsJSON, _ := simplejson.NewJson([]byte(json)) + model := &m.AlertNotification{ + Name: "ops", + Type: "email", + Settings: settingsJSON, + } + + _, err := NewEmailNotifier(model) + So(err, ShouldNotBeNil) + }) + + Convey("from settings", func() { + json := ` + { + "addresses": "ops@grafana.org" + }` + + settingsJSON, _ := simplejson.NewJson([]byte(json)) + model := &m.AlertNotification{ + Name: "ops", + Type: "email", + Settings: settingsJSON, + } + + not, err := NewEmailNotifier(model) + emailNotifier := not.(*EmailNotifier) + + So(err, ShouldBeNil) + So(emailNotifier.Name, ShouldEqual, "ops") + So(emailNotifier.Type, ShouldEqual, "email") + So(emailNotifier.Addresses[0], ShouldEqual, "ops@grafana.org") + }) + }) + }) +} diff --git a/pkg/services/alerting/notifiers/slack.go b/pkg/services/alerting/notifiers/slack.go new file mode 100644 index 00000000000..e099c7da690 --- /dev/null +++ b/pkg/services/alerting/notifiers/slack.go @@ -0,0 +1,91 @@ +package notifiers + +import ( + "encoding/json" + "time" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/metrics" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/alerting" + "github.com/grafana/grafana/pkg/setting" +) + +func init() { + alerting.RegisterNotifier("slack", NewSlackNotifier) +} + +func NewSlackNotifier(model *m.AlertNotification) (alerting.Notifier, error) { + url := model.Settings.Get("url").MustString() + if url == "" { + return nil, alerting.ValidationError{Reason: "Could not find url property in settings"} + } + + return &SlackNotifier{ + NotifierBase: NotifierBase{ + Name: model.Name, + Type: model.Type, + }, + Url: url, + log: log.New("alerting.notifier.slack"), + }, nil +} + +type SlackNotifier struct { + NotifierBase + Url string + log log.Logger +} + +func (this *SlackNotifier) Notify(context *alerting.EvalContext) { + this.log.Info("Executing slack notification", "ruleId", context.Rule.Id, "notification", this.Name) + metrics.M_Alerting_Notification_Sent_Slack.Inc(1) + + ruleUrl, err := context.GetRuleUrl() + if err != nil { + this.log.Error("Failed get rule link", "error", err) + return + } + + fields := make([]map[string]interface{}, 0) + fieldLimitCount := 4 + for index, evt := range context.EvalMatches { + fields = append(fields, map[string]interface{}{ + "title": evt.Metric, + "value": evt.Value, + "short": true, + }) + if index > fieldLimitCount { + break + } + } + + body := map[string]interface{}{ + "attachments": []map[string]interface{}{ + { + "color": context.GetColor(), + "title": context.GetNotificationTitle(), + "title_link": ruleUrl, + "text": context.Rule.Message, + "fields": fields, + "image_url": context.ImagePublicUrl, + "footer": "Grafana v" + setting.BuildVersion, + "footer_icon": "http://grafana.org/assets/img/fav32.png", + "ts": time.Now().Unix(), + //"pretext": "Optional text that appears above the attachment block", + // "author_name": "Bobby Tables", + // "author_link": "http://flickr.com/bobby/", + // "author_icon": "http://flickr.com/icons/bobby.jpg", + // "thumb_url": "http://example.com/path/to/thumb.png", + }, + }, + } + + data, _ := json.Marshal(&body) + cmd := &m.SendWebhook{Url: this.Url, Body: string(data)} + + if err := bus.Dispatch(cmd); err != nil { + this.log.Error("Failed to send slack notification", "error", err, "webhook", this.Name) + } +} diff --git a/pkg/services/alerting/notifiers/webhook.go b/pkg/services/alerting/notifiers/webhook.go new file mode 100644 index 00000000000..e725752778f --- /dev/null +++ b/pkg/services/alerting/notifiers/webhook.go @@ -0,0 +1,76 @@ +package notifiers + +import ( + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/metrics" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/alerting" +) + +func init() { + alerting.RegisterNotifier("webhook", NewWebHookNotifier) +} + +func NewWebHookNotifier(model *m.AlertNotification) (alerting.Notifier, error) { + url := model.Settings.Get("url").MustString() + if url == "" { + return nil, alerting.ValidationError{Reason: "Could not find url property in settings"} + } + + return &WebhookNotifier{ + NotifierBase: NotifierBase{ + Name: model.Name, + Type: model.Type, + }, + Url: url, + User: model.Settings.Get("user").MustString(), + Password: model.Settings.Get("password").MustString(), + log: log.New("alerting.notifier.webhook"), + }, nil +} + +type WebhookNotifier struct { + NotifierBase + Url string + User string + Password string + log log.Logger +} + +func (this *WebhookNotifier) Notify(context *alerting.EvalContext) { + this.log.Info("Sending webhook") + metrics.M_Alerting_Notification_Sent_Webhook.Inc(1) + + bodyJSON := simplejson.New() + bodyJSON.Set("title", context.GetNotificationTitle()) + bodyJSON.Set("ruleId", context.Rule.Id) + bodyJSON.Set("ruleName", context.Rule.Name) + bodyJSON.Set("state", context.Rule.State) + bodyJSON.Set("severity", context.Rule.Severity) + bodyJSON.Set("evalMatches", context.EvalMatches) + + ruleUrl, err := context.GetRuleUrl() + if err == nil { + bodyJSON.Set("rule_url", ruleUrl) + } + + imageUrl, err := context.GetImageUrl() + if err == nil { + bodyJSON.Set("image_url", imageUrl) + } + + body, _ := bodyJSON.MarshalJSON() + + cmd := &m.SendWebhook{ + Url: this.Url, + User: this.User, + Password: this.Password, + Body: string(body), + } + + if err := bus.Dispatch(cmd); err != nil { + this.log.Error("Failed to send webhook", "error", err, "webhook", this.Name) + } +} diff --git a/pkg/services/alerting/notifiers/webhook_test.go b/pkg/services/alerting/notifiers/webhook_test.go new file mode 100644 index 00000000000..6147f54d773 --- /dev/null +++ b/pkg/services/alerting/notifiers/webhook_test.go @@ -0,0 +1,52 @@ +package notifiers + +import ( + "testing" + + "github.com/grafana/grafana/pkg/components/simplejson" + m "github.com/grafana/grafana/pkg/models" + . "github.com/smartystreets/goconvey/convey" +) + +func TestWebhookNotifier(t *testing.T) { + Convey("Webhook notifier tests", t, func() { + + Convey("Parsing alert notification from settings", func() { + Convey("empty settings should return error", func() { + json := `{ }` + + settingsJSON, _ := simplejson.NewJson([]byte(json)) + model := &m.AlertNotification{ + Name: "ops", + Type: "email", + Settings: settingsJSON, + } + + _, err := NewWebHookNotifier(model) + So(err, ShouldNotBeNil) + }) + + Convey("from settings", func() { + json := ` + { + "url": "http://google.com" + }` + + settingsJSON, _ := simplejson.NewJson([]byte(json)) + model := &m.AlertNotification{ + Name: "ops", + Type: "email", + Settings: settingsJSON, + } + + not, err := NewWebHookNotifier(model) + emailNotifier := not.(*WebhookNotifier) + + So(err, ShouldBeNil) + So(emailNotifier.Name, ShouldEqual, "ops") + So(emailNotifier.Type, ShouldEqual, "email") + So(emailNotifier.Url, ShouldEqual, "http://google.com") + }) + }) + }) +} diff --git a/pkg/services/alerting/reader.go b/pkg/services/alerting/reader.go new file mode 100644 index 00000000000..68e7002be1a --- /dev/null +++ b/pkg/services/alerting/reader.go @@ -0,0 +1,84 @@ +package alerting + +import ( + "sync" + "time" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/metrics" + m "github.com/grafana/grafana/pkg/models" +) + +type RuleReader interface { + Fetch() []*Rule +} + +type DefaultRuleReader struct { + sync.RWMutex + serverID string + serverPosition int + clusterSize int + log log.Logger +} + +func NewRuleReader() *DefaultRuleReader { + ruleReader := &DefaultRuleReader{ + log: log.New("alerting.ruleReader"), + } + + go ruleReader.initReader() + return ruleReader +} + +func (arr *DefaultRuleReader) initReader() { + heartbeat := time.NewTicker(time.Second * 10) + + for { + select { + case <-heartbeat.C: + arr.heartbeat() + } + } +} + +func (arr *DefaultRuleReader) Fetch() []*Rule { + cmd := &m.GetAllAlertsQuery{} + + if err := bus.Dispatch(cmd); err != nil { + arr.log.Error("Could not load alerts", "error", err) + return []*Rule{} + } + + res := make([]*Rule, 0) + for _, ruleDef := range cmd.Result { + if model, err := NewRuleFromDBAlert(ruleDef); err != nil { + arr.log.Error("Could not build alert model for rule", "ruleId", ruleDef.Id, "error", err) + } else { + res = append(res, model) + } + } + + metrics.M_Alerting_Active_Alerts.Inc(int64(len(res))) + return res +} + +func (arr *DefaultRuleReader) heartbeat() { + + //Lets cheat on this until we focus on clustering + //log.Info("Heartbeat: Sending heartbeat from " + this.serverId) + arr.clusterSize = 1 + arr.serverPosition = 1 + + /* + cmd := &m.HeartBeatCommand{ServerId: this.serverId} + err := bus.Dispatch(cmd) + + if err != nil { + log.Error(1, "Failed to send heartbeat.") + } else { + this.clusterSize = cmd.Result.ClusterSize + this.serverPosition = cmd.Result.UptimePosition + } + */ +} diff --git a/pkg/services/alerting/reader_test.go b/pkg/services/alerting/reader_test.go new file mode 100644 index 00000000000..ea9294d41c7 --- /dev/null +++ b/pkg/services/alerting/reader_test.go @@ -0,0 +1,84 @@ +package alerting + +import ( + //m "github.com/grafana/grafana/pkg/models" + . "github.com/smartystreets/goconvey/convey" + "testing" +) + +func TestAlertingScheduler(t *testing.T) { + Convey("Testing alert job selection", t, func() { + /* + mockFn := func() []m.AlertRule { + return []m.AlertRule{ + {Id: 1, Title: "test 1"}, + {Id: 2, Title: "test 2"}, + {Id: 3, Title: "test 3"}, + {Id: 4, Title: "test 4"}, + {Id: 5, Title: "test 5"}, + {Id: 6, Title: "test 6"}, + } + } + + Convey("single server", func() { + scheduler := &Scheduler{ + jobs: make(map[int64]*AlertJob, 0), + runQueue: make(chan *AlertJob, 1000), + serverId: "", + serverPosition: 1, + clusterSize: 1, + } + + scheduler.updateJobs(mockFn) + So(len(scheduler.jobs), ShouldEqual, 6) + }) + + Convey("two servers", func() { + scheduler := &Scheduler{ + jobs: make(map[int64]*AlertJob, 0), + runQueue: make(chan *AlertJob, 1000), + serverId: "", + serverPosition: 1, + clusterSize: 2, + } + + scheduler.updateJobs(mockFn) + So(len(scheduler.jobs), ShouldEqual, 3) + So(scheduler.jobs[1].rule.Id, ShouldEqual, 1) + }) + + Convey("six servers", func() { + scheduler := &Scheduler{ + jobs: make(map[int64]*AlertJob, 0), + runQueue: make(chan *AlertJob, 1000), + serverId: "", + serverPosition: 6, + clusterSize: 6, + } + + scheduler.updateJobs(mockFn) + So(len(scheduler.jobs), ShouldEqual, 1) + So(scheduler.jobs[6].rule.Id, ShouldEqual, 6) + }) + + Convey("more servers then alerts", func() { + mockFn := func() []m.AlertRule { + return []m.AlertRule{ + {Id: 1, Title: "test 1"}, + } + } + + scheduler := &Scheduler{ + jobs: make(map[int64]*AlertJob, 0), + runQueue: make(chan *AlertJob, 1000), + serverId: "", + serverPosition: 3, + clusterSize: 3, + } + + scheduler.updateJobs(mockFn) + So(len(scheduler.jobs), ShouldEqual, 0) + }) + */ + }) +} diff --git a/pkg/services/alerting/result_handler.go b/pkg/services/alerting/result_handler.go new file mode 100644 index 00000000000..09c77c8edd7 --- /dev/null +++ b/pkg/services/alerting/result_handler.go @@ -0,0 +1,90 @@ +package alerting + +import ( + "time" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/metrics" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/annotations" +) + +type ResultHandler interface { + Handle(ctx *EvalContext) +} + +type DefaultResultHandler struct { + notifier Notifier + log log.Logger +} + +func NewResultHandler() *DefaultResultHandler { + return &DefaultResultHandler{ + log: log.New("alerting.resultHandler"), + notifier: NewRootNotifier(), + } +} + +func (handler *DefaultResultHandler) Handle(ctx *EvalContext) { + oldState := ctx.Rule.State + + exeuctionError := "" + if ctx.Error != nil { + handler.log.Error("Alert Rule Result Error", "ruleId", ctx.Rule.Id, "error", ctx.Error) + ctx.Rule.State = m.AlertStateExeuctionError + exeuctionError = ctx.Error.Error() + } else if ctx.Firing { + ctx.Rule.State = m.AlertStateType(ctx.Rule.Severity) + } else { + ctx.Rule.State = m.AlertStateOK + } + + countSeverity(ctx.Rule.Severity) + if ctx.Rule.State != oldState { + handler.log.Info("New state change", "alertId", ctx.Rule.Id, "newState", ctx.Rule.State, "oldState", oldState) + + cmd := &m.SetAlertStateCommand{ + AlertId: ctx.Rule.Id, + OrgId: ctx.Rule.OrgId, + State: ctx.Rule.State, + Error: exeuctionError, + } + + if err := bus.Dispatch(cmd); err != nil { + handler.log.Error("Failed to save state", "error", err) + } + + // save annotation + item := annotations.Item{ + OrgId: ctx.Rule.OrgId, + Type: annotations.AlertType, + AlertId: ctx.Rule.Id, + Title: ctx.Rule.Name, + Text: ctx.GetStateText(), + NewState: string(ctx.Rule.State), + PrevState: string(oldState), + Timestamp: time.Now(), + } + + annotationRepo := annotations.GetRepository() + if err := annotationRepo.Save(&item); err != nil { + handler.log.Error("Failed to save annotation for new alert state", "error", err) + } + + handler.notifier.Notify(ctx) + } +} + +func countSeverity(state m.AlertSeverityType) { + switch state { + case m.AlertSeverityOK: + metrics.M_Alerting_Result_Ok.Inc(1) + case m.AlertSeverityInfo: + metrics.M_Alerting_Result_Info.Inc(1) + case m.AlertSeverityWarning: + metrics.M_Alerting_Result_Warning.Inc(1) + case m.AlertSeverityCritical: + metrics.M_Alerting_Result_Critical.Inc(1) + } +} diff --git a/pkg/services/alerting/result_handler_test.go b/pkg/services/alerting/result_handler_test.go new file mode 100644 index 00000000000..32589bef172 --- /dev/null +++ b/pkg/services/alerting/result_handler_test.go @@ -0,0 +1,58 @@ +package alerting + +// import ( +// "testing" +// "time" +// +// "github.com/grafana/grafana/pkg/bus" +// m "github.com/grafana/grafana/pkg/models" +// "github.com/grafana/grafana/pkg/services/alerting/alertstates" +// +// . "github.com/smartystreets/goconvey/convey" +// ) +// +// func TestAlertResultHandler(t *testing.T) { +// Convey("Test result Handler", t, func() { +// resultHandler := ResultHandlerImpl{} +// mockResult := &AlertResultContext{ +// Triggered: false, +// Rule: &AlertRule{ +// Id: 1, +// OrgId 1, +// }, +// } +// mockAlertState := &m.AlertState{} +// bus.ClearBusHandlers() +// bus.AddHandler("test", func(query *m.GetLastAlertStateQuery) error { +// query.Result = mockAlertState +// return nil +// }) +// +// Convey("Should update", func() { +// +// Convey("when no earlier alert state", func() { +// mockAlertState = nil +// So(resultHandler.shouldUpdateState(mockResult), ShouldBeTrue) +// }) +// +// Convey("alert state have changed", func() { +// mockAlertState = &m.AlertState{ +// State: alertstates.Critical, +// } +// mockResult.Triggered = false +// So(resultHandler.shouldUpdateState(mockResult), ShouldBeTrue) +// }) +// +// Convey("last alert state was 15min ago", func() { +// now := time.Now() +// mockAlertState = &m.AlertState{ +// State: alertstates.Critical, +// Created: now.Add(time.Minute * -30), +// } +// mockResult.Triggered = true +// mockResult.StartTime = time.Now() +// So(resultHandler.shouldUpdateState(mockResult), ShouldBeTrue) +// }) +// }) +// }) +// } diff --git a/pkg/services/alerting/rule.go b/pkg/services/alerting/rule.go new file mode 100644 index 00000000000..8292041e04c --- /dev/null +++ b/pkg/services/alerting/rule.go @@ -0,0 +1,107 @@ +package alerting + +import ( + "fmt" + "regexp" + "strconv" + + "github.com/grafana/grafana/pkg/components/simplejson" + + m "github.com/grafana/grafana/pkg/models" +) + +type Rule struct { + Id int64 + OrgId int64 + DashboardId int64 + PanelId int64 + Frequency int64 + Name string + Message string + State m.AlertStateType + Severity m.AlertSeverityType + Conditions []Condition + Notifications []int64 +} + +type ValidationError struct { + Reason string +} + +func (e ValidationError) Error() string { + return e.Reason +} + +var ( + ValueFormatRegex = regexp.MustCompile("^\\d+") + UnitFormatRegex = regexp.MustCompile("\\w{1}$") +) + +var unitMultiplier = map[string]int{ + "s": 1, + "m": 60, + "h": 3600, +} + +func getTimeDurationStringToSeconds(str string) int64 { + multiplier := 1 + + value, _ := strconv.Atoi(ValueFormatRegex.FindAllString(str, 1)[0]) + unit := UnitFormatRegex.FindAllString(str, 1)[0] + + if val, ok := unitMultiplier[unit]; ok { + multiplier = val + } + + return int64(value * multiplier) +} + +func NewRuleFromDBAlert(ruleDef *m.Alert) (*Rule, error) { + model := &Rule{} + model.Id = ruleDef.Id + model.OrgId = ruleDef.OrgId + model.DashboardId = ruleDef.DashboardId + model.PanelId = ruleDef.PanelId + model.Name = ruleDef.Name + model.Message = ruleDef.Message + model.Frequency = ruleDef.Frequency + model.Severity = ruleDef.Severity + model.State = ruleDef.State + + for _, v := range ruleDef.Settings.Get("notifications").MustArray() { + jsonModel := simplejson.NewFromAny(v) + if id, err := jsonModel.Get("id").Int64(); err != nil { + return nil, ValidationError{Reason: "Invalid notification schema"} + } else { + model.Notifications = append(model.Notifications, id) + } + } + + for index, condition := range ruleDef.Settings.Get("conditions").MustArray() { + conditionModel := simplejson.NewFromAny(condition) + conditionType := conditionModel.Get("type").MustString() + if factory, exist := conditionFactories[conditionType]; !exist { + return nil, ValidationError{Reason: "Unknown alert condition: " + conditionType} + } else { + if queryCondition, err := factory(conditionModel, index); err != nil { + return nil, err + } else { + model.Conditions = append(model.Conditions, queryCondition) + } + } + } + + if len(model.Conditions) == 0 { + return nil, fmt.Errorf("Alert is missing conditions") + } + + return model, nil +} + +type ConditionFactory func(model *simplejson.Json, index int) (Condition, error) + +var conditionFactories map[string]ConditionFactory = make(map[string]ConditionFactory) + +func RegisterCondition(typeName string, factory ConditionFactory) { + conditionFactories[typeName] = factory +} diff --git a/pkg/services/alerting/rule_test.go b/pkg/services/alerting/rule_test.go new file mode 100644 index 00000000000..91b31d6d07f --- /dev/null +++ b/pkg/services/alerting/rule_test.go @@ -0,0 +1,85 @@ +package alerting + +import ( + "testing" + + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/models" + . "github.com/smartystreets/goconvey/convey" +) + +type FakeCondition struct{} + +func (f *FakeCondition) Eval(context *EvalContext) {} + +func TestAlertRuleModel(t *testing.T) { + Convey("Testing alert rule", t, func() { + + RegisterCondition("test", func(model *simplejson.Json, index int) (Condition, error) { + return &FakeCondition{}, nil + }) + + Convey("Can parse seconds", func() { + seconds := getTimeDurationStringToSeconds("10s") + So(seconds, ShouldEqual, 10) + }) + + Convey("Can parse minutes", func() { + seconds := getTimeDurationStringToSeconds("10m") + So(seconds, ShouldEqual, 600) + }) + + Convey("Can parse hours", func() { + seconds := getTimeDurationStringToSeconds("1h") + So(seconds, ShouldEqual, 3600) + }) + + Convey("defaults to seconds", func() { + seconds := getTimeDurationStringToSeconds("1o") + So(seconds, ShouldEqual, 1) + }) + + Convey("can construct alert rule model", func() { + json := ` + { + "name": "name2", + "description": "desc2", + "handler": 0, + "enabled": true, + "frequency": "60s", + "conditions": [ + { + "type": "test", + "prop": 123 + } + ], + "notifications": [ + {"id": 1134}, + {"id": 22} + ] + } + ` + + alertJSON, jsonErr := simplejson.NewJson([]byte(json)) + So(jsonErr, ShouldBeNil) + + alert := &models.Alert{ + Id: 1, + OrgId: 1, + DashboardId: 1, + PanelId: 1, + + Settings: alertJSON, + } + + alertRule, err := NewRuleFromDBAlert(alert) + So(err, ShouldBeNil) + + So(len(alertRule.Conditions), ShouldEqual, 1) + + Convey("Can read notifications", func() { + So(len(alertRule.Notifications), ShouldEqual, 2) + }) + }) + }) +} diff --git a/pkg/services/alerting/scheduler.go b/pkg/services/alerting/scheduler.go new file mode 100644 index 00000000000..ffac7ddb659 --- /dev/null +++ b/pkg/services/alerting/scheduler.go @@ -0,0 +1,54 @@ +package alerting + +import ( + "time" + + "github.com/grafana/grafana/pkg/log" +) + +type SchedulerImpl struct { + jobs map[int64]*Job + log log.Logger +} + +func NewScheduler() Scheduler { + return &SchedulerImpl{ + jobs: make(map[int64]*Job, 0), + log: log.New("alerting.scheduler"), + } +} + +func (s *SchedulerImpl) Update(rules []*Rule) { + s.log.Debug("Scheduling update", "ruleCount", len(rules)) + + jobs := make(map[int64]*Job, 0) + + for i, rule := range rules { + var job *Job + if s.jobs[rule.Id] != nil { + job = s.jobs[rule.Id] + } else { + job = &Job{ + Running: false, + } + } + + job.Rule = rule + job.Offset = int64(i) + + jobs[rule.Id] = job + } + + s.jobs = jobs +} + +func (s *SchedulerImpl) Tick(tickTime time.Time, execQueue chan *Job) { + now := tickTime.Unix() + + for _, job := range s.jobs { + if now%job.Rule.Frequency == 0 && job.Running == false { + s.log.Debug("Scheduler: Putting job on to exec queue", "name", job.Rule.Name) + execQueue <- job + } + } +} diff --git a/pkg/services/alerting/test_rule.go b/pkg/services/alerting/test_rule.go new file mode 100644 index 00000000000..25a08a3b3bf --- /dev/null +++ b/pkg/services/alerting/test_rule.go @@ -0,0 +1,57 @@ +package alerting + +import ( + "fmt" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/components/simplejson" + m "github.com/grafana/grafana/pkg/models" +) + +type AlertTestCommand struct { + Dashboard *simplejson.Json + PanelId int64 + OrgId int64 + + Result *EvalContext +} + +func init() { + bus.AddHandler("alerting", handleAlertTestCommand) +} + +func handleAlertTestCommand(cmd *AlertTestCommand) error { + + dash := m.NewDashboardFromJson(cmd.Dashboard) + + extractor := NewDashAlertExtractor(dash, cmd.OrgId) + alerts, err := extractor.GetAlerts() + if err != nil { + return err + } + + for _, alert := range alerts { + if alert.PanelId == cmd.PanelId { + rule, err := NewRuleFromDBAlert(alert) + if err != nil { + return err + } + + cmd.Result = testAlertRule(rule) + return nil + } + } + + return fmt.Errorf("Could not find alert with panel id %d", cmd.PanelId) +} + +func testAlertRule(rule *Rule) *EvalContext { + handler := NewEvalHandler() + + context := NewEvalContext(rule) + context.IsTestRun = true + + handler.Eval(context) + + return context +} diff --git a/pkg/services/alerting/ticker.go b/pkg/services/alerting/ticker.go new file mode 100644 index 00000000000..5ce19b1b232 --- /dev/null +++ b/pkg/services/alerting/ticker.go @@ -0,0 +1,60 @@ +package alerting + +import ( + "time" + + "github.com/benbjohnson/clock" +) + +// ticker is a ticker to power the alerting scheduler. it's like a time.Ticker, except: +// * it doesn't drop ticks for slow receivers, rather, it queues up. so that callers are in control to instrument what's going on. +// * it automatically ticks every second, which is the right thing in our current design +// * it ticks on second marks or very shortly after. this provides a predictable load pattern +// (this shouldn't cause too much load contention issues because the next steps in the pipeline just process at their own pace) +// * the timestamps are used to mark "last datapoint to query for" and as such, are a configurable amount of seconds in the past +// * because we want to allow: +// - a clean "resume where we left off" and "don't yield ticks we already did" +// - adjusting offset over time to compensate for storage backing up or getting fast and providing lower latency +// you specify a lastProcessed timestamp as well as an offset at creation, or runtime +type Ticker struct { + C chan time.Time + clock clock.Clock + last time.Time + offset time.Duration + newOffset chan time.Duration +} + +// NewTicker returns a ticker that ticks on second marks or very shortly after, and never drops ticks +func NewTicker(last time.Time, initialOffset time.Duration, c clock.Clock) *Ticker { + t := &Ticker{ + C: make(chan time.Time), + clock: c, + last: last, + offset: initialOffset, + newOffset: make(chan time.Duration), + } + go t.run() + return t +} + +func (t *Ticker) updateOffset(offset time.Duration) { + t.newOffset <- offset +} + +func (t *Ticker) run() { + for { + next := t.last.Add(time.Duration(1) * time.Second) + diff := t.clock.Now().Add(-t.offset).Sub(next) + if diff >= 0 { + t.C <- next + t.last = next + continue + } + // tick is too young. try again when ... + select { + case <-t.clock.After(-diff): // ...it'll definitely be old enough + case offset := <-t.newOffset: // ...it might be old enough + t.offset = offset + } + } +} diff --git a/pkg/services/alerting/ticker_test.go b/pkg/services/alerting/ticker_test.go new file mode 100644 index 00000000000..d4a5b958cdb --- /dev/null +++ b/pkg/services/alerting/ticker_test.go @@ -0,0 +1,121 @@ +package alerting + +import ( + "testing" + "time" + + "github.com/benbjohnson/clock" +) + +func inspectTick(tick time.Time, last time.Time, offset time.Duration, t *testing.T) { + if !tick.Equal(last.Add(time.Duration(1) * time.Second)) { + t.Fatalf("expected a tick 1 second more than prev, %s. got: %s", last, tick) + } +} + +// returns the new last tick seen +func assertAdvanceUntil(ticker *Ticker, last, desiredLast time.Time, offset, wait time.Duration, t *testing.T) time.Time { + for { + select { + case tick := <-ticker.C: + inspectTick(tick, last, offset, t) + last = tick + case <-time.NewTimer(wait).C: + if last.Before(desiredLast) { + t.Fatalf("waited %s for ticker to advance to %s, but only went up to %s", wait, desiredLast, last) + } + if last.After(desiredLast) { + t.Fatalf("timer advanced too far. should only have gone up to %s, but it went up to %s", desiredLast, last) + } + return last + } + } +} + +func assertNoAdvance(ticker *Ticker, desiredLast time.Time, wait time.Duration, t *testing.T) { + for { + select { + case tick := <-ticker.C: + t.Fatalf("timer should have stayed at %s, instead it advanced to %s", desiredLast, tick) + case <-time.NewTimer(wait).C: + return + } + } +} + +func TestTickerRetro1Hour(t *testing.T) { + offset := time.Duration(10) * time.Second + last := time.Unix(0, 0) + mock := clock.NewMock() + mock.Add(time.Duration(1) * time.Hour) + desiredLast := mock.Now().Add(-offset) + ticker := NewTicker(last, offset, mock) + + last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(10)*time.Millisecond, t) + assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) + +} + +func TestAdvanceWithUpdateOffset(t *testing.T) { + offset := time.Duration(10) * time.Second + last := time.Unix(0, 0) + mock := clock.NewMock() + mock.Add(time.Duration(1) * time.Hour) + desiredLast := mock.Now().Add(-offset) + ticker := NewTicker(last, offset, mock) + + last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(10)*time.Millisecond, t) + assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) + + // lowering offset should see a few more ticks + offset = time.Duration(5) * time.Second + ticker.updateOffset(offset) + desiredLast = mock.Now().Add(-offset) + last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(9)*time.Millisecond, t) + assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) + + // advancing clock should see even more ticks + mock.Add(time.Duration(1) * time.Hour) + desiredLast = mock.Now().Add(-offset) + last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(8)*time.Millisecond, t) + assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) + +} + +func getCase(lastSeconds, offsetSeconds int) (time.Time, time.Duration) { + last := time.Unix(int64(lastSeconds), 0) + offset := time.Duration(offsetSeconds) * time.Second + return last, offset +} + +func TestTickerNoAdvance(t *testing.T) { + + // it's 00:01:00 now. what are some cases where we don't want the ticker to advance? + mock := clock.NewMock() + mock.Add(time.Duration(60) * time.Second) + + type Case struct { + last int + offset int + } + + // note that some cases add up to now, others go into the future + cases := []Case{ + {50, 10}, + {50, 30}, + {59, 1}, + {59, 10}, + {59, 30}, + {60, 1}, + {60, 10}, + {60, 30}, + {90, 1}, + {90, 10}, + {90, 30}, + } + for _, c := range cases { + last, offset := getCase(c.last, c.offset) + ticker := NewTicker(last, offset, mock) + assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) + } +} diff --git a/pkg/services/annotations/annotations.go b/pkg/services/annotations/annotations.go new file mode 100644 index 00000000000..fd8c8ebdb9a --- /dev/null +++ b/pkg/services/annotations/annotations.go @@ -0,0 +1,43 @@ +package annotations + +import ( + "time" + + "github.com/grafana/grafana/pkg/components/simplejson" +) + +type Repository interface { + Save(item *Item) error +} + +var repositoryInstance Repository + +func GetRepository() Repository { + return repositoryInstance +} + +func SetRepository(rep Repository) { + repositoryInstance = rep +} + +type ItemType string + +const ( + AlertType ItemType = "alert" +) + +type Item struct { + Id int64 `json:"id"` + OrgId int64 `json:"orgId"` + Type ItemType `json:"type"` + Title string `json:"title"` + Text string `json:"text"` + Metric string `json:"metric"` + AlertId int64 `json:"alertId"` + UserId int64 `json:"userId"` + PrevState string `json:"prevState"` + NewState string `json:"newState"` + Timestamp time.Time `json:"timestamp"` + + Data *simplejson.Json `json:"data"` +} diff --git a/pkg/services/notifications/notifications.go b/pkg/services/notifications/notifications.go index 63ce7219618..04b11f73b84 100644 --- a/pkg/services/notifications/notifications.go +++ b/pkg/services/notifications/notifications.go @@ -23,11 +23,14 @@ var tmplWelcomeOnSignUp = "welcome_on_signup.html" func Init() error { initMailQueue() + initWebhookQueue() bus.AddHandler("email", sendResetPasswordEmail) bus.AddHandler("email", validateResetPasswordCode) bus.AddHandler("email", sendEmailCommandHandler) + bus.AddHandler("webhook", sendWebhook) + bus.AddEventListener(signUpStartedHandler) bus.AddEventListener(signUpCompletedHandler) @@ -53,6 +56,17 @@ func Init() error { return nil } +func sendWebhook(cmd *m.SendWebhook) error { + addToWebhookQueue(&Webhook{ + Url: cmd.Url, + User: cmd.User, + Password: cmd.Password, + Body: cmd.Body, + }) + + return nil +} + func subjectTemplateFunc(obj map[string]interface{}, value string) string { obj["value"] = value return "" diff --git a/pkg/services/notifications/notifications_test.go b/pkg/services/notifications/notifications_test.go index 110e24cb810..d4f4ee0a5fb 100644 --- a/pkg/services/notifications/notifications_test.go +++ b/pkg/services/notifications/notifications_test.go @@ -9,6 +9,12 @@ import ( . "github.com/smartystreets/goconvey/convey" ) +type testTriggeredAlert struct { + ActualValue float64 + Name string + State string +} + func TestNotifications(t *testing.T) { Convey("Given the notifications service", t, func() { @@ -35,5 +41,4 @@ func TestNotifications(t *testing.T) { So(sentMsg.Body, ShouldNotContainSubstring, "Subject") }) }) - } diff --git a/pkg/services/notifications/send_email_integration_test.go b/pkg/services/notifications/send_email_integration_test.go new file mode 100644 index 00000000000..b91cc178240 --- /dev/null +++ b/pkg/services/notifications/send_email_integration_test.go @@ -0,0 +1,62 @@ +package notifications + +import ( + "io/ioutil" + "testing" + + "github.com/grafana/grafana/pkg/bus" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/setting" + . "github.com/smartystreets/goconvey/convey" +) + +func TestEmailIntegrationTest(t *testing.T) { + SkipConvey("Given the notifications service", t, func() { + bus.ClearBusHandlers() + + setting.StaticRootPath = "../../../public/" + setting.Smtp.Enabled = true + setting.Smtp.TemplatesPattern = "emails/*.html" + setting.Smtp.FromAddress = "from@address.com" + setting.BuildVersion = "4.0.0" + + err := Init() + So(err, ShouldBeNil) + + addToMailQueue = func(msg *Message) { + ioutil.WriteFile("../../../tmp/test_email.html", []byte(msg.Body), 0777) + } + + Convey("When sending reset email password", func() { + cmd := &m.SendEmailCommand{ + + Data: map[string]interface{}{ + "Title": "[CRITICAL] Imaginary timeserie alert", + "State": "Firing", + "Name": "Imaginary timeserie alert", + "Severity": "ok", + "SeverityColor": "#D63232", + "Message": "Alert message that will support markdown in some distant future.", + "RuleUrl": "http://localhost:3000/dashboard/db/graphite-dashboard", + "ImageLink": "http://localhost:3000/render/dashboard-solo/db/graphite-dashboard?panelId=1&from=1471008499616&to=1471012099617&width=1000&height=500", + "AlertPageUrl": "http://localhost:3000/alerting", + "Events": []map[string]string{ + { + "Metric": "desktop", + "Value": "40", + }, + { + "Metric": "mobile", + "Value": "20", + }, + }, + }, + To: []string{"asdf@asdf.com "}, + Template: "alert_notification.html", + } + + err := sendEmailCommandHandler(cmd) + So(err, ShouldBeNil) + }) + }) +} diff --git a/pkg/services/notifications/webhook.go b/pkg/services/notifications/webhook.go new file mode 100644 index 00000000000..31f00baebd3 --- /dev/null +++ b/pkg/services/notifications/webhook.go @@ -0,0 +1,79 @@ +package notifications + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" + "time" + + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/util" +) + +type Webhook struct { + Url string + User string + Password string + Body string +} + +var webhookQueue chan *Webhook +var webhookLog log.Logger + +func initWebhookQueue() { + webhookLog = log.New("notifications.webhook") + webhookQueue = make(chan *Webhook, 10) + go processWebhookQueue() +} + +func processWebhookQueue() { + for { + select { + case webhook := <-webhookQueue: + err := sendWebRequest(webhook) + + if err != nil { + webhookLog.Error("Failed to send webrequest ", "error", err) + } + } + } +} + +func sendWebRequest(webhook *Webhook) error { + webhookLog.Debug("Sending webhook", "url", webhook.Url) + + client := http.Client{ + Timeout: time.Duration(3 * time.Second), + } + + request, err := http.NewRequest("POST", webhook.Url, bytes.NewReader([]byte(webhook.Body))) + if webhook.User != "" && webhook.Password != "" { + request.Header.Add("Authorization", util.GetBasicAuthHeader(webhook.User, webhook.Password)) + } + + if err != nil { + return err + } + + resp, err := client.Do(request) + if err != nil { + return err + } + + _, err = ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != 200 { + return fmt.Errorf("Webhook response code %v", resp.StatusCode) + } + + defer resp.Body.Close() + return nil +} + +var addToWebhookQueue = func(msg *Webhook) { + webhookQueue <- msg +} diff --git a/pkg/services/sqlstore/alert.go b/pkg/services/sqlstore/alert.go new file mode 100644 index 00000000000..be67749a627 --- /dev/null +++ b/pkg/services/sqlstore/alert.go @@ -0,0 +1,234 @@ +package sqlstore + +import ( + "bytes" + "fmt" + "time" + + "github.com/go-xorm/xorm" + "github.com/grafana/grafana/pkg/bus" + m "github.com/grafana/grafana/pkg/models" +) + +func init() { + bus.AddHandler("sql", SaveAlerts) + bus.AddHandler("sql", HandleAlertsQuery) + bus.AddHandler("sql", GetAlertById) + bus.AddHandler("sql", DeleteAlertById) + bus.AddHandler("sql", GetAllAlertQueryHandler) + bus.AddHandler("sql", SetAlertState) +} + +func GetAlertById(query *m.GetAlertByIdQuery) error { + alert := m.Alert{} + has, err := x.Id(query.Id).Get(&alert) + if !has { + return fmt.Errorf("could not find alert") + } + if err != nil { + return err + } + + query.Result = &alert + return nil +} + +func GetAllAlertQueryHandler(query *m.GetAllAlertsQuery) error { + var alerts []*m.Alert + err := x.Sql("select * from alert").Find(&alerts) + if err != nil { + return err + } + + query.Result = alerts + return nil +} + +func DeleteAlertById(cmd *m.DeleteAlertCommand) error { + return inTransaction(func(sess *xorm.Session) error { + if _, err := sess.Exec("DELETE FROM alert WHERE id = ?", cmd.AlertId); err != nil { + return err + } + + return nil + }) +} + +func HandleAlertsQuery(query *m.GetAlertsQuery) error { + var sql bytes.Buffer + params := make([]interface{}, 0) + + sql.WriteString(`SELECT * + from alert + `) + + sql.WriteString(`WHERE org_id = ?`) + params = append(params, query.OrgId) + + if query.DashboardId != 0 { + sql.WriteString(` AND dashboard_id = ?`) + params = append(params, query.DashboardId) + } + + if query.PanelId != 0 { + sql.WriteString(` AND panel_id = ?`) + params = append(params, query.PanelId) + } + + if len(query.State) > 0 && query.State[0] != "ALL" { + sql.WriteString(` AND (`) + for i, v := range query.State { + if i > 0 { + sql.WriteString(" OR ") + } + sql.WriteString("state = ? ") + params = append(params, v) + } + sql.WriteString(")") + } + + alerts := make([]*m.Alert, 0) + if err := x.Sql(sql.String(), params...).Find(&alerts); err != nil { + return err + } + + query.Result = alerts + return nil +} + +func DeleteAlertDefinition(dashboardId int64, sess *xorm.Session) error { + alerts := make([]*m.Alert, 0) + sess.Where("dashboard_id = ?", dashboardId).Find(&alerts) + + for _, alert := range alerts { + _, err := sess.Exec("DELETE FROM alert WHERE id = ? ", alert.Id) + if err != nil { + return err + } + + sqlog.Debug("Alert deleted (due to dashboard deletion)", "name", alert.Name, "id", alert.Id) + } + + return nil +} + +func SaveAlerts(cmd *m.SaveAlertsCommand) error { + return inTransaction(func(sess *xorm.Session) error { + existingAlerts, err := GetAlertsByDashboardId2(cmd.DashboardId, sess) + if err != nil { + return err + } + + if err := upsertAlerts(existingAlerts, cmd, sess); err != nil { + return err + } + + if err := deleteMissingAlerts(existingAlerts, cmd, sess); err != nil { + return err + } + + return nil + }) +} + +func upsertAlerts(existingAlerts []*m.Alert, cmd *m.SaveAlertsCommand, sess *xorm.Session) error { + for _, alert := range cmd.Alerts { + update := false + var alertToUpdate *m.Alert + + for _, k := range existingAlerts { + if alert.PanelId == k.PanelId { + update = true + alert.Id = k.Id + alertToUpdate = k + break + } + } + + if update { + if alertToUpdate.ContainsUpdates(alert) { + alert.Updated = time.Now() + alert.State = alertToUpdate.State + _, err := sess.Id(alert.Id).Update(alert) + if err != nil { + return err + } + + sqlog.Debug("Alert updated", "name", alert.Name, "id", alert.Id) + } + } else { + alert.Updated = time.Now() + alert.Created = time.Now() + alert.State = m.AlertStatePending + alert.NewStateDate = time.Now() + + _, err := sess.Insert(alert) + if err != nil { + return err + } + + sqlog.Debug("Alert inserted", "name", alert.Name, "id", alert.Id) + } + } + + return nil +} + +func deleteMissingAlerts(alerts []*m.Alert, cmd *m.SaveAlertsCommand, sess *xorm.Session) error { + for _, missingAlert := range alerts { + missing := true + + for _, k := range cmd.Alerts { + if missingAlert.PanelId == k.PanelId { + missing = false + break + } + } + + if missing { + _, err := sess.Exec("DELETE FROM alert WHERE id = ?", missingAlert.Id) + if err != nil { + return err + } + + sqlog.Debug("Alert deleted", "name", missingAlert.Name, "id", missingAlert.Id) + } + } + + return nil +} + +func GetAlertsByDashboardId2(dashboardId int64, sess *xorm.Session) ([]*m.Alert, error) { + alerts := make([]*m.Alert, 0) + err := sess.Where("dashboard_id = ?", dashboardId).Find(&alerts) + + if err != nil { + return []*m.Alert{}, err + } + + return alerts, nil +} + +func SetAlertState(cmd *m.SetAlertStateCommand) error { + return inTransaction(func(sess *xorm.Session) error { + alert := m.Alert{} + + if has, err := sess.Id(cmd.AlertId).Get(&alert); err != nil { + return err + } else if !has { + return fmt.Errorf("Could not find alert") + } + + alert.State = cmd.State + alert.StateChanges += 1 + alert.NewStateDate = time.Now() + if cmd.Error == "" { + alert.ExecutionError = " " //without this space, xorm skips updating this field + } else { + alert.ExecutionError = cmd.Error + } + + sess.Id(alert.Id).Update(&alert) + return nil + }) +} diff --git a/pkg/services/sqlstore/alert_heartbeat_test.go b/pkg/services/sqlstore/alert_heartbeat_test.go new file mode 100644 index 00000000000..196d3fd7dde --- /dev/null +++ b/pkg/services/sqlstore/alert_heartbeat_test.go @@ -0,0 +1,18 @@ +package sqlstore + +import ( + "testing" + + // m "github.com/grafana/grafana/pkg/models" + . "github.com/smartystreets/goconvey/convey" +) + +func TestAlertingHeartbeatDataAccess(t *testing.T) { + + Convey("Testing Alerting data access", t, func() { + InitTestDB(t) + //send heartbeat from server 1 + //send heartbeat from server 2 + + }) +} diff --git a/pkg/services/sqlstore/alert_notification.go b/pkg/services/sqlstore/alert_notification.go new file mode 100644 index 00000000000..c5b3a2f5975 --- /dev/null +++ b/pkg/services/sqlstore/alert_notification.go @@ -0,0 +1,145 @@ +package sqlstore + +import ( + "bytes" + "fmt" + "strings" + "time" + + "github.com/go-xorm/xorm" + "github.com/grafana/grafana/pkg/bus" + m "github.com/grafana/grafana/pkg/models" +) + +func init() { + bus.AddHandler("sql", GetAlertNotifications) + bus.AddHandler("sql", CreateAlertNotificationCommand) + bus.AddHandler("sql", UpdateAlertNotification) + bus.AddHandler("sql", DeleteAlertNotification) +} + +func DeleteAlertNotification(cmd *m.DeleteAlertNotificationCommand) error { + return inTransaction(func(sess *xorm.Session) error { + sql := "DELETE FROM alert_notification WHERE alert_notification.org_id = ? AND alert_notification.id = ?" + _, err := sess.Exec(sql, cmd.OrgId, cmd.Id) + + if err != nil { + return err + } + + return nil + }) +} + +func GetAlertNotifications(query *m.GetAlertNotificationsQuery) error { + return getAlertNotificationsInternal(query, x.NewSession()) +} + +func getAlertNotificationsInternal(query *m.GetAlertNotificationsQuery, sess *xorm.Session) error { + var sql bytes.Buffer + params := make([]interface{}, 0) + + sql.WriteString(`SELECT + alert_notification.id, + alert_notification.org_id, + alert_notification.name, + alert_notification.type, + alert_notification.created, + alert_notification.updated, + alert_notification.settings + FROM alert_notification + `) + + sql.WriteString(` WHERE alert_notification.org_id = ?`) + params = append(params, query.OrgId) + + if query.Name != "" { + sql.WriteString(` AND alert_notification.name = ?`) + params = append(params, query.Name) + } + + if query.Id != 0 { + sql.WriteString(` AND alert_notification.id = ?`) + params = append(params, query.Id) + } + + if len(query.Ids) > 0 { + sql.WriteString(` AND alert_notification.id IN (?` + strings.Repeat(",?", len(query.Ids)-1) + ")") + for _, v := range query.Ids { + params = append(params, v) + } + } + + results := make([]*m.AlertNotification, 0) + if err := sess.Sql(sql.String(), params...).Find(&results); err != nil { + return err + } + + query.Result = results + return nil +} + +func CreateAlertNotificationCommand(cmd *m.CreateAlertNotificationCommand) error { + return inTransaction(func(sess *xorm.Session) error { + existingQuery := &m.GetAlertNotificationsQuery{OrgId: cmd.OrgId, Name: cmd.Name} + err := getAlertNotificationsInternal(existingQuery, sess) + + if err != nil { + return err + } + + if len(existingQuery.Result) > 0 { + return fmt.Errorf("Alert notification name %s already exists", cmd.Name) + } + + alertNotification := &m.AlertNotification{ + OrgId: cmd.OrgId, + Name: cmd.Name, + Type: cmd.Type, + Settings: cmd.Settings, + Created: time.Now(), + Updated: time.Now(), + } + + if _, err = sess.Insert(alertNotification); err != nil { + return err + } + + cmd.Result = alertNotification + return nil + }) +} + +func UpdateAlertNotification(cmd *m.UpdateAlertNotificationCommand) error { + return inTransaction(func(sess *xorm.Session) (err error) { + current := m.AlertNotification{} + + if _, err = sess.Id(cmd.Id).Get(¤t); err != nil { + return err + } + + // check if name exists + sameNameQuery := &m.GetAlertNotificationsQuery{OrgId: cmd.OrgId, Name: cmd.Name} + if err := getAlertNotificationsInternal(sameNameQuery, sess); err != nil { + return err + } + + if len(sameNameQuery.Result) > 0 && sameNameQuery.Result[0].Id != current.Id { + return fmt.Errorf("Alert notification name %s already exists", cmd.Name) + } + + current.Updated = time.Now() + current.Settings = cmd.Settings + current.Name = cmd.Name + current.Type = cmd.Type + + if affected, err := sess.Id(cmd.Id).Update(current); err != nil { + return err + } else if affected == 0 { + return fmt.Errorf("Could not find alert notification") + } + + cmd.Result = ¤t + return nil + }) +} diff --git a/pkg/services/sqlstore/alert_notification_test.go b/pkg/services/sqlstore/alert_notification_test.go new file mode 100644 index 00000000000..4cbcf13a000 --- /dev/null +++ b/pkg/services/sqlstore/alert_notification_test.go @@ -0,0 +1,83 @@ +package sqlstore + +import ( + "fmt" + "testing" + + "github.com/grafana/grafana/pkg/components/simplejson" + m "github.com/grafana/grafana/pkg/models" + . "github.com/smartystreets/goconvey/convey" +) + +func TestAlertNotificationSQLAccess(t *testing.T) { + Convey("Testing Alert notification sql access", t, func() { + InitTestDB(t) + var err error + + Convey("Alert notifications should be empty", func() { + cmd := &m.GetAlertNotificationsQuery{ + OrgId: 2, + Name: "email", + } + + err := GetAlertNotifications(cmd) + fmt.Printf("errror %v", err) + So(err, ShouldBeNil) + So(len(cmd.Result), ShouldEqual, 0) + }) + + Convey("Can save Alert Notification", func() { + cmd := &m.CreateAlertNotificationCommand{ + Name: "ops", + Type: "email", + OrgId: 1, + Settings: simplejson.New(), + } + + err = CreateAlertNotificationCommand(cmd) + So(err, ShouldBeNil) + So(cmd.Result.Id, ShouldNotEqual, 0) + So(cmd.Result.OrgId, ShouldNotEqual, 0) + So(cmd.Result.Type, ShouldEqual, "email") + + Convey("Cannot save Alert Notification with the same name", func() { + err = CreateAlertNotificationCommand(cmd) + So(err, ShouldNotBeNil) + }) + + Convey("Can update alert notification", func() { + newCmd := &m.UpdateAlertNotificationCommand{ + Name: "NewName", + Type: "webhook", + OrgId: cmd.Result.OrgId, + Settings: simplejson.New(), + Id: cmd.Result.Id, + } + err := UpdateAlertNotification(newCmd) + So(err, ShouldBeNil) + So(newCmd.Result.Name, ShouldEqual, "NewName") + }) + }) + + Convey("Can search using an array of ids", func() { + cmd1 := m.CreateAlertNotificationCommand{Name: "nagios", Type: "webhook", OrgId: 1, Settings: simplejson.New()} + cmd2 := m.CreateAlertNotificationCommand{Name: "slack", Type: "webhook", OrgId: 1, Settings: simplejson.New()} + cmd3 := m.CreateAlertNotificationCommand{Name: "ops2", Type: "email", OrgId: 1, Settings: simplejson.New()} + + So(CreateAlertNotificationCommand(&cmd1), ShouldBeNil) + So(CreateAlertNotificationCommand(&cmd2), ShouldBeNil) + So(CreateAlertNotificationCommand(&cmd3), ShouldBeNil) + + Convey("search", func() { + query := &m.GetAlertNotificationsQuery{ + Ids: []int64{cmd1.Result.Id, cmd2.Result.Id, 112341231}, + OrgId: 1, + } + + err := GetAlertNotifications(query) + So(err, ShouldBeNil) + So(len(query.Result), ShouldEqual, 2) + }) + }) + }) +} diff --git a/pkg/services/sqlstore/alert_state.go b/pkg/services/sqlstore/alert_state.go new file mode 100644 index 00000000000..38c14b077b5 --- /dev/null +++ b/pkg/services/sqlstore/alert_state.go @@ -0,0 +1,77 @@ +package sqlstore + +// import ( +// "fmt" +// "time" +// +// "github.com/go-xorm/xorm" +// "github.com/grafana/grafana/pkg/bus" +// m "github.com/grafana/grafana/pkg/models" +// ) +// +// func init() { +// bus.AddHandler("sql", SetNewAlertState) +// bus.AddHandler("sql", GetAlertStateLogByAlertId) +// bus.AddHandler("sql", GetLastAlertStateQuery) +// } +// +// func GetLastAlertStateQuery(cmd *m.GetLastAlertStateQuery) error { +// states := make([]m.AlertState, 0) +// +// if err := x.Where("alert_id = ? and org_id = ? ", cmd.AlertId, cmd.OrgId).Desc("created").Find(&states); err != nil { +// return err +// } +// +// if len(states) == 0 { +// cmd.Result = nil +// return nil +// } +// +// cmd.Result = &states[0] +// return nil +// } +// +// func SetNewAlertState(cmd *m.UpdateAlertStateCommand) error { +// return inTransaction(func(sess *xorm.Session) error { +// if !cmd.IsValidState() { +// return fmt.Errorf("new state is invalid") +// } +// +// alert := m.Alert{} +// has, err := sess.Id(cmd.AlertId).Get(&alert) +// if err != nil { +// return err +// } +// +// if !has { +// return fmt.Errorf("Could not find alert") +// } +// +// alert.State = cmd.State +// sess.Id(alert.Id).Update(&alert) +// +// alertState := m.AlertState{ +// AlertId: cmd.AlertId, +// OrgId: cmd.OrgId, +// State: cmd.State, +// Info: cmd.Info, +// Created: time.Now(), +// } +// +// sess.Insert(&alertState) +// +// cmd.Result = &alert +// return nil +// }) +// } +// +// func GetAlertStateLogByAlertId(cmd *m.GetAlertsStateQuery) error { +// states := make([]m.AlertState, 0) +// +// if err := x.Where("alert_id = ?", cmd.AlertId).Desc("created").Find(&states); err != nil { +// return err +// } +// +// cmd.Result = &states +// return nil +// } diff --git a/pkg/services/sqlstore/alert_state_test.go b/pkg/services/sqlstore/alert_state_test.go new file mode 100644 index 00000000000..1db1fca2b78 --- /dev/null +++ b/pkg/services/sqlstore/alert_state_test.go @@ -0,0 +1,100 @@ +package sqlstore + +// import ( +// "testing" +// +// m "github.com/grafana/grafana/pkg/models" +// . "github.com/smartystreets/goconvey/convey" +// ) +// +// func TestAlertingStateAccess(t *testing.T) { +// Convey("Test alerting state changes", t, func() { +// InitTestDB(t) +// +// testDash := insertTestDashboard("dashboard with alerts", 1, "alert") +// +// items := []*m.Alert{ +// { +// PanelId: 1, +// DashboardId: testDash.Id, +// OrgId: testDash.OrgId, +// Name: "Alerting title", +// Description: "Alerting description", +// }, +// } +// +// cmd := m.SaveAlertsCommand{ +// Alerts: items, +// DashboardId: testDash.Id, +// OrgId: 1, +// UserId: 1, +// } +// +// err := SaveAlerts(&cmd) +// So(err, ShouldBeNil) +// +// Convey("Cannot insert invalid states", func() { +// err = SetNewAlertState(&m.UpdateAlertStateCommand{ +// AlertId: 1, +// NewState: "maybe ok", +// Info: "Shit just hit the fan", +// }) +// +// So(err, ShouldNotBeNil) +// }) +// +// Convey("Changes state to alert", func() { +// +// err = SetNewAlertState(&m.UpdateAlertStateCommand{ +// AlertId: 1, +// NewState: "CRITICAL", +// Info: "Shit just hit the fan", +// }) +// +// Convey("can get new state for alert", func() { +// query := &m.GetAlertByIdQuery{Id: 1} +// err := GetAlertById(query) +// So(err, ShouldBeNil) +// So(query.Result.State, ShouldEqual, "CRITICAL") +// }) +// +// Convey("Changes state to ok", func() { +// err = SetNewAlertState(&m.UpdateAlertStateCommand{ +// AlertId: 1, +// NewState: "OK", +// Info: "Shit just hit the fan", +// }) +// +// Convey("get ok state for alert", func() { +// query := &m.GetAlertByIdQuery{Id: 1} +// err := GetAlertById(query) +// So(err, ShouldBeNil) +// So(query.Result.State, ShouldEqual, "OK") +// }) +// +// Convey("should have two event state logs", func() { +// query := &m.GetAlertsStateQuery{ +// AlertId: 1, +// OrgId: 1, +// } +// +// err := GetAlertStateLogByAlertId(query) +// So(err, ShouldBeNil) +// +// So(len(*query.Result), ShouldEqual, 2) +// }) +// +// Convey("should not get any alerts with critical state", func() { +// query := &m.GetAlertsQuery{ +// OrgId: 1, +// State: []string{"Critical", "Warn"}, +// } +// +// err := HandleAlertsQuery(query) +// So(err, ShouldBeNil) +// So(len(query.Result), ShouldEqual, 0) +// }) +// }) +// }) +// }) +// } diff --git a/pkg/services/sqlstore/alert_test.go b/pkg/services/sqlstore/alert_test.go new file mode 100644 index 00000000000..e22b1c48c47 --- /dev/null +++ b/pkg/services/sqlstore/alert_test.go @@ -0,0 +1,179 @@ +package sqlstore + +import ( + "testing" + + "github.com/grafana/grafana/pkg/components/simplejson" + m "github.com/grafana/grafana/pkg/models" + . "github.com/smartystreets/goconvey/convey" +) + +func TestAlertingDataAccess(t *testing.T) { + Convey("Testing Alerting data access", t, func() { + InitTestDB(t) + + testDash := insertTestDashboard("dashboard with alerts", 1, "alert") + + items := []*m.Alert{ + { + PanelId: 1, + DashboardId: testDash.Id, + OrgId: testDash.OrgId, + Name: "Alerting title", + Message: "Alerting message", + Settings: simplejson.New(), + Frequency: 1, + }, + } + + cmd := m.SaveAlertsCommand{ + Alerts: items, + DashboardId: testDash.Id, + OrgId: 1, + UserId: 1, + } + + err := SaveAlerts(&cmd) + + Convey("Can create one alert", func() { + So(err, ShouldBeNil) + }) + + Convey("Can read properties", func() { + alertQuery := m.GetAlertsQuery{DashboardId: testDash.Id, PanelId: 1, OrgId: 1} + err2 := HandleAlertsQuery(&alertQuery) + + alert := alertQuery.Result[0] + So(err2, ShouldBeNil) + So(alert.Name, ShouldEqual, "Alerting title") + So(alert.Message, ShouldEqual, "Alerting message") + So(alert.State, ShouldEqual, "pending") + So(alert.Frequency, ShouldEqual, 1) + }) + + Convey("Alerts with same dashboard id and panel id should update", func() { + modifiedItems := items + modifiedItems[0].Name = "Name" + + modifiedCmd := m.SaveAlertsCommand{ + DashboardId: testDash.Id, + OrgId: 1, + UserId: 1, + Alerts: modifiedItems, + } + + err := SaveAlerts(&modifiedCmd) + + Convey("Can save alerts with same dashboard and panel id", func() { + So(err, ShouldBeNil) + }) + + Convey("Alerts should be updated", func() { + query := m.GetAlertsQuery{DashboardId: testDash.Id, OrgId: 1} + err2 := HandleAlertsQuery(&query) + + So(err2, ShouldBeNil) + So(len(query.Result), ShouldEqual, 1) + So(query.Result[0].Name, ShouldEqual, "Name") + + Convey("Alert state should not be updated", func() { + So(query.Result[0].State, ShouldEqual, "pending") + }) + }) + + Convey("Updates without changes should be ignored", func() { + err3 := SaveAlerts(&modifiedCmd) + So(err3, ShouldBeNil) + }) + }) + + Convey("Multiple alerts per dashboard", func() { + multipleItems := []*m.Alert{ + { + DashboardId: testDash.Id, + PanelId: 1, + Name: "1", + OrgId: 1, + Settings: simplejson.New(), + }, + { + DashboardId: testDash.Id, + PanelId: 2, + Name: "2", + OrgId: 1, + Settings: simplejson.New(), + }, + { + DashboardId: testDash.Id, + PanelId: 3, + Name: "3", + OrgId: 1, + Settings: simplejson.New(), + }, + } + + cmd.Alerts = multipleItems + err = SaveAlerts(&cmd) + + Convey("Should save 3 dashboards", func() { + So(err, ShouldBeNil) + + queryForDashboard := m.GetAlertsQuery{DashboardId: testDash.Id, OrgId: 1} + err2 := HandleAlertsQuery(&queryForDashboard) + + So(err2, ShouldBeNil) + So(len(queryForDashboard.Result), ShouldEqual, 3) + }) + + Convey("should updated two dashboards and delete one", func() { + missingOneAlert := multipleItems[:2] + + cmd.Alerts = missingOneAlert + err = SaveAlerts(&cmd) + + Convey("should delete the missing alert", func() { + query := m.GetAlertsQuery{DashboardId: testDash.Id, OrgId: 1} + err2 := HandleAlertsQuery(&query) + So(err2, ShouldBeNil) + So(len(query.Result), ShouldEqual, 2) + }) + }) + }) + + Convey("When dashboard is removed", func() { + items := []*m.Alert{ + { + PanelId: 1, + DashboardId: testDash.Id, + Name: "Alerting title", + Message: "Alerting message", + }, + } + + cmd := m.SaveAlertsCommand{ + Alerts: items, + DashboardId: testDash.Id, + OrgId: 1, + UserId: 1, + } + + SaveAlerts(&cmd) + + err = DeleteDashboard(&m.DeleteDashboardCommand{ + OrgId: 1, + Slug: testDash.Slug, + }) + + So(err, ShouldBeNil) + + Convey("Alerts should be removed", func() { + query := m.GetAlertsQuery{DashboardId: testDash.Id, OrgId: 1} + err2 := HandleAlertsQuery(&query) + + So(testDash.Id, ShouldEqual, 1) + So(err2, ShouldBeNil) + So(len(query.Result), ShouldEqual, 0) + }) + }) + }) +} diff --git a/pkg/services/sqlstore/annotation.go b/pkg/services/sqlstore/annotation.go new file mode 100644 index 00000000000..0530952144e --- /dev/null +++ b/pkg/services/sqlstore/annotation.go @@ -0,0 +1,21 @@ +package sqlstore + +import ( + "github.com/go-xorm/xorm" + "github.com/grafana/grafana/pkg/services/annotations" +) + +type SqlAnnotationRepo struct { +} + +func (r *SqlAnnotationRepo) Save(item *annotations.Item) error { + return inTransaction(func(sess *xorm.Session) error { + + if _, err := sess.Table("annotation").Insert(item); err != nil { + return err + } + + return nil + }) + +} diff --git a/pkg/services/sqlstore/dashboard.go b/pkg/services/sqlstore/dashboard.go index 7a0971fcdfd..e9f98a04471 100644 --- a/pkg/services/sqlstore/dashboard.go +++ b/pkg/services/sqlstore/dashboard.go @@ -242,6 +242,10 @@ func DeleteDashboard(cmd *m.DeleteDashboardCommand) error { } } + if err := DeleteAlertDefinition(dashboard.Id, sess.Session); err != nil { + return nil + } + return nil }) } diff --git a/pkg/services/sqlstore/dashboard_test.go b/pkg/services/sqlstore/dashboard_test.go index 609639f7788..a055500592b 100644 --- a/pkg/services/sqlstore/dashboard_test.go +++ b/pkg/services/sqlstore/dashboard_test.go @@ -5,6 +5,7 @@ import ( . "github.com/smartystreets/goconvey/convey" + "github.com/gosimple/slug" "github.com/grafana/grafana/pkg/components/simplejson" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/search" @@ -55,6 +56,19 @@ func TestDashboardDataAccess(t *testing.T) { So(query.Result.Slug, ShouldEqual, "test-dash-23") }) + Convey("Should be able to delete dashboard", func() { + insertTestDashboard("delete me", 1, "delete this") + + dashboardSlug := slug.Make("delete me") + + err := DeleteDashboard(&m.DeleteDashboardCommand{ + Slug: dashboardSlug, + OrgId: 1, + }) + + So(err, ShouldBeNil) + }) + Convey("Should return error if no dashboard is updated", func() { cmd := m.SaveDashboardCommand{ OrgId: 1, diff --git a/pkg/services/sqlstore/datasource.go b/pkg/services/sqlstore/datasource.go index 55a95413640..c028fd0fccc 100644 --- a/pkg/services/sqlstore/datasource.go +++ b/pkg/services/sqlstore/datasource.go @@ -19,22 +19,26 @@ func init() { } func GetDataSourceById(query *m.GetDataSourceByIdQuery) error { - sess := x.Limit(100, 0).Where("org_id=? AND id=?", query.OrgId, query.Id) - has, err := sess.Get(&query.Result) + datasource := m.DataSource{OrgId: query.OrgId, Id: query.Id} + has, err := x.Get(&datasource) if !has { return m.ErrDataSourceNotFound } + + query.Result = &datasource return err } func GetDataSourceByName(query *m.GetDataSourceByNameQuery) error { - sess := x.Limit(100, 0).Where("org_id=? AND name=?", query.OrgId, query.Name) - has, err := sess.Get(&query.Result) + datasource := m.DataSource{OrgId: query.OrgId, Name: query.Name} + has, err := x.Get(&datasource) if !has { return m.ErrDataSourceNotFound } + + query.Result = &datasource return err } diff --git a/pkg/services/sqlstore/migrations/alert_mig.go b/pkg/services/sqlstore/migrations/alert_mig.go new file mode 100644 index 00000000000..63d61d8b196 --- /dev/null +++ b/pkg/services/sqlstore/migrations/alert_mig.go @@ -0,0 +1,66 @@ +package migrations + +import ( + . "github.com/grafana/grafana/pkg/services/sqlstore/migrator" +) + +func addAlertMigrations(mg *Migrator) { + + alertV1 := Table{ + Name: "alert", + Columns: []*Column{ + {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, + {Name: "version", Type: DB_BigInt, Nullable: false}, + {Name: "dashboard_id", Type: DB_BigInt, Nullable: false}, + {Name: "panel_id", Type: DB_BigInt, Nullable: false}, + {Name: "org_id", Type: DB_BigInt, Nullable: false}, + {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "message", Type: DB_Text, Nullable: false}, + {Name: "state", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "settings", Type: DB_Text, Nullable: false}, + {Name: "frequency", Type: DB_BigInt, Nullable: false}, + {Name: "handler", Type: DB_BigInt, Nullable: false}, + {Name: "severity", Type: DB_Text, Nullable: false}, + {Name: "silenced", Type: DB_Bool, Nullable: false}, + {Name: "execution_error", Type: DB_Text, Nullable: false}, + {Name: "eval_data", Type: DB_Text, Nullable: true}, + {Name: "eval_date", Type: DB_DateTime, Nullable: true}, + {Name: "new_state_date", Type: DB_DateTime, Nullable: false}, + {Name: "state_changes", Type: DB_Int, Nullable: false}, + {Name: "created", Type: DB_DateTime, Nullable: false}, + {Name: "updated", Type: DB_DateTime, Nullable: false}, + }, + Indices: []*Index{ + {Cols: []string{"org_id", "id"}, Type: IndexType}, + {Cols: []string{"state"}, Type: IndexType}, + {Cols: []string{"dashboard_id"}, Type: IndexType}, + }, + } + + // create table + mg.AddMigration("create alert table v1", NewAddTableMigration(alertV1)) + + // create indices + mg.AddMigration("add index alert org_id & id ", NewAddIndexMigration(alertV1, alertV1.Indices[0])) + mg.AddMigration("add index alert state", NewAddIndexMigration(alertV1, alertV1.Indices[1])) + mg.AddMigration("add index alert dashboard_id", NewAddIndexMigration(alertV1, alertV1.Indices[2])) + + alert_notification := Table{ + Name: "alert_notification", + Columns: []*Column{ + {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, + {Name: "org_id", Type: DB_BigInt, Nullable: false}, + {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "type", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "settings", Type: DB_Text, Nullable: false}, + {Name: "created", Type: DB_DateTime, Nullable: false}, + {Name: "updated", Type: DB_DateTime, Nullable: false}, + }, + Indices: []*Index{ + {Cols: []string{"org_id", "name"}, Type: UniqueIndex}, + }, + } + + mg.AddMigration("create alert_notification table v1", NewAddTableMigration(alert_notification)) + mg.AddMigration("add index alert_notification org_id & name", NewAddIndexMigration(alert_notification, alert_notification.Indices[0])) +} diff --git a/pkg/services/sqlstore/migrations/annotation_mig.go b/pkg/services/sqlstore/migrations/annotation_mig.go new file mode 100644 index 00000000000..11b4eeed629 --- /dev/null +++ b/pkg/services/sqlstore/migrations/annotation_mig.go @@ -0,0 +1,38 @@ +package migrations + +import ( + . "github.com/grafana/grafana/pkg/services/sqlstore/migrator" +) + +func addAnnotationMig(mg *Migrator) { + table := Table{ + Name: "annotation", + Columns: []*Column{ + {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, + {Name: "org_id", Type: DB_BigInt, Nullable: false}, + {Name: "alert_id", Type: DB_BigInt, Nullable: true}, + {Name: "user_id", Type: DB_BigInt, Nullable: true}, + {Name: "type", Type: DB_NVarchar, Length: 25, Nullable: false}, + {Name: "title", Type: DB_Text, Nullable: false}, + {Name: "text", Type: DB_Text, Nullable: false}, + {Name: "metric", Type: DB_NVarchar, Length: 255, Nullable: true}, + {Name: "prev_state", Type: DB_NVarchar, Length: 25, Nullable: false}, + {Name: "new_state", Type: DB_NVarchar, Length: 25, Nullable: false}, + {Name: "data", Type: DB_Text, Nullable: false}, + {Name: "timestamp", Type: DB_DateTime, Nullable: false}, + }, + Indices: []*Index{ + {Cols: []string{"org_id", "alert_id"}, Type: IndexType}, + {Cols: []string{"org_id", "type"}, Type: IndexType}, + {Cols: []string{"timestamp"}, Type: IndexType}, + }, + } + + mg.AddMigration("create annotation table v1", NewAddTableMigration(table)) + + // create indices + mg.AddMigration("add index annotation org_id & alert_id ", NewAddIndexMigration(table, table.Indices[0])) + + mg.AddMigration("add index annotation org_id & type", NewAddIndexMigration(table, table.Indices[1])) + mg.AddMigration("add index annotation timestamp", NewAddIndexMigration(table, table.Indices[2])) +} diff --git a/pkg/services/sqlstore/migrations/heartbeat_mig.go b/pkg/services/sqlstore/migrations/heartbeat_mig.go new file mode 100644 index 00000000000..e0ee7a5f88f --- /dev/null +++ b/pkg/services/sqlstore/migrations/heartbeat_mig.go @@ -0,0 +1,18 @@ +package migrations + +// // create table +// mg.AddMigration("create alert table v1", NewAddTableMigration(alertV1)) +// +// alert_heartbeat := Table{ +// Name: "alert_heartbeat", +// Columns: []*Column{ +// {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, +// {Name: "server_id", Type: DB_NVarchar, Length: 50, Nullable: false}, +// {Name: "created", Type: DB_DateTime, Nullable: false}, +// {Name: "updated", Type: DB_DateTime, Nullable: false}, +// }, +// } +// +// mg.AddMigration("create alert_heartbeat table v1", NewAddTableMigration(alert_heartbeat)) +// +// diff --git a/pkg/services/sqlstore/migrations/migrations.go b/pkg/services/sqlstore/migrations/migrations.go index 7a6ba554246..f0f69ee0e23 100644 --- a/pkg/services/sqlstore/migrations/migrations.go +++ b/pkg/services/sqlstore/migrations/migrations.go @@ -22,6 +22,8 @@ func AddMigrations(mg *Migrator) { addSessionMigration(mg) addPlaylistMigrations(mg) addPreferencesMigrations(mg) + addAlertMigrations(mg) + addAnnotationMig(mg) } func addMigrationLogMigrations(mg *Migrator) { diff --git a/pkg/services/sqlstore/migrations/migrations_test.go b/pkg/services/sqlstore/migrations/migrations_test.go index 97b68877ae8..5bddf6ff605 100644 --- a/pkg/services/sqlstore/migrations/migrations_test.go +++ b/pkg/services/sqlstore/migrations/migrations_test.go @@ -8,6 +8,7 @@ import ( "github.com/grafana/grafana/pkg/services/sqlstore/sqlutil" . "github.com/smartystreets/goconvey/convey" + //"github.com/grafana/grafana/pkg/log" ) var indexTypes = []string{"Unknown", "INDEX", "UNIQUE INDEX"} diff --git a/pkg/services/sqlstore/sqlstore.go b/pkg/services/sqlstore/sqlstore.go index 031d8344a34..032554daebe 100644 --- a/pkg/services/sqlstore/sqlstore.go +++ b/pkg/services/sqlstore/sqlstore.go @@ -11,6 +11,7 @@ import ( "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/log" m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/sqlstore/migrations" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" "github.com/grafana/grafana/pkg/setting" @@ -98,6 +99,8 @@ func SetEngine(engine *xorm.Engine) (err error) { return fmt.Errorf("Sqlstore::Migration failed err: %v\n", err) } + annotations.SetRepository(&SqlAnnotationRepo{}) + return nil } diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index c5f994cc692..830291b7ffa 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -140,11 +140,21 @@ var ( // QUOTA Quota QuotaSettings + // Alerting + AlertingEnabled bool + // logger logger log.Logger // Grafana.NET URL GrafanaNetUrl string + + // S3 temp image store + S3TempImageStoreBucketUrl string + S3TempImageStoreAccessKey string + S3TempImageStoreSecretKey string + + ImageUploadProvider string ) type CommandLineArgs struct { @@ -534,6 +544,9 @@ func NewConfigContext(args *CommandLineArgs) error { LdapEnabled = ldapSec.Key("enabled").MustBool(false) LdapConfigFile = ldapSec.Key("config_file").String() + alerting := Cfg.Section("alerting") + AlertingEnabled = alerting.Key("enabled").MustBool(false) + readSessionConfig() readSmtpSettings() readQuotaSettings() @@ -544,6 +557,8 @@ func NewConfigContext(args *CommandLineArgs) error { GrafanaNetUrl = Cfg.Section("grafana.net").Key("url").MustString("https://grafana.net") + imageUploadingSection := Cfg.Section("external_image_storage") + ImageUploadProvider = imageUploadingSection.Key("provider").MustString("internal") return nil } diff --git a/pkg/tsdb/batch.go b/pkg/tsdb/batch.go new file mode 100644 index 00000000000..bc16ed1e75a --- /dev/null +++ b/pkg/tsdb/batch.go @@ -0,0 +1,90 @@ +package tsdb + +import "errors" + +type Batch struct { + DataSourceId int64 + Queries QuerySlice + Depends map[string]bool + Done bool + Started bool +} + +type BatchSlice []*Batch + +func newBatch(dsId int64, queries QuerySlice) *Batch { + return &Batch{ + DataSourceId: dsId, + Queries: queries, + Depends: make(map[string]bool), + } +} + +func (bg *Batch) process(context *QueryContext) { + executor := getExecutorFor(bg.Queries[0].DataSource) + + if executor == nil { + bg.Done = true + result := &BatchResult{ + Error: errors.New("Could not find executor for data source type " + bg.Queries[0].DataSource.PluginId), + QueryResults: make(map[string]*QueryResult), + } + for _, query := range bg.Queries { + result.QueryResults[query.RefId] = &QueryResult{Error: result.Error} + } + context.ResultsChan <- result + return + } + + res := executor.Execute(bg.Queries, context) + bg.Done = true + context.ResultsChan <- res +} + +func (bg *Batch) addQuery(query *Query) { + bg.Queries = append(bg.Queries, query) +} + +func (bg *Batch) allDependenciesAreIn(context *QueryContext) bool { + for key := range bg.Depends { + if _, exists := context.Results[key]; !exists { + return false + } + } + + return true +} + +func getBatches(req *Request) (BatchSlice, error) { + batches := make(BatchSlice, 0) + + for _, query := range req.Queries { + if foundBatch := findMatchingBatchGroup(query, batches); foundBatch != nil { + foundBatch.addQuery(query) + } else { + newBatch := newBatch(query.DataSource.Id, QuerySlice{query}) + batches = append(batches, newBatch) + + for _, refId := range query.Depends { + for _, batch := range batches { + for _, batchQuery := range batch.Queries { + if batchQuery.RefId == refId { + newBatch.Depends[refId] = true + } + } + } + } + } + } + + return batches, nil +} + +func findMatchingBatchGroup(query *Query, batches BatchSlice) *Batch { + for _, batch := range batches { + if batch.DataSourceId == query.DataSource.Id { + return batch + } + } + return nil +} diff --git a/pkg/tsdb/executor.go b/pkg/tsdb/executor.go new file mode 100644 index 00000000000..b39c2cdaa97 --- /dev/null +++ b/pkg/tsdb/executor.go @@ -0,0 +1,24 @@ +package tsdb + +type Executor interface { + Execute(queries QuerySlice, context *QueryContext) *BatchResult +} + +var registry map[string]GetExecutorFn + +type GetExecutorFn func(dsInfo *DataSourceInfo) Executor + +func init() { + registry = make(map[string]GetExecutorFn) +} + +func getExecutorFor(dsInfo *DataSourceInfo) Executor { + if fn, exists := registry[dsInfo.PluginId]; exists { + return fn(dsInfo) + } + return nil +} + +func RegisterExecutor(pluginId string, fn GetExecutorFn) { + registry[pluginId] = fn +} diff --git a/pkg/tsdb/fake_test.go b/pkg/tsdb/fake_test.go new file mode 100644 index 00000000000..2ba02792d6d --- /dev/null +++ b/pkg/tsdb/fake_test.go @@ -0,0 +1,39 @@ +package tsdb + +type FakeExecutor struct { + results map[string]*QueryResult + resultsFn map[string]ResultsFn +} + +type ResultsFn func(context *QueryContext) *QueryResult + +func NewFakeExecutor(dsInfo *DataSourceInfo) *FakeExecutor { + return &FakeExecutor{ + results: make(map[string]*QueryResult), + resultsFn: make(map[string]ResultsFn), + } +} + +func (e *FakeExecutor) Execute(queries QuerySlice, context *QueryContext) *BatchResult { + result := &BatchResult{QueryResults: make(map[string]*QueryResult)} + for _, query := range queries { + if results, has := e.results[query.RefId]; has { + result.QueryResults[query.RefId] = results + } + if testFunc, has := e.resultsFn[query.RefId]; has { + result.QueryResults[query.RefId] = testFunc(context) + } + } + + return result +} + +func (e *FakeExecutor) Return(refId string, series TimeSeriesSlice) { + e.results[refId] = &QueryResult{ + RefId: refId, Series: series, + } +} + +func (e *FakeExecutor) HandleQuery(refId string, fn ResultsFn) { + e.resultsFn[refId] = fn +} diff --git a/pkg/tsdb/graphite/graphite.go b/pkg/tsdb/graphite/graphite.go new file mode 100644 index 00000000000..2a68b23df71 --- /dev/null +++ b/pkg/tsdb/graphite/graphite.go @@ -0,0 +1,85 @@ +package graphite + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "net/url" + "strings" + "time" + + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/tsdb" +) + +type GraphiteExecutor struct { + *tsdb.DataSourceInfo +} + +func NewGraphiteExecutor(dsInfo *tsdb.DataSourceInfo) tsdb.Executor { + return &GraphiteExecutor{dsInfo} +} + +var glog log.Logger + +func init() { + glog = log.New("tsdb.graphite") + tsdb.RegisterExecutor("graphite", NewGraphiteExecutor) +} + +func (e *GraphiteExecutor) Execute(queries tsdb.QuerySlice, context *tsdb.QueryContext) *tsdb.BatchResult { + result := &tsdb.BatchResult{} + + params := url.Values{ + "from": []string{"-" + formatTimeRange(context.TimeRange.From)}, + "until": []string{formatTimeRange(context.TimeRange.To)}, + "format": []string{"json"}, + "maxDataPoints": []string{"500"}, + } + + for _, query := range queries { + params["target"] = []string{query.Query} + glog.Debug("Graphite request", "query", query.Query) + } + + client := http.Client{Timeout: time.Duration(10 * time.Second)} + res, err := client.PostForm(e.Url+"/render?", params) + if err != nil { + result.Error = err + return result + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + result.Error = err + return result + } + + var data []TargetResponseDTO + err = json.Unmarshal(body, &data) + if err != nil { + glog.Info("Failed to unmarshal graphite response", "error", err, "body", string(body)) + result.Error = err + return result + } + + result.QueryResults = make(map[string]*tsdb.QueryResult) + queryRes := &tsdb.QueryResult{} + for _, series := range data { + queryRes.Series = append(queryRes.Series, &tsdb.TimeSeries{ + Name: series.Target, + Points: series.DataPoints, + }) + } + + result.QueryResults["A"] = queryRes + return result +} + +func formatTimeRange(input string) string { + if input == "now" { + return input + } + return strings.Replace(strings.Replace(input, "m", "min", -1), "M", "mon", -1) +} diff --git a/pkg/tsdb/graphite/graphite_test.go b/pkg/tsdb/graphite/graphite_test.go new file mode 100644 index 00000000000..59007b43ed5 --- /dev/null +++ b/pkg/tsdb/graphite/graphite_test.go @@ -0,0 +1,23 @@ +package graphite + +// func TestGraphite(t *testing.T) { +// +// Convey("When executing graphite query", t, func() { +// executor := NewGraphiteExecutor(&tsdb.DataSourceInfo{ +// Url: "http://localhost:8080", +// }) +// +// queries := tsdb.QuerySlice{ +// &tsdb.Query{Query: "{\"target\": \"apps.backend.*.counters.requests.count\"}"}, +// } +// +// context := tsdb.NewQueryContext(queries, tsdb.TimeRange{}) +// result := executor.Execute(queries, context) +// So(result.Error, ShouldBeNil) +// +// Convey("Should return series", func() { +// So(result.QueryResults, ShouldNotBeEmpty) +// }) +// }) +// +// } diff --git a/pkg/tsdb/graphite/types.go b/pkg/tsdb/graphite/types.go new file mode 100644 index 00000000000..4cd1b601bbc --- /dev/null +++ b/pkg/tsdb/graphite/types.go @@ -0,0 +1,6 @@ +package graphite + +type TargetResponseDTO struct { + Target string `json:"target"` + DataPoints [][2]float64 `json:"datapoints"` +} diff --git a/pkg/tsdb/models.go b/pkg/tsdb/models.go new file mode 100644 index 00000000000..2954c630b68 --- /dev/null +++ b/pkg/tsdb/models.go @@ -0,0 +1,60 @@ +package tsdb + +type TimeRange struct { + From string + To string +} + +type Request struct { + TimeRange TimeRange + MaxDataPoints int + Queries QuerySlice +} + +type Response struct { + BatchTimings []*BatchTiming + Results map[string]*QueryResult +} + +type DataSourceInfo struct { + Id int64 + Name string + PluginId string + Url string + Password string + User string + Database string + BasicAuth bool + BasicAuthUser string + BasicAuthPassword string +} + +type BatchTiming struct { + TimeElapsed int64 +} + +type BatchResult struct { + Error error + QueryResults map[string]*QueryResult + Timings *BatchTiming +} + +type QueryResult struct { + Error error + RefId string + Series TimeSeriesSlice +} + +type TimeSeries struct { + Name string `json:"name"` + Points [][2]float64 `json:"points"` +} + +type TimeSeriesSlice []*TimeSeries + +func NewTimeSeries(name string, points [][2]float64) *TimeSeries { + return &TimeSeries{ + Name: name, + Points: points, + } +} diff --git a/pkg/tsdb/query.go b/pkg/tsdb/query.go new file mode 100644 index 00000000000..bcead660450 --- /dev/null +++ b/pkg/tsdb/query.go @@ -0,0 +1,12 @@ +package tsdb + +type Query struct { + RefId string + Query string + Depends []string + DataSource *DataSourceInfo + Results []*TimeSeries + Exclude bool +} + +type QuerySlice []*Query diff --git a/pkg/tsdb/query_context.go b/pkg/tsdb/query_context.go new file mode 100644 index 00000000000..a1fc4c9bcb5 --- /dev/null +++ b/pkg/tsdb/query_context.go @@ -0,0 +1,21 @@ +package tsdb + +import "sync" + +type QueryContext struct { + TimeRange TimeRange + Queries QuerySlice + Results map[string]*QueryResult + ResultsChan chan *BatchResult + Lock sync.RWMutex + BatchWaits sync.WaitGroup +} + +func NewQueryContext(queries QuerySlice, timeRange TimeRange) *QueryContext { + return &QueryContext{ + TimeRange: timeRange, + Queries: queries, + ResultsChan: make(chan *BatchResult), + Results: make(map[string]*QueryResult), + } +} diff --git a/pkg/tsdb/request.go b/pkg/tsdb/request.go new file mode 100644 index 00000000000..2e5e5eec25a --- /dev/null +++ b/pkg/tsdb/request.go @@ -0,0 +1,57 @@ +package tsdb + +type HandleRequestFunc func(req *Request) (*Response, error) + +func HandleRequest(req *Request) (*Response, error) { + context := NewQueryContext(req.Queries, req.TimeRange) + + batches, err := getBatches(req) + if err != nil { + return nil, err + } + + currentlyExecuting := 0 + + for _, batch := range batches { + if len(batch.Depends) == 0 { + currentlyExecuting += 1 + batch.Started = true + go batch.process(context) + } + } + + response := &Response{} + + for currentlyExecuting != 0 { + select { + case batchResult := <-context.ResultsChan: + currentlyExecuting -= 1 + + response.BatchTimings = append(response.BatchTimings, batchResult.Timings) + + if batchResult.Error != nil { + return nil, batchResult.Error + } + + for refId, result := range batchResult.QueryResults { + context.Results[refId] = result + } + + for _, batch := range batches { + // not interested in started batches + if batch.Started { + continue + } + + if batch.allDependenciesAreIn(context) { + currentlyExecuting += 1 + batch.Started = true + go batch.process(context) + } + } + } + } + + response.Results = context.Results + return response, nil +} diff --git a/pkg/tsdb/tsdb_test.go b/pkg/tsdb/tsdb_test.go new file mode 100644 index 00000000000..24d84a27c74 --- /dev/null +++ b/pkg/tsdb/tsdb_test.go @@ -0,0 +1,175 @@ +package tsdb + +import ( + "testing" + "time" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestMetricQuery(t *testing.T) { + + Convey("When batches groups for query", t, func() { + + Convey("Given 3 queries for 2 data sources", func() { + request := &Request{ + Queries: QuerySlice{ + {RefId: "A", Query: "asd", DataSource: &DataSourceInfo{Id: 1}}, + {RefId: "B", Query: "asd", DataSource: &DataSourceInfo{Id: 1}}, + {RefId: "C", Query: "asd", DataSource: &DataSourceInfo{Id: 2}}, + }, + } + + batches, err := getBatches(request) + So(err, ShouldBeNil) + + Convey("Should group into two batches", func() { + So(len(batches), ShouldEqual, 2) + }) + }) + + Convey("Given query 2 depends on query 1", func() { + request := &Request{ + Queries: QuerySlice{ + {RefId: "A", Query: "asd", DataSource: &DataSourceInfo{Id: 1}}, + {RefId: "B", Query: "asd", DataSource: &DataSourceInfo{Id: 2}}, + {RefId: "C", Query: "#A / #B", DataSource: &DataSourceInfo{Id: 3}, Depends: []string{"A", "B"}}, + }, + } + + batches, err := getBatches(request) + So(err, ShouldBeNil) + + Convey("Should return three batch groups", func() { + So(len(batches), ShouldEqual, 3) + }) + + Convey("Group 3 should have group 1 and 2 as dependencies", func() { + So(batches[2].Depends["A"], ShouldEqual, true) + So(batches[2].Depends["B"], ShouldEqual, true) + }) + + }) + }) + + Convey("When executing request with one query", t, func() { + req := &Request{ + Queries: QuerySlice{ + {RefId: "A", Query: "asd", DataSource: &DataSourceInfo{Id: 1, PluginId: "test"}}, + }, + } + + fakeExecutor := registerFakeExecutor() + fakeExecutor.Return("A", TimeSeriesSlice{&TimeSeries{Name: "argh"}}) + + res, err := HandleRequest(req) + So(err, ShouldBeNil) + + Convey("Should return query results", func() { + So(res.Results["A"].Series, ShouldNotBeEmpty) + So(res.Results["A"].Series[0].Name, ShouldEqual, "argh") + }) + }) + + Convey("When executing one request with two queries from same data source", t, func() { + req := &Request{ + Queries: QuerySlice{ + {RefId: "A", Query: "asd", DataSource: &DataSourceInfo{Id: 1, PluginId: "test"}}, + {RefId: "B", Query: "asd", DataSource: &DataSourceInfo{Id: 1, PluginId: "test"}}, + }, + } + + fakeExecutor := registerFakeExecutor() + fakeExecutor.Return("A", TimeSeriesSlice{&TimeSeries{Name: "argh"}}) + fakeExecutor.Return("B", TimeSeriesSlice{&TimeSeries{Name: "barg"}}) + + res, err := HandleRequest(req) + So(err, ShouldBeNil) + + Convey("Should return query results", func() { + So(len(res.Results), ShouldEqual, 2) + So(res.Results["B"].Series[0].Name, ShouldEqual, "barg") + }) + + Convey("Should have been batched in one request", func() { + So(len(res.BatchTimings), ShouldEqual, 1) + }) + + }) + + Convey("When executing one request with three queries from different datasources", t, func() { + req := &Request{ + Queries: QuerySlice{ + {RefId: "A", Query: "asd", DataSource: &DataSourceInfo{Id: 1, PluginId: "test"}}, + {RefId: "B", Query: "asd", DataSource: &DataSourceInfo{Id: 1, PluginId: "test"}}, + {RefId: "C", Query: "asd", DataSource: &DataSourceInfo{Id: 2, PluginId: "test"}}, + }, + } + + res, err := HandleRequest(req) + So(err, ShouldBeNil) + + Convey("Should have been batched in two requests", func() { + So(len(res.BatchTimings), ShouldEqual, 2) + }) + }) + + Convey("When query uses data source of unknown type", t, func() { + req := &Request{ + Queries: QuerySlice{ + {RefId: "A", Query: "asd", DataSource: &DataSourceInfo{Id: 1, PluginId: "asdasdas"}}, + }, + } + + _, err := HandleRequest(req) + So(err, ShouldNotBeNil) + }) + + Convey("When executing request that depend on other query", t, func() { + req := &Request{ + Queries: QuerySlice{ + { + RefId: "A", Query: "asd", DataSource: &DataSourceInfo{Id: 1, PluginId: "test"}, + }, + { + RefId: "B", Query: "#A / 2", DataSource: &DataSourceInfo{Id: 2, PluginId: "test"}, Depends: []string{"A"}, + }, + }, + } + + fakeExecutor := registerFakeExecutor() + fakeExecutor.HandleQuery("A", func(c *QueryContext) *QueryResult { + time.Sleep(10 * time.Millisecond) + return &QueryResult{ + Series: TimeSeriesSlice{ + &TimeSeries{Name: "Ares"}, + }} + }) + fakeExecutor.HandleQuery("B", func(c *QueryContext) *QueryResult { + return &QueryResult{ + Series: TimeSeriesSlice{ + &TimeSeries{Name: "Bres+" + c.Results["A"].Series[0].Name}, + }} + }) + + res, err := HandleRequest(req) + So(err, ShouldBeNil) + + Convey("Should have been batched in two requests", func() { + So(len(res.BatchTimings), ShouldEqual, 2) + }) + + Convey("Query B should have access to Query A results", func() { + So(res.Results["B"].Series[0].Name, ShouldEqual, "Bres+Ares") + }) + }) +} + +func registerFakeExecutor() *FakeExecutor { + executor := NewFakeExecutor(nil) + RegisterExecutor("test", func(dsInfo *DataSourceInfo) Executor { + return executor + }) + + return executor +} diff --git a/public/app/core/components/jsontree/jsontree.ts b/public/app/core/components/jsontree/jsontree.ts new file mode 100644 index 00000000000..14f6012ce12 --- /dev/null +++ b/public/app/core/components/jsontree/jsontree.ts @@ -0,0 +1,200 @@ + +/** Created by: Alex Wendland (me@alexwendland.com), 2014-08-06 + * + * angular-json-tree + * + * Directive for creating a tree-view out of a JS Object. Only loads + * sub-nodes on demand in order to improve performance of rendering large + * objects. + * + * Attributes: + * - object (Object, 2-way): JS object to build the tree from + * - start-expanded (Boolean, 1-way, ?=true): should the tree default to expanded + * + * Usage: + * // In the controller + * scope.someObject = { + * test: 'hello', + * array: [1,1,2,3,5,8] + * }; + * // In the html + * + * + * Dependencies: + * - utils (json-tree.js) + * - ajsRecursiveDirectiveHelper (json-tree.js) + * + * Test: json-tree-test.js + */ + +import angular from 'angular'; +import coreModule from 'app/core/core_module'; + +var utils = { + /* See link for possible type values to check against. + * http://stackoverflow.com/questions/4622952/json-object-containing-array + * + * Value Class Type + * ------------------------------------- + * "foo" String string + * new String("foo") String object + * 1.2 Number number + * new Number(1.2) Number object + * true Boolean boolean + * new Boolean(true) Boolean object + * new Date() Date object + * new Error() Error object + * [1,2,3] Array object + * new Array(1, 2, 3) Array object + * new Function("") Function function + * /abc/g RegExp object (function in Nitro/V8) + * new RegExp("meow") RegExp object (function in Nitro/V8) + * {} Object object + * new Object() Object object + */ + is: function is(obj, clazz) { + return Object.prototype.toString.call(obj).slice(8, -1) === clazz; + }, + + // See above for possible values + whatClass: function whatClass(obj) { + return Object.prototype.toString.call(obj).slice(8, -1); + }, + + // Iterate over an objects keyset + forKeys: function forKeys(obj, f) { + for (var key in obj) { + if (obj.hasOwnProperty(key) && typeof obj[key] !== 'function') { + if (f(key, obj[key])) { + break; + } + } + } + } +}; + +coreModule.directive('jsonTree', [function jsonTreeDirective() { + return { + restrict: 'E', + scope: { + object: '=', + startExpanded: '@', + rootName: '@', + }, + template: '' + }; +}]); + +coreModule.directive('jsonNode', ['ajsRecursiveDirectiveHelper', function jsonNodeDirective(ajsRecursiveDirectiveHelper) { + return { + restrict: 'E', + scope: { + key: '=', + value: '=', + startExpanded: '@' + }, + compile: function jsonNodeDirectiveCompile(elem) { + return ajsRecursiveDirectiveHelper.compile(elem, this); + }, + template: ' {{key}}' + + ' {{value}}' + + ' ' + + ' {{preview}}' + + '
    ' + + '
  • ' + + ' ' + + '
  • ' + + '
', + pre: function jsonNodeDirectiveLink(scope, elem, attrs) { + // Set value's type as Class for CSS styling + elem.addClass(utils.whatClass(scope.value).toLowerCase()); + // If the value is an Array or Object, use expandable view type + if (utils.is(scope.value, 'Object') || utils.is(scope.value, 'Array')) { + scope.isExpandable = true; + // Add expandable class for CSS usage + elem.addClass('expandable'); + // Setup preview text + var isArray = utils.is(scope.value, 'Array'); + scope.preview = isArray ? '[ ' : '{ '; + utils.forKeys(scope.value, function jsonNodeDirectiveLinkForKeys(key, value) { + if (isArray) { + scope.preview += value + ', '; + } else { + scope.preview += key + ': ' + value + ', '; + } + }); + scope.preview = scope.preview.substring(0, scope.preview.length - (scope.preview.length > 2 ? 2 : 0)) + (isArray ? ' ]' : ' }'); + // If directive initially has isExpanded set, also set shouldRender to true + if (scope.startExpanded) { + scope.shouldRender = true; + elem.addClass('expanded'); + } + // Setup isExpanded state handling + scope.isExpanded = scope.startExpanded; + scope.toggleExpanded = function jsonNodeDirectiveToggleExpanded() { + scope.isExpanded = !scope.isExpanded; + if (scope.isExpanded) { + elem.addClass('expanded'); + } else { + elem.removeClass('expanded'); + } + // For delaying subnode render until requested + scope.shouldRender = true; + }; + } else { + scope.isExpandable = false; + // Add expandable class for CSS usage + elem.addClass('not-expandable'); + } + } + }; +}]); + +/** Added by: Alex Wendland (me@alexwendland.com), 2014-08-09 + * Source: http://stackoverflow.com/questions/14430655/recursion-in-angular-directives + * + * Used to allow for recursion within directives + */ +coreModule.factory('ajsRecursiveDirectiveHelper', ['$compile', function RecursiveDirectiveHelper($compile) { + return { + /** + * Manually compiles the element, fixing the recursion loop. + * @param element + * @param [link] A post-link function, or an object with function(s) registered via pre and post properties. + * @returns An object containing the linking functions. + */ + compile: function RecursiveDirectiveHelperCompile(element, link) { + // Normalize the link parameter + if (angular.isFunction(link)) { + link = { + post: link + }; + } + + // Break the recursion loop by removing the contents + var contents = element.contents().remove(); + var compiledContents; + return { + pre: (link && link.pre) ? link.pre : null, + /** + * Compiles and re-adds the contents + */ + post: function RecursiveDirectiveHelperCompilePost(scope, element) { + // Compile the contents + if (!compiledContents) { + compiledContents = $compile(contents); + } + // Re-add the compiled contents to the element + compiledContents(scope, function (clone) { + element.append(clone); + }); + + // Call the post-linking function, if any + if (link && link.post) { + link.post.apply(null, arguments); + } + } + }; + } + }; +}]); diff --git a/public/app/core/components/query_part/query_part_editor.ts b/public/app/core/components/query_part/query_part_editor.ts index f9122ee283b..7bc309d1bd2 100644 --- a/public/app/core/components/query_part/query_part_editor.ts +++ b/public/app/core/components/query_part/query_part_editor.ts @@ -5,33 +5,34 @@ import $ from 'jquery'; import coreModule from 'app/core/core_module'; var template = ` -
- -
- -{{part.def.type}} + - diff --git a/public/app/plugins/datasource/grafana-live/plugin.json b/public/app/plugins/datasource/grafana-live/plugin.json new file mode 100644 index 00000000000..1f2ec204949 --- /dev/null +++ b/public/app/plugins/datasource/grafana-live/plugin.json @@ -0,0 +1,7 @@ +{ + "type": "datasource", + "name": "Grafana Live", + "id": "grafana-live", + + "metrics": true +} diff --git a/public/app/plugins/datasource/influxdb/partials/query.editor.html b/public/app/plugins/datasource/influxdb/partials/query.editor.html index 68b8ee60d98..df5c326b962 100644 --- a/public/app/plugins/datasource/influxdb/partials/query.editor.html +++ b/public/app/plugins/datasource/influxdb/partials/query.editor.html @@ -35,12 +35,7 @@
- +
@@ -62,11 +57,9 @@ GROUP BY - + diff --git a/public/app/plugins/datasource/influxdb/query_ctrl.ts b/public/app/plugins/datasource/influxdb/query_ctrl.ts index 4cc07e9a64b..aad613b8d5f 100644 --- a/public/app/plugins/datasource/influxdb/query_ctrl.ts +++ b/public/app/plugins/datasource/influxdb/query_ctrl.ts @@ -20,7 +20,6 @@ export class InfluxQueryCtrl extends QueryCtrl { measurementSegment: any; removeTagFilterSegment: any; - /** @ngInject **/ constructor($scope, $injector, private templateSrv, private $q, private uiSegmentSrv) { super($scope, $injector); @@ -106,23 +105,55 @@ export class InfluxQueryCtrl extends QueryCtrl { this.panelCtrl.refresh(); } - removeGroupByPart(part, index) { - this.queryModel.removeGroupByPart(part, index); - this.panelCtrl.refresh(); - } - addSelectPart(selectParts, cat, subitem) { this.queryModel.addSelectPart(selectParts, subitem.value); this.panelCtrl.refresh(); } - removeSelectPart(selectParts, part) { - this.queryModel.removeSelectPart(selectParts, part); - this.panelCtrl.refresh(); + handleSelectPartEvent(selectParts, part, evt) { + switch (evt.name) { + case "get-param-options": { + var fieldsQuery = this.queryBuilder.buildExploreQuery('FIELDS'); + return this.datasource.metricFindQuery(fieldsQuery) + .then(this.transformToSegments(true)) + .catch(this.handleQueryError.bind(this)); + } + case "part-param-changed": { + this.panelCtrl.refresh(); + break; + } + case "action": { + this.queryModel.removeSelectPart(selectParts, part); + this.panelCtrl.refresh(); + break; + } + case "get-part-actions": { + return this.$q.when([{text: 'Remove', value: 'remove-part'}]); + } + } } - selectPartUpdated() { - this.panelCtrl.refresh(); + handleGroupByPartEvent(part, index, evt) { + switch (evt.name) { + case "get-param-options": { + var tagsQuery = this.queryBuilder.buildExploreQuery('TAG_KEYS'); + return this.datasource.metricFindQuery(tagsQuery) + .then(this.transformToSegments(true)) + .catch(this.handleQueryError.bind(this)); + } + case "part-param-changed": { + this.panelCtrl.refresh(); + break; + } + case "action": { + this.queryModel.removeGroupByPart(part, index); + this.panelCtrl.refresh(); + break; + } + case "get-part-actions": { + return this.$q.when([{text: 'Remove', value: 'remove-part'}]); + } + } } fixTagSegments() { @@ -167,21 +198,6 @@ export class InfluxQueryCtrl extends QueryCtrl { .catch(this.handleQueryError.bind(this)); } - getPartOptions(part) { - if (part.def.type === 'field') { - var fieldsQuery = this.queryBuilder.buildExploreQuery('FIELDS'); - return this.datasource.metricFindQuery(fieldsQuery) - .then(this.transformToSegments(true)) - .catch(this.handleQueryError.bind(this)); - } - if (part.def.type === 'tag') { - var tagsQuery = this.queryBuilder.buildExploreQuery('TAG_KEYS'); - return this.datasource.metricFindQuery(tagsQuery) - .then(this.transformToSegments(true)) - .catch(this.handleQueryError.bind(true)); - } - } - handleQueryError(err) { this.error = err.message || 'Failed to issue metric query'; return []; @@ -243,11 +259,6 @@ export class InfluxQueryCtrl extends QueryCtrl { .catch(this.handleQueryError); } - setFill(fill) { - this.target.fill = fill; - this.panelCtrl.refresh(); - } - tagSegmentUpdated(segment, index) { this.tagSegments[index] = segment; @@ -323,4 +334,3 @@ export class InfluxQueryCtrl extends QueryCtrl { return this.queryModel.render(false); } } - diff --git a/public/app/plugins/panel/graph/graph.js b/public/app/plugins/panel/graph/graph.js index 185aaf0d692..0a8df0d51ef 100755 --- a/public/app/plugins/panel/graph/graph.js +++ b/public/app/plugins/panel/graph/graph.js @@ -5,6 +5,7 @@ define([ 'lodash', 'app/core/utils/kbn', './graph_tooltip', + './threshold_manager', 'jquery.flot', 'jquery.flot.selection', 'jquery.flot.time', @@ -14,7 +15,7 @@ define([ 'jquery.flot.crosshair', './jquery.flot.events', ], -function (angular, $, moment, _, kbn, GraphTooltip) { +function (angular, $, moment, _, kbn, GraphTooltip, thresholdManExports) { 'use strict'; var module = angular.module('grafana.directives'); @@ -33,6 +34,7 @@ function (angular, $, moment, _, kbn, GraphTooltip) { var legendSideLastValue = null; var rootScope = scope.$root; var panelWidth = 0; + var thresholdManager = new thresholdManExports.ThresholdManager(ctrl); rootScope.onAppEvent('setCrosshair', function(event, info) { // do not need to to this if event is from this panel @@ -155,6 +157,8 @@ function (angular, $, moment, _, kbn, GraphTooltip) { rightLabel[0].style.marginTop = (getLabelWidth(panel.yaxes[1].label, rightLabel) / 2) + 'px'; } + + thresholdManager.draw(plot); } function processOffsetHook(plot, gridMargin) { @@ -172,6 +176,9 @@ function (angular, $, moment, _, kbn, GraphTooltip) { return; } + // give space to alert editing + thresholdManager.prepare(elem, data); + var stack = panel.stack ? true : null; // Populate element @@ -242,7 +249,7 @@ function (angular, $, moment, _, kbn, GraphTooltip) { } addTimeAxis(options); - addGridThresholds(options, panel); + thresholdManager.addPlotOptions(options, panel); addAnnotations(options); configureAxisOptions(data, options); @@ -308,29 +315,6 @@ function (angular, $, moment, _, kbn, GraphTooltip) { }; } - function addGridThresholds(options, panel) { - if (_.isNumber(panel.grid.threshold1)) { - var limit1 = panel.grid.thresholdLine ? panel.grid.threshold1 : (panel.grid.threshold2 || null); - options.grid.markings.push({ - yaxis: { from: panel.grid.threshold1, to: limit1 }, - color: panel.grid.threshold1Color - }); - - if (_.isNumber(panel.grid.threshold2)) { - var limit2; - if (panel.grid.thresholdLine) { - limit2 = panel.grid.threshold2; - } else { - limit2 = panel.grid.threshold1 > panel.grid.threshold2 ? -Infinity : +Infinity; - } - options.grid.markings.push({ - yaxis: { from: panel.grid.threshold2, to: limit2 }, - color: panel.grid.threshold2Color - }); - } - } - } - function addAnnotations(options) { if(!annotations || annotations.length === 0) { return; diff --git a/public/app/plugins/panel/graph/jquery.flot.events.js b/public/app/plugins/panel/graph/jquery.flot.events.js index bf3b4b26eb3..60b6acd1518 100644 --- a/public/app/plugins/panel/graph/jquery.flot.events.js +++ b/public/app/plugins/panel/graph/jquery.flot.events.js @@ -365,12 +365,20 @@ function ($, _, angular, Drop) { plot.hooks.draw.push(function(plot) { var options = plot.getOptions(); + var container = plot.getPlaceholder(); + var containerElem = container[0]; + + if (containerElem.removeEventsElements) { + container.find(".events_line").remove(); + containerElem.removeEventsElements = false; + } if (eventMarkers.eventsEnabled) { // check for first run if (eventMarkers.getEvents().length < 1) { eventMarkers.setTypes(options.events.types); eventMarkers.setupEvents(options.events.data); + containerElem.removeEventsElements = true; } else { eventMarkers.updateEvents(); } diff --git a/public/app/plugins/panel/graph/module.ts b/public/app/plugins/panel/graph/module.ts index 8fbde9e84a1..05da5652b74 100644 --- a/public/app/plugins/panel/graph/module.ts +++ b/public/app/plugins/panel/graph/module.ts @@ -3,6 +3,7 @@ import './graph'; import './legend'; import './series_overrides_ctrl'; +import './thresholds_form'; import template from './template'; import angular from 'angular'; @@ -10,8 +11,9 @@ import moment from 'moment'; import kbn from 'app/core/utils/kbn'; import _ from 'lodash'; import TimeSeries from 'app/core/time_series2'; +import config from 'app/core/config'; import * as fileExport from 'app/core/utils/file_export'; -import {MetricsPanelCtrl} from 'app/plugins/sdk'; +import {MetricsPanelCtrl, alertTab} from 'app/plugins/sdk'; class GraphCtrl extends MetricsPanelCtrl { static template = template; @@ -25,6 +27,7 @@ class GraphCtrl extends MetricsPanelCtrl { datapointsOutside: boolean; datapointsWarning: boolean; colors: any = []; + subTabIndex: number; panelDefaults = { // datasource name, null = default datasource @@ -52,11 +55,9 @@ class GraphCtrl extends MetricsPanelCtrl { xaxis: { show: true }, - grid : { - threshold1: null, - threshold2: null, - threshold1Color: 'rgba(216, 200, 27, 0.27)', - threshold2Color: 'rgba(234, 112, 112, 0.22)' + alert: { + warn: {op: '>', value: undefined}, + crit: {op: '>', value: undefined}, }, // show/hide lines lines : true, @@ -104,6 +105,8 @@ class GraphCtrl extends MetricsPanelCtrl { aliasColors: {}, // other style overrides seriesOverrides: [], + alerting: {}, + thresholds: [], }; /** @ngInject */ @@ -112,7 +115,7 @@ class GraphCtrl extends MetricsPanelCtrl { _.defaults(this.panel, this.panelDefaults); _.defaults(this.panel.tooltip, this.panelDefaults.tooltip); - _.defaults(this.panel.grid, this.panelDefaults.grid); + _.defaults(this.panel.alert, this.panelDefaults.alert); _.defaults(this.panel.legend, this.panelDefaults.legend); this.colors = $scope.$root.colors; @@ -130,6 +133,10 @@ class GraphCtrl extends MetricsPanelCtrl { this.addEditorTab('Legend', 'public/app/plugins/panel/graph/tab_legend.html', 3); this.addEditorTab('Display', 'public/app/plugins/panel/graph/tab_display.html', 4); + if (config.alertingEnabled) { + this.addEditorTab('Alert', alertTab, 5); + } + this.logScales = { 'linear': 1, 'log (base 2)': 2, @@ -137,7 +144,9 @@ class GraphCtrl extends MetricsPanelCtrl { 'log (base 32)': 32, 'log (base 1024)': 1024 }; + this.unitFormats = kbn.getUnitFormats(); + this.subTabIndex = 0; } onInitPanelActions(actions) { @@ -304,6 +313,7 @@ class GraphCtrl extends MetricsPanelCtrl { this.refresh(); } + legendValuesOptionChanged() { var legend = this.panel.legend; legend.values = legend.min || legend.max || legend.avg || legend.current || legend.total; @@ -317,6 +327,7 @@ class GraphCtrl extends MetricsPanelCtrl { exportCsvColumns() { fileExport.exportSeriesListToCsvColumns(this.seriesList); } + } export {GraphCtrl, GraphCtrl as PanelCtrl} diff --git a/public/app/plugins/panel/graph/specs/graph_specs.ts b/public/app/plugins/panel/graph/specs/graph_specs.ts index b9c9362e5de..633832d4866 100644 --- a/public/app/plugins/panel/graph/specs/graph_specs.ts +++ b/public/app/plugins/panel/graph/specs/graph_specs.ts @@ -45,6 +45,7 @@ describe('grafanaGraph', function() { logBase: 1 } ], + thresholds: [], xaxis: {}, seriesOverrides: [], tooltip: { @@ -111,60 +112,6 @@ describe('grafanaGraph', function() { }); }); - graphScenario('grid thresholds 100, 200', function(ctx) { - ctx.setup(function(ctrl) { - ctrl.panel.grid = { - threshold1: 100, - threshold1Color: "#111", - threshold2: 200, - threshold2Color: "#222", - }; - }); - - it('should add grid markings', function() { - var markings = ctx.plotOptions.grid.markings; - expect(markings[0].yaxis.from).to.be(100); - expect(markings[0].yaxis.to).to.be(200); - expect(markings[0].color).to.be('#111'); - expect(markings[1].yaxis.from).to.be(200); - expect(markings[1].yaxis.to).to.be(Infinity); - }); - }); - - graphScenario('inverted grid thresholds 200, 100', function(ctx) { - ctx.setup(function(ctrl) { - ctrl.panel.grid = { - threshold1: 200, - threshold1Color: "#111", - threshold2: 100, - threshold2Color: "#222", - }; - }); - - it('should add grid markings', function() { - var markings = ctx.plotOptions.grid.markings; - expect(markings[0].yaxis.from).to.be(200); - expect(markings[0].yaxis.to).to.be(100); - expect(markings[0].color).to.be('#111'); - expect(markings[1].yaxis.from).to.be(100); - expect(markings[1].yaxis.to).to.be(-Infinity); - }); - }); - - graphScenario('grid thresholds from zero', function(ctx) { - ctx.setup(function(ctrl) { - ctrl.panel.grid = { - threshold1: 0, - threshold1Color: "#111", - }; - }); - - it('should add grid markings', function() { - var markings = ctx.plotOptions.grid.markings; - expect(markings[0].yaxis.from).to.be(0); - }); - }); - graphScenario('when logBase is log 10', function(ctx) { ctx.setup(function(ctrl) { ctrl.panel.yaxes[0].logBase = 10; diff --git a/public/app/plugins/panel/graph/specs/threshold_manager_specs.ts b/public/app/plugins/panel/graph/specs/threshold_manager_specs.ts new file mode 100644 index 00000000000..de598ea73ed --- /dev/null +++ b/public/app/plugins/panel/graph/specs/threshold_manager_specs.ts @@ -0,0 +1,115 @@ +/// + +import {describe, beforeEach, it, sinon, expect, angularMocks} from '../../../../../test/lib/common'; + +import {ThresholdManager} from '../threshold_manager'; + +describe('ThresholdManager', function() { + + function plotOptionsScenario(desc, func) { + describe(desc, function() { + var ctx: any = { + panel: { + thresholds: [], + }, + options: { + grid: {markings: []}, + }, + panelCtrl: {}, + }; + + ctx.setup = function(thresholds) { + ctx.panel.thresholds = thresholds; + var manager = new ThresholdManager(ctx.panelCtrl); + manager.addPlotOptions(ctx.options, ctx.panel); + }; + + func(ctx); + }); + } + + describe("When creating plot markings", () => { + + plotOptionsScenario("for simple gt threshold", ctx => { + ctx.setup([ + {op: 'gt', value: 300, fill: true, line: true, colorMode: 'critical'}, + ]); + + it('should add fill for threshold with fill: true', function() { + var markings = ctx.options.grid.markings; + + expect(markings[0].yaxis.from).to.be(300); + expect(markings[0].yaxis.to).to.be(Infinity); + expect(markings[0].color).to.be('rgba(234, 112, 112, 0.12)'); + }); + + it('should add line', function() { + var markings = ctx.options.grid.markings; + expect(markings[1].yaxis.from).to.be(300); + expect(markings[1].yaxis.to).to.be(300); + expect(markings[1].color).to.be('rgba(237, 46, 24, 0.60)'); + }); + }); + + plotOptionsScenario("for two gt thresholds", ctx => { + ctx.setup([ + {op: 'gt', value: 200, fill: true, colorMode: 'warning'}, + {op: 'gt', value: 300, fill: true, colorMode: 'critical'}, + ]); + + it('should add fill for first thresholds to next threshold', function() { + var markings = ctx.options.grid.markings; + expect(markings[0].yaxis.from).to.be(200); + expect(markings[0].yaxis.to).to.be(300); + }); + + it('should add fill for last thresholds to infinity', function() { + var markings = ctx.options.grid.markings; + expect(markings[1].yaxis.from).to.be(300); + expect(markings[1].yaxis.to).to.be(Infinity); + }); + + }); + + plotOptionsScenario("for lt then gt threshold (inside)", ctx => { + ctx.setup([ + {op: 'lt', value: 300, fill: true, colorMode: 'critical'}, + {op: 'gt', value: 200, fill: true, colorMode: 'critical'}, + ]); + + it('should add fill for first thresholds to next threshold', function() { + var markings = ctx.options.grid.markings; + expect(markings[0].yaxis.from).to.be(300); + expect(markings[0].yaxis.to).to.be(200); + }); + + it('should add fill for last thresholds to itself', function() { + var markings = ctx.options.grid.markings; + expect(markings[1].yaxis.from).to.be(200); + expect(markings[1].yaxis.to).to.be(200); + }); + + }); + + plotOptionsScenario("for gt then lt threshold (outside)", ctx => { + ctx.setup([ + {op: 'gt', value: 300, fill: true, colorMode: 'critical'}, + {op: 'lt', value: 200, fill: true, colorMode: 'critical'}, + ]); + + it('should add fill for first thresholds to next threshold', function() { + var markings = ctx.options.grid.markings; + expect(markings[0].yaxis.from).to.be(300); + expect(markings[0].yaxis.to).to.be(Infinity); + }); + + it('should add fill for last thresholds to itself', function() { + var markings = ctx.options.grid.markings; + expect(markings[1].yaxis.from).to.be(200); + expect(markings[1].yaxis.to).to.be(-Infinity); + }); + + }); + + }); +}); diff --git a/public/app/plugins/panel/graph/tab_axes.html b/public/app/plugins/panel/graph/tab_axes.html index eeaf27aff78..bb051649424 100644 --- a/public/app/plugins/panel/graph/tab_axes.html +++ b/public/app/plugins/panel/graph/tab_axes.html @@ -42,33 +42,4 @@ -
-
Thresholds
-
-
- - -
-
- -
- -
-
-
-
-
- - -
-
- -
- -
-
-
- - -
diff --git a/public/app/plugins/panel/graph/tab_display.html b/public/app/plugins/panel/graph/tab_display.html index c9f51dc5dde..14c8c4cf6fc 100644 --- a/public/app/plugins/panel/graph/tab_display.html +++ b/public/app/plugins/panel/graph/tab_display.html @@ -1,103 +1,105 @@ -
-
-
Draw Modes
- - - - - - -
-
-
Mode Options
-
- -
- +
+ + +
+
+
Draw Modes
+ + + +
+
+
Mode Options
+
+ +
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
-
- -
- +
+
Hover info
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
- - -
- -
- -
-
-
-
-
Hover info
-
- -
- -
-
-
- -
- -
-
-
- -
- + +
+
Stacking & Null value
+ + + + +
+ +
+ +
-
-
Stacking & Null value
- - - - -
- -
- -
-
-
- -
- -
-
-
Series specific overrides Regex match example: /server[0-3]/i
-
-
-
    -
  • - -
  • - -
  • - alias or regex -
  • - -
  • - -
  • - -
  • +
    +
    +
    Series specific overrides Regex match example: /server[0-3]/i
    +
    +
    + +
    +
    + +
    +
    +
  • + +
- - -
+
+ + +
+ +
+
+
+ +
+ +
-
+ +
+ +
+
diff --git a/public/app/plugins/panel/graph/threshold_manager.ts b/public/app/plugins/panel/graph/threshold_manager.ts new file mode 100644 index 00000000000..069f5f38292 --- /dev/null +++ b/public/app/plugins/panel/graph/threshold_manager.ts @@ -0,0 +1,239 @@ +/// + +import 'jquery.flot'; +import $ from 'jquery'; +import _ from 'lodash'; + +export class ThresholdManager { + plot: any; + placeholder: any; + height: any; + thresholds: any; + needsCleanup: boolean; + hasSecondYAxis: any; + + constructor(private panelCtrl) {} + + getHandleHtml(handleIndex, model, valueStr) { + var stateClass = model.colorMode; + if (model.colorMode === 'custom') { + stateClass = 'critical'; + } + + return ` +
+
+
+
+ + ${valueStr} +
+
`; + + } + + initDragging(evt) { + var handleElem = $(evt.currentTarget).parents(".alert-handle-wrapper"); + var handleIndex = $(evt.currentTarget).data("handleIndex"); + + var isMoving = false; + var lastY = null; + var posTop; + var plot = this.plot; + var panelCtrl = this.panelCtrl; + var model = this.thresholds[handleIndex]; + + function dragging(evt) { + if (lastY === null) { + lastY = evt.clientY; + } else { + var diff = evt.clientY - lastY; + posTop = posTop + diff; + lastY = evt.clientY; + handleElem.css({top: posTop + diff}); + } + } + + function stopped() { + isMoving = false; + // calculate graph level + var graphValue = plot.c2p({left: 0, top: posTop}).y; + graphValue = parseInt(graphValue.toFixed(0)); + model.value = graphValue; + + var valueCanvasPos = plot.p2c({x: 0, y: graphValue}); + + handleElem.off("mousemove", dragging); + handleElem.off("mouseup", dragging); + handleElem.off("mouseleave", dragging); + + // trigger digest and render + panelCtrl.$scope.$apply(function() { + panelCtrl.render(); + panelCtrl.events.emit('threshold-changed', {threshold: model, handleIndex: handleIndex}); + }); + } + + isMoving = true; + lastY = null; + posTop = handleElem.position().top; + + handleElem.on("mousemove", dragging); + handleElem.on("mouseup", stopped); + handleElem.on("mouseleave", stopped); + } + + cleanUp() { + this.placeholder.find(".alert-handle-wrapper").remove(); + this.needsCleanup = false; + } + + renderHandle(handleIndex, defaultHandleTopPos) { + var model = this.thresholds[handleIndex]; + var value = model.value; + var valueStr = value; + var handleTopPos = 0; + + // handle no value + if (!_.isNumber(value)) { + valueStr = ''; + handleTopPos = defaultHandleTopPos; + } else { + var valueCanvasPos = this.plot.p2c({x: 0, y: value}); + handleTopPos = Math.min(Math.max(valueCanvasPos.top, 0), this.height) - 6; + } + + var handleElem = $(this.getHandleHtml(handleIndex, model, valueStr)); + this.placeholder.append(handleElem); + + handleElem.toggleClass('alert-handle-wrapper--no-value', valueStr === ''); + handleElem.css({top: handleTopPos}); + } + + shouldDrawHandles() { + return !this.hasSecondYAxis && this.panelCtrl.editingThresholds && this.panelCtrl.panel.thresholds.length > 0; + } + + prepare(elem, data) { + this.hasSecondYAxis = false; + for (var i = 0; i < data.length; i++) { + if (data[i].yaxis > 1) { + this.hasSecondYAxis = true; + break; + } + } + + if (this.shouldDrawHandles()) { + var thresholdMargin = this.panelCtrl.panel.thresholds.length > 1 ? '220px' : '110px'; + elem.css('margin-right', thresholdMargin); + } else if (this.needsCleanup) { + elem.css('margin-right', '0'); + } + } + + draw(plot) { + this.thresholds = this.panelCtrl.panel.thresholds; + this.plot = plot; + this.placeholder = plot.getPlaceholder(); + + if (this.needsCleanup) { + this.cleanUp(); + } + + if (!this.shouldDrawHandles()) { + return; + } + + this.height = plot.height(); + + if (this.thresholds.length > 0) { + this.renderHandle(0, 10); + } + if (this.thresholds.length > 1) { + this.renderHandle(1, this.height-30); + } + + this.placeholder.off('mousedown', '.alert-handle'); + this.placeholder.on('mousedown', '.alert-handle', this.initDragging.bind(this)); + this.needsCleanup = true; + } + + addPlotOptions(options, panel) { + if (!panel.thresholds || panel.thresholds.length === 0) { + return; + } + + var gtLimit = Infinity; + var ltLimit = -Infinity; + var i, threshold, other; + + for (i = 0; i < panel.thresholds.length; i++) { + threshold = panel.thresholds[i]; + if (!_.isNumber(threshold.value)) { + continue; + } + + var limit; + switch (threshold.op) { + case 'gt': { + limit = gtLimit; + // if next threshold is less then op and greater value, then use that as limit + if (panel.thresholds.length > i+1) { + other = panel.thresholds[i+1]; + if (other.value > threshold.value) { + limit = other.value; + ltLimit = limit; + } + } + break; + } + case 'lt': { + limit = ltLimit; + // if next threshold is less then op and greater value, then use that as limit + if (panel.thresholds.length > i+1) { + other = panel.thresholds[i+1]; + if (other.value < threshold.value) { + limit = other.value; + gtLimit = limit; + } + } + break; + } + } + + var fillColor, lineColor; + switch (threshold.colorMode) { + case 'critical': { + fillColor = 'rgba(234, 112, 112, 0.12)'; + lineColor = 'rgba(237, 46, 24, 0.60)'; + break; + } + case 'warning': { + fillColor = 'rgba(235, 138, 14, 0.12)'; + lineColor = 'rgba(247, 149, 32, 0.60)'; + break; + } + case 'ok': { + fillColor = 'rgba(11, 237, 50, 0.090)'; + lineColor = 'rgba(6,163,69, 0.60)'; + break; + } + case 'custom': { + fillColor = threshold.fillColor; + lineColor = threshold.lineColor; + break; + } + } + + // fill + if (threshold.fill) { + options.grid.markings.push({yaxis: {from: threshold.value, to: limit}, color: fillColor}); + } + if (threshold.line) { + options.grid.markings.push({yaxis: {from: threshold.value, to: threshold.value}, color: lineColor}); + } + } + } + +} + diff --git a/public/app/plugins/panel/graph/thresholds_form.ts b/public/app/plugins/panel/graph/thresholds_form.ts new file mode 100644 index 00000000000..086d278f0c0 --- /dev/null +++ b/public/app/plugins/panel/graph/thresholds_form.ts @@ -0,0 +1,124 @@ +/// + + +import _ from 'lodash'; +import coreModule from 'app/core/core_module'; + +export class ThresholdFormCtrl { + panelCtrl: any; + panel: any; + disabled: boolean; + + /** @ngInject */ + constructor($scope) { + this.panel = this.panelCtrl.panel; + + if (this.panel.alert && this.panel.alert.enabled) { + this.disabled = true; + } + + $scope.$on("$destroy", () => { + this.panelCtrl.editingThresholds = false; + this.panelCtrl.render(); + }); + + this.panelCtrl.editingThresholds = true; + } + + addThreshold() { + this.panel.thresholds.push({value: undefined, colorMode: "critical", op: 'gt', fill: true, line: true}); + this.panelCtrl.render(); + } + + removeThreshold(index) { + this.panel.thresholds.splice(index, 1); + this.panelCtrl.render(); + } + + render() { + this.panelCtrl.render(); + } +} + +var template = ` +
+
Thresholds
+

+ Visual thresholds options disabled. + Visit the Alert tab update your thresholds.
+ To re-enable thresholds, the alert rule must be deleted from this panel. +

+
+
+
+ +
+ +
+
+ +
+ +
+ +
+ +
+ +
+
+ + + +
+ + + + +
+ + + +
+ + + + +
+ +
+ +
+
+ +
+ +
+
+
+`; + +coreModule.directive('graphThresholdForm', function() { + return { + restrict: 'E', + template: template, + controller: ThresholdFormCtrl, + bindToController: true, + controllerAs: 'ctrl', + scope: { + panelCtrl: "=" + } + }; +}); diff --git a/public/app/plugins/panel/singlestat/editor.html b/public/app/plugins/panel/singlestat/editor.html index e6be9f83032..c0c522abac9 100644 --- a/public/app/plugins/panel/singlestat/editor.html +++ b/public/app/plugins/panel/singlestat/editor.html @@ -182,9 +182,9 @@
  • -   - +   Min value is bigger than max. +  
  • diff --git a/public/app/plugins/sdk.ts b/public/app/plugins/sdk.ts index 854b8777766..468b6baa4a0 100644 --- a/public/app/plugins/sdk.ts +++ b/public/app/plugins/sdk.ts @@ -1,6 +1,7 @@ import {PanelCtrl} from 'app/features/panel/panel_ctrl'; import {MetricsPanelCtrl} from 'app/features/panel/metrics_panel_ctrl'; import {QueryCtrl} from 'app/features/panel/query_ctrl'; +import {alertTab} from 'app/features/alerting/alert_tab_ctrl'; import config from 'app/core/config'; @@ -16,4 +17,5 @@ export { PanelCtrl, MetricsPanelCtrl, QueryCtrl, + alertTab, } diff --git a/public/emails/alert_notification.html b/public/emails/alert_notification.html new file mode 100644 index 00000000000..f80a8330eaf --- /dev/null +++ b/public/emails/alert_notification.html @@ -0,0 +1,239 @@ + + + + + + + + + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    + + + + + + +
    + +
    + +
    + +
    +
    + + + + + + +
    + {{Subject .Subject "{{.Title}}"}} + + + + + +
    + + + + +
    +

    {{.Title}}

    +
    +
    + + + + + +
    + + + + +
    +

    {{.Message}}

    +
    +
    + +{{if ne .State "ok" }} + + + + +
    +
    + + + + + + {{range .EvalMatches}} + + + + + {{end}} +
    + Metric name + + Value +
    + {{.Metric}} + + {{.Value}} +
    +
    +
    +{{end}} + + + + + +
    + + + + +
    + +
    +
    + + + + + + +
    + + + + +
    + Alert rule - Alerts page +
    +
    + + + + + + + + + + + +
    +
    +
    + + diff --git a/public/emails/invited_to_org.html b/public/emails/invited_to_org.html index acfe6c354fc..8263fb65a15 100644 --- a/public/emails/invited_to_org.html +++ b/public/emails/invited_to_org.html @@ -149,7 +149,7 @@ color: #FFFFFF !important; - +
    Log in nowLog in now
    diff --git a/public/emails/new_user_invite.html b/public/emails/new_user_invite.html index 1504ca1453c..15de19a7bf6 100644 --- a/public/emails/new_user_invite.html +++ b/public/emails/new_user_invite.html @@ -147,7 +147,7 @@ color: #FFFFFF !important; - +
    Accept InvitationAccept Invitation
    diff --git a/public/emails/signup_started.html b/public/emails/signup_started.html index 425f36f67e9..a8ee02174a8 100644 --- a/public/emails/signup_started.html +++ b/public/emails/signup_started.html @@ -148,7 +148,7 @@ color: #FFFFFF !important; - +
    Complete Sign UpComplete Sign Up
    diff --git a/public/img/alert_howto_new.png b/public/img/alert_howto_new.png new file mode 100644 index 00000000000..b7663588656 Binary files /dev/null and b/public/img/alert_howto_new.png differ diff --git a/public/img/grab_dark.svg b/public/img/grab_dark.svg new file mode 100644 index 00000000000..e533274e7a0 --- /dev/null +++ b/public/img/grab_dark.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/public/img/grab_light.svg b/public/img/grab_light.svg new file mode 100644 index 00000000000..4b49c6d0d5e --- /dev/null +++ b/public/img/grab_light.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/public/sass/_grafana.scss b/public/sass/_grafana.scss index 194d7a5487c..936ce0af4d6 100644 --- a/public/sass/_grafana.scss +++ b/public/sass/_grafana.scss @@ -71,6 +71,8 @@ @import "components/query_editor"; @import "components/tabbed_view"; @import "components/query_part"; +@import "components/jsontree"; +@import "components/edit_sidemenu.scss"; // PAGES @import "pages/login"; diff --git a/public/sass/_variables.dark.scss b/public/sass/_variables.dark.scss index a231ae1d8ac..38ff4e1e96b 100644 --- a/public/sass/_variables.dark.scss +++ b/public/sass/_variables.dark.scss @@ -44,7 +44,7 @@ $brand-text-highlight: #f7941d; // Status colors // ------------------------- $online: #10a345; -$warn: #ffc03c; +$warn: #F79520; $critical: #ed2e18; // Scaffolding @@ -90,12 +90,12 @@ $component-active-bg: $brand-primary !default; // Panel // ------------------------- $panel-bg: $dark-2; -$panel-border: solid 1px $dark-3; +$panel-border: solid 1px $dark-3; -$divider-border-color: #555; +$divider-border-color: #555; // Graphite Target Editor -$tight-form-border: #050505; +$tight-form-border: #050505; $tight-form-bg: $dark-3; $tight-form-func-bg: #333; @@ -152,6 +152,11 @@ $btn-link-color: $gray-3; $iconContainerBackground: $black; +$btn-divider-left: $dark-4; +$btn-divider-right: $dark-2; + +$btn-drag-image: '../img/grab_dark.svg'; + // Forms // ------------------------- $input-bg: $dark-4; @@ -164,6 +169,7 @@ $input-border-focus: $input-border-color !default; $input-box-shadow-focus: rgba(102,175,233,.6) !default; $input-color-placeholder: $gray-1 !default; $input-label-bg: $dark-3; +$input-invalid-border-color: lighten($red, 5%); // Search $search-shadow: 0 0 35px 0 $body-bg; @@ -184,7 +190,6 @@ $dropdownLinkColorActive: $white; $dropdownLinkBackgroundActive: $dark-4; $dropdownLinkBackgroundHover: $dark-4; - // COMPONENT VARIABLES // -------------------------------------------------- diff --git a/public/sass/_variables.light.scss b/public/sass/_variables.light.scss index 6392586f88e..6727b88ca6b 100644 --- a/public/sass/_variables.light.scss +++ b/public/sass/_variables.light.scss @@ -99,7 +99,7 @@ $component-active-bg: $brand-primary !default; $panel-bg: $gray-7; $panel-border: solid 1px $gray-6; -$divider-border-color: $gray-2; +$divider-border-color: $gray-2; // Graphite Target Editor $tight-form-border: $gray-4; @@ -157,6 +157,10 @@ $btn-inverse-text-color: $dark-4; $btn-link-color: $gray-1; +$btn-divider-left: $gray-4; +$btn-divider-right: $gray-7; +$btn-drag-image: '../img/grab_light.svg'; + $iconContainerBackground: $white; // Forms @@ -171,6 +175,7 @@ $input-border-focus: $blue !default; $input-box-shadow-focus: $blue !default; $input-color-placeholder: $gray-4 !default; $input-label-bg: $gray-6; +$input-invalid-border-color: lighten($red, 5%); // Sidemenu // ------------------------- diff --git a/public/sass/base/_grafana_icons.scss b/public/sass/base/_grafana_icons.scss index f3264d409cd..65fe0e23871 100644 --- a/public/sass/base/_grafana_icons.scss +++ b/public/sass/base/_grafana_icons.scss @@ -31,7 +31,7 @@ .icon-gf-raintank_wordmark:before { content: "\e600"; } -.icon-gf-raintank_icn:before { +.micon-gf-raintank_icn:before { content: "\e601"; } .icon-gf-raintank_r-icn:before { @@ -79,7 +79,8 @@ .icon-gf-jump-to-dashboard:before { content: "\e60d"; } -.icon-gf-warn:before { +.icon-gf-warn, +.icon-gf-warning:before { content: "\e60e"; } .icon-gf-nodata:before { @@ -88,6 +89,9 @@ .icon-gf-critical:before { content: "\e610"; } +.icon-gf-crit:before { + content: "\e610"; +} .icon-gf-online:before { content: "\e611"; } diff --git a/public/sass/base/_type.scss b/public/sass/base/_type.scss index 7770be25a68..f165d40e2eb 100644 --- a/public/sass/base/_type.scss +++ b/public/sass/base/_type.scss @@ -48,6 +48,11 @@ a.text-success:hover, a.text-success:focus { color: darken($successText, 10%); } a { cursor: pointer; } +a[disabled] { + cursor: default; + pointer-events: none !important; +} + .text-left { text-align: left; } .text-right { text-align: right; } .text-center { text-align: center; } diff --git a/public/sass/components/_alerts.scss b/public/sass/components/_alerts.scss index 3e6a8bbef91..4434fa680f0 100644 --- a/public/sass/components/_alerts.scss +++ b/public/sass/components/_alerts.scss @@ -6,8 +6,10 @@ // Base styles // ------------------------- + + .alert { - padding: 8px 35px 13px 14px; + padding: 0.5rem 2rem 0.5rem 1rem; margin-bottom: $line-height-base; text-shadow: 0 1px 0 rgba(255,255,255,.5); background-color: $state-warning-bg; diff --git a/public/sass/components/_cards.scss b/public/sass/components/_cards.scss index c64fbbe8aa7..6dba94494b1 100644 --- a/public/sass/components/_cards.scss +++ b/public/sass/components/_cards.scss @@ -64,6 +64,13 @@ font-size: 11px; padding: 2px 6px; } + + &--alert { + padding: 0.5rem 1rem; + .card-item-name a { + font-size: $font-size-h5; + } + } } .card-item-body { @@ -75,6 +82,13 @@ overflow: hidden; } +.card-item-cog { + font-size: 130%; + position: relative; + top: 1rem; + color: $text-muted; +} + .card-item-header { margin-bottom: $spacer; } diff --git a/public/sass/components/_dropdown.scss b/public/sass/components/_dropdown.scss index 3934fa69640..142910033b0 100644 --- a/public/sass/components/_dropdown.scss +++ b/public/sass/components/_dropdown.scss @@ -140,6 +140,12 @@ & > .dropdown-menu { display: block; } + + &.cascade-open { + .dropdown-menu { + display: block; + } + } } // Backdrop to catch body clicks on mobile, etc. diff --git a/public/sass/components/_jsontree.scss b/public/sass/components/_jsontree.scss new file mode 100644 index 00000000000..011566f8731 --- /dev/null +++ b/public/sass/components/_jsontree.scss @@ -0,0 +1,61 @@ +/* Structure */ +json-tree { + .json-tree-key { + vertical-align: middle; + } + .expandable { + position: relative; + &::before { + pointer-events: none; + } + &::before, & > .json-tree-key { + cursor: pointer; + } + } + .json-tree-branch-preview { + display: inline-block; + vertical-align: middle; + } +} + +/* Looks */ +json-tree { + ul { + padding-left: $spacer; + } + li, ul { + list-style: none; + } + li { + line-height: 1.3rem; + } + .json-tree-key { + color: $variable; + padding: 5px 10px 5px 15px; + &::after { + content: ':'; + } + } + json-node.expandable { + &::before { + content: '\25b6'; + position: absolute; + left: 0px; + font-size: 8px; + transition: transform .1s ease; + } + &.expanded::before { + transform: rotate(90deg); + } + } + .json-tree-leaf-value, .json-tree-branch-preview { + word-break: break-all; + } + .json-tree-branch-preview { + overflow: hidden; + font-style: italic; + max-width: 40%; + height: 1.5em; + opacity: .7; + } +} diff --git a/public/sass/components/_modals.scss b/public/sass/components/_modals.scss index 40cab02eac8..67e2bc017ea 100644 --- a/public/sass/components/_modals.scss +++ b/public/sass/components/_modals.scss @@ -115,6 +115,13 @@ margin-right: $spacer/2; } } + + .modal-content-confirm-text { + margin-bottom: 2rem; + span { + text-align: center; + } + } } .share-modal-body { diff --git a/public/sass/components/_panel_graph.scss b/public/sass/components/_panel_graph.scss index 227069f83b6..d5cfedf03db 100644 --- a/public/sass/components/_panel_graph.scss +++ b/public/sass/components/_panel_graph.scss @@ -315,3 +315,92 @@ font-size: 12px; } +.alert-handle-wrapper { + position: absolute; + user-select: none; + + .alert-handle { + z-index: 10; + position: relative; + float: right; + box-shadow: $card-shadow; + background: $card-background; + cursor: move; + width: 100px; + font-size: $font-size-sm; + border-radius: 4px; + text-align: left; + color: $text-muted; + + &:hover { + background-color: $btn-inverse-bg-hl; + } + + .icon-gf { + font-size: 14px; + position: relative; + top: 0px; + float: left; + border-right: 1px solid $btn-divider-left; + padding: 0.5rem 0.3rem 0.4rem 0.4rem; + } + } + + .alert-handle-value { + border-left: 1px solid $btn-divider-right; + padding: 0.5rem; + line-height: 2rem; + + .alert-handle-grip { + background: url($btn-drag-image) no-repeat 50% 50%; + background-size: 8px; + float: right; + width: 1rem; + height: 2rem; + margin-right: 2px; + } + } + + &--T1 { + right: -222px; + width: 245px; + + .alert-handle-line { + width: 145px; + } + } + + &--T0{ + right: -105px; + width: 128px; + + .alert-handle-line { + width: 28px; + } + } + + &--no-value { + .alert-handle-line { + display: none; + } + } + + .alert-handle-line { + float: left; + height: 2px; + margin-top: 13px; + z-index: 0; + position: relative; + + &--critical { + background-color: rgba(237, 46, 24, 0.60); + } + &--warning { + background-color: rgba(247, 149, 32, 0.60); + } + } +} + +.thresholds-form-disabled { + filter: blur(3px); +} diff --git a/public/sass/components/_switch.scss b/public/sass/components/_switch.scss index 131a971fb2f..00b50c6da9a 100644 --- a/public/sass/components/_switch.scss +++ b/public/sass/components/_switch.scss @@ -88,4 +88,13 @@ $switch-height: 1.5rem; input:checked + label::after { transform: rotateY(0); } + +} + +gf-form-switch[disabled] { + .gf-form-label, + .gf-form-switch input + label { + cursor: default; + pointer-events: none !important; + } } diff --git a/public/sass/components/_tabbed_view.scss b/public/sass/components/_tabbed_view.scss index 6c8a42a8059..f1b59fa2363 100644 --- a/public/sass/components/_tabbed_view.scss +++ b/public/sass/components/_tabbed_view.scss @@ -28,7 +28,7 @@ float: left; font-style: italic; padding-top: 0.5rem; - margin: 0 $spacer*3 0 $spacer*1.5; + margin: 0 $spacer*3 0 $spacer*1; } .tabbed-view-close-btn { @@ -48,7 +48,7 @@ } .tabbed-view-body { - padding: $spacer*1.5; + padding: $spacer*2; min-height: 250px; } diff --git a/public/sass/components/_tags.scss b/public/sass/components/_tags.scss index 821e372e659..c00328c49c4 100644 --- a/public/sass/components/_tags.scss +++ b/public/sass/components/_tags.scss @@ -34,7 +34,7 @@ } .label-tag:hover { - opacity: 0.85; + opacity: 0.85; background-color: darken($purple, 10%); } diff --git a/public/sass/components/_tagsinput.scss b/public/sass/components/_tagsinput.scss index 85ab6d602fd..0753f045a61 100644 --- a/public/sass/components/_tagsinput.scss +++ b/public/sass/components/_tagsinput.scss @@ -7,6 +7,7 @@ background-color: $input-bg; input { + display: inline-block; border: none; border-right: 1px solid $tight-form-border; margin: 0px; diff --git a/public/sass/components/edit_sidemenu.scss b/public/sass/components/edit_sidemenu.scss new file mode 100644 index 00000000000..de3e92ee5e2 --- /dev/null +++ b/public/sass/components/edit_sidemenu.scss @@ -0,0 +1,45 @@ + +.edit-tab-with-sidemenu { + display: flex; + flex-direction: row; +} + +.edit-sidemenu-aside { + width: 14rem; +} + +.edit-sidemenu { + width: 100%; + list-style: none; + + li.active { + @include left-brand-border-gradient(); + } + + a { + display: block; + color: $text-color; + margin: 0 0 1.5rem 1rem; + } +} + + +@include media-breakpoint-down(sm) { + .edit-tab-with-sidemenu { + flex-direction: column; + } + + .edit-sidemenu-aside { + width: 100%; + margin-bottom: 2rem; + } + + .edit-sidemenu { + li { + float: left; + } + a { + margin: 0.3rem 1rem; + } + } +} diff --git a/public/sass/pages/_alerting.scss b/public/sass/pages/_alerting.scss index 00ecf707520..33577d1e30a 100644 --- a/public/sass/pages/_alerting.scss +++ b/public/sass/pages/_alerting.scss @@ -1,31 +1,18 @@ -.copy-query { - display: block; - width: 30px; - height: 36px; - margin: 0; - padding: 0; - border: 0; - background: transparent url(/img/CopyQuery.png) 50% 50% no-repeat; - cursor: pointer; +.alert-state-paused, +.alert-state-pending { + color: $text-muted; } -.alert-state { - display: inline-block; - padding-left: 30px; - background: 0 50% no-repeat; - background-size: 20px auto; -} - -.alert-state-online { - background-image: url('/img/online.svg'); +.alert-state-ok { + color: $online; } .alert-state-warning { - background-image: url('/img/warn-tiny.svg'); + color: $warn; } .alert-state-critical { - background-image: url('/img/critical.svg'); + color: $critical; } .alert-notify-emails { @@ -40,3 +27,14 @@ .alert-notify-emails .bootstrap-tagsinput input { border: 0; } + +// Alert List + +.alert-list-item-state { + font-weight: bold; + .icon-gf, .fa { + font-size: 120%; + position: relative; + top: 2px; + } +} diff --git a/public/sass/pages/_dashboard.scss b/public/sass/pages/_dashboard.scss index 98f8fcfb4ed..2d6de7d7584 100644 --- a/public/sass/pages/_dashboard.scss +++ b/public/sass/pages/_dashboard.scss @@ -195,12 +195,6 @@ div.flot-text { bottom: 0; } -.panel-fullscreen { - .panel-title-container { - padding: 8px; - } -} - .panel-full-edit { margin-top: 20px; margin-bottom: 20px; diff --git a/public/test/specs/dashboardSrv-specs.js b/public/test/specs/dashboardSrv-specs.js index 6fc53f09190..65441bb3b41 100644 --- a/public/test/specs/dashboardSrv-specs.js +++ b/public/test/specs/dashboardSrv-specs.js @@ -128,7 +128,18 @@ define([ { type: 'graph', legend: true, aliasYAxis: { test: 2 }, y_formats: ['kbyte', 'ms'], - grid: {min: 1, max: 10, rightMin: 5, rightMax: 15, leftLogBase: 1, rightLogBase: 2}, + grid: { + min: 1, + max: 10, + rightMin: 5, + rightMax: 15, + leftLogBase: 1, + rightLogBase: 2, + threshold1: 200, + threshold2: 400, + threshold1Color: 'yellow', + threshold2Color: 'red', + }, leftYAxisLabel: 'left label', targets: [{refId: 'A'}, {}], }, @@ -212,9 +223,17 @@ define([ }); it('dashboard schema version should be set to latest', function() { - expect(model.schemaVersion).to.be(12); + expect(model.schemaVersion).to.be(13); }); + it('graph thresholds should be migrated', function() { + expect(graph.thresholds.length).to.be(2); + expect(graph.thresholds[0].op).to.be('>'); + expect(graph.thresholds[0].value).to.be(400); + expect(graph.thresholds[0].fillColor).to.be('red'); + expect(graph.thresholds[1].value).to.be(200); + expect(graph.thresholds[1].fillColor).to.be('yellow'); + }); }); describe('when creating dashboard model with missing list for annoations or templating', function() { diff --git a/public/vendor/flot/jquery.flot.js b/public/vendor/flot/jquery.flot.js index 380030a77c9..45d76b440c3 100644 --- a/public/vendor/flot/jquery.flot.js +++ b/public/vendor/flot/jquery.flot.js @@ -1316,14 +1316,10 @@ Licensed under the MIT license. } function setupCanvases() { - // Make sure the placeholder is clear of everything except canvases // from a previous plot in this container that we'll try to re-use. - placeholder.css("padding", 0) // padding messes up the positioning - .children().filter(function(){ - return !$(this).hasClass("flot-overlay") && !$(this).hasClass('flot-base'); - }).remove(); + placeholder.find(".flot-text").remove(); if (placeholder.css("position") == 'static') placeholder.css("position", "relative"); // for positioning labels and overlay diff --git a/public/vendor/tagsinput/bootstrap-tagsinput.js b/public/vendor/tagsinput/bootstrap-tagsinput.js index b3a3c3bc386..702b6416962 100644 --- a/public/vendor/tagsinput/bootstrap-tagsinput.js +++ b/public/vendor/tagsinput/bootstrap-tagsinput.js @@ -35,7 +35,7 @@ this.inputSize = Math.max(1, this.placeholderText.length); this.$container = $('
    '); - this.$input = $('').appendTo(this.$container); this.$element.after(this.$container); diff --git a/vendor/phantomjs/render.js b/vendor/phantomjs/render.js index 92000bb9f12..3e10ee852f9 100644 --- a/vendor/phantomjs/render.js +++ b/vendor/phantomjs/render.js @@ -35,6 +35,17 @@ page.open(params.url, function (status) { // console.log('Loading a web page: ' + params.url + ' status: ' + status); + page.onError = function(msg, trace) { + var msgStack = ['ERROR: ' + msg]; + if (trace && trace.length) { + msgStack.push('TRACE:'); + trace.forEach(function(t) { + msgStack.push(' -> ' + t.file + ': ' + t.line + (t.function ? ' (in function "' + t.function +'")' : '')); + }); + } + console.error(msgStack.join('\n')); + }; + function checkIsReady() { var panelsRendered = page.evaluate(function() { if (!window.angular) { return false; }