From 16cae0b304c7bd8ce0ff62cc72e4ac2efb2bb0dc Mon Sep 17 00:00:00 2001 From: plastikfan Date: Wed, 21 Feb 2024 12:41:49 +0000 Subject: [PATCH] fix(proxy): re-repair existing path-finder-tests (#172) --- .vscode/settings.json | 1 + src/app/command/shrink-cmd.go | 18 +- src/app/proxy/enter-shrink.go | 5 +- src/app/proxy/entry-base.go | 19 +- src/app/proxy/filing/path-finder.go | 20 +- src/app/proxy/filing/path-finder_test.go | 116 ++- src/app/proxy/orc/controller.go | 18 +- src/app/proxy/path-finder-observer_test.go | 71 +- src/app/proxy/pixa-legacy_test.go | 820 +++++++++++++++++ src/app/proxy/pixa_test.go | 983 +++++++-------------- src/app/proxy/user/interaction.go | 20 +- src/app/proxy/user/model.go | 3 +- src/app/proxy/user/ui-textual.go | 3 +- test/data/configuration/pixa-test.yml | 3 +- 14 files changed, 1308 insertions(+), 792 deletions(-) create mode 100644 src/app/proxy/pixa-legacy_test.go diff --git a/.vscode/settings.json b/.vscode/settings.json index 02266ae..dab0e73 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -65,6 +65,7 @@ "mohae", "nakedret", "natefinch", + "navi", "nolint", "nolintlint", "nosec", diff --git a/src/app/command/shrink-cmd.go b/src/app/command/shrink-cmd.go index 3eda3db..d873e30 100644 --- a/src/app/command/shrink-cmd.go +++ b/src/app/command/shrink-cmd.go @@ -171,9 +171,12 @@ func (b *Bootstrap) buildShrinkCommand(container *assistant.CobraContainer) *cob defaultOutputPath, ), ¶mSet.Native.OutputPath, func(s string, f *pflag.Flag) error { - if f.Changed && !b.Vfs.DirectoryExists(s) { - return i18n.NewOutputPathDoesNotExistError(s) - } + // Instead of doing the commented out check, check that the location + // specified has the correct permission to write + // + // if f.Changed && !b.Vfs.DirectoryExists(s) { + // return i18n.NewOutputPathDoesNotExistError(s) + // } return nil }, @@ -191,9 +194,12 @@ func (b *Bootstrap) buildShrinkCommand(container *assistant.CobraContainer) *cob defaultTrashPath, ), ¶mSet.Native.TrashPath, func(s string, f *pflag.Flag) error { - if f.Changed && !b.Vfs.DirectoryExists(s) { - return i18n.NewOutputPathDoesNotExistError(s) - } + // Instead of doing the commented out check, check that the location + // specified has the correct permission to write + // + // if f.Changed && !b.Vfs.DirectoryExists(s) { + // return i18n.NewOutputPathDoesNotExistError(s) + // } return nil }, diff --git a/src/app/proxy/enter-shrink.go b/src/app/proxy/enter-shrink.go index 853de93..46e6cca 100644 --- a/src/app/proxy/enter-shrink.go +++ b/src/app/proxy/enter-shrink.go @@ -172,7 +172,7 @@ func EnterShrink( schemes := params.Inputs.Root.Configs.Schemes selectedScheme := params.Inputs.Root.ProfileFam.Native.Scheme scheme, _ := schemes.Scheme(selectedScheme) - noProfiles := lo.TernaryF(scheme == nil, + arity := lo.TernaryF(scheme == nil, func() uint { return 1 }, @@ -187,7 +187,7 @@ func EnterShrink( OutputPath: params.Inputs.ParamSet.Native.OutputPath, TrashPath: params.Inputs.ParamSet.Native.TrashPath, Observer: params.Inputs.Root.Observers.PathFinder, - Arity: noProfiles, + Arity: arity, }) fileManager := filing.NewManager(params.Vfs, finder, params.Inputs.Root.PreviewFam.Native.DryRun, @@ -220,6 +220,7 @@ func EnterShrink( interaction := user.NewInteraction( params.Inputs, params.Logger, + arity, ) entry := &ShrinkEntry{ EntryBase: EntryBase{ diff --git a/src/app/proxy/entry-base.go b/src/app/proxy/entry-base.go index ed4e737..c604bc2 100644 --- a/src/app/proxy/entry-base.go +++ b/src/app/proxy/entry-base.go @@ -7,7 +7,6 @@ import ( "log/slog" "os" "strings" - "time" "github.com/samber/lo" "github.com/snivilised/cobrass/src/assistant/configuration" @@ -18,20 +17,6 @@ import ( "github.com/snivilised/pixa/src/app/proxy/orc" ) -func summariseAfter(result *nav.TraverseResult, err error) { - measure := fmt.Sprintf("started: '%v', elapsed: '%v'", - result.Session.StartedAt().Format(time.RFC1123), result.Session.Elapsed(), - ) - files := result.Metrics.Count(nav.MetricNoFilesInvokedEn) - folders := result.Metrics.Count(nav.MetricNoFoldersInvokedEn) - summary := fmt.Sprintf("files: %v, folders: %v", files, folders) - message := lo.Ternary(err == nil, - fmt.Sprintf("๐Ÿšฉ navigation completed ok (%v) ๐Ÿ’ [%v]", summary, measure), - fmt.Sprintf("๐Ÿšฉ error occurred during navigation (%v)๐Ÿ’” [%v]", err, measure), - ) - fmt.Println(message) -} - // EntryBase is the base entry for all commands in pixa type EntryBase struct { // some parts of the struct should go into a TraverseBase (anything to with @@ -78,6 +63,10 @@ func (e *EntryBase) ConfigureOptions(o *nav.TraverseOptions) { }), nil } + o.Hooks.Extend = func(navi *nav.NavigationInfo, entries *nav.DirectoryContents) { + nav.DefaultExtendHookFn(navi, entries) + } + if o.Store.FilterDefs == nil { switch { case e.Inputs.FoldersFam.Native.FoldersGlob != "": diff --git a/src/app/proxy/filing/path-finder.go b/src/app/proxy/filing/path-finder.go index 4b1b4e0..12951bf 100644 --- a/src/app/proxy/filing/path-finder.go +++ b/src/app/proxy/filing/path-finder.go @@ -228,7 +228,7 @@ func (f *PathFinder) Scheme() string { func (f *PathFinder) Transfer(info *common.PathInfo) (folder, file string) { folder = func() string { if info.Cuddle { - return info.Origin // should we return empty string here? + return info.Origin } if info.Output != "" && info.Trash == "" { @@ -278,6 +278,14 @@ func (f *PathFinder) Transfer(info *common.PathInfo) (folder, file string) { return info.Item.Extension.Name }() + if filepath.Join(folder, file) == info.Item.Path { + // Since we have derived a path that is the same as the input, + // we should return nothing to indicate to the file manager + // that it does not have to move/rename the input. + // + return "", "" + } + return folder, file } @@ -351,6 +359,16 @@ func (f *PathFinder) Result(info *common.PathInfo) (folder, file string) { // The file name just matches the input file name. The folder name // provides the context. // + if info.Cuddle { + // decorate the input file to get the result file + // + supp := f.fileProfileSupplement(info.Profile) + + return SupplementFilename( + info.Item.Extension.Name, supp, f.Stats, + ) + } + return info.Item.Extension.Name }() diff --git a/src/app/proxy/filing/path-finder_test.go b/src/app/proxy/filing/path-finder_test.go index 82e9c73..5dc148b 100644 --- a/src/app/proxy/filing/path-finder_test.go +++ b/src/app/proxy/filing/path-finder_test.go @@ -68,7 +68,7 @@ var _ = Describe("PathFinder", Ordered, func() { } advanced = &cfg.MsAdvancedConfig{ - Abort: false, + Abort: true, LabelsCFG: cfg.MsLabelsConfig{ Adhoc: "ADHOC", Journal: "journal", @@ -150,7 +150,7 @@ var _ = Describe("PathFinder", Ordered, func() { // Entry(nil, &pfTE{ - given: "๐ŸŒ€ TRANSFER: transparent/profile/non-cuddled (๐ŸŽฏ @TID-CORE-1_TR-PR-NC_T)", + given: "๐ŸŒ€ TRANSFER: transparent/profile/not-cuddled (๐ŸŽฏ @TID-CORE-1_TR-PR-NC_T)", should: "redirect input to supplemented folder // filename not modified", reasons: reasons{ folder: "transparency, result should take place of input in same folder", @@ -166,7 +166,7 @@ var _ = Describe("PathFinder", Ordered, func() { }), Entry(nil, &pfTE{ - given: "๐ŸŽ RESULT: transparent/profile (๐ŸŽฏ @TID-CORE-2_TR-PR-NC_R)", + given: "๐ŸŽ RESULT: transparent/profile/not-cuddled (๐ŸŽฏ @TID-CORE-2_TR-PR-NC_R)", should: "not modify folder // not modify filename", reasons: reasons{ folder: "transparency, result should take place of input", @@ -180,11 +180,20 @@ var _ = Describe("PathFinder", Ordered, func() { }), Entry(nil, &pfTE{ + // If we say transparent and cuddled, then that implies + // - inputs and outputs should be in the same folder + // - transparent means the output take the place of the input + // - input has to be moved out of the way + // - but which directory? By default we attempt to be transparent, so + // the directory should be origin. This would be changed by the presence + // of either --trash(input), --output(result). + // - input renamed with supplement + given: "๐ŸŒ€ TRANSFER: transparent/profile/cuddled (๐ŸŽฏ @TID-CORE-3_TR-PR-CU_T)", - should: "not modify folder // file decorated with supplement", + should: "return origin folder // file decorated with supplement", reasons: reasons{ - folder: "not modify folder to enable cuddle", - file: "cuddled file needs to be disambiguated from the input", + folder: "origin folder to enable cuddle", + file: "input needs to be supplemented so result can be cuddled", }, profile: "blur", supplement: fmt.Sprintf("%v.%v", "$TRASH$", "blur"), @@ -192,6 +201,7 @@ var _ = Describe("PathFinder", Ordered, func() { cuddle: true, assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { Expect(folder).To(Equal(pi.Origin), because(entry.reasons.folder)) + // Expect(folder).To(BeEmpty(), because(entry.reasons.folder)) supplemented := filing.SupplementFilename( pi.Item.Extension.Name, entry.supplement, statics, ) @@ -204,7 +214,7 @@ var _ = Describe("PathFinder", Ordered, func() { should: "not modify folder // not modify filename", reasons: reasons{ folder: "not modify folder to enable cuddle", - file: "cuddled result file needs to replace the input", + file: "cuddled un-supplemented result file needs to replace the input", }, profile: "blur", assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { @@ -216,7 +226,18 @@ var _ = Describe("PathFinder", Ordered, func() { // === TRANSPARENT / SCHEME (non-cuddle) [BLUE] Entry(nil, &pfTE{ - given: "๐ŸŒ€ TRANSFER: transparent/scheme/non-cuddled (๐ŸŽฏ @TID-CORE-5_TR-SC-NC_BLUR_T)", + // NOT-TRANSPARENT: + // + // scheme not compatible with transparency, so this may not be a valid test + // since arity > 1, how can we achieve transparency? we can't, because only + // 1 result can take the place of the input. + // This is not transparent, but the case may still be valid. SInce this + // is not transparent, we either need: + // - --trash: to transfer the input to this explicit location + // - --output: to create new file as the output of operation + // if neither are specified, the the input stays as is and the results are + // decorated with the supplement, all origin. + given: "๐ŸŒ€ TRANSFER: not-transparent/scheme/not-cuddled (๐ŸŽฏ @TID-CORE-5_NTR-SC-NC_BLUR_T)", should: "redirect input to supplemented folder // filename not modified", reasons: reasons{ folder: "transparency, result should take place of input in same folder", @@ -235,7 +256,7 @@ var _ = Describe("PathFinder", Ordered, func() { // ... Entry(nil, &pfTE{ - given: "๐ŸŒ€ TRANSFER: transparent/scheme/non-cuddled (๐ŸŽฏ @TID-CORE-6_TR-SC-NC_SF_T)", + given: "๐ŸŒ€ TRANSFER: not-transparent/scheme/not-cuddled (๐ŸŽฏ @TID-CORE-6_NTR-SC-NC_SF_T)", should: "redirect input to supplemented folder // filename not modified", reasons: reasons{ folder: "transparency, result should take place of input in same folder", @@ -254,10 +275,12 @@ var _ = Describe("PathFinder", Ordered, func() { // === TRANSPARENT / SCHEME (cuddle) [GREEN] Entry(nil, &pfTE{ - given: "๐ŸŒ€ TRANSFER: transparent/scheme/cuddled (๐ŸŽฏ @TID-CORE-7_TR-SC-CU_BLUR_T)", - should: "not modify folder // file decorated with supplement", + // !!! input file should stay unmodified + // the results should be supplemented + given: "๐ŸŒ€ TRANSFER: not-transparent/scheme/cuddled (๐ŸŽฏ @TID-CORE-7_NTR-SC-CU_BLUR_T)", + should: "return origin folder // file decorated with supplement", reasons: reasons{ - folder: "not modify folder to enable cuddle", + folder: "return origin folder to enable cuddle", file: "cuddled file needs to be disambiguated from the input", }, scheme: "blur-sf", @@ -274,13 +297,33 @@ var _ = Describe("PathFinder", Ordered, func() { }, }), + Entry(nil, &pfTE{ + given: "๐ŸŽ RESULT: not-transparent/scheme/cuddled (๐ŸŽฏ @TID-CORE-(7:_TBD_)_NTR-SC-CU_BLUR_T)", + should: "return empty folder // file decorated with supplement", + reasons: reasons{ + folder: "return empty folder to enable cuddle", + file: "cuddled file needs to be disambiguated from the input", + }, + scheme: "blur-sf", + profile: "blur", + supplement: "blur-sf.blur", + cuddle: true, + assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { + Expect(folder).To(Equal(pi.Origin), because(entry.reasons.folder)) + supplemented := filing.SupplementFilename( + pi.Item.Extension.Name, entry.supplement, statics, + ) + Expect(file).To(Equal(supplemented), because(entry.reasons.file, file)) + }, + }), + // ... Entry(nil, &pfTE{ - given: "๐ŸŒ€ TRANSFER: transparent/scheme/cuddled (๐ŸŽฏ @TID-CORE-8_TR-SC-CU_SF_T)", - should: "not modify folder // file decorated with supplement", + given: "๐ŸŒ€ TRANSFER: not-transparent/scheme/cuddled (๐ŸŽฏ @TID-CORE-8_NTR-SC-CU_SF_T)", + should: "return origin folder // file decorated with supplement", reasons: reasons{ - folder: "not modify folder to enable cuddle", + folder: "return origin folder to enable cuddle", file: "cuddled file needs to be disambiguated from the input", }, scheme: "blur-sf", @@ -297,11 +340,31 @@ var _ = Describe("PathFinder", Ordered, func() { }, }), + Entry(nil, &pfTE{ + given: "๐ŸŽ RESULT: not-transparent/scheme/cuddled (๐ŸŽฏ @TID-CORE-(8:_TBD_)_NTR-SC-CU_SF_R)", + should: "return origin folder // file decorated with supplement", + reasons: reasons{ + folder: "return origin folder to enable cuddle", + file: "cuddled file needs to be disambiguated from the input", + }, + scheme: "blur-sf", + profile: "sf", + supplement: "blur-sf.sf", + cuddle: true, + assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { + Expect(folder).To(Equal(pi.Origin), because(entry.reasons.folder)) + supplemented := filing.SupplementFilename( + pi.Item.Extension.Name, entry.supplement, statics, + ) + Expect(file).To(Equal(supplemented), because(entry.reasons.file)) + }, + }), + // // === TRANSPARENT / ADHOC // Entry(nil, &pfTE{ - given: "๐ŸŒ€ TRANSFER: transparent/adhoc/non-cuddled (๐ŸŽฏ @TID-CORE-9_TR-AD-NC_SF_T)", + given: "๐ŸŒ€ TRANSFER: transparent/adhoc/not-cuddled (๐ŸŽฏ @TID-CORE-9_TR-AD-NC_SF_T)", should: "redirect input to supplemented folder // filename not modified", reasons: reasons{ folder: "transparency, result should take place of input in same folder", @@ -316,7 +379,7 @@ var _ = Describe("PathFinder", Ordered, func() { }), Entry(nil, &pfTE{ - given: "๐ŸŽ RESULT: transparent/adhoc (๐ŸŽฏ @TID-CORE-10_TR-AD_R)", + given: "๐ŸŽ RESULT: transparent/adhoc/not-cuddled (๐ŸŽฏ @TID-CORE-10_TR-AD-NC_SF_R)", should: "not modify folder // not modify filename", reasons: reasons{ folder: "transparency, result should take place of input", @@ -366,7 +429,9 @@ var _ = Describe("PathFinder", Ordered, func() { // === TRANSPARENT / SCHEME (non-cuddle) [BLUE] Entry(nil, &pfTE{ - given: "๐ŸŒ€ TRANSFER: transparent/scheme/trash (๐ŸŽฏ @TID-CORE-13_TR-SC-TRA_BLUR_T)", + // NOT-TRANSPARENT + // + given: "๐ŸŒ€ TRANSFER: not-transparent/scheme/trash (๐ŸŽฏ @TID-CORE-13_NTR-SC-TRA_BLUR_T)", should: "redirect input to supplemented folder // filename not modified", reasons: reasons{ folder: "transparency, result should take place of input in same folder", @@ -386,7 +451,7 @@ var _ = Describe("PathFinder", Ordered, func() { // ... Entry(nil, &pfTE{ - given: "๐ŸŒ€ TRANSFER: transparent/scheme/trash (๐ŸŽฏ @TID-CORE-14_TR-SC-TRA_SF_T)", + given: "๐ŸŒ€ TRANSFER: not-transparent/scheme/trash (๐ŸŽฏ @TID-CORE-14_NTR-SC-TRA_SF_T)", should: "redirect input to supplemented folder // filename not modified", reasons: reasons{ folder: "transparency, result should take place of input in same folder", @@ -408,7 +473,7 @@ var _ = Describe("PathFinder", Ordered, func() { // Entry(nil, &pfTE{ - given: "๐ŸŒ€ TRANSFER: profile/output (๐ŸŽฏ @TID-CORE-15_NT-PR-OUT_T)", + given: "๐ŸŒ€ TRANSFER: not-transparent/profile/output (๐ŸŽฏ @TID-CORE-15_NTR-PR-NC-OUT_T)", should: "return empty folder and file", reasons: reasons{ folder: "no transfer required", @@ -416,7 +481,6 @@ var _ = Describe("PathFinder", Ordered, func() { }, profile: "blur", output: filepath.Join("foo", "sessions", "scan01", "results"), - supplement: filepath.Join("$TRASH$", "blur"), actionTransfer: true, assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { Expect(folder).To(BeEmpty(), because(entry.reasons.folder, folder)) @@ -425,7 +489,7 @@ var _ = Describe("PathFinder", Ordered, func() { }), Entry(nil, &pfTE{ - given: "๐ŸŽ RESULT: profile/output (๐ŸŽฏ @TID-CORE-16_NT-PR-OUT_R)", + given: "๐ŸŽ RESULT: not-transparent/profile/output (๐ŸŽฏ @TID-CORE-16_NTR-PR-NC-OUT_R)", should: "redirect result to output // supplement folder // not modify filename", reasons: reasons{ folder: "result should be send to supplemented output folder", @@ -446,7 +510,7 @@ var _ = Describe("PathFinder", Ordered, func() { // === NON-TRANSPARENT / SCHEME (non-cuddle) [BLUE] Entry(nil, &pfTE{ - given: "๐ŸŒ€ TRANSFER: scheme/output (๐ŸŽฏ @TID-CORE-17_NT-SC-OUT_BLUR_T)", + given: "๐ŸŒ€ TRANSFER: not-transparent/scheme/output (๐ŸŽฏ @TID-CORE-17_NTR-SC-NC-OUT_BLUR_T)", should: "return empty folder and file", reasons: reasons{ folder: "no transfer required", @@ -465,7 +529,7 @@ var _ = Describe("PathFinder", Ordered, func() { // ... Entry(nil, &pfTE{ - given: "๐ŸŒ€ TRANSFER: scheme/output (๐ŸŽฏ @TID-CORE-18_NT-SC-OUT_SF_T)", + given: "๐ŸŒ€ TRANSFER: not-transparent/scheme/output (๐ŸŽฏ @TID-CORE-18_NTR-SC-NC-OUT_SF_T)", should: "return empty folder and file", reasons: reasons{ folder: "no transfer required", @@ -485,7 +549,7 @@ var _ = Describe("PathFinder", Ordered, func() { // === NON-TRANSPARENT / ADHOC // Entry(nil, &pfTE{ - given: "๐ŸŒ€ TRANSFER: adhoc/output (๐ŸŽฏ @TID-CORE-19_NT-AD-OUT_SF_T)", + given: "๐ŸŒ€ TRANSFER: not-transparent/adhoc/output (๐ŸŽฏ @TID-CORE-19_NTR-AD-OUT_SF_T)", should: "return empty folder and file", reasons: reasons{ folder: "no transfer required", @@ -500,7 +564,7 @@ var _ = Describe("PathFinder", Ordered, func() { }), Entry(nil, &pfTE{ - given: "๐ŸŽ RESULT: adhoc/output (๐ŸŽฏ @TID-CORE-20_NT-AD-OUT_SF_R)", + given: "๐ŸŽ RESULT: not-transparent/adhoc/output (๐ŸŽฏ @TID-CORE-20_NTR-AD-OUT_SF_R)", should: "redirect result to output // supplement folder // not modify filename", reasons: reasons{ folder: "result should be send to supplemented output folder", diff --git a/src/app/proxy/orc/controller.go b/src/app/proxy/orc/controller.go index 98c271c..9e3f7fa 100644 --- a/src/app/proxy/orc/controller.go +++ b/src/app/proxy/orc/controller.go @@ -140,19 +140,17 @@ func (c *Controller) Run(item *nav.TraverseItem, sequence common.Sequence) error err = e } - // TODO: this needs to change according to a new, not yet defined - // setting, 'ContinueOnError' - // - return e == nil + return e == nil || !c.configs.Advanced.AbortOnError() } c.private.Pi = common.PathInfo{ - Item: item, - Origin: item.Parent.Path, - Scheme: c.session.FileManager.Finder().Scheme(), - Cuddle: c.session.Inputs.ParamSet.Native.Cuddle, - Output: c.session.Inputs.ParamSet.Native.OutputPath, - Trash: c.session.Inputs.ParamSet.Native.TrashPath, + Item: item, + Origin: item.Parent.Path, + Profile: c.session.Inputs.Root.ProfileFam.Native.Profile, + Scheme: c.session.FileManager.Finder().Scheme(), + Cuddle: c.session.Inputs.ParamSet.Native.Cuddle, + Output: c.session.Inputs.ParamSet.Native.OutputPath, + Trash: c.session.Inputs.ParamSet.Native.TrashPath, } // TODO: need to decide a proper policy for cleaning up diff --git a/src/app/proxy/path-finder-observer_test.go b/src/app/proxy/path-finder-observer_test.go index 3955da1..5ded47d 100644 --- a/src/app/proxy/path-finder-observer_test.go +++ b/src/app/proxy/path-finder-observer_test.go @@ -2,22 +2,21 @@ package proxy_test import ( "fmt" - "path/filepath" "github.com/samber/lo" "github.com/snivilised/extendio/xfs/nav" "github.com/snivilised/extendio/xfs/storage" "github.com/snivilised/pixa/src/app/proxy/common" - "github.com/snivilised/pixa/src/app/proxy/filing" - "github.com/snivilised/pixa/src/internal/matchers" - - . "github.com/onsi/gomega" ) -type pathAssertion struct { +type splitPath struct { file string folder string } +type pathAssertion struct { + actual splitPath + info *common.PathInfo +} type observerAssertions map[string]*pathAssertion @@ -73,40 +72,30 @@ type testPathFinderObserver struct { // -------------|---------|---------|---------|--------|----------------------------------|----------------------------------------- // YES | NO | NO | NO | NO | - //OR/$N.$S | //OR/$N // YES | YES | YES | NO | NO | input > /null | output > /null +// assertL -func (o *testPathFinderObserver) assert(entry *samplerTE, +func (o *testPathFinderObserver) assertAll(entry *pixaTE, origin string, vfs storage.VirtualFS, ) { - if entry.supplements.file != "do not enter" { - return - } - - first := lo.Keys(o.transfers)[0] - fmt.Printf("\n ๐Ÿ“‚ FOLDER: '%v'\n", o.transfers[first].folder) - - for _, v := range o.transfers { - if o.TransparentInput() { - // input should just be renamed with supplement in the origin folder - // - statics := o.target.Statics() - - originalPath := filepath.Join(origin, - filing.SupplementFilename(v.file, entry.supplements.file, statics), - ) - Expect(matchers.AsFile(originalPath)).To(matchers.ExistInFS(vfs)) + if len(o.transfers) > 0 { + first := lo.Keys(o.transfers)[0] + fmt.Printf("\n ๐Ÿ“‚ TRANSFER FOLDER: '%v'\n", o.transfers[first].actual.folder) + + if !entry.dry && entry.asserters.transfer != nil { + for name, assertion := range o.transfers { + entry.asserters.transfer(name, entry, origin, assertion, vfs) + } } } - for _, v := range o.results { - if o.TransparentInput() { // ?? CHECK-VALID FOR OUTPUT? - // result should take the place of input - // - // directory - // intermediate - // name - // - originalPath := filepath.Join(origin, v.file) - Expect(matchers.AsFile(originalPath)).To(matchers.ExistInFS(vfs)) + if len(o.results) > 0 && entry.asserters.result != nil { + first := lo.Keys(o.results)[0] + fmt.Printf("\n ๐Ÿ“‚ RESULT FOLDER: '%v'\n", o.results[first].actual.folder) + + if !entry.dry { + for name, assertion := range o.results { + entry.asserters.result(name, entry, origin, assertion, vfs) + } } } } @@ -114,8 +103,11 @@ func (o *testPathFinderObserver) assert(entry *samplerTE, func (o *testPathFinderObserver) Transfer(info *common.PathInfo) (folder, file string) { folder, file = o.target.Transfer(info) o.transfers[info.Item.Extension.Name] = &pathAssertion{ - folder: folder, - file: file, + actual: splitPath{ + folder: folder, + file: file, + }, + info: info, } return folder, file @@ -124,8 +116,11 @@ func (o *testPathFinderObserver) Transfer(info *common.PathInfo) (folder, file s func (o *testPathFinderObserver) Result(info *common.PathInfo) (folder, file string) { folder, file = o.target.Result(info) o.results[info.Item.Extension.Name] = &pathAssertion{ - folder: folder, - file: file, + actual: splitPath{ + folder: folder, + file: file, + }, + info: info, } return folder, file diff --git a/src/app/proxy/pixa-legacy_test.go b/src/app/proxy/pixa-legacy_test.go new file mode 100644 index 0000000..eb45aa1 --- /dev/null +++ b/src/app/proxy/pixa-legacy_test.go @@ -0,0 +1,820 @@ +package proxy_test + +import ( + "fmt" + "os" + "path/filepath" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/pkg/errors" + "github.com/snivilised/cobrass/src/assistant/configuration" + "github.com/snivilised/extendio/xfs/storage" + "github.com/snivilised/extendio/xfs/utils" + "github.com/snivilised/pixa/src/app/command" + "github.com/snivilised/pixa/src/app/proxy/common" + + "github.com/snivilised/pixa/src/internal/helpers" +) + +func openInputTTY() (*os.File, error) { + f, err := os.Open("/dev/tty") + if err != nil { + return nil, fmt.Errorf("could not open a new TTY: %w", err) + } + + return f, nil +} + +const ( + BackyardWorldsPlanet9Scan01 = "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01" + BackyardWorldsPlanet9Scan02 = "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-02" + DejaVu = "$TRASH$" +) + +type supplements struct { + file string + folder string +} + +type controllerTE struct { + given string + should string + exists bool + args []string + isTui bool + dry bool + intermediate string + outputFlag string + trashFlag string + profile string + scheme string + relative string + mandatory []string + supplements supplements + inputs []string +} + +type samplerTE struct { + controllerTE +} + +func augmentL(entry *samplerTE, + args []string, vfs storage.VirtualFS, root, directory string, +) []string { + result := args + result = append(result, entry.args...) + + if entry.exists { + location := filepath.Join(directory, entry.intermediate, entry.supplements.folder) + if err := vfs.MkdirAll(location, common.Permissions.Write); err != nil { + Fail(errors.Wrap(err, err.Error()).Error()) + } + } + + if entry.outputFlag != "" { + output := helpers.Path(root, entry.outputFlag) + result = append(result, "--output", output) + } + + if entry.trashFlag != "" { + trash := helpers.Path(root, entry.trashFlag) + result = append(result, "--trash", trash) + } + + if entry.profile != "" { + result = append(result, "--profile", entry.profile) + } + + if entry.scheme != "" { + result = append(result, "--scheme", entry.scheme) + } + + if entry.dry { + result = append(result, "--dry-run") + } + + return result +} + +var _ = Describe("pixa-legacy", Ordered, func() { + var ( + repo string + l10nPath string + configPath string + root string + vfs storage.VirtualFS + withoutRenderer bool + ) + + BeforeAll(func() { + repo = helpers.Repo("") + l10nPath = helpers.Path(repo, "test/data/l10n") + configPath = helpers.Path(repo, "test/data/configuration") + + var ( + err error + f *os.File + ) + + if f, err = openInputTTY(); err != nil { + withoutRenderer = true + } + f.Close() + }) + + BeforeEach(func() { + vfs, root = helpers.SetupTest( + "nasa-scientist-index.xml", configPath, l10nPath, helpers.Silent, + ) + }) + + DescribeTable("interactive", + func(entry *samplerTE) { + origin := helpers.Path(root, entry.relative) + args := augmentL(entry, + []string{ + common.Definitions.Commands.Shrink, origin, + }, + vfs, root, origin, + ) + + observer := &testPathFinderObserver{ + transfers: make(observerAssertions), + results: make(observerAssertions), + } + + bootstrap := command.Bootstrap{ + Vfs: vfs, + Presentation: common.PresentationOptions{ + WithoutRenderer: withoutRenderer, + }, + Observers: common.Observers{ + PathFinder: observer, + }, + } + + if !entry.isTui { + args = append(args, "--no-tui") + } + + tester := helpers.CommandTester{ + Args: args, + Root: bootstrap.Root(func(co *command.ConfigureOptionsInfo) { + co.Detector = &helpers.DetectorStub{} + co.Config.Name = common.Definitions.Pixa.ConfigTestFilename + co.Config.ConfigPath = configPath + co.Config.Viper = &configuration.GlobalViperConfig{} + }), + } + + _, err := tester.Execute() + Expect(err).Error().To(BeNil(), + fmt.Sprintf("execution result non nil (%v)", err), + ) + + // assertInFs(entry, &bootstrap, origin, observer) + }, + func(entry *samplerTE) string { + return fmt.Sprintf("๐Ÿงช ===> given: '%v', should: '%v'", + entry.given, entry.should, + ) + }, + + // linear-ui + // + // full run + + XEntry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "full/transparent/adhoc/ex-glob", + should: "full run with ex-glob filter, result file takes place of input", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--files", "*Backyard-Worlds*", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + mandatory: helpers.BackyardWorldsPlanet9Scan01First6, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + file: "ADHOC.TRASH", + folder: "$pixa$/ADHOC/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "full run transparent adhoc, with regex", + should: "full run with regex filter, result file takes place of input", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--files-rx", "Backyard-Worlds", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + mandatory: helpers.BackyardWorldsPlanet9Scan01First6, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "ADHOC", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "full run transparent with profile, with ex-glob", + should: "full run with ex-glob filter, result file takes place of input", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--files", "*Backyard-Worlds*", + "--profile", "adaptive", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + mandatory: helpers.BackyardWorldsPlanet9Scan01First6, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + file: "adaptive", + folder: "adaptive/TRASH", + }, + + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "full run, profile", + should: "full run with regex filter using the defined profile", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--strip", + "--interlace", "plane", + "--quality", "85", + "--files-rx", "Backyard-Worlds", + "--profile", "adaptive", + }, + mandatory: helpers.BackyardWorldsPlanet9Scan01First6, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "adaptive/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "full run transparent with scheme with single profile", + should: "full run with ex-glob filter, result file takes place of input", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--files", "*Backyard-Worlds*", + "--scheme", "singleton", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + mandatory: helpers.BackyardWorldsPlanet9Scan01First6, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "singleton/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "full run non transparent adhoc", + should: "full run with ex-glob filter, input moved to alternative location", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--files", "*Backyard-Worlds*", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + trashFlag: "discard", + mandatory: helpers.BackyardWorldsPlanet9Scan01First6, + intermediate: "discard", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "adaptive/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "full run non transparent with profile", + should: "full run with ex-glob filter, input moved to alternative location", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--files", "*Backyard-Worlds*", + "--profile", "adaptive", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + trashFlag: "discard", + mandatory: helpers.BackyardWorldsPlanet9Scan01First6, + intermediate: "discard", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "adaptive/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "run non transparent scheme single with profile", + should: "full run with ex-glob filter, input moved to alternative location", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--files", "*Backyard-Worlds*", + "--scheme", "singleton", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + trashFlag: "discard", + mandatory: helpers.BackyardWorldsPlanet9Scan01First6, + intermediate: "discard", + supplements: supplements{ + file: "$SUPP/ADHOC.TRASH", + folder: "singleton/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "full run, scheme", + should: "full run, all profiles in the scheme", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--files", "*Backyard-Worlds*", + "--strip", + "--interlace", "plane", + "--quality", "85", + "--scheme", "blur-sf", + }, + mandatory: helpers.BackyardWorldsPlanet9Scan01First6, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "blur-sf/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "full run transparent adhoc and target already exists", + should: "full run with ex-glob filter, result file takes place of input", + exists: true, + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--files", "*Backyard-Worlds*", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + mandatory: helpers.BackyardWorldsPlanet9Scan01First6, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "ADHOC/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "directory contains files with same name different extensions", + should: "create journal file include file extension", + relative: BackyardWorldsPlanet9Scan02, + args: []string{ + "--files", "*Backyard-Worlds*", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + mandatory: helpers.BackyardWorldsPlanet9Scan02, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-02", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "ADHOC/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan02, + }, + }), + + // sample run + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "run transparent adhoc", + should: "sample(first) with ex-glob filter, result file takes place of input", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--sample", + "--no-files", "4", + "--files", "*Backyard-Worlds*", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + mandatory: helpers.BackyardWorldsPlanet9Scan01First4, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "ADHOC/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First4, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "run transparent with profile", + should: "sample(first) with ex-glob filter, result file takes place of input", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--sample", + "--no-files", "4", + "--files", "*Backyard-Worlds*", + "--profile", "adaptive", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + mandatory: helpers.BackyardWorldsPlanet9Scan01First4, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "adaptive/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First4, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "run(last) transparent with profile", + should: "sample(last) with ex-glob filter using the defined profile", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--sample", + "--last", + "--no-files", "4", + "--files", "*Backyard-Worlds*", + "--profile", "adaptive", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + mandatory: helpers.BackyardWorldsPlanet9Scan01Last4, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "adaptive/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01Last4, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "profile without no-files in args", + should: "sample(first) with ex-glob filter, using no-files from config", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--sample", + "--files", "*Backyard-Worlds*", + "--profile", "adaptive", + }, + mandatory: helpers.BackyardWorldsPlanet9Scan01First2, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "adaptive/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First2, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "profile", + should: "sample with regex filter using the defined profile", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--sample", + "--no-files", "4", + "--strip", + "--interlace", "plane", + "--quality", "85", + "--files-rx", "Backyard-Worlds", + "--profile", "adaptive", + }, + mandatory: helpers.BackyardWorldsPlanet9Scan01First4, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "adaptive/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First4, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "run transparent with scheme with single profile", + should: "sample(first) with ex-glob filter, result file takes place of input", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--sample", + "--no-files", "4", + "--files", "*Backyard-Worlds*", + "--scheme", "singleton", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + mandatory: helpers.BackyardWorldsPlanet9Scan01First4, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "singleton/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First4, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "run non transparent adhoc", + should: "sample(first) with ex-glob filter, input moved to alternative location", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--sample", + "--no-files", "4", + "--files", "*Backyard-Worlds*", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + trashFlag: "discard", + mandatory: helpers.BackyardWorldsPlanet9Scan01First4, + intermediate: "discard", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "ADHOC/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First4, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "run non transparent with profile", + should: "sample(first) with ex-glob filter, input moved to alternative location", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--sample", + "--no-files", "4", + "--files", "*Backyard-Worlds*", + "--profile", "adaptive", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + trashFlag: "discard", + mandatory: helpers.BackyardWorldsPlanet9Scan01First4, + intermediate: "discard", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "adaptive/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First4, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "run non transparent scheme single with profile", + should: "sample(first) with ex-glob filter, input moved to alternative location", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--sample", + "--no-files", "4", + "--files", "*Backyard-Worlds*", + "--scheme", "singleton", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + trashFlag: "discard", + mandatory: helpers.BackyardWorldsPlanet9Scan01First4, + intermediate: "discard", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "singleton/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First4, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "scheme", + should: "sample all profiles in the scheme", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--sample", + "--no-files", "4", + "--files", "*Backyard-Worlds*", + "--strip", + "--interlace", "plane", + "--quality", "85", + "--scheme", "blur-sf", + }, + mandatory: helpers.BackyardWorldsPlanet9Scan01First6, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "blur-sf/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First4, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "run transparent adhoc and target already exists", + should: "sample(first) with ex-glob filter, result file takes place of input", + exists: true, + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--sample", + "--no-files", "4", + "--files", "*Backyard-Worlds*", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + mandatory: helpers.BackyardWorldsPlanet9Scan01First4, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "ADHOC/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First4, + }, + }), + + // dry run + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "full dry run transparent adhoc, using glob", + should: "full run with ex-glob filter, without moving input", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--files", "*Backyard-Worlds*", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + dry: true, + // mandatory: helpers.BackyardWorldsPlanet9Scan01First6, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "ADHOC/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "full dry run transparent adhoc, using regex", + should: "full run with regex filter, without moving input", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--files-rx", "Backyard-Worlds", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + dry: true, + // mandatory: helpers.BackyardWorldsPlanet9Scan01First6, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "ADHOC/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + }, + }), + + Entry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "full dry run transparent with profile, using glob", + should: "full run with ex-glob filter, without moving input", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--files", "*Backyard-Worlds*", + "--profile", "adaptive", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + dry: true, + // mandatory: helpers.BackyardWorldsPlanet9Scan01First6, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "adaptive/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + }, + }), + + // textual-ui + // https://dev.to/pomdtr/how-to-debug-bubble-tea-applications-in-visual-studio-code-50jp + // + // full run + // + // ๐Ÿ“š debugging bubbletea + // !! use the predefined "Attach to dlv" launch task. It requires the task + // defined as "Run headless dlv". This starts the dlv debugger in headless mode. + // Note that because the args are hardcoded into the dlv task, if you need to + // debug pixa with different args, then the dlv task needs to be modified. + // + // to attach to dlv debugger manually, start dlv like this: + // dlv debug --headless --listen=:2345 ./src/app/main/ -- shrink /Users/plastikfan/dev/test --profile blur --files "wonky*" --dry-run + // the args come after -- + // the launch.json does not support args for an attach request, args are only + // appropriate for launch + // + // Beware, if you start dlv manually, you will need to define a new launch entry + // that does not depend on the "Run headless dlv" as that attempts to start dlv + // automatically. + // + XEntry(nil, &samplerTE{ + controllerTE: controllerTE{ + given: "bubbletea tui, full run transparent adhoc, with ex-glob", + should: "full run with ex-glob filter, result file takes place of input", + relative: BackyardWorldsPlanet9Scan01, + args: []string{ + "--files", "*Backyard-Worlds*", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + isTui: true, + mandatory: helpers.BackyardWorldsPlanet9Scan01First6, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + // file: "$SUPP/ADHOC.TRASH", + folder: "ADHOC/TRASH", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + }, + }), + ) +}) + +var _ = Describe("end to end", Ordered, func() { + Context("REAL", func() { + XIt("should: tinkle the ivories", func() { + // pixa shrink ~/dev/test/pics --profile blur --sample --no-files 1 --files "screen*" --dry-run + args := []string{ + "shrink", + "/Users/plastikfan/dev/test/pics", + "--profile", "blur", + // "--sample", + // "--no-files", "1", + "--files", "wonky*", + "--dry-run", + } + configPath := utils.ResolvePath("~/snivilised/pixa") + bootstrap := command.Bootstrap{ + Vfs: storage.UseNativeFS(), + } + tester := helpers.CommandTester{ + Args: args, + Root: bootstrap.Root(func(co *command.ConfigureOptionsInfo) { + co.Detector = &helpers.DetectorStub{} + co.Config.Name = common.Definitions.Pixa.AppName + co.Config.ConfigPath = configPath + }), + } + + _, err := tester.Execute() + Expect(err).Error().To(BeNil(), + fmt.Sprintf("execution result non nil (%v)", err), + ) + }) + }) +}) diff --git a/src/app/proxy/pixa_test.go b/src/app/proxy/pixa_test.go index bf0c1e7..ac31742 100644 --- a/src/app/proxy/pixa_test.go +++ b/src/app/proxy/pixa_test.go @@ -4,112 +4,194 @@ import ( "fmt" "os" "path/filepath" + "strings" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" "github.com/snivilised/cobrass/src/assistant/configuration" "github.com/snivilised/extendio/xfs/storage" - "github.com/snivilised/extendio/xfs/utils" "github.com/snivilised/pixa/src/app/command" "github.com/snivilised/pixa/src/app/proxy/common" + "github.com/snivilised/pixa/src/app/proxy/filing" "github.com/snivilised/pixa/src/internal/helpers" + "github.com/snivilised/pixa/src/internal/matchers" ) -func openInputTTY() (*os.File, error) { - f, err := os.Open("/dev/tty") - if err != nil { - return nil, fmt.Errorf("could not open a new TTY: %w", err) - } +type reasons struct { + folder string + file string +} + +type arrange func(entry *pixaTE, origin string, vfs storage.VirtualFS) - return f, nil +type asserter func(name string, entry *pixaTE, origin string, pa *pathAssertion, vfs storage.VirtualFS) + +type asserters struct { + transfer asserter + result asserter + bs *command.Bootstrap } -const ( - BackyardWorldsPlanet9Scan01 = "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01" - BackyardWorldsPlanet9Scan02 = "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-02" - DejaVu = "$TRASH$" -) +func assertTransfer(folder string, pa *pathAssertion, vfs storage.VirtualFS) { + actualDestination := filepath.Join(pa.actual.folder, pa.actual.file) + Expect(matchers.AsDirectory(folder)).To(matchers.ExistInFS(vfs), + because(actualDestination, "๐ŸŒ€ TRANSFER"), + ) + + file := filepath.Join(folder, pa.info.Item.Extension.Name) + Expect(matchers.AsFile(file)).To(matchers.ExistInFS(vfs), because(actualDestination)) +} + +func assertTransferSupplementedOrigin(name string, + entry *pixaTE, origin string, pa *pathAssertion, vfs storage.VirtualFS, +) { + _ = name + + folder := filing.SupplementFolder(origin, + entry.supplements.folder, + ) + assertTransfer(folder, pa, vfs) +} -type supplements struct { - file string - directory string +func assertResultItemFile(name string, + entry *pixaTE, origin string, pa *pathAssertion, +) { + _ = name + _ = entry + _ = origin + // We don't have anything that actually creates the result file + // so instead of checking that it exists in the file system, we + // check the path is what we expect. + // + file := pa.info.Item.Path + Expect(file).To(Equal(pa.info.Item.Path), because(file, "๐ŸŽ RESULT")) } -type controllerTE struct { +type pixaTE struct { given string should string + reasons reasons + arranger arrange + asserters asserters exists bool args []string isTui bool dry bool intermediate string - outputFlag string - trashFlag string + output string + trash string profile string + scheme string relative string mandatory []string supplements supplements inputs []string } -type samplerTE struct { - controllerTE - scheme string +func because(reason string, extras ...string) string { + if len(extras) == 0 { + return fmt.Sprintf("๐Ÿ”ฅ %v", reason) + } + + return fmt.Sprintf("๐Ÿ”ฅ %v (%v)", reason, strings.Join(extras, ",")) } -func augment(entry *samplerTE, +func augment(entry *pixaTE, args []string, vfs storage.VirtualFS, root, directory string, ) []string { result := args result = append(result, entry.args...) if entry.exists { - location := filepath.Join(directory, entry.intermediate, entry.supplements.directory) + location := filepath.Join(directory, entry.intermediate, entry.supplements.folder) if err := vfs.MkdirAll(location, common.Permissions.Write); err != nil { Fail(errors.Wrap(err, err.Error()).Error()) } } - if entry.outputFlag != "" { - output := helpers.Path(root, entry.outputFlag) + if entry.output != "" { + output := helpers.Path(root, entry.output) result = append(result, "--output", output) } - if entry.trashFlag != "" { - trash := helpers.Path(root, entry.trashFlag) - result = append(result, "--trash", trash) + if entry.trash != "" { + result = append(result, "--trash", entry.trash) + } + + if entry.profile != "" { + result = append(result, "--profile", entry.profile) + } + + if entry.scheme != "" { + result = append(result, "--scheme", entry.scheme) } if entry.dry { result = append(result, "--dry-run") } + if !entry.isTui { + result = append(result, "--no-tui") + } + return result } -func assertInFs(entry *samplerTE, - bs *command.Bootstrap, - directory string, - observer *testPathFinderObserver, -) { - vfs := bs.Vfs +type coreTest struct { + entry *pixaTE + root string + configPath string + vfs storage.VirtualFS + withoutRenderer bool +} - // this needs rework, to be done in another issue - // - // if entry.mandatory != nil { - // dejaVu := filepath.Join(DejaVu, entry.supplements.directory) - // supplement := helpers.Path(entry.intermediate, dejaVu) +func (t *coreTest) run() { + origin := helpers.Path(t.root, t.entry.relative) - // for _, original := range entry.mandatory { - // originalPath := filepath.Join(supplement, original) + if t.entry.arranger != nil { + t.entry.arranger(t.entry, origin, t.vfs) + } - // Expect(matchers.AsFile(originalPath)).To(matchers.ExistInFS(vfs)) - // } - // } + args := augment(t.entry, + []string{ + common.Definitions.Commands.Shrink, origin, + }, + t.vfs, t.root, origin, + ) + + observer := &testPathFinderObserver{ + transfers: make(observerAssertions), + results: make(observerAssertions), + } - observer.assert(entry, directory, vfs) + bootstrap := command.Bootstrap{ + Vfs: t.vfs, + Presentation: common.PresentationOptions{ + WithoutRenderer: t.withoutRenderer, + }, + Observers: common.Observers{ + PathFinder: observer, + }, + } + + tester := helpers.CommandTester{ + Args: args, + Root: bootstrap.Root(func(co *command.ConfigureOptionsInfo) { + co.Detector = &helpers.DetectorStub{} + co.Config.Name = common.Definitions.Pixa.ConfigTestFilename + co.Config.ConfigPath = t.configPath + co.Config.Viper = &configuration.GlobalViperConfig{} + }), + } + + _, err := tester.Execute() + Expect(err).Error().To(BeNil(), + fmt.Sprintf("execution result non nil (%v)", err), + ) + + observer.assertAll(t.entry, origin, t.vfs) } var _ = Describe("pixa", Ordered, func() { @@ -145,691 +227,230 @@ var _ = Describe("pixa", Ordered, func() { }) DescribeTable("interactive", - func(entry *samplerTE) { - origin := helpers.Path(root, entry.relative) - args := augment(entry, - []string{ - common.Definitions.Commands.Shrink, origin, - }, - vfs, root, origin, - ) - - observer := &testPathFinderObserver{ - transfers: make(observerAssertions), - results: make(observerAssertions), + func(entry *pixaTE) { + core := coreTest{ + entry: entry, + root: root, + configPath: configPath, + vfs: vfs, + withoutRenderer: withoutRenderer, } - - bootstrap := command.Bootstrap{ - Vfs: vfs, - Presentation: common.PresentationOptions{ - WithoutRenderer: withoutRenderer, - }, - Observers: common.Observers{ - PathFinder: observer, - }, - } - - if !entry.isTui { - args = append(args, "--no-tui") - } - - tester := helpers.CommandTester{ - Args: args, - Root: bootstrap.Root(func(co *command.ConfigureOptionsInfo) { - co.Detector = &helpers.DetectorStub{} - co.Config.Name = common.Definitions.Pixa.ConfigTestFilename - co.Config.ConfigPath = configPath - co.Config.Viper = &configuration.GlobalViperConfig{} - }), - } - - _, err := tester.Execute() - Expect(err).Error().To(BeNil(), - fmt.Sprintf("execution result non nil (%v)", err), - ) - - assertInFs(entry, &bootstrap, origin, observer) + core.run() }, - func(entry *samplerTE) string { + func(entry *pixaTE) string { return fmt.Sprintf("๐Ÿงช ===> given: '%v', should: '%v'", entry.given, entry.should, ) }, - - // linear-ui // - // full run - - XEntry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "full/transparent/adhoc/ex-glob", - should: "full run with ex-glob filter, result file takes place of input", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--files", "*Backyard-Worlds*", - "--gaussian-blur", "0.51", - "--interlace", "line", - }, - mandatory: helpers.BackyardWorldsPlanet9Scan01First6, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - file: "ADHOC.TRASH", - directory: "$pixa$/ADHOC/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01First6, - }, - }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "full run transparent adhoc, with regex", - should: "full run with regex filter, result file takes place of input", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--files-rx", "Backyard-Worlds", - "--gaussian-blur", "0.51", - "--interlace", "line", - }, - mandatory: helpers.BackyardWorldsPlanet9Scan01First6, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "ADHOC", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01First6, - }, - }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "full run transparent with profile, with ex-glob", - should: "full run with ex-glob filter, result file takes place of input", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--files", "*Backyard-Worlds*", - "--profile", "adaptive", - "--gaussian-blur", "0.51", - "--interlace", "line", - }, - mandatory: helpers.BackyardWorldsPlanet9Scan01First6, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - file: "adaptive", - directory: "adaptive/TRASH", - }, - - inputs: helpers.BackyardWorldsPlanet9Scan01First6, + // === TRANSPARENT / PROFILE + // + Entry(nil, &pixaTE{ + given: "regex/transparent/profile/not-cuddled (๐ŸŽฏ @TID-CORE-1/2:_TBD__TR-PR-NC_TR)", + should: "transfer input to supplemented folder // input filename not modified", + relative: BackyardWorldsPlanet9Scan01, + reasons: reasons{ + folder: "transparency, result should take place of input in same folder", + file: "file should be moved out of the way and not cuddled", }, - }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "full run, profile", - should: "full run with regex filter using the defined profile", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--strip", - "--interlace", "plane", - "--quality", "85", - "--files-rx", "Backyard-Worlds", - "--profile", "adaptive", - }, - mandatory: helpers.BackyardWorldsPlanet9Scan01First6, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "adaptive/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01First6, + profile: "blur", + args: []string{ + "--files-rx", "Backyard-Worlds", + "--gaussian-blur", "0.51", + "--interlace", "line", }, - }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "full run transparent with scheme with single profile", - should: "full run with ex-glob filter, result file takes place of input", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--files", "*Backyard-Worlds*", - "--scheme", "singleton", - "--gaussian-blur", "0.51", - "--interlace", "line", - }, - mandatory: helpers.BackyardWorldsPlanet9Scan01First6, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "singleton/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01First6, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + file: "$TRASH$.blur", + folder: filepath.Join("$TRASH$", "blur"), }, - }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "full run non transparent adhoc", - should: "full run with ex-glob filter, input moved to alternative location", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--files", "*Backyard-Worlds*", - "--gaussian-blur", "0.51", - "--interlace", "line", + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + asserters: asserters{ + transfer: func(name string, entry *pixaTE, origin string, pa *pathAssertion, vfs storage.VirtualFS) { + assertTransferSupplementedOrigin(name, entry, origin, pa, vfs) }, - trashFlag: "discard", - mandatory: helpers.BackyardWorldsPlanet9Scan01First6, - intermediate: "discard", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "adaptive/TRASH", + result: func(name string, entry *pixaTE, origin string, pa *pathAssertion, vfs storage.VirtualFS) { + assertResultItemFile(name, entry, origin, pa) }, - inputs: helpers.BackyardWorldsPlanet9Scan01First6, }, }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "full run non transparent with profile", - should: "full run with ex-glob filter, input moved to alternative location", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--files", "*Backyard-Worlds*", - "--profile", "adaptive", - "--gaussian-blur", "0.51", - "--interlace", "line", - }, - trashFlag: "discard", - mandatory: helpers.BackyardWorldsPlanet9Scan01First6, - intermediate: "discard", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "adaptive/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01First6, + // + // === TRANSPARENT / ADHOC + // + Entry(nil, &pixaTE{ + given: "regex/transparent/adhoc/not-cuddled (๐ŸŽฏ @TID-CORE-9/10:_TBD__TR-AD-NC_SF_TR)", + should: "transfer input to supplemented folder // input filename not modified", + relative: BackyardWorldsPlanet9Scan01, + reasons: reasons{ + folder: "transparency, result should take place of input", + file: "file should be moved out of the way and result not cuddled", }, - }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "run non transparent scheme single with profile", - should: "full run with ex-glob filter, input moved to alternative location", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--files", "*Backyard-Worlds*", - "--scheme", "singleton", - "--gaussian-blur", "0.51", - "--interlace", "line", - }, - trashFlag: "discard", - mandatory: helpers.BackyardWorldsPlanet9Scan01First6, - intermediate: "discard", - supplements: supplements{ - file: "$SUPP/ADHOC.TRASH", - directory: "singleton/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01First6, + args: []string{ + "--files-rx", "Backyard-Worlds", + "--gaussian-blur", "0.51", + "--interlace", "line", }, - }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "full run, scheme", - should: "full run, all profiles in the scheme", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--files", "*Backyard-Worlds*", - "--strip", - "--interlace", "plane", - "--quality", "85", - "--scheme", "blur-sf", - }, - mandatory: helpers.BackyardWorldsPlanet9Scan01First6, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "blur-sf/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01First6, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + file: "$TRASH$.ADHOC", + folder: filepath.Join("$TRASH$", "ADHOC"), }, - }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "full run transparent adhoc and target already exists", - should: "full run with ex-glob filter, result file takes place of input", - exists: true, - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--files", "*Backyard-Worlds*", - "--gaussian-blur", "0.51", - "--interlace", "line", + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + asserters: asserters{ + transfer: func(name string, entry *pixaTE, origin string, pa *pathAssertion, vfs storage.VirtualFS) { + assertTransferSupplementedOrigin(name, entry, origin, pa, vfs) }, - mandatory: helpers.BackyardWorldsPlanet9Scan01First6, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "ADHOC/TRASH", + result: func(name string, entry *pixaTE, origin string, pa *pathAssertion, vfs storage.VirtualFS) { + assertResultItemFile(name, entry, origin, pa) }, - inputs: helpers.BackyardWorldsPlanet9Scan01First6, }, }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "directory contains files with same name different extensions", - should: "create journal file include file extension", - relative: BackyardWorldsPlanet9Scan02, - args: []string{ - "--files", "*Backyard-Worlds*", - "--gaussian-blur", "0.51", - "--interlace", "line", - }, - mandatory: helpers.BackyardWorldsPlanet9Scan02, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-02", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "ADHOC/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan02, + // + // TRANSPARENT --trash SPECIFIED + // + Entry(nil, &pixaTE{ + given: "regex/transparent/adhoc/not-cuddled (๐ŸŽฏ @TID-CORE-11/12:_TBD__TR-PR-TRA_TR)", + should: "transfer input to supplemented folder // input filename not modified", + relative: BackyardWorldsPlanet9Scan01, + reasons: reasons{ + folder: "transparency, result should take place of input", + file: "file should be moved out of the way to specified trash and result not cuddled", }, - }), - - // sample run - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "run transparent adhoc", - should: "sample(first) with ex-glob filter, result file takes place of input", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--sample", - "--no-files", "4", - "--files", "*Backyard-Worlds*", - "--gaussian-blur", "0.51", - "--interlace", "line", - }, - mandatory: helpers.BackyardWorldsPlanet9Scan01First4, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "ADHOC/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01First4, + arranger: func(entry *pixaTE, origin string, vfs storage.VirtualFS) { + p := filepath.Join(origin, entry.trash) + entry.trash = p + _ = vfs.MkdirAll(p, common.Permissions.Write.Perm()) }, - }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "run transparent with profile", - should: "sample(first) with ex-glob filter, result file takes place of input", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--sample", - "--no-files", "4", - "--files", "*Backyard-Worlds*", - "--profile", "adaptive", - "--gaussian-blur", "0.51", - "--interlace", "line", - }, - mandatory: helpers.BackyardWorldsPlanet9Scan01First4, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "adaptive/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01First4, + profile: "blur", + trash: "rubbish", + args: []string{ + "--files-rx", "Backyard-Worlds", + "--gaussian-blur", "0.51", + "--interlace", "line", }, - }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "run(last) transparent with profile", - should: "sample(last) with ex-glob filter using the defined profile", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--sample", - "--last", - "--no-files", "4", - "--files", "*Backyard-Worlds*", - "--profile", "adaptive", - "--gaussian-blur", "0.51", - "--interlace", "line", - }, - mandatory: helpers.BackyardWorldsPlanet9Scan01Last4, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "adaptive/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01Last4, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + file: "$TRASH$.ADHOC", + folder: filepath.Join("$TRASH$", "blur"), }, - }), + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + asserters: asserters{ + transfer: func(name string, entry *pixaTE, origin string, pa *pathAssertion, vfs storage.VirtualFS) { + folder := filing.SupplementFolder(entry.trash, + entry.supplements.folder, + ) - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "profile without no-files in args", - should: "sample(first) with ex-glob filter, using no-files from config", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--sample", - "--files", "*Backyard-Worlds*", - "--profile", "adaptive", - }, - mandatory: helpers.BackyardWorldsPlanet9Scan01First2, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "adaptive/TRASH", + assertTransfer(folder, pa, vfs) }, - inputs: helpers.BackyardWorldsPlanet9Scan01First2, + result: func(name string, entry *pixaTE, origin string, pa *pathAssertion, vfs storage.VirtualFS) {}, }, }), + // + // โŒ --output SPECIFIED, can't be TRANSPARENT as the output is being diverted + // elsewhere and by definition can't take the place of the input. + // - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "profile", - should: "sample with regex filter using the defined profile", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--sample", - "--no-files", "4", - "--strip", - "--interlace", "plane", - "--quality", "85", - "--files-rx", "Backyard-Worlds", - "--profile", "adaptive", - }, - mandatory: helpers.BackyardWorldsPlanet9Scan01First4, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "adaptive/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01First4, + // + // NON-TRANSPARENT --output SPECIFIED + // + Entry(nil, &pixaTE{ + given: "regex/not-transparent/profile/not-cuddled (๐ŸŽฏ @TID-CORE-15/16:_TBD__NTR-PR-NC-OUT_TR)", + should: "not transfer input // not modify input filename // re-direct result to output", + relative: BackyardWorldsPlanet9Scan01, + reasons: reasons{ + folder: "result should be re-directed, so input can stay in place", + file: "input file remains un modified", }, - }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "run transparent with scheme with single profile", - should: "sample(first) with ex-glob filter, result file takes place of input", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--sample", - "--no-files", "4", - "--files", "*Backyard-Worlds*", - "--scheme", "singleton", - "--gaussian-blur", "0.51", - "--interlace", "line", - }, - mandatory: helpers.BackyardWorldsPlanet9Scan01First4, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "singleton/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01First4, + arranger: func(entry *pixaTE, origin string, vfs storage.VirtualFS) { + _ = vfs.MkdirAll(entry.output, common.Permissions.Write.Perm()) }, - }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "run non transparent adhoc", - should: "sample(first) with ex-glob filter, input moved to alternative location", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--sample", - "--no-files", "4", - "--files", "*Backyard-Worlds*", - "--gaussian-blur", "0.51", - "--interlace", "line", - }, - trashFlag: "discard", - mandatory: helpers.BackyardWorldsPlanet9Scan01First4, - intermediate: "discard", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "ADHOC/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01First4, + profile: "blur", + output: filepath.Join("foo", "sessions", "scan01", "results"), + args: []string{ + "--files-rx", "Backyard-Worlds", + "--gaussian-blur", "0.51", + "--interlace", "line", }, - }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "run non transparent with profile", - should: "sample(first) with ex-glob filter, input moved to alternative location", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--sample", - "--no-files", "4", - "--files", "*Backyard-Worlds*", - "--profile", "adaptive", - "--gaussian-blur", "0.51", - "--interlace", "line", - }, - trashFlag: "discard", - mandatory: helpers.BackyardWorldsPlanet9Scan01First4, - intermediate: "discard", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "adaptive/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01First4, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + folder: "blur", }, - }), + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + asserters: asserters{ + transfer: func(name string, entry *pixaTE, origin string, pa *pathAssertion, vfs storage.VirtualFS) { + folder := filing.SupplementFolder(entry.output, + entry.supplements.folder, + ) - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "run non transparent scheme single with profile", - should: "sample(first) with ex-glob filter, input moved to alternative location", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--sample", - "--no-files", "4", - "--files", "*Backyard-Worlds*", - "--scheme", "singleton", - "--gaussian-blur", "0.51", - "--interlace", "line", - }, - trashFlag: "discard", - mandatory: helpers.BackyardWorldsPlanet9Scan01First4, - intermediate: "discard", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "singleton/TRASH", + assertTransfer(folder, pa, vfs) }, - inputs: helpers.BackyardWorldsPlanet9Scan01First4, + result: func(name string, entry *pixaTE, origin string, pa *pathAssertion, vfs storage.VirtualFS) {}, }, }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "scheme", - should: "sample all profiles in the scheme", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--sample", - "--no-files", "4", - "--files", "*Backyard-Worlds*", - "--strip", - "--interlace", "plane", - "--quality", "85", - "--scheme", "blur-sf", - }, - mandatory: helpers.BackyardWorldsPlanet9Scan01First6, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "blur-sf/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01First4, + // + // === NON-TRANSPARENT / SCHEME (non-cuddle) [BLUE] + // + Entry(nil, &pixaTE{ + given: "regex/not-transparent/scheme/output (๐ŸŽฏ @TID-CORE-17/18:_TBD__NTR-SC-NC-OUT_BLUR_TR)", + should: "not transfer input // not modify input filename // re-direct result to output", + relative: BackyardWorldsPlanet9Scan01, + reasons: reasons{ + folder: "result should be re-directed, so input can stay in place", + file: "input file remains un modified", }, - }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "run transparent adhoc and target already exists", - should: "sample(first) with ex-glob filter, result file takes place of input", - exists: true, - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--sample", - "--no-files", "4", - "--files", "*Backyard-Worlds*", - "--gaussian-blur", "0.51", - "--interlace", "line", - }, - mandatory: helpers.BackyardWorldsPlanet9Scan01First4, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "ADHOC/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01First4, + scheme: "blur-sf", + arranger: func(entry *pixaTE, origin string, vfs storage.VirtualFS) { + _ = vfs.MkdirAll(entry.output, common.Permissions.Write.Perm()) }, - }), - - // dry run - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "full dry run transparent adhoc, using glob", - should: "full run with ex-glob filter, without moving input", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--files", "*Backyard-Worlds*", - "--gaussian-blur", "0.51", - "--interlace", "line", - }, - dry: true, - // mandatory: helpers.BackyardWorldsPlanet9Scan01First6, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "ADHOC/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01First6, + output: filepath.Join("foo", "sessions", "scan01", "results"), + args: []string{ + "--files-rx", "Backyard-Worlds", + "--gaussian-blur", "0.51", + "--interlace", "line", }, - }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "full dry run transparent adhoc, using regex", - should: "full run with regex filter, without moving input", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--files-rx", "Backyard-Worlds", - "--gaussian-blur", "0.51", - "--interlace", "line", - }, - dry: true, - // mandatory: helpers.BackyardWorldsPlanet9Scan01First6, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "ADHOC/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01First6, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + folder: "blur-sf", // !! +blue/sf }, - }), - - Entry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "full dry run transparent with profile, using glob", - should: "full run with ex-glob filter, without moving input", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--files", "*Backyard-Worlds*", - "--profile", "adaptive", - "--gaussian-blur", "0.51", - "--interlace", "line", + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + asserters: asserters{ + // transfer: not transparent; no transfer is invoked + result: func(name string, entry *pixaTE, origin string, pa *pathAssertion, vfs storage.VirtualFS) { + assertResultItemFile(name, entry, origin, pa) }, - dry: true, - // mandatory: helpers.BackyardWorldsPlanet9Scan01First6, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "adaptive/TRASH", - }, - inputs: helpers.BackyardWorldsPlanet9Scan01First6, }, }), - - // textual-ui - // https://dev.to/pomdtr/how-to-debug-bubble-tea-applications-in-visual-studio-code-50jp - // - // full run // - // ๐Ÿ“š debugging bubbletea - // !! use the predefined "Attach to dlv" launch task. It requires the task - // defined as "Run headless dlv". This starts the dlv debugger in headless mode. - // Note that because the args are hardcoded into the dlv task, if you need to - // debug pixa with different args, then the dlv task needs to be modified. + // === NON-TRANSPARENT / ADHOC // - // to attach to dlv debugger manually, start dlv like this: - // dlv debug --headless --listen=:2345 ./src/app/main/ -- shrink /Users/plastikfan/dev/test --profile blur --files "wonky*" --dry-run - // the args come after -- - // the launch.json does not support args for an attach request, args are only - // appropriate for launch - // - // Beware, if you start dlv manually, you will need to define a new launch entry - // that does not depend on the "Run headless dlv" as that attempts to start dlv - // automatically. - // - XEntry(nil, &samplerTE{ - controllerTE: controllerTE{ - given: "bubbletea tui, full run transparent adhoc, with ex-glob", - should: "full run with ex-glob filter, result file takes place of input", - relative: BackyardWorldsPlanet9Scan01, - args: []string{ - "--files", "*Backyard-Worlds*", - "--gaussian-blur", "0.51", - "--interlace", "line", - }, - isTui: true, - mandatory: helpers.BackyardWorldsPlanet9Scan01First6, - intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", - supplements: supplements{ - // file: "$SUPP/ADHOC.TRASH", - directory: "ADHOC/TRASH", + Entry(nil, &pixaTE{ + given: "regex/not-transparent/adhoc/output (๐ŸŽฏ @TID-CORE-19/20:_TBD__NTR-AD-OUT_SF_TR)", + should: "not transfer input // not modify input filename // re-direct result to output", + relative: BackyardWorldsPlanet9Scan01, + reasons: reasons{ + folder: "result should be re-directed, so input can stay in place", + file: "input file remains un modified", + }, + arranger: func(entry *pixaTE, origin string, vfs storage.VirtualFS) { + _ = vfs.MkdirAll(entry.output, common.Permissions.Write.Perm()) + }, + output: filepath.Join("foo", "sessions", "scan01", "results"), + args: []string{ + "--files-rx", "Backyard-Worlds", + "--gaussian-blur", "0.51", + "--interlace", "line", + }, + intermediate: "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01", + supplements: supplements{ + folder: "ADHOC", + }, + inputs: helpers.BackyardWorldsPlanet9Scan01First6, + asserters: asserters{ + // transfer: not transparent; no transfer is invoked + result: func(name string, entry *pixaTE, origin string, pa *pathAssertion, vfs storage.VirtualFS) { + assertResultItemFile(name, entry, origin, pa) }, - inputs: helpers.BackyardWorldsPlanet9Scan01First6, }, }), ) }) - -var _ = Describe("end to end", Ordered, func() { - Context("REAL", func() { - XIt("should: tinkle the ivories", func() { - // pixa shrink ~/dev/test/pics --profile blur --sample --no-files 1 --files "screen*" --dry-run - args := []string{ - "shrink", - "/Users/plastikfan/dev/test/pics", - "--profile", "blur", - // "--sample", - // "--no-files", "1", - "--files", "wonky*", - "--dry-run", - } - configPath := utils.ResolvePath("~/snivilised/pixa") - bootstrap := command.Bootstrap{ - Vfs: storage.UseNativeFS(), - } - tester := helpers.CommandTester{ - Args: args, - Root: bootstrap.Root(func(co *command.ConfigureOptionsInfo) { - co.Detector = &helpers.DetectorStub{} - co.Config.Name = common.Definitions.Pixa.AppName - co.Config.ConfigPath = configPath - }), - } - - _, err := tester.Execute() - Expect(err).Error().To(BeNil(), - fmt.Sprintf("execution result non nil (%v)", err), - ) - }) - }) -}) diff --git a/src/app/proxy/user/interaction.go b/src/app/proxy/user/interaction.go index 08fca23..34ad419 100644 --- a/src/app/proxy/user/interaction.go +++ b/src/app/proxy/user/interaction.go @@ -19,8 +19,15 @@ const ( var ( navigatorRoutineName = boost.GoRoutineName("โœจ pixa-navigator") + emojis = []rune( + "๐Ÿฆ๐Ÿง‹๐Ÿก๐Ÿค ๐Ÿ‘พ๐Ÿ˜ญ๐ŸฆŠ๐Ÿฏ๐Ÿฆ†๐Ÿ‘ฝ๐Ÿ‘ป๐Ÿ”๐Ÿ’๐Ÿฅ๐Ÿ˜ˆ๐Ÿคฎ๐Ÿฆ๐Ÿฐ๐Ÿถ๐Ÿธ๐Ÿ•๐Ÿฅ๐Ÿ’€๐Ÿ’ฉ๐Ÿฅ‡๐Ÿซ๐Ÿ†๐Ÿค–๐ŸŒฝ๐Ÿ‰๐Ÿฅ๐Ÿ“", + ) ) +func randemoji() string { + return string(emojis[rand.Intn(len(emojis))]) //nolint:gosec // foo +} + type walker interface { navigate(ci common.ClientTraverseInfo, with nav.CreateNewRunnerWith, @@ -31,12 +38,9 @@ type walker interface { type interaction struct { inputs *common.ShrinkCommandInputs logger *slog.Logger + arity uint } -var emojis = []rune( - "๐Ÿฆ๐Ÿง‹๐Ÿก๐Ÿค ๐Ÿ‘พ๐Ÿ˜ญ๐ŸฆŠ๐Ÿฏ๐Ÿฆ†๐Ÿ‘ฝ๐Ÿ‘ป๐Ÿ”๐Ÿ’๐Ÿฅ๐Ÿ˜ˆ๐Ÿคฎ๐Ÿฆ๐Ÿฐ๐Ÿถ๐Ÿธ๐Ÿ•๐Ÿฅ๐Ÿ’€๐Ÿ’ฉ๐Ÿฅ‡๐Ÿซ๐Ÿ†๐Ÿค–๐ŸŒฝ๐Ÿ‰๐Ÿฅ๐Ÿ“", -) - func (u *interaction) navigate(ci common.ClientTraverseInfo, with nav.CreateNewRunnerWith, after ...common.AfterFunc, @@ -72,10 +76,6 @@ func (u *interaction) navigate(ci common.ClientTraverseInfo, return result, err } -func randemoji() string { - return string(emojis[rand.Intn(len(emojis))]) //nolint:gosec // foo -} - func summary(result *nav.TraverseResult, err error) string { measure := fmt.Sprintf("started: '%v', elapsed: '%v'", result.Session.StartedAt().Format(time.RFC1123), result.Session.Elapsed(), @@ -92,7 +92,7 @@ func summary(result *nav.TraverseResult, err error) string { } func NewInteraction(inputs *common.ShrinkCommandInputs, - logger *slog.Logger, + logger *slog.Logger, arity uint, ) common.UserInteraction { return lo.TernaryF(inputs.Root.TextualFam.Native.IsNoTui, func() common.UserInteraction { @@ -100,6 +100,7 @@ func NewInteraction(inputs *common.ShrinkCommandInputs, interaction: interaction{ inputs: inputs, logger: logger, + arity: arity, }, } }, @@ -108,6 +109,7 @@ func NewInteraction(inputs *common.ShrinkCommandInputs, interaction: interaction{ inputs: inputs, logger: logger, + arity: arity, }, po: inputs.Root.Presentation, } diff --git a/src/app/proxy/user/model.go b/src/app/proxy/user/model.go index 4f138c5..7d16f2a 100644 --- a/src/app/proxy/user/model.go +++ b/src/app/proxy/user/model.go @@ -33,6 +33,7 @@ type model struct { executable string status string workload uint + arity uint level uint latest JobDescription di common.DriverTraverseInfo @@ -104,7 +105,7 @@ func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.result = msg.Result m.err = msg.Err m.status = "๐ŸŽญ discovered" - m.workload = msg.Result.Metrics.Count(nav.MetricNoFilesInvokedEn) + m.workload = msg.Result.Metrics.Count(nav.MetricNoFilesInvokedEn) * m.arity if msg.Err != nil { return m, tea.Quit diff --git a/src/app/proxy/user/ui-textual.go b/src/app/proxy/user/ui-textual.go index cd832ef..dc035c3 100644 --- a/src/app/proxy/user/ui-textual.go +++ b/src/app/proxy/user/ui-textual.go @@ -36,6 +36,7 @@ func (ui *textualUI) Traverse(di common.DriverTraverseInfo, inputs: ui.inputs, executable: ui.inputs.Root.Configs.Advanced.Executable().Symbol(), status: "๐Ÿ”Ž discovering ...", + arity: ui.arity, latest: JobDescription{ Source: "waiting ...", Destination: "waiting ...", @@ -56,7 +57,7 @@ func (ui *textualUI) Traverse(di common.DriverTraverseInfo, options := []tea.ProgramOption{} if ui.po.WithoutRenderer { - options = append(options, tea.WithoutRenderer()) + options = []tea.ProgramOption{tea.WithoutRenderer()} } ui.m.program = tea.NewProgram(ui.m, options...) diff --git a/test/data/configuration/pixa-test.yml b/test/data/configuration/pixa-test.yml index 03b7825..6fbf1a8 100644 --- a/test/data/configuration/pixa-test.yml +++ b/test/data/configuration/pixa-test.yml @@ -24,7 +24,7 @@ interaction: tui: per-item-delay: "1ms" advanced: - abort-on-error: false + abort-on-error: true overwrite-on-collision: false labels: adhoc: ADHOC @@ -37,7 +37,6 @@ advanced: suffixes-csv: "jpg,jpeg,png" transforms-csv: lower map: - jpeg: jpg executable: program-name: dummy timeout: "20s"