blob: dac6e0aeaa450c7d77c039a19a4b5af5d7a5b2ed [file] [log] [blame]
require File.expand_path('../../spec_helper', __FILE__)
def dependency_graph_from_array(locked_dependencies)
locked_dependencies.reduce(Molinillo::DependencyGraph.new) do |graph, dep|
graph.add_vertex(dep.name, dep, true)
graph
end
end
def empty_graph
Molinillo::DependencyGraph.new
end
module Pod
describe Resolver do
describe 'In general' do
before do
@podfile = Podfile.new do
platform :ios
pod 'BlocksKit', '1.5.2'
end
locked_deps = dependency_graph_from_array([Dependency.new('BlocksKit', '1.5.2')])
@resolver = Resolver.new(config.sandbox, @podfile, locked_deps, config.sources_manager.all)
end
it 'returns the sandbox' do
@resolver.sandbox.should == config.sandbox
end
it 'returns the podfile' do
@resolver.podfile.should == @podfile
end
it 'returns the locked dependencies' do
@resolver.locked_dependencies.
should == dependency_graph_from_array([Dependency.new('BlocksKit', '1.5.2')])
end
#--------------------------------------#
describe 'SpecificationProvider' do
it 'does not return nil specifications in #search_for even when a ' \
'subspec does not exist in all versions' do
@resolver.instance_variable_set(:@cached_sets, {})
possibilities = @resolver.search_for(Dependency.new('SDWebImage/Core'))
possibilities.should.not.include? nil
end
end
#--------------------------------------#
it 'resolves the specification of the podfile' do
target_definition = @podfile.target_definitions['Pods']
specs = @resolver.resolve[target_definition]
specs.map(&:spec).map(&:to_s).should == [
'A2DynamicDelegate (2.0.2)',
'BlocksKit (1.5.2)',
'libffi (3.0.13)',
]
end
it 'returns the resolved specifications grouped by target definition' do
@resolver.resolve
target_definition = @podfile.target_definitions['Pods']
specs = @resolver.resolver_specs_by_target[target_definition]
specs.map(&:spec).map(&:to_s).should == [
'A2DynamicDelegate (2.0.2)',
'BlocksKit (1.5.2)',
'libffi (3.0.13)',
]
end
it 'resolves specifications from external sources' do
podspec = fixture('integration/Reachability/Reachability.podspec')
spec = Specification.from_file(podspec)
config.sandbox.expects(:specification).with('Reachability').returns(spec)
podfile = Podfile.new do
platform :ios
pod 'Reachability', :podspec => podspec
end
resolver = Resolver.new(config.sandbox, podfile, empty_graph, config.sources_manager.all)
resolver.resolve
specs = resolver.resolver_specs_by_target.values.flatten
specs.map(&:spec).map(&:to_s).should == ['Reachability (3.0.0)']
end
it 'resolves an empty podfile' do
@podfile = Podfile.new do
platform :ios
end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort
specs.should == []
end
end
#-------------------------------------------------------------------------#
describe 'Resolution' do
before do
@podfile = Podfile.new do
platform :ios, '6.0'
pod 'BlocksKit', '1.5.2'
end
@resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
end
it 'cross resolves dependencies' do
@podfile = Podfile.new do
platform :ios, '6.0'
pod 'AFNetworking', '< 0.9.2' # 0.9.1 exits
pod 'AFQuickLookView', '= 0.1.0' # requires 'AFNetworking', '>= 0.9.0'
end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort
specs.should == ['AFNetworking (0.9.1)', 'AFQuickLookView (0.1.0)']
end
it 'resolves basic conflicts' do
@podfile = Podfile.new do
platform :ios, '7.0'
pod 'RestKit' # latest version (0.23.3) requires 'AFNetworking', '~> 1.3.0'
pod 'AFNetworking', '~> 1.2.0'
end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort
specs.should == ['AFNetworking (1.2.1)', 'RestKit (0.20.1)',
'RestKit/Core (0.20.1)', 'RestKit/CoreData (0.20.1)',
'RestKit/Network (0.20.1)', 'RestKit/ObjectMapping (0.20.1)',
'RestKit/Support (0.20.1)', 'SOCKit (1.1)', 'TransitionKit (1.1.0)']
end
it 'resolves three-way conflicts' do
@podfile = Podfile.new do
platform :ios, '7.0'
pod 'AFAmazonS3Client' # latest version (2.0.0) requires 'AFNetworking', '~> 2.0'
pod 'CargoBay' # latest version (2.1.0) requires 'AFNetworking', '~> 2.2'
pod 'AFOAuth2Client' # latest version (0.1.2) requires 'AFNetworking', '~> 1.3'
end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort
specs.should == ['AFAmazonS3Client (1.0.1)', 'AFNetworking (1.3.4)',
'AFOAuth2Client (1.0.0)', 'CargoBay (1.0.0)']
end
it 'uses a Podfile requirement even when a previously declared ' \
'dependency has a different requirement' do
@podfile = Podfile.new do
platform :ios, '7.0'
pod 'InstagramKit' # latest version (3.7) requires 'AFNetworking', '~> 2.0'
pod 'AFNetworking', '2.0.1'
end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
specs = resolver.resolve.values.flatten.map(&:spec).map(&:root).map(&:to_s).uniq.sort
specs.should == ['AFNetworking (2.0.1)', 'InstagramKit (3.7)']
end
it 'holds the context state, such as cached specification sets' do
@resolver.resolve
cached_sets = @resolver.send(:cached_sets)
cached_sets.values.sort_by(&:name).should == [
config.sources_manager.search_by_name('A2DynamicDelegate').first,
config.sources_manager.search_by_name('BlocksKit').first,
config.sources_manager.search_by_name('libffi').first,
].sort_by(&:name)
end
it 'raises when a resolved dependency has a platform incompatibility' do
@podfile = Podfile.new do
platform :osx, '10.7'
pod 'ReactiveCocoa', '0.16.1' # this version is iOS-only
end
@resolver.stubs(:podfile).returns(@podfile)
should.raise Informative do
@resolver.resolve
end.message.should.match /platform .* not compatible/
end
it 'selects only platform-compatible versions' do
@podfile = Podfile.new do
platform :osx, '10.7'
pod 'AFNetworking' # the most recent version requires 10.8
end
@resolver.stubs(:podfile).returns(@podfile)
@resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort.should == [
'AFNetworking (1.3.4)',
]
end
it 'selects only platform-compatible versions for transitive dependencies' do
spec = Pod::Spec.new do |s|
s.name = 'lib'
s.version = '1.0'
s.platform = :ios, '5.0'
s.subspec('Calendar') {}
s.subspec('Classes') { |ss| ss.dependency 'lib/Calendar' }
s.subspec('RequestManager') do |ss|
ss.dependency 'lib/Classes'
ss.dependency 'AFNetworking'
end
s.default_subspec = 'RequestManager'
end
@podfile = Podfile.new do
platform :ios, '5.0'
pod 'lib'
end
@resolver.stubs(:podfile).returns(@podfile)
@resolver.send(:cached_sets)['lib'] = stub(:all_specifications => [spec])
@resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort.should == [
'AFNetworking (1.3.4)', 'lib (1.0)', 'lib/Calendar (1.0)', 'lib/Classes (1.0)', 'lib/RequestManager (1.0)'
]
end
it 'raises an informative error when version conflicts are caused by platform incompatibilities' do
@podfile = Podfile.new do
platform :osx, '10.7'
pod 'AFNetworking', '2.0.0' # requires 10.8
end
@resolver.stubs(:podfile).returns(@podfile)
message = should.raise(Informative) { @resolver.resolve }.message
message.should.match /required a higher minimum deployment target/
end
it 'raises an informative error when version conflict is caused by platform incompatibilities for local pods' do
sandbox = config.sandbox
local_spec = Specification.from_hash('name' => 'LocalPod', 'version' => '1.0', 'platforms' => { 'ios' => '8.0' })
sandbox.stubs(:specification).with('LocalPod').returns(local_spec)
@podfile = Podfile.new do
target 'SampleProject' do
platform :ios, '7.0'
pod 'LocalPod', :path => '../'
end
end
@resolver.stubs(:podfile).returns(@podfile)
message = should.raise(Informative) { @resolver.resolve }.message
message.should.match /required a higher minimum deployment target/
end
it 'raises if unable to find a specification' do
Specification.any_instance.stubs(:all_dependencies).returns([Dependency.new('Windows')])
message = should.raise Informative do
@resolver.resolve
end.message
message.should.match /Unable to find a specification/
message.should.match /`Windows` depended upon by `BlocksKit`/
end
it 'does not raise if all dependencies are supported by the platform of the target definition' do
lambda { @resolver.resolve }.should.not.raise
end
it 'includes all the subspecs of a specification node' do
@podfile = Podfile.new do
platform :ios, '7.0'
pod 'RestKit', '0.10.3'
end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
resolver.resolve.values.flatten.map(&:name).sort.should == %w(
FileMD5Hash
ISO8601DateFormatter
JSONKit
LibComponentLogging-Core
LibComponentLogging-NSLog
NSData+Base64
RestKit
RestKit/JSON
RestKit/Network
RestKit/ObjectMapping
RestKit/ObjectMapping/Core
RestKit/ObjectMapping/CoreData
RestKit/ObjectMapping/JSON
RestKit/ObjectMapping/XML
RestKit/UI
SOCKit
XMLReader
cocoa-oauth
)
end
it 'handles pre-release dependencies with subspecs' do
@podfile = Podfile.new do
platform :ios, '7.0'
pod 'RestKit', '0.20.0-rc1'
end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort.should == [
'AFNetworking (1.1.0)',
'RestKit (0.20.0-rc1)',
'RestKit/Core (0.20.0-rc1)',
'RestKit/CoreData (0.20.0-rc1)',
'RestKit/Network (0.20.0-rc1)',
'RestKit/ObjectMapping (0.20.0-rc1)',
'RestKit/Support (0.20.0-rc1)',
'SOCKit (1.1)',
]
end
it 'handles correctly subspecs from external sources' do
@podfile = Podfile.new do
platform :ios
pod 'MainSpec/FirstSubSpec', :git => 'GIT-URL'
end
spec = Spec.new do |s|
s.name = 'MainSpec'
s.version = '1.2.3'
s.platform = :ios
s.subspec 'FirstSubSpec' do |fss|
fss.source_files = 'some/file'
fss.subspec 'SecondSubSpec'
end
end
config.sandbox.expects(:specification).with('MainSpec').returns(spec)
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
specs = resolver.resolve.values.flatten.map(&:name).sort
specs.should == %w(
MainSpec/FirstSubSpec MainSpec/FirstSubSpec/SecondSubSpec
)
end
it 'handles test only dependencies correctly' do
@podfile = Podfile.new do
platform :ios
pod 'MainSpec', :git => 'GIT-URL', :testspecs => ['Tests']
end
spec = Spec.new do |s|
s.name = 'MainSpec'
s.version = '1.2.3'
s.platform = :ios
s.test_spec 'Tests' do |tss|
tss.source_files = 'some/file'
end
end
config.sandbox.expects(:specification).with('MainSpec').returns(spec)
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
resolved_specs = resolver.resolve.values.flatten
spec_names = resolved_specs.map(&:name).sort
spec_names.should == %w(
MainSpec MainSpec/Tests
)
resolved_specs.find { |rs| rs.name == 'MainSpec' }.used_by_tests_only?.should.be.false
resolved_specs.find { |rs| rs.name == 'MainSpec/Tests' }.used_by_tests_only?.should.be.true
end
it 'handles test only transitive dependencies' do
@podfile = Podfile.new do
platform :ios
pod 'MainSpec', :git => 'GIT-URL', :testspecs => ['Tests']
end
spec = Spec.new do |s|
s.name = 'MainSpec'
s.version = '1.2.3'
s.platform = :ios
s.test_spec 'Tests' do |tss|
tss.source_files = 'some/file'
tss.dependency 'Expecta'
end
end
config.sandbox.expects(:specification).with('MainSpec').returns(spec)
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
resolved_specs = resolver.resolve.values.flatten
spec_names = resolved_specs.map(&:name).sort
spec_names.should == %w(
Expecta MainSpec MainSpec/Tests
)
resolved_specs.find { |rs| rs.name == 'Expecta' }.used_by_tests_only?.should.be.true
resolved_specs.find { |rs| rs.name == 'MainSpec' }.used_by_tests_only?.should.be.false
resolved_specs.find { |rs| rs.name == 'MainSpec/Tests' }.used_by_tests_only?.should.be.true
end
it 'handles test only dependencies when they are also required by sources' do
@podfile = Podfile.new do
platform :ios
pod 'MainSpec', :git => 'GIT-URL', :testspecs => ['Tests']
end
spec = Spec.new do |s|
s.name = 'MainSpec'
s.version = '1.2.3'
s.platform = :ios
s.dependency 'Expecta'
s.test_spec 'Tests' do |tss|
tss.source_files = 'some/file'
tss.dependency 'Expecta'
end
end
config.sandbox.expects(:specification).with('MainSpec').returns(spec)
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
resolved_specs = resolver.resolve.values.flatten
spec_names = resolved_specs.map(&:name).sort
spec_names.should == %w(
Expecta MainSpec MainSpec/Tests
)
resolved_specs.find { |rs| rs.name == 'Expecta' }.used_by_tests_only?.should.be.false
resolved_specs.find { |rs| rs.name == 'MainSpec' }.used_by_tests_only?.should.be.false
resolved_specs.find { |rs| rs.name == 'MainSpec/Tests' }.used_by_tests_only?.should.be.true
end
it 'allows pre-release spec versions when a requirement has an ' \
'external source' do
@podfile = Podfile.new do
platform :ios
pod 'MainSpec', :git => 'GIT-URL'
end
spec = Spec.new do |s|
s.name = 'MainSpec'
s.version = '1.2.3-pre'
s.platform = :ios
end
config.sandbox.expects(:specification).with('MainSpec').returns(spec)
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort
specs.should == [
'MainSpec (1.2.3-pre)',
]
end
it 'raises if it finds two conflicting explicit dependencies' do
podfile = Podfile.new do
platform :ios
pod 'JSONKit', '1.4'
pod 'JSONKit', '1.5pre'
end
resolver = Resolver.new(config.sandbox, podfile, empty_graph, config.sources_manager.all)
e = lambda { resolver.resolve }.should.raise Informative
e.message.should.include <<-EOS.strip
[!] CocoaPods could not find compatible versions for pod "JSONKit":
In Podfile:
JSONKit (= 1.4)
JSONKit (= 1.5pre)
EOS
end
it 'raises if it finds two conflicting dependencies' do
podfile = Podfile.new do
platform :ios, '8.0'
pod 'RestKit', '0.23.3' # dependends on AFNetworking ~> 1.3.0
pod 'AFNetworking', '> 2'
end
resolver = Resolver.new(config.sandbox, podfile, empty_graph, config.sources_manager.all)
e = lambda { resolver.resolve }.should.raise Informative
e.message.should.include <<-EOS.strip
[!] CocoaPods could not find compatible versions for pod "AFNetworking":
In Podfile:
AFNetworking (> 2)
RestKit (= 0.23.3) was resolved to 0.23.3, which depends on
RestKit/Core (= 0.23.3) was resolved to 0.23.3, which depends on
RestKit/Network (= 0.23.3) was resolved to 0.23.3, which depends on
AFNetworking (~> 1.3.0)
EOS
end
it 'raises if no such version of a dependency exists' do
podfile = Podfile.new do
platform :ios
pod 'AFNetworking', '999.999.999'
end
resolver = Resolver.new(config.sandbox, podfile, empty_graph, config.sources_manager.all)
e = lambda { resolver.resolve }.should.raise NoSpecFoundError
e.message.should.include <<-EOS.strip
[!] CocoaPods could not find compatible versions for pod "AFNetworking":
In Podfile:
AFNetworking (= 999.999.999)
None of your spec sources contain a spec satisfying the dependency: `AFNetworking \(= 999\.999\.999\)`.
You have either:
* out-of-date source repos which you can update with `pod repo update` or with `pod install --repo-update`.
* mistyped the name or version.
* not added the source repo that hosts the Podspec to your Podfile.
Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by default.
EOS
e.exit_status.should.equal(31)
end
it 'raises if repo are updated and no such version of a dependency exists' do
podfile = Podfile.new do
platform :ios
pod 'AFNetworking', '999.999.999'
end
resolver = Resolver.new(config.sandbox, podfile, empty_graph, config.sources_manager.all)
resolver.specs_updated = true
e = lambda { resolver.resolve }.should.raise NoSpecFoundError
e.message.should.include <<-EOS.strip
[!] CocoaPods could not find compatible versions for pod "AFNetworking":
In Podfile:
AFNetworking (= 999.999.999)
None of your spec sources contain a spec satisfying the dependency: `AFNetworking (= 999.999.999)`.
You have either:
* mistyped the name or version.
* not added the source repo that hosts the Podspec to your Podfile.
Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by default.
EOS
e.exit_status.should.equal(31)
end
it 'raises with a list of dependencies if there are many dependencies but no versions of a dependency exists' do
podfile = Podfile.new do
platform :ios
pod 'AFNetworking', '3.0.1'
end
locked_deps = dependency_graph_from_array([Dependency.new('AFNetworking', '= 1.4')])
resolver = Resolver.new(config.sandbox, podfile, locked_deps, config.sources_manager.all)
e = lambda { resolver.resolve }.should.raise NoSpecFoundError
e.message.should.include <<-EOS.strip
[!] CocoaPods could not find compatible versions for pod "AFNetworking":
In snapshot (Podfile.lock):
AFNetworking (= 1.4)
In Podfile:
AFNetworking (= 3.0.1)
None of your spec sources contain a spec satisfying the dependencies: `AFNetworking (= 3.0.1), AFNetworking (= 1.4)`.
You have either:
* out-of-date source repos which you can update with `pod repo update` or with `pod install --repo-update`.
* mistyped the name or version.
* not added the source repo that hosts the Podspec to your Podfile.
Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by default.
EOS
e.exit_status.should.equal(31)
end
it 'takes into account locked dependencies' do
podfile = Podfile.new do
platform :ios
pod 'JSONKit', '<= 1.5pre'
end
resolver = Resolver.new(config.sandbox, podfile, empty_graph, config.sources_manager.all)
version = resolver.resolve.values.flatten.first.spec.version
version.to_s.should == '1.5pre'
locked_deps = dependency_graph_from_array([Dependency.new('JSONKit', '= 1.4')])
resolver = Resolver.new(config.sandbox, podfile, locked_deps, config.sources_manager.all)
version = resolver.resolve.values.flatten.first.spec.version
version.to_s.should == '1.4'
end
it 'shows a helpful error message if the old resolver incorrectly ' \
'activated a pre-release version that now leads to a version ' \
'conflict' do
podfile = Podfile.new do
platform :ios, '8.0'
pod 'CocoaLumberjack'
end
locked_deps = dependency_graph_from_array([Dependency.new('CocoaLumberjack', '= 2.0.0-beta2')])
resolver = Resolver.new(config.sandbox, podfile, locked_deps, config.sources_manager.all)
e = lambda { puts resolver.resolve.values.flatten }.should.raise Informative
e.message.should.match(/you were using a pre-release version of `CocoaLumberjack`/)
e.message.should.match(/`pod 'CocoaLumberjack', '= 2.0.0-beta2'`/)
e.message.should.match(/`pod update CocoaLumberjack`/)
end
describe 'concerning dependencies that are scoped by consumer platform' do
def resolve
Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all).resolve
end
# AFNetworking Has an 'AFNetworking/UIKit' iOS-only default subspec
requirement = ['AFNetworking', '2.4.1']
ios_subspec = 'AFNetworking/UIKit (2.4.1)'
it 'excludes those for another platform' do
@podfile = Podfile.new do
platform :osx, '10.10'
pod(*requirement)
end
resolve.values.flatten.map(&:spec).map(&:to_s).should.not.include ios_subspec
end
it 'includes those for the requested platform' do
@podfile = Podfile.new do
platform :ios, '7'
pod(*requirement)
end
resolve.values.flatten.map(&:spec).map(&:to_s).should.include ios_subspec
end
it 'includes those in the target for the requested platform only' do
@podfile = Podfile.new do
target 'iOS' do
platform :ios, '7'
pod(*requirement)
end
target 'OSX' do
platform :osx, '10.10'
pod(*requirement)
end
end
resolved = resolve
ios_target = resolved.keys.find { |td| td.label == 'Pods-iOS' }
osx_target = resolved.keys.find { |td| td.label == 'Pods-OSX' }
resolved[ios_target].map(&:spec).map(&:to_s).should.include ios_subspec
resolved[osx_target].map(&:spec).map(&:to_s).should.not.include ios_subspec
end
it 'includes dependencies in the target for the requested platform only' do
osx_dependency = 'ARAnalytics/CoreMac (4.0.1)'
ios_dependency = 'ARAnalytics/CoreIOS (4.0.1)'
@podfile = Podfile.new do
target 'iOS' do
platform :ios, '8'
pod 'ARAnalytics', '4.0.1'
end
target 'OSX' do
platform :osx, '10.10'
pod 'ARAnalytics', '4.0.1'
end
end
resolved = resolve
ios_target = resolved.keys.find { |td| td.label == 'Pods-iOS' }
osx_target = resolved.keys.find { |td| td.label == 'Pods-OSX' }
resolved[ios_target].map(&:spec).map(&:to_s).should.include ios_dependency
resolved[osx_target].map(&:spec).map(&:to_s).should.not.include ios_dependency
resolved[ios_target].map(&:spec).map(&:to_s).should.not.include osx_dependency
resolved[osx_target].map(&:spec).map(&:to_s).should.include osx_dependency
end
end
end
#-------------------------------------------------------------------------#
describe 'Multiple sources' do
it 'consults all sources when finding a matching spec' do
podfile = Podfile.new do
platform :ios
pod 'JSONKit', '> 2'
end
file = fixture('spec-repos/test_repo/JSONKit/999.999.999/JSONKit.podspec')
sources = config.sources_manager.sources(%w(master test_repo))
resolver = Resolver.new(config.sandbox, podfile, empty_graph, sources)
spec = resolver.resolve.values.flatten.first.spec
spec.version.to_s.should == '999.999.999'
spec.defined_in_file.should == file
sources = config.sources_manager.sources(%w(test_repo master))
resolver = Resolver.new(config.sandbox, podfile, empty_graph, sources)
spec = resolver.resolve.values.flatten.first.spec
spec.version.to_s.should == '999.999.999'
resolver.resolve.values.flatten.first.spec.defined_in_file.should == file
end
it 'warns and chooses the first source when multiple sources contain ' \
'a pod' do
podfile = Podfile.new do
platform :ios
pod 'JSONKit', '1.4'
end
sources = config.sources_manager.sources(%w(master test_repo))
resolver = Resolver.new(config.sandbox, podfile, empty_graph, sources)
spec = resolver.resolve.values.flatten.first.spec
spec.version.to_s.should == '1.4'
spec.defined_in_file.should == fixture('spec-repos/master/Specs/1/3/f/JSONKit/1.4/JSONKit.podspec.json')
sources = config.sources_manager.sources(%w(test_repo master))
resolver = Resolver.new(config.sandbox, podfile, empty_graph, sources)
spec = resolver.resolve.values.flatten.first.spec
spec.version.to_s.should == '1.4'
resolver.resolve.values.flatten.first.spec.defined_in_file.should == fixture('spec-repos/test_repo/JSONKit/1.4/JSONKit.podspec')
UI.warnings.should.match /multiple specifications/
end
it 'does not warn when multiple sources contain a pod but a dependency ' \
'has an explicit source specified' do
test_repo_url = config.sources_manager.source_with_name_or_url('test_repo').url
podfile = Podfile.new do
platform :ios
pod 'JSONKit', '1.4', :source => test_repo_url
end
sources = config.sources_manager.sources(%w(master test_repo))
resolver = Resolver.new(config.sandbox, podfile, empty_graph, sources)
resolver.resolve
UI.warnings.should.not.match /multiple specifications/
end
it 'fails to resolve a dependency with an explicit source even if it can be ' \
'resolved using the global sources' do
test_repo_url = config.sources_manager.source_with_name_or_url('test_repo').url
podfile = Podfile.new do
platform :ios
pod 'JSONKit', '1.5pre', :source => test_repo_url
end
sources = config.sources_manager.sources(%w(master))
resolver = Resolver.new(config.sandbox, podfile, empty_graph, sources)
e = lambda { resolver.resolve }.should.raise Informative
e.message.should.match(/None of your spec sources contain a spec/)
e.message.should.match(/JSONKit/)
e.message.should.match(/\= 1.5pre/)
end
it 'resolves a dependency with an explicit source even if it can\'t be ' \
'resolved using the global sources' do
master_repo_url = config.sources_manager.source_with_name_or_url('master').url
podfile = Podfile.new do
platform :ios
pod 'JSONKit', '1.5pre', :source => master_repo_url
end
sources = config.sources_manager.sources(%w(test_repo))
sources.map(&:url).should.not.include(master_repo_url)
resolver = Resolver.new(config.sandbox, podfile, empty_graph, sources)
spec = resolver.resolve.values.flatten.first.spec
spec.version.to_s.should == '1.5pre'
spec.defined_in_file.should == fixture('spec-repos/master/Specs/1/3/f/JSONKit/1.5pre/JSONKit.podspec.json')
end
it 'uses explicit source repos for a dependency even when it\'s transitive' do
master_repo_url = config.sources_manager.source_with_name_or_url('master').url
test_repo_url = config.sources_manager.source_with_name_or_url('test_repo').url
podfile = Podfile.new do
platform :ios
# KeenClient has a dependency on JSONKit 1.4
pod 'KeenClient', '3.2.2', :source => master_repo_url
pod 'JSONKit', '1.4', :source => test_repo_url
end
sources = config.sources_manager.sources(%w(master test_repo))
resolver = Resolver.new(config.sandbox, podfile, empty_graph, sources)
resolver.resolve
possible_specs = resolver.search_for(Dependency.new('JSONKit', '1.4'))
# JSONKit, v1.4 exists in both repos, but we should only ever be offered the test_repo version.
possible_specs.count.should == 1
possible_specs.first.version.to_s.should == '1.4'
possible_specs.first.defined_in_file.should == fixture('spec-repos/test_repo/JSONKit/1.4/JSONKit.podspec')
end
it 'uses global source repos for resolving a transitive dependency even ' \
'if the root dependency has an explicit source' do
test_repo_url = config.sources_manager.source_with_name_or_url('test_repo').url
podfile = Podfile.new do
platform :ios, '6.0'
pod 'CrossRepoDependent', '1.0', :source => test_repo_url
end
# CrossRepoDependent depends on AFNetworking which is only available in the master repo.
sources = config.sources_manager.sources(%w(master))
resolver = Resolver.new(config.sandbox, podfile, empty_graph, sources)
resolver.resolve
specs = resolver.resolve.values.flatten.map(&:spec)
specs.map(&:name).should ==
%w(AFNetworking AFNetworking/NSURLConnection AFNetworking/NSURLSession AFNetworking/Reachability) +
%w(AFNetworking/Security AFNetworking/Serialization AFNetworking/UIKit CrossRepoDependent)
afnetworking_spec = specs.find { |s| s.name == 'AFNetworking' }
afnetworking_spec.should.not.be.nil
afnetworking_spec.defined_in_file.should == fixture('spec-repos/master/Specs/a/7/5/AFNetworking/2.4.0/AFNetworking.podspec.json')
# Check that if the master source is not available the dependency cannot be resolved.
sources = config.sources_manager.sources(%w(test_repo))
resolver = Resolver.new(config.sandbox, podfile, empty_graph, sources)
e = lambda { resolver.resolve }.should.raise Informative
e.message.should.match(/Unable to find a specification for/)
e.message.should.match(/`AFNetworking \(= 2.4.0\)`/)
end
end
#-------------------------------------------------------------------------#
describe 'Pre-release versions' do
it 'resolves explicitly requested pre-release versions' do
@podfile = Podfile.new do
platform :ios, '6.0'
pod 'AFNetworking', '1.0RC3'
end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort
specs.should == ['AFNetworking (1.0RC3)']
end
it 'resolves to latest minor version even when explicitly requesting pre-release versions when using ~>' do
@podfile = Podfile.new do
platform :ios, '6.0'
pod 'AFNetworking', '~> 1.0RC3'
end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort
specs.should != ['AFNetworking (1.0RC3)']
specs.should == ['AFNetworking (1.3.4)']
end
it 'does not resolve to a pre-release version implicitly when matching exact version' do
@podfile = Podfile.new do
platform :ios, '6.0'
pod 'AFNetworking', '1.0'
end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort
specs.should != ['AFNetworking (1.0RC3)']
specs.should == ['AFNetworking (1.0)']
end
it 'does not resolve to a pre-release version implicitly when using <' do
@podfile = Podfile.new do
platform :ios, '6.0'
pod 'AFNetworking', '< 1.0'
end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort
specs.should != ['AFNetworking (1.0RC3)']
specs.should == ['AFNetworking (0.10.1)']
end
it 'does not resolve to a pre-release version implicitly when using <=' do
@podfile = Podfile.new do
platform :ios, '6.0'
pod 'AFNetworking', '<= 1.0'
end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort
specs.should != ['AFNetworking (1.0RC3)']
specs.should == ['AFNetworking (1.0)']
end
it 'does not resolve to a pre-release version implicitly when using >' do
@podfile = Podfile.new do
platform :ios, '6.0'
pod 'AFNetworking', '> 1.0', '< 1.3'
end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort
specs.should != ['AFNetworking (1.0RC3)']
specs.should == ['AFNetworking (1.2.1)']
end
it 'does not resolve to a pre-release version implicitly when using >=' do
@podfile = Podfile.new do
platform :ios, '6.0'
pod 'AFNetworking', '>= 1.0', '< 1.3'
end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort
specs.should != ['AFNetworking (1.0RC3)']
specs.should == ['AFNetworking (1.2.1)']
end
it 'does not resolve to a pre-release version implicitly when using ~>' do
@podfile = Podfile.new do
platform :ios, '6.0'
pod 'AFNetworking', '~> 1.0', '< 1.3'
end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort
specs.should != ['AFNetworking (1.0RC3)']
specs.should == ['AFNetworking (1.2.1)']
end
it 'raises when no constraints are specified and only pre-release versions are available' do
podfile = Podfile.new do
platform :ios
pod 'PrereleaseMonkey'
end
resolver = Resolver.new(config.sandbox, podfile, empty_graph, config.sources_manager.all)
e = lambda { resolver.resolve }.should.raise Informative
e.message.should.match(/There are only pre-release versions available satisfying the following requirements/)
e.message.should.match(/PrereleaseMonkey.*>= 0/)
e.message.should.match(/You should explicitly specify the version in order to install a pre-release version/)
end
it 'raises when no explicit version is specified and only pre-release versions satisfy constraints' do
podfile = Podfile.new do
platform :ios
pod 'AFNetworking', '< 1.0', '> 0.10.1'
end
resolver = Resolver.new(config.sandbox, podfile, empty_graph, config.sources_manager.all)
e = lambda { resolver.resolve }.should.raise Informative
e.message.should.match(/There are only pre-release versions available satisfying the following requirements/)
e.message.should.match(/AFNetworking.*< 1\.0, > 0\.10\.1/)
e.message.should.match(/You should explicitly specify the version in order to install a pre-release version/)
end
it 'resolves when there is explicit pre-release version specified and there are only pre-release versions' do
podfile = Podfile.new do
platform :ios
pod 'PrereleaseMonkey', '1.0-beta1'
end
resolver = Resolver.new(config.sandbox, podfile, empty_graph, config.sources_manager.all)
specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort
specs.should == ['PrereleaseMonkey (1.0-beta1)']
end
end
end
end