blob: d2b52caa885bff6f95ce7ab64f1ec442e2ee402c [file] [log] [blame]
//
// GTMSignalHandlerTest.m
//
// Copyright 2008 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
//
#import "GTMSenTestCase.h"
#import "GTMSignalHandler.h"
#pragma clang diagnostic push
// Ignore all of the deprecation warnings for GTMRegex
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
@interface GTMSignalHandlerTest : GTMTestCase
@end
@interface SignalCounter : NSObject {
int signalCount_;
int lastSeenSignal_;
}
- (int)count;
- (int)lastSeen;
- (void)countSignal:(int)signo;
+ (id)signalCounter;
@end // SignalCounter
@implementation SignalCounter
+ (id)signalCounter {
return [[[self alloc] init] autorelease];
}
- (int)count {
return signalCount_;
}
- (int)lastSeen {
return lastSeenSignal_;
}
// Count the number of times this signal handler has fired.
- (void)countSignal:(int)signo {
signalCount_++;
lastSeenSignal_ = signo;
}
@end
@implementation GTMSignalHandlerTest
- (void)nomnomnom:(int)blah {
XCTFail(@"Should never be called!");
}
- (void)testNillage {
GTMSignalHandler *handler;
// Just an init should return nil.
handler = [[[GTMSignalHandler alloc] init] autorelease];
XCTAssertNil(handler);
// Zero signal should return nil as well.
handler = [[[GTMSignalHandler alloc]
initWithSignal:0
target:self
action:@selector(nomnomnom:)] autorelease];
XCTAssertNil(handler);
}
- (void)testSingleHandler {
// SIGIO and SIGWINCH were chosen for this test because LLDB does not trap
// them which allows you to run this test under the debugger.
// If you need to use other signals and the debugger is getting annoying
// https://stackoverflow.com/questions/11984051/how-to-tell-lldb-debugger-not-to-handle-sigbus
SignalCounter *counter = [SignalCounter signalCounter];
// Raising our signals off of a background queue becuase raising them
// off of dispatch_main_queue does not work with a CFRunLoop.
// https://openradar.appspot.com/radar?id=5030997057863680
dispatch_queue_t raiseQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
const int deltaT = 5000000;
XCTAssertNotNil(counter);
GTMSignalHandler *handler = [[[GTMSignalHandler alloc]
initWithSignal:SIGWINCH
target:counter
action:@selector(countSignal:)]
autorelease];
XCTAssertNotNil(handler);
[self expectationForPredicate:
[NSPredicate predicateWithFormat:@"self.lastSeen == %d", SIGWINCH]
evaluatedWithObject:counter handler:NULL];
[self expectationForPredicate:
[NSPredicate predicateWithFormat:@"self.count == 1"]
evaluatedWithObject:counter handler:NULL];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, deltaT), raiseQueue, ^{
// Using dispatch_after to make sure our signal is sent AFTER the runloop
// is being spun in waitForExpectationsWithTimeout.
raise(SIGWINCH);
});
[self waitForExpectationsWithTimeout:5 handler:NULL];
[self expectationForPredicate:
[NSPredicate predicateWithFormat:@"self.lastSeen == %d", SIGWINCH]
evaluatedWithObject:counter handler:NULL];
[self expectationForPredicate:
[NSPredicate predicateWithFormat:@"self.count == 2"]
evaluatedWithObject:counter handler:NULL];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, deltaT), raiseQueue, ^{
raise(SIGWINCH);
});
[self waitForExpectationsWithTimeout:5 handler:NULL];
// create a second one to make sure we're sending data where we want
SignalCounter *counter2 = [SignalCounter signalCounter];
XCTAssertNotNil(counter2);
[[[GTMSignalHandler alloc] initWithSignal:SIGIO
target:counter2
action:@selector(countSignal:)] autorelease];
[self expectationForPredicate:
[NSPredicate predicateWithFormat:@"self.lastSeen == %d", SIGIO]
evaluatedWithObject:counter2 handler:NULL];
[self expectationForPredicate:
[NSPredicate predicateWithFormat:@"self.count == 1"]
evaluatedWithObject:counter2 handler:NULL];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, deltaT), raiseQueue, ^{
raise(SIGIO);
});
[self waitForExpectationsWithTimeout:5 handler:NULL];
XCTAssertEqual([counter count], 2);
XCTAssertEqual([counter lastSeen], SIGWINCH);
[handler invalidate];
// The signal is still ignored (so we shouldn't die), but the
// the handler method should not get called.
[self expectationForPredicate:
[NSPredicate predicateWithFormat:@"self.lastSeen == %d", SIGWINCH]
evaluatedWithObject:counter handler:NULL].inverted = YES;
[self expectationForPredicate:
[NSPredicate predicateWithFormat:@"self.count == 2"]
evaluatedWithObject:counter handler:NULL].inverted = YES;
raise(SIGWINCH);
[self waitForExpectationsWithTimeout:.2 handler:NULL];
}
- (void)testIgnore {
SignalCounter *counter = [SignalCounter signalCounter];
XCTAssertNotNil(counter);
[[[GTMSignalHandler alloc] initWithSignal:SIGIO
target:counter
action:NULL] autorelease];
[self expectationForPredicate:
[NSPredicate predicateWithFormat:@"self.count == 0"]
evaluatedWithObject:counter handler:NULL].inverted = YES;
raise(SIGIO);
[self waitForExpectationsWithTimeout:.2 handler:NULL];
}
@end
#pragma clang diagnostic pop