From a2e106b7c3ba5be4c306e52755feed15dc3af199 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Tue, 3 Jun 2014 16:55:22 -0700 Subject: [PATCH] Introduce `test_specification` DSL --- CHANGELOG.md | 5 ++- lib/cocoapods-core/specification.rb | 36 +++++++++++++---- lib/cocoapods-core/specification/consumer.rb | 8 ++++ lib/cocoapods-core/specification/dsl.rb | 41 ++++++++++++++++++++ lib/cocoapods-core/specification/linter.rb | 8 +++- spec/specification/consumer_spec.rb | 7 ++++ spec/specification/dsl_spec.rb | 21 ++++++++++ spec/specification/linter_spec.rb | 13 +++++++ spec/specification_spec.rb | 35 +++++++++++++++++ 9 files changed, 165 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aecd2c4bf..48d1ba844 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,10 @@ ##### Enhancements -* None. +* Introduce `test_specification` DSL + [Dimitris Koutsogiorgas](https://github.com/dnkoutso) + [Kyle Fuller](https://github.com/kylef) + [#369](https://github.com/CocoaPods/Core/pull/369) ##### Bug Fixes diff --git a/lib/cocoapods-core/specification.rb b/lib/cocoapods-core/specification.rb index 0e687c6e0..fb18aa5d5 100644 --- a/lib/cocoapods-core/specification.rb +++ b/lib/cocoapods-core/specification.rb @@ -34,12 +34,16 @@ class Specification # @param [String] name # the name of the specification. # - def initialize(parent = nil, name = nil) + # @param [Bool] test_specification + # Whether the specification is a test specification + # + def initialize(parent = nil, name = nil, test_specification = false) @attributes_hash = {} @subspecs = [] @consumers = {} @parent = parent @hash_value = nil + @test_specification = test_specification attributes_hash['name'] = name yield self if block_given? @@ -203,7 +207,26 @@ def subspec? # @!group Dependencies & Subspecs - # @return [Array] the recursive list of all the subspecs of + # @return [Bool] if the specification is a test specification + # + def test_specification? + @test_specification + end + + # @return [Symbol] the test type supported if this is a test specification + # + def test_type + attributes_hash['test_type'] + end + + # @return [Array] the list of all the test subspecs of + # a specification. + # + def test_specs + subspecs.select(&:test_specification?) + end + + # @return [Array] the recursive list of all the subspecs of # a specification. # def recursive_subspecs @@ -241,7 +264,7 @@ def subspec_by_name(relative_name, raise_if_missing = true) else remainder = relative_name[base_name.size + 1..-1] subspec_name = remainder.split('/').shift - subspec = subspecs.find { |s| s.base_name == subspec_name } + subspec = subspecs.find { |s| s.base_name == subspec_name && !s.test_specification? } unless subspec if raise_if_missing raise Informative, 'Unable to find a specification named ' \ @@ -274,7 +297,7 @@ def default_subspecs # def subspec_dependencies(platform = nil) specs = if default_subspecs.empty? - subspecs.compact + subspecs.compact.reject(&:test_specification?) else default_subspecs.map do |subspec_name| root.subspec_by_name("#{name}/#{subspec_name}") @@ -288,9 +311,8 @@ def subspec_dependencies(platform = nil) # Returns the dependencies on other Pods or subspecs of other Pods. # - # @param [Bool] all_platforms - # whether the dependencies should be returned for all platforms - # instead of the active one. + # @param [Platform] platform + # return only dependencies supported on the given platform. # # @note External dependencies are inherited by subspecs # diff --git a/lib/cocoapods-core/specification/consumer.rb b/lib/cocoapods-core/specification/consumer.rb index eb1909f7d..c3c92cf5d 100644 --- a/lib/cocoapods-core/specification/consumer.rb +++ b/lib/cocoapods-core/specification/consumer.rb @@ -136,6 +136,14 @@ def user_target_xcconfig #-----------------------------------------------------------------------# + # @!group Test Support + + # @return [Symbol] the test type supported by this Pod. + # + spec_attr_accessor :test_type + + #-----------------------------------------------------------------------# + # @!group File patterns # @return [Array] the source files of the Pod. diff --git a/lib/cocoapods-core/specification/dsl.rb b/lib/cocoapods-core/specification/dsl.rb index b9b0b0aea..c60d36a7b 100644 --- a/lib/cocoapods-core/specification/dsl.rb +++ b/lib/cocoapods-core/specification/dsl.rb @@ -1324,6 +1324,47 @@ def subspec(name, &block) subspec end + # The list of the test types currently supported. + # + SUPPORTED_TEST_TYPES = [:unit].freeze + + # The test type this specification supports. This only applies to test specifications. + # + # --- + # + # @example + # + # test_spec.test_type = :unit + # + # @param [Symbol] type + # The test type to use. + attribute :test_type, + :default_value => :unit, + :types => [Symbol], + :multi_platform => false + + # Represents a test specification for the library. Here you can place all + # your tests for your podspec along with the test dependencies. + # + # --- + # + # @example + # + # Pod::Spec.new do |spec| + # spec.name = 'NSAttributedString+CCLFormat' + # + # spec.test_spec do |test_spec| + # test_spec.source_files = 'NSAttributedString+CCLFormatTests.m' + # test_spec.dependency 'Expecta' + # end + # end + # + def test_spec(name = 'Tests', &block) + subspec = Specification.new(self, name, true, &block) + @subspecs << subspec + subspec + end + #------------------# # @!method default_subspecs=(subspec_array) diff --git a/lib/cocoapods-core/specification/linter.rb b/lib/cocoapods-core/specification/linter.rb index 751821c39..837a85450 100644 --- a/lib/cocoapods-core/specification/linter.rb +++ b/lib/cocoapods-core/specification/linter.rb @@ -128,7 +128,7 @@ def run_root_validation_hooks run_validation_hooks(attributes, spec) end - # Run validations for multi-platform attributes activating . + # Run validations for multi-platform attributes activating. # # @return [void] # @@ -364,6 +364,12 @@ def _validate_deprecated_in_favor_of(d) end end + def _validate_test_type(t) + supported_test_types = Specification::DSL::SUPPORTED_TEST_TYPES + results.add_error('test_type', "The test type `#{t}` is not supported. " \ + "Supported test type values are #{supported_test_types}.") unless supported_test_types.include?(t) + end + # Performs validations related to github sources. # def perform_github_source_checks(s) diff --git a/spec/specification/consumer_spec.rb b/spec/specification/consumer_spec.rb index 85a292f3f..be90cfc53 100644 --- a/spec/specification/consumer_spec.rb +++ b/spec/specification/consumer_spec.rb @@ -246,6 +246,13 @@ module Pod @spec.header_mappings_dir = 'src/include' @subspec_consumer.header_mappings_dir.should == 'src/include' end + + #------------------# + + it 'allows to specify the test type' do + @subspec.test_type = :unit + @subspec_consumer.test_type.should == :unit + end end #-------------------------------------------------------------------------# diff --git a/spec/specification/dsl_spec.rb b/spec/specification/dsl_spec.rb index 7a5743e25..bf27ea176 100644 --- a/spec/specification/dsl_spec.rb +++ b/spec/specification/dsl_spec.rb @@ -368,6 +368,27 @@ module Pod #-----------------------------------------------------------------------------# + describe 'Test specs' do + before do + @spec = Spec.new do |spec| + spec.name = 'Spec' + spec.test_spec do |test_spec| + test_spec.test_type = :unit + end + end + end + + it 'allows you to specify a test spec' do + test_spec = @spec.subspecs.first + test_spec.class.should == Specification + test_spec.name.should == 'Spec/Tests' + test_spec.test_specification?.should == true + test_spec.test_type.should == :unit + end + end + + #-----------------------------------------------------------------------------# + describe 'Multi-Platform' do before do @spec = Spec.new do |s| diff --git a/spec/specification/linter_spec.rb b/spec/specification/linter_spec.rb index 738ae8382..9a5b56873 100644 --- a/spec/specification/linter_spec.rb +++ b/spec/specification/linter_spec.rb @@ -253,6 +253,19 @@ def result_should_include(*values) #------------------# + it 'checks the test type' do + podspec = 'Pod::Spec.new do |s|; s.test_spec do |ts|; ts.test_type = :unknown; end end' + path = SpecHelper.temporary_directory + 'BananaLib.podspec' + File.open(path, 'w') { |f| f.write(podspec) } + linter = Specification::Linter.new(path) + linter.lint + results = linter.results + test_type_error = results.find { |result| result.to_s.downcase.include?('test_type') } + test_type_error.message.should.include?('The test type `unknown` is not supported.') + end + + #------------------# + it 'checks if the description is not an empty string' do @spec.stubs(:description).returns('') result_should_include('description', 'empty') diff --git a/spec/specification_spec.rb b/spec/specification_spec.rb index 486506ce3..ed66fde07 100644 --- a/spec/specification_spec.rb +++ b/spec/specification_spec.rb @@ -217,23 +217,30 @@ module Pod s.name = 'Pod' s.subspec 'Subspec' do |_sp| end + s.test_spec do |_tsp| + end end @subspec = @spec.subspecs.first + @test_subspec = @spec.test_specs.first end it 'returns the root spec' do @spec.root.should == @spec @subspec.root.should == @spec + @test_subspec.root.should == @spec end it 'returns whether it is a root spec' do @spec.root?.should.be.true @subspec.root?.should.be.false + @test_subspec.root?.should.be.false end it 'returns whether it is a subspec' do @spec.subspec?.should.be.false @subspec.subspec?.should.be.true + @test_subspec.subspec?.should.be.true + @test_subspec.test_specification?.should.be.true end end @@ -273,6 +280,17 @@ module Pod @spec.subspec_by_name('Pod/Subspec/Subsubspec').should == @subsubspec end + it "doesn't return the test subspec given the Tests name" do + @spec = Spec.new do |s| + s.name = 'Pod' + s.version = '1.0' + s.dependency 'AFNetworking' + s.osx.dependency 'MagicalRecord' + s.test_spec {} + end + @spec.subspec_by_name('Pod/Tests', false).should. nil? + end + it 'returns a subspec given the relative name' do @subspec.subspec_by_name('Subspec/Subsubspec').should == @subsubspec end @@ -327,12 +345,29 @@ module Pod ] end + it 'excludes the test subspec from the subspec dependencies' do + @spec.test_spec {} + @spec.subspec_dependencies.sort.should == [ + Dependency.new('Pod/Subspec', '1.0'), + Dependency.new('Pod/SubspecOSX', '1.0'), + Dependency.new('Pod/SubspeciOS', '1.0')] + end + it 'returns all the dependencies' do @spec.dependencies.sort.should == [ Dependency.new('AFNetworking'), Dependency.new('MagicalRecord')] end + it 'returns the test spec dependencies' do + test_spec = @spec.test_spec { |s| s.dependency 'OCMock' } + test_spec.dependencies.sort.should == [ + Dependency.new('AFNetworking'), + Dependency.new('MagicalRecord'), + Dependency.new('OCMock'), + ] + end + it 'returns the dependencies given the platform' do @spec.dependencies(:ios).sort.should == [Dependency.new('AFNetworking')] end