blob: 33b7e32a4144f3501557e56e10fdcb753e25a193 [file] [log] [blame]
Fumitoshi Ukai0547db62015-07-29 16:20:59 +09001// Copyright 2015 Google Inc. All rights reserved
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package kati
16
17import (
18 "os"
19 "path/filepath"
20 "reflect"
21 "strings"
22 "testing"
23)
24
25type mockfs struct {
26 id fileid
27 ofscache *fsCacheT
28}
29
30func newFS() *mockfs {
31 fs := &mockfs{
32 ofscache: fsCache,
33 }
34 fsCache = &fsCacheT{
35 ids: make(map[string]fileid),
36 dirents: make(map[fileid][]dirent),
37 }
38 fsCache.ids["."] = fs.dir(".").id
39 return fs
40}
41
42func (m *mockfs) dump(t *testing.T) {
43 t.Log("fs ids:")
44 for name, id := range fsCache.ids {
45 t.Logf(" %q=%v", name, id)
46 }
47 t.Log("fs dirents:")
48 for id, ents := range fsCache.dirents {
49 t.Logf(" %v:", id)
50 for _, ent := range ents {
51 t.Logf(" %#v", ent)
52 }
53 }
54}
55
56func (m *mockfs) close() {
57 fsCache = m.ofscache
58}
59
60func (m *mockfs) dirent(name string, mode os.FileMode) dirent {
61 id := m.id
62 m.id.ino++
63 return dirent{id: id, name: name, mode: mode, lmode: mode}
64}
65
66func (m *mockfs) addent(name string, ent dirent) {
67 dir, name := filepath.Split(name)
68 dir = strings.TrimSuffix(dir, string(filepath.Separator))
69 if dir == "" {
70 dir = "."
71 }
72 di, ok := fsCache.ids[dir]
73 if !ok {
74 if dir == "." {
75 panic(". not found:" + name)
76 }
77 de := m.add(m.dir, dir)
78 fsCache.ids[dir] = de.id
79 di = de.id
80 }
81 for _, e := range fsCache.dirents[di] {
82 if e.name == ent.name {
83 return
84 }
85 }
86 fsCache.dirents[di] = append(fsCache.dirents[di], ent)
87}
88
89func (m *mockfs) add(t func(string) dirent, name string) dirent {
90 ent := t(filepath.Base(name))
91 m.addent(name, ent)
92 return ent
93}
94
95func (m *mockfs) symlink(name string, ent dirent) {
96 lent := ent
97 lent.lmode = os.ModeSymlink
98 lent.name = filepath.Base(name)
99 m.addent(name, lent)
100}
101
102func (m *mockfs) dirref(name string) dirent {
103 id := fsCache.ids[name]
104 return dirent{id: id, name: filepath.Base(name), mode: os.ModeDir, lmode: os.ModeDir}
105}
106
107func (m *mockfs) notfound() dirent { return dirent{id: invalidFileid} }
108func (m *mockfs) dir(name string) dirent { return m.dirent(name, os.ModeDir) }
109func (m *mockfs) file(name string) dirent { return m.dirent(name, os.FileMode(0644)) }
110
111func TestFilepathClean(t *testing.T) {
112 fs := newFS()
113 defer fs.close()
114 di := fs.add(fs.dir, "dir")
115 fs.symlink("link", di)
116
117 fs.dump(t)
118
119 for _, tc := range []struct {
120 path string
121 want string
122 }{
123 {path: "foo", want: "foo"},
124 {path: ".", want: "."},
125 {path: "./", want: "."},
126 {path: ".///", want: "."},
127 {path: "", want: "."},
128 {path: "foo/bar", want: "foo/bar"},
129 {path: "./foo", want: "foo"},
130 {path: "foo///", want: "foo"},
131 {path: "foo//bar", want: "foo/bar"},
132 {path: "foo/../bar", want: "foo/../bar"}, // foo doesn't exist
133 {path: "dir/../bar", want: "bar"}, // dir is real dir
134 {path: "link/../bar", want: "link/../bar"}, // link is symlink
135 {path: "foo/./bar", want: "foo/bar"},
136 {path: "/foo/bar", want: "/foo/bar"},
137 } {
138 if got, want := filepathClean(tc.path), tc.want; got != want {
139 t.Errorf("filepathClean(%q)=%q; want=%q", tc.path, got, want)
140 }
141 }
142}
143
144func TestParseFindCommand(t *testing.T) {
Fumitoshi Ukai2c6eff62015-08-11 17:50:56 +0900145 fs := newFS()
146 defer fs.close()
147 fs.add(fs.dir, "testdir")
148
Fumitoshi Ukai0547db62015-07-29 16:20:59 +0900149 maxdepth := 1<<31 - 1
150 for _, tc := range []struct {
151 cmd string
152 want findCommand
153 }{
154 {
155 cmd: "find testdir",
156 want: findCommand{
157 finddirs: []string{"testdir"},
158 ops: []findOp{findOpPrint{}},
159 depth: maxdepth,
160 },
161 },
162 {
163 cmd: "find .",
164 want: findCommand{
165 finddirs: []string{"."},
166 ops: []findOp{findOpPrint{}},
167 depth: maxdepth,
168 },
169 },
170 {
171 cmd: "find ",
172 want: findCommand{
173 finddirs: []string{"."},
174 ops: []findOp{findOpPrint{}},
175 depth: maxdepth,
176 },
177 },
178 {
179 cmd: "find testdir/../testdir",
180 want: findCommand{
181 finddirs: []string{"testdir/../testdir"},
182 ops: []findOp{findOpPrint{}},
183 depth: maxdepth,
184 },
185 },
186 {
187 cmd: "find testdir -print",
188 want: findCommand{
189 finddirs: []string{"testdir"},
190 ops: []findOp{findOpPrint{}},
191 depth: maxdepth,
192 },
193 },
194 {
195 cmd: "find testdir -name foo",
196 want: findCommand{
197 finddirs: []string{"testdir"},
198 ops: []findOp{findOpName("foo"), findOpPrint{}},
199 depth: maxdepth,
200 },
201 },
202 {
203 cmd: `find testdir -name "file1"`,
204 want: findCommand{
205 finddirs: []string{"testdir"},
206 ops: []findOp{findOpName("file1"), findOpPrint{}},
207 depth: maxdepth,
208 },
209 },
210 {
211 cmd: `find testdir -name "*1"`,
212 want: findCommand{
213 finddirs: []string{"testdir"},
214 ops: []findOp{findOpName("*1"), findOpPrint{}},
215 depth: maxdepth,
216 },
217 },
218 {
219 cmd: `find testdir -name "*1" -and -name "file*"`,
220 want: findCommand{
221 finddirs: []string{"testdir"},
222 ops: []findOp{findOpAnd{findOpName("*1"), findOpName("file*")}, findOpPrint{}},
223 depth: maxdepth,
224 },
225 },
226 {
227 cmd: `find testdir -name "*1" -or -name "file*"`,
228 want: findCommand{
229 finddirs: []string{"testdir"},
230 ops: []findOp{findOpOr{findOpName("*1"), findOpName("file*")}, findOpPrint{}},
231 depth: maxdepth,
232 },
233 },
234 {
235 cmd: `find testdir -name "*1" -or -type f`,
236 want: findCommand{
237 finddirs: []string{"testdir"},
238 ops: []findOp{findOpOr{findOpName("*1"), findOpRegular{}}, findOpPrint{}},
239 depth: maxdepth,
240 },
241 },
242 {
243 cmd: `find testdir -name "*1" -or -not -type f`,
244 want: findCommand{
245 finddirs: []string{"testdir"},
246 ops: []findOp{findOpOr{findOpName("*1"), findOpNot{findOpRegular{}}}, findOpPrint{}},
247 depth: maxdepth,
248 },
249 },
250 {
251 cmd: `find testdir -name "*1" -or \! -type f`,
252 want: findCommand{
253 finddirs: []string{"testdir"},
254 ops: []findOp{findOpOr{findOpName("*1"), findOpNot{findOpRegular{}}}, findOpPrint{}},
255 depth: maxdepth,
256 },
257 },
258 {
259 cmd: `find testdir -name "*1" -or -type d`,
260 want: findCommand{
261 finddirs: []string{"testdir"},
262 ops: []findOp{findOpOr{findOpName("*1"), findOpType{mode: os.ModeDir}}, findOpPrint{}},
263 depth: maxdepth,
264 },
265 },
266 {
267 cmd: `find testdir -name "*1" -or -type l`,
268 want: findCommand{
269 finddirs: []string{"testdir"},
270 ops: []findOp{findOpOr{findOpName("*1"), findOpType{mode: os.ModeSymlink}}, findOpPrint{}},
271 depth: maxdepth,
272 },
273 },
274 {
275 cmd: `find testdir -name "*1" -a -type l -o -name "dir*"`,
276 want: findCommand{
277 finddirs: []string{"testdir"},
278 ops: []findOp{findOpOr{findOpAnd([]findOp{findOpName("*1"), findOpType{mode: os.ModeSymlink}}), findOpName("dir*")}, findOpPrint{}},
279 depth: maxdepth,
280 },
281 },
282 {
283 cmd: `find testdir \( -name "dir*" -o -name "*1" \) -a -type f`,
284 want: findCommand{
285 finddirs: []string{"testdir"},
286 ops: []findOp{findOpAnd([]findOp{findOpOr{findOpName("dir*"), findOpName("*1")}, findOpRegular{}}), findOpPrint{}},
287 depth: maxdepth,
288 },
289 },
290 {
291 cmd: `cd testdir && find`,
292 want: findCommand{
293 chdir: "testdir",
294 finddirs: []string{"."},
295 ops: []findOp{findOpPrint{}},
296 depth: maxdepth,
297 },
298 },
299 {
300 cmd: `test -d testdir && find testdir`,
301 want: findCommand{
302 testdir: "testdir",
303 finddirs: []string{"testdir"},
304 ops: []findOp{findOpPrint{}},
305 depth: maxdepth,
306 },
307 },
308 {
309 cmd: `if [ -d testdir ] ; then find testdir ; fi`,
310 want: findCommand{
311 testdir: "testdir",
312 finddirs: []string{"testdir"},
313 ops: []findOp{findOpPrint{}},
314 depth: maxdepth,
315 },
316 },
317 {
318 cmd: `if [ -d testdir ]; then find testdir; fi`,
319 want: findCommand{
320 testdir: "testdir",
321 finddirs: []string{"testdir"},
322 ops: []findOp{findOpPrint{}},
323 depth: maxdepth,
324 },
325 },
326 {
327 cmd: `if [ -d testdir ]; then cd testdir && find .; fi`,
328 want: findCommand{
329 chdir: "testdir",
330 testdir: "testdir",
331 finddirs: []string{"."},
332 ops: []findOp{findOpPrint{}},
333 depth: maxdepth,
334 },
335 },
336 {
337 cmd: `find testdir -name dir2 -prune -o -name file1`,
338 want: findCommand{
339 finddirs: []string{"testdir"},
340 ops: []findOp{findOpOr{findOpAnd([]findOp{findOpName("dir2"), findOpPrune{}}), findOpName("file1")}, findOpPrint{}},
341 depth: maxdepth,
342 },
343 },
344 {
345 cmd: `find testdir testdir`,
346 want: findCommand{
347 finddirs: []string{"testdir", "testdir"},
348 ops: []findOp{findOpPrint{}},
349 depth: maxdepth,
350 },
351 },
352 {
353 cmd: `find -L testdir -type f`,
354 want: findCommand{
355 finddirs: []string{"testdir"},
356 followSymlinks: true,
357 ops: []findOp{findOpRegular{followSymlinks: true}, findOpPrint{}},
358 depth: maxdepth,
359 },
360 },
361 {
362 cmd: `cd testdir; find -L . -type f`,
363 want: findCommand{
364 chdir: "testdir",
365 finddirs: []string{"."},
366 followSymlinks: true,
367 ops: []findOp{findOpRegular{followSymlinks: true}, findOpPrint{}},
368 depth: maxdepth,
369 },
370 },
371 {
372 cmd: `find testdir -maxdepth 1`,
373 want: findCommand{
374 finddirs: []string{"testdir"},
375 ops: []findOp{findOpPrint{}},
376 depth: 1,
377 },
378 },
379 {
380 cmd: `find testdir -maxdepth 0`,
381 want: findCommand{
382 finddirs: []string{"testdir"},
383 ops: []findOp{findOpPrint{}},
384 depth: 0,
385 },
386 },
387 } {
388 fc, err := parseFindCommand(tc.cmd)
389 if err != nil {
390 t.Errorf("parseFindCommand(%q)=_, %v; want=_, <nil>", tc.cmd, err)
391 continue
392 }
393 if got, want := fc, tc.want; !reflect.DeepEqual(got, want) {
394 t.Errorf("parseFindCommand(%q)=%#v\n want=%#v\n", tc.cmd, got, want)
395 }
396 }
397
398}
399
400func TestParseFindCommandFail(t *testing.T) {
401 for _, cmd := range []string{
402 `find testdir -maxdepth hoge`,
403 `find testdir -maxdepth 1hoge`,
404 `find testdir -maxdepth -1`,
405 } {
406 _, err := parseFindCommand(cmd)
407 if err == nil {
408 t.Errorf("parseFindCommand(%q)=_, <nil>; want=_, err", cmd)
409 }
410 }
411}
412
413func TestFind(t *testing.T) {
414 fs := newFS()
415 defer fs.close()
416 fs.add(fs.file, "Makefile")
417 fs.add(fs.file, "testdir/file1")
418 fs.add(fs.file, "testdir/file2")
419 file1 := fs.add(fs.file, "testdir/dir1/file1")
420 dir1 := fs.dirref("testdir/dir1")
421 fs.add(fs.file, "testdir/dir1/file2")
422 fs.add(fs.file, "testdir/dir2/file1")
423 fs.add(fs.file, "testdir/dir2/file2")
424 fs.symlink("testdir/dir2/link1", file1)
425 fs.symlink("testdir/dir2/link2", dir1)
426 fs.symlink("testdir/dir2/link3", fs.notfound())
427
428 fs.dump(t)
429
430 maxdepth := 1<<31 - 1
431 for _, tc := range []struct {
432 fc findCommand
433 want string
434 }{
435 {
436 fc: findCommand{
437 finddirs: []string{"testdir"},
438 ops: []findOp{findOpPrint{}},
439 depth: maxdepth,
440 },
441 want: `testdir testdir/file1 testdir/file2 testdir/dir1 testdir/dir1/file1 testdir/dir1/file2 testdir/dir2 testdir/dir2/file1 testdir/dir2/file2 testdir/dir2/link1 testdir/dir2/link2 testdir/dir2/link3`,
442 },
443 {
444 fc: findCommand{
445 finddirs: []string{"."},
446 ops: []findOp{findOpPrint{}},
447 depth: maxdepth,
448 },
449 want: `. ./Makefile ./testdir ./testdir/file1 ./testdir/file2 ./testdir/dir1 ./testdir/dir1/file1 ./testdir/dir1/file2 ./testdir/dir2 ./testdir/dir2/file1 ./testdir/dir2/file2 ./testdir/dir2/link1 ./testdir/dir2/link2 ./testdir/dir2/link3`,
450 },
451 {
452 fc: findCommand{
453 finddirs: []string{"./"},
454 ops: []findOp{findOpPrint{}},
455 depth: maxdepth,
456 },
457 want: `./ ./Makefile ./testdir ./testdir/file1 ./testdir/file2 ./testdir/dir1 ./testdir/dir1/file1 ./testdir/dir1/file2 ./testdir/dir2 ./testdir/dir2/file1 ./testdir/dir2/file2 ./testdir/dir2/link1 ./testdir/dir2/link2 ./testdir/dir2/link3`,
458 },
459 {
460 fc: findCommand{
461 finddirs: []string{".///"},
462 ops: []findOp{findOpPrint{}},
463 depth: maxdepth,
464 },
465 want: `./// .///Makefile .///testdir .///testdir/file1 .///testdir/file2 .///testdir/dir1 .///testdir/dir1/file1 .///testdir/dir1/file2 .///testdir/dir2 .///testdir/dir2/file1 .///testdir/dir2/file2 .///testdir/dir2/link1 .///testdir/dir2/link2 .///testdir/dir2/link3`,
466 },
467 {
468 fc: findCommand{
469 finddirs: []string{"./."},
470 ops: []findOp{findOpPrint{}},
471 depth: maxdepth,
472 },
473 want: `./. ././Makefile ././testdir ././testdir/file1 ././testdir/file2 ././testdir/dir1 ././testdir/dir1/file1 ././testdir/dir1/file2 ././testdir/dir2 ././testdir/dir2/file1 ././testdir/dir2/file2 ././testdir/dir2/link1 ././testdir/dir2/link2 ././testdir/dir2/link3`,
474 },
475 {
476 fc: findCommand{
477 finddirs: []string{"././"},
478 ops: []findOp{findOpPrint{}},
479 depth: maxdepth,
480 },
481 want: `././ ././Makefile ././testdir ././testdir/file1 ././testdir/file2 ././testdir/dir1 ././testdir/dir1/file1 ././testdir/dir1/file2 ././testdir/dir2 ././testdir/dir2/file1 ././testdir/dir2/file2 ././testdir/dir2/link1 ././testdir/dir2/link2 ././testdir/dir2/link3`,
482 },
483 {
484 fc: findCommand{
485 finddirs: []string{"testdir/../testdir"},
486 ops: []findOp{findOpPrint{}},
487 depth: maxdepth,
488 },
489 want: `testdir/../testdir testdir/../testdir/file1 testdir/../testdir/file2 testdir/../testdir/dir1 testdir/../testdir/dir1/file1 testdir/../testdir/dir1/file2 testdir/../testdir/dir2 testdir/../testdir/dir2/file1 testdir/../testdir/dir2/file2 testdir/../testdir/dir2/link1 testdir/../testdir/dir2/link2 testdir/../testdir/dir2/link3`,
490 },
491 {
492 fc: findCommand{
493 finddirs: []string{"testdir"},
494 ops: []findOp{findOpName("foo"), findOpPrint{}},
495 depth: maxdepth,
496 },
497 want: ``,
498 },
499 {
500 fc: findCommand{
501 finddirs: []string{"testdir"},
502 ops: []findOp{findOpName("file1"), findOpPrint{}},
503 depth: maxdepth,
504 },
505 want: `testdir/file1 testdir/dir1/file1 testdir/dir2/file1`,
506 },
507 {
508 fc: findCommand{
509 finddirs: []string{"testdir"},
510 ops: []findOp{findOpAnd{findOpName("*1"), findOpName("file*")}, findOpPrint{}},
511 depth: maxdepth,
512 },
513 want: `testdir/file1 testdir/dir1/file1 testdir/dir2/file1`,
514 },
515 {
516 fc: findCommand{
517 finddirs: []string{"testdir"},
518 ops: []findOp{findOpOr{findOpName("*1"), findOpName("file*")}, findOpPrint{}},
519 depth: maxdepth,
520 },
521 want: `testdir/file1 testdir/file2 testdir/dir1 testdir/dir1/file1 testdir/dir1/file2 testdir/dir2/file1 testdir/dir2/file2 testdir/dir2/link1`,
522 },
523 {
524 fc: findCommand{
525 finddirs: []string{"testdir"},
526 ops: []findOp{findOpOr{findOpName("*1"), findOpRegular{}}, findOpPrint{}},
527 depth: maxdepth,
528 },
529 want: `testdir/file1 testdir/file2 testdir/dir1 testdir/dir1/file1 testdir/dir1/file2 testdir/dir2/file1 testdir/dir2/file2 testdir/dir2/link1`,
530 },
531 {
532 fc: findCommand{
533 finddirs: []string{"testdir"},
534 ops: []findOp{findOpOr{findOpName("*1"), findOpNot{findOpRegular{}}}, findOpPrint{}},
535 depth: maxdepth,
536 },
537 want: `testdir testdir/file1 testdir/dir1 testdir/dir1/file1 testdir/dir2 testdir/dir2/file1 testdir/dir2/link1 testdir/dir2/link2 testdir/dir2/link3`,
538 },
539 {
540 fc: findCommand{
541 finddirs: []string{"testdir"},
542 ops: []findOp{findOpOr{findOpName("*1"), findOpType{mode: os.ModeDir}}, findOpPrint{}},
543 depth: maxdepth,
544 },
545 want: `testdir testdir/file1 testdir/dir1 testdir/dir1/file1 testdir/dir2 testdir/dir2/file1 testdir/dir2/link1`,
546 },
547 {
548 fc: findCommand{
549 finddirs: []string{"testdir"},
550 ops: []findOp{findOpOr{findOpName("*1"), findOpType{mode: os.ModeSymlink}}, findOpPrint{}},
551 depth: maxdepth,
552 },
553 want: `testdir/file1 testdir/dir1 testdir/dir1/file1 testdir/dir2/file1 testdir/dir2/link1 testdir/dir2/link2 testdir/dir2/link3`,
554 },
555 {
556 fc: findCommand{
557 finddirs: []string{"testdir"},
558 ops: []findOp{findOpOr{findOpAnd([]findOp{findOpName("*1"), findOpType{mode: os.ModeSymlink}}), findOpName("dir*")}, findOpPrint{}},
559 depth: maxdepth,
560 },
561 want: `testdir/dir1 testdir/dir2 testdir/dir2/link1`,
562 },
563 {
564 fc: findCommand{
565 finddirs: []string{"testdir"},
566 ops: []findOp{findOpOr{findOpAnd([]findOp{findOpName("*1"), findOpType{mode: os.ModeSymlink}}), findOpName("dir*")}, findOpPrint{}},
567 depth: maxdepth,
568 },
569 want: `testdir/dir1 testdir/dir2 testdir/dir2/link1`,
570 },
571 {
572 fc: findCommand{
573 finddirs: []string{"testdir"},
574 ops: []findOp{findOpAnd([]findOp{findOpOr{findOpName("dir*"), findOpName("*1")}, findOpRegular{}}), findOpPrint{}},
575 depth: maxdepth,
576 },
577 want: `testdir/file1 testdir/dir1/file1 testdir/dir2/file1`,
578 },
579 {
580 fc: findCommand{
581 chdir: "testdir",
582 finddirs: []string{"."},
583 ops: []findOp{findOpPrint{}},
584 depth: maxdepth,
585 },
586 want: `. ./file1 ./file2 ./dir1 ./dir1/file1 ./dir1/file2 ./dir2 ./dir2/file1 ./dir2/file2 ./dir2/link1 ./dir2/link2 ./dir2/link3`,
587 },
588 {
589 fc: findCommand{
590 chdir: "testdir",
591 finddirs: []string{"../testdir"},
592 ops: []findOp{findOpPrint{}},
593 depth: maxdepth,
594 },
595 want: `../testdir ../testdir/file1 ../testdir/file2 ../testdir/dir1 ../testdir/dir1/file1 ../testdir/dir1/file2 ../testdir/dir2 ../testdir/dir2/file1 ../testdir/dir2/file2 ../testdir/dir2/link1 ../testdir/dir2/link2 ../testdir/dir2/link3`,
596 },
597 {
598 fc: findCommand{
599 testdir: "testdir",
600 finddirs: []string{"testdir"},
601 ops: []findOp{findOpPrint{}},
602 depth: maxdepth,
603 },
604 want: `testdir testdir/file1 testdir/file2 testdir/dir1 testdir/dir1/file1 testdir/dir1/file2 testdir/dir2 testdir/dir2/file1 testdir/dir2/file2 testdir/dir2/link1 testdir/dir2/link2 testdir/dir2/link3`,
605 },
606 {
607 fc: findCommand{
608 chdir: "testdir",
609 testdir: "testdir",
610 finddirs: []string{"."},
611 ops: []findOp{findOpPrint{}},
612 depth: maxdepth,
613 },
614 want: `. ./file1 ./file2 ./dir1 ./dir1/file1 ./dir1/file2 ./dir2 ./dir2/file1 ./dir2/file2 ./dir2/link1 ./dir2/link2 ./dir2/link3`,
615 },
616 {
617 fc: findCommand{
618 finddirs: []string{"testdir"},
619 ops: []findOp{findOpOr{findOpAnd([]findOp{findOpName("dir2"), findOpPrune{}}), findOpName("file1")}, findOpPrint{}},
620 depth: maxdepth,
621 },
622 want: `testdir/file1 testdir/dir1/file1 testdir/dir2`,
623 },
624 {
625 fc: findCommand{
626 finddirs: []string{"testdir", "testdir"},
627 ops: []findOp{findOpPrint{}},
628 depth: maxdepth,
629 },
630 want: `testdir testdir/file1 testdir/file2 testdir/dir1 testdir/dir1/file1 testdir/dir1/file2 testdir/dir2 testdir/dir2/file1 testdir/dir2/file2 testdir/dir2/link1 testdir/dir2/link2 testdir/dir2/link3 testdir testdir/file1 testdir/file2 testdir/dir1 testdir/dir1/file1 testdir/dir1/file2 testdir/dir2 testdir/dir2/file1 testdir/dir2/file2 testdir/dir2/link1 testdir/dir2/link2 testdir/dir2/link3`,
631 },
632 // symlink
633 {
634 fc: findCommand{
635 finddirs: []string{"testdir"},
636 followSymlinks: true,
637 ops: []findOp{findOpRegular{followSymlinks: true}, findOpPrint{}},
638 depth: maxdepth,
639 },
640 want: `testdir/file1 testdir/file2 testdir/dir1/file1 testdir/dir1/file2 testdir/dir2/file1 testdir/dir2/file2 testdir/dir2/link1 testdir/dir2/link2/file1 testdir/dir2/link2/file2`,
641 },
642 {
643 fc: findCommand{
644 finddirs: []string{"testdir"},
645 followSymlinks: true,
646 ops: []findOp{findOpType{mode: os.ModeDir, followSymlinks: true}, findOpPrint{}},
647 depth: maxdepth,
648 },
649 want: `testdir testdir/dir1 testdir/dir2 testdir/dir2/link2`,
650 },
651 {
652 fc: findCommand{
653 finddirs: []string{"testdir"},
654 followSymlinks: true,
655 ops: []findOp{findOpType{mode: os.ModeSymlink, followSymlinks: true}, findOpPrint{}},
656 depth: maxdepth,
657 },
658 want: `testdir/dir2/link3`,
659 },
660 {
661 fc: findCommand{
662 chdir: "testdir",
663 finddirs: []string{"."},
664 followSymlinks: true,
665 ops: []findOp{findOpRegular{followSymlinks: true}, findOpPrint{}},
666 depth: maxdepth,
667 },
668 want: `./file1 ./file2 ./dir1/file1 ./dir1/file2 ./dir2/file1 ./dir2/file2 ./dir2/link1 ./dir2/link2/file1 ./dir2/link2/file2`,
669 },
670 // maxdepth
671 {
672 fc: findCommand{
673 finddirs: []string{"testdir"},
674 ops: []findOp{findOpPrint{}},
675 depth: 1,
676 },
677 want: `testdir testdir/file1 testdir/file2 testdir/dir1 testdir/dir2`,
678 },
679 {
680 fc: findCommand{
681 finddirs: []string{"testdir"},
682 ops: []findOp{findOpPrint{}},
683 depth: 2,
684 },
685 want: `testdir testdir/file1 testdir/file2 testdir/dir1 testdir/dir1/file1 testdir/dir1/file2 testdir/dir2 testdir/dir2/file1 testdir/dir2/file2 testdir/dir2/link1 testdir/dir2/link2 testdir/dir2/link3`,
686 },
687 {
688 fc: findCommand{
689 finddirs: []string{"testdir"},
690 ops: []findOp{findOpPrint{}},
691 depth: 0,
692 },
693 want: `testdir`,
694 },
695 } {
696 var wb wordBuffer
697 tc.fc.run(&wb)
698 if got, want := wb.buf.String(), tc.want; got != want {
699 t.Errorf("%#v\n got %q\n want %q", tc.fc, got, want)
700 }
701 }
702}
703
704func TestParseFindleavesCommand(t *testing.T) {
705 for _, tc := range []struct {
706 cmd string
707 want findleavesCommand
708 }{
709 {
710 cmd: `build/tools/findleaves.py --prune=out --prune=.repo --prune=.git . CleanSpec.mk`,
711 want: findleavesCommand{
712 name: "CleanSpec.mk",
713 dirs: []string{"."},
714 prunes: []string{"out", ".repo", ".git"},
715 mindepth: -1,
716 },
717 },
718 {
719 cmd: `build/tools/findleaves.py --prune=out --prune=.repo --prune=.git --mindepth=2 art bionic Android.mk`,
720 want: findleavesCommand{
721 name: "Android.mk",
722 dirs: []string{"art", "bionic"},
723 prunes: []string{"out", ".repo", ".git"},
724 mindepth: 2,
725 },
726 },
727 } {
728 fc, err := parseFindleavesCommand(tc.cmd)
729 if err != nil {
730 t.Errorf("parseFindleavesCommand(%q)=_, %v; want=_, <nil", tc.cmd, err)
731 continue
732 }
733 if got, want := fc, tc.want; !reflect.DeepEqual(got, want) {
734 t.Errorf("parseFindleavesCommand(%q)=%#v\n want=%#v\n", tc.cmd, got, want)
735 }
736 }
737}
738
739func TestFindleaves(t *testing.T) {
740 fs := newFS()
741 defer fs.close()
742
743 fs.add(fs.file, "art/Android.mk")
744 fs.add(fs.file, "art/compiler/Android.mk")
745 fs.add(fs.file, "art/CleanSpec.mk")
746 fs.add(fs.file, "bionic/Android.mk")
747 fs.add(fs.file, "bionic/CleanSpec.mk")
748 fs.add(fs.file, "bootable/recovery/Android.mk")
749 fs.add(fs.file, "bootable/recovery/CleanSpec.mk")
750 fs.add(fs.file, "frameworks/base/Android.mk")
751 fs.add(fs.file, "frameworks/base/CleanSpec.mk")
752 fs.add(fs.file, "frameworks/base/cmds/am/Android.mk")
753 fs.add(fs.file, "frameworks/base/cmds/pm/Android.mk")
754 fs.add(fs.file, "frameworks/base/location/Android.mk")
755 fs.add(fs.file, "frameworks/base/packages/WAPPushManager/CleanSpec.mk")
756 fs.add(fs.file, "out/outputfile")
757 fs.add(fs.file, "art/.git/index")
758 fs.add(fs.file, ".repo/manifests")
759
760 fs.dump(t)
761
762 for _, tc := range []struct {
763 fc findleavesCommand
764 want string
765 }{
766 {
767 fc: findleavesCommand{
768 name: "CleanSpec.mk",
769 dirs: []string{"."},
770 prunes: []string{"out", ".repo", ".git"},
771 mindepth: -1,
772 },
773 want: `./art/CleanSpec.mk ./bionic/CleanSpec.mk ./bootable/recovery/CleanSpec.mk ./frameworks/base/CleanSpec.mk`,
774 },
775 {
776 fc: findleavesCommand{
777 name: "Android.mk",
778 dirs: []string{"art", "bionic", "frameworks/base"},
779 prunes: []string{"out", ".repo", ".git"},
780 mindepth: 2,
781 },
782 want: `art/compiler/Android.mk frameworks/base/cmds/am/Android.mk frameworks/base/cmds/pm/Android.mk frameworks/base/location/Android.mk`,
783 },
784 {
785 fc: findleavesCommand{
786 name: "Android.mk",
787 dirs: []string{"art", "bionic", "frameworks/base"},
788 prunes: []string{"out", ".repo", ".git"},
789 mindepth: 3,
790 },
791 want: `frameworks/base/cmds/am/Android.mk frameworks/base/cmds/pm/Android.mk`,
792 },
793 } {
794 var wb wordBuffer
795 tc.fc.run(&wb)
796 if got, want := wb.buf.String(), tc.want; got != want {
797 t.Errorf("%#v\n got %q\n want %q", tc.fc, got, want)
798 }
799 }
800}