import pytest

import rust2rpm
from rust2rpm.metadata import Version


@pytest.mark.parametrize("req, rpmdep", [
    ("^1.2.3",
     "(crate(test) >= 1.2.3 with crate(test) < 2.0.0)"),
    ("^1.2",
     "(crate(test) >= 1.2.0 with crate(test) < 2.0.0)"),
    ("^1",
     "(crate(test) >= 1.0.0 with crate(test) < 2.0.0)"),
    ("^0.2.3",
     "(crate(test) >= 0.2.3 with crate(test) < 0.3.0)"),
    ("^0.2",
     "(crate(test) >= 0.2.0 with crate(test) < 0.3.0)"),
    ("^0.0.3",
     "(crate(test) >= 0.0.3 with crate(test) < 0.0.4)"),
    ("^0.0",
     "(crate(test) >= 0.0.0 with crate(test) < 0.1.0)"),
    ("^0",
     "(crate(test) >= 0.0.0 with crate(test) < 1.0.0)"),
    ("~1.2.3",
     "(crate(test) >= 1.2.3 with crate(test) < 1.3.0)"),
    ("~1.2",
     "(crate(test) >= 1.2.0 with crate(test) < 1.3.0)"),
    ("~1",
     "(crate(test) >= 1.0.0 with crate(test) < 2.0.0)"),
    ("*",
     "crate(test) >= 0.0.0"),
    ("1.*",
     "(crate(test) >= 1.0.0 with crate(test) < 2.0.0)"),
    ("1.2.*",
     "(crate(test) >= 1.2.0 with crate(test) < 1.3.0)"),
    ("1.*.*",
     "(crate(test) >= 1.0.0 with crate(test) < 2.0.0)"),
    (">= 1.2.0",
     "crate(test) >= 1.2.0"),
    ("> 1",
     "crate(test) > 1.0.0"),
    ("< 2",
     "crate(test) < 2.0.0"),
    ("= 1.2.3",
     "crate(test) = 1.2.3"),
    (">= 1.2, < 1.5",
     "(crate(test) >= 1.2.0 with crate(test) < 1.5.0)"),
    ("^1.0.0-alpha.6",
     "(crate(test) >= 1.0.0~alpha.6 with crate(test) < 2.0.0)"),
    ("^0.1.0-alpha.6",
     "(crate(test) >= 0.1.0~alpha.6 with crate(test) < 0.2.0)"),
    ("^0.0.1-alpha.6",
     "(crate(test) >= 0.0.1~alpha.6 with crate(test) < 0.0.2)"),
    ("^0.0.0-alpha.6",
     "(crate(test) >= 0.0.0~alpha.6 with crate(test) < 0.0.1)"),
])
def test_dependency(req, rpmdep):
    dep = rust2rpm.Dependency("test", req)
    assert str(dep) == rpmdep


@pytest.mark.parametrize('version, parsed_version', [
    ('', (None, None, None, None, None)),
    ('0', (0, None, None, None, None)),
    ('1.0', (1, 0, None, None, None)),
    ('2.1.0', (2, 1, 0, None, None)),
    ('2.1.0+build1', (2, 1, 0, None, 'build1')),
    ('2.1.0-alpha1', (2, 1, 0, 'alpha1', None)),
    ('2.1.0-alpha1+build1', (2, 1, 0, 'alpha1', 'build1')),
])
def test_parse_version(version, parsed_version):
    result = rust2rpm.metadata.CargoSemVer.parse_version(version)
    assert result == parsed_version


@pytest.mark.parametrize('parsed_version, version', [
    (Version(0, None, None, None, None), '0.0.0'),
    (Version(1, 0, None, None, None), '1.0.0'),
    (Version(2, 1, 0, None, None), '2.1.0'),
    (Version(2, 1, 0, None, 'build1'), '2.1.0+build1'),
    (Version(2, 1, 0, 'alpha1', None), '2.1.0-alpha1'),
    (Version(2, 1, 0, 'alpha1', 'build1'), '2.1.0-alpha1+build1'),
])
def test_unparse_version(parsed_version, version):
    result = rust2rpm.metadata.CargoSemVer.unparse_version(parsed_version)
    assert result == version


@pytest.mark.parametrize('parsed_version, version', [
    (Version(2, 1, 0, None, None), '2.1.0'),
    (Version(2, 1, 0, None, 'build1'), '2.1.0+build1'),
    (Version(2, 1, 0, 'alpha1', None), '2.1.0~alpha1'),
    (Version(2, 1, 0, 'alpha1', 'build1'), '2.1.0~alpha1+build1'),
])
def test_unparse_version_sep(parsed_version, version):
    result = rust2rpm.metadata.CargoSemVer.unparse_version(
        parsed_version, sep='~')
    assert result == version


@pytest.mark.parametrize('requirement, parsed_requirement', [
    ('*', ('*', (None, None, None, None, None))),
    ('0.*', ('*', (0, None, None, None, None))),
    ('0.1.*', ('*', (0, 1, None, None, None))),
    ('0.*.*', ('*', (0, None, None, None, None))),
    ('<0', ('<', (0, None, None, None, None))),
    ('<0.1', ('<', (0, 1, None, None, None))),
    ('<0.1.2', ('<', (0, 1, 2, None, None))),
    ('<0.1.2-alpha1', ('<', (0, 1, 2, 'alpha1', None))),
    ('<=0.1.2', ('<=', (0, 1, 2, None, None))),
    ('=0.1.2', ('=', (0, 1, 2, None, None))),
    ('==0.1.2', ('==', (0, 1, 2, None, None))),
    ('>=0.1.2', ('>=', (0, 1, 2, None, None))),
    ('>0.1.2', ('>', (0, 1, 2, None, None))),
    ('0.1.2', ('', (0, 1, 2, None, None))),
    ('!=0.1.2', ('!=', (0, 1, 2, None, None))),
    ('^0.1.2', ('^', (0, 1, 2, None, None))),
    ('~0.1.2', ('~', (0, 1, 2, None, None))),
    ('~=0.1.2', ('~=', (0, 1, 2, None, None))),
])
def test_parse(requirement, parsed_requirement):
    result = rust2rpm.metadata.CargoSemVer.parse(requirement)
    assert result == parsed_requirement


@pytest.mark.parametrize('version, coerced_version', [
    (Version(0, None, None, None, None),
     (0, 0, 0, None, None)),
    (Version(1, 0, None, None, None),
     (1, 0, 0, None, None)),
    (Version(2, 1, 0, None, None),
     (2, 1, 0, None, None)),
    (Version(2, 1, 0, None, 'build1'),
     (2, 1, 0, None, 'build1')),
    (Version(2, 1, 0, 'alpha1', None),
     (2, 1, 0, 'alpha1', None)),
    (Version(2, 1, 0, 'alpha1', 'build1'),
     (2, 1, 0, 'alpha1', 'build1')),
])
def test_coerce(version, coerced_version):
    result = rust2rpm.metadata.CargoSemVer.coerce(version)
    assert result == coerced_version


@pytest.mark.parametrize('version, next_version', [
    ((0, None, None, None, None), (1, 0, 0, None, None)),
    ((1, 0, None, None, None), (2, 0, 0, None, None)),
    ((2, 1, 0, None, None), (3, 0, 0, None, None)),
    ((2, 0, 0, None, 'build1'), (3, 0, 0, None, None)),
    ((2, None, None, 'alpha1', None), (2, 0, 0, None, None)),
    ((2, 0, None, 'alpha1', None), (2, 0, 0, None, None)),
    ((2, 0, 0, 'alpha1', None), (2, 0, 0, None, None)),
    ((2, 1, None, 'alpha1', None), (3, 0, 0, None, None)),
    ((2, 1, 0, 'alpha1', None), (3, 0, 0, None, None)),
    ((2, 1, 1, 'alpha1', None), (3, 0, 0, None, None)),
    ((2, 0, 1, 'alpha1', 'build1'), (3, 0, 0, None, None)),
])
def test_next_major(version, next_version):
    result = rust2rpm.metadata.CargoSemVer.next_major(version)
    assert result == next_version


@pytest.mark.parametrize('version, next_version', [
    ((0, None, None, None, None), (0, 1, 0, None, None)),
    ((1, 0, None, None, None), (1, 1, 0, None, None)),
    ((2, 1, 0, None, None), (2, 2, 0, None, None)),
    ((2, 1, 0, None, 'build1'), (2, 2, 0, None, None)),
    ((2, None, None, 'alpha1', None), (2, 0, 0, None, None)),
    ((2, 0, None, 'alpha1', None), (2, 0, 0, None, None)),
    ((2, 0, 0, 'alpha1', None), (2, 0, 0, None, None)),
    ((2, 1, None, 'alpha1', None), (2, 1, 0, None, None)),
    ((2, 1, 0, 'alpha1', None), (2, 1, 0, None, None)),
    ((2, 1, 1, 'alpha1', None), (2, 2, 0, None, None)),
    ((2, 1, 0, 'alpha1', 'build1'), (2, 1, 0, None, None)),
])
def test_next_minor(version, next_version):
    result = rust2rpm.metadata.CargoSemVer.next_minor(version)
    assert result == next_version


@pytest.mark.parametrize('version, next_version', [
    ((0, None, None, None, None), (0, 0, 1, None, None)),
    ((1, 0, None, None, None), (1, 0, 1, None, None)),
    ((2, 1, 0, None, None), (2, 1, 1, None, None)),
    ((2, 1, 0, None, 'build1'), (2, 1, 1, None, None)),
    ((2, None, None, 'alpha1', None), (2, 0, 0, None, None)),
    ((2, 0, None, 'alpha1', None), (2, 0, 0, None, None)),
    ((2, 0, 0, 'alpha1', None), (2, 0, 0, None, None)),
    ((2, 1, None, 'alpha1', None), (2, 1, 0, None, None)),
    ((2, 1, 0, 'alpha1', None), (2, 1, 0, None, None)),
    ((2, 1, 1, 'alpha1', None), (2, 1, 1, None, None)),
    ((2, 1, 0, 'alpha1', 'build1'), (2, 1, 0, None, None)),
])
def test_next_patch(version, next_version):
    result = rust2rpm.metadata.CargoSemVer.next_patch(version)
    assert result == next_version


@pytest.mark.parametrize("requirement, normalized_requirement", [
    (('^', Version(1, 2, 3, None, None)),
     [('>=', (1, 2, 3, None, None)), ('<', (2, 0, 0, None, None))]),
    (('^', Version(1, 2, None, None, None)),
     [('>=', (1, 2, 0, None, None)), ('<', (2, 0, 0, None, None))]),
    (('^', Version(1, None, None, None, None)),
     [('>=', (1, 0, 0, None, None)), ('<', (2, 0, 0, None, None))]),
    (('^', Version(0, 2, 3, None, None)),
     [('>=', (0, 2, 3, None, None)), ('<', (0, 3, 0, None, None))]),
    (('^', Version(0, 2, None, None, None)),
     [('>=', (0, 2, 0, None, None)), ('<', (0, 3, 0, None, None))]),
    (('^', Version(0, 0, 3, None, None)),
     [('>=', (0, 0, 3, None, None)), ('<', (0, 0, 4, None, None))]),
    (('^', Version(0, 0, None, None, None)),
     [('>=', (0, 0, 0, None, None)), ('<', (0, 1, 0, None, None))]),
    (('^', Version(0, None, None, None, None)),
     [('>=', (0, 0, 0, None, None)), ('<', (1, 0, 0, None, None))]),
    (('~', Version(1, 2, 3, None, None)),
     [('>=', (1, 2, 3, None, None)), ('<', (1, 3, 0, None, None))]),
    (('~', Version(1, 2, None, None, None)),
     [('>=', (1, 2, 0, None, None)), ('<', (1, 3, 0, None, None))]),
    (('~', Version(1, None, None, None, None)),
     [('>=', (1, 0, 0, None, None)), ('<', (2, 0, 0, None, None))]),
    (('*', Version(None, None, None, None, None)),
     [('>=', (0, 0, 0, None, None))]),
    (('*', Version(1, None, None, None, None)),
     [('>=', (1, 0, 0, None, None)), ('<', (2, 0, 0, None, None))]),
    (('*', Version(1, 2, None, None, None)),
     [('>=', (1, 2, 0, None, None)), ('<', (1, 3, 0, None, None))]),
    (('>=', Version(1, 2, 0, None, None)),
     [('>=', (1, 2, 0, None, None))]),
    (('>', Version(1, None, None, None, None)),
     [('>', (1, 0, 0, None, None))]),
    (('<', Version(2, None, None, None, None)),
     [('<', (2, 0, 0, None, None))]),
    (('=', Version(1, 2, 3, None, None)),
     [('=', (1, 2, 3, None, None))]),
    (('^', Version(1, 0, 0, 'alpha.6', None)),
     [('>=', (1, 0, 0, 'alpha.6', None)), ('<', (2, 0, 0, None, None))]),
    (('^', Version(0, 1, 0, 'alpha.6', None)),
     [('>=', (0, 1, 0, 'alpha.6', None)), ('<', (0, 2, 0, None, None))]),
    (('^', Version(0, 0, 1, 'alpha.6', None)),
     [('>=', (0, 0, 1, 'alpha.6', None)), ('<', (0, 0, 2, None, None))]),
    (('^', Version(0, 0, 0, 'alpha.6', None)),
     [('>=', (0, 0, 0, 'alpha.6', None)), ('<', (0, 0, 1, None, None))]),
])
def test_normalize(requirement, normalized_requirement):
    result = rust2rpm.metadata.CargoSemVer.normalize(requirement)
    assert result == normalized_requirement
