@@ -252,6 +252,8 @@ import (
252
252
"sync"
253
253
"sync/atomic"
254
254
"time"
255
+ "unicode"
256
+ "unicode/utf8"
255
257
)
256
258
257
259
var initRan bool
@@ -908,11 +910,6 @@ func (c *common) Cleanup(f func()) {
908
910
c .cleanups = append (c .cleanups , fn )
909
911
}
910
912
911
- var tempDirReplacer struct {
912
- sync.Once
913
- r * strings.Replacer
914
- }
915
-
916
913
// TempDir returns a temporary directory for the test to use.
917
914
// The directory is automatically removed by Cleanup when the test and
918
915
// all its subtests complete.
@@ -936,13 +933,26 @@ func (c *common) TempDir() string {
936
933
if nonExistent {
937
934
c .Helper ()
938
935
939
- // os.MkdirTemp doesn't like path separators in its pattern,
940
- // so mangle the name to accommodate subtests.
941
- tempDirReplacer .Do (func () {
942
- tempDirReplacer .r = strings .NewReplacer ("/" , "_" , "\\ " , "_" , ":" , "_" )
943
- })
944
- pattern := tempDirReplacer .r .Replace (c .Name ())
945
-
936
+ // Drop unusual characters (such as path separators or
937
+ // characters interacting with globs) from the directory name to
938
+ // avoid surprising os.MkdirTemp behavior.
939
+ mapper := func (r rune ) rune {
940
+ if r < utf8 .RuneSelf {
941
+ const allowed = "!#$%&()+,-.=@^_{}~ "
942
+ if '0' <= r && r <= '9' ||
943
+ 'a' <= r && r <= 'z' ||
944
+ 'A' <= r && r <= 'Z' {
945
+ return r
946
+ }
947
+ if strings .ContainsRune (allowed , r ) {
948
+ return r
949
+ }
950
+ } else if unicode .IsLetter (r ) || unicode .IsNumber (r ) {
951
+ return r
952
+ }
953
+ return - 1
954
+ }
955
+ pattern := strings .Map (mapper , c .Name ())
946
956
c .tempDir , c .tempDirErr = os .MkdirTemp ("" , pattern )
947
957
if c .tempDirErr == nil {
948
958
c .Cleanup (func () {
0 commit comments