2017-05-30 04:58:26 +00:00
|
|
|
require "spec_helper"
|
2013-10-11 14:42:12 +00:00
|
|
|
|
2017-04-01 23:47:32 +00:00
|
|
|
module PaperTrail
|
2017-05-21 05:41:20 +00:00
|
|
|
::RSpec.describe Version, type: :model do
|
2016-02-16 03:32:40 +00:00
|
|
|
describe "object_changes column", versioning: true do
|
2016-03-05 22:07:32 +00:00
|
|
|
let(:widget) { Widget.create!(name: "Dashboard") }
|
2014-10-21 19:05:16 +00:00
|
|
|
let(:value) { widget.versions.last.object_changes }
|
|
|
|
|
|
|
|
context "serializer is YAML" do
|
|
|
|
specify { expect(PaperTrail.serializer).to be PaperTrail::Serializers::YAML }
|
|
|
|
|
2017-04-01 05:50:13 +00:00
|
|
|
it "store out as a plain hash" do
|
2014-10-21 19:30:29 +00:00
|
|
|
expect(value =~ /HashWithIndifferentAccess/).to be_nil
|
2014-10-21 19:05:16 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "serializer is JSON" do
|
|
|
|
before(:all) { PaperTrail.serializer = PaperTrail::Serializers::JSON }
|
|
|
|
|
2017-04-01 05:50:13 +00:00
|
|
|
it "store out as a plain hash" do
|
2014-10-21 19:30:29 +00:00
|
|
|
expect(value =~ /HashWithIndifferentAccess/).to be_nil
|
2014-10-21 19:05:16 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
after(:all) { PaperTrail.serializer = PaperTrail::Serializers::YAML }
|
|
|
|
end
|
|
|
|
end
|
2013-10-11 14:42:12 +00:00
|
|
|
|
2017-04-01 23:47:32 +00:00
|
|
|
describe "#paper_trail_originator" do
|
|
|
|
context "no previous versions" do
|
|
|
|
it "returns nil" do
|
|
|
|
expect(PaperTrail::Version.new.paper_trail_originator).to be_nil
|
2015-05-08 17:28:47 +00:00
|
|
|
end
|
2017-04-01 23:47:32 +00:00
|
|
|
end
|
2015-05-08 17:28:47 +00:00
|
|
|
|
2017-04-01 23:47:32 +00:00
|
|
|
context "has previous version", versioning: true do
|
|
|
|
it "returns name of whodunnit" do
|
|
|
|
name = FFaker::Name.name
|
|
|
|
widget = Widget.create!(name: FFaker::Name.name)
|
|
|
|
widget.versions.first.update_attributes!(whodunnit: name)
|
|
|
|
widget.update_attributes!(name: FFaker::Name.first_name)
|
|
|
|
expect(widget.versions.last.paper_trail_originator).to eq(name)
|
2015-05-08 17:28:47 +00:00
|
|
|
end
|
|
|
|
end
|
2017-04-01 23:47:32 +00:00
|
|
|
end
|
2015-05-08 17:28:47 +00:00
|
|
|
|
2017-04-01 23:47:32 +00:00
|
|
|
describe "#previous" do
|
|
|
|
context "no previous versions" do
|
|
|
|
it "returns nil" do
|
|
|
|
expect(PaperTrail::Version.new.previous).to be_nil
|
2015-05-08 17:28:47 +00:00
|
|
|
end
|
2017-04-01 23:47:32 +00:00
|
|
|
end
|
2015-05-08 17:28:47 +00:00
|
|
|
|
2017-04-01 23:47:32 +00:00
|
|
|
context "has previous version", versioning: true do
|
|
|
|
it "returns a PaperTrail::Version" do
|
|
|
|
name = FFaker::Name.name
|
|
|
|
widget = Widget.create!(name: FFaker::Name.name)
|
|
|
|
widget.versions.first.update_attributes!(whodunnit: name)
|
|
|
|
widget.update_attributes!(name: FFaker::Name.first_name)
|
|
|
|
expect(widget.versions.last.previous).to be_instance_of(PaperTrail::Version)
|
2015-05-08 17:28:47 +00:00
|
|
|
end
|
|
|
|
end
|
2017-04-01 23:47:32 +00:00
|
|
|
end
|
2015-05-08 17:28:47 +00:00
|
|
|
|
2017-04-01 23:47:32 +00:00
|
|
|
describe "#originator" do
|
2017-10-27 16:07:47 +00:00
|
|
|
it "delegates to paper_trail_originator" do
|
2017-04-01 23:47:32 +00:00
|
|
|
allow(ActiveSupport::Deprecation).to receive(:warn)
|
2017-10-27 16:07:47 +00:00
|
|
|
version = PaperTrail::Version.new
|
|
|
|
allow(version).to receive(:paper_trail_originator)
|
|
|
|
version.originator
|
|
|
|
expect(version).to have_received(:paper_trail_originator)
|
2013-10-11 14:42:12 +00:00
|
|
|
end
|
|
|
|
|
2017-04-01 23:47:32 +00:00
|
|
|
it "displays a deprecation warning" do
|
2017-09-19 03:56:07 +00:00
|
|
|
allow(ActiveSupport::Deprecation).to receive(:warn)
|
|
|
|
PaperTrail::Version.new.originator
|
|
|
|
expect(ActiveSupport::Deprecation).to have_received(:warn).
|
2017-04-01 23:47:32 +00:00
|
|
|
with(/Use paper_trail_originator instead of originator/)
|
2013-10-11 14:42:12 +00:00
|
|
|
end
|
|
|
|
end
|
2014-06-26 21:29:09 +00:00
|
|
|
|
2017-04-01 23:47:32 +00:00
|
|
|
describe "#terminator" do
|
|
|
|
it "is an alias for the `whodunnit` attribute" do
|
|
|
|
attributes = { whodunnit: FFaker::Name.first_name }
|
2017-10-27 16:07:47 +00:00
|
|
|
version = PaperTrail::Version.new(attributes)
|
|
|
|
expect(version.terminator).to eq(attributes[:whodunnit])
|
2017-04-01 23:47:32 +00:00
|
|
|
end
|
2017-04-01 06:28:55 +00:00
|
|
|
end
|
|
|
|
|
2017-04-01 23:47:32 +00:00
|
|
|
describe "#version_author" do
|
|
|
|
it "is an alias for the `terminator` method" do
|
2017-10-27 16:07:47 +00:00
|
|
|
version = PaperTrail::Version.new
|
|
|
|
expect(version.method(:version_author)).to eq(version.method(:terminator))
|
2017-04-01 23:47:32 +00:00
|
|
|
end
|
|
|
|
end
|
2017-04-01 06:28:55 +00:00
|
|
|
|
2017-10-27 16:07:47 +00:00
|
|
|
context "changing the data type of database columns on the fly" do
|
2017-05-24 05:08:53 +00:00
|
|
|
# TODO: Changing the data type of these database columns in the middle
|
|
|
|
# of the test suite adds a fair amount of complication. Is there a better
|
|
|
|
# way? We already have a `json_versions` table in our tests, maybe we
|
|
|
|
# could use that and add a `jsonb_versions` table?
|
2017-04-01 23:47:32 +00:00
|
|
|
column_overrides = [false]
|
|
|
|
if ENV["DB"] == "postgres" && ::ActiveRecord::VERSION::MAJOR >= 4
|
|
|
|
column_overrides << "json"
|
|
|
|
# 'jsonb' column types are only supported for ActiveRecord 4.2+
|
|
|
|
column_overrides << "jsonb" if ::ActiveRecord::VERSION::STRING >= "4.2"
|
|
|
|
end
|
2014-06-26 21:29:09 +00:00
|
|
|
|
2017-09-20 07:53:51 +00:00
|
|
|
column_overrides.shuffle.each do |column_datatype_override|
|
|
|
|
context "with a #{column_datatype_override || 'text'} column" do
|
2017-10-23 17:07:27 +00:00
|
|
|
let(:widget) { Widget.new }
|
|
|
|
let(:name) { FFaker::Name.first_name }
|
|
|
|
let(:int) { column_datatype_override ? 1 : rand(5) + 2 }
|
|
|
|
|
2014-06-26 21:29:09 +00:00
|
|
|
before do
|
2017-09-20 07:53:51 +00:00
|
|
|
if column_datatype_override
|
2017-05-24 05:08:53 +00:00
|
|
|
# In rails < 5, we use truncation, ie. there is no transaction
|
|
|
|
# around the tests, so we can't use a savepoint.
|
|
|
|
if active_record_gem_version >= ::Gem::Version.new("5")
|
|
|
|
ActiveRecord::Base.connection.execute("SAVEPOINT pgtest;")
|
|
|
|
end
|
2017-05-21 06:40:23 +00:00
|
|
|
%w[object object_changes].each do |column|
|
2017-04-01 23:47:32 +00:00
|
|
|
ActiveRecord::Base.connection.execute(
|
|
|
|
"ALTER TABLE versions DROP COLUMN #{column};"
|
|
|
|
)
|
|
|
|
ActiveRecord::Base.connection.execute(
|
2017-09-20 07:53:51 +00:00
|
|
|
"ALTER TABLE versions ADD COLUMN #{column} #{column_datatype_override};"
|
2017-04-01 23:47:32 +00:00
|
|
|
)
|
|
|
|
end
|
|
|
|
PaperTrail::Version.reset_column_information
|
2017-04-01 06:28:55 +00:00
|
|
|
end
|
2017-04-01 23:47:32 +00:00
|
|
|
end
|
2017-04-01 06:28:55 +00:00
|
|
|
|
2017-04-01 23:47:32 +00:00
|
|
|
after do
|
2017-09-20 07:53:51 +00:00
|
|
|
if column_datatype_override
|
2017-05-24 05:08:53 +00:00
|
|
|
# In rails < 5, we use truncation, ie. there is no transaction
|
|
|
|
# around the tests, so we can't use a savepoint.
|
|
|
|
if active_record_gem_version >= ::Gem::Version.new("5")
|
|
|
|
ActiveRecord::Base.connection.execute("ROLLBACK TO SAVEPOINT pgtest;")
|
|
|
|
else
|
|
|
|
%w[object object_changes].each do |column|
|
|
|
|
ActiveRecord::Base.connection.execute(
|
|
|
|
"ALTER TABLE versions DROP COLUMN #{column};"
|
|
|
|
)
|
|
|
|
ActiveRecord::Base.connection.execute(
|
|
|
|
"ALTER TABLE versions ADD COLUMN #{column} text;"
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
2017-04-01 23:47:32 +00:00
|
|
|
PaperTrail::Version.reset_column_information
|
2015-04-09 17:48:35 +00:00
|
|
|
end
|
2014-06-26 21:29:09 +00:00
|
|
|
end
|
2017-04-01 06:28:55 +00:00
|
|
|
|
2017-04-01 23:47:32 +00:00
|
|
|
describe "#where_object", versioning: true do
|
|
|
|
before do
|
|
|
|
widget.update_attributes!(name: name, an_integer: int)
|
|
|
|
widget.update_attributes!(name: "foobar", an_integer: 100)
|
|
|
|
widget.update_attributes!(name: FFaker::Name.last_name, an_integer: 15)
|
2017-04-01 06:28:55 +00:00
|
|
|
end
|
|
|
|
|
2017-04-01 23:47:32 +00:00
|
|
|
it "requires its argument to be a Hash" do
|
|
|
|
expect {
|
|
|
|
PaperTrail::Version.where_object(:foo)
|
|
|
|
}.to raise_error(ArgumentError)
|
|
|
|
expect {
|
|
|
|
PaperTrail::Version.where_object([])
|
|
|
|
}.to raise_error(ArgumentError)
|
2017-04-01 06:28:55 +00:00
|
|
|
end
|
|
|
|
|
2017-04-01 23:47:32 +00:00
|
|
|
context "`serializer == YAML`" do
|
|
|
|
specify do
|
|
|
|
expect(PaperTrail.serializer).to be PaperTrail::Serializers::YAML
|
|
|
|
end
|
|
|
|
|
|
|
|
it "locates versions according to their `object` contents" do
|
2017-10-23 17:07:27 +00:00
|
|
|
expect(
|
|
|
|
PaperTrail::Version.where_object(an_integer: int)
|
|
|
|
).to eq([widget.versions[1]])
|
2017-04-01 23:47:32 +00:00
|
|
|
expect(
|
|
|
|
PaperTrail::Version.where_object(name: name)
|
|
|
|
).to eq([widget.versions[1]])
|
|
|
|
expect(
|
|
|
|
PaperTrail::Version.where_object(an_integer: 100)
|
|
|
|
).to eq([widget.versions[2]])
|
|
|
|
end
|
2014-06-26 21:29:09 +00:00
|
|
|
end
|
2017-04-01 06:28:55 +00:00
|
|
|
|
2017-04-01 23:47:32 +00:00
|
|
|
context "JSON serializer" do
|
|
|
|
before(:all) do
|
|
|
|
PaperTrail.serializer = PaperTrail::Serializers::JSON
|
|
|
|
end
|
|
|
|
|
|
|
|
specify do
|
|
|
|
expect(PaperTrail.serializer).to be PaperTrail::Serializers::JSON
|
|
|
|
end
|
|
|
|
|
|
|
|
it "locates versions according to their `object` contents" do
|
2017-10-23 17:07:27 +00:00
|
|
|
expect(
|
|
|
|
PaperTrail::Version.where_object(an_integer: int)
|
|
|
|
).to eq([widget.versions[1]])
|
2017-04-01 23:47:32 +00:00
|
|
|
expect(
|
|
|
|
PaperTrail::Version.where_object(name: name)
|
|
|
|
).to eq([widget.versions[1]])
|
|
|
|
expect(
|
|
|
|
PaperTrail::Version.where_object(an_integer: 100)
|
|
|
|
).to eq([widget.versions[2]])
|
|
|
|
end
|
|
|
|
|
|
|
|
after(:all) do
|
|
|
|
PaperTrail.serializer = PaperTrail::Serializers::YAML
|
|
|
|
end
|
|
|
|
end
|
2017-04-01 06:28:55 +00:00
|
|
|
end
|
|
|
|
|
2017-04-01 23:47:32 +00:00
|
|
|
describe "#where_object_changes", versioning: true do
|
|
|
|
before do
|
|
|
|
widget.update_attributes!(name: name, an_integer: 0)
|
2017-10-23 17:07:27 +00:00
|
|
|
widget.update_attributes!(name: "foobar", an_integer: 100)
|
2017-04-01 23:47:32 +00:00
|
|
|
widget.update_attributes!(name: FFaker::Name.last_name, an_integer: int)
|
2014-06-26 21:29:09 +00:00
|
|
|
end
|
2014-10-21 19:05:16 +00:00
|
|
|
|
2017-04-01 23:47:32 +00:00
|
|
|
it "requires its argument to be a Hash" do
|
|
|
|
expect {
|
|
|
|
PaperTrail::Version.where_object_changes(:foo)
|
|
|
|
}.to raise_error(ArgumentError)
|
|
|
|
expect {
|
|
|
|
PaperTrail::Version.where_object_changes([])
|
|
|
|
}.to raise_error(ArgumentError)
|
2015-04-09 17:48:35 +00:00
|
|
|
end
|
2015-01-07 21:57:45 +00:00
|
|
|
|
2017-04-01 23:47:32 +00:00
|
|
|
context "YAML serializer" do
|
2017-10-23 17:07:27 +00:00
|
|
|
before do
|
|
|
|
unless column_datatype_override
|
|
|
|
allow(ActiveSupport::Deprecation).to receive(:warn)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-04-01 23:47:32 +00:00
|
|
|
it "locates versions according to their `object_changes` contents" do
|
|
|
|
expect(
|
|
|
|
widget.versions.where_object_changes(name: name)
|
|
|
|
).to eq(widget.versions[0..1])
|
|
|
|
expect(
|
2017-10-23 17:07:27 +00:00
|
|
|
widget.versions.where_object_changes(an_integer: 100)
|
2017-04-01 23:47:32 +00:00
|
|
|
).to eq(widget.versions[1..2])
|
|
|
|
expect(
|
|
|
|
widget.versions.where_object_changes(an_integer: int)
|
|
|
|
).to eq([widget.versions.last])
|
2017-10-23 17:07:27 +00:00
|
|
|
unless column_datatype_override
|
|
|
|
expect(ActiveSupport::Deprecation).to have_received(:warn).
|
|
|
|
exactly(3).times.with(/^where_object_changes/)
|
|
|
|
end
|
2017-04-01 23:47:32 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
it "handles queries for multiple attributes" do
|
|
|
|
expect(
|
2017-10-23 17:07:27 +00:00
|
|
|
widget.versions.where_object_changes(an_integer: 100, name: "foobar")
|
2017-04-01 23:47:32 +00:00
|
|
|
).to eq(widget.versions[1..2])
|
2017-10-23 17:07:27 +00:00
|
|
|
unless column_datatype_override
|
|
|
|
expect(ActiveSupport::Deprecation).to have_received(:warn).
|
|
|
|
at_least(:once).with(/^where_object_changes/)
|
|
|
|
end
|
2017-04-01 23:47:32 +00:00
|
|
|
end
|
2015-04-09 18:56:26 +00:00
|
|
|
end
|
2015-01-07 21:57:45 +00:00
|
|
|
|
2017-09-20 07:53:51 +00:00
|
|
|
# Only test the JSON serializer against where_object_changes
|
|
|
|
# for json and jsonb columns, not for text columns, which are
|
|
|
|
# no longer supported.
|
|
|
|
if column_datatype_override
|
|
|
|
context "JSON serializer" do
|
|
|
|
before(:all) { PaperTrail.serializer = PaperTrail::Serializers::JSON }
|
|
|
|
|
|
|
|
it "locates versions according to their `object_changes` contents" do
|
|
|
|
expect(
|
|
|
|
widget.versions.where_object_changes(name: name)
|
|
|
|
).to eq(widget.versions[0..1])
|
|
|
|
expect(
|
2017-10-23 17:07:27 +00:00
|
|
|
widget.versions.where_object_changes(an_integer: 100)
|
2017-09-20 07:53:51 +00:00
|
|
|
).to eq(widget.versions[1..2])
|
|
|
|
expect(
|
|
|
|
widget.versions.where_object_changes(an_integer: int)
|
|
|
|
).to eq([widget.versions.last])
|
2017-07-09 03:26:03 +00:00
|
|
|
end
|
2017-04-01 23:47:32 +00:00
|
|
|
|
2017-09-20 07:53:51 +00:00
|
|
|
it "handles queries for multiple attributes" do
|
|
|
|
expect(
|
2017-10-23 17:07:27 +00:00
|
|
|
widget.versions.where_object_changes(an_integer: 100, name: "foobar")
|
2017-09-20 07:53:51 +00:00
|
|
|
).to eq(widget.versions[1..2])
|
|
|
|
end
|
2017-04-01 23:47:32 +00:00
|
|
|
|
2017-09-20 07:53:51 +00:00
|
|
|
after(:all) { PaperTrail.serializer = PaperTrail::Serializers::YAML }
|
2017-04-01 23:47:32 +00:00
|
|
|
end
|
2015-01-07 21:57:45 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2014-06-26 21:29:09 +00:00
|
|
|
end
|
2013-10-11 14:42:12 +00:00
|
|
|
end
|
|
|
|
end
|