func Test_FinderNode_Expand_single_include(t *testing.T) { cleanup := testutils.Chtemp() defer cleanup() testutils.TouchFiles( "lib1/foo.c", "lib1/sub/blah.c", "include/bop.h", "include/bip.h") finder := NewFinderNode("*/*.c") assertExpand(t, nil, []string{"lib1/foo.c"}, finder) finder = NewFinderNode("**/*.c") assertExpand(t, nil, []string{"lib1/foo.c", "lib1/sub/blah.c"}, finder) finder = NewFinderNode("l?b?/**/*.c") assertExpand(t, nil, []string{"lib1/foo.c", "lib1/sub/blah.c"}, finder) finder = NewFinderNode("in?lu?e/*.h") assertExpand(t, nil, []string{"include/bip.h", "include/bop.h"}, finder) finder = NewFinderNode("inc*/?i*.h") assertExpand(t, nil, []string{"include/bip.h"}, finder) // adding new files changes nothing, because FinderNode caches the // result of Expand() testutils.TouchFiles("include/mip.h", "include/fibbb.h") assertExpand(t, nil, []string{"include/bip.h"}, finder) // but a new FileFinder instance will see them finder = NewFinderNode("inc*/?i*.h") assertExpand(t, nil, []string{"include/bip.h", "include/fibbb.h", "include/mip.h"}, finder) }
func Test_FinderNode_Expand_vars(t *testing.T) { // imagine code like this: // srcdir = "src/stuff" // files = <$srcdir/*.c> // "myapp": "$srcdir/main.c" { // "cc -c $files" // } // ...i.e. a FinderNode that is not in the DAG, so variable // references do not get expanded by DAG.ExpandNodes(). This is // clearly a bogus build script, but that's beside the point. We // need to ensure that the wildcard expanded is not "$srcdir/*.c" // but "src/stuff/*.c". cleanup := testutils.Chtemp() defer cleanup() testutils.TouchFiles( "lib1/foo.c", "lib1/sub/blah.c", "include/bop.h", "include/bip.h") ns := types.NewValueMap() ns.Assign("libsrc", types.MakeFuString("lib1")) finder := NewFinderNode("$libsrc/**/*.c") expect := []string{ "lib1/foo.c", "lib1/sub/blah.c", } assertExpand(t, ns, expect, finder) }
func Test_remove(t *testing.T) { cleanup := testutils.Chtemp() defer cleanup() args := RuntimeArgs{ BasicArgs: types.MakeBasicArgs(nil, []types.FuObject{}, nil), } // remove() doesn't care about empty arg list (same reason as mkdir()) result, errs := fn_remove(args) assert.Nil(t, result) assert.Equal(t, 0, len(errs)) // remove() ignores non-existent files args.SetArgs(types.MakeStringList("foo", "bar/bleep/meep", "qux").List()) result, errs = fn_remove(args) assert.Nil(t, result) assert.Equal(t, 0, len(errs)) // remove() removes regular files testutils.TouchFiles("foo", "bar/bleep/meep", "bar/bleep/feep", "qux") args.SetArgs(types.MakeStringList("foo", "bar/bleep/meep", "bogus").List()) result, errs = fn_remove(args) assert.Nil(t, result) assert.Equal(t, 0, len(errs)) assert.Equal(t, []string{"bar", "qux"}, dirContents(".")) assert.Equal(t, []string{"bleep"}, dirContents("bar")) assert.Equal(t, []string{"feep"}, dirContents("bar/bleep")) // remove() removes files and directories too testutils.TouchFiles("foo", "bar/bleep/meep", "qux") args.SetArgs(types.MakeStringList("bogus", "bar", "morebogus", "qux").List()) result, errs = fn_remove(args) assert.Nil(t, result) assert.Equal(t, 0, len(errs)) assert.Equal(t, []string{"foo"}, dirContents(".")) // remove() fails if it tries to delete from an unwriteable directory testutils.TouchFiles("bar/bong", "qux/bip") testutils.ChmodRO("bar") defer testutils.ChmodOwnerAll("bar") args.SetArgs(types.MakeStringList("bar", "qux").List()) result, errs = fn_remove(args) assert.Nil(t, result) assert.Equal(t, "remove bar/bong: permission denied", errs[0].Error()) }
func Test_findScripts(t *testing.T) { cleanup := testutils.Chtemp() defer cleanup() var script string var err error // case 1: user specifies the script to run, regardless of whether // it exists or not script, err = findScript("foo") assert.Equal(t, "foo", script) assert.Nil(t, err) // case 2: no *.fubsy files in current dir script, err = findScript("") assert.Equal(t, "main.fubsy not found (and no other *.fubsy files found)", err.Error()) // case 3: only main.fubsy exists testutils.TouchFiles("main.fubsy") script, err = findScript("") assert.Equal(t, "main.fubsy", script) assert.Nil(t, err) // case 4: multiple *.fubsy files exist, including main.fubsy testutils.TouchFiles("a.fubsy", "b.fubsy") script, err = findScript("") assert.Equal(t, "main.fubsy", script) assert.Nil(t, err) // case 5: multiple *.fubsy files exist, not including main.fubsy remove("main.fubsy") script, err = findScript("") assert.Equal(t, "", script) assert.True(t, strings.HasPrefix( err.Error(), "main.fubsy not found, and multiple *.fubsy files exist", )) // case 6: exactly one *.fubsy file exists, and it's not main.fubsy remove("a.fubsy") script, err = findScript("") assert.Equal(t, "b.fubsy", script) assert.Nil(t, err) }
func Test_FinderNode_FindFiles_prune(t *testing.T) { cleanup := testutils.Chtemp() defer cleanup() testutils.TouchFiles( "src/a/1.c", "src/a/2.c", "src/a/2.h", "src/a/3.h", "src/b/1.c", "src/b/2.c", "src/b/2.h", "src/b/3.h", "src/b/b/1.c", "src/b/b/2.c", "src/b/b/2.h", "lib/x.c", "lib/sub/x.c") var finder *FinderNode var expect []string test := func(expect []string) { actual, err := finder.FindFiles() assert.Nil(t, err) if !reflect.DeepEqual(expect, actual) { t.Errorf("includes = %v, prune = %v:\nexpected:\n%#v\nbut got:\n%#v", finder.includes, finder.prune, expect, actual) } // wipe the cache so this finder can be used again finder.matches = nil } finder = NewFinderNode("src/**/*.c", "src/b/**/*.h") finder.Prune("src/a") expect = []string{ "src/b/1.c", "src/b/2.c", "src/b/b/1.c", "src/b/b/2.c", "src/b/2.h", "src/b/3.h", "src/b/b/2.h"} test(expect) // successive calls to Prune() build up the prune set finder = NewFinderNode("*/*.c") finder.Prune("src") expect = []string{"lib/x.c"} test(expect) finder.Prune("lib") expect = []string{} test(expect) finder = NewFinderNode("*/*/?.c") expect = []string{ "lib/sub/x.c", "src/a/1.c", "src/a/2.c", "src/b/1.c", "src/b/2.c"} test(expect) finder.Prune("src/b") expect = []string{ "lib/sub/x.c", "src/a/1.c", "src/a/2.c"} test(expect) finder = NewFinderNode("**/b/?.h") expect = []string{"src/b/2.h", "src/b/3.h", "src/b/b/2.h"} test(expect) finder.Prune("src/b/b") expect = []string{"src/b/2.h", "src/b/3.h"} test(expect) finder.Prune("src/b") expect = []string{} test(expect) }
func Test_mkdir(t *testing.T) { cleanup := testutils.Chtemp() defer cleanup() // mkdir() happily accepts an empty argument list, to allow for // cases where a user-defined list becomes the arg list, and it // just happens to be empty pargs := []types.FuObject{} args := RuntimeArgs{ BasicArgs: types.MakeBasicArgs(nil, pargs, nil), } result, errs := fn_mkdir(args) assert.Nil(t, result) assert.Equal(t, 0, len(errs)) assert.Equal(t, []string{}, dirContents(".")) // easiest case: create a single dir pargs = types.MakeStringList("foo").List() args.SetArgs(pargs) result, errs = fn_mkdir(args) assert.Nil(t, result) assert.Equal(t, 0, len(errs)) assert.Equal(t, []string{"foo"}, dirContents(".")) assert.True(t, isDir("foo")) // create multiple dirs, including "foo" which already exists pargs = types.MakeStringList("meep/meep/meep", "foo", "meep/beep").List() args.SetArgs(pargs) result, errs = fn_mkdir(args) assert.Nil(t, result) assert.Equal(t, 0, len(errs)) assert.Equal(t, []string{"foo", "meep"}, dirContents(".")) assert.True(t, isDir("foo")) assert.True(t, isDir("meep/meep")) assert.True(t, isDir("meep/meep/meep")) assert.True(t, isDir("meep/beep")) // now with an error in the middle of the list (*but* we still // create the other requested dirs!) testutils.TouchFiles("meep/zap") pargs = types.MakeStringList("meep/bap", "meep/zap/zip", "foo/bar").List() args.SetArgs(pargs) result, errs = fn_mkdir(args) assert.Nil(t, result) assert.Equal(t, 1, len(errs)) assert.Equal(t, "mkdir meep/zap: not a directory", errs[0].Error()) assert.True(t, isDir("meep/bap")) assert.True(t, isDir("foo/bar")) // finally, with multiple errors pargs = append(pargs, types.MakeFuString("meep/zap/blop")) args.SetArgs(pargs) result, errs = fn_mkdir(args) assert.Nil(t, result) assert.Equal(t, 2, len(errs)) assert.Equal(t, "mkdir meep/zap: not a directory", errs[0].Error()) assert.Equal(t, "mkdir meep/zap: not a directory", errs[1].Error()) }
func touchSourceFiles(dag *DAG) { filenames := []string{} for id, node := range dag.nodes { if dag.parents[id].IsEmpty() { filenames = append(filenames, node.Name()) } } testutils.TouchFiles(filenames...) }
func Test_FinderNode_Add_Expand(t *testing.T) { cleanup := testutils.Chtemp() defer cleanup() testutils.TouchFiles( "src/foo.c", "src/foo.h", "main.c", "include/bop.h", "doc.txt", "doc/stuff.txt", "doc/blahblah.rst") finder1 := NewFinderNode("**/*.c") finder2 := NewFinderNode("doc/*.txt") // sum = <**/*.c> + <doc/*.txt> expect := []string{ "main.c", "src/foo.c", "doc/stuff.txt"} sum, err := finder1.Add(finder2) assert.Nil(t, err) assertExpand(t, nil, expect, sum) // sum = sum + <"*c*/?o?.h"> finder3 := NewFinderNode("*c*/?o?.h") expect = append(expect, "include/bop.h", "src/foo.h") sum, err = sum.Add(finder3) assert.Nil(t, err) assertExpand(t, nil, expect, sum) // sum = <*c*/?o?.h> + <**/*.c> expect = []string{ "include/bop.h", "src/foo.h", "main.c", "src/foo.c"} sum, err = finder3.Add(finder1) assert.Nil(t, err) assertExpand(t, nil, expect, sum) // sum = <doc/*.txt> + sum // (effectively: sum = <doc/*.txt> + (<*c*/?o?.h> + <**/*.c>)) expect = append([]string{"doc/stuff.txt"}, expect...) sum, err = finder2.Add(sum) assert.Nil(t, err) assertExpand(t, nil, expect, sum) // sum = <**/*.c> + "urgh" expect = []string{ "main.c", "src/foo.c", "urgh"} sum, err = finder1.Add(types.MakeFuString("urgh")) assert.Nil(t, err) assertExpand(t, nil, expect, sum) // sum = <**/*.c> + ["a", "b", "c"] expect = []string{ "main.c", "src/foo.c", "a", "b", "c"} list := types.MakeStringList("a", "b", "c") sum, err = finder1.Add(list) assert.Nil(t, err) assertExpand(t, nil, expect, sum) }
func Test_FinderNode_Expand_empty(t *testing.T) { cleanup := testutils.Chtemp() defer cleanup() // no patterns, no files: of course we find nothing finder := &FinderNode{} assertExpand(t, nil, []string{}, finder) // patterns, but no files: still nothing finder.includes = []string{"**/*.c", "include/*.h", "*/*.txt"} assertExpand(t, nil, []string{}, finder) // no patterns, some files: still nothing finder.includes = finder.includes[0:0] testutils.TouchFiles( "lib1/foo.c", "lib1/sub/blah.c", "include/bop.h", "include/bip.h") assertExpand(t, nil, []string{}, finder) }
func Test_FinderNode_Expand_double_recursion(t *testing.T) { // Java programmers love this sort of insanely deep structure, and // Ant supports patterns with multiple occurences of "**" ... so I // guess Fubsy has to support them too! cleanup := testutils.Chtemp() defer cleanup() testutils.TouchFiles( "app1/src/main/org/example/app1/App1.java", "app1/src/main/org/example/app1/Util.java", "app1/src/main/org/example/app1/doc.txt", "app1/src/main/org/example/app1/subpkg/Stuff.java", "app1/src/main/org/example/app1/subpkg/MoreStuff.java", "app1/src/test/org/example/app1/StuffTest.java", "misc/app2/src/main/org/example/app2/App2.java", "misc/app3/src/main/org/example/app3/App3.java", "misc/app3/src/main/org/example/app3/Helpers.java", "misc/app3/src/test/org/example/app3/TestHelpers.java", "misc/app3/src/test/org/example/app3/testdata", ) var finder *FinderNode var expect []string finder = NewFinderNode("**/test/**/*.java") expect = []string{ "app1/src/test/org/example/app1/StuffTest.java", "misc/app3/src/test/org/example/app3/TestHelpers.java", } assertExpand(t, nil, expect, finder) finder = NewFinderNode("**/test/**/*") expect = []string{ "app1/src/test/org/example/app1/StuffTest.java", "misc/app3/src/test/org/example/app3/TestHelpers.java", "misc/app3/src/test/org/example/app3/testdata", } assertExpand(t, nil, expect, finder) finder = NewFinderNode("**/test/**") assertExpand(t, nil, expect, finder) }
func Test_FileNode_Exists(t *testing.T) { cleanup := testutils.Chtemp() defer cleanup() testutils.TouchFiles("foo.txt", "a/a/a/a/foo.txt", "a/b/unreadable") testutils.ChmodNoAccess("a/b") defer testutils.ChmodOwnerAll("a/b") dag := NewDAG() tests := []struct { name string exists bool err string }{ {"foo.txt", true, ""}, {"a/a/a", false, "stat a/a/a: is a directory, not a regular file"}, {"a/a/a/bogus", false, ""}, {"a/a/a/a/foo.txt", true, ""}, {"a/b/unreadable", false, "stat a/b/unreadable: permission denied"}, } for _, test := range tests { node := MakeFileNode(dag, test.name) exists, err := node.Exists() if test.err != "" { assert.NotNil(t, err) assert.Equal(t, test.err, err.Error()) } if test.exists && !exists { t.Errorf("%v: expected Exists() true, got false", node) } else if !test.exists && exists { t.Errorf("%v: expected Exists() false, got true", node) } } }