Skip to content

Commit

Permalink
feat: improve fail on change test
Browse files Browse the repository at this point in the history
No longer relies on an arbitrary sleep.

Signed-off-by: Brian McGee <[email protected]>
  • Loading branch information
brianmcgee committed Oct 18, 2024
1 parent 9c96554 commit e32b5a2
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 40 deletions.
132 changes: 94 additions & 38 deletions cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"path"
"path/filepath"
"regexp"
"slices"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -575,28 +574,100 @@ func TestChangeWorkingDirectory(t *testing.T) {
func TestFailOnChange(t *testing.T) {
as := require.New(t)

tempDir := test.TempExamples(t)
configPath := tempDir + "/touch.toml"

// test without any excludes
cfg := &config.Config{
FormatterConfigs: map[string]*config.Formatter{
"touch": {
Command: "touch",
Includes: []string{"*"},
t.Run("change size", func(t *testing.T) {
tempDir := test.TempExamples(t)
configPath := filepath.Join(tempDir, "treefmt.toml")

cfg := &config.Config{
FormatterConfigs: map[string]*config.Formatter{
"append": {
// test-fmt-append is a helper defined in nix/packages/treefmt/formatters.nix which lets us append
// an arbitrary value to a list of files
Command: "test-fmt-append",
Options: []string{"hello"},
Includes: []string{"elm/*"},
},
},
},
}
}
test.WriteConfig(t, configPath, cfg)

test.WriteConfig(t, configPath, cfg)
_, _, err := treefmt(t, "--fail-on-change", "--config-file", configPath, "--tree-root", tempDir)
as.ErrorIs(err, formatCmd.ErrFailOnChange)
_, statz, err := treefmt(t, "--fail-on-change", "--config-file", configPath, "--tree-root", tempDir)
as.ErrorIs(err, formatCmd.ErrFailOnChange)

// test with no cache
t.Setenv("TREEFMT_FAIL_ON_CHANGE", "true")
test.WriteConfig(t, configPath, cfg)
_, _, err = treefmt(t, "--config-file", configPath, "--tree-root", tempDir, "--no-cache")
as.ErrorIs(err, formatCmd.ErrFailOnChange)
assertStats(t, as, statz, map[stats.Type]int{
stats.Traversed: 32,
stats.Matched: 2,
stats.Formatted: 2,
stats.Changed: 2,
})

// cached
_, statz, err = treefmt(t, "--fail-on-change", "--config-file", configPath, "--tree-root", tempDir)
as.NoError(err)

assertStats(t, as, statz, map[stats.Type]int{
stats.Traversed: 32,
stats.Matched: 2,
stats.Formatted: 0,
stats.Changed: 0,
})
})

t.Run("change modtime", func(t *testing.T) {
tempDir := test.TempExamples(t)
configPath := filepath.Join(tempDir, "treefmt.toml")

dateFormat := "2006 01 02 15:04.05"
replacer := strings.NewReplacer(" ", "", ":", "")

formatTime := func(t time.Time) string {
// go date formats are stupid
return replacer.Replace(t.Format(dateFormat))
}

writeConfig := func() {
// new mod time is in the next second
modTime := time.Now().Truncate(time.Second).Add(time.Second)

cfg := &config.Config{
FormatterConfigs: map[string]*config.Formatter{
"append": {
// test-fmt-modtime is a helper defined in nix/packages/treefmt/formatters.nix which lets us set
// a file's modtime to an arbitrary date.
// in this case, we move it forward more than a second so that our second level modtime comparison
// will detect it as a change.
Command: "test-fmt-modtime",
Options: []string{formatTime(modTime)},
Includes: []string{"haskell/*"},
},
},
}
test.WriteConfig(t, configPath, cfg)
}

writeConfig()

_, statz, err := treefmt(t, "--fail-on-change", "--config-file", configPath, "--tree-root", tempDir)
as.ErrorIs(err, formatCmd.ErrFailOnChange)

assertStats(t, as, statz, map[stats.Type]int{
stats.Traversed: 32,
stats.Matched: 7,
stats.Formatted: 7,
stats.Changed: 7,
})

// cached
_, statz, err = treefmt(t, "--fail-on-change", "--config-file", configPath, "--tree-root", tempDir)
as.NoError(err)

assertStats(t, as, statz, map[stats.Type]int{
stats.Traversed: 32,
stats.Matched: 7,
stats.Formatted: 0,
stats.Changed: 0,
})
})
}

func TestBustCacheOnFormatterChange(t *testing.T) {
Expand Down Expand Up @@ -1133,17 +1204,17 @@ func TestDeterministicOrderingInPipeline(t *testing.T) {
// a and b should execute in lexicographical order
// c should execute first since it has a priority of 1
"fmt-a": {
Command: "test-fmt",
Command: "test-fmt-append",
Options: []string{"fmt-a"},
Includes: []string{"*.py"},
},
"fmt-b": {
Command: "test-fmt",
Command: "test-fmt-append",
Options: []string{"fmt-b"},
Includes: []string{"*.py"},
},
"fmt-c": {
Command: "test-fmt",
Command: "test-fmt-append",
Options: []string{"fmt-c"},
Includes: []string{"*.py"},
Priority: 1,
Expand Down Expand Up @@ -1306,21 +1377,6 @@ func treefmt(t *testing.T, args ...string) ([]byte, *stats.Stats, error) {
root.SetOut(tempOut)
root.SetErr(tempOut)

failOnChange := os.Getenv("TREEFMT_FAIL_ON_CHANGE") == "true" ||
slices.Index(args, "--fail-on-change") != -1

if failOnChange {
// record the start time
start := time.Now()

defer func() {
// Wait until we tick over into the next second before continuing.
// This ensures we correctly detect changes as treefmt compares modtime at second level precision.
waitUntil := start.Truncate(time.Second).Add(time.Second)
time.Sleep(time.Until(waitUntil))
}()
}

// execute the command
cmdErr := root.Execute()

Expand Down
16 changes: 14 additions & 2 deletions nix/packages/treefmt/formatters.nix
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ with pkgs; [
opentofu
dos2unix
yamlfmt
# util for unit testing
# utils for unit testing
(pkgs.writeShellApplication {
name = "test-fmt";
name = "test-fmt-append";
text = ''
VALUE="$1"
shift
Expand All @@ -31,4 +31,16 @@ with pkgs; [
done
'';
})
(pkgs.writeShellApplication {
name = "test-fmt-modtime";
text = ''
VALUE="$1"
shift
# append value to each file
for FILE in "$@"; do
touch -t "$VALUE" "$FILE"
done
'';
})
]

0 comments on commit e32b5a2

Please sign in to comment.