# frozen_string_literal: true

require_relative 'apk_test_cases'

RSpec.describe SemverDialects::Apk::Version do
  describe '#<=>' do
    # https://github.com/alpinelinux/apk-tools/blob/6052bfef57a81d82451b4cad86f78a2d01959767/tests/version.data
    context 'consistency with tests of apk-tools' do
      APK_TOOLS_TEST_CASES.each do |a, expected, b|
        context "a=#{a}, b=#{b}" do
          subject { v1 <=> v2 }

          let(:v1) { SemverDialects::Apk::VersionParser.parse(a) }
          let(:v2) { SemverDialects::Apk::VersionParser.parse(b) }

          it { is_expected.to eq(expected) }
        end
      end
    end

    using RSpec::Parameterized::TableSyntax

    subject { version.<=>(other_version) }
    let(:version) { SemverDialects::Apk::VersionParser.parse(a) }
    let(:other_version) { SemverDialects::Apk::VersionParser.parse(b) }

    where(:a, :b, :result) do
      # semver
      '1.2.3' | '1.2.2' | 1
      '1.2.3' | '1.2.3' | 0 # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
      '1.2.0' | '1.2' | 1
      '1.2.0' | '1.3' | -1

      # semver with alphabets in patch
      '1.2.0a' | '1.2.0' | 1
      '1.2.0a' | '1.2.1' | -1

      # pre_release_suffix
      '1.2.3_alpha' | '1.2.3' | -1
      '1.2.3_beta' | '1.2.3_alpha' | 1
      '1.2.3_pre' | '1.2.3_beta' | 1
      '1.2.3_rc' | '1.2.3_pre' | 1
      '1.2.3' | '1.2.3_rc' | 1
      '1.2.3_alpha0' | '1.2.3_alpha' | 1
      '1.2.3_alpha0' | '1.2.3_alpha1' | -1
      '1.2.3_alpha1' | '1.2.3_beta0' | -1

      # post_release_suffix
      '1.2.3_cvs' | '1.2.3' | 1
      '1.2.3_svn' | '1.2.3_cvs' | 1
      '1.2.3_git' | '1.2.3_svn' | 1
      '1.2.3_hg' | '1.2.3_git' | 1
      '1.2.3_p' | '1.2.3_hg' | 1
      '1.2.3' | '1.2.3_p' | -1
      '1.2.3_cvs0' | '1.2.3_cvs' | 1
      '1.2.3_cvs0' | '1.2.3_cvs1' | -1
      '1.2.3_cvs1' | '1.2.3_svn0' | -1

      # revision
      '1.2.3-r' | '1.2.3' | 1
      '1.2.3-r0' | '1.2.3' | 1
      '1.2.3-r0' | '1.2.3-r' | 1
      '1.2.3-r1' | '1.2.3-r0' | 1
      '1.2.3-r1' | '1.2.3_alpha' | 1
      '1.2.3_alpha-r' | '1.2.3_alpha' | 1
      '1.2.3_alpha-r' | '1.2.3_beta' | -1
    end

    with_them do
      it { is_expected.to eq(result) }

      context 'when arguments are swapped' do
        subject { other_version.<=>(version) }

        it { is_expected.to eq(-result) }
      end
    end
  end
end

RSpec.describe SemverDialects::Apk::VersionParser do
  describe '.parse' do
    let(:version) { described_class.parse(input) }

    context 'with valid versions' do
      using RSpec::Parameterized::TableSyntax

      where(:input, :apk_version) do
        '1.2' | SemverDialects::Apk::Version.new([1, 2])
        '1.2.a' | SemverDialects::Apk::Version.new([1, 2, 'a'])
        '1.2.0a' | SemverDialects::Apk::Version.new([1, 2, 0, 'a'])
        '1.2_alpha' | SemverDialects::Apk::Version.new([1, 2], pre_release: ['alpha'])
        '1.2-r' | SemverDialects::Apk::Version.new([1, 2], revision: ['r'])
        '1.2_cvs1-r1' | SemverDialects::Apk::Version.new([1, 2], post_release: ['cvs', 1], revision: ['r', 1])
      end

      with_them do
        it 'returns an apk version instance' do
          expect(version).to eq(apk_version)
        end
      end
    end

    context 'with invalid versions' do
      using RSpec::Parameterized::TableSyntax

      where(:input) do
        [
          '1.2_a-r1',
          '1.2-a1',
          ' 1.1.a',
          '1.1.a ',
          '1.1. a',
          "\t1.1.a",
          "\n1.1.a",
          "\r\n1.1.a",
          "\f1.1.a",
          "\v1.1.a",
          '- ALPINE-13661',
          '_ ALPINE-13661'
        ]
      end

      with_them do
        it 'raises an error' do
          expect { described_class.parse(input) }
            .to raise_error(SemverDialects::InvalidVersionError, "invalid version '#{input}'")
        end
      end
    end

    context 'with unsupported versions' do
      using RSpec::Parameterized::TableSyntax

      where(:input) do
        [
          '013',
          '014-r1',
          '2.04',
          '4.09-r1',
          '4.09-r1',
          '0.1.0_alpha_pre2'
        ]
      end

      with_them do
        it 'raises an error' do
          expect { described_class.parse(input) }
            .to raise_error(SemverDialects::UnsupportedVersionError, "unsupported version '#{input}'")
        end
      end
    end
  end
end
