acts_as_versioned-decisiv 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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