# frozen_string_literal: true

describe Nanoc::Core::DependencyProps do
  let(:props) { described_class.new }

  let(:props_all) do
    described_class.new(raw_content: true, attributes: true, compiled_content: true, path: true)
  end

  describe '#inspect' do
    subject { props.inspect }

    context 'nothing active' do
      it { is_expected.to eql('Props(____)') }
    end

    context 'attributes active' do
      let(:props) { described_class.new(attributes: true) }

      it { is_expected.to eql('Props(_a__)') }
    end

    context 'attributes and compiled_content active' do
      let(:props) { described_class.new(attributes: true, compiled_content: true) }

      it { is_expected.to eql('Props(_ac_)') }
    end

    context 'compiled_content active' do
      let(:props) { described_class.new(compiled_content: true) }

      it { is_expected.to eql('Props(__c_)') }
    end
  end

  describe '#to_s' do
    subject { props.to_s }

    context 'nothing active' do
      it { is_expected.to eql('____') }
    end

    context 'attributes active' do
      let(:props) { described_class.new(attributes: true) }

      it { is_expected.to eql('_a__') }
    end

    context 'attributes and compiled_content active' do
      let(:props) { described_class.new(attributes: true, compiled_content: true) }

      it { is_expected.to eql('_ac_') }
    end

    context 'compiled_content active' do
      let(:props) { described_class.new(compiled_content: true) }

      it { is_expected.to eql('__c_') }
    end
  end

  describe '#raw_content?' do
    subject { props.raw_content? }

    context 'nothing active' do
      it { is_expected.to be(false) }
    end

    context 'raw_content active' do
      let(:props) { described_class.new(raw_content: true) }

      it { is_expected.to be(true) }
    end

    context 'raw_content and compiled_content active' do
      let(:props) { described_class.new(raw_content: true, compiled_content: true) }

      it { is_expected.to be(true) }
    end

    context 'compiled_content active' do
      let(:props) { described_class.new(compiled_content: true) }

      it { is_expected.to be(false) }
    end

    context 'all active' do
      let(:props) do
        described_class.new(raw_content: true, attributes: true, compiled_content: true, path: true)
      end

      it { is_expected.to be(true) }
    end

    context 'raw_content is empty list' do
      let(:props) { described_class.new(raw_content: []) }

      it { is_expected.to be(false) }
    end

    context 'raw_content is non-empty list' do
      let(:props) { described_class.new(raw_content: ['/asdf.*']) }

      it { is_expected.to be(true) }
    end
  end

  describe '#attributes?' do
    subject { props.attributes? }

    context 'nothing active' do
      it { is_expected.to be(false) }
    end

    context 'attributes active' do
      let(:props) { described_class.new(attributes: true) }

      it { is_expected.to be(true) }
    end

    context 'attributes and compiled_content active' do
      let(:props) { described_class.new(attributes: true, compiled_content: true) }

      it { is_expected.to be(true) }
    end

    context 'compiled_content active' do
      let(:props) { described_class.new(compiled_content: true) }

      it { is_expected.to be(false) }
    end

    context 'all active' do
      let(:props) do
        described_class.new(raw_content: true, attributes: true, compiled_content: true, path: true)
      end

      it { is_expected.to be(true) }
    end

    context 'attributes is empty list' do
      let(:props) { described_class.new(attributes: []) }

      it { is_expected.to be(false) }
    end

    context 'attributes is non-empty list' do
      let(:props) { described_class.new(attributes: [:donkey]) }

      it { is_expected.to be(true) }
    end
  end

  describe '#compiled_content?' do
    # …
  end

  describe '#path?' do
    # …
  end

  describe '#merge' do
    subject { props.merge(other_props).active }

    context 'nothing + nothing' do
      let(:props) { described_class.new }
      let(:other_props) { described_class.new }

      it { is_expected.to be(0x00) }
    end

    context 'nothing + some' do
      let(:props) { described_class.new }
      let(:other_props) { described_class.new(raw_content: true) }

      it { is_expected.to be(0x01) }
    end

    context 'nothing + all' do
      let(:props) { described_class.new }
      let(:other_props) { props_all }

      it { is_expected.to be(0x01 | 0x02 | 0x04 | 0x08) }
    end

    context 'some + nothing' do
      let(:props) { described_class.new(compiled_content: true) }
      let(:other_props) { described_class.new }

      it { is_expected.to be(0x04) }
    end

    context 'some + others' do
      let(:props) { described_class.new(compiled_content: true) }
      let(:other_props) { described_class.new(raw_content: true) }

      it { is_expected.to be(0x01 | 0x04) }
    end

    context 'some + all' do
      let(:props) { described_class.new(compiled_content: true) }
      let(:other_props) { props_all }

      it { is_expected.to be(0x01 | 0x02 | 0x04 | 0x08) }
    end

    context 'all + nothing' do
      let(:props) { props_all }
      let(:other_props) { described_class.new }

      it { is_expected.to be(0x01 | 0x02 | 0x04 | 0x08) }
    end

    context 'all + all' do
      let(:props) { props_all }
      let(:other_props) { props_all }

      it { is_expected.to be(0x01 | 0x02 | 0x04 | 0x08) }
    end
  end

  describe '#merge_attributes' do
    subject { props.merge(other_props).attributes }

    let(:props_attrs_true) do
      described_class.new(attributes: true)
    end

    let(:props_attrs_false) do
      described_class.new(attributes: false)
    end

    let(:props_attrs_list_a) do
      described_class.new(attributes: [:donkey, :giraffe])
    end

    let(:props_attrs_list_b) do
      described_class.new(attributes: [:giraffe, :zebra])
    end

    context 'false + false' do
      let(:props) { props_attrs_false }
      let(:other_props) { props_attrs_false }

      it { is_expected.to be(false) }
    end

    context 'false + true' do
      let(:props) { props_attrs_false }
      let(:other_props) { props_attrs_true }

      it { is_expected.to be(true) }
    end

    context 'false + list' do
      let(:props) { props_attrs_false }
      let(:other_props) { props_attrs_list_a }

      it { is_expected.to be_a(Array) }
      it { is_expected.to contain_exactly(:donkey, :giraffe) }
    end

    context 'true + false' do
      let(:props) { props_attrs_true }
      let(:other_props) { props_attrs_false }

      it { is_expected.to be(true) }
    end

    context 'true + true' do
      let(:props) { props_attrs_true }
      let(:other_props) { props_attrs_true }

      it { is_expected.to be(true) }
    end

    context 'true + list' do
      let(:props) { props_attrs_true }
      let(:other_props) { props_attrs_list_a }

      it { is_expected.to be(true) }
    end

    context 'list + false' do
      let(:props) { props_attrs_list_a }
      let(:other_props) { props_attrs_false }

      it { is_expected.to be_a(Array) }
      it { is_expected.to contain_exactly(:donkey, :giraffe) }
    end

    context 'list + true' do
      let(:props) { props_attrs_list_a }
      let(:other_props) { props_attrs_true }

      it { is_expected.to be(true) }
    end

    context 'list + list' do
      let(:props) { props_attrs_list_a }
      let(:other_props) { props_attrs_list_b }

      it { is_expected.to be_a(Set) }
      it { is_expected.to contain_exactly(:donkey, :giraffe, :zebra) }
    end
  end

  describe '#merge_raw_content' do
    subject { props.merge(other_props).raw_content }

    let(:props_raw_content_true) do
      described_class.new(raw_content: true)
    end

    let(:props_raw_content_false) do
      described_class.new(raw_content: false)
    end

    let(:props_raw_content_list_a) do
      described_class.new(raw_content: ['donkey', 'giraffe'])
    end

    let(:props_raw_content_list_b) do
      described_class.new(raw_content: ['giraffe', 'zebra'])
    end

    context 'false + false' do
      let(:props) { props_raw_content_false }
      let(:other_props) { props_raw_content_false }

      it { is_expected.to be(false) }
    end

    context 'false + true' do
      let(:props) { props_raw_content_false }
      let(:other_props) { props_raw_content_true }

      it { is_expected.to be(true) }
    end

    context 'false + list' do
      let(:props) { props_raw_content_false }
      let(:other_props) { props_raw_content_list_a }

      it { is_expected.to be_a(Array) }
      it { is_expected.to contain_exactly('donkey', 'giraffe') }
    end

    context 'true + false' do
      let(:props) { props_raw_content_true }
      let(:other_props) { props_raw_content_false }

      it { is_expected.to be(true) }
    end

    context 'true + true' do
      let(:props) { props_raw_content_true }
      let(:other_props) { props_raw_content_true }

      it { is_expected.to be(true) }
    end

    context 'true + list' do
      let(:props) { props_raw_content_true }
      let(:other_props) { props_raw_content_list_a }

      it { is_expected.to be(true) }
    end

    context 'list + false' do
      let(:props) { props_raw_content_list_a }
      let(:other_props) { props_raw_content_false }

      it { is_expected.to be_a(Array) }
      it { is_expected.to contain_exactly('donkey', 'giraffe') }
    end

    context 'list + true' do
      let(:props) { props_raw_content_list_a }
      let(:other_props) { props_raw_content_true }

      it { is_expected.to be(true) }
    end

    context 'list + list' do
      let(:props) { props_raw_content_list_a }
      let(:other_props) { props_raw_content_list_b }

      it { is_expected.to be_a(Set) }
      it { is_expected.to contain_exactly('donkey', 'giraffe', 'zebra') }
    end
  end

  describe '#active' do
    subject { props.active }

    context 'nothing active' do
      let(:props) { described_class.new }

      it { is_expected.to be(0x00) }
    end

    context 'raw_content active' do
      let(:props) { described_class.new(raw_content: true) }

      it { is_expected.to be(0x01) }
    end

    context 'attributes active' do
      let(:props) { described_class.new(attributes: true) }

      it { is_expected.to be(0x02) }
    end

    context 'compiled_content active' do
      let(:props) { described_class.new(compiled_content: true) }

      it { is_expected.to be(0x04) }
    end

    context 'path active' do
      let(:props) { described_class.new(path: true) }

      it { is_expected.to be(0x08) }
    end

    context 'attributes and compiled_content active' do
      let(:props) { described_class.new(attributes: true, compiled_content: true) }

      it { is_expected.to be(0x02 | 0x04) }
    end

    context 'all active' do
      let(:props) do
        described_class.new(raw_content: true, attributes: true, compiled_content: true, path: true)
      end

      it { is_expected.to be(0x01 | 0x02 | 0x04 | 0x08) }
    end
  end

  describe '#to_h' do
    subject(:to_h) { props.to_h }

    context 'nothing' do
      let(:props) { described_class.new }

      it {
        expect(to_h)
          .to eql(
            raw_content: false,
            attributes: false,
            compiled_content: false,
            path: false,
          )
      }
    end

    context 'some' do
      let(:props) { described_class.new(attributes: true, compiled_content: true) }

      it {
        expect(to_h)
          .to eql(
            raw_content: false,
            attributes: true,
            compiled_content: true,
            path: false,
          )
      }
    end

    context 'all' do
      let(:props) { props_all }

      it {
        expect(to_h)
          .to eql(
            raw_content: true,
            attributes: true,
            compiled_content: true,
            path: true,
          )
      }
    end
  end
end
