acts_as_versioned-decisiv 3.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.
@@ -0,0 +1,7 @@
1
+ module ActiveRecord
2
+ module Acts
3
+ module Versioned
4
+ VERSION = '3.2.0'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,63 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ require "bundler/setup"
4
+ Bundler.require
5
+ require 'acts_as_versioned'
6
+ require 'active_record/base'
7
+ require 'database_cleaner'
8
+ require 'minitest/autorun'
9
+ require 'logger'
10
+
11
+ TEST_ROOT = File.expand_path('./test')
12
+ ActiveRecord::Base.logger = nil # Logger.new("#{TEST_ROOT}/debug.log")
13
+ ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
14
+ DatabaseCleaner.strategy = :transaction
15
+
16
+ require 'lib/schema'
17
+ require 'lib/models'
18
+ require 'lib/factories'
19
+ require 'lib/fixtures'
20
+
21
+ class AAVTestCase < MiniTest::Spec
22
+
23
+ before { DatabaseCleaner.start }
24
+ after { DatabaseCleaner.clean }
25
+
26
+ protected
27
+
28
+ def authors(name)
29
+ case name
30
+ when :caged then Author.find_by_name('caged')
31
+ when :mly then Author.find_by_name('mly')
32
+ end
33
+ end
34
+
35
+ def pages(name)
36
+ case name
37
+ when :welcome then Page.find_by_title('Welcome to the weblog')
38
+ end
39
+ end
40
+
41
+ def page_versions(name)
42
+ case name
43
+ when :welcome_1 then Page::Version.find_by_title('Welcome to the weblg')
44
+ when :welcome_2 then Page::Version.find_by_title('Welcome to the weblog')
45
+ end
46
+ end
47
+
48
+ def locked_pages(name)
49
+ case name
50
+ when :welcome then LockedPage.find_by_title('Welcome to the weblog')
51
+ when :thinking then LockedPage.find_by_title('So I was thinking')
52
+ end
53
+ end
54
+
55
+ def landmarks(name)
56
+ case name
57
+ when :washington then Landmark.find_by_name('Washington, D.C.')
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+
@@ -0,0 +1,36 @@
1
+ require 'factory_girl'
2
+
3
+ module Seed
4
+ class Page < ActiveRecord::Base ; self.table_name = 'pages' ; end
5
+ class PageVersion < ActiveRecord::Base ; self.table_name = 'page_versions' ; end
6
+ class LockedPage < ActiveRecord::Base ; self.table_name = 'locked_pages' ; end
7
+ class LockedPageRevision < ActiveRecord::Base ; self.table_name = 'locked_pages_revisions' ; end
8
+ class Author < ActiveRecord::Base ; self.table_name = 'authors' ; end
9
+ class Widget < ActiveRecord::Base ; self.table_name = 'widgets' ; end
10
+ class WidgetVersion < ActiveRecord::Base ; self.table_name = 'widget_versions' ; end
11
+ class Landmark < ActiveRecord::Base ; self.table_name = 'landmarks' ; end
12
+ class LandmarkVersion < ActiveRecord::Base ; self.table_name = 'landmark_versions' ; end
13
+ end
14
+
15
+ FactoryGirl.define do
16
+
17
+ factory :page do
18
+ title { Forgery(:lorem_ipsum).words(4) }
19
+ body { Forgery(:lorem_ipsum).words(30) }
20
+ end
21
+
22
+ factory :locked_page do
23
+ title { Forgery(:lorem_ipsum).words(4) }
24
+ end
25
+
26
+ # Seeds
27
+
28
+ factory :seed_author, :class => Seed::Author
29
+ factory :seed_page, :class => Seed::Page
30
+ factory :seed_page_version, :class => Seed::PageVersion
31
+ factory :seed_locked_page, :class => Seed::LockedPage
32
+ factory :seed_locked_page_rev, :class => Seed::LockedPageRevision
33
+ factory :seed_landmark, :class => Seed::Landmark
34
+ factory :seed_landmark_version, :class => Seed::LandmarkVersion
35
+
36
+ end
@@ -0,0 +1,57 @@
1
+
2
+ # Authors
3
+
4
+ @caged = FactoryGirl.create :seed_author, :name => 'caged'
5
+ @mly = FactoryGirl.create :seed_author, :name => 'mly'
6
+
7
+ # Pages
8
+
9
+ @welcome_page = FactoryGirl.create :seed_page,
10
+ :title => 'Welcome to the weblog', :body => 'Such a lovely day',
11
+ :version => 24, :author_id => @caged.id, :revisor_id => @caged.id
12
+
13
+ FactoryGirl.create :seed_page_version,
14
+ :title => 'Welcome to the weblg', :body => 'Such a lovely day',
15
+ :version => 23, :author_id => @mly.id, :revisor_id => @mly.id,
16
+ :page_id => @welcome_page.id
17
+
18
+ FactoryGirl.create :seed_page_version,
19
+ :title => 'Welcome to the weblog', :body => 'Such a lovely day',
20
+ :version => 24, :author_id => @caged, :revisor_id => @caged,
21
+ :page_id => @welcome_page.id
22
+
23
+ # Locked Pages
24
+
25
+ @welcome_lpage = FactoryGirl.create :seed_locked_page,
26
+ :title => 'Welcome to the weblog', :lock_version => 24, :type => 'LockedPage'
27
+
28
+ FactoryGirl.create :seed_locked_page_rev,
29
+ :title => 'Welcome to the weblg', :lock_version => 23, :version_type => 'LockedPage',
30
+ :page_id => @welcome_lpage.id
31
+
32
+ FactoryGirl.create :seed_locked_page_rev,
33
+ :title => 'Welcome to the weblog', :lock_version => 24, :version_type => 'LockedPage',
34
+ :page_id => @welcome_lpage.id
35
+
36
+ @thinking_lpage = FactoryGirl.create :seed_locked_page,
37
+ :title => 'So I was thinking', :lock_version => 24, :type => 'SpecialLockedPage'
38
+
39
+ FactoryGirl.create :seed_locked_page_rev,
40
+ :title => 'So I was thinking!!!', :lock_version => 23, :version_type => 'SpecialLockedPage',
41
+ :page_id => @thinking_lpage.id
42
+
43
+ FactoryGirl.create :seed_locked_page_rev,
44
+ :title => 'So I was thinking', :lock_version => 24, :version_type => 'SpecialLockedPage',
45
+ :page_id => @thinking_lpage.id
46
+
47
+ # Landmarks
48
+
49
+ @washington = FactoryGirl.create :seed_landmark,
50
+ :name => 'Washington, D.C.', :latitude => 38.895, :longitude => -77.036667,
51
+ :version => 1, :doesnt_trigger_version => 'This is not important'
52
+
53
+ FactoryGirl.create :seed_landmark_version,
54
+ :name => 'Washington, D.C.', :latitude => 38.895, :longitude => -77.036667,
55
+ :version => 1, :doesnt_trigger_version => 'This is not important',
56
+ :landmark_id => @washington.id
57
+
@@ -0,0 +1,57 @@
1
+
2
+ class Author < ActiveRecord::Base
3
+ has_many :pages
4
+ end
5
+
6
+ class Page < ActiveRecord::Base
7
+ belongs_to :author
8
+ has_many :authors, :through => :versions, :order => 'name'
9
+ belongs_to :revisor, :class_name => 'Author'
10
+ has_many :revisors, :class_name => 'Author', :through => :versions, :order => 'name'
11
+ acts_as_versioned :if => :feeling_good? do
12
+ def self.included(base)
13
+ base.cattr_accessor :feeling_good
14
+ base.feeling_good = true
15
+ base.belongs_to :author
16
+ base.belongs_to :revisor, :class_name => 'Author'
17
+ end
18
+
19
+ def feeling_good?
20
+ self.class.feeling_good == true
21
+ end
22
+ end
23
+ end
24
+
25
+ module LockedPageExtension
26
+ def hello_world
27
+ 'hello_world'
28
+ end
29
+ end
30
+
31
+ class LockedPage < ActiveRecord::Base
32
+ acts_as_versioned \
33
+ :inheritance_column => :version_type,
34
+ :foreign_key => :page_id,
35
+ :table_name => :locked_pages_revisions,
36
+ :class_name => 'LockedPageRevision',
37
+ :version_column => :lock_version,
38
+ :limit => 2,
39
+ :if_changed => :title,
40
+ :extend => LockedPageExtension
41
+ end
42
+
43
+ class SpecialLockedPage < LockedPage
44
+ end
45
+
46
+ class Landmark < ActiveRecord::Base
47
+ acts_as_versioned :if_changed => [ :name, :longitude, :latitude ]
48
+ end
49
+
50
+ class Widget < ActiveRecord::Base
51
+ acts_as_versioned :sequence_name => 'widgets_seq', :association_options => {
52
+ :dependent => :nullify, :order => 'version desc'
53
+ }
54
+ non_versioned_columns << 'foo'
55
+ end
56
+
57
+
@@ -0,0 +1,86 @@
1
+ ActiveRecord::Base.class_eval do
2
+ silence do
3
+
4
+ connection.create_table :pages, :force => true do |t|
5
+ t.column :version, :integer
6
+ t.column :title, :string, :limit => 255
7
+ t.column :body, :text
8
+ t.column :created_on, :datetime
9
+ t.column :updated_on, :datetime
10
+ t.column :author_id, :integer
11
+ t.column :revisor_id, :integer
12
+ end
13
+
14
+ connection.create_table :page_versions, :force => true do |t|
15
+ t.column :page_id, :integer
16
+ t.column :version, :integer
17
+ t.column :title, :string, :limit => 255
18
+ t.column :body, :text
19
+ t.column :created_on, :datetime
20
+ t.column :updated_on, :datetime
21
+ t.column :author_id, :integer
22
+ t.column :revisor_id, :integer
23
+ end
24
+
25
+ connection.add_index :page_versions, [:page_id, :version], :unique => true
26
+
27
+ connection.create_table :authors, :force => true do |t|
28
+ t.column :page_id, :integer
29
+ t.column :name, :string
30
+ end
31
+
32
+ connection.create_table :locked_pages, :force => true do |t|
33
+ t.column :lock_version, :integer
34
+ t.column :title, :string, :limit => 255
35
+ t.column :body, :text
36
+ t.column :type, :string, :limit => 255
37
+ end
38
+
39
+ connection.create_table :locked_pages_revisions, :force => true do |t|
40
+ t.column :page_id, :integer
41
+ t.column :lock_version, :integer
42
+ t.column :title, :string, :limit => 255
43
+ t.column :body, :text
44
+ t.column :version_type, :string, :limit => 255
45
+ t.column :updated_at, :datetime
46
+ end
47
+
48
+ connection.add_index :locked_pages_revisions, [:page_id, :lock_version], :unique => true
49
+
50
+ connection.create_table :widgets, :force => true do |t|
51
+ t.column :name, :string, :limit => 50
52
+ t.column :foo, :string
53
+ t.column :version, :integer
54
+ t.column :updated_at, :datetime
55
+ end
56
+
57
+ connection.create_table :widget_versions, :force => true do |t|
58
+ t.column :widget_id, :integer
59
+ t.column :name, :string, :limit => 50
60
+ t.column :version, :integer
61
+ t.column :updated_at, :datetime
62
+ end
63
+
64
+ connection.add_index :widget_versions, [:widget_id, :version], :unique => true
65
+
66
+ connection.create_table :landmarks, :force => true do |t|
67
+ t.column :name, :string
68
+ t.column :latitude, :float
69
+ t.column :longitude, :float
70
+ t.column :doesnt_trigger_version,:string
71
+ t.column :version, :integer
72
+ end
73
+
74
+ connection.create_table :landmark_versions, :force => true do |t|
75
+ t.column :landmark_id, :integer
76
+ t.column :name, :string
77
+ t.column :latitude, :float
78
+ t.column :longitude, :float
79
+ t.column :doesnt_trigger_version,:string
80
+ t.column :version, :integer
81
+ end
82
+
83
+ connection.add_index :landmark_versions, [:landmark_id, :version], :unique => true
84
+
85
+ end
86
+ end
@@ -0,0 +1,34 @@
1
+ require 'helper'
2
+
3
+ class Thing < ActiveRecord::Base
4
+ attr_accessor :version
5
+ acts_as_versioned
6
+ end
7
+
8
+ class MigrationTest < AAVTestCase
9
+
10
+ let(:mig_dir) { "#{TEST_ROOT}/migrations" }
11
+
12
+ before do
13
+ ActiveRecord::Migration.verbose = false
14
+ end
15
+
16
+ def test_versioned_migration
17
+ assert_raises(ActiveRecord::StatementInvalid) { Thing.create :title => 'blah blah' }
18
+ # # take 'er up
19
+ ActiveRecord::Migrator.up(mig_dir)
20
+ t = Thing.create :title => 'blah blah', :price => 123.45, :type => 'Thing'
21
+ assert_equal 1, t.versions.size
22
+ # check that the price column has remembered its value correctly
23
+ assert_equal t.price, t.versions.first.price
24
+ assert_equal t.title, t.versions.first.title
25
+ assert_equal t[:type], t.versions.first[:type]
26
+ # make sure that the precision of the price column has been preserved
27
+ assert_equal 7, Thing::Version.columns.find{|c| c.name == "price"}.precision
28
+ assert_equal 2, Thing::Version.columns.find{|c| c.name == "price"}.scale
29
+ # # now lets take 'er back down
30
+ ActiveRecord::Migrator.down(mig_dir)
31
+ assert_raises(ActiveRecord::StatementInvalid) { Thing.create :title => 'blah blah' }
32
+ end
33
+
34
+ end
@@ -0,0 +1,17 @@
1
+ class AddVersionedTables < ActiveRecord::Migration
2
+
3
+ def up
4
+ create_table("things") do |t|
5
+ t.column :title, :text
6
+ t.column :price, :decimal, :precision => 7, :scale => 2
7
+ t.column :type, :string
8
+ end
9
+ Thing.create_versioned_table
10
+ end
11
+
12
+ def down
13
+ Thing.drop_versioned_table
14
+ drop_table "things" rescue nil
15
+ end
16
+
17
+ end
@@ -0,0 +1,344 @@
1
+ require 'helper'
2
+
3
+ class VersionedTest < AAVTestCase
4
+
5
+ def test_saves_versioned_copy
6
+ p = Page.create! :title => 'first title', :body => 'first body'
7
+ assert !p.new_record?
8
+ assert_equal 1, p.versions.size
9
+ assert_equal 1, p.version
10
+ assert_instance_of Page.versioned_class, p.versions.first
11
+ end
12
+
13
+ def test_saves_without_revision
14
+ p = pages(:welcome)
15
+ old_versions = p.versions.count
16
+ p.save_without_revision
17
+ p.without_revision do
18
+ p.update_attributes :title => 'changed'
19
+ end
20
+ assert_equal old_versions, p.versions.count
21
+ end
22
+
23
+ def test_rollback_with_version_number
24
+ p = pages(:welcome)
25
+ assert_equal 24, p.version
26
+ assert_equal 'Welcome to the weblog', p.title
27
+ assert p.revert_to!(23), "Couldn't revert to 23"
28
+ assert_equal 23, p.version
29
+ assert_equal 'Welcome to the weblg', p.title
30
+ end
31
+
32
+ def test_versioned_class_name
33
+ assert_equal 'Version', Page.versioned_class_name
34
+ assert_equal 'LockedPageRevision', LockedPage.versioned_class_name
35
+ end
36
+
37
+ def test_versioned_class
38
+ assert_equal Page::Version, Page.versioned_class
39
+ assert_equal LockedPage::LockedPageRevision, LockedPage.versioned_class
40
+ end
41
+
42
+ def test_special_methods
43
+ pages(:welcome).feeling_good?
44
+ pages(:welcome).versions.first.feeling_good?
45
+ locked_pages(:welcome).hello_world
46
+ locked_pages(:welcome).versions.first.hello_world
47
+ end
48
+
49
+ def test_rollback_with_version_class
50
+ p = pages(:welcome)
51
+ assert_equal 24, p.version
52
+ assert_equal 'Welcome to the weblog', p.title
53
+ assert p.revert_to!(p.versions.find_by_version(23)), "Couldn't revert to 23"
54
+ assert_equal 23, p.version
55
+ assert_equal 'Welcome to the weblg', p.title
56
+ end
57
+
58
+ def test_rollback_fails_with_invalid_revision
59
+ p = locked_pages(:welcome)
60
+ assert !p.revert_to!(locked_pages(:thinking))
61
+ end
62
+
63
+ def test_saves_versioned_copy_with_options
64
+ p = LockedPage.create! :title => 'first title'
65
+ assert !p.new_record?
66
+ assert_equal 1, p.versions.size
67
+ assert_instance_of LockedPage.versioned_class, p.versions.first
68
+ end
69
+
70
+ def test_rollback_with_version_number_with_options
71
+ p = locked_pages(:welcome)
72
+ assert_equal 'Welcome to the weblog', p.title
73
+ assert_equal 'LockedPage', p.versions.first.version_type
74
+ assert p.revert_to!(p.versions.first.lock_version), "Couldn't revert to 23"
75
+ assert_equal 'Welcome to the weblg', p.title
76
+ assert_equal 'LockedPage', p.versions.first.version_type
77
+ end
78
+
79
+ def test_rollback_with_version_class_with_options
80
+ p = locked_pages(:welcome)
81
+ assert_equal 'Welcome to the weblog', p.title
82
+ assert_equal 'LockedPage', p.versions.first.version_type
83
+ assert p.revert_to!(p.versions.first), "Couldn't revert to 1"
84
+ assert_equal 'Welcome to the weblg', p.title
85
+ assert_equal 'LockedPage', p.versions.first.version_type
86
+ end
87
+
88
+ def test_saves_versioned_copy_with_sti
89
+ p = SpecialLockedPage.create! :title => 'first title'
90
+ assert !p.new_record?
91
+ assert_equal 1, p.versions.size
92
+ assert_instance_of LockedPage.versioned_class, p.versions.first
93
+ assert_equal 'SpecialLockedPage', p.versions.first.version_type
94
+ end
95
+
96
+ def test_rollback_with_version_number_with_sti
97
+ p = locked_pages(:thinking)
98
+ assert_equal 'So I was thinking', p.title
99
+ assert p.revert_to!(p.versions.first.lock_version), "Couldn't revert to 1"
100
+ assert_equal 'So I was thinking!!!', p.title
101
+ assert_equal 'SpecialLockedPage', p.versions.first.version_type
102
+ end
103
+
104
+ def test_lock_version_works_with_versioning
105
+ p = locked_pages(:thinking)
106
+ p2 = LockedPage.find(p.id)
107
+ p.title = 'fresh title'
108
+ p.save
109
+ assert_equal 2, p.versions.size # limit!
110
+ assert_raises(ActiveRecord::StaleObjectError) do
111
+ p2.title = 'stale title'
112
+ p2.save
113
+ end
114
+ end
115
+
116
+ def test_version_if_condition
117
+ p = Page.create! :title => "title"
118
+ assert_equal 1, p.version
119
+ Page.feeling_good = false
120
+ p.save
121
+ assert_equal 1, p.version
122
+ Page.feeling_good = true
123
+ end
124
+
125
+ def test_version_if_condition2
126
+ # set new if condition
127
+ Page.class_eval do
128
+ def new_feeling_good() title[0..0] == 'a'; end
129
+ alias_method :old_feeling_good, :feeling_good?
130
+ alias_method :feeling_good?, :new_feeling_good
131
+ end
132
+ p = Page.create! :title => "title"
133
+ assert_equal 1, p.version # version does not increment
134
+ assert_equal 1, p.versions.count
135
+ p.update_attributes(:title => 'new title')
136
+ assert_equal 1, p.version # version does not increment
137
+ assert_equal 1, p.versions.count
138
+ p.update_attributes(:title => 'a title')
139
+ assert_equal 2, p.version
140
+ assert_equal 2, p.versions.count
141
+ # reset original if condition
142
+ Page.class_eval { alias_method :feeling_good?, :old_feeling_good }
143
+ end
144
+
145
+ def test_version_if_condition_with_block
146
+ # set new if condition
147
+ old_condition = Page.version_condition
148
+ Page.version_condition = Proc.new { |page| page.title[0..0] == 'b' }
149
+ p = Page.create! :title => "title"
150
+ assert_equal 1, p.version # version does not increment
151
+ assert_equal 1, p.versions.count
152
+ p.update_attributes(:title => 'a title')
153
+ assert_equal 1, p.version # version does not increment
154
+ assert_equal 1, p.versions.count
155
+ p.update_attributes(:title => 'b title')
156
+ assert_equal 2, p.version
157
+ assert_equal 2, p.versions.count
158
+ # reset original if condition
159
+ Page.version_condition = old_condition
160
+ end
161
+
162
+ def test_version_no_limit
163
+ p = Page.create! :title => "title", :body => 'first body'
164
+ p.save
165
+ p.save
166
+ 5.times do |i|
167
+ p.title = "title#{i}"
168
+ p.save
169
+ assert_equal "title#{i}", p.title
170
+ assert_equal (i+2), p.version
171
+ end
172
+ end
173
+
174
+ def test_version_max_limit
175
+ p = LockedPage.create! :title => "title"
176
+ p.update_attributes(:title => "title1")
177
+ p.update_attributes(:title => "title2")
178
+ 5.times do |i|
179
+ p.title = "title#{i}"
180
+ p.save
181
+ assert_equal "title#{i}", p.title
182
+ assert_equal (i+4), p.lock_version
183
+ assert p.versions(true).size <= 2, "locked version can only store 2 versions"
184
+ end
185
+ end
186
+
187
+ def test_track_altered_attributes_default_value
188
+ assert !Page.track_altered_attributes
189
+ assert LockedPage.track_altered_attributes
190
+ assert SpecialLockedPage.track_altered_attributes
191
+ end
192
+
193
+ def test_track_altered_attributes
194
+ p = LockedPage.create! :title => "title"
195
+ assert_equal 1, p.lock_version
196
+ assert_equal 1, p.versions(true).size
197
+ p.body = 'whoa'
198
+ assert !p.save_version?
199
+ p.save
200
+ assert_equal 2, p.lock_version # still increments version because of optimistic locking
201
+ assert_equal 1, p.versions(true).size
202
+ p.title = 'updated title'
203
+ assert p.save_version?
204
+ p.save
205
+ assert_equal 3, p.lock_version
206
+ assert_equal 1, p.versions(true).size # version 1 deleted
207
+ p.title = 'updated title!'
208
+ assert p.save_version?
209
+ p.save
210
+ assert_equal 4, p.lock_version
211
+ assert_equal 2, p.versions(true).size # version 1 deleted
212
+ end
213
+
214
+ def test_find_versions
215
+ assert_equal 1, locked_pages(:welcome).versions.find(:all, :conditions => ['title LIKE ?', '%weblog%']).size
216
+ end
217
+
218
+ def test_find_version
219
+ assert_equal page_versions(:welcome_1), pages(:welcome).versions.find_by_version(23)
220
+ end
221
+
222
+ def test_with_sequence
223
+ assert_equal 'widgets_seq', Widget.versioned_class.sequence_name
224
+ 3.times { Widget.create! :name => 'new widget' }
225
+ assert_equal 3, Widget.count
226
+ assert_equal 3, Widget.versioned_class.count
227
+ end
228
+
229
+ def test_has_many_through
230
+ assert_equal [authors(:caged), authors(:mly)], pages(:welcome).authors
231
+ end
232
+
233
+ def test_has_many_through_with_custom_association
234
+ assert_equal [authors(:caged), authors(:mly)], pages(:welcome).revisors
235
+ end
236
+
237
+ def test_referential_integrity
238
+ pages(:welcome).destroy
239
+ assert_equal 0, Page.count
240
+ assert_equal 0, Page::Version.count
241
+ end
242
+
243
+ def test_association_options
244
+ association = Page.reflect_on_association(:versions)
245
+ options = association.options
246
+ assert_equal :delete_all, options[:dependent]
247
+ association = Widget.reflect_on_association(:versions)
248
+ options = association.options
249
+ assert_equal :nullify, options[:dependent]
250
+ assert_equal 'version desc', options[:order]
251
+ assert_equal 'widget_id', options[:foreign_key]
252
+ widget = Widget.create! :name => 'new widget'
253
+ assert_equal 1, Widget.count
254
+ assert_equal 1, Widget.versioned_class.count
255
+ widget.destroy
256
+ assert_equal 0, Widget.count
257
+ assert_equal 1, Widget.versioned_class.count
258
+ end
259
+
260
+ def test_versioned_records_should_belong_to_parent
261
+ page = pages(:welcome)
262
+ page_version = page.versions.last
263
+ assert_equal page, page_version.page
264
+ end
265
+
266
+ def test_unaltered_attributes
267
+ landmarks(:washington).attributes = landmarks(:washington).attributes.except("id")
268
+ assert !landmarks(:washington).changed?
269
+ end
270
+
271
+ def test_unchanged_string_attributes
272
+ landmarks(:washington).attributes = landmarks(:washington).attributes.except("id").inject({}) { |params, (key, value)| params.update(key => value.to_s) }
273
+ assert !landmarks(:washington).changed?
274
+ end
275
+
276
+ def test_should_find_earliest_version
277
+ assert_equal page_versions(:welcome_1), pages(:welcome).versions.earliest
278
+ end
279
+
280
+ def test_should_find_latest_version
281
+ assert_equal page_versions(:welcome_2), pages(:welcome).versions.latest
282
+ end
283
+
284
+ def test_should_find_previous_version
285
+ assert_equal page_versions(:welcome_1), page_versions(:welcome_2).previous
286
+ assert_equal page_versions(:welcome_1), pages(:welcome).versions.before(page_versions(:welcome_2))
287
+ end
288
+
289
+ def test_should_find_next_version
290
+ assert_equal page_versions(:welcome_2), page_versions(:welcome_1).next
291
+ assert_equal page_versions(:welcome_2), pages(:welcome).versions.after(page_versions(:welcome_1))
292
+ end
293
+
294
+ def test_should_find_version_count
295
+ assert_equal 2, pages(:welcome).versions.size
296
+ end
297
+
298
+ def test_if_changed_creates_version_if_a_listed_column_is_changed
299
+ washington = landmarks(:washington)
300
+ washington.name = "Washington"
301
+ assert washington.changed?
302
+ assert washington.altered?
303
+ end
304
+
305
+ def test_if_changed_creates_version_if_all_listed_columns_are_changed
306
+ washington = landmarks(:washington)
307
+ washington.name = "Washington"
308
+ washington.latitude = 1.0
309
+ washington.longitude = 1.0
310
+ assert washington.changed?
311
+ assert washington.altered?
312
+ end
313
+
314
+ def test_if_changed_does_not_create_new_version_if_unlisted_column_is_changed
315
+ washington = landmarks(:washington)
316
+ washington.doesnt_trigger_version = "This should not trigger version"
317
+ assert washington.changed?
318
+ assert !washington.altered?
319
+ end
320
+
321
+ def test_without_locking_temporarily_disables_optimistic_locking
322
+ enabled1 = false
323
+ block_called = false
324
+ ActiveRecord::Base.lock_optimistically = true
325
+ LockedPage.without_locking do
326
+ enabled1 = ActiveRecord::Base.lock_optimistically
327
+ block_called = true
328
+ end
329
+ enabled2 = ActiveRecord::Base.lock_optimistically
330
+ assert block_called
331
+ assert !enabled1
332
+ assert enabled2
333
+ end
334
+
335
+ def test_without_locking_reverts_optimistic_locking_settings_if_block_raises_exception
336
+ assert_raises(RuntimeError) do
337
+ LockedPage.without_locking do
338
+ raise RuntimeError, "oh noes"
339
+ end
340
+ end
341
+ assert ActiveRecord::Base.lock_optimistically
342
+ end
343
+
344
+ end