From 598d95f5f7de9e3f62b2f1cd800cde9e6578001e Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Wed, 20 Jun 2018 10:31:04 -0400 Subject: [PATCH] fix display modified parents; fix tests --- filetree/data_test.go | 21 ++---- filetree/node.go | 26 ++++--- filetree/node_test.go | 34 +++++++-- filetree/tree.go | 34 ++++----- filetree/tree_test.go | 157 ++++++++++++++++++++++++++++++++++-------- ui/filetreeview.go | 4 +- 6 files changed, 198 insertions(+), 78 deletions(-) diff --git a/filetree/data_test.go b/filetree/data_test.go index 0d6fcbd..5c0c7e8 100644 --- a/filetree/data_test.go +++ b/filetree/data_test.go @@ -1,13 +1,16 @@ package filetree import ( - "fmt" "testing" ) func TestAssignDiffType(t *testing.T) { tree := NewFileTree() - tree.AddPath("/usr", BlankFileChangeInfo("/usr", Changed)) + node, err := tree.AddPath("/usr", BlankFileChangeInfo("/usr")) + if err != nil { + t.Errorf("Expected no error from fetching path. got: %v", err) + } + node.Data.DiffType = Changed if tree.Root.Children["usr"].Data.DiffType != Changed { t.Fail() } @@ -28,19 +31,7 @@ func TestMergeDiffTypes(t *testing.T) { } } -func AssertDiffType(node *FileNode, expectedDiffType DiffType, t *testing.T) error { - if node.Data.FileInfo == nil { - t.Errorf("Expected *FileInfo but got nil at Path %s", node.Path()) - return fmt.Errorf("expected *FileInfo but got nil at Path %s", node.Path()) - } - if node.Data.DiffType != expectedDiffType { - t.Errorf("Expecting node at %s to have DiffType %v, but had %v", node.Path(), expectedDiffType, node.Data.DiffType) - return fmt.Errorf("Assertion failed") - } - return nil -} - -func BlankFileChangeInfo(path string, diffType DiffType) (f *FileInfo) { +func BlankFileChangeInfo(path string) (f *FileInfo) { result := FileInfo{ Path: path, Typeflag: 1, diff --git a/filetree/node.go b/filetree/node.go index 2239b62..898fd9e 100644 --- a/filetree/node.go +++ b/filetree/node.go @@ -64,8 +64,6 @@ func (node *FileNode) String() string { var style *color.Color if node == nil { return "" - } else if node.Data.FileInfo == nil { - return node.Name } switch node.Data.DiffType { case Added: @@ -82,15 +80,20 @@ func (node *FileNode) String() string { return style.Sprint(node.Name) } -func (node *FileNode) VisitDepthChildFirst(visiter Visiter) error { +func (node *FileNode) VisitDepthChildFirst(visiter Visiter, evaluator VisitEvaluator) error { var keys []string for key := range node.Children { keys = append(keys, key) } sort.Strings(keys) for _, name := range keys { + if evaluator != nil { + if !evaluator(node) { + continue + } + } child := node.Children[name] - err := child.VisitDepthChildFirst(visiter) + err := child.VisitDepthChildFirst(visiter, evaluator) if err != nil { return err } @@ -110,10 +113,12 @@ func (node *FileNode) VisitDepthParentFirst(visiter Visiter, evaluator VisitEval } sort.Strings(keys) for _, name := range keys { - child := node.Children[name] - if evaluator == nil || !evaluator(node) { - continue + if evaluator != nil { + if !evaluator(node) { + continue + } } + child := node.Children[name] err = child.VisitDepthParentFirst(visiter, evaluator) if err != nil { return err @@ -155,8 +160,7 @@ func (node *FileNode) deriveDiffType(diffType DiffType) error { // THE CONTENTS ARE THE BYTES OF A FILE OR THE CHILDREN OF A DIRECTORY if node.IsLeaf() { - node.AssignDiffType(diffType) - return nil + return node.AssignDiffType(diffType) } myDiffType := diffType @@ -164,8 +168,8 @@ func (node *FileNode) deriveDiffType(diffType DiffType) error { myDiffType = myDiffType.merge(v.Data.DiffType) } - node.AssignDiffType(myDiffType) - return nil + + return node.AssignDiffType(myDiffType) } func (node *FileNode) AssignDiffType(diffType DiffType) error { diff --git a/filetree/node_test.go b/filetree/node_test.go index 18bdb27..4ad1e78 100644 --- a/filetree/node_test.go +++ b/filetree/node_test.go @@ -109,15 +109,18 @@ func TestIsWhiteout(t *testing.T) { } } -func TestDiffTypeFromChildren(t *testing.T) { +func TestDiffTypeFromAddedChildren(t *testing.T) { tree := NewFileTree() - tree.AddPath("/usr", BlankFileChangeInfo("/usr", Unchanged)) + node, _ := tree.AddPath("/usr", BlankFileChangeInfo("/usr")) + node.Data.DiffType = Unchanged - info1 := BlankFileChangeInfo("/usr/bin", Added) - tree.AddPath("/usr/bin", info1) + info1 := BlankFileChangeInfo("/usr/bin") + node, _ = tree.AddPath("/usr/bin", info1) + node.Data.DiffType = Added - info2 := BlankFileChangeInfo("/usr/bin2", Removed) - tree.AddPath("/usr/bin2", info2) + info2 := BlankFileChangeInfo("/usr/bin2") + node, _ = tree.AddPath("/usr/bin2", info2) + node.Data.DiffType = Removed tree.Root.Children["usr"].deriveDiffType(Unchanged) @@ -125,3 +128,22 @@ func TestDiffTypeFromChildren(t *testing.T) { t.Errorf("Expected Changed but got %v", tree.Root.Children["usr"].Data.DiffType) } } +func TestDiffTypeFromRemovedChildren(t *testing.T) { + tree := NewFileTree() + node, _ := tree.AddPath("/usr", BlankFileChangeInfo("/usr")) + + info1 := BlankFileChangeInfo("/usr/.wh.bin") + node, _ = tree.AddPath("/usr/.wh.bin", info1) + node.Data.DiffType = Removed + + info2 := BlankFileChangeInfo("/usr/.wh.bin2") + node, _ = tree.AddPath("/usr/.wh.bin2", info2) + node.Data.DiffType = Removed + + tree.Root.Children["usr"].deriveDiffType(Unchanged) + + if tree.Root.Children["usr"].Data.DiffType != Changed { + t.Errorf("Expected Changed but got %v", tree.Root.Children["usr"].Data.DiffType) + } + +} diff --git a/filetree/tree.go b/filetree/tree.go index 8879862..47b6a6b 100644 --- a/filetree/tree.go +++ b/filetree/tree.go @@ -93,7 +93,7 @@ func (tree *FileTree) Copy() *FileTree { newTree.VisitDepthChildFirst(func(node *FileNode) error { node.Tree = newTree return nil - }) + }, nil) return newTree } @@ -102,8 +102,8 @@ type Visiter func(*FileNode) error type VisitEvaluator func(*FileNode) bool // DFS bubble up -func (tree *FileTree) VisitDepthChildFirst(visiter Visiter) error { - return tree.Root.VisitDepthChildFirst(visiter) +func (tree *FileTree) VisitDepthChildFirst(visiter Visiter, evaluator VisitEvaluator) error { + return tree.Root.VisitDepthChildFirst(visiter, evaluator) } // DFS sink down @@ -126,7 +126,7 @@ func (tree *FileTree) Stack(upper *FileTree) error { } return nil } - return upper.VisitDepthChildFirst(graft) + return upper.VisitDepthChildFirst(graft, nil) } func (tree *FileTree) GetNode(path string) (*FileNode, error) { @@ -179,30 +179,30 @@ func (tree *FileTree) RemovePath(path string) error { } func (tree *FileTree) Compare(upper *FileTree) error { - graft := func(node *FileNode) error { - if node.IsWhiteout() { - err := tree.MarkRemoved(node.Path()) + graft := func(upperNode *FileNode) error { + if upperNode.IsWhiteout() { + err := tree.MarkRemoved(upperNode.Path()) if err != nil { - return fmt.Errorf("Cannot remove node %s: %v", node.Path(), err.Error()) + return fmt.Errorf("Cannot remove upperNode %s: %v", upperNode.Path(), err.Error()) } } else { - existingNode, _ := tree.GetNode(node.Path()) - if existingNode == nil { - newNode, err := tree.AddPath(node.Path(), node.Data.FileInfo) - // fmt.Printf("added new node at %s\n", newNode.Path()) + lowerNode, _ := tree.GetNode(upperNode.Path()) + if lowerNode == nil { + newNode, err := tree.AddPath(upperNode.Path(), upperNode.Data.FileInfo) + // fmt.Printf("added new upperNode at %s\n", newNode.Path()) if err != nil { - return fmt.Errorf("Cannot add new node %s: %v", node.Path(), err.Error()) + return fmt.Errorf("Cannot add new upperNode %s: %v", upperNode.Path(), err.Error()) } newNode.AssignDiffType(Added) } else { - diffType := existingNode.compare(node) - // fmt.Printf("found existing node at %s\n", existingNode.Path()) - return existingNode.deriveDiffType(diffType) + diffType := lowerNode.compare(upperNode) + // fmt.Printf("found existing upperNode at %s\n", lowerNode.Path()) + return lowerNode.deriveDiffType(diffType) } } return nil } - return upper.VisitDepthChildFirst(graft) + return upper.VisitDepthChildFirst(graft, nil) } func (tree *FileTree) MarkRemoved(path string) error { diff --git a/filetree/tree_test.go b/filetree/tree_test.go index a9c6652..1010124 100644 --- a/filetree/tree_test.go +++ b/filetree/tree_test.go @@ -5,6 +5,25 @@ import ( "testing" ) +func stringInSlice(a string, list []string) bool { + for _, b := range list { + if b == a { + return true + } + } + return false +} + +func AssertDiffType(node *FileNode, expectedDiffType DiffType) error { + if node.Data.FileInfo == nil { + return fmt.Errorf("expected *FileInfo but got nil at Path %s", node.Path()) + } + if node.Data.DiffType != expectedDiffType { + return fmt.Errorf("Expecting node at %s to have DiffType %v, but had %v", node.Path(), expectedDiffType, node.Data.DiffType) + } + return nil +} + func TestPrintTree(t *testing.T) { tree := NewFileTree() tree.Root.AddChild("first node!", nil) @@ -199,7 +218,7 @@ func TestCompareWithNoChanges(t *testing.T) { } return nil } - err := lowerTree.VisitDepthChildFirst(asserter) + err := lowerTree.VisitDepthChildFirst(asserter, nil) if err != nil { t.Error(err) } @@ -212,53 +231,116 @@ func TestCompareWithAdds(t *testing.T) { upperPaths := [...]string{"/etc", "/etc/sudoers", "/usr", "/etc/hosts", "/usr/bin", "/usr/bin/bash"} for _, value := range lowerPaths { - fakeData := FileInfo{ + lowerTree.AddPath(value, &FileInfo{ Path: value, Typeflag: 1, MD5sum: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - } - lowerTree.AddPath(value, &fakeData) + }) } for _, value := range upperPaths { - fakeData := FileInfo{ + upperTree.AddPath(value, &FileInfo{ Path: value, Typeflag: 1, MD5sum: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - } - upperTree.AddPath(value, &fakeData) + }) } - lowerTree.Compare(upperTree) + failedAssertions := []error{} + err := lowerTree.Compare(upperTree) + if err != nil { + t.Errorf("Expected tree compare to have no errors, got: %v", err) + } asserter := func(n *FileNode) error { p := n.Path() if p == "/" { return nil + } else if stringInSlice(p,[]string{"/usr/bin/bash"}) { + if err := AssertDiffType(n, Added); err != nil { + failedAssertions = append(failedAssertions, err) + } + } else if stringInSlice(p,[]string{"/usr/bin", "/usr"}) { + if err := AssertDiffType(n, Changed); err != nil { + failedAssertions = append(failedAssertions, err) + } + } else { + if err := AssertDiffType(n, Unchanged); err != nil { + failedAssertions = append(failedAssertions, err) + } } - // Adding a file changes the folders it's in - if p == "/usr/bin/bash" { - return AssertDiffType(n, Added, t) - } - if p == "/usr/bin" { - return AssertDiffType(n, Changed, t) - } - if p == "/usr" { - return AssertDiffType(n, Changed, t) - } - return AssertDiffType(n, Unchanged, t) + return nil } - err := lowerTree.VisitDepthChildFirst(asserter) + err = lowerTree.VisitDepthChildFirst(asserter, nil) if err != nil { - t.Error(err) + t.Errorf("Expected no errors when visiting nodes, got: %+v", err) + } + + if len(failedAssertions) > 0 { + str := "\n" + for _, value := range failedAssertions { + str += fmt.Sprintf(" - %s\n", value.Error()) + } + t.Errorf("Expected no errors when evaluating nodes, got: %s", str) } } func TestCompareWithChanges(t *testing.T) { lowerTree := NewFileTree() upperTree := NewFileTree() - lowerPaths := [...]string{"/etc", "/usr", "/etc/hosts", "/etc/sudoers", "/usr/bin"} - upperPaths := [...]string{"/etc", "/usr", "/etc/hosts", "/etc/sudoers", "/usr/bin"} + paths := [...]string{"/etc", "/usr", "/etc/hosts", "/etc/sudoers", "/usr/bin"} + + for _, value := range paths { + lowerTree.AddPath(value, &FileInfo{ + Path: value, + Typeflag: 1, + MD5sum: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }) + upperTree.AddPath(value, &FileInfo{ + Path: value, + Typeflag: 1, + MD5sum: [16]byte{1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0}, + }) + } + + + lowerTree.Compare(upperTree) + failedAssertions := []error{} + asserter := func(n *FileNode) error { + p := n.Path() + if p == "/" { + return nil + } else if stringInSlice(p, []string{"/etc", "/usr", "/etc/hosts", "/etc/sudoers", "/usr/bin"}) { + if err := AssertDiffType(n, Changed); err != nil { + failedAssertions = append(failedAssertions, err) + } + } else { + if err := AssertDiffType(n, Unchanged); err != nil { + failedAssertions = append(failedAssertions, err) + } + } + return nil + } + err := lowerTree.VisitDepthChildFirst(asserter, nil) + if err != nil { + t.Errorf("Expected no errors when visiting nodes, got: %+v", err) + } + + if len(failedAssertions) > 0 { + str := "\n" + for _, value := range failedAssertions { + str += fmt.Sprintf(" - %s\n", value.Error()) + } + t.Errorf("Expected no errors when evaluating nodes, got: %s", str) + } +} + + +func TestCompareWithRemoves(t *testing.T) { + lowerTree := NewFileTree() + upperTree := NewFileTree() + lowerPaths := [...]string{"/etc", "/usr", "/etc/hosts", "/etc/sudoers", "/usr/bin", "/root", "/root/example", "/root/example/some1", "/root/example/some2"} + upperPaths := [...]string{"/.wh.etc", "/usr", "/usr/.wh.bin", "/root/.wh.example"} for _, value := range lowerPaths { fakeData := FileInfo{ @@ -273,22 +355,43 @@ func TestCompareWithChanges(t *testing.T) { fakeData := FileInfo{ Path: value, Typeflag: 1, - MD5sum: [16]byte{1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0}, + MD5sum: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, } upperTree.AddPath(value, &fakeData) } lowerTree.Compare(upperTree) + failedAssertions := []error{} asserter := func(n *FileNode) error { p := n.Path() if p == "/" { return nil + } else if stringInSlice(p,[]string{"/etc", "/usr/bin", "/etc/hosts", "/etc/sudoers", "/root/example/some1", "/root/example/some2", "/root/example"}) { + if err := AssertDiffType(n, Removed); err != nil { + failedAssertions = append(failedAssertions, err) + } + } else if stringInSlice(p,[]string{"/usr", "/root"}) { + if err := AssertDiffType(n, Changed); err != nil { + failedAssertions = append(failedAssertions, err) + } + } else { + if err := AssertDiffType(n, Unchanged); err != nil { + failedAssertions = append(failedAssertions, err) + } } - return AssertDiffType(n, Changed, t) + return nil } - err := lowerTree.VisitDepthChildFirst(asserter) + err := lowerTree.VisitDepthChildFirst(asserter, nil) if err != nil { - t.Error(err) + t.Errorf("Expected no errors when visiting nodes, got: %+v", err) + } + + if len(failedAssertions) > 0 { + str := "\n" + for _, value := range failedAssertions { + str += fmt.Sprintf(" - %s\n", value.Error()) + } + t.Errorf("Expected no errors when evaluating nodes, got: %s", str) } } diff --git a/ui/filetreeview.go b/ui/filetreeview.go index 85dadeb..b72b99d 100644 --- a/ui/filetreeview.go +++ b/ui/filetreeview.go @@ -85,7 +85,7 @@ func (view *FileTreeView) setLayer(layerIndex int) error { } return nil } - view.Tree.VisitDepthChildFirst(visitor) + view.Tree.VisitDepthChildFirst(visitor, nil) // now that the tree has been rebuilt, keep the view seleciton in parity with the previous selection view.setHiddenFromDiffTypes() @@ -154,7 +154,7 @@ func (view *FileTreeView) setHiddenFromDiffTypes() error { node.Data.ViewInfo.Hidden = view.HiddenDiffTypes[node.Data.DiffType] return nil } - view.Tree.VisitDepthChildFirst(visitor) + view.Tree.VisitDepthChildFirst(visitor, nil) return view.Render() }