Skip to content

Commit

Permalink
util: add TempFile helper
Browse files Browse the repository at this point in the history
  • Loading branch information
brandondyck committed Aug 23, 2024
1 parent 2e48df0 commit 73a741a
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 62 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ There are five key packages,

### Changes

:ballot_box_with_check: v1.10.0 adds a `util` package for helpers that return values

- Adds ability to create and automatically clean up temporary files

:ballot_box_with_check: v1.9.0 substantially improves filesystem tests

- Greater compatibility with Windows
Expand Down
41 changes: 10 additions & 31 deletions must/must_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 10 additions & 31 deletions test_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"testing/fstest"
"time"

"github.com/shoenig/test/util"
"github.com/shoenig/test/wait"
)

Expand Down Expand Up @@ -1354,15 +1355,6 @@ func TestMapNotContainsValueEqual(t *testing.T) {
MapNotContainsValueEqual(tc, m, &Person{ID: 200, Name: "Daisy"})
}

func writeTempFile(t *testing.T, name, data string) (path string) {
path = filepath.Join(t.TempDir(), name)
err := os.WriteFile(path, []byte(data), os.ModePerm)
if err != nil {
t.Fatal("failed to create temp file")
}
return path
}

func TestFileExistsFS(t *testing.T) {
t.Run("file does not exist", func(t *testing.T) {
tc := newCase(t, `expected file to exist`)
Expand All @@ -1389,7 +1381,7 @@ func TestFileExists(t *testing.T) {
tc := newCase(t, "")
t.Cleanup(tc.assertNot)

FileExists(tc, writeTempFile(t, "real", ""))
FileExists(tc, util.TempFile(t, util.Pattern("real")))
})
}

Expand All @@ -1413,7 +1405,7 @@ func TestFileNotExists(t *testing.T) {
tc := newCase(t, `expected file to not exist`)
t.Cleanup(tc.assert)

FileNotExists(tc, writeTempFile(t, "real", ""))
FileNotExists(tc, util.TempFile(t, util.Pattern("real")))
})
t.Run("file does not exist", func(t *testing.T) {
tc := newCase(t, "")
Expand Down Expand Up @@ -1511,21 +1503,6 @@ func TestFileModeFS(t *testing.T) {
})
}

func createFileWithPerm(t *testing.T, perm fs.FileMode) (path string) {
t.Helper()
f, err := os.CreateTemp(t.TempDir(), "")
if err != nil {
t.Fatal("failed to created temp file")
}
f.Close()
err = os.Chmod(f.Name(), perm)
if err != nil {
t.Fatal("failed to set file permissions")
}
t.Log("created temp file", f.Name())
return f.Name()
}

func createDirWithPerm(t *testing.T, perm fs.FileMode) (path string) {
t.Helper()
path, err := os.MkdirTemp(t.TempDir(), "")
Expand All @@ -1548,7 +1525,7 @@ func TestFileMode(t *testing.T) {
tc := newCase(t, `expected different file permissions`)
t.Cleanup(tc.assert)

path := createFileWithPerm(t, 0666)
path := util.TempFile(t, util.Mode(0666))
FileMode(tc, path, 0755)
})

Expand All @@ -1557,7 +1534,7 @@ func TestFileMode(t *testing.T) {
t.Cleanup(tc.assertNot)

const perm fs.FileMode = 0666
path := createFileWithPerm(t, perm)
path := util.TempFile(t, util.Mode(perm))
FileMode(tc, path, perm)
})
}
Expand Down Expand Up @@ -1635,7 +1612,7 @@ func TestDirMode(t *testing.T) {
t.Cleanup(tc.assert)

const perm fs.FileMode = 0777
path := createFileWithPerm(t, perm)
path := util.TempFile(t, util.Mode(perm))
DirMode(tc, path, perm)
})
}
Expand All @@ -1660,13 +1637,15 @@ func TestFileContains(t *testing.T) {
tc := newCase(t, `expected file contents`)
t.Cleanup(tc.assert)

FileContains(tc, writeTempFile(t, "test", "real data"), "fake")
path := util.TempFile(t, util.Pattern("test"), util.StringData("real data"))
FileContains(tc, path, "fake")
})
t.Run("file contains data", func(t *testing.T) {
tc := newCase(t, "")
t.Cleanup(tc.assertNot)

FileContains(tc, writeTempFile(t, "test", "real data"), "real")
path := util.TempFile(t, util.Pattern("test"), util.StringData("real data"))
FileContains(tc, path, "real")
})
}

Expand Down
117 changes: 117 additions & 0 deletions util/tempfile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright (c) The Test Authors
// SPDX-License-Identifier: MPL-2.0

package util

import (
"io/fs"
"os"
)

type T interface {
TempDir() string
Helper()
Errorf(format string, args ...any)
Fatalf(format string, args ...any)
Cleanup(func())
}

type TempFileSettings struct {
data []byte
mode *fs.FileMode
namePattern string
path *string
}

type TempFileSetting func(s *TempFileSettings)

// Pattern sets the filename to pattern with a random string appended.
// If pattern contains a '*', the last '*' will be replaced by the
// random string.
func Pattern(pattern string) TempFileSetting {
return func(s *TempFileSettings) {
s.namePattern = pattern
}
}

// Mode sets the temporary file's mode.
func Mode(mode fs.FileMode) TempFileSetting {
return func(s *TempFileSettings) {
s.mode = &mode
}
}

// StringData writes data to the temporary file.
func StringData(data string) TempFileSetting {
return func(s *TempFileSettings) {
s.data = []byte(data)
}
}

// ByteData writes data to the temporary file.
func ByteData(data []byte) TempFileSetting {
return func(s *TempFileSettings) {
s.data = data
}
}

// Path specifies a directory path to contain the temporary file.
// A temporary file created in a custom directory will still be deleted
// after the test runs, though the directory may not.
func Path(path string) TempFileSetting {
return func(s *TempFileSettings) {
s.path = &path
}
}

// TempFile creates a temporary file that is deleted after the test is
// completed. If the file cannot be deleted, the test fails with a message
// containing its path. TempFile creates a new file every time it is called.
// By default, each file thus created is in a unique directory as
// created by (*testing.T).TempDir(); this directory is also deleted
// after the test is completed.
func TempFile(t T, settings ...TempFileSetting) (path string) {
t.Helper()
var allSettings TempFileSettings
for _, setting := range settings {
setting(&allSettings)
}
if allSettings.mode == nil {
allSettings.mode = new(fs.FileMode)
*allSettings.mode = 0600
}
if allSettings.path == nil {
allSettings.path = new(string)
*allSettings.path = t.TempDir()
}

var err error
crash := func() {
t.Fatalf("%s: %v", "TempFile", err)
}
file, err := os.CreateTemp(*allSettings.path, allSettings.namePattern)
if err != nil {
crash()
}
path = file.Name()
t.Cleanup(func() {
err := os.Remove(path)
if err != nil {
t.Fatalf("failed to clean up temp file: %s", path)
}
})
_, err = file.Write(allSettings.data)
if err != nil {
file.Close()
crash()
}
err = file.Close()
if err != nil {
crash()
}
err = os.Chmod(path, *allSettings.mode)
if err != nil {
crash()
}
return file.Name()
}
Loading

0 comments on commit 73a741a

Please sign in to comment.