# spec/sleeping_king_studios/shinkansen/errors/base_error_spec.rb

require 'rails_helper'

require 'sleeping_king_studios/shinkansen/errors'

RSpec.describe SleepingKingStudios::Shinkansen::Errors::BaseError do
  let(:problem)    { 'An error has occurred.' }
  let(:details)    { 'A failure has occured at the chair-to-keyboard interface.' }
  let(:resolution) { 'Have you tried turning it off and on again?' }

  describe '::new' do
    it { expect(described_class).to be_constructible.with(1).argument.and_keywords(:details, :resolution) }

    it 'should set the message components' do
      instance = described_class.new problem,
        :details    => details,
        :resolution => resolution

      expect(instance.details).to be == details
      expect(instance.resolution).to be == resolution
    end # it
  end # describe

  let(:instance) { described_class.new problem }

  describe '#details' do
    let(:expected) do
      "Problem:\n  #{problem}\n"\
      "Details:\n  #{details}"
    end # let

    include_examples 'should have property', :details, nil

    it 'should update the message' do
      expect { instance.details = details }.
        to change(instance, :message).
        to be == expected
    end # it
  end # describe

  describe '#message' do
    include_examples 'should have reader', :message, ->() { be == problem }

    context 'with details and a resolution' do
      let(:expected) do
        "Problem:\n  #{problem}\n"\
        "Details:\n  #{details}\n"\
        "Resolution:\n  #{resolution}"
      end # let

      before(:example) do
        instance.details    = details
        instance.resolution = resolution
      end # before

      it { expect(instance.message).to be == expected }
    end # context
  end # describe

  describe '#problem' do
    let(:updated) { 'Something has gone wrong.' }

    include_examples 'should have property', :problem, ->() { be == problem }

    it 'should update the message' do
      expect { instance.problem = updated }.
        to change(instance, :message).
        to be == updated
    end # it
  end # describe

  describe '#resolution' do
    let(:resolution) { 'Have you tried turning it off and on again?' }
    let(:expected) do
      "Problem:\n  #{problem}\n"\
      "Resolution:\n  #{resolution}"
    end # let

    include_examples 'should have property', :resolution, nil

    it 'should update the message' do
      expect { instance.resolution = resolution }.
        to change(instance, :message).
        to be == expected
    end # it
  end # describe

  describe '#to_s' do
    include_examples 'should have reader', :to_s, ->() { be == problem }

    context 'with details and a resolution' do
      let(:expected) do
        "Problem:\n  #{problem}\n"\
        "Details:\n  #{details}\n"\
        "Resolution:\n  #{resolution}"
      end # let

      before(:example) do
        instance.details    = details
        instance.resolution = resolution
      end # before

      it { expect(instance.to_s).to be == expected }
    end # context
  end # describe
end # describe
