blob: 73cc306e77ddb1b3d8ca35cf7f7993cf3f6ebbcc [file] [log] [blame]
//
// GTMLoggerRingBufferWriterTest.m
//
// Copyright 2007-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 "GTMLoggerRingBufferWriter.h"
#import "GTMLogger.h"
// --------------------------------------------------
// CountingWriter keeps a count of the number of times it has been
// told to write something, and also keeps track of what it was
// asked to log.
@interface CountingWriter : NSObject<GTMLogWriter> {
@private
NSMutableArray *loggedContents_;
}
- (NSUInteger)count;
- (NSArray *)loggedContents;
- (void)reset;
@end // CountingWriter
@implementation CountingWriter
- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
if (!loggedContents_) {
loggedContents_ = [[NSMutableArray alloc] init];
}
[loggedContents_ addObject:msg];
} // logMessage
- (void)dealloc {
[loggedContents_ release];
[super dealloc];
} // dealloc
- (void)reset {
[loggedContents_ release];
loggedContents_ = nil;
} // reset
- (NSUInteger)count {
return [loggedContents_ count];
} // count
- (NSArray *)loggedContents {
return loggedContents_;
} // loggedContents
@end // CountingWriter
@interface GTMLoggerRingBufferWriterTest : GTMTestCase {
@private
GTMLogger *logger_;
CountingWriter *countingWriter_;
}
@end // GTMLoggerRingBufferWriterTest
// --------------------------------------------------
@implementation GTMLoggerRingBufferWriterTest
// Utilty to compare the set of messages captured by a CountingWriter
// with an array of expected messages. The messages are expected to
// be in the same order in both places.
- (void)compareWriter:(CountingWriter *)writer
withExpectedLogging:(NSArray *)expected
line:(int)line {
NSArray *loggedContents = [writer loggedContents];
XCTAssertEqual([expected count], [loggedContents count],
@"count mismatch from line %d", line);
for (unsigned int i = 0; i < [expected count]; i++) {
XCTAssertEqualObjects([expected objectAtIndex:i],
[loggedContents objectAtIndex:i],
@"logging mistmatch at index %d from line %d",
i, line);
}
} // compareWithExpectedLogging
- (void)setUp {
countingWriter_ = [[CountingWriter alloc] init];
logger_ = [[GTMLogger alloc] init];
} // setUp
- (void)tearDown {
[countingWriter_ release];
[logger_ release];
} // tearDown
- (void)testCreation {
// Make sure initializers work.
GTMLoggerRingBufferWriter *writer =
[GTMLoggerRingBufferWriter ringBufferWriterWithCapacity:32
writer:countingWriter_];
XCTAssertEqual([writer capacity], (NSUInteger)32);
XCTAssertTrue([writer writer] == countingWriter_);
XCTAssertEqual([writer count], (NSUInteger)0);
XCTAssertEqual([writer droppedLogCount], (NSUInteger)0);
XCTAssertEqual([writer totalLogged], (NSUInteger)0);
// Try with invalid arguments. Should always get nil back.
writer =
[GTMLoggerRingBufferWriter ringBufferWriterWithCapacity:0
writer:countingWriter_];
XCTAssertNil(writer);
writer = [GTMLoggerRingBufferWriter ringBufferWriterWithCapacity:32
writer:nil];
XCTAssertNil(writer);
writer = [[GTMLoggerRingBufferWriter alloc] init];
XCTAssertNil(writer);
} // testCreation
- (void)testLogging {
GTMLoggerRingBufferWriter *writer =
[GTMLoggerRingBufferWriter ringBufferWriterWithCapacity:4
writer:countingWriter_];
[logger_ setWriter:writer];
// Shouldn't do anything if there are no contents.
[writer dumpContents];
XCTAssertEqual([writer count], (NSUInteger)0);
XCTAssertEqual([countingWriter_ count], (NSUInteger)0);
// Log a single item. Make sure the counts are accurate.
[logger_ logDebug:@"oop"];
XCTAssertEqual([writer count], (NSUInteger)1);
XCTAssertEqual([writer totalLogged], (NSUInteger)1);
XCTAssertEqual([writer droppedLogCount], (NSUInteger)0);
XCTAssertEqual([countingWriter_ count], (NSUInteger)0);
// Log a second item. Also make sure counts are accurate.
[logger_ logDebug:@"ack"];
XCTAssertEqual([writer count], (NSUInteger)2);
XCTAssertEqual([writer totalLogged], (NSUInteger)2);
XCTAssertEqual([writer droppedLogCount], (NSUInteger)0);
XCTAssertEqual([countingWriter_ count], (NSUInteger)0);
// Print them, and make sure the countingWriter sees the right stuff.
[writer dumpContents];
XCTAssertEqual([countingWriter_ count], (NSUInteger)2);
XCTAssertEqual([writer count], (NSUInteger)2); // Should not be zeroed.
XCTAssertEqual([writer totalLogged], (NSUInteger)2);
[self compareWriter:countingWriter_
withExpectedLogging:[NSArray arrayWithObjects:@"oop",@"ack", nil]
line:__LINE__];
// Wipe the slates clean.
[writer reset];
[countingWriter_ reset];
XCTAssertEqual([writer count], (NSUInteger)0);
XCTAssertEqual([writer totalLogged], (NSUInteger)0);
// An error log level should print the buffer and empty it.
[logger_ logDebug:@"oop"];
[logger_ logInfo:@"ack"];
XCTAssertEqual([writer droppedLogCount], (NSUInteger)0);
XCTAssertEqual([writer totalLogged], (NSUInteger)2);
[logger_ logError:@"blargh"];
XCTAssertEqual([countingWriter_ count], (NSUInteger)3);
XCTAssertEqual([writer droppedLogCount], (NSUInteger)0);
[self compareWriter:countingWriter_
withExpectedLogging:[NSArray arrayWithObjects:@"oop", @"ack",
@"blargh", nil]
line:__LINE__];
// An assert log level should do the same. This also fills the
// buffer to its limit without wrapping.
[countingWriter_ reset];
[logger_ logDebug:@"oop"];
[logger_ logInfo:@"ack"];
[logger_ logDebug:@"blargh"];
XCTAssertEqual([writer droppedLogCount], (NSUInteger)0);
XCTAssertEqual([writer count], (NSUInteger)3);
XCTAssertEqual([writer totalLogged], (NSUInteger)3);
[logger_ logAssert:@"ouch"];
XCTAssertEqual([countingWriter_ count], (NSUInteger)4);
XCTAssertEqual([writer droppedLogCount], (NSUInteger)0);
[self compareWriter:countingWriter_
withExpectedLogging:[NSArray arrayWithObjects:@"oop", @"ack",
@"blargh", @"ouch", nil]
line:__LINE__];
// Try with exactly one wrap around.
[countingWriter_ reset];
[logger_ logInfo:@"ack"];
[logger_ logDebug:@"oop"];
[logger_ logDebug:@"blargh"];
[logger_ logDebug:@"flong"]; // Fills buffer
XCTAssertEqual([writer droppedLogCount], (NSUInteger)0);
XCTAssertEqual([writer count], (NSUInteger)4);
[logger_ logAssert:@"ouch"]; // should drop "ack"
XCTAssertEqual([countingWriter_ count], (NSUInteger)4);
[self compareWriter:countingWriter_
withExpectedLogging:[NSArray arrayWithObjects:@"oop", @"blargh",
@"flong", @"ouch", nil]
line:__LINE__];
// Try with more than one wrap around.
[countingWriter_ reset];
[logger_ logInfo:@"ack"];
[logger_ logDebug:@"oop"];
[logger_ logDebug:@"blargh"];
[logger_ logDebug:@"flong"]; // Fills buffer
[logger_ logDebug:@"bloogie"]; // should drop "ack"
XCTAssertEqual([writer droppedLogCount], (NSUInteger)1);
XCTAssertEqual([writer count], (NSUInteger)4);
[logger_ logAssert:@"ouch"]; // should drop "oop"
XCTAssertEqual([countingWriter_ count], (NSUInteger)4);
[self compareWriter:countingWriter_
withExpectedLogging:[NSArray arrayWithObjects:@"blargh",
@"flong", @"bloogie", @"ouch", nil]
line:__LINE__];
} // testBasics
- (void)testCornerCases {
// make sure we work with small buffer sizes.
GTMLoggerRingBufferWriter *writer =
[GTMLoggerRingBufferWriter ringBufferWriterWithCapacity:1
writer:countingWriter_];
[logger_ setWriter:writer];
[logger_ logInfo:@"ack"];
XCTAssertEqual([countingWriter_ count], (NSUInteger)0);
XCTAssertEqual([writer count], (NSUInteger)1);
[writer dumpContents];
XCTAssertEqual([countingWriter_ count], (NSUInteger)1);
[self compareWriter:countingWriter_
withExpectedLogging:[NSArray arrayWithObject:@"ack"]
line:__LINE__];
[logger_ logDebug:@"oop"]; // should drop "ack"
XCTAssertEqual([writer count], (NSUInteger)1);
XCTAssertEqual([writer droppedLogCount], (NSUInteger)1);
[countingWriter_ reset];
[logger_ logError:@"snoogy"]; // should drop "oop"
XCTAssertEqual([countingWriter_ count], (NSUInteger)1);
[self compareWriter:countingWriter_
withExpectedLogging:[NSArray arrayWithObjects:@"snoogy", nil]
line:__LINE__];
} // testCornerCases
// Run 10 threads, all logging through the same logger.
static volatile NSUInteger gStoppedThreads = 0; // Total number that have stopped.
- (void)bangMe:(id)info {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
GTMLogger *logger = (GTMLogger *)info;
// Log a string.
for (int i = 0; i < 27; i++) {
[logger logDebug:@"oop"];
}
// log another string which should push the first string out.
// if we see any "oop"s in the logger output, then we know it got
// confused.
for (int i = 0; i < 15; i++) {
[logger logDebug:@"ack"];
}
[pool release];
@synchronized ([self class]) {
gStoppedThreads++;
}
} // bangMe
- (void)testThreading {
const NSUInteger kThreadCount = 10;
const NSUInteger kCapacity = 10;
GTMLoggerRingBufferWriter *writer =
[GTMLoggerRingBufferWriter ringBufferWriterWithCapacity:kCapacity
writer:countingWriter_];
[logger_ setWriter:writer];
for (NSUInteger i = 0; i < kThreadCount; i++) {
[NSThread detachNewThreadSelector:@selector(bangMe:)
toTarget:self
withObject:logger_];
}
// The threads are running, so wait for them all to finish.
while (1) {
NSDate *quick = [NSDate dateWithTimeIntervalSinceNow:0.2];
[[NSRunLoop currentRunLoop] runUntilDate:quick];
@synchronized ([self class]) {
if (gStoppedThreads == kThreadCount) break;
}
}
// Now make sure we get back what's expected.
XCTAssertEqual([writer count], kThreadCount);
XCTAssertEqual([countingWriter_ count], (NSUInteger)0); // Nothing should be logged
XCTAssertEqual([writer totalLogged], (NSUInteger)420);
[logger_ logError:@"bork"];
XCTAssertEqual([countingWriter_ count], kCapacity);
NSArray *expected = [NSArray arrayWithObjects:
@"ack", @"ack", @"ack", @"ack", @"ack",
@"ack", @"ack", @"ack", @"ack", @"bork",
nil];
[self compareWriter:countingWriter_
withExpectedLogging:expected
line:__LINE__];
} // testThreading
@end // GTMLoggerRingBufferWriterTest