Skip to content

Commit

Permalink
Refactor bfs tests to use gomega
Browse files Browse the repository at this point in the history
Co-authored-by: Anthony Dahanne <anthony.dahanne@gmail.com>
Signed-off-by: Ralf Pannemans <ralf.pannemans@sap.com>
  • Loading branch information
c0d1ngm0nk3y and anthonydahanne committed Oct 18, 2023
1 parent f96a870 commit 1883f27
Show file tree
Hide file tree
Showing 4 changed files with 217 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.6.0
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
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg=
github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
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)
}
297 changes: 184 additions & 113 deletions internal/fsutil/walk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,141 +10,212 @@ 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 {
type fileInfo struct {
Path string
Type fs.FileMode
}

const (
filename = "a.txt"
contentA1A2 = "a1/a2/" + filename
contentC1A2A3 = "c1/a2/a3/" + filename
)

var (
errSentinel = errors.New("sentinel")
)

func testWalk(t *testing.T, context spec.G, it spec.S) {
var (
root string
Expect = NewWithT(t).Expect
)

it.Before(func() {
root = createTestDir(t)
})

context("compare to stdlib Walk", func() {

var createWalkFn func(out *[]fileInfo) filepath.WalkFunc = 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
}
var typ fs.FileMode
if fi != nil {
typ = fi.Mode().Type()
}
*out = append(*out, fileInfo{
Path: path,
Type: typ,
})
return nil
}
}

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 {
it("basic", func() {
var ourFiles, theirFiles []fileInfo

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))
errOurs := fsutil.Walk(root, createWalkFn(&ourFiles))
Expect(errOurs).NotTo(HaveOccurred())

if (ourFiles == nil) != (theirsFiles == nil) {
t.Errorf("errors does not match, actual error: %#v, expected error: %#v", errOurs, errTheirs)
}
errTheirs := filepath.Walk(root, createWalkFn(&theirFiles))
Expect(errTheirs).NotTo(HaveOccurred())

// 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
})
sortBFSOrder(theirFiles)

if d := cmp.Diff(theirsFiles, ourFiles); d != "" {
t.Error("output missmatch (-want, +got):", d)
}
Expect(ourFiles).To(Equal(theirFiles))
})

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

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("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
})

}

// Create this file structure for the tests to run (obtained using `tree`)
// ├── a.lnk -> a1
// ├── a1
// │ ├── a2
// │ │ ├── a.txt
// │ │ ├── a3
// │ │ ├── b3
// │ │ └── c3
// │ ├── b2
// │ │ ├── a3
// │ │ ├── b3
// │ │ └── c3
// │ └── c2
// │ ├── a3
// │ ├── b3
// │ └── c3
// ├── b1
// │ ├── a2
// │ │ ├── a3
// │ │ ├── b3
// │ │ └── c3
// │ ├── b2
// │ │ ├── a3
// │ │ ├── b3
// │ │ └── c3
// │ └── c2
// │ ├── a3
// │ ├── b3
// │ └── c3
// └── c1
//
// ├── a2
// │ ├── a3
// │ │ └── a.txt
// │ ├── b3
// │ └── c3
// ├── b2
// │ ├── a3
// │ ├── b3
// │ └── c3
// └── c2
// ├── a3
// ├── b3
// └── c3
func createTestDir(t *testing.T) string {
root := t.TempDir()
var err error
Expand Down Expand Up @@ -181,12 +252,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 1883f27

Please sign in to comment.