Skip to content

Commit

Permalink
Refactor bfs tests to use gomega
Browse files Browse the repository at this point in the history
Signed-off-by: Ralf Pannemans <ralf.pannemans@sap.com>
  • Loading branch information
c0d1ngm0nk3y committed Oct 2, 2023
1 parent 7046139 commit 39153a8
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 116 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ go 1.20

require (
github.com/buildpacks/libcnb v1.29.0
github.com/google/go-cmp v0.5.9
github.com/magiconair/properties v1.8.7
github.com/onsi/gomega v1.28.0
github.com/paketo-buildpacks/libjvm v1.43.2
Expand All @@ -17,6 +16,7 @@ require (
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/creack/pty v1.1.18 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/h2non/filetype v1.1.3 // indirect
github.com/heroku/color v0.0.6 // indirect
github.com/imdario/mergo v0.3.16 // indirect
Expand Down
30 changes: 30 additions & 0 deletions internal/fsutil/init_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package fsutil_test

import (
"testing"

"github.com/sclevine/spec"
"github.com/sclevine/spec/report"
)

func TestUnit(t *testing.T) {
suite := spec.New("fsutil", spec.Report(report.Terminal{}))
suite("Walk", testWalk)
suite.Run(t)
}
261 changes: 146 additions & 115 deletions internal/fsutil/walk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,139 +10,170 @@ import (
"strings"
"testing"

"github.com/google/go-cmp/cmp"

. "github.com/onsi/gomega"
"github.com/paketo-buildpacks/executable-jar/v6/internal/fsutil"
"github.com/sclevine/spec"
)

func TestWalkAgainstStdlibWalk(t *testing.T) {
type fileInfo struct {
Path string
Type fs.FileMode
}
createWalkFn := func(out *[]fileInfo) filepath.WalkFunc {
return func(path string, fi fs.FileInfo, err error) error {
if err != nil {
return nil
}
var typ fs.FileMode
if fi != nil {
typ = fi.Mode().Type()
}
*out = append(*out, fileInfo{
Path: path,
Type: typ,
})
return nil
}
}
type fileInfo struct {
Path string
Type fs.FileMode
}

type args struct {
root string
}
tests := []struct {
name string
args args
}{
{
name: "basic",
args: args{
root: createTestDir(t),
},
},
{
name: "non-existent root",
args: args{
root: filepath.Join(t.TempDir(), "nonexistent"),
},
},
}
for _, tt := range tests {
const (
filename = "a.txt"
)

t.Run(tt.name, func(t *testing.T) {
var ourFiles, theirsFiles []fileInfo
errOurs := fsutil.Walk(tt.args.root, createWalkFn(&ourFiles))
errTheirs := filepath.Walk(tt.args.root, createWalkFn(&theirsFiles))
var (
contentA1A2 = "a1/a2/" + filename
contentC1A2A3 = "c1/a2/a3/" + filename
errSentinel = errors.New("sentinel")
)

if (ourFiles == nil) != (theirsFiles == nil) {
t.Errorf("errors does not match, actual error: %#v, expected error: %#v", errOurs, errTheirs)
}
func testWalk(t *testing.T, context spec.G, it spec.S) {
var (
root string
Expect = NewWithT(t).Expect
)

// sort output of filepath.Walk in BFS order
sort.SliceStable(theirsFiles, func(i, j int) bool {
iLen := len(strings.Split(theirsFiles[i].Path, string(filepath.Separator)))
jLen := len(strings.Split(theirsFiles[j].Path, string(filepath.Separator)))
return iLen < jLen
})
it.Before(func() {
root = createTestDir(t)
})

if d := cmp.Diff(theirsFiles, ourFiles); d != "" {
t.Error("output missmatch (-want, +got):", d)
context("compare to stdlib Walk", func() {

var createWalkFn func(out *[]fileInfo) filepath.WalkFunc

it.Before(func() {
createWalkFn = func(out *[]fileInfo) filepath.WalkFunc {
return func(path string, fi fs.FileInfo, err error) error {
if err != nil {
return nil
}
var typ fs.FileMode
if fi != nil {
typ = fi.Mode().Type()
}
*out = append(*out, fileInfo{
Path: path,
Type: typ,
})
return nil
}
}
})

}
}
it("basic", func() {
var ourFiles, theirFiles []fileInfo

func TestWalkSearch(t *testing.T) {
root := createTestDir(t)
sentinelErr := errors.New("sentinel")
var content string
err := fsutil.Walk(root, func(path string, fi fs.FileInfo, err error) error {
if err != nil {
return nil
}
if fi.Mode().Type() == 0 {
_, name := filepath.Split(path)
if name == "a.txt" {
bs, e := os.ReadFile(path)
if e != nil {
return e
errOurs := fsutil.Walk(root, createWalkFn(&ourFiles))
Expect(errOurs).NotTo(HaveOccurred())

errTheirs := filepath.Walk(root, createWalkFn(&theirFiles))
Expect(errTheirs).NotTo(HaveOccurred())

sortBFSOrder(theirFiles)

Expect(ourFiles).To(Equal(theirFiles))
})

it("non-existent root folder", func() {
var ourFiles, theirFiles []fileInfo
root = filepath.Join(t.TempDir(), "nonexistent")

errOurs := fsutil.Walk(root, createWalkFn(&ourFiles))
Expect(errOurs).NotTo(HaveOccurred())

errTheirs := filepath.Walk(root, createWalkFn(&theirFiles))
Expect(errTheirs).NotTo(HaveOccurred())

sortBFSOrder(theirFiles)

Expect(ourFiles).To(Equal(theirFiles))
})

it("propagate error", func() {
var ourFiles, theirFiles []fileInfo
createWalkFn = func(out *[]fileInfo) filepath.WalkFunc {
return func(path string, fi fs.FileInfo, err error) error {
return errSentinel
}
content = string(bs)
return sentinelErr
}
}
return nil

errOurs := fsutil.Walk(root, createWalkFn(&ourFiles))
Expect(errOurs).To(MatchError(errSentinel))

errTheirs := filepath.Walk(root, createWalkFn(&theirFiles))
Expect(errTheirs).To(MatchError(errSentinel))

sortBFSOrder(theirFiles)

Expect(ourFiles).To(Equal(theirFiles))
})

})
if !errors.Is(err, sentinelErr) {
t.Errorf("incorrect return value, expected sentinel error but got: %v", err)
}
if content != "a1/a2/a.txt" {
t.Errorf("unexpected content: %q", content)
}
}

func TestWalkSearchWithSkipDir(t *testing.T) {
root := createTestDir(t)
sentinelErr := errors.New("sentinel")
var content string
err := fsutil.Walk(root, func(path string, fi fs.FileInfo, err error) error {
if err != nil {
it("finds a file", func() {
var content string
err := fsutil.Walk(root, func(path string, fi fs.FileInfo, err error) error {
if err != nil {
return nil
}
if fi.Mode().Type() == 0 {
_, name := filepath.Split(path)
if name == filename {
bs, e := os.ReadFile(path)
if e != nil {
return e
}
content = string(bs)
return errSentinel
}
}
return nil
}
rp, err := filepath.Rel(root, path)
if rp == "a1" { // skip the first dir containing a.txt
return filepath.SkipDir
}
if fi.Mode().Type() == 0 {
_, name := filepath.Split(path)
if name == "a.txt" {
bs, e := os.ReadFile(path)
if e != nil {
return e
})

Expect(err).To(MatchError(errSentinel))
Expect(content).To(Equal(contentA1A2))
})

it("finds a file (skipping a dir)", func() {
var content string
err := fsutil.Walk(root, func(path string, fi fs.FileInfo, err error) error {
if err != nil {
return nil
}
rp, err := filepath.Rel(root, path)
Expect(err).NotTo(HaveOccurred())
if rp == "a1" { // skip the first dir containing a.txt
return filepath.SkipDir
}
if fi.Mode().Type() == 0 {
_, name := filepath.Split(path)
if name == filename {
bs, e := os.ReadFile(path)
if e != nil {
return e
}
content = string(bs)
return errSentinel
}
content = string(bs)
return sentinelErr
}
}
return nil
return nil
})

Expect(err).To(MatchError(errSentinel))
Expect(content).To(Equal(contentC1A2A3))
})
if !errors.Is(err, sentinelErr) {
t.Errorf("incorrect return value, expected sentinel error but got: %v", err)
}
if content != "c1/a2/a3/a.txt" {
t.Errorf("unexpected content: %q", content)
}
}

func sortBFSOrder(files []fileInfo) {
sort.SliceStable(files, func(i, j int) bool {
iLen := len(strings.Split(files[i].Path, string(filepath.Separator)))
jLen := len(strings.Split(files[j].Path, string(filepath.Separator)))
return iLen < jLen
})

}

func createTestDir(t *testing.T) string {
Expand Down Expand Up @@ -181,12 +212,12 @@ func createTestDir(t *testing.T) string {
t.Fatal(err)
}

err = os.WriteFile(filepath.Join(root, "a1", "a2", "a.txt"), []byte(`a1/a2/a.txt`), 0644)
err = os.WriteFile(filepath.Join(root, "a1", "a2", filename), []byte(contentA1A2), 0644)
if err != nil {
t.Fatal(err)
}

err = os.WriteFile(filepath.Join(root, "c1", "a2", "a3", "a.txt"), []byte(`c1/a2/a3/a.txt`), 0644)
err = os.WriteFile(filepath.Join(root, "c1", "a2", "a3", filename), []byte(contentC1A2A3), 0644)
if err != nil {
t.Fatal(err)
}
Expand Down

0 comments on commit 39153a8

Please sign in to comment.