Test note DAO

pull/6/head
Mickaël Menu 3 years ago
parent d655720181
commit 8a876f3b7f
No known key found for this signature in database
GPG Key ID: 53D73664CD359895

@ -8,6 +8,7 @@ import (
"github.com/mickael-menu/zk/core/file"
"github.com/mickael-menu/zk/core/note"
"github.com/mickael-menu/zk/util"
"github.com/mickael-menu/zk/util/errors"
)
// NoteDAO persists notes in the SQLite database.
@ -22,6 +23,7 @@ type NoteDAO struct {
addStmt *LazyStmt
updateStmt *LazyStmt
removeStmt *LazyStmt
existsStmt *LazyStmt
}
func NewNoteDAO(tx Transaction, root string, logger util.Logger) *NoteDAO {
@ -46,13 +48,18 @@ func NewNoteDAO(tx Transaction, root string, logger util.Logger) *NoteDAO {
DELETE FROM notes
WHERE dir = ? AND filename = ?
`),
existsStmt: tx.PrepareLazy(`
SELECT EXISTS (SELECT 1 FROM notes WHERE dir = ? AND filename = ?)
`),
}
}
func (d *NoteDAO) Indexed() (<-chan file.Metadata, error) {
wrap := errors.Wrapper("failed to get indexed notes")
rows, err := d.indexedStmt.Query()
if err != nil {
return nil, err
return nil, wrap(err)
}
c := make(chan file.Metadata)
@ -67,7 +74,7 @@ func (d *NoteDAO) Indexed() (<-chan file.Metadata, error) {
for rows.Next() {
err := rows.Scan(&dir, &filename, &modified)
if err != nil {
d.logger.Err(err)
d.logger.Err(wrap(err))
}
c <- file.Metadata{
@ -78,7 +85,7 @@ func (d *NoteDAO) Indexed() (<-chan file.Metadata, error) {
err = rows.Err()
if err != nil {
d.logger.Err(err)
d.logger.Err(wrap(err))
}
}()
@ -91,21 +98,54 @@ func (d *NoteDAO) Add(note note.Metadata) error {
note.Body, note.WordCount, note.Checksum,
note.Created, note.Modified,
)
return err
return errors.Wrapf(err, "%v: can't add note to the index", note.Path)
}
func (d *NoteDAO) Update(note note.Metadata) error {
_, err := d.updateStmt.Exec(
wrap := errors.Wrapperf("%v: failed to update note index", note.Path)
exists, err := d.exists(note.Path)
if err != nil {
return wrap(err)
}
if !exists {
return wrap(errors.New("note not found in the index"))
}
_, err = d.updateStmt.Exec(
note.Title, note.Body, note.WordCount,
note.Checksum, note.Modified,
note.Path.Dir, note.Path.Filename,
)
return err
return errors.Wrapf(err, "%v: failed to update note index", note.Path)
}
func (d *NoteDAO) Remove(path file.Path) error {
_, err := d.updateStmt.Exec(path.Dir, path.Filename)
return err
wrap := errors.Wrapperf("%v: failed to remove note index", path)
exists, err := d.exists(path)
if err != nil {
return wrap(err)
}
if !exists {
return wrap(errors.New("note not found in the index"))
}
_, err = d.removeStmt.Exec(path.Dir, path.Filename)
return wrap(err)
}
func (d *NoteDAO) exists(path file.Path) (bool, error) {
row, err := d.existsStmt.QueryRow(path.Dir, path.Filename)
if err != nil {
return false, err
}
var exists bool
row.Scan(&exists)
if err != nil {
return false, err
}
return exists, nil
}
func (d *NoteDAO) Find(callback func(note.Match) error, filters ...note.Filter) error {

@ -0,0 +1,199 @@
package sqlite
import (
"fmt"
"testing"
"time"
"github.com/mickael-menu/zk/core/file"
"github.com/mickael-menu/zk/core/note"
"github.com/mickael-menu/zk/util"
"github.com/mickael-menu/zk/util/assert"
)
func TestNoteDAOIndexed(t *testing.T) {
testTransaction(t, func(tx Transaction) {
dao := NewNoteDAO(tx, "/test", &util.NullLogger)
expected := []file.Metadata{
{
Path: file.Path{Dir: "", Filename: "f39c8.md", Abs: "/test/f39c8.md"},
Modified: date("2020-01-20T08:52:42.321024+01:00"),
},
{
Path: file.Path{Dir: "", Filename: "index.md", Abs: "/test/index.md"},
Modified: date("2019-12-04T12:17:21.720747+01:00"),
},
{
Path: file.Path{Dir: "log", Filename: "2021-01-03.md", Abs: "/test/log/2021-01-03.md"},
Modified: date("2020-11-22T16:27:45.734454655+01:00"),
},
{
Path: file.Path{Dir: "log", Filename: "2021-01-04.md", Abs: "/test/log/2021-01-04.md"},
Modified: date("2020-11-29T08:20:18.138907236+01:00"),
},
{
Path: file.Path{Dir: "ref/test", Filename: "a.md", Abs: "/test/ref/test/a.md"},
Modified: date("2019-11-20T20:34:06.120375+01:00"),
},
{
Path: file.Path{Dir: "ref/test", Filename: "b.md", Abs: "/test/ref/test/b.md"},
Modified: date("2019-11-20T20:34:06.120375+01:00"),
},
}
c, err := dao.Indexed()
assert.Nil(t, err)
i := 0
for item := range c {
assert.Equal(t, item, expected[i])
i++
}
})
}
func TestNoteDAOAdd(t *testing.T) {
testTransaction(t, func(tx Transaction) {
dao := NewNoteDAO(tx, "/test", &util.NullLogger)
err := dao.Add(note.Metadata{
Path: file.Path{
Dir: "log",
Filename: "added.md",
Abs: "/test/log/added.md",
},
Title: "Added note",
Body: "Note body",
WordCount: 2,
Created: date("2019-11-19T15:33:31.467036963+01:00"),
Modified: date("2020-01-16T16:04:59.396405+01:00"),
Checksum: "check",
})
assert.Nil(t, err)
row, err := queryNoteRow(tx, `filename = "added.md"`)
assert.Nil(t, err)
assert.Equal(t, row, noteRow{
Dir: "log",
Filename: "added.md",
Title: "Added note",
Body: "Note body",
WordCount: 2,
Checksum: "check",
Created: date("2019-11-19T15:33:31.467036963+01:00"),
Modified: date("2020-01-16T16:04:59.396405+01:00"),
})
})
}
// Check that we can't add a duplicate note with an existing path.
func TestNoteDAOAddExistingNote(t *testing.T) {
testTransaction(t, func(tx Transaction) {
dao := NewNoteDAO(tx, "/test", &util.NullLogger)
err := dao.Add(note.Metadata{
Path: file.Path{
Dir: "ref/test",
Filename: "a.md",
},
})
assert.Err(t, err, "ref/test/a.md: can't add note to the index: UNIQUE constraint failed: notes.filename, notes.dir")
})
}
func TestNoteDAOUpdate(t *testing.T) {
testTransaction(t, func(tx Transaction) {
dao := NewNoteDAO(tx, "/test", &util.NullLogger)
err := dao.Update(note.Metadata{
Path: file.Path{
Dir: "ref/test",
Filename: "a.md",
Abs: "/test/log/added.md",
},
Title: "Updated note",
Body: "Updated body",
WordCount: 42,
Created: date("2020-11-22T16:49:47.309530098+01:00"),
Modified: date("2020-11-22T16:49:47.309769915+01:00"),
Checksum: "updated checksum",
})
assert.Nil(t, err)
row, err := queryNoteRow(tx, `dir = "ref/test" AND filename = "a.md"`)
assert.Nil(t, err)
assert.Equal(t, row, noteRow{
Dir: "ref/test",
Filename: "a.md",
Title: "Updated note",
Body: "Updated body",
WordCount: 42,
Checksum: "updated checksum",
Created: date("2019-11-20T20:32:56.107028961+01:00"),
Modified: date("2020-11-22T16:49:47.309769915+01:00"),
})
})
}
func TestNoteDAOUpdateUnknown(t *testing.T) {
testTransaction(t, func(tx Transaction) {
dao := NewNoteDAO(tx, "/test", &util.NullLogger)
err := dao.Update(note.Metadata{
Path: file.Path{
Dir: "unknown",
Filename: "unknown.md",
Abs: "/test/unknown/unknown.md",
},
})
assert.Err(t, err, "unknown/unknown.md: failed to update note index: note not found in the index")
})
}
func TestNoteDAORemove(t *testing.T) {
testTransaction(t, func(tx Transaction) {
dao := NewNoteDAO(tx, "/test", &util.NullLogger)
err := dao.Remove(file.Path{
Dir: "ref/test",
Filename: "a.md",
Abs: "/test/ref/test/a.md",
})
assert.Nil(t, err)
})
}
func TestNoteDAORemoveUnknown(t *testing.T) {
testTransaction(t, func(tx Transaction) {
dao := NewNoteDAO(tx, "/test", &util.NullLogger)
err := dao.Remove(file.Path{
Dir: "unknown",
Filename: "unknown.md",
Abs: "/test/unknown/unknown.md",
})
assert.Err(t, err, "unknown/unknown.md: failed to remove note index: note not found in the index")
})
}
type noteRow struct {
Dir, Filename, Title, Body, Checksum string
WordCount int
Created, Modified time.Time
}
func queryNoteRow(tx Transaction, where string) (noteRow, error) {
var row noteRow
err := tx.QueryRow(fmt.Sprintf(`
SELECT dir, filename, title, body, word_count, checksum, created, modified
FROM notes
WHERE %v
`, where)).Scan(&row.Dir, &row.Filename, &row.Title, &row.Body, &row.WordCount, &row.Checksum, &row.Created, &row.Modified)
return row, err
}
func date(s string) time.Time {
date, _ := time.Parse(time.RFC3339, s)
return date
}

@ -50,8 +50,8 @@ func (db *DB) Migrate() error {
`
CREATE TABLE IF NOT EXISTS notes (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
filename TEXT NOT NULL,
dir TEXT NOT NULL,
filename TEXT NOT NULL,
title TEXT DEFAULT('') NOT NULL,
body TEXT DEFAULT('') NOT NULL,
word_count INTEGER DEFAULT(0) NOT NULL,

@ -0,0 +1,59 @@
- id: 1
dir: "log"
filename: "2021-01-03.md"
title: "January 3, 2021"
body: "A daily note"
word_count: 3
checksum: "qwfpgj"
created: "2020-11-22T16:27:45.734392408+01:00"
modified: "2020-11-22T16:27:45.734454655+01:00"
- id: 2
dir: "log"
filename: "2021-01-04.md"
title: "January 4, 2021"
body: "A second daily note"
word_count: 4
checksum: "arstde"
created: "2020-11-29T08:20:18.138816226+01:00"
modified: "2020-11-29T08:20:18.138907236+01:00"
- id: 3
dir: ""
filename: "index.md"
title: "Index"
body: "Index of the Zettelkasten"
word_count: 4
checksum: "iaefhv"
created: "2019-12-04T11:59:11.927409053+01:00"
modified: "2019-12-04T12:17:21.720747+01:00"
- id: 4
dir: ""
filename: "f39c8.md"
title: "An interesting note"
body: "Its content will surprise you"
word_count: 5
checksum: "irkwyc"
created: "2020-01-19T10:58:41.567911029+01:00"
modified: "2020-01-20T08:52:42.321024+01:00"
- id: 5
dir: "ref/test"
filename: "b.md"
title: "A nested note"
body: "This one is in a sub sub directory"
word_count: 8
checksum: "yvwbae"
created: "2019-11-20T20:32:56.107028961+01:00"
modified: "2019-11-20T20:34:06.120375+01:00"
- id: 6
dir: "ref/test"
filename: "a.md"
title: "Another nested note"
body: "It shall appear before b.md"
word_count: 5
checksum: "iecywst"
created: "2019-11-20T20:32:56.107028961+01:00"
modified: "2019-11-20T20:34:06.120375+01:00"

@ -0,0 +1,34 @@
package sqlite
import (
"testing"
"github.com/go-testfixtures/testfixtures/v3"
"github.com/mickael-menu/zk/util/assert"
)
// testTransaction is an utility function used to test a SQLite transaction to
// the DB.
func testTransaction(t *testing.T, test func(tx Transaction)) {
db, err := OpenInMemory()
assert.Nil(t, err)
err = db.Migrate()
assert.Nil(t, err)
fixtures, err := testfixtures.New(
testfixtures.Database(db.db),
testfixtures.Dialect("sqlite"),
testfixtures.Directory("fixtures"),
// Necessary to work with an in-memory database.
testfixtures.DangerousSkipTestDatabaseCheck(),
)
assert.Nil(t, err)
err = fixtures.Load()
assert.Nil(t, err)
err = db.WithTransaction(func(tx Transaction) error {
test(tx)
return nil
})
assert.Nil(t, err)
}

@ -1,6 +1,9 @@
package file
import "time"
import (
"path/filepath"
"time"
)
// Metadata holds information about a slip box file.
type Metadata struct {
@ -27,3 +30,7 @@ func (p Path) Less(other Path) bool {
return p.Filename < other.Filename
}
}
func (p Path) String() string {
return filepath.Join(p.Dir, p.Filename)
}

@ -15,62 +15,29 @@ var root = fixtures.Path("walk")
func TestWalkRootDir(t *testing.T) {
dir := zk.Dir{Name: "", Path: root}
res := toSlice(Walk(dir, "md", &util.NullLogger))
assert.Equal(t, res, []Metadata{
{
Path: Path{Dir: "", Filename: "a.md", Abs: filepath.Join(root, "a.md")},
Modified: date("2021-01-03T11:30:26.069257899+01:00"),
},
{
Path: Path{Dir: "", Filename: "b.md", Abs: filepath.Join(root, "b.md")},
Modified: date("2021-01-03T11:30:27.545667767+01:00"),
},
{
Path: Path{Dir: "dir1", Filename: "a.md", Abs: filepath.Join(root, "dir1/a.md")},
Modified: date("2021-01-03T11:31:18.961628888+01:00"),
},
{
Path: Path{Dir: "dir1", Filename: "b.md", Abs: filepath.Join(root, "dir1/b.md")},
Modified: date("2021-01-03T11:31:24.692881103+01:00"),
},
{
Path: Path{Dir: "dir1/dir1", Filename: "a.md", Abs: filepath.Join(root, "dir1/dir1/a.md")},
Modified: date("2021-01-03T11:31:27.900472856+01:00"),
},
{
Path: Path{Dir: "dir2", Filename: "a.md", Abs: filepath.Join(root, "dir2/a.md")},
Modified: date("2021-01-03T11:31:51.001827456+01:00"),
},
testEqual(t, Walk(dir, "md", &util.NullLogger), []Path{
{Dir: "", Filename: "a.md", Abs: filepath.Join(root, "a.md")},
{Dir: "", Filename: "b.md", Abs: filepath.Join(root, "b.md")},
{Dir: "dir1", Filename: "a.md", Abs: filepath.Join(root, "dir1/a.md")},
{Dir: "dir1", Filename: "b.md", Abs: filepath.Join(root, "dir1/b.md")},
{Dir: "dir1/dir1", Filename: "a.md", Abs: filepath.Join(root, "dir1/dir1/a.md")},
{Dir: "dir2", Filename: "a.md", Abs: filepath.Join(root, "dir2/a.md")},
})
}
func TestWalkSubDir(t *testing.T) {
dir := zk.Dir{Name: "dir1", Path: filepath.Join(root, "dir1")}
res := toSlice(Walk(dir, "md", &util.NullLogger))
assert.Equal(t, res, []Metadata{
{
Path: Path{Dir: "dir1", Filename: "a.md", Abs: filepath.Join(root, "dir1/a.md")},
Modified: date("2021-01-03T11:31:18.961628888+01:00"),
},
{
Path: Path{Dir: "dir1", Filename: "b.md", Abs: filepath.Join(root, "dir1/b.md")},
Modified: date("2021-01-03T11:31:24.692881103+01:00"),
},
{
Path: Path{Dir: "dir1/dir1", Filename: "a.md", Abs: filepath.Join(root, "dir1/dir1/a.md")},
Modified: date("2021-01-03T11:31:27.900472856+01:00"),
},
testEqual(t, Walk(dir, "md", &util.NullLogger), []Path{
{Dir: "dir1", Filename: "a.md", Abs: filepath.Join(root, "dir1/a.md")},
{Dir: "dir1", Filename: "b.md", Abs: filepath.Join(root, "dir1/b.md")},
{Dir: "dir1/dir1", Filename: "a.md", Abs: filepath.Join(root, "dir1/dir1/a.md")},
})
}
func TestWalkSubSubDir(t *testing.T) {
dir := zk.Dir{Name: "dir1/dir1", Path: filepath.Join(root, "dir1/dir1")}
res := toSlice(Walk(dir, "md", &util.NullLogger))
assert.Equal(t, res, []Metadata{
{
Path: Path{Dir: "dir1/dir1", Filename: "a.md", Abs: filepath.Join(root, "dir1/dir1/a.md")},
Modified: date("2021-01-03T11:31:27.900472856+01:00"),
},
testEqual(t, Walk(dir, "md", &util.NullLogger), []Path{
{Dir: "dir1/dir1", Filename: "a.md", Abs: filepath.Join(root, "dir1/dir1/a.md")},
})
}
@ -79,10 +46,27 @@ func date(s string) time.Time {
return date
}
func toSlice(c <-chan Metadata) []Metadata {
s := make([]Metadata, 0)
for fm := range c {
s = append(s, fm)
func testEqual(t *testing.T, actual <-chan Metadata, expected []Path) {
popExpected := func() (Path, bool) {
if len(expected) == 0 {
return Path{}, false
}
item := expected[0]
expected = expected[1:]
return item, true
}
for act := range actual {
exp, ok := popExpected()
if !ok {
t.Errorf("More paths available than expected")
return
}
assert.Equal(t, act.Path, exp)
assert.NotNil(t, act.Modified)
}
if len(expected) > 0 {
t.Errorf("Missing expected paths: %v", expected)
}
return s
}

@ -5,12 +5,16 @@ go 1.15
require (
github.com/alecthomas/kong v0.2.12
github.com/aymerick/raymond v2.0.2+incompatible
github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect
github.com/go-testfixtures/testfixtures/v3 v3.4.1
github.com/google/go-cmp v0.3.1
github.com/gosimple/slug v1.9.0
github.com/hashicorp/hcl/v2 v2.8.1
github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/lestrrat-go/strftime v1.0.3
github.com/mattn/go-sqlite3 v1.14.6
github.com/tebeka/strftime v0.1.5 // indirect
gopkg.in/djherbis/times.v1 v1.2.0
gopkg.in/yaml.v2 v2.4.0 // indirect
)

114
go.sum

@ -1,7 +1,9 @@
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/alecthomas/kong v0.2.12 h1:X3kkCOXGUNzLmiu+nQtoxWqj4U2a39MpSJR3QdQXOwI=
github.com/alecthomas/kong v0.2.12/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0=
github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk=
@ -9,30 +11,93 @@ github.com/apparentlymart/go-textseg/v12 v12.0.0 h1:bNEQyAGak9tojivJNkoqWErVCQbj
github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
github.com/aymerick/raymond v2.0.2+incompatible h1:VEp3GpgdAnv9B2GFyTvqgcKvY+mfKMjPOA3SbKLtnU0=
github.com/aymerick/raymond v2.0.2+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 h1:Ghm4eQYC0nEPnSJdVkTrXpu9KtoVCSo1hg7mtI7G9KU=
github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239/go.mod h1:Gdwt2ce0yfBxPvZrHkprdPPTTS3N5rwmLE8T22KBXlw=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-testfixtures/testfixtures v1.7.0 h1:a6HVQ3jYe0lm1H+T1ryt2fOwF1P5OGJs9SIZG9Ne1J0=
github.com/go-testfixtures/testfixtures v2.5.1+incompatible h1:IBJp7NQjfdUHc4+gDH0j1e76LilPeMZuvm/oEUhDwxo=
github.com/go-testfixtures/testfixtures/v3 v3.4.1 h1:Qz9y0wUOXPHzKhK6C79A/menChtEu/xd0Dn5ngVyMD0=
github.com/go-testfixtures/testfixtures/v3 v3.4.1/go.mod h1:P4L3WxgOsCLbAeUC50qX5rdj1ULZfUMqgCbqah3OH5U=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/gosimple/slug v1.9.0 h1:r5vDcYrFz9BmfIAMC829un9hq7hKM4cHUrsv36LbEqs=
github.com/gosimple/slug v1.9.0/go.mod h1:AMZ+sOVe65uByN3kgEyf9WEBKBCSS+dJjMX9x4vDJbg=
github.com/hashicorp/hcl/v2 v2.8.1 h1:FJ60CIYaMyJOKzPndhMyjiz353Fd+2jr6PodF5Xzb08=
github.com/hashicorp/hcl/v2 v2.8.1/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.3.0/go.mod h1:b0JqxHvPmljG+HQ5IsvQ0yqeSi4nGcDTVjFoiLDb0Ik=
github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.6.0/go.mod h1:vPh43ZzxijXUVJ+t/EmXBtFmbFVO72cuneCT9oAlxAg=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4=
github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8=
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is=
github.com/lestrrat-go/strftime v1.0.3 h1:qqOPU7y+TM8Y803I8fG9c/DyKG3xH/xkng6keC1015Q=
github.com/lestrrat-go/strftime v1.0.3/go.mod h1:E1nN3pCbtMSu1yjSVeyuRFVm/U0xoR76fd03sz+Qz4g=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
@ -43,34 +108,83 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be h1:ta7tUOvsPHVHGom5hKW5VXNc2xZIkfCKP8iaqOyYtUQ=
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/tebeka/strftime v0.1.5 h1:1NQKN1NiQgkqd/2moD6ySP/5CoZQsKa1d3ZhJ44Jpmg=
github.com/tebeka/strftime v0.1.5/go.mod h1:29/OidkoWHdEKZqzyDLUyC+LmgDgdHo4WAFCDT7D/Ig=
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/zclconf/go-cty v1.2.0 h1:sPHsy7ADcIZQP3vILvTjrh74ZA175TFP5vqiNK1UmlI=
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/djherbis/times.v1 v1.2.0 h1:UCvDKl1L/fmBygl2Y7hubXCnY7t4Yj46ZrBFNUipFbM=
gopkg.in/djherbis/times.v1 v1.2.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

@ -5,6 +5,8 @@ import (
"reflect"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
)
func Nil(t *testing.T, value interface{}) {
@ -25,7 +27,7 @@ func isNil(value interface{}) bool {
}
func Equal(t *testing.T, actual, expected interface{}) {
if !reflect.DeepEqual(actual, expected) {
if !(reflect.DeepEqual(actual, expected) || cmp.Equal(actual, expected)) {
t.Errorf("Received (type %v):\n%+v\n---\nBut expected (type %v):\n%+v", reflect.TypeOf(actual), toJSON(t, actual), reflect.TypeOf(expected), toJSON(t, expected))
}
}

@ -1,6 +1,7 @@
package errors
import (
"errors"
"fmt"
)
@ -24,3 +25,7 @@ func Wrap(err error, msg string) error {
}
return fmt.Errorf("%s: %w", msg, err)
}
func New(text string) error {
return errors.New(text)
}

Loading…
Cancel
Save