[from now] 2013/04/07 19:14:04

diff --git a/BlockInjectionTest/BlockInjectionTest.xcodeproj/project.pbxproj b/BlockInjectionTest/BlockInjectionTest.xcodeproj/project.pbxproj
index b3be226..2a96171 100644
--- a/BlockInjectionTest/BlockInjectionTest.xcodeproj/project.pbxproj
+++ b/BlockInjectionTest/BlockInjectionTest.xcodeproj/project.pbxproj
@@ -38,7 +38,7 @@
 		06584EB616DEFA6000CB2D68 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
 		06584ECF16DEFA6000CB2D68 /* BlockInjectionTestTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BlockInjectionTestTests.octest; sourceTree = BUILT_PRODUCTS_DIR; };
 		06584ED016DEFA6000CB2D68 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; };
-		06584ED816DEFA6000CB2D68 /* BlockInjectionTestTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "BlockInjectionTestTests-Info.plist"; sourceTree = "<group>"; };
+		06584ED816DEFA6000CB2D68 /* BlockInjectionTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "BlockInjectionTests-Info.plist"; sourceTree = "<group>"; };
 		06584EDA16DEFA6000CB2D68 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		06584EDC16DEFA6000CB2D68 /* BasicTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BasicTest.h; sourceTree = "<group>"; };
 		06584EDD16DEFA6000CB2D68 /* BasicTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BasicTest.m; sourceTree = "<group>"; };
@@ -69,7 +69,7 @@
 			isa = PBXGroup;
 			children = (
 				06584EE716DEFAF800CB2D68 /* BlockInjection */,
-				06584ED616DEFA6000CB2D68 /* BlockInjectionTestTests */,
+				06584ED616DEFA6000CB2D68 /* BlockInjectionTests */,
 				06584EB116DEFA6000CB2D68 /* Frameworks */,
 				06584EB016DEFA6000CB2D68 /* Products */,
 			);
@@ -94,7 +94,7 @@
 			name = Frameworks;
 			sourceTree = "<group>";
 		};
-		06584ED616DEFA6000CB2D68 /* BlockInjectionTestTests */ = {
+		06584ED616DEFA6000CB2D68 /* BlockInjectionTests */ = {
 			isa = PBXGroup;
 			children = (
 				06584EDC16DEFA6000CB2D68 /* BasicTest.h */,
@@ -109,14 +109,14 @@
 				0685AD09170DCB8D0082AD69 /* SkippingTest.m */,
 				06584ED716DEFA6000CB2D68 /* Supporting Files */,
 			);
-			path = BlockInjectionTestTests;
+			path = BlockInjectionTests;
 			sourceTree = "<group>";
 		};
 		06584ED716DEFA6000CB2D68 /* Supporting Files */ = {
 			isa = PBXGroup;
 			children = (
 				06584EF116DEFE7300CB2D68 /* BlockInjectionTest-Prefix.pch */,
-				06584ED816DEFA6000CB2D68 /* BlockInjectionTestTests-Info.plist */,
+				06584ED816DEFA6000CB2D68 /* BlockInjectionTests-Info.plist */,
 				06584ED916DEFA6000CB2D68 /* InfoPlist.strings */,
 			);
 			name = "Supporting Files";
@@ -141,9 +141,9 @@
 /* End PBXGroup section */

 /* Begin PBXNativeTarget section */
-		06584ECE16DEFA6000CB2D68 /* BlockInjectionTestTests */ = {
+		06584ECE16DEFA6000CB2D68 /* BlockInjectionTests */ = {
 			isa = PBXNativeTarget;
-			buildConfigurationList = 06584EE416DEFA6000CB2D68 /* Build configuration list for PBXNativeTarget "BlockInjectionTestTests" */;
+			buildConfigurationList = 06584EE416DEFA6000CB2D68 /* Build configuration list for PBXNativeTarget "BlockInjectionTests" */;
 			buildPhases = (
 				06584ECA16DEFA6000CB2D68 /* Sources */,
 				06584ECB16DEFA6000CB2D68 /* Frameworks */,
@@ -154,7 +154,7 @@
 			);
 			dependencies = (
 			);
-			name = BlockInjectionTestTests;
+			name = BlockInjectionTests;
 			productName = BlockInjectionTestTests;
 			productReference = 06584ECF16DEFA6000CB2D68 /* BlockInjectionTestTests.octest */;
 			productType = "com.apple.product-type.bundle";
@@ -180,7 +180,7 @@
 			projectDirPath = "";
 			projectRoot = "";
 			targets = (
-				06584ECE16DEFA6000CB2D68 /* BlockInjectionTestTests */,
+				06584ECE16DEFA6000CB2D68 /* BlockInjectionTests */,
 			);
 		};
 /* End PBXProject section */
@@ -310,7 +310,7 @@
 				);
 				GCC_PRECOMPILE_PREFIX_HEADER = YES;
 				GCC_PREFIX_HEADER = "BlockInjectionTest-Prefix.pch";
-				INFOPLIST_FILE = "BlockInjectionTestTests/BlockInjectionTestTests-Info.plist";
+				INFOPLIST_FILE = "BlockInjectionTests/BlockInjectionTests-Info.plist";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				TEST_HOST = "$(BUNDLE_LOADER)";
 				WRAPPER_EXTENSION = octest;
@@ -327,7 +327,7 @@
 				);
 				GCC_PRECOMPILE_PREFIX_HEADER = YES;
 				GCC_PREFIX_HEADER = "BlockInjectionTest-Prefix.pch";
-				INFOPLIST_FILE = "BlockInjectionTestTests/BlockInjectionTestTests-Info.plist";
+				INFOPLIST_FILE = "BlockInjectionTests/BlockInjectionTests-Info.plist";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				TEST_HOST = "$(BUNDLE_LOADER)";
 				WRAPPER_EXTENSION = octest;
@@ -346,7 +346,7 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
-		06584EE416DEFA6000CB2D68 /* Build configuration list for PBXNativeTarget "BlockInjectionTestTests" */ = {
+		06584EE416DEFA6000CB2D68 /* Build configuration list for PBXNativeTarget "BlockInjectionTests" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				06584EE516DEFA6000CB2D68 /* Debug */,
diff --git a/BlockInjectionTest/BlockInjectionTests/BasicTest.h b/BlockInjectionTest/BlockInjectionTests/BasicTest.h
new file mode 100644
index 0000000..c6d95e5
--- /dev/null
+++ b/BlockInjectionTest/BlockInjectionTests/BasicTest.h
@@ -0,0 +1,10 @@
+//
+//  BasicTest.h
+//
+//  Created by ToKoRo on 2013-02-28.
+//
+
+#import <SenTestingKit/SenTestingKit.h>
+
+@interface BasicTest : SenTestCase
+@end
diff --git a/BlockInjectionTest/BlockInjectionTests/BasicTest.m b/BlockInjectionTest/BlockInjectionTests/BasicTest.m
new file mode 100644
index 0000000..ea0e00b
--- /dev/null
+++ b/BlockInjectionTest/BlockInjectionTests/BasicTest.m
@@ -0,0 +1,464 @@
+//
+//  BasicTest.m
+//
+//  Created by ToKoRo on 2013-02-28.
+//
+
+#import "BasicTest.h"
+#import "BILib.h"
+
+#pragma mark - Bizz
+
+@interface Bizz : NSObject
+@property (assign) int count;
+@property (copy) NSString* backup;
+- (void)sayMessage:(NSString*)message;
+@end
+
+@implementation Bizz
+- (void)sayMessage:(NSString*)message
+{
+  ++self.count;
+  NSLog(@"Bizz says: %@", message);
+}
+@end
+
+#pragma mark - struct 17
+
+typedef struct bilib_test_17 {
+  char c;
+  long l1;
+  long l2;
+  long l3;
+  long l4;
+} bilib_test_17;
+
+#pragma mark - struct 17
+
+typedef struct bilib_test_1024 {
+  char buff[1024];
+  char c;
+} bilib_test_1024;
+
+#pragma mark - Buzz
+
+@interface Buzz : NSObject
+- (void)sendInt1:(int)int1 int2:(int)int2 long1:(long)long1;
+- (void)sendChar:(char)c d:(double)d;
+- (void)sendStruct17:(bilib_test_17)st1 st2:(bilib_test_17)st2;
+- (void)sendStruct1024:(bilib_test_1024)st1024;
+@end
+
+@implementation Buzz
+- (void)sendInt1:(int)int1 int2:(int)int2 long1:(long)long1
+{
+  NSLog(@"%d %d %ld", int1, int2, long1);
+}
+- (void)sendChar:(char)c d:(double)d
+{
+  NSLog(@"%c %f", c, d);
+}
+- (void)sendStruct17:(bilib_test_17)st1 st2:(bilib_test_17)st2
+{
+}
+- (void)sendStruct1024:(bilib_test_1024)st1024
+{
+}
+@end
+
+#pragma mark - Child
+
+@interface Child : Bizz
+- (void)sayMessage:(NSString*)message tag:(int)tag;
+@end
+
+@implementation Child
+- (void)sayMessage:(NSString*)message tag:(int)tag
+{
+  NSLog(@"Child says: %@ %d", message, tag);
+  [super sayMessage:message];
+}
+@end
+
+#pragma mark - ViewController
+
+@interface ViewController : NSObject
+- (void)buttonDidPush:(id)sender;
+@end
+
+@implementation ViewController
+- (void)buttonDidPush:(id)sender
+{
+  NSLog(@"buttonDidPush:");
+}
+@end
+
+#pragma mark - TestCase
+
+@implementation BasicTest
+
+- (void)setUp
+{
+  [super setUp];
+  [BILib clear];
+}
+
+- (void)tearDown
+{
+  [super tearDown];
+}
+
+- (void)testInject
+{
+  __block int i = 0;
+  [BILib injectToClass:[Bizz class] selector:@selector(sayMessage:) preprocess:^{
+    ++i;
+  }];
+
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [[Bizz new] sayMessage:@"hello!"];
+
+  STAssertEquals(i, 1, @"i is invalid.");
+}
+
+- (void)testPostprocess
+{
+  __block int i = 0;
+  [BILib injectToClass:[Bizz class] selector:@selector(sayMessage:) postprocess:^{
+    ++i;
+  }];
+
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [[Bizz new] sayMessage:@"hello!"];
+
+  STAssertEquals(i, 1, @"i is invalid.");
+}
+
+- (void)testCallTwice
+{
+  __block int i = 0;
+  [BILib injectToClass:[Bizz class] selector:@selector(sayMessage:) preprocess:^{
+    ++i;
+  }];
+
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [[Bizz new] sayMessage:@"hello!"];
+  [[Bizz new] sayMessage:@"hello!"];
+
+  STAssertEquals(i, 2, @"i is invalid.");
+}
+
+- (void)testHandleProperty
+{
+  __block NSString* b = nil;
+  [BILib injectToClass:[Bizz class] selector:@selector(sayMessage:) preprocess:^(Bizz* bizz){
+    b = bizz.backup;
+  }];
+
+  STAssertNil(b, @"b is invalid.");
+
+  Bizz* bizz = [Bizz new];
+  bizz.backup = @"backup";
+  [bizz sayMessage:@"hello!"];
+
+  STAssertTrue([b isEqualToString:@"backup"], @"b is invalid: %@", b);
+}
+
+- (void)testHandleArg
+{
+  __block NSString* b = nil;
+  [BILib injectToClass:[Bizz class] selector:@selector(sayMessage:) preprocess:^(Bizz* bizz, NSString* message){
+    b = message;
+  }];
+
+  STAssertNil(b, @"b is invalid.");
+
+  Bizz* bizz = [Bizz new];
+  [bizz sayMessage:@"hello!"];
+
+  STAssertTrue([b isEqualToString:@"hello!"], @"b is invalid: %@", b);
+}
+
+- (void)testPremitiveArgs
+{
+  __block int x, y;
+  __block long l;
+  [BILib injectToClass:[Buzz class] selector:@selector(sendInt1:int2:long1:) preprocess:^(Buzz* buzz, int int1, int int2, long long1){
+    x = int1;
+    y = int2;
+    l = long1;
+  }];
+
+  [[Buzz new] sendInt1:1 int2:2 long1:0xFFFFFFFF];
+
+  STAssertEquals(x, 1, @"x is invalid.");
+  STAssertEquals(y, 2, @"y is invalid.");
+  STAssertEquals(l, (long)0xFFFFFFFF, @"l is invalid.");
+}
+
+- (void)testInjectWithString
+{
+  __block int i = 0;
+  [BILib injectToClassWithName:@"Bizz" methodName:@"sayMessage:" preprocess:^{
+    ++i;
+  }];
+
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [[Bizz new] sayMessage:@"hello!"];
+
+  STAssertEquals(i, 1, @"i is invalid.");
+}
+
+- (void)testInjectTwice
+{
+  __block int i = 0;
+  [BILib injectToClass:[Bizz class] selector:@selector(sayMessage:) preprocess:^(Bizz* bizz, NSString* message){
+    i += 100;
+  }];
+  [BILib injectToClass:[Bizz class] selector:@selector(sayMessage:) preprocess:^(Bizz* bizz, NSString* message){
+    i += 200;
+  }];
+
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [[Bizz new] sayMessage:@"hello!"];
+
+  STAssertEquals(i, 300, @"i is invalid.");
+}
+
+- (void)testInjectTriple
+{
+  __block int i = 0;
+  [BILib injectToClass:[Bizz class] selector:@selector(sayMessage:) preprocess:^(Bizz* bizz, NSString* message){
+    i += 100;
+  }];
+  [BILib injectToClass:[Bizz class] selector:@selector(sayMessage:) preprocess:^(Bizz* bizz, NSString* message){
+    i += 200;
+  }];
+  [BILib injectToClass:[Bizz class] selector:@selector(sayMessage:) preprocess:^(Bizz* bizz, NSString* message){
+    i += 300;
+  }];
+
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [[Bizz new] sayMessage:@"hello!"];
+
+  STAssertEquals(i, 600, @"i is invalid.");
+}
+
+- (void)testSubclass
+{
+  [BILib injectToClass:[Child class] selector:@selector(sayMessage:tag:) preprocess:^(Child* child, NSString* message, int tag){
+    ++child.count;
+  }];
+
+  Child* child = [Child new];
+
+  STAssertEquals(child.count, 0, @"count is invalid.");
+
+  [child sayMessage:@"hello!" tag:5];
+
+  STAssertEquals(child.count, 2, @"count is invalid.");
+}
+
+- (void)testUIView
+{
+  [BILib injectToClass:[UIView class] selector:@selector(setFrame:) preprocess:^(UIView* view, CGRect frame){
+    view.tag += 100;
+  }];
+
+  UIView* view = [UIView new];
+
+  STAssertEquals(view.tag, 100, @"tag is invalid.");
+
+  [view setFrame:CGRectMake(0, 0, 20, 20)];
+
+  STAssertEquals(view.tag, 200, @"tag is invalid.");
+}
+
+- (void)testUIViewController
+{
+  __block BOOL bflag = NO;
+  [BILib injectToClass:[UIViewController class]
+              selector:@selector(presentViewController:animated:completion:)
+            preprocess:^(id target, UIViewController* vc, BOOL flag, id completion)
+  {
+    NSLog(@"presentViewController:%@ animated:%d completion:%@", vc, flag, completion);
+
+    bflag = flag;
+  }];
+
+  UIViewController* viewController = [UIViewController new];
+
+  STAssertEquals(bflag, NO, @"blag is invalid.");
+
+  [viewController presentViewController:[UIViewController new] animated:YES completion:NULL];
+
+  STAssertEquals(bflag, YES, @"blag is invalid.");
+}
+
+- (void)testReturnValue
+{
+  [BILib injectToClass:[Bizz class] selector:@selector(count) preprocess:^(Bizz* bizz){
+    NSLog(@"preprocess");
+  }];
+
+  Bizz* bizz = [Bizz new];
+
+  STAssertEquals(bizz.count, 0, @"i is invalid.");
+
+  bizz.count = 100;
+  int ret = bizz.count;
+
+  STAssertEquals(ret, 100, @"ret is invalid.");
+}
+
+- (void)testReturnValueForObject
+{
+  [BILib injectToClass:[Bizz class] selector:@selector(backup) preprocess:^(Bizz* bizz){
+    NSLog(@"preprocess");
+  }];
+
+  Bizz* bizz = [Bizz new];
+
+  bizz.backup = @"xxx";
+
+  STAssertTrue([bizz.backup isEqualToString:@"xxx"], @"bizz.backup is invalid: %@", bizz.backup);
+}
+
+- (void)testForReadme
+{
+  __block int i = 0;
+  [BILib injectToClass:[ViewController class] selector:@selector(buttonDidPush:) preprocess:^{
+
+    //[tracker sendEventWithCategory:@"uiAction"
+                        //withAction:@"buttonDidPush"
+                         //withLabel:nil
+                         //withValue:0];
+
+    ++i;
+  }];
+
+  [[ViewController new] buttonDidPush:nil];
+
+  STAssertEquals(i, 1, @"i is invalid.");
+
+  [BILib injectToClassWithName:@"ViewController" methodName:@"buttonDidPush:" preprocess:^{
+
+    //[tracker sendEventWithCategory:@"uiAction"
+                        //withAction:@"buttonDidPush"
+                         //withLabel:nil
+                         //withValue:0];
+
+    i = 10;
+  }];
+
+  [[ViewController new] buttonDidPush:nil];
+
+  STAssertEquals(i, 10, @"i is invalid.");
+}
+
+- (void)testNilArgument
+{
+  __block NSString* str = nil;
+  __block int i = 0;
+  [BILib injectToClass:[Child class] selector:@selector(sayMessage:tag:) preprocess:^(Child* child, NSString* message, int tag){
+    str = message;
+    i = tag;
+  }];
+
+  Child* child = [Child new];
+
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [child sayMessage:nil tag:999];
+
+  STAssertNil(str, @"str is not nil.");
+  STAssertEquals(i, 999, @"i is invalid.");
+}
+
+- (void)testLongLongArgument
+{
+  __block char bc;
+  __block double bd;
+  [BILib injectToClass:[Buzz class] selector:@selector(sendChar:d:) preprocess:^(Buzz* buzz, char c, double d){
+    bc = c;
+    bd = d;
+  }];
+
+  [[Buzz new] sendChar:'k' d:0.33333];
+
+  STAssertEquals(bc, (char)'k', @"bc is invalid.");
+  STAssertEquals(bd, (double)0.33333, @"bd is invalid.");
+}
+
+- (void)testStructArgument
+{
+  __block CGFloat height = 0.0;
+  [BILib injectToClass:[UIView class] selector:@selector(setFrame:) preprocess:^(UIView* view, CGRect frame){
+    NSLog(@"%@ setFarme:(%f, %f, %f, %f)", NSStringFromClass(view.class), frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
+    height = frame.size.height;
+  }];
+
+  UIView* view = [UIView new];
+
+  STAssertEquals(height, (CGFloat)0.0, @"height is invalid.");
+
+  [view setFrame:CGRectMake(10, 0, 20, 50)];
+
+  STAssertEquals(height, (CGFloat)50.0, @"height is invalid.");
+}
+
+- (void)testStruct17Argument
+{
+  __block long l14 = 0;
+  __block long l24 = 0;
+  [BILib injectToClass:[Buzz class] selector:@selector(sendStruct17:st2:) preprocess:^(id target, bilib_test_17 st1, bilib_test_17 st2){
+    NSLog(@"st1:(%c, %ld, %ld, %ld, %ld)", st1.c, st1.l1, st1.l2, st1.l3, st1.l4);
+    NSLog(@"st2:(%c, %ld, %ld, %ld, %ld)", st2.c, st2.l1, st2.l2, st2.l3, st2.l4);
+    l14 = st1.l4;
+    l24 = st2.l4;
+  }];
+
+  STAssertEquals(l14, (long)0, @"l14 is invalid.");
+  STAssertEquals(l24, (long)0, @"l24 is invalid.");
+
+  bilib_test_17 st1;
+  st1.c = 'c';
+  st1.l1 = 1;
+  st1.l2 = 2;
+  st1.l3 = 3;
+  st1.l4 = 256;
+  bilib_test_17 st2;
+  st2.c = '0';
+  st2.l1 = 11;
+  st2.l2 = 12;
+  st2.l3 = 13;
+  st2.l4 = 1256;
+  [[Buzz new] sendStruct17:st1 st2:st2];
+
+  STAssertEquals(l14, (long)256, @"l14 is invalid.");
+  STAssertEquals(l24, (long)1256, @"l24 is invalid.");
+}
+
+- (void)testStruct1024Argument
+{
+  __block char c = 0;
+  [BILib injectToClass:[Buzz class] selector:@selector(sendStruct1024:) preprocess:^(id target, bilib_test_1024 st1024){
+    c = st1024.c;
+  }];
+
+  STAssertEquals(c, (char)0, @"c is invalid.");
+
+  bilib_test_1024 st1024;
+  st1024.c = 'x';
+  [[Buzz new] sendStruct1024:st1024];
+
+  STAssertEquals(c, (char)'x', @"c is invalid.");
+}
+
+@end
diff --git a/BlockInjectionTest/BlockInjectionTests/BlockInjectionTests-Info.plist b/BlockInjectionTest/BlockInjectionTests/BlockInjectionTests-Info.plist
new file mode 100644
index 0000000..0471440
--- /dev/null
+++ b/BlockInjectionTest/BlockInjectionTests/BlockInjectionTests-Info.plist
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>${EXECUTABLE_NAME}</string>
+	<key>CFBundleIdentifier</key>
+	<string>me.tokoro.${PRODUCT_NAME:rfc1034identifier}</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundlePackageType</key>
+	<string>BNDL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>0.6.1</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>0.6.1</string>
+</dict>
+</plist>
diff --git a/BlockInjectionTest/BlockInjectionTests/ClassMethodTest.h b/BlockInjectionTest/BlockInjectionTests/ClassMethodTest.h
new file mode 100644
index 0000000..f2b7c80
--- /dev/null
+++ b/BlockInjectionTest/BlockInjectionTests/ClassMethodTest.h
@@ -0,0 +1,13 @@
+//
+//  ClassMethodTest.h
+//  BlockInjectionTest
+//
+//  Created by ytokoro on 3/23/13.
+//  Copyright (c) 2013 tokorom. All rights reserved.
+//
+
+#import <SenTestingKit/SenTestingKit.h>
+
+@interface ClassMethodTest : SenTestCase
+
+@end
diff --git a/BlockInjectionTest/BlockInjectionTests/ClassMethodTest.m b/BlockInjectionTest/BlockInjectionTests/ClassMethodTest.m
new file mode 100644
index 0000000..dfc67a8
--- /dev/null
+++ b/BlockInjectionTest/BlockInjectionTests/ClassMethodTest.m
@@ -0,0 +1,56 @@
+//
+//  ClassMethodTest.m
+//  BlockInjectionTest
+//
+//  Created by ytokoro on 3/23/13.
+//  Copyright (c) 2013 tokorom. All rights reserved.
+//
+
+#import "ClassMethodTest.h"
+#import "BILib.h"
+
+#pragma mark - SubjectForClass
+
+@interface SubjectForClass : NSObject
++ (void)classMethod:(id)arg;
+@end
+
+@implementation SubjectForClass
+
++ (void)classMethod:(id)arg
+{
+  NSLog(@"classMethod: %@", arg);
+}
+
+@end
+
+#pragma mark - ClassMethodTest
+
+@implementation ClassMethodTest
+
+- (void)setUp
+{
+  [super setUp];
+  [BILib clear];
+}
+
+- (void)tearDown
+{
+  [super tearDown];
+}
+
+- (void)testInjectToClassMethod
+{
+  __block int i = 0;
+  [BILib injectToClass:[SubjectForClass class] selector:@selector(classMethod:) preprocess:^{
+    ++i;
+  }];
+
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [SubjectForClass classMethod:@"hello!"];
+
+  STAssertEquals(i, 1, @"i is invalid.");
+}
+
+@end
diff --git a/BlockInjectionTest/BlockInjectionTests/RegexTest.h b/BlockInjectionTest/BlockInjectionTests/RegexTest.h
new file mode 100644
index 0000000..627a872
--- /dev/null
+++ b/BlockInjectionTest/BlockInjectionTests/RegexTest.h
@@ -0,0 +1,13 @@
+//
+//  RegexTest.h
+//  BlockInjectionTest
+//
+//  Created by ytokoro on 3/24/13.
+//  Copyright (c) 2013 tokorom. All rights reserved.
+//
+
+#import <SenTestingKit/SenTestingKit.h>
+
+@interface RegexTest : SenTestCase
+
+@end
diff --git a/BlockInjectionTest/BlockInjectionTests/RegexTest.m b/BlockInjectionTest/BlockInjectionTests/RegexTest.m
new file mode 100644
index 0000000..f190290
--- /dev/null
+++ b/BlockInjectionTest/BlockInjectionTests/RegexTest.m
@@ -0,0 +1,242 @@
+//
+//  RegexTest.m
+//  BlockInjectionTest
+//
+//  Created by ytokoro on 3/24/13.
+//  Copyright (c) 2013 tokorom. All rights reserved.
+//
+
+#import "RegexTest.h"
+#import "BILib.h"
+
+#pragma mark - SubjectForRegex
+
+@interface SubjectForRegex : NSObject
+@end
+
+@implementation SubjectForRegex
+
+- (void)instanceMethod:(id)arg
+{
+  NSLog(@"instanceMethod: %@", arg);
+}
+
+- (void)instanceMethod2
+{
+  NSLog(@"instanceMethod2");
+}
+
+@end
+
+#pragma mark - SubjectForRegex2
+
+@interface SubjectForRegex2 : NSObject
+@end
+
+@implementation SubjectForRegex2
+
+- (void)instanceMethod:(id)arg
+{
+  NSLog(@"instanceMethod: %@", arg);
+}
+
+@end
+
+#pragma mark - RegexTest
+
+@implementation RegexTest
+
+- (void)setUp
+{
+  [super setUp];
+  [BILib clear];
+}
+
+- (void)tearDown
+{
+  [super tearDown];
+}
+
+- (void)testAnyMethodsWithPreprocess
+{
+  __block int i = 0;
+  [BILib injectToClassWithNames:@[@"SubjectForRegex"] methodNames:@[@"instanceMethod:", @"instanceMethod2"] preprocess:^{
+    ++i;
+  }];
+
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [[SubjectForRegex new] instanceMethod:@"hello!"];
+
+  STAssertEquals(i, 1, @"i is invalid.");
+
+  [[SubjectForRegex new] instanceMethod2];
+
+  STAssertEquals(i, 2, @"i is invalid.");
+}
+
+- (void)testAnyMethodsWithPostprocess
+{
+  __block int i = 0;
+  [BILib injectToClassWithNames:@[@"SubjectForRegex"] methodNames:@[@"instanceMethod:", @"instanceMethod2"] postprocess:^{
+    ++i;
+  }];
+
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [[SubjectForRegex new] instanceMethod:@"hello!"];
+
+  STAssertEquals(i, 1, @"i is invalid.");
+
+  [[SubjectForRegex new] instanceMethod2];
+
+  STAssertEquals(i, 2, @"i is invalid.");
+}
+
+- (void)testAnyClassesAndAnyMethodsWithPreprocess
+{
+  __block int i = 0;
+  [BILib injectToClassWithNames:@[@"SubjectForRegex", @"SubjectForRegex2"] methodNames:@[@"instanceMethod:", @"instanceMethod2"] preprocess:^{
+    ++i;
+  }];
+
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [[SubjectForRegex2 new] instanceMethod:@"hello!"];
+
+  STAssertEquals(i, 1, @"i is invalid.");
+
+  [[SubjectForRegex new] instanceMethod:@"hello!"];
+
+  STAssertEquals(i, 2, @"i is invalid.");
+
+  [[SubjectForRegex new] instanceMethod2];
+
+  STAssertEquals(i, 3, @"i is invalid.");
+}
+
+- (void)testAnyClassesAndAnyMethodsWithPostprocess
+{
+  __block int i = 0;
+  [BILib injectToClassWithNames:@[@"SubjectForRegex", @"SubjectForRegex2"] methodNames:@[@"instanceMethod:", @"instanceMethod2"] postprocess:^{
+    ++i;
+  }];
+
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [[SubjectForRegex2 new] instanceMethod:@"hello!"];
+
+  STAssertEquals(i, 1, @"i is invalid.");
+
+  [[SubjectForRegex new] instanceMethod:@"hello!"];
+
+  STAssertEquals(i, 2, @"i is invalid.");
+
+  [[SubjectForRegex new] instanceMethod2];
+
+  STAssertEquals(i, 3, @"i is invalid.");
+}
+
+- (void)testHandlePrettyFunction
+{
+  __block NSString* handlePrettyFunction = @"";
+  [BILib injectToClassWithNames:@[@"SubjectForRegex", @"SubjectForRegex2"] methodNames:@[@"instanceMethod:", @"instanceMethod2"] preprocess:^{
+    handlePrettyFunction = [BILib prettyFunction];
+  }];
+
+  [[SubjectForRegex2 new] instanceMethod:@"hello!"];
+
+  STAssertTrue([handlePrettyFunction isEqualToString:@"-[SubjectForRegex2 instanceMethod:]"], @"handlePrettyFunction is invalid: %@", handlePrettyFunction);
+
+  [[SubjectForRegex new] instanceMethod:@"hello!"];
+
+  STAssertTrue([handlePrettyFunction isEqualToString:@"-[SubjectForRegex instanceMethod:]"], @"handlePrettyFunction is invalid: %@", handlePrettyFunction);
+
+  [[SubjectForRegex new] instanceMethod2];
+
+  STAssertTrue([handlePrettyFunction isEqualToString:@"-[SubjectForRegex instanceMethod2]"], @"handlePrettyFunction is invalid: %@", handlePrettyFunction);
+}
+
+- (void)testRegexWithPreprocess
+{
+  NSError* error = nil;
+  NSRegularExpression* classNameRegex = [NSRegularExpression regularExpressionWithPattern:@"^SubjectForRegex$" options:0 error:&error];
+  NSRegularExpression* methodNameRegex = [NSRegularExpression regularExpressionWithPattern:@"^instance.*$" options:0 error:&error];
+
+  __block int i = 0;
+  [BILib injectToClassWithNameRegex:classNameRegex methodNameRegex:methodNameRegex preprocess:^{
+    ++i;
+  }];
+
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [[SubjectForRegex new] instanceMethod:@"hello!"];
+
+  STAssertEquals(i, 1, @"i is invalid.");
+
+  [[SubjectForRegex new] instanceMethod2];
+
+  STAssertEquals(i, 2, @"i is invalid.");
+}
+
+- (void)testRegexWithPostprocess
+{
+  NSError* error = nil;
+  NSRegularExpression* classNameRegex = [NSRegularExpression regularExpressionWithPattern:@"^SubjectForRegex.*$" options:0 error:&error];
+  NSRegularExpression* methodNameRegex = [NSRegularExpression regularExpressionWithPattern:@"^instance.*$" options:0 error:&error];
+
+  __block int i = 0;
+  [BILib injectToClassWithNameRegex:classNameRegex methodNameRegex:methodNameRegex postprocess:^{
+    ++i;
+  }];
+
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [[SubjectForRegex new] instanceMethod:@"hello!"];
+
+  STAssertEquals(i, 1, @"i is invalid.");
+
+  [[SubjectForRegex new] instanceMethod2];
+
+  STAssertEquals(i, 2, @"i is invalid.");
+
+  [[SubjectForRegex2 new] instanceMethod:@"hello!"];
+
+  STAssertEquals(i, 3, @"i is invalid.");
+}
+
+- (void)testRegexWithUIView
+{
+  NSError* error = nil;
+  NSRegularExpression* classNameRegex = [NSRegularExpression regularExpressionWithPattern:@"^UIView$" options:0 error:&error];
+  NSRegularExpression* methodNameRegex = [NSRegularExpression regularExpressionWithPattern:@"^set.*$" options:0 error:&error];
+
+  [BILib injectToClassWithNameRegex:classNameRegex methodNameRegex:methodNameRegex postprocess:^{
+    NSLog(@"%@", [BILib prettyFunction]);
+  }];
+
+  UIView* view = [UIView new];
+  view.frame = CGRectMake(0.0, 0.0, 10.0, 5.0);
+
+  STAssertEquals(1, 1, nil);
+}
+
+- (void)testRegexWithMacro
+{
+  __block int i = 0;
+  [BILib injectToClassWithNameRegex:BIRegex(@"^SubjectForRegex$") methodNameRegex:BIRegex(@"^instance.*$") preprocess:^{
+    ++i;
+  }];
+
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [[SubjectForRegex new] instanceMethod:@"hello!"];
+
+  STAssertEquals(i, 1, @"i is invalid.");
+
+  [[SubjectForRegex new] instanceMethod2];
+
+  STAssertEquals(i, 2, @"i is invalid.");
+}
+
+@end
diff --git a/BlockInjectionTest/BlockInjectionTests/ReplaceTest.h b/BlockInjectionTest/BlockInjectionTests/ReplaceTest.h
new file mode 100644
index 0000000..95859ed
--- /dev/null
+++ b/BlockInjectionTest/BlockInjectionTests/ReplaceTest.h
@@ -0,0 +1,13 @@
+//
+//  ReplaceTest.h
+//  BlockInjectionTest
+//
+//  Created by ytokoro on 3/23/13.
+//  Copyright (c) 2013 tokorom. All rights reserved.
+//
+
+#import <SenTestingKit/SenTestingKit.h>
+
+@interface ReplaceTest : SenTestCase
+
+@end
diff --git a/BlockInjectionTest/BlockInjectionTests/ReplaceTest.m b/BlockInjectionTest/BlockInjectionTests/ReplaceTest.m
new file mode 100644
index 0000000..f251352
--- /dev/null
+++ b/BlockInjectionTest/BlockInjectionTests/ReplaceTest.m
@@ -0,0 +1,124 @@
+//
+//  ReplaceTest.m
+//  BlockInjectionTest
+//
+//  Created by ytokoro on 3/23/13.
+//  Copyright (c) 2013 tokorom. All rights reserved.
+//
+
+#import "ReplaceTest.h"
+#import "BILib.h"
+
+#pragma mark - SubjectForReplace
+
+@interface SubjectForReplace : NSObject
+- (void)instanceMethod:(id)arg;
++ (void)classMethod:(id)arg;
+@end
+
+@implementation SubjectForReplace
+
+- (void)instanceMethod:(id)arg
+{
+  NSLog(@"instanceMethod: %@", arg);
+}
+
++ (void)classMethod:(id)arg
+{
+  NSLog(@"classMethod: %@", arg);
+}
+
+@end
+
+#pragma mark - ReplaceTest
+
+@implementation ReplaceTest
+
+- (void)setUp
+{
+  [super setUp];
+  [BILib clear];
+}
+
+- (void)tearDown
+{
+  [super tearDown];
+}
+
+- (void)testReplaceImplementation
+{
+  __block int i = 0;
+  [BILib replaceImplementationForClass:[SubjectForReplace class] selector:@selector(instanceMethod:) block:^{
+    ++i;
+  }];
+
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [[SubjectForReplace new] instanceMethod:@"hello!"];
+
+  STAssertEquals(i, 1, @"i is invalid.");
+}
+
+- (void)testReplaceImplementationWithArg
+{
+  __block NSString* got = nil;
+  [BILib replaceImplementationForClass:[SubjectForReplace class] selector:@selector(instanceMethod:) block:^(id target, id arg){
+    got = arg;
+  }];
+
+  STAssertNil(got, @"got is invalid.");
+
+  [[SubjectForReplace new] instanceMethod:@"got!"];
+
+  STAssertTrue([got isEqualToString:@"got!"], @"got is invalid: %@", got);
+}
+
+- (void)testReplaceWithName
+{
+  __block int i = 0;
+  [BILib replaceImplementationForClassName:@"SubjectForReplace" methodName:@"instanceMethod:" block:^{
+    ++i;
+  }];
+
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [[SubjectForReplace new] instanceMethod:@"hello!"];
+
+  STAssertEquals(i, 1, @"i is invalid.");
+}
+
+- (void)testReplaceClassMethod
+{
+  __block int i = 0;
+  [BILib replaceImplementationForClass:[SubjectForReplace class] selector:@selector(classMethod:) block:^{
+    ++i;
+  }];
+
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [SubjectForReplace classMethod:@"hello!"];
+
+  STAssertEquals(i, 1, @"i is invalid.");
+}
+
+- (void)testReplaceAndInject
+{
+  __block NSString* got = nil;
+  [BILib replaceImplementationForClass:[SubjectForReplace class] selector:@selector(instanceMethod:) block:^(id target, id arg){
+    got = arg;
+  }];
+
+  __block int i = 0;
+  [BILib injectToClass:[SubjectForReplace class] selector:@selector(instanceMethod:) preprocess:^{
+    ++i;
+  }];
+
+  STAssertNil(got, @"got is invalid.");
+  STAssertEquals(i, 0, @"i is invalid.");
+
+  [[SubjectForReplace new] instanceMethod:@"got!"];
+
+  STAssertTrue([got isEqualToString:@"got!"], @"got is invalid: %@", got);
+  STAssertEquals(i, 1, @"i is invalid.");
+}
+@end
diff --git a/BlockInjectionTest/BlockInjectionTests/SkippingTest.h b/BlockInjectionTest/BlockInjectionTests/SkippingTest.h
new file mode 100644
index 0000000..0854265
--- /dev/null
+++ b/BlockInjectionTest/BlockInjectionTests/SkippingTest.h
@@ -0,0 +1,13 @@
+//
+//  SkippingTest.h
+//  BlockInjectionTest
+//
+//  Created by ytokoro on 4/4/13.
+//  Copyright (c) 2013 tokorom. All rights reserved.
+//
+
+#import <SenTestingKit/SenTestingKit.h>
+
+@interface SkippingTest : SenTestCase
+
+@end
diff --git a/BlockInjectionTest/BlockInjectionTests/SkippingTest.m b/BlockInjectionTest/BlockInjectionTests/SkippingTest.m
new file mode 100644
index 0000000..e4a8d09
--- /dev/null
+++ b/BlockInjectionTest/BlockInjectionTests/SkippingTest.m
@@ -0,0 +1,119 @@
+//
+//  SkippingTest.m
+//  BlockInjectionTest
+//
+//  Created by ytokoro on 4/4/13.
+//  Copyright (c) 2013 tokorom. All rights reserved.
+//
+
+#import "SkippingTest.h"
+#import "BILib.h"
+
+#import <objc/runtime.h>
+#import "BIItem.h"
+#import "BIItemManager.h"
+
+#pragma mark - SubjectForSkipping
+
+@interface SubjectForSkipping : NSObject
+@end
+
+@implementation SubjectForSkipping
+
+- (int)intValue
+{
+  return 100;
+}
+
+- (CGRect)rectValue
+{
+  return CGRectMake(10.0, 20.0, 30.0, 40.0);
+}
+
+- (char)charValue
+{
+  return 'a';
+}
+
+@end
+
+#pragma mark - SkippingTest
+
+@implementation SkippingTest
+
+- (void)setUp
+{
+  [super setUp];
+  [BILib clear];
+}
+
+- (void)tearDown
+{
+  [super tearDown];
+}
+
+- (void)testNormallyReturnValue
+{
+  [BILib injectToClassWithName:@"SubjectForSkipping" methodName:@"intValue" preprocess:^{
+  }];
+
+  int ret = [[SubjectForSkipping new] intValue];
+
+  STAssertEquals(ret, 100, @"ret is invalid.");
+}
+
+- (void)testSkippingOriginalMethod
+{
+  [BILib injectToClassWithName:@"SubjectForSkipping" methodName:@"intValue" preprocess:^{
+    int ret = 10;
+    [BILib skipAfterProcessesWithReturnValue:&ret];
+  }];
+
+  int ret = [[SubjectForSkipping new] intValue];
+
+  STAssertEquals(ret, 10, @"ret is invalid.");
+}
+
+- (void)testSkippingPostprocess
+{
+  [BILib injectToClassWithName:@"SubjectForSkipping" methodName:@"intValue" preprocess:^{
+    int ret = 10;
+    [BILib skipAfterProcessesWithReturnValue:&ret];
+  }];
+
+  __block int i = 0;
+  [BILib injectToClassWithName:@"SubjectForSkipping" methodName:@"intValue" postprocess:^{
+    i = 1;
+  }];
+
+  int ret = [[SubjectForSkipping new] intValue];
+
+  STAssertEquals(ret, 10, @"ret is invalid.");
+  STAssertEquals(i, 0, @"i is invalid.");
+}
+
+- (void)testOverrideReturnValueByPostprocess
+{
+  [BILib injectToClassWithName:@"SubjectForSkipping" methodName:@"intValue" preprocess:^{
+    int ret = 99;
+    [BILib skipAfterProcessesWithReturnValue:&ret];
+  }];
+
+  int ret = [[SubjectForSkipping new] intValue];
+
+  STAssertEquals(ret, 99, @"ret is invalid.");
+}
+
+- (void)testReturnChar
+{
+  [BILib injectToClassWithName:@"SubjectForSkipping" methodName:@"charValue" preprocess:^{
+    char c = 'c';
+    [BILib skipAfterProcessesWithReturnValue:&c];
+  }];
+
+  char c = [[SubjectForSkipping new] charValue];
+
+  STAssertEquals(c, (char)'c', @"c is invalid.");
+}
+
+@end
diff --git a/BlockInjectionTest/BlockInjectionTests/en.lproj/InfoPlist.strings b/BlockInjectionTest/BlockInjectionTests/en.lproj/InfoPlist.strings
new file mode 100644
index 0000000..477b28f
--- /dev/null
+++ b/BlockInjectionTest/BlockInjectionTests/en.lproj/InfoPlist.strings
@@ -0,0 +1,2 @@
+/* Localized versions of Info.plist keys */
+
.
[from now] 2013/04/07 23:01:57

diff --git a/BlockInjection/BIItem.m b/BlockInjection/BIItem.m
index 8abf7a6..4d7ef84 100644
--- a/BlockInjection/BIItem.m
+++ b/BlockInjection/BIItem.m
@@ -80,7 +80,8 @@
   void* result = NULL;
   NSUInteger returnLength = [[invocation methodSignature] methodReturnLength];
   if (returnLength) {
-    result = __builtin_alloca(returnLength);
+    //result = __builtin_alloca(returnLength);
+    result = malloc(returnLength);
   }
   // Preprocess
   [self prepareWithInvocation:invocation];
@@ -90,7 +91,6 @@
     [invocation setSelector:self.originalSel];
     [invocation invoke];
     // Get return value
-    NSUInteger returnLength = [[invocation methodSignature] methodReturnLength];
     if (returnLength && result) {
       [invocation getReturnValue:result];
     }
diff --git a/BlockInjection/BILib.m b/BlockInjection/BILib.m
index 8814fa3..124b137 100644
--- a/BlockInjection/BILib.m
+++ b/BlockInjection/BILib.m
@@ -9,6 +9,25 @@
 #import "BIItemManager.h"
 #import <objc/runtime.h>

+#define REPLACEBLOCK_FOR_VOID \
+  ^(id target, ...){ \
+    [[BIItemManager sharedInstance] setCurrentItem:item]; \
+    va_list argp; \
+    va_start(argp, target); \
+    [item invokeWithTarget:target args:&argp]; \
+    va_end(argp); \
+  }
+
+#define REPLACEBLOCK_FOR(type) \
+  ^(id target, ...){ \
+    [[BIItemManager sharedInstance] setCurrentItem:item]; \
+    va_list argp; \
+    va_start(argp, target); \
+    void* retp = [item invokeWithTarget:target args:&argp]; \
+    va_end(argp); \
+    return *(type*)retp; \
+  }
+
 @implementation BILib

 #pragma mark - Public Interface
@@ -236,14 +255,46 @@
 + (void)replaceImplementationWithItem:(BIItem*)item
 {
   if (item.signature) {
-    id replaceBlock = ^(id target, ...){
-      [[BIItemManager sharedInstance] setCurrentItem:item];
-      va_list argp;
-      va_start(argp, target);
-      void* retp = [item invokeWithTarget:target args:&argp];
-      va_end(argp);
-      return retp ? *(void**)retp : NULL;
-    };
+    id replaceBlock;
+    const char* returnType = [item.signature methodReturnType];
+  NSLog(@"##### returnType: %s", returnType);
+    if (NULL == returnType || 0 == strlen(returnType) || 'v' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR_VOID; }
+    else if ('c' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(char); }
+    else if ('i' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(int); }
+    else if ('s' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(short); }
+    else if ('l' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(long); }
+    else if ('q' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(long long); }
+    else if ('C' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(unsigned char); }
+    else if ('I' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(unsigned int); }
+    else if ('S' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(unsigned short); }
+    else if ('L' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(unsigned long); }
+    else if ('Q' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(unsigned long long); }
+    else if ('f' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(float); }
+    else if ('d' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(double); }
+    else if ('B' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(bool); }
+    else { replaceBlock = REPLACEBLOCK_FOR(int); }
+
+    /*
+    NSGetSizeAndAlignment(returnType, &returnLength, &alignment);
+    NSLog(@"##### %s : %d", returnType, returnLength);
+    switch (returnLength) {
+      case 0: { replaceBlock = ^(id target, ...){
+        [[BIItemManager sharedInstance] setCurrentItem:item];
+        va_list argp;
+        va_start(argp, target);
+        [item invokeWithTarget:target args:&argp];
+        va_end(argp);
+      }; } break;
+      default: { replaceBlock = ^(id target, ...){
+        [[BIItemManager sharedInstance] setCurrentItem:item];
+        va_list argp;
+        va_start(argp, target);
+        void* retp = [item invokeWithTarget:target args:&argp];
+        va_end(argp);
+        return *(int*)retp;
+      }; } break;
+    }
+    */
     method_setImplementation(item.originalMethod, imp_implementationWithBlock(replaceBlock));
   }
 }
diff --git a/BlockInjectionTest/BlockInjectionTest.xcodeproj/project.pbxproj b/BlockInjectionTest/BlockInjectionTest.xcodeproj/project.pbxproj
index 2a96171..9b2c06a 100644
--- a/BlockInjectionTest/BlockInjectionTest.xcodeproj/project.pbxproj
+++ b/BlockInjectionTest/BlockInjectionTest.xcodeproj/project.pbxproj
@@ -20,6 +20,7 @@
 		06584EF016DEFC8D00CB2D68 /* BILib.m in Sources */ = {isa = PBXBuildFile; fileRef = 06584EEB16DEFAF800CB2D68 /* BILib.m */; };
 		0685AD0A170DCB8D0082AD69 /* SkippingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0685AD09170DCB8D0082AD69 /* SkippingTest.m */; };
 		06941C1016E7344800EDAA36 /* BILibArg.m in Sources */ = {isa = PBXBuildFile; fileRef = 06941C0F16E7344800EDAA36 /* BILibArg.m */; };
+		06BC319917117EBD0017A9CF /* ReturnValueTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 06BC319817117EBD0017A9CF /* ReturnValueTest.m */; };
 /* End PBXBuildFile section */

 /* Begin PBXFileReference section */
@@ -49,6 +50,8 @@
 		0685AD09170DCB8D0082AD69 /* SkippingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SkippingTest.m; sourceTree = "<group>"; };
 		06941C0E16E7344800EDAA36 /* BILibArg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BILibArg.h; sourceTree = "<group>"; };
 		06941C0F16E7344800EDAA36 /* BILibArg.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BILibArg.m; sourceTree = "<group>"; };
+		06BC319717117EBD0017A9CF /* ReturnValueTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReturnValueTest.h; sourceTree = "<group>"; };
+		06BC319817117EBD0017A9CF /* ReturnValueTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReturnValueTest.m; sourceTree = "<group>"; };
 /* End PBXFileReference section */

 /* Begin PBXFrameworksBuildPhase section */
@@ -107,6 +110,8 @@
 				06162C1216FF350900213ACD /* RegexTest.m */,
 				0685AD08170DCB8D0082AD69 /* SkippingTest.h */,
 				0685AD09170DCB8D0082AD69 /* SkippingTest.m */,
+				06BC319717117EBD0017A9CF /* ReturnValueTest.h */,
+				06BC319817117EBD0017A9CF /* ReturnValueTest.m */,
 				06584ED716DEFA6000CB2D68 /* Supporting Files */,
 			);
 			path = BlockInjectionTests;
@@ -226,6 +231,7 @@
 				06162C1016FDECB000213ACD /* ReplaceTest.m in Sources */,
 				06162C1316FF350900213ACD /* RegexTest.m in Sources */,
 				0685AD0A170DCB8D0082AD69 /* SkippingTest.m in Sources */,
+				06BC319917117EBD0017A9CF /* ReturnValueTest.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/BlockInjectionTest/BlockInjectionTests/ReturnValueTest.h b/BlockInjectionTest/BlockInjectionTests/ReturnValueTest.h
new file mode 100644
index 0000000..cf650bc
--- /dev/null
+++ b/BlockInjectionTest/BlockInjectionTests/ReturnValueTest.h
@@ -0,0 +1,13 @@
+//
+//  ReturnValueTest.h
+//  BlockInjectionTest
+//
+//  Created by ytokoro on 4/7/13.
+//  Copyright (c) 2013 tokorom. All rights reserved.
+//
+
+#import <SenTestingKit/SenTestingKit.h>
+
+@interface ReturnValueTest : SenTestCase
+
+@end
diff --git a/BlockInjectionTest/BlockInjectionTests/ReturnValueTest.m b/BlockInjectionTest/BlockInjectionTests/ReturnValueTest.m
new file mode 100644
index 0000000..35d8fd9
--- /dev/null
+++ b/BlockInjectionTest/BlockInjectionTests/ReturnValueTest.m
@@ -0,0 +1,105 @@
+//
+//  ReturnValueTest.m
+//  BlockInjectionTest
+//
+//  Created by ytokoro on 4/7/13.
+//  Copyright (c) 2013 tokorom. All rights reserved.
+//
+
+#import "ReturnValueTest.h"
+#import "BILib.h"
+
+@implementation ReturnValueTest
+
+- (void)setUp
+{
+  [super setUp];
+  [BILib clear];
+}
+
+- (void)tearDown
+{
+  [super tearDown];
+}
+
+- (void)testReturnBool
+{
+  __block BOOL success = NO;
+  [BILib injectToClassWithName:@"UIView" methodName:@"isHidden" preprocess:^(UIView* view){
+    if ([view isKindOfClass:[UIView class]]) {
+      success = YES;
+    }
+  }];
+
+  UIView* view = [UIView new];
+  view.hidden = YES;
+
+  BOOL isHidden = view.isHidden;
+
+  STAssertTrue(success, @"success is invalid.");
+  STAssertTrue(isHidden, @"isHidden is invalid.");
+}
+
+- (void)testReturnInt
+{
+  __block BOOL success = NO;
+  [BILib injectToClassWithName:@"UIView" methodName:@"tag" preprocess:^(UIView* view){
+    if ([view isKindOfClass:[UIView class]]) {
+      success = YES;
+    }
+  }];
+
+  UIView* view = [UIView new];
+  view.tag = 5;
+
+  int tag = view.tag;
+
+  STAssertTrue(success, @"success is invalid.");
+  STAssertEquals(tag, (int)5, @"tag is invalid.");
+}
+
+- (void)testReturnId
+{
+  __block BOOL success = NO;
+  [BILib injectToClassWithName:@"UIView" methodName:@"backgroundColor" preprocess:^(UIView* view){
+    if ([view isKindOfClass:[UIView class]]) {
+      success = YES;
+    }
+  }];
+
+  UIView* view = [UIView new];
+  view.backgroundColor = [UIColor redColor];
+
+  UIColor* color = view.backgroundColor;
+
+  STAssertTrue(success, @"success is invalid.");
+
+  CGFloat r1, r2, g1, g2, b1, b2, a1, a2;
+  [color getRed:&r1 green:&g1 blue:&b1 alpha:&a1];
+  [[UIColor redColor] getRed:&r2 green:&g2 blue:&b2 alpha:&a2];
+
+  STAssertEquals(r1, r2, @"r is invalid.");
+  STAssertEquals(g1, g2, @"g is invalid.");
+  STAssertEquals(b1, b2, @"b is invalid.");
+  STAssertEquals(a1, a2, @"a is invalid.");
+}
+
+- (void)testReturnCGFloat
+{
+  __block BOOL success = NO;
+  [BILib injectToClassWithName:@"UIView" methodName:@"alpha" preprocess:^(UIView* view){
+    if ([view isKindOfClass:[UIView class]]) {
+      success = YES;
+    }
+  }];
+
+  UIView* view = [UIView new];
+  view.alpha = 0.8;
+
+  CGFloat alpha = view.alpha;
+
+  STAssertTrue(success, @"success is invalid.");
+  STAssertEquals(alpha, (CGFloat)0.8, @"alpha is invalid.");
+}
+
+@end
[from now] 2013/04/08 00:16:27

diff --git a/BlockInjection/BILib.m b/BlockInjection/BILib.m
index 124b137..7daed2e 100644
--- a/BlockInjection/BILib.m
+++ b/BlockInjection/BILib.m
@@ -258,21 +258,38 @@
     id replaceBlock;
     const char* returnType = [item.signature methodReturnType];
   NSLog(@"##### returnType: %s", returnType);
-    if (NULL == returnType || 0 == strlen(returnType) || 'v' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR_VOID; }
-    else if ('c' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(char); }
-    else if ('i' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(int); }
-    else if ('s' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(short); }
-    else if ('l' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(long); }
-    else if ('q' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(long long); }
-    else if ('C' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(unsigned char); }
-    else if ('I' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(unsigned int); }
-    else if ('S' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(unsigned short); }
-    else if ('L' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(unsigned long); }
-    else if ('Q' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(unsigned long long); }
-    else if ('f' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(float); }
-    else if ('d' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(double); }
-    else if ('B' == returnType[0]) { replaceBlock = REPLACEBLOCK_FOR(bool); }
-    else { replaceBlock = REPLACEBLOCK_FOR(int); }
+    if (NULL == returnType || 0 == strlen(returnType)) {
+      replaceBlock = REPLACEBLOCK_FOR_VOID;
+    } else {
+      char prefix = returnType[0];
+      char type = returnType[strlen(returnType) - 1];
+      if ('^' == prefix || '{' == prefix) {
+        type = prefix;
+      }
+      switch (type) {
+        case 'v': { replaceBlock = REPLACEBLOCK_FOR_VOID; } break;
+        //case 'c': { replaceBlock = REPLACEBLOCK_FOR(char); } break;
+        //case 'i': { replaceBlock = REPLACEBLOCK_FOR(int); } break;
+        //case 's': { replaceBlock = REPLACEBLOCK_FOR(short); } break;
+        //case 'l': { replaceBlock = REPLACEBLOCK_FOR(long); } break;
+        //case 'q': { replaceBlock = REPLACEBLOCK_FOR(long long); } break;
+        //case 'C': { replaceBlock = REPLACEBLOCK_FOR(unsigned char); } break;
+        //case 'I': { replaceBlock = REPLACEBLOCK_FOR(unsigned int); } break;
+        //case 'S': { replaceBlock = REPLACEBLOCK_FOR(unsigned short); } break;
+        //case 'L': { replaceBlock = REPLACEBLOCK_FOR(unsigned long); } break;
+        //case 'Q': { replaceBlock = REPLACEBLOCK_FOR(unsigned long long); } break;
+        case 'f': { replaceBlock = REPLACEBLOCK_FOR(float); } break;
+        case 'd': { replaceBlock = REPLACEBLOCK_FOR(double); } break;
+        //case 'B': { replaceBlock = REPLACEBLOCK_FOR(bool); } break;
+        //case '*': { replaceBlock = REPLACEBLOCK_FOR(void*); } break;
+        //case '@': { replaceBlock = REPLACEBLOCK_FOR(void*); } break;
+        //case '#': { replaceBlock = REPLACEBLOCK_FOR(Class); } break;
+        //case ':': { replaceBlock = REPLACEBLOCK_FOR(SEL); } break;
+        case '{': { replaceBlock = REPLACEBLOCK_FOR(CGRect); } break;
+        //case '^': { replaceBlock = REPLACEBLOCK_FOR(int*); } break;
+        default: { replaceBlock = REPLACEBLOCK_FOR(int); } break;
+      }
+    }

     /*
     NSGetSizeAndAlignment(returnType, &returnLength, &alignment);
diff --git a/BlockInjectionTest/BlockInjectionTests/ReturnValueTest.m b/BlockInjectionTest/BlockInjectionTests/ReturnValueTest.m
index 35d8fd9..1569fd5 100644
--- a/BlockInjectionTest/BlockInjectionTests/ReturnValueTest.m
+++ b/BlockInjectionTest/BlockInjectionTests/ReturnValueTest.m
@@ -9,6 +9,42 @@
 #import "ReturnValueTest.h"
 #import "BILib.h"

+static int ia[2] = {1, 2};
+
+#pragma mark - ClassForReturnValue
+
+@interface ClassForReturnValue : NSObject
+@end
+
+@implementation ClassForReturnValue
+- (const int)ci {
+  return 100;
+}
+- (const char*)constChars {
+  return "ci";
+}
+- (double)doubleValue {
+  return 99.99;
+}
+- (bool)boolValue {
+  return true;
+}
+- (char)charValue {
+  return 'c';
+}
+- (int*)arrayValue {
+  return ia;
+}
+- (Class)classValue {
+  return NSClassFromString(@"UIView");
+}
+- (SEL)selValue {
+  return @selector(tag);
+}
+@end
+
+#pragma mark - Private Methods
+
 @implementation ReturnValueTest

 - (void)setUp
@@ -102,4 +138,149 @@
   STAssertEquals(alpha, (CGFloat)0.8, @"alpha is invalid.");
 }

+- (void)testReturnConstInt
+{
+  __block BOOL success = NO;
+  [BILib injectToClassWithName:@"ClassForReturnValue" methodName:@"ci" preprocess:^(id target){
+    if ([target isKindOfClass:[ClassForReturnValue class]]) {
+      success = YES;
+    }
+  }];
+
+  const int ret = [[ClassForReturnValue new] ci];
+
+  STAssertTrue(success, @"success is invalid.");
+  STAssertEquals(ret, (const int)100, @"ret is invalid.");
+}
+
+- (void)testReturnConstChars
+{
+  __block BOOL success = NO;
+  [BILib injectToClassWithName:@"ClassForReturnValue" methodName:@"constChars" preprocess:^(id target){
+    if ([target isKindOfClass:[ClassForReturnValue class]]) {
+      success = YES;
+    }
+  }];
+
+  const char* ret = [[ClassForReturnValue new] constChars];
+
+  STAssertTrue(success, @"success is invalid.");
+  STAssertEquals(ret[0], (char)'c', @"ret is invalid.");
+  STAssertEquals(ret[1], (char)'i', @"ret is invalid.");
+}
+
+- (void)testReturnDouble
+{
+  __block BOOL success = NO;
+  [BILib injectToClassWithName:@"ClassForReturnValue" methodName:@"doubleValue" preprocess:^(id target){
+    if ([target isKindOfClass:[ClassForReturnValue class]]) {
+      success = YES;
+    }
+  }];
+
+  double ret = [[ClassForReturnValue new] doubleValue];
+
+  STAssertTrue(success, @"success is invalid.");
+  STAssertEquals(ret, (double)99.99, @"ret is invalid.");
+}
+
+- (void)testReturnCppBool
+{
+  __block BOOL success = NO;
+  [BILib injectToClassWithName:@"ClassForReturnValue" methodName:@"boolValue" preprocess:^(id target){
+    if ([target isKindOfClass:[ClassForReturnValue class]]) {
+      success = YES;
+    }
+  }];
+
+  bool ret = [[ClassForReturnValue new] boolValue];
+
+  STAssertTrue(success, @"success is invalid.");
+  STAssertEquals(ret, (bool)true, @"ret is invalid.");
+}
+
+- (void)testReturnChar
+{
+  __block BOOL success = NO;
+  [BILib injectToClassWithName:@"ClassForReturnValue" methodName:@"charValue" preprocess:^(id target){
+    if ([target isKindOfClass:[ClassForReturnValue class]]) {
+      success = YES;
+    }
+  }];
+
+  char ret = [[ClassForReturnValue new] charValue];
+
+  STAssertTrue(success, @"success is invalid.");
+  STAssertEquals(ret, (char)'c', @"ret is invalid.");
+}
+
+- (void)testReturnArray
+{
+  __block BOOL success = NO;
+  [BILib injectToClassWithName:@"ClassForReturnValue" methodName:@"arrayValue" preprocess:^(id target){
+    if ([target isKindOfClass:[ClassForReturnValue class]]) {
+      success = YES;
+    }
+  }];
+
+  int* ret = [[ClassForReturnValue new] arrayValue];
+
+  STAssertTrue(success, @"success is invalid.");
+  STAssertEquals(ret[0], (int)1, @"ret is invalid.");
+  STAssertEquals(ret[1], (int)2, @"ret is invalid.");
+}
+
+- (void)testReturnClass
+{
+  __block BOOL success = NO;
+  [BILib injectToClassWithName:@"ClassForReturnValue" methodName:@"classValue" preprocess:^(id target){
+    if ([target isKindOfClass:[ClassForReturnValue class]]) {
+      success = YES;
+    }
+  }];
+
+  Class ret = [[ClassForReturnValue new] classValue];
+
+  STAssertTrue(success, @"success is invalid.");
+  STAssertTrue([@"UIView" isEqualToString:NSStringFromClass(ret)], @"ret is invalid.");
+}
+
+- (void)testReturnSelector
+{
+  __block BOOL success = NO;
+  [BILib injectToClassWithName:@"ClassForReturnValue" methodName:@"selValue" preprocess:^(id target){
+    if ([target isKindOfClass:[ClassForReturnValue class]]) {
+      success = YES;
+    }
+  }];
+
+  SEL ret = [[ClassForReturnValue new] selValue];
+
+  STAssertTrue(success, @"success is invalid.");
+  STAssertTrue([@"tag" isEqualToString:NSStringFromSelector(ret)], @"ret is invalid.");
+}
+
+- (void)testReturnCGRect
+{
+  __block BOOL success = NO;
+  [BILib injectToClassWithName:@"UIView" methodName:@"frame" preprocess:^(UIView* view){
+    if ([view isKindOfClass:[UIView class]]) {
+      success = YES;
+    }
+    return CGRectMake(0,0,0,0);
+  }];
+
+  UIView* view = [UIView new];
+  view.frame = CGRectMake(1.0, 2.0, 3.0, 4.0);
+
+  CGRect frame = view.frame;
+
+  STAssertTrue(success, @"success is invalid.");
+
+  STAssertEquals(frame.origin.x, (CGFloat)1.0, @"x is invalid.");
+  STAssertEquals(frame.origin.y, (CGFloat)2.0, @"y is invalid.");
+  STAssertEquals(frame.size.width, (CGFloat)3.0, @"w is invalid.");
+  STAssertEquals(frame.size.height, (CGFloat)4.0, @"h is invalid.");
+}
+
 @end
[from now] 2013/04/08 00:16:39

diff --git a/BlockInjection/BILib.m b/BlockInjection/BILib.m
index 7daed2e..7327fad 100644
--- a/BlockInjection/BILib.m
+++ b/BlockInjection/BILib.m
@@ -290,28 +290,6 @@
         default: { replaceBlock = REPLACEBLOCK_FOR(int); } break;
       }
     }
-
-    /*
-    NSGetSizeAndAlignment(returnType, &returnLength, &alignment);
-    NSLog(@"##### %s : %d", returnType, returnLength);
-    switch (returnLength) {
-      case 0: { replaceBlock = ^(id target, ...){
-        [[BIItemManager sharedInstance] setCurrentItem:item];
-        va_list argp;
-        va_start(argp, target);
-        [item invokeWithTarget:target args:&argp];
-        va_end(argp);
-      }; } break;
-      default: { replaceBlock = ^(id target, ...){
-        [[BIItemManager sharedInstance] setCurrentItem:item];
-        va_list argp;
-        va_start(argp, target);
-        void* retp = [item invokeWithTarget:target args:&argp];
-        va_end(argp);
-        return *(int*)retp;
-      }; } break;
-    }
-    */
     method_setImplementation(item.originalMethod, imp_implementationWithBlock(replaceBlock));
   }
 }
[from now] 2013/04/08 01:41:12

diff --git a/BlockInjection/BIItem.m b/BlockInjection/BIItem.m
index 4d7ef84..0761225 100644
--- a/BlockInjection/BIItem.m
+++ b/BlockInjection/BIItem.m
@@ -80,8 +80,7 @@
   void* result = NULL;
   NSUInteger returnLength = [[invocation methodSignature] methodReturnLength];
   if (returnLength) {
-    //result = __builtin_alloca(returnLength);
-    result = malloc(returnLength);
+    result = __builtin_alloca(returnLength);
   }
   // Preprocess
   [self prepareWithInvocation:invocation];
diff --git a/BlockInjection/BILib.m b/BlockInjection/BILib.m
index 7327fad..8651020 100644
--- a/BlockInjection/BILib.m
+++ b/BlockInjection/BILib.m
@@ -8,6 +8,7 @@
 #import "BIItem.h"
 #import "BIItemManager.h"
 #import <objc/runtime.h>
+#import "BILibDummyStruct.h"

 #define REPLACEBLOCK_FOR_VOID \
   ^(id target, ...){ \
@@ -28,6 +29,34 @@
     return *(type*)retp; \
   }

+#define REPLACE_BLOCK_FOR_STRUCT_CASE(cas) case cas: return REPLACEBLOCK_FOR(BILibStruct##cas)
+
+#define EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(prf) \
+  REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 0); \
+  REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 1); \
+  REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 2); \
+  REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 3); \
+  REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 4); \
+  REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 5); \
+  REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 6); \
+  REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 7); \
+  REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 8); \
+  REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 9)
+
+#define EXPAND_EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(prf) \
+  EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 0); \
+  EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 1); \
+  EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 2); \
+  EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 3); \
+  EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 4); \
+  EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 5); \
+  EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 6); \
+  EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 7); \
+  EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 8); \
+  EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(prf ## 9)
+
+#pragma mark - BILib
+
 @implementation BILib

 #pragma mark - Public Interface
@@ -256,8 +285,8 @@
 {
   if (item.signature) {
     id replaceBlock;
+    NSUInteger returnLength = [item.signature methodReturnLength];
     const char* returnType = [item.signature methodReturnType];
-  NSLog(@"##### returnType: %s", returnType);
     if (NULL == returnType || 0 == strlen(returnType)) {
       replaceBlock = REPLACEBLOCK_FOR_VOID;
     } else {
@@ -285,7 +314,7 @@
         //case '@': { replaceBlock = REPLACEBLOCK_FOR(void*); } break;
         //case '#': { replaceBlock = REPLACEBLOCK_FOR(Class); } break;
         //case ':': { replaceBlock = REPLACEBLOCK_FOR(SEL); } break;
-        case '{': { replaceBlock = REPLACEBLOCK_FOR(CGRect); } break;
+        case '{': { replaceBlock = [BILib replaceBlockForStructWithSize:returnLength withItem:item]; } break;
         //case '^': { replaceBlock = REPLACEBLOCK_FOR(int*); } break;
         default: { replaceBlock = REPLACEBLOCK_FOR(int); } break;
       }
@@ -294,6 +323,41 @@
   }
 }

++ (id)replaceBlockForStructWithSize:(NSUInteger)size withItem:(BIItem*)item
+{
+  switch (size) {
+    REPLACE_BLOCK_FOR_STRUCT_CASE(1);
+    REPLACE_BLOCK_FOR_STRUCT_CASE(2);
+    REPLACE_BLOCK_FOR_STRUCT_CASE(3);
+    REPLACE_BLOCK_FOR_STRUCT_CASE(4);
+    REPLACE_BLOCK_FOR_STRUCT_CASE(5);
+    REPLACE_BLOCK_FOR_STRUCT_CASE(6);
+    REPLACE_BLOCK_FOR_STRUCT_CASE(7);
+    REPLACE_BLOCK_FOR_STRUCT_CASE(8);
+    REPLACE_BLOCK_FOR_STRUCT_CASE(9);
+    EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(1);
+    EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(2);
+    EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(3);
+    EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(4);
+    EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(5);
+    EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(6);
+    EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(7);
+    EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(8);
+    EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(9);
+    EXPAND_EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(1);
+    EXPAND_EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(2);
+    EXPAND_EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(3);
+    EXPAND_EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(4);
+    EXPAND_EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(5);
+    EXPAND_EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(6);
+    EXPAND_EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(7);
+    EXPAND_EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(8);
+    EXPAND_EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(9);
+    EXPAND_EXPAND_REPLACE_BLOCK_FOR_STRUCT_CASE(10);
+    default: return REPLACEBLOCK_FOR(int);
+  }
+}
+
 + (NSArray*)classesWithRegex:(NSRegularExpression*)regex
 {
   @autoreleasepool {
diff --git a/BlockInjection/BILibArg.m b/BlockInjection/BILibArg.m
index aed11b9..864b05b 100644
--- a/BlockInjection/BILibArg.m
+++ b/BlockInjection/BILibArg.m
@@ -5,68 +5,7 @@
 //

 #import "BILibArg.h"
-
-#define BILIBARG_STRUCT(siz) struct bilib_struct_##siz { char buff[siz]; }
-
-#define EXPAND_BITBARG_STRUCT(prf) \
-  BILIBARG_STRUCT(prf ## 00); \
-  BILIBARG_STRUCT(prf ## 04); \
-  BILIBARG_STRUCT(prf ## 08); \
-  BILIBARG_STRUCT(prf ## 12); \
-  BILIBARG_STRUCT(prf ## 16); \
-  BILIBARG_STRUCT(prf ## 20); \
-  BILIBARG_STRUCT(prf ## 24); \
-  BILIBARG_STRUCT(prf ## 28); \
-  BILIBARG_STRUCT(prf ## 32); \
-  BILIBARG_STRUCT(prf ## 36); \
-  BILIBARG_STRUCT(prf ## 40); \
-  BILIBARG_STRUCT(prf ## 44); \
-  BILIBARG_STRUCT(prf ## 48); \
-  BILIBARG_STRUCT(prf ## 52); \
-  BILIBARG_STRUCT(prf ## 56); \
-  BILIBARG_STRUCT(prf ## 60); \
-  BILIBARG_STRUCT(prf ## 64); \
-  BILIBARG_STRUCT(prf ## 68); \
-  BILIBARG_STRUCT(prf ## 72); \
-  BILIBARG_STRUCT(prf ## 76); \
-  BILIBARG_STRUCT(prf ## 80); \
-  BILIBARG_STRUCT(prf ## 84); \
-  BILIBARG_STRUCT(prf ## 88); \
-  BILIBARG_STRUCT(prf ## 92); \
-  BILIBARG_STRUCT(prf ## 96)
-
-BILIBARG_STRUCT(12);
-BILIBARG_STRUCT(16);
-BILIBARG_STRUCT(20);
-BILIBARG_STRUCT(24);
-BILIBARG_STRUCT(28);
-BILIBARG_STRUCT(32);
-BILIBARG_STRUCT(36);
-BILIBARG_STRUCT(40);
-BILIBARG_STRUCT(44);
-BILIBARG_STRUCT(48);
-BILIBARG_STRUCT(52);
-BILIBARG_STRUCT(56);
-BILIBARG_STRUCT(60);
-BILIBARG_STRUCT(64);
-BILIBARG_STRUCT(68);
-BILIBARG_STRUCT(72);
-BILIBARG_STRUCT(76);
-BILIBARG_STRUCT(80);
-BILIBARG_STRUCT(84);
-BILIBARG_STRUCT(88);
-BILIBARG_STRUCT(92);
-BILIBARG_STRUCT(96);
-EXPAND_BITBARG_STRUCT(1);
-EXPAND_BITBARG_STRUCT(2);
-EXPAND_BITBARG_STRUCT(3);
-EXPAND_BITBARG_STRUCT(4);
-EXPAND_BITBARG_STRUCT(5);
-EXPAND_BITBARG_STRUCT(6);
-EXPAND_BITBARG_STRUCT(7);
-EXPAND_BITBARG_STRUCT(8);
-EXPAND_BITBARG_STRUCT(9);
-EXPAND_BITBARG_STRUCT(10);
+#import "BILibDummyStruct.h"

 #define ELSE_BILIBARG(siz) } else if (siz >= size) { \
   struct bilib_struct_##siz arg = va_arg(*pargp, struct bilib_struct_##siz); \
diff --git a/BlockInjection/BILibDummyStruct.h b/BlockInjection/BILibDummyStruct.h
new file mode 100644
index 0000000..340b41f
--- /dev/null
+++ b/BlockInjection/BILibDummyStruct.h
@@ -0,0 +1,62 @@
+//
+//  BILibDummyStruct.h
+//
+//  Created by ToKoRo on 2013-04-08.
+//
+
+#define BILIB_STRUCT_DECLARATION(siz) typedef struct bilib_struct_##siz { char buff[siz]; } BILibStruct##siz
+
+#define EXPAND_BITBARG_STRUCT(prf) \
+  BILIB_STRUCT_DECLARATION(prf ## 0); \
+  BILIB_STRUCT_DECLARATION(prf ## 1); \
+  BILIB_STRUCT_DECLARATION(prf ## 2); \
+  BILIB_STRUCT_DECLARATION(prf ## 3); \
+  BILIB_STRUCT_DECLARATION(prf ## 4); \
+  BILIB_STRUCT_DECLARATION(prf ## 5); \
+  BILIB_STRUCT_DECLARATION(prf ## 6); \
+  BILIB_STRUCT_DECLARATION(prf ## 7); \
+  BILIB_STRUCT_DECLARATION(prf ## 8); \
+  BILIB_STRUCT_DECLARATION(prf ## 9)
+
+#define EXPAND_EXPAND_BITBARG_STRUCT(prf) \
+  EXPAND_BITBARG_STRUCT(prf ## 0); \
+  EXPAND_BITBARG_STRUCT(prf ## 1); \
+  EXPAND_BITBARG_STRUCT(prf ## 2); \
+  EXPAND_BITBARG_STRUCT(prf ## 3); \
+  EXPAND_BITBARG_STRUCT(prf ## 4); \
+  EXPAND_BITBARG_STRUCT(prf ## 5); \
+  EXPAND_BITBARG_STRUCT(prf ## 6); \
+  EXPAND_BITBARG_STRUCT(prf ## 7); \
+  EXPAND_BITBARG_STRUCT(prf ## 8); \
+  EXPAND_BITBARG_STRUCT(prf ## 9)
+
+BILIB_STRUCT_DECLARATION(1);
+BILIB_STRUCT_DECLARATION(2);
+BILIB_STRUCT_DECLARATION(3);
+BILIB_STRUCT_DECLARATION(4);
+BILIB_STRUCT_DECLARATION(5);
+BILIB_STRUCT_DECLARATION(6);
+BILIB_STRUCT_DECLARATION(7);
+BILIB_STRUCT_DECLARATION(8);
+BILIB_STRUCT_DECLARATION(9);
+
+EXPAND_BITBARG_STRUCT(1);
+EXPAND_BITBARG_STRUCT(2);
+EXPAND_BITBARG_STRUCT(3);
+EXPAND_BITBARG_STRUCT(4);
+EXPAND_BITBARG_STRUCT(5);
+EXPAND_BITBARG_STRUCT(6);
+EXPAND_BITBARG_STRUCT(7);
+EXPAND_BITBARG_STRUCT(8);
+EXPAND_BITBARG_STRUCT(9);
+
+EXPAND_EXPAND_BITBARG_STRUCT(1);
+EXPAND_EXPAND_BITBARG_STRUCT(2);
+EXPAND_EXPAND_BITBARG_STRUCT(3);
+EXPAND_EXPAND_BITBARG_STRUCT(4);
+EXPAND_EXPAND_BITBARG_STRUCT(5);
+EXPAND_EXPAND_BITBARG_STRUCT(6);
+EXPAND_EXPAND_BITBARG_STRUCT(7);
+EXPAND_EXPAND_BITBARG_STRUCT(8);
+EXPAND_EXPAND_BITBARG_STRUCT(9);
+EXPAND_EXPAND_BITBARG_STRUCT(10);
diff --git a/BlockInjectionTest/BlockInjectionTests/ReturnValueTest.m b/BlockInjectionTest/BlockInjectionTests/ReturnValueTest.m
index 1569fd5..bd13fac 100644
--- a/BlockInjectionTest/BlockInjectionTests/ReturnValueTest.m
+++ b/BlockInjectionTest/BlockInjectionTests/ReturnValueTest.m
@@ -11,6 +11,12 @@

 static int ia[2] = {1, 2};

+struct ReturnValueBigStruct {
+  char buff[500];
+  CGFloat f;
+  char buff2[500];
+};
+
 #pragma mark - ClassForReturnValue

 @interface ClassForReturnValue : NSObject
@@ -41,6 +47,11 @@ static int ia[2] = {1, 2};
 - (SEL)selValue {
   return @selector(tag);
 }
+- (struct ReturnValueBigStruct)bigStructValue {
+  struct ReturnValueBigStruct bigStruct;
+  bigStruct.f = 0.255;
+  return bigStruct;
+}
 @end

 #pragma mark - Private Methods
@@ -283,4 +294,42 @@ static int ia[2] = {1, 2};
   STAssertEquals(frame.size.height, (CGFloat)4.0, @"h is invalid.");
 }

+- (void)testReturnCGPoint
+{
+  __block BOOL success = NO;
+  [BILib injectToClassWithName:@"UIView" methodName:@"center" preprocess:^(UIView* view){
+    if ([view isKindOfClass:[UIView class]]) {
+      success = YES;
+    }
+    return CGPointMake(0,0);
+  }];
+
+  UIView* view = [UIView new];
+  view.center = CGPointMake(1.0, 2.0);
+
+  CGPoint center = view.center;
+
+  STAssertTrue(success, @"success is invalid.");
+
+  STAssertEquals(center.x, (CGFloat)1.0, @"x is invalid.");
+  STAssertEquals(center.y, (CGFloat)2.0, @"y is invalid.");
+}
+
+- (void)testReturnBigStruct
+{
+  __block BOOL success = NO;
+  [BILib injectToClassWithName:@"ClassForReturnValue" methodName:@"bigStructValue" preprocess:^(id target){
+    if ([target isKindOfClass:[ClassForReturnValue class]]) {
+      success = YES;
+    }
+    struct ReturnValueBigStruct st;
+    return st;
+  }];
+
+  struct ReturnValueBigStruct ret = [[ClassForReturnValue new] bigStructValue];
+
+  STAssertTrue(success, @"success is invalid.");
+  STAssertEquals(ret.f, (CGFloat)0.255, @"ret is invalid.");
+}
+
 @end
Fix #9 Support most return value type
Merge pull request #10 from tokorom/t9-fix

Fix #9 Support most return value type