1// Copyright 2010 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package os_test
6
7import (
8	"errors"
9	"io/fs"
10	. "os"
11	"path/filepath"
12	"regexp"
13	"strings"
14	"testing"
15)
16
17func TestCreateTemp(t *testing.T) {
18	t.Parallel()
19
20	dir, err := MkdirTemp("", "TestCreateTempBadDir")
21	if err != nil {
22		t.Fatal(err)
23	}
24	defer RemoveAll(dir)
25
26	nonexistentDir := filepath.Join(dir, "_not_exists_")
27	f, err := CreateTemp(nonexistentDir, "foo")
28	if f != nil || err == nil {
29		t.Errorf("CreateTemp(%q, `foo`) = %v, %v", nonexistentDir, f, err)
30	}
31}
32
33func TestCreateTempPattern(t *testing.T) {
34	t.Parallel()
35
36	tests := []struct{ pattern, prefix, suffix string }{
37		{"tempfile_test", "tempfile_test", ""},
38		{"tempfile_test*", "tempfile_test", ""},
39		{"tempfile_test*xyz", "tempfile_test", "xyz"},
40	}
41	for _, test := range tests {
42		f, err := CreateTemp("", test.pattern)
43		if err != nil {
44			t.Errorf("CreateTemp(..., %q) error: %v", test.pattern, err)
45			continue
46		}
47		defer Remove(f.Name())
48		base := filepath.Base(f.Name())
49		f.Close()
50		if !(strings.HasPrefix(base, test.prefix) && strings.HasSuffix(base, test.suffix)) {
51			t.Errorf("CreateTemp pattern %q created bad name %q; want prefix %q & suffix %q",
52				test.pattern, base, test.prefix, test.suffix)
53		}
54	}
55}
56
57func TestCreateTempBadPattern(t *testing.T) {
58	t.Parallel()
59
60	tmpDir, err := MkdirTemp("", t.Name())
61	if err != nil {
62		t.Fatal(err)
63	}
64	defer RemoveAll(tmpDir)
65
66	const sep = string(PathSeparator)
67	tests := []struct {
68		pattern string
69		wantErr bool
70	}{
71		{"ioutil*test", false},
72		{"tempfile_test*foo", false},
73		{"tempfile_test" + sep + "foo", true},
74		{"tempfile_test*" + sep + "foo", true},
75		{"tempfile_test" + sep + "*foo", true},
76		{sep + "tempfile_test" + sep + "*foo", true},
77		{"tempfile_test*foo" + sep, true},
78	}
79	for _, tt := range tests {
80		t.Run(tt.pattern, func(t *testing.T) {
81			tmpfile, err := CreateTemp(tmpDir, tt.pattern)
82			if tmpfile != nil {
83				defer tmpfile.Close()
84			}
85			if tt.wantErr {
86				if err == nil {
87					t.Errorf("CreateTemp(..., %#q) succeeded, expected error", tt.pattern)
88				}
89				if !errors.Is(err, ErrPatternHasSeparator) {
90					t.Errorf("CreateTemp(..., %#q): %v, expected ErrPatternHasSeparator", tt.pattern, err)
91				}
92			} else if err != nil {
93				t.Errorf("CreateTemp(..., %#q): %v", tt.pattern, err)
94			}
95		})
96	}
97}
98
99func TestMkdirTemp(t *testing.T) {
100	t.Parallel()
101
102	name, err := MkdirTemp("/_not_exists_", "foo")
103	if name != "" || err == nil {
104		t.Errorf("MkdirTemp(`/_not_exists_`, `foo`) = %v, %v", name, err)
105	}
106
107	tests := []struct {
108		pattern                string
109		wantPrefix, wantSuffix string
110	}{
111		{"tempfile_test", "tempfile_test", ""},
112		{"tempfile_test*", "tempfile_test", ""},
113		{"tempfile_test*xyz", "tempfile_test", "xyz"},
114	}
115
116	dir := filepath.Clean(TempDir())
117
118	runTestMkdirTemp := func(t *testing.T, pattern, wantRePat string) {
119		name, err := MkdirTemp(dir, pattern)
120		if name == "" || err != nil {
121			t.Fatalf("MkdirTemp(dir, `tempfile_test`) = %v, %v", name, err)
122		}
123		defer Remove(name)
124
125		re := regexp.MustCompile(wantRePat)
126		if !re.MatchString(name) {
127			t.Errorf("MkdirTemp(%q, %q) created bad name\n\t%q\ndid not match pattern\n\t%q", dir, pattern, name, wantRePat)
128		}
129	}
130
131	for _, tt := range tests {
132		t.Run(tt.pattern, func(t *testing.T) {
133			wantRePat := "^" + regexp.QuoteMeta(filepath.Join(dir, tt.wantPrefix)) + "[0-9]+" + regexp.QuoteMeta(tt.wantSuffix) + "$"
134			runTestMkdirTemp(t, tt.pattern, wantRePat)
135		})
136	}
137
138	// Separately testing "*xyz" (which has no prefix). That is when constructing the
139	// pattern to assert on, as in the previous loop, using filepath.Join for an empty
140	// prefix filepath.Join(dir, ""), produces the pattern:
141	//     ^<DIR>[0-9]+xyz$
142	// yet we just want to match
143	//     "^<DIR>/[0-9]+xyz"
144	t.Run("*xyz", func(t *testing.T) {
145		wantRePat := "^" + regexp.QuoteMeta(filepath.Join(dir)) + regexp.QuoteMeta(string(filepath.Separator)) + "[0-9]+xyz$"
146		runTestMkdirTemp(t, "*xyz", wantRePat)
147	})
148}
149
150// test that we return a nice error message if the dir argument to TempDir doesn't
151// exist (or that it's empty and TempDir doesn't exist)
152func TestMkdirTempBadDir(t *testing.T) {
153	t.Parallel()
154
155	dir, err := MkdirTemp("", "MkdirTempBadDir")
156	if err != nil {
157		t.Fatal(err)
158	}
159	defer RemoveAll(dir)
160
161	badDir := filepath.Join(dir, "not-exist")
162	_, err = MkdirTemp(badDir, "foo")
163	if pe, ok := err.(*fs.PathError); !ok || !IsNotExist(err) || pe.Path != badDir {
164		t.Errorf("TempDir error = %#v; want PathError for path %q satisfying IsNotExist", err, badDir)
165	}
166}
167
168func TestMkdirTempBadPattern(t *testing.T) {
169	t.Parallel()
170
171	tmpDir, err := MkdirTemp("", t.Name())
172	if err != nil {
173		t.Fatal(err)
174	}
175	defer RemoveAll(tmpDir)
176
177	const sep = string(PathSeparator)
178	tests := []struct {
179		pattern string
180		wantErr bool
181	}{
182		{"ioutil*test", false},
183		{"tempfile_test*foo", false},
184		{"tempfile_test" + sep + "foo", true},
185		{"tempfile_test*" + sep + "foo", true},
186		{"tempfile_test" + sep + "*foo", true},
187		{sep + "tempfile_test" + sep + "*foo", true},
188		{"tempfile_test*foo" + sep, true},
189	}
190	for _, tt := range tests {
191		t.Run(tt.pattern, func(t *testing.T) {
192			_, err := MkdirTemp(tmpDir, tt.pattern)
193			if tt.wantErr {
194				if err == nil {
195					t.Errorf("MkdirTemp(..., %#q) succeeded, expected error", tt.pattern)
196				}
197				if !errors.Is(err, ErrPatternHasSeparator) {
198					t.Errorf("MkdirTemp(..., %#q): %v, expected ErrPatternHasSeparator", tt.pattern, err)
199				}
200			} else if err != nil {
201				t.Errorf("MkdirTemp(..., %#q): %v", tt.pattern, err)
202			}
203		})
204	}
205}
206