# frozen_string_literal: true

RSpec.describe Dry::Types::Nominal, :maybe do
  describe 'with opt-in maybe types' do
    context 'with strict string' do
      let(:string) { Dry::Types['maybe.strict.string'] }

      it_behaves_like 'Dry::Types::Nominal without primitive' do
        let(:type) { string }
      end

      it 'accepts nil' do
        expect(string[nil]).to be_none
      end

      it 'accepts a string' do
        expect(string['something'].value!).to eql('something')
      end
    end

    context 'with coercible string' do
      let(:string) { Dry::Types['maybe.coercible.string'] }

      it_behaves_like 'Dry::Types::Nominal without primitive' do
        let(:type) { string }
      end

      it 'accepts nil' do
        expect(string[nil]).to be_none
      end

      it 'accepts a string' do
        expect(string[:something].value!).to eql('something')
      end
    end
  end

  describe 'defining coercible Maybe String' do
    let(:maybe_string) { Dry::Types['coercible.string'].maybe }

    it_behaves_like 'Dry::Types::Nominal without primitive' do
      let(:type) { maybe_string }
    end

    it 'accepts nil' do
      expect(maybe_string[nil]).to be_none
    end

    it 'accepts an object coercible to a string' do
      expect(maybe_string[123].value!).to eql('123')
    end
  end

  describe 'defining Maybe String' do
    let(:maybe_string) { Dry::Types['strict.string'].maybe }

    it_behaves_like 'Dry::Types::Nominal without primitive' do
      let(:type) { maybe_string }
    end

    it 'accepts nil and returns None instance' do
      value = maybe_string[nil]

      expect(value).to be_none
      expect(value.fmap(&:downcase).fmap(&:upcase)).to be_none
    end

    it 'accepts a string and returns Some instance' do
      value = maybe_string['SomeThing']

      expect(value).to be_some
      expect(value.fmap(&:downcase).fmap(&:upcase).value!).to eql('SOMETHING')
    end
  end
end
