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,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe ActiveValidation::Decorators::ConsistentRegistry do
4
+ subject { described_class.new(klass, registry) }
5
+
6
+ let(:klass) { define_const("VerifierDouble") { def initialize(_arg); end } }
7
+ let(:bar) { define_const "Bar" }
8
+
9
+ let(:registry) { ActiveValidation::Registry.new("Great thing") }
10
+ let(:inconsistent_error_class) { ActiveValidation::Errors::InconsistentRegistryError }
11
+
12
+ let(:registered_object) { instance_double("registered object") }
13
+
14
+ context "#initialize" do
15
+ context "raise" do
16
+ it "raises an error if klass not provided" do
17
+ expect { described_class.new(nil, registry) }.to raise_error NameError
18
+ end
19
+
20
+ it "raises an error if klass argument is not a class" do
21
+ expect { described_class.new(:not_a_class, registry) }.to raise_error NameError
22
+ end
23
+ end
24
+
25
+ it "works if klass provided as Class" do
26
+ expect(subject).to be_a ActiveValidation::Registry
27
+ end
28
+
29
+ it "works if klass provided as String" do
30
+ expect(described_class.new(klass.name, registry)).to be_a ActiveValidation::Registry
31
+ end
32
+ end
33
+
34
+ it "have :klass reader" do
35
+ decorator = described_class.new(klass, "name")
36
+
37
+ expect(decorator.klass).to eq(klass)
38
+ end
39
+
40
+ context "#first_or_build" do
41
+ context "existed record" do
42
+ before { subject.register(bar.name, klass.new(bar)) }
43
+
44
+ it "find" do
45
+ expect(subject.find_or_build(bar.name)).to be_a klass
46
+ end
47
+
48
+ it "yield given block" do
49
+ expect { |b| subject.find_or_build(bar.name, &b) }.to yield_control
50
+ end
51
+ end
52
+
53
+ context "new record" do
54
+ it "if not found build a new record" do
55
+ expect(subject.find_or_build(klass.name)).to be_a klass
56
+ end
57
+
58
+ it "is not registered by registry by default" do
59
+ subject.find_or_build(klass.name)
60
+ expect(registry).not_to be_registered(klass.name)
61
+ end
62
+
63
+ it "yield given block on new record" do
64
+ klass_instance = klass.new bar
65
+ allow(klass).to receive(:new) do |record, &blk|
66
+ expect(record).to eq bar
67
+ expect(blk.call).to eq :passed
68
+ klass_instance
69
+ end
70
+
71
+ subject.find_or_build(bar, &-> { :passed })
72
+ end
73
+ end
74
+ end
75
+
76
+ context "#find_or_add" do
77
+ context "with existed record" do
78
+ before { subject.register(bar.name, klass.new(bar)) }
79
+
80
+ it "finds" do
81
+ expect(subject.find_or_add(bar.name)).to be_a klass
82
+ end
83
+
84
+ it "do not try to add record to registry" do
85
+ expect(registry).to include subject.find_or_add(bar.name)
86
+ expect(registry.count).to eq 1
87
+ end
88
+ end
89
+
90
+ context "with new record" do
91
+ it "finds" do
92
+ expect(subject.find_or_add(bar.name)).to be_a klass
93
+ end
94
+
95
+ it "add record to registry" do
96
+ expect(registry).to include subject.find_or_add(bar.name)
97
+ expect(registry.count).to eq 1
98
+ end
99
+ end
100
+ end
101
+
102
+ context "register" do
103
+ context "raise" do
104
+ it "with inconsistent value" do
105
+ value = define_const "Wrong"
106
+ expect { subject.register(bar.name, value) }.to raise_error ActiveValidation::Errors::InconsistentRegistryError
107
+ expect { subject.find(bar.name) }.to raise_error KeyError
108
+ end
109
+ end
110
+
111
+ it "registers the entry" do
112
+ value = klass.new(bar)
113
+ expect(subject.register(bar.name, value)).to eq value
114
+ expect(subject.find(bar.name)).to eq value
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe ActiveValidation::Decorators::DisallowsDuplicatesRegistry do
4
+ subject { described_class.new(registry) }
5
+
6
+ let(:registry) { ActiveValidation::Registry.new("Great thing") }
7
+ let(:error_class) { ActiveValidation::Errors::DuplicateRegistryEntryError }
8
+
9
+ let(:registered_object) { instance_double("registered object") }
10
+
11
+ it "finds a registered object" do
12
+ subject.register(:object_name, registered_object)
13
+ expect { subject.register(:object_name, registered_object) }.to raise_error error_class
14
+ end
15
+
16
+ it "find a registered class" do
17
+ define_const "Foo"
18
+ subject.register(:object_name, Foo)
19
+ expect { subject.register(:object_name, Foo) }.to raise_error error_class
20
+ end
21
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe ActiveValidation::Formatters::ManifestNameFormatter do
4
+ it "formats the name" do
5
+ expect(described_class.call("Test")).to eq "Manifest for Test"
6
+ end
7
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe ActiveValidation::Formatters::ValidationContextFormatter do
4
+ context "no options" do
5
+ context "no name" do
6
+ let(:manifest) do
7
+ instance_double ActiveValidation::Internal::Models::Manifest, id: 23, options: {}, name: nil
8
+ end
9
+
10
+ it { expect(described_class.call(manifest)).to eq "active_validation_id23" }
11
+ end
12
+
13
+ context "with name" do
14
+ let(:manifest) do
15
+ instance_double ActiveValidation::Internal::Models::Manifest, id: 23, options: {}, name: :my_name
16
+ end
17
+
18
+ it { expect(described_class.call(manifest)).to eq "active_validation_id23_my_name" }
19
+ end
20
+ end
21
+
22
+ context "with `on` option" do
23
+ context "no name" do
24
+ let(:manifest) do
25
+ instance_double ActiveValidation::Internal::Models::Manifest, id: 23, options: { on: :new }, name: nil
26
+ end
27
+
28
+ it { expect(described_class.call(manifest)).to eq "active_validation_id23_on_new" }
29
+ end
30
+
31
+ context "with name" do
32
+ let(:manifest) do
33
+ instance_double ActiveValidation::Internal::Models::Manifest, id: 23, options: { on: :new }, name: :my_name
34
+ end
35
+
36
+ it { expect(described_class.call(manifest)).to eq "active_validation_id23_on_new_my_name" }
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe ActiveValidation::Internal::Models::Check do
4
+ subject { described_class.new method_name: "validates", argument: "name" }
5
+
6
+ let(:registry) { ActiveValidation.config.method_name_values_registry }
7
+
8
+ %i[method_name argument options created_at].each do |m|
9
+ it { is_expected.to have_attr_reader m }
10
+ end
11
+
12
+ it "converts the method name to value object" do
13
+ expect(subject.method_name).to be_a ActiveValidation::Values::MethodName
14
+ end
15
+
16
+ it "add method name to the registry" do
17
+ registry.clear
18
+ subject
19
+ expect(registry.count).to eq 1
20
+ end
21
+
22
+ context "#to_hash" do
23
+ it "converts to Hash with out coercion" do
24
+ expect { Hash(subject) }.not_to raise_error
25
+ end
26
+ end
27
+
28
+ context "#as_json" do
29
+ %i[method_name argument options].each do |attr|
30
+ it("has '#{attr}' attribute") { expect(subject.as_json[attr]).to be_truthy }
31
+ end
32
+
33
+ it "works correctly with out 'only' option" do
34
+ expect(subject.as_json).to eq subject.to_hash
35
+ end
36
+
37
+ it "produce right output with 'only' option argument" do
38
+ expect(subject.as_json(only: [:argument])).to eq(argument: "name")
39
+ end
40
+
41
+ it "produce right output with 'only' option created_at" do
42
+ check = described_class.new method_name: "validates", argument: "name", created_at: "10AM"
43
+ expect(check.as_json(only: [:created_at])).to eq(created_at: "10AM")
44
+ end
45
+ end
46
+
47
+ context "#normalized_argument" do
48
+ %i[validate validates].each do |m|
49
+ it "for #{m}" do
50
+ check = described_class.new method_name: m, argument: "name"
51
+ expect(check.normalized_argument).to eq :name
52
+ end
53
+ end
54
+
55
+ it "for validates_with" do
56
+ define_const "MyValidator", superclass: ActiveModel::Validator
57
+ check = described_class.new method_name: :validates_with, argument: "MyValidator"
58
+ expect(check.normalized_argument).to eq MyValidator
59
+ end
60
+ end
61
+
62
+ it "is equal" do
63
+ check1 = described_class.new method_name: "validates", argument: "name", options: { name: "foo" }
64
+ check2 = described_class.new method_name: "validates", argument: "name", options: { name: "foo" }
65
+ expect(check1).to eq check2
66
+ end
67
+ end
@@ -0,0 +1,177 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe ActiveValidation::Internal::Models::Manifest::Installer do
4
+ subject { described_class.new base_class: Bar, context: context }
5
+
6
+ let(:check_validate) { build :internal_check_validate }
7
+ let(:check_validates) { build :internal_check_validates }
8
+ let(:check_validates_with) { build :internal_check_validates_with }
9
+
10
+ let(:callbacks) { Bar._validate_callbacks.send(:chain) }
11
+ let(:context) { "active_validation_1" }
12
+
13
+ before do
14
+ define_const("Bar") { include ActiveModel::Validations }
15
+ end
16
+
17
+ %i[base_class installed_callbacks checks context].each do |m|
18
+ it { is_expected.to have_attr_reader m }
19
+ end
20
+
21
+ context "#install" do
22
+ context "with 3 validations" do
23
+ before do
24
+ subject.checks << check_validate << check_validates << check_validates_with
25
+ subject.install
26
+ end
27
+
28
+ it "setup validations to base_klass" do
29
+ expect(Bar.validators).to include a_kind_of ActiveModel::Validations::PresenceValidator
30
+ expect(Bar.validators).to include a_kind_of MyValidator
31
+ expect(Bar.validators.size).to eq 2
32
+ end
33
+
34
+ it "setups default factories callbacks to default model" do
35
+ expect(callbacks.size).to eq 3
36
+ end
37
+
38
+ it "setups installed callbacks to default model" do
39
+ expect(subject.installed_callbacks.size).to eq 3
40
+ end
41
+ end
42
+
43
+ context "validations should be in the right context" do
44
+ let(:callback) { callbacks.last }
45
+ let(:bar) { Bar.new }
46
+
47
+ shared_examples "check with context" do
48
+ it "does not execute with out the context" do
49
+ bar.valid?
50
+ expect(validator).not_to have_received(:validate)
51
+ end
52
+
53
+ it "executes with the context" do
54
+ bar.valid?(subject.context)
55
+ expect(validator).to have_received(:validate)
56
+ end
57
+ end
58
+
59
+ context "validates_with" do
60
+ let(:validator) { instance_double MyValidator }
61
+
62
+ before do
63
+ subject.checks << check_validates_with
64
+ allow(MyValidator).to receive(:new).and_return(validator)
65
+ allow(validator).to receive(:validate)
66
+ subject.install
67
+ end
68
+
69
+ include_examples "check with context"
70
+ end
71
+
72
+ context "validates" do
73
+ let(:validator) { instance_double ActiveModel::Validations::PresenceValidator }
74
+
75
+ before do
76
+ subject.checks << check_validates
77
+ allow(ActiveModel::Validations::PresenceValidator).to receive(:new).and_return(validator)
78
+ allow(validator).to receive(:validate)
79
+ subject.install
80
+ end
81
+
82
+ include_examples "check with context"
83
+ end
84
+
85
+ context "validate" do
86
+ before do
87
+ define_const("Bar") do
88
+ include ActiveModel::Validations
89
+ def my_method; end
90
+ end
91
+
92
+ subject.checks << check_validate
93
+ allow(Bar).to receive(:new).and_return(bar)
94
+ allow(bar).to receive(:my_method)
95
+ subject.install
96
+ end
97
+
98
+ it "does not execute with out the context" do
99
+ bar.valid?
100
+ expect(bar).not_to have_received(:my_method)
101
+ end
102
+
103
+ it "executes with the context" do
104
+ bar.valid?(subject.context)
105
+ expect(bar).to have_received(:my_method)
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ context "#uninstall" do
112
+ let(:check_validate2) { build :internal_check_validate }
113
+ let(:check_validates2) { build :internal_check_validates }
114
+ let(:check_validates_with2) { build :internal_check_validates_with, argument: "MyValidator2" }
115
+
116
+ before do
117
+ define_const("Bar") { include ActiveModel::Validations }
118
+ subject.checks << check_validate << check_validates << check_validates_with
119
+ subject.install
120
+ end
121
+
122
+ context "should correctly remove all checks" do
123
+ before { subject.uninstall }
124
+
125
+ it("does not have any callback chain") { expect(callbacks).to be_empty }
126
+
127
+ it("does not contain any validators") { expect(Bar.validators).to be_empty }
128
+ end
129
+
130
+ context "does not affect checks from another installer on another class" do
131
+ let(:installer2) { described_class.new context: context, base_class: Baz }
132
+
133
+ before do
134
+ define_const("Baz") { include ActiveModel::Validations }
135
+ installer2.checks << check_validate2 << check_validates2 << check_validates_with2
136
+ installer2.install
137
+ subject.uninstall
138
+ end
139
+
140
+ it("does not have any callback chain") { expect(callbacks).to be_empty }
141
+
142
+ it("does not affect installer2 checks") { expect(installer2.callbacks_chain.count).to eq 3 }
143
+ end
144
+
145
+ context "does not other affect native checks on the base class" do
146
+ before do
147
+ subject.base_class.public_send(*check_validate2.to_validation_arguments)
148
+ subject.base_class.public_send(*check_validates_with2.to_validation_arguments)
149
+ subject.uninstall
150
+ end
151
+
152
+ it("has 2 callbacks in the chain") { expect(callbacks.count).to eq 2 }
153
+
154
+ it("have correct validator") { expect(Bar.validators).to all(be_a_kind_of(MyValidator2)) }
155
+ it("has only one validator") { expect(Bar.validators.size).to eq 1 }
156
+ end
157
+
158
+ context "with nested class" do
159
+ let(:child) { described_class.new base_class: BarChild, context: context }
160
+ let(:child_callbacks) { BarChild._validate_callbacks.send(:chain) }
161
+
162
+ before do
163
+ define_const "BarChild", superclass: Bar
164
+ end
165
+
166
+ it("has 3 callbacks in the chain") { expect(child_callbacks.count).to eq 3 }
167
+ it("has 2 validators") { expect(BarChild.validators.size).to eq 2 }
168
+
169
+ context "after uninstall on the parent" do
170
+ before { subject.uninstall }
171
+
172
+ it("has 0 callbacks in the chain") { expect(child_callbacks.count).to eq 0 }
173
+ it("has 0 validators") { expect(BarChild.validators.size).to eq 0 }
174
+ end
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe ActiveValidation::Internal::Models::Manifest do
4
+ subject { described_class.new version: 1, base_klass: "Foo" }
5
+
6
+ before { define_const "Foo" }
7
+
8
+ let(:check_validate) { build :internal_check_validate }
9
+ let(:check_validates) { build :internal_check_validates }
10
+ let(:check_validates_with) { build :internal_check_validates_with }
11
+
12
+ %i[version base_klass created_at checks options other id name].each do |m|
13
+ it { is_expected.to have_attr_reader m }
14
+ end
15
+
16
+ context "#class_name" do
17
+ it "converts the method name to value object" do
18
+ expect(subject.base_class).to eq Foo
19
+ end
20
+ end
21
+
22
+ context "equality check" do
23
+ it "if id is equal" do
24
+ common = { version: 1, base_klass: "Foo", id: 42 }
25
+ manifest1 = described_class.new common
26
+ manifest2 = described_class.new common
27
+ expect(manifest1).to eq manifest2
28
+ end
29
+
30
+ it "if attributes is equal, if even id are not" do
31
+ common = { version: 1, base_klass: "Foo", checks: [], options: { bar: :baz } }
32
+ manifest1 = described_class.new common.merge id: 1
33
+ manifest2 = described_class.new common.merge id: 2
34
+ expect(manifest1).to eq manifest2
35
+ end
36
+ end
37
+
38
+ context "#to_hash" do
39
+ it "converts to Hash with out coercion" do
40
+ expect { Hash(subject) }.not_to raise_error
41
+ end
42
+ end
43
+
44
+ context "#as_json" do
45
+ %i[version base_klass checks name id].each do |attr|
46
+ it("has '#{attr}' attribute") { expect(subject.as_json).to have_key attr }
47
+ end
48
+
49
+ it "works correctly with out 'only' option" do
50
+ expect(subject.as_json).to eq subject.to_hash
51
+ end
52
+
53
+ it "produce right output with 'only' option base_klass" do
54
+ expect(subject.as_json(only: [:base_klass])).to eq(base_klass: "Foo")
55
+ end
56
+
57
+ context "with checks" do
58
+ subject { described_class.new version: 1, base_klass: "Foo", checks: [check1, check2] }
59
+
60
+ let(:check1) { build :internal_check_validates, argument: "check1" }
61
+ let(:check2) { build :internal_check_validate, argument: "check2" }
62
+
63
+ it "with out options" do
64
+ hash = { version: 1,
65
+ base_klass: "Foo",
66
+ checks: [{ method_name: "validates", argument: "check1", options: { "presence" => true } },
67
+ { method_name: "validate", argument: "check2", options: {} }],
68
+ name: nil,
69
+ id: nil }
70
+ expect(subject.as_json).to eq hash
71
+ end
72
+
73
+ it "with options for manifest" do
74
+ hash = { version: 1,
75
+ checks: [{ method_name: "validates", argument: "check1", options: { "presence" => true } },
76
+ { method_name: "validate", argument: "check2", options: {} }] }
77
+ expect(subject.as_json(only: %i[checks version])).to eq hash
78
+ end
79
+
80
+ it "with options for checks" do
81
+ hash = { version: 1,
82
+ base_klass: "Foo",
83
+ checks: [{ argument: "check1" },
84
+ { argument: "check2" }],
85
+ name: nil,
86
+ id: nil }
87
+ expect(subject.as_json(checks: { only: [:argument] })).to eq hash
88
+ end
89
+
90
+ it "with renamed checks" do
91
+ hash = { version: 1,
92
+ base_klass: "Foo",
93
+ checks_attributes: [{ method_name: "validates", argument: "check1", options: { "presence" => true } },
94
+ { method_name: "validate", argument: "check2", options: {} }],
95
+ name: nil,
96
+ id: nil }
97
+ expect(subject.as_json(checks: { as: :checks_attributes })).to eq hash
98
+ end
99
+ end
100
+ end
101
+
102
+ context "installation" do
103
+ before do
104
+ allow(ActiveValidation::Internal::Models::Manifest::Installer).to receive(:new).and_return(installer)
105
+ end
106
+
107
+ let(:installer) do
108
+ instance_double ActiveValidation::Internal::Models::Manifest::Installer, uninstall: false, install: true
109
+ end
110
+
111
+ context "install" do
112
+ before { subject.install }
113
+
114
+ it("installs once installed") do
115
+ subject.install
116
+ expect(installer).to have_received(:install).once
117
+ end
118
+
119
+ it { expect(subject).to be_installed }
120
+ end
121
+
122
+ context "uninstall" do
123
+ before do
124
+ subject.install
125
+ subject.uninstall
126
+ end
127
+
128
+ it("uninstalls once when installed") do
129
+ subject.uninstall
130
+ expect(installer).to have_received(:uninstall).once
131
+ end
132
+
133
+ it { expect(subject).not_to be_installed }
134
+ end
135
+ end
136
+ end