Permalink
Browse files

[VERSION] 0.0.1

  • Loading branch information...
0 parents commit 23bd58b69dc4a807e91995824f4d2d5e995adf22 @rentzsch committed Jun 8, 2012
Showing with 325 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +80 −0 JRErr.h
  3. +68 −0 JRErr.m
  4. +13 −0 Makefile
  5. +163 −0 TestJRErr.m
@@ -0,0 +1 @@
+build
80 JRErr.h
@@ -0,0 +1,80 @@
+// JRErr.h semver:0.0.1
+// Copyright (c) 2012 Jonathan 'Wolf' Rentzsch: http://rentzsch.com
+// Some rights reserved: http://opensource.org/licenses/MIT
+// https://github.com/rentzsch/JRErr
+
+#import <Foundation/Foundation.h>
+
+#define jrErr [[JRErrContext currentContext] currentError]
+
+#define JRPushErr(CODE) \
+ {{ \
+ NSError *_jrErr = nil; \
+ NSError **jrErrRef = &_jrErr; \
+ BOOL _hasVoidReturnType; \
+ intptr_t _codeResult = (intptr_t) __builtin_choose_expr(__builtin_types_compatible_p(typeof(CODE), void), \
+ (_hasVoidReturnType = YES, CODE, -1), \
+ (_hasVoidReturnType = NO, CODE)); \
+ BOOL _hasError = NO; \
+ if (_hasVoidReturnType) { \
+ if (_jrErr) { \
+ _hasError = YES; \
+ } \
+ } else { \
+ if (!_codeResult) { \
+ _hasError = YES; \
+ } \
+ } \
+ if (_hasError) { \
+ NSMutableDictionary *_userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: \
+ [NSString stringWithUTF8String:__FILE__], @"__FILE__", \
+ [NSNumber numberWithInt:__LINE__], @"__LINE__", \
+ [NSString stringWithUTF8String:__PRETTY_FUNCTION__], @"__PRETTY_FUNCTION__", \
+ [NSString stringWithUTF8String:#CODE], @"CODE", \
+ [NSThread callStackSymbols], @"callStack", \
+ nil]; \
+ NSError *_mergedError; \
+ if (_jrErr) { \
+ [_userInfo setValuesForKeysWithDictionary:[_jrErr userInfo]]; \
+ _mergedError = [NSError errorWithDomain:[_jrErr domain] \
+ code:[_jrErr code] \
+ userInfo:_userInfo]; \
+ } else { \
+ _mergedError = [NSError errorWithDomain:@"JRErrDomain" \
+ code:-1 \
+ userInfo:_userInfo]; \
+ } \
+ [[JRErrContext currentContext] pushError:_mergedError]; \
+ } \
+ jrErrRef++; \
+ }}
+
+#define ReturnOrReportLocoErr(ERROR_RESULT_REF) \
+ if (jrerr) { \
+ if (ERROR_RESULT_REF) { \
+ *ERROR_RESULT_REF = locoErr; \
+ } else { \
+ JRLogNSError(locoErr); \
+ } \
+ return NO; \
+ } else { \
+ return YES; \
+ }
+
+
+@interface JRErrContext : NSObject {
+#ifndef NOIVARS
+ @protected
+ NSMutableArray *errorStack;
+#endif
+}
+@property(retain) NSMutableArray *errorStack;
+
++ (JRErrContext*)currentContext;
+
+- (NSError*)currentError;
+
+- (void)pushError:(NSError*)error;
+- (NSError*)popError;
+
+@end
68 JRErr.m
@@ -0,0 +1,68 @@
+// JRErr.m semver:0.0.1
+// Copyright (c) 2012 Jonathan 'Wolf' Rentzsch: http://rentzsch.com
+// Some rights reserved: http://opensource.org/licenses/MIT
+// https://github.com/rentzsch/JRErr
+
+#import "JRErr.h"
+
+void JRErrRunLoopObserver(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
+ JRErrContext *errContext = [JRErrContext currentContext];
+ for (NSError *error in errContext.errorStack) {
+ NSLog(@"unhandled error: %@", error);
+ }
+ [errContext.errorStack removeAllObjects];
+}
+
+@implementation JRErrContext
+@synthesize errorStack;
+
+- (id)init {
+ self = [super init];
+ if (self) {
+ errorStack = [[NSMutableArray alloc] init];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [errorStack release];
+ [super dealloc];
+}
+
++ (JRErrContext*)currentContext {
+ NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary];
+ JRErrContext *result = [threadDict objectForKey:@"locoErrorContext"];
+ if (!result) {
+ result = [[[JRErrContext alloc] init] autorelease];
+ [threadDict setObject:result forKey:@"locoErrorContext"];
+
+ CFRunLoopObserverContext observerContext = {0, NULL, NULL, NULL, NULL};
+ CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault,
+ kCFRunLoopExit,
+ true,
+ 0,
+ JRErrRunLoopObserver,
+ &observerContext);
+ CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopCommonModes);
+
+ }
+ return result;
+}
+
+- (NSError*)currentError {
+ return [self.errorStack lastObject];
+}
+
+- (void)pushError:(NSError*)error {
+ [self.errorStack addObject:error];
+}
+
+- (NSError*)popError {
+ NSError *result = [self.errorStack lastObject];
+ if (result) {
+ [self.errorStack removeLastObject];
+ }
+ return result;
+}
+
+@end
@@ -0,0 +1,13 @@
+test: build
+ build/TestJRErrGCC
+ build/TestJRErrClang
+
+build: *.m
+ mkdir build
+ gcc -o build/TestJRErrGCC *.m -framework Foundation
+ clang -o build/TestJRErrClang *.m -framework Foundation
+
+.PHONY: clean
+
+clean:
+ rm -rf build
@@ -0,0 +1,163 @@
+#import <Foundation/Foundation.h>
+#import "JRErr.h"
+
+@interface NSObject (TestJRErr)
+- (BOOL)returnYesAndNoError:(NSError**)error;
+- (BOOL)returnYesAndAnError:(NSError**)error;
+- (BOOL)returnNoAndNoError:(NSError**)error;
+- (BOOL)returnNoAndAnError:(NSError**)error;
+- (void)returnVoidAndNoError:(NSError**)error;
+- (void)returnVoidAndAnError:(NSError**)error;
+
+- (id)returnPtrAndNoError:(NSError**)error;
+- (id)returnPtrAndAnError:(NSError**)error;
+- (id)returnNilPtrAndNoError:(NSError**)error;
+- (id)returnNilPtrAndAnError:(NSError**)error;
+@end
+
+int main (int argc, const char * argv[]) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSObject *obj = [[[NSObject alloc] init] autorelease];
+
+ assert(!jrErr);
+ JRPushErr([obj returnYesAndNoError:jrErrRef]);
+ assert(!jrErr);
+ [[JRErrContext currentContext] popError];
+ assert(!jrErr);
+
+ assert(!jrErr);
+ JRPushErr([obj returnYesAndAnError:jrErrRef]);
+ assert(!jrErr);
+ [[JRErrContext currentContext] popError];
+ assert(!jrErr);
+
+ assert(!jrErr);
+ JRPushErr([obj returnNoAndNoError:jrErrRef]);
+ assert(jrErr);
+ [[JRErrContext currentContext] popError];
+ assert(!jrErr);
+
+ assert(!jrErr);
+ JRPushErr([obj returnNoAndAnError:jrErrRef]);
+ assert(jrErr);
+ assert([jrErr code] == 42);
+ [[JRErrContext currentContext] popError];
+ assert(!jrErr);
+
+ assert(!jrErr);
+ JRPushErr([obj returnVoidAndNoError:jrErrRef]);
+ assert(!jrErr);
+ [[JRErrContext currentContext] popError];
+ assert(!jrErr);
+
+ assert(!jrErr);
+ JRPushErr([obj returnVoidAndAnError:jrErrRef]);
+ assert(jrErr);
+ assert([jrErr code] == 42);
+ [[JRErrContext currentContext] popError];
+ assert(!jrErr);
+
+ assert(!jrErr);
+ JRPushErr([obj returnPtrAndNoError:jrErrRef]);
+ assert(!jrErr);
+ [[JRErrContext currentContext] popError];
+ assert(!jrErr);
+
+ assert(!jrErr);
+ JRPushErr([obj returnPtrAndAnError:jrErrRef]);
+ assert(!jrErr);
+ [[JRErrContext currentContext] popError];
+ assert(!jrErr);
+
+ assert(!jrErr);
+ JRPushErr([obj returnNilPtrAndNoError:jrErrRef]);
+ assert(jrErr);
+ assert([[jrErr domain] isEqualToString:@"JRErrDomain"]);
+ assert([jrErr code] == -1);
+ [[JRErrContext currentContext] popError];
+ assert(!jrErr);
+
+ assert(!jrErr);
+ JRPushErr([obj returnNilPtrAndAnError:jrErrRef]);
+ assert(jrErr);
+ assert([[jrErr domain] isEqualToString:@"TestJRErrDomain"]);
+ assert([jrErr code] == 42);
+ [[JRErrContext currentContext] popError];
+ assert(!jrErr);
+
+ [pool drain];
+ printf("success\n");
+ return 0;
+}
+
+@implementation NSObject (TestJRErr)
+
+- (BOOL)returnYesAndNoError:(NSError**)error {
+ NSParameterAssert(error);
+ NSParameterAssert(*error == nil);
+ // Poison the error object so we'll crash if it's inspected
+ // (errors shouldn't be looked at if the method indicates success):
+ *error = (NSError*)0x1;
+ return YES;
+}
+
+- (BOOL)returnYesAndAnError:(NSError**)error {
+ NSParameterAssert(error);
+ NSParameterAssert(*error == nil);
+ *error = [NSError errorWithDomain:@"TestJRErrDomain" code:42 userInfo:nil];
+ return YES;
+}
+
+- (BOOL)returnNoAndNoError:(NSError**)error {
+ NSParameterAssert(error);
+ NSParameterAssert(*error == nil);
+ return NO;
+}
+
+- (BOOL)returnNoAndAnError:(NSError**)error {
+ NSParameterAssert(error);
+ NSParameterAssert(*error == nil);
+ *error = [NSError errorWithDomain:@"TestJRErrDomain" code:42 userInfo:nil];
+ return NO;
+}
+
+- (void)returnVoidAndNoError:(NSError**)error {
+ NSParameterAssert(error);
+ NSParameterAssert(*error == nil);
+}
+
+- (void)returnVoidAndAnError:(NSError**)error {
+ NSParameterAssert(error);
+ NSParameterAssert(*error == nil);
+ *error = [NSError errorWithDomain:@"TestJRErrDomain" code:42 userInfo:nil];
+}
+
+- (id)returnPtrAndNoError:(NSError**)error {
+ NSParameterAssert(error);
+ NSParameterAssert(*error == nil);
+ *error = (NSError*)0x1;
+ return self;
+}
+
+- (id)returnPtrAndAnError:(NSError**)error {
+ NSParameterAssert(error);
+ NSParameterAssert(*error == nil);
+ *error = [NSError errorWithDomain:@"TestJRErrDomain" code:42 userInfo:nil];
+ return self;
+}
+
+- (id)returnNilPtrAndNoError:(NSError**)error {
+ NSParameterAssert(error);
+ NSParameterAssert(*error == nil);
+ return nil;
+}
+
+- (id)returnNilPtrAndAnError:(NSError**)error {
+ NSParameterAssert(error);
+ NSParameterAssert(*error == nil);
+ *error = [NSError errorWithDomain:@"TestJRErrDomain" code:42 userInfo:nil];
+ return nil;
+}
+
+@end

0 comments on commit 23bd58b

Please sign in to comment.