github.com/sdboyer/gps@v0.16.3/constraint_test.go (about)

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