Skip to content

Commit

Permalink
Report impossible assertions based on predicate argument types.
Browse files Browse the repository at this point in the history
  • Loading branch information
jmalloc committed Sep 24, 2024
1 parent 827c0ef commit 78518c6
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 32 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ The format is based on [Keep a Changelog], and this project adheres to

- Fixed issue that caused an empty `SUGGESTIONS` section to be printed on test
reports in some circumstances.
- `ToExecuteCommandMatching()`, `ToOnlyExecuteCommandsMatching()`,
`ToRecordEventMatching()` and `ToOnlyRecordEventsMatching()` now properly
report impossible assertions when the predicate's argument type is not a
recognized message.

## [0.17.0] - 2024-08-21

Expand Down
5 changes: 0 additions & 5 deletions expectation.message.command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ var _ = g.Describe("func ToExecuteCommand()", func() {
ConfigureFunc: func(c dogma.ApplicationConfigurer) {
c.Identity("<app>", "ce773269-4ad7-4c7f-a0ff-cda2e5899743")

// Register a process that will execute the commands about which
// we will make assertions using ToExecuteCommand().
c.RegisterProcess(&ProcessMessageHandlerStub{
ConfigureFunc: func(c dogma.ProcessConfigurer) {
c.Identity("<process>", "8b4c4701-be92-4b28-83b6-0d69b97fb451")
Expand Down Expand Up @@ -90,9 +88,6 @@ var _ = g.Describe("func ToExecuteCommand()", func() {
},
})

// Register an integration so that we can test what happens when
// we expect execution of a command that is never executed by
// any handler (only consumed).
c.RegisterIntegration(&IntegrationMessageHandlerStub{
ConfigureFunc: func(c dogma.IntegrationConfigurer) {
c.Identity("<integration>", "49fa7c5f-7682-4743-bf8a-ed96dee2d81a")
Expand Down
83 changes: 72 additions & 11 deletions expectation.messagematch.command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ var _ = g.Describe("func ToExecuteCommandMatching()", func() {

CommandThatIsExecuted = CommandStub[TypeC]
CommandThatIsNeverExecuted = CommandStub[TypeX]
CommandThatIsOnlyConsumed = CommandStub[TypeO]

TimeoutThatIsScheduled = TimeoutStub[TypeT]
)
Expand Down Expand Up @@ -97,6 +98,15 @@ var _ = g.Describe("func ToExecuteCommandMatching()", func() {
return nil
},
})

c.RegisterIntegration(&IntegrationMessageHandlerStub{
ConfigureFunc: func(c dogma.IntegrationConfigurer) {
c.Identity("<integration>", "7cf5a7fe-9f69-46be-8c59-cc12c4825aaf")
c.Routes(
dogma.HandlesCommand[CommandThatIsOnlyConsumed](),
)
},
})
},
}
})
Expand Down Expand Up @@ -129,7 +139,7 @@ var _ = g.Describe("func ToExecuteCommandMatching()", func() {
),
expectPass,
expectReport(
`✓ execute a command that matches the predicate near expectation.messagematch.command_test.go:122`,
`✓ execute a command that matches the predicate near expectation.messagematch.command_test.go:132`,
),
),
g.Entry(
Expand All @@ -146,7 +156,7 @@ var _ = g.Describe("func ToExecuteCommandMatching()", func() {
),
expectPass,
expectReport(
`✓ execute a command that matches the predicate near expectation.messagematch.command_test.go:139`,
`✓ execute a command that matches the predicate near expectation.messagematch.command_test.go:149`,
),
),
g.Entry(
Expand All @@ -159,7 +169,7 @@ var _ = g.Describe("func ToExecuteCommandMatching()", func() {
),
expectFail,
expectReport(
`✗ execute a command that matches the predicate near expectation.messagematch.command_test.go:156`,
`✗ execute a command that matches the predicate near expectation.messagematch.command_test.go:166`,
``,
` | EXPLANATION`,
` | none of the engaged handlers executed a matching command`,
Expand All @@ -182,7 +192,7 @@ var _ = g.Describe("func ToExecuteCommandMatching()", func() {
),
expectFail,
expectReport(
`✗ execute a command that matches the predicate near expectation.messagematch.command_test.go:179`,
`✗ execute a command that matches the predicate near expectation.messagematch.command_test.go:189`,
``,
` | EXPLANATION`,
` | none of the engaged handlers executed a matching command`,
Expand All @@ -201,7 +211,7 @@ var _ = g.Describe("func ToExecuteCommandMatching()", func() {
),
expectFail,
expectReport(
`✗ execute a command that matches the predicate near expectation.messagematch.command_test.go:198`,
`✗ execute a command that matches the predicate near expectation.messagematch.command_test.go:208`,
``,
` | EXPLANATION`,
` | no messages were produced at all`,
Expand All @@ -220,7 +230,7 @@ var _ = g.Describe("func ToExecuteCommandMatching()", func() {
),
expectFail,
expectReport(
`✗ execute a command that matches the predicate near expectation.messagematch.command_test.go:217`,
`✗ execute a command that matches the predicate near expectation.messagematch.command_test.go:227`,
``,
` | EXPLANATION`,
` | no commands were executed at all`,
Expand All @@ -239,7 +249,7 @@ var _ = g.Describe("func ToExecuteCommandMatching()", func() {
),
expectFail,
expectReport(
`✗ execute a command that matches the predicate near expectation.messagematch.command_test.go:236`,
`✗ execute a command that matches the predicate near expectation.messagematch.command_test.go:246`,
``,
` | EXPLANATION`,
` | no relevant handler types were enabled`,
Expand All @@ -261,7 +271,7 @@ var _ = g.Describe("func ToExecuteCommandMatching()", func() {
),
expectFail,
expectReport(
`✗ execute a command that matches the predicate near expectation.messagematch.command_test.go:258`,
`✗ execute a command that matches the predicate near expectation.messagematch.command_test.go:268`,
``,
` | EXPLANATION`,
` | none of the engaged handlers executed a matching command`,
Expand All @@ -283,7 +293,7 @@ var _ = g.Describe("func ToExecuteCommandMatching()", func() {
),
expectFail,
expectReport(
`✗ execute a command that matches the predicate near expectation.messagematch.command_test.go:280`,
`✗ execute a command that matches the predicate near expectation.messagematch.command_test.go:290`,
``,
` | EXPLANATION`,
` | none of the engaged handlers executed a matching command`,
Expand Down Expand Up @@ -314,12 +324,63 @@ var _ = g.Describe("func ToExecuteCommandMatching()", func() {
expectFail,
expectReport(
`✗ none of (1 of the expectations passed unexpectedly)`,
` ✓ execute a command that matches the predicate near expectation.messagematch.command_test.go:305`,
` ✗ execute a command that matches the predicate near expectation.messagematch.command_test.go:309`,
` ✓ execute a command that matches the predicate near expectation.messagematch.command_test.go:315`,
` ✗ execute a command that matches the predicate near expectation.messagematch.command_test.go:319`,
),
),
)

g.It("fails the test if the message type is unrecognized", func() {
test := Begin(testingT, app)
test.Expect(
noop,
ToExecuteCommandMatching(
func(CommandStub[TypeU]) error {
return nil
},
),
)

Expect(testingT.Failed()).To(BeTrue())
Expect(testingT.Logs).To(ContainElement(
"a command of type stubs.CommandStub[TypeU] can never be executed, the application does not use this message type",
))
})

g.It("fails the test if the message type is not a command", func() {
test := Begin(testingT, app)
test.Expect(
noop,
ToExecuteCommandMatching(
func(EventThatExecutesCommand) error {
return nil
},
),
)

Expect(testingT.Failed()).To(BeTrue())
Expect(testingT.Logs).To(ContainElement(
"stubs.EventStub[TypeC] is an event, it can never be executed as a command",
))
})

g.It("fails the test if the message type is not produced by any handlers", func() {
test := Begin(testingT, app)
test.Expect(
noop,
ToExecuteCommandMatching(
func(CommandThatIsOnlyConsumed) error {
return nil
},
),
)

Expect(testingT.Failed()).To(BeTrue())
Expect(testingT.Logs).To(ContainElement(
"no handlers execute commands of type stubs.CommandStub[TypeO], it is only ever consumed",
))
})

g.It("panics if the function is nil", func() {
Expect(func() {
var fn func(dogma.Command) error
Expand Down
80 changes: 72 additions & 8 deletions expectation.messagematch.commandonly_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ var _ = g.Describe("func ToOnlyExecuteCommandsMatching()", func() {

type (
EventThatExecutesCommands = EventStub[TypeC]
CommandThatIsExecuted = CommandStub[TypeC]

CommandThatIsExecuted = CommandStub[TypeC]
CommandThatIsNeverExecuted = CommandStub[TypeX]
CommandThatIsOnlyConsumed = CommandStub[TypeO]
)

g.BeforeEach(func() {
Expand All @@ -38,6 +41,7 @@ var _ = g.Describe("func ToOnlyExecuteCommandsMatching()", func() {
c.Routes(
dogma.HandlesEvent[EventThatExecutesCommands](),
dogma.ExecutesCommand[CommandThatIsExecuted](),
dogma.ExecutesCommand[CommandThatIsNeverExecuted](),
)
},
RouteEventToInstanceFunc: func(
Expand All @@ -58,6 +62,15 @@ var _ = g.Describe("func ToOnlyExecuteCommandsMatching()", func() {
return nil
},
})

c.RegisterIntegration(&IntegrationMessageHandlerStub{
ConfigureFunc: func(c dogma.IntegrationConfigurer) {
c.Identity("<integration>", "20bf2831-1887-4148-9539-eb7c294e80b6")
c.Routes(
dogma.HandlesCommand[CommandThatIsOnlyConsumed](),
)
},
})
},
}
})
Expand Down Expand Up @@ -86,7 +99,7 @@ var _ = g.Describe("func ToOnlyExecuteCommandsMatching()", func() {
),
expectPass,
expectReport(
`✓ only execute commands that match the predicate near expectation.messagematch.commandonly_test.go:84`,
`✓ only execute commands that match the predicate near expectation.messagematch.commandonly_test.go:97`,
),
),
g.Entry(
Expand All @@ -99,7 +112,7 @@ var _ = g.Describe("func ToOnlyExecuteCommandsMatching()", func() {
),
expectPass,
expectReport(
`✓ only execute commands that match the predicate near expectation.messagematch.commandonly_test.go:97`,
`✓ only execute commands that match the predicate near expectation.messagematch.commandonly_test.go:110`,
),
),
g.Entry(
Expand All @@ -112,7 +125,7 @@ var _ = g.Describe("func ToOnlyExecuteCommandsMatching()", func() {
),
expectPass,
expectReport(
`✓ only execute commands that match the predicate near expectation.messagematch.commandonly_test.go:109`,
`✓ only execute commands that match the predicate near expectation.messagematch.commandonly_test.go:122`,
),
),
g.Entry(
Expand All @@ -125,7 +138,7 @@ var _ = g.Describe("func ToOnlyExecuteCommandsMatching()", func() {
),
expectFail,
expectReport(
`✗ only execute commands that match the predicate near expectation.messagematch.commandonly_test.go:122`,
`✗ only execute commands that match the predicate near expectation.messagematch.commandonly_test.go:135`,
``,
` | EXPLANATION`,
` | none of the 3 relevant commands matched the predicate`,
Expand Down Expand Up @@ -155,7 +168,7 @@ var _ = g.Describe("func ToOnlyExecuteCommandsMatching()", func() {
),
expectFail,
expectReport(
`✗ only execute commands that match the predicate near expectation.messagematch.commandonly_test.go:145`,
`✗ only execute commands that match the predicate near expectation.messagematch.commandonly_test.go:158`,
``,
` | EXPLANATION`,
` | only 1 of 2 relevant commands matched the predicate`,
Expand All @@ -172,13 +185,13 @@ var _ = g.Describe("func ToOnlyExecuteCommandsMatching()", func() {
"no executed commands match, using predicate with a more specific type",
RecordEvent(EventThatExecutesCommands{}),
ToOnlyExecuteCommandsMatching(
func(m CommandStub[TypeX]) error {
func(m CommandThatIsNeverExecuted) error {
panic("unexpected call")
},
),
expectFail,
expectReport(
`✗ only execute commands that match the predicate near expectation.messagematch.commandonly_test.go:175`,
`✗ only execute commands that match the predicate near expectation.messagematch.commandonly_test.go:188`,
``,
` | EXPLANATION`,
` | none of the 3 relevant commands matched the predicate`,
Expand All @@ -193,6 +206,57 @@ var _ = g.Describe("func ToOnlyExecuteCommandsMatching()", func() {
),
)

g.It("fails the test if the message type is unrecognized", func() {
test := Begin(testingT, app)
test.Expect(
noop,
ToOnlyExecuteCommandsMatching(
func(CommandStub[TypeU]) error {
return nil
},
),
)

Expect(testingT.Failed()).To(BeTrue())
Expect(testingT.Logs).To(ContainElement(
"a command of type stubs.CommandStub[TypeU] can never be executed, the application does not use this message type",
))
})

g.It("fails the test if the message type is not a command", func() {
test := Begin(testingT, app)
test.Expect(
noop,
ToOnlyExecuteCommandsMatching(
func(EventThatExecutesCommands) error {
return nil
},
),
)

Expect(testingT.Failed()).To(BeTrue())
Expect(testingT.Logs).To(ContainElement(
"stubs.EventStub[TypeC] is an event, it can never be executed as a command",
))
})

g.It("fails the test if the message type is not produced by any handlers", func() {
test := Begin(testingT, app)
test.Expect(
noop,
ToOnlyExecuteCommandsMatching(
func(CommandThatIsOnlyConsumed) error {
return nil
},
),
)

Expect(testingT.Failed()).To(BeTrue())
Expect(testingT.Logs).To(ContainElement(
"no handlers execute commands of type stubs.CommandStub[TypeO], it is only ever consumed",
))
})

g.It("panics if the function is nil", func() {
Expect(func() {
var fn func(dogma.Command) error
Expand Down
Loading

0 comments on commit 78518c6

Please sign in to comment.