chrono_model 0.8.2 → 0.9.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.
@@ -14,11 +14,11 @@ describe 'JSON equality operator' do
14
14
  ChronoModel::Json.drop
15
15
  end
16
16
 
17
- it { adapter.select_value(%[ SELECT '{"a":1}'::json = '{"a":1}'::json ]).should == 't' }
18
- it { adapter.select_value(%[ SELECT '{"a":1}'::json = '{"a" : 1}'::json ]).should == 't' }
19
- it { adapter.select_value(%[ SELECT '{"a":1}'::json = '{"a":2}'::json ]).should == 'f' }
20
- it { adapter.select_value(%[ SELECT '{"a":1,"b":2}'::json = '{"b":2,"a":1}'::json ]).should == 't' }
21
- it { adapter.select_value(%[ SELECT '{"a":1,"b":2,"x":{"c":4,"d":5}}'::json = '{"b":2, "x": { "d": 5, "c": 4}, "a":1}'::json ]).should == 't' }
17
+ it { expect(adapter.select_value(%[ SELECT '{"a":1}'::json = '{"a":1}'::json ])).to eq 't' }
18
+ it { expect(adapter.select_value(%[ SELECT '{"a":1}'::json = '{"a" : 1}'::json ])).to eq 't' }
19
+ it { expect(adapter.select_value(%[ SELECT '{"a":1}'::json = '{"a":2}'::json ])).to eq 'f' }
20
+ it { expect(adapter.select_value(%[ SELECT '{"a":1,"b":2}'::json = '{"b":2,"a":1}'::json ])).to eq 't' }
21
+ it { expect(adapter.select_value(%[ SELECT '{"a":1,"b":2,"x":{"c":4,"d":5}}'::json = '{"b":2, "x": { "d": 5, "c": 4}, "a":1}'::json ])).to eq 't' }
22
22
 
23
23
  context 'on a temporal table' do
24
24
  before :all do
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
2
2
  #
3
+ require 'codeclimate-test-reporter'
4
+ CodeClimate::TestReporter.start
5
+
3
6
  require 'chrono_model'
4
7
 
5
8
  require 'support/connection'
@@ -9,8 +12,6 @@ require 'support/matchers/column'
9
12
  require 'support/matchers/index'
10
13
 
11
14
  RSpec.configure do |config|
12
- config.treat_symbols_as_metadata_keys_with_true_values = true
13
-
14
15
  config.include(ChronoTest::Matchers::Schema)
15
16
  config.include(ChronoTest::Matchers::Table)
16
17
  config.include(ChronoTest::Matchers::Column)
@@ -1,7 +1,7 @@
1
- require 'ostruct'
2
-
3
1
  module ChronoTest::Matchers
4
2
  class Base
3
+ include ActiveRecord::Sanitization::ClassMethods
4
+
5
5
  attr_reader :table
6
6
 
7
7
  def matches?(table)
@@ -15,6 +15,7 @@ module ChronoTest::Matchers
15
15
  end
16
16
 
17
17
  protected
18
+
18
19
  def connection
19
20
  ChronoTest.connection
20
21
  end
@@ -46,13 +47,9 @@ module ChronoTest::Matchers
46
47
  end
47
48
 
48
49
  private
49
- FooColumn = OpenStruct.new(:name => '')
50
-
51
50
  def exec_query(sql, binds, name)
52
- binds.map! do |col, val|
53
- val ? [col, val] : [FooColumn, col]
54
- end
55
- connection.exec_query(sql, name, binds)
51
+ sql = sanitize_sql_array([ sql, *Array.wrap(binds) ])
52
+ connection.exec_query(sql, name)
56
53
  end
57
54
  end
58
55
 
@@ -21,25 +21,38 @@ module ChronoTest::Matchers
21
21
  @matches.values.all?
22
22
  end
23
23
 
24
- def failure_message_for_should
25
- "expected #{@schema}.#{table} to have ".tap do |message|
26
- message << @matches.map do |(name, type), match|
27
- "a #{name}(#{type}) column" unless match
28
- end.compact.to_sentence
29
- end
24
+ def failure_message
25
+ message_matches("expected #{@schema}.#{table} to have")
26
+ end
27
+
28
+ def failure_message_when_negated
29
+ message_matches("expected #{@schema}.#{table} to not have")
30
30
  end
31
31
 
32
32
  protected
33
33
  def has_column?(name, type)
34
+ column_type(name) == [name, type]
35
+ end
36
+
37
+ def column_type(name)
34
38
  table = "#{@schema}.#{self.table}"
35
39
 
36
- select_rows(<<-SQL, [table, name], 'Check column').first == [name, type]
40
+ select_rows(<<-SQL, [table, name], 'Check column').first
37
41
  SELECT attname, FORMAT_TYPE(atttypid, atttypmod)
38
42
  FROM pg_attribute
39
- WHERE attrelid = $1::regclass::oid
40
- AND attname = $2
43
+ WHERE attrelid = ?::regclass::oid
44
+ AND attname = ?
41
45
  SQL
42
46
  end
47
+
48
+ private
49
+ def message_matches(message)
50
+ (message << ' ').tap do |message|
51
+ message << @matches.map do |(name, type), match|
52
+ "a #{name}(#{type}) column" unless match
53
+ end.compact.to_sentence
54
+ end
55
+ end
43
56
  end
44
57
 
45
58
  def have_columns(*args)
@@ -24,18 +24,22 @@ module ChronoTest::Matchers
24
24
  JOIN pg_class i ON i.oid = d.indexrelid
25
25
  JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(d.indkey)
26
26
  WHERE i.relkind = 'i'
27
- AND t.relname = $1
28
- AND i.relname = $2
27
+ AND t.relname = ?
28
+ AND i.relname = ?
29
29
  AND i.relnamespace = (
30
- SELECT oid FROM pg_namespace WHERE nspname = $3
30
+ SELECT oid FROM pg_namespace WHERE nspname = ?
31
31
  )
32
32
  ORDER BY a.attname
33
33
  SQL
34
34
  end
35
35
 
36
- def failure_message_for_should
36
+ def failure_message
37
37
  "expected #{schema}.#{table} to have a #{name} index on #{columns}"
38
38
  end
39
+
40
+ def failure_message_when_negated
41
+ "expected #{schema}.#{table} to not have a #{name} index on #{columns}"
42
+ end
39
43
  end
40
44
 
41
45
  def have_index(*args)
@@ -14,10 +14,14 @@ module ChronoTest::Matchers
14
14
  'be in schema'
15
15
  end
16
16
 
17
- def failure_message_for_should
17
+ def failure_message
18
18
  "expected to be in schema #@expected, but was in #@current"
19
19
  end
20
20
 
21
+ def failure_message_when_negated
22
+ "expected to be in schema #@current, but was in #@expected"
23
+ end
24
+
21
25
  def matches?(*)
22
26
  @current = select_value(<<-SQL, [], 'Current schema')
23
27
  SHOW search_path
@@ -18,8 +18,8 @@ module ChronoTest::Matchers
18
18
  FROM pg_class c
19
19
  LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
20
20
  WHERE c.relkind = '#{kind}'
21
- AND c.relname = $1
22
- AND n.nspname = $2
21
+ AND c.relname = ?
22
+ AND n.nspname = ?
23
23
  )
24
24
  SQL
25
25
  end
@@ -39,9 +39,13 @@ module ChronoTest::Matchers
39
39
  'be in the public schema'
40
40
  end
41
41
 
42
- def failure_message_for_should
42
+ def failure_message
43
43
  "expected #{table} to exist in the #{public_schema} schema"
44
44
  end
45
+
46
+ def failure_message_when_negated
47
+ "expected #{table} to not exist in the #{public_schema} schema"
48
+ end
45
49
  end
46
50
 
47
51
  def have_public_backing
@@ -63,9 +67,13 @@ module ChronoTest::Matchers
63
67
  'be in the temporal schema'
64
68
  end
65
69
 
66
- def failure_message_for_should
70
+ def failure_message
67
71
  "expected #{table} to exist in the #{temporal_schema} schema"
68
72
  end
73
+
74
+ def failure_message_when_negated
75
+ "expected #{table} to not exist in the #{temporal_schema} schema"
76
+ end
69
77
  end
70
78
 
71
79
  def have_temporal_backing
@@ -91,7 +99,7 @@ module ChronoTest::Matchers
91
99
  'be in history schema'
92
100
  end
93
101
 
94
- def failure_message_for_should
102
+ def failure_message
95
103
  "expected #{table} ".tap do |message|
96
104
  message << [
97
105
  ("to exist in the #{history_schema} schema" unless @existance),
@@ -102,6 +110,17 @@ module ChronoTest::Matchers
102
110
  end
103
111
  end
104
112
 
113
+ def failure_message_when_negated
114
+ "expected #{table} ".tap do |message|
115
+ message << [
116
+ ("to not exist in the #{history_schema} schema" if @existance),
117
+ ("to not inherit from #{temporal_schema}.#{table}" if @inheritance),
118
+ ("to not have a timeline consistency constraint" if @constraint),
119
+ ("to not have history indexes" if @indexes)
120
+ ].compact.to_sentence
121
+ end
122
+ end
123
+
105
124
  private
106
125
  def table_exists?
107
126
  @existance = relation_exists? :in => history_schema
@@ -113,8 +132,8 @@ module ChronoTest::Matchers
113
132
  @inheritance = select_value(<<-SQL, binds, 'Check inheritance') == 't'
114
133
  SELECT EXISTS (
115
134
  SELECT 1 FROM pg_catalog.pg_inherits
116
- WHERE inhrelid = $1::regclass::oid
117
- AND inhparent = $2::regclass::oid
135
+ WHERE inhrelid = ?::regclass::oid
136
+ AND inhparent = ?::regclass::oid
118
137
  )
119
138
  SQL
120
139
  end
@@ -124,8 +143,8 @@ module ChronoTest::Matchers
124
143
 
125
144
  indexes = select_values(<<-SQL, binds, 'Check history indexes')
126
145
  SELECT indexdef FROM pg_indexes
127
- WHERE schemaname = $1
128
- AND tablename = $2
146
+ WHERE schemaname = ?
147
+ AND tablename = ?
129
148
  SQL
130
149
 
131
150
  fqtn = [history_schema, table].join('.')
@@ -146,26 +165,26 @@ module ChronoTest::Matchers
146
165
  end
147
166
 
148
167
  def has_consistency_constraint?
149
- binds = [
150
- connection.timeline_consistency_constraint_name(table), # conname
151
- history_schema, # connamespace
152
- [history_schema, table].join('.'), # conrelid, attrelid
153
- connection.primary_key(table) # attnum
154
- ]
168
+ binds = {
169
+ conname: connection.timeline_consistency_constraint_name(table),
170
+ connamespace: history_schema,
171
+ conrelid: [history_schema, table].join('.'),
172
+ attname: connection.primary_key(table)
173
+ }
155
174
 
156
175
  @constraint = select_value(<<-SQL, binds, 'Check Consistency Constraint') == 't'
157
176
  SELECT EXISTS (
158
177
  SELECT 1 FROM pg_catalog.pg_constraint
159
- WHERE conname = $1
178
+ WHERE conname = :conname
160
179
  AND contype = 'x'
161
- AND conrelid = $3::regclass
180
+ AND conrelid = :conrelid::regclass
162
181
  AND connamespace = (
163
- SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = $2
182
+ SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = :connamespace
164
183
  )
165
184
  AND conkey = (
166
185
  SELECT array_agg(attnum) FROM pg_catalog.pg_attribute
167
- WHERE attname IN ($4, 'validity')
168
- AND attrelid = $3::regclass
186
+ WHERE attname IN (:attname, 'validity')
187
+ AND attrelid = :conrelid::regclass
169
188
  )
170
189
  )
171
190
  SQL
@@ -192,7 +211,7 @@ module ChronoTest::Matchers
192
211
  'be an updatable view'
193
212
  end
194
213
 
195
- def failure_message_for_should
214
+ def failure_message
196
215
  "expected #{table} ".tap do |message|
197
216
  message << [
198
217
  ("to exist in the #{public_schema} schema" unless @existance ),
@@ -204,6 +223,18 @@ module ChronoTest::Matchers
204
223
  end
205
224
  end
206
225
 
226
+ def failure_message_when_negated
227
+ "expected #{table} ".tap do |message|
228
+ message << [
229
+ ("to not exist in the #{public_schema} schema" if @existance ),
230
+ ('to not be an updatable view' if @updatable ),
231
+ ('to not have an INSERT trigger' if @insert_trigger),
232
+ ('to not have an UPDATE trigger' if @update_trigger),
233
+ ('to not have a DELETE trigger' if @delete_trigger)
234
+ ].compact.to_sentence
235
+ end
236
+ end
237
+
207
238
  private
208
239
  def view_exists?
209
240
  @existance = relation_exists? :in => public_schema, :kind => :view
@@ -214,7 +245,7 @@ module ChronoTest::Matchers
214
245
 
215
246
  @updatable = select_value(<<-SQL, binds, 'Check updatable') == 'YES'
216
247
  SELECT is_updatable FROM information_schema.views
217
- WHERE table_schema = $1 AND table_name = $2
248
+ WHERE table_schema = ? AND table_name = ?
218
249
  SQL
219
250
  end
220
251
 
@@ -224,8 +255,8 @@ module ChronoTest::Matchers
224
255
  FROM pg_catalog.pg_trigger t, pg_catalog.pg_class c, pg_catalog.pg_namespace n
225
256
  WHERE t.tgrelid = c.relfilenode
226
257
  AND n.oid = c.relnamespace
227
- AND n.nspname = $1
228
- AND c.relname = $2;
258
+ AND n.nspname = ?
259
+ AND c.relname = ?;
229
260
  SQL
230
261
 
231
262
  @insert_trigger = triggers.include? 'chronomodel_insert'
@@ -25,85 +25,118 @@ describe ChronoModel::TimeMachine do
25
25
  baz = Baz.create :name => 'baz', :bar => bar
26
26
 
27
27
  describe '.chrono?' do
28
+ subject { model.chrono? }
29
+
28
30
  context 'on a temporal model' do
29
- subject { Foo }
30
- it { should be_chrono }
31
+ let(:model) { Foo }
32
+ it { is_expected.to be(true) }
33
+ end
34
+
35
+ context 'on a plain model' do
36
+ let(:model) { Plain }
37
+ it { is_expected.to be(false) }
38
+ end
39
+ end
40
+
41
+ describe '.history?' do
42
+ subject { model.history? }
43
+
44
+ context 'on a temporal parent model' do
45
+ let(:model) { Foo }
46
+ it { is_expected.to be(false) }
47
+ end
48
+
49
+ context 'on a temporal history model' do
50
+ let(:model) { Foo::History }
51
+ it { is_expected.to be(true) }
31
52
  end
32
53
 
33
54
  context 'on a plain model' do
34
- subject { Plain }
35
- it { should_not be_chrono }
55
+ let(:model) { Plain }
56
+ it { expect { subject }.to raise_error(NoMethodError) }
36
57
  end
37
58
  end
38
59
 
60
+ describe '.descendants' do
61
+ subject { Element.descendants }
62
+ it { is_expected.to_not include(Element::History) }
63
+ it { is_expected.to include(Publication) }
64
+ end
65
+
66
+ describe '.descendants_with_history' do
67
+ subject { Element.descendants_with_history }
68
+ it { is_expected.to include(Element::History) }
69
+ it { is_expected.to include(Publication) }
70
+ end
71
+
39
72
  # Specs start here
40
73
  #
41
74
  describe '.chrono_models' do
42
75
  subject { ChronoModel::TimeMachine.chrono_models }
43
76
 
44
- it { should == {
77
+ it { is_expected.to eq(
45
78
  'foos' => Foo::History,
46
79
  'defoos' => Defoo::History,
47
80
  'bars' => Bar::History,
48
81
  'elements' => Element::History
49
- } }
82
+ ) }
50
83
  end
51
84
 
52
85
  describe '#as_of' do
53
86
  describe 'accepts a Time instance' do
54
- it { foo.as_of(Time.now).name.should == 'new foo' }
55
- it { bar.as_of(Time.now).name.should == 'new bar' }
87
+ it { expect(foo.as_of(Time.now).name).to eq 'new foo' }
88
+ it { expect(bar.as_of(Time.now).name).to eq 'new bar' }
56
89
  end
57
90
 
58
91
  describe 'ignores time zones' do
59
- it { foo.as_of(Time.now.in_time_zone('America/Havana')).name.should == 'new foo' }
60
- it { bar.as_of(Time.now.in_time_zone('America/Havana')).name.should == 'new bar' }
92
+ it { expect(foo.as_of(Time.now.in_time_zone('America/Havana')).name).to eq 'new foo' }
93
+ it { expect(bar.as_of(Time.now.in_time_zone('America/Havana')).name).to eq 'new bar' }
61
94
  end
62
95
 
63
96
  describe 'returns records as they were before' do
64
- it { foo.as_of(foo.ts[0]).name.should == 'foo' }
65
- it { foo.as_of(foo.ts[1]).name.should == 'foo bar' }
66
- it { foo.as_of(foo.ts[2]).name.should == 'new foo' }
97
+ it { expect(foo.as_of(foo.ts[0]).name).to eq 'foo' }
98
+ it { expect(foo.as_of(foo.ts[1]).name).to eq 'foo bar' }
99
+ it { expect(foo.as_of(foo.ts[2]).name).to eq 'new foo' }
67
100
 
68
- it { bar.as_of(bar.ts[0]).name.should == 'bar' }
69
- it { bar.as_of(bar.ts[1]).name.should == 'foo bar' }
70
- it { bar.as_of(bar.ts[2]).name.should == 'bar bar' }
71
- it { bar.as_of(bar.ts[3]).name.should == 'new bar' }
101
+ it { expect(bar.as_of(bar.ts[0]).name).to eq 'bar' }
102
+ it { expect(bar.as_of(bar.ts[1]).name).to eq 'foo bar' }
103
+ it { expect(bar.as_of(bar.ts[2]).name).to eq 'bar bar' }
104
+ it { expect(bar.as_of(bar.ts[3]).name).to eq 'new bar' }
72
105
  end
73
106
 
74
107
  describe 'takes care of associated records' do
75
- it { foo.as_of(foo.ts[0]).bars.should == [] }
76
- it { foo.as_of(foo.ts[1]).bars.should == [] }
77
- it { foo.as_of(foo.ts[2]).bars.should == [bar] }
108
+ it { expect(foo.as_of(foo.ts[0]).bars).to eq [] }
109
+ it { expect(foo.as_of(foo.ts[1]).bars).to eq [] }
110
+ it { expect(foo.as_of(foo.ts[2]).bars).to eq [bar] }
78
111
 
79
- it { foo.as_of(foo.ts[2]).bars.first.name.should == 'foo bar' }
112
+ it { expect(foo.as_of(foo.ts[2]).bars.first.name).to eq 'foo bar' }
80
113
 
81
114
 
82
- it { foo.as_of(bar.ts[0]).bars.should == [bar] }
83
- it { foo.as_of(bar.ts[1]).bars.should == [bar] }
84
- it { foo.as_of(bar.ts[2]).bars.should == [bar] }
85
- it { foo.as_of(bar.ts[3]).bars.should == [bar] }
115
+ it { expect(foo.as_of(bar.ts[0]).bars).to eq [bar] }
116
+ it { expect(foo.as_of(bar.ts[1]).bars).to eq [bar] }
117
+ it { expect(foo.as_of(bar.ts[2]).bars).to eq [bar] }
118
+ it { expect(foo.as_of(bar.ts[3]).bars).to eq [bar] }
86
119
 
87
- it { foo.as_of(bar.ts[0]).bars.first.name.should == 'bar' }
88
- it { foo.as_of(bar.ts[1]).bars.first.name.should == 'foo bar' }
89
- it { foo.as_of(bar.ts[2]).bars.first.name.should == 'bar bar' }
90
- it { foo.as_of(bar.ts[3]).bars.first.name.should == 'new bar' }
120
+ it { expect(foo.as_of(bar.ts[0]).bars.first.name).to eq 'bar' }
121
+ it { expect(foo.as_of(bar.ts[1]).bars.first.name).to eq 'foo bar' }
122
+ it { expect(foo.as_of(bar.ts[2]).bars.first.name).to eq 'bar bar' }
123
+ it { expect(foo.as_of(bar.ts[3]).bars.first.name).to eq 'new bar' }
91
124
 
92
125
 
93
- it { bar.as_of(bar.ts[0]).foo.should == foo }
94
- it { bar.as_of(bar.ts[1]).foo.should == foo }
95
- it { bar.as_of(bar.ts[2]).foo.should == foo }
96
- it { bar.as_of(bar.ts[3]).foo.should == foo }
126
+ it { expect(bar.as_of(bar.ts[0]).foo).to eq foo }
127
+ it { expect(bar.as_of(bar.ts[1]).foo).to eq foo }
128
+ it { expect(bar.as_of(bar.ts[2]).foo).to eq foo }
129
+ it { expect(bar.as_of(bar.ts[3]).foo).to eq foo }
97
130
 
98
- it { bar.as_of(bar.ts[0]).foo.name.should == 'foo bar' }
99
- it { bar.as_of(bar.ts[1]).foo.name.should == 'foo bar' }
100
- it { bar.as_of(bar.ts[2]).foo.name.should == 'new foo' }
101
- it { bar.as_of(bar.ts[3]).foo.name.should == 'new foo' }
131
+ it { expect(bar.as_of(bar.ts[0]).foo.name).to eq 'foo bar' }
132
+ it { expect(bar.as_of(bar.ts[1]).foo.name).to eq 'foo bar' }
133
+ it { expect(bar.as_of(bar.ts[2]).foo.name).to eq 'new foo' }
134
+ it { expect(bar.as_of(bar.ts[3]).foo.name).to eq 'new foo' }
102
135
  end
103
136
 
104
137
  it 'doesn\'t raise RecordNotFound when no history records are found' do
105
138
  expect { foo.as_of(1.minute.ago) }.to_not raise_error
106
- foo.as_of(1.minute.ago).should be_nil
139
+ expect(foo.as_of(1.minute.ago)).to be(nil)
107
140
  end
108
141
 
109
142
 
@@ -118,164 +151,161 @@ describe ChronoModel::TimeMachine do
118
151
  hidden = ts_eval { Defoo.create! :name => 'hidden 1', :active => false }
119
152
  ts_eval(hidden) { update_attributes! :name => 'hidden 2' }
120
153
 
121
- it { Defoo.as_of(active.ts[0]).map(&:name).should == ['active 1'] }
122
- it { Defoo.as_of(active.ts[1]).map(&:name).should == ['active 2'] }
123
- it { Defoo.as_of(hidden.ts[0]).map(&:name).should == ['active 2'] }
124
- it { Defoo.as_of(hidden.ts[1]).map(&:name).should == ['active 2'] }
154
+ it { expect(Defoo.as_of(active.ts[0]).map(&:name)).to eq ['active 1'] }
155
+ it { expect(Defoo.as_of(active.ts[1]).map(&:name)).to eq ['active 2'] }
156
+ it { expect(Defoo.as_of(hidden.ts[0]).map(&:name)).to eq ['active 2'] }
157
+ it { expect(Defoo.as_of(hidden.ts[1]).map(&:name)).to eq ['active 2'] }
125
158
 
126
- it { Defoo.unscoped.as_of(active.ts[0]).map(&:name).should == ['active 1'] }
127
- it { Defoo.unscoped.as_of(active.ts[1]).map(&:name).should == ['active 2'] }
128
- it { Defoo.unscoped.as_of(hidden.ts[0]).map(&:name).should == ['active 2', 'hidden 1'] }
129
- it { Defoo.unscoped.as_of(hidden.ts[1]).map(&:name).should == ['active 2', 'hidden 2'] }
159
+ it { expect(Defoo.unscoped.as_of(active.ts[0]).map(&:name)).to eq ['active 1'] }
160
+ it { expect(Defoo.unscoped.as_of(active.ts[1]).map(&:name)).to eq ['active 2'] }
161
+ it { expect(Defoo.unscoped.as_of(hidden.ts[0]).map(&:name)).to eq ['active 2', 'hidden 1'] }
162
+ it { expect(Defoo.unscoped.as_of(hidden.ts[1]).map(&:name)).to eq ['active 2', 'hidden 2'] }
130
163
  end
131
164
 
132
165
  describe 'proxies from non-temporal models to temporal ones' do
133
- it { baz.as_of(bar.ts[0]).name.should == 'baz' }
134
- it { baz.as_of(bar.ts[1]).name.should == 'baz' }
135
- it { baz.as_of(bar.ts[2]).name.should == 'baz' }
136
- it { baz.as_of(bar.ts[3]).name.should == 'baz' }
166
+ it { expect(baz.as_of(bar.ts[0]).name).to eq 'baz' }
167
+ it { expect(baz.as_of(bar.ts[1]).name).to eq 'baz' }
168
+ it { expect(baz.as_of(bar.ts[2]).name).to eq 'baz' }
169
+ it { expect(baz.as_of(bar.ts[3]).name).to eq 'baz' }
137
170
 
138
- it { baz.as_of(bar.ts[0]).bar.name.should == 'bar' }
139
- it { baz.as_of(bar.ts[1]).bar.name.should == 'foo bar' }
140
- it { baz.as_of(bar.ts[2]).bar.name.should == 'bar bar' }
141
- it { baz.as_of(bar.ts[3]).bar.name.should == 'new bar' }
171
+ it { expect(baz.as_of(bar.ts[0]).bar.name).to eq 'bar' }
172
+ it { expect(baz.as_of(bar.ts[1]).bar.name).to eq 'foo bar' }
173
+ it { expect(baz.as_of(bar.ts[2]).bar.name).to eq 'bar bar' }
174
+ it { expect(baz.as_of(bar.ts[3]).bar.name).to eq 'new bar' }
142
175
 
143
- it { baz.as_of(bar.ts[0]).bar.foo.name.should == 'foo bar' }
144
- it { baz.as_of(bar.ts[1]).bar.foo.name.should == 'foo bar' }
145
- it { baz.as_of(bar.ts[2]).bar.foo.name.should == 'new foo' }
146
- it { baz.as_of(bar.ts[3]).bar.foo.name.should == 'new foo' }
176
+ it { expect(baz.as_of(bar.ts[0]).bar.foo.name).to eq 'foo bar' }
177
+ it { expect(baz.as_of(bar.ts[1]).bar.foo.name).to eq 'foo bar' }
178
+ it { expect(baz.as_of(bar.ts[2]).bar.foo.name).to eq 'new foo' }
179
+ it { expect(baz.as_of(bar.ts[3]).bar.foo.name).to eq 'new foo' }
147
180
  end
148
181
  end
149
182
 
150
183
  describe '#history' do
151
184
  describe 'returns historical instances' do
152
- it { foo.history.should have(3).entries }
153
- it { foo.history.map(&:name).should == ['foo', 'foo bar', 'new foo'] }
185
+ it { expect(foo.history.size).to eq(3) }
186
+ it { expect(foo.history.map(&:name)).to eq ['foo', 'foo bar', 'new foo'] }
154
187
 
155
- it { bar.history.should have(4).entries }
156
- it { bar.history.map(&:name).should == ['bar', 'foo bar', 'bar bar', 'new bar'] }
188
+ it { expect(bar.history.size).to eq(4) }
189
+ it { expect(bar.history.map(&:name)).to eq ['bar', 'foo bar', 'bar bar', 'new bar'] }
157
190
  end
158
191
 
159
192
  describe 'does not return read only records' do
160
- it { foo.history.all?(&:readonly?).should_not be_true }
161
- it { bar.history.all?(&:readonly?).should_not be_true }
193
+ it { expect(foo.history.all?(&:readonly?)).to be(false) }
194
+ it { expect(bar.history.all?(&:readonly?)).to be(false) }
162
195
  end
163
196
 
164
197
  describe 'takes care of associated records' do
165
198
  subject { foo.history.map {|f| f.bars.first.try(:name)} }
166
- it { should == [nil, 'foo bar', 'new bar'] }
199
+ it { is_expected.to eq [nil, 'foo bar', 'new bar'] }
167
200
  end
168
201
 
169
202
  describe 'does not return read only associated records' do
170
- it { foo.history[2].bars.all?(&:readonly?).should_not be_true }
171
- it { bar.history.all? {|b| b.foo.readonly?}.should_not be_true }
203
+ it { expect(foo.history[2].bars.all?(&:readonly?)).to_not be(true) }
204
+ it { expect(bar.history.all? {|b| b.foo.readonly?}).to_not be(true) }
172
205
  end
173
206
 
174
207
  describe 'allows a custom select list' do
175
- it { foo.history.select(:id).first.attributes.keys.should == %w( id as_of_time ) }
208
+ it { expect(foo.history.select(:id).first.attributes.keys).to eq %w( id ) }
176
209
  end
177
210
 
178
211
  describe 'does not add as_of_time when there are aggregates' do
179
- it { foo.history.select('max (id)').to_sql.should_not =~ /as_of_time/ } # The id is automatically added by ActiveRecord
180
- it { foo.history.select('max(id) as foo, min(id) as bar').order(nil).first.attributes.keys.should == %w( foo bar id ) }
212
+ it { expect(foo.history.select('max(id)').to_sql).to_not match /as_of_time/ }
213
+
214
+ it { expect(foo.history.except(:order).select('max(id) as foo, min(id) as bar').group('id').first.attributes.keys).to eq %w( id foo bar ) }
181
215
  end
182
216
 
183
217
  context 'with STI models' do
184
218
  pub = ts_eval { Publication.create! :title => 'wrong title' }
185
219
  ts_eval(pub) { update_attributes! :title => 'correct title' }
186
220
 
187
- it { pub.history.map(&:title).should == ['wrong title', 'correct title'] }
188
- end
189
-
190
- describe 'allows a custom order list' do
191
- it { expect { foo.history.order('id') }.to_not raise_error }
192
- it { foo.history.order('id').to_sql.should =~ /order by id/i }
221
+ it { expect(pub.history.map(&:title)).to eq ['wrong title', 'correct title'] }
193
222
  end
194
223
 
195
224
  context '.sorted' do
196
225
  describe 'orders by recorded_at, hid' do
197
- it { foo.history.sorted.to_sql.should =~ /order by .+"recorded_at", .+"hid"/i }
226
+ it { expect(foo.history.sorted.to_sql).to match /order by .+"recorded_at", .+"hid"/i }
198
227
  end
199
228
  end
200
-
201
229
  end
202
230
 
203
231
  describe '#pred' do
204
232
  context 'on the first history entry' do
205
233
  subject { foo.history.first.pred }
206
- it { should be_nil }
234
+ it { is_expected.to be(nil) }
207
235
  end
208
236
 
209
237
  context 'on the second history entry' do
210
238
  subject { foo.history.second.pred }
211
- it { should == foo.history.first }
239
+ it { is_expected.to eq foo.history.first }
212
240
  end
213
241
 
214
242
  context 'on the last history entry' do
215
243
  subject { foo.history.last.pred }
216
- it { should == foo.history[foo.history.size - 2] }
244
+ it { is_expected.to eq foo.history[foo.history.size - 2] }
217
245
  end
218
246
  end
219
247
 
220
248
  describe '#succ' do
221
249
  context 'on the first history entry' do
222
250
  subject { foo.history.first.succ }
223
- it { should == foo.history.second }
251
+ it { is_expected.to eq foo.history.second }
224
252
  end
225
253
 
226
254
  context 'on the second history entry' do
227
255
  subject { foo.history.second.succ }
228
- it { should == foo.history.third }
256
+ it { is_expected.to eq foo.history.third }
229
257
  end
230
258
 
231
259
  context 'on the last history entry' do
232
260
  subject { foo.history.last.succ }
233
- it { should be_nil }
261
+ it { is_expected.to be(nil) }
234
262
  end
235
263
  end
236
264
 
237
265
  describe '#first' do
238
266
  subject { foo.history.sample.first }
239
- it { should == foo.history.first }
267
+ it { is_expected.to eq foo.history.first }
240
268
  end
241
269
 
242
270
  describe '#last' do
243
271
  subject { foo.history.sample.last }
244
- it { should == foo.history.last }
272
+ it { is_expected.to eq foo.history.last }
245
273
  end
246
274
 
247
275
  describe '#current_version' do
248
276
  describe 'on plain records' do
249
277
  subject { foo.current_version }
250
- it { should == foo }
278
+ it { is_expected.to eq foo }
251
279
  end
252
280
 
253
281
  describe 'from #as_of' do
254
282
  subject { foo.as_of(Time.now) }
255
- it { should == foo }
283
+ it { is_expected.to eq foo }
256
284
  end
257
285
 
258
286
  describe 'on historical records' do
259
287
  subject { foo.history.sample.current_version }
260
- it { should == foo }
288
+ it { is_expected.to eq foo }
261
289
  end
262
290
  end
263
291
 
264
292
  describe '#historical?' do
293
+ subject { record.historical? }
294
+
265
295
  describe 'on plain records' do
266
- subject { foo.historical? }
267
- it { should be_false }
296
+ let(:record) { foo }
297
+ it { is_expected.to be(false) }
268
298
  end
269
299
 
270
300
  describe 'on historical records' do
271
301
  describe 'from #history' do
272
- subject { foo.history.first }
273
- it { should be_true }
302
+ let(:record) { foo.history.first }
303
+ it { is_expected.to be(true) }
274
304
  end
275
305
 
276
306
  describe 'from #as_of' do
277
- subject { foo.as_of(Time.now) }
278
- it { should be_true }
307
+ let(:record) { foo.as_of(Time.now) }
308
+ it { is_expected.to be(true) }
279
309
  end
280
310
  end
281
311
  end
@@ -302,24 +332,26 @@ describe ChronoModel::TimeMachine do
302
332
  it { expect { rec.reload }.to raise_error(ActiveRecord::RecordNotFound) }
303
333
 
304
334
  describe 'does not delete its history' do
335
+ subject { record.name }
336
+
305
337
  context do
306
- subject { rec.as_of(rec.ts.first) }
307
- its(:name) { should == 'alive foo' }
338
+ let(:record) { rec.as_of(rec.ts.first) }
339
+ it { is_expected.to eq 'alive foo' }
308
340
  end
309
341
 
310
342
  context do
311
- subject { rec.as_of(rec.ts.last) }
312
- its(:name) { should == 'dying foo' }
343
+ let(:record) { rec.as_of(rec.ts.last) }
344
+ it { is_expected.to eq 'dying foo' }
313
345
  end
314
346
 
315
347
  context do
316
- subject { Foo.as_of(rec.ts.first).where(:fooity => 42).first }
317
- its(:name) { should == 'alive foo' }
348
+ let(:record) { Foo.as_of(rec.ts.first).where(:fooity => 42).first }
349
+ it { is_expected.to eq 'alive foo' }
318
350
  end
319
351
 
320
352
  context do
321
353
  subject { Foo.history.where(:fooity => 42).map(&:name) }
322
- it { should == ['alive foo', 'dying foo'] }
354
+ it { is_expected.to eq ['alive foo', 'dying foo'] }
323
355
  end
324
356
  end
325
357
  end
@@ -339,14 +371,14 @@ describe ChronoModel::TimeMachine do
339
371
  describe 'on records having an :has_many relationship' do
340
372
  describe 'by default returns timestamps of the record only' do
341
373
  subject { split.call(foo.timeline) }
342
- its(:size) { should == foo.ts.size }
343
- it { should == timestamps_from.call(foo) }
374
+ it { expect(subject.size).to eq foo.ts.size }
375
+ it { is_expected.to eq timestamps_from.call(foo) }
344
376
  end
345
377
 
346
378
  describe 'when asked, returns timestamps including the related objects' do
347
379
  subject { split.call(foo.timeline(:with => :bars)) }
348
- its(:size) { should == foo.ts.size + bar.ts.size }
349
- it { should == timestamps_from.call(foo, *foo.bars) }
380
+ it { expect(subject.size).to eq(foo.ts.size + bar.ts.size) }
381
+ it { is_expected.to eq(timestamps_from.call(foo, *foo.bars)) }
350
382
  end
351
383
  end
352
384
 
@@ -364,8 +396,8 @@ describe ChronoModel::TimeMachine do
364
396
  }
365
397
  end
366
398
 
367
- its(:size) { should == expected.size }
368
- it { should == expected }
399
+ it { expect(subject.size).to eq expected.size }
400
+ it { is_expected.to eq expected }
369
401
  end
370
402
  end
371
403
 
@@ -373,8 +405,8 @@ describe ChronoModel::TimeMachine do
373
405
  subject { split.call(baz.timeline) }
374
406
 
375
407
  describe 'returns timestamps of its temporal associations' do
376
- its(:size) { should == bar.ts.size }
377
- it { should == timestamps_from.call(bar) }
408
+ it { expect(subject.size).to eq bar.ts.size }
409
+ it { is_expected.to eq timestamps_from.call(bar) }
378
410
  end
379
411
  end
380
412
  end
@@ -383,13 +415,13 @@ describe ChronoModel::TimeMachine do
383
415
  context 'on plain records' do
384
416
  context 'having history' do
385
417
  subject { bar.last_changes }
386
- it { should == {'name' => ['bar bar', 'new bar']} }
418
+ it { is_expected.to eq('name' => ['bar bar', 'new bar']) }
387
419
  end
388
420
 
389
421
  context 'without history' do
390
422
  let(:record) { Bar.create!(:name => 'foreveralone') }
391
423
  subject { record.last_changes }
392
- it { should be_nil }
424
+ it { is_expected.to be_nil }
393
425
  after { record.destroy.history.delete_all } # UGLY
394
426
  end
395
427
  end
@@ -397,56 +429,46 @@ describe ChronoModel::TimeMachine do
397
429
  context 'on history records' do
398
430
  context 'at the beginning of the timeline' do
399
431
  subject { bar.history.first.last_changes }
400
- it { should be_nil }
432
+ it { is_expected.to be_nil }
401
433
  end
402
434
 
403
435
  context 'in the middle of the timeline' do
404
436
  subject { bar.history.second.last_changes }
405
- it { should == {'name' => ['bar', 'foo bar']} }
437
+ it { is_expected.to eq('name' => ['bar', 'foo bar']) }
406
438
  end
407
439
  end
408
440
  end
409
441
 
410
442
  describe '#changes_against' do
411
443
  context 'can compare records against history' do
412
- it { bar.changes_against(bar.history.first).should ==
413
- {'name' => ['bar', 'new bar']} }
414
-
415
- it { bar.changes_against(bar.history.second).should ==
416
- {'name' => ['foo bar', 'new bar']} }
417
-
418
- it { bar.changes_against(bar.history.third).should ==
419
- {'name' => ['bar bar', 'new bar']} }
420
-
421
- it { bar.changes_against(bar.history.last).should == {} }
444
+ it { expect(bar.changes_against(bar.history.first)).to eq('name' => ['bar', 'new bar']) }
445
+ it { expect(bar.changes_against(bar.history.second)).to eq('name' => ['foo bar', 'new bar']) }
446
+ it { expect(bar.changes_against(bar.history.third)).to eq('name' => ['bar bar', 'new bar']) }
447
+ it { expect(bar.changes_against(bar.history.last)).to eq({}) }
422
448
  end
423
449
 
424
450
  context 'can compare history against history' do
425
- it { bar.history.first.changes_against(bar.history.third).should ==
426
- {'name' => ['bar bar', 'bar']} }
427
-
428
- it { bar.history.second.changes_against(bar.history.third).should ==
429
- {'name' => ['bar bar', 'foo bar']} }
430
-
431
- it { bar.history.third.changes_against(bar.history.third).should == {} }
451
+ it { expect(bar.history.first.changes_against(bar.history.third)).to eq('name' => ['bar bar', 'bar']) }
452
+ it { expect(bar.history.second.changes_against(bar.history.third)).to eq('name' => ['bar bar', 'foo bar']) }
453
+ it { expect(bar.history.third.changes_against(bar.history.third)).to eq({}) }
432
454
  end
433
455
  end
434
456
 
435
457
  describe '#pred' do
436
458
  context 'on records having history' do
437
459
  subject { bar.pred }
438
- its(:name) { should == 'bar bar' }
460
+ it { expect(subject.name).to eq 'bar bar' }
439
461
  end
440
462
 
441
463
  context 'when there is enough history' do
442
464
  subject { bar.pred.pred.pred.pred }
443
- its(:name) { should == 'bar' }
465
+ it { expect(subject.name).to eq 'bar' }
444
466
  end
445
467
 
446
468
  context 'when no history is recorded' do
447
469
  let(:record) { Bar.create!(:name => 'quuuux') }
448
470
  subject { record.pred }
449
- it { should be_nil }
471
+ it { is_expected.to be(nil) }
450
472
  after { record.destroy.history.delete_all }
451
473
  end
452
474
  end
@@ -462,9 +484,9 @@ describe ChronoModel::TimeMachine do
462
484
  describe ['#', attr].join do
463
485
  subject { record.public_send(attr) }
464
486
 
465
- it { should be_present }
466
- it { should be_a(Time) }
467
- it { should be_utc }
487
+ it { is_expected.to be_present }
488
+ it { is_expected.to be_a(Time) }
489
+ it { is_expected.to be_utc }
468
490
  end
469
491
  end
470
492
  end
@@ -484,7 +506,7 @@ describe ChronoModel::TimeMachine do
484
506
  describe ['#', attr].join do
485
507
  subject { record.public_send(attr) }
486
508
 
487
- it { should be_nil }
509
+ it { is_expected.to be(nil) }
488
510
  end
489
511
  end
490
512
  end
@@ -499,38 +521,38 @@ describe ChronoModel::TimeMachine do
499
521
  after(:all) { foos.each(&:destroy); bars.each(&:destroy) }
500
522
 
501
523
  describe '.as_of' do
502
- it { Foo.as_of(1.month.ago).should == [] }
524
+ it { expect(Foo.as_of(1.month.ago)).to eq [] }
503
525
 
504
- it { Foo.as_of(foos[0].ts[0]).should == [foo, foos[0]] }
505
- it { Foo.as_of(foos[1].ts[0]).should == [foo, foos[0], foos[1]] }
506
- it { Foo.as_of(Time.now ).should == [foo, foos[0], foos[1]] }
526
+ it { expect(Foo.as_of(foos[0].ts[0])).to eq [foo, foos[0]] }
527
+ it { expect(Foo.as_of(foos[1].ts[0])).to eq [foo, foos[0], foos[1]] }
528
+ it { expect(Foo.as_of(Time.now )).to eq [foo, foos[0], foos[1]] }
507
529
 
508
- it { Bar.as_of(foos[1].ts[0]).should == [bar] }
530
+ it { expect(Bar.as_of(foos[1].ts[0])).to eq [bar] }
509
531
 
510
- it { Bar.as_of(bars[0].ts[0]).should == [bar, bars[0]] }
511
- it { Bar.as_of(bars[1].ts[0]).should == [bar, bars[0], bars[1]] }
512
- it { Bar.as_of(Time.now ).should == [bar, bars[0], bars[1]] }
532
+ it { expect(Bar.as_of(bars[0].ts[0])).to eq [bar, bars[0]] }
533
+ it { expect(Bar.as_of(bars[1].ts[0])).to eq [bar, bars[0], bars[1]] }
534
+ it { expect(Bar.as_of(Time.now )).to eq [bar, bars[0], bars[1]] }
513
535
 
514
536
  # Associations
515
537
  context do
516
- subject { foos[0] }
538
+ subject { foos[0].id }
517
539
 
518
- it { Foo.as_of(foos[0].ts[0]).find(subject).bars.should == [] }
519
- it { Foo.as_of(foos[1].ts[0]).find(subject).bars.should == [] }
520
- it { Foo.as_of(bars[0].ts[0]).find(subject).bars.should == [bars[0]] }
521
- it { Foo.as_of(bars[1].ts[0]).find(subject).bars.should == [bars[0]] }
522
- it { Foo.as_of(Time.now ).find(subject).bars.should == [bars[0]] }
540
+ it { expect(Foo.as_of(foos[0].ts[0]).find(subject).bars).to eq [] }
541
+ it { expect(Foo.as_of(foos[1].ts[0]).find(subject).bars).to eq [] }
542
+ it { expect(Foo.as_of(bars[0].ts[0]).find(subject).bars).to eq [bars[0]] }
543
+ it { expect(Foo.as_of(bars[1].ts[0]).find(subject).bars).to eq [bars[0]] }
544
+ it { expect(Foo.as_of(Time.now ).find(subject).bars).to eq [bars[0]] }
523
545
  end
524
546
 
525
547
  context do
526
- subject { foos[1] }
548
+ subject { foos[1].id }
527
549
 
528
550
  it { expect { Foo.as_of(foos[0].ts[0]).find(subject) }.to raise_error(ActiveRecord::RecordNotFound) }
529
551
  it { expect { Foo.as_of(foos[1].ts[0]).find(subject) }.to_not raise_error }
530
552
 
531
- it { Foo.as_of(bars[0].ts[0]).find(subject).bars.should == [] }
532
- it { Foo.as_of(bars[1].ts[0]).find(subject).bars.should == [bars[1]] }
533
- it { Foo.as_of(Time.now ).find(subject).bars.should == [bars[1]] }
553
+ it { expect(Foo.as_of(bars[0].ts[0]).find(subject).bars).to eq [] }
554
+ it { expect(Foo.as_of(bars[1].ts[0]).find(subject).bars).to eq [bars[1]] }
555
+ it { expect(Foo.as_of(Time.now ).find(subject).bars).to eq [bars[1]] }
534
556
  end
535
557
  end
536
558
 
@@ -543,17 +565,17 @@ describe ChronoModel::TimeMachine do
543
565
  ['bar', 'foo bar', 'bar bar', 'new bar', 'bar 0', 'bar 1']
544
566
  }
545
567
 
546
- it { Foo.history.all.map(&:name).should == foo_history }
547
- it { Bar.history.all.map(&:name).should == bar_history }
568
+ it { expect(Foo.history.all.map(&:name)).to eq foo_history }
569
+ it { expect(Bar.history.all.map(&:name)).to eq bar_history }
548
570
  end
549
571
 
550
572
  describe '.time_query' do
551
- it { Foo.history.time_query(:after, :now, inclusive: true ).count.should == 3 }
552
- it { Foo.history.time_query(:after, :now, inclusive: false).count.should == 0 }
553
- it { Foo.history.time_query(:before, :now, inclusive: true ).count.should == 5 }
554
- it { Foo.history.time_query(:before, :now, inclusive: false).count.should == 2 }
573
+ it { expect(Foo.history.time_query(:after, :now, inclusive: true ).count).to eq 3 }
574
+ it { expect(Foo.history.time_query(:after, :now, inclusive: false).count).to eq 0 }
575
+ it { expect(Foo.history.time_query(:before, :now, inclusive: true ).count).to eq 5 }
576
+ it { expect(Foo.history.time_query(:before, :now, inclusive: false).count).to eq 2 }
555
577
 
556
- it { Foo.history.past.size.should == 2 }
578
+ it { expect(Foo.history.past.size).to eq 2 }
557
579
  end
558
580
 
559
581
  end
@@ -571,10 +593,10 @@ describe ChronoModel::TimeMachine do
571
593
  end
572
594
 
573
595
  it "generate only a single history record" do
574
- r1.history.should have(2).entries
596
+ expect(r1.history.size).to eq(2)
575
597
 
576
- r1.history.first.name.should == 'xact test'
577
- r1.history.last.name.should == 'does work'
598
+ expect(r1.history.first.name).to eq 'xact test'
599
+ expect(r1.history.last.name).to eq 'does work'
578
600
  end
579
601
  end
580
602
 
@@ -589,9 +611,8 @@ describe ChronoModel::TimeMachine do
589
611
  end
590
612
 
591
613
  it 'generates a single history record' do
592
- r2.history.should have(1).entry
593
-
594
- r2.history.first.name.should == 'I am Foo'
614
+ expect(r2.history.size).to eq(1)
615
+ expect(r2.history.first.name).to eq 'I am Foo'
595
616
  end
596
617
  end
597
618
 
@@ -603,7 +624,7 @@ describe ChronoModel::TimeMachine do
603
624
  end
604
625
 
605
626
  it 'does not generate any history' do
606
- Foo.history.where(:id => r3.id).should be_empty
627
+ expect(Foo.history.where(:id => r3.id)).to be_empty
607
628
  end
608
629
  end
609
630
  end
@@ -620,9 +641,8 @@ describe ChronoModel::TimeMachine do
620
641
  subject.reload
621
642
  end
622
643
 
623
- it { should be_a(Bar::History) }
624
- it { should be_true }
625
- its(:name) { should == 'modified bar history' }
644
+ it { is_expected.to be_a(Bar::History) }
645
+ it { expect(subject.name).to eq 'modified bar history' }
626
646
  end
627
647
 
628
648
  describe '#save!' do
@@ -634,9 +654,8 @@ describe ChronoModel::TimeMachine do
634
654
  subject.reload
635
655
  end
636
656
 
637
- it { should be_a(Bar::History) }
638
- it { should be_true }
639
- its(:name) { should == 'another modified bar history' }
657
+ it { is_expected.to be_a(Bar::History) }
658
+ it { expect(subject.name).to eq 'another modified bar history' }
640
659
  end
641
660
  end
642
661