From a1b0abf20016c030c6335bd4e154e2e5ed4d107e Mon Sep 17 00:00:00 2001 From: plastikfan Date: Mon, 9 Sep 2024 10:56:52 +0100 Subject: [PATCH] test: improve test coverage (#114) --- .github/workflows/ci-workflow.yml | 44 ++++-- .gitignore | 1 + Taskfile.yml | 66 +++++---- builders.go | 7 +- collections/positional-set_test.go | 20 +++ core/navigator.go | 6 - core/node.go | 12 -- cycle/events.go | 8 - director-prime_test.go | 2 + enums/directory-contents-en-auto.go | 24 --- enums/directory-contents-en.go | 17 --- extent.go | 2 +- internal/feat/filter/filter-plugin.go | 4 - internal/feat/filter/scheme-custom.go | 7 - internal/feat/filter/scheme-sampler.go | 10 +- internal/feat/hiber/hibernate-plugin.go | 4 - internal/feat/hiber/hibernate_test.go | 8 + internal/feat/nanny/nanny-plugin.go | 4 - internal/feat/resume/resume-plugin.go | 4 - .../feat/sampling/navigator-sample_test.go | 1 + internal/feat/sampling/sampling-plugin.go | 4 - internal/kernel/contents.go | 11 +- internal/kernel/mediator.go | 2 +- internal/kernel/navigator-hades.go | 9 +- internal/third/lo/condition.go | 12 +- internal/types/definitions.go | 1 - locale/messages-errors.go | 51 ------- pref/defaults.go | 2 - pref/options-navigation-behaviours.go | 8 +- pref/options.go | 10 +- .../doc/TEMP-NOTES.md | 137 +++++++++++------- scripts/apply-coverage-exclusions.sh | 34 +++++ scripts/coverage-exclusion-list.txt | 30 ++++ 33 files changed, 279 insertions(+), 283 deletions(-) delete mode 100644 enums/directory-contents-en-auto.go delete mode 100644 enums/directory-contents-en.go rename tapable/legacy-defs.go => resources/doc/TEMP-NOTES.md (54%) create mode 100755 scripts/apply-coverage-exclusions.sh create mode 100644 scripts/coverage-exclusion-list.txt diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index 050e532..7ff347c 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -1,4 +1,5 @@ name: Traverse Continuous Integration + on: push: @@ -25,25 +26,50 @@ jobs: runs-on: ${{ matrix.platform }} + env: + COVER_DIR: ${{ github.workspace }}/coverage + COVER_FILE: coverage.out + COVER_OUT_PATH: ${{ github.workspace }}/coverage/coverage.out + COVER_HTML_PATH: ${{ github.workspace }}/coverage/coverage.html + GINKGO_REPORT: ginkgo.report + steps: - name: Install Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.go-version }} - name: Install goveralls run: go install github.com/mattn/goveralls@latest + - name: Install ginkgo + run: go install github.com/onsi/ginkgo/v2/ginkgo@v2.20.0 + - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - run: go test -v -coverprofile=coverage.out ./... + - name: Ensure coverage directory exists + run: | + mkdir -p ${{ github.workspace }}/coverage + + - name: Run tests and generate coverage profile with Ginkgo + run: | + ginkgo run -r -json-report {{env.GINKGO_REPORT}} -coverpkg=./... -coverprofile=coverage.out - - uses: shogo82148/actions-goveralls@v1 + - name: Apply coverage exclusions + run: | + ${{ github.workspace }}/scripts/apply-coverage-exclusions.sh + + - name: Check coverage directory contents + run: | + echo "Contents of ${{ github.workspace }}/coverage:" + ls -la ${{ github.workspace }}/coverage + + - name: Generate HTML coverage report + run: | + go tool cover -html=coverage.out -o ${{ github.workspace }}/coverage/coverage.html + + - name: Upload coverage to Coveralls + uses: shogo82148/actions-goveralls@v1 with: path-to-profile: coverage.out - - - name: Send coverage - env: - COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: goveralls -coverprofile=coverage.out -service=github diff --git a/.gitignore b/.gitignore index 1a179ca..3a75f14 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ coverage coverage.out ginkgo.report +report.json .task/ diff --git a/Taskfile.yml b/Taskfile.yml index 55cc22b..49938cf 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -26,6 +26,10 @@ vars: ACTIVE_US: "{{.BINARY_NAME}}.active.en-US.{{.FORMAT}}" TRANSLATE_US: "{{.BINARY_NAME}}.translate.en-US.{{.FORMAT}}" TRANSLATE_US_FILEPATH: "{{.US_OUT_DIR}}/{{.TRANSLATE_US}}" + COVER_DIR: "./coverage/" + COVER_FILE: "coverage.out" + COVER_HTML_PATH: "./coverage/coverage.html" + GINKGO_REPORT: "ginkgo.report" tasks: # === build ================================================ @@ -88,6 +92,10 @@ tasks: cmds: - go test ./internal/feat/hiber + tf-samp: + cmds: + - go test ./internal/feat/sampling + toc: cmds: - go test ./collections @@ -172,44 +180,38 @@ tasks: # === coverage ============================================= - publish-cover: + cover-clean: + cmds: + - rm -rf ./coverage + + cover-publish: cmds: - goveralls -repotoken {{.COVERALLS_TOKEN}} - cover: + cover-setup: cmds: - mkdir -p ./coverage - - mkdir -p ./collections/coverage - - mkdir -p ./core/coverage/ - - mkdir -p ./cycle/coverage - - mkdir -p ./enums/coverage - - mkdir -p ./internal/feat/filter/coverage - - mkdir -p ./internal/feat/hiber/coverage - - mkdir -p ./internal/feat/resume/coverage - - mkdir -p ./internal/feat/sampling/coverage - - mkdir -p ./internal/filtering/coverage - - mkdir -p ./internal/kernel/coverage - - mkdir -p ./internal/level/coverage - - mkdir -p ./internal/measure/coverage - - mkdir -p ./internal/services/coverage - - mkdir -p ./internal/level/coverage - - mkdir -p ./internal/third/bus/coverage - - mkdir -p ./internal/third/lo/coverage - - mkdir -p ./internal/types/coverage - - mkdir -p ./locale/coverage - - mkdir -p ./nfs/coverage - - mkdir -p ./pref/coverage - - mkdir -p ./tapable/coverage - - ginkgo --json-report - ./ginkgo.report - -coverpkg=./... - -coverprofile=./coverage/coverage.out -r - - go tool cover -html=./coverage/coverage.out -o ./coverage/coverage.html - - open ./coverage/coverage.html - view-cover: - cmds: - - open ./coverage/coverage.html + cover-ginkgo: + cmds: + - ginkgo run -r -json-report {{.GINKGO_REPORT}} -coverpkg=./... -coverprofile={{.COVER_FILE}} --output-dir {{.COVER_DIR}} + + cover-show: + cmds: + - open {{.COVER_HTML_PATH}} + + # https://dev.to/talalyousif/excluding-files-from-code-coverage-in-go-291f + cover-exclude: + cmds: + - ./scripts/apply-coverage-exclusions.sh + + cover: + cmds: + - task: cover-setup + - task: cover-ginkgo + - task: cover-exclude + - go tool cover -html=./coverage/coverage.out -o ./coverage/coverage.html + - open {{.COVER_HTML_PATH}} # === i18n ================================================= diff --git a/builders.go b/builders.go index 66fc2c3..37a29ee 100644 --- a/builders.go +++ b/builders.go @@ -41,14 +41,13 @@ func (bs *Builders) buildAll() (*buildArtefacts, error) { if optionsErr != nil { return &buildArtefacts{ o: o, - kc: kernel.HadesNav(optionsErr), + kc: kernel.HadesNav(o, optionsErr), ext: ext, }, optionsErr } // BUILD NAVIGATOR // - artefacts, navErr := bs.navigator.Build(o, &types.Resources{ FS: FileSystems{ N: ext.navFS(), @@ -61,7 +60,7 @@ func (bs *Builders) buildAll() (*buildArtefacts, error) { if navErr != nil { return &buildArtefacts{ o: o, - kc: kernel.HadesNav(navErr), + kc: kernel.HadesNav(o, navErr), ext: ext, }, navErr } @@ -78,7 +77,7 @@ func (bs *Builders) buildAll() (*buildArtefacts, error) { if pluginsErr != nil { return &buildArtefacts{ o: o, - kc: kernel.HadesNav(pluginsErr), + kc: kernel.HadesNav(o, pluginsErr), ext: ext, }, pluginsErr } diff --git a/collections/positional-set_test.go b/collections/positional-set_test.go index 825ad65..edde3df 100644 --- a/collections/positional-set_test.go +++ b/collections/positional-set_test.go @@ -190,4 +190,24 @@ var _ = Describe("PositionalSet", func() { }) }) }) + + Context("Contains", func() { + When("item is present", func() { + It("🧪 should: return true", func() { + set.All(rainbow...) + Expect(set.Contains("richard")).To(BeTrue(), + lab.Reason("richard IS contained in set"), + ) + }) + }) + + When("item is NOT present", func() { + It("🧪 should: return false", func() { + set.All(rainbow...) + Expect(set.Contains("james")).To(BeFalse(), + lab.Reason("james is NOT contained in set"), + ) + }) + }) + }) }) diff --git a/core/navigator.go b/core/navigator.go index ee89320..8009d81 100644 --- a/core/navigator.go +++ b/core/navigator.go @@ -7,9 +7,3 @@ import ( type Navigator interface { Navigate(ctx context.Context) (TraverseResult, error) } - -type Navigate func() (TraverseResult, error) - -func (fn Navigate) Navigate() (TraverseResult, error) { - return fn() -} diff --git a/core/node.go b/core/node.go index 58e525b..01503ca 100644 --- a/core/node.go +++ b/core/node.go @@ -65,23 +65,11 @@ func Root(root string, info fs.FileInfo) *Node { return node } -// Clone makes shallow copy of Node (excluding the error). -func (n *Node) Clone() *Node { - c := *n - c.Error = nil - - return &c -} - // IsFolder indicates wether this node is a folder. func (n *Node) IsFolder() bool { return n.dir } -func (n *Node) key() string { - return n.Extension.SubPath -} - func isDir(n *Node) bool { if n.Entry != nil { return n.Entry.IsDir() diff --git a/cycle/events.go b/cycle/events.go index 78b4f7a..adbf3ae 100644 --- a/cycle/events.go +++ b/cycle/events.go @@ -148,11 +148,3 @@ func broadcastHibernate(listeners []HibernateHandler) HibernateHandler { } func nopHibernate(_ string) {} - -func broadcastSimple(listeners []SimpleHandler) SimpleHandler { - return func() { - for _, listener := range listeners { - listener() - } - } -} diff --git a/director-prime_test.go b/director-prime_test.go index 87ce7cf..b9a6872 100644 --- a/director-prime_test.go +++ b/director-prime_test.go @@ -48,6 +48,7 @@ var _ = Describe("Director(Prime)", Ordered, func() { Handler: noOpHandler, }, tv.WithOnAscend(func(_ *core.Node) {}), + tv.WithNoRecurse(), )).Navigate(ctx) Expect(err).To(Succeed()) @@ -105,6 +106,7 @@ var _ = Describe("Director(Prime)", Ordered, func() { Handler: noOpHandler, }, tv.WithOnBegin(func(_ *cycle.BeginState) {}), + tv.WithCPU(), )).Navigate(ctx) wg.Wait() diff --git a/enums/directory-contents-en-auto.go b/enums/directory-contents-en-auto.go deleted file mode 100644 index 6bd95e3..0000000 --- a/enums/directory-contents-en-auto.go +++ /dev/null @@ -1,24 +0,0 @@ -// Code generated by "stringer -type=DirectoryContentsOrder -linecomment -trimprefix=DirectoryContentsOrder -output directory-contents-en-auto.go"; DO NOT EDIT. - -package enums - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[DirectoryContentsOrderFoldersFirst-0] - _ = x[DirectoryContentsOrderFilesFirst-1] -} - -const _DirectoryContentsOrder_name = "folders-firstfiles-first" - -var _DirectoryContentsOrder_index = [...]uint8{0, 13, 24} - -func (i DirectoryContentsOrder) String() string { - if i >= DirectoryContentsOrder(len(_DirectoryContentsOrder_index)-1) { - return "DirectoryContentsOrder(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _DirectoryContentsOrder_name[_DirectoryContentsOrder_index[i]:_DirectoryContentsOrder_index[i+1]] -} diff --git a/enums/directory-contents-en.go b/enums/directory-contents-en.go deleted file mode 100644 index fdd3153..0000000 --- a/enums/directory-contents-en.go +++ /dev/null @@ -1,17 +0,0 @@ -package enums - -//go:generate stringer -type=DirectoryContentsOrder -linecomment -trimprefix=DirectoryContentsOrder -output directory-contents-en-auto.go - -// DirectoryContentsOrder determines what order a directories -// entries are invoked for. -type DirectoryContentsOrder uint - -const ( - // DirectoryContentsOrderFoldersFirst invoke folders first - // - DirectoryContentsOrderFoldersFirst DirectoryContentsOrder = iota // folders-first - - // DirectoryContentsOrderFilesFirst invoke files first - // - DirectoryContentsOrderFilesFirst // files-first -) diff --git a/extent.go b/extent.go index 5f31463..fa4fce8 100644 --- a/extent.go +++ b/extent.go @@ -97,7 +97,7 @@ func (ex *resumeExtent) options(settings ...pref.Option) (*pref.Options, error) loaded, err := resume.Load(ex.fileSys.res, ex.w.From, settings...) ex.loaded = loaded - // get the resume point from the resume persistence file + // TODO: get the resume point from the resume persistence file // then set up hibernation with this defined as a hibernation // filter. // diff --git a/internal/feat/filter/filter-plugin.go b/internal/feat/filter/filter-plugin.go index d569563..ba0645f 100644 --- a/internal/feat/filter/filter-plugin.go +++ b/internal/feat/filter/filter-plugin.go @@ -35,10 +35,6 @@ type plugin struct { scheme scheme } -func (p *plugin) Name() string { - return "filtering" -} - func (p *plugin) Register(kc types.KernelController) error { if err := p.BasePlugin.Register(kc); err != nil { return err diff --git a/internal/feat/filter/scheme-custom.go b/internal/feat/filter/scheme-custom.go index 3307444..74c5301 100644 --- a/internal/feat/filter/scheme-custom.go +++ b/internal/feat/filter/scheme-custom.go @@ -6,7 +6,6 @@ import ( "github.com/snivilised/traverse/internal/measure" "github.com/snivilised/traverse/internal/third/lo" "github.com/snivilised/traverse/internal/types" - "github.com/snivilised/traverse/pref" ) type customScheme struct { @@ -17,12 +16,6 @@ type customScheme struct { func (s *customScheme) create() error { s.filter = s.o.Filter.Custom - if s.o.Filter.Sink != nil { - s.o.Filter.Sink(pref.FilterReply{ - Node: s.filter, - }) - } - return s.filter.Validate() } diff --git a/internal/feat/filter/scheme-sampler.go b/internal/feat/filter/scheme-sampler.go index 6326430..311595c 100644 --- a/internal/feat/filter/scheme-sampler.go +++ b/internal/feat/filter/scheme-sampler.go @@ -9,7 +9,6 @@ import ( "github.com/snivilised/traverse/internal/third/lo" "github.com/snivilised/traverse/internal/types" "github.com/snivilised/traverse/nfs" - "github.com/snivilised/traverse/pref" ) type samplerScheme struct { @@ -33,13 +32,8 @@ func (s *samplerScheme) create() error { _ fs.ReadDirFS, _ string, ) ([]fs.DirEntry, error) { return s.filter.Matching(result), err - }) - - if s.o.Filter.Sink != nil { - s.o.Filter.Sink(pref.FilterReply{ - Sampler: s.filter, - }) - } + }, + ) return filter.Validate() } diff --git a/internal/feat/hiber/hibernate-plugin.go b/internal/feat/hiber/hibernate-plugin.go index 8bdcd39..58d1111 100644 --- a/internal/feat/hiber/hibernate-plugin.go +++ b/internal/feat/hiber/hibernate-plugin.go @@ -32,10 +32,6 @@ type plugin struct { profile profile } -func (p *plugin) Name() string { - return "hibernation" -} - func (p *plugin) Next(node *core.Node, inspection types.Inspection) (bool, error) { return p.profile.next(node, inspection) } diff --git a/internal/feat/hiber/hibernate_test.go b/internal/feat/hiber/hibernate_test.go index 6fa2c14..566bb92 100644 --- a/internal/feat/hiber/hibernate_test.go +++ b/internal/feat/hiber/hibernate_test.go @@ -88,6 +88,14 @@ var _ = Describe("feature", Ordered, func() { }, ), + // This is only required to change the default inclusivity + // of the wake condition; by default is inclusive. + tv.WithHibernationBehaviourExclusiveWake(), + + // This is only required to change the default inclusivity + // of the sleep condition; by default is exclusive. + tv.WithHibernationBehaviourInclusiveSleep(), + tv.WithHookQueryStatus( func(qsys fs.StatFS, path string) (fs.FileInfo, error) { return qsys.Stat(lab.TrimRoot(path)) diff --git a/internal/feat/nanny/nanny-plugin.go b/internal/feat/nanny/nanny-plugin.go index 084db89..17a38d0 100644 --- a/internal/feat/nanny/nanny-plugin.go +++ b/internal/feat/nanny/nanny-plugin.go @@ -33,10 +33,6 @@ type plugin struct { crate measure.Crate } -func (p *plugin) Name() string { - return "nanny" -} - func (p *plugin) Next(node *core.Node, inspection types.Inspection, ) (bool, error) { diff --git a/internal/feat/resume/resume-plugin.go b/internal/feat/resume/resume-plugin.go index 2d8eafd..58b1194 100644 --- a/internal/feat/resume/resume-plugin.go +++ b/internal/feat/resume/resume-plugin.go @@ -15,10 +15,6 @@ type Plugin struct { IfResult core.ResultCompletion } -func (p *Plugin) Name() string { - return "resume" -} - func (p *Plugin) Next(node *core.Node, inspection types.Inspection) (bool, error) { _, _ = node, inspection // apply the wake filter diff --git a/internal/feat/sampling/navigator-sample_test.go b/internal/feat/sampling/navigator-sample_test.go index cd95aac..d910464 100644 --- a/internal/feat/sampling/navigator-sample_test.go +++ b/internal/feat/sampling/navigator-sample_test.go @@ -70,6 +70,7 @@ var _ = Describe("feature", Ordered, func() { Folders: 2, }, }), + tv.WithHookQueryStatus( func(qsys fs.StatFS, path string) (fs.FileInfo, error) { return qsys.Stat(lab.TrimRoot(path)) diff --git a/internal/feat/sampling/sampling-plugin.go b/internal/feat/sampling/sampling-plugin.go index 72e8533..4f27ede 100644 --- a/internal/feat/sampling/sampling-plugin.go +++ b/internal/feat/sampling/sampling-plugin.go @@ -33,10 +33,6 @@ type plugin struct { ctrl controller } -func (p *plugin) Name() string { - return "sampling" -} - func (p *plugin) Init(_ *types.PluginInit) error { p.O.Hooks.ReadDirectory.Chain( p.ctrl.sample, diff --git a/internal/kernel/contents.go b/internal/kernel/contents.go index f67b88e..161caed 100644 --- a/internal/kernel/contents.go +++ b/internal/kernel/contents.go @@ -47,16 +47,15 @@ func (c *Contents) Files() []fs.DirEntry { // All returns the contents of a directory respecting the directory sorting // order defined in the traversal options. func (c *Contents) All() []fs.DirEntry { + //nolint:ineffassign,staticcheck // prealloc result := make([]fs.DirEntry, 0, len(c.files)+len(c.folders)) - switch c.behaviour.DirectoryEntryOrder { - case enums.DirectoryContentsOrderFoldersFirst: - result = c.folders - result = append(result, c.files...) - - case enums.DirectoryContentsOrderFilesFirst: + if c.behaviour.SortFilesFirst { result = c.files result = append(result, c.folders...) + } else { + result = c.folders + result = append(result, c.files...) } return result diff --git a/internal/kernel/mediator.go b/internal/kernel/mediator.go index aa78b9d..1385cf1 100644 --- a/internal/kernel/mediator.go +++ b/internal/kernel/mediator.go @@ -106,7 +106,7 @@ func (m *mediator) Navigate(ctx context.Context) (core.TraverseResult, error) { root: m.root, }) - if !IsBenignError(err) { + if !IsBenignError(err) && m.o != nil { m.o.Monitor.Log.Error(err.Error()) } diff --git a/internal/kernel/navigator-hades.go b/internal/kernel/navigator-hades.go index 0b1fb72..9574671 100644 --- a/internal/kernel/navigator-hades.go +++ b/internal/kernel/navigator-hades.go @@ -5,15 +5,18 @@ import ( "github.com/snivilised/traverse/core" "github.com/snivilised/traverse/internal/types" + "github.com/snivilised/traverse/pref" ) -func HadesNav(err error) types.KernelController { +func HadesNav(o *pref.Options, err error) types.KernelController { return &navigatorHades{ + o: o, err: err, } } type navigatorHades struct { + o *pref.Options err error } @@ -28,6 +31,10 @@ func (n *navigatorHades) Navigate(ctx context.Context) (core.TraverseResult, err } func (n *navigatorHades) Result(_ context.Context, err error) *types.KernelResult { + if !IsBenignError(err) && n.o != nil { + n.o.Monitor.Log.Error(err.Error()) + } + return types.NewFailed(err) } diff --git a/internal/third/lo/condition.go b/internal/third/lo/condition.go index b2b97a4..d127b9a 100644 --- a/internal/third/lo/condition.go +++ b/internal/third/lo/condition.go @@ -22,13 +22,13 @@ func TernaryF[T any](condition bool, ifFunc, elseFunc func() T) T { // TernaryE is the same as TernaryF except the functions defined // must return an error -func TernaryE[T any](condition bool, ifFunc, elseFunc func() (T, error)) (T, error) { - if condition { - return ifFunc() - } +// func TernaryE[T any](condition bool, ifFunc, elseFunc func() (T, error)) (T, error) { +// if condition { +// return ifFunc() +// } - return elseFunc() -} +// return elseFunc() +// } // type IfElse[T any] struct { // result T diff --git a/internal/types/definitions.go b/internal/types/definitions.go index 45bda35..2f1be5b 100644 --- a/internal/types/definitions.go +++ b/internal/types/definitions.go @@ -72,7 +72,6 @@ type ( // Plugin used to define interaction with supplementary features Plugin interface { - Name() string Register(kc KernelController) error Role() enums.Role Init(pi *PluginInit) error diff --git a/locale/messages-errors.go b/locale/messages-errors.go index fd36235..3254bb7 100644 --- a/locale/messages-errors.go +++ b/locale/messages-errors.go @@ -475,54 +475,3 @@ var ErrIDGeneratorFuncCantBeNil = IDGeneratorFuncCantBeNilError{ Data: IDGeneratorFuncCantBeNilErrorTemplData{}, }, } - -// ❌ FooBar - -// FooBarTemplData - TODO: this is a none existent error that should be -// replaced by the client. Its just defined here to illustrate the pattern -// that should be used to implement i18n with li18ngo. Also note, -// that this message has been removed from the translation files, so -// it is not useable at run time. -type FooBarTemplData struct { - traverseTemplData - Path string - Reason error -} - -// the ID should use spp/library specific code, so replace astrolib with the -// name of the library implementing this template project. -func (td FooBarTemplData) Message() *i18n.Message { - return &i18n.Message{ - ID: "foo-bar.traverse.nav", - Description: "Foo Bar description", - Other: "foo bar failure '{{.Path}}' (reason: {{.Reason}})", - } -} - -// FooBarErrorBehaviourQuery used to query if an error is: -// "Failed to read directory contents from the path specified" -type FooBarErrorBehaviourQuery interface { - FooBar() bool -} - -type FooBarError struct { - li18ngo.LocalisableError -} - -// FooBar enables the client to check if error is FooBarError -// via FooBarErrorBehaviourQuery -func (e FooBarError) FooBar() bool { - return true -} - -// NewFooBarError creates a FooBarError -func NewFooBarError(path string, reason error) FooBarError { - return FooBarError{ - LocalisableError: li18ngo.LocalisableError{ - Data: FooBarTemplData{ - Path: path, - Reason: reason, - }, - }, - } -} diff --git a/pref/defaults.go b/pref/defaults.go index 71fd1f2..c15eacc 100644 --- a/pref/defaults.go +++ b/pref/defaults.go @@ -16,8 +16,6 @@ import ( func DefaultReadEntriesHook(sys fs.ReadDirFS, dirname string, ) ([]fs.DirEntry, error) { - const all = -1 - contents, err := fs.ReadDir(sys, dirname) if err != nil { return nil, err diff --git a/pref/options-navigation-behaviours.go b/pref/options-navigation-behaviours.go index de217d8..5a5a656 100644 --- a/pref/options-navigation-behaviours.go +++ b/pref/options-navigation-behaviours.go @@ -1,9 +1,5 @@ package pref -import ( - "github.com/snivilised/traverse/enums" -) - type ( // SubPathBehaviour SubPathBehaviour struct { @@ -15,10 +11,10 @@ type ( // IsCaseSensitive bool - // DirectoryEntryOrder defines whether a folder's files or directories + // SortFilesFirst defines whether a folder's files or directories // should be navigated first. // - DirectoryEntryOrder enums.DirectoryContentsOrder + SortFilesFirst bool } // HibernationBehaviour diff --git a/pref/options.go b/pref/options.go index 330ac2c..c6e8f23 100644 --- a/pref/options.go +++ b/pref/options.go @@ -1,13 +1,13 @@ package pref import ( + "io" "io/fs" "log/slog" "runtime" "github.com/snivilised/traverse/core" "github.com/snivilised/traverse/cycle" - "github.com/snivilised/traverse/enums" "github.com/snivilised/traverse/tapable" ) @@ -75,7 +75,7 @@ func Get(settings ...Option) (o *Options, err error) { err = apply(o, settings...) o.Binder = binder - return + return o, err } type ActiveState struct { @@ -149,7 +149,7 @@ func IfOptionF(condition bool, option ConditionalOption) Option { // DefaultOptions func DefaultOptions() *Options { - nopLogger := &slog.Logger{} + nopLogger := slog.New(slog.NewTextHandler(io.Discard, nil)) o := &Options{ Hibernate: core.HibernateOptions{ @@ -163,8 +163,8 @@ func DefaultOptions() *Options { KeepTrailingSep: true, }, Sort: SortBehaviour{ - IsCaseSensitive: false, - DirectoryEntryOrder: enums.DirectoryContentsOrderFoldersFirst, + IsCaseSensitive: false, + SortFilesFirst: false, }, }, Concurrency: ConcurrencyOptions{ diff --git a/tapable/legacy-defs.go b/resources/doc/TEMP-NOTES.md similarity index 54% rename from tapable/legacy-defs.go rename to resources/doc/TEMP-NOTES.md index e40b1d2..9271fe8 100644 --- a/tapable/legacy-defs.go +++ b/resources/doc/TEMP-NOTES.md @@ -1,11 +1,28 @@ -package tapable +# 💩 Temporary Notes -import ( - "fmt" +This is just a place to put some garbage notes. - "golang.org/x/exp/constraints" -) + + + + + + + + + + + + + + + + + +## legacy defs + +```go type ( // ActivityL represents an entity that performs an action that is tapable. The type // F should be a function signature, defined by the tapable, so F is not really @@ -113,55 +130,63 @@ func (r *Receiver) When(from *Component) { return widget, nil }) } +``` + +The above is still confused. Let's start again we have these scenarios: + +--> internal (during bootstrap): ==> actually, this is di, not tap + +* 1 component needs to custom another + +--> external (via options): + +* notification of life-cycle events (broadcast) | [On/Notify] (eg, OnBegin/On(enums.cycle.begin)) +* customise core behaviour, by role (targeted) | [Tap/Role] (eg, ReadDirectory, role=directory-reader) +* -// The above is still confused. Let's start again we have these scenarios: -// -// --> internal (during bootstrap): ==> actually, this is di, not tap -// * 1 component needs to custom another -// -// --> external (via options): -// * notification of life-cycle events (broadcast) | [On/Notify] (eg, OnBegin/On(enums.cycle.begin)) -// * customise core behaviour, by role (targeted) | [Tap/Role] (eg, ReadDirectory, role=directory-reader) -// * - -// Since we now have finer grain control; ie there are more but smaller packages -// organised as features, each feature can expose its own set of hooks. Having -// said this, I can still only think of nav as needing to expose hooks, but others -// may emerge. -// -// For a component, we have the following situations -// - broadcast, multiple callbacks -// - targeted, single callback -// -// - may expose multiple hooks with different signatures -// the problem this poses is that we can't have a collection of different -// items. This means we need to define a hook container struct that contains the hooks. -// The component aggregates this hook container with a member called hooks. -// For example, in extendio, the options contains a hooks struct TraverseHooks: -// -// type TraverseHooks struct { -// QueryStatus QueryStatusHookFn -// ReadDirectory ReadDirectoryHookFn -// FolderSubPath SubPathHookFn -// FileSubPath SubPathHookFn -// InitFilters FilterInitHookFn -// Sort SortEntriesHookFn -// Extend ExtendHookFn -// } -// -// But we need to ba able to tap these, -// -// if hooks is of type TraverseHooks, in object Component -// component.hooks.ReadDirectory.tap("name", hookFn) -// therefore ReadDirectoryHookFn, can't be the function, there must be a -// level of indirection in-between, -// -// in TraverseHooks, ReadDirectory must be of type ReadDirectoryHook, -// which is an instantiation of a generic type: -// HookFunc[F any], where HookFunc contains the Tap function -// -// type ReadDirectoryHook tapable.HookFunc[ReadDirectoryHookFn] -// -// type TraverseHooks struct { -// ReadDirectory ReadDirectoryHook -// } +Since we now have finer grain control; ie there are more but smaller packages +organised as features, each feature can expose its own set of hooks. Having +said this, I can still only think of nav as needing to expose hooks, but others +may emerge. + +For a component, we have the following situations + +* broadcast, multiple callbacks +* targeted, single callback +* may expose multiple hooks with different signatures +the problem this poses is that we can't have a collection of different +items. This means we need to define a hook container struct that contains the hooks. +The component aggregates this hook container with a member called hooks. +For example, in extendio, the options contains a hooks struct TraverseHooks: + +```go +type TraverseHooks struct { + QueryStatus QueryStatusHookFn + ReadDirectory ReadDirectoryHookFn + FolderSubPath SubPathHookFn + FileSubPath SubPathHookFn + InitFilters FilterInitHookFn + Sort SortEntriesHookFn + Extend ExtendHookFn +} +``` + +But we need to ba able to tap these, + +if hooks is of type TraverseHooks, in object Component +component.hooks.ReadDirectory.tap("name", hookFn) +therefore ReadDirectoryHookFn, can't be the function, there must be a +level of indirection in-between, + +in TraverseHooks, ReadDirectory must be of type ReadDirectoryHook, +which is an instantiation of a generic type: + +```go +HookFunc[F any], where HookFunc contains the Tap function + +type ReadDirectoryHook tapable.HookFunc[ReadDirectoryHookFn] + +type TraverseHooks struct { + ReadDirectory ReadDirectoryHook +} +``` diff --git a/scripts/apply-coverage-exclusions.sh b/scripts/apply-coverage-exclusions.sh new file mode 100755 index 0000000..9f3c6d6 --- /dev/null +++ b/scripts/apply-coverage-exclusions.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# Define paths relative to the root directory +ROOT_DIR="$(git rev-parse --show-toplevel)" +COVERAGE_FILE="$ROOT_DIR/coverage.out" +EXCLUSIONS_FILE="$ROOT_DIR/scripts/coverage-exclusion-list.txt" + +# Check if required files exist +if [ ! -f "$COVERAGE_FILE" ]; then + echo "Error: Coverage file not found at $COVERAGE_FILE" + exit 1 +fi + +if [ ! -f "$EXCLUSIONS_FILE" ]; then + echo "Error: Exclusions file not found at $EXCLUSIONS_FILE" + exit 1 +fi + +# Create a temporary file +TEMP_FILE=$(mktemp) + +# Process the exclusions +while IFS= read -r line || [[ -n "$line" ]]; do + # Escape special characters in the line for use in sed + escaped_line=$(echo "$line" | sed 's/[\/&]/\\&/g') + + # Remove matching lines from the coverage file + sed "/${escaped_line}/d" "$COVERAGE_FILE" > "$TEMP_FILE" + + # Replace the original file with the modified content + mv "$TEMP_FILE" "$COVERAGE_FILE" +done < "$EXCLUSIONS_FILE" + +echo "Coverage exclusions have been applied successfully." diff --git a/scripts/coverage-exclusion-list.txt b/scripts/coverage-exclusion-list.txt new file mode 100644 index 0000000..bb69c1b --- /dev/null +++ b/scripts/coverage-exclusion-list.txt @@ -0,0 +1,30 @@ +github.com/snivilised/traverse/enums/entry-type-en-auto.go +github.com/snivilised/traverse/enums/entry-type-en.go +github.com/snivilised/traverse/enums/filter-scope-en-auto.go +github.com/snivilised/traverse/enums/filter-scope-en.go +github.com/snivilised/traverse/enums/filter-type-en-auto.go +github.com/snivilised/traverse/enums/filter-type-en.go +github.com/snivilised/traverse/enums/hibernation-en-auto.go +github.com/snivilised/traverse/enums/hibernation-en.go +github.com/snivilised/traverse/enums/internal-role-en-auto.go +github.com/snivilised/traverse/enums/internal-role-en.go +github.com/snivilised/traverse/enums/metric-en-auto.go +github.com/snivilised/traverse/enums/metric-en.go +github.com/snivilised/traverse/enums/notification-en-auto.go +github.com/snivilised/traverse/enums/notification-en.go +github.com/snivilised/traverse/enums/persistence-format-en-auto.go +github.com/snivilised/traverse/enums/persistence-format-en.go +github.com/snivilised/traverse/enums/resume-strategy-en-auto.go +github.com/snivilised/traverse/enums/resume-strategy-en.go +github.com/snivilised/traverse/enums/role-en-auto.go +github.com/snivilised/traverse/enums/role-en.go +github.com/snivilised/traverse/enums/sample-type-en-auto.go +github.com/snivilised/traverse/enums/sample-type-en.go +github.com/snivilised/traverse/enums/skip-traversal-en-auto.go +github.com/snivilised/traverse/enums/skip-traversal-en.go +github.com/snivilised/traverse/enums/subscription-en-auto.go +github.com/snivilised/traverse/enums/subscription-en.go +github.com/snivilised/traverse/enums/tri-state-bool-en-auto.go +github.com/snivilised/traverse/enums/tri-state-bool-en.go +github.com/snivilised/traverse/enums/way-point-en-auto.go +github.com/snivilised/traverse/enums/way-point-en.go