diff options
Diffstat (limited to 'UnitTesting/GTMAppKit+UnitTesting.m')
-rw-r--r-- | UnitTesting/GTMAppKit+UnitTesting.m | 583 |
1 files changed, 0 insertions, 583 deletions
diff --git a/UnitTesting/GTMAppKit+UnitTesting.m b/UnitTesting/GTMAppKit+UnitTesting.m deleted file mode 100644 index 5b4d6f7..0000000 --- a/UnitTesting/GTMAppKit+UnitTesting.m +++ /dev/null @@ -1,583 +0,0 @@ -// -// GTMAppKit+UnitTesting.m -// -// Categories for making unit testing of graphics/UI easier. -// -// Copyright 2006-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 "GTMDefines.h" -#import "GTMAppKit+UnitTesting.h" -#import "GTMGeometryUtils.h" -#import "GTMMethodCheck.h" - -#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 - #define ENCODE_NSINTEGER(coder, i, key) [(coder) encodeInt:(i) forKey:(key)] -#else - #define ENCODE_NSINTEGER(coder, i, key) [(coder) encodeInteger:(i) forKey:(key)] -#endif - -@implementation NSApplication (GTMUnitTestingAdditions) -GTM_METHOD_CHECK(NSObject, gtm_unitTestEncodeState:); - -- (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { - [super gtm_unitTestEncodeState:inCoder]; - ENCODE_NSINTEGER(inCoder, [[self mainWindow] windowNumber], @"ApplicationMainWindow"); - - // Descend down into the windows allowing them to store their state - NSWindow *window = nil; - int i = 0; - GTM_FOREACH_OBJECT(window, [self windows]) { - if ([window isVisible]) { - // Only record visible windows because invisible windows may be closing on us - // This appears to happen differently in 64 bit vs 32 bit, and items - // in the window may hold an extra retain count for a while until the - // event loop is spun. To avoid all this, we just don't record non - // visible windows. - // See rdar://5851458 for details. - [inCoder encodeObject:window forKey:[NSString stringWithFormat:@"Window %d", i]]; - i = i + 1; - } - } - - // and encode the menu bar - NSMenu *mainMenu = [self mainMenu]; - if (mainMenu) { - [inCoder encodeObject:mainMenu forKey:@"MenuBar"]; - } -} -@end - -@implementation NSWindow (GTMUnitTestingAdditions) - -- (CGImageRef)gtm_unitTestImage { - return [[[self contentView] superview] gtm_unitTestImage]; -} - -- (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { - [super gtm_unitTestEncodeState:inCoder]; - [inCoder encodeObject:[self title] forKey:@"WindowTitle"]; - [inCoder encodeBool:[self isVisible] forKey:@"WindowIsVisible"]; - // Do not record if window is key, because users running unit tests - // and clicking around to other apps, could change this mid test causing - // issues. - // [inCoder encodeBool:[self isKeyWindow] forKey:@"WindowIsKey"]; - [inCoder encodeBool:[self isMainWindow] forKey:@"WindowIsMain"]; - [inCoder encodeObject:[self contentView] forKey:@"WindowContent"]; - if ([self toolbar]) { - [inCoder encodeObject:[self toolbar] forKey:@"WindowToolbar"]; - } -} - -@end - -@implementation NSControl (GTMUnitTestingAdditions) - -// Encodes the state of an object in a manner suitable for comparing -// against a master state file so we can determine whether the -// object is in a suitable state. -// -// Arguments: -// inCoder - the coder to encode our state into -- (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { - [super gtm_unitTestEncodeState:inCoder]; - [inCoder encodeObject:[self class] forKey:@"ControlType"]; - [inCoder encodeObject:[self objectValue] forKey:@"ControlValue"]; - [inCoder encodeObject:[self selectedCell] forKey:@"ControlSelectedCell"]; - ENCODE_NSINTEGER(inCoder, [self tag], @"ControlTag"); - [inCoder encodeBool:[self isEnabled] forKey:@"ControlIsEnabled"]; -} - -@end - -@implementation NSButton (GTMUnitTestingAdditions) - -// Encodes the state of an object in a manner suitable for comparing -// against a master state file so we can determine whether the -// object is in a suitable state. -// -// Arguments: -// inCoder - the coder to encode our state into -- (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { - [super gtm_unitTestEncodeState:inCoder]; - NSString *alternateTitle = [self alternateTitle]; - if (alternateTitle) { - [inCoder encodeObject:alternateTitle forKey:@"ButtonAlternateTitle"]; - } -} - -@end - -@implementation NSTextField (GTMUnitTestingAdditions) - -- (BOOL)gtm_shouldEncodeStateForSubviews { - return NO; -} - -// Encodes the state of an object in a manner suitable for comparing -// against a master state file so we can determine whether the -// object is in a suitable state. -// -// Arguments: -// inCoder - the coder to encode our state into -- (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { - [super gtm_unitTestEncodeState:inCoder]; - id controlCell = [self cell]; - if ([controlCell isKindOfClass:[NSTextFieldCell class]]) { - NSTextFieldCell *textFieldCell = controlCell; - [inCoder encodeObject:[textFieldCell placeholderString] - forKey:@"PlaceHolderString"]; - } -} - -@end - -@implementation NSCell (GTMUnitTestingAdditions) - -// Encodes the state of an object in a manner suitable for comparing -// against a master state file so we can determine whether the -// object is in a suitable state. -// -// Arguments: -// inCoder - the coder to encode our state into -- (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { - [super gtm_unitTestEncodeState:inCoder]; - BOOL isImageCell = NO; - if ([self hasValidObjectValue]) { - id val = [self objectValue]; - [inCoder encodeObject:val forKey:@"CellValue"]; - isImageCell = [val isKindOfClass:[NSImage class]]; - } - if (!isImageCell) { - // Image cells have a title that includes addresses that aren't going - // to be constant, so we don't encode them. All the info we need - // is going to be in the CellValue encoding. - [inCoder encodeObject:[self title] forKey:@"CellTitle"]; - } - ENCODE_NSINTEGER(inCoder, [self state], @"CellState"); - ENCODE_NSINTEGER(inCoder, [self tag], @"CellTag"); -} - -@end - -@implementation NSImage (GTMUnitTestingAdditions) - -- (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { - [super gtm_unitTestEncodeState:inCoder]; - [inCoder encodeObject:NSStringFromSize([self size]) forKey:@"ImageSize"]; - [inCoder encodeObject:[self name] forKey:@"ImageName"]; -} - -- (CGImageRef)gtm_unitTestImage { - // Create up a context - NSSize size = [self size]; - NSRect rect = GTMNSRectOfSize(size); - CGSize cgSize = GTMNSSizeToCGSize(size); - CGContextRef contextRef = GTMCreateUnitTestBitmapContextOfSizeWithData(cgSize, - NULL); - NSGraphicsContext *bitmapContext - = [NSGraphicsContext graphicsContextWithGraphicsPort:contextRef flipped:NO]; - _GTMDevAssert(bitmapContext, @"Couldn't create ns bitmap context"); - - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:bitmapContext]; - [self drawInRect:rect fromRect:rect operation:NSCompositeCopy fraction:1.0]; - - CGImageRef image = CGBitmapContextCreateImage(contextRef); - CFRelease(contextRef); - [NSGraphicsContext restoreGraphicsState]; - return (CGImageRef)GTMCFAutorelease(image); -} - -@end - -@implementation NSMenu (GTMUnitTestingAdditions) - -// Encodes the state of an object in a manner suitable for comparing -// against a master state file so we can determine whether the -// object is in a suitable state. -// -// Arguments: -// inCoder - the coder to encode our state into -- (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { - [super gtm_unitTestEncodeState:inCoder]; - // Hack here to work around - // rdar://5881796 Application menu item title wrong when accessed programatically - // which causes us to have different results on x86_64 vs x386. - // Hack is braced intentionally. We don't record the title of the - // "application" menu or it's menu title because they are wrong on 32 bit. - // They appear to work right on 64bit. - { - NSMenu *mainMenu = [NSApp mainMenu]; - NSMenu *appleMenu = [[mainMenu itemAtIndex:0] submenu]; - if (![self isEqual:appleMenu]) { - [inCoder encodeObject:[self title] forKey:@"MenuTitle"]; - } - } - // Descend down into the menuitems allowing them to store their state - NSMenuItem *menuItem = nil; - int i = 0; - GTM_FOREACH_OBJECT(menuItem, [self itemArray]) { - [inCoder encodeObject:menuItem - forKey:[NSString stringWithFormat:@"MenuItem %d", i]]; - ++i; - } -} - -@end - -@implementation NSMenuItem (GTMUnitTestingAdditions) - -- (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { - [super gtm_unitTestEncodeState:inCoder]; - // Hack here to work around - // rdar://5881796 Application menu item title wrong when accessed programatically - // which causes us to have different results on x86_64 vs x386. - // See comment above. - { - NSMenu *mainMenu = [NSApp mainMenu]; - NSMenuItem *appleMenuItem = [mainMenu itemAtIndex:0]; - if (![self isEqual:appleMenuItem]) { - [inCoder encodeObject:[self title] forKey:@"MenuItemTitle"]; - } - } - [inCoder encodeObject:[self keyEquivalent] forKey:@"MenuItemKeyEquivalent"]; - [inCoder encodeBool:[self isSeparatorItem] forKey:@"MenuItemIsSeparator"]; - ENCODE_NSINTEGER(inCoder, [self state], @"MenuItemState"); - [inCoder encodeBool:[self isEnabled] forKey:@"MenuItemIsEnabled"]; - [inCoder encodeBool:[self isAlternate] forKey:@"MenuItemIsAlternate"]; - [inCoder encodeObject:[self toolTip] forKey:@"MenuItemTooltip"]; - ENCODE_NSINTEGER(inCoder, [self tag], @"MenuItemTag"); - ENCODE_NSINTEGER(inCoder, [self indentationLevel], @"MenuItemIndentationLevel"); - - // Do our submenu if neccessary - if ([self hasSubmenu]) { - [inCoder encodeObject:[self submenu] forKey:@"MenuItemSubmenu"]; - } -} - -@end - -@implementation NSTabView (GTMUnitTestingAdditions) - -// Encodes the state of an object in a manner suitable for comparing -// against a master state file so we can determine whether the -// object is in a suitable state. -// -// Arguments: -// inCoder - the coder to encode our state into -- (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { - [super gtm_unitTestEncodeState:inCoder]; - NSTabViewItem *tab = nil; - int i = 0; - GTM_FOREACH_OBJECT(tab, [self tabViewItems]) { - NSString *key = [NSString stringWithFormat:@"TabItem %d", i]; - [inCoder encodeObject:tab forKey:key]; - i = i + 1; - } -} - -@end - -@implementation NSTabViewItem (GTMUnitTestingAdditions) - -// Encodes the state of an object in a manner suitable for comparing -// against a master state file so we can determine whether the -// object is in a suitable state. -// -// Arguments: -// inCoder - the coder to encode our state into -- (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { - [super gtm_unitTestEncodeState:inCoder]; - [inCoder encodeObject:[self label] forKey:@"TabLabel"]; - [inCoder encodeObject:[self view] forKey:@"TabView"]; -} - -@end - -@implementation NSToolbar (GTMUnitTestingAdditions) - -// Encodes the state of an object in a manner suitable for comparing -// against a master state file so we can determine whether the -// object is in a suitable state. -// -// Arguments: -// inCoder - the coder to encode our state into -- (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { - [super gtm_unitTestEncodeState:inCoder]; - NSToolbarItem *item = nil; - NSUInteger i = 0; - GTM_FOREACH_OBJECT(item, [self items]) { - NSString *key - = [NSString stringWithFormat:@"ToolbarItem %lu", (unsigned long)i]; - [inCoder encodeObject:item forKey:key]; - i = i + 1; - } -} - -@end - -@implementation NSToolbarItem (GTMUnitTestingAdditions) - -// Encodes the state of an object in a manner suitable for comparing -// against a master state file so we can determine whether the -// object is in a suitable state. -// -// Arguments: -// inCoder - the coder to encode our state into -- (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { - [super gtm_unitTestEncodeState:inCoder]; - [inCoder encodeObject:[self label] forKey:@"Label"]; - [inCoder encodeObject:[self paletteLabel] forKey:@"PaletteLabel"]; - [inCoder encodeObject:[self toolTip] forKey:@"ToolTip"]; - NSView *view = [self view]; - if (view) { - [inCoder encodeObject:view forKey:@"View"]; - } -} - -@end - -@implementation NSMatrix (GTMUnitTestingAdditions) - -// Encodes the state of an object in a manner suitable for comparing -// against a master state file so we can determine whether the -// object is in a suitable state. -// -// Arguments: -// inCoder - the coder to encode our state into -- (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { - [super gtm_unitTestEncodeState:inCoder]; - - ENCODE_NSINTEGER(inCoder, [self mode], @"MatrixMode"); - ENCODE_NSINTEGER(inCoder, [self numberOfRows], @"MatrixRowCount"); - ENCODE_NSINTEGER(inCoder, [self numberOfColumns], @"MatrixColumnCount"); - [inCoder encodeBool:[self allowsEmptySelection] - forKey:@"MatrixAllowEmptySelection"]; - [inCoder encodeBool:[self isSelectionByRect] forKey:@"MatrixSelectionByRect"]; - [inCoder encodeBool:[self autosizesCells] forKey:@"MatrixAutosizesCells"]; - [inCoder encodeSize:[self intercellSpacing] forKey:@"MatrixIntercellSpacing"]; - - [inCoder encodeObject:[self prototype] forKey:@"MatrixCellPrototype"]; - - // Dump the list of cells - NSCell *cell; - long i = 0; - GTM_FOREACH_OBJECT(cell, [self cells]) { - [inCoder encodeObject:cell - forKey:[NSString stringWithFormat:@"MatrixCell %ld", i]]; - ++i; - } -} - -@end - -@implementation NSBox (GTMUnitTestingAdditions) - -// Encodes the state of an object in a manner suitable for comparing -// against a master state file so we can determine whether the -// object is in a suitable state. -// -// Arguments: -// inCoder - the coder to encode our state into -- (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { - [super gtm_unitTestEncodeState:inCoder]; - - [inCoder encodeObject:[self title] forKey:@"BoxTitle"]; - ENCODE_NSINTEGER(inCoder, [self titlePosition], @"BoxTitlePosition"); - ENCODE_NSINTEGER(inCoder, [self boxType], @"BoxType"); - ENCODE_NSINTEGER(inCoder, [self borderType], @"BoxBorderType"); - // 10.5+ [inCoder encodeBool:[self isTransparent] forKey:@"BoxIsTransparent"]; -} - -@end - -@implementation NSSegmentedControl (GTMUnitTestingAdditions) - -// Encodes the state of an NSSegmentedControl and all its segments. -// -// Arguments: -// inCoder - the coder to encode state into -- (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { - [super gtm_unitTestEncodeState:inCoder]; - - NSInteger segmentCount = [self segmentCount]; - ENCODE_NSINTEGER(inCoder, segmentCount, @"SegmentCount"); - - for (NSInteger i = 0; i < segmentCount; ++i) { - NSString *key = [NSString stringWithFormat:@"Segment %ld", (long)i]; - [inCoder encodeObject:[self labelForSegment:i] forKey:key]; - } -} - -@end - -@implementation NSComboBox (GTMUnitTestingAdditions) - -- (BOOL)gtm_shouldEncodeStateForSubviews { - // Subclass of NSTextView, don't want subviews for the same reason. - return NO; -} - -// Encodes the state of an NSSegmentedControl and all its segments. -// -// Arguments: -// inCoder - the coder to encode state into -- (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { - [super gtm_unitTestEncodeState:inCoder]; - - NSInteger aCount = [self numberOfItems]; - ENCODE_NSINTEGER(inCoder, aCount, @"ComboBoxNumberOfItems"); - aCount = [self numberOfVisibleItems]; - ENCODE_NSINTEGER(inCoder, aCount, @"ComboBoxNumberOfVisibleItems"); - - // Include the objectValues if it doesn't use a data source. - if (![self usesDataSource]) { - NSArray *objectValues = [self objectValues]; - for (NSUInteger i = 0; i < [objectValues count]; ++i) { - id value = [objectValues objectAtIndex:i]; - if ([value isKindOfClass:[NSString class]]) { - NSString *key = [NSString stringWithFormat:@"ComboBoxObjectValue %lu", - (unsigned long)i]; - [inCoder encodeObject:value forKey:key]; - } - } - } -} - -@end - - -// A view that allows you to delegate out drawing using the formal -// GTMUnitTestViewDelegate protocol above. This is useful when writing up unit -// tests for visual elements. -// Your test will often end up looking like this: -// - (void)testFoo { -// GTMAssertDrawingEqualToFile(self, NSMakeSize(200, 200), @"Foo", nil, nil); -// } -// and your testSuite will also implement the unitTestViewDrawRect method to do -// it's actual drawing. The above creates a view of size 200x200 that draws -// it's content using |self|'s unitTestViewDrawRect method and compares it to -// the contents of the file Foo.tif to make sure it's valid -@implementation GTMUnitTestView - -- (id)initWithFrame:(NSRect)frame - drawer:(id<GTMUnitTestViewDrawer>)drawer - contextInfo:(void*)contextInfo { - self = [super initWithFrame:frame]; - if (self != nil) { - drawer_ = [drawer retain]; - contextInfo_ = contextInfo; - } - return self; -} - -- (void)dealloc { - [drawer_ release]; - [super dealloc]; -} - - -- (void)drawRect:(NSRect)rect { - [drawer_ gtm_unitTestViewDrawRect:rect contextInfo:contextInfo_]; -} - - -@end - -@implementation NSView (GTMUnitTestingAdditions) - -// Returns an image containing a representation of the object -// suitable for use in comparing against a master image. -// Does all of it's drawing with smoothfonts and antialiasing off -// to avoid issues with font smoothing settings and antialias differences -// between ppc and x86. -// -// Returns: -// an image of the object -- (CGImageRef)gtm_unitTestImage { - // Create up a context - NSRect bounds = [self bounds]; - CGSize cgSize = GTMNSSizeToCGSize(bounds.size); - CGContextRef contextRef = GTMCreateUnitTestBitmapContextOfSizeWithData(cgSize, - NULL); - NSGraphicsContext *bitmapContext - = [NSGraphicsContext graphicsContextWithGraphicsPort:contextRef flipped:NO]; - _GTMDevAssert(bitmapContext, @"Couldn't create ns bitmap context"); - - // Save our state and turn off font smoothing and antialias. - CGContextSaveGState(contextRef); - CGContextSetShouldSmoothFonts(contextRef, false); - CGContextSetShouldAntialias(contextRef, false); - [self displayRectIgnoringOpacity:bounds inContext:bitmapContext]; - - CGImageRef image = CGBitmapContextCreateImage(contextRef); - CFRelease(contextRef); - return (CGImageRef)GTMCFAutorelease(image); -} - -// Returns whether gtm_unitTestEncodeState should recurse into subviews -// of a particular view. -// If you have "Full keyboard access" in the -// Keyboard & Mouse > Keyboard Shortcuts preferences pane set to "Text boxes -// and Lists only" that Apple adds a set of subviews to NSTextFields. So in the -// case of NSTextFields we don't want to recurse into their subviews. There may -// be other cases like this, so instead of specializing gtm_unitTestEncodeState: to -// look for NSTextFields, NSTextFields will just not allow us to recurse into -// their subviews. -// -// Returns: -// should gtm_unitTestEncodeState pick up subview state. -- (BOOL)gtm_shouldEncodeStateForSubviews { - return YES; -} - -// Encodes the state of an object in a manner suitable for comparing -// against a master state file so we can determine whether the -// object is in a suitable state. -// -// Arguments: -// inCoder - the coder to encode our state into -- (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { - [super gtm_unitTestEncodeState:inCoder]; - [inCoder encodeBool:[self isHidden] forKey:@"ViewIsHidden"]; - [inCoder encodeObject:[self toolTip] forKey:@"ViewToolTip"]; - NSArray *supportedAttrs = [self accessibilityAttributeNames]; - if ([supportedAttrs containsObject:NSAccessibilityHelpAttribute]) { - NSString *help - = [self accessibilityAttributeValue:NSAccessibilityHelpAttribute]; - [inCoder encodeObject:help forKey:@"ViewAccessibilityHelp"]; - } - if ([supportedAttrs containsObject:NSAccessibilityDescriptionAttribute]) { - NSString *description - = [self accessibilityAttributeValue:NSAccessibilityDescriptionAttribute]; - [inCoder encodeObject:description forKey:@"ViewAccessibilityDescription"]; - } - NSMenu *menu = [self menu]; - if (menu) { - [inCoder encodeObject:menu forKey:@"ViewMenu"]; - } - if ([self gtm_shouldEncodeStateForSubviews]) { - NSView *subview = nil; - int i = 0; - GTM_FOREACH_OBJECT(subview, [self subviews]) { - [inCoder encodeObject:subview forKey:[NSString stringWithFormat:@"ViewSubView %d", i]]; - i = i + 1; - } - } -} - -@end - |