go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/fs/find_files_test.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package fs 5 6 import ( 7 "fmt" 8 "io/fs" 9 "os" 10 "regexp" 11 "strings" 12 "testing" 13 14 "github.com/spf13/afero" 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 ) 18 19 func TestFindFilesMatcher(t *testing.T) { 20 possibleTypes := []byte{'b', 'c', 'd', 'p', 'f', 'l'} 21 possibleModes := []fs.FileMode{ 22 fs.ModeDevice, 23 fs.ModeDevice | fs.ModeCharDevice, 24 fs.ModeDir, 25 fs.ModeNamedPipe, 26 fs.ModePerm, 27 fs.ModeSymlink, 28 } 29 t.Run("type matching", func(t *testing.T) { 30 testCases := []struct { 31 typ fs.FileMode 32 matches byte 33 }{ 34 { 35 typ: fs.ModeDir, 36 matches: 'd', 37 }, 38 { 39 typ: fs.ModePerm, 40 matches: 'f', 41 }, 42 { 43 typ: fs.ModeDevice | fs.ModeCharDevice, 44 matches: 'c', 45 }, 46 { 47 typ: fs.ModeDevice, 48 matches: 'b', 49 }, 50 { 51 typ: fs.ModeSymlink, 52 matches: 'l', 53 }, 54 { 55 typ: fs.ModeNamedPipe, 56 matches: 'p', 57 }, 58 } 59 60 for _, tc := range testCases { 61 excludeTypes := []string{} 62 for _, b := range possibleTypes { 63 if b != tc.matches { 64 excludeTypes = append(excludeTypes, string(b)) 65 } 66 } 67 t.Run(fmt.Sprintf("%s matcher", string(tc.matches)), func(t *testing.T) { 68 exclusionMatcher := createFindFilesMatcher(strings.Join(excludeTypes, ","), nil) 69 exactMatcher := createFindFilesMatcher(string(tc.matches), nil) 70 assert.True(t, exactMatcher.Match("/foo", tc.typ), "exact matcher failed to match") 71 assert.False(t, exclusionMatcher.Match("/foo", tc.typ), "exclusion matcher matched") 72 }) 73 } 74 }) 75 76 t.Run("regex", func(t *testing.T) { 77 t.Run("any type", func(t *testing.T) { 78 exactMatcher := createFindFilesMatcher("", regexp.MustCompile("foo.*")) 79 80 for _, m := range possibleModes { 81 t.Run(fmt.Sprintf("mode %s", m.String()), func(t *testing.T) { 82 assert.True(t, exactMatcher.Match("foobar", m)) 83 assert.True(t, exactMatcher.Match("foofoobar", m)) 84 assert.False(t, exactMatcher.Match("barfoo", m)) 85 }) 86 } 87 }) 88 89 t.Run("specific type", func(t *testing.T) { 90 exactMatcher := createFindFilesMatcher("f", regexp.MustCompile("foo.*")) 91 92 assert.False(t, exactMatcher.Match("foobar", fs.ModeDir)) 93 assert.True(t, exactMatcher.Match("foobar", fs.ModePerm)) 94 }) 95 }) 96 97 t.Run("no type or regex", func(t *testing.T) { 98 testCases := []struct { 99 typ fs.FileMode 100 matches byte 101 }{ 102 { 103 typ: fs.ModeDir, 104 matches: 'd', 105 }, 106 { 107 typ: fs.ModePerm, 108 matches: 'f', 109 }, 110 { 111 typ: fs.ModeDevice | fs.ModeCharDevice, 112 matches: 'c', 113 }, 114 { 115 typ: fs.ModeDevice, 116 matches: 'b', 117 }, 118 { 119 typ: fs.ModeSymlink, 120 matches: 'l', 121 }, 122 { 123 typ: fs.ModeNamedPipe, 124 matches: 'p', 125 }, 126 } 127 for _, tc := range testCases { 128 excludeTypes := []string{} 129 for _, b := range possibleTypes { 130 if b != tc.matches { 131 excludeTypes = append(excludeTypes, string(b)) 132 } 133 } 134 t.Run(fmt.Sprintf("%s matcher", string(tc.matches)), func(t *testing.T) { 135 exactMatcher := createFindFilesMatcher("", nil) 136 assert.True(t, exactMatcher.Match("/foo", tc.typ), "matcher failed to match") 137 }) 138 } 139 }) 140 } 141 142 func TestFindFiles(t *testing.T) { 143 fs := afero.NewMemMapFs() 144 mkDir(t, fs, "root/a") 145 mkDir(t, fs, "root/b") 146 mkDir(t, fs, "root/c") 147 mkFile(t, fs, "root/a/file1") 148 mkFile(t, fs, "root/a/file2") 149 mkFile(t, fs, "root/b/file1") 150 151 rootAFiles, err := FindFiles(afero.NewIOFS(fs), "root/a", nil, "f") 152 require.NoError(t, err) 153 assert.ElementsMatch(t, rootAFiles, []string{"root/a/file1", "root/a/file2"}) 154 155 rootAFilesAndDir, err := FindFiles(afero.NewIOFS(fs), "root/a", nil, "f,d") 156 require.NoError(t, err) 157 assert.ElementsMatch(t, rootAFilesAndDir, []string{"root/a", "root/a/file1", "root/a/file2"}) 158 159 rootBFiles, err := FindFiles(afero.NewIOFS(fs), "root", regexp.MustCompile("root/b.*"), "f") 160 assert.ElementsMatch(t, rootBFiles, []string{"root/b/file1"}) 161 } 162 163 func mkFile(t *testing.T, fs afero.Fs, name string) { 164 t.Helper() 165 f, err := fs.Create(name) 166 require.NoError(t, err) 167 err = f.Close() 168 require.NoError(t, err) 169 } 170 171 func mkDir(t *testing.T, fs afero.Fs, name string) { 172 t.Helper() 173 err := fs.MkdirAll(name, os.ModePerm) 174 require.NoError(t, err) 175 }