blob: 8d2d015b511e5f8e7fb5600144a7671c4608b274 [file] [log] [blame]
# ------------------------------------ #
# CocoaPods Integration tests #
# ------------------------------------ #
#-----------------------------------------------------------------------------#
# The following integrations tests are based on file comparison.
#
# 1. For each test there is a folder with a `before` and `after` subfolders.
# 2. The contents of the before folder are copied to the `TMP_DIR` folder and
# then the given arguments are passed to the `POD_BINARY`.
# 3. After the pod command completes the execution the each file in the
# `after` subfolder is compared to be to the contents of the temporary
# directory. If the contents of the file do not match an error is
# registered. Xcode projects are compared in an UUID agnostic way.
#
# Notes:
#
# - The output of the pod command is saved in the `execution_output.txt` file
# which should be added to the `after` folder to test the CocoaPods UI.
# - To create a new test, just create a before folder with the environment to
# test, copy it to the after folder and run the tested pod command inside.
# Then just add the tests below this files with the name of the folder and
# the arguments.
#
# Rationale:
#
# - Have a way to track precisely the evolution of the artifacts (and of the
# UI) produced by CocoaPods (git diff of the after folders).
# - Allow users to submit pull requests with the environment necessary to
# reproduce an issue.
# - Have robust tests which don't depend on the programmatic interface of
# CocoaPods. These tests depend only the binary and its arguments and thus are
# suitable for testing CP regardless of the implementation (they could even
# work for an Objective-C one)
#-----------------------------------------------------------------------------#
# @return [Pathname] The root of the repo.
#
ROOT = Pathname.new(File.expand_path('../../', __FILE__)) unless defined? ROOT
$:.unshift((ROOT + 'spec').to_s)
require 'rubygems'
require 'bundler/setup'
require 'pretty_bacon'
require 'CLIntegracon'
require 'colored2'
require 'cocoapods-core/lockfile'
require 'cocoapods-core/yaml_helper'
require 'fileutils'
require 'integration/file_tree'
require 'integration/xcodeproj_project_yaml'
require 'tmpdir'
if (developer_bin = `xcode-select -p 2>/dev/null`.strip) && $?.success?
developer_bin = Pathname(developer_bin) + 'usr/bin'
ENV['PATH'] = "#{developer_bin}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
end
CLIntegracon.configure do |c|
c.spec_path = ROOT + 'spec/cocoapods-integration-specs'
c.temp_path = ROOT + 'tmp'
# Transform produced project files to YAMLs
c.transform_produced '**/*.xcodeproj' do |path|
# Creates a YAML representation of the Xcodeproj files
# which should be used as a reference for comparison.
xcodeproj = Xcodeproj::Project.open(path)
yaml = xcodeproj.to_yaml
path.rmtree
path.open('w') { |f| f << yaml }
end
c.transform_produced '**/*.framework' do |path|
tree = FileTree.to_tree(path)
path.rmtree
path.open('w') { |f| f << tree }
end
# Register special handling for YAML files
c.transform_produced %r{(^|/)(Podfile|Manifest).lock$} do |path|
# Remove CocoaPods version & Podfile checksum
yaml = YAML.load(path.read)
deleted_keys = ['COCOAPODS', 'PODFILE CHECKSUM']
deleted_keys.each { |key| yaml.delete(key) }
keys_hint = Pod::Lockfile::HASH_KEY_ORDER - deleted_keys
path.open('w') { |f| f << Pod::YAMLHelper.convert_hash(yaml, keys_hint, "\n\n") }
end
c.preprocess('**/*.xcodeproj', %r{(^|/)(Podfile|Manifest).lock$}) do |path|
keys_hint = if path.extname == '.lock'
Pod::Lockfile::HASH_KEY_ORDER
end
contents = path.read
if contents.strip.empty?
contents
else
Pod::YAMLHelper.convert_hash(YAML.load(contents), keys_hint, "\n\n")
end
end
# So we don't need to compare them directly
c.ignores 'Podfile'
# Ignore certain OSX files
c.ignores '.DS_Store'
# Ignore xcuserdata
c.ignores %r{/xcuserdata/}
# Needed for some test cases
c.ignores '*.podspec'
c.ignores 'PodTest-hg-source/**/*'
c.hook_into :bacon
end
describe_cli 'pod' do
Process.wait(spawn('which hg', :err => :out, :out => '/dev/null'))
has_mercurial = $?.success?
subject do |s|
s.executable = "ruby #{ROOT + 'bin/pod'}"
s.environment_vars = {
'CLAIDE_DISABLE_AUTO_WRAP' => 'TRUE',
'COCOAPODS_DISABLE_STATS' => 'TRUE',
'COCOAPODS_SKIP_CACHE' => 'TRUE',
'COCOAPODS_VALIDATOR_SKIP_XCODEBUILD' => 'TRUE',
'CP_REPOS_DIR' => ROOT + 'spec/fixtures/spec-repos',
}
s.default_args = [
'--verbose',
'--no-ansi',
]
s.replace_path %r{#{CLIntegracon.shared_config.temp_path}/\w+/transformed}, 'PROJECT'
s.replace_path ROOT.to_s, 'ROOT'
s.replace_path `which git`.chomp, 'GIT_BIN'
s.replace_path `which hg`.chomp, 'HG_BIN' if has_mercurial
s.replace_path `which bash`.chomp, 'BASH_BIN'
s.replace_path `which curl`.chomp, 'CURL_BIN'
s.replace_user_path 'Library/Caches/CocoaPods', 'CACHES_DIR'
s.replace_pattern /#{Dir.tmpdir}\/[\w-]+/io, 'TMPDIR'
s.replace_pattern /\d{4}-\d\d-\d\d \d\d:\d\d:\d\d [-+]\d{4}/, '<#DATE#>'
s.replace_pattern /\(Took \d+.\d+ seconds\)/, '(Took <#DURATION#> seconds)'
# This was changed in a very recent git version
s.replace_pattern /git checkout -b <new-branch-name>/, 'git checkout -b new_branch_name'
# git sometimes prints this, but not always ¯\_(ツ)_/¯
s.replace_pattern /^\s*Checking out files.*done\./, ''
s.replace_path %r{
`[^`]*? # The opening backtick on a plugin path
([[[:alnum:]]_+-]+?) # The plugin name
(- ([[:xdigit:]]+ | #{Gem::Version::VERSION_PATTERN}))? # The version or SHA
/lib/cocoapods_plugin.rb # The actual plugin file that gets loaded
}iox, '`\1/lib/cocoapods_plugin.rb'
s.replace_pattern %r{
^(\s* \$ \s (CURL_BIN | #{`which curl`.strip}) .* \n)
^\s* % \s* Total .* \n
^\s* Dload \s* Upload .* \n
(^\s* [[:cntrl:]] .* \n)+
}iox, "\\1\n"
end
describe 'Pod install' do
# Test installation with no integration
# Test subspecs inheritance
#--------------------------------------#
describe 'Pod init' do
describe 'Initializes a Podfile with a single platform' do
behaves_like cli_spec 'init_single_platform',
'init'
end
end
#--------------------------------------#
describe 'Integrates a project with an empty Podfile with CocoaPods' do
behaves_like cli_spec 'install_no_dependencies',
'install --no-repo-update'
end
describe 'Integrates a project with CocoaPods' do
behaves_like cli_spec 'install_new',
'install --no-repo-update'
end
describe 'Adds a Pod to an existing installation' do
behaves_like cli_spec 'install_add_pod',
'install --no-repo-update'
end
describe 'Removes a Pod from an existing installation' do
behaves_like cli_spec 'install_remove_pod',
'install --no-repo-update'
end
describe 'Creates an installation with multiple target definitions' do
behaves_like cli_spec 'install_multiple_targets',
'install --no-repo-update'
end
description = 'Installs a Pod with different subspecs activated across different targets'
if has_mercurial
describe description do
behaves_like cli_spec 'install_subspecs',
'install --no-repo-update'
end
else
Bacon::ErrorLog << "[!] Skipping test due to missing `hg` executable: #{description}".red << "\n\n"
end
describe 'Installs a Pod with subspecs and does not duplicate the prefix header' do
behaves_like cli_spec 'install_subspecs_no_duplicate_prefix',
'install --no-repo-update'
end
describe 'Installs a Pod with a local source' do
behaves_like cli_spec 'install_local_source',
'install --no-repo-update'
end
description = 'Installs a Pod with an external source'
if has_mercurial
describe description do
behaves_like cli_spec 'install_external_source',
'install --no-repo-update'
end
else
Bacon::ErrorLog << "[!] Skipping test due to missing `hg` executable: #{description}".red << "\n\n"
end
describe 'Installs a Pod given the podspec' do
behaves_like cli_spec 'install_podspec',
'install --no-repo-update'
end
describe 'Installs a Pod with a custom module map' do
behaves_like cli_spec 'install_custom_module_map',
'install --no-repo-update'
end
describe 'Installs a Pod with a custom module name' do
behaves_like cli_spec 'install_custom_module_name',
'install --no-repo-update'
end
describe 'Performs an installation using a custom workspace' do
behaves_like cli_spec 'install_custom_workspace',
'install --no-repo-update'
end
describe 'Integrates a target with custom build settings' do
behaves_like cli_spec 'install_custom_build_configuration',
'install --no-repo-update'
end
describe 'Integrates a Pod with resources' do
behaves_like cli_spec 'install_resources',
'install --no-repo-update'
end
describe 'Integrates a Pod without source files but with resources' do
behaves_like cli_spec 'install_resources_no_source_files',
'install --no-repo-update'
end
describe 'Integrates a Pod using frameworks with resources' do
behaves_like cli_spec 'install_framework_resources',
'install --no-repo-update'
end
describe 'Integrates a Pod using non Objective-C source files' do
behaves_like cli_spec 'install_non_objective_c_files',
'install --no-repo-update'
end
describe 'Integrates a Pod using a dynamic vendored framework' do
# We have to disable verbose mode by adding --no-verbose here,
# otherwise curl output is included in execution output.
behaves_like cli_spec 'install_vendored_dynamic_framework',
'install --no-repo-update --no-verbose'
end
# @todo add tests for all the hooks API
#
describe 'Runs the Podfile callbacks' do
behaves_like cli_spec 'install_podfile_callbacks',
'install --no-repo-update'
end
describe 'Uses Lockfile checkout options' do
behaves_like cli_spec 'install_using_checkout_options',
'install --no-repo-update'
end
describe 'Integrates a pod with search paths inheritance' do
behaves_like cli_spec 'install_search_paths_inheritance',
'install --no-repo-update'
end
describe 'Integrates a Pod with circular subspec dependencies' do
behaves_like cli_spec 'install_circular_subspec_dependency',
'install --no-repo-update'
end
end
#--------------------------------------#
describe 'Pod update' do
describe 'Updates an existing installation' do
behaves_like cli_spec 'update_all',
'update --no-repo-update'
end
describe 'Updates a selected Pod in an existing installation' do
behaves_like cli_spec 'update_selected',
'update Reachability --no-repo-update'
end
end
#--------------------------------------#
describe 'Pod lint' do
describe 'Lints a Pod from source with a prepare_command' do
# We have to disable verbose mode by adding --no-verbose here,
# otherwise xcodebuild output is included in execution output.
behaves_like cli_spec 'lib_lint_with_prepare_command',
'lib lint',
'--no-verbose'
end
describe 'Lints a Pod' do
behaves_like cli_spec 'spec_lint',
'spec lint --quick'
end
describe 'Lints a remote Pod' do
spec_url = 'https://github.com/CocoaPods/Specs/raw/2d939ca0abb4172b9ef087d784b43e0696109e7c/Specs/A2DynamicDelegate/2.0.2/A2DynamicDelegate.podspec.json'
behaves_like cli_spec 'spec_lint_remote',
"spec lint --quick --allow-warnings --silent #{spec_url}"
end
end
#--------------------------------------#
end