How do I unit test a private Cocoapods library? - swift

I am trying to find out how to set up unit testing for my private cocoapod library.
Here is the expecting result:
I added a unit testing target 'MyPodTests' to the 'Pods' Project, then I changed target to my 'MyPodTests' scheme. Then I created test classes for my unit tests. I can now select my 'MyPodLib' scheme and press CMD+U and the testing target executes the tests. This is the behavior I am looking for.
This approach, however, has some drawbacks. If I do 'pod update' or 'pod install' on my example app, the test target is gone. if I call pod update on my Example application, the tests are gone too. I'm certain there is a correct way to do this. Also, I would like to prevent the test classes from being loaded into any consumers using the library, therefore I added an exclusion to my podspec:
s.exclude_files = 'Pod/Classes/**/Test/*'
When I select MyPodLib and press CMD+U nothing is happening, and if I select MyPodTests and press CMD+U it throws "No such module 'MyPodLib'" error.

You'll probably want to have the tests running independently of your example app. If that's the case add a test subspec in your pod spec and set its source files.
For example, say you have an Xcode project with a framework target MyFramework and a test target MyFrameworkTests. Your pod spec will look like this:
Pod::Spec.new do |s|
s.name = "MyFramework"
s.version = "1.0.0"
s.summary = "Summary of what MyFramework does"
s.homepage = "https://www.website.com"
s.license = { :type => "MIT", :file => "LICENCE.txt" }
s.author = "Ramesh Boosa"
s.platform = :ios, "11.0"
s.swift_versions = ["5.0", "5.1"]
s.source = { :git => "https://github.com/MyName/MyFramework.git", :tag => "v#{s.version}" }
s.source_files = "MyFramework/*.swift"
s.test_spec do|test|
test.source_files = "MyFrameworkTests/*.swift"
end
end
To lint your pod spec and to run your unit tests execute pod spec lint MyFramework.podspec.
If your example app is included with your pod you can add an app host to your podspec. The CocoaPods documentation has more details.

Related

CoreML in Cocoapod (pod spec lint won't work)

I am attempting to update my cocoapod. Since the last update, I have added a .coreml file and not when I try pod spec lint, I am getting some errors. Things I've done:
Added s.resources = "JacquardToolkit/**/*.mlmodel" to my .podspec file
There was also a few name changes with my .coreml file. Ultimately I want to include only ForceTouch.coreml, so I also need help to get rid of the references to Forcetouch.coreml and ForceTouch2.coreml.
Here is the error message I get in terminal...
try this:
add the MLModel to your spec.source_files in your podspec:
spec.source_files = 'Classes/**/*.{swift,mlmodel,mlmodelc}'
You may also need this if it fails to compile because codegen language is not set:
spec.xcconfig = {'COREML_CODEGEN_LANGUAGE' => 'Swift', 'COREML_CODEGEN_SWIFT_GLOBAL_MODULE' => 'NO'}

CocoaPods podspec generated from GitHub not matching any source_files

I am developing a Swift 2 project which includes many CocoaPods that work and am struggling to create a podspec file for this OrderedDictionary class from GitHub since the author didn't create a Podfile. I ran:
pod spec create "OrderedDictionary|https://github.com/lukaskubanek/OrderedDictionary"
which created OrderedDictionary.podspec in the root of my project directory:
#
# Be sure to run `pod spec lint OrderedDictionary.podspec' to ensure this is a
# valid spec and to remove all comments including this before submitting the spec.
#
# To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html
# To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
#
Pod::Spec.new do |s|
# ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# These will help people to find your library, and whilst it
# can feel like a chore to fill in it's definitely to your advantage. The
# summary should be tweet-length, and the description more in depth.
#
s.name = "OrderedDictionary"
s.version = "0.5"
s.summary = "An implementation of OrderedDictionary in Swift"
# This description is used to generate tags and improve search results.
# * Think: What does it do? Why did you write it? What is the focus?
# * Try to keep it short, snappy and to the point.
# * Write the description between the DESC delimiters below.
# * Finally, don't worry about the indent, CocoaPods strips it!
s.description = "This is a lightweight implementation of an ordered dictionary data structure in Swift packed into a µframework."
s.homepage = "https://github.com/lukaskubanek/OrderedDictionary"
# s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif"
# ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# Licensing your code is important. See http://choosealicense.com for more info.
# CocoaPods will detect a license file if there is a named LICENSE*
# Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'.
#
s.license = "MIT"
# s.license = { :type => "MIT", :file => "LICENSE.md" }
# ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# Specify the authors of the library, with email addresses. Email addresses
# of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also
# accepts just a name if you'd rather not provide an email address.
#
# Specify a social_media_url where others can refer to, for example a twitter
# profile URL.
#
s.author = { "Lukas Kubanek" => "lukas.kubanek#me.com" }
# Or just: s.author = "Lukas Kubanek"
# s.authors = { "Lukas Kubanek" => "lukas.kubanek#me.com" }
# s.social_media_url = "http://twitter.com/Lukas Kubanek"
# ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# If this Pod runs only on iOS or OS X, then specify the platform and
# the deployment target. You can optionally include the target after the platform.
#
# s.platform = :ios
s.platform = :ios, "8.0"
# When using multiple platforms
s.ios.deployment_target = "8.0"
# s.osx.deployment_target = "10.7"
# s.watchos.deployment_target = "2.0"
# s.tvos.deployment_target = "9.0"
# ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# Specify the location from where the source should be retrieved.
# Supports git, hg, bzr, svn and HTTP.
#
s.source = { :git => "https://github.com/lukaskubanek/OrderedDictionary.git", :tag => "v0.5" }
# ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# CocoaPods is smart about how it includes source code. For source files
# giving a folder will include any swift, h, m, mm, c & cpp files.
# For header files it will include any header in the folder.
# Not including the public_header_files will make all headers public.
#
s.source_files = "Sources"
#s.exclude_files = "Classes/Exclude"
# s.public_header_files = "Classes/**/*.h"
# ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# A list of resources included with the Pod. These are copied into the
# target bundle with a build phase script. Anything else will be cleaned.
# You can preserve files from being cleaned, please don't preserve
# non-essential files like tests, examples and documentation.
#
# s.resource = "icon.png"
# s.resources = "Resources/*.png"
# s.preserve_paths = "FilesToSave", "MoreFilesToSave"
# ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# Link your library with frameworks, or libraries. Libraries do not include
# the lib prefix of their name.
#
# s.framework = "SomeFramework"
# s.frameworks = "SomeFramework", "AnotherFramework"
# s.library = "iconv"
# s.libraries = "iconv", "xml2"
# ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# If your library depends on compiler flags you can set them in the xcconfig hash
# where they will only apply to your library. If you depend on other Podspecs
# you can include multiple dependencies to ensure it works.
# s.requires_arc = true
# s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
# s.dependency "JSONKit", "~> 1.4"
end
next to my Podfile:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
pod 'OrderedDictionary', :podspec => "OrderedDictionary.podspec"
I ran:
pod cache clean OrderedDictionary && pod install
which created a Pods/OrderedDictionary group under the Pods project.
Unfortunately the group is empty, so the project fails to build at:
import OrderedDictionary
error: No such module 'OrderedDictionary'
Linting passes:
pod spec lint OrderedDictionary.podspec --verbose
For the life of me I can't get OrderedDictionary.swift and OrderedDictionary.h to copy into the pod's group in the project.
The weird thing is that I did see OrderedDictionary.h appear in the group once but couldn't get it to happen again. I'm concerned that CocoaPods might not be idempotent, but could be overlooking something obvious. Thanks for any help you can provide.
Xcode 7.2.1 (7C1002), OS X 10.10.5 (14F27), CocoaPods 0.39.0
Answering my own question based on IvanRublev's comment. I tried my podspec in this IceCreamShop CocoaPods swift example and then after it worked there, it worked in my original project.
Reproduction steps:
After I wrote this question last night, I bit the bullet and downloaded the zip of the OrderedDictionary GitHub project, expanded it to the root level of my project directory, moved my podspec inside it, and changed my Podfile to say:
pod 'OrderedDictionary', :path => "OrderedDictionary"
That allowed me to use it as a development pod, and I saw OrderedDictionary.swift and OrderedDictionary.h copied into the pod's group.
Today after I got IceCreamShop to work, I removed the OrderedDictionary directory from my project directory, moved my podspec back to the root level of my project directory, and changed the Podfile back to:
pod 'OrderedDictionary', :podspec => "OrderedDictionary.podspec"
The pod now worked, even though I didn't change anything.
I believe this may be a caching issue in CocoaPods, causing it to be inconsistent for one of the following reasons:
Being nontransparent, where issues like the subproject failing to build or a process being terminated leave the cache in an inconsistent state that allow us to detect the presence of the cache by its malfunction.
Not being invalidated correctly, so once it found files in my project dir, it somehow remembered them and was able to include them after they were removed.
Loads and stores behaving differently depending on where they are performed, allowing side effects to affect future loads and stores.
Having temporal issues where loads and stores are nondeterministic because timeouts take priority over the source of truth.
A cosmic ray from a distant galaxy flipping a bit in the cache causing my wave state to collapse into the reality where I spent hours chasing a bug instead of the one where I never knew the bug existed.
I like CocoaPods and realize this is all a bit tongue in cheek, but caching issues often have a detrimental impact on productivity and I would recommend that all projects have an option to disable their cache as well as have it run an internal consistency check every time it's used.
Here are some commands that might help someone experiencing similar problems:
sudo rm -rf ~/Library/Caches/CocoaPods/
sudo rm -rf ~/.cocoapods/repos/master/
sudo rm -rf Pods/
pod install

How to correctly create a cocoa pod spec for a vendor framework

This question is in regards to podspec with vendor framework and use_frameworks! in the pod file
I've created a Podspec for my framework (which contains swift and obj-c code).
The aforementioned pod spec is for a vendor framework (i.e closed-source) which is already compiled as an an iOS embedded framework, which itself contains swift and objective-c code ("mixed project").
The framework has an umbrella header and defines a module and works as expected when embedded directly to a project (manually without pods ,Drag-and-drop into a project) and using the syntax in the hosting app:
#import <MyFramework/Myframework.h>
The framework header has the standard lines:
//! Project version number for MyFramework.
FOUNDATION_EXPORT double MyFrameworkVersionNumber;
//! Project version string for MyFramework.
FOUNDATION_EXPORT const unsigned char MyFrameworkVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <MyFramework/PublicHeader.h>
#import <MyFramework/Header_one.h>
#import <MyFramework/Header_two.h>
... etc.
The corresponding pod-spec that I am trying (and many combinations there of...)
Pod::Spec.new do |s|
s.name = "MyFramework"
s.version = "1.0.0"
s.summary = "MyFramework SDK."
s.description = "Some sort of long description of the pod"
s.homepage = "http://MyFramework.com/"
s.license = { :type => "Commercial", :text => "MyFramework Copyright 2015 ...." }
s.author = { "Avner Barr" => "avner#abc.com" }
s.platform = :ios, "8.0"
s.source = { :http => "http://somewhere_over_the_rainbow/MyFramework.zip" }
s.public_header_files = "MyFramework.framework/Headers/*.h"
s.module_map = "MyFramework.framework/Modules/module.modulemap"
s.preserve_paths = "InsertFramework.framework/*"
s.vendored_frameworks = "MyFramework.framework"
s.requires_arc = true
end
In the pod file of the host app:
source '.../.../MyPrivateTestingPodSpecRepo.git'
use_frameworks!
target 'TestPSpec1' do
pod 'MyFramework'
end
The pod downloads and creates the workspace as expected but in swift code when trying to do:
import MyFramework
I get the error:
Include of non-modular header inside framework module 'MyFramework'
With a "red" error in the objective-c header (the <> syntax).
i.e.
MyFramework.h
#import <MyFramework/Header_one.h> Include of non-modular header inside framework module 'MyFramework'
Try going to the root of your project directory where the podfile is located in terminal, then type in 'pod install' and hit enter.
If it still doesn't work try typing in 'pod uodate'

Swift CocoaPods Deployment - Can't access any functions

I'm new to CocoaPods and wanted to explore it by deploying an open source github project ( Banner notification for curious )
So I followed step by step the Cocoapods Guide as well as the Trunk guide for deployment. OK.
So my pod is called AWBanner (github : https://github.com/Aymenworks/AWBanner ) and I can add it in any project that use pods like that : pod 'AWBanner'. No problem.
My pod library contains only one file I want to provide, which is : AWBanner.swift
Both pod lib lint and pod spec lint success. ✅
This is my spec file
#
# Be sure to run `pod lib lint AWBanner.podspec' to ensure this is a
# valid spec before submitting.
#
# Any lines starting with a # are optional, but their use is encouraged
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
#
Pod::Spec.new do |s|
s.name = "AWBanner"
s.version = "0.1.1"
s.summary = 'An easy, customizable and soft Swift banner notification for iOS applications.'
# This description is used to generate tags and improve search results.
# * Think: What does it do? Why did you write it? What is the focus?
# * Try to keep it short, snappy and to the point.
# * Write the description between the DESC delimiters below.
# * Finally, don't worry about the indent, CocoaPods strips it!
s.description = <<-DESC
An easy, customizable and soft banner notification for iOS applications.
AWBanner library provides an easy to use class to show a banner view on the screen ( wherever you want, you can specify the Y origin ).
The banner moves from the Y origin ( default 0, but you can change it 👍) and stays there until the duration you choose elapse ( Personally I choose in general 2.5s ).
To dismiss the banner before the time elapse, the user can tap it.
DESC
s.homepage = "https://github.com/Aymenworks/AWBanner"
# s.screenshots = "www.example.com/screenshots_1", "www.example.com/screenshots_2"
s.license = 'MIT'
s.author = { "Rebouh Aymen" => ".." }
s.source = { :git => "https://github.com/Aymenworks/AWBanner.git", :tag => s.version.to_s }
s.platform = :ios, '8.0'
s.requires_arc = true
s.source_files = 'Pod/Classes/AWBanner.swift'
s.resource_bundles = {
'AWBanner' => ['Pod/Assets/*.png']
}
s.frameworks = 'UIKit'
end
So the problem is that when importing the lib in my swift project , like that :
import AWBanner
No errors are found, but I can't use any functions I made. It's like it's an empty module. I can't access any of my functions, even after setting them public.
Someone can give me pointers if I have missed something ?

cocoapods: The resources are not copied to mainBundle

I am struggling with resources. I want to be able to put a nib in my pod. One of the classes uses this nib.
Here is the podspec:
Pod::Spec.new do |s|
s.name = "MyCBD_BSManagedDocument"
s.requires_arc = true
s.osx.platform = :osx, '10.7'
s.subspec 'MyCBD_BSManagedDocument' do |ss|
ss.source_files = 'Classes/MyCBD_BSManagedDocument/**/*.{h,m}'
end
s.subspec 'Auxiliary classes' do |ss|
ss.subspec 'MyCBDLockManager' do |sss|
sss.source_files = 'Classes/Auxiliary classes/MyCBDLockManager/**/*.{h,m}'
sss.resource_bundle = {'MyCBDLockManager' => 'Classes/Auxiliary classes/MyCBDLockManager/MyCBDLockManager.xib'}
end
ss.subspec 'MyCBDSafeguardManager' do |sss|
sss.source_files = 'Classes/Auxiliary classes/MyCBDSafeguardManager/**/*.{h,m}'
end
end
end
Very strangely, in my toy-project to test the pod, it works (I can check the nib is in the mainBundle), but in my real project, the nib is not in the mainBundle, and I have the error
-[MyCBDLockManager loadWindow]: failed to load window nib file 'MyCBDLockManager'.
Any advice on how to include resources with cocoa pods?
For some reason, one phase in the build phases was missing. I don't know why, though.
So, I had to add this phase again with pod install.
If that phase is missing you should try to run pod install again and make sure you're opening the xcworkspace that is generated. Also you want just resources not resource_bundles for a single xib like that.