[Mac] UMA histogram for uncaught NSExceptions.

NSExceptions break C++ assumptions.  This starts to track how often
NSExceptions happen.

http://crbug.com/24463
TEST=Brower continues to operate.

Review URL: http://codereview.chromium.org/264061

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29204 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/chrome_application_mac_unittest.mm b/chrome/browser/chrome_application_mac_unittest.mm
new file mode 100644
index 0000000..dbc1d905
--- /dev/null
+++ b/chrome/browser/chrome_application_mac_unittest.mm
@@ -0,0 +1,81 @@
+// Copyright (c) 2009 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 <Cocoa/Cocoa.h>
+
+#include "base/histogram.h"
+#import "chrome/browser/chrome_application_mac.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace CrApplicationNSException {
+
+// Generate an NSException with the given name.
+NSException* ExceptionNamed(NSString* name) {
+  return [NSException exceptionWithName:name
+                                 reason:@"No reason given"
+                               userInfo:nil];
+}
+
+// Helper to keep binning expectations readible.
+size_t BinForExceptionNamed(NSString* name) {
+  return BinForException(ExceptionNamed(name));
+}
+
+TEST(ChromeApplicationMacTest, ExceptionBinning) {
+  // These exceptions must be in this order.
+  EXPECT_EQ(BinForExceptionNamed(NSGenericException), 0U);
+  EXPECT_EQ(BinForExceptionNamed(NSRangeException), 1U);
+  EXPECT_EQ(BinForExceptionNamed(NSInvalidArgumentException), 2U);
+  EXPECT_EQ(BinForExceptionNamed(NSMallocException), 3U);
+
+  // Random other exceptions map to |kUnknownNSException|.
+  EXPECT_EQ(BinForExceptionNamed(@"CustomName"), kUnknownNSException);
+  EXPECT_EQ(BinForExceptionNamed(@"Custom Name"), kUnknownNSException);
+  EXPECT_EQ(BinForExceptionNamed(@""), kUnknownNSException);
+  EXPECT_EQ(BinForException(nil), kUnknownNSException);
+}
+
+TEST(ChromeApplicationMacTest, RecordException) {
+  // Start up a histogram recorder.
+  StatisticsRecorder recorder;
+
+  StatisticsRecorder::Histograms histograms;
+  StatisticsRecorder::GetSnapshot("OSX.NSException", &histograms);
+  EXPECT_EQ(0U, histograms.size());
+
+  // Record some known exceptions.
+  RecordExceptionWithUma(ExceptionNamed(NSGenericException));
+  RecordExceptionWithUma(ExceptionNamed(NSGenericException));
+  RecordExceptionWithUma(ExceptionNamed(NSGenericException));
+  RecordExceptionWithUma(ExceptionNamed(NSGenericException));
+  RecordExceptionWithUma(ExceptionNamed(NSRangeException));
+  RecordExceptionWithUma(ExceptionNamed(NSInvalidArgumentException));
+  RecordExceptionWithUma(ExceptionNamed(NSInvalidArgumentException));
+  RecordExceptionWithUma(ExceptionNamed(NSInvalidArgumentException));
+  RecordExceptionWithUma(ExceptionNamed(NSMallocException));
+  RecordExceptionWithUma(ExceptionNamed(NSMallocException));
+
+  // Record some unknown exceptions.
+  RecordExceptionWithUma(ExceptionNamed(@"CustomName"));
+  RecordExceptionWithUma(ExceptionNamed(@"Custom Name"));
+  RecordExceptionWithUma(ExceptionNamed(@""));
+  RecordExceptionWithUma(nil);
+
+  // We should have exactly the right number of exceptions.
+  StatisticsRecorder::GetSnapshot("OSX.NSException", &histograms);
+  EXPECT_EQ(1U, histograms.size());
+  EXPECT_EQ(kUmaTargetedHistogramFlag, histograms[0]->flags());
+  Histogram::SampleSet sample;
+  histograms[0]->SnapshotSample(&sample);
+  EXPECT_EQ(4, sample.counts(0));
+  EXPECT_EQ(1, sample.counts(1));
+  EXPECT_EQ(3, sample.counts(2));
+  EXPECT_EQ(2, sample.counts(3));
+
+  // The unknown exceptions should end up in the overflow bucket.
+  EXPECT_EQ(kUnknownNSException + 1, histograms[0]->bucket_count());
+  EXPECT_EQ(4, sample.counts(kUnknownNSException));
+}
+
+}  // CrApplicationNSException