View Javadoc
1   package org.eclipse.aether.internal.test.util;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   * 
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   * 
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.eclipse.aether.version.InvalidVersionSpecificationException;
23  import org.eclipse.aether.version.Version;
24  import org.eclipse.aether.version.VersionRange;
25  
26  import java.util.Objects;
27  
28  /**
29   * A version range inspired by mathematical range syntax. For example, "[1.0,2.0)", "[1.0,)" or "[1.0]".
30   */
31  final class TestVersionRange
32      implements VersionRange
33  {
34  
35      private final Version lowerBound;
36  
37      private final boolean lowerBoundInclusive;
38  
39      private final Version upperBound;
40  
41      private final boolean upperBoundInclusive;
42  
43      /**
44       * Creates a version range from the specified range specification.
45       * 
46       * @param range The range specification to parse, must not be {@code null}.
47       * @throws InvalidVersionSpecificationException If the range could not be parsed.
48       */
49      TestVersionRange( String range )
50          throws InvalidVersionSpecificationException
51      {
52          String process = range;
53  
54          if ( range.startsWith( "[" ) )
55          {
56              lowerBoundInclusive = true;
57          }
58          else if ( range.startsWith( "(" ) )
59          {
60              lowerBoundInclusive = false;
61          }
62          else
63          {
64              throw new InvalidVersionSpecificationException( range, "Invalid version range " + range
65                  + ", a range must start with either [ or (" );
66          }
67  
68          if ( range.endsWith( "]" ) )
69          {
70              upperBoundInclusive = true;
71          }
72          else if ( range.endsWith( ")" ) )
73          {
74              upperBoundInclusive = false;
75          }
76          else
77          {
78              throw new InvalidVersionSpecificationException( range, "Invalid version range " + range
79                  + ", a range must end with either [ or (" );
80          }
81  
82          process = process.substring( 1, process.length() - 1 );
83  
84          int index = process.indexOf( "," );
85  
86          if ( index < 0 )
87          {
88              if ( !lowerBoundInclusive || !upperBoundInclusive )
89              {
90                  throw new InvalidVersionSpecificationException( range, "Invalid version range " + range
91                      + ", single version must be surrounded by []" );
92              }
93  
94              lowerBound = new TestVersion( process.trim() );
95              upperBound = new TestVersion( process.trim() );
96          }
97          else
98          {
99              String parsedLowerBound = process.substring( 0, index ).trim();
100             String parsedUpperBound = process.substring( index + 1 ).trim();
101 
102             // more than two bounds, e.g. (1,2,3)
103             if ( parsedUpperBound.contains( "," ) )
104             {
105                 throw new InvalidVersionSpecificationException( range, "Invalid version range " + range
106                     + ", bounds may not contain additional ','" );
107             }
108 
109             lowerBound = parsedLowerBound.length() > 0 ? new TestVersion( parsedLowerBound ) : null;
110             upperBound = parsedUpperBound.length() > 0 ? new TestVersion( parsedUpperBound ) : null;
111 
112             if ( upperBound != null && lowerBound != null )
113             {
114                 if ( upperBound.compareTo( lowerBound ) < 0 )
115                 {
116                     throw new InvalidVersionSpecificationException( range, "Invalid version range " + range
117                         + ", lower bound must not be greater than upper bound" );
118                 }
119             }
120         }
121     }
122 
123     public Bound getLowerBound()
124     {
125         return new Bound( lowerBound, lowerBoundInclusive );
126     }
127 
128     public Bound getUpperBound()
129     {
130         return new Bound( upperBound, upperBoundInclusive );
131     }
132 
133     public boolean acceptsSnapshots()
134     {
135         return isSnapshot( lowerBound ) || isSnapshot( upperBound );
136     }
137 
138     public boolean containsVersion( Version version )
139     {
140         boolean snapshot = isSnapshot( version );
141 
142         if ( lowerBound != null )
143         {
144             int comparison = lowerBound.compareTo( version );
145 
146             if ( snapshot && comparison == 0 )
147             {
148                 return true;
149             }
150 
151             if ( comparison == 0 && !lowerBoundInclusive )
152             {
153                 return false;
154             }
155             if ( comparison > 0 )
156             {
157                 return false;
158             }
159         }
160 
161         if ( upperBound != null )
162         {
163             int comparison = upperBound.compareTo( version );
164 
165             if ( snapshot && comparison == 0 )
166             {
167                 return true;
168             }
169 
170             if ( comparison == 0 && !upperBoundInclusive )
171             {
172                 return false;
173             }
174             if ( comparison < 0 )
175             {
176                 return false;
177             }
178         }
179 
180         if ( lowerBound != null || upperBound != null )
181         {
182             return !snapshot;
183         }
184 
185         return true;
186     }
187 
188     private boolean isSnapshot( Version version )
189     {
190         return version != null && version.toString().endsWith( "SNAPSHOT" );
191     }
192 
193     @Override
194     public boolean equals( Object obj )
195     {
196         if ( obj == this )
197         {
198             return true;
199         }
200         else if ( obj == null || !getClass().equals( obj.getClass() ) )
201         {
202             return false;
203         }
204 
205         TestVersionRange that = (TestVersionRange) obj;
206 
207         return upperBoundInclusive == that.upperBoundInclusive && lowerBoundInclusive == that.lowerBoundInclusive
208             && Objects.equals( upperBound, that.upperBound )
209             && Objects.equals( lowerBound, that.lowerBound );
210     }
211 
212     @Override
213     public int hashCode()
214     {
215         int hash = 17;
216         hash = hash * 31 + hash( upperBound );
217         hash = hash * 31 + ( upperBoundInclusive ? 1 : 0 );
218         hash = hash * 31 + hash( lowerBound );
219         hash = hash * 31 + ( lowerBoundInclusive ? 1 : 0 );
220         return hash;
221     }
222 
223     private static int hash( Object obj )
224     {
225         return obj != null ? obj.hashCode() : 0;
226     }
227 
228     @Override
229     public String toString()
230     {
231         StringBuilder buffer = new StringBuilder( 64 );
232         buffer.append( lowerBoundInclusive ? '[' : '(' );
233         if ( lowerBound != null )
234         {
235             buffer.append( lowerBound );
236         }
237         buffer.append( ',' );
238         if ( upperBound != null )
239         {
240             buffer.append( upperBound );
241         }
242         buffer.append( upperBoundInclusive ? ']' : ')' );
243         return buffer.toString();
244     }
245 
246 }