OCMock Woes


So I’m building and running tests and banging my head against oncoming traffic while trying to get the OCMock framework to do something… I dunno… mocky? I’m running Xcode 4.2 build (4D199) on Lion. Dragging and dropping the freshly downloaded “.framework” bundle doesn’t want to link. Hi, I’m Cliff and you’re here because you have linker errors in your XC4 project while trying to get objects to pretend to be other objects. I’m here to try to help you work through some of the issues.

So I try building the static lib and forcing it. The first roadblock I hit was with the ${BUILD_STYLE} environment no longer being set. ${BUILD_STYLE} is changed to ${CONFIGURATION} in Xcode 4. The second bump I hit was with categories not loading from the static lib I generated. Setting “-ObjC” under “Other Linker Flags” solved this. Next I get OCMock to load but auto complete doesn’t work with the category methods added to “id”. (Eg. stub, expect, verify, etc.) I accidentally set my “Header Search Path” incorrectly. You have to set it to point to the folder that contains the OCMock folder with the header files in it, then you can successfully import in your test cases. Finally auto-complete works and things load but setting simple expectations on a mocked string appears to be broken. I’m now wondering if I should download source from the git repo instead of building the source included in the dmg. It’s late and I’m incredibly frustrated with not being able to write a single test all day…

Re-sign your iPhone release builds


I have a quick post for tonight that I don’t want to lose. The problem I was trying to solve about a month ago regarded testing my iOS release builds that had been signed for the AppStore distribution. Our QE guy, a bright fellow, taught me how to re-sign the package with my development certificate so that it could be run on the device.

codesign -f -s “iPhone Developer: Clifton Craig (DUWQRS4KP8BM9)” -vv MyCoolProduct.app

Speex On iPhone Explained Part II


*Update*
From part I I neglected to point out that you should un comment #define _USE_SSE in the config.h as mentioned below. This preproc directive will allow you to run on device. It was also mentioned that you could get more speed out of Speex if you #define FIXED_POINT instead of FLOATING_POINT. I have not verified this and Speex runs acceptable in my implementation without it but its worth mentioning.
*Update*

You have a lot of vocal audio data. Maybe it needs to be stored on an iPhone. Maybe it needs to glide effortlessly over the network like a slice of dental floss blowing in the wind. Whatever the case, you need a good compressor and Speex is a great solution. Hi, I’m Cliff. You’re here because you’re looking for an answer to your audio compression needs. I’m here to deliver the secrets to decompressing audio with the Speex codec. That, for what it’s worth, is the only reason I’m still hanging around here. In any other event you’d probably find me on South Street sharing a soda with a cat. I digress . . .

In part I of this series I explained how to get Speex to compile. Today we’ll try to import the OGG container format into our project and move onto Speex decompression. Because not everyone may be aware, a brief explanation on codecs and containers is in order. Audio encoding is typically made of two distinct pieces. You would usually have a container format and an encoding. The audio container holds the meta data, or descriptive information, for the actual audio file. This meta or descriptive information includes things like how many channels are in the audio data, what sample rate it is recorded at, and the endianness (not Indianness) of the audio data. There are other potential data held in the container format depending on the type of encoding you use. Finally, the descriptive (meta) data will have the location (offset) of the actual audio data in the file. The encoding is the actual raw audio data that is to be delivered directly to the output device or speakers. The encoding can be a direct digital dump (that is the actual audio samples taken over time as the audio was recorded) or it can be a compressed variant of the raw samples. It’s important to note that the encoding and the container are not usually dependent upon one another. That mean you can mix and match Speex encoding with a wave container format just the same as you can put raw uncompressed samples in an OGG container. It’s just more common to find uncompressed data in a wave container and Speex compressed audio in an OGG container.

Let’s take a step back and try some TDD. Following best practices, we need to create a need for the Speex codec and the OGG container. I realize this is cart before the horse style since we’ve already imported Speex but bear with me as I’m doing this tutorial on my time off. Also up until now I’ve been completely out of the TDD habit for a while as I strive to work closely with others who are uncomfortable with the style. We start by creating a “Unit Test Bundle” target in the project. Create a new objective C class named “CCCSpeexDecoderTest” using the “New File…” dialog and do not choose (unselect) the “also create .h file” option. Include the following in your new Objective-C class file.

//
//  CCCSpeexDecoderTest.m
//  SpeexLib
//
//  Created by Clifton Craig on 11/13/10.
//  Copyright 2010 Craig Corporation. All rights reserved.
//
#include <SenTestingKit/SenTestingKit.h>

@interface CCCSpeexDecoderTest : SenTestCase
{
	NSString* wavFile;
	NSString* speexFile;
}
@end

@implementation CCCSpeexDecoderTest

-(void) setUp
{
	wavFile = [[NSBundle bundleForClass:[self class]] pathForResource:@"sample" ofType:@"wav"];
	speexFile = [[NSBundle bundleForClass:[self class]] pathForResource:@"sample" ofType:@"spx"];
}

-(void) testFirstTest
{
	STAssertNotNil(wavFile,@"A sample wav file is required to test speex decoding.");
	STAssertNotNil(speexFile,@"A sample speex file is required to test speex decoding.");
}

@end

Running this tells us that we’re going to need some speex data to operate on. (I’ve taken the liberty to generate a wav file using the “say” command and converted it to a Speex encoded file using the JSpeex API via Groovy. I’ll include both in a download of the project for this lesson.) Next we’ll create a structure to hold our unit tests and test resources. We will be following the “golden copy” testing pattern. You later learn that using the pattern here is rather fragile, however a more purist approach would take us through an exercise of re-writing the entire Speex project which is outside the scope of my tutorial. Using Finder, I created a “Tests” and a “Resources” folder under my src folder in my project. Drag/drop these folders into XCode to create the corresponding groups. Then drag/drop the sample wave and sample speex files (named “sample.wav” and “sample.spx” respectively) into the “Resources” group in XCode. Running the test will now pass.

We now work our way through creating the decoder. I’ll spare the individual steps in TDD as it would make this text overly verbose and I’ll try to summarize instead. We need an actual decoder instance which we’ll be importing. TDD suggests we import what we don’t have so add the import for a CCCSpeexDecoder type which does not exist. Build and fail. (The failure is important as it formalizes the class or feature you are about to add/change/delete.) We also need to be able to create this type and give it some audio to decode. It will also need a place to send the decoded audio data. I’m going to define an abstraction for providing/receiving the audio data so that we don’t necessarily need a file system so I’m adding a test to demonstrate/document the need for an audio source, a test to demonstrate/document the need for an audio sink, and one other test that formalizes how we plug these two abstractions into the decoder.

#import "CCCSpeexDecoder.h"

@interface CCCSpeexDecoderTest : SenTestCase <CCCSpeexAudioSource, CCCSpeexAudioSink>
{
	NSString* wavFile;
	NSString* speexFile;
	CCCSpeexDecoder *decoder;
}
@end

@implementation CCCSpeexDecoderTest

//...

-(void) testAudioSourceIsDefined
{
	id<CCCSpeexAudioSource> anAudioSource = self;
}

-(void) testAudioSinkIsDefined
{
	id<CCCSpeexAudioSink> anAudioSink = self;
}

-(void) testCanCreateDecoder
{
	[[CCCSpeexDecoder alloc] initWithAudioSource:self andAudioSink:self];
}

And this calls for the additional CCCSpeexDecoder class which defines the abstractions…

#import <Foundation/Foundation.h>

@protocol CCCSpeexAudioSource

@end

@protocol CCCSpeexAudioSink

@end

@interface CCCSpeexDecoder : NSObject {

}

- (id) initWithAudioSource:(id<CCCSpeexAudioSource>) anAudioSource andAudioSink:(id<CCCSpeexAudioSink>) anAudioSink;

@end

#import "CCCSpeexDecoder.h"

@implementation CCCSpeexDecoder

- (id) initWithAudioSource:(id<CCCSpeexAudioSource>) anAudioSource andAudioSink:(id<CCCSpeexAudioSink>) anAudioSink
{
	self = [super init];
	if (self != nil) {

	}
	return self;
}

@end

Now we go back and add one more test that explains what we’re after.

-(void) testCanDecode
{
	[decoder decodeAudio];
}

Build and fail so that we know to define the method.

-(void) decodeAudio
{
}

We now have defined the ability to decode audio. We have to set our expectation for this method. (Test first begins with declaring or expressing a need for a feature or function then setting an expectation for its behavior.) After invoking decodeAudio we would expect to have collected the decoded audio bytes somewhere. I’ll add a mutable data fieldin the test for this.

@interface CCCSpeexDecoderTest : SenTestCase <CCCSpeexAudioSource, CCCSpeexAudioSink>
{
	NSString* wavFile;
	NSString* speexFile;
	CCCSpeexDecoder *decoder;
	NSMutableData *decodedAudio;
}
@end

@implementation CCCSpeexDecoderTest

-(void) setUp
{
	wavFile = [[NSBundle bundleForClass:[self class]] pathForResource:@"sample" ofType:@"wav"];
	speexFile = [[NSBundle bundleForClass:[self class]] pathForResource:@"sample" ofType:@"spx"];
	decoder = [[CCCSpeexDecoder alloc] init];
	decodedAudio = [[NSMutableData alloc] init];
}

And we add a test to exercise the method and document/verify our expectation:

-(void) testDecodeAudioFillsDecodedAudio
{
	STAssertTrue([decodedAudio length] == 0, @"Should NOT have accumulated data");
	[decoder decodeAudio];
	STAssertTrue([decodedAudio length] > 0, @"Should have accumulated data");
}

Here’s the Oogly part. We are calling a method with no return value. We’ve defined an abstraction around collecting data (an audio sink) and we’ve made our test case adopt the protocol for this abstraction. The protocol defines no methods. The test calls for data to magically arrive in the mutable data field. Indirectly, our test is stating that given a source and a sink, when the decodeAudio message is sent we should have accumulated data in the sink. running the test fails because we haven’t added the functionality. We step into the decodeAudio implementation and fill in the simplest thing that works.

-(void) decodeAudio
{
	NSString *pretendData = @"pretendData";
	[audioSink audioWasDecoded:
		[NSData dataWithBytes:[pretendData cStringUsingEncoding:NSUTF8StringEncoding] length:[pretendData length]]
	 ];
}

You see we are talking to an audioSink object here. Because we don’t really have an audiosink object in scope (I just made it up b/c it felt right) we need to declare it.

@interface CCCSpeexDecoder : NSObject {
	id<CCCSpeexAudioSink> audioSink;
}

If we run we still won’t get satisfaction because we haven’t ensured that the audiosink given in the constructor is the one we talk to when we decode audio. So we revisit the init method.

- (id) initWithAudioSource:(id<CCCSpeexAudioSource>) anAudioSource andAudioSink:(id<CCCSpeexAudioSink>) anAudioSink
{
	self = [super init];
	if (self != nil) {
		audioSink = [anAudioSink retain];
	}
	return self;
}

We also need to release in our dealloc.

- (void) dealloc
{
	[audioSink release];
	[super dealloc];
}

Let’s be more specific. When decoding audio we will want to discover the meta data or attributes of the audio. This information is usually the first group of bytes in a file and it explains what the rest of the file contains. We’ll declare an expectation to receive a callback in our sink which contains the meta data in an easily navigable NSDictionary.

-(void) testDecodeAudioReturnsHeaderInfoToSink
{
	STAssertNil(headerInfo, @"We should start with no header info.");
	[decoder decodeAudio];
	STAssertNotNil(headerInfo, @"We should now have header info.");
}

and we need to add an NSDictionary field to our test to record the header info.

@interface CCCSpeexDecoderTest : SenTestCase <CCCSpeexAudioSource, CCCSpeexAudioSink>
{
        //Other fields...
	NSDictionary *headerInfo;
}
@end

we add the simplest thing that will work.

-(void) decodeAudio
{
	NSString *pretendData = @"pretendData";
	[audioSink headerWasDecoded:[NSDictionary dictionary]];
	[audioSink audioWasDecoded:
		[NSData dataWithBytes:[pretendData cStringUsingEncoding:NSUTF8StringEncoding] length:[pretendData length]]
	 ];
}

…And this calls for an additional method in our AudioSink protocol.

@protocol CCCSpeexAudioSink <NSObject>

-(void) audioWasDecoded:(NSData*) someDecodedAudio;
-(void) headerWasDecoded:(NSDictionary*) theAudioAttributes;
@end

Which bleed back into the test where we store the attibutes as our header info. Add the following to the test case.

-(void) headerWasDecoded:(NSDictionary*) theAudioAttributes
{
	headerInfo = theAudioAttributes;
}

Now we’ll look at individual attributes given to the sink during the parse. We set some expectations for numeric values mapped to specific keys in the header info.

-(void) testDecodeAudioHeaderInfoIncludesSpecificValues
{
	[decoder decodeAudio];
	NSNumber *value = [headerInfo valueForKey:@"sampleRate"];
	STAssertNotNil(value, @"Should have returned a number");
	value = [headerInfo valueForKey:@"frameSize"];
	STAssertNotNil(value, @"Should have returned a number");
	value = [headerInfo valueForKey:@"numberOfChannels"];
	STAssertNotNil(value, @"Should have returned a number");
	value = [headerInfo valueForKey:@"decodeBlockSize"];
	STAssertNotNil(value, @"Should have returned a number");
	value = [headerInfo valueForKey:@"framesPerPacket"];
	STAssertNotNil(value, @"Should have returned a number");
}

And as you’ll note a pattern here we should do some refactoring.

-(void) assertNumericValueInDictionary:(NSDictionary*)aDictionary atKey:(NSString*)aKey
{
	NSNumber *value = [headerInfo valueForKey:aKey];
	STAssertNotNil(value, @"Should have returned a number");
}

-(void) testDecodeAudioHeaderInfoIncludesSpecificValues
{
	[decoder decodeAudio];
	[self assertNumericValueInDictionary:headerInfo atKey:@"sampleRate"];
	[self assertNumericValueInDictionary:headerInfo atKey:@"frameSize"];
	[self assertNumericValueInDictionary:headerInfo atKey:@"numberOfChannels"];
	[self assertNumericValueInDictionary:headerInfo atKey:@"decodeBlockSize"];
	[self assertNumericValueInDictionary:headerInfo atKey:@"framesPerPacket"];
}

Because I forget the attributes of the file provided I’m going to use a discovery test technique. With this technique we use a dummy expected value in our assert and allow the assertion error message tell us what the actual value is. I wouldn’t do this in normal testing. It’s only because I already have working code that I’m plugging in and because this tutorial is getting wordy that I’m going to take the cheap way out.

-(void) assertIntValue:(int)anInt isInDictionary:(NSDictionary*)aDictionary atKey:(NSString*)aKey
{
	NSNumber *value = [headerInfo valueForKey:aKey];
	STAssertNotNil(value, @"Should have returned a number");
	STAssertEquals([value intValue], anInt, @"Integer value %i should exist for key %@", anInt, aKey);
}

-(void) testDecodeAudioHeaderInfoIncludesSpecificValues
{
	[decoder decodeAudio];
	[self assertIntValue:-999 isInDictionary:headerInfo atKey:@"sampleRate"];
	[self assertIntValue:-999 isInDictionary:headerInfo atKey:@"frameSize"];
	[self assertIntValue:-999 isInDictionary:headerInfo atKey:@"numberOfChannels"];
	[self assertIntValue:-999 isInDictionary:headerInfo atKey:@"decodeBlockSize"];
	[self assertIntValue:-999 isInDictionary:headerInfo atKey:@"framesPerPacket"];
}

Once we implement the actual parsing logic we will start to see the actual values reported in the assertion errors. (I am adapting existing working code rather than developing the code from test cases.) We will pull the values from the errors back into the asserts to make the test pass and document what our expectations actually are.

Now we need to actually start pulling audio from our audio source abstraction. Because we used protocols, our test can pose (using the self-shunt pattern) as the audio source and provide data for the decoder. We step into the decoder and start doing some actual parsing.

-(void) decodeHeader
{
	[audioSink headerWasDecoded:[NSDictionary dictionary]];
}

-(void) decodeAudio
{
	NSString *pretendData = @"pretendData";
	[self decodeHeader];
	[audioSink audioWasDecoded:
		[NSData dataWithBytes:[pretendData cStringUsingEncoding:NSUTF8StringEncoding] length:[pretendData length]]
	 ];
}

Importing OGG

At this point we have to import OGG for decoding the container so we can read the file meta data. Download and unpack libogg (not liboggz) from the Xiph.org download site.

We need to add the ogg header files to the header search path, so drag/drop the ogg folder from the include folder in the root of the unpacked directory into your XCode project. (/path/to/libogg-1.2.1/include/ogg) Choose to Copy the files from the dialog and select your static lib target before accepting the dialog. Delete the config_types.h.in and makefile.am and Makefile.in from this folder and group. (Also move them to trash.) Double click the project icon in the left tree pane and select the “Build” tab. Type “header search” in the search box at the top to narrow the options to the header search path. You need to add, “$(SRCROOT)” as one of your header search path values here. Create an XCode group for the ogg source code and drag/drop the “bitwise.c” and “framing.c” files from the unpacked libogg source folder. (/path/to/libogg-1.2.1/src).

At this point building unit test target should leave you with errors from the latest round of header info asserts which we will fix in the next part of the series. We have a fully configured project with access to both the speex and ogg encoding/decoding APIs which is exciting. In the next part of the series we will tackle calling into these APIs to decode the data. I’m going to upload my part II example project to my box account so it will be in the right and pane for your downloading pleasure. Until next time…

(Some of you will have noticed I accidentally published this post the other day before finishing it. This is why I’m publishing it half baked tonight. There’s alot here and a lot more to cover. Keep checking back for updates!)

Speex On iPhone Explained


*Update*
I neglected to point out that you should un comment #define _USE_SSE in the config.h as mentioned below. This preproc directive will allow you to run on device. It was also mentioned that you could get more speed out of Speex if you #define FIXED_POINT instead of FLOATING_POINT. I have not verified this and Speex runs acceptable in my implementation without it but its worth mentioning.
*Update*

I get a lot of questions on how I implemented Speex on iPhone. So I’m going to take this time to do a quick tutorial series. This is part 1, which will show you how to import the speex source into XCode and get a clean compile.

First download and explode the Speex source to any location. Run “./configure” in the exploded folder and create an iPhone subfolder within the speex in this same location. Now we’ll begin creating an XCode project inside the iPhone subfolder. I use a static lib project so that I can reused my work in several other projects, but if you’re new to XCode and iPhone you may forego static libs and just create a typical view based project. I start out being anal about my project structure. I prefer to have only the project folder and a single src folder at my project root. I realize this is non standard iPhone but it makes perfect sense from a build perspective. (I see: build description + src = build output) So a little refactoring and adjusting my target settings to find the new location of the plist and pch files.

  • Drag/drop the libspeex and include/speex folders into your XCode project.
  • Drag/drop the config.h file from the unpackaged speex tar into your project.
  • Add the include folder to your header search path
  • Double click the project in the left hand tree and add the following user defined setting: GCC_PREPROCESSOR_DEFINITIONS = HAVE_CONFIG_H
  • (User defined settings can be added by clicking the little wrench in the lower left corner.)
  • Finally, you need to take “libspeex/echo_diagnostic.m” out of the compile loop. Either uncheck the target membership box next to the left hand “Groups & Files” tree pane on the left or open and drill into your Application (or static lib) target and select the “Compile Sources” branch. Find the file under there and delete it.

By now your compiles should be squeaky clean. Stay tuned to the next parts of the series where I’ll discuss how to import ogg and wave container formats into XCode and perform Speex decompression in an app. I’ve upoaded my source (SpeexLib) to my box.net account so you can click here to download it or find it in the Box widget to the right of this post.

Compile Speex For iPhone


Speex is an audio codec specially designed for voice audio. I’m sorry, a codec is a software component used for encoding and decoding something. Oops, I’m terribly sorry! An iPhone is kinda like a phone but it has no wires, y’see… and the letter i is prefixed to it because… Hi, I’m Cliff. You’re probably here because you already know what an iPhone is. Maybe you’ve seen one of the commercials. Maybe your cousin’s best friend’s uncle’s nephew’s best friend’s cousin has one. (In case you missed it, that was a really really verbose way of saying “your cousin”!) Maybe you’ve been around the block once or twice and happen to know about both codecs and Speex. (Maybe it was dem fools throwin’ bones by the liquor store that taught you about Speex. Don’t laugh, cause you’d be surprised by what you learn on the streets these days.) Whatever the case, I’m going to explain how I got a clean compile on the Speex library using XCode. Hold tight because the remainder of this post is designed to be informative… that is all jokes and nonsense to the side.

  1. Download the Speex C source bundle
  2. Unpack it
  3. you might wanna try building it from the cmd line. Run “./configure;make” from the folder where you unpacked it.
  4. Create a new project in XCode. This can be an iPhone or an OSX project but for consistency’s sake (and because it’s what I put in the title) let’s use an iPhone project.
  5. Create an actual folder, not an XCode group, under the root of your new project and call it “CSource”. This is where we’ll put the Speex source code.
  6. Drag/drop the folder into your XCode project or create a group that points to that folder.
  7. Double click your project icon in the left hand tree in XCode to edit the project settings.
  8. Goto the build tab and type “header” in the search field to filter your choices to the things that deal with headers. (Yes I just blatantly included a “goto” in a modern day technical writeup.)
  9. Look for the “Header Search paths” build setting. It should fall under the search paths category somewhere toward the middle of the screen. If you don’t see it finish typing the term “header search paths” in the search bar above. It does an incremental search as you type.
  10. Double click the Header Search Paths build setting to bring up the edit dialog then double click in the value field and set the value to “$(SRCROOT)/CSource”
  11. Open the folder that you unpacked Speex to in Finder and drag the “libspeex” folder directly into the CSource grouping you created in XCode. Choose yes to copy the files.
  12. Back in Finder, navigate to the include folder under the Speex unpack directory. Drag the “speex” folder out of here and next to the libspeex folder you added to your project in XCode. Choose yes to copy the files.
  13. Back in Finder, drag the “config.h” file out of the root of the speex unpacked folder and into your XCode project.
  14. Back in XCode, hit Cmd+Shift+D and type “arch.h” to find and open the arch.h file we’ve imported into our project.
  15. Add a “#include” to include “config.h” at the top.
  16. Remove the “echo_diagnostic.m” file under libspeex from the project as it will just cause complications.
  17. Hit compile and wait for the errors to roll in!

If you followed the above steps correctly then you should only see a few errors relating to duplicate symbols. If you get thousands of errors then it’s likely related to missing header files. You probably have to make sure you imported the speex folder with all the headers and double check your header search path to make sure that it points to the directory containing the imported “speex” folder. You might find a bunch of errors if you don’t remove the “echo_diagnostic.m” file from compilation. The last order of busniess would be to import the ogg container source.I downloaded libogg-1.1.4 which appears to work with speex-1.2rc1. Including the “ogg.h”, “os_types.h”, “bitwise.c”, and “framing.c” files allows me to compile code included from the “speexen.c” and “speexdec.c” examples.

Objective-C Gotchas


You’re working in Objective-C land trying to get a product out the door and into the Apple iTunes Store, right? (Don’t argue with me I’m just setting the stage.) You’re feeling the second cup of coffee seep into your bloodstream which creates a certain euphoric sensation as the last 3 times you mashed Cmd+B turned up no errors. Yes, that’s what’s happening in your copy of XCode right now. You then Cmd+Tilde to toggle the other XCode window active (Cmd+Tilde is a nifty Apple shortcut for switching active windows in the current app) and Cmd+B once again when a red flag on the play pops up in some code that had been just fine moments ago? What happened? Hi, I’m Cliff. You’re here because XCode got’cha and you’re not quite sure how/why/where. I’m here because I wanna list as many of these got’chas before I forget them.

Property accessor notation in Earlier SDKs
Here’s one weird gotcha that I just hit again for the first time. If you have a variable typed as a protocol and that protocol has a setter, which takes another protocol type defined then you may get an error when using dot notation in SDKs earlier than 3.0. That is a definition like this:

@protocol MyCoolAbstractType <NSObject>
-(void) setNetworkDataProvider:(id<MyNetworkDataProvider>)aNetworkDataProvider;
@end

…should be coded like this:

@protocol MyCoolAbstractType <NSObject>
@property (nonatomic, retain) id<MyNetworkDataProvider> networkDataProvider;
@end

…before you can do this:

id<MyCoolAbstractType> myObj = //create object from factory
myObj.networkDataProvider = [[MyConcreteNetworkDataProvider alloc] init];

Evidently the “Discover setter is a property” feature is something new Santa delivered with 3.0 and never told me about. Here I thought I had that toy from 2 years ago!

Unit Tests Can’t Be Signed
I added a unit test dependency to my “Application” target the other week in order to streamline my dev cycles. The idea was to ensure any changes I made to satisfy the integrated application bundle did not impact behaviors outlined in my test cases. (I use mini applications to perform my integration testing.) The problem here is that, even though this works well for simulator builds, an on-device build will fail as XCode attempts to sign your unit test target output. I haven’t discovered a work-around for this one yet so I’m gonna just punt and remove the test dependency from any targets meant to run on device.

I’ll trow up more as I find them…

Hard to test things


So I’d been thinking. Because I’m back into iPhone development and getting warmed up not only to ObjC issues and errors but also C++ oddities, I’m wondering how do you write tests for some of the more difficult things to capture? For instance, I’ve figured out how to capture some of the manual reference counting that’s required by CocoaTouch. (I assert that objects passed into other objects are properly retained and properly released when the object itself is released.) Still I can’t capture the more involved memory management problems. How do you assert an autorelease? What about dynamic memory allocation with pointers? I ended up with a single method that dynamically allocates for a pointer via malloc. I then changed it to use new with array notation.

void MySpecialObject::writeRequestToStream(CFStringRef aRequest, CFWriteStreamRef requestStream)
{
if(CFWriteStreamGetStatus(requestStream) == kCFStreamStatusNotOpen) CFWriteStreamOpen(requestStream);
UInt8* convertedString =(UInt8*)convertToCString(aRequest);
CFWriteStreamWrite(requestStream, convertedString, CFStringGetLength(aRequest));
free(convertedString);
}

It’s used in one spot so far and I’ve manually added the free without a prior failing test. I felt dirty. Assuming there were no call to free, how would you write a failing test for the code above? Is this just one of those things where you have to be extra careful? Maybe I should investigate the use of Velocity style code macros/templates that expand after keying special abbreviation similar to what we have in IntelliJ. I can imagine something like “cstr” expanding to:

char *myCStr = new char[size];
// use myCStr here
free(myCStr);

With the ability to tab through highlighting the variable name, declared size and commented insert code section. Any bright ideas?