activevalidation 0.1.0 → 1.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.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +32 -9
  3. data/.overcommit.yml +93 -0
  4. data/.rspec +1 -1
  5. data/.rubocop.yml +80 -0
  6. data/.rubocop_todo.yml +7 -0
  7. data/.travis.yml +42 -2
  8. data/.yardops +9 -0
  9. data/Appraisals +27 -0
  10. data/Gemfile +24 -1
  11. data/MIT-LICENSE +20 -0
  12. data/README.md +142 -20
  13. data/Rakefile +21 -3
  14. data/activevalidation.gemspec +35 -25
  15. data/bin/console +4 -7
  16. data/gemfiles/am_5.0.gemfile +17 -0
  17. data/gemfiles/am_5.0.gemfile.lock +159 -0
  18. data/gemfiles/am_5.1.gemfile +17 -0
  19. data/gemfiles/am_5.1.gemfile.lock +159 -0
  20. data/gemfiles/am_5.2.gemfile +17 -0
  21. data/gemfiles/am_5.2.gemfile.lock +159 -0
  22. data/gemfiles/am_6.0.gemfile +18 -0
  23. data/gemfiles/am_6.0.gemfile.lock +158 -0
  24. data/lib/active_validation.rb +27 -0
  25. data/lib/active_validation/base_adapter.rb +103 -0
  26. data/lib/active_validation/configuration.rb +52 -0
  27. data/lib/active_validation/decorator.rb +27 -0
  28. data/lib/active_validation/decorators/consistent_registry.rb +36 -0
  29. data/lib/active_validation/decorators/disallows_duplicates_registry.rb +17 -0
  30. data/lib/active_validation/errors.rb +28 -0
  31. data/lib/active_validation/ext/add_active_validation_context_check.rb +21 -0
  32. data/lib/active_validation/formatters/manifest_name_formatter.rb +13 -0
  33. data/lib/active_validation/formatters/validation_context_formatter.rb +28 -0
  34. data/lib/active_validation/frameworks/rspec.rb +10 -0
  35. data/lib/active_validation/frameworks/rspec/helpers.rb +15 -0
  36. data/lib/active_validation/internal/models/check.rb +51 -0
  37. data/lib/active_validation/internal/models/concerns/to_internal.rb +27 -0
  38. data/lib/active_validation/internal/models/manifest.rb +122 -0
  39. data/lib/active_validation/internal/models/manifest/installer.rb +86 -0
  40. data/lib/active_validation/internal/observers/manifest.rb +114 -0
  41. data/lib/active_validation/model_extension_base.rb +33 -0
  42. data/lib/active_validation/orm_plugins/active_record_plugin/adapter.rb +59 -0
  43. data/lib/active_validation/orm_plugins/active_record_plugin/internals/active_validation/internal_model_extensions/check.rb +11 -0
  44. data/lib/active_validation/orm_plugins/active_record_plugin/model_extension/active_validation/active_record_model_extension.rb +25 -0
  45. data/lib/active_validation/orm_plugins/active_record_plugin/models/active_validation/check.rb +31 -0
  46. data/lib/active_validation/orm_plugins/active_record_plugin/models/active_validation/check/concerns/method_must_be_allowed.rb +38 -0
  47. data/lib/active_validation/orm_plugins/active_record_plugin/models/active_validation/check/validate_method.rb +9 -0
  48. data/lib/active_validation/orm_plugins/active_record_plugin/models/active_validation/check/validates_method.rb +9 -0
  49. data/lib/active_validation/orm_plugins/active_record_plugin/models/active_validation/check/validates_with_method.rb +19 -0
  50. data/lib/active_validation/orm_plugins/active_record_plugin/models/active_validation/concerns/protect_from_mutable_instance_methods.rb +31 -0
  51. data/lib/active_validation/orm_plugins/active_record_plugin/models/active_validation/manifest.rb +21 -0
  52. data/lib/active_validation/orm_plugins/active_record_plugin/types/active_validation/type/version.rb +17 -0
  53. data/lib/active_validation/registry.rb +55 -0
  54. data/lib/active_validation/values/base.rb +39 -0
  55. data/lib/active_validation/values/method_name.rb +22 -0
  56. data/lib/active_validation/values/version.rb +17 -0
  57. data/lib/active_validation/verifier.rb +150 -0
  58. data/lib/active_validation/version.rb +5 -0
  59. data/spec/active_validation/base_adapter_spec.rb +23 -0
  60. data/spec/active_validation/configuration_spec.rb +52 -0
  61. data/spec/active_validation/decorators/consistent_registry_spec.rb +117 -0
  62. data/spec/active_validation/decorators/disallows_duplicates_registry_spec.rb +21 -0
  63. data/spec/active_validation/formatters/manifest_name_formatter_spec.rb +7 -0
  64. data/spec/active_validation/formatters/validation_context_formatter_spec.rb +39 -0
  65. data/spec/active_validation/internal/models/check_spec.rb +67 -0
  66. data/spec/active_validation/internal/models/manifest/installer_spec.rb +177 -0
  67. data/spec/active_validation/internal/models/manifest_spec.rb +136 -0
  68. data/spec/active_validation/internal/observers/manifest_spec.rb +201 -0
  69. data/spec/active_validation/model_extension_base_spec.rb +71 -0
  70. data/spec/active_validation/orm_plugins/active_record_plugin/adapter_spec.rb +31 -0
  71. data/spec/active_validation/orm_plugins/active_record_plugin/adapter_spec_orm_specific_spec.rb +84 -0
  72. data/spec/active_validation/orm_plugins/active_record_plugin/models/active_validation/check/validate_method_spec.rb +26 -0
  73. data/spec/active_validation/orm_plugins/active_record_plugin/models/active_validation/check/validates_method_spec.rb +26 -0
  74. data/spec/active_validation/orm_plugins/active_record_plugin/models/active_validation/check/validates_with_method_spec.rb +34 -0
  75. data/spec/active_validation/orm_plugins/active_record_plugin/models/active_validation/check_spec.rb +48 -0
  76. data/spec/active_validation/orm_plugins/active_record_plugin/models/active_validation/manifest_spec.rb +61 -0
  77. data/spec/active_validation/orm_plugins/active_record_plugin/readme_spec.rb +89 -0
  78. data/spec/active_validation/registry_spec.rb +76 -0
  79. data/spec/active_validation/values/base_spec.rb +61 -0
  80. data/spec/active_validation/values/method_name_spec.rb +16 -0
  81. data/spec/active_validation/values/version_spec.rb +36 -0
  82. data/spec/active_validation/verifier_spec.rb +214 -0
  83. data/spec/active_validation_spec.rb +19 -0
  84. data/spec/factories/internal/internal_check.rb +43 -0
  85. data/spec/features/active_record/child_record.feature +32 -0
  86. data/spec/features/active_record/new_record.feature +22 -0
  87. data/spec/features/no_orm/install.feature +19 -0
  88. data/spec/features/no_orm/validate.feature +27 -0
  89. data/spec/features/no_orm/validate_with_multiple_manifests.feature +29 -0
  90. data/spec/features/no_orm/validate_with_multiple_versions.feature +42 -0
  91. data/spec/features/placeholders/be_matcher.rb +7 -0
  92. data/spec/features/placeholders/klass.rb +5 -0
  93. data/spec/features/placeholders/version.rb +11 -0
  94. data/spec/features/placeholders/whether_to.rb +11 -0
  95. data/spec/features/step_definitions/active_record_steps.rb +7 -0
  96. data/spec/features/step_definitions/steps.rb +85 -0
  97. data/spec/orm/active_record/db_adapters/database.mysql.yml +12 -0
  98. data/spec/orm/active_record/db_adapters/database.postgres.yml +11 -0
  99. data/spec/orm/active_record/db_adapters/database.sqlite.yml +8 -0
  100. data/spec/orm/active_record/factories/check/check_validate.rb +8 -0
  101. data/spec/orm/active_record/factories/check/check_validates.rb +8 -0
  102. data/spec/orm/active_record/factories/check/check_validates_with.rb +19 -0
  103. data/spec/orm/active_record/factories/manifest.rb +29 -0
  104. data/spec/orm/active_record/prepare_db.rb +89 -0
  105. data/spec/orm/active_record/setup.rb +11 -0
  106. data/spec/orm/mongoid/setup.rb +15 -0
  107. data/spec/spec_helper.rb +38 -0
  108. data/spec/support/database_cleaner.rb +16 -0
  109. data/spec/support/deferred_garbage_collection.rb +31 -0
  110. data/spec/support/define_constant_macros.rb +17 -0
  111. data/spec/support/factory_bot.rb +12 -0
  112. data/spec/support/helpers.rb +3 -0
  113. data/spec/support/helpers/only_with_active_record.rb +15 -0
  114. data/spec/support/matchers/delegate.rb +50 -0
  115. data/spec/support/matchers/have_attr.rb +58 -0
  116. data/spec/support/mongoid.yml +6 -0
  117. data/spec/support/shared_examples/check_attributes.rb +9 -0
  118. data/spec/support/shared_examples/verifiers_registry.rb +10 -0
  119. data/spec/support/simplecov.rb +11 -0
  120. data/spec/turnip_helper.rb +4 -0
  121. metadata +304 -20
  122. data/lib/activevalidation.rb +0 -6
  123. data/lib/activevalidation/version.rb +0 -3
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe ActiveValidation::Check, type: :active_record do
4
+ it "return empty collection" do
5
+ expect(described_class.all).to be_empty
6
+ end
7
+
8
+ %i[update update_attribute update_attributes].each do |method|
9
+ it "raises on #{method}" do
10
+ expect { subject.send(method) }.to raise_error ActiveValidation::Errors::ImmutableError
11
+ end
12
+ end
13
+
14
+ context "#method_name" do
15
+ it { expect { subject.method_name }.to raise_error NotImplementedError }
16
+ end
17
+
18
+ context "#method_name=" do
19
+ it("Set correct type") do
20
+ subject.method_name = "foo"
21
+ expect(subject.type).to eq "FooMethod"
22
+ end
23
+ end
24
+
25
+ context "#to_internal_check" do
26
+ %i[check_validate check_validates check_validates_with].each do |type|
27
+ context(type) do
28
+ let(:subject) { build type }
29
+
30
+ it "produces right class" do
31
+ expect(subject.to_internal_check).to be_a ActiveValidation::Internal::Models::Check
32
+ end
33
+
34
+ context "has value" do
35
+ %w[method_name argument].each do |key|
36
+ it key.to_s do
37
+ expect(subject.to_internal_check.public_send(key)).to eq subject.public_send(key)
38
+ end
39
+
40
+ it "options" do
41
+ expect(subject.to_internal_check.options).to eq subject.options.deep_symbolize_keys
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe ActiveValidation::Manifest, type: :active_record do
4
+ %i[update update_attribute update_attributes].each do |method|
5
+ it "raises on #{method}" do
6
+ expect { subject.send(method) }.to raise_error ActiveValidation::Errors::ImmutableError
7
+ end
8
+ end
9
+
10
+ context "with existed model" do
11
+ before do
12
+ define_const("Foo", superclass: ActiveRecord::Base)
13
+ define_const("FooValidator", superclass: ActiveModel::Validator)
14
+ end
15
+
16
+ it "accepts nested attributes for checks" do
17
+ described_class.create name: "foo's manifest", version: 1, base_klass: "Foo", checks_attributes: [
18
+ attributes_for(:check_validates),
19
+ attributes_for(:check_validate),
20
+ attributes_for(:check_validates_with)
21
+ ]
22
+
23
+ expect(described_class.count).to eq 1
24
+ expect(ActiveValidation::Check.count).to eq 3
25
+ end
26
+ end
27
+
28
+ context "factories traits" do
29
+ %i[validate validates validates_with].each do |trait|
30
+ it "accept Factory trait #{trait} and build corresponding check" do
31
+ expect(build(:manifest, trait).checks.size).to eq 1
32
+ end
33
+ end
34
+ end
35
+
36
+ context "#to_internal_manifest" do
37
+ let(:subject) { build :manifest, :validate }
38
+
39
+ it "produces right class" do
40
+ expect(subject.to_internal_manifest).to be_a ActiveValidation::Internal::Models::Manifest
41
+ end
42
+
43
+ context "has value" do
44
+ %w[name version base_klass].each do |key|
45
+ it key.to_s do
46
+ expect(subject.to_internal_manifest.public_send(key)).to eq subject.public_send(key)
47
+ end
48
+ end
49
+
50
+ context "checks" do
51
+ subject { build(:manifest, :validate, :validates).to_internal_manifest.checks }
52
+
53
+ let!(:wrong) { build(:manifest, :validate) }
54
+
55
+ it { is_expected.to be_a Array }
56
+ it { is_expected.to all a_kind_of ActiveValidation::Internal::Models::Check }
57
+ it { is_expected.to have_attributes length: 2 }
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ # At this moment there is only Active record Plugin, so it is
4
+ # used in the Readme files for examples.
5
+
6
+ # rubocop:disable RSpec/DescribeClass
7
+ # rubocop:disable RSpec/ExampleLength
8
+ describe "Readme" do
9
+ let(:manifest_with_checks) do
10
+ {
11
+ base_klass: "Foo", # Name of the Model Class
12
+ version: 1, # optional, by default use locked or latest version
13
+ name: "awesome-foo", # optional, some name for easier managing
14
+
15
+ # the syntax is the same with ActiveModel. For :validates_with and :validate `options` field is optional
16
+ checks_attributes: [
17
+ { method_name: "validates", argument: "my_method", options: { presence: true } },
18
+ { method_name: "validates_with", argument: "MyValidator" },
19
+ { method_name: "validate", argument: "my_validation_method" }
20
+ ]
21
+ }
22
+ end
23
+
24
+ let(:empty_manifest) do
25
+ {
26
+ base_klass: "Foo", # Name of the Model Class
27
+ checks_attributes: []
28
+ }
29
+ end
30
+
31
+ before do
32
+ define_const("Foo", superclass: ActiveRecord::Base) do
33
+ active_validation
34
+
35
+ def my_method; end
36
+
37
+ def my_validation_method
38
+ errors.add(:base, "we'd called validation method")
39
+ end
40
+ end
41
+
42
+ define_const("MyValidator", superclass: ActiveModel::Validator) do
43
+ def validate(*); end
44
+ end
45
+
46
+ define_const "Foo::Validations::V1"
47
+ end
48
+
49
+ it "manifest manipulations" do
50
+ # This is how you can add the new manifest
51
+
52
+ Foo.active_validation.add_manifest(manifest_with_checks)
53
+
54
+ f = Foo.new
55
+
56
+ expect(f).not_to be_valid
57
+ expect(f.errors.messages).to have_key(:my_method)
58
+ expect(f.errors.messages).to have_key(:base)
59
+
60
+ # new manifest will be used for new records, while existed records
61
+ # continue using one of the previous versions
62
+ # the same result will be with `Foo.active_validation.add_manifest`
63
+ Foo.active_validation.add_manifest(empty_manifest)
64
+
65
+ expect(f).to be_valid
66
+
67
+ # get all manifests for current version
68
+ manifests = Foo.active_validation.find_manifests
69
+
70
+ expect(manifests.size).to eq 2
71
+
72
+ # we can specify version, if we want to
73
+ Foo.active_validation.find_manifests version: 42
74
+
75
+ # Get the latest manifest
76
+ manifest = Foo.active_validation.find_manifest
77
+
78
+ # we can con edit existed manifests, but we can easily
79
+ # create the new one based on the existed
80
+ Foo.active_validation.add_manifest(manifest.as_json.tap do |m|
81
+ m[:name] = "Something"
82
+ m[:id] = nil
83
+ end)
84
+
85
+ expect(Foo.active_validation.find_manifest.name).to eq "Something"
86
+ end
87
+ end
88
+ # rubocop:enable RSpec/DescribeClass
89
+ # rubocop:enable RSpec/ExampleLength
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe ActiveValidation::Registry do
4
+ subject { described_class.new("Great thing") }
5
+
6
+ let(:registered_object) { instance_double("registered object") }
7
+ let(:second_registered_object) { instance_double("second registered object") }
8
+
9
+ it { is_expected.to be_kind_of(Enumerable) }
10
+
11
+ it "finds a registered object" do
12
+ subject.register(:object_name, registered_object)
13
+ expect(subject.find(:object_name)).to eq registered_object
14
+ end
15
+
16
+ it "finds a registered object with square brackets" do
17
+ subject.register(:object_name, registered_object)
18
+ expect(subject[:object_name]).to eq registered_object
19
+ end
20
+
21
+ it "raises when an object cannot be found" do
22
+ expect { subject.find(:object_name) }
23
+ .to raise_error(KeyError, "Great thing not registered: \"object_name\"")
24
+ end
25
+
26
+ it "adds and returns the object registered" do
27
+ expect(subject.register(:object_name, registered_object)).to eq registered_object
28
+ end
29
+
30
+ it "knows that an object is registered by symbol" do
31
+ subject.register(:object_name, registered_object)
32
+ expect(subject).to be_registered(:object_name)
33
+ end
34
+
35
+ it "knows that an object is registered by string" do
36
+ subject.register(:object_name, registered_object)
37
+ expect(subject).to be_registered("object_name")
38
+ end
39
+
40
+ it "knows when an object is not registered" do
41
+ expect(subject).not_to be_registered("bogus")
42
+ end
43
+
44
+ it "iterates registered objects" do
45
+ subject.register(:first_object, registered_object)
46
+ subject.register(:second_object, second_registered_object)
47
+ expect(subject.to_a).to eq [registered_object, second_registered_object]
48
+ end
49
+
50
+ it "does not include duplicate objects with registered under different names" do
51
+ subject.register(:first_object, registered_object)
52
+ subject.register(:second_object, registered_object)
53
+ expect(subject.to_a).to eq [registered_object]
54
+ end
55
+
56
+ it "clears registered objects" do
57
+ subject.register(:object_name, registered_object)
58
+ subject.clear
59
+ expect(subject.count).to be_zero
60
+ end
61
+
62
+ it "delete selected object" do
63
+ subject.register(:first_object, registered_object)
64
+ subject.register(:second_object, second_registered_object)
65
+ subject.delete :first_object
66
+ expect(subject.to_a).to eq [second_registered_object]
67
+ end
68
+
69
+ it "store object key as symbol" do
70
+ subject.register("first object", registered_object)
71
+ subject.register(42, registered_object)
72
+ expect(subject).to be_registered(:"first object")
73
+ expect(subject).to be_registered(:"42")
74
+ expect(subject).not_to be_registered(:not_exist)
75
+ end
76
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe ActiveValidation::Values::Base do
4
+ subject { described_class.new("42") }
5
+
6
+ context "Set" do
7
+ it("value") { expect(described_class.new(1).value).to eq 1 }
8
+ end
9
+
10
+ context "Get" do
11
+ it("value") { expect(subject.value).to eq "42" }
12
+ end
13
+
14
+ context "raise" do
15
+ [nil, true, false].each do |el|
16
+ it("from #{el}") { expect { described_class.new(el).value }.to raise_error ArgumentError }
17
+ end
18
+ end
19
+
20
+ context "<=>" do
21
+ subject { %i[1 5 9 3 7].map { |n| described_class.new n } }
22
+
23
+ it("sort") { expect(subject.sort.map(&:to_s)).to eq %w[1 3 5 7 9] }
24
+ end
25
+
26
+ context "==" do
27
+ context "comarison instance vs value" do
28
+ let(:version1) { described_class.new 1 }
29
+ let(:another_version1) { described_class.new 1 }
30
+
31
+ it("is equal") { expect(version1).to eq another_version1 }
32
+ it("is not equal") { expect(version1).not_to eq subject }
33
+ end
34
+
35
+ context "comarison instance vs instance" do
36
+ let(:struct) { Struct.new(:foo) }
37
+ let(:version1) { described_class.new struct.new(foo: 42) }
38
+ let(:another_version1) { described_class.new struct.new(foo: 42) }
39
+
40
+ it("is equal") { expect(version1).to eq another_version1 }
41
+ it("is not equal") { expect(version1).not_to eq subject }
42
+ end
43
+ end
44
+
45
+ context "to_s" do
46
+ it("convert integer to string") { expect(described_class.new(1).to_s).to eq "1" }
47
+ it("convert symbol to string") { expect(described_class.new(:foo).to_s).to eq "foo" }
48
+ end
49
+
50
+ context "to_sym" do
51
+ it("convert string to symbol") { expect(described_class.new(:foo).to_sym).to eq :foo }
52
+ end
53
+
54
+ context "to_json" do
55
+ it("return only value") { expect(described_class.new(42).to_json).to eq "42" }
56
+ end
57
+
58
+ context "as_json" do
59
+ it("return only value") { expect(described_class.new(42).as_json).to eq 42 }
60
+ end
61
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe ActiveValidation::Values::MethodName do
4
+ context "::new" do
5
+ %w[validates validates_with validate].each do |name|
6
+ it("generate #{name}") { expect(described_class.new(name).value).to eq name }
7
+ it("is a String #{name}") { expect(described_class.new(name).value).to be_a String }
8
+ end
9
+
10
+ context "raise" do
11
+ let(:error_class) { ActiveValidation::Errors::UnsupportedMethodError }
12
+
13
+ it("method is not allowed") { expect { described_class.new("bad").value }.to raise_error error_class }
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe ActiveValidation::Values::Version do
4
+ context "::new" do
5
+ context 'with "V" prefix' do
6
+ it("from symbol") { expect(described_class.new(:V42).value).to eq 42 }
7
+ it("from string") { expect(described_class.new("V42").value).to eq 42 }
8
+ end
9
+
10
+ context 'with out "V" prefix' do
11
+ it("from symbol") { expect(described_class.new(:'42').value).to eq 42 }
12
+ it("from string") { expect(described_class.new("42").value).to eq 42 }
13
+ end
14
+
15
+ context "raise" do
16
+ [nil, true, false, "Foo1", "V55A"].each do |el|
17
+ it("from #{el}") { expect { described_class.new(el).value }.to raise_error ArgumentError }
18
+ end
19
+ end
20
+
21
+ it("set the value from integer") { expect(described_class.new(42).value).to eq 42 }
22
+
23
+ context "to_i" do
24
+ it("string to integer") { expect(described_class.new("42").to_i).to eq 42 }
25
+ it("symbol to integer") { expect(described_class.new("V42").to_i).to eq 42 }
26
+ end
27
+
28
+ context "to_json" do
29
+ it("return only value") { expect(described_class.new(42).to_json).to eq "42" }
30
+ end
31
+
32
+ context "as_json" do
33
+ it("return only value") { expect(described_class.new(42).as_json).to eq 42 }
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,214 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe ActiveValidation::Verifier do
4
+ subject { described_class.find_or_build "Foo" }
5
+
6
+ let(:model) { define_const("Foo") { attr_reader :manifest } }
7
+
8
+ context "class methods" do
9
+ subject { described_class }
10
+
11
+ it "return the global registry for verifier" do
12
+ expect(subject.registry).to eq ActiveValidation.config.verifiers_registry
13
+ end
14
+
15
+ it { is_expected.to delegate(:find_or_build).to(:registry) }
16
+ end
17
+
18
+ %i[failed_attempt_retry_time
19
+ enabled
20
+ observer
21
+ validations_module_name
22
+ base_klass
23
+ orm_adapter
24
+ manifest_name_formatter
25
+ manifest].each { |m| it { is_expected.to have_attr_reader m } }
26
+
27
+ it { is_expected.to delegate(:install).to(:observer) }
28
+
29
+ context "with fake registry" do
30
+ subject { described_class.find_or_build "Bar" }
31
+
32
+ let!(:bar) do
33
+ define_const "Bar" do
34
+ include ActiveValidation::ModelExtensionBase
35
+ active_validation
36
+ end
37
+ end
38
+
39
+ include_examples "verifiers registry"
40
+
41
+ context "orm methods" do
42
+ context "#add_manifest" do
43
+ before do
44
+ allow(subject.orm_adapter).to receive(:add_manifest)
45
+ define_const "Bar::Validations::V17"
46
+ end
47
+
48
+ it "calculate name and set default klass & version" do
49
+ subject.add_manifest
50
+ defaults = { base_klass: bar.to_s,
51
+ version: ActiveValidation::Values::Version.new(17),
52
+ name: "Manifest for Bar" }
53
+ expect(subject.orm_adapter).to have_received(:add_manifest).with(defaults)
54
+ end
55
+ end
56
+
57
+ context "#find_manifest" do
58
+ before { allow(subject.orm_adapter).to receive(:find_manifest) }
59
+
60
+ it "set defaults" do
61
+ subject.find_manifest
62
+ defaults = { base_klass: bar.to_s }
63
+ expect(subject.orm_adapter).to have_received(:find_manifest).with(defaults)
64
+ end
65
+ end
66
+
67
+ context "#find_manifests" do
68
+ before { allow(subject.orm_adapter).to receive(:find_manifests) }
69
+
70
+ it "set defaults" do
71
+ subject.find_manifests
72
+ defaults = { base_klass: bar.to_s }
73
+ expect(subject.orm_adapter).to have_received(:find_manifests).with(defaults)
74
+ end
75
+ end
76
+ end
77
+
78
+ context "#versions" do
79
+ before do
80
+ define_consts "Bar::Validations::V1",
81
+ "Bar::Validations::V2",
82
+ "Bar::Validations::V23",
83
+ "Bar::Validations::V42"
84
+ end
85
+
86
+ it "returns correct versions in asc order" do
87
+ expect(subject.versions.map(&:to_i)).to eq [1, 2, 23, 42]
88
+ end
89
+
90
+ it "returns only value version type" do
91
+ expect(subject.versions).to all be_an ActiveValidation::Values::Version
92
+ end
93
+ end
94
+
95
+ context "#version" do
96
+ before do
97
+ define_consts "Bar::Validations::V300",
98
+ "Bar::Validations::V301",
99
+ "Bar::Validations::V302"
100
+ end
101
+
102
+ it "use latest version by default" do
103
+ expect(subject.version).to eq ActiveValidation::Values::Version.new(302)
104
+ end
105
+
106
+ it "set/gets version" do
107
+ subject.version = :V300
108
+ expect(subject.version).to eq ActiveValidation::Values::Version.new(300)
109
+ end
110
+ end
111
+
112
+ context "#base_class" do
113
+ it "return Class if base_klass as String given" do
114
+ expect(described_class.new(model.name).base_class).to eq model
115
+ end
116
+
117
+ it "return Class if base_klass as Class given" do
118
+ expect(described_class.new(model).base_class).to eq model
119
+ end
120
+ end
121
+
122
+ context "#descendants_with_active_validation" do
123
+ subject { described_class.find_or_build(foo_descendant3).descendants_with_active_validation }
124
+
125
+ let!(:should_not_be_in_the_list) { define_const "ShouldNotBeInTheList" }
126
+ let!(:baz) do
127
+ define_const("Baz", superclass: should_not_be_in_the_list) do
128
+ include ActiveValidation::ModelExtensionBase
129
+ active_validation
130
+ end
131
+ end
132
+
133
+ let(:foo) do
134
+ define_const("Foo", superclass: should_not_be_in_the_list) do
135
+ include ActiveValidation::ModelExtensionBase
136
+ active_validation
137
+ attr_reader :manifest
138
+ end
139
+ end
140
+
141
+ let(:foo_descendant1) { define_const("FooDescendant1", superclass: foo) { attr_reader :manifest } }
142
+ let(:foo_descendant2) { define_const("FooDescendant2", superclass: foo_descendant1) { attr_reader :manifest } }
143
+ let(:foo_descendant3) { define_const("FooDescendant3", superclass: foo_descendant2) }
144
+
145
+ it "returns only Foo based constants" do
146
+ expect(subject).to match [foo_descendant2, foo_descendant1, foo]
147
+ end
148
+
149
+ it "returns empty array for foo" do
150
+ expect(described_class.find_or_build(foo).descendants_with_active_validation).to be_empty
151
+ end
152
+ end
153
+
154
+ context "#current_manifest" do
155
+ let(:manifest) { ActiveValidation::Internal::Models::Manifest.new version: 1, base_klass: "Bar" }
156
+
157
+ it "return manifest, if it was set" do
158
+ subject.manifest = manifest
159
+ expect(subject.current_manifest).to eq manifest
160
+ end
161
+
162
+ it "call #find_manifests if manifest is not set" do
163
+ allow(subject).to receive(:find_manifests).and_return([]) # rubocop:disable RSpec/SubjectStub
164
+ define_consts "Bar::Validations::V11"
165
+ expect(subject.current_manifest).to be_nil
166
+ expect(subject).to have_received(:find_manifests)
167
+ end
168
+ end
169
+
170
+ context "#initialize" do
171
+ it "yield given block" do
172
+ expect { |b| described_class.find_or_build(bar.name, &b) }.to yield_control
173
+ end
174
+
175
+ it "register self in global registry" do
176
+ subject
177
+ expect(registry).to be_registered(bar.to_s)
178
+ end
179
+
180
+ it "invoke default config" do
181
+ allow(ActiveValidation.config.verifier_defaults).to receive(:call)
182
+ expect(ActiveValidation.config.verifier_defaults).to have_received(:call).with(subject)
183
+ end
184
+ end
185
+ end
186
+
187
+ context "#enabled" do
188
+ context "true" do
189
+ subject { described_class.find_or_build("Foo") { |c| c.enabled = true }.enabled? }
190
+
191
+ it { is_expected.to be true }
192
+ end
193
+
194
+ context "false" do
195
+ subject { described_class.find_or_build("Foo") { |c| c.enabled = false }.enabled? }
196
+
197
+ it { is_expected.to be false }
198
+ end
199
+ end
200
+
201
+ context "#install!" do
202
+ let!(:bar) { define_const("Bar", superclass: model) { attr_reader :manifest } }
203
+
204
+ before do
205
+ model.include ActiveValidation::ModelExtensionBase
206
+ allow(Foo.active_validation).to receive(:install)
207
+ allow(Bar.active_validation).to receive(:install)
208
+ described_class.find_or_build("Bar").install!
209
+ end
210
+
211
+ it("installs on Foo") { expect(Foo.active_validation).to have_received(:install) }
212
+ it("installs on Bar") { expect(Bar.active_validation).to have_received(:install) }
213
+ end
214
+ end