Load files in xcode unit tests - xcode

I have an Xcode 5 unit test project and some test xml files related to it. I've tried a bunch of approaches but I can't seem to load the xml files.
I've tried the following which does not work
NSData* nsData = [NSData dataWithContentsOfFile:#"TestResource/TestData.xml"];
NSString* fileString = [NSString stringWithContentsOfFile:#"TestData.xml" encoding:NSUTF8StringEncoding error:&error];
Also if I try to preview all the bundles using [NSBundle allBundles] the unit test bundle does not appear in the list?
I tried to create a separate resource bundle and I can't seem to locate it programmatically although it does get built and deployed.
What am I doing wrong ?

When running tests the application bundle is still the main bundle. You need to use unit tests bundle.
Objective C:
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *path = [bundle pathForResource:#"TestData" ofType:#"xml"];
NSData *xmlData = [NSData dataWithContentsOfFile:path];
Swift 2:
let bundle = NSBundle(forClass: self.dynamicType)
let path = bundle.pathForResource("TestData", ofType: "xml")!
let xmlData = NSData(contentsOfFile: path)
Swift 3 and up:
let bundle = Bundle(for: type(of: self))
let path = bundle.path(forResource: "TestData", ofType: "xml")!
let xmlData = NSData(contentsOfFile: path)

With swift Swift 3 the syntax self.dynamicType has been deprecated, use this instead
let testBundle = Bundle(for: type(of: self))
guard let ressourceURL = testBundle.url(forResource: "TestData", ofType: "xml") else {
// file does not exist
return
}
do {
let ressourceData = try Data(contentsOf: ressourceURL)
} catch let error {
// some error occurred when reading the file
}
or
guard let ressourceURL = testBundle.url(forResource: "TestData", withExtension: "xml")

As stated in this answer:
When the unit test harness runs your code, your unit test bundle is NOT the main bundle. Even though you are running tests, not your application, your application bundle is still the main bundle.
If you use following code, then your code will search the bundle that your unit test class is in, and everything will be fine.
Objective C:
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *path = [bundle pathForResource:#"TestData" ofType:#"xml"];
NSData *xmlData = [NSData dataWithContentsOfFile:path];
Swift:
let bundle = NSBundle(forClass: self.dynamicType)
if let path = bundle.pathForResource("TestData", ofType: "xml")
{
let xmlData = NSData(contentsOfFile: path)
}

Swift 4+
I found none of the answers here up–to date or using a URL.
First add the following function to your testClass:
/// getFile. Opens a file in the current bundle and return as data
/// - Parameters:
/// - name: fileName
/// - withExtension: extension name, i.e. "json"
/// - Returns: Data of the contents of the file on nil if not found
static func getFile(_ name: String, withExtension: String) -> Data? {
guard let url = Bundle(for: Self.self)
.url(forResource: name, withExtension: withExtension) else { return nil }
guard let data = try? Data(contentsOf: url) else { return nil }
return data
}
Then you can call it in your test class like this:
func test() throws {
let xmlData = Self.getFile("TestData", withExtension: "xml")
XCTAssertNotNil(xmlData, "File not found")
}
Note: Apple recommends that URL's should always be used for resources (not paths) for security reasons.

Relative paths are relative to the current working directory. By default, that's / — the root directory. It's looking for that folder at the root level of your startup disk.
The correct way to get a resource that's within your bundle is to ask your bundle for it.
In an application, you'd get the bundle using [NSBundle mainBundle]. I don't know if that works in a test case; try it, and if it doesn't (if it returns nil or an unuseful bundle object), substitute [NSBundle bundleForClass:[self class]].
Either way, once you have the bundle, you can ask it for the path or URL for a resource. You generally should go for URLs unless you have a very specific reason to need a path (like passing it to a command-line tool using NSTask). Send the bundle a URLForResource:withExtension: message to get the resource's URL.
Then, for the purpose of reading a string from it, use [NSString stringWithContentsOfURL:encoding:error:], passing the URL you got from the bundle.

One thing to note is(It waste me serval minutes to figure it out):
Don't forget to add the test file to "Copy Bundle Resources" section of Build Phases
Without it, you couldn't load the file successfully.

Get main bundle
Use main bundle to get local mock data
Load data from JSON
let mainBundle = Bundle(identifier: "com.mainBundle.Identifier")
if let path = mainBundle?.path(forResource: "mockData", ofType: "json") {
do {
let testData = try Data(contentsOf: URL(fileURLWithPath: path))
networkTestSession.data = testData
} catch {
debugPrint("local json test data missing")
}
}

I know this specific question is asking for xml files, but if you're trying to do the same with json files, try this:
let url = Bundle.main.url(forResource: "data", withExtension: ".json")
guard let dataURL = url, let data = try? Data(contentsOf: dataURL) else {
fatalError("Couldn't read data.json file") }

Related

NSURLDownload: Assertion failed ([path isAbsolutePath]) troubles

I'm trying to download a file off the internet and place it in the application name directory under the Application Support directory and I keep getting a
Assertion failed: ([path isAbsolutePath]), function -[NSURLDownload setDestination:allowOverwrite:], file /SourceCache/CFNetwork/CFNetwork-720.5.7/Foundation/NSURLDownload.mm, line 370.
Here's the code that I wrote:
var imageRequest = NSURLRequest(URL: self.source)
var imageDownload = NSURLDownload(request: imageRequest, delegate:self)
var error: NSError? = NSError()
/* does path exist */
let directoryPath = self.destination.stringByDeletingLastPathComponent
let fileMgr = NSFileManager();
fileMgr.createDirectoryAtPath(directoryPath, withIntermediateDirectories: true, attributes: nil, error: &error)
imageDownload.setDestination(self.destination, allowOverwrite: true);
When I step through the code everything looks correct. self.source is
(https:/remoteDomain.com/img/downloadimage.jpg)
a NSURL
self.destination is the full path in my system (file:/Users/ryan/Library/Application%20Support/AppName/downloadimage.jpg)
Any Ideas?
To answer the question to your specific topic:
The error message says that your path is invalid. The right way to create the path for your image is the following:
let fileManager = NSFileManager.defaultManager()
var folder = "~/Library/Application Support/[APPNAME]/someFolder" as NSString
folder = folder.stringByExpandingTildeInPath
if fileManager.fileExistsAtPath(folder as String) == false {
do {
try fileManager.createDirectoryAtPath(folder as String, withIntermediateDirectories: true, attributes: nil)
}
catch {
//Deal with the error
}
}
BUT
#jtbandes is right. You should use NSURLSessionDownloadTask to download your files.
It is part of the Foundation.framework, which is available on OS X, iOS and watchOS.
The reason to use it is that Apple keeps updating this Api to meet the latest standards. For example, you don't need to worry about IPv4 or IPv6 etc. This avoids crashes and weird behavior in your app.
This is how you use it (Swift):
var imageRequest = NSURLRequest(URL: self.source)
let session = NSURLSession.sharedSession()
let downloadTask = session.downloadTaskWithRequest(imageRequest) { (url: NSURL?, response: NSURLResponse?, error: NSError?) -> Void in
//Work with data
}
downloadTask.resume()
Note that url is the path to the downloaded image.

How can I download an mp4 straight to my hard drive in Swift?

I'm using this code to download an mp4 file:
func downloadImageFile() {
let myURLstring = getImageURLCM()
let myFilePathString = "/Users/jack/Desktop/Comics/"+getTitle()+".mp4"
let url = NSURL(string: myURLstring)
let dataFromURL = NSData(contentsOfURL: url!)
let fileManager = NSFileManager.defaultManager()
fileManager.createFileAtPath(myFilePathString, contents: dataFromURL, attributes: nil)
}
But I've noticed that the file actually gets loaded up into my RAM first, before the NSFileManager saves it to my hard drive (based on the Xcode debug session). That's tolerable for smaller files, but most of the files I want to download with this will be at least 1GB.
My main question is: how to make this more RAM friendly?
I've also noticed that I get the spinning wheel of death until the download is finished, so if advice on fixing that would be appreciated as well.
You would be better to go with the system managed download in NSURLSession, specifically NSURLDownloadTask. This way you don't have to worry about memory management of large downloads. From NSURLSession swift file
/*
* download task convenience methods. When a download successfully
* completes, the NSURL will point to a file that must be read or
* copied during the invocation of the completion routine. The file
* will be removed automatically.
*/
func downloadTaskWithURL(url: NSURL, completionHandler: (NSURL?, NSURLResponse?, NSError?) -> Void) -> NSURLSessionDownloadTask?
Example of Use below - copy and paste into new Swift Playground:
import UIKit
import XCPlayground
func downloadFile(filePath: String) {
let url = NSURL(string: filePath)
if let unwrappedURL = url {
let downloadTask = NSURLSession.sharedSession().downloadTaskWithURL(unwrappedURL) { (urlToCompletedFile, reponse, error) -> Void in
// unwrap error if present
if let unwrappedError = error {
print(unwrappedError)
}
else {
if let unwrappedURLToCachedCompletedFile = urlToCompletedFile {
print(unwrappedURLToCachedCompletedFile)
// Copy this file to your destinationURL with
//NSFileManager.defaultManager().copyItemAtURL
}
}
}
downloadTask?.resume()
}
}
downloadFile("http://devstreaming.apple.com/videos/wwdc/2015/711y6zlz0ll/711/711_networking_with_nsurlsession.pdf?dl=1")
XCPSetExecutionShouldContinueIndefinitely()
Simple Example on github here - https://github.com/serendipityapps/NSURLSessionDownloadTaskExample
dataFromURL.writeToFile(myFilePathString, atomically: true)
This is the snippet I use, it writes the loaded data into the file at the given path.

How come I can't successfully load an NSImage from it's full path? Swift 2

I'm trying to load an image from an absolute path into an NSImage and even though the same full path works in other scenarios when I'm using it in this context, the variable just ends up being nil. I've tried using both the file path and an NSURL to achieve it.
//: Playground - noun: a place where people can play
import Cocoa
import AppKit
print ("Starting")
/**
Attempt to do via NSURL
**/
// The workspace
var workspace = NSWorkspace.sharedWorkspace()
// Main screen
var screen = NSScreen.mainScreen()
let filemgr = NSFileManager.defaultManager()
print(filemgr.currentDirectoryPath)
let filePath1 = "/Users/daniel/Google Drive/elementarian wallpapers/Bicycle by midnighttokerkate.png"
let filePath2 = "/Users/daniel/Google Drive/elementarian wallpapers/Buildings Foggy Sky by solutionall.png"
let file1 = NSURL(fileURLWithPath: filePath1, isDirectory: false)
let file2 = NSURL(fileURLWithPath: filePath2, isDirectory: false)
do {
try workspace.setDesktopImageURL(file2, forScreen: screen!, options: [:])
print("Successfully set background from NSURL")
} catch {
print("Failed to set")
}
print("Attempting to set from NSData...")
/**
Attempt to do via NSData
**/
// Load image from URL first
if filemgr.fileExistsAtPath(filePath2) {
print("File exists")
var image = NSImage(contentsOfURL: file2)
if image != nil {
print ("Not nil")
} else {
print ("Nil")
}
} else {
print("File not found")
}
My final goal is to load the image into an NSData object so I can run a transform on it and then set the manipulated in memory image as the desktop background.
As per Droppy's comment, this was due to the Swift Playground running in a sandbox and not allowing access to files outside of it's workplace. I've moved the images I need into the playground itself to test and it now works as expected. Details on how to do this can be found here.

Simple Swift file download with URL

So I have the URL as string (in this case a JPG but would like a general procedure for any file type if possible) and I have the file path as string where I want to save the file.
What would be the fastest way to get this implemented?
Please keep in mind this is for OSX command line application. I tried few sample codes found here, mostly using UIImage but I get error:"Use of unresolved identifier", adding "import UIKit" gets me error:"No such Module". Please help!
import Foundation
let myURLstring = "http://www.safety.vanderbilt.edu/images/staff/Bob-Wheaton.jpg"
let myFilePathString = "/Volumes/HD/Staff Pictures/Bob-VEHS.jpg"
---> ABOVE IS THE ORIGINAL QUESTION <---
---> BELOW IS NEW IMPROVED CODE: WORKING <---
import Foundation
let myURLstring = "http://www.safety.vanderbilt.edu/images/staff/Bob-Wheaton.jpg"
let myFilePathString = "/Volumes/HD/Staff Pictures/Bob-VEHS.jpg"
let url = NSURL(string: myURLstring)
let imageDataFromURL = NSData(contentsOfURL: url)
let fileManager = NSFileManager.defaultManager()
fileManager.createFileAtPath(myFilePathString, contents: imageDataFromURL, attributes: nil)
If you're writing for OS X, you'll use NSImage instead of UIImage. You'll need import Cocoa for that - UIKit is for iOS, Cocoa is for the Mac.
NSData has an initializer that takes a NSURL, and another that takes a file path, so you can load the data either way.
if let url = NSURL(string: myURLstring) {
let imageDataFromURL = NSData(contentsOfURL: url)
}
let imageDataFromFile = NSData(contentsOfFile: myFilePathString)
With Swift 4, the code will be:
if let url = URL(string: myURLstring) {
let imageDataFromURL = try Data(contentsOf: url)
}

List files in iTunes shared folder using Swift

I would like to list all files in my iTunes shared folder in a 'Table View' using Swift.
I check on Google and nobody talk about it, it look like it's a uncommon need, so if anyone can help it would be really helpful.
EDIT: I found three links talking about it but in Objective-C, I have no experience in this language. If someone understand this, here are the links.
http://www.exampledb.com/objective-c-get-itunes-file-sharing-folder-files-with-full-path.htm
http://www.infragistics.com/community/blogs/stevez/archive/2013/10/14/ios-objective-c-working-with-files.aspx
http://www.raywenderlich.com/1948/itunes-tutorial-for-ios-how-to-integrate-itunes-file-sharing-with-your-ios-app
Based on this objective-C tutorial http://mobiforge.com/design-development/importing-exporting-documents-ios, I created three methods: listFilesFromDocumentsFolder which returns a list of the names of all documents I have in the apps iTunes shared folder and loadFileFromDocumentsFolder which loads the url for a given filename and passes the url to handleDocumentOpenUrl to load the file on a UIWebView. Find below the three methods.
You can also download the project from github: https://github.com/Euniceadu/Load-Shared-Documents
listFilesFromDocumentsFolder
func listFilesFromDocumentsFolder() {
var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
var documentsDirectory : String;
documentsDirectory = paths[0] as String
var fileManager: NSFileManager = NSFileManager()
var fileList: NSArray = fileManager.contentsOfDirectoryAtPath(documentsDirectory, error: nil)!
var filesStr: NSMutableString = NSMutableString(string: "Files in Documents folder \n")
for s in fileList {
filesStr.appendFormat("%#", s as String)
}
self.displayAlert(filesStr)
}
loadFileFromDocumentsFolder
func loadFileFromDocumentsFolder(fileName: String) {
var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
var documentsDirectory : String;
documentsDirectory = paths[0] as String
var filePath: String = documentsDirectory.stringByAppendingPathComponent(fileName);
var fileUrl: NSURL = NSURL(fileURLWithPath: filePath);
self.handleDocumentOpenURL(fileUrl)
}
handleDocumentOpenUrl
func handleDocumentOpenURL(url: NSURL) {
var requestObj = NSURLRequest(URL: url)
webView.userInteractionEnabled = true
webView.loadRequest(requestObj)
}
Hope this helps.

Resources