cocoapods-unit-test 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 141801ab890eb855285c6536ea74d179ea11bdd09de628f0107492b44af96065
4
+ data.tar.gz: 45213aa79c396edbd79749e4f759a65b092bcb651b123c2c1f617c20d002bf32
5
+ SHA512:
6
+ metadata.gz: 87b5c7bc63cd7ca0d6ae7d84d3fef4ff175db3cbf2ac8e0b55605bb3d8006bf236eb5da62079141e93f516e6f4b40f7b3360eb6a89576de92bf82f4778d5098b
7
+ data.tar.gz: 7d869825eab17f3b1d923b335db37c7d7660d89ab34f11d202addd46cc3bfc14c7001a23e470c71cee48c677af0e5bddbee70aa57ed9fb68cab021acaa77d27f
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .DS_Store
2
+ pkg
3
+ .idea/
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cocoapods-unit-test.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem 'cocoapods'
8
+
9
+ gem 'mocha'
10
+ gem 'bacon'
11
+ gem 'mocha-on-bacon'
12
+ gem 'prettybacon'
13
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2020 bob <bob170731@gmail.com>
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # cocoapods-unit-test
2
+
3
+ A cocoapods plugin to work with Unit-Test
4
+
5
+ ## Installation
6
+
7
+ Just install it
8
+
9
+ ```
10
+ gem install cocoapods-unit-test
11
+ ```
12
+
13
+ or use Gemfile with `bundle install`
14
+
15
+ ```
16
+ source 'https://rubygems.org/'
17
+
18
+ gem 'cocoapods', '>= 1.8.4'
19
+ gem 'xcpretty','~> 0.3.0'
20
+ gem 'cocoapods-unit-test','~ 1.0'
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ### 1. modify Podspec
26
+
27
+ - add test_spec
28
+ - add dependency XcodeCoverage
29
+
30
+ ```
31
+ Pod::Spec.new do |s|
32
+ s.name = 'TestExample'
33
+ ...
34
+
35
+ s.subspec 'Core' do |c|
36
+ ...
37
+ end
38
+
39
+ s.test_spec 'Tests' do |h|
40
+ h.source_files = 'TestExample/Tests/**/*.{h,m}'
41
+ h.dependency 'TestExample/Core'
42
+ h.dependency 'XcodeCoverage','>= 1.3.2'
43
+ h.frameworks = 'UIKit','Foundation'
44
+ end
45
+ end
46
+
47
+ ```
48
+
49
+ ### 2. Add plugin in Podfile
50
+
51
+ - if you just test with develop pod, ignore the names parameter
52
+ - or use names if you have more than one pod to Test
53
+
54
+ ```
55
+
56
+ ## use names if you have more than one pod to Test
57
+ plugin 'cocoapods-unit-test',
58
+ :names => ["TestExample"]
59
+
60
+
61
+ target 'Example' do
62
+ pod 'XcodeCoverage', '>= 1.3.2'
63
+ pod 'TestExample',
64
+ :path => '../',
65
+ :testspecs => ["Tests"]
66
+ end
67
+
68
+ ```
69
+
70
+ ### 3. run pod install
71
+
72
+ ```
73
+ bundle exec pod install
74
+ ```
75
+
76
+ ### 4. Testing
77
+
78
+ - testing with cli with pod name `TestExample`
79
+ - simulator default is iPhone 8, you can change it
80
+
81
+ ```
82
+ bundle exec pod test TestExample --simulator='iPhone 8'
83
+ ```
84
+
85
+ - auto open result or you can check it
86
+
87
+
88
+
89
+ ## Example
90
+
91
+ see []
92
+
93
+ ## Contribute
94
+
95
+ if you like
96
+
97
+
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ def specs(dir)
4
+ FileList["spec/#{dir}/*_spec.rb"].shuffle.join(' ')
5
+ end
6
+
7
+ desc 'Runs all the specs'
8
+ task :specs do
9
+ sh "bundle exec bacon #{specs('**')}"
10
+ end
11
+
12
+ task :default => :specs
13
+
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cocoapods-unit-test/gem_version.rb'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'cocoapods-unit-test'
8
+ spec.version = CocoapodsUnitTest::VERSION
9
+ spec.authors = ['bob']
10
+ spec.email = ['bob170731@gmail.com']
11
+ spec.description = %q{A short description of cocoapods-unit-test.}
12
+ spec.summary = %q{A longer description of cocoapods-unit-test.}
13
+ spec.homepage = 'https://github.com/DanboDuan/cocoapods-unit-test'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'xcodeproj','~> 1.10'
22
+ spec.add_dependency 'cocoapods-core','~> 1.8'
23
+ spec.add_dependency 'cocoapods','~> 1.8'
24
+ spec.add_dependency 'xcpretty','~> 0.3'
25
+ spec.add_dependency 'neatjson','~> 0.9'
26
+
27
+ spec.add_development_dependency 'bundler', '~> 1.3'
28
+ spec.add_development_dependency 'rake','~> 10'
29
+ end
@@ -0,0 +1,48 @@
1
+ require 'cocoapods-unit-test/project'
2
+
3
+ module Pod
4
+ class Command
5
+ class Test < Command
6
+
7
+ self.summary = 'Short description of cocoapods-unit-test.'
8
+ self.command = 'test'
9
+ self.description = <<-DESC
10
+ Longer description of cocoapods-unit-test.
11
+ DESC
12
+
13
+ self.arguments = [
14
+ CLAide::Argument.new('NAME', true),
15
+ ]
16
+ def self.options
17
+ options = [
18
+ ['--reinstall', 're pod install'],
19
+ ["--simulator='SIMULATOR'", "simulator name like 'iPhone 8'"],
20
+ ]
21
+ options.concat(super.reject { |option, _| option == '--silent' })
22
+ end
23
+
24
+ def initialize(argv)
25
+ @simulator = argv.option('simulator', 'iPhone 8')
26
+ @reinstall = argv.flag?('reinstall')
27
+ @name = argv.shift_argument
28
+ @project = TestProject.new(@name, @simulator)
29
+ super
30
+ end
31
+
32
+ def validate!
33
+ super
34
+ help! 'A Pod name is required.' unless @name
35
+ @project.validate!
36
+ end
37
+
38
+ def run
39
+ UI.title "Runing Test..." do
40
+ @project.run(@reinstall)
41
+ end
42
+
43
+ UI.title "Finish Test..."
44
+
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1 @@
1
+ require 'cocoapods-unit-test/command/test'
@@ -0,0 +1,146 @@
1
+ require 'open3'
2
+ module Pod
3
+ module UnitExecutable
4
+
5
+ def executable(name)
6
+ unless respond_to?("#{name.to_s}!")
7
+ define_method(name.to_s + '!') do |*command|
8
+ UnitExecutable.execute_command(name, Array(command).flatten, true)
9
+ end
10
+ end
11
+
12
+ end
13
+
14
+ def self.execute_command(executable, command, raise_on_failure = true)
15
+ bin = which!(executable)
16
+
17
+ command = command.map(&:to_s)
18
+ if File.basename(bin) == 'tar.exe'
19
+ # Tar on Windows needs --force-local
20
+ command.push('--force-local')
21
+ end
22
+ full_command = "#{bin} #{command.join(' ')}"
23
+
24
+ stdout = Indenter.new(STDOUT)
25
+ stderr = Indenter.new(STDERR)
26
+
27
+ status = popen3(bin, command, stdout, stderr)
28
+ stdout = stdout.join
29
+ stderr = stderr.join
30
+ output = stdout + stderr
31
+ unless status.success?
32
+ UI.puts("$ #{full_command}")
33
+ if raise_on_failure
34
+ raise Informative, "#{full_command}\n\n#{output}"
35
+ else
36
+ UI.puts("[!] Failed: #{full_command}".red)
37
+ end
38
+ end
39
+
40
+ output
41
+ end
42
+
43
+ def self.which(program)
44
+ program = program.to_s
45
+ paths = ENV.fetch('PATH') { '' }.split(File::PATH_SEPARATOR)
46
+ paths.unshift('./')
47
+ paths.uniq!
48
+ paths.each do |path|
49
+ bin = File.expand_path(program, path)
50
+ if Gem.win_platform?
51
+ bin += '.exe'
52
+ end
53
+ if File.file?(bin) && File.executable?(bin)
54
+ return bin
55
+ end
56
+ end
57
+ nil
58
+ end
59
+
60
+ def self.which!(program)
61
+ which(program).tap do |bin|
62
+ raise Informative, "Unable to locate the executable `#{program}`" unless bin
63
+ end
64
+ end
65
+
66
+ def self.capture_command(executable, command, capture: :merge, env: {}, **kwargs)
67
+ bin = which!(executable)
68
+ command = command.map(&:to_s)
69
+ case capture
70
+ when :merge then Open3.capture2e(env, [bin, bin], *command, **kwargs)
71
+ when :both then Open3.capture3(env, [bin, bin], *command, **kwargs)
72
+ when :out then Open3.capture3(env, [bin, bin], *command, **kwargs).values_at(0, -1)
73
+ when :err then Open3.capture3(env, [bin, bin], *command, **kwargs).drop(1)
74
+ when :none then Open3.capture3(env, [bin, bin], *command, **kwargs).last
75
+ end
76
+ end
77
+
78
+ def self.capture_command!(executable, command, **kwargs)
79
+ capture_command(executable, command, **kwargs).tap do |result|
80
+ result = Array(result)
81
+ status = result.last
82
+ unless status.success?
83
+ output = result[0..-2].join
84
+ raise Informative, "#{bin} #{command.join(' ')}\n\n#{output}".strip
85
+ end
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def self.popen3(bin, command, stdout, stderr)
92
+ Open3.popen3(bin, *command) do |i, o, e, t|
93
+ reader(o, stdout)
94
+ reader(e, stderr)
95
+ i.close
96
+
97
+ status = t.value
98
+
99
+ o.flush
100
+ e.flush
101
+ sleep(0.01)
102
+
103
+ status
104
+ end
105
+ end
106
+
107
+ def self.reader(input, output)
108
+ Thread.new do
109
+ buf = ''
110
+ begin
111
+ loop do
112
+ buf << input.readpartial(4096)
113
+ loop do
114
+ string, separator, buf = buf.partition(/[\r\n]/)
115
+ if separator.empty?
116
+ buf = string
117
+ break
118
+ end
119
+ output << (string << separator)
120
+ end
121
+ end
122
+ rescue EOFError, IOError
123
+ output << (buf << $/) unless buf.empty?
124
+ end
125
+ end
126
+ end
127
+
128
+
129
+ class Indenter < ::Array
130
+ attr_reader :indent
131
+ attr_reader :io
132
+
133
+ def initialize(io = nil)
134
+ @io = io
135
+ @indent = ' ' * UI.indentation_level
136
+ end
137
+
138
+ def <<(value)
139
+ super
140
+ io << "#{indent}#{value}" if io
141
+ end
142
+ end
143
+
144
+
145
+ end
146
+ end
@@ -0,0 +1,3 @@
1
+ module CocoapodsUnitTest
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,156 @@
1
+ require 'xcodeproj'
2
+ require 'rubygems'
3
+ require 'cocoapods-unit-test/result'
4
+ require 'cocoapods-unit-test/xcodeproj/project'
5
+
6
+ module Pod
7
+ class TestProject
8
+
9
+ attr_accessor :path
10
+ attr_accessor :podfile
11
+ attr_accessor :pods_project
12
+ attr_accessor :workspace
13
+ attr_accessor :schemes
14
+ attr_accessor :target
15
+ attr_accessor :derived_data_path
16
+ attr_accessor :destination
17
+ attr_accessor :cov_shell
18
+
19
+ def initialize(name, simulator, path = Dir.pwd)
20
+ @destination = "platform=iOS Simulator,name=#{simulator}"
21
+ @target = name
22
+ @path = File.expand_path(path)
23
+ end
24
+
25
+ def podfile
26
+ @podfile ||= File.expand_path("Podfile", path)
27
+ end
28
+
29
+ def workspace
30
+ @workspace ||= begin
31
+ ws = Dir["*.xcworkspace"].first
32
+ raise Informative, "No xcworkspace" if ws.nil? || ws.empty?
33
+ raise Informative, "No xcworkspace in #{path}" unless File.directory?(ws)
34
+ File.expand_path(ws, path)
35
+ end
36
+ end
37
+
38
+ def schemes
39
+ @schemes ||= Dir[File.join(path, '**', 'xcschemes', '*.xcscheme')].select { |e|
40
+ e.include?("-Unit-")
41
+ }.map {|scheme|
42
+ File.basename(scheme, '.xcscheme')
43
+ }.select { |scheme|
44
+ scheme.start_with?("#{target}-Unit")
45
+ }
46
+ end
47
+
48
+ def pods_project
49
+ @pods_project ||= begin
50
+ pods = Dir["**/*.xcodeproj"].select { |e| e.end_with?("Pods.xcodeproj") }
51
+ raise Informative, "can not find Pods.xcodeproj" if pods.empty?
52
+ pod = pods.first
53
+ raise Informative, "can not find Pods.xcodeproj in #{path}" unless File.directory?(pod)
54
+ File.expand_path(pod, path)
55
+ end
56
+ end
57
+
58
+ def validate_target!
59
+ project = Xcodeproj::Project.open(pods_project)
60
+ return true if project.unit_test_dev_pods().include?(@target)
61
+ return true if project.unit_test_dependency_pods().include?(@target)
62
+ raise Informative, "can not find test target #{@target} in Pods.xcodeproj"
63
+ return false
64
+ end
65
+
66
+ def derived_data_path
67
+ @derived_data_path ||= File.expand_path("build/derivedDataPath", path)
68
+ end
69
+
70
+ def result_bundle_path(scheme)
71
+ File.expand_path("build/#{scheme}/Test.xcresult", path)
72
+ end
73
+
74
+ def result_json_path(scheme)
75
+ File.expand_path("build/#{scheme}/TestResult.json", path)
76
+ end
77
+
78
+ def destination
79
+ @destination ||= "platform=iOS Simulator,name=iPhone 8"
80
+ end
81
+
82
+ def archives_path(scheme)
83
+ File.expand_path("build/#{scheme}/archives", path)
84
+ end
85
+
86
+ def cov_shell
87
+ @cov_shell ||= File.expand_path("Pods/XcodeCoverage/getcov", path)
88
+ end
89
+
90
+ def validate!
91
+ raise Informative, "No Podfile!" unless File.file?(podfile)
92
+ validate_target!
93
+ raise Informative, "No Test schemes!" if schemes.empty?
94
+ end
95
+
96
+ def pod_install
97
+ UI.puts "pod install..."
98
+ raise Informative, "Please use a Gemfile or run pod install by yourself" unless File.file?("Gemfile")
99
+ system( "bundle install")
100
+ system( "bundle exec pod install")
101
+ raise Informative, "XcodeCoverage not found" unless File.file?(cov_shell)
102
+ raise Informative, "workspace not found" unless File.directory?(workspace)
103
+ end
104
+
105
+ def run_test_with_scheme(scheme)
106
+ system("rm -fr #{result_bundle_path(scheme)}")
107
+ system("rm -fr #{result_json_path(scheme)}")
108
+ system("rm -fr #{archives_path(scheme)}")
109
+ system("mkdir -p #{archives_path(scheme)}")
110
+
111
+ cmd = %W(xcodebuild test -workspace #{workspace} -scheme #{scheme} -UseModernBuildSystem=NO
112
+ -derivedDataPath #{derived_data_path} -resultBundlePath #{result_bundle_path(scheme)}) + [
113
+ "-destination '#{destination}'",
114
+ "| xcpretty",
115
+ ]
116
+
117
+ UI.puts cmd.join(" ")
118
+ system(cmd.join(" "))
119
+
120
+ cmd = %W(xcrun xcresulttool get --path #{result_bundle_path(scheme)} --format json) + [
121
+ "> #{result_json_path(scheme)}",
122
+ ]
123
+ UI.puts cmd.join(" ")
124
+ system(cmd.join(" "))
125
+
126
+ cmd = %W(#{cov_shell} -x -o #{archives_path(scheme)})
127
+ UI.puts cmd.join(" ")
128
+ system(cmd.join(" "))
129
+
130
+ index_file = File.join(archives_path(scheme),"lcov/index.html")
131
+ TestResult.new(result_json_path(scheme),index_file).parse()
132
+ UI.puts "Test result path #{index_file}"
133
+ system("open #{index_file}") if File.file?(index_file)
134
+ end
135
+
136
+ def run_test
137
+ UI.title "Test target: #{target}" do
138
+ schemes.each { |e| UI.puts "Test Schemes: #{e}" }
139
+ end
140
+
141
+ system( "rm -fr #{derived_data_path}")
142
+ system( "mkdir -p #{derived_data_path}")
143
+
144
+ schemes.each do |scheme|
145
+ UI.puts "Testing #{scheme}..."
146
+ run_test_with_scheme(scheme)
147
+ end
148
+ end
149
+
150
+
151
+ def run(install_flag)
152
+ pod_install if install_flag
153
+ run_test
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,56 @@
1
+ require 'xcodeproj'
2
+ require 'rubygems'
3
+ require "json"
4
+ require 'neatjson'
5
+
6
+ module Pod
7
+ class TestResult
8
+ attr_accessor :cov_path
9
+ attr_accessor :json_path
10
+
11
+ def initialize(json_path, cov_path)
12
+ @json_path = File.expand_path(json_path)
13
+ @cov_path = File.expand_path(cov_path)
14
+ end
15
+
16
+ def parse_json_result
17
+ ## build_success, tests_count, tests_failed_count
18
+ load_json_from_file.fetch("metrics", {}).tap { |result|
19
+ UI.puts "Test case count :" + result.fetch("testsCount", {}).fetch("_value", 0).to_s
20
+ UI.puts "Test case fail count :" + result.fetch("testsFailedCount", {}).fetch("_value", 0).to_s
21
+
22
+ result.fetch("issues", {}).fetch("errorSummaries", {}).fetch("_values", []).each { |issues|
23
+ UI.puts "❌ #{issues.fetch("issueType", {}).fetch("_value", "").to_s} -> #{issues.fetch("message", {}).fetch("_value", "").to_s}"
24
+ }
25
+
26
+ result.fetch("issues", {}).fetch("testFailureSummaries", {}).fetch("_values", []).each { |issues|
27
+ UI.puts "❌ #{issues.fetch("testCaseName", {}).fetch("_value", "").to_s} -> #{issues.fetch("message", {}).fetch("_value", "").to_s}"
28
+ }
29
+ }
30
+ end
31
+
32
+ def parse_cov_result
33
+ ## line_cov fun_cov headerCovTableEntry
34
+ end
35
+
36
+ def parse
37
+ parse_json_result
38
+ parse_cov_result
39
+ end
40
+
41
+ def load_json_from_file
42
+ if File.file?(json_path)
43
+ json_file = File.open json_path
44
+ return JSON.load json_file
45
+ end
46
+ {}
47
+ end
48
+
49
+ def dump_json_to_file(result, file)
50
+ File.open(file,"w") do |w|
51
+ w.write(JSON.neat_generate(result, sort:true, wrap:true, after_colon:1))
52
+ end
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,24 @@
1
+ require 'xcodeproj'
2
+
3
+ module Xcodeproj
4
+ class Project
5
+ module Object
6
+ # Encapsulates the information a specific build configuration referenced
7
+ # by a {XCConfigurationList} which in turn might be referenced by a
8
+ # {PBXProject} or a {PBXNativeTarget}.
9
+ #
10
+ class XCBuildConfiguration
11
+
12
+ def coverage_build_settings=(flag)
13
+ value = 'NO'
14
+ value = 'YES' if flag
15
+
16
+ build_settings['CLANG_ENABLE_CODE_COVERAGE'] = value
17
+ build_settings['GCC_INSTRUMENT_PROGRAM_FLOW_ARCS'] = value
18
+ build_settings['GCC_GENERATE_TEST_COVERAGE_FILES'] = value
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ require 'xcodeproj'
2
+
3
+ module Xcodeproj
4
+ class Project
5
+ module Object
6
+ class AbstractTarget
7
+
8
+ def add_coverage_script_phase
9
+ if shell_script_build_phases.select { |e| e.name == "CodeCoverageScripts" }.length < 1
10
+ codeCoverageScript = new_shell_script_build_phase()
11
+ codeCoverageScript.name = "CodeCoverageScripts"
12
+ codeCoverageScript.shell_path = "/bin/bash"
13
+ codeCoverageScript.shell_script = "${SRCROOT}/XcodeCoverage/exportenv.sh"
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,23 @@
1
+ require 'xcodeproj'
2
+
3
+ module Xcodeproj
4
+ class Project
5
+
6
+ def unit_test_dev_pods
7
+ return groups.select { |e| e.name == "Development Pods" }.map { |e|
8
+ e.children.map { |x| x.to_s }
9
+ }.flatten.uniq
10
+ end
11
+
12
+ def unit_test_dependency_pods
13
+ return groups.select { |e| e.name == "Pods" }.map { |e|
14
+ e.children.map { |x| x.to_s }
15
+ }.flatten.uniq
16
+ end
17
+
18
+ def unit_test_all_pods
19
+ unit_test_dev_pods() + unit_test_dependency_pods()
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,43 @@
1
+ require 'xcodeproj'
2
+ require 'rexml/document'
3
+
4
+ module Xcodeproj
5
+ class XCScheme
6
+ # This class wraps the TestAction node of a .xcscheme XML file
7
+ #
8
+ class TestAction
9
+
10
+ def coverage_specified_targets?
11
+ string_to_bool(@xml_element.attributes['onlyGenerateCoverageForSpecifiedTargets'])
12
+ end
13
+
14
+ # @param [Bool] flag
15
+ def coverage_specified_targets=(flag)
16
+ @xml_element.attributes['onlyGenerateCoverageForSpecifiedTargets'] = bool_to_string(flag)
17
+ end
18
+
19
+ # @param [BuildableReference] targets
20
+ #
21
+ def add_coverage_target_ref(ref)
22
+ coverage_targets = @xml_element.elements['CodeCoverageTargets'] || @xml_element.add_element('CodeCoverageTargets')
23
+
24
+ added = coverage_targets.get_elements('BuildableReference').map { |node|
25
+ BuildableReference.new(node)
26
+ }.select { |build| build.target_name == ref.target_name }
27
+
28
+ if added.empty?
29
+ coverage_targets.add_element(ref.xml_element)
30
+ end
31
+ end
32
+
33
+ # @param [Xcodeproj::Project::Object::AbstractTarget] test_target
34
+ # @param [Xcodeproj::Project] the root project to reference from
35
+ # (when nil the project of the target is used)
36
+ def add_coverage_target(target, root_project = nil)
37
+ add_coverage_target_ref BuildableReference.new(target, root_project) unless target.nil?
38
+ end
39
+
40
+ end
41
+ end
42
+
43
+ end
@@ -0,0 +1 @@
1
+ require 'cocoapods-unit-test/gem_version'
@@ -0,0 +1,94 @@
1
+ require 'cocoapods-unit-test/command'
2
+ require 'cocoapods-unit-test/xcodeproj/test_action'
3
+ require 'cocoapods-unit-test/xcodeproj/native_target'
4
+ require 'cocoapods-unit-test/xcodeproj/build_configuration'
5
+ require 'cocoapods-unit-test/xcodeproj/project'
6
+
7
+ require 'cocoapods-core'
8
+ require 'xcodeproj'
9
+ require 'cocoapods'
10
+
11
+ module CocoapodsUnitTest
12
+
13
+ def self.modify_build_settings(target, is_target)
14
+ target.build_configurations.each {|config| config.coverage_build_settings = is_target}
15
+ if is_target
16
+ target.add_coverage_script_phase()
17
+ end
18
+ end
19
+
20
+ def self.modify_schemes_settings(xcproj, test_specs)
21
+ project_path = xcproj.path
22
+ test_targets = xcproj.targets.select { |target| test_specs.include?(target.name.to_s) }
23
+
24
+ Dir[File.join(project_path, 'xcuserdata', '**', 'xcschemes', '*.xcscheme')].select { |e|
25
+ !test_targets.select { |target|
26
+ File.basename(e, '.xcscheme').start_with?("#{target.name.to_s}-Unit")
27
+ }.empty?
28
+ }.each do |path|
29
+ scheme = File.basename(path, '.xcscheme')
30
+ puts "Check scheme: #{scheme}"
31
+ scheme_targets = test_targets.select { |e| scheme.include?(e.name.to_s) }
32
+ unless scheme_targets.empty?
33
+ puts "Test scheme: #{scheme} with targets: " + scheme_targets.map { |e| e.name.to_s }.join(",")
34
+ xcproj_scheme = Xcodeproj::XCScheme.new(file_path = path)
35
+ testAction = xcproj_scheme.test_action
36
+ testAction.code_coverage_enabled = true
37
+ testAction.coverage_specified_targets = true
38
+ scheme_targets.each { |e| testAction.add_coverage_target(e) }
39
+ # xcproj_scheme.save!
40
+ File.delete(path)
41
+ xcproj_scheme.save_as(project_path, scheme)
42
+ else
43
+ File.delete(path)
44
+ end
45
+ end
46
+ end
47
+
48
+ Pod::HooksManager.register('cocoapods-unit-test', :post_install) do |context, user_options|
49
+ project_path = File.dirname(context.pods_project.path)
50
+ puts project_path
51
+ Dir[File.join(project_path,"**" ,'xcshareddata', '**', 'xcschemes', '*.xcscheme')].select { |e|
52
+ e.include?("-Unit-")
53
+ }.each do |path|
54
+ puts "Clean Tests xcscheme #{File.basename(path, '.xcscheme')}"
55
+ File.delete(path)
56
+ end
57
+
58
+ coverages = context.pods_project.unit_test_dependency_pods().select { |e| e == "XcodeCoverage" }
59
+ if coverages.empty?
60
+ puts "can not find XcodeCoverage"
61
+ next
62
+ else
63
+ puts "XcodeCoverage ready"
64
+ end
65
+
66
+ test_specs = user_options.fetch(:names,[])
67
+
68
+ if test_specs.nil? || test_specs.empty?
69
+ test_specs = context.pods_project.unit_test_dev_pods()
70
+ end
71
+
72
+ all_pods = context.pods_project.unit_test_all_pods()
73
+
74
+ test_specs = test_specs.select { |e| all_pods.include?(e) }
75
+
76
+ test_specs.each { |x| puts "Test target: #{x.to_s}"}
77
+ if test_specs.empty?
78
+ puts "can not find Test targets"
79
+ next
80
+ end
81
+
82
+ Dir["**/*.xcodeproj"].each do |path|
83
+ xcproj = Xcodeproj::Project.open(path)
84
+ xcproj.targets.each do |target|
85
+ CocoapodsUnitTest.modify_build_settings(target, test_specs.include?(target.name.to_s))
86
+ end
87
+ CocoapodsUnitTest.modify_schemes_settings(xcproj, test_specs)
88
+ xcproj.save
89
+ end
90
+
91
+ end
92
+
93
+ end
94
+
@@ -0,0 +1,12 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ module Pod
4
+ describe Command::Test do
5
+ describe 'CLAide' do
6
+ it 'registers it self' do
7
+ Command.parse(%w{ test }).should.be.instance_of Command::Test
8
+ end
9
+ end
10
+ end
11
+ end
12
+
@@ -0,0 +1,50 @@
1
+ require 'pathname'
2
+ ROOT = Pathname.new(File.expand_path('../../', __FILE__))
3
+ $:.unshift((ROOT + 'lib').to_s)
4
+ $:.unshift((ROOT + 'spec').to_s)
5
+
6
+ require 'bundler/setup'
7
+ require 'bacon'
8
+ require 'mocha-on-bacon'
9
+ require 'pretty_bacon'
10
+ require 'pathname'
11
+ require 'cocoapods'
12
+
13
+ Mocha::Configuration.prevent(:stubbing_non_existent_method)
14
+
15
+ require 'cocoapods_plugin'
16
+
17
+ #-----------------------------------------------------------------------------#
18
+
19
+ module Pod
20
+
21
+ # Disable the wrapping so the output is deterministic in the tests.
22
+ #
23
+ UI.disable_wrap = true
24
+
25
+ # Redirects the messages to an internal store.
26
+ #
27
+ module UI
28
+ @output = ''
29
+ @warnings = ''
30
+
31
+ class << self
32
+ attr_accessor :output
33
+ attr_accessor :warnings
34
+
35
+ def puts(message = '')
36
+ @output << "#{message}\n"
37
+ end
38
+
39
+ def warn(message = '', actions = [])
40
+ @warnings << "#{message}\n"
41
+ end
42
+
43
+ def print(message)
44
+ @output << message
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ #-----------------------------------------------------------------------------#
metadata ADDED
@@ -0,0 +1,163 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cocoapods-unit-test
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - bob
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-05-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: xcodeproj
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: cocoapods-core
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.8'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: cocoapods
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.8'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.8'
55
+ - !ruby/object:Gem::Dependency
56
+ name: xcpretty
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.3'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: neatjson
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.9'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.9'
83
+ - !ruby/object:Gem::Dependency
84
+ name: bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '10'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '10'
111
+ description: A short description of cocoapods-unit-test.
112
+ email:
113
+ - bob170731@gmail.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - Gemfile
120
+ - LICENSE.txt
121
+ - README.md
122
+ - Rakefile
123
+ - cocoapods-unit-test.gemspec
124
+ - lib/cocoapods-unit-test.rb
125
+ - lib/cocoapods-unit-test/command.rb
126
+ - lib/cocoapods-unit-test/command/test.rb
127
+ - lib/cocoapods-unit-test/executable.rb
128
+ - lib/cocoapods-unit-test/gem_version.rb
129
+ - lib/cocoapods-unit-test/project.rb
130
+ - lib/cocoapods-unit-test/result.rb
131
+ - lib/cocoapods-unit-test/xcodeproj/build_configuration.rb
132
+ - lib/cocoapods-unit-test/xcodeproj/native_target.rb
133
+ - lib/cocoapods-unit-test/xcodeproj/project.rb
134
+ - lib/cocoapods-unit-test/xcodeproj/test_action.rb
135
+ - lib/cocoapods_plugin.rb
136
+ - spec/command/test_spec.rb
137
+ - spec/spec_helper.rb
138
+ homepage: https://github.com/DanboDuan/cocoapods-unit-test
139
+ licenses:
140
+ - MIT
141
+ metadata: {}
142
+ post_install_message:
143
+ rdoc_options: []
144
+ require_paths:
145
+ - lib
146
+ required_ruby_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ required_rubygems_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ requirements: []
157
+ rubygems_version: 3.1.2
158
+ signing_key:
159
+ specification_version: 4
160
+ summary: A longer description of cocoapods-unit-test.
161
+ test_files:
162
+ - spec/command/test_spec.rb
163
+ - spec/spec_helper.rb