Skip to content

Commit

Permalink
feat(aggregate.go): add Comparable interface and TransitionWithEqual …
Browse files Browse the repository at this point in the history
…function for custom event data comparison

refactor(aggregate.go): modify TransitionTest struct and related functions to use custom isEqual function for event data comparison
test(aggregate_test.go): add tests for new TransitionWithEqual function and Comparable interface usage
  • Loading branch information
bounoable committed Sep 20, 2023
1 parent 1126952 commit a2d22e4
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 7 deletions.
45 changes: 38 additions & 7 deletions exp/gtest/aggregate.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,13 @@ func (test *ConstructorTest[A]) Run(t *testing.T) {
// to a specific event with the specified data. It can be used to ensure that an
// aggregate properly handles its internal state changes and produces the
// correct events with the expected data.
type TransitionTest[EventData comparable] struct {
type TransitionTest[EventData any] struct {
transitionTestConfig

Event string
Data EventData

isEqual func(EventData, EventData) bool
}

type transitionTestConfig struct {
Expand Down Expand Up @@ -106,9 +108,33 @@ func Once() TransitionTestOption {
// event with the provided data when running the Run method on a *testing.T
// instance.
func Transition[EventData comparable](event string, data EventData, opts ...TransitionTestOption) *TransitionTest[EventData] {
return newTransitionTest(event, data, func(a, b EventData) bool { return a == b }, opts...)
}

// Comparable is an interface that provides a method for comparing two instances
// of the same type. The Equal method should return true if the two instances
// are considered equivalent, and false otherwise.
type Comparable[T any] interface {
Equal(T) bool
}

// TransitionWithEqual creates a new TransitionTest with the specified event
// name and data, using the Equal method of the Comparable interface to compare
// event data. It is used for testing if an aggregate transitions to the
// specified event with the provided data, when running the Run method on a
// [*testing.T] instance. The comparison of event data is based on the Equal
// method, which should be implemented by the provided EventData type.
// TransitionTestOptions can be provided to customize the behavior of the
// TransitionTest.
func TransitionWithEqual[EventData Comparable[EventData]](event string, data EventData, opts ...TransitionTestOption) *TransitionTest[EventData] {
return newTransitionTest(event, data, func(a, b EventData) bool { return a.Equal(b) }, opts...)
}

func newTransitionTest[EventData any](event string, data EventData, isEqual func(EventData, EventData) bool, opts ...TransitionTestOption) *TransitionTest[EventData] {
test := TransitionTest[EventData]{
Event: event,
Data: data,
Event: event,
Data: data,
isEqual: isEqual,
}

for _, opt := range opts {
Expand Down Expand Up @@ -163,11 +189,16 @@ func (test *TransitionTest[EventData]) testEquality(evt event.Event) error {
return fmt.Errorf("event name %q does not match expected event name %q", evt.Name(), test.Event)
}

cevt, ok := event.TryCast[EventData](evt)
if !ok {
return fmt.Errorf("event %q is not of type %T but of type %T", evt.Name(), test.Data, evt.Data())
}

var zero EventData
if test.Data != zero {
data := evt.Data()
if test.Data != data {
return fmt.Errorf("event data %T does not match expected event data %T\n%s", evt.Data(), test.Data, cmp.Diff(test.Data, data))
if !test.isEqual(test.Data, zero) {
data := cevt.Data()
if !test.isEqual(test.Data, data) {
return fmt.Errorf("event data %T does not match expected event data %T\n%s", data, test.Data, cmp.Diff(test.Data, data))
}
}

Expand Down
46 changes: 46 additions & 0 deletions exp/gtest/aggregate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package gtest_test

import (
"slices"
"testing"

"github.com/google/uuid"
"github.com/modernice/goes/aggregate"
"github.com/modernice/goes/exp/gtest"
)

func TestTransition(t *testing.T) {
type data struct {
Foo string
Bar int
}

foo := aggregate.New("foo", uuid.New())

d := data{Foo: "foo", Bar: 42}
aggregate.Next(foo, "foo", d)

gtest.Transition("foo", d).Run(t, foo)
}

type comparableData struct {
Foo string
Bar int
Baz []bool
}

// Equal checks if two instances of comparableData are equivalent by comparing
// their Foo, Bar, and Baz fields. It returns true if all corresponding fields
// between the two instances are equal, false otherwise.
func (d comparableData) Equal(d2 comparableData) bool {
return d.Foo == d2.Foo && d.Bar == d2.Bar && slices.Equal(d.Baz, d2.Baz)
}

func TestTransitionWithEqual(t *testing.T) {
foo := aggregate.New("foo", uuid.New())

d := comparableData{Foo: "foo", Bar: 42, Baz: []bool{true, false}}
aggregate.Next(foo, "foo", d)

gtest.TransitionWithEqual("foo", d).Run(t, foo)
}

0 comments on commit a2d22e4

Please sign in to comment.