paper_trail 6.0.2 → 7.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/CONTRIBUTING.md +20 -0
- data/.rubocop.yml +30 -2
- data/.rubocop_todo.yml +20 -0
- data/.travis.yml +3 -5
- data/Appraisals +5 -6
- data/CHANGELOG.md +33 -0
- data/README.md +43 -81
- data/Rakefile +1 -1
- data/doc/bug_report_template.rb +4 -2
- data/gemfiles/ar_4.0.gemfile +7 -0
- data/gemfiles/ar_4.2.gemfile +0 -1
- data/lib/generators/paper_trail/templates/create_version_associations.rb +1 -1
- data/lib/generators/paper_trail/templates/create_versions.rb +1 -1
- data/lib/paper_trail.rb +7 -9
- data/lib/paper_trail/config.rb +0 -15
- data/lib/paper_trail/frameworks/rspec.rb +8 -2
- data/lib/paper_trail/model_config.rb +6 -2
- data/lib/paper_trail/record_trail.rb +3 -1
- data/lib/paper_trail/reifier.rb +43 -354
- data/lib/paper_trail/reifiers/belongs_to.rb +48 -0
- data/lib/paper_trail/reifiers/has_and_belongs_to_many.rb +50 -0
- data/lib/paper_trail/reifiers/has_many.rb +110 -0
- data/lib/paper_trail/reifiers/has_many_through.rb +90 -0
- data/lib/paper_trail/reifiers/has_one.rb +76 -0
- data/lib/paper_trail/serializers/yaml.rb +2 -25
- data/lib/paper_trail/version_concern.rb +5 -5
- data/lib/paper_trail/version_number.rb +7 -3
- data/paper_trail.gemspec +7 -34
- data/spec/controllers/articles_controller_spec.rb +1 -1
- data/spec/generators/install_generator_spec.rb +40 -34
- data/spec/models/animal_spec.rb +50 -25
- data/spec/models/boolit_spec.rb +8 -7
- data/spec/models/callback_modifier_spec.rb +13 -13
- data/spec/models/document_spec.rb +21 -0
- data/spec/models/gadget_spec.rb +35 -39
- data/spec/models/joined_version_spec.rb +4 -4
- data/spec/models/json_version_spec.rb +14 -15
- data/spec/models/not_on_update_spec.rb +1 -1
- data/spec/models/post_with_status_spec.rb +2 -2
- data/spec/models/skipper_spec.rb +4 -4
- data/spec/models/thing_spec.rb +1 -1
- data/spec/models/truck_spec.rb +1 -1
- data/spec/models/vehicle_spec.rb +1 -1
- data/spec/models/version_spec.rb +152 -168
- data/spec/models/widget_spec.rb +170 -196
- data/spec/modules/paper_trail_spec.rb +3 -3
- data/spec/modules/version_concern_spec.rb +5 -8
- data/spec/modules/version_number_spec.rb +11 -36
- data/spec/paper_trail/cleaner_spec.rb +152 -0
- data/spec/paper_trail/config_spec.rb +1 -1
- data/spec/paper_trail/serializers/custom_yaml_serializer_spec.rb +45 -0
- data/spec/paper_trail/serializers/json_spec.rb +57 -0
- data/spec/paper_trail/version_limit_spec.rb +55 -0
- data/spec/paper_trail_spec.rb +45 -32
- data/spec/requests/articles_spec.rb +4 -4
- data/test/dummy/app/models/custom_primary_key_record.rb +4 -2
- data/test/dummy/app/models/document.rb +1 -1
- data/test/dummy/app/models/not_on_update.rb +1 -1
- data/test/dummy/app/models/on/create.rb +6 -0
- data/test/dummy/app/models/on/destroy.rb +6 -0
- data/test/dummy/app/models/on/empty_array.rb +6 -0
- data/test/dummy/app/models/on/update.rb +6 -0
- data/test/dummy/app/models/person.rb +1 -0
- data/test/dummy/app/models/song.rb +19 -28
- data/test/dummy/config/application.rb +10 -43
- data/test/dummy/config/routes.rb +1 -1
- data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +25 -51
- data/test/dummy/db/schema.rb +29 -19
- data/test/test_helper.rb +0 -16
- data/test/unit/associations_test.rb +81 -81
- data/test/unit/model_test.rb +48 -131
- data/test/unit/serializer_test.rb +34 -45
- data/test/unit/serializers/mixin_json_test.rb +3 -1
- data/test/unit/serializers/yaml_test.rb +1 -5
- metadata +44 -19
- data/lib/paper_trail/frameworks/sinatra.rb +0 -40
- data/test/functional/modular_sinatra_test.rb +0 -46
- data/test/functional/sinatra_test.rb +0 -51
- data/test/unit/cleaner_test.rb +0 -151
- data/test/unit/inheritance_column_test.rb +0 -41
- data/test/unit/serializers/json_test.rb +0 -95
- data/test/unit/serializers/mixin_yaml_test.rb +0 -53
@@ -4,13 +4,13 @@ describe PaperTrail, type: :module, versioning: true do
|
|
4
4
|
describe "#config" do
|
5
5
|
it { is_expected.to respond_to(:config) }
|
6
6
|
|
7
|
-
it "
|
7
|
+
it "allows for config values to be set" do
|
8
8
|
expect(subject.config.enabled).to eq(true)
|
9
9
|
subject.config.enabled = false
|
10
10
|
expect(subject.config.enabled).to eq(false)
|
11
11
|
end
|
12
12
|
|
13
|
-
it "
|
13
|
+
it "accepts blocks and yield the config instance" do
|
14
14
|
expect(subject.config.enabled).to eq(true)
|
15
15
|
subject.config { |c| c.enabled = false }
|
16
16
|
expect(subject.config.enabled).to eq(false)
|
@@ -20,7 +20,7 @@ describe PaperTrail, type: :module, versioning: true do
|
|
20
20
|
describe "#configure" do
|
21
21
|
it { is_expected.to respond_to(:configure) }
|
22
22
|
|
23
|
-
it "
|
23
|
+
it "is an alias for the `config` method" do
|
24
24
|
expect(subject.method(:configure)).to eq(subject.method(:config))
|
25
25
|
end
|
26
26
|
end
|
@@ -18,14 +18,11 @@ describe PaperTrail::VersionConcern do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
describe "persistence", versioning: true do
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
it "should store versions in the correct corresponding db location" do
|
27
|
-
expect(@foo_doc.versions.first).to be_instance_of(Foo::Version)
|
28
|
-
expect(@bar_doc.versions.first).to be_instance_of(Bar::Version)
|
21
|
+
it "stores versions in the correct corresponding db location" do
|
22
|
+
foo_doc = Foo::Document.create!(name: "foobar")
|
23
|
+
bar_doc = Bar::Document.create!(name: "raboof")
|
24
|
+
expect(foo_doc.versions.first).to be_instance_of(Foo::Version)
|
25
|
+
expect(bar_doc.versions.first).to be_instance_of(Bar::Version)
|
29
26
|
end
|
30
27
|
end
|
31
28
|
end
|
@@ -1,43 +1,18 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
|
4
|
-
describe
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
end
|
15
|
-
describe :TINY do
|
16
|
-
it { is_expected.to be_const_defined(:TINY) }
|
17
|
-
it { expect(subject::TINY).to be_a(Integer) }
|
18
|
-
end
|
19
|
-
describe :PRE do
|
20
|
-
it { is_expected.to be_const_defined(:PRE) }
|
21
|
-
if PaperTrail::VERSION::PRE
|
22
|
-
it { expect(subject::PRE).to be_instance_of(String) }
|
23
|
-
end
|
24
|
-
end
|
25
|
-
describe :STRING do
|
26
|
-
it { is_expected.to be_const_defined(:STRING) }
|
27
|
-
it { expect(subject::STRING).to be_instance_of(String) }
|
28
|
-
|
29
|
-
it "should join the numbers into a period separated string" do
|
30
|
-
expect(subject::STRING).to eq(
|
31
|
-
[subject::MAJOR, subject::MINOR, subject::TINY, subject::PRE].compact.join(".")
|
3
|
+
module PaperTrail
|
4
|
+
RSpec.describe VERSION do
|
5
|
+
describe "STRING" do
|
6
|
+
it "joins the numbers into a period separated string" do
|
7
|
+
expect(described_class::STRING).to eq(
|
8
|
+
[
|
9
|
+
described_class::MAJOR,
|
10
|
+
described_class::MINOR,
|
11
|
+
described_class::TINY,
|
12
|
+
described_class::PRE
|
13
|
+
].compact.join(".")
|
32
14
|
)
|
33
15
|
end
|
34
16
|
end
|
35
17
|
end
|
36
18
|
end
|
37
|
-
|
38
|
-
describe PaperTrail do
|
39
|
-
describe "#version" do
|
40
|
-
it { is_expected.to respond_to(:version) }
|
41
|
-
it { expect(subject.version).to eq(PaperTrail::VERSION::STRING) }
|
42
|
-
end
|
43
|
-
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require "rails_helper"
|
2
|
+
|
3
|
+
module PaperTrail
|
4
|
+
RSpec.describe Cleaner, versioning: true do
|
5
|
+
describe "clean_versions!" do
|
6
|
+
let(:animal) { ::Animal.new }
|
7
|
+
let(:dog) { ::Dog.new }
|
8
|
+
let(:cat) { ::Cat.new }
|
9
|
+
let(:animals) { [animal, dog, cat] }
|
10
|
+
|
11
|
+
before do
|
12
|
+
animals.each do |animal|
|
13
|
+
3.times do
|
14
|
+
animal.update_attribute(:name, FFaker::Name.name)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "baseline test setup" do
|
20
|
+
expect(PaperTrail::Version.count).to(eq(9))
|
21
|
+
animals.each { |animal| expect(animal.versions.size).to(eq(3)) }
|
22
|
+
end
|
23
|
+
|
24
|
+
context "no options provided" do
|
25
|
+
it "removes extra versions for each item" do
|
26
|
+
PaperTrail.clean_versions!
|
27
|
+
expect(PaperTrail::Version.count).to(eq(3))
|
28
|
+
animals.each { |animal| expect(animal.versions.size).to(eq(1)) }
|
29
|
+
end
|
30
|
+
|
31
|
+
it "removes the earliest version(s)" do
|
32
|
+
before = animals.map { |animal| animal.versions.last.reify.name }
|
33
|
+
PaperTrail.clean_versions!
|
34
|
+
after = animals.map { |animal| animal.versions.last.reify.name }
|
35
|
+
expect(after).to(eq(before))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "keeping 2" do
|
40
|
+
it "keeps two records, instead of the usual one" do
|
41
|
+
PaperTrail.clean_versions!(keeping: 2)
|
42
|
+
expect(PaperTrail::Version.all.count).to(eq(6))
|
43
|
+
animals.each { |animal| expect(animal.versions.size).to(eq(2)) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "with the :date option" do
|
48
|
+
it "only deletes versions created on the given date" do
|
49
|
+
animal.versions.each do |ver|
|
50
|
+
ver.update_attribute(:created_at, (ver.created_at - 1.day))
|
51
|
+
end
|
52
|
+
date = animal.versions.first.created_at.to_date
|
53
|
+
animal.update_attribute(:name, FFaker::Name.name)
|
54
|
+
expect(PaperTrail::Version.count).to(eq(10))
|
55
|
+
expect(animal.versions.size).to(eq(4))
|
56
|
+
expect(animal.paper_trail.versions_between(date, (date + 1.day)).size).to(eq(3))
|
57
|
+
PaperTrail.clean_versions!(date: date)
|
58
|
+
expect(PaperTrail::Version.count).to(eq(8))
|
59
|
+
expect(animal.versions.reload.size).to(eq(2))
|
60
|
+
expect(animal.versions.first.created_at.to_date).to(eq(date))
|
61
|
+
# Why use `equal?` here instead of something less strict?
|
62
|
+
# Doesn't `to_date` always produce a new date object?
|
63
|
+
expect(date.equal?(animal.versions.last.created_at.to_date)).to eq(false)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "with the :item_id option" do
|
68
|
+
context "single ID received" do
|
69
|
+
it "only deletes the versions for the Item with that ID" do
|
70
|
+
PaperTrail.clean_versions!(item_id: animal.id)
|
71
|
+
expect(animal.versions.size).to(eq(1))
|
72
|
+
expect(PaperTrail::Version.count).to(eq(7))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "collection of IDs received" do
|
77
|
+
it "only deletes versions for the Item(s) with those IDs" do
|
78
|
+
PaperTrail.clean_versions!(item_id: [animal.id, dog.id])
|
79
|
+
expect(animal.versions.size).to(eq(1))
|
80
|
+
expect(dog.versions.size).to(eq(1))
|
81
|
+
expect(PaperTrail::Version.count).to(eq(5))
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "options combinations" do
|
87
|
+
context ":date" do
|
88
|
+
before do
|
89
|
+
[animal, dog].each do |animal|
|
90
|
+
animal.versions.each do |ver|
|
91
|
+
ver.update_attribute(:created_at, (ver.created_at - 1.day))
|
92
|
+
end
|
93
|
+
animal.update_attribute(:name, FFaker::Name.name)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
it "baseline test setup" do
|
98
|
+
date = animal.versions.first.created_at.to_date
|
99
|
+
expect(PaperTrail::Version.count).to(eq(11))
|
100
|
+
[animal, dog].each do |animal|
|
101
|
+
expect(animal.versions.size).to(eq(4))
|
102
|
+
expect(animal.versions.between(date, (date + 1.day)).size).to(eq(3))
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context "and :keeping" do
|
107
|
+
it "restrict cleaning properly" do
|
108
|
+
date = animal.versions.first.created_at.to_date
|
109
|
+
PaperTrail.clean_versions!(date: date, keeping: 2)
|
110
|
+
[animal, dog].each do |animal|
|
111
|
+
animal.versions.reload
|
112
|
+
expect(animal.versions.size).to(eq(3))
|
113
|
+
expect(animal.versions.between(date, (date + 1.day)).size).to(eq(2))
|
114
|
+
end
|
115
|
+
expect(PaperTrail::Version.count).to(eq(9))
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context "and :item_id" do
|
120
|
+
it "restrict cleaning properly" do
|
121
|
+
date = animal.versions.first.created_at.to_date
|
122
|
+
PaperTrail.clean_versions!(date: date, item_id: dog.id)
|
123
|
+
dog.versions.reload
|
124
|
+
expect(dog.versions.size).to(eq(2))
|
125
|
+
expect(dog.versions.between(date, (date + 1.day)).size).to(eq(1))
|
126
|
+
expect(PaperTrail::Version.count).to(eq(9))
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context ", :item_id, and :keeping" do
|
131
|
+
it "restrict cleaning properly" do
|
132
|
+
date = animal.versions.first.created_at.to_date
|
133
|
+
PaperTrail.clean_versions!(date: date, item_id: dog.id, keeping: 2)
|
134
|
+
dog.versions.reload
|
135
|
+
expect(dog.versions.size).to(eq(3))
|
136
|
+
expect(dog.versions.between(date, (date + 1.day)).size).to(eq(2))
|
137
|
+
expect(PaperTrail::Version.count).to(eq(10))
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context ":keeping and :item_id" do
|
143
|
+
it "restrict cleaning properly" do
|
144
|
+
PaperTrail.clean_versions!(keeping: 2, item_id: animal.id)
|
145
|
+
expect(animal.versions.size).to(eq(2))
|
146
|
+
expect(PaperTrail::Version.count).to(eq(8))
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "rails_helper"
|
2
|
+
|
3
|
+
module CustomYamlSerializer
|
4
|
+
extend PaperTrail::Serializers::YAML
|
5
|
+
|
6
|
+
def self.load(string)
|
7
|
+
parsed_value = super(string)
|
8
|
+
if parsed_value.is_a?(Hash)
|
9
|
+
parsed_value.reject { |k, v| (k.blank? || v.blank?) }
|
10
|
+
else
|
11
|
+
parsed_value
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.dump(object)
|
16
|
+
object.is_a?(Hash) ? super(object.reject { |_k, v| v.nil? }) : super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
RSpec.describe CustomYamlSerializer do
|
21
|
+
let(:word_hash) {
|
22
|
+
{
|
23
|
+
"key1" => ::FFaker::Lorem.word,
|
24
|
+
"key2" => nil,
|
25
|
+
"tkey" => nil,
|
26
|
+
"" => "foo"
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
context(".load") do
|
31
|
+
it("deserializes YAML to Ruby, removing pairs with blank keys or values") do
|
32
|
+
expect(described_class.load(word_hash.to_yaml)).to eq(
|
33
|
+
word_hash.reject { |k, v| (k.blank? || v.blank?) }
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context(".dump") do
|
39
|
+
it("serializes Ruby to YAML, removing pairs with nil values") do
|
40
|
+
expect(described_class.dump(word_hash)).to eq(
|
41
|
+
word_hash.reject { |_k, v| v.nil? }.to_yaml
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "rails_helper"
|
2
|
+
|
3
|
+
module PaperTrail
|
4
|
+
module Serializers
|
5
|
+
RSpec.describe JSON do
|
6
|
+
let(:word_hash) {
|
7
|
+
(1..4).each_with_object({}) { |i, a| a["key#{i}"] = ::FFaker::Lorem.word }
|
8
|
+
}
|
9
|
+
let(:word_array) { [].fill(0, rand(5) + 4) { ::FFaker::Lorem.word } }
|
10
|
+
|
11
|
+
describe ".load" do
|
12
|
+
it "deserialize JSON to Ruby" do
|
13
|
+
expect(described_class.load(word_hash.to_json)).to eq(word_hash)
|
14
|
+
expect(described_class.load(word_array.to_json)).to eq(word_array)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe ".dump" do
|
19
|
+
it "serializes Ruby to JSON" do
|
20
|
+
expect(described_class.dump(word_hash)).to eq(word_hash.to_json)
|
21
|
+
expect(described_class.dump(word_array)).to eq(word_array.to_json)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe ".where_object_condition" do
|
26
|
+
context "when value is a string" do
|
27
|
+
it "construct correct WHERE query" do
|
28
|
+
matches = described_class.
|
29
|
+
where_object_condition(PaperTrail::Version.arel_table[:object], :arg1, "Val 1")
|
30
|
+
expect(matches.instance_of?(Arel::Nodes::Matches)).to(eq(true))
|
31
|
+
expect(matches.right.val).to eq("%\"arg1\":\"Val 1\"%")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "when value is null" do
|
36
|
+
it "construct correct WHERE query" do
|
37
|
+
matches = described_class.
|
38
|
+
where_object_condition(PaperTrail::Version.arel_table[:object], :arg1, nil)
|
39
|
+
expect(matches.instance_of?(Arel::Nodes::Matches)).to(eq(true))
|
40
|
+
expect(matches.right.val).to(eq("%\"arg1\":null%"))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when value is a number" do
|
45
|
+
it "construct correct WHERE query" do
|
46
|
+
grouping = described_class.
|
47
|
+
where_object_condition(PaperTrail::Version.arel_table[:object], :arg1, -3.5)
|
48
|
+
expect(grouping.instance_of?(Arel::Nodes::Grouping)).to(eq(true))
|
49
|
+
matches = grouping.select { |v| v.instance_of?(Arel::Nodes::Matches) }
|
50
|
+
expect(matches.first.right.val).to eq("%\"arg1\":-3.5,%")
|
51
|
+
expect(matches.last.right.val).to eq("%\"arg1\":-3.5}%")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "rails_helper"
|
2
|
+
|
3
|
+
module PaperTrail
|
4
|
+
RSpec.describe Cleaner, versioning: true do
|
5
|
+
after do
|
6
|
+
PaperTrail.config.version_limit = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
it "cleans up old versions" do
|
10
|
+
PaperTrail.config.version_limit = 10
|
11
|
+
widget = Widget.create
|
12
|
+
|
13
|
+
100.times do |i|
|
14
|
+
widget.update_attributes(name: "Name #{i}")
|
15
|
+
expect(Widget.find(widget.id).versions.count).to be <= 11
|
16
|
+
# 11 versions = 10 updates + 1 create.
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "deletes oldest versions, when the database returns them in a different order" do
|
21
|
+
epoch = DateTime.new(2017, 1, 1)
|
22
|
+
|
23
|
+
widget = Timecop.freeze(epoch) { Widget.create }
|
24
|
+
|
25
|
+
# Sometimes a database will returns records in a different order than
|
26
|
+
# they were inserted. That's hard to get the database to do, so we'll
|
27
|
+
# just create them out-of-order:
|
28
|
+
(1..5).to_a.shuffle.each do |n|
|
29
|
+
Timecop.freeze(epoch + n.hours) do
|
30
|
+
PaperTrail::Version.create!(
|
31
|
+
item: widget,
|
32
|
+
event: "update",
|
33
|
+
object: { "id" => widget.id, "name" => "Name #{n}" }.to_yaml
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
expect(Widget.find(widget.id).versions.count).to eq(6) # 1 create + 5 updates
|
38
|
+
|
39
|
+
# Now, we've recreated the scenario where we can accidentally clean up
|
40
|
+
# the wrong versions. Re-enable the version_limit, and trigger the
|
41
|
+
# clean-up:
|
42
|
+
PaperTrail.config.version_limit = 3
|
43
|
+
widget.versions.last.send(:enforce_version_limit!)
|
44
|
+
|
45
|
+
# Verify that we have fewer versions:
|
46
|
+
expect(widget.reload.versions.count).to eq(4) # 1 create + 4 updates
|
47
|
+
|
48
|
+
# Exclude the create, because the create will return nil for `#reify`.
|
49
|
+
last_names = widget.versions.not_creates.map(&:reify).map(&:name)
|
50
|
+
expect(last_names).to eq(["Name 3", "Name 4", "Name 5"])
|
51
|
+
# No matter what order the version records are returned it, we should
|
52
|
+
# always keep the most-recent changes.
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/spec/paper_trail_spec.rb
CHANGED
@@ -1,79 +1,92 @@
|
|
1
1
|
require "rails_helper"
|
2
2
|
|
3
|
-
describe PaperTrail do
|
3
|
+
RSpec.describe PaperTrail do
|
4
|
+
describe ".gem_version" do
|
5
|
+
it "returns a Gem::Version" do
|
6
|
+
v = described_class.gem_version
|
7
|
+
expect(v).to be_a(::Gem::Version)
|
8
|
+
expect(v.to_s).to eq(::PaperTrail::VERSION::STRING)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
4
12
|
context "when enabled" do
|
5
13
|
it "affects all threads" do
|
6
|
-
Thread.new {
|
7
|
-
assert_equal false,
|
14
|
+
Thread.new { described_class.enabled = false }.join
|
15
|
+
assert_equal false, described_class.enabled?
|
8
16
|
end
|
9
17
|
|
10
18
|
after do
|
11
|
-
|
19
|
+
described_class.enabled = true
|
12
20
|
end
|
13
21
|
end
|
14
22
|
|
15
23
|
context "default" do
|
16
|
-
it "
|
17
|
-
expect(
|
24
|
+
it "has versioning off by default" do
|
25
|
+
expect(described_class).not_to be_enabled
|
18
26
|
end
|
19
27
|
|
20
|
-
it "
|
21
|
-
expect(
|
28
|
+
it "has versioning on in a `with_versioning` block" do
|
29
|
+
expect(described_class).not_to be_enabled
|
22
30
|
with_versioning do
|
23
|
-
expect(
|
31
|
+
expect(described_class).to be_enabled
|
24
32
|
end
|
25
|
-
expect(
|
33
|
+
expect(described_class).not_to be_enabled
|
26
34
|
end
|
27
35
|
|
28
36
|
context "error within `with_versioning` block" do
|
29
|
-
it "
|
30
|
-
expect(
|
37
|
+
it "reverts the value of `PaperTrail.enabled?` to its previous state" do
|
38
|
+
expect(described_class).not_to be_enabled
|
31
39
|
expect { with_versioning { raise } }.to raise_error(RuntimeError)
|
32
|
-
expect(
|
40
|
+
expect(described_class).not_to be_enabled
|
33
41
|
end
|
34
42
|
end
|
35
43
|
end
|
36
44
|
|
37
45
|
context "`versioning: true`", versioning: true do
|
38
|
-
it "
|
39
|
-
expect(
|
46
|
+
it "has versioning on by default" do
|
47
|
+
expect(described_class).to be_enabled
|
40
48
|
end
|
41
49
|
|
42
|
-
it "
|
43
|
-
expect(
|
50
|
+
it "keeps versioning on after a with_versioning block" do
|
51
|
+
expect(described_class).to be_enabled
|
44
52
|
with_versioning do
|
45
|
-
expect(
|
53
|
+
expect(described_class).to be_enabled
|
46
54
|
end
|
47
|
-
expect(
|
55
|
+
expect(described_class).to be_enabled
|
48
56
|
end
|
49
57
|
end
|
50
58
|
|
51
59
|
context "`with_versioning` block at class level" do
|
52
|
-
it { expect(
|
60
|
+
it { expect(described_class).not_to be_enabled }
|
53
61
|
|
54
62
|
with_versioning do
|
55
|
-
it "
|
56
|
-
expect(
|
63
|
+
it "has versioning on by default" do
|
64
|
+
expect(described_class).to be_enabled
|
57
65
|
end
|
58
66
|
end
|
59
|
-
it "
|
60
|
-
expect(
|
67
|
+
it "does not leak the `enabled?` state into successive tests" do
|
68
|
+
expect(described_class).not_to be_enabled
|
61
69
|
end
|
62
70
|
end
|
63
71
|
|
64
|
-
describe
|
65
|
-
|
72
|
+
describe ".version" do
|
73
|
+
it { expect(described_class).to respond_to(:version) }
|
74
|
+
it { expect(described_class.version).to eq(described_class::VERSION::STRING) }
|
75
|
+
end
|
76
|
+
|
77
|
+
describe ".whodunnit" do
|
78
|
+
before(:all) { described_class.whodunnit = "foobar" }
|
66
79
|
|
67
|
-
it "
|
68
|
-
expect(
|
80
|
+
it "is nil by default" do
|
81
|
+
expect(described_class.whodunnit).to be_nil
|
69
82
|
end
|
70
83
|
end
|
71
84
|
|
72
|
-
describe
|
73
|
-
before(:all) {
|
85
|
+
describe ".controller_info" do
|
86
|
+
before(:all) { described_class.controller_info = { foo: "bar" } }
|
74
87
|
|
75
|
-
it "
|
76
|
-
expect(
|
88
|
+
it "is set to an empty hash before each test" do
|
89
|
+
expect(described_class.controller_info).to eq({})
|
77
90
|
end
|
78
91
|
end
|
79
92
|
end
|