ruby_event_store-rspec 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/ruby_event_store/rspec.rb +26 -8
- data/lib/ruby_event_store/rspec/apply.rb +32 -46
- data/lib/ruby_event_store/rspec/be_event.rb +15 -13
- data/lib/ruby_event_store/rspec/crude_failure_message_formatter.rb +130 -0
- data/lib/ruby_event_store/rspec/expected_collection.rb +43 -0
- data/lib/ruby_event_store/rspec/fetch_events.rb +33 -0
- data/lib/ruby_event_store/rspec/fetch_unpublished_events.rb +19 -0
- data/lib/ruby_event_store/rspec/have_applied.rb +15 -22
- data/lib/ruby_event_store/rspec/have_published.rb +28 -24
- data/lib/ruby_event_store/rspec/have_subscribed_to_events.rb +2 -2
- data/lib/ruby_event_store/rspec/match_events.rb +32 -0
- data/lib/ruby_event_store/rspec/matchers.rb +5 -5
- data/lib/ruby_event_store/rspec/publish.rb +47 -48
- data/lib/ruby_event_store/rspec/step_by_step_failure_message_formatter.rb +218 -0
- data/lib/ruby_event_store/rspec/version.rb +1 -1
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2824fc38cdb13ea93b60cc332617ae107281ca075102897cf3b3627b5455bd07
|
4
|
+
data.tar.gz: 2ad9ac851fb63a5707d679679a86aa294bc80754c054d4b1210005212cb395d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6756a69b71fb2c42cb484988a85f365134026f7fc8a4f9dde87cbac934d9190234a2788790fb89a6f9588e4b3ff9aa4b799ca893524c8614482aa76ec592dc5c
|
7
|
+
data.tar.gz: 5f9c80aff6dffe7c16ec7da698e7f1d84af2554121d51b0bcefae0ff113fc785cf97162d811441a7e29ba375ad4fee208c263c2ba9ac6b8c56d5711189f896cd
|
@@ -8,14 +8,32 @@ module RubyEventStore
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
11
|
+
require_relative "rspec/version"
|
12
|
+
require_relative "rspec/be_event"
|
13
|
+
require_relative "rspec/expected_collection"
|
14
|
+
require_relative "rspec/fetch_events"
|
15
|
+
require_relative "rspec/fetch_unpublished_events"
|
16
|
+
require_relative "rspec/match_events"
|
17
|
+
require_relative "rspec/have_published"
|
18
|
+
require_relative "rspec/have_applied"
|
19
|
+
require_relative "rspec/have_subscribed_to_events"
|
20
|
+
require_relative "rspec/publish"
|
21
|
+
require_relative "rspec/apply"
|
22
|
+
require_relative "rspec/crude_failure_message_formatter"
|
23
|
+
require_relative "rspec/step_by_step_failure_message_formatter"
|
24
|
+
require_relative "rspec/matchers"
|
25
|
+
|
26
|
+
module RubyEventStore
|
27
|
+
module RSpec
|
28
|
+
def self.default_formatter=(new_formatter)
|
29
|
+
@@default_formatter = new_formatter
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.default_formatter
|
33
|
+
@@default_formatter ||= CrudeFailureMessageFormatter.new
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
19
37
|
|
20
38
|
::RSpec.configure do |config|
|
21
39
|
config.include ::RubyEventStore::RSpec::Matchers
|
@@ -3,58 +3,51 @@
|
|
3
3
|
module RubyEventStore
|
4
4
|
module RSpec
|
5
5
|
class Apply
|
6
|
+
def initialize(*expected, failure_message_formatter:)
|
7
|
+
@expected = ExpectedCollection.new(expected)
|
8
|
+
@failure_message_formatter = failure_message_formatter
|
9
|
+
@fetch_events = FetchUnpublishedEvents.new
|
10
|
+
end
|
11
|
+
|
6
12
|
def in(aggregate)
|
7
|
-
|
13
|
+
fetch_events.in(aggregate)
|
8
14
|
self
|
9
15
|
end
|
10
16
|
|
11
17
|
def strict
|
12
|
-
|
18
|
+
expected.strict
|
13
19
|
self
|
14
20
|
end
|
15
21
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
event_proc.call
|
20
|
-
@applied_events = @aggregate.unpublished_events.to_a - before
|
21
|
-
if match_events?
|
22
|
-
@matcher.matches?(@applied_events)
|
23
|
-
else
|
24
|
-
!@applied_events.empty?
|
25
|
-
end
|
22
|
+
def exactly(count)
|
23
|
+
expected.exactly(count)
|
24
|
+
self
|
26
25
|
end
|
27
26
|
|
28
|
-
def
|
29
|
-
|
30
|
-
|
31
|
-
|
27
|
+
def times
|
28
|
+
self
|
29
|
+
end
|
30
|
+
alias :time :times
|
32
31
|
|
33
|
-
|
32
|
+
def once
|
33
|
+
expected.once
|
34
|
+
self
|
35
|
+
end
|
34
36
|
|
35
|
-
|
37
|
+
def matches?(event_proc)
|
38
|
+
raise_aggregate_not_set unless fetch_events.aggregate?
|
39
|
+
before = fetch_events.aggregate.unpublished_events.to_a
|
40
|
+
event_proc.call
|
41
|
+
@applied_events = fetch_events.aggregate.unpublished_events.to_a - before
|
42
|
+
MatchEvents.new.call(expected, applied_events)
|
43
|
+
end
|
36
44
|
|
37
|
-
|
38
|
-
|
39
|
-
else
|
40
|
-
"expected block to have applied any events"
|
41
|
-
end
|
45
|
+
def failure_message
|
46
|
+
failure_message_formatter.failure_message(expected, applied_events)
|
42
47
|
end
|
43
48
|
|
44
49
|
def failure_message_when_negated
|
45
|
-
|
46
|
-
<<-EOS
|
47
|
-
expected block not to have applied:
|
48
|
-
|
49
|
-
#{@expected}
|
50
|
-
|
51
|
-
but applied:
|
52
|
-
|
53
|
-
#{@applied_events}
|
54
|
-
EOS
|
55
|
-
else
|
56
|
-
"expected block not to have applied any events"
|
57
|
-
end
|
50
|
+
failure_message_formatter.failure_message_when_negated(expected, applied_events)
|
58
51
|
end
|
59
52
|
|
60
53
|
def description
|
@@ -67,18 +60,11 @@ EOS
|
|
67
60
|
|
68
61
|
private
|
69
62
|
|
70
|
-
def initialize(*expected)
|
71
|
-
@expected = expected
|
72
|
-
@matcher = ::RSpec::Matchers::BuiltIn::Include.new(*expected)
|
73
|
-
end
|
74
|
-
|
75
|
-
def match_events?
|
76
|
-
!@expected.empty?
|
77
|
-
end
|
78
|
-
|
79
63
|
def raise_aggregate_not_set
|
80
|
-
raise
|
64
|
+
raise "You have to set the aggregate instance with `in`, e.g. `expect { ... }.to apply(an_event(MyEvent)).in(aggregate)`"
|
81
65
|
end
|
66
|
+
|
67
|
+
attr_reader :expected, :applied_events, :failure_message_formatter, :fetch_events
|
82
68
|
end
|
83
69
|
end
|
84
70
|
end
|
@@ -90,7 +90,7 @@ module RubyEventStore
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def to_s
|
93
|
-
@expected && ["\n#{@label} diff:", @differ.
|
93
|
+
@expected && ["\n#{@label} diff:", @differ.diff(@actual.to_s + "\n", @expected.to_s)]
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
@@ -124,7 +124,7 @@ module RubyEventStore
|
|
124
124
|
|
125
125
|
def matches?(actual)
|
126
126
|
@actual = actual
|
127
|
-
matches_kind && matches_data && matches_metadata
|
127
|
+
matches_kind?(actual) && matches_data?(actual) && matches_metadata?(actual)
|
128
128
|
end
|
129
129
|
|
130
130
|
def with_data(expected_data)
|
@@ -167,25 +167,27 @@ expected: not a kind of #{expected}
|
|
167
167
|
" (#{expectation_list.join(" and ")})" if expectation_list.any?
|
168
168
|
end
|
169
169
|
|
170
|
-
|
170
|
+
attr_reader :expected, :expected_data, :expected_metadata
|
171
171
|
|
172
|
-
def
|
173
|
-
|
172
|
+
def strict?
|
173
|
+
@strict
|
174
174
|
end
|
175
175
|
|
176
|
-
def
|
177
|
-
|
176
|
+
def matches_kind?(actual_event)
|
177
|
+
KindMatcher.new(expected).matches?(actual_event)
|
178
178
|
end
|
179
179
|
|
180
|
-
|
181
|
-
DataMatcher.new(expected_metadata, strict: strict?).matches?(actual.metadata.to_h)
|
182
|
-
end
|
180
|
+
private
|
183
181
|
|
184
|
-
|
182
|
+
def matches_data?(actual_event)
|
183
|
+
DataMatcher.new(expected_data, strict: strict?).matches?(actual_event.data)
|
184
|
+
end
|
185
185
|
|
186
|
-
def
|
187
|
-
|
186
|
+
def matches_metadata?(actual_event)
|
187
|
+
DataMatcher.new(expected_metadata, strict: strict?).matches?(actual_event.metadata.to_h)
|
188
188
|
end
|
189
|
+
|
190
|
+
attr_reader :actual, :differ, :formatter
|
189
191
|
end
|
190
192
|
end
|
191
193
|
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyEventStore
|
4
|
+
module RSpec
|
5
|
+
class CrudeFailureMessageFormatter
|
6
|
+
class HavePublished
|
7
|
+
def initialize(differ)
|
8
|
+
@differ = differ
|
9
|
+
end
|
10
|
+
|
11
|
+
def failure_message(expected, events, stream_name)
|
12
|
+
stream_expectation = " in stream #{stream_name}" unless stream_name.nil?
|
13
|
+
"expected #{expected.events} to be published#{stream_expectation}, diff:" +
|
14
|
+
differ.diff(expected.events.to_s + "\n", events)
|
15
|
+
end
|
16
|
+
|
17
|
+
def failure_message_when_negated(expected, events, stream_name)
|
18
|
+
stream_expectation = " in stream #{stream_name}" unless stream_name.nil?
|
19
|
+
"expected #{expected.events} not to be published#{stream_expectation}, diff:" +
|
20
|
+
differ.diff(expected.events.to_s + "\n", events)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
attr_reader :differ
|
25
|
+
end
|
26
|
+
|
27
|
+
class Publish
|
28
|
+
def failure_message(expected, events, stream)
|
29
|
+
if !expected.empty?
|
30
|
+
<<~EOS
|
31
|
+
expected block to have published:
|
32
|
+
|
33
|
+
#{expected.events}
|
34
|
+
|
35
|
+
#{"in stream #{stream} " if stream}but published:
|
36
|
+
|
37
|
+
#{events}
|
38
|
+
EOS
|
39
|
+
else
|
40
|
+
"expected block to have published any events"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def failure_message_when_negated(expected, events, stream)
|
45
|
+
if !expected.empty?
|
46
|
+
<<~EOS
|
47
|
+
expected block not to have published:
|
48
|
+
|
49
|
+
#{expected.events}
|
50
|
+
|
51
|
+
#{"in stream #{stream} " if stream}but published:
|
52
|
+
|
53
|
+
#{events}
|
54
|
+
EOS
|
55
|
+
else
|
56
|
+
"expected block not to have published any events"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class HaveApplied
|
62
|
+
def initialize(differ)
|
63
|
+
@differ = differ
|
64
|
+
end
|
65
|
+
|
66
|
+
def failure_message(expected, events)
|
67
|
+
"expected #{expected.events} to be applied, diff:" +
|
68
|
+
differ.diff(expected.events.to_s + "\n", events)
|
69
|
+
end
|
70
|
+
|
71
|
+
def failure_message_when_negated(expected, events)
|
72
|
+
"expected #{expected.events} not to be applied, diff:" +
|
73
|
+
differ.diff(expected.events.inspect + "\n", events)
|
74
|
+
end
|
75
|
+
|
76
|
+
attr_reader :differ
|
77
|
+
end
|
78
|
+
|
79
|
+
class Apply
|
80
|
+
def failure_message(expected, applied_events)
|
81
|
+
if !expected.empty?
|
82
|
+
<<~EOS
|
83
|
+
expected block to have applied:
|
84
|
+
|
85
|
+
#{expected.events}
|
86
|
+
|
87
|
+
but applied:
|
88
|
+
|
89
|
+
#{applied_events}
|
90
|
+
EOS
|
91
|
+
else
|
92
|
+
"expected block to have applied any events"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def failure_message_when_negated(expected, applied_events)
|
97
|
+
if !expected.empty?
|
98
|
+
<<~EOS
|
99
|
+
expected block not to have applied:
|
100
|
+
|
101
|
+
#{expected.events}
|
102
|
+
|
103
|
+
but applied:
|
104
|
+
|
105
|
+
#{applied_events}
|
106
|
+
EOS
|
107
|
+
else
|
108
|
+
"expected block not to have applied any events"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def have_published(differ)
|
114
|
+
HavePublished.new(differ)
|
115
|
+
end
|
116
|
+
|
117
|
+
def publish(_differ)
|
118
|
+
Publish.new
|
119
|
+
end
|
120
|
+
|
121
|
+
def have_applied(differ)
|
122
|
+
HaveApplied.new(differ)
|
123
|
+
end
|
124
|
+
|
125
|
+
def apply(_differ)
|
126
|
+
Apply.new
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
module RSpec
|
3
|
+
class ExpectedCollection
|
4
|
+
def initialize(events)
|
5
|
+
@events = events
|
6
|
+
@strict = false
|
7
|
+
end
|
8
|
+
|
9
|
+
def exactly(count)
|
10
|
+
raise NotSupported if !events.size.equal?(1)
|
11
|
+
raise NotSupported if count < 1
|
12
|
+
@count = count
|
13
|
+
end
|
14
|
+
|
15
|
+
def empty?
|
16
|
+
events.empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
def once
|
20
|
+
exactly(1)
|
21
|
+
end
|
22
|
+
|
23
|
+
def specified_count?
|
24
|
+
!count.nil?
|
25
|
+
end
|
26
|
+
|
27
|
+
def strict
|
28
|
+
@strict = true
|
29
|
+
end
|
30
|
+
|
31
|
+
def strict?
|
32
|
+
@strict
|
33
|
+
end
|
34
|
+
|
35
|
+
def event
|
36
|
+
raise NotSupported if !events.size.equal?(1)
|
37
|
+
events.first
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_reader :events, :count
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
module RSpec
|
3
|
+
class FetchEvents
|
4
|
+
MissingEventStore = Class.new(StandardError)
|
5
|
+
|
6
|
+
def from(event_id)
|
7
|
+
@start = event_id
|
8
|
+
end
|
9
|
+
|
10
|
+
def stream(stream_name)
|
11
|
+
@stream_name = stream_name
|
12
|
+
end
|
13
|
+
|
14
|
+
def in(event_store)
|
15
|
+
@event_store = event_store
|
16
|
+
end
|
17
|
+
|
18
|
+
def from_last
|
19
|
+
@start = call.last&.event_id
|
20
|
+
end
|
21
|
+
|
22
|
+
def call
|
23
|
+
raise MissingEventStore if event_store.nil?
|
24
|
+
events = event_store.read
|
25
|
+
events = events.stream(stream_name) if stream_name
|
26
|
+
events = events.from(start) if start
|
27
|
+
events
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :start, :stream_name, :event_store
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
module RSpec
|
3
|
+
class FetchUnpublishedEvents
|
4
|
+
def in(aggregate)
|
5
|
+
@aggregate = aggregate
|
6
|
+
end
|
7
|
+
|
8
|
+
def call
|
9
|
+
aggregate.unpublished_events.to_a
|
10
|
+
end
|
11
|
+
|
12
|
+
def aggregate?
|
13
|
+
!aggregate.nil?
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :aggregate
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -3,20 +3,21 @@
|
|
3
3
|
module RubyEventStore
|
4
4
|
module RSpec
|
5
5
|
class HaveApplied
|
6
|
-
def initialize(
|
7
|
-
@expected =
|
8
|
-
@
|
9
|
-
@differ = differ
|
6
|
+
def initialize(*expected, phraser:, failure_message_formatter:)
|
7
|
+
@expected = ExpectedCollection.new(expected)
|
8
|
+
@failure_message_formatter = failure_message_formatter
|
10
9
|
@phraser = phraser
|
10
|
+
@fetch_events = FetchUnpublishedEvents.new
|
11
11
|
end
|
12
12
|
|
13
13
|
def matches?(aggregate_root)
|
14
|
-
|
15
|
-
|
14
|
+
fetch_events.in(aggregate_root)
|
15
|
+
@events = fetch_events.call
|
16
|
+
MatchEvents.new.call(expected, events)
|
16
17
|
end
|
17
18
|
|
18
19
|
def exactly(count)
|
19
|
-
|
20
|
+
expected.exactly(count)
|
20
21
|
self
|
21
22
|
end
|
22
23
|
|
@@ -26,38 +27,30 @@ module RubyEventStore
|
|
26
27
|
alias :time :times
|
27
28
|
|
28
29
|
def once
|
29
|
-
|
30
|
+
expected.once
|
31
|
+
self
|
30
32
|
end
|
31
33
|
|
32
34
|
def strict
|
33
|
-
|
35
|
+
expected.strict
|
34
36
|
self
|
35
37
|
end
|
36
38
|
|
37
39
|
def failure_message
|
38
|
-
|
39
|
-
differ.diff_as_string(expected.to_s, events.to_s)
|
40
|
+
failure_message_formatter.failure_message(expected, events)
|
40
41
|
end
|
41
42
|
|
42
43
|
def failure_message_when_negated
|
43
|
-
|
44
|
-
differ.diff_as_string(expected.inspect, events.inspect)
|
44
|
+
failure_message_formatter.failure_message_when_negated(expected, events)
|
45
45
|
end
|
46
46
|
|
47
47
|
def description
|
48
|
-
"have applied events that have to (#{phraser.(expected)})"
|
48
|
+
"have applied events that have to (#{phraser.(expected.events)})"
|
49
49
|
end
|
50
50
|
|
51
51
|
private
|
52
52
|
|
53
|
-
|
54
|
-
return true unless count
|
55
|
-
raise NotSupported if expected.size > 1
|
56
|
-
events.select { |e| expected.first === e }.size.equal?(count)
|
57
|
-
end
|
58
|
-
|
59
|
-
attr_reader :differ, :phraser, :expected, :events, :count, :matcher
|
53
|
+
attr_reader :phraser, :expected, :events, :failure_message_formatter, :fetch_events
|
60
54
|
end
|
61
55
|
end
|
62
56
|
end
|
63
|
-
|
@@ -3,28 +3,35 @@
|
|
3
3
|
module RubyEventStore
|
4
4
|
module RSpec
|
5
5
|
class HavePublished
|
6
|
-
def initialize(
|
7
|
-
@expected =
|
8
|
-
@matcher = ::RSpec::Matchers::BuiltIn::Include.new(*expected)
|
9
|
-
@differ = differ
|
6
|
+
def initialize(*expected, phraser:, failure_message_formatter:)
|
7
|
+
@expected = ExpectedCollection.new(expected)
|
10
8
|
@phraser = phraser
|
9
|
+
@failure_message_formatter = failure_message_formatter
|
10
|
+
@fetch_events = FetchEvents.new
|
11
11
|
end
|
12
12
|
|
13
13
|
def matches?(event_store)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
stream_names.all? do |stream_name|
|
15
|
+
fetch_events.stream(stream_name)
|
16
|
+
fetch_events.in(event_store)
|
17
|
+
@published_events = fetch_events.call.to_a
|
18
|
+
@failed_on_stream = stream_name
|
19
|
+
MatchEvents.new.call(expected, published_events)
|
20
|
+
end
|
19
21
|
end
|
20
22
|
|
21
23
|
def exactly(count)
|
22
|
-
|
24
|
+
expected.exactly(count)
|
23
25
|
self
|
24
26
|
end
|
25
27
|
|
26
28
|
def in_stream(stream_name)
|
27
|
-
@
|
29
|
+
@stream_names = [stream_name]
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def in_streams(stream_names)
|
34
|
+
@stream_names = Array(stream_names)
|
28
35
|
self
|
29
36
|
end
|
30
37
|
|
@@ -34,42 +41,39 @@ module RubyEventStore
|
|
34
41
|
alias :time :times
|
35
42
|
|
36
43
|
def from(event_id)
|
37
|
-
|
44
|
+
fetch_events.from(event_id)
|
38
45
|
self
|
39
46
|
end
|
40
47
|
|
41
48
|
def once
|
42
|
-
|
49
|
+
expected.once
|
50
|
+
self
|
43
51
|
end
|
44
52
|
|
45
53
|
def failure_message
|
46
|
-
|
47
|
-
differ.diff_as_string(expected.to_s, events.to_a.to_s)
|
54
|
+
failure_message_formatter.failure_message(expected, published_events, failed_on_stream)
|
48
55
|
end
|
49
56
|
|
50
57
|
def failure_message_when_negated
|
51
|
-
|
52
|
-
differ.diff_as_string(expected.to_s, events.to_a.to_s)
|
58
|
+
failure_message_formatter.failure_message_when_negated(expected, published_events, failed_on_stream)
|
53
59
|
end
|
54
60
|
|
55
61
|
def description
|
56
|
-
"have published events that have to (#{phraser.(expected)})"
|
62
|
+
"have published events that have to (#{phraser.(expected.events)})"
|
57
63
|
end
|
58
64
|
|
59
65
|
def strict
|
60
|
-
|
66
|
+
expected.strict
|
61
67
|
self
|
62
68
|
end
|
63
69
|
|
64
70
|
private
|
65
71
|
|
66
|
-
def
|
67
|
-
|
68
|
-
raise NotSupported if expected.size > 1
|
69
|
-
events.select { |e| expected.first === e }.size.equal?(count)
|
72
|
+
def stream_names
|
73
|
+
@stream_names || [nil]
|
70
74
|
end
|
71
75
|
|
72
|
-
attr_reader :
|
76
|
+
attr_reader :phraser, :expected, :published_events, :failed_on_stream, :failure_message_formatter, :fetch_events
|
73
77
|
end
|
74
78
|
end
|
75
79
|
end
|
@@ -26,12 +26,12 @@ module RubyEventStore
|
|
26
26
|
|
27
27
|
def failure_message
|
28
28
|
"expected #{handler} to be subscribed to events, diff:" +
|
29
|
-
differ.
|
29
|
+
differ.diff(expected.to_s + "\n", subscribed_to)
|
30
30
|
end
|
31
31
|
|
32
32
|
def failure_message_when_negated
|
33
33
|
"expected #{handler} not to be subscribed to events, diff:" +
|
34
|
-
differ.
|
34
|
+
differ.diff(expected.to_s + "\n", subscribed_to)
|
35
35
|
end
|
36
36
|
|
37
37
|
def description
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
module RSpec
|
3
|
+
class MatchEvents
|
4
|
+
def call(expected, events)
|
5
|
+
if match_events?(expected)
|
6
|
+
matcher(expected).matches?(events) && matches_count?(expected, events)
|
7
|
+
else
|
8
|
+
!events.empty?
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def matches_count?(expected, events)
|
15
|
+
return true unless expected.specified_count?
|
16
|
+
events.select { |e| expected.event === e }.size.equal?(expected.count)
|
17
|
+
end
|
18
|
+
|
19
|
+
def matcher(expected)
|
20
|
+
if expected.strict?
|
21
|
+
::RSpec::Matchers::BuiltIn::Match.new(expected.events)
|
22
|
+
else
|
23
|
+
::RSpec::Matchers::BuiltIn::Include.new(*expected.events)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def match_events?(expected)
|
28
|
+
!expected.empty?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -39,11 +39,11 @@ module RubyEventStore
|
|
39
39
|
alias :event :be_an_event
|
40
40
|
|
41
41
|
def have_published(*expected)
|
42
|
-
HavePublished.new(*expected,
|
42
|
+
HavePublished.new(*expected, phraser: phraser, failure_message_formatter: RSpec.default_formatter.have_published(differ))
|
43
43
|
end
|
44
44
|
|
45
45
|
def have_applied(*expected)
|
46
|
-
HaveApplied.new(*expected,
|
46
|
+
HaveApplied.new(*expected, phraser: phraser, failure_message_formatter: RSpec.default_formatter.have_applied(differ))
|
47
47
|
end
|
48
48
|
|
49
49
|
def have_subscribed_to_events(*expected)
|
@@ -51,11 +51,11 @@ module RubyEventStore
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def publish(*expected)
|
54
|
-
Publish.new(*expected)
|
54
|
+
Publish.new(*expected, failure_message_formatter: RSpec.default_formatter.publish(differ))
|
55
55
|
end
|
56
56
|
|
57
57
|
def apply(*expected)
|
58
|
-
Apply.new(*expected)
|
58
|
+
Apply.new(*expected, failure_message_formatter: RSpec.default_formatter.apply(differ))
|
59
59
|
end
|
60
60
|
|
61
61
|
private
|
@@ -65,7 +65,7 @@ module RubyEventStore
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def differ
|
68
|
-
::RSpec::
|
68
|
+
::RSpec::Expectations.differ
|
69
69
|
end
|
70
70
|
|
71
71
|
def phraser
|
@@ -3,61 +3,66 @@
|
|
3
3
|
module RubyEventStore
|
4
4
|
module RSpec
|
5
5
|
class Publish
|
6
|
+
def initialize(*expected, failure_message_formatter:)
|
7
|
+
@expected = ExpectedCollection.new(expected)
|
8
|
+
@failure_message_formatter = failure_message_formatter
|
9
|
+
@fetch_events = FetchEvents.new
|
10
|
+
end
|
11
|
+
|
6
12
|
def in(event_store)
|
7
|
-
|
13
|
+
fetch_events.in(event_store)
|
8
14
|
self
|
9
15
|
end
|
10
16
|
|
11
|
-
def in_stream(
|
12
|
-
@
|
17
|
+
def in_stream(stream_name)
|
18
|
+
@stream_names = [stream_name]
|
13
19
|
self
|
14
20
|
end
|
15
21
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
spec = spec.stream(@stream) if @stream
|
20
|
-
last_event_before_block = spec.last
|
21
|
-
event_proc.call
|
22
|
-
spec = spec.from(last_event_before_block.event_id) if last_event_before_block
|
23
|
-
@published_events = spec.to_a
|
24
|
-
if match_events?
|
25
|
-
::RSpec::Matchers::BuiltIn::Include.new(*@expected).matches?(@published_events)
|
26
|
-
else
|
27
|
-
!@published_events.empty?
|
28
|
-
end
|
22
|
+
def in_streams(stream_names)
|
23
|
+
@stream_names = Array(stream_names)
|
24
|
+
self
|
29
25
|
end
|
30
26
|
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
#{@expected}
|
27
|
+
def exactly(count)
|
28
|
+
expected.exactly(count)
|
29
|
+
self
|
30
|
+
end
|
37
31
|
|
38
|
-
|
32
|
+
def once
|
33
|
+
expected.once
|
34
|
+
self
|
35
|
+
end
|
39
36
|
|
40
|
-
|
41
|
-
|
42
|
-
else
|
43
|
-
"expected block to have published any events"
|
44
|
-
end
|
37
|
+
def times
|
38
|
+
self
|
45
39
|
end
|
40
|
+
alias :time :times
|
46
41
|
|
47
|
-
def
|
48
|
-
|
49
|
-
|
50
|
-
|
42
|
+
def strict
|
43
|
+
expected.strict
|
44
|
+
self
|
45
|
+
end
|
51
46
|
|
52
|
-
|
47
|
+
def matches?(event_proc)
|
48
|
+
fetch_events.from_last
|
49
|
+
event_proc.call
|
50
|
+
stream_names.all? do |stream_name|
|
51
|
+
fetch_events.stream(stream_name)
|
52
|
+
@published_events = fetch_events.call.to_a
|
53
|
+
@failed_on_stream = stream_name
|
54
|
+
MatchEvents.new.call(expected, published_events)
|
55
|
+
end
|
56
|
+
rescue FetchEvents::MissingEventStore
|
57
|
+
raise "You have to set the event store instance with `in`, e.g. `expect { ... }.to publish(an_event(MyEvent)).in(event_store)`"
|
58
|
+
end
|
53
59
|
|
54
|
-
|
60
|
+
def failure_message
|
61
|
+
failure_message_formatter.failure_message(expected, published_events, failed_on_stream)
|
62
|
+
end
|
55
63
|
|
56
|
-
|
57
|
-
|
58
|
-
else
|
59
|
-
"expected block not to have published any events"
|
60
|
-
end
|
64
|
+
def failure_message_when_negated
|
65
|
+
failure_message_formatter.failure_message_when_negated(expected, published_events, fetch_events.stream_name)
|
61
66
|
end
|
62
67
|
|
63
68
|
def description
|
@@ -70,17 +75,11 @@ EOS
|
|
70
75
|
|
71
76
|
private
|
72
77
|
|
73
|
-
def
|
74
|
-
@
|
78
|
+
def stream_names
|
79
|
+
@stream_names || [nil]
|
75
80
|
end
|
76
81
|
|
77
|
-
|
78
|
-
!@expected.empty?
|
79
|
-
end
|
80
|
-
|
81
|
-
def raise_event_store_not_set
|
82
|
-
raise SyntaxError, "You have to set the event store instance with `in`, e.g. `expect { ... }.to publish(an_event(MyEvent)).in(event_store)`"
|
83
|
-
end
|
82
|
+
attr_reader :fetch_events, :expected, :failure_message_formatter, :published_events, :failed_on_stream
|
84
83
|
end
|
85
84
|
end
|
86
85
|
end
|
@@ -0,0 +1,218 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyEventStore
|
4
|
+
module RSpec
|
5
|
+
class StepByStepFailureMessageFormatter
|
6
|
+
class Lingo
|
7
|
+
def initialize(published)
|
8
|
+
@published = published
|
9
|
+
end
|
10
|
+
attr_reader :published
|
11
|
+
end
|
12
|
+
|
13
|
+
class HavePublished
|
14
|
+
def initialize(differ, lingo)
|
15
|
+
@differ = differ
|
16
|
+
@lingo = lingo
|
17
|
+
end
|
18
|
+
|
19
|
+
def failure_message(expected, events, stream_name = nil)
|
20
|
+
return failure_message_strict(expected, events) if expected.strict?
|
21
|
+
return failure_message_no_events if expected.empty?
|
22
|
+
expected.events.each do |expected_event|
|
23
|
+
correct_event_count = 0
|
24
|
+
events_with_correct_type = []
|
25
|
+
events.each do |actual_event|
|
26
|
+
if expected_event.matches?(actual_event)
|
27
|
+
correct_event_count += 1
|
28
|
+
elsif expected_event.matches_kind?(actual_event)
|
29
|
+
events_with_correct_type << actual_event
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
expectations = expected_message(expected, expected_event, stream_name)
|
34
|
+
|
35
|
+
if expected.specified_count?
|
36
|
+
if correct_event_count >= 1
|
37
|
+
reality = failure_message_incorrect_count(expected_event, events_with_correct_type, correct_event_count)
|
38
|
+
elsif !events_with_correct_type.empty?
|
39
|
+
reality = failure_message_correct_type_incorrect_payload(expected_event, events_with_correct_type)
|
40
|
+
else
|
41
|
+
reality = failure_message_incorrect_type
|
42
|
+
end
|
43
|
+
else
|
44
|
+
if correct_event_count >= 1
|
45
|
+
next
|
46
|
+
else
|
47
|
+
if !events_with_correct_type.empty?
|
48
|
+
reality = failure_message_correct_type_incorrect_payload(expected_event, events_with_correct_type)
|
49
|
+
else
|
50
|
+
reality = failure_message_incorrect_type
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
return (expectations + reality)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def failure_message_when_negated(expected, events, _stream_name = nil)
|
60
|
+
return failure_message_when_negated_no_events if expected.empty?
|
61
|
+
if expected.specified_count?
|
62
|
+
<<~EOS
|
63
|
+
expected
|
64
|
+
#{expected.events.first.description}
|
65
|
+
not to be #{lingo.published} exactly #{expected.count} times
|
66
|
+
|
67
|
+
#{actual_events_list(events)}
|
68
|
+
EOS
|
69
|
+
else
|
70
|
+
<<~EOS
|
71
|
+
expected #{expected_events_list(expected.events)} not to #{"exactly " if expected.strict?}be #{lingo.published}
|
72
|
+
|
73
|
+
#{actual_events_list(events)}
|
74
|
+
EOS
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
attr_reader :differ, :lingo
|
80
|
+
|
81
|
+
def failure_message_no_events
|
82
|
+
"expected anything to be #{lingo.published}\n"
|
83
|
+
end
|
84
|
+
|
85
|
+
def failure_message_when_negated_no_events
|
86
|
+
"expected something to be #{lingo.published}\n"
|
87
|
+
end
|
88
|
+
|
89
|
+
def failure_message_incorrect_count(expected_event, events_with_correct_type, correct_event_count)
|
90
|
+
[
|
91
|
+
<<~EOS,
|
92
|
+
|
93
|
+
but was #{lingo.published} #{correct_event_count} times
|
94
|
+
EOS
|
95
|
+
|
96
|
+
if !events_with_correct_type.empty?
|
97
|
+
[
|
98
|
+
<<~EOS.strip,
|
99
|
+
There are events of correct type but with incorrect payload:
|
100
|
+
EOS
|
101
|
+
events_with_correct_type.each_with_index.map {|event_with_correct_type, index| event_diff(expected_event, event_with_correct_type, index) },
|
102
|
+
nil
|
103
|
+
]
|
104
|
+
end
|
105
|
+
].compact.join("\n")
|
106
|
+
end
|
107
|
+
|
108
|
+
def failure_message_correct_type_incorrect_payload(expected_event, events_with_correct_type)
|
109
|
+
<<~EOS
|
110
|
+
, but it was not #{lingo.published}
|
111
|
+
|
112
|
+
There are events of correct type but with incorrect payload:
|
113
|
+
#{events_with_correct_type.each_with_index.map {|event_with_correct_type, index| event_diff(expected_event, event_with_correct_type, index) }.join("\n")}
|
114
|
+
EOS
|
115
|
+
end
|
116
|
+
|
117
|
+
def event_diff(expected_event, event_with_correct_type, index)
|
118
|
+
[
|
119
|
+
"#{index + 1}) #{event_with_correct_type.inspect}",
|
120
|
+
indent(data_diff(expected_event, event_with_correct_type), 4),
|
121
|
+
indent(metadata_diff(expected_event, event_with_correct_type), 4),
|
122
|
+
].reject(&:empty?)
|
123
|
+
end
|
124
|
+
|
125
|
+
def indent(str, count)
|
126
|
+
str.to_s.split("\n").map {|l| l.sub(//, " " * count) }
|
127
|
+
end
|
128
|
+
|
129
|
+
def failure_message_incorrect_type
|
130
|
+
<<~EOS
|
131
|
+
, but there is no event with such type
|
132
|
+
EOS
|
133
|
+
end
|
134
|
+
|
135
|
+
def failure_message_strict(expected, events)
|
136
|
+
if expected.specified_count?
|
137
|
+
<<~EOS
|
138
|
+
expected only
|
139
|
+
#{expected.events.first.description}
|
140
|
+
to be #{lingo.published} #{expected.count} times
|
141
|
+
|
142
|
+
#{actual_events_list(events)}
|
143
|
+
EOS
|
144
|
+
else
|
145
|
+
<<~EOS
|
146
|
+
expected only #{expected_events_list(expected.events)} to be #{lingo.published}
|
147
|
+
|
148
|
+
#{actual_events_list(events)}
|
149
|
+
EOS
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def data_diff(expected_event, event_with_correct_type)
|
154
|
+
if !expected_event.expected_data.nil?
|
155
|
+
"data diff:#{differ.diff(expected_event.expected_data, event_with_correct_type.data)}"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def metadata_diff(expected_event, event_with_correct_type)
|
160
|
+
if !expected_event.expected_metadata.nil?
|
161
|
+
"metadata diff:#{differ.diff(expected_event.expected_metadata, event_with_correct_type.metadata.to_h)}"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def expected_message(expected, expected_event, stream_name)
|
166
|
+
expected_stream = " in stream #{stream_name}" if stream_name
|
167
|
+
if expected.specified_count?
|
168
|
+
<<~EOS
|
169
|
+
expected event
|
170
|
+
#{expected_event.description}
|
171
|
+
to be #{lingo.published} #{expected.count} times#{expected_stream}
|
172
|
+
EOS
|
173
|
+
else
|
174
|
+
<<~EOS
|
175
|
+
expected #{expected_events_list(expected.events)} to be #{lingo.published}#{expected_stream}
|
176
|
+
|
177
|
+
i.e. expected event
|
178
|
+
#{expected_event.description}
|
179
|
+
to be #{lingo.published}
|
180
|
+
EOS
|
181
|
+
end.strip
|
182
|
+
end
|
183
|
+
|
184
|
+
def expected_events_list(expected)
|
185
|
+
<<~EOS.strip
|
186
|
+
[
|
187
|
+
#{expected.map(&:description).map {|d| indent(d, 2) }.join("\n")}
|
188
|
+
]
|
189
|
+
EOS
|
190
|
+
end
|
191
|
+
|
192
|
+
def actual_events_list(actual)
|
193
|
+
<<~EOS.strip
|
194
|
+
but the following was #{lingo.published}: [
|
195
|
+
#{actual.map(&:inspect).map {|d| indent(d, 2) }.join("\n")}
|
196
|
+
]
|
197
|
+
EOS
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def have_published(differ)
|
202
|
+
HavePublished.new(differ, Lingo.new("published"))
|
203
|
+
end
|
204
|
+
|
205
|
+
def publish(differ)
|
206
|
+
HavePublished.new(differ, Lingo.new("published"))
|
207
|
+
end
|
208
|
+
|
209
|
+
def have_applied(differ)
|
210
|
+
HavePublished.new(differ, Lingo.new("applied"))
|
211
|
+
end
|
212
|
+
|
213
|
+
def apply(differ)
|
214
|
+
HavePublished.new(differ, Lingo.new("applied"))
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_event_store-rspec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arkency
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-04-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -35,11 +35,17 @@ files:
|
|
35
35
|
- lib/ruby_event_store/rspec.rb
|
36
36
|
- lib/ruby_event_store/rspec/apply.rb
|
37
37
|
- lib/ruby_event_store/rspec/be_event.rb
|
38
|
+
- lib/ruby_event_store/rspec/crude_failure_message_formatter.rb
|
39
|
+
- lib/ruby_event_store/rspec/expected_collection.rb
|
40
|
+
- lib/ruby_event_store/rspec/fetch_events.rb
|
41
|
+
- lib/ruby_event_store/rspec/fetch_unpublished_events.rb
|
38
42
|
- lib/ruby_event_store/rspec/have_applied.rb
|
39
43
|
- lib/ruby_event_store/rspec/have_published.rb
|
40
44
|
- lib/ruby_event_store/rspec/have_subscribed_to_events.rb
|
45
|
+
- lib/ruby_event_store/rspec/match_events.rb
|
41
46
|
- lib/ruby_event_store/rspec/matchers.rb
|
42
47
|
- lib/ruby_event_store/rspec/publish.rb
|
48
|
+
- lib/ruby_event_store/rspec/step_by_step_failure_message_formatter.rb
|
43
49
|
- lib/ruby_event_store/rspec/version.rb
|
44
50
|
homepage: https://railseventstore.org
|
45
51
|
licenses:
|
@@ -57,7 +63,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
63
|
requirements:
|
58
64
|
- - ">="
|
59
65
|
- !ruby/object:Gem::Version
|
60
|
-
version: '2.
|
66
|
+
version: '2.6'
|
61
67
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
68
|
requirements:
|
63
69
|
- - ">="
|