diff options
author | dwillist <dthornton@vmware.com> | 2021-02-14 17:23:30 -0500 |
---|---|---|
committer | dwillist <dthornton@vmware.com> | 2021-02-14 17:23:30 -0500 |
commit | ae89e3dc2ca81401d8c8ad91f83a07d4473f4c26 (patch) | |
tree | 3bd623c40e25f05b5ac504189b0d43277838646c | |
parent | 13c58c005518870f949af5d4bae160ce748c97d3 (diff) |
create constructors package, move viewmodel initialization into this package
Signed-off-by: dwillist <dthornton@vmware.com>
-rw-r--r-- | runtime/ui/app.go | 24 | ||||
-rw-r--r-- | runtime/ui/components/keybinding_primitive.go | 2 | ||||
-rw-r--r-- | runtime/ui/components/visible_primitive.go | 29 | ||||
-rw-r--r-- | runtime/ui/constructors/key_config.go | 19 | ||||
-rw-r--r-- | runtime/ui/viewmodels/tree_view_model.go | 5 | ||||
-rw-r--r-- | runtime/ui/viewmodels/tree_view_model_test.go | 143 |
6 files changed, 86 insertions, 136 deletions
diff --git a/runtime/ui/app.go b/runtime/ui/app.go index df527fd..e9a576a 100644 --- a/runtime/ui/app.go +++ b/runtime/ui/app.go @@ -2,6 +2,7 @@ package ui import ( "fmt" + "log" "sync" "github.com/gdamore/tcell/v2" @@ -9,8 +10,8 @@ import ( "github.com/sirupsen/logrus" "github.com/wagoodman/dive/dive/filetree" "github.com/wagoodman/dive/dive/image" - "github.com/wagoodman/dive/runtime/ui/constructors" "github.com/wagoodman/dive/runtime/ui/components" + "github.com/wagoodman/dive/runtime/ui/constructors" "github.com/wagoodman/dive/runtime/ui/format" "github.com/wagoodman/dive/runtime/ui/viewmodels" ) @@ -39,20 +40,19 @@ func newApp(app *tview.Application, analysis *image.AnalysisResult, cache filetr diveApplication := components.NewDiveApplication(app) //initialize viewmodels - filterViewModel := viewmodels.NewFilterViewModel(nil) + modelConfig := constructors.ModelConfig{ + Cache: &CacheWrapper{Cache: &cache}, + Layers: analysis.Layers, + } + _, layersViewModel, treeViewModel, err := constructors.InitializeModels(modelConfig) + if err != nil { + log.Fatal(fmt.Errorf("unable to initialize viewmodels: %q", err)) + } - layerModel := viewmodels.NewLayersViewModel(analysis.Layers) - regularLayerDetailsView := components.NewLayerDetailsView(layerModel).Setup() + regularLayerDetailsView := components.NewLayerDetailsView(layersViewModel).Setup() layerDetailsBox := components.NewWrapper("Layer Details", "", regularLayerDetailsView).Setup() layerDetailsBox.SetVisibility(components.MinHeightVisibility(10)) - //layerViewModel := viewmodels.NewLayersViewModel(analysis.Layers) - cacheWrapper := CacheWrapper{Cache: &cache} - treeViewModel, err := viewmodels.NewTreeViewModel(&cacheWrapper, layerModel, filterViewModel) - if err != nil { - panic(err) - } - // initialize views imageDetailsView := components.NewImageDetailsView(analysis).Setup() imageDetailsBox := components.NewWrapper("Image Details", "", imageDetailsView).Setup() @@ -155,7 +155,7 @@ func newApp(app *tview.Application, analysis *image.AnalysisResult, cache filetr // additional setup configuration if appConfig.GetAggregateLayerSetting() { - err := layerModel.SwitchLayerMode() + err := layersViewModel.SwitchLayerMode() if err != nil { panic(err) } diff --git a/runtime/ui/components/keybinding_primitive.go b/runtime/ui/components/keybinding_primitive.go index d26d60a..7733b45 100644 --- a/runtime/ui/components/keybinding_primitive.go +++ b/runtime/ui/components/keybinding_primitive.go @@ -65,7 +65,6 @@ func (t *KeyMenuView) GetKeyBindings() []helpers.KeyBindingDisplay { func (t *KeyMenuView) Draw(screen tcell.Screen) { t.Box.Draw(screen) x, y, width, _ := t.Box.GetInnerRect() - // TODO: add logic to highlight selected options lines := []string{} keyBindings := t.GetKeyBindings() @@ -80,7 +79,6 @@ func (t *KeyMenuView) Draw(screen tcell.Screen) { keyBindingFormatter = format.StatusControlSelectedBold } postfix := "⎹" - //postfix := "▏" if idx == len(keyBindings)-1 { postfix = " " } diff --git a/runtime/ui/components/visible_primitive.go b/runtime/ui/components/visible_primitive.go index 3c64025..702c953 100644 --- a/runtime/ui/components/visible_primitive.go +++ b/runtime/ui/components/visible_primitive.go @@ -1,36 +1,31 @@ package components import ( - "github.com/rivo/tview" + "github.com/rivo/tview" ) type Visiblility interface { - Visible() bool + Visible() bool } type VisiblePrimitive interface { - tview.Primitive - Visiblility + tview.Primitive + Visiblility } type VisibleFunc func(tview.Primitive) bool func Always(alwaysVal bool) VisibleFunc { - return func (_ tview.Primitive) bool { - return alwaysVal - } + return func (_ tview.Primitive) bool { + return alwaysVal + } } func MinHeightVisibility(minHeight int) VisibleFunc { - return func(p tview.Primitive) bool { - _, _, _, height := p.GetRect() - return height >= minHeight - } + return func(p tview.Primitive) bool { + _, _, _, height := p.GetRect() + return height >= minHeight + } } -// How can we actually implement this???? -// Either we have to do one of the following -// 1) we want to use particular and specific methods on an item -// - we Have to make VisibleFunc methods know what their base class is ( or at least have a larger interface ) -// 2) How can we make this configurable -// 3) make this an implementaion detail of each struct that conforms to this interface (this seems like the best idea) + diff --git a/runtime/ui/constructors/key_config.go b/runtime/ui/constructors/key_config.go index 5b5ec42..735f8f8 100644 --- a/runtime/ui/constructors/key_config.go +++ b/runtime/ui/constructors/key_config.go @@ -9,25 +9,6 @@ import ( "gitlab.com/tslocum/cbind" ) -// TODO move key constants out to their own file -var DisplayNames = map[string]string{ - "keybinding.quit": "Quit", - "keybinding.toggle-view": "Switch View", - "keybinding.filter-files": "Find", - "keybinding.compare-all": "Compare All", - "keybinding.compare-layer": "Compare Layer", - "keybinding.toggle-collapse-dir": "Collapse", - "keybinding.toggle-collapse-all-dir": "Collapse All", - "keybinding.toggle-filetree-attributes": "Attributes", - "keybinding.toggle-added-files": "Added", - "keybinding.toggle-removed-files": "Removed", - "keybinding.toggle-modified-files": "Modified", - "keybinding.toggle-unmodified-files": "Unmodified", - "keybinding.page-up": "Pg Up", - "keybinding.page-down": "Pg Down", -} - -// TODO move this to a more appropriate place type KeyConfig struct{} type MissingConfigError struct { diff --git a/runtime/ui/viewmodels/tree_view_model.go b/runtime/ui/viewmodels/tree_view_model.go index 8f669bb..5294e06 100644 --- a/runtime/ui/viewmodels/tree_view_model.go +++ b/runtime/ui/viewmodels/tree_view_model.go @@ -84,6 +84,7 @@ func (tvm *TreeViewModel) VisibleSize() int { func (tvm *TreeViewModel) SetFilter(filterRegex *regexp.Regexp) { tvm.FilterModel.SetFilter(filterRegex) if err := tvm.filterUpdate(); err != nil { + // TODO -Dan- handle panics panic(err) } } @@ -106,9 +107,7 @@ func (tvm *TreeViewModel) GetHiddenFileType(filetype filetree.DiffType) bool { -// TODO: maek this method private, cant think of a reason for this to be public func (tvm *TreeViewModel) filterUpdate() error { - logrus.Debug("Updating filter!!!") // keep the t selection in parity with the current DiffType selection filter := tvm.GetFilter() err := tvm.currentTree.VisitDepthChildFirst(func(node *filetree.FileNode) error { @@ -127,7 +126,7 @@ func (tvm *TreeViewModel) filterUpdate() error { if filter != nil && !node.Data.ViewInfo.Hidden { // hide nodes that do not match the current file filter regex (also don't unhide nodes that are already hidden) match := filter.FindString(node.Path()) - node.Data.ViewInfo.Hidden = len(match) != 0 + node.Data.ViewInfo.Hidden = len(match) == 0 } return nil }, nil) diff --git a/runtime/ui/viewmodels/tree_view_model_test.go b/runtime/ui/viewmodels/tree_view_model_test.go index 7f8314b..916393e 100644 --- a/runtime/ui/viewmodels/tree_view_model_test.go +++ b/runtime/ui/viewmodels/tree_view_model_test.go @@ -2,12 +2,14 @@ package viewmodels_test import ( tar "archive/tar" - "github.com/wagoodman/dive/dive/filetree" - "github.com/wagoodman/dive/runtime/ui/viewmodels" - "github.com/wagoodman/dive/runtime/ui/viewmodels/fakes" "os" + "reflect" "regexp" "testing" + + "github.com/wagoodman/dive/dive/filetree" + "github.com/wagoodman/dive/runtime/ui/viewmodels" + "github.com/wagoodman/dive/runtime/ui/viewmodels/fakes" ) func TestTreeViewModel(t *testing.T) { @@ -37,7 +39,7 @@ func testStringBetween(t *testing.T) { t.Fatalf("unexpected error: %s", err) } - out := tvm.StringBetween(1,2,true) + out := tvm.StringBetween(1, 2, true) if out != expectedString { t.Fatalf("expected: %s got: %s", expectedString, out) } @@ -149,7 +151,7 @@ func testSetFilter(t *testing.T) { lModel := &fakes.LayersModel{} tCache := &fakes.TreeCache{} tModel := filetree.NewFileTree() - _,_, err := tModel.AddPath("/dirA/dirB/file", filetree.FileInfo { + _, _, err := tModel.AddPath("/dirA/dirB/file", filetree.FileInfo{ Path: "/dirA/dirB/file", TypeFlag: tar.TypeReg, Size: 100, @@ -158,10 +160,9 @@ func testSetFilter(t *testing.T) { Gid: 200, IsDir: false, }) - errorCheck(t,err) - + errorCheck(t, err) - _,_,err = tModel.AddPath("/dirA/dirC/other-thing", filetree.FileInfo { + _, _, err = tModel.AddPath("/dirA/dirC/other-thing", filetree.FileInfo{ Path: "/dirA/dirC/other-thing", TypeFlag: tar.TypeReg, Size: 1000, @@ -170,9 +171,9 @@ func testSetFilter(t *testing.T) { Gid: 200, IsDir: false, }) - errorCheck(t,err) + errorCheck(t, err) - _,_, err = tModel.AddPath("/dirA/dirB/other-file", filetree.FileInfo { + _, _, err = tModel.AddPath("/dirA/dirB/other-file", filetree.FileInfo{ Path: "/dirA/dirB/other-file", TypeFlag: tar.TypeReg, Size: 1000, @@ -181,7 +182,7 @@ func testSetFilter(t *testing.T) { Gid: 200, IsDir: false, }) - errorCheck(t,err) + errorCheck(t, err) tCache.GetTreeCall.Returns.TreeModel = tModel @@ -192,21 +193,17 @@ func testSetFilter(t *testing.T) { hiddenNodes, err := getHiddenNodes(tModel) errorCheck(t, err) - if len(hiddenNodes) != 0 { - t.Fatalf("expected no nodes to be hidden, got %d", len(hiddenNodes)) - } + assertEqual(t, 0, len(hiddenNodes)) r := regexp.MustCompile("other-file") tvm.SetFilter(r) hiddenNodes, err = getHiddenNodes(tModel) errorCheck(t, err) - if len(hiddenNodes) != 1 { - t.Fatalf("expected 1 to be hidden, got %d", len(hiddenNodes)) - } - if hiddenNodes[0].Name != "other-file" { - t.Fatalf("expected 'other-file' to be hidden, got %s", hiddenNodes[0].Name) - } + assertEqual(t, 3, len(hiddenNodes)) + assertEqual(t, "file", hiddenNodes[0].Name) + assertEqual(t, "dirC", hiddenNodes[1].Name) + assertEqual(t, "other-thing", hiddenNodes[2].Name) // Check if directories where all children are hidden are hidden as well r = regexp.MustCompile("file") @@ -214,26 +211,10 @@ func testSetFilter(t *testing.T) { hiddenNodes, err = getHiddenNodes(tModel) errorCheck(t, err) - if len(hiddenNodes) != 3 { - t.Fatalf("expected 3 nodes to be hidden, got %d", len(hiddenNodes)) - } - - hiddenNames := []string{} - for _, node := range hiddenNodes { - hiddenNames = append(hiddenNames, node.Name) - } - - if !containsString("other-file", hiddenNames) { - t.Fatalf("expected %#v to contain other-file", hiddenNames) - } - - if !containsString("file", hiddenNames) { - t.Fatalf("expected %#v to contain file", hiddenNames) - } + assertEqual(t, 2, len(hiddenNodes)) - if !containsString("dirB", hiddenNames) { - t.Fatalf("expected %#v to contain dirB", hiddenNames) - } + assertEqual(t, "dirC", hiddenNodes[0].Name) + assertEqual(t, "other-thing", hiddenNodes[1].Name) } func testToggleHiddenFileType(t *testing.T) { @@ -241,7 +222,7 @@ func testToggleHiddenFileType(t *testing.T) { lModel := &fakes.LayersModel{} tCache := &fakes.TreeCache{} tModel := filetree.NewFileTree() - _,_,err := tModel.AddPath("/dirA/file", filetree.FileInfo { + _, _, err := tModel.AddPath("/dirA/file", filetree.FileInfo{ Path: "/dirA/file", TypeFlag: tar.TypeReg, Size: 100, @@ -250,7 +231,7 @@ func testToggleHiddenFileType(t *testing.T) { Gid: 200, IsDir: false, }) - errorCheck(t,err) + errorCheck(t, err) tModel.Root.Children["dirA"].Children["file"].Data.DiffType = filetree.Added tCache.GetTreeCall.Returns.TreeModel = tModel @@ -262,30 +243,15 @@ func testToggleHiddenFileType(t *testing.T) { hiddenNodes, err := getHiddenNodes(tModel) errorCheck(t, err) - if len(hiddenNodes) != 0 { - t.Fatalf("expected no nodes to be hidden, got %d", len(hiddenNodes)) - } + assertEqual(t, 0, len(hiddenNodes)) tvm.ToggleHiddenFileType(filetree.Added) hiddenNodes, err = getHiddenNodes(tModel) errorCheck(t, err) - if len(hiddenNodes) != 2 { - t.Fatalf("expected 2 to be hidden, got %d", len(hiddenNodes)) - } - hiddenNames := []string{} - for _, node := range hiddenNodes { - hiddenNames = append(hiddenNames, node.Name) - } - - if !containsString("file", hiddenNames) { - t.Fatalf("expected 'file' to be hidden in %#v", hiddenNames) - } - - if !containsString("dirA", hiddenNames) { - t.Fatalf("expected 'file' to be hidden in %#v", hiddenNames) - } - + assertEqual(t, 2, len(hiddenNodes)) + assertEqual(t, "dirA", hiddenNodes[0].Name) + assertEqual(t, "file", hiddenNodes[1].Name) } func testGetHiddenFileType(t *testing.T) { @@ -351,9 +317,7 @@ func testSetLayerIndex(t *testing.T) { testIndex := 10 tvm.SetLayerIndex(testIndex) - if lModel.SetLayerIndexCall.Receives.Index != testIndex { - t.Fatalf("expected index to be %d, got %d", testIndex, lModel.SetLayerIndexCall.Receives.Index) - } + assertEqual(t, testIndex, lModel.SetLayerIndexCall.Receives.Index) } func testSwitchLayerMode(t *testing.T) { @@ -361,7 +325,7 @@ func testSwitchLayerMode(t *testing.T) { lModel := &fakes.LayersModel{} tCache := &fakes.TreeCache{} firstTreeModel := filetree.NewFileTree() - _, _, err := firstTreeModel.AddPath("/collapsed-dir/collapsed-file", filetree.FileInfo { + _, _, err := firstTreeModel.AddPath("/collapsed-dir/collapsed-file", filetree.FileInfo{ Path: "/collapsed-dir/collapsed-file", TypeFlag: tar.TypeReg, Size: 100, @@ -370,14 +334,14 @@ func testSwitchLayerMode(t *testing.T) { Gid: 200, IsDir: false, }) - errorCheck(t,err) + errorCheck(t, err) // Second tree has no collapsed or hidden values set secondTreeModel := firstTreeModel.Copy() firstTreeModel.Root.Children["collapsed-dir"].Data.ViewInfo.Collapsed = true - _,_, err = secondTreeModel.AddPath("/visible/visible-file", filetree.FileInfo { + _, _, err = secondTreeModel.AddPath("/visible/visible-file", filetree.FileInfo{ Path: "/visible/visible-file", TypeFlag: tar.TypeReg, Size: 100, @@ -386,8 +350,7 @@ func testSwitchLayerMode(t *testing.T) { Gid: 200, IsDir: false, }) - errorCheck(t,err) - + errorCheck(t, err) collapsedNodes, err := getCollapsedNodes(secondTreeModel) errorCheck(t, err) @@ -395,10 +358,10 @@ func testSwitchLayerMode(t *testing.T) { t.Fatalf("expected no nodes to be collapsed got %v", collapsedNodes) } - key := filetree.NewTreeIndexKey(1,2,3,4) + key := filetree.NewTreeIndexKey(1, 2, 3, 4) tCache.GetTreeCall.Stub = func(k filetree.TreeIndexKey) (viewmodels.TreeModel, error) { if k == key { - return secondTreeModel,nil + return secondTreeModel, nil } return firstTreeModel, nil @@ -409,23 +372,17 @@ func testSwitchLayerMode(t *testing.T) { t.Fatalf("unexpected error: %s", err) } - lModel.GetCompareIndiciesCall.Returns.TreeIndexKey = filetree.NewTreeIndexKey(1,2,3,4) + lModel.GetCompareIndiciesCall.Returns.TreeIndexKey = filetree.NewTreeIndexKey(1, 2, 3, 4) err = tvm.SwitchLayerMode() errorCheck(t, err) collapsedNodes, err = getCollapsedNodes(secondTreeModel) errorCheck(t, err) - if len(collapsedNodes) != 1 { - t.Fatalf("expected no nodes to be collapsed got %v", collapsedNodes) - } + assertEqual(t, 1, len(collapsedNodes)) - if collapsedNodes[0].Name != "collapsed-dir" { - t.Fatalf("expected 'collapsed-dir' to be collapsed got %s", collapsedNodes[0].Name) - } + assertEqual(t, "collapsed-dir", collapsedNodes[0].Name) } - - func containsString(needle string, haystack []string) bool { for _, s := range haystack { if s == needle { @@ -457,15 +414,35 @@ func getCollapsedNodes(tModel *filetree.FileTree) ([]*filetree.FileNode, error) result = append(result, node) } return nil - },nil) - + }, nil) return result, err } - func errorCheck(t *testing.T, err error) { if err != nil { t.Fatalf("unexpected error: %s", err) } -}
\ No newline at end of file +} + +// +// Assertion helpers +// + +func assertEqual(t *testing.T, expected interface{}, actual interface{}) { + t.Helper() + if !reflect.DeepEqual(expected, actual) { + t.Fatalf("Expected %#v, got %#v", expected, actual) + } +} + +func assertSliceContains(t *testing.T, expected interface{}, container []interface{}) { + t.Helper() + for i := range container { + if reflect.DeepEqual(container[i], expected) { + return + } + } + t.Fatalf("Expected value %v not found", expected) +} + |