06th Apr 2007
My first! I’m so excited.
Title: NSCalendarDate’s descriptionWithCalendarFormat method doesn’t work properly
Product: Mac OS X
Version: 10.4.9
Classification: Other Bug
Is it Reproducible?: Always
Summary:
When using NSCalendarDate’s descriptionWithCalendarFormat method, incorrect values are returned.
Steps to Reproduce:
1. Create a Cocoa app. Use the following code it in:
NSCalendarDate *time = [NSCalendarDate calendarDate];
NSString *timeOfDay = [time descriptionWithCalendarFormat:@”%X”];
NSString *dayName = [time descriptionWithCalendarFormat:@”%A”];
NSLog(@”Today is %@, and the time is %@.”, dayName, timeOfDay”);
Expected Results:
The app should print “Today is Friday, and the time is 11:02 PM.” (Assuming it actually is Friday at 11:02PM, and those your time formats are the same.)
Actual Results:
The app prints “Today is Friday, and the time is 23:02:23 Canada/Eastern.”, which is not how the time should look according to the documentation for %X. If you use descriptionWithCalendarFormat:@”%X” locale:[[NSUserDefaults standardUserDefaults] dictionaryRepresentation], the output is not much better: “Today is Friday, and the time is Friday, April 6, 2007 11:08:51 PM Canada/Eastern”.
The dates and times programming guide states that %X should return “time using the time representation for the locale”. This is obviously not happening.
Regression:
Always occurs. Other regressions unknown.
Notes:
No Known work arounds, other than specifying the time format explicitly (@”%1I:%M %p”) which is ugly and doesn’t take into account localized formats.
Posted by patrick under
AppleBugFriday, apple, cocoa, code
No Comments »
31st Mar 2007
Good news: The Adium Time Zone Plugin is now out. I hoped to have it out by the end of the week, and (I think) I squashed the last two bugs that were preventing me from releasing, so off it goes! I made a page for it that I will keep updated with the latest version and other news. The BSD licensed source code is also there if you want to check it out.
I’m proud of the code. I’m not super proud of the model, in fact I’m sure it will become something that I will look back on one day and say “What the hell was I thinking?!”. I’ll probably refactor it in the future, it’s just that I’ve held off on releasing this for long enough, and with my finals looming I was scared that If I didn’t release by my self-imposed deadline of this week then I wouldn’t have time to work on it again in a while.
I hope you like it. I hope it doesn’t sink your Adium. Please send me some feedback if it does (or if it doesn’t). Thanks!
Posted by patrick under
adium, cocoa, code, open-source, universalbinary
6 Comments »
23rd Mar 2007
Last time I wrote about unit testing Adium, I was actually writing about unit testing Adium.framework - The public API that plugin developers and the like can use to tie into Adium. After talking with David Smith from Adium about some of my other SoC Ideas (such as improving plugin support) I realized that Adium’s API really shouldn’t be considered stable, and that using it as a starting point for unit testing is a bad idea.
That being said, I switched gears and started again, this time unit testing the application itself as oppose to the framework. In hindsight I guess I probably should have started here first, but being familiar with Adium.framework from my plugin development, I assumed that would come more quickly. Wrongo.
Anyways, thanks again to Chris Hanson, his short tutorial on getting unit testing up and running in cocoa apps helped me get started, and everything is now working as expected. When you build the test bundle, it launches the Adium build, executes it’s tests, quits, and reports any failures. Good stuff.
Here’s a bit of what my AIEmoticonPack unit test looks like:
- (void)setUp
{
fileManager = [NSFileManager defaultManager];
//NSLog(@"Current Directory is %@/", [fileManager currentDirectoryPath]);
emoticonPack = [AIEmoticonPack emoticonPackFromPath:[[fileManager currentDirectoryPath] stringByAppendingString:EMOTICONSET_PATH1]];
//NSLog(@"Testing Emoticon Pack: %@", emoticonPack);
NSArray *fooarray = [emoticonPack emoticons];
//NSLog(@"Foo: %@", fooarray);
}
- (void)tearDown
{
// No necessary tear down.
}
- (void)testPath
{
NSString *expectedPath = [[fileManager currentDirectoryPath] stringByAppendingString:EMOTICONSET_PATH1];
STAssertEqualObjects(expectedPath, [emoticonPack path], @"Path wasn't right, should have been %@ but was %@", expectedPath, [emoticonPack path]);
}
- (void)testName
{
NSString *expectedName = [[[NSString stringWithString:EMOTICONSET_PATH1] lastPathComponent] stringByDeletingPathExtension];
STAssertEqualObjects(expectedName, [emoticonPack name], @"Name wasn't right, should have been %@ but was %@", expectedName, [emoticonPack name]);
}
- (void)testEnabled
{
[emoticonPack setIsEnabled:YES];
STAssertTrue([emoticonPack isEnabled], @"Emoticon Pack isn't enabled by default");
[emoticonPack setIsEnabled:NO];
STAssertFalse([emoticonPack isEnabled], @"Emoticon Pack is enabled when it shouldn't be");
[emoticonPack setIsEnabled:YES];
STAssertTrue([emoticonPack isEnabled], @"Emoticon Pack isn't enabled when it shouldn't be");
}
Hmm. I really need to write my own wordpress theme.
Adium devs look out, incoming SoC application! 
Posted by patrick under
Summerofcode, adium, cocoa, code, open-source, unittesting
No Comments »
18th Mar 2007
With Google’s Summer of Code roaring up again this summer and me without summer job plans yet, I have dug into investigating one of the project ideas by my favourite OSS project, Adium. The project idea I’m looking into submitting a proposal for is that of unit testing much of Adium’s code. Currently Adium does no unit testing. Although my experience with Cocoa is growing to a point where I am fairly comfortable with it, my experience with unit testing doesn’t stretch as far. It’s not a difficult concept, however, so I decided to try and put it into action and see what I could come up with.
I chose to write a unit test for the emoticon classes, AIEmoticon and AIEmoticonPack. I choose these classes because they are documented, making understanding them quicker and easier, and because they aren’t ridiculously large. A good start for a unit test.
Creating a new test bundle target and the test classes were easy thanks to the fact that OCUnit is bundled with Xcode. As soon as I added the necessary frameworks though, I ran into a problem.
Adium.framework references FriBidi.framework, but because the unit test actually runs from /Developer/Tools/otest, the FriBidi.framework isn’t found in the @executable_path (where dyld is looking for it). Copying it to the build products Frameworks directory is no help since it doesn’t look there either. You could create a symlink to the build products directory but that’s rather messy and Xcode provides us with a much easier way of doing this: In the Run Script phase of the build process for your Test Bundle target, define DYLD_FRAMEWORK_PATH to the directory containing your referenced frameworks before the tests are run. Mine looks like this:
export DYLD_FRAMEWORK_PATH="${PROJECT_DIR}/Frameworks"
I spent several hours figuring this little detail out. Big thanks to both Peter Hosey and chanson of #macdev for helping me nail this down and explaining it to me.
I now have the beginnings of a working unit test of AIEmoticonPack. I’ve run into a new problem where certain methods cannot be tested since they require a running instance of Adium. I plan to address this by defining a base test class which instantiates such an Adium instance then changing my test case to inherit from that class. We’ll see how it goes.
Posted by patrick under
Summerofcode, adium, open-source, unittesting
1 Comment »
01st Mar 2007
Creating a Plugin for Adium is actually really easy. Here’s a quick guide through the proper set up to help get you started. There is even a skeleton project at the end.
- Create a new Xcode project, choose Bundle -> Cocoa Bundle.
- Add the following frameworks to your project:
- Adium.framework
- AIUtilities.framework
- FriBidi.framework
These are necessary if you plan on using or changing any part of Adium, which you will likely be doing.
- Create your main class. It should be named something like ABMyTestPlugin. Your class should inherit from AIPlugin, found in Adium/AIPlugin. So you will need to import that.
- Override the -installPlugin and (if necessary) -uninstallPlugin methods. The meat of your code goes there.
- Override -pluginAuthor, -pluginVersion, -pluginDescription, and -pluginURL as well, to all return appropriate NSStrings. This isn’t required, but is good practice, so do it anyways.
- Get info on the build target (your bundle). Change the build settings to add the following:
- Other Linker Flags: -undefined dynamic_lookup
- Wrapper Extension: AdiumPlugin
Also, under the Properties tab change the Creator to “AdiM” and the set the Principal class to the name of your main class (ABMyTestPlugin).
- Build your bundle, drag and drop it onto the Adium icon and test it out.
That’s pretty much all there is to it. More information on what you can do once you hook into adium can be found at the Map of Adium. It’s not really complete, but if you poke around inside the Adium.framework headers you will find that most of the methods are “self-documenting” and not to difficult to figure out. I’d also suggest looking at some existing plugins, like my Time Zone Plugin and the ones included within Adium itself.
If you’d like a skeleton of the Xcode project, grab it right here: AdiumTestPlugin.zip
You might want to also grab the Adium Source and compile your own frameworks since the ones included may be out of date.
Update: luapffuh pointed me to Toby’s guide to creating an Adium Plugin. Although mostly the same, his has bit more detail and is definitely worth checking out.
Posted by patrick under
adium, cocoa, code, how-to, open-source
1 Comment »