Commit 946380c7 authored by Fabio Pelosin's avatar Fabio Pelosin

Merge pull request #2371 from mrackwitz/clintegracon

Use CLIntegracon for Integration Tests
parents 4965bade 237a88d6
...@@ -4,10 +4,16 @@ To install or update CocoaPods see this [guide](http://docs.cocoapods.org/guides ...@@ -4,10 +4,16 @@ To install or update CocoaPods see this [guide](http://docs.cocoapods.org/guides
## Master ## Master
##### Enhancements
* Display indication for deprecated pods when searching for Pods. * Display indication for deprecated pods when searching for Pods.
[Hugo Tunius][k0nserv] [Hugo Tunius][k0nserv]
[#2180](https://github.com/CocoaPods/CocoaPods/issues/2180) [#2180](https://github.com/CocoaPods/CocoaPods/issues/2180)
* Use gem CLIntegracon for the integration tests.
[Marius Rackwitz][mrackwitz]
[#2371](https://github.com/CocoaPods/CocoaPods/issues/2371)
##### Bug Fixes ##### Bug Fixes
* Fixed pod repo push to first check if Specs directory exists and if so push * Fixed pod repo push to first check if Specs directory exists and if so push
...@@ -2465,5 +2471,5 @@ allowing you to automate Xcode related tasks. ...@@ -2465,5 +2471,5 @@ allowing you to automate Xcode related tasks.
[irrationalfab]: https://github.com/irrationalfab [irrationalfab]: https://github.com/irrationalfab
[kylef]: (https://github.com/kylef) [kylef]: (https://github.com/kylef)
[neonichu]: (https://github.com/neonichu) [neonichu]: (https://github.com/neonichu)
[mrackwitz]: https://github.com/mrackwitz
[k0nserv]: https://github.com/k0nserv [k0nserv]: https://github.com/k0nserv
...@@ -21,6 +21,7 @@ group :development do ...@@ -21,6 +21,7 @@ group :development do
gem "bacon" gem "bacon"
gem "mocha-on-bacon" gem "mocha-on-bacon"
gem 'prettybacon' gem 'prettybacon'
gem 'clintegracon'
gem 'webmock', "< 1.16" gem 'webmock', "< 1.16"
# For the integration tests # For the integration tests
......
...@@ -92,6 +92,9 @@ GEM ...@@ -92,6 +92,9 @@ GEM
addressable (2.3.6) addressable (2.3.6)
awesome_print (1.2.0) awesome_print (1.2.0)
bacon (1.2.0) bacon (1.2.0)
clintegracon (0.5.2)
colored (~> 1.2)
diffy
coderay (1.1.0) coderay (1.1.0)
colored (1.2) colored (1.2)
coveralls (0.7.0) coveralls (0.7.0)
...@@ -175,6 +178,7 @@ DEPENDENCIES ...@@ -175,6 +178,7 @@ DEPENDENCIES
awesome_print awesome_print
bacon bacon
claide! claide!
clintegracon
cocoapods! cocoapods!
cocoapods-core! cocoapods-core!
cocoapods-downloader! cocoapods-downloader!
......
...@@ -37,274 +37,83 @@ ...@@ -37,274 +37,83 @@
#-----------------------------------------------------------------------------# #-----------------------------------------------------------------------------#
# The spec helper is not required on purpose to keep those tests segregated.
# It would also create issues because it clears the temp folder before every
# requirement (`it` call).
require 'pathname'
# @return [Pathname] The root of the repo. # @return [Pathname] The root of the repo.
# #
ROOT = Pathname.new(File.expand_path('../../', __FILE__)) unless defined? ROOT ROOT = Pathname.new(File.expand_path("../../", __FILE__)) unless defined? ROOT
$:.unshift((ROOT + 'spec').to_s)
require 'rubygems' require 'rubygems'
require 'bundler/setup' require 'bundler/setup'
require 'pretty_bacon' require 'pretty_bacon'
require 'colored' require 'colored'
require 'diffy' require "clintegracon"
require 'xcodeproj' # For Differ require "integration/xcodeproj_project_yaml"
# @return [Pathname The folder where the CocoaPods binary should operate.
#
TMP_DIR = ROOT + 'tmp' unless defined? TMP_DIR
# @return [String] The CocoaPods binary to use for the tests.
#
POD_BINARY = "ruby " + ROOT.to_s + '/bin/pod' unless defined? POD_BINARY
#-----------------------------------------------------------------------------#
# @!group Helpers
# Copies the before subdirectory of the given tests folder in the temporary
# directory.
#
# @param [String] folder
# the name of the folder of the tests.
#
def copy_files(folder)
source = File.expand_path("../cocoapods-integration-specs/#{folder}/before", __FILE__)
destination = TMP_DIR + folder
destination.mkpath
FileUtils.cp_r(Dir.glob("#{source}/*"), destination)
end
# Runs the Pod executable with the given arguments in the temporary directory.
#
# @param [String] arguments
# the arguments to pass to the CocoaPods binary.
#
# @note If the pod binary is called with the ruby executable it requires
# bundler ensuring that the execution is performed in the correct
# environment.
#
def launch_binary(arguments, folder)
command = "CP_AGGRESSIVE_CACHE=TRUE #{POD_BINARY} #{arguments} --verbose --no-ansi 2>&1"
Dir.chdir(TMP_DIR + folder) do
output = `#{command}`
it "$ pod #{arguments}" do
$?.should.satisfy("Pod binary failed\n\n#{output}") do
$?.success?
end
end
File.open('execution_output.txt', 'w') do |file| CLIntegracon.configure do |c|
file.write(command.gsub(POD_BINARY, '$ pod')) c.spec_path = ROOT + "spec/cocoapods-integration-specs"
file.write(output.gsub(ROOT.to_s, 'ROOT').gsub(%r[/Users/.*/Library/Caches/CocoaPods/],"CACHES_DIR/")) c.temp_path = ROOT + "tmp"
end
end
$?.success?
end
# Creates a YAML representation of the Xcodeproj files which should be used as # Transform produced project files to YAMLs
# a reference. c.transform_produced "**/*.xcodeproj" do |path|
# # Creates a YAML representation of the Xcodeproj files
def run_post_execution_actions(folder) # which should be used as a reference for comparison.
Dir.glob("#{TMP_DIR + folder}/**/*.xcodeproj") do |project_path| xcodeproj = Xcodeproj::Project.open(path)
xcodeproj = Xcodeproj::Project.open(project_path) File.open("#{path}.yaml", "w") do |file|
require 'yaml' file.write xcodeproj.to_yaml
pretty_print = xcodeproj.pretty_print
sections = []
sorted_keys = ['File References', 'Targets', 'Build Configurations']
sorted_keys.each do |key|
yaml = { key => pretty_print[key]}.to_yaml
sections << yaml
end
file_contents = (sections * "\n\n").gsub!("---",'')
File.open("#{project_path}.yaml", 'w') do |file|
file.write(file_contents)
end end
end end
end
# Creates a requirement which compares every file in the after folder with the # Register special handling for YAML files
# artifacts created by the pod executable in the temporary directory according paths = [%r{Podfile\.lock}, %r{Manifest\.lock$}, %r{xcodeproj\.yaml$}]
# to its file type. c.has_special_handling_for *paths do |path|
# if RUBY_VERSION < "1.9"
# @param [String] folder nil # CP is not sorting array derived from hashes whose order is
# the name of the folder of the tests. # undefined in 1.8.7
#
def check_with_folder(folder)
source = File.expand_path("../cocoapods-integration-specs/#{folder}", __FILE__)
Dir.glob("#{source}/after/**/*") do |expected_path|
next unless File.file?(expected_path)
relative_path = expected_path.gsub("#{source}/after/", '')
expected = Pathname.new(expected_path)
produced = TMP_DIR + folder + relative_path
case expected_path
when %r[/xcuserdata/], %r[\.pbxproj$]
# Projects are compared through the more readable yaml representation
next
when %r[execution_output.txt$]
# TODO The output from the caches changes on Travis
next
end
it relative_path do
case expected_path
when %r[Podfile\.lock$], %r[Manifest\.lock$], %r[xcodeproj\.yaml$]
file_should_exist(produced)
yaml_should_match(expected, produced)
else else
file_should_exist(produced)
file_should_match(expected, produced)
end
end
end
end
#--------------------------------------#
# @!group File Comparisons
# Checks that the file exits.
#
# @param [Pathname] file
# The file to check.
#
def file_should_exist(file)
file.should.exist?
end
# Compares two lockfiles because CocoaPods 0.16 doesn't oder them in 1.8.7.
#
# @param [Pathname] expected
# The reference in the `after` folder.
#
# @param [Pathname] produced
# The file in the temporary directory after running the pod command.
#
def yaml_should_match(expected, produced)
expected_yaml = File.open(expected) { |f| YAML.load(f) }
produced_yaml = File.open(produced) { |f| YAML.load(f) }
# Remove CocoaPods version # Remove CocoaPods version
expected_yaml.delete('COCOAPODS') yaml = File.open(path) { |f| YAML.load(f) }
produced_yaml.delete('COCOAPODS') yaml.delete("COCOAPODS")
desc = [] yaml.to_s
desc << "YAML comparison error `#{expected}`"
desc << ("--- YAML DIFF " << "-" * 65)
diffy_diff = ''
Diffy::Diff.new(expected.to_s, produced.to_s, :source => 'files', :context => 3).each do |line|
case line
when /^\+/ then diffy_diff << line.green
when /^-/ then diffy_diff << line.red
else diffy_diff << line
end end
end end
desc << diffy_diff
desc << ("--- XCODEPROJ DIFF " << "-" * 60) # So we don't need to compare them directly
diff_options = {:key_1 => "$produced", :key_2 => "$expected"} c.ignores %r{\.xcodeproj/}
diff = Xcodeproj::Differ.diff(produced_yaml, expected_yaml, diff_options).to_yaml c.ignores "Podfile"
diff.gsub!("$produced", "produced".green)
diff.gsub!("$expected", "expected".red)
desc << diff
desc << ("--- END " << "-" * 70)
expected_yaml.should.satisfy(desc * "\n\n") do # Ignore certain OSX files
if RUBY_VERSION < "1.9" c.ignores ".DS_Store"
true # CP is not sorting array derived from hashes whose order is
# undefined in 1.8.7
else
expected_yaml == produced_yaml
end
end
end
# Compares two Xcode projects in an UUID insensitive fashion and producing a # Ignore xcuserdata
# clear diff to highlight the differences. c.ignores %r{/xcuserdata/}
#
# @param [Pathname] expected @see #yaml_should_match
# @param [Pathname] produced @see #yaml_should_match
#
# def xcodeproj_should_match(expected, produced)
# expected_proj = Xcodeproj::Project.open(expected + '..')
# produced_proj = Xcodeproj::Project.open(produced + '..')
# diff = produced_proj.to_tree_hash.recursive_diff(expected_proj.to_tree_hash, "#produced#", "#reference#")
# desc = "Project comparison error `#{expected}`"
# if diff
# desc << "\n\n#{diff.inspect.cyan}"
# pretty_yaml = diff.to_yaml
# pretty_yaml = pretty_yaml.gsub(/['"]#produced#['"]/,'produced'.cyan)
# pretty_yaml = pretty_yaml.gsub(/['"]#reference#['"]/,'reference'.magenta)
# desc << "\n\n#{pretty_yaml}"
# end
# diff.should.satisfy(desc) do |diff|
# diff.nil?
# end
# end
# Compares two files to check if they are identical and produces a clear diff
# to highlight the differences.
#
# @param [Pathname] expected @see #yaml_should_match
# @param [Pathname] produced @see #yaml_should_match
#
def file_should_match(expected, produced)
is_equal = FileUtils.compare_file(expected, produced)
description = []
description << "File comparison error `#{expected}`"
description << ""
description << ("--- DIFF " << "-" * 70)
Diffy::Diff.new(expected.to_s, produced.to_s, :source => 'files', :context => 3).each do |line|
case line
when /^\+/ then description << line.gsub("\n",'').green
when /^-/ then description << line.gsub("\n",'').red
else description << line.gsub("\n",'')
end
end
description << ("--- END " << "-" * 70)
description << ""
is_equal.should.satisfy(description * "\n") do
is_equal == true
end
end
#-----------------------------------------------------------------------------# # TODO The output from the caches changes on Travis
c.ignores "execution_output.txt"
# @!group Description implementation # Needed for some test cases
c.ignores "Reachability.podspec"
c.ignores "PodTest-hg-source/**"
# Performs the checks for the test with the given folder using the given c.hook_into :bacon
# arguments.
#
# @param [String] arguments
# The arguments to pass to the Pod executable.
#
# @param [String] folder
# The name of the folder which contains the `before` and `after`
# subfolders.
#
def check(arguments, folder)
focused_check(arguments, folder)
end end
# Shortcut to focus on a test: Comment the implementation of #check and
# call this from the relevant test.
#
def focused_check(arguments, folder)
copy_files(folder)
executed = launch_binary(arguments, folder)
run_post_execution_actions(folder)
check_with_folder(folder) if executed
end
#-----------------------------------------------------------------------------# describe_cli "pod" do
describe "Integration" do subject do |s|
TMP_DIR.rmtree if TMP_DIR.exist? s.executable = "ruby #{ROOT + "bin/pod"}"
TMP_DIR.mkpath s.environment_vars = {
"CP_AGGRESSIVE_CACHE" => "TRUE"
}
s.default_args = [
"--verbose",
"--no-ansi"
]
s.replace_path ROOT.to_s, "ROOT"
s.replace_user_path "Library/Caches/CocoaPods", "CACHES_DIR"
end
describe "Pod install" do describe "Pod install" do
...@@ -312,53 +121,65 @@ describe "Integration" do ...@@ -312,53 +121,65 @@ describe "Integration" do
# Test subspecs inheritance # Test subspecs inheritance
describe "Integrates a project with CocoaPods" do describe "Integrates a project with CocoaPods" do
check "install --no-repo-update", "install_new" behaves_like cli_spec "install_new",
"install --no-repo-update"
end end
describe "Adds a Pod to an existing installation" do describe "Adds a Pod to an existing installation" do
check "install --no-repo-update", "install_add_pod" behaves_like cli_spec "install_add_pod",
"install --no-repo-update"
end end
describe "Removes a Pod from an existing installation" do describe "Removes a Pod from an existing installation" do
check "install --no-repo-update", "install_remove_pod" behaves_like cli_spec "install_remove_pod",
"install --no-repo-update"
end end
describe "Creates an installation with multiple target definitions" do describe "Creates an installation with multiple target definitions" do
check "install --no-repo-update", "install_multiple_targets" behaves_like cli_spec "install_multiple_targets",
"install --no-repo-update"
end end
describe "Installs a Pod with different subspecs activated across different targets" do describe "Installs a Pod with different subspecs activated across different targets" do
check "install --no-repo-update", "install_subspecs" behaves_like cli_spec "install_subspecs",
"install --no-repo-update"
end end
describe "Installs a Pod with subspecs and does not duplicate the prefix header" do describe "Installs a Pod with subspecs and does not duplicate the prefix header" do
check "install --no-repo-update", "install_subspecs_no_duplicate_prefix" behaves_like cli_spec "install_subspecs_no_duplicate_prefix",
"install --no-repo-update"
end end
describe "Installs a Pod with a local source" do describe "Installs a Pod with a local source" do
check "install --no-repo-update", "install_local_source" behaves_like cli_spec "install_local_source",
"install --no-repo-update"
end end
describe "Installs a Pod with an external source" do describe "Installs a Pod with an external source" do
check "install --no-repo-update", "install_external_source" behaves_like cli_spec "install_external_source",
"install --no-repo-update"
end end
describe "Installs a Pod given the podspec" do describe "Installs a Pod given the podspec" do
check "install --no-repo-update", "install_podspec" behaves_like cli_spec "install_podspec",
"install --no-repo-update"
end end
describe "Performs an installation using a custom workspace" do describe "Performs an installation using a custom workspace" do
check "install --no-repo-update", "install_custom_workspace" behaves_like cli_spec "install_custom_workspace",
"install --no-repo-update"
end end
describe "Integrates a target with custom build settings" do describe "Integrates a target with custom build settings" do
check "install --no-repo-update", "install_custom_build_configuration" behaves_like cli_spec "install_custom_build_configuration",
"install --no-repo-update"
end end
# @todo add tests for all the hooks API # @todo add tests for all the hooks API
# #
describe "Runs the Podfile callbacks" do describe "Runs the Podfile callbacks" do
check "install --no-repo-update", "install_podfile_callbacks" behaves_like cli_spec "install_podfile_callbacks",
"install --no-repo-update"
end end
end end
...@@ -367,11 +188,13 @@ describe "Integration" do ...@@ -367,11 +188,13 @@ describe "Integration" do
describe "Pod update" do describe "Pod update" do
describe "Updates an existing installation" do describe "Updates an existing installation" do
check "update --no-repo-update", "update_all" behaves_like cli_spec "update_all",
"update --no-repo-update"
end end
describe "Updates a selected Pod in an existing installation" do describe "Updates a selected Pod in an existing installation" do
check "update Reachability --no-repo-update", "update_selected" behaves_like cli_spec "update_selected",
"update Reachability --no-repo-update"
end end
end end
...@@ -381,7 +204,8 @@ describe "Integration" do ...@@ -381,7 +204,8 @@ describe "Integration" do
describe "Pod lint" do describe "Pod lint" do
describe "Lints a Pod" do describe "Lints a Pod" do
check "spec lint --quick", "spec_lint" behaves_like cli_spec "spec_lint",
"spec lint --quick"
end end
end end
...@@ -391,7 +215,8 @@ describe "Integration" do ...@@ -391,7 +215,8 @@ describe "Integration" do
describe "Pod init" do describe "Pod init" do
describe "Initializes a Podfile with a single platform" do describe "Initializes a Podfile with a single platform" do
check "init", "init_single_platform" behaves_like cli_spec "init_single_platform",
"init"
end end
end end
......
require "xcodeproj"
require "yaml"
class Xcodeproj::Project
def to_yaml
pretty_print_output = pretty_print
sections = []
sorted_keys = ["File References", "Targets", "Build Configurations"]
sorted_keys.each do |key|
yaml = { key => pretty_print_output[key] }.to_yaml
sections << yaml
end
(sections * "\n\n").gsub!("---", '')
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