1package mem
2
3import (
4	"bytes"
5	"io"
6	"testing"
7	"time"
8)
9
10func TestFileDataNameRace(t *testing.T) {
11	t.Parallel()
12	const someName = "someName"
13	const someOtherName = "someOtherName"
14	d := FileData{
15		name: someName,
16	}
17
18	if d.Name() != someName {
19		t.Errorf("Failed to read correct Name, was %v", d.Name())
20	}
21
22	ChangeFileName(&d, someOtherName)
23	if d.Name() != someOtherName {
24		t.Errorf("Failed to set Name, was %v", d.Name())
25	}
26
27	go func() {
28		ChangeFileName(&d, someName)
29	}()
30
31	if d.Name() != someName && d.Name() != someOtherName {
32		t.Errorf("Failed to read either Name, was %v", d.Name())
33	}
34}
35
36func TestFileDataModTimeRace(t *testing.T) {
37	t.Parallel()
38	someTime := time.Now()
39	someOtherTime := someTime.Add(1 * time.Minute)
40
41	d := FileData{
42		modtime: someTime,
43	}
44
45	s := FileInfo{
46		FileData: &d,
47	}
48
49	if s.ModTime() != someTime {
50		t.Errorf("Failed to read correct value, was %v", s.ModTime())
51	}
52
53	SetModTime(&d, someOtherTime)
54	if s.ModTime() != someOtherTime {
55		t.Errorf("Failed to set ModTime, was %v", s.ModTime())
56	}
57
58	go func() {
59		SetModTime(&d, someTime)
60	}()
61
62	if s.ModTime() != someTime && s.ModTime() != someOtherTime {
63		t.Errorf("Failed to read either modtime, was %v", s.ModTime())
64	}
65}
66
67func TestFileDataModeRace(t *testing.T) {
68	t.Parallel()
69	const someMode = 0777
70	const someOtherMode = 0660
71
72	d := FileData{
73		mode: someMode,
74	}
75
76	s := FileInfo{
77		FileData: &d,
78	}
79
80	if s.Mode() != someMode {
81		t.Errorf("Failed to read correct value, was %v", s.Mode())
82	}
83
84	SetMode(&d, someOtherMode)
85	if s.Mode() != someOtherMode {
86		t.Errorf("Failed to set Mode, was %v", s.Mode())
87	}
88
89	go func() {
90		SetMode(&d, someMode)
91	}()
92
93	if s.Mode() != someMode && s.Mode() != someOtherMode {
94		t.Errorf("Failed to read either mode, was %v", s.Mode())
95	}
96}
97
98// See https://github.com/spf13/afero/issues/286.
99func TestFileWriteAt(t *testing.T) {
100	t.Parallel()
101
102	data := CreateFile("abc.txt")
103	f := NewFileHandle(data)
104
105	testData := []byte{1, 2, 3, 4, 5}
106	offset := len(testData)
107
108	// 5 zeros + testdata
109	_, err := f.WriteAt(testData, int64(offset))
110	if err != nil {
111		t.Fatal(err)
112	}
113
114	// 2 * testdata
115	_, err = f.WriteAt(testData, 0)
116	if err != nil {
117		t.Fatal(err)
118	}
119
120	// 3 * testdata
121	_, err = f.WriteAt(testData, int64(offset*2))
122	if err != nil {
123		t.Fatal(err)
124	}
125
126	// 3 * testdata + 5 zeros + testdata
127	_, err = f.WriteAt(testData, int64(offset*4))
128	if err != nil {
129		t.Fatal(err)
130	}
131
132	// 5 * testdata
133	_, err = f.WriteAt(testData, int64(offset*3))
134	if err != nil {
135		t.Fatal(err)
136	}
137
138	err = f.Close()
139	if err != nil {
140		t.Fatal(err)
141	}
142
143	expected := bytes.Repeat(testData, 5)
144	if !bytes.Equal(expected, data.data) {
145		t.Fatalf("expected: %v, got: %v", expected, data.data)
146	}
147}
148
149func TestFileDataIsDirRace(t *testing.T) {
150	t.Parallel()
151
152	d := FileData{
153		dir: true,
154	}
155
156	s := FileInfo{
157		FileData: &d,
158	}
159
160	if s.IsDir() != true {
161		t.Errorf("Failed to read correct value, was %v", s.IsDir())
162	}
163
164	go func() {
165		s.Lock()
166		d.dir = false
167		s.Unlock()
168	}()
169
170	//just logging the value to trigger a read:
171	t.Logf("Value is %v", s.IsDir())
172}
173
174func TestFileDataSizeRace(t *testing.T) {
175	t.Parallel()
176
177	const someData = "Hello"
178	const someOtherDataSize = "Hello World"
179
180	d := FileData{
181		data: []byte(someData),
182		dir:  false,
183	}
184
185	s := FileInfo{
186		FileData: &d,
187	}
188
189	if s.Size() != int64(len(someData)) {
190		t.Errorf("Failed to read correct value, was %v", s.Size())
191	}
192
193	go func() {
194		s.Lock()
195		d.data = []byte(someOtherDataSize)
196		s.Unlock()
197	}()
198
199	//just logging the value to trigger a read:
200	t.Logf("Value is %v", s.Size())
201
202	//Testing the Dir size case
203	d.dir = true
204	if s.Size() != int64(42) {
205		t.Errorf("Failed to read correct value for dir, was %v", s.Size())
206	}
207}
208
209func TestFileReadAtSeekOffset(t *testing.T) {
210	t.Parallel()
211
212	fd := CreateFile("foo")
213	f := NewFileHandle(fd)
214
215	_, err := f.WriteString("TEST")
216	if err != nil {
217		t.Fatal(err)
218	}
219	offset, err := f.Seek(0, io.SeekStart)
220	if err != nil {
221		t.Fatal(err)
222	}
223	if offset != 0 {
224		t.Fail()
225	}
226
227	offsetBeforeReadAt, err := f.Seek(0, io.SeekCurrent)
228	if err != nil {
229		t.Fatal(err)
230	}
231	if offsetBeforeReadAt != 0 {
232		t.Fatal("expected 0")
233	}
234
235	b := make([]byte, 4)
236	n, err := f.ReadAt(b, 0)
237	if err != nil {
238		t.Fatal(err)
239	}
240	if n != 4 {
241		t.Fail()
242	}
243	if string(b) != "TEST" {
244		t.Fail()
245	}
246
247	offsetAfterReadAt, err := f.Seek(0, io.SeekCurrent)
248	if err != nil {
249		t.Fatal(err)
250	}
251	if offsetAfterReadAt != offsetBeforeReadAt {
252		t.Fatal("ReadAt should not affect offset")
253	}
254
255	err = f.Close()
256	if err != nil {
257		t.Fatal(err)
258	}
259}
260
261func TestFileWriteAndSeek(t *testing.T) {
262	fd := CreateFile("foo")
263	f := NewFileHandle(fd)
264
265	assert := func(expected bool, v ...interface{}) {
266		if !expected {
267			t.Helper()
268			t.Fatal(v...)
269		}
270	}
271
272	data4 := []byte{0, 1, 2, 3}
273	data20 := bytes.Repeat(data4, 5)
274	var off int64
275
276	for i := 0; i < 100; i++ {
277		// write 20 bytes
278		n, err := f.Write(data20)
279		assert(err == nil, err)
280		off += int64(n)
281		assert(n == len(data20), n)
282		assert(off == int64((i+1)*len(data20)), off)
283
284		// rewind to start and write 4 bytes there
285		cur, err := f.Seek(-off, io.SeekCurrent)
286		assert(err == nil, err)
287		assert(cur == 0, cur)
288
289		n, err = f.Write(data4)
290		assert(err == nil, err)
291		assert(n == len(data4), n)
292
293		// back at the end
294		cur, err = f.Seek(off-int64(n), io.SeekCurrent)
295		assert(err == nil, err)
296		assert(cur == off, cur, off)
297	}
298}
299