# frozen_string_literal: true

RSpec::Matchers.define(:have_version_constant) do
  match do |version_mod|
    version_mod.const_defined?(:VERSION, false)
  end
end

RSpec::Matchers.define(:have_version_as_string) do
  match do |version_mod|
    !version_mod::VERSION.nil? && version_mod::VERSION.is_a?(String)
  end
end

RSpec::Matchers.define(:have_epoch_as_integer) do
  match do |version_mod|
    version_mod.epoch.is_a?(Integer)
  end
end

RSpec::Matchers.define(:have_major_as_integer) do
  match do |version_mod|
    version_mod.major.is_a?(Integer)
  end
end

RSpec::Matchers.define(:have_minor_as_integer) do
  match do |version_mod|
    version_mod.minor.is_a?(Integer)
  end
end

RSpec::Matchers.define(:have_patch_as_integer) do
  match do |version_mod|
    version_mod.patch.is_a?(Integer)
  end
end

RSpec::Matchers.define(:have_pre_as_nil_or_string) do
  match do |version_mod|
    version_mod.pre.nil? || version_mod.pre.is_a?(String)
  end
end

RSpec.shared_examples_for("a Version module") do |version_mod|
  it "is introspectable" do
    aggregate_failures "introspectable api" do
      expect(version_mod).is_a?(Module)
      expect(version_mod).to(have_version_constant)
      expect(version_mod).to(have_version_as_string)
      expect(version_mod.to_s).to(be_a(String))
      expect(version_mod).to(have_major_as_integer)
      expect(version_mod).to(have_minor_as_integer)
      expect(version_mod).to(have_patch_as_integer)
      expect(version_mod).to(have_pre_as_nil_or_string)
      expect(version_mod.to_h.keys).to(match_array(%i[major minor patch pre]))
      expect(version_mod.to_a).to(be_a(Array))
    end
  end
end

# This one is more Epoch ;)
RSpec.shared_examples_for("an Epoch Version module") do |version_mod|
  it "is introspectable" do
    aggregate_failures "introspectable api" do
      expect(version_mod).is_a?(Module)
      expect(version_mod).to(have_version_constant)
      expect(version_mod).to(have_version_as_string)
      expect(version_mod.to_s).to(be_a(String))
      expect(version_mod).to(have_epoch_as_integer)
      expect(version_mod).to(have_major_as_integer)
      expect(version_mod).to(have_minor_as_integer)
      expect(version_mod).to(have_patch_as_integer)
      expect(version_mod).to(have_pre_as_nil_or_string)
      expect(version_mod.to_h.keys).to(match_array(%i[epoch major minor patch pre]))
      expect(version_mod.to_a).to(be_a(Array))
    end
  end
end
