Commit 2ddf015

mo <mo.khan@gmail.com>
2019-01-06 19:57:48
normalize value based on type
1 parent e0b29c0
Changed files (4)
lib/scim/kit/v2/attribute.rb
@@ -6,12 +6,37 @@ module Scim
       # Represents a SCIM Attribute
       class Attribute
         attr_reader :type
-        attr_accessor :value
+        attr_reader :value
 
         def initialize(type:, value: nil)
           @type = type
           @value = value
         end
+
+        def value=(new_value)
+          case type.type
+          when :string
+            @value = new_value.to_s
+          when :boolean
+            raise ArgumentError, new_value unless [true, false].include?(new_value)
+
+            @value = new_value
+          when :decimal
+            @value = new_value.to_f
+          when :integer
+            @value = new_value.to_i
+          when :datetime
+            @value = new_value.is_a?(::String) ?
+              DateTime.parse(new_value) :
+              new_value
+          when :binary
+            @value = Base64.strict_encode64(new_value)
+          end
+
+          if type.canonical_values && !type.canonical_values.empty?
+            raise ArgumentError, new_value unless type.canonical_values.include?(new_value)
+          end
+        end
       end
     end
   end
lib/scim/kit/v2/attribute_type.rb
@@ -29,7 +29,7 @@ module Scim
 
         def initialize(name:, type: :string)
           @name = name
-          @type = type
+          @type = type.to_sym
           @description = ''
           @multi_valued = false
           @required = false
@@ -37,7 +37,7 @@ module Scim
           @mutability = Mutability::READ_WRITE
           @returned = Returned::DEFAULT
           @uniqueness = Uniqueness::NONE
-          raise ArgumentError, :type unless DATATYPES[type.to_sym]
+          raise ArgumentError, :type unless DATATYPES[@type]
         end
 
         def mutability=(value)
spec/fixtures/avatar.png
Binary file
spec/scim/kit/v2/attribute_spec.rb
@@ -3,12 +3,125 @@
 RSpec.describe Scim::Kit::V2::Attribute do
   subject { described_class.new(type: type) }
 
-  context 'with custom string attribute' do
+  context 'with strings' do
     let(:type) { Scim::Kit::V2::AttributeType.new(name: 'userName', type: :string) }
-    let(:user_name) { FFaker::Internet.user_name }
 
-    before { subject.value = user_name }
+    context 'valid' do
+      let(:user_name) { FFaker::Internet.user_name }
 
-    specify { expect(subject.value).to eql(user_name) }
+      before { subject.value = user_name }
+
+      specify { expect(subject.value).to eql(user_name) }
+    end
+
+    context 'given integer' do
+      let(:number) { rand(100) }
+
+      before { subject.value = number }
+
+      specify { expect(subject.value).to eql(number.to_s) }
+    end
+
+    context 'given datetime' do
+      let(:datetime) { DateTime.now }
+
+      before { subject.value = datetime }
+
+      specify { expect(subject.value).to eql(datetime.to_s) }
+    end
+
+    context 'when canonical values are provided' do
+      before { type.canonical_values = %w[batman robin] }
+
+      context 'when not matching a canonical value' do
+        specify { expect { subject.value = 'spider man' }.to raise_error(ArgumentError) }
+      end
+
+      context 'when canonical value is given' do
+        before { subject.value = 'batman' }
+
+        specify { expect(subject.value).to eql('batman') }
+      end
+    end
+  end
+
+  context 'with boolean' do
+    let(:type) { Scim::Kit::V2::AttributeType.new(name: 'hungry', type: :boolean) }
+
+    context 'when true' do
+      before { subject.value = true }
+
+      specify { expect(subject.value).to be(true) }
+    end
+
+    context 'when false' do
+      before { subject.value = false }
+
+      specify { expect(subject.value).to be(false) }
+    end
+
+    context 'when string' do
+      specify { expect { subject.value = 'hello' }.to raise_error(ArgumentError) }
+    end
+  end
+
+  context 'with decimal' do
+    let(:type) { Scim::Kit::V2::AttributeType.new(name: 'measurement', type: :decimal) }
+
+    context 'when given float' do
+      before { subject.value = Math::PI }
+
+      specify { expect(subject.value).to eql(Math::PI) }
+    end
+
+    context 'when given an integer' do
+      before { subject.value = 42 }
+
+      specify { expect(subject.value).to eql(42.to_f) }
+    end
+  end
+
+  context 'with integer' do
+    let(:type) { Scim::Kit::V2::AttributeType.new(name: 'age', type: :integer) }
+
+    context 'when given integer' do
+      before { subject.value = 34 }
+
+      specify { expect(subject.value).to be(34) }
+    end
+
+    context 'when given float' do
+      before { subject.value = Math::PI }
+
+      specify { expect(subject.value).to eql(Math::PI.to_i) }
+    end
+  end
+
+  context 'with datetime' do
+    let(:type) { Scim::Kit::V2::AttributeType.new(name: 'birthdate', type: :datetime) }
+    let(:datetime) { DateTime.new(2019, 0o1, 0o6, 12, 35, 0o0) }
+
+    context 'when given a date time' do
+      before { subject.value = datetime }
+
+      specify { expect(subject.value).to eql(datetime) }
+    end
+
+    context 'when given a string' do
+      before { subject.value = datetime.to_s }
+
+      specify { expect(subject.value).to eql(datetime) }
+    end
+  end
+
+  context 'with binary' do
+    let(:type) { Scim::Kit::V2::AttributeType.new(name: 'photo', type: :binary) }
+    let(:photo) { IO.read('./spec/fixtures/avatar.png', mode: 'rb') }
+
+    context 'when given a .png' do
+      before { subject.value = photo }
+
+      specify { expect(subject.value).to eql(Base64.strict_encode64(photo)) }
+    end
   end
 end