from semver import Version, Spec, valid, clean, satisfies, lt, le, eq, ne, gt, ge, inc, validSpec


def ok(cond, message):
    if not cond:
        print("ERROR:", message)

def equal(a, b, message):
    if not a == b:
        print("ERROR:", message)

def comparison():
  # [version1, version2]
  # version1 should be greater than version2
  tests = [['0.0.0', '0.0.0-foo'],
    ['0.0.1', '0.0.0'],
    ['1.0.0', '0.9.9'],
    ['0.10.0', '0.9.0'],
    ['0.99.0', '0.10.0'],
    ['2.0.0', '1.2.3'],
    ['v0.0.0', '0.0.0-foo'],
    ['v0.0.1', '0.0.0'],
    ['v1.0.0', '0.9.9'],
    ['v0.10.0', '0.9.0'],
    ['v0.99.0', '0.10.0'],
    ['v2.0.0', '1.2.3'],
    ['0.0.0', 'v0.0.0-foo'],
    ['0.0.1', 'v0.0.0'],
    ['1.0.0', 'v0.9.9'],
    ['0.10.0', 'v0.9.0'],
    ['0.99.0', 'v0.10.0'],
    ['2.0.0', 'v1.2.3'],
    ['1.2.3', '1.2.3-asdf'],
    ['1.2.3', '1.2.3-4'],
    ['1.2.3', '1.2.3-4-foo'],
    ['1.2.3-5-foo', '1.2.3-5'],
    ['1.2.3-5', '1.2.3-4'],
    ['1.2.3-5-foo', '1.2.3-5-Foo'],
    ['3.0.0', '2.7.2+asdf'],
    ['1.2.3-a.10', '1.2.3-a.5'],
    ['1.2.3-a.b', '1.2.3-a.5'],
    ['1.2.3-a.b', '1.2.3-a'],
    ['1.2.3-a.b.c.10.d.5', '1.2.3-a.b.c.5.d.100']
  ]

  for v in tests:
    v0 = v[0]
    v1 = v[1]
    ok(gt(v0, v1), "gt('" + v0 + "', '" + v1 + "')")
    ok(lt(v1, v0), "lt('" + v1 + "', '" + v0 + "')")
    ok(not gt(v1, v0), "!gt('" + v1 + "', '" + v0 + "')")
    ok(not lt(v0, v1), "!lt('" + v0 + "', '" + v1 + "')")
    ok(eq(v0, v0), "eq('" + v0 + "', '" + v0 + "')")
    ok(eq(v1, v1), "eq('" + v1 + "', '" + v1 + "')")
    ok(ne(v0, v1), "ne('" + v0 + "', '" + v1 + "')")

def equality():
  # [version1, version2]
  # version1 should be equivalent to version2
  tests = [['1.2.3', 'v1.2.3'],
    ['1.2.3', '=1.2.3'],
    ['1.2.3', 'v 1.2.3'],
    ['1.2.3', '= 1.2.3'],
    ['1.2.3', ' v1.2.3'],
    ['1.2.3', ' =1.2.3'],
    ['1.2.3', ' v 1.2.3'],
    ['1.2.3', ' = 1.2.3'],
    ['1.2.3-0', 'v1.2.3-0'],
    ['1.2.3-0', '=1.2.3-0'],
    ['1.2.3-0', 'v 1.2.3-0'],
    ['1.2.3-0', '= 1.2.3-0'],
    ['1.2.3-0', ' v1.2.3-0'],
    ['1.2.3-0', ' =1.2.3-0'],
    ['1.2.3-0', ' v 1.2.3-0'],
    ['1.2.3-0', ' = 1.2.3-0'],
    ['1.2.3-1', 'v1.2.3-1'],
    ['1.2.3-1', '=1.2.3-1'],
    ['1.2.3-1', 'v 1.2.3-1'],
    ['1.2.3-1', '= 1.2.3-1'],
    ['1.2.3-1', ' v1.2.3-1'],
    ['1.2.3-1', ' =1.2.3-1'],
    ['1.2.3-1', ' v 1.2.3-1'],
    ['1.2.3-1', ' = 1.2.3-1'],
    ['1.2.3-beta', 'v1.2.3-beta'],
    ['1.2.3-beta', '=1.2.3-beta'],
    ['1.2.3-beta', 'v 1.2.3-beta'],
    ['1.2.3-beta', '= 1.2.3-beta'],
    ['1.2.3-beta', ' v1.2.3-beta'],
    ['1.2.3-beta', ' =1.2.3-beta'],
    ['1.2.3-beta', ' v 1.2.3-beta'],
    ['1.2.3-beta', ' = 1.2.3-beta'],
    ['1.2.3-beta+build', ' = 1.2.3-beta+otherbuild'],
    ['1.2.3+build', ' = 1.2.3+otherbuild'],
    ['1.2.3-beta+build', '1.2.3-beta+otherbuild'],
    ['1.2.3+build', '1.2.3+otherbuild'],
    ['  v1.2.3+build', '1.2.3+otherbuild']
  ]

  for v in tests:
    v0 = v[0]
    v1 = v[1]
    ok(eq(v0, v1), "eq('" + v0 + "', '" + v1 + "')")
    ok(not ne(v0, v1), "!ne('" + v0 + "', '" + v1 + "')")
    ok(not gt(v0, v1), "!gt('" + v0 + "', '" + v1 + "')")
    ok(ge(v0, v1), "ge('" + v0 + "', '" + v1 + "')")
    ok(not lt(v0, v1), "!lt('" + v0 + "', '" + v1 + "')")
    ok(le(v0, v1), "le('" + v0 + "', '" + v1 + "')")


def ranges():
  # [range, version]
  # version should be included by range
  tests = [['1.0.0 - 2.0.0', '1.2.3'],
    ['1.0.0', '1.0.0'],
    ['>=*', '0.2.4'],
    ['', '1.0.0'],
    ['*', '1.2.3'],
    ['*', 'v1.2.3-foo'],
    ['>=1.0.0', '1.0.0'],
    ['>=1.0.0', '1.0.1'],
    ['>=1.0.0', '1.1.0'],
    ['>1.0.0', '1.0.1'],
    ['>1.0.0', '1.1.0'],
    ['<=2.0.0', '2.0.0'],
    ['<=2.0.0', '1.9999.9999'],
    ['<=2.0.0', '0.2.9'],
    ['<2.0.0', '1.9999.9999'],
    ['<2.0.0', '0.2.9'],
    ['>= 1.0.0', '1.0.0'],
    ['>=  1.0.0', '1.0.1'],
    ['>=   1.0.0', '1.1.0'],
    ['> 1.0.0', '1.0.1'],
    ['>  1.0.0', '1.1.0'],
    ['<=   2.0.0', '2.0.0'],
    ['<= 2.0.0', '1.9999.9999'],
    ['<=  2.0.0', '0.2.9'],
    ['<    2.0.0', '1.9999.9999'],
    ['<\t2.0.0', '0.2.9'],
    ['>=0.1.97', 'v0.1.97'],
    ['>=0.1.97', '0.1.97'],
    ['0.1.20 || 1.2.4', '1.2.4'],
    ['>=0.2.3 || <0.0.1', '0.0.0'],
    ['>=0.2.3 || <0.0.1', '0.2.3'],
    ['>=0.2.3 || <0.0.1', '0.2.4'],
    ['||', '1.3.4'],
    ['2.x.x', '2.1.3'],
    ['1.2.x', '1.2.3'],
    ['1.2.x || 2.x', '2.1.3'],
    ['1.2.x || 2.x', '1.2.3'],
    ['x', '1.2.3'],
    ['2.*.*', '2.1.3'],
    ['1.2.*', '1.2.3'],
    ['1.2.* || 2.*', '2.1.3'],
    ['1.2.* || 2.*', '1.2.3'],
    ['*', '1.2.3'],
    ['2', '2.1.2'],
    ['2.3', '2.3.1'],
    ['~2.4', '2.4.0'], # >=2.4.0 <2.5.0
    ['~2.4', '2.4.5'],
    ['~>3.2.1', '3.2.2'], # >=3.2.1 <3.3.0,
    ['~1', '1.2.3'], # >=1.0.0 <2.0.0
    ['~>1', '1.2.3'],
    ['~> 1', '1.2.3'],
    ['~1.0', '1.0.2'], # >=1.0.0 <1.1.0,
    ['~ 1.0', '1.0.2'],
    ['~ 1.0.3', '1.0.12'],
    ['>=1', '1.0.0'],
    ['>= 1', '1.0.0'],
    ['<1.2', '1.1.1'],
    ['< 1.2', '1.1.1'],
    ['1', '1.0.0beta'],
    ['~v0.5.4-pre', '0.5.5'],
    ['~v0.5.4-pre', '0.5.4'],
    ['=0.7.x', '0.7.2'],
    ['>=0.7.x', '0.7.2'],
    ['=0.7.x', '0.7.0-asdf'],
    ['>=0.7.x', '0.7.0-asdf'],
    ['<=0.7.x', '0.6.2'],
    ['~1.2.1 >=1.2.3', '1.2.3'],
    ['~1.2.1 =1.2.3', '1.2.3'],
    ['~1.2.1 1.2.3', '1.2.3'],
    ['~1.2.1 >=1.2.3 1.2.3', '1.2.3'],
    ['~1.2.1 1.2.3 >=1.2.3', '1.2.3'],
    ['~1.2.1 1.2.3', '1.2.3'],
    ['>=1.2.1 1.2.3', '1.2.3'],
    ['1.2.3 >=1.2.1', '1.2.3'],
    ['>=1.2.3 >=1.2.1', '1.2.3'],
    ['>=1.2.1 >=1.2.3', '1.2.3'],
    ['<=1.2.3', '1.2.3-beta'],
    ['>1.2', '1.3.0-beta'],
    ['>=1.2', '1.2.8'],
    ['^1.2.3', '1.8.1'],
    ['^1.2.3', '1.2.3-beta'],
    ['^0.1.2', '0.1.2'],
    ['^0.1', '0.1.2'],
    ['^1.2', '1.4.2'],
    ['^1.2 ^1', '1.4.2'],
    ['^1.2', '1.2.0-pre'],
    ['^1.2.3', '1.2.3-pre']
  ]

  for v in tests:
    range = v[0]
    ver = v[1]
    ok(satisfies(ver, range), range + ' satisfied by ' + ver)

def negative():
  # [range, version]
  # version should not be included by range
  tests = [['1.0.0 - 2.0.0', '2.2.3'],
    ['1.0.0', '1.0.1'],
    ['>=1.0.0', '0.0.0'],
    ['>=1.0.0', '0.0.1'],
    ['>=1.0.0', '0.1.0'],
    ['>1.0.0', '0.0.1'],
    ['>1.0.0', '0.1.0'],
    ['<=2.0.0', '3.0.0'],
    ['<=2.0.0', '2.9999.9999'],
    ['<=2.0.0', '2.2.9'],
    ['<2.0.0', '2.9999.9999'],
    ['<2.0.0', '2.2.9'],
    ['>=0.1.97', 'v0.1.93'],
    ['>=0.1.97', '0.1.93'],
    ['0.1.20 || 1.2.4', '1.2.3'],
    ['>=0.2.3 || <0.0.1', '0.0.3'],
    ['>=0.2.3 || <0.0.1', '0.2.2'],
    ['2.x.x', '1.1.3'],
    ['2.x.x', '3.1.3'],
    ['1.2.x', '1.3.3'],
    ['1.2.x || 2.x', '3.1.3'],
    ['1.2.x || 2.x', '1.1.3'],
    ['2.*.*', '1.1.3'],
    ['2.*.*', '3.1.3'],
    ['1.2.*', '1.3.3'],
    ['1.2.* || 2.*', '3.1.3'],
    ['1.2.* || 2.*', '1.1.3'],
    ['2', '1.1.2'],
    ['2.3', '2.4.1'],
    ['~2.4', '2.5.0'], # >=2.4.0 <2.5.0
    ['~2.4', '2.3.9'],
    ['~>3.2.1', '3.3.2'], # >=3.2.1 <3.3.0
    ['~>3.2.1', '3.2.0'], # >=3.2.1 <3.3.0
    ['~1', '0.2.3'], # >=1.0.0 <2.0.0
    ['~>1', '2.2.3'],
    ['~1.0', '1.1.0'], # >=1.0.0 <1.1.0
    ['<1', '1.0.0'],
    ['>=1.2', '1.1.1'],
    ['1', '2.0.0beta'],
    ['~v0.5.4-beta', '0.5.4-alpha'],
    ['<1', '1.0.0beta'],
    ['< 1', '1.0.0beta'],
    ['=0.7.x', '0.8.2'],
    ['>=0.7.x', '0.6.2'],
    ['<=0.7.x', '0.7.2'],
    ['<1.2.3', '1.2.3-beta'],
    ['=1.2.3', '1.2.3-beta'],
    ['>1.2', '1.2.8'],
    ['^1.2.3', '2.0.0-alpha'],
    ['^1.2.3', '1.2.2'],
    ['^1.2', '1.1.9'],
    # invalid ranges never satisfied!
    ['blerg', '1.2.3'],
    ['git+https:#user:password0123@github.com/foo', '123.0.0'],
    ['^1.2.3', '2.0.0-pre']
  ]

  for v in tests:
    range = v[0]
    ver = v[1]
    found = satisfies(ver, range)
    ok(not found, ver + ' not satisfied by ' + range)

def increment():
  # [version, inc, result]
  # inc(version, inc) -> result
  tests = [['1.2.3', 'major', '2.0.0'],
    ['1.2.3', 'minor', '1.3.0'],
    ['1.2.3', 'patch', '1.2.4'],
    ['1.2.3tag', 'major', '2.0.0'],
    ['1.2.3-tag', 'major', '2.0.0'],
    ['1.2.3', 'fake', None],
    ['fake', 'major', None],
    ['1.2.3', 'prerelease', '1.2.3-0'],
    ['1.2.3-0', 'prerelease', '1.2.3-1'],
    ['1.2.3-alpha.0', 'prerelease', '1.2.3-alpha.1'],
    ['1.2.3-alpha.1', 'prerelease', '1.2.3-alpha.2'],
    ['1.2.3-alpha.2', 'prerelease', '1.2.3-alpha.3'],
    ['1.2.3-alpha.0.beta', 'prerelease', '1.2.3-alpha.1.beta'],
    ['1.2.3-alpha.1.beta', 'prerelease', '1.2.3-alpha.2.beta'],
    ['1.2.3-alpha.2.beta', 'prerelease', '1.2.3-alpha.3.beta'],
    ['1.2.3-alpha.10.0.beta', 'prerelease', '1.2.3-alpha.10.1.beta'],
    ['1.2.3-alpha.10.1.beta', 'prerelease', '1.2.3-alpha.10.2.beta'],
    ['1.2.3-alpha.10.2.beta', 'prerelease', '1.2.3-alpha.10.3.beta'],
    ['1.2.3-alpha.10.beta.0', 'prerelease', '1.2.3-alpha.10.beta.1'],
    ['1.2.3-alpha.10.beta.1', 'prerelease', '1.2.3-alpha.10.beta.2'],
    ['1.2.3-alpha.10.beta.2', 'prerelease', '1.2.3-alpha.10.beta.3'],
    ['1.2.3-alpha.9.beta', 'prerelease', '1.2.3-alpha.10.beta'],
    ['1.2.3-alpha.10.beta', 'prerelease', '1.2.3-alpha.11.beta'],
    ['1.2.3-alpha.11.beta', 'prerelease', '1.2.3-alpha.12.beta']
  ]

  for v in tests:
    pre = v[0]
    what = v[1]
    wanted = v[2]
    found = inc(pre, what)

    equal(found, wanted, 'inc(' + pre + ', ' + what + ') === ' + str(wanted) + " got " + str(found))


def valid():
  # [range, result]
  # validRange(range) -> result
  # translate ranges into their canonical form
  tests = [['1.0.0 - 2.0.0', '>=1.0.0 <=2.0.0'],
    ['1.0.0', '1.0.0'],
    ['>=*', '>=0.0.0-0'],
    ['', '*'],
    ['*', '*'],
    ['*', '*'],
    ['>=1.0.0', '>=1.0.0'],
    ['>1.0.0', '>1.0.0'],
    ['<=2.0.0', '<=2.0.0'],
    ['1', '>=1.0.0-0 <2.0.0-0'],
    ['<=2.0.0', '<=2.0.0'],
    ['<=2.0.0', '<=2.0.0'],
    ['<2.0.0', '<2.0.0-0'],
    ['<2.0.0', '<2.0.0-0'],
    ['>= 1.0.0', '>=1.0.0'],
    ['>=  1.0.0', '>=1.0.0'],
    ['>=   1.0.0', '>=1.0.0'],
    ['> 1.0.0', '>1.0.0'],
    ['>  1.0.0', '>1.0.0'],
    ['<=   2.0.0', '<=2.0.0'],
    ['<= 2.0.0', '<=2.0.0'],
    ['<=  2.0.0', '<=2.0.0'],
    ['<    2.0.0', '<2.0.0-0'],
    ['<	2.0.0', '<2.0.0-0'],
    ['>=0.1.97', '>=0.1.97'],
    ['>=0.1.97', '>=0.1.97'],
    ['0.1.20 || 1.2.4', '0.1.20||1.2.4'],
    ['>=0.2.3 || <0.0.1', '>=0.2.3||<0.0.1-0'],
    ['>=0.2.3 || <0.0.1', '>=0.2.3||<0.0.1-0'],
    ['>=0.2.3 || <0.0.1', '>=0.2.3||<0.0.1-0'],
    ['||', '*||*'],
    ['2.x.x', '>=2.0.0-0 <3.0.0-0'],
    ['1.2.x', '>=1.2.0-0 <1.3.0-0'],
    ['1.2.x || 2.x', '>=1.2.0-0 <1.3.0-0||>=2.0.0-0 <3.0.0-0'],
    ['1.2.x || 2.x', '>=1.2.0-0 <1.3.0-0||>=2.0.0-0 <3.0.0-0'],
    ['x', '*'],
    ['2.*.*', '>=2.0.0-0 <3.0.0-0'],
    ['1.2.*', '>=1.2.0-0 <1.3.0-0'],
    ['1.2.* || 2.*', '>=1.2.0-0 <1.3.0-0||>=2.0.0-0 <3.0.0-0'],
    ['*', '*'],
    ['2', '>=2.0.0-0 <3.0.0-0'],
    ['2.3', '>=2.3.0-0 <2.4.0-0'],
    ['~2.4', '>=2.4.0-0 <2.5.0-0'],
    ['~2.4', '>=2.4.0-0 <2.5.0-0'],
    ['~>3.2.1', '>=3.2.1-0 <3.3.0-0'],
    ['~1', '>=1.0.0-0 <2.0.0-0'],
    ['~>1', '>=1.0.0-0 <2.0.0-0'],
    ['~> 1', '>=1.0.0-0 <2.0.0-0'],
    ['~1.0', '>=1.0.0-0 <1.1.0-0'],
    ['~ 1.0', '>=1.0.0-0 <1.1.0-0'],
    ['^0', '>=0.0.0-0 <1.0.0-0'],
    ['^ 1', '>=1.0.0-0 <2.0.0-0'],
    ['^0.1', '>=0.1.0-0 <0.2.0-0'],
    ['^1.0', '>=1.0.0-0 <2.0.0-0'],
    ['^1.2', '>=1.2.0-0 <2.0.0-0'],
    ['^0.0.1', '=0.0.1'],
    ['^0.0.1-beta', '=0.0.1-beta'],
    ['^0.1.2', '>=0.1.2-0 <0.2.0-0'],
    ['^1.2.3', '>=1.2.3-0 <2.0.0-0'],
    ['^1.2.3-beta.4', '>=1.2.3-beta.4 <2.0.0-0'],
    ['<1', '<1.0.0-0'],
    ['< 1', '<1.0.0-0'],
    ['>=1', '>=1.0.0-0'],
    ['>= 1', '>=1.0.0-0'],
    ['<1.2', '<1.2.0-0'],
    ['< 1.2', '<1.2.0-0'],
    ['1', '>=1.0.0-0 <2.0.0-0'],
    ['>01.02.03', '>1.2.3'],
    ['~1.2.3beta', '>=1.2.3-beta <1.3.0-0'],
    ['^ 1.2 ^ 1', '>=1.2.0-0 <2.0.0-0 >=1.0.0-0 <2.0.0-0']
  ]

  for v in tests:
    pre = v[0]
    wanted = v[1]

    found = validSpec(pre)

    equal(found, wanted, 'validRange(' + pre + ') === ' + str(wanted) + " got " + str(found))

if __name__ == "__main__":
    comparison()
    equality()
    ranges()
    negative()
    increment()
    valid()
