diff options
author | Thomas Van Lenten <thomasvl@google.com> | 2016-04-29 13:47:13 -0400 |
---|---|---|
committer | Thomas Van Lenten <thomasvl@google.com> | 2016-04-29 13:47:13 -0400 |
commit | 91fdd6d09d6390b67ff3258b6418437dca11d6e1 (patch) | |
tree | acf04a347085046a74a1ab14b8c1ee33b314b8fa /DebugUtils/GTMSynchronizationAssertsTest.m | |
parent | c485d79b9289a4f6ff1402babbf44b6fba0aa6e7 (diff) |
Add GTMSynchronizationAsserts.h/m and a unit test file.
These macros allow code to assert being in or not in a @sync-protected section,
which is important when calling across methods or calling out to other classes
or callbacks.
Diffstat (limited to 'DebugUtils/GTMSynchronizationAssertsTest.m')
-rw-r--r-- | DebugUtils/GTMSynchronizationAssertsTest.m | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/DebugUtils/GTMSynchronizationAssertsTest.m b/DebugUtils/GTMSynchronizationAssertsTest.m new file mode 100644 index 0000000..f08fc3e --- /dev/null +++ b/DebugUtils/GTMSynchronizationAssertsTest.m @@ -0,0 +1,288 @@ +/* Copyright (c) 2016 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 <XCTest/XCTest.h> + +#import <objc/runtime.h> + +// For testing, force use of the default debug versions of the _GTMDevAssert macro. +#undef _GTMDevAssert +#undef NS_BLOCK_ASSERTIONS +#undef DEBUG +#define DEBUG 1 + +#import "GTMSynchronizationAsserts.h" + +@interface GTMSynchonizationAssertsTest : XCTestCase +@end + +@implementation GTMSynchonizationAssertsTest + +- (void)verifySynchronized { + // Test both GTMCheckSynchronized and GTMCheckNotSynchronized assuming we're in a sync block. + @try { + GTMCheckSynchronized(self); + } @catch (NSException *exception) { + XCTFail(@"shouldn't have thrown"); + } + + @try { + GTMCheckNotSynchronized(self); + XCTFail(@"should have thrown"); + } @catch (NSException *exception) { + } +} + +- (void)verifyNotSynchronized { + // Test both GTMCheckSynchronized and GTMCheckNotSynchronized assuming we're not in a sync block. + @try { + GTMCheckNotSynchronized(self); + } @catch (NSException *exception) { + XCTFail(@"shouldn't have thrown"); + } + + @try { + GTMCheckSynchronized(self); + XCTFail(@"shoul have thrown"); + } @catch (NSException *exception) { + } +} + +- (void)testChecks_SingleMethod { + [self verifyNotSynchronized]; + + @synchronized(self) { + GTMMonitorSynchronized(self); + [self verifySynchronized]; + + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [self verifySynchronized]; + + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [self verifySynchronized]; + } + } + } + [self verifyNotSynchronized]; +} + +- (void)testChecks_AcrossMethods { + [self doIndirectCheckNotSynchronized]; + + @synchronized(self) { + GTMMonitorSynchronized(self); + [self verifySynchronized]; + + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [self doIndirectCheckSynchronized]; + + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [self doIndirectCheckSynchronized]; + } + } + } + [self doIndirectCheckNotSynchronized]; +} + +- (void)doIndirectCheckSynchronized { + // Verify from a separate method. + [self verifySynchronized]; +} + +- (void)doIndirectCheckNotSynchronized { + // Verify from a separate method. + [self verifyNotSynchronized]; +} + +#pragma mark Sync Monitor Tests + +- (void)testNonrecursiveSync { + // Non-recursive monitors. + XCTestExpectation *outer = [self expectationWithDescription:@"outer"]; + XCTestExpectation *inner = [self expectationWithDescription:@"inner"]; + + @try { + @synchronized(self) { + GTMMonitorSynchronized(self); + [outer fulfill]; + + @synchronized(self) { + GTMMonitorSynchronized(self); + XCTFail(@"should have thrown"); + } + } + } @catch (NSException *exception) { + [inner fulfill]; + } + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + +- (void)testRecursiveSync_SingleMethod { + // The inner monitors are recursive. + XCTestExpectation *outer = [self expectationWithDescription:@"outer"]; + XCTestExpectation *inner1 = [self expectationWithDescription:@"inner1"]; + XCTestExpectation *inner2 = [self expectationWithDescription:@"inner2"]; + + @try { + @synchronized(self) { + GTMMonitorSynchronized(self); + [outer fulfill]; + + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [inner1 fulfill]; + + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [inner2 fulfill]; + } + } + } + } @catch (NSException *exception) { + XCTFail(@"shouldn't have thrown"); + } + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + +- (void)testRecursiveSync_AcrossMethods { + // The inner monitors are recursive. + XCTestExpectation *outer = [self expectationWithDescription:@"outer"]; + XCTestExpectation *inner1 = [self expectationWithDescription:@"inner1"]; + XCTestExpectation *inner2 = [self expectationWithDescription:@"inner2"]; + + @try { + @synchronized(self) { + GTMMonitorSynchronized(self); + [outer fulfill]; + + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [inner1 fulfill]; + + [self doInnerRecursiveSync]; + [inner2 fulfill]; + } + } + } @catch (NSException *exception) { + XCTFail(@"shouldn't have thrown"); + } + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + +- (void)doInnerRecursiveSync { + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + } +} + +- (void)testRecursiveThenNonrecursiveSync_SingleMethod { + // The outer monitors are recursive, but the inner one is not and should throw. + XCTestExpectation *outer1 = [self expectationWithDescription:@"outer1"]; + XCTestExpectation *outer2 = [self expectationWithDescription:@"outer2"]; + XCTestExpectation *inner = [self expectationWithDescription:@"inner"]; + + @try { + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [outer1 fulfill]; + + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [outer2 fulfill]; + + @synchronized(self) { + GTMMonitorSynchronized(self); + XCTFail(@"should have thrown"); + } + } + } + } @catch (NSException *exception) { + [inner fulfill]; + } + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + +- (void)testRecursiveThenNonrecursiveSync_AcrossMethods { + // The outer monitors are recursive, but the inner one is not and should throw. + XCTestExpectation *outer1 = [self expectationWithDescription:@"outer1"]; + XCTestExpectation *outer2 = [self expectationWithDescription:@"outer2"]; + XCTestExpectation *inner = [self expectationWithDescription:@"inner"]; + + @try { + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [outer1 fulfill]; + + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [outer2 fulfill]; + + [self doInnerNonrecursiveSync]; + } + } + } @catch (NSException *exception) { + [inner fulfill]; + } + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + +- (void)doInnerNonrecursiveSync { + @synchronized(self) { + GTMMonitorSynchronized(self); + XCTFail(@"should have thrown"); + } +} + +- (void)testSyncOnSeparateObjects { + // Verify that monitoring works for distinct sync objects. + XCTestExpectation *outer = [self expectationWithDescription:@"outer"]; + XCTestExpectation *innerA = [self expectationWithDescription:@"innerA"]; + XCTestExpectation *innerB = [self expectationWithDescription:@"innerB"]; + + id obj1 = [[NSObject alloc] init]; + id obj2 = [[NSObject alloc] init]; + + @try { + @synchronized(obj1) { + GTMMonitorSynchronized(obj1); + [outer fulfill]; + + @synchronized(obj2) { + GTMMonitorSynchronized(obj2); + [innerA fulfill]; + + @synchronized(obj1) { + GTMMonitorSynchronized(obj1); + XCTFail(@"should have thrown"); + } + } + } + } @catch (NSException *exception) { + [innerB fulfill]; + } + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + +@end |