Add support for test target creation in the pods project generator

parent ad59b03d
......@@ -8,6 +8,10 @@ To install release candidates run `[sudo] gem install cocoapods --pre`
##### Enhancements
* Add support for test target creation in the pods project generator
[Dimitris Koutsogiorgas](https://github.com/dnkoutso)
[#6703](https://github.com/CocoaPods/CocoaPods/pull/6703)
* Copy dSYM for vendored frameworks.
[Dimitris Koutsogiorgas](https://github.com/dnkoutso)
[#1698](https://github.com/CocoaPods/CocoaPods/issues/1698)
......
......@@ -7,7 +7,7 @@ GIT
GIT
remote: https://github.com/CocoaPods/Core.git
revision: 77639caff51a44aac7696adc23ac9ca04dfe5e82
revision: 5574572de5dd607f7dbc29025f7cf9f7c5d12cec
branch: master
specs:
cocoapods-core (1.2.1)
......@@ -31,7 +31,7 @@ GIT
GIT
remote: https://github.com/CocoaPods/Xcodeproj.git
revision: 526f5128a23ca0f8702b9eab4fc1ff67873fab84
revision: 7355a4eac5d3634725e0925cfbfa46fbcd88b933
branch: master
specs:
xcodeproj (1.4.4)
......
......@@ -71,8 +71,9 @@ module Pod
XCConfigHelper.add_target_specific_settings(target, @xcconfig)
generate_vendored_build_settings
generate_other_ld_flags
targets = pod_targets + target.search_paths_aggregate_targets.flat_map(&:pod_targets)
XCConfigHelper.generate_vendored_build_settings(target, targets, @xcconfig)
XCConfigHelper.generate_other_ld_flags(target, pod_targets, @xcconfig)
# TODO: Need to decide how we are going to ensure settings like these
# are always excluded from the user's project.
......@@ -176,40 +177,6 @@ module Pod
end
end
# Add custom build settings and required build settings to link to
# vendored libraries and frameworks.
#
# @note
# In case of generated pod targets, which require frameworks, the
# vendored frameworks and libraries are already linked statically
# into the framework binary and must not be linked again to the
# user target.
#
def generate_vendored_build_settings
targets = pod_targets + target.search_paths_aggregate_targets.flat_map(&:pod_targets)
targets.each do |pod_target|
unless pod_target.should_build? && pod_target.requires_frameworks?
XCConfigHelper.add_settings_for_file_accessors_of_target(target, pod_target, @xcconfig)
end
end
end
# Add pod target to list of frameworks / libraries that are linked
# with the user’s project.
#
def generate_other_ld_flags
other_ld_flags = pod_targets.select(&:should_build?).map do |pod_target|
if pod_target.requires_frameworks?
%(-framework "#{pod_target.product_basename}")
else
%(-l "#{pod_target.product_basename}") if XCConfigHelper.links_dependency?(target, pod_target)
end
end
@xcconfig.merge!('OTHER_LDFLAGS' => other_ld_flags.compact.join(' '))
end
# Ensure to add the default linker run path search paths as they could
# be not present due to being historically absent in the project or
# target template or just being removed by being superficial when
......
......@@ -16,8 +16,12 @@ module Pod
#
# @param [Target] target @see target
#
def initialize(target)
# @param [Boolean] test_xcconfig
# whether this is an xcconfig for a test native target.
#
def initialize(target, test_xcconfig = false)
@target = target
@test_xcconfig = test_xcconfig
end
# @return [Xcodeproj::Config] The generated xcconfig.
......@@ -49,7 +53,7 @@ module Pod
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1',
'HEADER_SEARCH_PATHS' => XCConfigHelper.quote(search_paths),
'LIBRARY_SEARCH_PATHS' => '$(inherited) ',
'OTHER_LDFLAGS' => XCConfigHelper.default_ld_flags(target),
'OTHER_LDFLAGS' => XCConfigHelper.default_ld_flags(target, @test_xcconfig),
'PODS_ROOT' => '${SRCROOT}',
'PODS_TARGET_SRCROOT' => target.pod_target_srcroot,
'PRODUCT_BUNDLE_IDENTIFIER' => 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}',
......@@ -66,6 +70,11 @@ module Pod
end
XCConfigHelper.add_target_specific_settings(target, @xcconfig)
@xcconfig.merge! XCConfigHelper.settings_for_dependent_targets(target, target.recursive_dependent_targets)
if @test_xcconfig
@xcconfig.merge! XCConfigHelper.settings_for_dependent_targets(target, target.test_dependent_targets)
XCConfigHelper.generate_vendored_build_settings(nil, target.test_dependent_targets, @xcconfig)
XCConfigHelper.generate_other_ld_flags(nil, target.test_dependent_targets, @xcconfig)
end
@xcconfig
end
......
......@@ -45,13 +45,15 @@ module Pod
# the target, which is used to check if the ARC compatibility
# flag is required.
#
# @return [String] the default linker flags. `-ObjC` is always included
# while `-fobjc-arc` is included only if requested in the
# Podfile.
# @param [Boolean] include_objc_flag
# whether to include `-ObjC` in the other linker flags
#
def self.default_ld_flags(target, includes_static_libraries = false)
# @return [String] the default linker flags. `-ObjC` is optionally included depending
# on the target while `-fobjc-arc` is included only if requested in the Podfile.
#
def self.default_ld_flags(target, include_objc_flag = false)
ld_flags = ''
ld_flags << '-ObjC' if includes_static_libraries
ld_flags << '-ObjC' if include_objc_flag
if target.podfile.set_arc_compatibility_flag? &&
target.spec_consumers.any?(&:requires_arc?)
ld_flags << ' -fobjc-arc'
......@@ -296,6 +298,57 @@ module Pod
build_settings
end
# Add custom build settings and required build settings to link to
# vendored libraries and frameworks.
#
# @param [AggregateTarget] aggregate_target
# The aggregate target, may be nil.
#
# @param [Array<PodTarget] pod_targets
# The pod targets to add the vendored build settings for.
#
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @note
# In case of generated pod targets, which require frameworks, the
# vendored frameworks and libraries are already linked statically
# into the framework binary and must not be linked again to the
# user target.
#
def self.generate_vendored_build_settings(aggregate_target, pod_targets, xcconfig)
pod_targets.each do |pod_target|
unless pod_target.should_build? && pod_target.requires_frameworks?
XCConfigHelper.add_settings_for_file_accessors_of_target(aggregate_target, pod_target, xcconfig)
end
end
end
# Add pod target to list of frameworks / libraries that are linked
# with the user’s project.
#
# @param [AggregateTarget] aggregate_target
# The aggregate target, may be nil.
#
# @param [Array<PodTarget] pod_targets
# The pod targets to add the vendored build settings for.
#
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @return [void]
#
def self.generate_other_ld_flags(aggregate_target, pod_targets, xcconfig)
other_ld_flags = pod_targets.select(&:should_build?).map do |pod_target|
if pod_target.requires_frameworks?
%(-framework "#{pod_target.product_basename}")
elsif XCConfigHelper.links_dependency?(aggregate_target, pod_target)
%(-l "#{pod_target.product_basename}")
end
end
xcconfig.merge!('OTHER_LDFLAGS' => other_ld_flags.compact.join(' '))
end
# Checks if the given target requires language specific settings and
# configures the given Xcconfig.
#
......
......@@ -492,15 +492,12 @@ module Pod
hash[name] = values.sort_by { |pt| pt.specs.count }
end
pod_targets.each do |target|
dependencies = transitive_dependencies_for_specs(target.specs, target.platform, all_specs).group_by(&:root)
target.dependent_targets = dependencies.map do |root_spec, deps|
pod_targets_by_name[root_spec.name].find do |t|
next false if t.platform.symbolic_name != target.platform.symbolic_name ||
t.requires_frameworks? != target.requires_frameworks?
spec_names = t.specs.map(&:name)
deps.all? { |dep| spec_names.include?(dep.name) }
end
end
dependencies = transitive_dependencies_for_specs(target.specs.reject(&:test_specification?), target.platform, all_specs).group_by(&:root)
test_dependencies = transitive_dependencies_for_specs(target.specs.select(&:test_specification?), target.platform, all_specs).group_by(&:root)
target.dependent_targets = filter_dependencies(dependencies, pod_targets_by_name, target)
target.test_dependent_targets = filter_dependencies(test_dependencies, pod_targets_by_name, target)
# Test dependendent targets include our own target as a test dependency.
target.test_dependent_targets << target
end
else
dedupe_cache = {}
......@@ -512,12 +509,27 @@ module Pod
pod_targets.each do |target|
dependencies = transitive_dependencies_for_specs(target.specs, target.platform, specs).group_by(&:root)
test_dependencies = transitive_dependencies_for_specs(target.specs.select(&:test_specification?), target.platform, all_specs).group_by(&:root)
target.dependent_targets = pod_targets.reject { |t| dependencies[t.root_spec].nil? }
target.test_dependent_targets = pod_targets.reject { |t| test_dependencies[t.root_spec].nil? }
# Test dependendent targets include our own target as a test dependency.
target.test_dependent_targets << target
end
end
end
end
def filter_dependencies(dependencies, pod_targets_by_name, target)
dependencies.map do |root_spec, deps|
pod_targets_by_name[root_spec.name].find do |t|
next false if t.platform.symbolic_name != target.platform.symbolic_name ||
t.requires_frameworks? != target.requires_frameworks?
spec_names = t.specs.map(&:name)
deps.all? { |dep| spec_names.include?(dep.name) }
end
end
end
# Returns the specs upon which the given specs _transitively_ depend.
#
# @note: This is implemented in the analyzer, because we don't have to
......
......@@ -86,6 +86,11 @@ module Pod
development_pod_targets.select(&:should_build?).each do |pod_target|
next unless share_scheme_for_development_pod?(pod_target.pod_name)
Xcodeproj::XCScheme.share_scheme(project.path, pod_target.label)
if pod_target.contains_test_specifications?
pod_target.supported_test_types.each do |test_type|
Xcodeproj::XCScheme.share_scheme(project.path, pod_target.test_target_label(test_type))
end
end
end
end
......@@ -203,16 +208,10 @@ module Pod
aggregate_target.native_target.add_dependency(pod_target.native_target)
configure_app_extension_api_only_for_target(pod_target) if is_app_extension
pod_target.dependent_targets.each do |pod_dependency_target|
next unless pod_dependency_target.should_build?
pod_target.native_target.add_dependency(pod_dependency_target.native_target)
configure_app_extension_api_only_for_target(pod_dependency_target) if is_app_extension
add_dependent_targets_to_native_target(pod_target.dependent_targets, pod_target.native_target, is_app_extension, pod_target.requires_frameworks?, frameworks_group)
if pod_target.requires_frameworks?
product_ref = frameworks_group.files.find { |f| f.path == pod_dependency_target.product_name } ||
frameworks_group.new_product_ref_for_target(pod_dependency_target.product_basename, pod_dependency_target.product_type)
pod_target.native_target.frameworks_build_phase.add_file_reference(product_ref, true)
end
pod_target.test_native_targets.each do |test_native_target|
add_dependent_targets_to_native_target(pod_target.test_dependent_targets, test_native_target, false, pod_target.requires_frameworks?, frameworks_group)
end
end
end
......@@ -251,6 +250,20 @@ module Pod
private
def add_dependent_targets_to_native_target(dependent_targets, native_target, is_app_extension, requires_frameworks, frameworks_group)
dependent_targets.each do |pod_dependency_target|
next unless pod_dependency_target.should_build?
native_target.add_dependency(pod_dependency_target.native_target)
configure_app_extension_api_only_for_target(pod_dependency_target) if is_app_extension
if requires_frameworks
product_ref = frameworks_group.files.find { |f| f.path == pod_dependency_target.product_name } ||
frameworks_group.new_product_ref_for_target(pod_dependency_target.product_basename, pod_dependency_target.product_type)
native_target.frameworks_build_phase.add_file_reference(product_ref, true)
end
end
end
# Sets the APPLICATION_EXTENSION_API_ONLY build setting to YES for all
# configurations of the given target
#
......
......@@ -18,20 +18,24 @@ module Pod
UI.message "- Installing target `#{target.name}` #{target.platform}" do
add_target
add_test_targets if target.contains_test_specifications?
create_support_files_dir
add_resources_bundle_targets
add_files_to_build_phases
create_xcconfig_file
create_test_xcconfig_files if target.contains_test_specifications?
if target.requires_frameworks?
create_info_plist_file
create_module_map
create_umbrella_header do |generator|
file_accessors = target.file_accessors
file_accessors = file_accessors.reject { |f| f.spec.test_specification? } if target.contains_test_specifications?
generator.imports += if header_mappings_dir
target.file_accessors.flat_map(&:public_headers).map do |pathname|
file_accessors.flat_map(&:public_headers).map do |pathname|
pathname.relative_path_from(header_mappings_dir)
end
else
target.file_accessors.flat_map(&:public_headers).map(&:basename)
file_accessors.flat_map(&:public_headers).map(&:basename)
end
end
create_build_phase_to_symlink_header_folders
......@@ -130,6 +134,7 @@ module Pod
target.file_accessors.each do |file_accessor|
consumer = file_accessor.spec_consumer
native_target = native_target_for_consumer(consumer)
headers = file_accessor.headers
public_headers = file_accessor.public_headers
private_headers = file_accessor.private_headers
......@@ -147,7 +152,7 @@ module Pod
header_file_refs = project_file_references_array(headers, 'header')
native_target.add_file_references(header_file_refs) do |build_file|
add_header(build_file, public_headers, private_headers)
add_header(build_file, public_headers, private_headers, native_target)
end
other_file_refs = other_source_files.map { |sf| project.reference_for_path(sf) }
......@@ -162,6 +167,72 @@ module Pod
end
end
# Returns the corresponding native target to use based on the provided consumer.
# This is used to figure out whether to add a source file into the library native target or any of the
# test native targets.
#
# @param [Consumer] consumer
# The consumer to base from in order to find the native target.
#
# @return [PBXNativeTarget] the native target to use or `nil` if none is found.
#
def native_target_for_consumer(consumer)
return native_target unless consumer.spec.test_specification?
target.test_native_targets.find do |native_target|
native_target.symbol_type == product_type_for_test_type(consumer.spec.test_type)
end
end
# Returns the corresponding native product type to use given the test type.
# This is primarily used when creating the native targets in order to produce the correct test bundle target
# based on the type of tests included.
#
# @param [Symbol] test_type
# The test type to map to provided by the test specification DSL.
#
# @return [Symbol] The native product type to use.
#
def product_type_for_test_type(test_type)
case test_type
when :unit
:unit_test_bundle
else
raise Informative, "Unknown test type passed `#{test_type}`."
end
end
# Adds the test targets for the library to the Pods project with the
# appropriate build configurations.
#
# @return [void]
#
def add_test_targets
target.supported_test_types.each do |test_type|
product_type = product_type_for_test_type(test_type)
name = target.test_target_label(test_type)
platform = target.platform.name
language = target.uses_swift? ? :swift : :objc
native_test_target = project.new_target(product_type, name, platform, deployment_target, nil, language)
product_name = target.product_name
product = native_test_target.product_reference
product.name = product_name
target.user_build_configurations.each do |bc_name, type|
native_test_target.add_build_configuration(bc_name, type)
end
native_test_target.build_configurations.each do |configuration|
configuration.build_settings.merge!(custom_build_settings)
# target_installer will automatically add an empth `OTHER_LDFLAGS`. For test
# targets those are set via a test xcconfig file instead.
configuration.build_settings.delete('OTHER_LDFLAGS')
end
target.test_native_targets << native_test_target
end
end
# Adds the resources of the Pods to the Pods project.
#
# @note The source files are grouped by Pod and in turn by subspec
......@@ -186,6 +257,7 @@ module Pod
bundle_target.add_resources(resource_phase_refs + compile_phase_refs)
end
native_target = native_target_for_consumer(file_accessor.spec_consumer)
target.user_build_configurations.each do |bc_name, type|
bundle_target.add_build_configuration(bc_name, type)
end
......@@ -221,7 +293,7 @@ module Pod
:watchos => '1,2' # The device family for watchOS is 4, but Xcode creates watchkit-compatible bundles as 1,2
}
if family = device_family_by_platform[target.platform.name]
if (family = device_family_by_platform[target.platform.name])
c.build_settings['TARGETED_DEVICE_FAMILY'] = family
end
end
......@@ -251,6 +323,25 @@ module Pod
end
end
# Generates the contents of the xcconfig file used for each test target type and saves it to disk.
#
# @return [void]
#
def create_test_xcconfig_files
target.supported_test_types.each do |test_type|
path = target.xcconfig_path(test_type.to_s)
xcconfig_gen = Generator::XCConfig::PodXCConfig.new(target, true)
xcconfig_gen.save_as(path)
xcconfig_file_ref = add_file_to_support_group(path)
target.test_native_targets.each do |test_target|
test_target.build_configurations.each do |test_target_bc|
test_target_bc.base_configuration_reference = xcconfig_file_ref
end
end
end
end
# Creates a build phase which links the versioned header folders
# of the OS X into the framework bundle's root root directory.
# This is only necessary because the way how headers are copied
......@@ -400,7 +491,7 @@ module Pod
end
end
def add_header(build_file, public_headers, private_headers)
def add_header(build_file, public_headers, private_headers, native_target)
file_ref = build_file.file_ref
acl = if public_headers.include?(file_ref.real_path)
'Public'
......
......@@ -305,7 +305,7 @@ module Pod
find_cached_set(dependency).
all_specifications(installation_options.warn_for_multiple_pod_sources).
select { |s| requirement.satisfied_by? s.version }.
map { |s| s.subspec_by_name(dependency.name, false) }.
map { |s| s.subspec_by_name(dependency.name, false, true) }.
compact.
reverse
end
......
......@@ -18,11 +18,11 @@ module Pod
specification.respond_to?(method, include_all)
end
def subspec_by_name(name = nil, raise_if_missing = true)
def subspec_by_name(name = nil, raise_if_missing = true, include_test_specifications = false)
if !name || name == self.name
self
else
specification.subspec_by_name(name, raise_if_missing)
specification.subspec_by_name(name, raise_if_missing, include_test_specifications)
end
end
......
......@@ -28,6 +28,16 @@ module Pod
#
attr_accessor :dependent_targets
# @return [Array<PodTarget>] the targets that this target has a test dependency
# upon.
#
attr_accessor :test_dependent_targets
# return [Array<PBXNativeTarget>] the test target generated in the Pods project for
# this library or `nil` if there is no test target created.
#
attr_accessor :test_native_targets
# @param [Array<Specification>] specs @see #specs
# @param [Array<TargetDefinition>] target_definitions @see #target_definitions
# @param [Sandbox] sandbox @see #sandbox
......@@ -46,7 +56,9 @@ module Pod
@build_headers = Sandbox::HeadersStore.new(sandbox, 'Private')
@file_accessors = []
@resource_bundle_targets = []
@test_native_targets = []
@dependent_targets = []
@test_dependent_targets = []
@build_config_cache = {}
end
......@@ -133,7 +145,7 @@ module Pod
#
attr_accessor :file_accessors
# @return [Array<PBXTarget>] the resource bundle targets belonging
# @return [Array<PBXNativeTarget>] the resource bundle targets belonging
# to this target.
attr_reader :resource_bundle_targets
......@@ -157,7 +169,7 @@ module Pod
specs.map { |spec| spec.consumer(platform) }
end
# @return [Boolean] Whether the target uses Swift code
# @return [Boolean] Whether the target uses Swift code.
#
def uses_swift?
return @uses_swift if defined? @uses_swift
......@@ -168,6 +180,18 @@ module Pod
end
end
# @return [Boolean] Whether the target has any tests specifications.
#
def contains_test_specifications?
specs.any?(&:test_specification?)
end
# @return [Array<Symbol>] All of the test supported types within this target.
#
def supported_test_types
specs.select(&:test_specification?).map(&:test_type).uniq
end
# @return [Specification] The root specification for the target.
#
def root_spec
......@@ -189,6 +213,15 @@ module Pod
"#{label}-#{bundle_name}"
end
# @param [Symbol] test_type
# The test type to use for producing the test label.
#
# @return [String] The derived name of the test target.
#
def test_target_label(test_type)
"#{label}-#{test_type.capitalize}-Tests"
end
# @return [Array<String>] The names of the Pods on which this target
# depends.
#
......@@ -234,7 +267,7 @@ module Pod
if whitelists.empty?
@build_config_cache[key] = true
return true
true
elsif whitelists.count == 1
@build_config_cache[key] = whitelists.first
whitelists.first
......@@ -258,7 +291,7 @@ module Pod
if whitelists.empty?
@inhibit_warnings = false
return false
false
elsif whitelists.count == 1
@inhibit_warnings = whitelists.first
whitelists.first
......@@ -268,7 +301,7 @@ module Pod
'settings to inhibit warnings. CocoaPods does not currently ' \
'support different settings and will fall back to your preference ' \
'set in the root target definition.'
return podfile.root_target_definitions.first.inhibits_warnings_for_pod?(root_spec.name)
podfile.root_target_definitions.first.inhibits_warnings_for_pod?(root_spec.name)
end
end
......
#import <Foundation/Foundation.h>
/** Coconuts are cool */
@interface CoconutObj : NSObject
@end
Pod::Spec.new do |s|
s.name = 'CoconutLib'
s.version = '1.0'
s.authors = 'Coconut Corp', { 'Monkey Boy' => 'monkey@coconut-corp.local' }
s.homepage = 'http://coconut-corp.local/coconut-lib.html'
s.summary = 'Coconuts For the Win.'
s.description = 'All the Coconuts'
s.source = { :git => 'http://coconut-corp.local/coconut-lib.git', :tag => 'v1.0' }
s.license = {
:type => 'MIT',
:file => 'LICENSE',
:text => 'Permission is hereby granted ...'
}
s.source_files = 'Classes/*.{h,m}'
s.test_spec do |test_spec|
test_spec.source_files = 'Tests/*.{h,m}'
test_spec.dependency 'OCMock'
end
end
#import <XCTest/XCTest.h>
@interface CoconutTests : XCTestCase
@end
@implementation CoconutTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testExample {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
- (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
}];
}
@end
......@@ -128,6 +128,48 @@ module Pod
generated.class.should == Xcodeproj::Config
end
end
describe 'test xcconfig generation' do
before do
@monkey_spec = fixture_spec('monkey/monkey.podspec')
@monkey_pod_target = fixture_pod_target(@monkey_spec)
@banana_spec = fixture_spec('banana-lib/BananaLib.podspec')
@banana_pod_target = fixture_pod_target(@banana_spec)
@coconut_spec = fixture_spec('coconut-lib/CoconutLib.podspec')
@coconut_pod_target = fixture_pod_target(@coconut_spec)
@consumer = @coconut_pod_target.spec_consumers.first
@podfile = @coconut_pod_target.podfile
file_accessors = [Sandbox::FileAccessor.new(fixture('coconut-lib'), @consumer)]
@coconut_pod_target.stubs(:file_accessors).returns(file_accessors)
end
it 'includes other ld flags for test dependent targets' do
@coconut_pod_target.test_dependent_targets = [@monkey_pod_target]
generator = PodXCConfig.new(@coconut_pod_target, true)
xcconfig = generator.generate
xcconfig.to_hash['OTHER_LDFLAGS'].should.include '-l"monkey" -framework "dynamic-monkey"'
end
it 'adds settings for test dependent targets' do
@coconut_pod_target.test_dependent_targets = [@banana_pod_target]
generator = PodXCConfig.new(@coconut_pod_target, true)
xcconfig = generator.generate
xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should == '$(inherited) "$PODS_CONFIGURATION_BUILD_DIR/BananaLib" $(inherited) "${PODS_ROOT}/../../spec/fixtures/banana-lib"'
end
it 'does not include other ld flags for test dependent targets if its not a test xcconfig' do
@coconut_pod_target.test_dependent_targets = [@monkey_pod_target]
generator = PodXCConfig.new(@coconut_pod_target)
xcconfig = generator.generate
xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should.be.nil
xcconfig.to_hash['OTHER_LDFLAGS'].should.be.nil
end
end
end
end
end
......
......@@ -139,6 +139,106 @@ module Pod
end
end
describe 'test target generation' do
before do
config.sandbox.prepare
@podfile = Podfile.new do
platform :ios, '6.0'
project 'SampleProject/SampleProject'
target 'SampleProject'
end
@target_definition = @podfile.target_definitions['SampleProject']
@project = Project.new(config.sandbox.project_path)
config.sandbox.project = @project
@coconut_spec = fixture_spec('coconut-lib/CoconutLib.podspec')
# Add sources to the project.
file_accessor = Sandbox::FileAccessor.new(Sandbox::PathList.new(fixture('coconut-lib')), @coconut_spec.consumer(:ios))
@project.add_pod_group('CoconutLib', fixture('coconut-lib'))
group = @project.group_for_spec('CoconutLib')
file_accessor.source_files.each do |file|
@project.add_file_reference(file, group)
end
file_accessor.resources.each do |resource|
@project.add_file_reference(resource, group)
end
# Add test sources to the project.
test_file_accessor = Sandbox::FileAccessor.new(Sandbox::PathList.new(fixture('coconut-lib')), @coconut_spec.test_specs.first.consumer(:ios))
@project.add_pod_group('CoconutLibTests', fixture('coconut-lib'))
group = @project.group_for_spec('CoconutLibTests')
test_file_accessor.source_files.each do |file|
@project.add_file_reference(file, group)
end
test_file_accessor.resources.each do |resource|
@project.add_file_reference(resource, group)
end
@coconut_pod_target = PodTarget.new([@coconut_spec, *@coconut_spec.recursive_subspecs], [@target_definition], config.sandbox)
@coconut_pod_target.file_accessors = [file_accessor, test_file_accessor]
@coconut_pod_target.user_build_configurations = { 'Debug' => :debug, 'Release' => :release }
@installer = PodTargetInstaller.new(config.sandbox, @coconut_pod_target)
end
it 'adds the native test target to the project' do
@installer.install!
@project.targets.count.should == 2
@project.targets.first.name.should == 'CoconutLib'
native_test_target = @project.targets[1]
native_test_target.name.should == 'CoconutLib-Unit-Tests'
native_test_target.symbol_type.should == :unit_test_bundle
@coconut_pod_target.test_native_targets.count.should == 1
end
it 'adds files to build phases correctly depending on the native target' do
@installer.install!
@project.targets.count.should == 2
native_target = @project.targets[0]
native_target.source_build_phase.files.count.should == 2
native_target.source_build_phase.files.map(&:display_name).sort.should == [
'Coconut.m',
'CoconutLib-dummy.m',
]
native_test_target = @project.targets[1]
native_test_target.source_build_phase.files.count.should == 1
native_test_target.source_build_phase.files.map(&:display_name).sort.should == [
'CoconutTests.m',
]
end
it 'adds xcconfig file reference for test native targets' do
@installer.install!
@project.support_files_group
group = @project['Pods/CoconutLib/Support Files']
group.children.map(&:display_name).sort.should.include 'CoconutLib.unit.xcconfig'
end
it 'does not add test header imports to umbrella header' do
@coconut_pod_target.stubs(:requires_frameworks?).returns(true)
@installer.install!
content = @coconut_pod_target.umbrella_header_path.read
content.should.not =~ /"CoconutTestHeader.h"/
end
it 'returns the correct native target based on the consumer provided' do
@installer.install!
native_target = @installer.send(:native_target_for_consumer, @coconut_spec.consumer(:ios))
native_target.name.should == 'CoconutLib'
test_native_target = @installer.send(:native_target_for_consumer, @coconut_spec.test_specs.first.consumer(:ios))
test_native_target.name.should == 'CoconutLib-Unit-Tests'
end
it 'returns the correct product type for test type' do
@installer.send(:product_type_for_test_type, :unit).should == :unit_test_bundle
end
it 'raises for unknown test type' do
exception = lambda { @installer.send(:product_type_for_test_type, :weird_test_type) }.should.raise Informative
exception.message.should.include 'Unknown test type passed `weird_test_type`.'
end
end
#--------------------------------------#
it 'adds the source files of each pod to the target of the Pod library' do
......
......@@ -242,6 +242,50 @@ module Pod
#--------------------------------------#
describe '#set_test_target_dependencies' do
before do
spec = fixture_spec('coconut-lib/CoconutLib.podspec')
target_definition = Podfile::TargetDefinition.new(:default, @installer.podfile.root_target_definitions.first)
@pod_target = PodTarget.new([spec, *spec.recursive_subspecs], [target_definition], config.sandbox)
@target = AggregateTarget.new(target_definition, config.sandbox)
@mock_target = mock('PodNativeTarget')
mock_project = mock('PodsProject', :frameworks_group => mock('FrameworksGroup'))
@generator.stubs(:project).returns(mock_project)
@target.stubs(:native_target).returns(@mock_target)
@target.stubs(:pod_targets).returns([@pod_target])
@generator.stubs(:aggregate_targets).returns([@target])
end
it 'adds test dependent targets to test native targets' do
mock_native_target = mock('CoconutLib')
mock_test_native_target = mock('CoconutLib-Unit-Tests')
dependent_target = mock('dependent-target', :should_build? => true, :native_target => 'DependentNativeTarget')
test_dependent_target = mock('dependent-test-target', :should_build? => true, :native_target => 'TestDependentNativeTarget')
@pod_target.stubs(:native_target).returns(mock_native_target)
@pod_target.stubs(:test_native_targets).returns([mock_test_native_target])
@pod_target.stubs(:dependent_targets).returns([dependent_target])
@pod_target.stubs(:test_dependent_targets).returns([test_dependent_target])
@pod_target.stubs(:should_build? => true)
@mock_target.expects(:add_dependency).with(mock_native_target)
mock_native_target.expects(:add_dependency).with('DependentNativeTarget')
mock_native_target.expects(:add_dependency).with('TestDependentNativeTarget').never
mock_test_native_target.expects(:add_dependency).with('DependentNativeTarget').never
mock_test_native_target.expects(:add_dependency).with('TestDependentNativeTarget')
@generator.send(:set_target_dependencies)
end
end
#--------------------------------------#
describe '#write' do
before do
@generator.stubs(:aggregate_targets).returns([])
......@@ -303,6 +347,30 @@ module Pod
@generator.send(:share_development_pod_schemes)
end
it 'shares test schemes' do
spec = fixture_spec('coconut-lib/CoconutLib.podspec')
target_definition = Podfile::TargetDefinition.new(:default, @installer.podfile.root_target_definitions.first)
pod_target = Pod::PodTarget.new([spec, *spec.recursive_subspecs], [target_definition], config.sandbox)
pod_target.stubs(:should_build?).returns(true)
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns(true)
@generator.stubs(:pod_targets).returns([pod_target])
@generator.sandbox.stubs(:development_pods).returns('CoconutLib' => nil)
Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path,
'CoconutLib')
Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path,
'CoconutLib-Unit-Tests')
@generator.send(:share_development_pod_schemes)
end
it 'allows opting out' do
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
......
......@@ -219,6 +219,10 @@ module Pod
it 'returns that it requires being built as framework' do
@pod_target.requires_frameworks?.should == true
end
it 'returns that it has no test specifications' do
@pod_target.contains_test_specifications?.should == false
end
end
describe 'Host does not requires frameworks' do
......@@ -304,6 +308,28 @@ module Pod
end
end
end
describe 'test spec support' do
before do
spec = fixture_spec('coconut-lib/CoconutLib.podspec')
@test_spec_target_definition = Podfile::TargetDefinition.new('Pods', nil)
@test_spec_target_definition.abstract = false
@test_pod_target = PodTarget.new([spec, *spec.recursive_subspecs], [@test_spec_target_definition], config.sandbox)
@test_pod_target.stubs(:platform).returns(:ios)
end
it 'returns that it has test specifications' do
@test_pod_target.contains_test_specifications?.should == true
end
it 'returns supported test types' do
@test_pod_target.supported_test_types.should == [:unit]
end
it 'returns test label based on test type' do
@test_pod_target.test_target_label(:unit).should == 'CoconutLib-Unit-Tests'
end
end
end
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment