xref: /aosp_15_r20/build/make/tools/compliance/testfs/testfs.go (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
1*9e94795aSAndroid Build Coastguard Worker// Copyright 2022 Google LLC
2*9e94795aSAndroid Build Coastguard Worker//
3*9e94795aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*9e94795aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*9e94795aSAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*9e94795aSAndroid Build Coastguard Worker//
7*9e94795aSAndroid Build Coastguard Worker//      http://www.apache.org/licenses/LICENSE-2.0
8*9e94795aSAndroid Build Coastguard Worker//
9*9e94795aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*9e94795aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*9e94795aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9e94795aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*9e94795aSAndroid Build Coastguard Worker// limitations under the License.
14*9e94795aSAndroid Build Coastguard Worker
15*9e94795aSAndroid Build Coastguard Workerpackage testfs
16*9e94795aSAndroid Build Coastguard Worker
17*9e94795aSAndroid Build Coastguard Workerimport (
18*9e94795aSAndroid Build Coastguard Worker	"fmt"
19*9e94795aSAndroid Build Coastguard Worker	"io"
20*9e94795aSAndroid Build Coastguard Worker	"io/fs"
21*9e94795aSAndroid Build Coastguard Worker	"strings"
22*9e94795aSAndroid Build Coastguard Worker	"time"
23*9e94795aSAndroid Build Coastguard Worker)
24*9e94795aSAndroid Build Coastguard Worker
25*9e94795aSAndroid Build Coastguard Worker// TestFS implements a test file system (fs.FS) simulated by a map from filename to []byte content.
26*9e94795aSAndroid Build Coastguard Workertype TestFS map[string][]byte
27*9e94795aSAndroid Build Coastguard Worker
28*9e94795aSAndroid Build Coastguard Workervar _ fs.FS = (*TestFS)(nil)
29*9e94795aSAndroid Build Coastguard Workervar _ fs.StatFS = (*TestFS)(nil)
30*9e94795aSAndroid Build Coastguard Worker
31*9e94795aSAndroid Build Coastguard Worker// Open implements fs.FS.Open() to open a file based on the filename.
32*9e94795aSAndroid Build Coastguard Workerfunc (tfs *TestFS) Open(name string) (fs.File, error) {
33*9e94795aSAndroid Build Coastguard Worker	if _, ok := (*tfs)[name]; !ok {
34*9e94795aSAndroid Build Coastguard Worker		return nil, fmt.Errorf("unknown file %q", name)
35*9e94795aSAndroid Build Coastguard Worker	}
36*9e94795aSAndroid Build Coastguard Worker	return &TestFile{tfs, name, 0}, nil
37*9e94795aSAndroid Build Coastguard Worker}
38*9e94795aSAndroid Build Coastguard Worker
39*9e94795aSAndroid Build Coastguard Worker// Stat implements fs.StatFS.Stat() to examine a file based on the filename.
40*9e94795aSAndroid Build Coastguard Workerfunc (tfs *TestFS) Stat(name string) (fs.FileInfo, error) {
41*9e94795aSAndroid Build Coastguard Worker	if content, ok := (*tfs)[name]; ok {
42*9e94795aSAndroid Build Coastguard Worker		return &TestFileInfo{name, len(content), 0666}, nil
43*9e94795aSAndroid Build Coastguard Worker	}
44*9e94795aSAndroid Build Coastguard Worker	dirname := name
45*9e94795aSAndroid Build Coastguard Worker	if !strings.HasSuffix(dirname, "/") {
46*9e94795aSAndroid Build Coastguard Worker		dirname = dirname + "/"
47*9e94795aSAndroid Build Coastguard Worker	}
48*9e94795aSAndroid Build Coastguard Worker	for name := range (*tfs) {
49*9e94795aSAndroid Build Coastguard Worker		if strings.HasPrefix(name, dirname) {
50*9e94795aSAndroid Build Coastguard Worker			return &TestFileInfo{name, 8, fs.ModeDir | fs.ModePerm}, nil
51*9e94795aSAndroid Build Coastguard Worker		}
52*9e94795aSAndroid Build Coastguard Worker	}
53*9e94795aSAndroid Build Coastguard Worker	return nil, fmt.Errorf("file not found: %q", name)
54*9e94795aSAndroid Build Coastguard Worker}
55*9e94795aSAndroid Build Coastguard Worker
56*9e94795aSAndroid Build Coastguard Worker// TestFileInfo implements a file info (fs.FileInfo) based on TestFS above.
57*9e94795aSAndroid Build Coastguard Workertype TestFileInfo struct {
58*9e94795aSAndroid Build Coastguard Worker	name string
59*9e94795aSAndroid Build Coastguard Worker	size int
60*9e94795aSAndroid Build Coastguard Worker	mode fs.FileMode
61*9e94795aSAndroid Build Coastguard Worker}
62*9e94795aSAndroid Build Coastguard Worker
63*9e94795aSAndroid Build Coastguard Workervar _ fs.FileInfo = (*TestFileInfo)(nil)
64*9e94795aSAndroid Build Coastguard Worker
65*9e94795aSAndroid Build Coastguard Worker// Name returns the name of the file
66*9e94795aSAndroid Build Coastguard Workerfunc (fi *TestFileInfo) Name() string {
67*9e94795aSAndroid Build Coastguard Worker	return fi.name
68*9e94795aSAndroid Build Coastguard Worker}
69*9e94795aSAndroid Build Coastguard Worker
70*9e94795aSAndroid Build Coastguard Worker// Size returns the size of the file in bytes.
71*9e94795aSAndroid Build Coastguard Workerfunc (fi *TestFileInfo) Size() int64 {
72*9e94795aSAndroid Build Coastguard Worker	return int64(fi.size)
73*9e94795aSAndroid Build Coastguard Worker}
74*9e94795aSAndroid Build Coastguard Worker
75*9e94795aSAndroid Build Coastguard Worker// Mode returns the fs.FileMode bits.
76*9e94795aSAndroid Build Coastguard Workerfunc (fi *TestFileInfo) Mode() fs.FileMode {
77*9e94795aSAndroid Build Coastguard Worker	return fi.mode
78*9e94795aSAndroid Build Coastguard Worker}
79*9e94795aSAndroid Build Coastguard Worker
80*9e94795aSAndroid Build Coastguard Worker// ModTime fakes a modification time.
81*9e94795aSAndroid Build Coastguard Workerfunc (fi *TestFileInfo) ModTime() time.Time {
82*9e94795aSAndroid Build Coastguard Worker	return time.UnixMicro(0xb0bb)
83*9e94795aSAndroid Build Coastguard Worker}
84*9e94795aSAndroid Build Coastguard Worker
85*9e94795aSAndroid Build Coastguard Worker// IsDir is a synonym for Mode().IsDir()
86*9e94795aSAndroid Build Coastguard Workerfunc (fi *TestFileInfo) IsDir() bool {
87*9e94795aSAndroid Build Coastguard Worker	return fi.mode.IsDir()
88*9e94795aSAndroid Build Coastguard Worker}
89*9e94795aSAndroid Build Coastguard Worker
90*9e94795aSAndroid Build Coastguard Worker// Sys is unused and returns nil.
91*9e94795aSAndroid Build Coastguard Workerfunc (fi *TestFileInfo) Sys() any {
92*9e94795aSAndroid Build Coastguard Worker	return nil
93*9e94795aSAndroid Build Coastguard Worker}
94*9e94795aSAndroid Build Coastguard Worker
95*9e94795aSAndroid Build Coastguard Worker// TestFile implements a test file (fs.File) based on TestFS above.
96*9e94795aSAndroid Build Coastguard Workertype TestFile struct {
97*9e94795aSAndroid Build Coastguard Worker	fs   *TestFS
98*9e94795aSAndroid Build Coastguard Worker	name string
99*9e94795aSAndroid Build Coastguard Worker	posn int
100*9e94795aSAndroid Build Coastguard Worker}
101*9e94795aSAndroid Build Coastguard Worker
102*9e94795aSAndroid Build Coastguard Workervar _ fs.File = (*TestFile)(nil)
103*9e94795aSAndroid Build Coastguard Worker
104*9e94795aSAndroid Build Coastguard Worker// Stat not implemented to obviate implementing fs.FileInfo.
105*9e94795aSAndroid Build Coastguard Workerfunc (f *TestFile) Stat() (fs.FileInfo, error) {
106*9e94795aSAndroid Build Coastguard Worker	return f.fs.Stat(f.name)
107*9e94795aSAndroid Build Coastguard Worker}
108*9e94795aSAndroid Build Coastguard Worker
109*9e94795aSAndroid Build Coastguard Worker// Read copies bytes from the TestFS map.
110*9e94795aSAndroid Build Coastguard Workerfunc (f *TestFile) Read(b []byte) (int, error) {
111*9e94795aSAndroid Build Coastguard Worker	if f.posn < 0 {
112*9e94795aSAndroid Build Coastguard Worker		return 0, fmt.Errorf("file not open: %q", f.name)
113*9e94795aSAndroid Build Coastguard Worker	}
114*9e94795aSAndroid Build Coastguard Worker	if f.posn >= len((*f.fs)[f.name]) {
115*9e94795aSAndroid Build Coastguard Worker		return 0, io.EOF
116*9e94795aSAndroid Build Coastguard Worker	}
117*9e94795aSAndroid Build Coastguard Worker	n := copy(b, (*f.fs)[f.name][f.posn:])
118*9e94795aSAndroid Build Coastguard Worker	f.posn += n
119*9e94795aSAndroid Build Coastguard Worker	return n, nil
120*9e94795aSAndroid Build Coastguard Worker}
121*9e94795aSAndroid Build Coastguard Worker
122*9e94795aSAndroid Build Coastguard Worker// Close marks the TestFile as no longer in use.
123*9e94795aSAndroid Build Coastguard Workerfunc (f *TestFile) Close() error {
124*9e94795aSAndroid Build Coastguard Worker	if f.posn < 0 {
125*9e94795aSAndroid Build Coastguard Worker		return fmt.Errorf("file already closed: %q", f.name)
126*9e94795aSAndroid Build Coastguard Worker	}
127*9e94795aSAndroid Build Coastguard Worker	f.posn = -1
128*9e94795aSAndroid Build Coastguard Worker	return nil
129*9e94795aSAndroid Build Coastguard Worker}
130