├── .github
└── workflows
│ ├── standard-go-test.yml
│ └── standard-stale.yml
├── .gitignore
├── LICENSE
├── README.md
├── SHOULDERS.md
├── fix
├── fix.go
├── fix_test.go
├── init-context-fixtures
│ └── contextsample.toml
├── init-fixtures
│ └── sample.toml
├── plush.go
├── plush_test.go
└── scenario.go
├── go.mod
├── go.sum
├── model.go
├── session.go
├── suite.go
├── suite_test.go
└── version.go
/.github/workflows/standard-go-test.yml:
--------------------------------------------------------------------------------
1 | name: Standard Test
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 |
8 | jobs:
9 | call-standard-test:
10 | name: Test
11 | uses: gobuffalo/.github/.github/workflows/go-test.yml@v1
12 | secrets: inherit
13 |
--------------------------------------------------------------------------------
/.github/workflows/standard-stale.yml:
--------------------------------------------------------------------------------
1 | name: Standard Autocloser
2 |
3 | on:
4 | schedule:
5 | - cron: "30 1 * * *"
6 |
7 | jobs:
8 | call-standard-autocloser:
9 | name: Autocloser
10 | uses: gobuffalo/.github/.github/workflows/stale.yml@v1
11 | secrets: inherit
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | .DS_Store
3 | doc
4 | tmp
5 | pkg
6 | *.gem
7 | *.pid
8 | coverage
9 | coverage.data
10 | build/*
11 | *.pbxuser
12 | *.mode1v3
13 | .svn
14 | profile
15 | .console_history
16 | .sass-cache/*
17 | .rake_tasks~
18 | *.log.lck
19 | solr/
20 | .jhw-cache/
21 | jhw.*
22 | *.sublime*
23 | node_modules/
24 | dist/
25 | generated/
26 | .vendor/
27 | bin/*
28 | gin-bin
29 | .idea/
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2019 Mark Bates
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Suite
2 |
3 | [](https://github.com/gobuffalo/suite/actions/workflows/standard-go-test.yml)
4 | [](https://pkg.go.dev/github.com/gobuffalo/suite/v4)
5 |
6 | Suite is a package meant to make testing [gobuffalo.io](http://gobuffalo.io) applications easier.
7 |
8 | ## Setup
9 |
10 | This is the entry point into your unit testing suite. The `Test_ActionSuite(t *testing.T)` function is
11 | compatible with the `go test` command, and it should:
12 |
13 | - Create and configure your new test suite instance (`ActionSuite` in this case)
14 | - Call `suite.Run` with the `*testing.T` passed by the Go testing system, and your new `ActionSuite` instance
15 |
16 | ```go
17 | package actions_test
18 |
19 | import (
20 | "testing"
21 |
22 | "github.com/gobuffalo/suite/v4"
23 | "github.com/gobuffalo/toodo/actions"
24 | )
25 |
26 | type ActionSuite struct {
27 | *suite.Action
28 | }
29 |
30 | func Test_ActionSuite(t *testing.T) {
31 | as := &ActionSuite{suite.NewAction(actions.App())}
32 | suite.Run(t, as)
33 | }
34 | ```
35 |
36 | ## Usage
37 |
38 | This is where you write your actual test logic. The rules for test names are similar, but not the same, as with `go test`:
39 |
40 | - Each test is a method on your `*ActionSuite`
41 | - Test method names should start with `Test` (note the upper case `T`)
42 | - Test methods should have no arguments
43 |
44 | A few additional notes:
45 |
46 | - To avoid race conditions on the testing database, always use the `ActionSuite` variable called `DB` to access the database (not your production app's database)
47 | - You can access the raw `*testing.T` value if needed with `as.T()`
48 | - `ActionSuite` has support for [`testify`](https://github.com/stretchr/testify)'s [`require` package](https://godoc.org/github.com/stretchr/testify/require) and [`assert` package](https://godoc.org/github.com/stretchr/testify/assert)
49 | - ... So try to use one of those instead packages of using the raw methods on the `*testing.T`
50 | - The default database that `suite` will connect to is called `testing` in your [database.yml](https://github.com/markbates/pop#connecting-to-databases)
51 |
52 | ```go
53 | package actions_test
54 |
55 | import (
56 | "fmt"
57 |
58 | "github.com/gobuffalo/toodo/models"
59 | )
60 |
61 | func (as *ActionSuite) Test_TodosResource_List() {
62 | todos := models.Todos{
63 | {Title: "buy milk"},
64 | {Title: "read a good book"},
65 | }
66 | for _, t := range todos {
67 | err := as.DB.Create(&t)
68 | as.NoError(err)
69 | }
70 |
71 | res := as.HTML("/todos").Get()
72 | body := res.Body.String()
73 | for _, t := range todos {
74 | as.Contains(body, fmt.Sprintf("
%s
", t.Title))
75 | }
76 | }
77 |
78 | func (as *ActionSuite) Test_TodosResource_New() {
79 | res := as.HTML("/todos/new").Get()
80 | as.Contains(res.Body.String(), "New Todo
")
81 | }
82 |
83 | func (as *ActionSuite) Test_TodosResource_Create() {
84 | todo := &models.Todo{Title: "Learn Go"}
85 | res := as.HTML("/todos").Post(todo)
86 | as.Equal(301, res.Code)
87 | as.Equal("/todos", res.Location())
88 |
89 | err := as.DB.First(todo)
90 | as.NoError(err)
91 | as.NotZero(todo.ID)
92 | as.NotZero(todo.CreatedAt)
93 | as.Equal("Learn Go", todo.Title)
94 | }
95 |
96 | func (as *ActionSuite) Test_TodosResource_Create_Errors() {
97 | todo := &models.Todo{}
98 | res := as.HTML("/todos").Post(todo)
99 | as.Equal(422, res.Code)
100 | as.Contains(res.Body.String(), "Title can not be blank.")
101 |
102 | c, err := as.DB.Count(todo)
103 | as.NoError(err)
104 | as.Equal(0, c)
105 | }
106 |
107 | func (as *ActionSuite) Test_TodosResource_Update() {
108 | todo := &models.Todo{Title: "Lern Go"}
109 | verrs, err := as.DB.ValidateAndCreate(todo)
110 | as.NoError(err)
111 | as.False(verrs.HasAny())
112 |
113 | res := as.HTML("/todos/%s", todo.ID).Put(&models.Todo{ID: todo.ID, Title: "Learn Go"})
114 | as.Equal(200, res.Code)
115 |
116 | err = as.DB.Reload(todo)
117 | as.NoError(err)
118 | as.Equal("Learn Go", todo.Title)
119 | }
120 | ```
121 |
122 | ## Fixtures (Test Data)
123 |
124 | Often it is useful to load a series of data into the database at the start of the test to make testing easier. For example, you need to have a user in the database to log a person into the application, or you need some data in the database to test destroying that data. Fixtures let us solve these problems easily.
125 |
126 | ### Using Fixtures
127 |
128 | First you need to setup your test suite to use fixtures. You can do this by using `suite.NewActionWithFixtures` or `suite.NewModelWithFixtures` methods to create new test suites that take an `fs.FS` pointing to where the files for this suite live.
129 |
130 | ```go
131 | package actions
132 |
133 | import (
134 | "os"
135 | "testing"
136 |
137 | "github.com/gobuffalo/suite/v4"
138 | )
139 |
140 | type ActionSuite struct {
141 | *suite.Action
142 | }
143 |
144 | func Test_ActionSuite(t *testing.T) {
145 | action, err := suite.NewActionWithFixtures(App(), os.DirFS("../fixtures"))
146 | if err != nil {
147 | t.Fatal(err)
148 | }
149 |
150 | as := &ActionSuite{
151 | Action: action,
152 | }
153 | suite.Run(t, as)
154 | }
155 | ```
156 |
157 | Once your suite is set up, you can create `N` numbers of `*.toml` files in the directory you've chosen for your fixtures, in this example, `../fixtures`.
158 |
159 | ### Example Fixture File
160 |
161 | ```toml
162 | [[scenario]]
163 | name = "lots of widgets"
164 |
165 | [[scenario.table]]
166 | name = "widgets"
167 |
168 | [[scenario.table.row]]
169 | id = "<%= uuidNamed("widget") %>"
170 | name = "This is widget #1"
171 | body = "some widget body"
172 | created_at = "<%= now() %>"
173 | updated_at = "<%= now() %>"
174 |
175 | [[scenario.table.row]]
176 | id = "<%= uuid() %>"
177 | name = "This is widget #2"
178 | body = "some widget body"
179 | created_at = "<%= now() %>"
180 | updated_at = "<%= now() %>"
181 |
182 | [[scenario.table]]
183 | name = "users"
184 |
185 | [[scenario.table.row]]
186 | id = "<%= uuid() %>"
187 | name = "Mark Bates"
188 | admin = true
189 | price = 19.99
190 | widget_id = "<%= uuidNamed("widget") %>"
191 | created_at = "<%= now() %>"
192 | updated_at = "<%= now() %>"
193 | ```
194 |
195 | #### Helper Methods
196 |
197 | The `*.toml` files all get run through [https://github.com/gobuffalo/plush](https://github.com/gobuffalo/plush) before they're decoded, so you can make use of the helpful helper methods that ship with Plush.
198 |
199 | We've also add a couple of useful helpers for you as well:
200 |
201 | - `uuid()` - returns a new `github.com/gobuffalo/uuid.UUID`
202 | - `now()` - returns `time.Now()`
203 | - `nowAdd(s)` and `nowSub(s)` - similar to `now()` but `s` amount of seconds is added or substracted, respectively, from the return value
204 | - `uuidNamed(name)` - will attempt to return a previously declared UUID with that name, useful, for relations/associations. If there was one that wasn't defined with that name, a new one will be created.
205 | - `hash(string, opts)` - will create the hashed value of the string (useful for creating a password), you can define the cost as an opts (the default is `bcrypt.DefaultCost`)
206 |
207 | ### Using in Tests
208 |
209 | In your suite tests you need to call the `LoadFixture` method giving it the name of the fixtures you would like to use for this test.
210 |
211 | ```go
212 | func (as *ActionSuite) Test_WidgetsResource_List() {
213 | as.LoadFixture("lots of widgets")
214 | res := as.HTML("/widgets").Get()
215 |
216 | body := res.Body.String()
217 | as.Contains(body, "widget #1")
218 | as.Contains(body, "widget #2")
219 | }
220 | ```
221 |
222 | ### FAQs
223 |
224 | - _Can I call `LoadFixture` more than once in a test?_ - Absolutely! Call it as many times as you want!
225 | - _Can I load multiple rows into a table in one scenario?_ - Absolutely!
226 | - _Can I load data into multiple tables in one scenario?_ - Absolutely!
227 | - _Will it load all my fixtures?_ - No, you have to load specific scenarios, so don't be afraid to create lots of scenarios and only call the ones you need per test.
228 | - _Will this pollute my database, and how do I clear data between tests?_ - No need to worry, the suite will truncate any data in your database between test runs, so you never have to worry about it.
229 |
--------------------------------------------------------------------------------
/SHOULDERS.md:
--------------------------------------------------------------------------------
1 | # Suite Stands on the Shoulders of Giants
2 |
3 | Suite does not try to reinvent the wheel! Instead, it uses the already great wheels developed by the Go community and puts them all together in the best way possible. Without these giants, this project would not be possible. Please make sure to check them out and thank them for all of their hard work.
4 |
5 | Thank you to the following **GIANTS**:
6 |
7 | * [github.com/BurntSushi/toml](https://godoc.org/github.com/BurntSushi/toml)
8 | * [github.com/Masterminds/semver/v3](https://godoc.org/github.com/Masterminds/semver/v3)
9 | * [github.com/aymerick/douceur](https://godoc.org/github.com/aymerick/douceur)
10 | * [github.com/cockroachdb/apd](https://godoc.org/github.com/cockroachdb/apd)
11 | * [github.com/coreos/go-systemd](https://godoc.org/github.com/coreos/go-systemd)
12 | * [github.com/cpuguy83/go-md2man/v2](https://godoc.org/github.com/cpuguy83/go-md2man/v2)
13 | * [github.com/creack/pty](https://godoc.org/github.com/creack/pty)
14 | * [github.com/davecgh/go-spew](https://godoc.org/github.com/davecgh/go-spew)
15 | * [github.com/dustin/go-humanize](https://godoc.org/github.com/dustin/go-humanize)
16 | * [github.com/fatih/color](https://godoc.org/github.com/fatih/color)
17 | * [github.com/fatih/structs](https://godoc.org/github.com/fatih/structs)
18 | * [github.com/felixge/httpsnoop](https://godoc.org/github.com/felixge/httpsnoop)
19 | * [github.com/fsnotify/fsnotify](https://godoc.org/github.com/fsnotify/fsnotify)
20 | * [github.com/go-kit/log](https://godoc.org/github.com/go-kit/log)
21 | * [github.com/go-logfmt/logfmt](https://godoc.org/github.com/go-logfmt/logfmt)
22 | * [github.com/go-sql-driver/mysql](https://godoc.org/github.com/go-sql-driver/mysql)
23 | * [github.com/go-stack/stack](https://godoc.org/github.com/go-stack/stack)
24 | * [github.com/gobuffalo/attrs](https://godoc.org/github.com/gobuffalo/attrs)
25 | * [github.com/gobuffalo/buffalo](https://godoc.org/github.com/gobuffalo/buffalo)
26 | * [github.com/gobuffalo/envy](https://godoc.org/github.com/gobuffalo/envy)
27 | * [github.com/gobuffalo/events](https://godoc.org/github.com/gobuffalo/events)
28 | * [github.com/gobuffalo/fizz](https://godoc.org/github.com/gobuffalo/fizz)
29 | * [github.com/gobuffalo/flect](https://godoc.org/github.com/gobuffalo/flect)
30 | * [github.com/gobuffalo/genny/v2](https://godoc.org/github.com/gobuffalo/genny/v2)
31 | * [github.com/gobuffalo/github_flavored_markdown](https://godoc.org/github.com/gobuffalo/github_flavored_markdown)
32 | * [github.com/gobuffalo/grift](https://godoc.org/github.com/gobuffalo/grift)
33 | * [github.com/gobuffalo/helpers](https://godoc.org/github.com/gobuffalo/helpers)
34 | * [github.com/gobuffalo/here](https://godoc.org/github.com/gobuffalo/here)
35 | * [github.com/gobuffalo/httptest](https://godoc.org/github.com/gobuffalo/httptest)
36 | * [github.com/gobuffalo/logger](https://godoc.org/github.com/gobuffalo/logger)
37 | * [github.com/gobuffalo/meta](https://godoc.org/github.com/gobuffalo/meta)
38 | * [github.com/gobuffalo/middleware](https://godoc.org/github.com/gobuffalo/middleware)
39 | * [github.com/gobuffalo/nulls](https://godoc.org/github.com/gobuffalo/nulls)
40 | * [github.com/gobuffalo/packd](https://godoc.org/github.com/gobuffalo/packd)
41 | * [github.com/gobuffalo/plush/v4](https://godoc.org/github.com/gobuffalo/plush/v4)
42 | * [github.com/gobuffalo/pop/v6](https://godoc.org/github.com/gobuffalo/pop/v6)
43 | * [github.com/gobuffalo/refresh](https://godoc.org/github.com/gobuffalo/refresh)
44 | * [github.com/gobuffalo/tags/v3](https://godoc.org/github.com/gobuffalo/tags/v3)
45 | * [github.com/gobuffalo/validate/v3](https://godoc.org/github.com/gobuffalo/validate/v3)
46 | * [github.com/gofrs/uuid](https://godoc.org/github.com/gofrs/uuid)
47 | * [github.com/google/go-cmp](https://godoc.org/github.com/google/go-cmp)
48 | * [github.com/google/renameio](https://godoc.org/github.com/google/renameio)
49 | * [github.com/gorilla/css](https://godoc.org/github.com/gorilla/css)
50 | * [github.com/gorilla/handlers](https://godoc.org/github.com/gorilla/handlers)
51 | * [github.com/gorilla/mux](https://godoc.org/github.com/gorilla/mux)
52 | * [github.com/gorilla/securecookie](https://godoc.org/github.com/gorilla/securecookie)
53 | * [github.com/gorilla/sessions](https://godoc.org/github.com/gorilla/sessions)
54 | * [github.com/inconshreveable/mousetrap](https://godoc.org/github.com/inconshreveable/mousetrap)
55 | * [github.com/jackc/chunkreader](https://godoc.org/github.com/jackc/chunkreader)
56 | * [github.com/jackc/chunkreader/v2](https://godoc.org/github.com/jackc/chunkreader/v2)
57 | * [github.com/jackc/pgconn](https://godoc.org/github.com/jackc/pgconn)
58 | * [github.com/jackc/pgio](https://godoc.org/github.com/jackc/pgio)
59 | * [github.com/jackc/pgmock](https://godoc.org/github.com/jackc/pgmock)
60 | * [github.com/jackc/pgpassfile](https://godoc.org/github.com/jackc/pgpassfile)
61 | * [github.com/jackc/pgproto3](https://godoc.org/github.com/jackc/pgproto3)
62 | * [github.com/jackc/pgproto3/v2](https://godoc.org/github.com/jackc/pgproto3/v2)
63 | * [github.com/jackc/pgservicefile](https://godoc.org/github.com/jackc/pgservicefile)
64 | * [github.com/jackc/pgtype](https://godoc.org/github.com/jackc/pgtype)
65 | * [github.com/jackc/pgx/v4](https://godoc.org/github.com/jackc/pgx/v4)
66 | * [github.com/jackc/puddle](https://godoc.org/github.com/jackc/puddle)
67 | * [github.com/jmoiron/sqlx](https://godoc.org/github.com/jmoiron/sqlx)
68 | * [github.com/joho/godotenv](https://godoc.org/github.com/joho/godotenv)
69 | * [github.com/kballard/go-shellquote](https://godoc.org/github.com/kballard/go-shellquote)
70 | * [github.com/kisielk/gotool](https://godoc.org/github.com/kisielk/gotool)
71 | * [github.com/konsorten/go-windows-terminal-sequences](https://godoc.org/github.com/konsorten/go-windows-terminal-sequences)
72 | * [github.com/kr/pretty](https://godoc.org/github.com/kr/pretty)
73 | * [github.com/kr/pty](https://godoc.org/github.com/kr/pty)
74 | * [github.com/kr/text](https://godoc.org/github.com/kr/text)
75 | * [github.com/lib/pq](https://godoc.org/github.com/lib/pq)
76 | * [github.com/luna-duclos/instrumentedsql](https://godoc.org/github.com/luna-duclos/instrumentedsql)
77 | * [github.com/mattn/go-colorable](https://godoc.org/github.com/mattn/go-colorable)
78 | * [github.com/mattn/go-isatty](https://godoc.org/github.com/mattn/go-isatty)
79 | * [github.com/mattn/go-sqlite3](https://godoc.org/github.com/mattn/go-sqlite3)
80 | * [github.com/microcosm-cc/bluemonday](https://godoc.org/github.com/microcosm-cc/bluemonday)
81 | * [github.com/mitchellh/go-homedir](https://godoc.org/github.com/mitchellh/go-homedir)
82 | * [github.com/monoculum/formam](https://godoc.org/github.com/monoculum/formam)
83 | * [github.com/nicksnyder/go-i18n](https://godoc.org/github.com/nicksnyder/go-i18n)
84 | * [github.com/pelletier/go-toml](https://godoc.org/github.com/pelletier/go-toml)
85 | * [github.com/pkg/diff](https://godoc.org/github.com/pkg/diff)
86 | * [github.com/pkg/errors](https://godoc.org/github.com/pkg/errors)
87 | * [github.com/pmezard/go-difflib](https://godoc.org/github.com/pmezard/go-difflib)
88 | * [github.com/psanford/memfs](https://godoc.org/github.com/psanford/memfs)
89 | * [github.com/rogpeppe/go-internal](https://godoc.org/github.com/rogpeppe/go-internal)
90 | * [github.com/rs/xid](https://godoc.org/github.com/rs/xid)
91 | * [github.com/rs/zerolog](https://godoc.org/github.com/rs/zerolog)
92 | * [github.com/russross/blackfriday/v2](https://godoc.org/github.com/russross/blackfriday/v2)
93 | * [github.com/satori/go.uuid](https://godoc.org/github.com/satori/go.uuid)
94 | * [github.com/sergi/go-diff](https://godoc.org/github.com/sergi/go-diff)
95 | * [github.com/shopspring/decimal](https://godoc.org/github.com/shopspring/decimal)
96 | * [github.com/sirupsen/logrus](https://godoc.org/github.com/sirupsen/logrus)
97 | * [github.com/sourcegraph/annotate](https://godoc.org/github.com/sourcegraph/annotate)
98 | * [github.com/sourcegraph/syntaxhighlight](https://godoc.org/github.com/sourcegraph/syntaxhighlight)
99 | * [github.com/spf13/cobra](https://godoc.org/github.com/spf13/cobra)
100 | * [github.com/spf13/pflag](https://godoc.org/github.com/spf13/pflag)
101 | * [github.com/stretchr/objx](https://godoc.org/github.com/stretchr/objx)
102 | * [github.com/stretchr/testify](https://godoc.org/github.com/stretchr/testify)
103 | * [github.com/unrolled/secure](https://godoc.org/github.com/unrolled/secure)
104 | * [github.com/yuin/goldmark](https://godoc.org/github.com/yuin/goldmark)
105 | * [github.com/zenazn/goji](https://godoc.org/github.com/zenazn/goji)
106 | * [go.uber.org/atomic](https://godoc.org/go.uber.org/atomic)
107 | * [go.uber.org/multierr](https://godoc.org/go.uber.org/multierr)
108 | * [go.uber.org/tools](https://godoc.org/go.uber.org/tools)
109 | * [go.uber.org/zap](https://godoc.org/go.uber.org/zap)
110 | * [golang.org/x/crypto](https://godoc.org/golang.org/x/crypto)
111 | * [golang.org/x/lint](https://godoc.org/golang.org/x/lint)
112 | * [golang.org/x/mod](https://godoc.org/golang.org/x/mod)
113 | * [golang.org/x/net](https://godoc.org/golang.org/x/net)
114 | * [golang.org/x/sync](https://godoc.org/golang.org/x/sync)
115 | * [golang.org/x/sys](https://godoc.org/golang.org/x/sys)
116 | * [golang.org/x/term](https://godoc.org/golang.org/x/term)
117 | * [golang.org/x/text](https://godoc.org/golang.org/x/text)
118 | * [golang.org/x/tools](https://godoc.org/golang.org/x/tools)
119 | * [golang.org/x/xerrors](https://godoc.org/golang.org/x/xerrors)
120 | * [gopkg.in/check.v1](https://godoc.org/gopkg.in/check.v1)
121 | * [gopkg.in/errgo.v2](https://godoc.org/gopkg.in/errgo.v2)
122 | * [gopkg.in/inconshreveable/log15.v2](https://godoc.org/gopkg.in/inconshreveable/log15.v2)
123 | * [gopkg.in/yaml.v2](https://godoc.org/gopkg.in/yaml.v2)
124 | * [gopkg.in/yaml.v3](https://godoc.org/gopkg.in/yaml.v3)
125 | * [honnef.co/go/tools](https://godoc.org/honnef.co/go/tools)
126 |
--------------------------------------------------------------------------------
/fix/fix.go:
--------------------------------------------------------------------------------
1 | package fix
2 |
3 | import (
4 | "fmt"
5 | "io/fs"
6 | "path/filepath"
7 | "sync"
8 |
9 | "github.com/BurntSushi/toml"
10 | "github.com/gobuffalo/plush/v4"
11 | )
12 |
13 | var scenes = map[string]Scenario{}
14 | var moot = &sync.RWMutex{}
15 |
16 | func InitWithContext(fsys fs.FS, ctx *plush.Context) error {
17 | err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
18 | if err != nil {
19 | return err
20 | }
21 |
22 | if d.IsDir() {
23 | return nil
24 | }
25 |
26 | if filepath.Ext(d.Name()) != ".toml" {
27 | return nil
28 | }
29 |
30 | f, err := fsys.Open(path)
31 | if err != nil {
32 | return err
33 | }
34 |
35 | x, err := renderWithContext(f, ctx)
36 | if err != nil {
37 | return err
38 | }
39 |
40 | sc := Scenarios{}
41 | _, err = toml.Decode(x, &sc)
42 | if err != nil {
43 | return err
44 | }
45 |
46 | moot.Lock()
47 | for _, s := range sc.Scenarios {
48 | scenes[s.Name] = s
49 | }
50 | moot.Unlock()
51 | return nil
52 | })
53 | return err
54 | }
55 |
56 | func Init(fsys fs.FS) error {
57 | err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
58 | if err != nil {
59 | return err
60 | }
61 |
62 | if d.IsDir() {
63 | return nil
64 | }
65 |
66 | if filepath.Ext(d.Name()) != ".toml" {
67 | return nil
68 | }
69 |
70 | f, err := fsys.Open(path)
71 | if err != nil {
72 | return err
73 | }
74 |
75 | x, err := render(f)
76 | if err != nil {
77 | return err
78 | }
79 |
80 | sc := Scenarios{}
81 | _, err = toml.Decode(x, &sc)
82 | if err != nil {
83 | return err
84 | }
85 |
86 | moot.Lock()
87 | for _, s := range sc.Scenarios {
88 | scenes[s.Name] = s
89 | }
90 | moot.Unlock()
91 | return nil
92 | })
93 | return err
94 | }
95 |
96 | func Find(name string) (Scenario, error) {
97 | moot.RLock()
98 | s, ok := scenes[name]
99 | moot.RUnlock()
100 | if !ok {
101 | return Scenario{}, fmt.Errorf("could not find a scenario named %q", name)
102 | }
103 | return s, nil
104 | }
105 |
--------------------------------------------------------------------------------
/fix/fix_test.go:
--------------------------------------------------------------------------------
1 | package fix
2 |
3 | import (
4 | "os"
5 | "testing"
6 |
7 | "github.com/gobuffalo/plush/v4"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func Test_Init_And_Find(t *testing.T) {
12 | r := require.New(t)
13 |
14 | fsys := os.DirFS("./init-fixtures")
15 | r.NoError(Init(fsys))
16 |
17 | s, err := Find("lots of widgets")
18 | r.NoError(err)
19 | r.Equal("lots of widgets", s.Name)
20 |
21 | r.Len(s.Tables, 2)
22 |
23 | table := s.Tables[0]
24 | r.Equal("widgets", table.Name)
25 | r.Len(table.Row, 3)
26 |
27 | row := table.Row[0]
28 | r.NotZero(row["id"])
29 | r.NotZero(row["created_at"])
30 | r.NotZero(row["updated_at"])
31 | r.Equal("This is widget #1", row["name"])
32 | r.Equal("some widget body", row["body"])
33 |
34 | wid := row["id"]
35 |
36 | row = table.Row[1]
37 | r.NotZero(row["id"])
38 | r.NotZero(row["created_at"])
39 | r.NotZero(row["updated_at"])
40 | r.Equal("This is widget #2", row["name"])
41 | r.Equal("some widget body", row["body"])
42 |
43 | row = table.Row[2]
44 | r.NotZero(row["id"])
45 | r.NotZero(row["created_at"])
46 | r.NotZero(row["updated_at"])
47 | r.Equal("This is widget #3", row["name"])
48 | r.Equal("some widget body", row["body"])
49 |
50 | table = s.Tables[1]
51 | r.Equal("users", table.Name)
52 | r.Len(table.Row, 1)
53 |
54 | row = table.Row[0]
55 | r.NotZero(row["id"])
56 | r.NotZero(row["created_at"])
57 | r.NotZero(row["updated_at"])
58 | r.True(row["admin"].(bool))
59 | r.Equal(19.99, row["price"].(float64))
60 | r.Equal(wid, row["widget_id"])
61 | }
62 |
63 | func Test_InitWithContext_And_Find_CustomConfig(t *testing.T) {
64 | r := require.New(t)
65 |
66 | fsys := os.DirFS("./init-context-fixtures")
67 | ctx := plush.NewContextWith(map[string]interface{}{
68 | "double": func(num int, help plush.HelperContext) int {
69 | return num * 2
70 | },
71 | })
72 | r.NoError(InitWithContext(fsys, ctx))
73 |
74 | s, err := Find("widget with context")
75 | r.NoError(err)
76 | r.Equal("widget with context", s.Name)
77 |
78 | r.Len(s.Tables, 2)
79 |
80 | table := s.Tables[0]
81 | r.Equal("widgets", table.Name)
82 | r.Len(table.Row, 2)
83 |
84 | row := table.Row[0]
85 | r.NotZero(row["id"])
86 | r.NotZero(row["created_at"])
87 | r.NotZero(row["updated_at"])
88 | r.Equal("This is widget #1", row["name"])
89 | r.Equal("some widget body", row["body"])
90 |
91 | wid := row["id"]
92 |
93 | row = table.Row[1]
94 | r.NotZero(row["id"])
95 | r.NotZero(row["created_at"])
96 | r.NotZero(row["updated_at"])
97 | r.Equal("This is widget #2", row["name"])
98 | r.Equal("some widget body", row["body"])
99 |
100 | table = s.Tables[1]
101 | r.Equal("users", table.Name)
102 | r.Len(table.Row, 1)
103 |
104 | row = table.Row[0]
105 | r.NotZero(row["id"])
106 | r.NotZero(row["created_at"])
107 | r.NotZero(row["updated_at"])
108 | r.True(row["admin"].(bool))
109 | r.Equal(int64(36), row["price"].(int64))
110 | r.Equal(wid, row["widget_id"])
111 | }
112 |
--------------------------------------------------------------------------------
/fix/init-context-fixtures/contextsample.toml:
--------------------------------------------------------------------------------
1 | [[scenario]]
2 | name = "widget with context"
3 |
4 | [[scenario.table]]
5 | name = "widgets"
6 |
7 | [[scenario.table.row]]
8 | id = "<%= uuidNamed("widget") %>"
9 | name = "This is widget #1"
10 | body = "some widget body"
11 | created_at = "<%= now() %>"
12 | updated_at = "<%= now() %>"
13 |
14 | [[scenario.table.row]]
15 | id = "<%= uuid() %>"
16 | name = "This is widget #2"
17 | body = "some widget body"
18 | created_at = "<%= now() %>"
19 | updated_at = "<%= now() %>"
20 |
21 | [[scenario.table]]
22 | name = "users"
23 |
24 | [[scenario.table.row]]
25 | id = "<%= uuid() %>"
26 | name = "Mark Bates"
27 | admin = true
28 | price = <%= double(18) %>
29 | widget_id = "<%= uuidNamed("widget") %>"
30 | created_at = "<%= now() %>"
31 | updated_at = "<%= now() %>"
32 |
33 |
--------------------------------------------------------------------------------
/fix/init-fixtures/sample.toml:
--------------------------------------------------------------------------------
1 | [[scenario]]
2 | name = "lots of widgets"
3 |
4 | [[scenario.table]]
5 | name = "widgets"
6 |
7 | [[scenario.table.row]]
8 | id = "<%= uuidNamed("widget") %>"
9 | name = "This is widget #1"
10 | body = "some widget body"
11 | created_at = "<%= now() %>"
12 | updated_at = "<%= now() %>"
13 |
14 | [[scenario.table.row]]
15 | id = "<%= uuid() %>"
16 | name = "This is widget #2"
17 | body = "some widget body"
18 | created_at = "<%= now() %>"
19 | updated_at = "<%= now() %>"
20 |
21 | [[scenario.table.row]]
22 | id = "<%= uuid() %>"
23 | name = "This is widget #3"
24 | body = "some widget body"
25 | created_at = "<%= nowSub(3600) %>"
26 | updated_at = "<%= nowAdd(3600) %>"
27 |
28 | [[scenario.table]]
29 | name = "users"
30 |
31 | [[scenario.table.row]]
32 | id = "<%= uuid() %>"
33 | name = "Mark Bates"
34 | admin = true
35 | price = 19.99
36 | widget_id = "<%= uuidNamed("widget") %>"
37 | created_at = "<%= now() %>"
38 | updated_at = "<%= now() %>"
39 |
40 |
--------------------------------------------------------------------------------
/fix/plush.go:
--------------------------------------------------------------------------------
1 | package fix
2 |
3 | import (
4 | "io"
5 | "time"
6 |
7 | "github.com/gobuffalo/plush/v4"
8 | "github.com/gofrs/uuid"
9 | "golang.org/x/crypto/bcrypt"
10 | )
11 |
12 | func renderWithContext(r io.Reader, ctx *plush.Context) (string, error) {
13 | cm := map[string]interface{}{
14 | "uuid": func() uuid.UUID {
15 | u, _ := uuid.NewV4()
16 | return u
17 | },
18 | "uuidNamed": uuidNamed,
19 | "now": now,
20 | "hash": hash,
21 | "nowAdd": nowAdd,
22 | "nowSub": nowSub,
23 | }
24 | for k, v := range cm {
25 | if !ctx.Has(k) {
26 | ctx.Set(k, v)
27 | }
28 | }
29 | return plush.RenderR(r, ctx)
30 | }
31 |
32 | func render(r io.Reader) (string, error) {
33 | ctx := plush.NewContextWith(map[string]interface{}{
34 | "uuid": func() uuid.UUID {
35 | u, _ := uuid.NewV4()
36 | return u
37 | },
38 | "uuidNamed": uuidNamed,
39 | "now": now,
40 | "hash": hash,
41 | "nowAdd": nowAdd,
42 | "nowSub": nowSub,
43 | })
44 |
45 | return renderWithContext(r, ctx)
46 | }
47 |
48 | func hash(s string, opts map[string]interface{}, help plush.HelperContext) (string, error) {
49 | cost := bcrypt.DefaultCost
50 | if i, ok := opts["cost"].(int); ok {
51 | cost = i
52 | }
53 | ph, err := bcrypt.GenerateFromPassword([]byte(s), cost)
54 | return string(ph), err
55 | }
56 |
57 | func now(help plush.HelperContext) string {
58 | return time.Now().Format(time.RFC3339)
59 | }
60 |
61 | func nowAdd(s int) string {
62 | return time.Now().Add(time.Second * time.Duration(s)).Format(time.RFC3339)
63 | }
64 |
65 | func nowSub(s int) string {
66 | return time.Now().Add(time.Second * -time.Duration(s)).Format(time.RFC3339)
67 | }
68 |
69 | func uuidNamed(name string, help plush.HelperContext) uuid.UUID {
70 | u, _ := uuid.NewV4()
71 | if ux, ok := help.Value(name).(uuid.UUID); ok {
72 | return ux
73 | }
74 | help.Set(name, u)
75 | return u
76 | }
77 |
--------------------------------------------------------------------------------
/fix/plush_test.go:
--------------------------------------------------------------------------------
1 | package fix
2 |
3 | import (
4 | "testing"
5 | "time"
6 |
7 | "github.com/gobuffalo/plush/v4"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func Test_hash(t *testing.T) {
12 | r := require.New(t)
13 | s, err := hash("password", map[string]interface{}{}, plush.HelperContext{})
14 | r.NoError(err)
15 | r.NotEqual("password", s)
16 | }
17 |
18 | func Test_nowAdd(t *testing.T) {
19 | offset := 1000
20 | r := require.New(t)
21 | tStr := nowAdd(offset)
22 | r.NotEmpty(tStr)
23 | exp := time.Now().Add(time.Second * time.Duration(offset))
24 | act, err := time.Parse(time.RFC3339, tStr)
25 | r.NoError(err)
26 | r.WithinDuration(exp, act, time.Second*10)
27 | }
28 |
29 | func Test_nowSub(t *testing.T) {
30 | offset := 1000
31 | r := require.New(t)
32 | tStr := nowSub(offset)
33 | r.NotEmpty(tStr)
34 | exp := time.Now().Add(time.Second * -time.Duration(offset))
35 | act, err := time.Parse(time.RFC3339, tStr)
36 | r.NoError(err)
37 | r.WithinDuration(exp, act, time.Second*10)
38 | }
39 |
--------------------------------------------------------------------------------
/fix/scenario.go:
--------------------------------------------------------------------------------
1 | package fix
2 |
3 | type Scenario struct {
4 | Name string `toml:"name"`
5 | Tables Tables `toml:"table"`
6 | }
7 |
8 | // type Scenarios []Scenario
9 | type Scenarios struct {
10 | Scenarios []Scenario `toml:"scenario"`
11 | }
12 |
13 | type Table struct {
14 | Name string `toml:"name"`
15 | Row []map[string]interface{} `toml:"row"`
16 | }
17 |
18 | type Tables []Table
19 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/gobuffalo/suite/v4
2 |
3 | go 1.16
4 |
5 | require (
6 | github.com/BurntSushi/toml v1.3.2
7 | github.com/gobuffalo/buffalo v1.1.0
8 | github.com/gobuffalo/envy v1.10.2
9 | github.com/gobuffalo/httptest v1.5.2
10 | github.com/gobuffalo/middleware v1.0.0
11 | github.com/gobuffalo/plush/v4 v4.1.19
12 | github.com/gobuffalo/pop/v6 v6.1.1
13 | github.com/gofrs/uuid v4.4.0+incompatible
14 | github.com/gorilla/sessions v1.2.2
15 | github.com/stretchr/testify v1.8.4
16 | golang.org/x/crypto v0.31.0
17 | )
18 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
2 | github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
3 | github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
4 | github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
5 | github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
6 | github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
7 | github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
8 | github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
9 | github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
10 | github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
11 | github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
12 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
13 | github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
14 | github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
15 | github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
16 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
17 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
18 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
19 | github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
20 | github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
21 | github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
22 | github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
23 | github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
24 | github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
25 | github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
26 | github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
27 | github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
28 | github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
29 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
30 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
31 | github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
32 | github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
33 | github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
34 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
35 | github.com/gobuffalo/attrs v1.0.3/go.mod h1:KvDJCE0avbufqS0Bw3UV7RQynESY0jjod+572ctX4t8=
36 | github.com/gobuffalo/buffalo v1.1.0 h1:6y1fUC47QWevaM1ImukJFHNgxiRIT+Y74VcP4ZQaz80=
37 | github.com/gobuffalo/buffalo v1.1.0/go.mod h1:lLsx9Y8bFYu9uvQyIEB3M0QA908ChHUPjwOGumZWARU=
38 | github.com/gobuffalo/envy v1.10.2 h1:EIi03p9c3yeuRCFPOKcSfajzkLb3hrRjEpHGI8I2Wo4=
39 | github.com/gobuffalo/envy v1.10.2/go.mod h1:qGAGwdvDsaEtPhfBzb3o0SfDea8ByGn9j8bKmVft9z8=
40 | github.com/gobuffalo/events v1.4.3 h1:JYDq7NbozP10zaN9Ijfem6Ozox2KacU2fU38RyquXM8=
41 | github.com/gobuffalo/events v1.4.3/go.mod h1:2BwfpV5X63t8xkUcVqIv4IbyAobJazRSVu1F1pgf3rc=
42 | github.com/gobuffalo/fizz v1.14.4 h1:8uume7joF6niTNWN582IQ2jhGTUoa9g1fiV/tIoGdBs=
43 | github.com/gobuffalo/fizz v1.14.4/go.mod h1:9/2fGNXNeIFOXEEgTPJwiK63e44RjG+Nc4hfMm1ArGM=
44 | github.com/gobuffalo/flect v0.3.0/go.mod h1:5pf3aGnsvqvCj50AVni7mJJF8ICxGZ8HomberC3pXLE=
45 | github.com/gobuffalo/flect v1.0.0 h1:eBFmskjXZgAOagiTXJH25Nt5sdFwNRcb8DKZsIsAUQI=
46 | github.com/gobuffalo/flect v1.0.0/go.mod h1:l9V6xSb4BlXwsxEMj3FVEub2nkdQjWhPvD8XTTlHPQc=
47 | github.com/gobuffalo/genny/v2 v2.1.0/go.mod h1:4yoTNk4bYuP3BMM6uQKYPvtP6WsXFGm2w2EFYZdRls8=
48 | github.com/gobuffalo/github_flavored_markdown v1.1.3/go.mod h1:IzgO5xS6hqkDmUh91BW/+Qxo/qYnvfzoz3A7uLkg77I=
49 | github.com/gobuffalo/github_flavored_markdown v1.1.4 h1:WacrEGPXUDX+BpU1GM/Y0ADgMzESKNWls9hOTG1MHVs=
50 | github.com/gobuffalo/github_flavored_markdown v1.1.4/go.mod h1:Vl9686qrVVQou4GrHRK/KOG3jCZOKLUqV8MMOAYtlso=
51 | github.com/gobuffalo/grift v1.5.2 h1:mC0vHRs+nXz+JhkH3sv+rVnnTQRDXrUrOXOPYpgPjpo=
52 | github.com/gobuffalo/grift v1.5.2/go.mod h1:Uf/3T2AR1Vv+t84EPmxCjqQ8oyJwXs0FAoLMFUn/JVs=
53 | github.com/gobuffalo/helpers v0.6.7 h1:C9CedoRSfgWg2ZoIkVXgjI5kgmSpL34Z3qdnzpfNVd8=
54 | github.com/gobuffalo/helpers v0.6.7/go.mod h1:j0u1iC1VqlCaJEEVkZN8Ia3TEzfj/zoXANqyJExTMTA=
55 | github.com/gobuffalo/here v0.6.7/go.mod h1:vuCfanjqckTuRlqAitJz6QC4ABNnS27wLb816UhsPcc=
56 | github.com/gobuffalo/httptest v1.5.2 h1:GpGy520SfY1QEmyPvaqmznTpG4gEQqQ82HtHqyNEreM=
57 | github.com/gobuffalo/httptest v1.5.2/go.mod h1:FA23yjsWLGj92mVV74Qtc8eqluc11VqcWr8/C1vxt4g=
58 | github.com/gobuffalo/logger v1.0.7 h1:LTLwWelETXDYyqF/ASf0nxaIcdEOIJNxRokPcfI/xbU=
59 | github.com/gobuffalo/logger v1.0.7/go.mod h1:u40u6Bq3VVvaMcy5sRBclD8SXhBYPS0Qk95ubt+1xJM=
60 | github.com/gobuffalo/meta v0.3.3 h1:GwPWdbdnp4JrKASvMLa03OtmzISq7z/nE7T6aMqzoYM=
61 | github.com/gobuffalo/meta v0.3.3/go.mod h1:o4B099IUFUfK4555Guqxz1zHAqyuUQ/KtHXi8WvVeFE=
62 | github.com/gobuffalo/middleware v1.0.0 h1:7k3jWjdit45aK5Ri9DAKBKAp1QL3bXe2PCtWBBomMww=
63 | github.com/gobuffalo/middleware v1.0.0/go.mod h1:ubE1XogeGL39dXeS0PEKLeEAdFcGXRMMwTW3RGXK/b4=
64 | github.com/gobuffalo/nulls v0.4.2 h1:GAqBR29R3oPY+WCC7JL9KKk9erchaNuV6unsOSZGQkw=
65 | github.com/gobuffalo/nulls v0.4.2/go.mod h1:EElw2zmBYafU2R9W4Ii1ByIj177wA/pc0JdjtD0EsH8=
66 | github.com/gobuffalo/packd v1.0.2/go.mod h1:sUc61tDqGMXON80zpKGp92lDb86Km28jfvX7IAyxFT8=
67 | github.com/gobuffalo/plush/v4 v4.1.16/go.mod h1:6t7swVsarJ8qSLw1qyAH/KbrcSTwdun2ASEQkOznakg=
68 | github.com/gobuffalo/plush/v4 v4.1.18/go.mod h1:xi2tJIhFI4UdzIL8sxZtzGYOd2xbBpcFbLZlIPGGZhU=
69 | github.com/gobuffalo/plush/v4 v4.1.19 h1:o0E5gEJw+ozkAwQoCeiaWC6VOU2lEmX+GhtGkwpqZ8o=
70 | github.com/gobuffalo/plush/v4 v4.1.19/go.mod h1:WiKHJx3qBvfaDVlrv8zT7NCd3dEMaVR/fVxW4wqV17M=
71 | github.com/gobuffalo/pop/v6 v6.1.1 h1:eUDBaZcb0gYrmFnKwpuTEUA7t5ZHqNfvS4POqJYXDZY=
72 | github.com/gobuffalo/pop/v6 v6.1.1/go.mod h1:1n7jAmI1i7fxuXPZjZb0VBPQDbksRtCoFnrDV5IsvaI=
73 | github.com/gobuffalo/refresh v1.13.3 h1:HYQlI6RiqWUf2yzCXvUHAYqm9M9/teVnox+mjzo/9rQ=
74 | github.com/gobuffalo/refresh v1.13.3/go.mod h1:NkzgLKZGk5suOvgvOD0/VALog0fH29Ib7fwym9JmRxA=
75 | github.com/gobuffalo/tags/v3 v3.1.4 h1:X/ydLLPhgXV4h04Hp2xlbI2oc5MDaa7eub6zw8oHjsM=
76 | github.com/gobuffalo/tags/v3 v3.1.4/go.mod h1:ArRNo3ErlHO8BtdA0REaZxijuWnWzF6PUXngmMXd2I0=
77 | github.com/gobuffalo/validate/v3 v3.3.3 h1:o7wkIGSvZBYBd6ChQoLxkz2y1pfmhbI4jNJYh6PuNJ4=
78 | github.com/gobuffalo/validate/v3 v3.3.3/go.mod h1:YC7FsbJ/9hW/VjQdmXPvFqvRis4vrRYFxr69WiNZw6g=
79 | github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
80 | github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
81 | github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
82 | github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
83 | github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
84 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
85 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
86 | github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
87 | github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
88 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
89 | github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
90 | github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
91 | github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
92 | github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
93 | github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
94 | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
95 | github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
96 | github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
97 | github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
98 | github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
99 | github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
100 | github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
101 | github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
102 | github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
103 | github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
104 | github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
105 | github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
106 | github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
107 | github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
108 | github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
109 | github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
110 | github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
111 | github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
112 | github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
113 | github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
114 | github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys=
115 | github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI=
116 | github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
117 | github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
118 | github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
119 | github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
120 | github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
121 | github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
122 | github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
123 | github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
124 | github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
125 | github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
126 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
127 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
128 | github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
129 | github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
130 | github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
131 | github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
132 | github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y=
133 | github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
134 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
135 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
136 | github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
137 | github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
138 | github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
139 | github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
140 | github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w=
141 | github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
142 | github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
143 | github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
144 | github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
145 | github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
146 | github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E=
147 | github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw=
148 | github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
149 | github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
150 | github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
151 | github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
152 | github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
153 | github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
154 | github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
155 | github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
156 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
157 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
158 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
159 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
160 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
161 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
162 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
163 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
164 | github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
165 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
166 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
167 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
168 | github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
169 | github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
170 | github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
171 | github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
172 | github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
173 | github.com/luna-duclos/instrumentedsql v1.1.3 h1:t7mvC0z1jUt5A0UQ6I/0H31ryymuQRnJcWCiqV3lSAA=
174 | github.com/luna-duclos/instrumentedsql v1.1.3/go.mod h1:9J1njvFds+zN7y85EDhN9XNQLANWwZt2ULeIC8yMNYs=
175 | github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
176 | github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
177 | github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
178 | github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
179 | github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
180 | github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
181 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
182 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
183 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
184 | github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
185 | github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
186 | github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
187 | github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
188 | github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50=
189 | github.com/microcosm-cc/bluemonday v1.0.22 h1:p2tT7RNzRdCi0qmwxG+HbqD6ILkmwter1ZwVZn1oTxA=
190 | github.com/microcosm-cc/bluemonday v1.0.22/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM=
191 | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
192 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
193 | github.com/monoculum/formam v3.5.5+incompatible h1:iPl5csfEN96G2N2mGu8V/ZB62XLf9ySTpC8KRH6qXec=
194 | github.com/monoculum/formam v3.5.5+incompatible/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q=
195 | github.com/nicksnyder/go-i18n v1.10.1/go.mod h1:e4Di5xjP9oTVrC6y3C7C0HoSYXjSbhh/dU0eUV32nB4=
196 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
197 | github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
198 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
199 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
200 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
201 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
202 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
203 | github.com/psanford/memfs v0.0.0-20210214183328-a001468d78ef h1:NKxTG6GVGbfMXc2mIk+KphcH6hagbVXhcFkbTgYleTI=
204 | github.com/psanford/memfs v0.0.0-20210214183328-a001468d78ef/go.mod h1:tcaRap0jS3eifrEEllL6ZMd9dg8IlDpi2S1oARrQ+NI=
205 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
206 | github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
207 | github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
208 | github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
209 | github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
210 | github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
211 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
212 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
213 | github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
214 | github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
215 | github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
216 | github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
217 | github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
218 | github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
219 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
220 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
221 | github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
222 | github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
223 | github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d h1:yKm7XZV6j9Ev6lojP2XaIshpT4ymkqhMeSghO5Ps00E=
224 | github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
225 | github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e h1:qpG93cPwA5f7s/ZPBJnGOYQNK/vKsaDaseuKT5Asee8=
226 | github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
227 | github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
228 | github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
229 | github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
230 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
231 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
232 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
233 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
234 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
235 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
236 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
237 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
238 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
239 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
240 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
241 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
242 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
243 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
244 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
245 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
246 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
247 | github.com/unrolled/secure v1.13.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40=
248 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
249 | github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
250 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
251 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
252 | go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
253 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
254 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
255 | go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
256 | go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
257 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
258 | go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
259 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
260 | go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
261 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
262 | golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
263 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
264 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
265 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
266 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
267 | golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
268 | golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
269 | golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
270 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
271 | golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
272 | golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
273 | golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
274 | golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
275 | golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
276 | golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
277 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
278 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
279 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
280 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
281 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
282 | golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
283 | golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
284 | golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
285 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
286 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
287 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
288 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
289 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
290 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
291 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
292 | golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
293 | golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
294 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
295 | golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
296 | golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
297 | golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
298 | golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
299 | golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
300 | golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
301 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
302 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
303 | golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
304 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
305 | golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
306 | golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
307 | golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
308 | golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
309 | golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
310 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
311 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
312 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
313 | golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
314 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
315 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
316 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
317 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
318 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
319 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
320 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
321 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
322 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
323 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
324 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
325 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
326 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
327 | golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
328 | golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
329 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
330 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
331 | golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
332 | golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
333 | golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
334 | golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
335 | golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
336 | golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
337 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
338 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
339 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
340 | golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
341 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
342 | golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
343 | golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
344 | golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
345 | golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
346 | golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
347 | golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
348 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
349 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
350 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
351 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
352 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
353 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
354 | golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
355 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
356 | golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
357 | golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
358 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
359 | golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
360 | golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
361 | golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
362 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
363 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
364 | golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
365 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
366 | golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
367 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
368 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
369 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
370 | golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
371 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
372 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
373 | golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
374 | golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
375 | golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
376 | golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
377 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
378 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
379 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
380 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
381 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
382 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
383 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
384 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
385 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
386 | gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
387 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
388 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
389 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
390 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
391 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
392 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
393 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
394 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
395 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
396 |
--------------------------------------------------------------------------------
/model.go:
--------------------------------------------------------------------------------
1 | package suite
2 |
3 | import (
4 | "fmt"
5 | "io/fs"
6 | "strings"
7 |
8 | "github.com/gobuffalo/envy"
9 | "github.com/gobuffalo/plush/v4"
10 | "github.com/gobuffalo/pop/v6"
11 | "github.com/gobuffalo/suite/v4/fix"
12 | "github.com/stretchr/testify/require"
13 | "github.com/stretchr/testify/suite"
14 | )
15 |
16 | // Model suite
17 | type Model struct {
18 | suite.Suite
19 | *require.Assertions
20 | DB *pop.Connection
21 | Fixtures fs.FS
22 | }
23 |
24 | // SetupTest clears database
25 | func (m *Model) SetupTest() {
26 | m.Assertions = require.New(m.T())
27 | if m.DB != nil {
28 | err := m.CleanDB()
29 | m.NoError(err)
30 | }
31 | }
32 |
33 | // TearDownTest will be called after tests finish
34 | func (m *Model) TearDownTest() {}
35 |
36 | // DBDelta checks database table count change for a passed table name.
37 | func (m *Model) DBDelta(delta int, name string, fn func()) {
38 | sc, err := m.DB.Count(name)
39 | m.NoError(err)
40 | fn()
41 | ec, err := m.DB.Count(name)
42 | m.NoError(err)
43 | m.Equal(sc+delta, ec)
44 | }
45 |
46 | // LoadFixture loads a named fixture into the database.
47 | func (m *Model) LoadFixture(name string) {
48 | sc, err := fix.Find(name)
49 | m.NoError(err)
50 | db := m.DB.Store
51 |
52 | for _, table := range sc.Tables {
53 | for _, row := range table.Row {
54 | q := "insert into " + table.Name
55 | keys := []string{}
56 | skeys := []string{}
57 | for k := range row {
58 | keys = append(keys, k)
59 | skeys = append(skeys, ":"+k)
60 | }
61 |
62 | q = q + fmt.Sprintf(" (%s) values (%s)", strings.Join(keys, ","), strings.Join(skeys, ","))
63 | _, err = db.NamedExec(q, row)
64 | m.NoError(err)
65 | }
66 | }
67 | }
68 |
69 | // NewModel creates a new model suite
70 | func NewModel() *Model {
71 | m := &Model{}
72 | c, err := pop.Connect(envy.Get("GO_ENV", "test"))
73 | if err == nil {
74 | m.DB = c
75 | }
76 | return m
77 | }
78 |
79 | // NewModelWithFixturesAndContext creates a new model suite with fixtures and a passed context.
80 | func NewModelWithFixturesAndContext(fsys fs.FS, ctx *plush.Context) (*Model, error) {
81 | m := NewModel()
82 | m.Fixtures = fsys
83 | return m, fix.InitWithContext(fsys, ctx)
84 | }
85 |
86 | // NewModelWithFixtures creates a new model with passed fixtures box
87 | func NewModelWithFixtures(fsys fs.FS) (*Model, error) {
88 | m := NewModel()
89 | m.Fixtures = fsys
90 | return m, fix.Init(fsys)
91 | }
92 |
93 | func (m *Model) Run(name string, subtest func()) bool {
94 | return m.Suite.Run(name, func() {
95 | m.Assertions = require.New(m.Suite.T())
96 | subtest()
97 | })
98 | }
99 |
100 | // CleanDB clears records from the database, this function is
101 | // useful to run before tests to ensure other tests are not
102 | // affecting the one running.
103 | func (m *Model) CleanDB() error {
104 | if m.DB == nil {
105 | return nil
106 | }
107 |
108 | switch m.DB.Dialect.Name() {
109 | case "postgres":
110 | deleteAllQuery := `DO
111 | $func$
112 | DECLARE
113 | _tbl text;
114 | _sch text;
115 | BEGIN
116 | FOR _sch, _tbl IN
117 | SELECT schemaname, tablename
118 | FROM pg_tables
119 | WHERE tablename <> '%s' AND schemaname NOT IN ('pg_catalog', 'information_schema') AND tableowner = current_user
120 | LOOP
121 | EXECUTE format('ALTER TABLE %%I.%%I DISABLE TRIGGER ALL;', _sch, _tbl);
122 | EXECUTE format('DELETE FROM %%I.%%I CASCADE', _sch, _tbl);
123 | EXECUTE format('ALTER TABLE %%I.%%I ENABLE TRIGGER ALL;', _sch, _tbl);
124 | END LOOP;
125 | END
126 | $func$;`
127 |
128 | q := m.DB.RawQuery(fmt.Sprintf(deleteAllQuery, m.DB.MigrationTableName()))
129 | return q.Exec()
130 | default:
131 | return m.DB.TruncateAll()
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/session.go:
--------------------------------------------------------------------------------
1 | package suite
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/gorilla/sessions"
7 | )
8 |
9 | type sessionStore struct {
10 | sessions map[string]*sessions.Session
11 | }
12 |
13 | func (s *sessionStore) Get(r *http.Request, name string) (*sessions.Session, error) {
14 | if s, ok := s.sessions[name]; ok {
15 | return s, nil
16 | }
17 | return s.New(r, name)
18 | }
19 |
20 | func (s *sessionStore) New(r *http.Request, name string) (*sessions.Session, error) {
21 | sess := sessions.NewSession(s, name)
22 | s.sessions[name] = sess
23 | return sess, nil
24 | }
25 |
26 | func (s *sessionStore) Save(r *http.Request, w http.ResponseWriter, sess *sessions.Session) error {
27 | if s.sessions == nil {
28 | s.sessions = map[string]*sessions.Session{}
29 | }
30 | s.sessions[sess.Name()] = sess
31 | return nil
32 | }
33 |
34 | //NewSessionStore for action suite
35 | func newSessionStore() sessions.Store {
36 | return &sessionStore{
37 | sessions: map[string]*sessions.Session{},
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/suite.go:
--------------------------------------------------------------------------------
1 | package suite
2 |
3 | import (
4 | "io/fs"
5 | "testing"
6 |
7 | "github.com/gobuffalo/buffalo"
8 | "github.com/gobuffalo/httptest"
9 | "github.com/gobuffalo/middleware/csrf"
10 | "github.com/stretchr/testify/suite"
11 | )
12 |
13 | // Action suite
14 | type Action struct {
15 | *Model
16 | Session *buffalo.Session
17 | App *buffalo.App
18 | csrf buffalo.MiddlewareFunc
19 | }
20 |
21 | // HTML creates an httptest.Request with HTML content type.
22 | func (as *Action) HTML(u string, args ...interface{}) *httptest.Request {
23 | return httptest.New(as.App).HTML(u, args...)
24 | }
25 |
26 | // JSON creates an httptest.JSON request
27 | func (as *Action) JSON(u string, args ...interface{}) *httptest.JSON {
28 | return httptest.New(as.App).JSON(u, args...)
29 | }
30 |
31 | // XML creates an httptest.XML request
32 | func (as *Action) XML(u string, args ...interface{}) *httptest.XML {
33 | return httptest.New(as.App).XML(u, args...)
34 | }
35 |
36 | // SetupTest sets the session store, CSRF and clears database
37 | func (as *Action) SetupTest() {
38 | as.App.SessionStore = newSessionStore()
39 | s, _ := as.App.SessionStore.New(nil, as.App.SessionName)
40 | as.Session = &buffalo.Session{
41 | Session: s,
42 | }
43 |
44 | if as.Model != nil {
45 | as.Model.SetupTest()
46 | }
47 | as.csrf = csrf.New
48 | csrf.New = func(next buffalo.Handler) buffalo.Handler {
49 | return func(c buffalo.Context) error {
50 | return next(c)
51 | }
52 | }
53 | }
54 |
55 | // TearDownTest resets csrf
56 | func (as *Action) TearDownTest() {
57 | csrf.New = as.csrf
58 | if as.Model != nil {
59 | as.Model.TearDownTest()
60 | }
61 | }
62 |
63 | // NewAction returns new Action for given buffalo.App
64 | func NewAction(app *buffalo.App) *Action {
65 | as := &Action{
66 | App: app,
67 | Model: NewModel(),
68 | }
69 | return as
70 | }
71 |
72 | // NewActionWithFixtures creates a new ActionSuite with passed box for fixtures.
73 | func NewActionWithFixtures(app *buffalo.App, fsys fs.FS) (*Action, error) {
74 | m, err := NewModelWithFixtures(fsys)
75 | if err != nil {
76 | return nil, err
77 | }
78 | as := &Action{
79 | App: app,
80 | Model: m,
81 | }
82 | return as, nil
83 | }
84 |
85 | //Run the passed suite
86 | func Run(t *testing.T, s suite.TestingSuite) {
87 | suite.Run(t, s)
88 | }
89 |
--------------------------------------------------------------------------------
/suite_test.go:
--------------------------------------------------------------------------------
1 | package suite
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/gobuffalo/buffalo"
8 | "github.com/gobuffalo/buffalo/render"
9 | )
10 |
11 | type aSuite struct {
12 | *Action
13 | }
14 |
15 | func Test_aSuite(t *testing.T) {
16 | app := buffalo.New(buffalo.Options{})
17 | app.GET("/session-hello", func(c buffalo.Context) error {
18 | if n, ok := c.Session().Get("name").(string); ok {
19 | return c.Render(200, render.String(n))
20 | }
21 | return c.Error(500, fmt.Errorf("could not find name in session"))
22 | })
23 | as := &aSuite{NewAction(app)}
24 | Run(t, as)
25 | }
26 |
27 | func (as *aSuite) Test_Session() {
28 | as.Session.Set("name", "Homer Simpson")
29 | res := as.HTML("/session-hello").Get()
30 | as.Equal(200, res.Code)
31 | as.Contains(res.Body.String(), "Homer Simpson")
32 |
33 | as.Session.Clear()
34 | res = as.HTML("/session-hello").Get()
35 | as.Equal(500, res.Code)
36 | }
37 |
38 | func (as *aSuite) Test_Session_Resets() {
39 | res := as.HTML("/session-hello").Get()
40 | as.Equal(500, res.Code)
41 | }
42 |
--------------------------------------------------------------------------------
/version.go:
--------------------------------------------------------------------------------
1 | package suite
2 |
3 | // Version of Suite
4 | const Version = "v4.0.4"
5 |
--------------------------------------------------------------------------------