@@ -3,6 +3,8 @@ package iofs
3
3
import (
4
4
"errors"
5
5
"io/fs"
6
+ "path/filepath"
7
+ "runtime"
6
8
"strings"
7
9
"testing"
8
10
"testing/fstest"
@@ -38,24 +40,7 @@ func TestWithFSTest(t *testing.T) {
38
40
39
41
err := fstest .TestFS (iofs , created_files ... )
40
42
if err != nil {
41
- if unwrapped := errors .Unwrap (err ); unwrapped != nil {
42
- err = unwrapped
43
- }
44
- if errs , ok := err .(errorList ); ok {
45
- for _ , e := range errs .Unwrap () {
46
-
47
- if strings .Contains (e .Error (), "ModTime" ) {
48
- // Memfs returns the current time for Stat().ModTime(), which triggers
49
- // a diff complaint in fstest. We can ignore this, or store modtimes
50
- // for every file in Memfs (at a cost of 16 bytes / file).
51
- t .Log ("Skipping ModTime error (ok)." )
52
- } else {
53
- t .Errorf ("Unexpected fstest error: %v" , e )
54
- }
55
- }
56
- } else {
57
- t .Fatalf ("Failed to test fs:\n %v" , err )
58
- }
43
+ checkFsTestError (t , err , files )
59
44
}
60
45
}
61
46
@@ -100,3 +85,64 @@ func makeFile(fs billyfs.Basic, t *testing.T, filename string, contents string)
100
85
t .Fatalf ("failed to write to file %s: %v" , filename , err )
101
86
}
102
87
}
88
+
89
+ func checkFsTestError (t * testing.T , err error , files map [string ]string ) {
90
+ t .Helper ()
91
+
92
+ if unwrapped := errors .Unwrap (err ); unwrapped != nil {
93
+ err = unwrapped
94
+ }
95
+
96
+ // Go >= 1.23 (after https://cs.opensource.google/go/go/+/74cce866f865c3188a34309e4ebc7a5c9ed0683d)
97
+ // has nicely-Joined wrapped errors. Try that first.
98
+ if errs , ok := err .(errorList ); ok {
99
+ for _ , e := range errs .Unwrap () {
100
+
101
+ if strings .Contains (e .Error (), "ModTime" ) {
102
+ // Memfs returns the current time for Stat().ModTime(), which triggers
103
+ // a diff complaint in fstest. We can ignore this, or store modtimes
104
+ // for every file in Memfs (at a cost of 16 bytes / file).
105
+ t .Log ("Skipping ModTime error (ok)." )
106
+ } else {
107
+ t .Errorf ("Unexpected fstest error: %v" , e )
108
+ }
109
+ }
110
+ } else {
111
+ if runtime .Version () >= "go1.23" {
112
+ t .Fatalf ("Failed to test fs:\n %v" , err )
113
+ }
114
+ // filter lines from the error text corresponding to the above errors;
115
+ // output looks like:
116
+ // bar.txt: mismatch:
117
+ // entry.Info() = bar.txt IsDir=false Mode=-rw-rw-rw- Size=14 ModTime=2024-09-17 10:09:00.377023639 +0000 UTC m=+0.002625548
118
+ // file.Stat() = bar.txt IsDir=false Mode=-rw-rw-rw- Size=14 ModTime=2024-09-17 10:09:00.376907011 +0000 UTC m=+0.002508970
119
+ //
120
+ // bar.txt: fs.Stat(...) = bar.txt IsDir=false Mode=-rw-rw-rw- Size=14 ModTime=2024-09-17 10:09:00.381356651 +0000 UTC m=+0.006959191
121
+ // want bar.txt IsDir=false Mode=-rw-rw-rw- Size=14 ModTime=2024-09-17 10:09:00.376907011 +0000 UTC m=+0.002508970
122
+ // bar.txt: fsys.Stat(...) = bar.txt IsDir=false Mode=-rw-rw-rw- Size=14 ModTime=2024-09-17 10:09:00.381488617 +0000 UTC m=+0.007090346
123
+ // want bar.txt IsDir=false Mode=-rw-rw-rw- Size=14 ModTime=2024-09-17 10:09:00.376907011 +0000 UTC m=+0.002508970
124
+ // We filter on "empty line" or "ModTime" or "$filename: mismatch" to ignore these.
125
+ lines := strings .Split (err .Error (), "\n " )
126
+ filtered := make ([]string , 0 , len (lines ))
127
+ filename_mismatches := make (map [string ]struct {}, len (files ) * 2 )
128
+ for name , _ := range files {
129
+ for dirname := name ; dirname != "." ; dirname = filepath .Dir (dirname ) {
130
+ filename_mismatches [dirname + ": mismatch:" ] = struct {}{}
131
+ }
132
+ }
133
+ for _ , line := range lines {
134
+ line = strings .TrimSpace (line )
135
+ if line == "" || strings .Contains (line , "ModTime=" ) {
136
+ continue
137
+ }
138
+
139
+ if _ , ok := filename_mismatches [line ]; ok {
140
+ continue
141
+ }
142
+ filtered = append (filtered , line )
143
+ }
144
+ if len (filtered ) > 0 {
145
+ t .Fatalf ("Failed to test fs:\n %s" , strings .Join (filtered , "\n " ))
146
+ }
147
+ }
148
+ }
0 commit comments