I am using XCTest to do unit test of some c++/OC mixed codes. I found it seems that XCTAssertThrows cannot catch c++ exception?
My usage is very simple
say, an expression like in c++ test()
XCTAssertThrows(test(), "has throws")
Any suggestion?
Short Answer: wrap it by yourself
Long Answer: you can wrap an NSException for any std::exception, like this
#import <XCTest/XCTest.h>
#import <exception>
#interface NSException (ForCppException)
#end
#implementation NSException (ForCppException)
- (id)initWithCppException:(std::exception)cppException
{
NSString* description = [NSString stringWithUTF8String:cppException.what()];
return [self initWithName:#"cppException" reason:description userInfo:nil];
}
#end
#interface XCTestCase (ForCppException)
#end
#implementation XCTestCase (ForCppException)
- (void)rethowNSExceptionForCppException:(void(^)())action {
try {
action();
} catch (const std::exception& e) {
#throw [[NSException alloc] initWithCppException:e];
}
}
#end
#define XCTAssertCppThrows(expression, format...) \
XCTAssertThrows([self rethowNSExceptionForCppException:^{expression;}], ## format)
Use it like this:
#pragma mark - test
void foo() {
throw std::exception();
}
void bar() {
}
#interface testTests : XCTestCase
#end
#implementation testTests
- (void)testExample
{
XCTAssertCppThrows(foo(), #"should thow exception"); // succeed
XCTAssertCppThrows(bar(), #"should thow exception"); // failed
}
#end
Related
I have an issue when implementing OpenCV's K-Nearest to Objective-C++
Below is my sample code for implementation:
BridgeClass.h
#ifndef BridgeClass_h
#define BridgeClass_h
#include <Foundation/Foundation.h>
#interface BridgeClass : NSObject
- (void)testFunction;
#end
#endif
BridgeClass.mm
using namespace ml;
typedef KNearest KNN;
#implementation BridgeClass{
KNN* kNearest;
}
- (id) init {
self = [super init];
if (self) {
kNearest = KNN::create();
}
return self;
}
- (void) testFunction {
BOOL test = kNearest->isTrained();
NSLog(#"Test: %d", test);
}
But when I called testFunction, it shows error:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x400000048)
What is the problem with my implementation?
Assume that I want to skip one level in call super.viewDidLoad(), for example. So I wish to be able to do something like this:
override func viewDidLoad() {
super.super.viewDidLoad()
}
or
-(void)viewDidLoad {
[[super super] viewDidLoad];
}
This code will not compile. Is this possible by some other solution?
For expository purposes only, the following code does as requested. It only fails to crash when compiled without ARC, which means it has a bug in it. It does no error checking.
Never use this code unless you are playing around and trying to learn.
#import Foundation;
#import <objc/runtime.h>
#import <objc/message.h>
#interface M : NSObject
- (void)print;
#end
#implementation M
- (void)print { NSLog(#"M"); }
#end
#interface N : M
#end
#implementation N
- (void)print { NSLog(#"N"); }
#end
#interface O : N
#end
#implementation O
- (void)print {
Class mysupersuper = [[self superclass] superclass];
Method supersuperMethod = class_getInstanceMethod(mysupersuper, _cmd);
method_invoke(self, supersuperMethod);
}
#end
int main(int argc, char **argv)
{
O *o = O.new;
[o print];
return 0;
}
I compiled it using the command: clang -framework Foundation -fno-objc-arc -fmodules test.m.
Here is what you could do in Swift. Suppose you have classes A and B:
class A
{
func fun() { print("called fun() in A") }
}
class B : A
{
override func fun() { print("called fun() in B") }
}
You can't modify their definitions, but want to call fun() from A in a class C derived from B. You could do that as follows:
extension B
{
func funInA()
{
super.fun()
}
}
class C : B
{
override func fun() { funInA() }
}
I think you can pull off something like this in Objective-C using categories.
I need to call from the category a concrete implementation of the method (even if it's overridden). Is it possible? (Just in case: I know, all methods in Objective-C are virtual.)
// class A
#interface A
- (void)foo;
#end
#implementation A
- (void)foo
{
NSLog(#"initial foo");
}
#end
// subclass of A
#interface A1: A
#end
#implementation A1
- (void)foo
{
NSLog(#"overridden foo");
}
#end
// category to A
#interface A (Category)
- (void)bar;
#end
#impletemtation A (Category)
- (void)bar
{
[self foo]; // probably, I should specify here what exactly must be self
// but I don't know how
}
#end
/////////////////////////////////////////////////////////////////
A1 *a = [[A1 alloc] init];
[a bar]; // now the "overridden foo" string will be printed
// my goal is to print "initial foo" !!!
Of course, you do not have to change anything.
You can get a function pointer to the implementation of every method on a specific class:
A* receiver = …
IMP impOnA = class_getMethodImplementation( [A class], #selector( foo ));
((void (*)(id, SEL))impOnA)( receiver, #selector( foo ) ); // or whatever signature
You can adapt Matt Gallagher's supersequent implementation approach to find the specific method you want to invoke.
Alternatively, you could just set the class temporarily:
Class realClass = object_getClass(self);
Class fakeClass = [A class];
object_setClass(self, fakeClass);
[self foo];
object_setClass(self, realClass);
(I'm on my phone, so not 100% sure about the syntax, but the idea should work.)
Finally. indeed method swizzing works
#implementation A (Category)
- (void)quux
{
NSLog(#"quux");
}
- (void)bar
{
Class class = [A class];
SEL originalSelector = #selector(foo);
SEL swizzledSelector = #selector(quux);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
method_exchangeImplementations(originalMethod, swizzledMethod);
[self quux];
method_exchangeImplementations(originalMethod, swizzledMethod);
}
#end
This may solve your problem:
// class A
#interface A
- (void)foo;
#end
#implementation A
- (void)foo
{
[self fooImpl];
}
- (void)fooImpl
{
NSLog(#"initial foo");
}
#end
// subclass of A
#interface A1: A
#end
#implementation A1
- (void)foo
{
NSLog(#"overridden foo");
}
#end
// category to A
#interface A (Category)
- (void)bar;
#end
#impletemtation A (Category)
- (void)bar
{
[self fooImpl]; // probably, I should specify here what exactly must be self
// but I don't know how
}
#end
/////////////////////////////////////////////////////////////////
A1 *a = [[A1 alloc] init];
[a bar]; // now the "overridden foo" string will be printed
// my goal is to print "initial foo" !!!
I've dived into learning Objective-C and hit a little snag in when calling a method. Here's my simple code snippets:
Player.h code snippet:
#interface Player : NSObject{
}
-(void) performAction;
-(int) addNumber:(int) a toNumber:(int) b;
#end
Player.m code snippet:
#implementation Player
-(void)performAction{
NSLog(#"Here it is!");
}
-(int)addNumber:(int)a toNumber:(int)b{
return a+b;
}
#end
Calling method from main.m:
int val = [playerOne addNumber:(int)3 toNumber:(int)3];
In the above line of code, i keep getting an 'Expected expression' error.
Any ideas ?
This code works for me.
Player.h
#import <Foundation/Foundation.h>
#interface Player : NSObject
- (void)performAction;
- (int)addNumber:(int)a toNumber:(int)b;
#end
Player.m
#import "Player.h"
#implementation Player
- (void)performAction {
NSLog(#"Here it is!");
}
- (int)addNumber:(int)a toNumber:(int)b {
return a+b;
}
#end
main.m
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "Player.h"
int main(int argc, char *argv[])
{
#autoreleasepool {
Player *playerOne = [Player new];
int val = [playerOne addNumber:(int)3 toNumber:(int)3];
NSLog(#"%d", val);
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
In Objective-C, it is possible to pass a class as a parameter to a method:
- (void) methodThatTakesClass:(Class)theClass;
And it is possible to pass an instance that is conforming to a protocol as a parameter:
- (void) myConformInstance:(id <MyProtocol>)theObject;
Is it possible to use the combined functionality? A method which takes a class which is conforming to a certain protocol.
Yes. The following is a valid program which will log the NSObject class.
#import <Foundation/Foundation.h>
void f(Class <NSObject> c) {
NSLog(#"%#",c);
}
int main() {
f([NSObject class]);
}
This would cause a compiler error if you tried to pass a class which doesn't conform to NSObject, such as the Object class. You can also use it for methods.
- (void)printClass:(Class <NSObject>)c;
also valid:
#interface Something: Object {
}
- (void) foo:(int(*)(void))bar;
#end
#implementation Something
- (void) foo:(int(*)(void))bar {
return (*bar)();
}
#end
int someFunc( void ) {
return 9;
}
int main ( int argc, char **argv ) {
Something *object = [[Something alloc] init];
printf( "%i\n", [object foo:&someFunc] );
[object release];
return 0;
}