fix display modified parents; fix tests

This commit is contained in:
Alex Goodman 2018-06-20 10:31:04 -04:00
parent a47105cc7d
commit 598d95f5f7
No known key found for this signature in database
GPG Key ID: 05328C611D8A520E
6 changed files with 198 additions and 78 deletions

View File

@ -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,

View File

@ -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 {

View File

@ -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)
}
}

View File

@ -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 {

View File

@ -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)
}
}

View File

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