10 Commits

Author SHA1 Message Date
jimehbot[bot]
8a88e5174b chore(main): release 0.2.0 (#8)
Co-authored-by: jimehbot[bot] <132453784+jimehbot[bot]@users.noreply.github.com>
2025-03-24 13:19:39 +00:00
bc86ba7a6d feat(do): add new Do function to simplify golden usage (#11)
Add new Do function whihc ecapsulates the common pattern of writing to
golden file if the update mechnism evaluates to true, followed by
immediately reading the file. Compresses four lines into one.
2025-03-24 13:17:17 +00:00
62e8344ff3 feat(interface): use TestingT interface intead of *testing.T in function signatures (#13) 2025-03-24 13:04:34 +00:00
e46dc124ff feat(defaults): expose a Default *Golden instance (#9)
Also change the Default* constants to variables so they can be modified
as well.
2025-03-24 12:54:29 +00:00
6817ec6101 feat(update): make default GOLDEN_UPDATE env var check case-insensitive (#10) 2025-03-24 12:53:34 +00:00
8f4d3d4170 chore(deps/dev): upgrade development dependencies, including golangci-lint (#12) 2025-03-24 12:52:20 +00:00
b2112ca475 ci(release): add release-please config and workflow job (#7) 2025-03-24 11:36:39 +00:00
27e0134701 doc(readme): fix badges 2025-03-22 02:00:17 +00:00
85ae6e9ae3 feat(go)!: upgrade to Go 1.17 (from 1.15) (#6)
BREAKING CHANGE: Go 1.17 or later is now required, up from Go 1.15.
2025-03-22 01:37:06 +00:00
f5a03af9ce ci(deps): update actions and lint config to get them all running again (#5) 2025-03-22 01:23:12 +00:00
15 changed files with 667 additions and 304 deletions

3
.github/.release-please-manifest.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
".": "0.2.0"
}

15
.github/release-please-config.json vendored Normal file
View File

@@ -0,0 +1,15 @@
{
"bootstrap-sha": "edb189f0863fddd94211a5b4c5b5bcf7a90fbd10",
"packages": {
".": {
"release-type": "go",
"changelog-path": "CHANGELOG.md",
"bump-minor-pre-major": true,
"bump-patch-for-minor-pre-major": true,
"always-update": true,
"draft": false,
"prerelease": false
}
},
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"
}

View File

@@ -6,29 +6,28 @@ jobs:
lint:
name: Lint
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
checks: write
steps:
- uses: actions/checkout@v2
- name: golangci-lint
uses: golangci/golangci-lint-action@v2
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
version: v1.42
env:
VERBOSE: "true"
go-version: stable
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: v1.64
tidy:
name: Tidy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: 1.15
- uses: actions/cache@v2
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
go-version-file: go.mod
- name: Check if mods are tidy
run: make check-tidy
@@ -36,18 +35,12 @@ jobs:
name: Coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: 1.15
- uses: actions/cache@v2
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
go-version-file: go.mod
- name: Publish coverage
uses: paambaati/codeclimate-action@v2.7.4
uses: paambaati/codeclimate-action@v9.0.0
env:
VERBOSE: "true"
GOMAXPROCS: 4
@@ -68,20 +61,30 @@ jobs:
- macos-latest
- windows-latest
go_version:
- "1.15"
- "1.16"
- "1.17"
- "1.18"
- "1.19"
- "1.20"
- "stable"
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go_version }}
- uses: actions/cache@v2
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
check-latest: true
- name: Run tests
run: go test -v -count=1 -race ./...
release-please:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
outputs:
release_created: ${{ steps.release-please.outputs.release_created }}
version: ${{ steps.release-please.outputs.version }}
steps:
- uses: jimeh/release-please-manifest-action@v2
id: release-please
with:
app-id: ${{ secrets.RELEASE_BOT_APP_ID }}
private-key: ${{ secrets.RELEASE_BOT_PRIVATE_KEY }}

View File

@@ -4,18 +4,13 @@ linters-settings:
statements: 150
gocyclo:
min-complexity: 20
golint:
min-confidence: 0
govet:
check-shadowing: true
enable-all: true
disable:
- fieldalignment
lll:
line-length: 80
tab-width: 4
maligned:
suggest-new: true
misspell:
locale: US
@@ -24,13 +19,11 @@ linters:
enable:
- asciicheck
- bodyclose
- deadcode
- depguard
- copyloopvar
- durationcheck
- errcheck
- errorlint
- exhaustive
- exportloopref
- funlen
- gochecknoinits
- goconst
@@ -58,13 +51,10 @@ linters:
- rowserrcheck
- sqlclosecheck
- staticcheck
- structcheck
- tparallel
- typecheck
- unconvert
- unparam
- unused
- varcheck
- wastedassign
- whitespace

View File

@@ -2,6 +2,21 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [0.2.0](https://github.com/jimeh/go-golden/compare/v0.1.0...v0.2.0) (2025-03-24)
### ⚠ BREAKING CHANGES
* **go:** Go 1.17 or later is now required, up from Go 1.15.
### Features
* **defaults:** expose a Default *Golden instance ([#9](https://github.com/jimeh/go-golden/issues/9)) ([e46dc12](https://github.com/jimeh/go-golden/commit/e46dc124ff22e52dfc050174c7b3de980c980912))
* **do:** add new Do function to simplify golden usage ([#11](https://github.com/jimeh/go-golden/issues/11)) ([bc86ba7](https://github.com/jimeh/go-golden/commit/bc86ba7a6d9f4374c9fb15f78e51eedf50df04d2))
* **go:** upgrade to Go 1.17 (from 1.15) ([#6](https://github.com/jimeh/go-golden/issues/6)) ([85ae6e9](https://github.com/jimeh/go-golden/commit/85ae6e9ae3c4222d68faee0c44a1fd105a2e04b4))
* **interface:** use TestingT interface intead of *testing.T in function signatures ([#13](https://github.com/jimeh/go-golden/issues/13)) ([62e8344](https://github.com/jimeh/go-golden/commit/62e8344ff33dccf0a5666e94361a143d34558bf0))
* **update:** make default GOLDEN_UPDATE env var check case-insensitive ([#10](https://github.com/jimeh/go-golden/issues/10)) ([6817ec6](https://github.com/jimeh/go-golden/commit/6817ec6101558b3914984d4ee3fe816d534f87bb))
## 0.1.0 (2021-10-28)

View File

@@ -34,23 +34,19 @@ SHELL := env \
# Tools
#
TOOLS += $(TOOLDIR)/gobin
$(TOOLDIR)/gobin:
GO111MODULE=off go get -u github.com/myitcv/gobin
# external tool
define tool # 1: binary-name, 2: go-import-path
TOOLS += $(TOOLDIR)/$(1)
$(TOOLDIR)/$(1): $(TOOLDIR)/gobin Makefile
gobin $(V) "$(2)"
$(TOOLDIR)/$(1): Makefile
GOBIN="$(CURDIR)/$(TOOLDIR)" go install "$(2)"
endef
$(eval $(call tool,godoc,golang.org/x/tools/cmd/godoc))
$(eval $(call tool,gofumpt,mvdan.cc/gofumpt))
$(eval $(call tool,goimports,golang.org/x/tools/cmd/goimports))
$(eval $(call tool,golangci-lint,github.com/golangci/golangci-lint/cmd/golangci-lint@v1.42))
$(eval $(call tool,gomod,github.com/Helcaraxan/gomod))
$(eval $(call tool,godoc,golang.org/x/tools/cmd/godoc@latest))
$(eval $(call tool,gofumpt,mvdan.cc/gofumpt@latest))
$(eval $(call tool,goimports,golang.org/x/tools/cmd/goimports@latest))
$(eval $(call tool,golangci-lint,github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64))
$(eval $(call tool,gomod,github.com/Helcaraxan/gomod@latest))
.PHONY: tools
tools: $(TOOLS)
@@ -186,20 +182,3 @@ check-tidy:
docs: $(TOOLDIR)/godoc
$(info serviing docs on http://127.0.0.1:6060/pkg/$(GOMODNAME)/)
@godoc -http=127.0.0.1:6060
#
# Release
#
.PHONY: new-version
new-version: check-npx
npx standard-version
.PHONY: next-version
next-version: check-npx
npx standard-version --dry-run
.PHONY: check-npx
check-npx:
$(if $(shell which npx),,\
$(error No npx found in PATH, please install NodeJS))

View File

@@ -10,26 +10,12 @@
</p>
<p align="center">
<a href="https://pkg.go.dev/github.com/jimeh/go-golden">
<img src="https://img.shields.io/badge/%E2%80%8B-reference-387b97.svg?logo=go&logoColor=white"
alt="Go Reference">
</a>
<a href="https://github.com/jimeh/go-golden/actions">
<img src="https://img.shields.io/github/workflow/status/jimeh/go-golden/CI.svg?logo=github" alt="Actions Status">
</a>
<a href="https://codeclimate.com/github/jimeh/go-golden">
<img src="https://img.shields.io/codeclimate/coverage/jimeh/go-golden.svg?logo=code%20climate" alt="Coverage">
</a>
<a href="https://github.com/jimeh/go-golden/issues">
<img src="https://img.shields.io/github/issues-raw/jimeh/go-golden.svg?style=flat&logo=github&logoColor=white"
alt="GitHub issues">
</a>
<a href="https://github.com/jimeh/go-golden/pulls">
<img src="https://img.shields.io/github/issues-pr-raw/jimeh/go-golden.svg?style=flat&logo=github&logoColor=white" alt="GitHub pull requests">
</a>
<a href="https://github.com/jimeh/go-golden/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/jimeh/go-golden.svg?style=flat" alt="License Status">
</a>
<a href="https://pkg.go.dev/github.com/jimeh/go-golden"><img src="https://img.shields.io/badge/%E2%80%8B-reference-387b97.svg?logo=go&logoColor=white" alt="Go Reference"></a>
<a href="https://github.com/jimeh/go-golden/actions"><img src="https://img.shields.io/github/actions/workflow/status/jimeh/go-golden/ci.yml?logo=github" alt="Actions Status"></a>
<a href="https://codeclimate.com/github/jimeh/go-golden"><img src="https://img.shields.io/codeclimate/coverage/jimeh/go-golden.svg?logo=code%20climate" alt="Coverage"></a>
<a href="https://github.com/jimeh/go-golden/issues"><img src="https://img.shields.io/github/issues-raw/jimeh/go-golden.svg?style=flat&logo=github&logoColor=white" alt="GitHub issues"></a>
<a href="https://github.com/jimeh/go-golden/pulls"><img src="https://img.shields.io/github/issues-pr-raw/jimeh/go-golden.svg?style=flat&logo=github&logoColor=white" alt="GitHub pull requests"></a>
<a href="https://github.com/jimeh/go-golden/blob/master/LICENSE"><img src="https://img.shields.io/github/license/jimeh/go-golden.svg?style=flat" alt="License Status"></a>
</p>
## Import
@@ -42,15 +28,12 @@ import "github.com/jimeh/go-golden"
```go
func TestExampleMyStruct(t *testing.T) {
got, err := json.Marshal(&MyStruct{Foo: "Bar"})
require.NoError(t, err)
got, err := json.Marshal(&MyStruct{Foo: "Bar"})
require.NoError(t, err)
if golden.Update() {
golden.Set(t, got)
}
want := golden.Get(t)
want := golden.Do(t, got)
assert.Equal(t, want, got)
assert.Equal(t, want, got)
}
```
@@ -58,6 +41,15 @@ The above example will read/write to:
- `testdata/TestExampleMyStruct.golden`
The call to `golden.Do()` is equivalent to:
```go
if golden.Update() {
golden.Set(t, got)
}
want := golden.Get(t)
```
To update the golden file (have `golden.Update()` return `true`), simply set the
`GOLDEN_UPDATE` environment variable to one of `1`, `y`, `t`, `yes`, `on`, or
`true` when running tests.

View File

@@ -10,31 +10,29 @@ import (
"github.com/stretchr/testify/require"
)
// The tests in this file are examples from the README and the package-level Go
// documentation.
type MyStruct struct {
Foo string `json:"foo,omitempty"`
}
// TestExampleMyStruct reads/writes the following golden file:
//
// testdata/TestExampleMyStruct.golden
//
// testdata/TestExampleMyStruct.golden
func TestExampleMyStruct(t *testing.T) {
got, err := json.Marshal(&MyStruct{Foo: "Bar"})
require.NoError(t, err)
if golden.Update() {
golden.Set(t, got)
}
want := golden.Get(t)
want := golden.Do(t, got)
assert.Equal(t, want, got)
}
// TestExampleMyStructTabular reads/writes the following golden files:
//
// testdata/TestExampleMyStructTabular/empty_struct.golden
// testdata/TestExampleMyStructTabular/full_struct.golden
//
// testdata/TestExampleMyStructTabular/empty_struct.golden
// testdata/TestExampleMyStructTabular/full_struct.golden
func TestExampleMyStructTabular(t *testing.T) {
tests := []struct {
name string
@@ -48,10 +46,7 @@ func TestExampleMyStructTabular(t *testing.T) {
got, err := json.Marshal(tt.obj)
require.NoError(t, err)
if golden.Update() {
golden.Set(t, got)
}
want := golden.Get(t)
want := golden.Do(t, got)
assert.Equal(t, want, got)
})
@@ -60,29 +55,25 @@ func TestExampleMyStructTabular(t *testing.T) {
// TestExampleMyStructP reads/writes the following golden file:
//
// testdata/TestExampleMyStructP/json.golden
// testdata/TestExampleMyStructP/xml.golden
//
// testdata/TestExampleMyStructP/json.golden
// testdata/TestExampleMyStructP/xml.golden
func TestExampleMyStructP(t *testing.T) {
gotJSON, _ := json.Marshal(&MyStruct{Foo: "Bar"})
gotXML, _ := xml.Marshal(&MyStruct{Foo: "Bar"})
if golden.Update() {
golden.SetP(t, "json", gotJSON)
golden.SetP(t, "xml", gotXML)
}
wantJSON := golden.DoP(t, "json", gotJSON)
wantXML := golden.DoP(t, "xml", gotXML)
assert.Equal(t, golden.GetP(t, "json"), gotJSON)
assert.Equal(t, golden.GetP(t, "xml"), gotXML)
assert.Equal(t, wantJSON, gotJSON)
assert.Equal(t, wantXML, gotXML)
}
// TestExampleMyStructTabularP reads/writes the following golden file:
//
// testdata/TestExampleMyStructTabularP/empty_struct/json.golden
// testdata/TestExampleMyStructTabularP/empty_struct/xml.golden
// testdata/TestExampleMyStructTabularP/full_struct/json.golden
// testdata/TestExampleMyStructTabularP/full_struct/xml.golden
//
// testdata/TestExampleMyStructTabularP/empty_struct/json.golden
// testdata/TestExampleMyStructTabularP/empty_struct/xml.golden
// testdata/TestExampleMyStructTabularP/full_struct/json.golden
// testdata/TestExampleMyStructTabularP/full_struct/xml.golden
func TestExampleMyStructTabularP(t *testing.T) {
tests := []struct {
name string
@@ -96,13 +87,11 @@ func TestExampleMyStructTabularP(t *testing.T) {
gotJSON, _ := json.Marshal(tt.obj)
gotXML, _ := xml.Marshal(tt.obj)
if golden.Update() {
golden.SetP(t, "json", gotJSON)
golden.SetP(t, "xml", gotXML)
}
wantJSON := golden.DoP(t, "json", gotJSON)
wantXML := golden.DoP(t, "xml", gotXML)
assert.Equal(t, golden.GetP(t, "json"), gotJSON)
assert.Equal(t, golden.GetP(t, "xml"), gotXML)
assert.Equal(t, wantJSON, gotJSON)
assert.Equal(t, wantXML, gotXML)
})
}
}

9
go.mod
View File

@@ -1,8 +1,11 @@
module github.com/jimeh/go-golden
go 1.15
go 1.17
require github.com/stretchr/testify v1.10.0
require (
github.com/jimeh/envctl v0.1.0
github.com/stretchr/testify v1.7.0
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

19
go.sum
View File

@@ -1,14 +1,19 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/jimeh/envctl v0.1.0 h1:KTv3D+pi5M4/PgFVE/W8ssWqiZP3pDJ8Cga50L+1avo=
github.com/jimeh/envctl v0.1.0/go.mod h1:aM27ffBbO1yUBKUzgJGCUorS4z+wyh+qhQe1ruxXZZo=
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

326
golden.go
View File

@@ -1,178 +1,200 @@
// Package golden is yet another package for working with *.golden test files,
// with a focus on simplicity through it's default behavior.
//
// Golden file names are based on the name of the test function and any subtest
// Golden file names are based on the name of the test function and any sub-test
// names by calling t.Name(). File names are sanitized to ensure they're
// compatible with Linux, macOS and Windows systems regardless of what crazy
// characters might be in a subtest's name.
// characters might be in a sub-test's name.
//
// Usage
// # Usage
//
// Typical usage should look something like this:
//
// func TestExampleMyStruct(t *testing.T) {
// got, err := json.Marshal(&MyStruct{Foo: "Bar"})
// require.NoError(t, err)
// func TestExampleMyStruct(t *testing.T) {
// got, err := json.Marshal(&MyStruct{Foo: "Bar"})
// require.NoError(t, err)
//
// if golden.Update() {
// golden.Set(t, got)
// }
// want := golden.Get(t)
// want := golden.Do(t, got)
//
// assert.Equal(t, want, got)
// }
// assert.Equal(t, want, got)
// }
//
// The above example will read/write to:
//
// testdata/TestExampleMyStruct.golden
// testdata/TestExampleMyStruct.golden
//
// The call to golden.Do() is equivalent to:
//
// if golden.Update() {
// golden.Set(t, got)
// }
// want := golden.Get(t)
//
// To update the golden file (have golden.Update() return true), simply set the
// GOLDEN_UPDATE environment variable to one of "1", "y", "t", "yes", "on", or
// "true" when running tests.
//
// Sub-Tests
// # Sub-Tests
//
// As the golden filename is based on t.Name(), it works with sub-tests too,
// ensuring each sub-test gets it's own golden file. For example:
// ensuring each sub-test gets its own golden file. For example:
//
// func TestExampleMyStructTabular(t *testing.T) {
// tests := []struct {
// name string
// obj *MyStruct
// }{
// {name: "empty struct", obj: &MyStruct{}},
// {name: "full struct", obj: &MyStruct{Foo: "Bar"}},
// }
// for _, tt := range tests {
// t.Run(tt.name, func(t *testing.T) {
// got, err := json.Marshal(tt.obj)
// require.NoError(t, err)
// func TestExampleMyStructTabular(t *testing.T) {
// tests := []struct {
// name string
// obj *MyStruct
// }{
// {name: "empty struct", obj: &MyStruct{}},
// {name: "full struct", obj: &MyStruct{Foo: "Bar"}},
// }
// for _, tt := range tests {
// t.Run(tt.name, func(t *testing.T) {
// got, err := json.Marshal(tt.obj)
// require.NoError(t, err)
//
// if golden.Update() {
// golden.Set(t, got)
// }
// want := golden.Get(t)
// want := golden.Do(t, got)
//
// assert.Equal(t, want, got)
// })
// }
// }
// assert.Equal(t, want, got)
// })
// }
// }
//
// The above example will read/write to:
//
// testdata/TestExampleMyStructTabular/empty_struct.golden
// testdata/TestExampleMyStructTabular/full_struct.golden
// testdata/TestExampleMyStructTabular/empty_struct.golden
// testdata/TestExampleMyStructTabular/full_struct.golden
//
// Multiple Golden Files in a Single Test
// # Multiple Golden Files in a Single Test
//
// The "P" suffixed methods, GetP(), SetP(), and FileP(), all take a name
// argument which allows using specific golden files within a given *testing.T
// instance.
//
// func TestExampleMyStructP(t *testing.T) {
// gotJSON, _ := json.Marshal(&MyStruct{Foo: "Bar"})
// gotXML, _ := xml.Marshal(&MyStruct{Foo: "Bar"})
// func TestExampleMyStructP(t *testing.T) {
// gotJSON, _ := json.Marshal(&MyStruct{Foo: "Bar"})
// gotXML, _ := xml.Marshal(&MyStruct{Foo: "Bar"})
//
// if golden.Update() {
// golden.SetP(t, "json", gotJSON)
// golden.SetP(t, "xml", gotXML)
// }
// wantJSON := golden.DoP(t, "json", gotJSON)
// wantXML := golden.DoP(t, "xml", gotXML)
//
// assert.Equal(t, golden.GetP(t, "json"), gotJSON)
// assert.Equal(t, golden.GetP(t, "xml"), gotXML)
// }
// assert.Equal(t, wantJSON, gotJSON)
// assert.Equal(t, wantXML, gotXML)
// }
//
// The above example will read/write to:
//
// testdata/TestExampleMyStructP/json.golden
// testdata/TestExampleMyStructP/xml.golden
// testdata/TestExampleMyStructP/json.golden
// testdata/TestExampleMyStructP/xml.golden
//
// This works with tabular tests too of course:
//
// func TestExampleMyStructTabularP(t *testing.T) {
// tests := []struct {
// name string
// obj *MyStruct
// }{
// {name: "empty struct", obj: &MyStruct{}},
// {name: "full struct", obj: &MyStruct{Foo: "Bar"}},
// }
// for _, tt := range tests {
// t.Run(tt.name, func(t *testing.T) {
// gotJSON, _ := json.Marshal(tt.obj)
// gotXML, _ := xml.Marshal(tt.obj)
// func TestExampleMyStructTabularP(t *testing.T) {
// tests := []struct {
// name string
// obj *MyStruct
// }{
// {name: "empty struct", obj: &MyStruct{}},
// {name: "full struct", obj: &MyStruct{Foo: "Bar"}},
// }
// for _, tt := range tests {
// t.Run(tt.name, func(t *testing.T) {
// gotJSON, _ := json.Marshal(tt.obj)
// gotXML, _ := xml.Marshal(tt.obj)
//
// if golden.Update() {
// golden.SetP(t, "json", gotJSON)
// golden.SetP(t, "xml", gotXML)
// }
// wantJSON := golden.DoP(t, "json", gotJSON)
// wantXML := golden.DoP(t, "xml", gotXML)
//
// assert.Equal(t, golden.GetP(t, "json"), gotJSON)
// assert.Equal(t, golden.GetP(t, "xml"), gotXML)
// })
// }
// }
// assert.Equal(t, wantJSON, gotJSON)
// assert.Equal(t, wantXML, gotXML)
// })
// }
// }
//
// The above example will read/write to:
//
// testdata/TestExampleMyStructTabularP/empty_struct/json.golden
// testdata/TestExampleMyStructTabularP/empty_struct/xml.golden
// testdata/TestExampleMyStructTabularP/full_struct/json.golden
// testdata/TestExampleMyStructTabularP/full_struct/xml.golden
//
// testdata/TestExampleMyStructTabularP/empty_struct/json.golden
// testdata/TestExampleMyStructTabularP/empty_struct/xml.golden
// testdata/TestExampleMyStructTabularP/full_struct/json.golden
// testdata/TestExampleMyStructTabularP/full_struct/xml.golden
package golden
import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
)
const (
DefaultDirMode = 0o755
DefaultFileMode = 0o644
DefaultSuffix = ".golden"
DefaultDirname = "testdata"
var (
// Default is the default *Golden instance. All package-level functions use
// the Default instance.
Default = New()
// DefaultDirMode is the default DirMode value used by New().
DefaultDirMode = os.FileMode(0o755)
// DefaultFileMode is the default FileMode value used by New().
DefaultFileMode = os.FileMode(0o644)
// DefaultSuffix is the default Suffix value used by New().
DefaultSuffix = ".golden"
// DefaultDirname is the default Dirname value used by New().
DefaultDirname = "testdata"
// DefaultUpdateFunc is the default UpdateFunc value used by New().
DefaultUpdateFunc = EnvUpdateFunc
)
var DefaultUpdateFunc = EnvUpdateFunc
// Do is a convenience function for calling Update(), Set(), and Get() in a
// single call. If Update() returns true, data will be written to the golden
// file using Set(), before reading it back with Get().
func Do(t TestingT, data []byte) []byte {
t.Helper()
var global = New()
return Default.Do(t, data)
}
// File returns the filename of the golden file for the given *testing.T
// instance as determined by t.Name().
func File(t *testing.T) string {
func File(t TestingT) string {
t.Helper()
return global.File(t)
return Default.File(t)
}
// Get returns the content of the golden file for the given *testing.T instance
// as determined by t.Name(). If no golden file can be found/read, it will fail
// the test by calling t.Fatal().
func Get(t *testing.T) []byte {
func Get(t TestingT) []byte {
t.Helper()
return global.Get(t)
return Default.Get(t)
}
// Set writes given data to the golden file for the given *testing.T instance as
// determined by t.Name(). If writing fails it will fail the test by calling
// t.Fatal() with error details.
func Set(t *testing.T, data []byte) {
func Set(t TestingT, data []byte) {
t.Helper()
global.Set(t, data)
Default.Set(t, data)
}
// DoP is a convenience function for calling Update(), SetP(), and GetP() in a
// single call. If Update() returns true, data will be written to the golden
// file using SetP(), before reading it back with GetP().
func DoP(t TestingT, name string, data []byte) []byte {
t.Helper()
return Default.DoP(t, name, data)
}
// FileP returns the filename of the specifically named golden file for the
// given *testing.T instance as determined by t.Name().
func FileP(t *testing.T, name string) string {
func FileP(t TestingT, name string) string {
t.Helper()
return global.FileP(t, name)
return Default.FileP(t, name)
}
// GetP returns the content of the specifically named golden file belonging
@@ -181,10 +203,10 @@ func FileP(t *testing.T, name string) string {
//
// This is very similar to Get(), but it allows multiple different golden files
// to be used within the same one *testing.T instance.
func GetP(t *testing.T, name string) []byte {
func GetP(t TestingT, name string) []byte {
t.Helper()
return global.GetP(t, name)
return Default.GetP(t, name)
}
// SetP writes given data of the specifically named golden file belonging to
@@ -193,10 +215,10 @@ func GetP(t *testing.T, name string) []byte {
//
// This is very similar to Set(), but it allows multiple different golden files
// to be used within the same one *testing.T instance.
func SetP(t *testing.T, name string, data []byte) {
func SetP(t TestingT, name string, data []byte) {
t.Helper()
global.SetP(t, name, data)
Default.SetP(t, name, data)
}
// Update returns true when golden is set to update golden files. Should be used
@@ -206,7 +228,7 @@ func SetP(t *testing.T, name string, data []byte) {
// environment variable is set to a truthy value. To customize create a custom
// *Golden instance with New() and set a new UpdateFunc value.
func Update() bool {
return global.Update()
return Default.Update()
}
// Golden handles all interactions with golden files. The top-level package
@@ -221,7 +243,7 @@ type Golden struct {
FileMode os.FileMode
// Suffix determines the filename suffix for all golden files. Typically
// this should be ".golden", but can be changed here if needed.
// this would be ".golden".
Suffix string
// Dirname is the name of the top-level directory at the root of the package
@@ -234,9 +256,7 @@ type Golden struct {
UpdateFunc UpdateFunc
}
// New returns a new *Golden instance with default values correctly
// populated. This is ideally how you should create a custom *Golden, and then
// modify the relevant fields as you see fit.
// New returns a new *Golden instance with default values correctly populated.
func New() *Golden {
return &Golden{
DirMode: DefaultDirMode,
@@ -247,35 +267,69 @@ func New() *Golden {
}
}
// Do is a convenience function for calling Update(), Set(), and Get() in a
// single call. If Update() returns true, data will be written to the golden
// file using Set(), before reading it back with Get().
func (s *Golden) Do(t TestingT, data []byte) []byte {
t.Helper()
if s.Update() {
s.Set(t, data)
}
return s.Get(t)
}
// File returns the filename of the golden file for the given *testing.T
// instance as determined by t.Name().
func (s *Golden) File(t *testing.T) string {
func (s *Golden) File(t TestingT) string {
t.Helper()
return s.file(t, "")
}
// Get returns the content of the golden file for the given *testing.T instance
// as determined by t.Name(). If no golden file can be found/read, it will fail
// the test by calling t.Fatal().
func (s *Golden) Get(t *testing.T) []byte {
func (s *Golden) Get(t TestingT) []byte {
t.Helper()
return s.get(t, "")
}
// Set writes given data to the golden file for the given *testing.T instance as
// determined by t.Name(). If writing fails it will fail the test by calling
// t.Fatal() with error details.
func (s *Golden) Set(t *testing.T, data []byte) {
func (s *Golden) Set(t TestingT, data []byte) {
t.Helper()
s.set(t, "", data)
}
// DoP is a convenience function for calling Update(), SetP(), and GetP() in a
// single call. If Update() returns true, data will be written to the golden
// file using SetP(), before reading it back with GetP().
func (s *Golden) DoP(t TestingT, name string, data []byte) []byte {
t.Helper()
if name == "" {
t.Fatalf("golden: name cannot be empty")
}
if s.Update() {
s.SetP(t, name, data)
}
return s.GetP(t, name)
}
// FileP returns the filename of the specifically named golden file for the
// given *testing.T instance as determined by t.Name().
func (s *Golden) FileP(t *testing.T, name string) string {
if name == "" {
if t != nil {
t.Fatal("golden: name cannot be empty")
}
func (s *Golden) FileP(t TestingT, name string) string {
t.Helper()
return ""
if name == "" {
t.Fatalf("golden: name cannot be empty")
}
return s.file(t, name)
@@ -287,11 +341,11 @@ func (s *Golden) FileP(t *testing.T, name string) string {
//
// This is very similar to Get(), but it allows multiple different golden files
// to be used within the same one *testing.T instance.
func (s *Golden) GetP(t *testing.T, name string) []byte {
if name == "" {
t.Fatal("golden: name cannot be empty")
func (s *Golden) GetP(t TestingT, name string) []byte {
t.Helper()
return nil
if name == "" {
t.Fatalf("golden: name cannot be empty")
}
return s.get(t, name)
@@ -303,19 +357,29 @@ func (s *Golden) GetP(t *testing.T, name string) []byte {
//
// This is very similar to Set(), but it allows multiple different golden files
// to be used within the same one *testing.T instance.
func (s *Golden) SetP(t *testing.T, name string, data []byte) {
func (s *Golden) SetP(t TestingT, name string, data []byte) {
t.Helper()
if name == "" {
t.Fatal("golden: name cannot be empty")
t.Fatalf("golden: name cannot be empty")
}
s.set(t, name, data)
}
func (s *Golden) file(t *testing.T, name string) string {
if t.Name() == "" {
t.Fatalf("golden: could not determine filename for: %+v", t)
// Update returns true when golden is set to update golden files. Should be used
// to determine if golden.Set() or golden.SetP() should be called or not.
//
// Default behavior uses EnvUpdateFunc() to check if the "GOLDEN_UPDATE"
// environment variable is set to a truthy value. To customize set a new
// UpdateFunc value on *Golden.
func (s *Golden) Update() bool {
return s.UpdateFunc()
}
return ""
func (s *Golden) file(t TestingT, name string) string {
if t.Name() == "" {
t.Fatalf("golden: could not determine filename")
}
base := []string{s.Dirname, filepath.FromSlash(t.Name())}
@@ -334,10 +398,10 @@ func (s *Golden) file(t *testing.T, name string) string {
return strings.Join(clean, string(os.PathSeparator))
}
func (s *Golden) get(t *testing.T, name string) []byte {
func (s *Golden) get(t TestingT, name string) []byte {
f := s.file(t, name)
b, err := ioutil.ReadFile(f)
b, err := os.ReadFile(f)
if err != nil {
t.Fatalf("golden: failed reading %s: %s", f, err.Error())
}
@@ -345,7 +409,7 @@ func (s *Golden) get(t *testing.T, name string) []byte {
return b
}
func (s *Golden) set(t *testing.T, name string, data []byte) {
func (s *Golden) set(t TestingT, name string, data []byte) {
f := s.file(t, name)
dir := filepath.Dir(f)
@@ -354,22 +418,10 @@ func (s *Golden) set(t *testing.T, name string, data []byte) {
err := os.MkdirAll(dir, s.DirMode)
if err != nil {
t.Fatalf("golden: failed to create directory: %s", err.Error())
return
}
err = ioutil.WriteFile(f, data, s.FileMode)
err = os.WriteFile(f, data, s.FileMode)
if err != nil {
t.Fatalf("golden: filed to write file: %s", err.Error())
}
}
// Update returns true when golden is set to update golden files. Should be used
// to determine if golden.Set() or golden.SetP() should be called or not.
//
// Default behavior uses EnvUpdateFunc() to check if the "GOLDEN_UPDATE"
// environment variable is set to a truthy value. To customize set a new
// UpdateFunc value on *Golden.
func (s *Golden) Update() bool {
return s.UpdateFunc()
}

View File

@@ -1,16 +1,201 @@
package golden
import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"runtime"
"testing"
"github.com/jimeh/envctl"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDefaults(t *testing.T) {
t.Run("Default", func(t *testing.T) {
assert.IsType(t, &Golden{}, Default)
assert.Equal(t, DefaultDirMode, Default.DirMode)
assert.Equal(t, DefaultFileMode, Default.FileMode)
assert.Equal(t, DefaultSuffix, Default.Suffix)
assert.Equal(t, DefaultDirname, Default.Dirname)
// Use runtime.FuncForPC() to verify the UpdateFunc value is set to
// the EnvUpdateFunc function by default.
gotFP := reflect.ValueOf(Default.UpdateFunc).Pointer()
gotFuncName := runtime.FuncForPC(gotFP).Name()
wantFP := reflect.ValueOf(EnvUpdateFunc).Pointer()
wantFuncName := runtime.FuncForPC(wantFP).Name()
assert.Equal(t, wantFuncName, gotFuncName)
})
t.Run("DefaultDirMode", func(t *testing.T) {
assert.Equal(t, os.FileMode(0o755), DefaultDirMode)
})
t.Run("DefaultFileMode", func(t *testing.T) {
assert.Equal(t, os.FileMode(0o644), DefaultFileMode)
})
t.Run("DefaultSuffix", func(t *testing.T) {
assert.Equal(t, ".golden", DefaultSuffix)
})
t.Run("DefaultDirname", func(t *testing.T) {
assert.Equal(t, "testdata", DefaultDirname)
})
t.Run("DefaultUpdateFunc", func(t *testing.T) {
gotFP := reflect.ValueOf(DefaultUpdateFunc).Pointer()
gotFuncName := runtime.FuncForPC(gotFP).Name()
wantFP := reflect.ValueOf(EnvUpdateFunc).Pointer()
wantFuncName := runtime.FuncForPC(wantFP).Name()
assert.Equal(t, wantFuncName, gotFuncName)
})
}
// TestNew is a horribly hack to test that the New() function uses the
// package-level Default* variables.
func TestNew(t *testing.T) {
// Capture the default values before we change them.
defaultDirMode := DefaultDirMode
defaultFileMode := DefaultFileMode
defaultSuffix := DefaultSuffix
defaultDirname := DefaultDirname
defaultUpdateFunc := DefaultUpdateFunc
// Restore the default values after the test.
t.Cleanup(func() {
DefaultDirMode = defaultDirMode
DefaultFileMode = defaultFileMode
DefaultSuffix = defaultSuffix
DefaultDirname = defaultDirname
DefaultUpdateFunc = defaultUpdateFunc
})
// Set all the default values to new values.
DefaultDirMode = os.FileMode(0o700)
DefaultFileMode = os.FileMode(0o600)
DefaultSuffix = ".gold"
DefaultDirname = "goldenfiles"
updateFunc := func() bool { return true }
DefaultUpdateFunc = updateFunc
// Create a new Golden instance with the new values.
got := New()
assert.Equal(t, DefaultDirMode, got.DirMode)
assert.Equal(t, DefaultFileMode, got.FileMode)
assert.Equal(t, DefaultSuffix, got.Suffix)
assert.Equal(t, DefaultDirname, got.Dirname)
// Verify the UpdateFunc value is set to the new value.
gotFP := reflect.ValueOf(got.UpdateFunc).Pointer()
gotFuncName := runtime.FuncForPC(gotFP).Name()
wantFP := reflect.ValueOf(updateFunc).Pointer()
wantFuncName := runtime.FuncForPC(wantFP).Name()
assert.Equal(t, wantFuncName, gotFuncName)
}
func TestDo(t *testing.T) {
t.Cleanup(func() {
err := os.RemoveAll(filepath.Join("testdata", "TestDo"))
require.NoError(t, err)
err = os.Remove(filepath.Join("testdata", "TestDo.golden"))
require.NoError(t, err)
})
//
// Test when Update is false
//
content := []byte("This is the golden file for TestDo")
err := os.MkdirAll("testdata", 0o755)
require.NoError(t, err)
err = os.WriteFile(
filepath.Join("testdata", "TestDo.golden"),
content, 0o600,
)
require.NoError(t, err)
newContent := []byte("This should not be written")
t.Setenv("GOLDEN_UPDATE", "false")
got := Do(t, newContent)
assert.Equal(t, content, got)
// Verify file wasn't changed
fileContent, err := os.ReadFile(
filepath.Join("testdata", "TestDo.golden"),
)
require.NoError(t, err)
assert.Equal(t, content, fileContent)
//
// Test when Update is true
//
updatedContent := []byte("This is the updated content for TestDo")
t.Setenv("GOLDEN_UPDATE", "true")
got = Do(t, updatedContent)
assert.Equal(t, updatedContent, got)
// Verify file was updated
fileContent, err = os.ReadFile(
filepath.Join("testdata", "TestDo.golden"),
)
require.NoError(t, err)
assert.Equal(t, updatedContent, fileContent)
//
// Test with sub-tests
//
tests := []struct {
name string
content []byte
}{
{
name: "simple",
content: []byte("Simple content for sub-test"),
},
{
name: "complex/path",
content: []byte("Complex path content for sub-test"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Test with Update true
t.Setenv("GOLDEN_UPDATE", "true")
got := Do(t, tt.content)
assert.Equal(t, tt.content, got)
// Verify file was written with correct content
f := File(t)
fileContent, err := os.ReadFile(f)
require.NoError(t, err)
assert.Equal(t, tt.content, fileContent)
// Test with Update false
t.Setenv("GOLDEN_UPDATE", "false")
newContent := []byte(
"This should not be written in sub-test",
)
got = Do(t, newContent)
assert.Equal(t, tt.content, got)
// Verify file wasn't changed
f = File(t)
fileContent, err = os.ReadFile(f)
require.NoError(t, err)
assert.Equal(t, tt.content, fileContent)
})
}
}
func TestFile(t *testing.T) {
got := File(t)
@@ -58,8 +243,8 @@ func TestGet(t *testing.T) {
require.NoError(t, err)
content := []byte("foobar\nhello world :)")
err = ioutil.WriteFile( //nolint:gosec
filepath.Join("testdata", "TestGet.golden"), content, 0o644,
err = os.WriteFile(
filepath.Join("testdata", "TestGet.golden"), content, 0o600,
)
require.NoError(t, err)
@@ -109,7 +294,7 @@ func TestGet(t *testing.T) {
err := os.MkdirAll(dir, 0o755)
require.NoError(t, err)
err = ioutil.WriteFile(f, tt.want, 0o644) //nolint:gosec
err = os.WriteFile(f, tt.want, 0o600)
require.NoError(t, err)
got := Get(t)
@@ -131,7 +316,7 @@ func TestSet(t *testing.T) {
content := []byte("This is the default golden file for TestSet ^_^")
Set(t, content)
b, err := ioutil.ReadFile(filepath.Join("testdata", "TestSet.golden"))
b, err := os.ReadFile(filepath.Join("testdata", "TestSet.golden"))
require.NoError(t, err)
assert.Equal(t, content, b)
@@ -177,7 +362,7 @@ func TestSet(t *testing.T) {
Set(t, tt.content)
got, err := ioutil.ReadFile(f)
got, err := os.ReadFile(f)
require.NoError(t, err)
assert.Equal(t, tt.file, f)
@@ -186,6 +371,97 @@ func TestSet(t *testing.T) {
}
}
func TestDoP(t *testing.T) {
t.Cleanup(func() {
err := os.RemoveAll(filepath.Join("testdata", "TestDoP"))
require.NoError(t, err)
})
//
// Test when Update is false
//
name := "test-format"
content := []byte("This is the golden file for TestDoP")
err := os.MkdirAll(filepath.Join("testdata", "TestDoP"), 0o755)
require.NoError(t, err)
goldenFile := filepath.Join("testdata", "TestDoP", name+".golden")
err = os.WriteFile(goldenFile, content, 0o600)
require.NoError(t, err)
newContent := []byte("This should not be written")
t.Setenv("GOLDEN_UPDATE", "false")
got := DoP(t, name, newContent)
assert.Equal(t, content, got)
// Verify file wasn't changed
fileContent, err := os.ReadFile(goldenFile)
require.NoError(t, err)
assert.Equal(t, content, fileContent)
//
// Test when Update is true
//
updatedContent := []byte("This is the updated content for TestDoP")
t.Setenv("GOLDEN_UPDATE", "true")
got = DoP(t, name, updatedContent)
assert.Equal(t, updatedContent, got)
// Verify file was updated
fileContent, err = os.ReadFile(goldenFile)
require.NoError(t, err)
assert.Equal(t, updatedContent, fileContent)
//
// Test with sub-tests
//
tests := []struct {
testName string
name string
content []byte
}{
{
testName: "json format",
name: "json",
content: []byte(`{"key": "value"}`),
},
{
testName: "xml format",
name: "xml",
content: []byte(`<root><key>value</key></root>`),
},
}
for _, tt := range tests {
t.Run(tt.testName, func(t *testing.T) {
// Test with Update true
t.Setenv("GOLDEN_UPDATE", "true")
got := DoP(t, tt.name, tt.content)
assert.Equal(t, tt.content, got)
// Verify file was written with correct content
f := FileP(t, tt.name)
fileContent, err := os.ReadFile(f)
require.NoError(t, err)
assert.Equal(t, tt.content, fileContent)
// Test with Update false
t.Setenv("GOLDEN_UPDATE", "false")
newContent := []byte(
"This should not be written in sub-test",
)
got = DoP(t, tt.name, newContent)
assert.Equal(t, tt.content, got)
// Verify file wasn't changed
f = FileP(t, tt.name)
fileContent, err = os.ReadFile(f)
require.NoError(t, err)
assert.Equal(t, tt.content, fileContent)
})
}
}
func TestFileP(t *testing.T) {
got := FileP(t, "sub-name")
assert.Equal(t,
@@ -247,9 +523,9 @@ func TestGetP(t *testing.T) {
require.NoError(t, err)
content := []byte("this is the named golden file for TestGetP")
err = ioutil.WriteFile( //nolint:gosec
err = os.WriteFile(
filepath.Join("testdata", "TestGetP", "sub-name.golden"),
content, 0o644,
content, 0o600,
)
require.NoError(t, err)
@@ -331,7 +607,7 @@ func TestGetP(t *testing.T) {
err := os.MkdirAll(dir, 0o755)
require.NoError(t, err)
err = ioutil.WriteFile(f, tt.want, 0o644) //nolint:gosec
err = os.WriteFile(f, tt.want, 0o600)
require.NoError(t, err)
got := GetP(t, tt.named)
@@ -351,7 +627,7 @@ func TestSetP(t *testing.T) {
content := []byte("This is the named golden file for TestSetP ^_^")
SetP(t, "sub-name", content)
b, err := ioutil.ReadFile(
b, err := os.ReadFile(
filepath.Join("testdata", "TestSetP", "sub-name.golden"),
)
require.NoError(t, err)
@@ -421,7 +697,7 @@ func TestSetP(t *testing.T) {
SetP(t, tt.named, tt.content)
got, err := ioutil.ReadFile(f)
got, err := os.ReadFile(f)
require.NoError(t, err)
assert.Equal(t, tt.file, f)
@@ -433,11 +709,13 @@ func TestSetP(t *testing.T) {
func TestUpdate(t *testing.T) {
for _, tt := range envUpdateFuncTestCases {
t.Run(tt.name, func(t *testing.T) {
envctl.WithClean(tt.env, func() {
got := Update()
for k, v := range tt.env {
t.Setenv(k, v)
}
assert.Equal(t, tt.want, got)
})
got := Update()
assert.Equal(t, tt.want, got)
})
}
}

9
testing_t.go Normal file
View File

@@ -0,0 +1,9 @@
package golden
type TestingT interface {
Errorf(format string, args ...interface{})
Fatalf(format string, args ...interface{})
Helper()
Logf(format string, args ...interface{})
Name() string
}

View File

@@ -1,6 +1,9 @@
package golden
import "os"
import (
"os"
"strings"
)
var truthyStrings = []string{"1", "y", "t", "yes", "on", "true"}
@@ -14,7 +17,7 @@ type UpdateFunc func() bool
func EnvUpdateFunc() bool {
env := os.Getenv("GOLDEN_UPDATE")
for _, v := range truthyStrings {
if env == v {
if strings.EqualFold(env, v) {
return true
}
}

View File

@@ -3,7 +3,6 @@ package golden
import (
"testing"
"github.com/jimeh/envctl"
"github.com/stretchr/testify/assert"
)
@@ -91,16 +90,44 @@ var envUpdateFuncTestCases = []struct {
env: map[string]string{"GOLDEN_UPDATE": "foobarnopebbq"},
want: false,
},
// Case-insensitive test cases
{
name: "GOLDEN_UPDATE set to Y (uppercase)",
env: map[string]string{"GOLDEN_UPDATE": "Y"},
want: true,
},
{
name: "GOLDEN_UPDATE set to TRUE (uppercase)",
env: map[string]string{"GOLDEN_UPDATE": "TRUE"},
want: true,
},
{
name: "GOLDEN_UPDATE set to Yes (mixed case)",
env: map[string]string{"GOLDEN_UPDATE": "Yes"},
want: true,
},
{
name: "GOLDEN_UPDATE set to ON (uppercase)",
env: map[string]string{"GOLDEN_UPDATE": "ON"},
want: true,
},
{
name: "GOLDEN_UPDATE set to TrUe (mixed case)",
env: map[string]string{"GOLDEN_UPDATE": "TrUe"},
want: true,
},
}
func TestEnvUpdateFunc(t *testing.T) {
for _, tt := range envUpdateFuncTestCases {
t.Run(tt.name, func(t *testing.T) {
envctl.WithClean(tt.env, func() {
got := EnvUpdateFunc()
for k, v := range tt.env {
t.Setenv(k, v)
}
assert.Equal(t, tt.want, got)
})
got := EnvUpdateFunc()
assert.Equal(t, tt.want, got)
})
}
}