paper_trail 4.2.0 → 7.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (171) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/paper_trail/install_generator.rb +91 -17
  3. data/lib/generators/paper_trail/templates/add_object_changes_to_versions.rb.erb +12 -0
  4. data/lib/generators/paper_trail/templates/{add_transaction_id_column_to_versions.rb → add_transaction_id_column_to_versions.rb.erb} +3 -1
  5. data/lib/generators/paper_trail/templates/create_version_associations.rb.erb +22 -0
  6. data/lib/generators/paper_trail/templates/{create_versions.rb → create_versions.rb.erb} +9 -7
  7. data/lib/paper_trail.rb +180 -148
  8. data/lib/paper_trail/attribute_serializers/README.md +10 -0
  9. data/lib/paper_trail/attribute_serializers/cast_attribute_serializer.rb +80 -0
  10. data/lib/paper_trail/attribute_serializers/legacy_active_record_shim.rb +48 -0
  11. data/lib/paper_trail/attribute_serializers/object_attribute.rb +39 -0
  12. data/lib/paper_trail/attribute_serializers/object_changes_attribute.rb +42 -0
  13. data/lib/paper_trail/cleaner.rb +16 -10
  14. data/lib/paper_trail/config.rb +28 -27
  15. data/lib/paper_trail/frameworks/active_record/models/paper_trail/version.rb +5 -1
  16. data/lib/paper_trail/frameworks/active_record/models/paper_trail/version_association.rb +6 -2
  17. data/lib/paper_trail/frameworks/cucumber.rb +1 -0
  18. data/lib/paper_trail/frameworks/rails.rb +2 -7
  19. data/lib/paper_trail/frameworks/rails/controller.rb +20 -18
  20. data/lib/paper_trail/frameworks/rails/engine.rb +6 -1
  21. data/lib/paper_trail/frameworks/rspec.rb +17 -6
  22. data/lib/paper_trail/frameworks/rspec/helpers.rb +3 -1
  23. data/lib/paper_trail/has_paper_trail.rb +25 -503
  24. data/lib/paper_trail/model_config.rb +207 -0
  25. data/lib/paper_trail/queries/versions/where_object.rb +60 -0
  26. data/lib/paper_trail/queries/versions/where_object_changes.rb +68 -0
  27. data/lib/paper_trail/record_history.rb +2 -12
  28. data/lib/paper_trail/record_trail.rb +573 -0
  29. data/lib/paper_trail/reifier.rb +164 -215
  30. data/lib/paper_trail/reifiers/belongs_to.rb +48 -0
  31. data/lib/paper_trail/reifiers/has_and_belongs_to_many.rb +50 -0
  32. data/lib/paper_trail/reifiers/has_many.rb +110 -0
  33. data/lib/paper_trail/reifiers/has_many_through.rb +90 -0
  34. data/lib/paper_trail/reifiers/has_one.rb +76 -0
  35. data/lib/paper_trail/serializers/json.rb +16 -7
  36. data/lib/paper_trail/serializers/yaml.rb +9 -13
  37. data/lib/paper_trail/version_association_concern.rb +3 -5
  38. data/lib/paper_trail/version_concern.rb +138 -111
  39. data/lib/paper_trail/version_number.rb +10 -9
  40. metadata +95 -327
  41. data/.gitignore +0 -22
  42. data/.rspec +0 -2
  43. data/.travis.yml +0 -41
  44. data/CHANGELOG.md +0 -362
  45. data/CONTRIBUTING.md +0 -84
  46. data/Gemfile +0 -2
  47. data/MIT-LICENSE +0 -20
  48. data/README.md +0 -1535
  49. data/Rakefile +0 -30
  50. data/doc/bug_report_template.rb +0 -65
  51. data/gemfiles/ar3.gemfile +0 -61
  52. data/lib/generators/paper_trail/templates/add_object_changes_to_versions.rb +0 -10
  53. data/lib/generators/paper_trail/templates/create_version_associations.rb +0 -17
  54. data/lib/paper_trail/attributes_serialization.rb +0 -89
  55. data/lib/paper_trail/frameworks/sinatra.rb +0 -38
  56. data/paper_trail.gemspec +0 -59
  57. data/spec/generators/install_generator_spec.rb +0 -67
  58. data/spec/models/animal_spec.rb +0 -36
  59. data/spec/models/boolit_spec.rb +0 -48
  60. data/spec/models/callback_modifier_spec.rb +0 -96
  61. data/spec/models/fluxor_spec.rb +0 -19
  62. data/spec/models/gadget_spec.rb +0 -70
  63. data/spec/models/joined_version_spec.rb +0 -47
  64. data/spec/models/json_version_spec.rb +0 -103
  65. data/spec/models/kitchen/banana_spec.rb +0 -14
  66. data/spec/models/not_on_update_spec.rb +0 -19
  67. data/spec/models/post_with_status_spec.rb +0 -17
  68. data/spec/models/skipper_spec.rb +0 -46
  69. data/spec/models/thing_spec.rb +0 -11
  70. data/spec/models/version_spec.rb +0 -239
  71. data/spec/models/widget_spec.rb +0 -298
  72. data/spec/modules/paper_trail_spec.rb +0 -27
  73. data/spec/modules/version_concern_spec.rb +0 -32
  74. data/spec/modules/version_number_spec.rb +0 -44
  75. data/spec/paper_trail/config_spec.rb +0 -52
  76. data/spec/paper_trail_spec.rb +0 -66
  77. data/spec/rails_helper.rb +0 -34
  78. data/spec/requests/articles_spec.rb +0 -30
  79. data/spec/spec_helper.rb +0 -95
  80. data/spec/support/alt_db_init.rb +0 -59
  81. data/test/custom_json_serializer.rb +0 -13
  82. data/test/dummy/Rakefile +0 -7
  83. data/test/dummy/app/controllers/application_controller.rb +0 -20
  84. data/test/dummy/app/controllers/articles_controller.rb +0 -17
  85. data/test/dummy/app/controllers/test_controller.rb +0 -5
  86. data/test/dummy/app/controllers/widgets_controller.rb +0 -31
  87. data/test/dummy/app/helpers/application_helper.rb +0 -2
  88. data/test/dummy/app/models/animal.rb +0 -6
  89. data/test/dummy/app/models/article.rb +0 -16
  90. data/test/dummy/app/models/authorship.rb +0 -5
  91. data/test/dummy/app/models/book.rb +0 -9
  92. data/test/dummy/app/models/boolit.rb +0 -4
  93. data/test/dummy/app/models/callback_modifier.rb +0 -45
  94. data/test/dummy/app/models/cat.rb +0 -2
  95. data/test/dummy/app/models/chapter.rb +0 -9
  96. data/test/dummy/app/models/citation.rb +0 -5
  97. data/test/dummy/app/models/customer.rb +0 -4
  98. data/test/dummy/app/models/document.rb +0 -4
  99. data/test/dummy/app/models/dog.rb +0 -2
  100. data/test/dummy/app/models/editor.rb +0 -4
  101. data/test/dummy/app/models/editorship.rb +0 -5
  102. data/test/dummy/app/models/elephant.rb +0 -3
  103. data/test/dummy/app/models/fluxor.rb +0 -3
  104. data/test/dummy/app/models/foo_widget.rb +0 -2
  105. data/test/dummy/app/models/fruit.rb +0 -5
  106. data/test/dummy/app/models/gadget.rb +0 -3
  107. data/test/dummy/app/models/kitchen/banana.rb +0 -5
  108. data/test/dummy/app/models/legacy_widget.rb +0 -4
  109. data/test/dummy/app/models/line_item.rb +0 -4
  110. data/test/dummy/app/models/not_on_update.rb +0 -4
  111. data/test/dummy/app/models/order.rb +0 -5
  112. data/test/dummy/app/models/paragraph.rb +0 -5
  113. data/test/dummy/app/models/person.rb +0 -38
  114. data/test/dummy/app/models/post.rb +0 -3
  115. data/test/dummy/app/models/post_with_status.rb +0 -8
  116. data/test/dummy/app/models/protected_widget.rb +0 -3
  117. data/test/dummy/app/models/quotation.rb +0 -5
  118. data/test/dummy/app/models/section.rb +0 -6
  119. data/test/dummy/app/models/skipper.rb +0 -6
  120. data/test/dummy/app/models/song.rb +0 -32
  121. data/test/dummy/app/models/thing.rb +0 -3
  122. data/test/dummy/app/models/translation.rb +0 -4
  123. data/test/dummy/app/models/whatchamajigger.rb +0 -4
  124. data/test/dummy/app/models/widget.rb +0 -15
  125. data/test/dummy/app/models/wotsit.rb +0 -8
  126. data/test/dummy/app/versions/joined_version.rb +0 -5
  127. data/test/dummy/app/versions/json_version.rb +0 -3
  128. data/test/dummy/app/versions/kitchen/banana_version.rb +0 -5
  129. data/test/dummy/app/versions/post_version.rb +0 -3
  130. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  131. data/test/dummy/config.ru +0 -4
  132. data/test/dummy/config/application.rb +0 -69
  133. data/test/dummy/config/boot.rb +0 -10
  134. data/test/dummy/config/database.mysql.yml +0 -19
  135. data/test/dummy/config/database.postgres.yml +0 -15
  136. data/test/dummy/config/database.sqlite.yml +0 -15
  137. data/test/dummy/config/environment.rb +0 -5
  138. data/test/dummy/config/environments/development.rb +0 -40
  139. data/test/dummy/config/environments/production.rb +0 -73
  140. data/test/dummy/config/environments/test.rb +0 -41
  141. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  142. data/test/dummy/config/initializers/inflections.rb +0 -10
  143. data/test/dummy/config/initializers/mime_types.rb +0 -5
  144. data/test/dummy/config/initializers/paper_trail.rb +0 -10
  145. data/test/dummy/config/initializers/secret_token.rb +0 -7
  146. data/test/dummy/config/initializers/session_store.rb +0 -8
  147. data/test/dummy/config/locales/en.yml +0 -5
  148. data/test/dummy/config/routes.rb +0 -4
  149. data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +0 -287
  150. data/test/dummy/db/schema.rb +0 -246
  151. data/test/dummy/script/rails +0 -6
  152. data/test/functional/controller_test.rb +0 -91
  153. data/test/functional/enabled_for_controller_test.rb +0 -29
  154. data/test/functional/modular_sinatra_test.rb +0 -48
  155. data/test/functional/sinatra_test.rb +0 -49
  156. data/test/functional/thread_safety_test.rb +0 -48
  157. data/test/paper_trail_test.rb +0 -38
  158. data/test/test_helper.rb +0 -105
  159. data/test/time_travel_helper.rb +0 -15
  160. data/test/unit/associations_test.rb +0 -726
  161. data/test/unit/cleaner_test.rb +0 -182
  162. data/test/unit/inheritance_column_test.rb +0 -43
  163. data/test/unit/model_test.rb +0 -1373
  164. data/test/unit/protected_attrs_test.rb +0 -47
  165. data/test/unit/serializer_test.rb +0 -117
  166. data/test/unit/serializers/json_test.rb +0 -88
  167. data/test/unit/serializers/mixin_json_test.rb +0 -36
  168. data/test/unit/serializers/mixin_yaml_test.rb +0 -49
  169. data/test/unit/serializers/yaml_test.rb +0 -52
  170. data/test/unit/timestamp_test.rb +0 -43
  171. data/test/unit/version_test.rb +0 -119
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
-
4
- APP_PATH = File.expand_path('../../config/application', __FILE__)
5
- require File.expand_path('../../config/boot', __FILE__)
6
- require 'rails/commands'
@@ -1,91 +0,0 @@
1
- require 'test_helper'
2
-
3
- class ControllerTest < ActionController::TestCase
4
- tests WidgetsController
5
-
6
- setup do
7
- @request.env['REMOTE_ADDR'] = '127.0.0.1'
8
- end
9
-
10
- # Mimick what RequestStore will do outside of the test env, since it is
11
- # middleware, and doesn't get executed in controller / request specs
12
- teardown do
13
- RequestStore.store[:paper_trail] = nil
14
- end
15
-
16
- test 'disable on create' do
17
- @request.env['HTTP_USER_AGENT'] = 'Disable User-Agent'
18
- post :create, :widget => { :name => 'Flugel' }
19
- assert_equal 0, assigns(:widget).versions.length
20
- end
21
-
22
- test 'disable on update' do
23
- @request.env['HTTP_USER_AGENT'] = 'Disable User-Agent'
24
- post :create, :widget => { :name => 'Flugel' }
25
- w = assigns(:widget)
26
- assert_equal 0, w.versions.length
27
- put :update, :id => w.id, :widget => { :name => 'Bugle' }
28
- widget = assigns(:widget)
29
- assert_equal 0, widget.versions.length
30
- end
31
-
32
- test 'disable on destroy' do
33
- @request.env['HTTP_USER_AGENT'] = 'Disable User-Agent'
34
- post :create, :widget => { :name => 'Flugel' }
35
- w = assigns(:widget)
36
- assert_equal 0, w.versions.length
37
- delete :destroy, :id => w.id
38
- widget = assigns(:widget)
39
- assert_equal 0, PaperTrail::Version.with_item_keys('Widget', w.id).size
40
- end
41
-
42
- test 'create' do
43
- post :create, :widget => { :name => 'Flugel' }
44
- widget = assigns(:widget)
45
- assert_equal 1, widget.versions.length
46
- assert_equal 153, widget.versions.last.whodunnit.to_i
47
- assert_equal '127.0.0.1', widget.versions.last.ip
48
- assert_equal 'Rails Testing', widget.versions.last.user_agent
49
- end
50
-
51
- test 'update' do
52
- w = Widget.create :name => 'Duvel'
53
- assert_equal 1, w.versions.length
54
- put :update, :id => w.id, :widget => { :name => 'Bugle' }
55
- widget = assigns(:widget)
56
- assert_equal 2, widget.versions.length
57
- assert_equal 153, widget.versions.last.whodunnit.to_i
58
- assert_equal '127.0.0.1', widget.versions.last.ip
59
- assert_equal 'Rails Testing', widget.versions.last.user_agent
60
- end
61
-
62
- test 'destroy' do
63
- w = Widget.create :name => 'Roundel'
64
- assert_equal 1, w.versions.length
65
- delete :destroy, :id => w.id
66
- widget = assigns(:widget)
67
- assert_equal 2, widget.versions.length
68
- assert_equal '127.0.0.1', widget.versions.last.ip
69
- assert_equal 'Rails Testing', widget.versions.last.user_agent
70
- assert_equal 153, widget.versions.last.whodunnit.to_i
71
- end
72
-
73
- test "controller metadata methods should get evaluated if paper trail is enabled for controller" do
74
- @request.env['HTTP_USER_AGENT'] = 'User-Agent'
75
- post :create, :widget => { :name => 'Flugel' }
76
- assert PaperTrail.enabled_for_controller?
77
- assert_equal 153, PaperTrail.whodunnit
78
- assert PaperTrail.controller_info.present?
79
- assert PaperTrail.controller_info.keys.include?(:ip)
80
- assert PaperTrail.controller_info.keys.include?(:user_agent)
81
- end
82
-
83
- test "controller metadata methods should not get evaluated if paper trail is disabled for controller" do
84
- @request.env['HTTP_USER_AGENT'] = 'Disable User-Agent'
85
- post :create, :widget => { :name => 'Flugel' }
86
- assert_equal 0, assigns(:widget).versions.length
87
- assert !PaperTrail.enabled_for_controller?
88
- assert PaperTrail.whodunnit.nil?
89
- assert PaperTrail.controller_info.nil?
90
- end
91
- end
@@ -1,29 +0,0 @@
1
- require 'test_helper'
2
-
3
- class EnabledForControllerTest < ActionController::TestCase
4
- tests ArticlesController
5
-
6
- context "`PaperTrail.enabled? == true`" do
7
- should 'enabled_for_controller?.should == true' do
8
- assert PaperTrail.enabled?
9
- post :create, :article => { :title => 'Doh', :content => Faker::Lorem.sentence }
10
- assert_not_nil assigns(:article)
11
- assert PaperTrail.enabled_for_controller?
12
- assert_equal 1, assigns(:article).versions.length
13
- end
14
- end
15
-
16
- context "`PaperTrail.enabled? == false`" do
17
- setup { PaperTrail.enabled = false }
18
-
19
- should 'enabled_for_controller?.should == false' do
20
- assert !PaperTrail.enabled?
21
- post :create, :article => { :title => 'Doh', :content => Faker::Lorem.sentence }
22
- assert !PaperTrail.enabled_for_controller?
23
- assert_equal 0, assigns(:article).versions.length
24
- end
25
-
26
- teardown { PaperTrail.enabled = true }
27
- end
28
-
29
- end
@@ -1,48 +0,0 @@
1
- require 'test_helper'
2
- require 'sinatra/base'
3
-
4
- # --- Tests for modular `Sinatra::Base` style ----
5
- class BaseApp < Sinatra::Base
6
- configs = YAML.load_file(File.expand_path('../../dummy/config/database.yml', __FILE__))
7
- ActiveRecord::Base.configurations = configs
8
- ActiveRecord::Base.establish_connection(:test)
9
- register PaperTrail::Sinatra
10
-
11
- get '/test' do
12
- Widget.create!(:name => 'foo')
13
- 'Hello'
14
- end
15
-
16
- def current_user
17
- @current_user ||= OpenStruct.new(:id => 'foobar').tap do |obj|
18
- # Invoking `id` returns the `object_id` value in Ruby18 unless specifically overwritten
19
- def obj.id; 'foobar'; end if RUBY_VERSION < '1.9'
20
- end
21
- end
22
- end
23
-
24
- class ModularSinatraTest < ActionDispatch::IntegrationTest
25
- include Rack::Test::Methods
26
-
27
- def app
28
- @app ||= BaseApp
29
- end
30
-
31
- test 'baseline' do
32
- assert_nil Widget.create.versions.first.whodunnit
33
- end
34
-
35
- context "`PaperTrail::Sinatra` in a `Sinatra::Base` application" do
36
-
37
- should "sets the `user_for_paper_trail` from the `current_user` method" do
38
- get '/test'
39
- assert_equal 'Hello', last_response.body
40
- widget = Widget.last
41
- assert_not_nil widget
42
- assert_equal 'foo', widget.name
43
- assert_equal 1, widget.versions.size
44
- assert_equal 'foobar', widget.versions.first.whodunnit
45
- end
46
-
47
- end
48
- end
@@ -1,49 +0,0 @@
1
- require 'test_helper'
2
- # require 'sinatra/main'
3
-
4
- # --- Tests for non-modular `Sinatra::Application` style ----
5
- class Sinatra::Application
6
- configs = YAML.load_file(File.expand_path('../../dummy/config/database.yml', __FILE__))
7
- ActiveRecord::Base.configurations = configs
8
- ActiveRecord::Base.establish_connection(:test)
9
- register PaperTrail::Sinatra # we shouldn't actually need this line if I'm not mistaken but the tests seem to fail without it ATM
10
-
11
- get '/test' do
12
- Widget.create!(:name => 'bar')
13
- 'Hai'
14
- end
15
-
16
- def current_user
17
- @current_user ||= OpenStruct.new(:id => 'raboof').tap do |obj|
18
- # Invoking `id` returns the `object_id` value in Ruby18 unless specifically overwritten
19
- def obj.id; 'raboof'; end if RUBY_VERSION < '1.9'
20
- end
21
- end
22
-
23
- end
24
-
25
- class SinatraTest < ActionDispatch::IntegrationTest
26
- include Rack::Test::Methods
27
-
28
- def app
29
- @app ||= Sinatra::Application
30
- end
31
-
32
- test 'baseline' do
33
- assert_nil Widget.create.versions.first.whodunnit
34
- end
35
-
36
- context "`PaperTrail::Sinatra` in a `Sinatra::Application` application" do
37
-
38
- should "sets the `user_for_paper_trail` from the `current_user` method" do
39
- get '/test'
40
- assert_equal 'Hai', last_response.body
41
- widget = Widget.last
42
- assert_not_nil widget
43
- assert_equal 'bar', widget.name
44
- assert_equal 1, widget.versions.size
45
- assert_equal 'raboof', widget.versions.first.whodunnit
46
- end
47
-
48
- end
49
- end
@@ -1,48 +0,0 @@
1
- require 'test_helper'
2
-
3
- class ThreadSafetyTest < ActionController::TestCase
4
- test "be thread safe when using #set_paper_trail_whodunnit" do
5
- blocked = true
6
-
7
- slow_thread = Thread.new do
8
- controller = TestController.new
9
- controller.send :set_paper_trail_whodunnit
10
- begin
11
- sleep 0.001
12
- end while blocked
13
- PaperTrail.whodunnit
14
- end
15
-
16
- fast_thread = Thread.new do
17
- controller = TestController.new
18
- controller.send :set_paper_trail_whodunnit
19
- who = PaperTrail.whodunnit
20
- blocked = false
21
- who
22
- end
23
-
24
- assert_not_equal slow_thread.value, fast_thread.value
25
- end
26
-
27
- test "be thread safe when using #without_versioning" do
28
- enabled = nil
29
-
30
- slow_thread = Thread.new do
31
- Widget.new.without_versioning do
32
- sleep(0.01)
33
- enabled = Widget.paper_trail_enabled_for_model?
34
- sleep(0.01)
35
- end
36
- enabled
37
- end
38
-
39
- fast_thread = Thread.new do
40
- sleep(0.005)
41
- Widget.paper_trail_enabled_for_model?
42
- end
43
-
44
- assert_not_equal slow_thread.value, fast_thread.value
45
- assert Widget.paper_trail_enabled_for_model?
46
- assert PaperTrail.enabled_for_model?(Widget)
47
- end
48
- end
@@ -1,38 +0,0 @@
1
- require 'test_helper'
2
-
3
- class PaperTrailTest < ActiveSupport::TestCase
4
- test 'Sanity test' do
5
- assert_kind_of Module, PaperTrail::Version
6
- end
7
-
8
- test 'Version Number' do
9
- assert PaperTrail.const_defined?(:VERSION)
10
- end
11
-
12
- test 'enabled is thread-safe' do
13
- Thread.new do
14
- PaperTrail.enabled = false
15
- end.join
16
- assert PaperTrail.enabled?
17
- end
18
-
19
- test 'create with plain model class' do
20
- widget = Widget.create
21
- assert_equal 1, widget.versions.length
22
- end
23
-
24
- test 'update with plain model class' do
25
- widget = Widget.create
26
- assert_equal 1, widget.versions.length
27
- widget.update_attributes(:name => 'Bugle')
28
- assert_equal 2, widget.versions.length
29
- end
30
-
31
- test 'destroy with plain model class' do
32
- widget = Widget.create
33
- assert_equal 1, widget.versions.length
34
- widget.destroy
35
- versions_for_widget = PaperTrail::Version.with_item_keys('Widget', widget.id)
36
- assert_equal 2, versions_for_widget.length
37
- end
38
- end
data/test/test_helper.rb DELETED
@@ -1,105 +0,0 @@
1
- begin
2
- require 'pry-nav'
3
- rescue LoadError
4
- # It's OK, we don't include pry in e.g. gemfiles/3.0.gemfile
5
- end
6
-
7
- ENV["RAILS_ENV"] = "test"
8
- ENV["DB"] ||= "sqlite"
9
-
10
- unless File.exists?(File.expand_path('../../test/dummy/config/database.yml', __FILE__))
11
- warn "WARNING: No database.yml detected for the dummy app, please run `rake prepare` first"
12
- end
13
-
14
- def using_mysql?
15
- @using_mysql ||= ActiveRecord::Base.connection_config[:adapter].to_sym == :mysql2
16
- end
17
-
18
- require File.expand_path("../dummy/config/environment.rb", __FILE__)
19
- require "rails/test_help"
20
- require 'shoulda'
21
- require 'ffaker'
22
- require 'database_cleaner'
23
-
24
- Rails.backtrace_cleaner.remove_silencers!
25
-
26
- # Run any available migration
27
- ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
28
-
29
- # Load support files
30
- Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
31
-
32
- # DatabaseCleaner is apparently necessary for doing proper transactions within MySQL (ugh)
33
- DatabaseCleaner.strategy = :truncation
34
-
35
- # global setup block resetting Thread.current
36
- class ActiveSupport::TestCase
37
- if using_mysql?
38
- self.use_transactional_fixtures = false
39
- setup { DatabaseCleaner.start }
40
- end
41
-
42
- teardown do
43
- DatabaseCleaner.clean if using_mysql?
44
- Thread.current[:paper_trail] = nil
45
- end
46
-
47
- private
48
-
49
- def assert_attributes_equal(expected, actual)
50
- if using_mysql?
51
- expected, actual = expected.dup, actual.dup
52
-
53
- # Adjust timestamps for missing fractional seconds precision.
54
- %w(created_at updated_at).each do |timestamp|
55
- expected[timestamp] = expected[timestamp].change(:usec => 0)
56
- actual[timestamp] = actual[timestamp].change(:usec => 0)
57
- end
58
- end
59
-
60
- assert_equal expected, actual
61
- end
62
-
63
- def assert_changes_equal(expected, actual)
64
- if using_mysql?
65
- expected, actual = expected.dup, actual.dup
66
-
67
- # Adjust timestamps for missing fractional seconds precision.
68
- %w(created_at updated_at).each do |timestamp|
69
- expected[timestamp][1] = expected[timestamp][1].change(:usec => 0)
70
- actual[timestamp][1] = actual[timestamp][1].change(:usec => 0)
71
- end
72
- end
73
-
74
- assert_equal expected, actual
75
- end
76
- end
77
-
78
- #
79
- # Helpers
80
- #
81
-
82
- def change_schema
83
- ActiveRecord::Migration.verbose = false
84
- ActiveRecord::Schema.define do
85
- remove_column :widgets, :sacrificial_column
86
- add_column :versions, :custom_created_at, :datetime
87
- end
88
- ActiveRecord::Migration.verbose = true
89
- reset_version_class_column_info!
90
- end
91
-
92
- def restore_schema
93
- ActiveRecord::Migration.verbose = false
94
- ActiveRecord::Schema.define do
95
- add_column :widgets, :sacrificial_column, :string
96
- remove_column :versions, :custom_created_at
97
- end
98
- ActiveRecord::Migration.verbose = true
99
- reset_version_class_column_info!
100
- end
101
-
102
- def reset_version_class_column_info!
103
- PaperTrail::Version.connection.schema_cache.clear!
104
- PaperTrail::Version.reset_column_information
105
- end
@@ -1,15 +0,0 @@
1
- if RUBY_VERSION < "1.9.2"
2
- require 'delorean'
3
-
4
- class Timecop
5
- def self.travel(t)
6
- Delorean.time_travel_to t
7
- end
8
-
9
- def self.return
10
- Delorean.back_to_the_present
11
- end
12
- end
13
- else
14
- require 'timecop'
15
- end
@@ -1,726 +0,0 @@
1
- require 'test_helper'
2
- require 'time_travel_helper'
3
-
4
- class AssociationsTest < ActiveSupport::TestCase
5
- CHAPTER_NAMES = [
6
- "Down the Rabbit-Hole",
7
- "The Pool of Tears",
8
- "A Caucus-Race and a Long Tale",
9
- "The Rabbit Sends in a Little Bill",
10
- "Advice from a Caterpillar",
11
- "Pig and Pepper",
12
- "A Mad Tea-Party",
13
- "The Queen's Croquet-Ground",
14
- "The Mock Turtle's Story",
15
- "The Lobster Quadrille",
16
- "Who Stole the Tarts?",
17
- "Alice's Evidence"
18
- ]
19
-
20
- # These would have been done in test_helper.rb if using_mysql? is true
21
- unless using_mysql?
22
- self.use_transactional_fixtures = false
23
- setup { DatabaseCleaner.start }
24
- end
25
-
26
- teardown do
27
- Timecop.return
28
- # This would have been done in test_helper.rb if using_mysql? is true
29
- DatabaseCleaner.clean unless using_mysql?
30
- end
31
-
32
- context "a has_one association" do
33
- setup { @widget = Widget.create :name => 'widget_0' }
34
-
35
- context 'before the associated was created' do
36
- setup do
37
- @widget.update_attributes :name => 'widget_1'
38
- @wotsit = @widget.create_wotsit :name => 'wotsit_0'
39
- end
40
-
41
- context 'when reified' do
42
- setup { @widget_0 = @widget.versions.last.reify(:has_one => true) }
43
-
44
- should 'see the associated as it was at the time' do
45
- assert_nil @widget_0.wotsit
46
- end
47
-
48
- should 'not persist changes to the live association' do
49
- assert_equal @wotsit, @widget.wotsit(true)
50
- end
51
- end
52
- end
53
-
54
- context 'where the association is created between model versions' do
55
- setup do
56
- @wotsit = @widget.create_wotsit :name => 'wotsit_0'
57
- Timecop.travel 1.second.since
58
- @widget.update_attributes :name => 'widget_1'
59
- end
60
-
61
- context 'when reified' do
62
- setup { @widget_0 = @widget.versions.last.reify(:has_one => true) }
63
-
64
- should 'see the associated as it was at the time' do
65
- assert_equal 'wotsit_0', @widget_0.wotsit.name
66
- end
67
-
68
- should 'not persist changes to the live association' do
69
- assert_equal @wotsit, @widget.wotsit(true)
70
- end
71
- end
72
-
73
- context 'and then the associated is updated between model versions' do
74
- setup do
75
- @wotsit.update_attributes :name => 'wotsit_1'
76
- @wotsit.update_attributes :name => 'wotsit_2'
77
- Timecop.travel 1.second.since
78
- @widget.update_attributes :name => 'widget_2'
79
- @wotsit.update_attributes :name => 'wotsit_3'
80
- end
81
-
82
- context 'when reified' do
83
- setup { @widget_1 = @widget.versions.last.reify(:has_one => true) }
84
-
85
- should 'see the associated as it was at the time' do
86
- assert_equal 'wotsit_2', @widget_1.wotsit.name
87
- end
88
-
89
- should 'not persist changes to the live association' do
90
- assert_equal 'wotsit_3', @widget.wotsit(true).name
91
- end
92
- end
93
-
94
- context 'when reified opting out of has_one reification' do
95
- setup { @widget_1 = @widget.versions.last.reify(:has_one => false) }
96
-
97
- should 'see the associated as it is live' do
98
- assert_equal 'wotsit_3', @widget_1.wotsit.name
99
- end
100
- end
101
- end
102
-
103
- context 'and then the associated is destroyed' do
104
- setup do
105
- @wotsit.destroy
106
- end
107
-
108
- context 'when reify' do
109
- setup { @widget_1 = @widget.versions.last.reify(:has_one => true) }
110
-
111
- should 'see the associated as it was at the time' do
112
- assert_equal @wotsit, @widget_1.wotsit
113
- end
114
-
115
- should 'not persist changes to the live association' do
116
- assert_nil @widget.wotsit(true)
117
- end
118
- end
119
-
120
- context 'and then the model is updated' do
121
- setup do
122
- Timecop.travel 1.second.since
123
- @widget.update_attributes :name => 'widget_3'
124
- end
125
-
126
- context 'when reified' do
127
- setup { @widget_2 = @widget.versions.last.reify(:has_one => true) }
128
-
129
- should 'see the associated as it was at the time' do
130
- assert_nil @widget_2.wotsit
131
- end
132
- end
133
- end
134
- end
135
- end
136
- end
137
-
138
- context "a has_many association" do
139
- setup { @customer = Customer.create :name => 'customer_0' }
140
-
141
- context 'updated before the associated was created' do
142
- setup do
143
- @customer.update_attributes! :name => 'customer_1'
144
- @customer.orders.create! :order_date => Date.today
145
- end
146
-
147
- context 'when reified' do
148
- setup { @customer_0 = @customer.versions.last.reify(:has_many => true) }
149
-
150
- should 'see the associated as it was at the time' do
151
- assert_equal [], @customer_0.orders
152
- end
153
-
154
- should 'not persist changes to the live association' do
155
- assert_not_equal [], @customer.orders(true)
156
- end
157
- end
158
-
159
- context 'when reified with option mark_for_destruction' do
160
- setup { @customer_0 = @customer.versions.last.reify(:has_many => true, :mark_for_destruction => true) }
161
-
162
- should 'mark the associated for destruction' do
163
- assert_equal [true], @customer_0.orders.map(&:marked_for_destruction?)
164
- end
165
- end
166
- end
167
-
168
- context 'where the association is created between model versions' do
169
- setup do
170
- @order = @customer.orders.create! :order_date => 'order_date_0'
171
- Timecop.travel 1.second.since
172
- @customer.update_attributes :name => 'customer_1'
173
- end
174
-
175
- context 'when reified' do
176
- setup { @customer_0 = @customer.versions.last.reify(:has_many => true) }
177
-
178
- should 'see the associated as it was at the time' do
179
- assert_equal ['order_date_0'], @customer_0.orders.map(&:order_date)
180
- end
181
- end
182
-
183
- context 'and then a nested has_many association is created' do
184
- setup do
185
- @order.line_items.create! :product => 'product_0'
186
- end
187
-
188
- context 'when reified' do
189
- setup { @customer_0 = @customer.versions.last.reify(:has_many => true) }
190
-
191
- should 'see the live version of the nested association' do
192
- assert_equal ['product_0'], @customer_0.orders.first.line_items.map(&:product)
193
- end
194
- end
195
- end
196
-
197
- context 'and then the associated is updated between model versions' do
198
- setup do
199
- @order.update_attributes :order_date => 'order_date_1'
200
- @order.update_attributes :order_date => 'order_date_2'
201
- Timecop.travel 1.second.since
202
- @customer.update_attributes :name => 'customer_2'
203
- @order.update_attributes :order_date => 'order_date_3'
204
- end
205
-
206
- context 'when reified' do
207
- setup { @customer_1 = @customer.versions.last.reify(:has_many => true) }
208
-
209
- should 'see the associated as it was at the time' do
210
- assert_equal ['order_date_2'], @customer_1.orders.map(&:order_date)
211
- end
212
-
213
- should 'not persist changes to the live association' do
214
- assert_equal ['order_date_3'], @customer.orders(true).map(&:order_date)
215
- end
216
- end
217
-
218
- context 'when reified opting out of has_many reification' do
219
- setup { @customer_1 = @customer.versions.last.reify(:has_many => false) }
220
-
221
- should 'see the associated as it is live' do
222
- assert_equal ['order_date_3'], @customer_1.orders.map(&:order_date)
223
- end
224
- end
225
-
226
- context 'and then the associated is destroyed' do
227
- setup do
228
- @order.destroy
229
- end
230
-
231
- context 'when reified' do
232
- setup { @customer_1 = @customer.versions.last.reify(:has_many => true) }
233
-
234
- should 'see the associated as it was at the time' do
235
- assert_equal ['order_date_2'], @customer_1.orders.map(&:order_date)
236
- end
237
-
238
- should 'not persist changes to the live association' do
239
- assert_equal [], @customer.orders(true)
240
- end
241
- end
242
- end
243
- end
244
-
245
- context 'and then the associated is destroyed' do
246
- setup do
247
- @order.destroy
248
- end
249
-
250
- context 'when reified' do
251
- setup { @customer_1 = @customer.versions.last.reify(:has_many => true) }
252
-
253
- should 'see the associated as it was at the time' do
254
- assert_equal [@order.order_date], @customer_1.orders.map(&:order_date)
255
- end
256
-
257
- should 'not persist changes to the live association' do
258
- assert_equal [], @customer.orders(true)
259
- end
260
- end
261
- end
262
-
263
- context 'and then the associated is destroyed between model versions' do
264
- setup do
265
- @order.destroy
266
- Timecop.travel 1.second.since
267
- @customer.update_attributes :name => 'customer_2'
268
- end
269
-
270
- context 'when reified' do
271
- setup { @customer_1 = @customer.versions.last.reify(:has_many => true) }
272
-
273
- should 'see the associated as it was at the time' do
274
- assert_equal [], @customer_1.orders
275
- end
276
- end
277
- end
278
-
279
- context 'and then another association is added' do
280
- setup do
281
- @customer.orders.create! :order_date => 'order_date_1'
282
- end
283
-
284
- context 'when reified' do
285
- setup { @customer_0 = @customer.versions.last.reify(:has_many => true) }
286
-
287
- should 'see the associated as it was at the time' do
288
- assert_equal ['order_date_0'], @customer_0.orders.map(&:order_date)
289
- end
290
-
291
- should 'not persist changes to the live association' do
292
- assert_equal ['order_date_0', 'order_date_1'], @customer.orders(true).map(&:order_date).sort
293
- end
294
- end
295
-
296
- context 'when reified with option mark_for_destruction' do
297
- setup { @customer_0 = @customer.versions.last.reify(:has_many => true, :mark_for_destruction => true) }
298
-
299
- should 'mark the newly associated for destruction' do
300
- assert @customer_0.orders.detect { |o| o.order_date == 'order_date_1'}.marked_for_destruction?
301
- end
302
- end
303
- end
304
- end
305
- end
306
-
307
- context "has_many through associations" do
308
- context "Books, Authors, and Authorships" do
309
- setup { @book = Book.create :title => 'book_0' }
310
-
311
- context 'updated before the associated was created' do
312
- setup do
313
- @book.update_attributes! :title => 'book_1'
314
- @book.authors.create! :name => 'author_0'
315
- end
316
-
317
- context 'when reified' do
318
- setup { @book_0 = @book.versions.last.reify(:has_many => true) }
319
-
320
- should 'see the associated as it was at the time' do
321
- assert_equal [], @book_0.authors
322
- end
323
-
324
- should 'not persist changes to the live association' do
325
- assert_equal ['author_0'], @book.authors(true).map(&:name)
326
- end
327
- end
328
-
329
- context 'when reified with option mark_for_destruction' do
330
- setup { @book_0 = @book.versions.last.reify(:has_many => true, :mark_for_destruction => true) }
331
-
332
- should 'mark the associated for destruction' do
333
- assert_equal [true], @book_0.authors.map(&:marked_for_destruction?)
334
- end
335
-
336
- should 'mark the associated-through for destruction' do
337
- assert_equal [true], @book_0.authorships.map(&:marked_for_destruction?)
338
- end
339
- end
340
- end
341
-
342
- context 'updated before it is associated with an existing one' do
343
- setup do
344
- person_existing = Person.create(:name => 'person_existing')
345
- Timecop.travel 1.second.since
346
- @book.update_attributes! :title => 'book_1'
347
- @book.authors << person_existing
348
- end
349
-
350
- context 'when reified' do
351
- setup { @book_0 = @book.versions.last.reify(:has_many => true) }
352
-
353
- should 'see the associated as it was at the time' do
354
- assert_equal [], @book_0.authors
355
- end
356
- end
357
-
358
- context 'when reified with option mark_for_destruction' do
359
- setup { @book_0 = @book.versions.last.reify(:has_many => true, :mark_for_destruction => true) }
360
-
361
- should 'not mark the associated for destruction' do
362
- assert_equal [false], @book_0.authors.map(&:marked_for_destruction?)
363
- end
364
-
365
- should 'mark the associated-through for destruction' do
366
- assert_equal [true], @book_0.authorships.map(&:marked_for_destruction?)
367
- end
368
- end
369
- end
370
-
371
- context 'where the association is created between model versions' do
372
- setup do
373
- @author = @book.authors.create! :name => 'author_0'
374
- @person_existing = Person.create(:name => 'person_existing')
375
- Timecop.travel 1.second.since
376
- @book.update_attributes! :title => 'book_1'
377
- end
378
-
379
- context 'when reified' do
380
- setup { @book_0 = @book.versions.last.reify(:has_many => true) }
381
-
382
- should 'see the associated as it was at the time' do
383
- assert_equal ['author_0'], @book_0.authors.map(&:name)
384
- end
385
- end
386
-
387
- context 'and then the associated is updated between model versions' do
388
- setup do
389
- @author.update_attributes :name => 'author_1'
390
- @author.update_attributes :name => 'author_2'
391
- Timecop.travel 1.second.since
392
- @book.update_attributes :title => 'book_2'
393
- @author.update_attributes :name => 'author_3'
394
- end
395
-
396
- context 'when reified' do
397
- setup { @book_1 = @book.versions.last.reify(:has_many => true) }
398
-
399
- should 'see the associated as it was at the time' do
400
- assert_equal ['author_2'], @book_1.authors.map(&:name)
401
- end
402
-
403
- should 'not persist changes to the live association' do
404
- assert_equal ['author_3'], @book.authors(true).map(&:name)
405
- end
406
- end
407
-
408
- context 'when reified opting out of has_many reification' do
409
- setup { @book_1 = @book.versions.last.reify(:has_many => false) }
410
-
411
- should 'see the associated as it is live' do
412
- assert_equal ['author_3'], @book_1.authors.map(&:name)
413
- end
414
- end
415
- end
416
-
417
- context 'and then the associated is destroyed' do
418
- setup do
419
- @author.destroy
420
- end
421
-
422
- context 'when reified' do
423
- setup { @book_1 = @book.versions.last.reify(:has_many => true) }
424
-
425
- should 'see the associated as it was at the time' do
426
- assert_equal [@author.name], @book_1.authors.map(&:name)
427
- end
428
-
429
- should 'not persist changes to the live association' do
430
- assert_equal [], @book.authors(true)
431
- end
432
- end
433
- end
434
-
435
- context 'and then the associated is destroyed between model versions' do
436
- setup do
437
- @author.destroy
438
- Timecop.travel 1.second.since
439
- @book.update_attributes :title => 'book_2'
440
- end
441
-
442
- context 'when reified' do
443
- setup { @book_1 = @book.versions.last.reify(:has_many => true) }
444
-
445
- should 'see the associated as it was at the time' do
446
- assert_equal [], @book_1.authors
447
- end
448
- end
449
- end
450
-
451
- context 'and then the associated is dissociated between model versions' do
452
- setup do
453
- @book.authors = []
454
- Timecop.travel 1.second.since
455
- @book.update_attributes :title => 'book_2'
456
- end
457
-
458
- context 'when reified' do
459
- setup { @book_1 = @book.versions.last.reify(:has_many => true) }
460
-
461
- should 'see the associated as it was at the time' do
462
- assert_equal [], @book_1.authors
463
- end
464
- end
465
- end
466
-
467
- context 'and then another associated is created' do
468
- setup do
469
- @book.authors.create! :name => 'author_1'
470
- end
471
-
472
- context 'when reified' do
473
- setup { @book_0 = @book.versions.last.reify(:has_many => true) }
474
-
475
- should 'only see the first associated' do
476
- assert_equal ['author_0'], @book_0.authors.map(&:name)
477
- end
478
-
479
- should 'not persist changes to the live association' do
480
- assert_equal ['author_0', 'author_1'], @book.authors(true).map(&:name)
481
- end
482
- end
483
-
484
- context 'when reified with option mark_for_destruction' do
485
- setup { @book_0 = @book.versions.last.reify(:has_many => true, :mark_for_destruction => true) }
486
-
487
- should 'mark the newly associated for destruction' do
488
- assert @book_0.authors.detect { |a| a.name == 'author_1' }.marked_for_destruction?
489
- end
490
-
491
- should 'mark the newly associated-through for destruction' do
492
- assert @book_0.authorships.detect { |as| as.person.name == 'author_1' }.marked_for_destruction?
493
- end
494
- end
495
- end
496
-
497
- context 'and then an existing one is associated' do
498
- setup do
499
- @book.authors << @person_existing
500
- end
501
-
502
- context 'when reified' do
503
- setup { @book_0 = @book.versions.last.reify(:has_many => true) }
504
-
505
- should 'only see the first associated' do
506
- assert_equal ['author_0'], @book_0.authors.map(&:name)
507
- end
508
-
509
- should 'not persist changes to the live association' do
510
- assert_equal ['author_0', 'person_existing'], @book.authors(true).map(&:name).sort
511
- end
512
- end
513
-
514
- context 'when reified with option mark_for_destruction' do
515
- setup { @book_0 = @book.versions.last.reify(:has_many => true, :mark_for_destruction => true) }
516
-
517
- should 'not mark the newly associated for destruction' do
518
- assert !@book_0.authors.detect { |a| a.name == 'person_existing' }.marked_for_destruction?
519
- end
520
-
521
- should 'mark the newly associated-through for destruction' do
522
- assert @book_0.authorships.detect { |as| as.person.name == 'person_existing' }.marked_for_destruction?
523
- end
524
- end
525
- end
526
- end
527
-
528
- context 'updated before the associated without paper_trail was created' do
529
- setup do
530
- @book.update_attributes! :title => 'book_1'
531
- @book.editors.create! :name => 'editor_0'
532
- end
533
-
534
- context 'when reified' do
535
- setup { @book_0 = @book.versions.last.reify(:has_many => true) }
536
-
537
- should 'see the live association' do
538
- assert_equal ['editor_0'], @book_0.editors.map(&:name)
539
- end
540
- end
541
- end
542
- end
543
-
544
- context "Chapters, Sections, Paragraphs, Quotations, and Citations" do
545
- setup { @chapter = Chapter.create(:name => CHAPTER_NAMES[0]) }
546
-
547
- context "before any associations are created" do
548
- setup do
549
- @chapter.update_attributes(:name => CHAPTER_NAMES[1])
550
- end
551
-
552
- should "not reify any associations" do
553
- chapter_v1 = @chapter.versions[1].reify(:has_many => true)
554
- assert_equal CHAPTER_NAMES[0], chapter_v1.name
555
- assert_equal [], chapter_v1.sections
556
- assert_equal [], chapter_v1.paragraphs
557
- end
558
- end
559
-
560
- context "after the first has_many through relationship is created" do
561
- setup do
562
- assert_equal 1, @chapter.versions.size
563
- @chapter.update_attributes :name => CHAPTER_NAMES[1]
564
- assert_equal 2, @chapter.versions.size
565
-
566
- Timecop.travel 1.second.since
567
- @chapter.sections.create :name => "section 1"
568
- Timecop.travel 1.second.since
569
- @chapter.sections.first.update_attributes :name => "section 2"
570
- Timecop.travel 1.second.since
571
- @chapter.update_attributes :name => CHAPTER_NAMES[2]
572
- assert_equal 3, @chapter.versions.size
573
-
574
- Timecop.travel 1.second.since
575
- @chapter.sections.first.update_attributes :name => "section 3"
576
- end
577
-
578
- context "version 1" do
579
- should "have no sections" do
580
- chapter_v1 = @chapter.versions[1].reify(:has_many => true)
581
- assert_equal [], chapter_v1.sections
582
- end
583
- end
584
-
585
- context "version 2" do
586
- should "have one section" do
587
- chapter_v2 = @chapter.versions[2].reify(:has_many => true)
588
- assert_equal 1, chapter_v2.sections.size
589
-
590
- # Shows the value of the section as it was before
591
- # the chapter was updated.
592
- assert_equal ['section 2'], chapter_v2.sections.map(&:name)
593
-
594
- # Shows the value of the chapter as it was before
595
- assert_equal CHAPTER_NAMES[1], chapter_v2.name
596
- end
597
- end
598
-
599
- context "version 2, before the section was destroyed" do
600
- setup do
601
- @chapter.update_attributes :name => CHAPTER_NAMES[2]
602
- Timecop.travel 1.second.since
603
- @chapter.sections.destroy_all
604
- Timecop.travel 1.second.since
605
- end
606
-
607
- should "have the one section" do
608
- chapter_v2 = @chapter.versions[2].reify(:has_many => true)
609
- assert_equal ['section 2'], chapter_v2.sections.map(&:name)
610
- end
611
- end
612
-
613
- context "version 3, after the section was destroyed" do
614
- setup do
615
- @chapter.sections.destroy_all
616
- Timecop.travel 1.second.since
617
- @chapter.update_attributes :name => CHAPTER_NAMES[3]
618
- Timecop.travel 1.second.since
619
- end
620
-
621
- should "have no sections" do
622
- chapter_v3 = @chapter.versions[3].reify(:has_many => true)
623
- assert_equal 0, chapter_v3.sections.size
624
- end
625
- end
626
-
627
- context "after creating a paragraph" do
628
- setup do
629
- assert_equal 3, @chapter.versions.size
630
- @section = @chapter.sections.first
631
- Timecop.travel 1.second.since
632
- @paragraph = @section.paragraphs.create :name => 'para1'
633
- end
634
-
635
- context "new chapter version" do
636
- should "have one paragraph" do
637
- initial_section_name = @section.name
638
- initial_paragraph_name = @paragraph.name
639
- Timecop.travel 1.second.since
640
- @chapter.update_attributes :name => CHAPTER_NAMES[4]
641
- assert_equal 4, @chapter.versions.size
642
- Timecop.travel 1.second.since
643
- @paragraph.update_attributes :name => 'para3'
644
- chapter_v3 = @chapter.versions[3].reify(:has_many => true)
645
- assert_equal [initial_section_name], chapter_v3.sections.map(&:name)
646
- paragraphs = chapter_v3.sections.first.paragraphs
647
- assert_equal 1, paragraphs.size
648
- assert_equal [initial_paragraph_name], paragraphs.map(&:name)
649
- end
650
- end
651
-
652
- context "the version before a section is destroyed" do
653
- should "have the section and paragraph" do
654
- Timecop.travel 1.second.since
655
- @chapter.update_attributes(:name => CHAPTER_NAMES[3])
656
- assert_equal 4, @chapter.versions.size
657
- Timecop.travel 1.second.since
658
- @section.destroy
659
- assert_equal 4, @chapter.versions.size
660
- chapter_v3 = @chapter.versions[3].reify(:has_many => true)
661
- assert_equal CHAPTER_NAMES[2], chapter_v3.name
662
- assert_equal [@section], chapter_v3.sections
663
- assert_equal [@paragraph], chapter_v3.sections[0].paragraphs
664
- assert_equal [@paragraph], chapter_v3.paragraphs
665
- end
666
- end
667
-
668
- context "the version after a section is destroyed" do
669
- should "not have any sections or paragraphs" do
670
- @section.destroy
671
- Timecop.travel 1.second.since
672
- @chapter.update_attributes(:name => CHAPTER_NAMES[5])
673
- assert_equal 4, @chapter.versions.size
674
- chapter_v3 = @chapter.versions[3].reify(:has_many => true)
675
- assert_equal 0, chapter_v3.sections.size
676
- assert_equal 0, chapter_v3.paragraphs.size
677
- end
678
- end
679
-
680
- context "the version before a paragraph is destroyed" do
681
- should "have the one paragraph" do
682
- initial_paragraph_name = @section.paragraphs.first.name
683
- Timecop.travel 1.second.since
684
- @chapter.update_attributes(:name => CHAPTER_NAMES[5])
685
- Timecop.travel 1.second.since
686
- @paragraph.destroy
687
- chapter_v3 = @chapter.versions[3].reify(:has_many => true)
688
- paragraphs = chapter_v3.sections.first.paragraphs
689
- assert_equal 1, paragraphs.size
690
- assert_equal initial_paragraph_name, paragraphs.first.name
691
- end
692
- end
693
-
694
- context "the version after a paragraph is destroyed" do
695
- should "have no paragraphs" do
696
- @paragraph.destroy
697
- Timecop.travel 1.second.since
698
- @chapter.update_attributes(:name => CHAPTER_NAMES[5])
699
- chapter_v3 = @chapter.versions[3].reify(:has_many => true)
700
- assert_equal 0, chapter_v3.paragraphs.size
701
- assert_equal [], chapter_v3.sections.first.paragraphs
702
- end
703
- end
704
- end
705
- end
706
-
707
- context "a chapter with one paragraph and one citation" do
708
- should "reify paragraphs and citations" do
709
- chapter = Chapter.create(:name => CHAPTER_NAMES[0])
710
- section = Section.create(:name => 'Section One', :chapter => chapter)
711
- paragraph = Paragraph.create(:name => 'Paragraph One', :section => section)
712
- quotation = Quotation.create(:chapter => chapter)
713
- citation = Citation.create(:quotation => quotation)
714
- Timecop.travel 1.second.since
715
- chapter.update_attributes(:name => CHAPTER_NAMES[1])
716
- assert_equal 2, chapter.versions.count
717
- paragraph.destroy
718
- citation.destroy
719
- reified = chapter.versions[1].reify(:has_many => true)
720
- assert_equal [paragraph], reified.sections.first.paragraphs
721
- assert_equal [citation], reified.quotations.first.citations
722
- end
723
- end
724
- end
725
- end
726
- end