Index: chrome/browser/mac/exception_processor_unittest.mm |
diff --git a/chrome/browser/chrome_browser_application_mac_unittest.mm b/chrome/browser/mac/exception_processor_unittest.mm |
similarity index 54% |
rename from chrome/browser/chrome_browser_application_mac_unittest.mm |
rename to chrome/browser/mac/exception_processor_unittest.mm |
index 4252a7597133aba8edd39fb15b313ca364dd98c8..74c1128fe65a6bc72aedd0ec1d3d07d5a5465110 100644 |
--- a/chrome/browser/chrome_browser_application_mac_unittest.mm |
+++ b/chrome/browser/mac/exception_processor_unittest.mm |
@@ -1,14 +1,14 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#import "chrome/browser/chrome_browser_application_mac.h" |
+#import "chrome/browser/mac/exception_processor.h" |
#import <Cocoa/Cocoa.h> |
#include <stddef.h> |
+#include <sys/wait.h> |
-#include <memory> |
- |
+#include "base/mac/os_crash_dumps.h" |
#include "base/metrics/histogram_macros.h" |
#include "base/metrics/histogram_samples.h" |
#include "base/metrics/statistics_recorder.h" |
@@ -18,7 +18,7 @@ using base::HistogramBase; |
using base::HistogramSamples; |
using base::StatisticsRecorder; |
-namespace chrome_browser_application_mac { |
+namespace chrome { |
// Generate an NSException with the given name. |
NSException* ExceptionNamed(NSString* name) { |
@@ -32,7 +32,7 @@ size_t BinForExceptionNamed(NSString* name) { |
return BinForException(ExceptionNamed(name)); |
} |
-TEST(ChromeApplicationMacTest, ExceptionBinning) { |
+TEST(ExceptionProcessorTest, ExceptionBinning) { |
// These exceptions must be in this order. |
EXPECT_EQ(BinForExceptionNamed(NSGenericException), 0U); |
EXPECT_EQ(BinForExceptionNamed(NSRangeException), 1U); |
@@ -46,7 +46,7 @@ TEST(ChromeApplicationMacTest, ExceptionBinning) { |
EXPECT_EQ(BinForException(nil), kUnknownNSException); |
} |
-TEST(ChromeApplicationMacTest, RecordException) { |
+TEST(ExceptionProcessorTest, RecordException) { |
// Start up a histogram recorder. |
// TODO(rtenneti): Leaks StatisticsRecorder and will update suppressions. |
base::StatisticsRecorder::Initialize(); |
@@ -91,4 +91,92 @@ TEST(ChromeApplicationMacTest, RecordException) { |
EXPECT_EQ(4, samples->GetCount(kUnknownNSException)); |
} |
-} // chrome_browser_application_mac |
+void RaiseExceptionInRunLoop() { |
+ CFRunLoopRef run_loop = CFRunLoopGetCurrent(); |
+ |
+ CFRunLoopPerformBlock(run_loop, kCFRunLoopCommonModes, ^{ |
+ [NSException raise:@"ThrowExceptionInRunLoop" format:nil]; |
+ }); |
+ CFRunLoopPerformBlock(run_loop, kCFRunLoopCommonModes, ^{ |
+ CFRunLoopStop(run_loop); |
+ }); |
+ CFRunLoopRun(); |
+} |
+ |
+void ThrowExceptionInRunLoop() { |
+ base::mac::DisableOSCrashDumps(); |
+ chrome::InstallObjcExceptionPreprocessor(); |
+ |
+ RaiseExceptionInRunLoop(); |
+ |
+ fprintf(stderr, "TEST FAILED\n"); |
+ exit(1); |
+} |
+ |
+// Tests that when the preprocessor is installed, exceptions thrown from |
+// a runloop callout are made fatal, so that the stack trace is useful. |
+TEST(ExceptionProcessorTest, ThrowExceptionInRunLoop) { |
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe"; |
+ EXPECT_DEATH(ThrowExceptionInRunLoop(), |
+ ".*FATAL:exception_processor\\.mm.*" |
+ "Terminating from Objective-C exception:.*"); |
+} |
+ |
+void ThrowAndCatchExceptionInRunLoop() { |
+ base::mac::DisableOSCrashDumps(); |
+ chrome::InstallObjcExceptionPreprocessor(); |
+ |
+ CFRunLoopRef run_loop = CFRunLoopGetCurrent(); |
+ CFRunLoopPerformBlock(run_loop, kCFRunLoopCommonModes, ^{ |
+ @try { |
+ [NSException raise:@"ObjcExceptionPreprocessCaught" format:nil]; |
+ } @catch (id exception) { |
+ } |
+ }); |
+ |
+ CFRunLoopPerformBlock(run_loop, kCFRunLoopCommonModes, ^{ |
+ CFRunLoopStop(run_loop); |
+ }); |
+ |
+ CFRunLoopRun(); |
+ |
+ fprintf(stderr, "TEST PASS\n"); |
+ exit(0); |
+} |
+ |
+// Tests that exceptions can still be caught when the preprocessor is enabled. |
+TEST(ExceptionProcessorTest, ThrowAndCatchExceptionInRunLoop) { |
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe"; |
+ EXPECT_EXIT(ThrowAndCatchExceptionInRunLoop(), |
+ [](int exit_code) -> bool { |
+ return WEXITSTATUS(exit_code) == 0; |
+ }, |
+ ".*TEST PASS.*"); |
+} |
+ |
+void ThrowExceptionInRunLoopWithoutProcessor() { |
+ base::mac::DisableOSCrashDumps(); |
+ chrome::UninstallObjcExceptionPreprocessor(); |
+ |
+ @try { |
+ RaiseExceptionInRunLoop(); |
+ } @catch (id exception) { |
+ fprintf(stderr, "TEST PASS\n"); |
+ exit(0); |
+ } |
+ |
+ fprintf(stderr, "TEST FAILED\n"); |
+ exit(1); |
+} |
+ |
+// Tests basic exception handling when the preprocessor is disabled. |
+TEST(ExceptionProcessorTest, ThrowExceptionInRunLoopWithoutProcessor) { |
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe"; |
+ EXPECT_EXIT(ThrowExceptionInRunLoopWithoutProcessor(), |
+ [](int exit_code) -> bool { |
+ return WEXITSTATUS(exit_code) == 0; |
+ }, |
+ ".*TEST PASS.*"); |
+} |
+ |
+} // namespace chrome |