// Copyright 2016 clair authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package rpm import ( "testing" "github.com/stretchr/testify/assert" ) const ( LESS = -1 EQUAL = 0 GREATER = 1 ) func TestParse(t *testing.T) { cases := []struct { str string ver version err bool }{ // Test 0 {"0", version{epoch: 0, version: "0", release: ""}, false}, {"0:0", version{epoch: 0, version: "0", release: ""}, false}, {"0:0-", version{epoch: 0, version: "0", release: ""}, false}, {"0:0-0", version{epoch: 0, version: "0", release: "0"}, false}, {"0:0.0-0.0", version{epoch: 0, version: "0.0", release: "0.0"}, false}, // Test epoched {"1:0", version{epoch: 1, version: "0", release: ""}, false}, {"5:1", version{epoch: 5, version: "1", release: ""}, false}, // Test multiple hypens {"0:0-0-0", version{epoch: 0, version: "0", release: "0-0"}, false}, {"0:0-0-0-0", version{epoch: 0, version: "0", release: "0-0-0"}, false}, // Test multiple colons {"0:0:0-0", version{epoch: 0, version: "0:0", release: "0"}, false}, {"0:0:0:0-0", version{epoch: 0, version: "0:0:0", release: "0"}, false}, // Test multiple hyphens and colons {"0:0:0-0-0", version{epoch: 0, version: "0:0", release: "0-0"}, false}, {"0:0-0:0-0", version{epoch: 0, version: "0", release: "0:0-0"}, false}, // Test version with leading and trailing spaces {" 0:0-1", version{epoch: 0, version: "0", release: "1"}, false}, {"0:0-1 ", version{epoch: 0, version: "0", release: "1"}, false}, {" 0:0-1 ", version{epoch: 0, version: "0", release: "1"}, false}, // Test empty version {"", version{}, true}, {" ", version{}, true}, {"0:", version{}, true}, // Test version with embedded spaces {"0:0 0-1", version{}, true}, // Test version with negative epoch {"-1:0-1", version{}, true}, // Test invalid characters in epoch {"a:0-0", version{}, true}, {"A:0-0", version{}, true}, // Test version not starting with a digit {"0:abc3-0", version{epoch: 0, version: "abc3", release: "0"}, false}, } for _, c := range cases { v, err := newVersion(c.str) if c.err { assert.Error(t, err, "When parsing '%s'", c.str) } else { assert.Nil(t, err, "When parsing '%s'", c.str) } assert.Equal(t, c.ver, v, "When parsing '%s'", c.str) } } func TestParseAndCompare(t *testing.T) { cases := []struct { v1 string expected int v2 string }{ // Oracle Linux corner cases. {"2.9.1-6.0.1.el7_2.3", GREATER, "2.9.1-6.el7_2.3"}, {"3.10.0-327.28.3.el7", GREATER, "3.10.0-327.el7"}, {"3.14.3-23.3.el6_8", GREATER, "3.14.3-23.el6_7"}, {"2.23.2-22.el7_1", LESS, "2.23.2-22.el7_1.1"}, // Tests imported from tests/rpmvercmp.at {"1.0", EQUAL, "1.0"}, {"1.0", LESS, "2.0"}, {"2.0", GREATER, "1.0"}, {"2.0.1", EQUAL, "2.0.1"}, {"2.0", LESS, "2.0.1"}, {"2.0.1", GREATER, "2.0"}, {"2.0.1a", EQUAL, "2.0.1a"}, {"2.0.1a", GREATER, "2.0.1"}, {"2.0.1", LESS, "2.0.1a"}, {"5.5p1", EQUAL, "5.5p1"}, {"5.5p1", LESS, "5.5p2"}, {"5.5p2", GREATER, "5.5p1"}, {"5.5p10", EQUAL, "5.5p10"}, {"5.5p1", LESS, "5.5p10"}, {"5.5p10", GREATER, "5.5p1"}, {"10xyz", LESS, "10.1xyz"}, {"10.1xyz", GREATER, "10xyz"}, {"xyz10", EQUAL, "xyz10"}, {"xyz10", LESS, "xyz10.1"}, {"xyz10.1", GREATER, "xyz10"}, {"xyz.4", EQUAL, "xyz.4"}, {"xyz.4", LESS, "8"}, {"8", GREATER, "xyz.4"}, {"xyz.4", LESS, "2"}, {"2", GREATER, "xyz.4"}, {"5.5p2", LESS, "5.6p1"}, {"5.6p1", GREATER, "5.5p2"}, {"5.6p1", LESS, "6.5p1"}, {"6.5p1", GREATER, "5.6p1"}, {"6.0.rc1", GREATER, "6.0"}, {"6.0", LESS, "6.0.rc1"}, {"10b2", GREATER, "10a1"}, {"10a2", LESS, "10b2"}, {"1.0aa", EQUAL, "1.0aa"}, {"1.0a", LESS, "1.0aa"}, {"1.0aa", GREATER, "1.0a"}, {"10.0001", EQUAL, "10.0001"}, {"10.0001", EQUAL, "10.1"}, {"10.1", EQUAL, "10.0001"}, {"10.0001", LESS, "10.0039"}, {"10.0039", GREATER, "10.0001"}, {"4.999.9", LESS, "5.0"}, {"5.0", GREATER, "4.999.9"}, {"20101121", EQUAL, "20101121"}, {"20101121", LESS, "20101122"}, {"20101122", GREATER, "20101121"}, {"2_0", EQUAL, "2_0"}, {"2.0", EQUAL, "2_0"}, {"2_0", EQUAL, "2.0"}, {"a", EQUAL, "a"}, {"a+", EQUAL, "a+"}, {"a+", EQUAL, "a_"}, {"a_", EQUAL, "a+"}, {"+a", EQUAL, "+a"}, {"+a", EQUAL, "_a"}, {"_a", EQUAL, "+a"}, {"+_", EQUAL, "+_"}, {"_+", EQUAL, "+_"}, {"_+", EQUAL, "_+"}, {"+", EQUAL, "_"}, {"_", EQUAL, "+"}, {"1.0~rc1", EQUAL, "1.0~rc1"}, {"1.0~rc1", LESS, "1.0"}, {"1.0", GREATER, "1.0~rc1"}, {"1.0~rc1", LESS, "1.0~rc2"}, {"1.0~rc2", GREATER, "1.0~rc1"}, {"1.0~rc1~git123", EQUAL, "1.0~rc1~git123"}, {"1.0~rc1~git123", LESS, "1.0~rc1"}, {"1.0~rc1", GREATER, "1.0~rc1~git123"}, {"1~", GREATER, "1~~"}, {"2~", GREATER, "1"}, {"1.0", GREATER, "1.0-~"}, {"1.0", LESS, "1.0-1~"}, {"~", GREATER, "~~"}, } var ( p parser cmp int err error ) for _, c := range cases { cmp, err = p.Compare(c.v1, c.v2) assert.Nil(t, err) assert.Equal(t, c.expected, cmp, "%s vs. %s, = %d, expected %d", c.v1, c.v2, cmp, c.expected) cmp, err = p.Compare(c.v2, c.v1) assert.Nil(t, err) assert.Equal(t, -c.expected, cmp, "%s vs. %s, = %d, expected %d", c.v2, c.v1, cmp, -c.expected) } }