github.com/golang/dep@v0.5.4/gps/constraint_test.go (about)

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package gps
     6  
     7  import (
     8  	"fmt"
     9  	"testing"
    10  
    11  	"github.com/golang/dep/gps/internal/pb"
    12  	"github.com/golang/protobuf/proto"
    13  	"github.com/pkg/errors"
    14  )
    15  
    16  // gu - helper func for stringifying what we assume is a VersionPair (otherwise
    17  // will panic), but is given as a Constraint
    18  func gu(v Constraint) string {
    19  	return fmt.Sprintf("%q at rev %q", v, v.(PairedVersion).Revision())
    20  }
    21  
    22  func TestBranchConstraintOps(t *testing.T) {
    23  	v1 := NewBranch("master").(branchVersion)
    24  	v2 := NewBranch("test").(branchVersion)
    25  
    26  	if !v1.MatchesAny(any) {
    27  		t.Errorf("Branches should always match the any constraint")
    28  	}
    29  	if v1.Intersect(any) != v1 {
    30  		t.Errorf("Branches should always return self when intersecting the any constraint, but got %s", v1.Intersect(any))
    31  	}
    32  
    33  	if v1.MatchesAny(none) {
    34  		t.Errorf("Branches should never match the none constraint")
    35  	}
    36  	if v1.Intersect(none) != none {
    37  		t.Errorf("Branches should always return none when intersecting the none constraint, but got %s", v1.Intersect(none))
    38  	}
    39  
    40  	if v1.Matches(v2) {
    41  		t.Errorf("%s should not match %s", v1, v2)
    42  	}
    43  
    44  	if v1.MatchesAny(v2) {
    45  		t.Errorf("%s should not allow any matches when combined with %s", v1, v2)
    46  	}
    47  
    48  	if v1.Intersect(v2) != none {
    49  		t.Errorf("Intersection of %s with %s should result in empty set", v1, v2)
    50  	}
    51  
    52  	// Add rev to one
    53  	snuffster := Revision("snuffleupagus")
    54  	v3 := v1.Pair(snuffster).(versionPair)
    55  	if v2.Matches(v3) {
    56  		t.Errorf("%s should not match %s", v2, gu(v3))
    57  	}
    58  	if v3.Matches(v2) {
    59  		t.Errorf("%s should not match %s", gu(v3), v2)
    60  	}
    61  
    62  	if v2.MatchesAny(v3) {
    63  		t.Errorf("%s should not allow any matches when combined with %s", v2, gu(v3))
    64  	}
    65  	if v3.MatchesAny(v2) {
    66  		t.Errorf("%s should not allow any matches when combined with %s", v2, gu(v3))
    67  	}
    68  
    69  	if v2.Intersect(v3) != none {
    70  		t.Errorf("Intersection of %s with %s should result in empty set", v2, gu(v3))
    71  	}
    72  	if v3.Intersect(v2) != none {
    73  		t.Errorf("Intersection of %s with %s should result in empty set", gu(v3), v2)
    74  	}
    75  
    76  	// Add different rev to the other
    77  	v4 := v2.Pair(Revision("cookie monster")).(versionPair)
    78  	if v4.Matches(v3) {
    79  		t.Errorf("%s should not match %s", gu(v4), gu(v3))
    80  	}
    81  	if v3.Matches(v4) {
    82  		t.Errorf("%s should not match %s", gu(v3), gu(v4))
    83  	}
    84  
    85  	if v4.MatchesAny(v3) {
    86  		t.Errorf("%s should not allow any matches when combined with %s", gu(v4), gu(v3))
    87  	}
    88  	if v3.MatchesAny(v4) {
    89  		t.Errorf("%s should not allow any matches when combined with %s", gu(v4), gu(v3))
    90  	}
    91  
    92  	if v4.Intersect(v3) != none {
    93  		t.Errorf("Intersection of %s with %s should result in empty set", gu(v4), gu(v3))
    94  	}
    95  	if v3.Intersect(v4) != none {
    96  		t.Errorf("Intersection of %s with %s should result in empty set", gu(v3), gu(v4))
    97  	}
    98  
    99  	// Now add same rev to different branches
   100  	v5 := v2.Pair(Revision("snuffleupagus")).(versionPair)
   101  	if !v5.Matches(v3) {
   102  		t.Errorf("%s should match %s", gu(v5), gu(v3))
   103  	}
   104  	if !v3.Matches(v5) {
   105  		t.Errorf("%s should match %s", gu(v3), gu(v5))
   106  	}
   107  
   108  	if !v5.MatchesAny(v3) {
   109  		t.Errorf("%s should allow some matches when combined with %s", gu(v5), gu(v3))
   110  	}
   111  	if !v3.MatchesAny(v5) {
   112  		t.Errorf("%s should allow some matches when combined with %s", gu(v5), gu(v3))
   113  	}
   114  
   115  	if v5.Intersect(v3) != snuffster {
   116  		t.Errorf("Intersection of %s with %s should return underlying rev", gu(v5), gu(v3))
   117  	}
   118  	if v3.Intersect(v5) != snuffster {
   119  		t.Errorf("Intersection of %s with %s should return underlying rev", gu(v3), gu(v5))
   120  	}
   121  
   122  	// Set up for cross-type constraint ops
   123  	cookie := Revision("cookie monster")
   124  	o1 := NewVersion("master").(plainVersion)
   125  	o2 := NewVersion("1.0.0").(semVersion)
   126  	o3 := o1.Pair(cookie).(versionPair)
   127  	o4 := o2.Pair(cookie).(versionPair)
   128  	v6 := v1.Pair(cookie).(versionPair)
   129  
   130  	if v1.Matches(o1) {
   131  		t.Errorf("%s (branch) should not match %s (version) across types", v1, o1)
   132  	}
   133  
   134  	if v1.MatchesAny(o1) {
   135  		t.Errorf("%s (branch) should not allow any matches when combined with %s (version)", v1, o1)
   136  	}
   137  
   138  	if v1.Intersect(o1) != none {
   139  		t.Errorf("Intersection of %s (branch) with %s (version) should result in empty set", v1, o1)
   140  	}
   141  
   142  	if v1.Matches(o2) {
   143  		t.Errorf("%s (branch) should not match %s (semver) across types", v1, o2)
   144  	}
   145  
   146  	if v1.MatchesAny(o2) {
   147  		t.Errorf("%s (branch) should not allow any matches when combined with %s (semver)", v1, o2)
   148  	}
   149  
   150  	if v1.Intersect(o2) != none {
   151  		t.Errorf("Intersection of %s (branch) with %s (semver) should result in empty set", v1, o2)
   152  	}
   153  
   154  	if v1.Matches(o3) {
   155  		t.Errorf("%s (branch) should not match %s (version) across types", v1, gu(o3))
   156  	}
   157  
   158  	if v1.MatchesAny(o3) {
   159  		t.Errorf("%s (branch) should not allow any matches when combined with %s (version)", v1, gu(o3))
   160  	}
   161  
   162  	if v1.Intersect(o3) != none {
   163  		t.Errorf("Intersection of %s (branch) with %s (version) should result in empty set", v1, gu(o3))
   164  	}
   165  
   166  	if v1.Matches(o4) {
   167  		t.Errorf("%s (branch) should not match %s (semver) across types", v1, gu(o4))
   168  	}
   169  
   170  	if v1.MatchesAny(o4) {
   171  		t.Errorf("%s (branch) should not allow any matches when combined with %s (semver)", v1, gu(o4))
   172  	}
   173  
   174  	if v1.Intersect(o4) != none {
   175  		t.Errorf("Intersection of %s (branch) with %s (semver) should result in empty set", v1, gu(o4))
   176  	}
   177  
   178  	if !v6.Matches(o3) {
   179  		t.Errorf("%s (branch) should match %s (version) across types due to shared rev", gu(v6), gu(o3))
   180  	}
   181  
   182  	if !v6.MatchesAny(o3) {
   183  		t.Errorf("%s (branch) should allow some matches when combined with %s (version) across types due to shared rev", gu(v6), gu(o3))
   184  	}
   185  
   186  	if v6.Intersect(o3) != cookie {
   187  		t.Errorf("Intersection of %s (branch) with %s (version) should return shared underlying rev", gu(v6), gu(o3))
   188  	}
   189  
   190  	if !v6.Matches(o4) {
   191  		t.Errorf("%s (branch) should match %s (version) across types due to shared rev", gu(v6), gu(o4))
   192  	}
   193  
   194  	if !v6.MatchesAny(o4) {
   195  		t.Errorf("%s (branch) should allow some matches when combined with %s (version) across types due to shared rev", gu(v6), gu(o4))
   196  	}
   197  
   198  	if v6.Intersect(o4) != cookie {
   199  		t.Errorf("Intersection of %s (branch) with %s (version) should return shared underlying rev", gu(v6), gu(o4))
   200  	}
   201  }
   202  
   203  func TestVersionConstraintOps(t *testing.T) {
   204  	v1 := NewVersion("ab123").(plainVersion)
   205  	v2 := NewVersion("b2a13").(plainVersion)
   206  
   207  	if !v1.MatchesAny(any) {
   208  		t.Errorf("Versions should always match the any constraint")
   209  	}
   210  	if v1.Intersect(any) != v1 {
   211  		t.Errorf("Versions should always return self when intersecting the any constraint, but got %s", v1.Intersect(any))
   212  	}
   213  
   214  	if v1.MatchesAny(none) {
   215  		t.Errorf("Versions should never match the none constraint")
   216  	}
   217  	if v1.Intersect(none) != none {
   218  		t.Errorf("Versions should always return none when intersecting the none constraint, but got %s", v1.Intersect(none))
   219  	}
   220  
   221  	if v1.Matches(v2) {
   222  		t.Errorf("%s should not match %s", v1, v2)
   223  	}
   224  
   225  	if v1.MatchesAny(v2) {
   226  		t.Errorf("%s should not allow any matches when combined with %s", v1, v2)
   227  	}
   228  
   229  	if v1.Intersect(v2) != none {
   230  		t.Errorf("Intersection of %s with %s should result in empty set", v1, v2)
   231  	}
   232  
   233  	// Add rev to one
   234  	snuffster := Revision("snuffleupagus")
   235  	v3 := v1.Pair(snuffster).(versionPair)
   236  	if v2.Matches(v3) {
   237  		t.Errorf("%s should not match %s", v2, gu(v3))
   238  	}
   239  	if v3.Matches(v2) {
   240  		t.Errorf("%s should not match %s", gu(v3), v2)
   241  	}
   242  
   243  	if v2.MatchesAny(v3) {
   244  		t.Errorf("%s should not allow any matches when combined with %s", v2, gu(v3))
   245  	}
   246  	if v3.MatchesAny(v2) {
   247  		t.Errorf("%s should not allow any matches when combined with %s", v2, gu(v3))
   248  	}
   249  
   250  	if v2.Intersect(v3) != none {
   251  		t.Errorf("Intersection of %s with %s should result in empty set", v2, gu(v3))
   252  	}
   253  	if v3.Intersect(v2) != none {
   254  		t.Errorf("Intersection of %s with %s should result in empty set", gu(v3), v2)
   255  	}
   256  
   257  	// Add different rev to the other
   258  	v4 := v2.Pair(Revision("cookie monster")).(versionPair)
   259  	if v4.Matches(v3) {
   260  		t.Errorf("%s should not match %s", gu(v4), gu(v3))
   261  	}
   262  	if v3.Matches(v4) {
   263  		t.Errorf("%s should not match %s", gu(v3), gu(v4))
   264  	}
   265  
   266  	if v4.MatchesAny(v3) {
   267  		t.Errorf("%s should not allow any matches when combined with %s", gu(v4), gu(v3))
   268  	}
   269  	if v3.MatchesAny(v4) {
   270  		t.Errorf("%s should not allow any matches when combined with %s", gu(v4), gu(v3))
   271  	}
   272  
   273  	if v4.Intersect(v3) != none {
   274  		t.Errorf("Intersection of %s with %s should result in empty set", gu(v4), gu(v3))
   275  	}
   276  	if v3.Intersect(v4) != none {
   277  		t.Errorf("Intersection of %s with %s should result in empty set", gu(v3), gu(v4))
   278  	}
   279  
   280  	// Now add same rev to different versions, and things should line up
   281  	v5 := v2.Pair(Revision("snuffleupagus")).(versionPair)
   282  	if !v5.Matches(v3) {
   283  		t.Errorf("%s should match %s", gu(v5), gu(v3))
   284  	}
   285  	if !v3.Matches(v5) {
   286  		t.Errorf("%s should match %s", gu(v3), gu(v5))
   287  	}
   288  
   289  	if !v5.MatchesAny(v3) {
   290  		t.Errorf("%s should allow some matches when combined with %s", gu(v5), gu(v3))
   291  	}
   292  	if !v3.MatchesAny(v5) {
   293  		t.Errorf("%s should allow some matches when combined with %s", gu(v5), gu(v3))
   294  	}
   295  
   296  	if v5.Intersect(v3) != snuffster {
   297  		t.Errorf("Intersection of %s with %s should return underlying rev", gu(v5), gu(v3))
   298  	}
   299  	if v3.Intersect(v5) != snuffster {
   300  		t.Errorf("Intersection of %s with %s should return underlying rev", gu(v3), gu(v5))
   301  	}
   302  
   303  	// Set up for cross-type constraint ops
   304  	cookie := Revision("cookie monster")
   305  	o1 := NewBranch("master").(branchVersion)
   306  	o2 := NewVersion("1.0.0").(semVersion)
   307  	o3 := o1.Pair(cookie).(versionPair)
   308  	o4 := o2.Pair(cookie).(versionPair)
   309  	v6 := v1.Pair(cookie).(versionPair)
   310  
   311  	if v1.Matches(o1) {
   312  		t.Errorf("%s (version) should not match %s (branch) across types", v1, o1)
   313  	}
   314  
   315  	if v1.MatchesAny(o1) {
   316  		t.Errorf("%s (version) should not allow any matches when combined with %s (branch)", v1, o1)
   317  	}
   318  
   319  	if v1.Intersect(o1) != none {
   320  		t.Errorf("Intersection of %s (version) with %s (branch) should result in empty set", v1, o1)
   321  	}
   322  
   323  	if v1.Matches(o2) {
   324  		t.Errorf("%s (version) should not match %s (semver) across types", v1, o2)
   325  	}
   326  
   327  	if v1.MatchesAny(o2) {
   328  		t.Errorf("%s (version) should not allow any matches when combined with %s (semver)", v1, o2)
   329  	}
   330  
   331  	if v1.Intersect(o2) != none {
   332  		t.Errorf("Intersection of %s (version) with %s (semver) should result in empty set", v1, o2)
   333  	}
   334  
   335  	if v1.Matches(o3) {
   336  		t.Errorf("%s (version) should not match %s (branch) across types", v1, gu(o3))
   337  	}
   338  
   339  	if v1.MatchesAny(o3) {
   340  		t.Errorf("%s (version) should not allow any matches when combined with %s (branch)", v1, gu(o3))
   341  	}
   342  
   343  	if v1.Intersect(o3) != none {
   344  		t.Errorf("Intersection of %s (version) with %s (branch) should result in empty set", v1, gu(o3))
   345  	}
   346  
   347  	if v1.Matches(o4) {
   348  		t.Errorf("%s (version) should not match %s (semver) across types", v1, gu(o4))
   349  	}
   350  
   351  	if v1.MatchesAny(o4) {
   352  		t.Errorf("%s (version) should not allow any matches when combined with %s (semver)", v1, gu(o4))
   353  	}
   354  
   355  	if v1.Intersect(o4) != none {
   356  		t.Errorf("Intersection of %s (version) with %s (semver) should result in empty set", v1, gu(o4))
   357  	}
   358  
   359  	if !v6.Matches(o3) {
   360  		t.Errorf("%s (version) should match %s (branch) across types due to shared rev", gu(v6), gu(o3))
   361  	}
   362  
   363  	if !v6.MatchesAny(o3) {
   364  		t.Errorf("%s (version) should allow some matches when combined with %s (branch) across types due to shared rev", gu(v6), gu(o3))
   365  	}
   366  
   367  	if v6.Intersect(o3) != cookie {
   368  		t.Errorf("Intersection of %s (version) with %s (branch) should return shared underlying rev", gu(v6), gu(o3))
   369  	}
   370  
   371  	if !v6.Matches(o4) {
   372  		t.Errorf("%s (version) should match %s (branch) across types due to shared rev", gu(v6), gu(o4))
   373  	}
   374  
   375  	if !v6.MatchesAny(o4) {
   376  		t.Errorf("%s (version) should allow some matches when combined with %s (branch) across types due to shared rev", gu(v6), gu(o4))
   377  	}
   378  
   379  	if v6.Intersect(o4) != cookie {
   380  		t.Errorf("Intersection of %s (version) with %s (branch) should return shared underlying rev", gu(v6), gu(o4))
   381  	}
   382  }
   383  
   384  func TestSemverVersionConstraintOps(t *testing.T) {
   385  	v1 := NewVersion("1.0.0").(semVersion)
   386  	v2 := NewVersion("2.0.0").(semVersion)
   387  
   388  	if !v1.MatchesAny(any) {
   389  		t.Errorf("Semvers should always match the any constraint")
   390  	}
   391  	if v1.Intersect(any) != v1 {
   392  		t.Errorf("Semvers should always return self when intersecting the any constraint, but got %s", v1.Intersect(any))
   393  	}
   394  
   395  	if v1.MatchesAny(none) {
   396  		t.Errorf("Semvers should never match the none constraint")
   397  	}
   398  	if v1.Intersect(none) != none {
   399  		t.Errorf("Semvers should always return none when intersecting the none constraint, but got %s", v1.Intersect(none))
   400  	}
   401  
   402  	if v1.Matches(v2) {
   403  		t.Errorf("%s should not match %s", v1, v2)
   404  	}
   405  
   406  	if v1.MatchesAny(v2) {
   407  		t.Errorf("%s should not allow any matches when combined with %s", v1, v2)
   408  	}
   409  
   410  	if v1.Intersect(v2) != none {
   411  		t.Errorf("Intersection of %s with %s should result in empty set", v1, v2)
   412  	}
   413  
   414  	// Add rev to one
   415  	snuffster := Revision("snuffleupagus")
   416  	v3 := v1.Pair(snuffster).(versionPair)
   417  	if v2.Matches(v3) {
   418  		t.Errorf("%s should not match %s", v2, gu(v3))
   419  	}
   420  	if v3.Matches(v2) {
   421  		t.Errorf("%s should not match %s", gu(v3), v2)
   422  	}
   423  
   424  	if v2.MatchesAny(v3) {
   425  		t.Errorf("%s should not allow any matches when combined with %s", v2, gu(v3))
   426  	}
   427  	if v3.MatchesAny(v2) {
   428  		t.Errorf("%s should not allow any matches when combined with %s", v2, gu(v3))
   429  	}
   430  
   431  	if v2.Intersect(v3) != none {
   432  		t.Errorf("Intersection of %s with %s should result in empty set", v2, gu(v3))
   433  	}
   434  	if v3.Intersect(v2) != none {
   435  		t.Errorf("Intersection of %s with %s should result in empty set", gu(v3), v2)
   436  	}
   437  
   438  	// Add different rev to the other
   439  	v4 := v2.Pair(Revision("cookie monster")).(versionPair)
   440  	if v4.Matches(v3) {
   441  		t.Errorf("%s should not match %s", gu(v4), gu(v3))
   442  	}
   443  	if v3.Matches(v4) {
   444  		t.Errorf("%s should not match %s", gu(v3), gu(v4))
   445  	}
   446  
   447  	if v4.MatchesAny(v3) {
   448  		t.Errorf("%s should not allow any matches when combined with %s", gu(v4), gu(v3))
   449  	}
   450  	if v3.MatchesAny(v4) {
   451  		t.Errorf("%s should not allow any matches when combined with %s", gu(v4), gu(v3))
   452  	}
   453  
   454  	if v4.Intersect(v3) != none {
   455  		t.Errorf("Intersection of %s with %s should result in empty set", gu(v4), gu(v3))
   456  	}
   457  	if v3.Intersect(v4) != none {
   458  		t.Errorf("Intersection of %s with %s should result in empty set", gu(v3), gu(v4))
   459  	}
   460  
   461  	// Now add same rev to different versions, and things should line up
   462  	v5 := v2.Pair(Revision("snuffleupagus")).(versionPair)
   463  	if !v5.Matches(v3) {
   464  		t.Errorf("%s should match %s", gu(v5), gu(v3))
   465  	}
   466  	if !v3.Matches(v5) {
   467  		t.Errorf("%s should match %s", gu(v3), gu(v5))
   468  	}
   469  
   470  	if !v5.MatchesAny(v3) {
   471  		t.Errorf("%s should allow some matches when combined with %s", gu(v5), gu(v3))
   472  	}
   473  	if !v3.MatchesAny(v5) {
   474  		t.Errorf("%s should allow some matches when combined with %s", gu(v5), gu(v3))
   475  	}
   476  
   477  	if v5.Intersect(v3) != snuffster {
   478  		t.Errorf("Intersection of %s with %s should return underlying rev", gu(v5), gu(v3))
   479  	}
   480  	if v3.Intersect(v5) != snuffster {
   481  		t.Errorf("Intersection of %s with %s should return underlying rev", gu(v3), gu(v5))
   482  	}
   483  
   484  	// Set up for cross-type constraint ops
   485  	cookie := Revision("cookie monster")
   486  	o1 := NewBranch("master").(branchVersion)
   487  	o2 := NewVersion("ab123").(plainVersion)
   488  	o3 := o1.Pair(cookie).(versionPair)
   489  	o4 := o2.Pair(cookie).(versionPair)
   490  	v6 := v1.Pair(cookie).(versionPair)
   491  
   492  	if v1.Matches(o1) {
   493  		t.Errorf("%s (semver) should not match %s (branch) across types", v1, o1)
   494  	}
   495  
   496  	if v1.MatchesAny(o1) {
   497  		t.Errorf("%s (semver) should not allow any matches when combined with %s (branch)", v1, o1)
   498  	}
   499  
   500  	if v1.Intersect(o1) != none {
   501  		t.Errorf("Intersection of %s (semver) with %s (branch) should result in empty set", v1, o1)
   502  	}
   503  
   504  	if v1.Matches(o2) {
   505  		t.Errorf("%s (semver) should not match %s (version) across types", v1, o2)
   506  	}
   507  
   508  	if v1.MatchesAny(o2) {
   509  		t.Errorf("%s (semver) should not allow any matches when combined with %s (version)", v1, o2)
   510  	}
   511  
   512  	if v1.Intersect(o2) != none {
   513  		t.Errorf("Intersection of %s (semver) with %s (version) should result in empty set", v1, o2)
   514  	}
   515  
   516  	if v1.Matches(o3) {
   517  		t.Errorf("%s (semver) should not match %s (branch) across types", v1, gu(o3))
   518  	}
   519  
   520  	if v1.MatchesAny(o3) {
   521  		t.Errorf("%s (semver) should not allow any matches when combined with %s (branch)", v1, gu(o3))
   522  	}
   523  
   524  	if v1.Intersect(o3) != none {
   525  		t.Errorf("Intersection of %s (semver) with %s (branch) should result in empty set", v1, gu(o3))
   526  	}
   527  
   528  	if v1.Matches(o4) {
   529  		t.Errorf("%s (semver) should not match %s (version) across types", v1, gu(o4))
   530  	}
   531  
   532  	if v1.MatchesAny(o4) {
   533  		t.Errorf("%s (semver) should not allow any matches when combined with %s (version)", v1, gu(o4))
   534  	}
   535  
   536  	if v1.Intersect(o4) != none {
   537  		t.Errorf("Intersection of %s (semver) with %s (version) should result in empty set", v1, gu(o4))
   538  	}
   539  
   540  	if !v6.Matches(o3) {
   541  		t.Errorf("%s (semver) should match %s (branch) across types due to shared rev", gu(v6), gu(o3))
   542  	}
   543  
   544  	if !v6.MatchesAny(o3) {
   545  		t.Errorf("%s (semver) should allow some matches when combined with %s (branch) across types due to shared rev", gu(v6), gu(o3))
   546  	}
   547  
   548  	if v6.Intersect(o3) != cookie {
   549  		t.Errorf("Intersection of %s (semver) with %s (branch) should return shared underlying rev", gu(v6), gu(o3))
   550  	}
   551  
   552  	if !v6.Matches(o4) {
   553  		t.Errorf("%s (semver) should match %s (branch) across types due to shared rev", gu(v6), gu(o4))
   554  	}
   555  
   556  	if !v6.MatchesAny(o4) {
   557  		t.Errorf("%s (semver) should allow some matches when combined with %s (branch) across types due to shared rev", gu(v6), gu(o4))
   558  	}
   559  
   560  	if v6.Intersect(o4) != cookie {
   561  		t.Errorf("Intersection of %s (semver) with %s (branch) should return shared underlying rev", gu(v6), gu(o4))
   562  	}
   563  
   564  	// Regression check - make sure that semVersion -> semverConstraint works
   565  	// the same as verified in the other test
   566  	c1, _ := NewSemverConstraint("=1.0.0")
   567  	if !v1.MatchesAny(c1) {
   568  		t.Errorf("%s (semver) should allow some matches - itself - when combined with an equivalent semverConstraint", gu(v1))
   569  	}
   570  	if v1.Intersect(c1) != v1 {
   571  		t.Errorf("Intersection of %s (semver) with equivalent semver constraint should return self, got %s", gu(v1), v1.Intersect(c1))
   572  	}
   573  
   574  	if !v6.MatchesAny(c1) {
   575  		t.Errorf("%s (semver pair) should allow some matches - itself - when combined with an equivalent semverConstraint", gu(v6))
   576  	}
   577  	if v6.Intersect(c1) != v6 {
   578  		t.Errorf("Intersection of %s (semver pair) with equivalent semver constraint should return self, got %s", gu(v6), v6.Intersect(c1))
   579  	}
   580  
   581  }
   582  
   583  // The other test is about the semverVersion, this is about semverConstraint
   584  func TestSemverConstraintOps(t *testing.T) {
   585  	v1 := NewBranch("master").(branchVersion)
   586  	v2 := NewVersion("ab123").(plainVersion)
   587  	v3 := NewVersion("1.0.0").(semVersion)
   588  
   589  	fozzie := Revision("fozzie bear")
   590  	v4 := v1.Pair(fozzie).(versionPair)
   591  	v5 := v2.Pair(fozzie).(versionPair)
   592  	v6 := v3.Pair(fozzie).(versionPair)
   593  
   594  	// TODO(sdboyer) we can't use the same range as below b/c semver.rangeConstraint is
   595  	// still an incomparable type
   596  	c1, err := NewSemverConstraint("=1.0.0")
   597  	if err != nil {
   598  		t.Fatalf("Failed to create constraint: %s", err)
   599  	}
   600  
   601  	if !c1.MatchesAny(any) {
   602  		t.Errorf("Semver constraints should always match the any constraint")
   603  	}
   604  	if c1.Intersect(any) != c1 {
   605  		t.Errorf("Semver constraints should always return self when intersecting the any constraint, but got %s", c1.Intersect(any))
   606  	}
   607  
   608  	if c1.MatchesAny(none) {
   609  		t.Errorf("Semver constraints should never match the none constraint")
   610  	}
   611  	if c1.Intersect(none) != none {
   612  		t.Errorf("Semver constraints should always return none when intersecting the none constraint, but got %s", c1.Intersect(none))
   613  	}
   614  
   615  	c1, err = NewSemverConstraint(">= 1.0.0")
   616  	if err != nil {
   617  		t.Fatalf("Failed to create constraint: %s", err)
   618  	}
   619  
   620  	if c1.Matches(v1) {
   621  		t.Errorf("Semver constraint should not match simple branch")
   622  	}
   623  	if c1.Matches(v2) {
   624  		t.Errorf("Semver constraint should not match simple version")
   625  	}
   626  	if !c1.Matches(v3) {
   627  		t.Errorf("Semver constraint should match a simple semver version in its range")
   628  	}
   629  	if c1.Matches(v4) {
   630  		t.Errorf("Semver constraint should not match paired branch")
   631  	}
   632  	if c1.Matches(v5) {
   633  		t.Errorf("Semver constraint should not match paired version")
   634  	}
   635  	if !c1.Matches(v6) {
   636  		t.Errorf("Semver constraint should match a paired semver version in its range")
   637  	}
   638  
   639  	if c1.MatchesAny(v1) {
   640  		t.Errorf("Semver constraint should not allow any when intersected with simple branch")
   641  	}
   642  	if c1.MatchesAny(v2) {
   643  		t.Errorf("Semver constraint should not allow any when intersected with simple version")
   644  	}
   645  	if !c1.MatchesAny(v3) {
   646  		t.Errorf("Semver constraint should allow some when intersected with a simple semver version in its range")
   647  	}
   648  	if c1.MatchesAny(v4) {
   649  		t.Errorf("Semver constraint should not allow any when intersected with paired branch")
   650  	}
   651  	if c1.MatchesAny(v5) {
   652  		t.Errorf("Semver constraint should not allow any when intersected with paired version")
   653  	}
   654  	if !c1.MatchesAny(v6) {
   655  		t.Errorf("Semver constraint should allow some when intersected with a paired semver version in its range")
   656  	}
   657  
   658  	if c1.Intersect(v1) != none {
   659  		t.Errorf("Semver constraint should return none when intersected with a simple branch")
   660  	}
   661  	if c1.Intersect(v2) != none {
   662  		t.Errorf("Semver constraint should return none when intersected with a simple version")
   663  	}
   664  	if c1.Intersect(v3) != v3 {
   665  		t.Errorf("Semver constraint should return input when intersected with a simple semver version in its range")
   666  	}
   667  	if c1.Intersect(v4) != none {
   668  		t.Errorf("Semver constraint should return none when intersected with a paired branch")
   669  	}
   670  	if c1.Intersect(v5) != none {
   671  		t.Errorf("Semver constraint should return none when intersected with a paired version")
   672  	}
   673  	if c1.Intersect(v6) != v6 {
   674  		t.Errorf("Semver constraint should return input when intersected with a paired semver version in its range")
   675  	}
   676  }
   677  
   678  func TestSemverConstraint_ImpliedCaret(t *testing.T) {
   679  	c, _ := NewSemverConstraintIC("1.0.0")
   680  
   681  	wantS := "^1.0.0"
   682  	gotS := c.String()
   683  	if wantS != gotS {
   684  		t.Errorf("Expected string %s, got %s", wantS, gotS)
   685  	}
   686  
   687  	wantI := "1.0.0"
   688  	gotI := c.ImpliedCaretString()
   689  	if wantI != gotI {
   690  		t.Errorf("Expected implied string %s, got %s", wantI, gotI)
   691  	}
   692  
   693  	wantT := "svc-^1.0.0"
   694  	gotT := c.typedString()
   695  	if wantT != gotT {
   696  		t.Errorf("Expected type string %s, got %s", wantT, gotT)
   697  	}
   698  }
   699  
   700  func TestTypedConstraintString(t *testing.T) {
   701  	// Also tests typedVersionString(), as this nests down into that
   702  	rev := Revision("flooboofoobooo")
   703  	v1 := NewBranch("master")
   704  	v2 := NewBranch("test").Pair(rev)
   705  	v3 := NewVersion("1.0.1")
   706  	v4 := NewVersion("v2.0.5")
   707  	v5 := NewVersion("2.0.5.2")
   708  
   709  	table := []struct {
   710  		in  Constraint
   711  		out string
   712  	}{
   713  		{
   714  			in:  anyConstraint{},
   715  			out: "any-*",
   716  		},
   717  		{
   718  			in:  noneConstraint{},
   719  			out: "none-",
   720  		},
   721  		{
   722  			in:  mkSVC("^1.0.0"),
   723  			out: "svc-^1.0.0",
   724  		},
   725  		{
   726  			in:  v1,
   727  			out: "b-master",
   728  		},
   729  		{
   730  			in:  v2,
   731  			out: "b-test-r-" + string(rev),
   732  		},
   733  		{
   734  			in:  v3,
   735  			out: "sv-1.0.1",
   736  		},
   737  		{
   738  			in:  v4,
   739  			out: "sv-v2.0.5",
   740  		},
   741  		{
   742  			in:  v5,
   743  			out: "pv-2.0.5.2",
   744  		},
   745  	}
   746  
   747  	for _, fix := range table {
   748  		got := fix.in.typedString()
   749  		if got != fix.out {
   750  			t.Errorf("Typed string for %v (%T) was not expected %q; got %q", fix.in, fix.in, fix.out, got)
   751  		}
   752  	}
   753  }
   754  
   755  func TestConstraintsIdentical(t *testing.T) {
   756  	for _, test := range []struct {
   757  		a, b Constraint
   758  		eq   bool
   759  	}{
   760  		{Any(), Any(), true},
   761  		{none, noneConstraint{}, true},
   762  		{NewVersion("test"), NewVersion("test"), true},
   763  		{NewVersion("test"), NewVersion("test2"), false},
   764  		{NewBranch("test"), NewBranch("test"), true},
   765  		{NewBranch("test"), newDefaultBranch("test"), false},
   766  		{newDefaultBranch("test"), newDefaultBranch("test"), true},
   767  		{Revision("test"), Revision("test"), true},
   768  		{Revision("test"), Revision("test2"), false},
   769  		{testSemverConstraint(t, "v2.10.7"), testSemverConstraint(t, "v2.10.7"), true},
   770  	} {
   771  		if test.eq != test.a.identical(test.b) {
   772  			want := "identical"
   773  			if !test.eq {
   774  				want = "not " + want
   775  			}
   776  			t.Errorf("expected %s:\n\t(a) %#v\n\t(b) %#v", want, test.a, test.b)
   777  		}
   778  	}
   779  }
   780  
   781  func testSemverConstraint(t *testing.T, body string) Constraint {
   782  	c, err := NewSemverConstraint(body)
   783  	if err != nil {
   784  		t.Fatal(errors.Wrapf(err, "failed to create semver constraint: %s", body))
   785  	}
   786  	return c
   787  }
   788  
   789  func TestConstraintEncoding(t *testing.T) {
   790  	for _, test := range []struct {
   791  		name string
   792  		c    Constraint
   793  	}{
   794  		{"defaultBranch", newDefaultBranch("test")},
   795  		{"branch", NewBranch("test")},
   796  		{"ver", NewVersion("test")},
   797  		{"semver", testSemverConstraint(t, "^1.0.0")},
   798  		{"rev", Revision("test")},
   799  	} {
   800  		t.Run(test.name, func(t *testing.T) {
   801  			var msg pb.Constraint
   802  			test.c.copyTo(&msg)
   803  			b, err := proto.Marshal(&msg)
   804  			if err != nil {
   805  				t.Fatal(err)
   806  			}
   807  
   808  			if err := proto.Unmarshal(b, &msg); err != nil {
   809  				t.Fatal(err)
   810  			}
   811  			got, err := constraintFromCache(&msg)
   812  			if err != nil {
   813  				t.Error("failed to decode:", err)
   814  			} else if !got.identical(test.c) {
   815  				t.Errorf("decoded non-identical Constraint:\n\t(GOT): %#v\n\t(WNT): %#v", got, test.c)
   816  			}
   817  
   818  			if _, ok := test.c.(UnpairedVersion); ok {
   819  				got, err := unpairedVersionFromCache(&msg)
   820  				if err != nil {
   821  					t.Error("failed to decode:", err)
   822  				} else if !got.identical(test.c) {
   823  					t.Errorf("decoded non-identical UnpairedVersion:\n\t(GOT): %#v\n\t(WNT): %#v", got, test.c)
   824  				}
   825  			}
   826  		})
   827  	}
   828  }