paper_trail 6.0.2 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|