Commit acd8364

mokha <mokha@cisco.com>
2019-01-09 18:56:31
move validations to attribute class
1 parent bbcc51b
lib/scim/kit/v2/attribute.rb
@@ -5,11 +5,15 @@ module Scim
     module V2
       # Represents a SCIM Attribute
       class Attribute
+        include ::ActiveModel::Validations
         include Attributable
         include Templatable
         attr_reader :type
         attr_reader :_value
 
+        validate :presence_of_value, if: proc { |x| x.type.required }
+        validate :inclusion_of_value, if: proc { |x| x.type.canonical_values }
+
         def initialize(type:, value: nil)
           @type = type
           @_value = value
@@ -18,12 +22,20 @@ module Scim
 
         def _value=(new_value)
           @_value = type.coerce(new_value)
+        end
+
+        private
+
+        def presence_of_value
+          return unless type.required && _value.blank?
+
+          errors.add(type.name, "can't be blank")
+        end
+
+        def inclusion_of_value
+          return unless type.canonical_values && !type.canonical_values.include?(_value)
 
-          if type.canonical_values &&
-             !type.canonical_values.empty? &&
-             !type.canonical_values.include?(new_value)
-            raise ArgumentError, new_value
-          end
+          errors.add(type.name, 'is not included in the list')
         end
       end
     end
lib/scim/kit/v2/resource.rb
@@ -1,5 +1,4 @@
 # frozen_string_literal: true
-require 'active_model'
 
 module Scim
   module Kit
@@ -36,9 +35,8 @@ module Scim
         end
 
         def validate_attribute(type)
-          attribute = read_attribute(type.name)
-
-          errors.add(type.name, "is required") if type.required && attribute.nil?
+          attribute = attribute_for(type.name)
+          errors.copy!(attribute.errors) unless attribute.valid?
         end
       end
     end
lib/scim/kit.rb
@@ -1,8 +1,9 @@
 # frozen_string_literal: true
 
+require 'active_model'
+require 'active_support/core_ext/hash/indifferent_access'
 require 'tilt'
 require 'tilt/jbuilder'
-require 'active_support/core_ext/hash/indifferent_access'
 
 require 'scim/kit/dynamic_attributes'
 require 'scim/kit/templatable'
spec/scim/kit/v2/attribute_spec.rb
@@ -41,9 +41,14 @@ RSpec.describe Scim::Kit::V2::Attribute do
     end
 
     context 'when not matching a canonical value' do
-      before { type.canonical_values = %w[batman robin] }
+      before do
+        type.canonical_values = %w[batman robin]
+        subject._value = 'spider man'
+        subject.valid?
+      end
 
-      specify { expect { subject._value = 'spider man' }.to raise_error(ArgumentError) }
+      specify { expect(subject).not_to be_valid }
+      specify { expect(subject.errors[:user_name]).to be_present }
     end
 
     context 'when canonical value is given' do
spec/scim/kit/v2/resource_spec.rb
@@ -117,21 +117,21 @@ RSpec.describe Scim::Kit::V2::Resource do
     specify { expect(subject.as_json[extension_id][:department]).to eql('voltron') }
   end
 
-  describe "#valid?" do
-    context "when invalid" do
+  describe '#valid?' do
+    context 'when invalid' do
       before { subject.valid? }
 
       specify { expect(subject).not_to be_valid }
       specify { expect(subject.errors[:id]).to be_present }
     end
 
-    context "when valid" do
+    context 'when valid' do
       before { subject.id = SecureRandom.uuid }
 
       specify { expect(subject).to be_valid }
     end
 
-    context "when a required attribute is blank" do
+    context 'when a required simple attribute is blank' do
       before do
         schema.add_attribute(name: 'userName') do |x|
           x.required = true
@@ -143,5 +143,19 @@ RSpec.describe Scim::Kit::V2::Resource do
       specify { expect(subject).not_to be_valid }
       specify { expect(subject.errors[:user_name]).to be_present }
     end
+
+    context 'when not matching a canonical value' do
+      before do
+        schema.add_attribute(name: 'hero') do |x|
+          x.canonical_values = %w[batman robin]
+        end
+        subject.id = SecureRandom.uuid
+        subject.hero = 'spiderman'
+        subject.valid?
+      end
+
+      specify { expect(subject).not_to be_valid }
+      specify { expect(subject.errors[:hero]).to be_present }
+    end
   end
 end