Sing it with me


I know you don’t tweet… I know this, man! But today I’m gonna get you tweeting. Cause it’s Friday, and you ain’t got s**t to do!

If you ever saw me or tried following me on Twitter you’d know that I don’t get it. I don’t tweet. That aside, I finally found an excuse, no, a reason to tweet. Reading techknow I learned about the #songsincode trend that started around a week ago on the 20th and decided to jump in. Here’s some of mine in case they whizzed by you:

@snf -(double) get {return getpaper && trash == taken_out ? spending_cash : nil} #songsincode
9:02 PM Aug 26th from web
it=new Thread(go); try{it.start();} catch(InterruptedException e) {it.start(); out.println(“ah-ah-ah-ah” + it.isAlive());} #songsincode
8:46 PM Aug 26th from web
foreverTask = new Thread(this); while(foreverTask.isAlive()) {System.out.println(“ah… ah… ah… ah…”);} #songsincode
8:33 PM Aug 26th from web
everybody.each { it.dance(new Date()); } rhythm.take(new Control()); rhythm.move(you); #songsincode
8:23 PM Aug 26th from web
if(i.shouldStay()) yourWay.contains(i); else { i.go(); for(eachStep : theWay) i.know(i.hasThoughtsOfYou); } #songsincode
9:42 PM Aug 25th from web
4.times{ someOfThem.each { them -> assertFalse this.rhyme.compareTo(them.tryToRhyme()) : “can’t be done”} } #songsincode
9:36 PM Aug 25th from web
[@”you” caseInsensativeCompare:@”a kiss from a rose on the grey”]; while([self get:@”you”]) {NSAssert([self feelStranger]);} #songsincode
9:21 PM Aug 25th from web
if(you.gunUpInYoWaist()) {please {shootUpthePlace(NO)} } else { ladies.each{ i.see it.canBeHavingMyBaby() } } #songsincode
9:01 PM Aug 25th from web
MJ RIP: while(true) { if(you.getEnough()) break; else keepOnWith(THE_FORCE) } #songsincode
8:48 PM Aug 25th from web
Bobby Brown in Groovy: 2.times{ [1..99].step {assert you.willBeThere() && me.isTogetherWith(you)} } #songsincode
8:43 PM Aug 25th from web
thinkAboutIt = {i.setBelief({ assert i.canFly() && i.canTouch(getSky())})} nightsAndDays.each { thinkAboutIt() } #songsincode
8:35 PM Aug 25th from web

Here’s the thing. If you can decipher these or any of the others on twitter I’d love to hear about it. As a matter of fact, we need some sort of #songsincode decompiler.

Why won’t my dotNet J# ISAPI filter play nice with your Python interface for Ruby?


I have an ObjC project that I compiled under Cygwin using the trunk GCC. I’m linking against a rare .dll that I could only find in my Eclipse download as its no longer supported. The whole thing powers my web service. It works fine on my 32 bit XP box but crashes on my 64 bit Vista server when I call it from a Linux VM running on the same box. However, if I run it on my other 64bit Vista server which has an Itanium processor, then it will work but slows down over time due to a known memory leak in the IIS server that front-ends it. Does this sound like you? Do you often find yourself in the middle of a smorgasbord of ELF files, incompatible IDE plugins that sometimes work well enough on Tuesdays and Wednesdays, and other layered technologies that only you seem to understand? How does that happen? Hi, I’m Cliff. You’re here because your VPN client conflicts with a video driver running on your modified Debian kernel that supports both Ubuntu and Lenny binaries. I’m here because it’s not your fault. Don’t most people hack undocumented config files just prior to building a Linux distro to power the mission critical server that they plan to release just prior to taking vacation. How were you supposed to know that the “#IF DEF” you hand authored to work around a segmentation fault would cause a kernel panic at peak time?

Here at “Can’t see nothing but the source” we discuss a lot of diverse technologies. I’m no stranger to loading something as proprietary as the RIM compiler directly on Mac hardware under OS X. I’ve also tried my hand at dynamically defining Ant tasks using the Ant-Maven jar under a Groovy/Gant build launched from a Maven pom invoked from a custom GMaven plug-in. My point here is that I’m crazy. I’m crazy and you’re stoopid for following me. Now I’d normally refrain from insulting my audience especially since I only have 3 audience people that visit regularly, but C’mon son! I’ve been at this for years now and not once has anybody posted a comment like, “Dude, the OS X platform was like, not made for running AS/400 binaries!” Instead, my audience agrees with most of the nonsense I post. No matter how hard I try to launch VMWare on my Blackberry, nobody stands up and says, “Stobbit you clown! There’s only 1MB of free memory on that thing!”

I’ve come to this realization today while I almost figured out how to use BZR to hook IntelliJ up to an svn repo to work around the Kerberos issue that causes SVNKit to give up the ghost. I said, “gosh, nobody does this sort of stuff! Why not?” You know that feeling you get when you finally realize that everyone else on the planet wears a T-shirt under a turtleneck? (And I promised I would never get personal on my site!) Well that’s how I feel. Don’t act like it’s just me! A whole lot of you probably go through this every evening! Dare to be different!

So this is what we’re gonna do. I want you, yes you, to think back. Remember the craziest combination or kludge of software you ever assembled. Remember how hard you toiled to get two or more totally opposite software packages to pretend like they were one. Re-live the feeling of superiority you experienced when it finally, almost, kinda worked, sorta? After you summon those old thoughts list them below. Include various detail like, how heavy was the font use to list said accomplishment on your resume? How many other people actually cared or prevented you from connecting your dishwasher to your leaf blower? Did the lights go dim when you ran the four billion record full outer join query that was so necessary to add the cost column from the first four records on your screen? Sure you could have copy/pasted to Excel or even launched the calculator to get the same number, but who does that when there’s obviously production servers available that were hand crafted for this particular task? How about that OCR routine you called from VBScript to parse the values from the MS Access screen shot? The one where you took the actual screen shot after using OLE DB to connect to the remote Oracle server then later used the parsed numbers to automate an SQL stored procedure update to the same server… a stored procedure that you wrote. Whatever it is, go ahead and embarass yourself below.

AIM status fun


Not too many people know that you can work your AIM status the same way as Twitter. It’s even more fun when you start noticing other people’s status message throughout the day. Here’s a little AIM fun tip me and my buddy learned by accident. A great way to throw people completely off, especially people like me that have nothing better to do but pay attention to status messages, is to reverse your away and available messages. Try it now. Let it ride for about a week or so and pretend like nothing is wrong. Not only is it funny to see other’s reactions but you’ll notice nobody will bother you during the day. All of the hard questions come when you’re on lunch break. You can easily duck them with the ol’, “I was getting my taxes done during lunch” excuse.

“But it said you were back from lunch??!!!”

“Did it? I just installed Pidgin and haven’t been able to follow the new setup. Sorry!”

How not to link a framework in iPhone dev


With much help from Erik, the owner of OCMock, I discovered how much of a loon I can be. Let me set the stage with a story, like I typically do on this site. You’re writing unit tests for a spankin’ new iPhone project that’s gonna shake the world if it ever releases. You’ve got backing suport from everybody from MGM Studios to Barack Obama helping you to make your release date. You are an advocate of all things Agile, TDD, and behavior driven. You absolutely cannot fail! You now need to do something clever in your unit tests. Something Apple doesn’t provide facilities for. You find a framework that does it. Maybe you’re bringing in OCMock or maybe you’re just trying to link Hamcrest. Hi, I’m Cliff. You’re here because your framework won’t load in your unit tests. I’m here to tell you how not to link against it.

Many years ago (like 1), I tried to link against OCMock. The only way to make it work was to drop it into the magic place called “/Library/Frameworks/”. It worked. It worked well. It worked so well that I decided to become the OCMock super hero. I wrote a blog about it. (Like to hear it? Here it go!) I wrote an OCMock setup thing with Automator/AppleScript for other developers that weren’t as John Blazed as I was so that they too could enjoy the beauty that was OCMock. (Just had a flashback to the little stored procedure runner tool I wrote when I was being the VB6-toRPGIV super hero many more years ago.) Here’s where a super hero becomes a super zero.

I neglected the principles of software development. Anything that goes in a System folder is visible to everything. Putting files, tools, trinkets there are always error prone, remedies for disaster. Why? Because it’s fire and forget… A one time setup that you never need to worry about. The forget part of the fire is what bites. The one time step that you always need to think about when troubleshooting but never do. Like I said, a year passes and I haven’t done much with OCMock except for occasions. Now I wanna upgrade to the latest version. I’ve since learned a better way to link projects to frameworks but my machine still “remembers” the old way. My new process, from memory, goes something like:

  • Find a framework
  • Drag/drop it into your project
  • Do something in the build configs, like setting a framework search path
  • I think that’s it, right? Yeah. Compile and run and I see the green button. I’m good!

Everything works as expected. I’m pretty sure I’m picking up the right version because I just double clicked the little framework icon and triple checked the path pointing to the newly downloaded folder. I could go the extra mile and look for the notes I wrote last year and make sure there’s no other gotcha’s but things are working. Why bother?

There’s two critical problems here. the first is that I never removed the frameworks from the magic “fire and forget” place. Just don’t put things here and you’ll never have to remember to delete them when you upgrade or when they break other things. The second problem is that I didn’t remember my new method for linking because my machine still remembered the old way making me feel like I was all good. The better way to link frameworks in iPhone dev is to put a “copy files” build phase into your target, set the destination path to “products directory” and drag/drop your frameworks into this phase. One caution is that while you can run on the Mac using the Simulator you still can’t load frameworks on the device. So I conclude this long winded article that could have been summarized in 2-3 sentences by saying, if you wanna suck at programming overload your system folders with development frameworks and libraries. Not only will you immediately solve the problem at hand and meet your immediate deadline but you’ll break the next twelve identical problems in the future and miss all of those deadlines. Good luck making up weeks of productivity lost chasing a problem that only exists on your machine. Good luck making up several more weeks of lost productivity while you reinstall your OS and lose several other important files/temporary projects trying to fix the problem that only happens on your machine.

Java is not a “Program Files”


I don’t know how many times I’ve been through the scenario. Key “java.sun.com” into the address bar. Click around a few times, getting side tracked by JavaFX or the new WTK or whatever. “Where’s that JDK link again?” Finally find the link to the JDK. Check the box next to the link. “Wait a sec! I can just click the link.” Begin the lengthy download. Begin the install process. Hi, I’m Cliff. You’re here because you put your JDK under “C:\Program Files”. No matter how many times I go through the process, I always make the same mistakes. I always get distracted by some non-jdk link that spins me off on a tangent. I always get confused which link is the JDK, which is the JRE, which one is yucky EJB. I always check the box next to the download link but never use Sun’s download manager. (Who needs to install yet another piece of software to download one file?) And I always, ALWAYS get tempted to install the JDK under “C:\Program Files”.

If you’re new to this site, relax. There’s a strong point buried somewhere in the text. If you’re new to java don’t install to “C:\Program Files”. It’s tempting but dangerous. Here’s what’ll happen. You complete your install. Everything is cool and you’re now a Java programmer. The birds will sing at 7am and the espresso will smell just splendid. Then one day it will happen. You’re running a piece of software, written in Java. You’re getting some crazy error, yet you’ve followed the instructions to the letter. You’re frustrated beyond belief. You write to all the user forums with no definitive answer. Eventually one day (several months later), a piece of the error message becomes clear. The program is complaining about invalid argument, “Files”. If you know like I know, you’ll realize the problem is rooted in the way some apps (Laszlo, Maven plugins, etc.) attempt to track down your local Java installation, then reuse the path as a command line string without quoting or escaping for potential white-space. In other words, somewhere the app is saying, “set JDKHOME = where your jDKHOME is installed. Ok, now run JDKHOME/bin/javac somefiles”. When JDKHOME expands, the whitespace is interpreted as the end of the comand and the beginning of your arguments. You end up running a command named “C:\Program” and giving it an initial argument “Files/bin/javac”. The command interpreter does not recognize C:\Program as a command or an executable file so it coughs.

OCMock with iPhone dev, I Git in trouble with Bzr


Mo’ coding mo’ problems. I’d love to have a stretch where the compiler and the command line actually agreed with the way I do things. Where do I start? First I needed to revert one or two files in my project. So now I’m arguing with Git on the command line as I unsuccessfully try to revert files individually. After a long bout with documentation across three different sites obsessed with Linux I’ve determined that Git works only when you do Kernel development. (That wasn’t exactly my conclusion but with every how to and tutorial using Kernel dev as an example… I’m just saying!) I read something in the docs about not being good with individual file versioning then reluctantly gave up on Git because I was gitting nowhere with my real work. I fell back on BZR.

I like BZR. I don’t wanna learn it over again. I installed and learned it over a year ago and remember there were some fickle issues but I couldn’t remember what they were. I went back to the BZR docs which are decent quality like the SVN red book. I skimmed to what I needed to refresh on. I had questions like, “This works kinda like svn doesn’t it?” Unlike Git, the docs for bzr didn’t let me down reminding me that I could revert a single file without adding a cache or an index to my mental user model. BZR refunded my $250 investment in a Git headache with store credit to be used on a reduced priced BZR belly ache. Hack, hack, hackity-hack. Bam!

Oh yeah! Now I remember what I couldn’t do in BZR! I couldn’t create a repository following its easy setup documentation. Running “bzr init” in an established project directory keeps telling me that my svn client is too old. More trips down memory lane, Oh yeah, I remember installing or thinking about installing bzr-svn support! Was that on this Mac or on my Linux box? (I couldn’t remember what state my BZR install was in.) Because I like to play with plugins and break things I remember being extra careful with BZR and only installing bzrtools, the recommended tool. I couldn’t rememebr how bzr plugins worked and I also realized my bzr install was dated. How do you upgrade? There’s that experimental uninstaller pyhton script that you have to click around 5-6 times to get the link to. Did I install from a dmg or from fink? Where does fink put its packages? Wasn’t it /usr/bin/sw? Google trips to the fink documentation almost got side tracked by reading up on MacPorts.

Bill Cosby spoke of Alzheimer’s. He had this joke of his brain sending his body into a room to pick up some “thing”… his body being excited upon entering the room to pick up the thing and not knowing what the thing was. I’m reading fink documentation completely ignorant of why I sent myself here. I was excited about fink and what it could do for me. I saw blurbs about apt-get. “Hey, its just like Mepis installs!” Poor Cliff! Will he ever find the secret to the kingdom of iPhone unit testing?

Unit Testing! I have to get back to writing test first! Un-rolling my stack after finally remembering it was /sw not /opt/sw or some other dumb path, I finally figure out that I didn’t install bzr with fink. I could just download the dmg. The plugins are easy to manage right under $HOME/.bazarr/plugins. I do only have bzrtools installed. Removing bzrtools temporarily does not get rid of the svn error. I have to run bzr init-repo over a non-existant directory and eventually copy my git exported code there. (Did I mentioned how side tracked I got figuring out how to git export? Yes I knew I could just “rm -frd .git” but I needed to learn the non-existant official way in case I got bit by something I didn’t know!)

My project is imported successfully into bzr, my stack is just about unrolled, I think. There’s still the matter of the files I was trying to revert. The OCMock stuff that just wouldn’t work in iPhone land. After all that fuss I took an entirely different approach.

I tried again with a bare bones iPhone project. Using XCode 3.1.3 I created a “UnitTests” target (new feature in the later version of XCode). I added my original modified unit test for verifying OCMock is correctly attached to the project. (See attached OCMockInstallVerificationTest.m) It build the “UnitTests” target and all of the tests complete successfully. I then [cleanly] checkout OCMock and build it’s main target with no issue. I build its test target and all the tests run successfully. I copy OCMockObjectTests.m and OCMockObjectTests.h into my fresh iPhone project and build and I start seeing the errors I blogged about earlier, returning booleans. (I’m starting to believe typeof is supported differently in the iPhone SDK.) After commenting these out temporarily I get errors that “setExpectationOrderMatters:” isn’t a recognized selector. I comment out the two sequence tests that use this important feature (the main reason I wanted to upgrade) and build again. I finally get stumped at a Bus error. If I fiddle around (do diffs and what not) I could probably get to the test that causes the problem but I’m giving up for now. The net result is that you can’t do everything you might want to with OCMock on an iPhone project. This is a real let down, not from the developer of OCMock but from Apple.

Below are my two versions of OCMock’s unit tests. The first is my initial attempt at using OCMock from last year. It’s named OCMockInstallVerificationTest.m and is a stripped down version of the unit test suite from the project as of last year. The second is a snapshot of what I just pulled from OCMock’s svn repo today.

OCMockInstallVerificationTest.m

//
//  OCMockInstallVerificationTest.m
//  iNav
//
//  Created by cliftoncraig07 on 1/9/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import 
#import 

@protocol TestProtocol
- (int)primitiveValue;
@end

@protocol ProtocolWithTypeQualifierMethod
- (bycopy NSString *)byCopyString;
@end

@interface OCMockInstallVerificationTest : SenTestCase {
	id mock;
}

@end


@implementation OCMockInstallVerificationTest

-(void) setUp {
	mock = [OCMockObject mockForClass:[NSString class]];
}

- (void)testAcceptsStubbedMethod
{
	[[mock stub] lowercaseString];
	[mock lowercaseString];
}

- (void)testRaisesExceptionWhenUnknownMethodIsCalled
{
	[[mock stub] lowercaseString];
	STAssertThrows([mock uppercaseString], @"Should have raised an exception.");
}


- (void)testAcceptsStubbedMethodWithSpecificArgument
{
	[[mock stub] hasSuffix:@"foo"];
	[mock hasSuffix:@"foo"];
}


- (void)testAcceptsStubbedMethodWithConstraint
{
	[[mock stub] hasSuffix:[OCMConstraint any]];
	[mock hasSuffix:@"foo"];
	[mock hasSuffix:@"bar"];
}


- (void)testAcceptsStubbedMethodWithNilArgument
{
	[[mock stub] hasSuffix:nil];
	
	[mock hasSuffix:nil];
}

- (void)testRaisesExceptionWhenMethodWithWrongArgumentIsCalled
{
	[[mock stub] hasSuffix:@"foo"];
	STAssertThrows([mock hasSuffix:@"xyz"], @"Should have raised an exception.");
}


- (void)testAcceptsStubbedMethodWithScalarArgument
{
	[[mock stub] stringByPaddingToLength:20 withString:@"foo" startingAtIndex:5];
	[mock stringByPaddingToLength:20 withString:@"foo" startingAtIndex:5];
}


- (void)testRaisesExceptionWhenMethodWithOneWrongScalarArgumentIsCalled
{
	[[mock stub] stringByPaddingToLength:20 withString:@"foo" startingAtIndex:5];
	STAssertThrows([mock stringByPaddingToLength:20 withString:@"foo" startingAtIndex:3], @"Should have raised an exception.");	
}

- (void)testAcceptsStubbedMethodWithVoidPointerArgument
{
	mock = [OCMockObject mockForClass:[NSMutableData class]];
	[[mock stub] appendBytes:NULL length:0];
	[mock appendBytes:NULL length:0];
}


- (void)testRaisesExceptionWhenMethodWithWrongVoidPointerArgumentIsCalled
{
	mock = [OCMockObject mockForClass:[NSMutableData class]];
	[[mock stub] appendBytes:"foo" length:3];
	STAssertThrows([mock appendBytes:"bar" length:3], @"Should have raised an exception.");
}


- (void)testAcceptsStubbedMethodWithPointerPointerArgument
{
	NSError *error = nil;
	[[mock stub] initWithContentsOfFile:@"foo.txt" encoding:NSASCIIStringEncoding error:&error];	
	[mock initWithContentsOfFile:@"foo.txt" encoding:NSASCIIStringEncoding error:&error];
}


- (void)testRaisesExceptionWhenMethodWithWrongPointerPointerArgumentIsCalled
{
	NSError *error = nil, *error2;
	[[mock stub] initWithContentsOfFile:@"foo.txt" encoding:NSASCIIStringEncoding error:&error];	
	STAssertThrows([mock initWithContentsOfFile:@"foo.txt" encoding:NSASCIIStringEncoding error:&error2], @"Should have raised.");
}


- (void)testAcceptsStubbedMethodWithStructArgument
{
    NSRange range = NSMakeRange(0,20);
	[[mock stub] substringWithRange:range];
	[mock substringWithRange:range];
}


- (void)testRaisesExceptionWhenMethodWithWrongStructArgumentIsCalled
{
    NSRange range = NSMakeRange(0,20);
    NSRange otherRange = NSMakeRange(0,10);
	[[mock stub] substringWithRange:range];
	STAssertThrows([mock substringWithRange:otherRange], @"Should have raised an exception.");	
}


- (void)testReturnsStubbedReturnValue
{
	id returnValue;  
	
	[[[mock stub] andReturn:@"megamock"] lowercaseString];
	returnValue = [mock lowercaseString];
	
	STAssertEqualObjects(@"megamock", returnValue, @"Should have returned stubbed value.");
	
}


- (void)testReturnsStubbedNilReturnValue
{
	[[[mock stub] andReturn:nil] uppercaseString];
	
	id returnValue = [mock uppercaseString];
	
	STAssertNil(returnValue, @"Should have returned stubbed value, which is nil.");
}

- (void)testReturnsStubbedByCopyReturnValue
{
	id myMock = [OCMockObject mockForProtocol:@protocol(ProtocolWithTypeQualifierMethod)];
	
	[[[myMock stub] andReturn:@"megamock"] byCopyString];
	
	STAssertEqualObjects(@"megamock", [myMock byCopyString], @"Should have returned stubbed value.");
}


- (void)testAcceptsExpectedMethod
{
	[[mock expect] lowercaseString];
	[mock lowercaseString];
}


- (void)testAcceptsExpectedMethodAndReturnsValue
{
	id returnValue;
	
	[[[mock expect] andReturn:@"Objective-C"] lowercaseString];
	returnValue = [mock lowercaseString];
	
	STAssertEqualObjects(@"Objective-C", returnValue, @"Should have returned stubbed value.");
}


- (void)testAcceptsExpectedMethodsInRecordedSequence
{
	[[mock expect] lowercaseString];
	[[mock expect] uppercaseString];
	
	[mock lowercaseString];
	[mock uppercaseString];
}


- (void)testAcceptsExpectedMethodsInDifferentSequence
{
	[[mock expect] lowercaseString];
	[[mock expect] uppercaseString];
	
	[mock uppercaseString];
	[mock lowercaseString];
}


- (void)testAcceptsAndVerifiesTwoExpectedInvocationsOfSameMethod
{
	[[mock expect] lowercaseString];
	[[mock expect] lowercaseString];
	
	[mock lowercaseString];
	[mock lowercaseString];
	
	[mock verify];
}


- (void)testAcceptsAndVerifiesTwoExpectedInvocationsOfSameMethodAndReturnsCorrespondingValues
{
	[[[mock expect] andReturn:@"foo"] lowercaseString];
	[[[mock expect] andReturn:@"bar"] lowercaseString];
	
	STAssertEqualObjects(@"foo", [mock lowercaseString], @"Should have returned first stubbed value");
	STAssertEqualObjects(@"bar", [mock lowercaseString], @"Should have returned seconds stubbed value");
	
	[mock verify];
}

- (void)testReturnsStubbedValuesIndependentOfExpectations
{
	[[mock stub] hasSuffix:@"foo"];
	[[mock expect] hasSuffix:@"bar"];
	
	[mock hasSuffix:@"foo"];
	[mock hasSuffix:@"bar"];
	[mock hasSuffix:@"foo"]; // Since it's a stub, shouldn't matter how many times we call this
	
	[mock verify];
}

- (void)testAcceptsAndVerifiesExpectedMethods
{
	[[mock expect] lowercaseString];
	[[mock expect] uppercaseString];
	
	[mock lowercaseString];
	[mock uppercaseString];
	
	[mock verify];
}


- (void)testRaisesExceptionOnVerifyWhenNotAllExpectedMethodsWereCalled
{
	[[mock expect] lowercaseString];
	[[mock expect] uppercaseString];
	
	[mock lowercaseString];
	
	STAssertThrows([mock verify], @"Should have raised an exception.");
}


- (void)testRaisesExceptionWhenAskedTo
{
	NSException *exception = [NSException exceptionWithName:@"TestException" reason:@"test" userInfo:nil];
	[[[mock expect] andThrow:exception] lowercaseString];
	
	STAssertThrows([mock lowercaseString], @"Should have raised an exception.");
}

- (void)testCanStubValueForKeyMethod
{
	id returnValue;
	
	mock = [OCMockObject mockForClass:[NSObject class]];
	[[[mock stub] andReturn:@"SomeValue"] valueForKey:@"SomeKey"];
	
	returnValue = [mock valueForKey:@"SomeKey"];
	
	STAssertEqualObjects(@"SomeValue", returnValue, @"Should have returned value that was set up.");
}


- (void)testCanMockFormalProtocol
{
	mock = [OCMockObject mockForProtocol:@protocol(NSLocking)];
	[[mock expect] lock];
	
	[mock lock];
	
	[mock verify];
}


- (void)testRaisesWhenUnknownMethodIsCalledOnProtocol
{
	mock = [OCMockObject mockForProtocol:@protocol(NSLocking)];
	STAssertThrows([mock lowercaseString], @"Should have raised an exception.");
}


- (void)testMockedProtocolConforms
{
	mock = [OCMockObject mockForProtocol:@protocol(NSLocking)];
	STAssertTrue([mock conformsToProtocol:@protocol(NSLocking)], nil);
}


- (void)testReturnsDefaultValueWhenUnknownMethodIsCalledOnNiceClassMock
{
	mock = [OCMockObject niceMockForClass:[NSString class]];
	STAssertNil([mock lowercaseString], @"Should return nil on unexpected method call (for nice mock).");	
	[mock verify];
}

- (void)testRaisesAnExceptionWhenAnExpectedMethodIsNotCalledOnNiceClassMock
{
	mock = [OCMockObject niceMockForClass:[NSString class]];	
	[[[mock expect] andReturn:@"HELLO!"] uppercaseString];
	STAssertThrows([mock verify], @"Should have raised an exception because method was not called.");
}

- (void)testReturnDefaultValueWhenUnknownMethodIsCalledOnProtocolMock
{
	mock = [OCMockObject niceMockForProtocol:@protocol(TestProtocol)];
	STAssertTrue(0 == [mock primitiveValue], @"Should return 0 on unexpected method call (for nice mock).");
	[mock verify];
}

- (void)testRaisesAnExceptionWenAnExpectedMethodIsNotCalledOnNiceProtocolMock
{
	mock = [OCMockObject niceMockForProtocol:@protocol(TestProtocol)];	
	[[mock expect] primitiveValue];
	STAssertThrows([mock verify], @"Should have raised an exception because method was not called.");
}

- (void)testReRaisesFailFastExceptionsOnVerify
{
	@try
	{
		[mock lowercaseString];
	}
	@catch(NSException *exception)
	{
		// expected
	}
	STAssertThrows([mock verify], @"Should have reraised the exception.");
}


/*
 - (void)testCanMockInformalProtocol
 {
 mock = [OCMockObject mock];
 NSArray *params = [NSArray arrayWithObject:@"steve"];
 [[mock expect] authenticationDataForComponents:params];
 
 [mock authenticationDataForComponents:params];
 
 [mock verify];
 }
 */

- (void)testCanCreateExpectationsAfterInvocations
{
	[[mock expect] lowercaseString];
	[mock lowercaseString];
	[mock expect];
}

@end

OCMockObjectTests.h

//---------------------------------------------------------------------------------------
//  $Id: OCMockObjectTests.h 21 2008-01-24 18:59:39Z erik $
//  Copyright (c) 2004-2008 by Mulle Kybernetik. See License file for details.
//---------------------------------------------------------------------------------------

#import <SenTestingKit/SenTestingKit.h>

@interface OCMockObjectTests : SenTestCase
{
	id mock;
}

@end

OCMockObjectTests.m

//---------------------------------------------------------------------------------------
//  $Id: OCMockObjectTests.m 52 2009-08-14 07:21:10Z erik $
//  Copyright (c) 2004-2008 by Mulle Kybernetik. See License file for details.
//---------------------------------------------------------------------------------------

#import <OCMock/OCMock.h>
#import "OCMockObjectTests.h"

// --------------------------------------------------------------------------------------
//	Helper classes and protocols for testing
// --------------------------------------------------------------------------------------

@protocol TestProtocol
- (int)primitiveValue;
@optional
- (id)objectValue;
@end

@protocol ProtocolWithTypeQualifierMethod
- (void)aSpecialMethod:(byref in void *)someArg;
@end

@interface TestClassThatCallsSelf : NSObject
- (NSString *)method1;
- (NSString *)method2;
@end

@implementation TestClassThatCallsSelf

- (NSString *)method1
{
	id retVal = [self method2];
	return retVal;
}

- (NSString *)method2
{
	return @"Foo";
}

@end

@interface TestObserver	: NSObject
{
	@public
	NSNotification *notification;
}

@end

@implementation TestObserver

- (void)dealloc
{
	[[NSNotificationCenter defaultCenter] removeObserver:self];
	[notification release];
	[super dealloc];
}

- (void)receiveNotification:(NSNotification *)aNotification
{
	notification = [aNotification retain];
}

@end

static NSString *TestNotification = @"TestNotification";


// --------------------------------------------------------------------------------------
//  setup
// --------------------------------------------------------------------------------------


@implementation OCMockObjectTests

- (void)setUp
{
	mock = [OCMockObject mockForClass:[NSString class]];
}


// --------------------------------------------------------------------------------------
//	accepting stubbed methods / rejecting methods not stubbed
// --------------------------------------------------------------------------------------

- (void)testAcceptsStubbedMethod
{
	[[mock stub] lowercaseString];
	[mock lowercaseString];
}

- (void)testRaisesExceptionWhenUnknownMethodIsCalled
{
	[[mock stub] lowercaseString];
	STAssertThrows([mock uppercaseString], @"Should have raised an exception.");
}


- (void)testAcceptsStubbedMethodWithSpecificArgument
{
	[[mock stub] hasSuffix:@"foo"];
	[mock hasSuffix:@"foo"];
}


- (void)testAcceptsStubbedMethodWithConstraint
{
	[[mock stub] hasSuffix:[OCMArg any]];
	[mock hasSuffix:@"foo"];
	[mock hasSuffix:@"bar"];
}


- (void)testAcceptsStubbedMethodWithNilArgument
{
	[[mock stub] hasSuffix:nil];
	
	[mock hasSuffix:nil];
}

- (void)testRaisesExceptionWhenMethodWithWrongArgumentIsCalled
{
	[[mock stub] hasSuffix:@"foo"];
	STAssertThrows([mock hasSuffix:@"xyz"], @"Should have raised an exception.");
}


- (void)testAcceptsStubbedMethodWithScalarArgument
{
	[[mock stub] stringByPaddingToLength:20 withString:@"foo" startingAtIndex:5];
	[mock stringByPaddingToLength:20 withString:@"foo" startingAtIndex:5];
}


- (void)testRaisesExceptionWhenMethodWithOneWrongScalarArgumentIsCalled
{
	[[mock stub] stringByPaddingToLength:20 withString:@"foo" startingAtIndex:5];
	STAssertThrows([mock stringByPaddingToLength:20 withString:@"foo" startingAtIndex:3], @"Should have raised an exception.");	
}

- (void)testAcceptsStubbedMethodWithPointerArgument
{
//	NSError *error;
//	BOOL yes = YES;
//	[[[mock stub] andReturnValue:OCMOCK_VALUE(yes)] writeToFile:OCMOCK_ANY atomically:YES encoding:NSMacOSRomanStringEncoding error:&error];
//	
//	STAssertTrue([mock writeToFile:@"foo" atomically:YES encoding:NSMacOSRomanStringEncoding error:&error], nil);
}

- (void)testAcceptsStubbedMethodWithAnyPointerArgument
{
//	BOOL yes = YES;
//	NSError *error;
//	[[[mock stub] andReturnValue:OCMOCK_VALUE(yes)] writeToFile:OCMOCK_ANY atomically:YES encoding:NSMacOSRomanStringEncoding error:[OCMArg anyPointer]];
//	
//	STAssertTrue([mock writeToFile:@"foo" atomically:YES encoding:NSMacOSRomanStringEncoding error:&error], nil);
}

- (void)testRaisesExceptionWhenMethodWithWrongPointerArgumentIsCalled
{
	NSString *string;
	NSString *anotherString;
	NSArray *array;
	
	[[mock stub] completePathIntoString:&string caseSensitive:YES matchesIntoArray:&array filterTypes:OCMOCK_ANY];
	
	STAssertThrows([mock completePathIntoString:&anotherString caseSensitive:YES matchesIntoArray:&array filterTypes:OCMOCK_ANY], nil);
}

- (void)testAcceptsStubbedMethodWithVoidPointerArgument
{
	mock = [OCMockObject mockForClass:[NSMutableData class]];
	[[mock stub] appendBytes:NULL length:0];
	[mock appendBytes:NULL length:0];
}


- (void)testRaisesExceptionWhenMethodWithWrongVoidPointerArgumentIsCalled
{
	mock = [OCMockObject mockForClass:[NSMutableData class]];
	[[mock stub] appendBytes:"foo" length:3];
	STAssertThrows([mock appendBytes:"bar" length:3], @"Should have raised an exception.");
}


- (void)testAcceptsStubbedMethodWithPointerPointerArgument
{
	NSError *error = nil;
	[[mock stub] initWithContentsOfFile:@"foo.txt" encoding:NSASCIIStringEncoding error:&error];	
	[mock initWithContentsOfFile:@"foo.txt" encoding:NSASCIIStringEncoding error:&error];
}


- (void)testRaisesExceptionWhenMethodWithWrongPointerPointerArgumentIsCalled
{
	NSError *error = nil, *error2;
	[[mock stub] initWithContentsOfFile:@"foo.txt" encoding:NSASCIIStringEncoding error:&error];	
	STAssertThrows([mock initWithContentsOfFile:@"foo.txt" encoding:NSASCIIStringEncoding error:&error2], @"Should have raised.");
}


- (void)testAcceptsStubbedMethodWithStructArgument
{
    NSRange range = NSMakeRange(0,20);
	[[mock stub] substringWithRange:range];
	[mock substringWithRange:range];
}


- (void)testRaisesExceptionWhenMethodWithWrongStructArgumentIsCalled
{
    NSRange range = NSMakeRange(0,20);
    NSRange otherRange = NSMakeRange(0,10);
	[[mock stub] substringWithRange:range];
	STAssertThrows([mock substringWithRange:otherRange], @"Should have raised an exception.");	
}


// --------------------------------------------------------------------------------------
//	returning values from stubbed methods
// --------------------------------------------------------------------------------------

- (void)testReturnsStubbedReturnValue
{
	id returnValue;  

	[[[mock stub] andReturn:@"megamock"] lowercaseString];
	returnValue = [mock lowercaseString];
	
	STAssertEqualObjects(@"megamock", returnValue, @"Should have returned stubbed value.");
	
}

- (void)testReturnsStubbedIntReturnValue
{
//    int expectedValue = 42;
//	[[[mock stub] andReturnValue:OCMOCK_VALUE(expectedValue)] intValue];
//	int returnValue = [mock intValue];
//    
//	STAssertEquals(expectedValue, returnValue, @"Should have returned stubbed value.");
}

- (void)testRaisesWhenBoxedValueTypesDoNotMatch
{
//    double expectedValue = 42;
//	[[[mock stub] andReturnValue:OCMOCK_VALUE(expectedValue)] intValue];
//    
//	STAssertThrows([mock intValue], @"Should have raised an exception.");
}

- (void)testReturnsStubbedNilReturnValue
{
	[[[mock stub] andReturn:nil] uppercaseString];
	
	id returnValue = [mock uppercaseString];
	
	STAssertNil(returnValue, @"Should have returned stubbed value, which is nil.");
}


// --------------------------------------------------------------------------------------
//	raising exceptions, posting notifications, etc.
// --------------------------------------------------------------------------------------

- (void)testRaisesExceptionWhenAskedTo
{
	NSException *exception = [NSException exceptionWithName:@"TestException" reason:@"test" userInfo:nil];
	[[[mock expect] andThrow:exception] lowercaseString];
	
	STAssertThrows([mock lowercaseString], @"Should have raised an exception.");
}

- (void)testPostsNotificationWhenAskedTo
{
	TestObserver *observer = [[[TestObserver alloc] init] autorelease];
	[[NSNotificationCenter defaultCenter] addObserver:observer selector:@selector(receiveNotification:) name:TestNotification object:nil];
	
	NSNotification *notification = [NSNotification notificationWithName:TestNotification object:self];
	[[[mock stub] andPost:notification] lowercaseString];
	
	[mock lowercaseString];
	
	STAssertNotNil(observer->notification, @"Should have sent a notification.");
	STAssertEqualObjects(TestNotification, [observer->notification name], @"Name should match posted one.");
	STAssertEqualObjects(self, [observer->notification object], @"Object should match posted one.");
}

- (void)testPostsNotificationInAddtionToReturningValue
{
	TestObserver *observer = [[[TestObserver alloc] init] autorelease];
	[[NSNotificationCenter defaultCenter] addObserver:observer selector:@selector(receiveNotification:) name:TestNotification object:nil];
	
	NSNotification *notification = [NSNotification notificationWithName:TestNotification object:self];
	[[[[mock stub] andReturn:@"foo"] andPost:notification] lowercaseString];
	
	STAssertEqualObjects(@"foo", [mock lowercaseString], @"Should have returned stubbed value.");
	STAssertNotNil(observer->notification, @"Should have sent a notification.");
}


- (NSString *)valueForTest
{
	return @"value for test";
}

- (void)testCallsMethodAndReturnsItsReturnValueWhenAskedTo
{
	[[[mock stub] andCall:@selector(valueForTest) onObject:self] lowercaseString];
	
	STAssertEqualObjects(@"value for test", [mock lowercaseString], @"Should have returned value from called method");
}


- (NSString *)valueForTest:(NSInvocation *)originalInvocation
{
	return (id)originalInvocation;
}

- (void)testCallsMethodAndPassesOriginalInvocation
{
	[[[mock stub] andCall:@selector(valueForTest:) onObject:self] lowercaseString];
	
	NSInvocation *invocation = (id)[mock lowercaseString];
	
	STAssertEquals(@selector(lowercaseString), [invocation selector], @"Should have passed and returned invocation.");
}

// --------------------------------------------------------------------------------------
//	returning values in pass-by-reference arguments
// --------------------------------------------------------------------------------------

- (void)testReturnsValuesInPassByReferenceArguments
{
	NSString *expectedName = [NSString stringWithString:@"Test"];
	NSArray *expectedArray = [NSArray array];
	
	[[mock expect] completePathIntoString:[OCMArg setTo:expectedName] caseSensitive:YES 
						 matchesIntoArray:[OCMArg setTo:expectedArray] filterTypes:OCMOCK_ANY];
	
	NSString *actualName = nil;
	NSArray *actualArray = nil;
	[mock completePathIntoString:&actualName caseSensitive:YES matchesIntoArray:&actualArray filterTypes:nil];

	STAssertNoThrow([mock verify], @"An unexpected exception was thrown");
	STAssertEqualObjects(expectedName, actualName, @"The two string objects should be equal");
	STAssertEqualObjects(expectedArray, actualArray, @"The two array objects should be equal");
}


// --------------------------------------------------------------------------------------
//	accepting expected methods
// --------------------------------------------------------------------------------------

- (void)testAcceptsExpectedMethod
{
	[[mock expect] lowercaseString];
	[mock lowercaseString];
}


- (void)testAcceptsExpectedMethodAndReturnsValue
{
	id returnValue;

	[[[mock expect] andReturn:@"Objective-C"] lowercaseString];
	returnValue = [mock lowercaseString];

	STAssertEqualObjects(@"Objective-C", returnValue, @"Should have returned stubbed value.");
}


- (void)testAcceptsExpectedMethodsInRecordedSequence
{
	[[mock expect] lowercaseString];
	[[mock expect] uppercaseString];
	
	[mock lowercaseString];
	[mock uppercaseString];
}


- (void)testAcceptsExpectedMethodsInDifferentSequence
{
	[[mock expect] lowercaseString];
	[[mock expect] uppercaseString];
	
	[mock uppercaseString];
	[mock lowercaseString];
}


// --------------------------------------------------------------------------------------
//	verifying expected methods
// --------------------------------------------------------------------------------------

- (void)testAcceptsAndVerifiesExpectedMethods
{
	[[mock expect] lowercaseString];
	[[mock expect] uppercaseString];
	
	[mock lowercaseString];
	[mock uppercaseString];
	
	[mock verify];
}


- (void)testRaisesExceptionOnVerifyWhenNotAllExpectedMethodsWereCalled
{
	[[mock expect] lowercaseString];
	[[mock expect] uppercaseString];
	
	[mock lowercaseString];
	
	STAssertThrows([mock verify], @"Should have raised an exception.");
}

- (void)testAcceptsAndVerifiesTwoExpectedInvocationsOfSameMethod
{
	[[mock expect] lowercaseString];
	[[mock expect] lowercaseString];
	
	[mock lowercaseString];
	[mock lowercaseString];
	
	[mock verify];
}


- (void)testAcceptsAndVerifiesTwoExpectedInvocationsOfSameMethodAndReturnsCorrespondingValues
{
	[[[mock expect] andReturn:@"foo"] lowercaseString];
	[[[mock expect] andReturn:@"bar"] lowercaseString];
	
	STAssertEqualObjects(@"foo", [mock lowercaseString], @"Should have returned first stubbed value");
	STAssertEqualObjects(@"bar", [mock lowercaseString], @"Should have returned seconds stubbed value");
	
	[mock verify];
}

- (void)testReturnsStubbedValuesIndependentOfExpectations
{
	[[mock stub] hasSuffix:@"foo"];
	[[mock expect] hasSuffix:@"bar"];
	
	[mock hasSuffix:@"foo"];
	[mock hasSuffix:@"bar"];
	[mock hasSuffix:@"foo"]; // Since it's a stub, shouldn't matter how many times we call this
	
	[mock verify];
}

-(void)testAcceptsAndVerifiesMethodsWithSelectorArgument
{
	[[mock expect] performSelector:@selector(lowercaseString)];
	[mock performSelector:@selector(lowercaseString)];
	[mock verify];
}


// --------------------------------------------------------------------------------------
//	ordered expectations
// --------------------------------------------------------------------------------------

- (void)testAcceptsExpectedMethodsInRecordedSequenceWhenOrderMatters
{
//	[mock setExpectationOrderMatters:YES];
//	
//	[[mock expect] lowercaseString];
//	[[mock expect] uppercaseString];
//	
//	STAssertNoThrow([mock lowercaseString], @"Should have accepted expected method in sequence.");
//	STAssertNoThrow([mock uppercaseString], @"Should have accepted expected method in sequence.");
}

- (void)testRaisesExceptionWhenSequenceIsWrongAndOrderMatters
{
//	[mock setExpectationOrderMatters:YES];
//	
//	[[mock expect] lowercaseString];
//	[[mock expect] uppercaseString];
//	
//	STAssertThrows([mock uppercaseString], @"Should have complained about wrong sequence.");
}


// --------------------------------------------------------------------------------------
//	protocol mocks
// --------------------------------------------------------------------------------------

- (void)testCanMockFormalProtocol
{
	mock = [OCMockObject mockForProtocol:@protocol(NSLocking)];
	[[mock expect] lock];
	
	[mock lock];
	
	[mock verify];
}

- (void)testRaisesWhenUnknownMethodIsCalledOnProtocol
{
	mock = [OCMockObject mockForProtocol:@protocol(NSLocking)];
	STAssertThrows([mock lowercaseString], @"Should have raised an exception.");
}

- (void)testConformsToMockedProtocol
{
	mock = [OCMockObject mockForProtocol:@protocol(NSLocking)];
	STAssertTrue([mock conformsToProtocol:@protocol(NSLocking)], nil);
}

- (void)testRespondsToValidProtocolRequiredSelector
{
	mock = [OCMockObject mockForProtocol:@protocol(TestProtocol)];	
    STAssertTrue([mock respondsToSelector:@selector(primitiveValue)], nil);
}

- (void)testRespondsToValidProtocolOptionalSelector
{
	mock = [OCMockObject mockForProtocol:@protocol(TestProtocol)];	
    STAssertTrue([mock respondsToSelector:@selector(objectValue)], nil);
}

- (void)testDoesNotRespondToInvalidProtocolSelector
{
	mock = [OCMockObject mockForProtocol:@protocol(TestProtocol)];	
    STAssertFalse([mock respondsToSelector:@selector(fooBar)], nil);
}


// --------------------------------------------------------------------------------------
//	nice mocks don't complain about unknown methods
// --------------------------------------------------------------------------------------

- (void)testReturnsDefaultValueWhenUnknownMethodIsCalledOnNiceClassMock
{
	mock = [OCMockObject niceMockForClass:[NSString class]];
	STAssertNil([mock lowercaseString], @"Should return nil on unexpected method call (for nice mock).");	
	[mock verify];
}

- (void)testRaisesAnExceptionWhenAnExpectedMethodIsNotCalledOnNiceClassMock
{
	mock = [OCMockObject niceMockForClass:[NSString class]];	
	[[[mock expect] andReturn:@"HELLO!"] uppercaseString];
	STAssertThrows([mock verify], @"Should have raised an exception because method was not called.");
}

- (void)testReturnDefaultValueWhenUnknownMethodIsCalledOnProtocolMock
{
	mock = [OCMockObject niceMockForProtocol:@protocol(TestProtocol)];
	STAssertTrue(0 == [mock primitiveValue], @"Should return 0 on unexpected method call (for nice mock).");
	[mock verify];
}

- (void)testRaisesAnExceptionWenAnExpectedMethodIsNotCalledOnNiceProtocolMock
{
	mock = [OCMockObject niceMockForProtocol:@protocol(TestProtocol)];	
	[[mock expect] primitiveValue];
	STAssertThrows([mock verify], @"Should have raised an exception because method was not called.");
}


// --------------------------------------------------------------------------------------
//	partial mocks forward unknown methods to a real instance
// --------------------------------------------------------------------------------------

- (void)testStubsMethodsOnPartialMock
{
	TestClassThatCallsSelf *foo = [[[TestClassThatCallsSelf alloc] init] autorelease];
	mock = [OCMockObject partialMockForObject:foo];
	[[[mock stub] andReturn:@"hi"] method1];
	STAssertEqualObjects(@"hi", [mock method1], @"Should have returned stubbed value");
}


//- (void)testStubsMethodsOnPartialMockForTollFreeBridgedClasses
//{
//	mock = [OCMockObject partialMockForObject:[NSString stringWithString:@"hello"]];
//	[[[mock stub] andReturn:@"hi"] uppercaseString];
//	STAssertEqualObjects(@"hi", [mock uppercaseString], @"Should have returned stubbed value");
//}

- (void)testForwardsUnstubbedMethodsCallsToRealObjectOnPartialMock
{
	TestClassThatCallsSelf *foo = [[[TestClassThatCallsSelf alloc] init] autorelease];
	mock = [OCMockObject partialMockForObject:foo];
	STAssertEqualObjects(@"Foo", [mock method2], @"Should have returned value from real object.");
}

//- (void)testForwardsUnstubbedMethodsCallsToRealObjectOnPartialMockForTollFreeBridgedClasses
//{
//	mock = [OCMockObject partialMockForObject:[NSString stringWithString:@"hello2"]];
//	STAssertEqualObjects(@"HELLO2", [mock uppercaseString], @"Should have returned value from real object.");
//}

- (void)testStubsMethodOnRealObjectReference
{
	TestClassThatCallsSelf *realObject = [[[TestClassThatCallsSelf alloc] init] autorelease];
	mock = [OCMockObject partialMockForObject:realObject];
	[[[mock stub] andReturn:@"FooFoo"] method1];
	STAssertEqualObjects(@"FooFoo", [realObject method1], @"Should have stubbed method.");
}

- (void)testCallsToSelfInRealObjectAreShadowedByPartialMock
{
	TestClassThatCallsSelf *foo = [[[TestClassThatCallsSelf alloc] init] autorelease];
	mock = [OCMockObject partialMockForObject:foo];
	[[[mock stub] andReturn:@"FooFoo"] method2];
	STAssertEqualObjects(@"FooFoo", [mock method1], @"Should have called through to stubbed method.");
}


- (NSString *)differentMethodInDifferentClass
{
	return @"swizzled!";
}

- (void)testImplementsMethodSwizzling
{
	// using partial mocks and the indirect return value provider
	TestClassThatCallsSelf *foo = [[[TestClassThatCallsSelf alloc] init] autorelease];
	mock = [OCMockObject partialMockForObject:foo];
	[[[mock stub] andCall:@selector(differentMethodInDifferentClass) onObject:self] method1];
	STAssertEqualObjects(@"swizzled!", [foo method1], @"Should have returned value from different method");
}


- (void)aMethodWithVoidReturn
{
}

- (void)testMethodSwizzlingWorksForVoidReturns
{
	TestClassThatCallsSelf *foo = [[[TestClassThatCallsSelf alloc] init] autorelease];
	mock = [OCMockObject partialMockForObject:foo];
	[[[mock stub] andCall:@selector(aMethodWithVoidReturn) onObject:self] method1];
	STAssertNoThrow([foo method1], @"Should have worked.");
}


// --------------------------------------------------------------------------------------
//	mocks should honour the NSObject contract, etc.
// --------------------------------------------------------------------------------------

- (void)testRespondsToValidSelector
{
	STAssertTrue([mock respondsToSelector:@selector(lowercaseString)], nil);
}

- (void)testDoesNotRespondToInvalidSelector
{
	STAssertFalse([mock respondsToSelector:@selector(fooBar)], nil);
}

- (void)testCanStubValueForKeyMethod
{
	id returnValue;
	
	mock = [OCMockObject mockForClass:[NSObject class]];
	[[[mock stub] andReturn:@"SomeValue"] valueForKey:@"SomeKey"];
	
	returnValue = [mock valueForKey:@"SomeKey"];
	
	STAssertEqualObjects(@"SomeValue", returnValue, @"Should have returned value that was set up.");
}

- (void)testWorksWithTypeQualifiers
{
	id myMock = [OCMockObject mockForProtocol:@protocol(ProtocolWithTypeQualifierMethod)];
	
	STAssertNoThrow([[myMock expect] aSpecialMethod:"foo"], @"Should not complain about method with type qualifiers.");
	STAssertNoThrow([myMock aSpecialMethod:"foo"], @"Should not complain about method with type qualifiers.");
}


// --------------------------------------------------------------------------------------
//  some internal tests
// --------------------------------------------------------------------------------------

- (void)testReRaisesFailFastExceptionsOnVerify
{
	@try
	{
		[mock lowercaseString];
	}
	@catch(NSException *exception)
	{
		// expected
	}
	STAssertThrows([mock verify], @"Should have reraised the exception.");
}


- (void)testCanCreateExpectationsAfterInvocations
{
	[[mock expect] lowercaseString];
	[mock lowercaseString];
	[mock expect];
}

@end