Ignore builds when comparing. Add more tests. Fix errors in __lt

This commit is contained in:
kikito 2015-10-20 23:43:06 +02:00
parent f558f99022
commit 84e37a1993
2 changed files with 113 additions and 137 deletions

View File

@ -99,23 +99,13 @@ local function compare(a,b)
return a == b and 0 or a < b and -1 or 1
end
local function compareNilPrereleases(mine, other)
if mine == other then return 0
elseif not mine then return 1
elseif not other then return -1
end -- else return nil
end
local function compareIds(myId, otherId)
if myId == otherId then return 0
elseif not myId then return -1
elseif not otherId then return 1
end
-- notice that builds compare nils inversely than prereleases (the -1 and 1 are switched)
local function compareNilBuilds(mine, other)
if mine == other then return 0
elseif not mine then return -1
elseif not other then return 1
end -- else return nil
end
local function compareIds(selfId, otherId)
local selfNumber, otherNumber = tonumber(selfId), tonumber(otherId)
local selfNumber, otherNumber = tonumber(myId), tonumber(otherId)
if selfNumber and otherNumber then -- numerical comparison
return compare(selfNumber, otherNumber)
@ -125,18 +115,16 @@ local function compareIds(selfId, otherId)
elseif otherNumber then
return 1
else
return compare(selfId, otherId) -- alphanumerical comparison
return compare(myId, otherId) -- alphanumerical comparison
end
end
local function smallerIds(mine, other, compareNil)
local myIds, otherIds = splitByDot(mine), splitByDot(other)
local function smallerIdList(myIds, otherIds)
local myLength = #myIds
local comparison, myId, otherId
local comparison
for i = 1, myLength do
myId, otherId = myIds[i], otherIds[i]
comparison = compareNil(myId, otherId) or compareIds(myId, otherId)
for i=1, myLength do
comparison = compareIds(myIds[i], otherIds[i])
if comparison ~= 0 then
return comparison == -1
end
@ -147,19 +135,11 @@ local function smallerIds(mine, other, compareNil)
end
local function smallerPrerelease(mine, other)
if mine == other or not mine then return false
if mine == other or not mine then return false
elseif not other then return true
end
return smallerIds(mine, other, compareNilPrereleases)
end
local function smallerBuild(mine, other)
if mine == other or not other then return false
elseif not mine then return true
end
return smallerIds(mine, other, compareNilBuilds)
return smallerIdList(splitByDot(mine), splitByDot(other))
end
local methods = {}
@ -179,16 +159,19 @@ function mt:__eq(other)
return self.major == other.major and
self.minor == other.minor and
self.patch == other.patch and
self.prerelease == other.prerelease and
self.build == other.build
self.prerelease == other.prerelease
-- notice that build is ignored for precedence in semver 2.0.0
end
function mt:__lt(other)
return self.major < other.major or
self.minor < other.minor or
self.patch < other.patch or
smallerPrerelease(self.prerelease, other.prerelease) or
smallerBuild(self.build, other.build)
if self.major ~= other.major then return self.major < other.major end
if self.minor ~= other.minor then return self.minor < other.minor end
if self.patch ~= other.patch then return self.patch < other.patch end
return smallerPrerelease(self.prerelease, other.prerelease)
-- notice that build is ignored for precedence in semver 2.0.0
end
-- This works like the "pessimisstic operator" in Rubygems.
-- if a and b are versions, a ^ b means "b is backwards-compatible with a"
-- in other words, "it's safe to upgrade from a to b"
function mt:__pow(other)
return self.major == other.major and
self.minor <= other.minor

View File

@ -39,59 +39,59 @@ describe('semver', function()
end)
describe("from strings", function()
test("1.2.3", function()
it("1.2.3", function()
checkVersion( v'1.2.3', 1,2,3)
end)
test("10.20.123", function()
it("10.20.123", function()
checkVersion( v'10.20.123', 10,20,123)
end)
test("2.0", function()
it("2.0", function()
checkVersion( v'2.0', 2,0,0)
end)
test("5", function()
it("5", function()
checkVersion( v'5', 5,0,0)
end)
test("1.2.3-alpha", function()
it("1.2.3-alpha", function()
checkVersion( v'1.2.3-alpha', 1,2,3,'alpha' )
end)
test("1.2.3+build.15", function()
it("1.2.3+build.15", function()
checkVersion( v'1.2.3+build.15', 1,2,3,nil,'build.15' )
end)
test("1.2.3-rc1+build.15", function()
it("1.2.3-rc1+build.15", function()
checkVersion( v'1.2.3-rc1+build.15', 1,2,3,'rc1','build.15' )
end)
end)
describe('errors', function()
test('no parameters are passed', function()
it('no parameters are passed', function()
assert.error(function() v() end)
end)
test('negative numbers', function()
it('negative numbers', function()
assert.error(function() v(-1, 0, 0) end)
assert.error(function() v( 0,-1, 0) end)
assert.error(function() v( 0, 0,-1) end)
end)
test('floats', function()
it('floats', function()
assert.error(function() v(.1, 0, 0) end)
assert.error(function() v( 0,.1, 0) end)
assert.error(function() v( 0, 0,.1) end)
end)
test('empty string', function()
it('empty string', function()
assert.error(function() v("") end)
end)
test('garbage at the beginning of the string', function()
it('garbage at the beginning of the string', function()
assert.error(function() v("foobar1.2.3") end)
end)
test('garbage at the end of the string', function()
it('garbage at the end of the string', function()
assert.error(function() v("1.2.3foobar") end)
end)
test('a non-string or number is passed', function()
it('a non-string or number is passed', function()
assert.error(function() v({}) end)
end)
test('an invalid prerelease', function()
it('an invalid prerelease', function()
assert.error(function() v'1.2.3-%?' end)
end)
test('an invalid build', function()
it('an invalid build', function()
assert.error(function() v'1.2.3+%?' end)
end)
end)
@ -115,115 +115,112 @@ describe('semver', function()
describe("==", function()
it("is true when major, minor and patch are the same", function()
assert.equal(v(1,2,3), v'1.2.3')
assert.equal(v'1.0.0', v'1.0.0')
end)
it("is false when major, minor and patch are not the same", function()
assert.not_equal(v(1,2,3), v(4,5,6))
it("is false when major, minor, patch or prerelease are not the same", function()
assert.not_equal(v'1.0.0', v'1.0.1')
assert.not_equal(v'1.0.0', v'1.1.0')
assert.not_equal(v'1.0.0', v'2.0.0')
assert.not_equal(v'1.0.0', v'1.0.0-alpha')
end)
it("false if all is the same except the prerelease", function()
assert.not_equal(v(1,2,3), v'1.2.3-alpha')
end)
it("false if all is the same except the build", function()
assert.not_equal(v(1,2,3), v'1.2.3+peter.1')
it("ignores builds", function()
assert.equal(v'1.2.3', v'1.2.3+1')
assert.equal(v'1.2.3+1', v'1.2.3+2')
end)
end)
describe("<", function()
test("true if major < minor", function()
assert.less(v'1.100.10', v'2.0.0')
it("compares correctly when major, minor and patch are equal", function()
assert.not_less(v'1.0.0', v'1.0.0')
assert.not_greater(v'1.0.0', v'1.0.0')
assert.equal(v'1.0.0', v'1.0.0')
end)
test("false if major > minor", function()
assert.greater(v'2', v'1')
it("#focus prioritizes major over minor", function()
--assert.less(v'1.100.10', v'2.0.0')
assert.not_greater(v'1.100.10', v'2.0.0')
--assert.greater(v'2', v'1')
--assert.not_less(v'2', v'1')
end)
test("true if major = major but minor < minor", function()
it("when equal major, compares minor", function()
assert.less(v'1.2.0', v'1.3.0')
end)
test("false if minor < minor", function()
assert.not_greater(v'1.2.0', v'1.3.0')
assert.greater(v'1.1', v'1.0')
assert.not_less(v'1.1', v'1.0')
end)
test("true if major =, minor =, but patch <", function()
it("when equal major and minor, compares patch", function()
assert.less(v'0.0.1', v'0.0.10')
end)
test("false if major =, minor =, but patch >", function()
assert.not_greater(v'0.0.1', v'0.0.10')
assert.greater(v'0.0.2', v'0.0.1')
assert.not_less(v'0.0.2', v'0.0.1')
end)
describe("prereleases", function()
test("false if exact same prerelease", function()
assert.not_less(v'1.0.0-beta', v'1.0.0-beta')
it("compares correctly when major, minor, patch and prerelease are equal", function()
assert.not_less(v'1.0.0-1', v'1.0.0-1')
assert.not_greater(v'1.0.0-1', v'1.0.0-1')
assert.equal(v'1.0.0-1', v'1.0.0-1')
end)
test("#focus a prerelease version is less than the official version", function()
it("prioritizes non-prereleases over prereleases", function()
assert.less(v'1.0.0-rc1', v'1.0.0')
assert.not_greater(v'1.0.0-rc1', v'1.0.0')
assert.greater(v'1.2.3', v'1.2.3-alpha')
assert.not_less(v'1.2.3', v'1.2.3-alpha')
end)
test("identifiers with only digits are compared numerically", function()
it("compares identifiers with only digits numerically", function()
assert.less(v'1.0.0-1', v'1.0.0-2')
assert.not_greater(v'1.0.0-1', v'1.0.0-2')
assert.greater(v'1.0.0-2', v'1.0.0-1')
assert.not_less(v'1.0.0-2', v'1.0.0-1')
end)
test("idendifiers with letters or dashes are compared lexiconumerically", function()
it("compares idendifiers with letters or dashes lexiconumerically", function()
assert.less(v'1.0.0-alpha', v'1.0.0-beta')
assert.less(v'1.0.0-alpha-10', v'1.0.0-alpha-2')
assert.not_greater(v'1.0.0-alpha', v'1.0.0-beta')
assert.less(v'1.0.0-alpha-10', v'1.0.0-alpha-2')
assert.not_greater(v'1.0.0-alpha-10', v'1.0.0-alpha-2')
assert.greater(v'1.0.0-beta', v'1.0.0-alpha')
assert.not_less(v'1.0.0-beta', v'1.0.0-alpha')
assert.greater(v'1.0.0-alpha-2', v'1.0.0-alpha-10')
assert.not_less(v'1.0.0-alpha-2', v'1.0.0-alpha-10')
end)
test("numerical ids always have less priority than lexiconumericals", function()
it("prioritizes lexiconumericals over numbers", function()
assert.less(v'1.0.0-1', v'1.0.0-alpha')
assert.less(v'1.0.0-2', v'1.0.0-1asdf')
assert.not_greater(v'1.0.0-1', v'1.0.0-alpha')
assert.less(v'1.0.0-2', v'1.0.0-1asdf')
assert.not_greater(v'1.0.0-2', v'1.0.0-1asdf')
assert.greater(v'1.0.0-alpha', v'1.0.0-1')
assert.not_less(v'1.0.0-alpha', v'1.0.0-1')
assert.greater(v'1.0.0-1asdf', v'1.0.0-2')
assert.not_less(v'1.0.0-1asdf', v'1.0.0-2')
end)
test("identifiers can be separated by colons; they must be compared individually", function()
--assert.less(v'1.0.0-alpha' , v'1.0.0-alpha.1')
--assert.less(v'1.0.0-alpha.1' , v'1.0.0-beta.2')
--assert.less(v'1.0.0-beta.2' , v'1.0.0-beta.11')
--assert.less(v'1.0.0-beta.11' , v'1.0.0-rc.1')
it("splits identifiers by colons, comparing every pair individually", function()
assert.less(v'1.0.0-alpha', v'1.0.0-alpha.1')
assert.not_greater(v'1.0.0-alpha', v'1.0.0-alpha.1')
--assert.not_greater(v'1.0.0-alpha.1', v'1.0.0-beta.2')
--assert.not_greater(v'1.0.0-beta.2' , v'1.0.0-beta.11')
--assert.not_greater(v'1.0.0-beta.11', v'1.0.0-rc.1')
assert.less(v'1.0.0-alpha.1', v'1.0.0-beta.2')
assert.not_greater(v'1.0.0-alpha.1', v'1.0.0-beta.2')
assert.less(v'1.0.0-beta.2', v'1.0.0-beta.11')
assert.not_greater(v'1.0.0-beta.2', v'1.0.0-beta.11')
assert.less(v'1.0.0-beta.11', v'1.0.0-rc.1')
assert.not_greater(v'1.0.0-beta.11', v'1.0.0-rc.1')
assert.greater(v'1.0.0-alpha.1', v'1.0.0-alpha')
assert.not_less(v'1.0.0-alpha.1', v'1.0.0-alpha')
assert.greater(v'1.0.0-beta.2', v'1.0.0-alpha.1')
assert.not_less(v'1.0.0-beta.2', v'1.0.0-alpha.1')
assert.greater(v'1.0.0-beta.11', v'1.0.0-beta.2')
assert.not_less(v'1.0.0-beta.11', v'1.0.0-beta.2')
assert.greater(v'1.0.0-rc.1', v'1.0.0-beta.11')
assert.not_less(v'1.0.0-rc.1', v'1.0.0-beta.11')
end)
end)
describe("builds", function()
test("false if exact same build", function()
assert.not_less(v'1.0.0+build1', v'1.0.0+build1')
it("false independently of the build", function()
assert.not_less(v'1.0.0+build1', v'1.0.0')
assert.not_less(v'1.0.0+build1', v'1.0.0+build3')
assert.not_less(v'1.0.0-beta+build1', v'1.0.0-beta+build2')
assert.not_greater(v'1.0.0+build1', v'1.0.0')
assert.not_greater(v'1.0.0+build1', v'1.0.0+build3')
assert.not_greater(v'1.0.0-beta+build1', v'1.0.0-beta+build2')
end)
test("a regular (not-build) version is always less than a build version", function()
assert.less(v'1.0.0', v'1.0.0+12')
assert.less(v'1.0.0', v'1.0.0+12')
end)
test("identifiers with only digits are compared numerically", function()
assert.less(v'1.0.0+1', v'1.0.0+2')
assert.less(v'1.0.0+2', v'1.0.0+10')
assert.not_greater(v'1.0.0+1', v'1.0.0+2')
assert.not_greater(v'1.0.0+2', v'1.0.0+10')
end)
test("idendifiers with letters or dashes are compared lexiconumerically", function()
assert.less(v'1.0.0+build1' , v'1.0.0+build2')
assert.less(v'1.0.0+build10', v'1.0.0+build2')
assert.not_greater(v'1.0.0+build1' , v'1.0.0+build2')
assert.not_greater(v'1.0.0+build10' , v'1.0.0+build2')
end)
test("numerical ids always have less priority than lexiconumericals", function()
assert.less(v'1.0.0+1', v'1.0.0+build1')
assert.less(v'1.0.0+2', v'1.0.0+1build')
assert.not_greater(v'1.0.0+1', v'1.0.0+build1')
assert.not_greater(v'1.0.0+2', v'1.0.0+1build')
end)
test("identifiers can be separated by colons; they must be compared individually", function()
assert.less(v'1.0.0+0.3.7', v'1.3.7+build')
assert.less(v'1.3.7+build', v'1.3.7+build.2.b8f12d7')
assert.less(v'1.3.7+build.2.b8f12d7', v'1.3.7+build.11.e0f985a')
assert.not_greater(v'1.0.0+0.3.7', v'1.3.7+build')
assert.not_greater(v'1.3.7+build', v'1.3.7+build.2.b8f12d7')
assert.not_greater(v'1.3.7+build.2.b8f12d7', v'1.3.7+build.11.e0f985a')
end)
end)
test("#focus prereleases + builds", function()
--assert.less(v'1.0.0-rc.1', v'1.0.0-rc.1+build.1')
--assert.less(v'1.0.0-rc.1+build.1', v'1.0.0')
--assert.not_greater(v'1.0.0-rc.1', v'1.0.0-rc.1+build.1')
assert.not_greater(v'1.0.0-rc.1+build.1', v'1.0.0')
end)
end)
@ -254,30 +251,26 @@ describe('semver', function()
end)
end)
-- This works like the "pessimisstic operator" in Rubygems.
-- if a and b are versions, a ^ b means "b is backwards-compatible with a"
-- in other words, "it's safe to upgrade from a to b"
describe("^", function()
test("true for self", function()
it("true for self", function()
assert.is_true(v(1,2,3) ^ v(1,2,3))
end)
test("different major versions mean it's always unsafe", function()
it("different major versions mean it's always unsafe", function()
assert.is_false(v(2,0,0) ^ v(3,0,0))
assert.is_false(v(2,0,0) ^ v(1,0,0))
end)
test("patches, prereleases and builds are ignored", function()
it("patches, prereleases and builds are ignored", function()
assert.is_true(v(1,2,3) ^ v(1,2,0))
assert.is_true(v(1,2,3) ^ v(1,2,5))
assert.is_true(v(1,2,3,'foo') ^ v(1,2,3))
assert.is_true(v(1,2,3,nil,'bar') ^ v(1,2,3))
end)
test("it's safe to upgrade to a newer minor version", function()
it("is safe to upgrade to a newer minor version", function()
assert.is_true(v(1,2,0) ^ v(1,5,0))
end)
test("it's unsafe to downgrade to an earlier minor version", function()
it("is unsafe to downgrade to an earlier minor version", function()
assert.is_false(v(1,5,0) ^ v(1,2,0))
end)
end)