lib/ree_lib/packages/ree_object/spec/ree_object/functions/to_obj_spec.rb



# frozen_string_literal = true

RSpec.describe :to_obj do
  link :to_obj, from: :ree_object

  let(:klass) {
    Class.new do
      attr_reader :integer, :settings

      def initialize
        @name = 'John'
        @work = 'Company'
        @array = [1, 'string', 3, { 'name' => 'Johny', 'last_name': 'Doe'}]
        @settings = Object.new
        @settings.instance_exec do
          @name = 'Steven'
          @last_name = 'Doe'
          @pass = 'pass'
        end
      end 
    end
  }

  context "blank, string, array, boolean" do
    it {
      expect(to_obj(nil)).to eq(nil)
      expect(to_obj("")).to eq("")
      expect(to_obj("   ")).to eq("   ")
      expect(to_obj([])).to eq([])
      expect(to_obj(Hash.new)).to be_a(Object)
      expect(to_obj(Object.new).instance_variables).to eq([])
      expect(to_obj(false)).to eq(false)
      expect(to_obj(true)).to eq(true)
      expect(to_obj("test")).to eq("test")
      expect(to_obj([1, 2, 3])).to eq([1, 2, 3])
    }
  end

  context "Struct" do
    it {
      obj = to_obj(Struct.new(:id, :name).new(1, 'John'))
      
      expect(obj.name).to eq('John')
      expect(obj.id).to eq(1)
    }
  end

  context "OpenStruct" do
    it {
      require 'ostruct'
      obj = to_obj(OpenStruct.new(id: 1, name: 'John'))

      expect(obj.name).to eq('John')
      expect(obj.id).to eq(1)
    }
  end

  context "hash and object" do
    it {
      obj = to_obj(
        {
          name: 'John',
          settings: {
            pass: 'pass',
            last_name: 'Doe'
          }
        }
      )
      obj2 = to_obj(klass.new)

      expect(obj.name).to eq("John")
      expect(obj.settings.class).to be_a(Object)
      expect(obj2.name).to eq("John")
      expect(obj2.settings.class).to be_a(Object)
    }    
  end

  context "custom object" do
    it {
      klass = Struct.new(:id, :object)
      object = Object.new

      object.instance_exec do
        @list = [1, 'string', klass.new(1, Object.new)]
      end

      obj = klass.new(1, object)

      result = to_obj(obj)
      
      expect(result.id).to eq(1)
      expect(result.object.list[0]).to eq(1)
      expect(result.object.list[1]).to eq('string')
      expect(result.object.list[2]).to be_a(Object)
    }
  end

  context "array" do
    it {
      obj = to_obj([1, 2, name: 'John'])
      obj2 = to_obj([1, 2, [3, name: 'John']])

      expect(obj[2]).to be_a(Object)
      expect(obj[2].name).to eq('John')
      expect(obj2[2][1]).to be_a(Object)
      expect(obj2[2][1].name).to eq('John')
    }
  end

  context "exclude option" do
    it {
      obj = to_obj(klass.new, exclude: [:name])

      expect(obj.respond_to?(:name)).to be false
      expect(obj.respond_to?(:work)).to be true
    } 

    it {
      obj = to_obj(klass.new, exclude: [:name, {settings: [:pass]}])

      expect(obj.respond_to?(:name)).to be false
      expect(obj.respond_to?(:work)).to be true
      expect(obj.settings.respond_to?(:pass)).to be false
    }    
  end

  context "global exclude option" do
    it {
      obj = to_obj(klass.new, global_exclude: [:name])

      expect(obj.respond_to?(:name)).to be false
      expect(obj.settings.pass).to eq('pass')
      expect(obj.settings.respond_to?(:name)).to be false
      expect(obj.array[3].last_name).to eq('Doe')
      expect(obj.array[3].respond_to?(:name)).to be false
    }    
  end

  context "include option" do
    it {
      obj = to_obj(klass.new, include: [:name, :work])

      expect(obj.name).to eq('John')
      expect(obj.work).to eq('Company')
      expect(obj.respond_to?(:array)).to be false
      expect(obj.respond_to?(:settings)).to be false
    }
  end

  context "same include and exclude hash" do
    it {
      obj = to_obj(klass.new, include: [:settings], exclude:[{settings: [:pass]}])

      expect(obj.settings).to be_a(Object)
      expect(obj.settings.name).to eq('Steven')
      expect(obj.settings.respond_to?(:pass)).to be false
      expect(obj.respond_to?(:work)).to be false
    }
  end

  context "same include and exclude key" do
    it {
      expect {
        to_obj(klass.new, include: [:name], exclude:[:name])
      }.to raise_error(ArgumentError, /Exclude and include have the same values: /)
    }

    it {
      expect {
        to_obj(klass.new, include: [:name, :work], global_exclude:[:name])
      }.to raise_error(ArgumentError, /Exclude and include have the same values: /)
    }
  end
end