The Elegant Chaos Blog

March 12, 2013

Hot on the heels of 1.3b1 came 1.3b2, which fixed the support for OS 10.6 that had accidentally got broken!

And if that weren’t enough, hot on the heels of that came 1.3b3, which adds support for a new service command: “Add To Templates…”.

This command adds a copy of the selected files into Neu’s templates folder.

As always, you can find this version on the beta software page.

The software update mechanism within Neu will also grab this new version, if you have the “Update to beta versions when available” box checked. Unfortunately, if you auto-updated to 1.3b1 on OS X 10.6, you’ll have to download it, since 1.3b1 is totally broken on 10.6.

more...

Things have been quite quiet on the Neu front, but under the surface we have been doing a bit of paddling!

Available now on the beta software page is a new beta - 1.3b1 - which adds some new features.

Folder Expansion

The first of these is the ability to use folders properly as templates, and to have variables expanded in the contents of the folders (including in their filenames).

Applescript

The second big change is applescript support. You can now use Neu via, applescript, doing this sort of thing:

tell application id "com.elegantchaos.neu"
    make new document
        with properties {template:template "MyClass", extension:"hpp", replacing:yes, revealing:false, opening:true} 
        at POSIX file "/Users/sam/Desktop/"
end tell

Currently there’s also an alternative syntax, which looks like this:

tell application id "com.elegantchaos.neu"
    make new document
        duplicate template (template "MyClass") at destination name "Blah" with revealing, opening and replacing
end tell

We’re interested in hearing if people have a preference.

Finder Menu

Finally, we’ve added experimental support for a proper menu in the Finder.

This is classed as “experimental” because Apple doesn’t officially support allowing apps to add Finder menus, so it involves installing a small hack to the Finder.

You can enable this support in the new “Finder” preferences pane. Note that you may have to log out and in again before the Neu menu appears. You will also need to have Neu running.

Feedback Required

To some extent all of these features are still experimental, and there may be bugs in them.

We’re really keen to hear what you think about the features, and about any problems you encounter.

more...

In a blog post last month I introduced Mock Server, an Objective-C toolkit to help with the unit testing of networking code.

Basically, Mock Server works by running on a local network port, pretending to be some sort of server (ftp, http, you name it). You point your networking code at it in your unit tests, thus avoiding the need to be connected to the network, and ensuring that you always have an available, predictable server to test against.

Since then I’ve been using MockServer a fair bit, and have expanded it’s capabilities somewhat, with hopefully more to come.

To help everyone else use it, in this post, I thought I’d go into a bit more detail about how exactly to set up a unit test to talk to Mock Server.

Using KMSTestCase

MockServer can be used in a number of different ways, but to simlpify things I’ve tried to make it easy to use it in what I think is the most likely scenario: as part of a suite of unit tests using the standard SenTestKit framework that ships with Xcode.

To do this, you need to make just two things:

  • a responses file
  • a unit test class that inherits from KMSTestCase.

Response file examples for ftp, http and webdav can be found in the MockServer project.

In a future post I’ll talk about how to set up your own response file to mimic a custom protocol, or to mimic something like an FTP server behaving in a very specific way (great for testing those obscure bugs that only show up on really weird FTP servers).

For now though, I’ll just use the example FTP response file, which provides responses for most of the common commands than an FTP client is likely to throw at an FTP server.

Imports

After making a new source file, you first need to import the MockServer headers that you need. You’ll definitely need KMSTestCase.h, and probably also KMSServer.h:

#import "KMSTestCase.h"
#import "KMSServer.h"

A Class And A Test

Next, you want to declare your unit test class, inheriting from KMSTestCase:

@interface KMSCollectionTests : KMSTestCase

@end

Set Up Server

As a simple example, we’ll just implement a single test, which performs an FTP request.

@implementation KMSCollectionTests

- (void)testFTP
{

First, we need to set up a new mock server instance, and start it running.

Luckily KMSTestCase has a method that does all the hard work for us: [KMSTestCase setupServerWithResponseFileNamed:].

This method takes the name of a response file, and sets up a MockServer instance, running on a dynamically allocated port, and using the “default” set of responses from the response file, which should be added as a resource to your unit test bundle.

We have to check the result of this call (which is a BOOL), in case anything goes wrong with the setup.

	// setup a server object, using the ftp: scheme and taking
	// the "default" set of responses from the "ftp.json" file.
	if ([self setupServerWithResponseFileNamed:@"ftp"])
	{

Because we’re going to fake a download, the next thing we have to do is to give the server some data to return to us when it pretends to respond to the download request.

This is the way MockServer works generally. It doesn’t actually perform as a server at all in any real sense; instead, you give it the thing you want it to return, then run the real client code that sends a request to it, then check that the client code got back the thing that you asked MockServer to return.

So, to set some data to be returned, we use the [KMSServer data] property:

        // set up the data that the server will return
        NSString* testData = @"This is some test data";
        self.server.data = [testData dataUsingEncoding:NSUTF8StringEncoding];

Make A Request

Next, we need to make an NSURLRequest object that we’re going to use in our client code to do our actual FTP request.

It’s important to note here that we don’t have to use NSURLRequest, or NSURLConnection, or any particular client-side technology. We can formulate the network request in whatever way we like, and can use any sort of third-party library (or even low level socket code) to perform the client part of the transaction (which is the part that we’re trying to test).

However, I’m using NSURLConnection here for simplicity, so I need an NSURLRequest, which means that I first need an NSURL object, including the address of the server and the path of the file we want to download.

We know that the server is running locally (as that’s the point of MockServer). However, because the server is using a dynamically allocated port, we can’t just hard-code the URL into the test; we have to figure it out on the fly. We do this by grabbing the port number back from the server, grabbing the scheme from the responses collection, and building up a URL from that information.

Luckily KMSTestCase provides a helper method to simplify this.

In this case we’re going to pretend to download a file called “test.txt” from the root of the FTP server:

		// setup an ftp request
		NSURL* url = [self URLForPath:@"test.txt"];
		NSURLRequest* request = [NSURLRequest requestWithURL:url];

Perform The Download

Next, we want to actually peform the download.

Because this is a unit test, the first instinct might be to do this synchronously. After all, a unit test is just one method, and we can’t perform a test on what we got back until we’ve actually got it. For an asynchronous case we’d have to give back control to the main loop for a while until we somehow know that the request is done, and that all sounds a bit complicated. There’s a danger that the unit test would just finish before anything had happened.

To test in real-world conditions though, we really do want to do things asynchronously. A synchronous test at this point really isn’t a good idea, since (hopefully) we aren’t going to be writing synchronous downloads in our apps.

Luckily, MockServer and KMSTestCase have this covered. KMSTestCase has a two methods: runUntilPaused, and pause.

The first of these hands back control to the main run loop, and pumps it until something calls pause. If we arrange to call this in our completion handler, we can happily set up an asynchronous request, wait for it to do it’s thing, and then return control to our unit test so that we can check the results.

Here’s the code:

	__block NSString* string = nil;
	
	[NSURLConnection sendAsynchronousRequest:request 
		queue:[NSOperationQueue currentQueue] 
		completionHandler:
			^(NSURLResponse* response, NSData* data, NSError* error)
			 {
			     if (error)
			     {
			         NSLog(@"got error %@", error);
			     }
			     else
			     {
			         string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
			     }
		 
			     [self pause];
			 }];
	 
	[self runUntilPaused];

Test The Results

Finally, we can check that we got back whatever it is that we were expecting to get back.

In this case we should receive the test string that we asked MockServer to return to us:

    STAssertEqualObjects(string, testData, @"got the wrong response: %@", string);

And that, as they say, is that.

By using KMSTestCase, most of the setup work and all of the cleanup work is done for us, and we can just concentrate on the code that performs whatever network operation it is that we’re trying to test, and then checks the results to verify that they are ok.

Clearly there’s more going on under the hood of KMSTestCase, but most of it is just housekeeping and for a lot of situations it should be sufficient for your needs.

You can obviously use KMSServer directly if you need to do something more complicated - examining the source code of KMSTestCase should give you everything you need.

For More Info

You can find full source code and documentation for MockServer on github.

more...

Once or twice I’ve had the situation where I ran some unit tests in Xcode, and they seem to run incredibly fast. Too fast.

Spoiler: they didn’t Instead of Xcode’s Log Navigator looking something like this:

unit tests that ran ok

it instead shows this:

unit tests saying that it succeeded, but where nothing ran

The observant amongst you will have already spotted the flaw in this otherwise nice, friendly, green display of unit testing happiness.

There are no issues because no unit tests ran.

What’s Going On?

Unless you know where to look, just beginning to discover why this might be is a little challenging.

You might think to yourself: “silly me, I must have turned them all off”. A quick look at the Tests settings in the Scheme will verify this:

test settings in the scheme

Nope, they’re on, but Xcode isn’t running them for some reason.

Console Yourself

Normally when something goes wrong with unit tests my first port of call is the console output, and the way I get to it is via the little button that appears on the right hand side of a test when you hover over it:

console button

But with no tests apparently running, there is no little button, so we need to actually go and look in the separate console area.

If you’re the kind of person who leaves everything visible all the time in Xcode, you’ll probably be wondering why I’m even mentioning this, but if (like me), you have behaviors that hide things at various times, then it’s quite possible to not even remember that the console output is still there once the run has finished.

You can get to it like this:

Activate Console menu item

When you do, you’ll discover that something very odd is going on. The normally copious unit test console output has been reduced to:

Console Output

Luckily, Xcode tells us what’s happening (I’ve shortened the paths):

    The test bundle at CURLHandleTests.octest could not be loaded because its
    Objective-C runtime information does not match the runtime 
    information required by the test rig.

and why:

    This is likely because the test rig is being run with
    Objective-C garbage collection disabled, but the test
    bundle requires Objective-C garbage collection.
    To enable Objective-C garbage collection for the test rig,
    run it in an environment without the OBJC_DISABLE_GC 
    environment variable.

Thank you Mr Xcode, you are so good to me.

So, I got my build settings wrong and forgot to disable garbage collection right? I’ll just go and fix it and… oh, hang on… no I didn’t. No garbage collection here.

So, what the hell is going on?

Back to the console. It looks like otest is having trouble:

    2013-01-22 18:25:46.057 otest[5433:203] *** NSTask: Task
    create for path 'CURLHandleTests.octest/Contents/MacOS/CURLHandleTests'
    failed: 22, "Invalid argument".  Terminating temporary process.

For those who are wondering, otest is the command line tool that loads and runs your unit tests.

So it seems to be having trouble. It’s failed, with error code 22. Which is an invalid argument.

Well, that clears things up then.

Long Story Short

Ok, so let’s cut to (somewhat nearer) the chase.

What’s actually happening here, in the cases that I’ve encountered at least, is that otest is failing to load CURLHandleTests.octest - which is the bundle that contains your compiled tests.

There are probably a few reasons why it could fail. Clearly Xcode thinks that garbage collection incompatibility is right up there. However, also high up on the list is that the dynamic loader is failing to load it because it can’t find a shared library or framework that your test code depends on.

If you are using the default Xcode setup, the octest bundle is built into the Products directory, along with any other dependent targets. If your tests need to link at runtime to any custom libraries or frameworks, you need to make sure that they end up here (or somewhere else that the dyld loader can find them).

This is fairly obvious in most cases - for example if you are unit testing a framework that you’re building, it kind of makes sense that you’ll need the framework. In these cases Xcode generally does the right thing anyway - your unit test target will probably depend on the framework target, and they’ll both end up in the Products directory.

So most of the time you’ll be ok, and perhaps even blissfully unaware of how your tests are loaded and run.

However, things can get tricky when the library dependencies are a bit more complex. For example if you’re testing a framework and the framework itself relies on some other shared libraries that are custom built, and not just pre-installed in some convent location like /Library/Frameworks/.

It’s possible in this case for the framework to embed these libraries as part of it’s own build process, which makes life a lot simpler for people who use it - and will probably not cause the sort of issues I’m talking about. That doesn’t always happen though, for good reasons such as not wanting to end up with multiple copies of a library embedded in more than one framework.

In this situation, where your framework is looking for a shared library that it can’t find, what will happen is a runtime failure to load your framework. This in turn will cause your unit test bundle to fail to load, which in turn will cause otest to bomb out with the useful error 22, which in turn will cause Xcode to LIE TO YOU BY PUTTING UP A BIG GREEN THING SAYING ALL YOUR TESTS RAN.

Sorry. Deep breaths.

## The Fix

So once you’ve figured out what library you’re missing, the fix is quite simple. Just add a build phase to your unit test target which copies the relevant things into the Products Directory:

Copy Files Phase

(yes, in this case we’re linking against our own builds of libssh2, libssl and libcrypto - they aren’t the normal builds, so if they are missing, everything goes pear-shaped).

Happily, if you’ve got the right libraries, all will now be well and the unit tests will run.

Of course, working out what library you’re missing isn’t always trivial, especially if it’s a big codebase and/or you aren’t in control of it all.

How to work out which libraries depend on which is a blog post all of its own, but here are a few handy hints.

otool

You can use otool (not to be confused with otest, which I mentioned earlier), to work out what something links to.

You have to run it on the actual binary inside your octest bundle

otool -l /Caches/DerivedData/CURLHandle-flfotwdrtmazzmdpxjznosnizjlm/Build/Products/Debug/CURLHandleTests.octest/Contents/MacOS/CURLHandleTests 

This will produce a big load of output, including things like this:

          cmd LC_LOAD_DYLIB
      cmdsize 104
         name /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (offset 24)
   time stamp 2 Thu Jan  1 01:00:02 1970
      current version 744.1.0
compatibility version 150.0.0

Which tells you that you’re linking against CoreFoundation - which you could probably have guessed.

All the system ones are probably fairly expected and aren’t likely to be the problem. However, if something shows up in this dump that you weren’t expecting, it’s a good clue where to look.

Update: otool -L actually gives you a much more compact output here, just listing the libraries that are linked to:

    @rpath/Connection.framework/Versions/A/Connection (compatibility version 1.0.0, current version 1.0.0)
    @rpath/SenTestingKit.framework/Versions/A/SenTestingKit (compatibility version 1.0.0, current version 4053.0.0)
    @rpath/DAVKit.framework/Versions/A/DAVKit (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 945.11.0)
    /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)
    /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 744.1.0)

DYLD_ variables

Another thing that may help is to enable a few DYLD_ environment variables and then run otest manually. Knock up a little script like this:

export DYLD_PRINT_LIBRARIES=YES
export DYLD_PREBIND_DEBUG=YES
export DYLD_PRINT_ENV=YES
export DYLD_PRINT_APIS=YES

export OBJC_DISABLE_GC=YES

xcrun otest /Caches/DerivedData/CURLHandle-flfotwdrtmazzmdpxjznosnizjlm/Build/Products/Debug/CURLHandleTests.octest 

What you’ll see when you run this is a whole load of debug output from the DYLD loader itself.

...
dlopen(/Caches/DerivedData/CURLHandle-flfotwdrtmazzmdpxjznosnizjlm/Build/Products/Debug/CURLHandleTests.octest/Contents/MacOS/CURLHandleTests, 0x00000115)
dlopen(/Caches/DerivedData/CURLHandle-flfotwdrtmazzmdpxjznosnizjlm/Build/Products/Debug/CURLHandleTests.octest/Contents/MacOS/CURLHandleTests, 0x00000109)
dyld: loaded: /Caches/DerivedData/CURLHandle-flfotwdrtmazzmdpxjznosnizjlm/Build/Products/Debug/CURLHandleTests.octest/Contents/MacOS/CURLHandleTests
dyld: loaded: /Volumes/titan/Users/Shared/Applications/Xcode/Xcode46-DP4.app/Contents/Developer/Tools/../Library/Frameworks//SenTest
....

This may give you a clue about which library or framework is failing.

Other References

The topic of libraries, frameworks and dynamic linking is a fairly complicated one in its own right.

If you encounter the problem that I’ve described above, the chances are that you’re working with a fairly large and/or complex project with multiple libraries, and you’ll already know a bit about dynamic linking.

If not, these links may help.

  • Run-Path Dependent Libraries: This article explains how the system finds out where your libraries are at runtime, and how you can set up any frameworks or libraries that you build so that they can be hosted in the the /Library/Frameworks folder, or inside your app, or embedded in another framework, in a way which still allows them to be found.

  • Mac OS X Debugging Magic: This tech note gives a lot of helpful advice on debugging.

  • Friday Q&A 2009-11-06: Linking and Install Names: Mike Ash has also covered this topic.

  • You can also use man dyld in the terminal to get a full list of the DYLD_ variables.

In Conclusion

This problem can be really tricky to solve.

Just knowing what the problem is would be a good start, but Xcode does it’s best not to tell you.

Of course, I have filed a radar. Feel free to dupe it.

Hopefully, if you’ve stumbled across this blog post whilst tracking it down, I’ll have pointed you in the right direction!

more...

January 07, 2013

Well, 2012 turned out to be quite a busy year for me on the contracting front.

Some of the main highlights:

  • Most of the coding for the iOS game Bag It and Bin It was actually done in 2011, but it finally came out at the end of the year, and I did a bit more work on an update during 2012. Written using Cocos2D, this was great to work on, and it was nice to get the chance to do a little game from scratch.

  • On the other end of the spectrum, I spent some time in the summer wrapping up a C++ library and turning it into an Objective-C iOS framework for another client. This couldn’t be more different from writing a game, but designing code to be used by other programmers is also something that I enjoy, so this was also a nice little job.

  • In the early spring, I started doing some MacOS X work for Karelia, which continued through the year (and hopefully on into 2013!). This work has covered all sorts of territory, from unit testing their libraries to some networking and user interface work for their main product Sandvox. They like to keep me on my toes…

  • Finally, in the autumn I also started working on the SVG import/export component of Bohemian Coding’s excellent MacOS X vector graphics app Sketch. Once again, a very different area to work in, with a whole new set of challenges, but definitely fun. The SVG standard is a bit of a monster, and making software that can understand everything in the standard would be a monumental task, so we took a pragmatic approach, trying to identify the areas that are most often used and tackle them first. It feels a bit like painting the Forth Bridge, in that by the time we’ve done everything there will probably be a new version of the standard out :)

So a pretty varied year, and those are just the highlights.

The one down side of this is that the time I’ve had to spend on Neu, Ambientweet, and some other as-yet-unreleased projects of my own, has been somewhat limited. I really hope that I can rectify that in 2013, and give them a bit more love.

The only problem is that the work for Karelia and Bohemian is continuing, and I’m enjoying it too! If anyone invents a time machine, please let me know…

more...