From 42fb6efd01e3640ea9d15dc1e0a072c1ea8295b1 Mon Sep 17 00:00:00 2001 From: ewy Date: Wed, 29 Apr 2026 22:34:47 +0200 Subject: fix very embarrassing bug where -a didnt actually work --- cache/cache.go | 81 ++++++++++++++++++++---------- cache/cache_test.go | 2 +- indexers/pikdex/hydrate_test.go | 4 +- main.go | 39 +++++++-------- runner/create.go | 83 +++++++++++++++++++++++++++++++ runner/create_test.go | 34 +++++++++++++ runner/stub.go | 7 ++- search/search_test.go | 106 ++++++++++++++++++++-------------------- spool/spool.go | 11 ++++- testx/create.go | 84 ------------------------------- testx/create_test.go | 34 ------------- viewport/viewport.go | 6 +-- 12 files changed, 262 insertions(+), 229 deletions(-) create mode 100644 runner/create.go create mode 100644 runner/create_test.go delete mode 100644 testx/create.go delete mode 100644 testx/create_test.go diff --git a/cache/cache.go b/cache/cache.go index 328b1e9..39ee062 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -16,13 +16,38 @@ type Cache struct { Entries []Entry } +type cacheInit struct{} + +// Path is the file path to the "contexts" cache file +var Path string + +// FsPath is the Path with the leading slash removed, to be opened from fs.FS +var FsPath string + +var Init model.Initializer = &cacheInit{} + +func (i *cacheInit) Init() error { + Path = path.Join(paths.Cache, "contexts") + FsPath = Path[1:] + return nil +} + // Merge combines two caches and filters duplicate keys -func (c Cache) Merge(other Cache) Cache { +func (c *Cache) Merge(other *Cache) *Cache { + if other == nil && c != nil { + return c + } + if c == nil && other != nil { + return other + } + if c == nil { + return nil + } mp := make(map[string]string) for _, e := range append(c.Entries, other.Entries...) { mp[e.Path] = e.Label } - result := Cache{} + result := &Cache{} for p, l := range mp { result.Entries = append(result.Entries, Entry{Label: l, Path: p}) } @@ -36,22 +61,16 @@ type Entry struct { var Empty = Cache{} -// Path is the file path to the "contexts" cache file -var Path = path.Join(paths.Cache, "contexts") - -// FsPath is the Path with the leading slash removed, to be opened from fs.FS -var FsPath = Path[1:] - var UnexpectedEntryError = errors.New("unexpected cache entry") // LoadFile creates a Cache from a file or an empty one if the file does not exist // this handles opening a reader for Unmarshal -func LoadFile(root fs.FS, path string) (Cache, error) { +func LoadFile(root fs.FS, path string) (*Cache, error) { fd, err := root.Open(path) if errors.Is(err, fs.ErrNotExist) { - return Cache{}, nil + return nil, nil } else if err != nil { - return Cache{}, err + return nil, err } if fd != nil { defer fd.Close() @@ -60,8 +79,8 @@ func LoadFile(root fs.FS, path string) (Cache, error) { } // Unmarshal attempts to create a Cache from reader content -func Unmarshal(r io.Reader) (Cache, error) { - c := Cache{} +func Unmarshal(r io.Reader) (*Cache, error) { + c := &Cache{} scanner := bufio.NewScanner(r) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) @@ -86,7 +105,7 @@ func Unmarshal(r io.Reader) (Cache, error) { } // Marshal returns the file representation of the Cache -func (c Cache) Marshal() []byte { +func (c *Cache) Marshal() []byte { b := strings.Builder{} for _, e := range c.Entries { b.WriteString(e.Path) @@ -97,12 +116,10 @@ func (c Cache) Marshal() []byte { return []byte(b.String()) } -func (c Cache) String() string { +func (c *Cache) String() string { return string(c.Marshal()) } - -// New creates a new Cache from a model.State -func New(st *model.State) Cache { +func New(st *model.State) *Cache { c := &Cache{} for _, s := range st.Sources { c.Entries = append(c.Entries, Entry{ @@ -110,11 +127,22 @@ func New(st *model.State) Cache { Label: s.Label(), }) } - return *c + return c +} + +func Insert(in *model.State) error { + f := os.DirFS("/") + loaded, err := LoadFile(f, FsPath) + if err != nil { + return err + } + insert := New(in) + result := loaded.Merge(insert) + return SaveFile(Path, result) } // SaveFile helps you use Save with a file path instead of a reader -func SaveFile(path string, s *model.State, loaded Cache) error { +func SaveFile(path string, loaded *Cache) error { fd, err := os.Create(path) if err != nil { return err @@ -122,19 +150,18 @@ func SaveFile(path string, s *model.State, loaded Cache) error { if fd != nil { defer fd.Close() } - return Save(s, fd, loaded) + return Save(fd, loaded) } -// Save writes the cache combined with the "loaded" cache to the writer. -func Save(s *model.State, w io.Writer, loaded Cache) error { - result := New(s).Merge(loaded) - _, err := w.Write([]byte(result.Marshal())) +// Save writes a cache to the contexts file +func Save(w io.Writer, loaded *Cache) error { + _, err := w.Write(loaded.Marshal()) return err } // LoadState creates a state with model.NewState based on cache content -func LoadState(f fs.FS, cache Cache, indexers []model.Indexer, runners []model.Runner) (*model.State, []error) { +func LoadState(f fs.FS, cache *Cache, indexers []model.Indexer, runners []model.Runner) (*model.State, []error) { var locs []string for _, e := range cache.Entries { locs = append(locs, e.Path) @@ -144,7 +171,7 @@ func LoadState(f fs.FS, cache Cache, indexers []model.Indexer, runners []model.R // Strip removes the needle's entries from the receiver's entries when they have matching paths. // used to skip already indexed locations when auto-all-ing -func (c Cache) Strip(needle Cache) Cache { +func (c *Cache) Strip(needle Cache) Cache { var result []Entry outer: for _, e := range c.Entries { diff --git a/cache/cache_test.go b/cache/cache_test.go index 1a9c46d..95ded9d 100644 --- a/cache/cache_test.go +++ b/cache/cache_test.go @@ -5,7 +5,7 @@ package cache import ( "github.com/stretchr/testify/assert" "path/filepath" - . "pik/testx" + . "pik/runner" "strings" "testing" "testing/fstest" diff --git a/indexers/pikdex/hydrate_test.go b/indexers/pikdex/hydrate_test.go index e72954e..72ac8ea 100644 --- a/indexers/pikdex/hydrate_test.go +++ b/indexers/pikdex/hydrate_test.go @@ -4,7 +4,7 @@ package pikdex import ( "github.com/stretchr/testify/assert" - "pik/testx" + "pik/runner" "testing" ) @@ -19,7 +19,7 @@ func TestHydrate(t *testing.T) { }, }, } - src := testx.TSource("asdf", "target") + src := runner.TSource("asdf", "target") hyd := src.Hydrate(nil) assert.NotNil(t, hyd) err := p.Mod(src, hyd) diff --git a/main.go b/main.go index 045e5e0..ff7fc9e 100644 --- a/main.go +++ b/main.go @@ -24,14 +24,15 @@ import ( "sync" ) -// preInitializers are ran before the initializers. +// syncInitializers are ran before the initializers. // useful for initializing stuff like paths, preparing directories, and reading the environment -var preInitializers = []model.Initializer{ +var syncInitializers = []model.Initializer{ paths.Paths, + cache.Init, } // initializers are ran before indexing with the indexers, -// data from the preInitializers can be accessed at this time. +// data from the syncInitializers can be accessed at this time. var initializers = []model.Initializer{ pikdex.Indexer, python.Python, @@ -65,7 +66,7 @@ var ForceConfirm = false // SourcesWithoutResults is a failed cache from the previous iteration // used for stripping out results to prevent double-index -var SourcesWithoutResults cache.Cache +var SourcesWithoutResults *cache.Cache //go:embed version.txt var version string @@ -79,18 +80,14 @@ func main() { os.Exit(0) } - wg := sync.WaitGroup{} - for _, i := range preInitializers { - wg.Go(func() { - err := i.Init() - if err != nil { - _, _ = spool.Warn("%v\n", err) - } - }) + for _, i := range syncInitializers { + err := i.Init() + if err != nil { + _, _ = spool.Warn("%v\n", err) + } } - wg.Wait() - wg = sync.WaitGroup{} + wg := sync.WaitGroup{} for _, i := range initializers { wg.Go(func() { err := i.Init() @@ -121,12 +118,15 @@ func main() { var st *model.State var stateErrors []error - var c cache.Cache + var c *cache.Cache if !*flags.All { st, stateErrors = model.NewState(fs, locs, indexers, runners) + err = cache.Insert(st) + if err != nil { + spool.Warn("%v\n", err) + } } else { c, err = cache.LoadFile(fs, cache.Path[1:]) - c.Strip(SourcesWithoutResults) if err != nil { _, _ = spool.Warn("%v\n", err) os.Exit(1) @@ -135,11 +135,6 @@ func main() { } if stateErrors != nil { _, _ = spool.Warn("%v\n", stateErrors) - } else { - err = cache.SaveFile(cache.Path, st, c) - if err != nil { - _, _ = spool.Warn("%v", err) - } } if *flags.List { @@ -186,7 +181,7 @@ func main() { } if result.Target == nil { - _, _ = spool.Print("target not found.") + _, _ = spool.Warn("target not found.") os.Exit(1) return } diff --git a/runner/create.go b/runner/create.go new file mode 100644 index 0000000..4e9035b --- /dev/null +++ b/runner/create.go @@ -0,0 +1,83 @@ +//go:build test + +package runner + +import ( + "github.com/stretchr/testify/assert" + "os/exec" + "pik/identity" + "pik/model" + "testing" +) + +func TTarget(name string, sub ...string) model.Target { + t := TestTarget{Id: identity.New(name), MyTags: model.TagsFromFilename(name), SubValue: sub} + return &t +} + +func TSource(name string, targets ...string) *model.Source { + src := &model.Source{ + Path: name, + Identity: identity.New(name), + } + for _, t := range targets { + src.Targets = append(src.Targets, TTarget(t)) + } + return src +} + +func TState(sources ...*model.Source) *model.State { + return &model.State{ + Sources: sources, + } +} + +type TestTarget struct { + Stub + Id identity.Identity + SubValue []string + MyTags model.Tags +} + +func (t TestTarget) Invocation(src *model.Source) []string { + return []string{src.Identity.Reduced, t.Id.Reduced} +} + +func (t TestTarget) Matches(input string) bool { + return t.Id.Is(input) +} + +func (t TestTarget) Visible() bool { + return true +} + +func (t TestTarget) Hydrate(src *model.Source) (model.HydratedTarget, error) { + return HydratedStub{}, nil +} + +func (t TestTarget) Sub() []string { + return t.SubValue +} + +func (t TestTarget) Label() string { + return t.Id.Full +} + +func (t TestTarget) Create(s *model.Source) *exec.Cmd { + panic("whadafak") +} + +func AssertTargetIs(t *testing.T, input string, target model.Target) { + assert.Equal(t, input, target.Label()) +} +func AssertTargetIsNot(t *testing.T, input string, target model.Target) { + assert.NotEqual(t, input, target.Label()) +} +func AssertSourceIs(t *testing.T, input string, src *model.Source) { + assert.NotNil(t, src.Identity) + assert.Equal(t, input, src.Identity.Reduced) +} +func AssertSourceIsNot(t *testing.T, input string, src *model.Source) { + assert.NotNil(t, src.Identity) + assert.NotEqual(t, input, src.Identity.Reduced) +} diff --git a/runner/create_test.go b/runner/create_test.go new file mode 100644 index 0000000..fc9e535 --- /dev/null +++ b/runner/create_test.go @@ -0,0 +1,34 @@ +//go:build test + +package runner + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestAssertSourceIs_Correct(t *testing.T) { + src := TSource("abc", "def") + AssertSourceIs(t, "abc", src) +} + +func TestAssertSourceIs_Wrong(t *testing.T) { + src := TSource("abc", "def") + AssertSourceIsNot(t, ";lkjh", src) +} + +func TestAssertTargetIs_Correct(t *testing.T) { + ta := TTarget("aaaa") + AssertTargetIs(t, "aaaa", ta) +} + +func TestAssertTargetIs_Wrong(t *testing.T) { + ta := TTarget("aaaa") + AssertTargetIsNot(t, "bbbbbb", ta) +} + +func TestTTargetIdentity(t *testing.T) { + ta := TTarget("asdf.hidden.sh") + assert.True(t, ta.Matches("asdf")) + assert.False(t, ta.Matches("hidden")) +} diff --git a/runner/stub.go b/runner/stub.go index 3282fe8..9899b0d 100644 --- a/runner/stub.go +++ b/runner/stub.go @@ -11,6 +11,11 @@ import ( type Stub struct { } +func (s Stub) File(src *model.Source) string { + //TODO implement me + panic("implement me") +} + func (s Stub) Matches(input string) bool { //TODO implement me panic("implement me") @@ -108,7 +113,7 @@ func (h HydratedStub) Icon() string { panic("implement me") } -func (h HydratedStub) Description() string { +func (h HydratedStub) Description(src *model.HydratedSource) string { //TODO implement me panic("implement me") } diff --git a/search/search_test.go b/search/search_test.go index 3671f75..7246ffc 100644 --- a/search/search_test.go +++ b/search/search_test.go @@ -4,121 +4,121 @@ package search import ( "github.com/stretchr/testify/assert" - "pik/testx" + "pik/runner" "testing" ) func TestSearch_TargetOnly(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "def")) + st := runner.TState(runner.TSource("src", "abc", "def")) res := Search(st, "def") - testx.AssertSourceIs(t, "src", res.Source) - testx.AssertTargetIs(t, "def", res.Target) + runner.AssertSourceIs(t, "src", res.Source) + runner.AssertTargetIs(t, "def", res.Target) } func TestSearch_TargetAndSource(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "def")) + st := runner.TState(runner.TSource("src", "abc", "def")) res := Search(st, "src", "def") - testx.AssertSourceIs(t, "src", res.Source) - testx.AssertTargetIs(t, "def", res.Target) + runner.AssertSourceIs(t, "src", res.Source) + runner.AssertTargetIs(t, "def", res.Target) } func TestSearch_TargetAndSource_CaseInsensitive(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "def")) + st := runner.TState(runner.TSource("src", "abc", "def")) res := Search(st, "SRC", "DeF") - testx.AssertSourceIs(t, "src", res.Source) - testx.AssertTargetIs(t, "def", res.Target) + runner.AssertSourceIs(t, "src", res.Source) + runner.AssertTargetIs(t, "def", res.Target) } func TestSearch_SourceDefaultTarget(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "src")) + st := runner.TState(runner.TSource("src", "abc", "src")) res := Search(st, "src") - testx.AssertSourceIs(t, "src", res.Source) + runner.AssertSourceIs(t, "src", res.Source) assert.NotNil(t, res.Target) } func TestSearch_SubdirWrong(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "src")) - st.Sources[0].Targets = append(st.Sources[0].Targets, testx.TTarget("script", "subdir")) + st := runner.TState(runner.TSource("src", "abc", "src")) + st.Sources[0].Targets = append(st.Sources[0].Targets, runner.TTarget("script", "subdir")) res := Search(st, "wrong", "script") - testx.AssertSourceIs(t, "src", res.Source) - testx.AssertTargetIs(t, "script", res.Target) + runner.AssertSourceIs(t, "src", res.Source) + runner.AssertTargetIs(t, "script", res.Target) assert.Equal(t, []string{"wrong"}, res.Sub) assert.NotNil(t, res.Target) assert.True(t, res.NeedsConfirmation) } func TestSearch_SubdirMissing(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "src")) - st.Sources[0].Targets = append(st.Sources[0].Targets, testx.TTarget("script", "subdir")) + st := runner.TState(runner.TSource("src", "abc", "src")) + st.Sources[0].Targets = append(st.Sources[0].Targets, runner.TTarget("script", "subdir")) res := Search(st, "script") - testx.AssertSourceIs(t, "src", res.Source) - testx.AssertTargetIs(t, "script", res.Target) + runner.AssertSourceIs(t, "src", res.Source) + runner.AssertTargetIs(t, "script", res.Target) assert.Nil(t, res.Sub) assert.NotNil(t, res.Target) assert.False(t, res.NeedsConfirmation) } func TestSearch_Args(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "def")) + st := runner.TState(runner.TSource("src", "abc", "def")) res := Search(st, "def", "a1", "a2") - testx.AssertSourceIs(t, "src", res.Source) - testx.AssertTargetIs(t, "def", res.Target) + runner.AssertSourceIs(t, "src", res.Source) + runner.AssertTargetIs(t, "def", res.Target) assert.Equal(t, []string{"a1", "a2"}, res.Args) } func TestSearch_Args_SubdirMissing(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "src")) - st.Sources[0].Targets = append(st.Sources[0].Targets, testx.TTarget("script", "subdir")) + st := runner.TState(runner.TSource("src", "abc", "src")) + st.Sources[0].Targets = append(st.Sources[0].Targets, runner.TTarget("script", "subdir")) res := Search(st, "script", "a1", "a2") - testx.AssertSourceIs(t, "src", res.Source) - testx.AssertTargetIs(t, "script", res.Target) + runner.AssertSourceIs(t, "src", res.Source) + runner.AssertTargetIs(t, "script", res.Target) assert.Equal(t, []string{"a1", "a2"}, res.Args) } func TestSearch_Args_SubdirPresent(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "src")) - st.Sources[0].Targets = append(st.Sources[0].Targets, testx.TTarget("script", "subdir")) + st := runner.TState(runner.TSource("src", "abc", "src")) + st.Sources[0].Targets = append(st.Sources[0].Targets, runner.TTarget("script", "subdir")) res := Search(st, "subdir", "script", "a1", "a2") - testx.AssertSourceIs(t, "src", res.Source) - testx.AssertTargetIs(t, "script", res.Target) + runner.AssertSourceIs(t, "src", res.Source) + runner.AssertTargetIs(t, "script", res.Target) assert.Equal(t, []string{"a1", "a2"}, res.Args) } func TestSearch_SecondarySource(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "def"), testx.TSource("aaa", "hjkl")) + st := runner.TState(runner.TSource("src", "abc", "def"), runner.TSource("aaa", "hjkl")) res := Search(st, "aaa", "hjkl") - testx.AssertSourceIs(t, "aaa", res.Source) - testx.AssertTargetIs(t, "hjkl", res.Target) + runner.AssertSourceIs(t, "aaa", res.Source) + runner.AssertTargetIs(t, "hjkl", res.Target) } func TestSearch_SecondarySource_DuplicateTargetName(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc", "def"), testx.TSource("aaa", "abc")) + st := runner.TState(runner.TSource("src", "abc", "def"), runner.TSource("aaa", "abc")) res := Search(st, "aaa", "def") - testx.AssertSourceIs(t, "src", res.Source) - testx.AssertTargetIs(t, "def", res.Target) + runner.AssertSourceIs(t, "src", res.Source) + runner.AssertTargetIs(t, "def", res.Target) assert.True(t, res.NeedsConfirmation) } func TestSearch_SourceTargetMixup(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc"), testx.TSource("aaa", "ccc")) + st := runner.TState(runner.TSource("src", "abc"), runner.TSource("aaa", "ccc")) res := Search(st, "src", "ccc") - testx.AssertSourceIs(t, "aaa", res.Source) - testx.AssertTargetIs(t, "ccc", res.Target) + runner.AssertSourceIs(t, "aaa", res.Source) + runner.AssertTargetIs(t, "ccc", res.Target) assert.True(t, res.NeedsConfirmation) } func TestSearch_Override(t *testing.T) { - st := testx.TState(testx.TSource("src", "abc.override.sh", "abc.sh")) + st := runner.TState(runner.TSource("src", "abc.override.sh", "abc.sh")) res := Search(st, "src", "abc") - assert.Equal(t, "abc.override.sh", res.Target.(*testx.TestTarget).Id.Full) + assert.Equal(t, "abc.override.sh", res.Target.(*runner.TestTarget).Id.Full) assert.False(t, res.NeedsConfirmation) } func TestSearch_SubdirDefault(t *testing.T) { - tgt := testx.TTarget("subname", "subname") - src := testx.TSource("src") + tgt := runner.TTarget("subname", "subname") + src := runner.TSource("src") src.Targets = append(src.Targets, tgt) - st := testx.TState(src) + st := runner.TState(src) res := Search(st, "subname") assert.Nil(t, res.Args) assert.Equal(t, res.Target, tgt) @@ -126,8 +126,8 @@ func TestSearch_SubdirDefault(t *testing.T) { } func TestSearch_SourceDefault(t *testing.T) { - src := testx.TSource("sourcename", "sourcename") - st := testx.TState(src) + src := runner.TSource("sourcename", "sourcename") + st := runner.TState(src) res := Search(st, "sourcename") assert.Nil(t, res.Args) assert.Equal(t, res.Target, src.Targets[0]) @@ -135,8 +135,8 @@ func TestSearch_SourceDefault(t *testing.T) { } func TestSearch_SourceDefault_Other(t *testing.T) { - src := testx.TSource("src", "src", "other") - st := testx.TState(src) + src := runner.TSource("src", "src", "other") + st := runner.TState(src) res := Search(st, "src", "other") assert.Nil(t, res.Args) assert.Equal(t, res.Target, src.Targets[1]) @@ -144,11 +144,11 @@ func TestSearch_SourceDefault_Other(t *testing.T) { } func TestSearch_SubdirDefault_Other(t *testing.T) { - tgt := testx.TTarget("subname", "subname") - other := testx.TTarget("othername", "subname") - src := testx.TSource("src") + tgt := runner.TTarget("subname", "subname") + other := runner.TTarget("othername", "subname") + src := runner.TSource("src") src.Targets = append(src.Targets, tgt, other) - st := testx.TState(src) + st := runner.TState(src) res := Search(st, "subname", "othername") assert.Nil(t, res.Args) assert.Equal(t, other, res.Target) diff --git a/spool/spool.go b/spool/spool.go index 4dc7b87..e7b13e9 100644 --- a/spool/spool.go +++ b/spool/spool.go @@ -5,8 +5,15 @@ import ( "os" ) -var Print = fmt.Printf +var ( + Stderr = os.Stderr + Stdout = os.Stdout +) + +var Print = func(format string, values ...any) (any, error) { + return fmt.Fprintf(Stdout, format, values...) +} var Warn = func(format string, values ...any) (any, error) { - return fmt.Fprintf(os.Stderr, format, values...) + return fmt.Fprintf(Stderr, format, values...) } diff --git a/testx/create.go b/testx/create.go deleted file mode 100644 index 24faaed..0000000 --- a/testx/create.go +++ /dev/null @@ -1,84 +0,0 @@ -//go:build test - -package testx - -import ( - "github.com/stretchr/testify/assert" - "os/exec" - "pik/identity" - "pik/model" - "pik/runner" - "testing" -) - -func TTarget(name string, sub ...string) model.Target { - t := TestTarget{Id: identity.New(name), MyTags: model.TagsFromFilename(name), SubValue: sub} - return &t -} - -func TSource(name string, targets ...string) *model.Source { - src := &model.Source{ - Path: name, - Identity: identity.New(name), - } - for _, t := range targets { - src.Targets = append(src.Targets, TTarget(t)) - } - return src -} - -func TState(sources ...*model.Source) *model.State { - return &model.State{ - Sources: sources, - } -} - -type TestTarget struct { - runner.Stub - Id identity.Identity - SubValue []string - MyTags model.Tags -} - -func (t TestTarget) Invocation(src *model.Source) []string { - return []string{src.Identity.Reduced, t.Id.Reduced} -} - -func (t TestTarget) Matches(input string) bool { - return t.Id.Is(input) -} - -func (t TestTarget) Visible() bool { - return true -} - -func (t TestTarget) Hydrate(src *model.Source) (model.HydratedTarget, error) { - return runner.HydratedStub{}, nil -} - -func (t TestTarget) Sub() []string { - return t.SubValue -} - -func (t TestTarget) Label() string { - return t.Id.Full -} - -func (t TestTarget) Create(s *model.Source) *exec.Cmd { - panic("whadafak") -} - -func AssertTargetIs(t *testing.T, input string, target model.Target) { - assert.Equal(t, input, target.Label()) -} -func AssertTargetIsNot(t *testing.T, input string, target model.Target) { - assert.NotEqual(t, input, target.Label()) -} -func AssertSourceIs(t *testing.T, input string, src *model.Source) { - assert.NotNil(t, src.Identity) - assert.Equal(t, input, src.Identity.Reduced) -} -func AssertSourceIsNot(t *testing.T, input string, src *model.Source) { - assert.NotNil(t, src.Identity) - assert.NotEqual(t, input, src.Identity.Reduced) -} diff --git a/testx/create_test.go b/testx/create_test.go deleted file mode 100644 index d0e3099..0000000 --- a/testx/create_test.go +++ /dev/null @@ -1,34 +0,0 @@ -//go:build test - -package testx - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func TestAssertSourceIs_Correct(t *testing.T) { - src := TSource("abc", "def") - AssertSourceIs(t, "abc", src) -} - -func TestAssertSourceIs_Wrong(t *testing.T) { - src := TSource("abc", "def") - AssertSourceIsNot(t, ";lkjh", src) -} - -func TestAssertTargetIs_Correct(t *testing.T) { - ta := TTarget("aaaa") - AssertTargetIs(t, "aaaa", ta) -} - -func TestAssertTargetIs_Wrong(t *testing.T) { - ta := TTarget("aaaa") - AssertTargetIsNot(t, "bbbbbb", ta) -} - -func TestTTargetIdentity(t *testing.T) { - ta := TTarget("asdf.hidden.sh") - assert.True(t, ta.Matches("asdf")) - assert.False(t, ta.Matches("hidden")) -} diff --git a/viewport/viewport.go b/viewport/viewport.go index ff1ca05..7b897e7 100644 --- a/viewport/viewport.go +++ b/viewport/viewport.go @@ -52,9 +52,9 @@ func Crop(input string, lines []string, height int) (output string, scrollStart } if end >= size { - diff := size - 1 - end - start += diff - end += diff + diff := end - size + start -= diff + end -= diff } scrollStart = float32(start) / float32(size) -- cgit v1.3.1