Skip to content

Commit e32b5a2

Browse files
committed
feat: improve fail on change test
No longer relies on an arbitrary sleep. Signed-off-by: Brian McGee <[email protected]>
1 parent 9c96554 commit e32b5a2

File tree

2 files changed

+108
-40
lines changed

2 files changed

+108
-40
lines changed

cmd/root_test.go

+94-38
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"path"
1010
"path/filepath"
1111
"regexp"
12-
"slices"
1312
"strings"
1413
"testing"
1514
"time"
@@ -575,28 +574,100 @@ func TestChangeWorkingDirectory(t *testing.T) {
575574
func TestFailOnChange(t *testing.T) {
576575
as := require.New(t)
577576

578-
tempDir := test.TempExamples(t)
579-
configPath := tempDir + "/touch.toml"
580-
581-
// test without any excludes
582-
cfg := &config.Config{
583-
FormatterConfigs: map[string]*config.Formatter{
584-
"touch": {
585-
Command: "touch",
586-
Includes: []string{"*"},
577+
t.Run("change size", func(t *testing.T) {
578+
tempDir := test.TempExamples(t)
579+
configPath := filepath.Join(tempDir, "treefmt.toml")
580+
581+
cfg := &config.Config{
582+
FormatterConfigs: map[string]*config.Formatter{
583+
"append": {
584+
// test-fmt-append is a helper defined in nix/packages/treefmt/formatters.nix which lets us append
585+
// an arbitrary value to a list of files
586+
Command: "test-fmt-append",
587+
Options: []string{"hello"},
588+
Includes: []string{"elm/*"},
589+
},
587590
},
588-
},
589-
}
591+
}
592+
test.WriteConfig(t, configPath, cfg)
590593

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

595-
// test with no cache
596-
t.Setenv("TREEFMT_FAIL_ON_CHANGE", "true")
597-
test.WriteConfig(t, configPath, cfg)
598-
_, _, err = treefmt(t, "--config-file", configPath, "--tree-root", tempDir, "--no-cache")
599-
as.ErrorIs(err, formatCmd.ErrFailOnChange)
597+
assertStats(t, as, statz, map[stats.Type]int{
598+
stats.Traversed: 32,
599+
stats.Matched: 2,
600+
stats.Formatted: 2,
601+
stats.Changed: 2,
602+
})
603+
604+
// cached
605+
_, statz, err = treefmt(t, "--fail-on-change", "--config-file", configPath, "--tree-root", tempDir)
606+
as.NoError(err)
607+
608+
assertStats(t, as, statz, map[stats.Type]int{
609+
stats.Traversed: 32,
610+
stats.Matched: 2,
611+
stats.Formatted: 0,
612+
stats.Changed: 0,
613+
})
614+
})
615+
616+
t.Run("change modtime", func(t *testing.T) {
617+
tempDir := test.TempExamples(t)
618+
configPath := filepath.Join(tempDir, "treefmt.toml")
619+
620+
dateFormat := "2006 01 02 15:04.05"
621+
replacer := strings.NewReplacer(" ", "", ":", "")
622+
623+
formatTime := func(t time.Time) string {
624+
// go date formats are stupid
625+
return replacer.Replace(t.Format(dateFormat))
626+
}
627+
628+
writeConfig := func() {
629+
// new mod time is in the next second
630+
modTime := time.Now().Truncate(time.Second).Add(time.Second)
631+
632+
cfg := &config.Config{
633+
FormatterConfigs: map[string]*config.Formatter{
634+
"append": {
635+
// test-fmt-modtime is a helper defined in nix/packages/treefmt/formatters.nix which lets us set
636+
// a file's modtime to an arbitrary date.
637+
// in this case, we move it forward more than a second so that our second level modtime comparison
638+
// will detect it as a change.
639+
Command: "test-fmt-modtime",
640+
Options: []string{formatTime(modTime)},
641+
Includes: []string{"haskell/*"},
642+
},
643+
},
644+
}
645+
test.WriteConfig(t, configPath, cfg)
646+
}
647+
648+
writeConfig()
649+
650+
_, statz, err := treefmt(t, "--fail-on-change", "--config-file", configPath, "--tree-root", tempDir)
651+
as.ErrorIs(err, formatCmd.ErrFailOnChange)
652+
653+
assertStats(t, as, statz, map[stats.Type]int{
654+
stats.Traversed: 32,
655+
stats.Matched: 7,
656+
stats.Formatted: 7,
657+
stats.Changed: 7,
658+
})
659+
660+
// cached
661+
_, statz, err = treefmt(t, "--fail-on-change", "--config-file", configPath, "--tree-root", tempDir)
662+
as.NoError(err)
663+
664+
assertStats(t, as, statz, map[stats.Type]int{
665+
stats.Traversed: 32,
666+
stats.Matched: 7,
667+
stats.Formatted: 0,
668+
stats.Changed: 0,
669+
})
670+
})
600671
}
601672

602673
func TestBustCacheOnFormatterChange(t *testing.T) {
@@ -1133,17 +1204,17 @@ func TestDeterministicOrderingInPipeline(t *testing.T) {
11331204
// a and b should execute in lexicographical order
11341205
// c should execute first since it has a priority of 1
11351206
"fmt-a": {
1136-
Command: "test-fmt",
1207+
Command: "test-fmt-append",
11371208
Options: []string{"fmt-a"},
11381209
Includes: []string{"*.py"},
11391210
},
11401211
"fmt-b": {
1141-
Command: "test-fmt",
1212+
Command: "test-fmt-append",
11421213
Options: []string{"fmt-b"},
11431214
Includes: []string{"*.py"},
11441215
},
11451216
"fmt-c": {
1146-
Command: "test-fmt",
1217+
Command: "test-fmt-append",
11471218
Options: []string{"fmt-c"},
11481219
Includes: []string{"*.py"},
11491220
Priority: 1,
@@ -1306,21 +1377,6 @@ func treefmt(t *testing.T, args ...string) ([]byte, *stats.Stats, error) {
13061377
root.SetOut(tempOut)
13071378
root.SetErr(tempOut)
13081379

1309-
failOnChange := os.Getenv("TREEFMT_FAIL_ON_CHANGE") == "true" ||
1310-
slices.Index(args, "--fail-on-change") != -1
1311-
1312-
if failOnChange {
1313-
// record the start time
1314-
start := time.Now()
1315-
1316-
defer func() {
1317-
// Wait until we tick over into the next second before continuing.
1318-
// This ensures we correctly detect changes as treefmt compares modtime at second level precision.
1319-
waitUntil := start.Truncate(time.Second).Add(time.Second)
1320-
time.Sleep(time.Until(waitUntil))
1321-
}()
1322-
}
1323-
13241380
// execute the command
13251381
cmdErr := root.Execute()
13261382

nix/packages/treefmt/formatters.nix

+14-2
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ with pkgs; [
1818
opentofu
1919
dos2unix
2020
yamlfmt
21-
# util for unit testing
21+
# utils for unit testing
2222
(pkgs.writeShellApplication {
23-
name = "test-fmt";
23+
name = "test-fmt-append";
2424
text = ''
2525
VALUE="$1"
2626
shift
@@ -31,4 +31,16 @@ with pkgs; [
3131
done
3232
'';
3333
})
34+
(pkgs.writeShellApplication {
35+
name = "test-fmt-modtime";
36+
text = ''
37+
VALUE="$1"
38+
shift
39+
40+
# append value to each file
41+
for FILE in "$@"; do
42+
touch -t "$VALUE" "$FILE"
43+
done
44+
'';
45+
})
3446
]

0 commit comments

Comments
 (0)