Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(hydra): export virtual tree (#224) #245

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
"nicksnyder",
"nolint",
"nolintlint",
"Nuxx",
"onsi",
"outdir",
"Persistable",
Expand Down
129 changes: 91 additions & 38 deletions ...rnal/laboratory/directory-tree-builder.go → hydra/virtual-tree.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package lab
package hydra

import (
"bytes"
"encoding/xml"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"testing/fstest"
Expand All @@ -14,47 +15,69 @@ import (
"github.com/snivilised/traverse/internal/third/lo"
)

const (
offset = 2
tabSize = 2
doWrite = true
)
// Nuxx is a luna.MemFS factory hardcoded to Musico
func Nuxx(verbose bool, portions ...string) (fS *luna.MemFS) {
fS = luna.NewMemFS()

musico(
newMemWriteProvider(fS, os.ReadFile, verbose, portions...),
verbose,
)

return fS
}

func Musico(verbose bool, portions ...string) (fS *luna.MemFS, root string) {
// CustomTree is a luna.MemFS factory, equivalent to Nuxx that is populated by an
// alternative xml file. index is the full path the xml index file and
// tree is the name of the root element in the file (for Nuxx, this would be
// "MUSICO"). The tree can be filtered by specifying 'portions'.
func CustomTree(index, element string, verbose bool,
portions ...string,
) (fS *luna.MemFS, err error) {
fS = luna.NewMemFS()

root = Provision(
NewMemWriteProvider(fS, os.ReadFile, portions...),
err = custom(
index,
element,
newMemWriteProvider(fS, os.ReadFile, verbose, portions...),
verbose,
portions...,
)

return fS, root
return fS, err
}

func Provision(provider *IOProvider, verbose bool, portions ...string) (root string) {
repo := Repo("")
root = filepath.Join(repo, "test", "data", "MUSICO")
index := Join(repo, "test/data/musico-index.xml")
// index is the full path to the xml index to load, including the xml file name
// tree is the name of the root element of the tree
func custom(index, tree string, provider *IOProvider, verbose bool) error {
if _, err := os.Stat(index); err != nil {
return err
}

if err := ensure(index, provider, verbose); err != nil {
if err := ensure(index, tree, provider, verbose); err != nil {
fmt.Printf("provision failed %v\n", err.Error())
return ""
}

if verbose {
fmt.Printf("\n🤖 re-generated tree at '%v' (filters: '%v')\n\n",
root, strings.Join(portions, ", "),
)
}
return nil
}
Comment on lines +56 to +60
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Return the error from the ensure function call in custom

The custom function calls ensure, and if ensure returns an error, it currently prints the error message but does not return the error. This can lead to silent failures for callers of custom who might assume that no error occurred. It's important to propagate the error to allow proper handling upstream.

Apply this diff to fix the error handling:

 func custom(index, tree string, provider *IOProvider, verbose bool) error {
     if _, err := os.Stat(index); err != nil {
         return err
     }

     if err := ensure(index, tree, provider, verbose); err != nil {
         fmt.Printf("provision failed %v\n", err.Error())
+        return err
     }

     return nil
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if err := ensure(index, tree, provider, verbose); err != nil {
fmt.Printf("provision failed %v\n", err.Error())
return ""
}
if verbose {
fmt.Printf("\n🤖 re-generated tree at '%v' (filters: '%v')\n\n",
root, strings.Join(portions, ", "),
)
}
return nil
if err := ensure(index, tree, provider, verbose); err != nil {
fmt.Printf("provision failed %v\n", err.Error())
return err
}
return nil


const (
offset = 2
tabSize = 2
doWrite = true
)

return root
func musico(provider *IOProvider, verbose bool) {
repo := Repo("")
index := Combine(repo, "test/data/musico-index.xml")

if err := ensure(index, "MUSICO", provider, verbose); err != nil {
fmt.Printf("provision failed %v\n", err.Error())
}
}

// ensure
func ensure(index string, provider *IOProvider, verbose bool) error {
builder := directoryTreeBuilder{
tree: "MUSICO",
func ensure(index, tree string, provider *IOProvider, verbose bool) error {
builder := virtualTree{
tree: tree,
stack: collections.NewStack[string](),
index: index,
doWrite: doWrite,
Expand All @@ -74,8 +97,9 @@ func ensure(index string, provider *IOProvider, verbose bool) error {
return builder.walk()
}

func NewMemWriteProvider(fS *luna.MemFS,
func newMemWriteProvider(fS *luna.MemFS,
indexReader readFile,
verbose bool,
portions ...string,
) *IOProvider {
filter := lo.Ternary(len(portions) > 0,
Expand All @@ -93,6 +117,12 @@ func NewMemWriteProvider(fS *luna.MemFS,
}),
)

if verbose {
fmt.Printf("\n🤖 re-generating tree (filters: '%v')\n\n",
strings.Join(portions, ", "),
)
}

// PS: to check the existence of a path in an fs in production
// code, use fs.Stat(fsys, path) instead of os.Stat/os.Lstat

Expand Down Expand Up @@ -230,8 +260,8 @@ func (fn matcher) match(portion string) bool {
return fn(portion)
}

// directoryTreeBuilder
type directoryTreeBuilder struct {
// virtualTree
type virtualTree struct {
tree string
full string
stack *collections.Stack[string]
Expand All @@ -244,7 +274,7 @@ type directoryTreeBuilder struct {
show display
}

func (r *directoryTreeBuilder) read() (*Directory, error) {
func (r *virtualTree) read() (*Directory, error) {
data, err := r.provider.file.in.read(r.index)

if err != nil {
Expand All @@ -260,32 +290,32 @@ func (r *directoryTreeBuilder) read() (*Directory, error) {
return &tree.Root, nil
}

func (r *directoryTreeBuilder) pad() string {
func (r *virtualTree) pad() string {
return string(bytes.Repeat([]byte{' '}, (r.depth+offset)*tabSize))
}

func (r *directoryTreeBuilder) refill() string {
func (r *virtualTree) refill() string {
segments := r.stack.Content()
return filepath.Join(segments...)
}

func (r *directoryTreeBuilder) inc(name string) {
func (r *virtualTree) inc(name string) {
r.stack.Push(name)
r.full = r.refill()

r.depth++
r.padding = r.pad()
}

func (r *directoryTreeBuilder) dec() {
func (r *virtualTree) dec() {
_, _ = r.stack.Pop()
r.full = r.refill()

r.depth--
r.padding = r.pad()
}

func (r *directoryTreeBuilder) walk() error {
func (r *virtualTree) walk() error {
top, err := r.read()

if err != nil {
Expand All @@ -297,7 +327,7 @@ func (r *directoryTreeBuilder) walk() error {
return r.dir(*top, true)
}

func (r *directoryTreeBuilder) dir(dir Directory, isRoot bool) error { //nolint:gocritic // performance is not a concern
func (r *virtualTree) dir(dir Directory, isRoot bool) error { //nolint:gocritic // performance is not a concern
if !isRoot {
// We dont to add the root because only the descendents of the root
// should be added
Expand All @@ -322,7 +352,7 @@ func (r *directoryTreeBuilder) dir(dir Directory, isRoot bool) error { //nolint:
}

for _, file := range dir.Files {
full := Join(r.full, file.Name)
full := Combine(r.full, file.Name)

if r.doWrite {
if err := r.provider.file.out.write(
Expand All @@ -340,3 +370,26 @@ func (r *directoryTreeBuilder) dir(dir Directory, isRoot bool) error { //nolint:

return nil
}

// remember to remove Join and Repo from lab

// Combine creates a path from the parent combined with the relative path. The relative
// path is a file system path so should only contain forward slashes, not the standard
// file path separator as denoted by filepath.Separator, typically used when interacting
// with the local file system. Do not use trailing "/".
func Combine(parent, relative string) string {
if relative == "" {
return parent
}

return parent + "/" + relative
}

// Repo gets the path of the repo with relative joined on
func Repo(relative string) string {
cmd := exec.Command("git", "rev-parse", "--show-toplevel")
output, _ := cmd.Output()
repo := strings.TrimSpace(string(output))

return Combine(repo, relative)
Comment on lines +391 to +393
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle the error returned by cmd.Output() in Repo

The Repo function calls cmd.Output() but ignores the returned error. If an error occurs while executing the git command, repo may be empty or invalid, leading to unexpected behavior downstream. It's important to check and handle the error to ensure reliability.

Apply this diff to handle the error:

 func Repo(relative string) string {
     cmd := exec.Command("git", "rev-parse", "--show-toplevel")
-    output, _ := cmd.Output()
+    output, err := cmd.Output()
+    if err != nil {
+        fmt.Printf("Error obtaining repository path: %v\n", err)
+        return Combine("", relative)
+    }
     repo := strings.TrimSpace(string(output))

     return Combine(repo, relative)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
output, _ := cmd.Output()
repo := strings.TrimSpace(string(output))
output, err := cmd.Output()
if err != nil {
fmt.Printf("Error obtaining repository path: %v\n", err)
return Combine("", relative)
}
repo := strings.TrimSpace(string(output))

}
15 changes: 10 additions & 5 deletions internal/feat/hiber/hibernate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,31 @@ import (
tv "github.com/snivilised/traverse"
"github.com/snivilised/traverse/core"
"github.com/snivilised/traverse/enums"
"github.com/snivilised/traverse/hydra"
lab "github.com/snivilised/traverse/internal/laboratory"
"github.com/snivilised/traverse/internal/services"
"github.com/snivilised/traverse/internal/third/lo"
)

var _ = Describe("feature", Ordered, func() {
var (
fS *luna.MemFS
root string
fS *luna.MemFS
)

BeforeAll(func() {
const (
verbose = false
)

fS, root = lab.Musico(verbose,
lab.Static.RetroWave, "edm",
var (
err error
)
Expect(root).NotTo(BeEmpty())

repo := hydra.Repo("")
index := hydra.Combine(repo, "test/data/musico-index.xml")
fS, err = hydra.CustomTree(index, "MUSICO", verbose, lab.Static.RetroWave, "edm")

Expect(err).To(Succeed())
Expect(li18ngo.Use()).To(Succeed())
})

Expand Down
9 changes: 3 additions & 6 deletions internal/feat/hiber/with-filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,23 @@ import (

"github.com/snivilised/traverse/core"
"github.com/snivilised/traverse/enums"
"github.com/snivilised/traverse/hydra"
lab "github.com/snivilised/traverse/internal/laboratory"
"github.com/snivilised/traverse/internal/services"
"github.com/snivilised/traverse/pref"
)

var _ = Describe("feature", Ordered, func() {
var (
fS *luna.MemFS
root string
fS *luna.MemFS
)

BeforeAll(func() {
const (
verbose = false
)

fS, root = lab.Musico(verbose,
lab.Static.RetroWave, "edm",
)
Expect(root).NotTo(BeEmpty())
fS = hydra.Nuxx(verbose, lab.Static.RetroWave, "edm")
Expect(li18ngo.Use()).To(Succeed())
})

Expand Down
9 changes: 3 additions & 6 deletions internal/feat/sampling/navigator-sample_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
tv "github.com/snivilised/traverse"
"github.com/snivilised/traverse/core"
"github.com/snivilised/traverse/enums"
"github.com/snivilised/traverse/hydra"
lab "github.com/snivilised/traverse/internal/laboratory"
"github.com/snivilised/traverse/internal/services"
"github.com/snivilised/traverse/internal/third/lo"
Expand All @@ -19,19 +20,15 @@ import (

var _ = Describe("feature", Ordered, func() {
var (
fS *luna.MemFS
root string
fS *luna.MemFS
)

BeforeAll(func() {
const (
verbose = false
)

fS, root = lab.Musico(verbose,
lab.Static.RetroWave, "edm",
)
Expect(root).NotTo(BeEmpty())
fS = hydra.Nuxx(verbose, lab.Static.RetroWave, "edm")
Expect(li18ngo.Use()).To(Succeed())
})

Expand Down
9 changes: 3 additions & 6 deletions internal/filtering/filter-custom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/snivilised/nefilim/luna"
tv "github.com/snivilised/traverse"
"github.com/snivilised/traverse/enums"
"github.com/snivilised/traverse/hydra"
lab "github.com/snivilised/traverse/internal/laboratory"
"github.com/snivilised/traverse/internal/services"
"github.com/snivilised/traverse/internal/third/lo"
Expand All @@ -17,19 +18,15 @@ import (

var _ = Describe("NavigatorFilterCustom", Ordered, func() {
var (
fS *luna.MemFS
root string
fS *luna.MemFS
)

BeforeAll(func() {
const (
verbose = false
)

fS, root = lab.Musico(verbose,
lab.Static.RetroWave,
)
Expect(root).NotTo(BeEmpty())
fS = hydra.Nuxx(verbose, lab.Static.RetroWave)
Expect(li18ngo.Use()).To(Succeed())
})

Expand Down
Loading
Loading