From 5c34c0edf09441ba500260ff6a4e097a71a8822c Mon Sep 17 00:00:00 2001 From: Aiden <12055114+aidenwallis@users.noreply.github.com> Date: Fri, 26 May 2023 08:51:44 +0100 Subject: [PATCH] add `factory.ChainableModifier` --- factory/chainable_modifier.go | 33 ++++++++++++++++++++++++++++++ factory/chainable_modifier_test.go | 30 +++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 factory/chainable_modifier.go create mode 100644 factory/chainable_modifier_test.go diff --git a/factory/chainable_modifier.go b/factory/chainable_modifier.go new file mode 100644 index 0000000..7b5d48f --- /dev/null +++ b/factory/chainable_modifier.go @@ -0,0 +1,33 @@ +package factory + +// ChainableModifier creates a factory that produces an initial value from initFactory, then lets you change modifiers to modify that value. +// You're then returned the value once all modifiers have ran over it. This can be particularly useful when building mock data in tests. +// +// func example() { +// chain := ChainableModifier(func() *pb.MyRequest { +// return &pb.MyRequest{Foo: true, Bar: false} +// }) +// +// firstRequest := chain() // returns &pb.MyRequest{Foo: true, Bar: false} +// +// secondRequestWithBarTrue := chain(func(v *pb.MyRequest) { +// v.Bar = true +// }) // returns &pb.MyRequest{Foo: true, Bar: true} +// +// thirdRequestWithValuesSwapped := chain(func(v *pb.MyRequest) { +// v.Foo = false +// }, func(v *pb.MyRequest) { +// v.Bar = true +// }) // returns &pb.MyRequest{Foo: false, Bar: true} +// } +func ChainableModifier[T any](initFactory func() T) func(modifiers ...func(T)) T { + return func(modifiers ...func(T)) T { + out := initFactory() + + for _, fn := range modifiers { + fn(out) + } + + return out + } +} diff --git a/factory/chainable_modifier_test.go b/factory/chainable_modifier_test.go new file mode 100644 index 0000000..b29c951 --- /dev/null +++ b/factory/chainable_modifier_test.go @@ -0,0 +1,30 @@ +package factory_test + +import ( + "testing" + + "github.com/aidenwallis/go-utils/factory" + "github.com/aidenwallis/go-utils/internal/assert" +) + +func TestChainableModifier(t *testing.T) { + t.Parallel() + + type testValue struct { + Foo bool + Bar bool + } + + chain := factory.ChainableModifier(func() *testValue { + return &testValue{ + Foo: true, + Bar: false, + } + }) + + out := chain(func(v *testValue) { + v.Foo = false + }) + assert.False(t, out.Foo) + assert.False(t, out.Bar) +}