github.com/rogpeppe/juju@v0.0.0-20140613142852-6337964b789e/version/version_test.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package version_test
     5  
     6  import (
     7  	"encoding/json"
     8  	"io/ioutil"
     9  	"path/filepath"
    10  	"runtime"
    11  	"strings"
    12  	stdtesting "testing"
    13  
    14  	"labix.org/v2/mgo/bson"
    15  	gc "launchpad.net/gocheck"
    16  	"launchpad.net/goyaml"
    17  
    18  	"github.com/juju/juju/testing"
    19  	"github.com/juju/juju/version"
    20  )
    21  
    22  type suite struct {
    23  	testing.BaseSuite
    24  }
    25  
    26  var _ = gc.Suite(&suite{})
    27  
    28  func Test(t *stdtesting.T) {
    29  	gc.TestingT(t)
    30  }
    31  
    32  // N.B. The FORCE-VERSION logic is tested in the environs package.
    33  
    34  func (*suite) TestCompare(c *gc.C) {
    35  	cmpTests := []struct {
    36  		v1, v2  string
    37  		compare int
    38  	}{
    39  		{"1.0.0", "1.0.0", 0},
    40  		{"01.0.0", "1.0.0", 0},
    41  		{"10.0.0", "9.0.0", 1},
    42  		{"1.0.0", "1.0.1", -1},
    43  		{"1.0.1", "1.0.0", 1},
    44  		{"1.0.0", "1.1.0", -1},
    45  		{"1.1.0", "1.0.0", 1},
    46  		{"1.0.0", "2.0.0", -1},
    47  		{"1.2-alpha1", "1.2.0", -1},
    48  		{"1.2-alpha2", "1.2-alpha1", 1},
    49  		{"1.2-alpha2.1", "1.2-alpha2", 1},
    50  		{"1.2-alpha2.2", "1.2-alpha2.1", 1},
    51  		{"1.2-beta1", "1.2-alpha1", 1},
    52  		{"1.2-beta1", "1.2-alpha2.1", 1},
    53  		{"1.2-beta1", "1.2.0", -1},
    54  		{"1.2.1", "1.2.0", 1},
    55  		{"2.0.0", "1.0.0", 1},
    56  		{"2.0.0.0", "2.0.0", 0},
    57  		{"2.0.0.0", "2.0.0.0", 0},
    58  		{"2.0.0.1", "2.0.0.0", 1},
    59  		{"2.0.1.10", "2.0.0.0", 1},
    60  	}
    61  
    62  	for i, test := range cmpTests {
    63  		c.Logf("test %d", i)
    64  		v1, err := version.Parse(test.v1)
    65  		c.Assert(err, gc.IsNil)
    66  		v2, err := version.Parse(test.v2)
    67  		c.Assert(err, gc.IsNil)
    68  		compare := v1.Compare(v2)
    69  		c.Check(compare, gc.Equals, test.compare)
    70  		// Check that reversing the operands has
    71  		// the expected result.
    72  		compare = v2.Compare(v1)
    73  		c.Check(compare, gc.Equals, -test.compare)
    74  	}
    75  }
    76  
    77  var parseTests = []struct {
    78  	v      string
    79  	err    string
    80  	expect version.Number
    81  	dev    bool
    82  }{{
    83  	v: "0.0.0",
    84  }, {
    85  	v:      "0.0.1",
    86  	expect: version.Number{Major: 0, Minor: 0, Patch: 1},
    87  }, {
    88  	v:      "0.0.2",
    89  	expect: version.Number{Major: 0, Minor: 0, Patch: 2},
    90  }, {
    91  	v:      "0.1.0",
    92  	expect: version.Number{Major: 0, Minor: 1, Patch: 0},
    93  	dev:    true,
    94  }, {
    95  	v:      "0.2.3",
    96  	expect: version.Number{Major: 0, Minor: 2, Patch: 3},
    97  }, {
    98  	v:      "1.0.0",
    99  	expect: version.Number{Major: 1, Minor: 0, Patch: 0},
   100  }, {
   101  	v:      "10.234.3456",
   102  	expect: version.Number{Major: 10, Minor: 234, Patch: 3456},
   103  }, {
   104  	v:      "10.234.3456.1",
   105  	expect: version.Number{Major: 10, Minor: 234, Patch: 3456, Build: 1},
   106  	dev:    true,
   107  }, {
   108  	v:      "10.234.3456.64",
   109  	expect: version.Number{Major: 10, Minor: 234, Patch: 3456, Build: 64},
   110  	dev:    true,
   111  }, {
   112  	v:      "10.235.3456",
   113  	expect: version.Number{Major: 10, Minor: 235, Patch: 3456},
   114  }, {
   115  	v:      "1.21-alpha1",
   116  	expect: version.Number{Major: 1, Minor: 21, Patch: 1, Tag: "alpha"},
   117  	dev:    true,
   118  }, {
   119  	v:      "1.21-alpha1.1",
   120  	expect: version.Number{Major: 1, Minor: 21, Patch: 1, Tag: "alpha", Build: 1},
   121  	dev:    true,
   122  }, {
   123  	v:      "1.21.0",
   124  	expect: version.Number{Major: 1, Minor: 21},
   125  }, {
   126  	v:   "1234567890.2.1",
   127  	err: "invalid version.*",
   128  }, {
   129  	v:   "0.2..1",
   130  	err: "invalid version.*",
   131  }, {
   132  	v:   "1.21.alpha1",
   133  	err: "invalid version.*",
   134  }, {
   135  	v:   "1.21-alpha",
   136  	err: "invalid version.*",
   137  }, {
   138  	v:   "1.21-alpha1beta",
   139  	err: "invalid version.*",
   140  }, {
   141  	v:   "1.21-alpha-dev",
   142  	err: "invalid version.*",
   143  }}
   144  
   145  func (*suite) TestParse(c *gc.C) {
   146  	for i, test := range parseTests {
   147  		c.Logf("test %d", i)
   148  		got, err := version.Parse(test.v)
   149  		if test.err != "" {
   150  			c.Assert(err, gc.ErrorMatches, test.err)
   151  		} else {
   152  			c.Assert(err, gc.IsNil)
   153  			c.Assert(got, gc.Equals, test.expect)
   154  			c.Check(got.IsDev(), gc.Equals, test.dev)
   155  			c.Check(got.String(), gc.Equals, test.v)
   156  		}
   157  	}
   158  }
   159  
   160  func binaryVersion(major, minor, patch, build int, tag, series, arch string) version.Binary {
   161  	return version.Binary{
   162  		Number: version.Number{
   163  			Major: major,
   164  			Minor: minor,
   165  			Patch: patch,
   166  			Build: build,
   167  			Tag:   tag,
   168  		},
   169  		Series: series,
   170  		Arch:   arch,
   171  	}
   172  }
   173  
   174  func (*suite) TestParseBinary(c *gc.C) {
   175  	parseBinaryTests := []struct {
   176  		v      string
   177  		err    string
   178  		expect version.Binary
   179  	}{{
   180  		v:      "1.2.3-a-b",
   181  		expect: binaryVersion(1, 2, 3, 0, "", "a", "b"),
   182  	}, {
   183  		v:      "1.2.3.4-a-b",
   184  		expect: binaryVersion(1, 2, 3, 4, "", "a", "b"),
   185  	}, {
   186  		v:      "1.2-alpha3-a-b",
   187  		expect: binaryVersion(1, 2, 3, 0, "alpha", "a", "b"),
   188  	}, {
   189  		v:      "1.2-alpha3.4-a-b",
   190  		expect: binaryVersion(1, 2, 3, 4, "alpha", "a", "b"),
   191  	}, {
   192  		v:   "1.2.3",
   193  		err: "invalid binary version.*",
   194  	}, {
   195  		v:   "1.2-beta1",
   196  		err: "invalid binary version.*",
   197  	}, {
   198  		v:   "1.2.3--b",
   199  		err: "invalid binary version.*",
   200  	}, {
   201  		v:   "1.2.3-a-",
   202  		err: "invalid binary version.*",
   203  	}}
   204  
   205  	for i, test := range parseBinaryTests {
   206  		c.Logf("test 1: %d", i)
   207  		got, err := version.ParseBinary(test.v)
   208  		if test.err != "" {
   209  			c.Assert(err, gc.ErrorMatches, test.err)
   210  		} else {
   211  			c.Assert(err, gc.IsNil)
   212  			c.Assert(got, gc.Equals, test.expect)
   213  		}
   214  	}
   215  
   216  	for i, test := range parseTests {
   217  		c.Logf("test 2: %d", i)
   218  		v := test.v + "-a-b"
   219  		got, err := version.ParseBinary(v)
   220  		expect := version.Binary{
   221  			Number: test.expect,
   222  			Series: "a",
   223  			Arch:   "b",
   224  		}
   225  		if test.err != "" {
   226  			c.Assert(err, gc.ErrorMatches, strings.Replace(test.err, "version", "binary version", 1))
   227  		} else {
   228  			c.Assert(err, gc.IsNil)
   229  			c.Assert(got, gc.Equals, expect)
   230  			c.Check(got.IsDev(), gc.Equals, test.dev)
   231  		}
   232  	}
   233  }
   234  
   235  var marshallers = []struct {
   236  	name      string
   237  	marshal   func(interface{}) ([]byte, error)
   238  	unmarshal func([]byte, interface{}) error
   239  }{{
   240  	"json",
   241  	json.Marshal,
   242  	json.Unmarshal,
   243  }, {
   244  	"bson",
   245  	bson.Marshal,
   246  	bson.Unmarshal,
   247  }, {
   248  	"yaml",
   249  	goyaml.Marshal,
   250  	goyaml.Unmarshal,
   251  }}
   252  
   253  func (*suite) TestBinaryMarshalUnmarshal(c *gc.C) {
   254  	for _, m := range marshallers {
   255  		c.Logf("encoding %v", m.name)
   256  		type doc struct {
   257  			Version *version.Binary
   258  		}
   259  		// Work around goyaml bug #1096149
   260  		// SetYAML is not called for non-pointer fields.
   261  		bp := version.MustParseBinary("1.2.3-foo-bar")
   262  		v := doc{&bp}
   263  		data, err := m.marshal(&v)
   264  		c.Assert(err, gc.IsNil)
   265  		var bv doc
   266  		err = m.unmarshal(data, &bv)
   267  		c.Assert(err, gc.IsNil)
   268  		c.Assert(bv, gc.DeepEquals, v)
   269  	}
   270  }
   271  
   272  func (*suite) TestNumberMarshalUnmarshal(c *gc.C) {
   273  	for _, m := range marshallers {
   274  		c.Logf("encoding %v", m.name)
   275  		type doc struct {
   276  			Version *version.Number
   277  		}
   278  		// Work around goyaml bug #1096149
   279  		// SetYAML is not called for non-pointer fields.
   280  		np := version.MustParse("1.2.3")
   281  		v := doc{&np}
   282  		data, err := m.marshal(&v)
   283  		c.Assert(err, gc.IsNil)
   284  		var nv doc
   285  		err = m.unmarshal(data, &nv)
   286  		c.Assert(err, gc.IsNil)
   287  		c.Assert(nv, gc.DeepEquals, v)
   288  	}
   289  }
   290  
   291  func (*suite) TestParseMajorMinor(c *gc.C) {
   292  	parseMajorMinorTests := []struct {
   293  		v           string
   294  		err         string
   295  		expectMajor int
   296  		expectMinor int
   297  	}{{
   298  		v:           "1.2",
   299  		expectMajor: 1,
   300  		expectMinor: 2,
   301  	}, {
   302  		v:           "1",
   303  		expectMajor: 1,
   304  		expectMinor: -1,
   305  	}, {
   306  		v:   "1.2.3",
   307  		err: "invalid major.minor version number 1.2.3",
   308  	}, {
   309  		v:   "blah",
   310  		err: `invalid major version number blah: strconv.ParseInt: parsing "blah": invalid syntax`,
   311  	}}
   312  
   313  	for i, test := range parseMajorMinorTests {
   314  		c.Logf("test %d", i)
   315  		major, minor, err := version.ParseMajorMinor(test.v)
   316  		if test.err != "" {
   317  			c.Check(err, gc.ErrorMatches, test.err)
   318  		} else {
   319  			c.Check(err, gc.IsNil)
   320  			c.Check(major, gc.Equals, test.expectMajor)
   321  			c.Check(minor, gc.Equals, test.expectMinor)
   322  		}
   323  	}
   324  }
   325  
   326  func (s *suite) TestUseFastLXC(c *gc.C) {
   327  	for i, test := range []struct {
   328  		message        string
   329  		releaseContent string
   330  		expected       string
   331  	}{{
   332  		message: "missing release file",
   333  	}, {
   334  		message:        "missing prefix in file",
   335  		releaseContent: "some junk\nand more junk",
   336  	}, {
   337  		message: "precise release",
   338  		releaseContent: `
   339  DISTRIB_ID=Ubuntu
   340  DISTRIB_RELEASE=12.04
   341  DISTRIB_CODENAME=precise
   342  DISTRIB_DESCRIPTION="Ubuntu 12.04.3 LTS"
   343  `,
   344  		expected: "12.04",
   345  	}, {
   346  		message: "trusty release",
   347  		releaseContent: `
   348  DISTRIB_ID=Ubuntu
   349  DISTRIB_RELEASE=14.04
   350  DISTRIB_CODENAME=trusty
   351  DISTRIB_DESCRIPTION="Ubuntu Trusty Tahr (development branch)"
   352  `,
   353  		expected: "14.04",
   354  	}, {
   355  		message:        "minimal trusty release",
   356  		releaseContent: `DISTRIB_RELEASE=14.04`,
   357  		expected:       "14.04",
   358  	}, {
   359  		message:        "minimal unstable unicorn",
   360  		releaseContent: `DISTRIB_RELEASE=14.10`,
   361  		expected:       "14.10",
   362  	}, {
   363  		message:        "minimal jaunty",
   364  		releaseContent: `DISTRIB_RELEASE=9.10`,
   365  		expected:       "9.10",
   366  	}} {
   367  		c.Logf("%v: %v", i, test.message)
   368  		filename := filepath.Join(c.MkDir(), "lsbRelease")
   369  		s.PatchValue(version.LSBReleaseFileVar, filename)
   370  		if test.releaseContent != "" {
   371  			err := ioutil.WriteFile(filename, []byte(test.releaseContent+"\n"), 0644)
   372  			c.Assert(err, gc.IsNil)
   373  		}
   374  		value := version.ReleaseVersion()
   375  		c.Assert(value, gc.Equals, test.expected)
   376  	}
   377  }
   378  
   379  func (s *suite) TestCompiler(c *gc.C) {
   380  	c.Assert(version.Compiler, gc.Equals, runtime.Compiler)
   381  }