mirror of
https://github.com/jimeh/go-golden.git
synced 2026-02-19 11:16:47 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a88e5174b | ||
| bc86ba7a6d | |||
| 62e8344ff3 | |||
| e46dc124ff | |||
| 6817ec6101 | |||
| 8f4d3d4170 | |||
| b2112ca475 | |||
|
27e0134701
|
|||
| 85ae6e9ae3 | |||
| f5a03af9ce |
3
.github/.release-please-manifest.json
vendored
Normal file
3
.github/.release-please-manifest.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
".": "0.2.0"
|
||||||
|
}
|
||||||
15
.github/release-please-config.json
vendored
Normal file
15
.github/release-please-config.json
vendored
Normal 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"
|
||||||
|
}
|
||||||
73
.github/workflows/ci.yml
vendored
73
.github/workflows/ci.yml
vendored
@@ -6,29 +6,28 @@ jobs:
|
|||||||
lint:
|
lint:
|
||||||
name: Lint
|
name: Lint
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: read
|
||||||
|
checks: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: golangci-lint
|
- uses: actions/setup-go@v5
|
||||||
uses: golangci/golangci-lint-action@v2
|
|
||||||
with:
|
with:
|
||||||
version: v1.42
|
go-version: stable
|
||||||
env:
|
- name: golangci-lint
|
||||||
VERBOSE: "true"
|
uses: golangci/golangci-lint-action@v6
|
||||||
|
with:
|
||||||
|
version: v1.64
|
||||||
|
|
||||||
tidy:
|
tidy:
|
||||||
name: Tidy
|
name: Tidy
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.15
|
go-version-file: go.mod
|
||||||
- uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: ~/go/pkg/mod
|
|
||||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-go-
|
|
||||||
- name: Check if mods are tidy
|
- name: Check if mods are tidy
|
||||||
run: make check-tidy
|
run: make check-tidy
|
||||||
|
|
||||||
@@ -36,18 +35,12 @@ jobs:
|
|||||||
name: Coverage
|
name: Coverage
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.15
|
go-version-file: go.mod
|
||||||
- uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: ~/go/pkg/mod
|
|
||||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-go-
|
|
||||||
- name: Publish coverage
|
- name: Publish coverage
|
||||||
uses: paambaati/codeclimate-action@v2.7.4
|
uses: paambaati/codeclimate-action@v9.0.0
|
||||||
env:
|
env:
|
||||||
VERBOSE: "true"
|
VERBOSE: "true"
|
||||||
GOMAXPROCS: 4
|
GOMAXPROCS: 4
|
||||||
@@ -68,20 +61,30 @@ jobs:
|
|||||||
- macos-latest
|
- macos-latest
|
||||||
- windows-latest
|
- windows-latest
|
||||||
go_version:
|
go_version:
|
||||||
- "1.15"
|
|
||||||
- "1.16"
|
|
||||||
- "1.17"
|
- "1.17"
|
||||||
|
- "1.18"
|
||||||
|
- "1.19"
|
||||||
|
- "1.20"
|
||||||
|
- "stable"
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go_version }}
|
go-version: ${{ matrix.go_version }}
|
||||||
- uses: actions/cache@v2
|
check-latest: true
|
||||||
with:
|
|
||||||
path: ~/go/pkg/mod
|
|
||||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-go-
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: go test -v -count=1 -race ./...
|
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 }}
|
||||||
|
|||||||
@@ -4,18 +4,13 @@ linters-settings:
|
|||||||
statements: 150
|
statements: 150
|
||||||
gocyclo:
|
gocyclo:
|
||||||
min-complexity: 20
|
min-complexity: 20
|
||||||
golint:
|
|
||||||
min-confidence: 0
|
|
||||||
govet:
|
govet:
|
||||||
check-shadowing: true
|
|
||||||
enable-all: true
|
enable-all: true
|
||||||
disable:
|
disable:
|
||||||
- fieldalignment
|
- fieldalignment
|
||||||
lll:
|
lll:
|
||||||
line-length: 80
|
line-length: 80
|
||||||
tab-width: 4
|
tab-width: 4
|
||||||
maligned:
|
|
||||||
suggest-new: true
|
|
||||||
misspell:
|
misspell:
|
||||||
locale: US
|
locale: US
|
||||||
|
|
||||||
@@ -24,13 +19,11 @@ linters:
|
|||||||
enable:
|
enable:
|
||||||
- asciicheck
|
- asciicheck
|
||||||
- bodyclose
|
- bodyclose
|
||||||
- deadcode
|
- copyloopvar
|
||||||
- depguard
|
|
||||||
- durationcheck
|
- durationcheck
|
||||||
- errcheck
|
- errcheck
|
||||||
- errorlint
|
- errorlint
|
||||||
- exhaustive
|
- exhaustive
|
||||||
- exportloopref
|
|
||||||
- funlen
|
- funlen
|
||||||
- gochecknoinits
|
- gochecknoinits
|
||||||
- goconst
|
- goconst
|
||||||
@@ -58,13 +51,10 @@ linters:
|
|||||||
- rowserrcheck
|
- rowserrcheck
|
||||||
- sqlclosecheck
|
- sqlclosecheck
|
||||||
- staticcheck
|
- staticcheck
|
||||||
- structcheck
|
|
||||||
- tparallel
|
|
||||||
- typecheck
|
- typecheck
|
||||||
- unconvert
|
- unconvert
|
||||||
- unparam
|
- unparam
|
||||||
- unused
|
- unused
|
||||||
- varcheck
|
|
||||||
- wastedassign
|
- wastedassign
|
||||||
- whitespace
|
- whitespace
|
||||||
|
|
||||||
|
|||||||
15
CHANGELOG.md
15
CHANGELOG.md
@@ -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.
|
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)
|
## 0.1.0 (2021-10-28)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
35
Makefile
35
Makefile
@@ -34,23 +34,19 @@ SHELL := env \
|
|||||||
# Tools
|
# Tools
|
||||||
#
|
#
|
||||||
|
|
||||||
TOOLS += $(TOOLDIR)/gobin
|
|
||||||
$(TOOLDIR)/gobin:
|
|
||||||
GO111MODULE=off go get -u github.com/myitcv/gobin
|
|
||||||
|
|
||||||
# external tool
|
# external tool
|
||||||
define tool # 1: binary-name, 2: go-import-path
|
define tool # 1: binary-name, 2: go-import-path
|
||||||
TOOLS += $(TOOLDIR)/$(1)
|
TOOLS += $(TOOLDIR)/$(1)
|
||||||
|
|
||||||
$(TOOLDIR)/$(1): $(TOOLDIR)/gobin Makefile
|
$(TOOLDIR)/$(1): Makefile
|
||||||
gobin $(V) "$(2)"
|
GOBIN="$(CURDIR)/$(TOOLDIR)" go install "$(2)"
|
||||||
endef
|
endef
|
||||||
|
|
||||||
$(eval $(call tool,godoc,golang.org/x/tools/cmd/godoc))
|
$(eval $(call tool,godoc,golang.org/x/tools/cmd/godoc@latest))
|
||||||
$(eval $(call tool,gofumpt,mvdan.cc/gofumpt))
|
$(eval $(call tool,gofumpt,mvdan.cc/gofumpt@latest))
|
||||||
$(eval $(call tool,goimports,golang.org/x/tools/cmd/goimports))
|
$(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.42))
|
$(eval $(call tool,golangci-lint,github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64))
|
||||||
$(eval $(call tool,gomod,github.com/Helcaraxan/gomod))
|
$(eval $(call tool,gomod,github.com/Helcaraxan/gomod@latest))
|
||||||
|
|
||||||
.PHONY: tools
|
.PHONY: tools
|
||||||
tools: $(TOOLS)
|
tools: $(TOOLS)
|
||||||
@@ -186,20 +182,3 @@ check-tidy:
|
|||||||
docs: $(TOOLDIR)/godoc
|
docs: $(TOOLDIR)/godoc
|
||||||
$(info serviing docs on http://127.0.0.1:6060/pkg/$(GOMODNAME)/)
|
$(info serviing docs on http://127.0.0.1:6060/pkg/$(GOMODNAME)/)
|
||||||
@godoc -http=127.0.0.1:6060
|
@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))
|
|
||||||
|
|||||||
46
README.md
46
README.md
@@ -10,26 +10,12 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://pkg.go.dev/github.com/jimeh/go-golden">
|
<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>
|
||||||
<img src="https://img.shields.io/badge/%E2%80%8B-reference-387b97.svg?logo=go&logoColor=white"
|
<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>
|
||||||
alt="Go Reference">
|
<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>
|
<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/actions">
|
<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>
|
||||||
<img src="https://img.shields.io/github/workflow/status/jimeh/go-golden/CI.svg?logo=github" alt="Actions Status">
|
<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>
|
|
||||||
<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>
|
</p>
|
||||||
|
|
||||||
## Import
|
## Import
|
||||||
@@ -42,15 +28,12 @@ import "github.com/jimeh/go-golden"
|
|||||||
|
|
||||||
```go
|
```go
|
||||||
func TestExampleMyStruct(t *testing.T) {
|
func TestExampleMyStruct(t *testing.T) {
|
||||||
got, err := json.Marshal(&MyStruct{Foo: "Bar"})
|
got, err := json.Marshal(&MyStruct{Foo: "Bar"})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if golden.Update() {
|
want := golden.Do(t, got)
|
||||||
golden.Set(t, got)
|
|
||||||
}
|
|
||||||
want := golden.Get(t)
|
|
||||||
|
|
||||||
assert.Equal(t, want, got)
|
assert.Equal(t, want, got)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -58,6 +41,15 @@ The above example will read/write to:
|
|||||||
|
|
||||||
- `testdata/TestExampleMyStruct.golden`
|
- `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
|
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
|
`GOLDEN_UPDATE` environment variable to one of `1`, `y`, `t`, `yes`, `on`, or
|
||||||
`true` when running tests.
|
`true` when running tests.
|
||||||
|
|||||||
@@ -10,31 +10,29 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// The tests in this file are examples from the README and the package-level Go
|
||||||
|
// documentation.
|
||||||
|
|
||||||
type MyStruct struct {
|
type MyStruct struct {
|
||||||
Foo string `json:"foo,omitempty"`
|
Foo string `json:"foo,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestExampleMyStruct reads/writes the following golden file:
|
// TestExampleMyStruct reads/writes the following golden file:
|
||||||
//
|
//
|
||||||
// testdata/TestExampleMyStruct.golden
|
// testdata/TestExampleMyStruct.golden
|
||||||
//
|
|
||||||
func TestExampleMyStruct(t *testing.T) {
|
func TestExampleMyStruct(t *testing.T) {
|
||||||
got, err := json.Marshal(&MyStruct{Foo: "Bar"})
|
got, err := json.Marshal(&MyStruct{Foo: "Bar"})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if golden.Update() {
|
want := golden.Do(t, got)
|
||||||
golden.Set(t, got)
|
|
||||||
}
|
|
||||||
want := golden.Get(t)
|
|
||||||
|
|
||||||
assert.Equal(t, want, got)
|
assert.Equal(t, want, got)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestExampleMyStructTabular reads/writes the following golden files:
|
// TestExampleMyStructTabular reads/writes the following golden files:
|
||||||
//
|
//
|
||||||
// testdata/TestExampleMyStructTabular/empty_struct.golden
|
// testdata/TestExampleMyStructTabular/empty_struct.golden
|
||||||
// testdata/TestExampleMyStructTabular/full_struct.golden
|
// testdata/TestExampleMyStructTabular/full_struct.golden
|
||||||
//
|
|
||||||
func TestExampleMyStructTabular(t *testing.T) {
|
func TestExampleMyStructTabular(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -48,10 +46,7 @@ func TestExampleMyStructTabular(t *testing.T) {
|
|||||||
got, err := json.Marshal(tt.obj)
|
got, err := json.Marshal(tt.obj)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if golden.Update() {
|
want := golden.Do(t, got)
|
||||||
golden.Set(t, got)
|
|
||||||
}
|
|
||||||
want := golden.Get(t)
|
|
||||||
|
|
||||||
assert.Equal(t, want, got)
|
assert.Equal(t, want, got)
|
||||||
})
|
})
|
||||||
@@ -60,29 +55,25 @@ func TestExampleMyStructTabular(t *testing.T) {
|
|||||||
|
|
||||||
// TestExampleMyStructP reads/writes the following golden file:
|
// TestExampleMyStructP reads/writes the following golden file:
|
||||||
//
|
//
|
||||||
// testdata/TestExampleMyStructP/json.golden
|
// testdata/TestExampleMyStructP/json.golden
|
||||||
// testdata/TestExampleMyStructP/xml.golden
|
// testdata/TestExampleMyStructP/xml.golden
|
||||||
//
|
|
||||||
func TestExampleMyStructP(t *testing.T) {
|
func TestExampleMyStructP(t *testing.T) {
|
||||||
gotJSON, _ := json.Marshal(&MyStruct{Foo: "Bar"})
|
gotJSON, _ := json.Marshal(&MyStruct{Foo: "Bar"})
|
||||||
gotXML, _ := xml.Marshal(&MyStruct{Foo: "Bar"})
|
gotXML, _ := xml.Marshal(&MyStruct{Foo: "Bar"})
|
||||||
|
|
||||||
if golden.Update() {
|
wantJSON := golden.DoP(t, "json", gotJSON)
|
||||||
golden.SetP(t, "json", gotJSON)
|
wantXML := golden.DoP(t, "xml", gotXML)
|
||||||
golden.SetP(t, "xml", gotXML)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(t, golden.GetP(t, "json"), gotJSON)
|
assert.Equal(t, wantJSON, gotJSON)
|
||||||
assert.Equal(t, golden.GetP(t, "xml"), gotXML)
|
assert.Equal(t, wantXML, gotXML)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestExampleMyStructTabularP reads/writes the following golden file:
|
// TestExampleMyStructTabularP reads/writes the following golden file:
|
||||||
//
|
//
|
||||||
// testdata/TestExampleMyStructTabularP/empty_struct/json.golden
|
// testdata/TestExampleMyStructTabularP/empty_struct/json.golden
|
||||||
// testdata/TestExampleMyStructTabularP/empty_struct/xml.golden
|
// testdata/TestExampleMyStructTabularP/empty_struct/xml.golden
|
||||||
// testdata/TestExampleMyStructTabularP/full_struct/json.golden
|
// testdata/TestExampleMyStructTabularP/full_struct/json.golden
|
||||||
// testdata/TestExampleMyStructTabularP/full_struct/xml.golden
|
// testdata/TestExampleMyStructTabularP/full_struct/xml.golden
|
||||||
//
|
|
||||||
func TestExampleMyStructTabularP(t *testing.T) {
|
func TestExampleMyStructTabularP(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -96,13 +87,11 @@ func TestExampleMyStructTabularP(t *testing.T) {
|
|||||||
gotJSON, _ := json.Marshal(tt.obj)
|
gotJSON, _ := json.Marshal(tt.obj)
|
||||||
gotXML, _ := xml.Marshal(tt.obj)
|
gotXML, _ := xml.Marshal(tt.obj)
|
||||||
|
|
||||||
if golden.Update() {
|
wantJSON := golden.DoP(t, "json", gotJSON)
|
||||||
golden.SetP(t, "json", gotJSON)
|
wantXML := golden.DoP(t, "xml", gotXML)
|
||||||
golden.SetP(t, "xml", gotXML)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(t, golden.GetP(t, "json"), gotJSON)
|
assert.Equal(t, wantJSON, gotJSON)
|
||||||
assert.Equal(t, golden.GetP(t, "xml"), gotXML)
|
assert.Equal(t, wantXML, gotXML)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
9
go.mod
9
go.mod
@@ -1,8 +1,11 @@
|
|||||||
module github.com/jimeh/go-golden
|
module github.com/jimeh/go-golden
|
||||||
|
|
||||||
go 1.15
|
go 1.17
|
||||||
|
|
||||||
|
require github.com/stretchr/testify v1.10.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/jimeh/envctl v0.1.0
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
19
go.sum
19
go.sum
@@ -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/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/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/jimeh/envctl v0.1.0/go.mod h1:aM27ffBbO1yUBKUzgJGCUorS4z+wyh+qhQe1ruxXZZo=
|
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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/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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
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 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
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.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
326
golden.go
@@ -1,178 +1,200 @@
|
|||||||
// Package golden is yet another package for working with *.golden test files,
|
// Package golden is yet another package for working with *.golden test files,
|
||||||
// with a focus on simplicity through it's default behavior.
|
// 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
|
// names by calling t.Name(). File names are sanitized to ensure they're
|
||||||
// compatible with Linux, macOS and Windows systems regardless of what crazy
|
// 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:
|
// Typical usage should look something like this:
|
||||||
//
|
//
|
||||||
// func TestExampleMyStruct(t *testing.T) {
|
// func TestExampleMyStruct(t *testing.T) {
|
||||||
// got, err := json.Marshal(&MyStruct{Foo: "Bar"})
|
// got, err := json.Marshal(&MyStruct{Foo: "Bar"})
|
||||||
// require.NoError(t, err)
|
// require.NoError(t, err)
|
||||||
//
|
//
|
||||||
// if golden.Update() {
|
// want := golden.Do(t, got)
|
||||||
// golden.Set(t, got)
|
|
||||||
// }
|
|
||||||
// want := golden.Get(t)
|
|
||||||
//
|
//
|
||||||
// assert.Equal(t, want, got)
|
// assert.Equal(t, want, got)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// The above example will read/write to:
|
// 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
|
// 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
|
// GOLDEN_UPDATE environment variable to one of "1", "y", "t", "yes", "on", or
|
||||||
// "true" when running tests.
|
// "true" when running tests.
|
||||||
//
|
//
|
||||||
// Sub-Tests
|
// # Sub-Tests
|
||||||
//
|
//
|
||||||
// As the golden filename is based on t.Name(), it works with sub-tests too,
|
// 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) {
|
// func TestExampleMyStructTabular(t *testing.T) {
|
||||||
// tests := []struct {
|
// tests := []struct {
|
||||||
// name string
|
// name string
|
||||||
// obj *MyStruct
|
// obj *MyStruct
|
||||||
// }{
|
// }{
|
||||||
// {name: "empty struct", obj: &MyStruct{}},
|
// {name: "empty struct", obj: &MyStruct{}},
|
||||||
// {name: "full struct", obj: &MyStruct{Foo: "Bar"}},
|
// {name: "full struct", obj: &MyStruct{Foo: "Bar"}},
|
||||||
// }
|
// }
|
||||||
// for _, tt := range tests {
|
// for _, tt := range tests {
|
||||||
// t.Run(tt.name, func(t *testing.T) {
|
// t.Run(tt.name, func(t *testing.T) {
|
||||||
// got, err := json.Marshal(tt.obj)
|
// got, err := json.Marshal(tt.obj)
|
||||||
// require.NoError(t, err)
|
// require.NoError(t, err)
|
||||||
//
|
//
|
||||||
// if golden.Update() {
|
// want := golden.Do(t, got)
|
||||||
// golden.Set(t, got)
|
|
||||||
// }
|
|
||||||
// want := golden.Get(t)
|
|
||||||
//
|
//
|
||||||
// assert.Equal(t, want, got)
|
// assert.Equal(t, want, got)
|
||||||
// })
|
// })
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// The above example will read/write to:
|
// The above example will read/write to:
|
||||||
//
|
//
|
||||||
// testdata/TestExampleMyStructTabular/empty_struct.golden
|
// testdata/TestExampleMyStructTabular/empty_struct.golden
|
||||||
// testdata/TestExampleMyStructTabular/full_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
|
// The "P" suffixed methods, GetP(), SetP(), and FileP(), all take a name
|
||||||
// argument which allows using specific golden files within a given *testing.T
|
// argument which allows using specific golden files within a given *testing.T
|
||||||
// instance.
|
// instance.
|
||||||
//
|
//
|
||||||
// func TestExampleMyStructP(t *testing.T) {
|
// func TestExampleMyStructP(t *testing.T) {
|
||||||
// gotJSON, _ := json.Marshal(&MyStruct{Foo: "Bar"})
|
// gotJSON, _ := json.Marshal(&MyStruct{Foo: "Bar"})
|
||||||
// gotXML, _ := xml.Marshal(&MyStruct{Foo: "Bar"})
|
// gotXML, _ := xml.Marshal(&MyStruct{Foo: "Bar"})
|
||||||
//
|
//
|
||||||
// if golden.Update() {
|
// wantJSON := golden.DoP(t, "json", gotJSON)
|
||||||
// golden.SetP(t, "json", gotJSON)
|
// wantXML := golden.DoP(t, "xml", gotXML)
|
||||||
// golden.SetP(t, "xml", gotXML)
|
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
// assert.Equal(t, golden.GetP(t, "json"), gotJSON)
|
// assert.Equal(t, wantJSON, gotJSON)
|
||||||
// assert.Equal(t, golden.GetP(t, "xml"), gotXML)
|
// assert.Equal(t, wantXML, gotXML)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// The above example will read/write to:
|
// The above example will read/write to:
|
||||||
//
|
//
|
||||||
// testdata/TestExampleMyStructP/json.golden
|
// testdata/TestExampleMyStructP/json.golden
|
||||||
// testdata/TestExampleMyStructP/xml.golden
|
// testdata/TestExampleMyStructP/xml.golden
|
||||||
//
|
//
|
||||||
// This works with tabular tests too of course:
|
// This works with tabular tests too of course:
|
||||||
//
|
//
|
||||||
// func TestExampleMyStructTabularP(t *testing.T) {
|
// func TestExampleMyStructTabularP(t *testing.T) {
|
||||||
// tests := []struct {
|
// tests := []struct {
|
||||||
// name string
|
// name string
|
||||||
// obj *MyStruct
|
// obj *MyStruct
|
||||||
// }{
|
// }{
|
||||||
// {name: "empty struct", obj: &MyStruct{}},
|
// {name: "empty struct", obj: &MyStruct{}},
|
||||||
// {name: "full struct", obj: &MyStruct{Foo: "Bar"}},
|
// {name: "full struct", obj: &MyStruct{Foo: "Bar"}},
|
||||||
// }
|
// }
|
||||||
// for _, tt := range tests {
|
// for _, tt := range tests {
|
||||||
// t.Run(tt.name, func(t *testing.T) {
|
// t.Run(tt.name, func(t *testing.T) {
|
||||||
// gotJSON, _ := json.Marshal(tt.obj)
|
// gotJSON, _ := json.Marshal(tt.obj)
|
||||||
// gotXML, _ := xml.Marshal(tt.obj)
|
// gotXML, _ := xml.Marshal(tt.obj)
|
||||||
//
|
//
|
||||||
// if golden.Update() {
|
// wantJSON := golden.DoP(t, "json", gotJSON)
|
||||||
// golden.SetP(t, "json", gotJSON)
|
// wantXML := golden.DoP(t, "xml", gotXML)
|
||||||
// golden.SetP(t, "xml", gotXML)
|
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
// assert.Equal(t, golden.GetP(t, "json"), gotJSON)
|
// assert.Equal(t, wantJSON, gotJSON)
|
||||||
// assert.Equal(t, golden.GetP(t, "xml"), gotXML)
|
// assert.Equal(t, wantXML, gotXML)
|
||||||
// })
|
// })
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// The above example will read/write to:
|
// The above example will read/write to:
|
||||||
//
|
//
|
||||||
// testdata/TestExampleMyStructTabularP/empty_struct/json.golden
|
// testdata/TestExampleMyStructTabularP/empty_struct/json.golden
|
||||||
// testdata/TestExampleMyStructTabularP/empty_struct/xml.golden
|
// testdata/TestExampleMyStructTabularP/empty_struct/xml.golden
|
||||||
// testdata/TestExampleMyStructTabularP/full_struct/json.golden
|
// testdata/TestExampleMyStructTabularP/full_struct/json.golden
|
||||||
// testdata/TestExampleMyStructTabularP/full_struct/xml.golden
|
// testdata/TestExampleMyStructTabularP/full_struct/xml.golden
|
||||||
//
|
|
||||||
package golden
|
package golden
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
var (
|
||||||
DefaultDirMode = 0o755
|
// Default is the default *Golden instance. All package-level functions use
|
||||||
DefaultFileMode = 0o644
|
// the Default instance.
|
||||||
DefaultSuffix = ".golden"
|
Default = New()
|
||||||
DefaultDirname = "testdata"
|
|
||||||
|
// 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
|
// File returns the filename of the golden file for the given *testing.T
|
||||||
// instance as determined by t.Name().
|
// instance as determined by t.Name().
|
||||||
func File(t *testing.T) string {
|
func File(t TestingT) string {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
return global.File(t)
|
return Default.File(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the content of the golden file for the given *testing.T instance
|
// 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
|
// as determined by t.Name(). If no golden file can be found/read, it will fail
|
||||||
// the test by calling t.Fatal().
|
// the test by calling t.Fatal().
|
||||||
func Get(t *testing.T) []byte {
|
func Get(t TestingT) []byte {
|
||||||
t.Helper()
|
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
|
// 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
|
// determined by t.Name(). If writing fails it will fail the test by calling
|
||||||
// t.Fatal() with error details.
|
// t.Fatal() with error details.
|
||||||
func Set(t *testing.T, data []byte) {
|
func Set(t TestingT, data []byte) {
|
||||||
t.Helper()
|
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
|
// FileP returns the filename of the specifically named golden file for the
|
||||||
// given *testing.T instance as determined by t.Name().
|
// 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()
|
t.Helper()
|
||||||
|
|
||||||
return global.FileP(t, name)
|
return Default.FileP(t, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetP returns the content of the specifically named golden file belonging
|
// 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
|
// This is very similar to Get(), but it allows multiple different golden files
|
||||||
// to be used within the same one *testing.T instance.
|
// 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()
|
t.Helper()
|
||||||
|
|
||||||
return global.GetP(t, name)
|
return Default.GetP(t, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetP writes given data of the specifically named golden file belonging to
|
// 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
|
// This is very similar to Set(), but it allows multiple different golden files
|
||||||
// to be used within the same one *testing.T instance.
|
// 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()
|
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
|
// 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
|
// environment variable is set to a truthy value. To customize create a custom
|
||||||
// *Golden instance with New() and set a new UpdateFunc value.
|
// *Golden instance with New() and set a new UpdateFunc value.
|
||||||
func Update() bool {
|
func Update() bool {
|
||||||
return global.Update()
|
return Default.Update()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Golden handles all interactions with golden files. The top-level package
|
// Golden handles all interactions with golden files. The top-level package
|
||||||
@@ -221,7 +243,7 @@ type Golden struct {
|
|||||||
FileMode os.FileMode
|
FileMode os.FileMode
|
||||||
|
|
||||||
// Suffix determines the filename suffix for all golden files. Typically
|
// 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
|
Suffix string
|
||||||
|
|
||||||
// Dirname is the name of the top-level directory at the root of the package
|
// Dirname is the name of the top-level directory at the root of the package
|
||||||
@@ -234,9 +256,7 @@ type Golden struct {
|
|||||||
UpdateFunc UpdateFunc
|
UpdateFunc UpdateFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new *Golden instance with default values correctly
|
// New returns a new *Golden instance with default values correctly populated.
|
||||||
// populated. This is ideally how you should create a custom *Golden, and then
|
|
||||||
// modify the relevant fields as you see fit.
|
|
||||||
func New() *Golden {
|
func New() *Golden {
|
||||||
return &Golden{
|
return &Golden{
|
||||||
DirMode: DefaultDirMode,
|
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
|
// File returns the filename of the golden file for the given *testing.T
|
||||||
// instance as determined by t.Name().
|
// 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, "")
|
return s.file(t, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the content of the golden file for the given *testing.T instance
|
// 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
|
// as determined by t.Name(). If no golden file can be found/read, it will fail
|
||||||
// the test by calling t.Fatal().
|
// 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, "")
|
return s.get(t, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set writes given data to the golden file for the given *testing.T instance as
|
// 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
|
// determined by t.Name(). If writing fails it will fail the test by calling
|
||||||
// t.Fatal() with error details.
|
// 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)
|
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
|
// FileP returns the filename of the specifically named golden file for the
|
||||||
// given *testing.T instance as determined by t.Name().
|
// given *testing.T instance as determined by t.Name().
|
||||||
func (s *Golden) FileP(t *testing.T, name string) string {
|
func (s *Golden) FileP(t TestingT, name string) string {
|
||||||
if name == "" {
|
t.Helper()
|
||||||
if t != nil {
|
|
||||||
t.Fatal("golden: name cannot be empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
if name == "" {
|
||||||
|
t.Fatalf("golden: name cannot be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.file(t, name)
|
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
|
// This is very similar to Get(), but it allows multiple different golden files
|
||||||
// to be used within the same one *testing.T instance.
|
// to be used within the same one *testing.T instance.
|
||||||
func (s *Golden) GetP(t *testing.T, name string) []byte {
|
func (s *Golden) GetP(t TestingT, name string) []byte {
|
||||||
if name == "" {
|
t.Helper()
|
||||||
t.Fatal("golden: name cannot be empty")
|
|
||||||
|
|
||||||
return nil
|
if name == "" {
|
||||||
|
t.Fatalf("golden: name cannot be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.get(t, name)
|
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
|
// This is very similar to Set(), but it allows multiple different golden files
|
||||||
// to be used within the same one *testing.T instance.
|
// 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 == "" {
|
if name == "" {
|
||||||
t.Fatal("golden: name cannot be empty")
|
t.Fatalf("golden: name cannot be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.set(t, name, data)
|
s.set(t, name, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Golden) file(t *testing.T, name string) string {
|
// Update returns true when golden is set to update golden files. Should be used
|
||||||
if t.Name() == "" {
|
// to determine if golden.Set() or golden.SetP() should be called or not.
|
||||||
t.Fatalf("golden: could not determine filename for: %+v", t)
|
//
|
||||||
|
// 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())}
|
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))
|
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)
|
f := s.file(t, name)
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(f)
|
b, err := os.ReadFile(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("golden: failed reading %s: %s", f, err.Error())
|
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
|
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)
|
f := s.file(t, name)
|
||||||
dir := filepath.Dir(f)
|
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)
|
err := os.MkdirAll(dir, s.DirMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("golden: failed to create directory: %s", err.Error())
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("golden: filed to write file: %s", err.Error())
|
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()
|
|
||||||
}
|
|
||||||
|
|||||||
310
golden_test.go
310
golden_test.go
@@ -1,16 +1,201 @@
|
|||||||
package golden
|
package golden
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/jimeh/envctl"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"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) {
|
func TestFile(t *testing.T) {
|
||||||
got := File(t)
|
got := File(t)
|
||||||
|
|
||||||
@@ -58,8 +243,8 @@ func TestGet(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
content := []byte("foobar\nhello world :)")
|
content := []byte("foobar\nhello world :)")
|
||||||
err = ioutil.WriteFile( //nolint:gosec
|
err = os.WriteFile(
|
||||||
filepath.Join("testdata", "TestGet.golden"), content, 0o644,
|
filepath.Join("testdata", "TestGet.golden"), content, 0o600,
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -109,7 +294,7 @@ func TestGet(t *testing.T) {
|
|||||||
err := os.MkdirAll(dir, 0o755)
|
err := os.MkdirAll(dir, 0o755)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = ioutil.WriteFile(f, tt.want, 0o644) //nolint:gosec
|
err = os.WriteFile(f, tt.want, 0o600)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
got := Get(t)
|
got := Get(t)
|
||||||
@@ -131,7 +316,7 @@ func TestSet(t *testing.T) {
|
|||||||
content := []byte("This is the default golden file for TestSet ^_^")
|
content := []byte("This is the default golden file for TestSet ^_^")
|
||||||
Set(t, content)
|
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)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, content, b)
|
assert.Equal(t, content, b)
|
||||||
@@ -177,7 +362,7 @@ func TestSet(t *testing.T) {
|
|||||||
|
|
||||||
Set(t, tt.content)
|
Set(t, tt.content)
|
||||||
|
|
||||||
got, err := ioutil.ReadFile(f)
|
got, err := os.ReadFile(f)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, tt.file, f)
|
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) {
|
func TestFileP(t *testing.T) {
|
||||||
got := FileP(t, "sub-name")
|
got := FileP(t, "sub-name")
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
@@ -247,9 +523,9 @@ func TestGetP(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
content := []byte("this is the named golden file for TestGetP")
|
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"),
|
filepath.Join("testdata", "TestGetP", "sub-name.golden"),
|
||||||
content, 0o644,
|
content, 0o600,
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -331,7 +607,7 @@ func TestGetP(t *testing.T) {
|
|||||||
err := os.MkdirAll(dir, 0o755)
|
err := os.MkdirAll(dir, 0o755)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = ioutil.WriteFile(f, tt.want, 0o644) //nolint:gosec
|
err = os.WriteFile(f, tt.want, 0o600)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
got := GetP(t, tt.named)
|
got := GetP(t, tt.named)
|
||||||
@@ -351,7 +627,7 @@ func TestSetP(t *testing.T) {
|
|||||||
content := []byte("This is the named golden file for TestSetP ^_^")
|
content := []byte("This is the named golden file for TestSetP ^_^")
|
||||||
SetP(t, "sub-name", content)
|
SetP(t, "sub-name", content)
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(
|
b, err := os.ReadFile(
|
||||||
filepath.Join("testdata", "TestSetP", "sub-name.golden"),
|
filepath.Join("testdata", "TestSetP", "sub-name.golden"),
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -421,7 +697,7 @@ func TestSetP(t *testing.T) {
|
|||||||
|
|
||||||
SetP(t, tt.named, tt.content)
|
SetP(t, tt.named, tt.content)
|
||||||
|
|
||||||
got, err := ioutil.ReadFile(f)
|
got, err := os.ReadFile(f)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, tt.file, f)
|
assert.Equal(t, tt.file, f)
|
||||||
@@ -433,11 +709,13 @@ func TestSetP(t *testing.T) {
|
|||||||
func TestUpdate(t *testing.T) {
|
func TestUpdate(t *testing.T) {
|
||||||
for _, tt := range envUpdateFuncTestCases {
|
for _, tt := range envUpdateFuncTestCases {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
envctl.WithClean(tt.env, func() {
|
for k, v := range tt.env {
|
||||||
got := Update()
|
t.Setenv(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
assert.Equal(t, tt.want, got)
|
got := Update()
|
||||||
})
|
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
9
testing_t.go
Normal file
9
testing_t.go
Normal 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
|
||||||
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
package golden
|
package golden
|
||||||
|
|
||||||
import "os"
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
var truthyStrings = []string{"1", "y", "t", "yes", "on", "true"}
|
var truthyStrings = []string{"1", "y", "t", "yes", "on", "true"}
|
||||||
|
|
||||||
@@ -14,7 +17,7 @@ type UpdateFunc func() bool
|
|||||||
func EnvUpdateFunc() bool {
|
func EnvUpdateFunc() bool {
|
||||||
env := os.Getenv("GOLDEN_UPDATE")
|
env := os.Getenv("GOLDEN_UPDATE")
|
||||||
for _, v := range truthyStrings {
|
for _, v := range truthyStrings {
|
||||||
if env == v {
|
if strings.EqualFold(env, v) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package golden
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/jimeh/envctl"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -91,16 +90,44 @@ var envUpdateFuncTestCases = []struct {
|
|||||||
env: map[string]string{"GOLDEN_UPDATE": "foobarnopebbq"},
|
env: map[string]string{"GOLDEN_UPDATE": "foobarnopebbq"},
|
||||||
want: false,
|
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) {
|
func TestEnvUpdateFunc(t *testing.T) {
|
||||||
for _, tt := range envUpdateFuncTestCases {
|
for _, tt := range envUpdateFuncTestCases {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
envctl.WithClean(tt.env, func() {
|
for k, v := range tt.env {
|
||||||
got := EnvUpdateFunc()
|
t.Setenv(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
assert.Equal(t, tt.want, got)
|
got := EnvUpdateFunc()
|
||||||
})
|
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user