require 'spec_helper' require 'semantic_puppet/version' describe SemanticPuppet::VersionRange do describe '.parse' do def self.test_expressions(expressions) expressions.each do |range, vs| test_range(range, vs[:to_str], vs[:includes], vs[:excludes]) end end def self.test_range(range_list, str, includes, excludes) Array(range_list).each do |expr| example "#{expr.inspect} stringifies as #{str}" do range = SemanticPuppet::VersionRange.parse(expr) expect(range.inspect).to eql str end includes.each do |vstring| example "#{expr.inspect} includes #{vstring}" do range = SemanticPuppet::VersionRange.parse(expr) expect(range).to cover(SemanticPuppet::Version.parse(vstring)) end example "parse(#{expr.inspect}).to_s includes #{vstring}" do range = SemanticPuppet::VersionRange.parse(expr) range = SemanticPuppet::VersionRange.parse(range.to_s) expect(range).to cover(SemanticPuppet::Version.parse(vstring)) end end excludes.each do |vstring| example "#{expr.inspect} excludes #{vstring}" do range = SemanticPuppet::VersionRange.parse(expr) expect(range).to_not cover(SemanticPuppet::Version.parse(vstring)) end example "parse(#{expr.inspect}).to_s excludes #{vstring}" do range = SemanticPuppet::VersionRange.parse(expr) range = SemanticPuppet::VersionRange.parse(range.to_s) expect(range).to_not cover(SemanticPuppet::Version.parse(vstring)) end end end end context 'loose version expressions' do test_expressions( [ '1.2.3-alpha' ] => { :to_str => '1.2.3-alpha', :includes => [ '1.2.3-alpha' ], :excludes => [ '1.2.3-999', '1.2.3-beta' ], }, [ '1.2.3' ] => { :to_str => '1.2.3', :includes => [ '1.2.3' ], :excludes => [ '1.2.2', '1.2.3-alpha', '1.2.4-alpha' ], }, [ '1.2', '1.2.x', '1.2.X' ] => { :to_str => '>=1.2.0 <1.3.0', :includes => [ '1.2.0', '1.2.999' ], :excludes => [ '1.1.999', '1.2.0-alpha', '1.3.0-0' ], }, [ '1', '1.x', '1.X' ] => { :to_str => '>=1.0.0 <2.0.0', :includes => [ '1.0.0', '1.999.0' ], :excludes => [ '0.999.999', '1.0.0-alpha', '2.0.0-0' ], }, ) end context 'open-ended expressions' do test_expressions( [ '>1.2.3', '> 1.2.3' ] => { :to_str => '>1.2.3', :includes => [ '999.0.0' ], :excludes => [ '1.2.3', '1.2.4-0' ], }, [ '>1.2.3-alpha', '> 1.2.3-alpha' ] => { :to_str => '>1.2.3-alpha', :includes => [ '1.2.3-alpha.0', '1.2.3-alpha0', '999.0.0' ], :excludes => [ '1.2.3-alpha' ], }, [ '>=1.2.3', '>= 1.2.3' ] => { :to_str => '>=1.2.3', :includes => [ '999.0.0' ], :excludes => [ '1.2.2', '1.2.3-0' ], }, [ '>=1.2.3-alpha', '>= 1.2.3-alpha' ] => { :to_str => '>=1.2.3-alpha', :includes => [ '1.2.3-alpha', '1.2.3-alpha0', '999.0.0' ], :excludes => [ '1.2.3-alph', '1.2.4-alpha' ], }, [ '<1.2.3', '< 1.2.3' ] => { :to_str => '<1.2.3', :includes => [ '0.0.0', '1.2.2' ], :excludes => [ '0.0.0-0', '1.2.3-0', '2.0.0' ], }, [ '<1.2.3-alpha', '< 1.2.3-alpha' ] => { :to_str => '<1.2.3-alpha', :includes => [ '0.0.0', '1.2.3-alph' ], :excludes => [ '0.0.0-0', '1.2.3-alpha', '2.0.0' ], }, [ '<=1.2.3', '<= 1.2.3' ] => { :to_str => '<=1.2.3', :includes => [ '0.0.0', '1.2.3' ], :excludes => [ '0.0.0-0', '1.2.3-0' ], }, [ '<=1.2.3-alpha', '<= 1.2.3-alpha' ] => { :to_str => '<=1.2.3-alpha', :includes => [ '0.0.0', '1.2.3-alpha' ], :excludes => [ '0.0.0-0', '1.2.3-alpha0', '1.2.3-alpha.0', '1.2.3-alpha'.next ], }, ) end context '"reasonably close" expressions' do test_expressions( [ '~ 1', '~1' ] => { :to_str => '>=1.0.0 <2.0.0', :includes => [ '1.0.0', '1.999.999' ], :excludes => [ '0.999.999', '1.0.0-0', '2.0.0-0' ], }, [ '~ 1.2', '~1.2' ] => { :to_str => '>=1.2.0 <1.3.0', :includes => [ '1.2.0', '1.2.999' ], :excludes => [ '1.1.999', '1.2.0-0', '1.3.0-0' ], }, [ '~ 1.2.3', '~1.2.3' ] => { :to_str => '>=1.2.3 <1.3.0', :includes => [ '1.2.3', '1.2.5' ], :excludes => [ '1.2.2', '1.2.3-0', '1.3.0-0' ], }, [ '~ 1.2.3-alpha', '~1.2.3-alpha' ] => { :to_str => '>=1.2.3-alpha <1.3.0', :includes => [ '1.2.3-alpha', '1.2.3' ], :excludes => [ '1.2.3-alph', '1.2.4-0' ], }, ) end context 'inclusive range expressions' do test_expressions( '1.2.3 - 1.3.4' => { :to_str => '>=1.2.3 <=1.3.4', :includes => [ '1.2.3', '1.3.4' ], :excludes => [ '1.2.2', '1.2.3-0', '1.3.5-0' ], }, '1.2.3 - 1.3.4-alpha' => { :to_str => '>=1.2.3 <=1.3.4-alpha', :includes => [ '1.2.3', '1.3.4-alpha' ], :excludes => [ '1.2.2', '1.2.3-0', '1.3.4-alpha0', '1.3.5' ], }, '1.2.3-alpha - 1.3.4' => { :to_str => '>=1.2.3-alpha <=1.3.4', :includes => [ '1.2.3-alpha', '1.3.4' ], :excludes => [ '1.2.3-alph', '1.3.5-0' ], }, '1.2.3-alpha - 1.3.4-alpha' => { :to_str => '>=1.2.3-alpha <=1.3.4-alpha', :includes => [ '1.2.3-alpha', '1.3.4-alpha' ], :excludes => [ '1.2.3-alph', '1.3.4-alpha0', '1.3.5' ], }, ) end context 'unioned expressions' do test_expressions( [ '1.2 <1.2.5' ] => { :to_str => '>=1.2.0 <1.2.5', :includes => [ '1.2.0', '1.2.4' ], :excludes => [ '1.1.999', '1.2.0-0', '1.2.5-0', '1.9.0' ], }, [ '1 <=1.2.5' ] => { :to_str => '>=1.0.0 <=1.2.5', :includes => [ '1.0.0', '1.2.5' ], :excludes => [ '0.999.999', '1.0.0-0', '1.2.6-0', '1.9.0' ], }, [ '>1.0.0 >2.0.0 >=3.0.0 <5.0.0' ] => { :to_str => '>=3.0.0 <5.0.0', :includes => [ '3.0.0', '4.999.999' ], :excludes => [ '2.999.999', '3.0.0-0', '5.0.0-0' ], }, [ '<1.0.0 >2.0.0' ] => { :to_str => '<0.0.0', :includes => [ ], :excludes => [ '0.0.0-0', '0.0.0' ], }, ) end context 'ored expressions' do context 'overlapping' do test_expressions( [ '>=1.2.3 || 1.2.5' ] => { :to_str => '>=1.2.3', :includes => [ '1.2.3', '1.2.4' ], :excludes => [ '1.2.3-0', '1.2.4-0' ], }, [ '>=1.2.3 <=1.2.5 || >=1.2.5 <1.3.0' ] => { :to_str => '>=1.2.3 <1.3.0', :includes => [ '1.2.3', '1.2.6' ], :excludes => [ '1.2.3-0', '1.2.6-0' ], }, ) end context 'adjacent' do test_expressions( [ '1.2.3 || 1.2.4 || 1.2.5' ] => { :to_str => '>=1.2.3 <=1.2.5', :includes => [ '1.2.3', '1.2.5' ], :excludes => [ '1.2.3-0', '1.2.5-0' ], }, [ '>=1.2.3 <1.2.5 || >=1.2.5 <1.3.0' ] => { :to_str => '>=1.2.3 <1.3.0', :includes => [ '1.2.3', '1.2.6' ], :excludes => [ '1.2.3-0', '1.2.6-0' ], }, ) let(:range) { SemanticPuppet::VersionRange.parse('>=1.2.3 <1.2.5 || >=1.2.5 <1.3.0') } it 'returns expected begin' do expect(range.begin.to_s).to eql('1.2.3') end it 'returns nil on end' do expect(range.end.to_s).to eql('1.3.0') end it 'returns nil on exclude_begin?' do expect(range.exclude_begin?).to be_falsey end it 'returns nil on exclude_end?' do expect(range.exclude_end?).to be_truthy end end context 'non-overlapping' do test_expressions( [ '1.2.3 || 1.2.5' ] => { :to_str => '1.2.3 || 1.2.5', :includes => [ '1.2.3', '1.2.5' ], :excludes => [ '1.2.4', '1.2.3-0', '1.2.5-0' ], }, ) let(:range) { SemanticPuppet::VersionRange.parse('1.2.3 || 1.2.5') } it 'returns nil on begin' do expect(range.begin).to be_nil end it 'returns nil on end' do expect(range.end).to be_nil end it 'returns nil on exclude_begin?' do expect(range.exclude_begin?).to be_nil end it 'returns nil on exclude_end?' do expect(range.exclude_end?).to be_nil end end end context 'invalid expressions' do example 'raise an appropriate exception' do ex = [ ArgumentError, 'Unparsable version range: "invalid"' ] expect { SemanticPuppet::VersionRange.parse('invalid') }.to raise_error(*ex) end end end describe '#intersection' do def self.v(num) SemanticPuppet::Version.parse("#{num}.0.0") end def self.range(x, y, ex = false) SemanticPuppet::VersionRange.new(v(x), v(y), ex) end EMPTY_RANGE = SemanticPuppet::VersionRange::EMPTY_RANGE tests = { # This falls entirely before the target range range(1, 4) => [ EMPTY_RANGE ], # This falls entirely after the target range range(11, 15) => [ EMPTY_RANGE ], # This overlaps the beginning of the target range range(1, 6) => [ range(5, 6) ], # This overlaps the end of the target range range(9, 15) => [ range(9, 10), range(9, 10, true) ], # This shares the first value of the target range range(1, 5) => [ range(5, 5) ], # This shares the last value of the target range range(10, 15) => [ range(10, 10), EMPTY_RANGE ], # This shares both values with the target range range(5, 10) => [ range(5, 10), range(5, 10, true) ], # This is a superset of the target range range(4, 11) => [ range(5, 10), range(5, 10, true) ], # This is a subset of the target range range(6, 9) => [ range(6, 9) ], # This shares the first value of the target range, but excludes it range(1, 5, true) => [ EMPTY_RANGE ], # This overlaps the beginning of the target range, with an excluded end range(1, 7, true) => [ range(5, 7, true) ], # This shares both values with the target range, and excludes the end range(5, 10, true) => [ range(5, 10, true) ], } inclusive = range(5, 10) context "between #{inclusive} &" do tests.each do |subject, result| result = result.first example subject do expect(inclusive & subject).to eql(result) end end end exclusive = range(5, 10, true) context "between #{exclusive} &" do tests.each do |subject, result| result = result.last example subject do expect(exclusive & subject).to eql(result) end end end context 'is commutative' do tests.each do |subject, _| example "between #{inclusive} & #{subject}" do expect(inclusive & subject).to eql(subject & inclusive) end example "between #{exclusive} & #{subject}" do expect(exclusive & subject).to eql(subject & exclusive) end end end it 'cannot intersect with non-VersionRanges' do msg = "value must be a SemanticPuppet::VersionRange" expect { inclusive.intersection(1..2) }.to raise_error(msg) end end context 'The version' do def below(version, range) version = SemanticPuppet::Version.parse(version) range = SemanticPuppet::VersionRange.parse(range) !range.include?(version) && range.ranges.all? { |part| part.exclude_begin? ? part.begin >= version : part.begin > version } end def above(version, range) version = SemanticPuppet::Version.parse(version) range = SemanticPuppet::VersionRange.parse(range) !range.include?(version) && range.ranges.all? { |part| part.exclude_end? ? part.end <= version.to_stable : part.end < version.to_stable } end [ ['~1.2.2', '1.3.0'], ['~0.6.1-1', '0.7.1-1'], ['1.0.0 - 2.0.0', '2.0.1'], ['1.0.0', '1.0.1-beta1'], ['1.0.0', '2.0.0'], ['<=2.0.0', '2.1.1'], ['<=2.0.0', '3.2.9'], ['<2.0.0', '2.0.0'], ['0.1.20 || 1.2.4', '1.2.5'], ['2.x.x', '3.0.0'], ['1.2.x', '1.3.0'], ['1.2.x || 2.x', '3.0.0'], ['2.*.*', '5.0.1'], ['1.2.*', '1.3.3'], ['1.2.* || 2.*', '4.0.0'], ['2', '3.0.0'], ['2.3', '2.4.2'], ['~2.4', '2.5.0'], # >=2.4.0 <2.5.0 ['~2.4', '2.5.5'], ['~>3.2.1', '3.3.0'], # >=3.2.1 <3.3.0 ['~1', '2.2.3'], # >=1.0.0 <2.0.0 ['~>1', '2.2.4'], ['~> 1', '3.2.3'], ['~1.0', '1.1.2'], # >=1.0.0 <1.1.0 ['~ 1.0', '1.1.0'], ['<1.2', '1.2.0'], ['< 1.2', '1.2.1'], ['1', '2.0.0-beta'], ['~v0.5.4-pre', '0.6.0'], ['~v0.5.4-pre', '0.6.1-pre'], ['=0.7.x', '0.8.0'], ['=0.7.x', '0.8.0-asdf'], ['<0.7.x', '0.7.0'], ['~1.2.2', '1.3.0'], ['1.0.0 - 2.0.0', '2.2.3'], ['1.0.0', '1.0.1'], ['<=2.0.0', '3.0.0'], ['<=2.0.0', '2.9999.9999'], ['<=2.0.0', '2.2.9'], ['<2.0.0', '2.9999.9999'], ['<2.0.0', '2.2.9'], ['2.x.x', '3.1.3'], ['1.2.x', '1.3.3'], ['1.2.x || 2.x', '3.1.3'], ['2.*.*', '3.1.3'], ['1.2.*', '1.3.3'], ['1.2.* || 2.*', '3.1.3'], ['2', '3.1.2'], ['2.3', '2.4.1'], ['~2.4', '2.5.0'], # >=2.4.0 <2.5.0 ['~>3.2.1', '3.3.2'], # >=3.2.1 <3.3.0 ['~1', '2.2.3'], # >=1.0.0 <2.0.0 ['~>1', '2.2.3'], ['~1.0', '1.1.0'], # >=1.0.0 <1.1.0 ['<1', '1.0.0'], ['1', '2.0.0-beta'], ['<1', '1.0.0-beta'], ['< 1', '1.0.0-beta'], ['=0.7.x', '0.8.2'], ['<0.7.x', '0.7.2'] ].each do |tuple| it "#{tuple[1]} should be above range #{tuple[0]}" do expect(above(tuple[1], tuple[0])).to be_truthy end end [ ['~0.6.1-1', '0.6.1-1'], ['1.0.0 - 2.0.0', '1.2.3'], ['1.0.0 - 2.0.0', '0.9.9'], ['1.0.0', '1.0.0'], ['>=*', '0.2.4'], ['', '1.0.0'], ['*', '1.2.3'], ['*', '1.2.3-foo'], ['>=1.0.0', '1.0.0'], ['>=1.0.0', '1.0.1'], ['>=1.0.0', '1.1.0'], ['>1.0.0', '1.0.1'], ['>1.0.0', '1.1.0'], ['<=2.0.0', '2.0.0'], ['<=2.0.0', '1.9999.9999'], ['<=2.0.0', '0.2.9'], ['<2.0.0', '1.9999.9999'], ['<2.0.0', '0.2.9'], ['>= 1.0.0', '1.0.0'], ['>= 1.0.0', '1.0.1'], ['>= 1.0.0', '1.1.0'], ['> 1.0.0', '1.0.1'], ['> 1.0.0', '1.1.0'], ['<= 2.0.0', '2.0.0'], ['<= 2.0.0', '1.9999.9999'], ['<= 2.0.0', '0.2.9'], ['< 2.0.0', '1.9999.9999'], ["<\t2.0.0", '0.2.9'], ['>=0.1.97', '0.1.97'], ['>=0.1.97', '0.1.97'], ['0.1.20 || 1.2.4', '1.2.4'], ['0.1.20 || >1.2.4', '1.2.4'], ['0.1.20 || 1.2.4', '1.2.3'], ['0.1.20 || 1.2.4', '0.1.20'], ['>=0.2.3 || <0.0.1', '0.0.0'], ['>=0.2.3 || <0.0.1', '0.2.3'], ['>=0.2.3 || <0.0.1', '0.2.4'], ['||', '1.3.4'], ['2.x.x', '2.1.3'], ['1.2.x', '1.2.3'], ['1.2.x || 2.x', '2.1.3'], ['1.2.x || 2.x', '1.2.3'], ['x', '1.2.3'], ['2.*.*', '2.1.3'], ['1.2.*', '1.2.3'], ['1.2.* || 2.*', '2.1.3'], ['1.2.* || 2.*', '1.2.3'], ['1.2.* || 2.*', '1.2.3'], ['*', '1.2.3'], ['2', '2.1.2'], ['2.3', '2.3.1'], ['~2.4', '2.4.0'], # >=2.4.0 <2.5.0 ['~2.4', '2.4.5'], ['~>3.2.1', '3.2.2'], # >=3.2.1 <3.3.0 ['~1', '1.2.3'], # >=1.0.0 <2.0.0 ['~>1', '1.2.3'], ['~> 1', '1.2.3'], ['~1.0', '1.0.2'], # >=1.0.0 <1.1.0 ['~ 1.0', '1.0.2'], ['>=1', '1.0.0'], ['>= 1', '1.0.0'], ['<1.2', '1.1.1'], ['< 1.2', '1.1.1'], ['1', '1.0.0-beta'], ['~v0.5.4-pre', '0.5.5'], ['~v0.5.4-pre', '0.5.4'], ['=0.7.x', '0.7.2'], ['>=0.7.x', '0.7.2'], ['=0.7.x', '0.7.0-asdf'], ['>=0.7.x', '0.7.0-asdf'], ['<=0.7.x', '0.6.2'], ['>0.2.3 >0.2.4 <=0.2.5', '0.2.5'], ['>=0.2.3 <=0.2.4', '0.2.4'], ['1.0.0 - 2.0.0', '2.0.0'], ['^1', '0.0.0-0'], ['^3.0.0', '2.0.0'], ['^1.0.0 || ~2.0.1', '2.0.0'], ['^0.1.0 || ~3.0.1 || 5.0.0', '3.2.0'], ['^0.1.0 || ~3.0.1 || 5.0.0', '1.0.0-beta'], ['^0.1.0 || ~3.0.1 || 5.0.0', '5.0.0-0'], ['^0.1.0 || ~3.0.1 || >4 <=5.0.0', '3.5.0'] ].each do |tuple| it "#{tuple[1]} should not be above range #{tuple[0]}(#{SemanticPuppet::VersionRange.parse(tuple[0]).inspect})" do expect(above(tuple[1], tuple[0])).to be_falsey end end [ ['~1.2.2', '1.2.1'], ['~0.6.1-1', '0.6.1-0'], ['1.0.0 - 2.0.0', '0.0.1'], ['1.0.0-beta.2', '1.0.0-beta.1'], ['1.0.0', '0.0.0'], ['>=2.0.0', '1.1.1'], ['>=2.0.0', '1.2.9'], ['>2.0.0', '2.0.0'], ['0.1.20 || 1.2.4', '0.1.5'], ['2.x.x', '1.0.0'], ['1.2.x', '1.1.0'], ['1.2.x || 2.x', '1.0.0'], ['2.*.*', '1.0.1'], ['1.2.*', '1.1.3'], ['1.2.* || 2.*', '1.1.9999'], ['2', '1.0.0'], ['2.3', '2.2.2'], ['~2.4', '2.3.0'], # >=2.4.0 <2.5.0 ['~2.4', '2.3.5'], ['~>3.2.1', '3.2.0'], # >=3.2.1 <3.3.0 ['~1', '0.2.3'], # >=1.0.0 <2.0.0 ['~>1', '0.2.4'], ['~> 1', '0.2.3'], ['~1.0', '0.1.2'], # >=1.0.0 <1.1.0 ['~ 1.0', '0.1.0'], ['>1.2', '1.2.0'], ['> 1.2', '1.2.1'], ['1', '0.0.0-beta'], ['~v0.5.4-pre', '0.5.4-alpha'], ['~v0.5.4-pre', '0.5.4-alpha'], ['=0.7.x', '0.6.0'], ['=0.7.x', '0.6.0-asdf'], ['>=0.7.x', '0.6.0'], ['~1.2.2', '1.2.1'], ['1.0.0 - 2.0.0', '0.2.3'], ['1.0.0', '0.0.1'], ['>=2.0.0', '1.0.0'], ['>=2.0.0', '1.9999.9999'], ['>=2.0.0', '1.2.9'], ['>2.0.0', '2.0.0'], ['>2.0.0', '1.2.9'], ['2.x.x', '1.1.3'], ['1.2.x', '1.1.3'], ['1.2.x || 2.x', '1.1.3'], ['2.*.*', '1.1.3'], ['1.2.*', '1.1.3'], ['1.2.* || 2.*', '1.1.3'], ['2', '1.9999.9999'], ['2.3', '2.2.1'], ['~2.4', '2.3.0'], # >=2.4.0 <2.5.0 ['~>3.2.1', '2.3.2'], # >=3.2.1 <3.3.0 ['~1', '0.2.3'], # >=1.0.0 <2.0.0 ['~>1', '0.2.3'], ['~1.0', '0.0.0'], # >=1.0.0 <1.1.0 ['>1', '1.0.0'], ['2', '1.0.0-beta'], ['>1', '1.0.0-beta'], ['> 1', '1.0.0-beta'], ['=0.7.x', '0.6.2'], ['=0.7.x', '0.7.0-asdf'], ['^1', '1.0.0-0'], ['>=0.7.x', '0.7.0-asdf'], ['1', '1.0.0-beta'], ['>=0.7.x', '0.6.2'] ].each do |tuple| it "#{tuple[1]} should be below range #{tuple[0]}" do expect(below(tuple[1], tuple[0])).to be_truthy end end [ ['~ 1.0', '1.1.0'], ['~0.6.1-1', '0.6.1-1'], ['1.0.0 - 2.0.0', '1.2.3'], ['1.0.0 - 2.0.0', '2.9.9'], ['1.0.0', '1.0.0'], ['>=*', '0.2.4'], ['', '1.0.0'], ['*', '1.2.3'], ['>=1.0.0', '1.0.0'], ['>=1.0.0', '1.0.1'], ['>=1.0.0', '1.1.0'], ['>1.0.0', '1.0.1'], ['>1.0.0', '1.1.0'], ['<=2.0.0', '2.0.0'], ['<=2.0.0', '1.9999.9999'], ['<=2.0.0', '0.2.9'], ['<2.0.0', '1.9999.9999'], ['<2.0.0', '0.2.9'], ['>= 1.0.0', '1.0.0'], ['>= 1.0.0', '1.0.1'], ['>= 1.0.0', '1.1.0'], ['> 1.0.0', '1.0.1'], ['> 1.0.0', '1.1.0'], ['<= 2.0.0', '2.0.0'], ['<= 2.0.0', '1.9999.9999'], ['<= 2.0.0', '0.2.9'], ['< 2.0.0', '1.9999.9999'], ["<\t2.0.0", '0.2.9'], ['>=0.1.97', '0.1.97'], ['0.1.20 || 1.2.4', '1.2.4'], ['0.1.20 || >1.2.4', '1.2.4'], ['0.1.20 || 1.2.4', '1.2.3'], ['0.1.20 || 1.2.4', '0.1.20'], ['>=0.2.3 || <0.0.1', '0.0.0'], ['>=0.2.3 || <0.0.1', '0.2.3'], ['>=0.2.3 || <0.0.1', '0.2.4'], ['||', '1.3.4'], ['2.x.x', '2.1.3'], ['1.2.x', '1.2.3'], ['1.2.x || 2.x', '2.1.3'], ['1.2.x || 2.x', '1.2.3'], ['x', '1.2.3'], ['2.*.*', '2.1.3'], ['1.2.*', '1.2.3'], ['1.2.* || 2.*', '2.1.3'], ['1.2.* || 2.*', '1.2.3'], ['1.2.* || 2.*', '1.2.3'], ['*', '1.2.3'], ['2', '2.1.2'], ['2.3', '2.3.1'], ['~2.4', '2.4.0'], # >=2.4.0 <2.5.0 ['~2.4', '2.4.5'], ['~>3.2.1', '3.2.2'], # >=3.2.1 <3.3.0 ['~1', '1.2.3'], # >=1.0.0 <2.0.0 ['~>1', '1.2.3'], ['~> 1', '1.2.3'], ['~1.0', '1.0.2'], # >=1.0.0 <1.1.0 ['~ 1.0', '1.0.2'], ['>=1', '1.0.0'], ['>= 1', '1.0.0'], ['<1.2', '1.1.1'], ['< 1.2', '1.1.1'], ['~v0.5.4-pre', '0.5.5'], ['~v0.5.4-pre', '0.5.4'], ['=0.7.x', '0.7.2'], ['>=0.7.x', '0.7.2'], ['<=0.7.x', '0.6.2'], ['>0.2.3 >0.2.4 <=0.2.5', '0.2.5'], ['>=0.2.3 <=0.2.4', '0.2.4'], ['1.0.0 - 2.0.0', '2.0.0'], ['^3.0.0', '4.0.0'], ['^1.0.0 || ~2.0.1', '2.0.0'], ['^0.1.0 || ~3.0.1 || 5.0.0', '3.2.0'], ['^0.1.0 || ~3.0.1 || 5.0.0', '1.0.0-beta'], ['^0.1.0 || ~3.0.1 || 5.0.0', '5.0.0-0'], ['^0.1.0 || ~3.0.1 || >4 <=5.0.0', '3.5.0'], ['^1.0.0-alpha', '1.0.0-beta'], ['~1.0.0-alpha', '1.0.0-beta'], ['=0.1.0', '1.0.0'] ].each do |tuple| it "#{tuple[1]} should not be below range #{tuple[0]}" do expect(below(tuple[1], tuple[0])).to be_falsey end end end end