GTMUIKit+UnitTesting.m 3.77 KB
//
//  GTMUIKit+UnitTesting.m
//  
//  Category for making unit testing of graphics/UI easier.
//  Allows you to save a view out to a image file, and compare a view
//  with a previously stored representation to make sure it hasn't changed.
//
//  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 "GTMUIKit+UnitTesting.h"
#import "GTMCALayer+UnitTesting.h"
#import "GTMDefines.h"

#if !GTM_IPHONE_SDK
#error This file is for iPhone use only
#endif // GTM_IPHONE_SDK

//  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, CGSizeMake(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:(CGRect)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:(CGRect)rect {
  [drawer_ gtm_unitTestViewDrawRect:rect contextInfo:contextInfo_];
}

@end

@implementation UIView (GTMUnitTestingAdditions) 

//  Returns an image containing a representation of the object
//  suitable for use in comparing against a master image.
//  NB this means that all colors should be from "NSDevice" color space
//  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_createUnitTestImage {
  CALayer* layer = [self layer];
  return [layer gtm_createUnitTestImage];
}

//  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"];
  CALayer* layer = [self layer];
  if (layer) {
    [layer gtm_unitTestEncodeState:inCoder];
  }
  if ([self gtm_shouldEncodeStateForSubviews]) {
    NSEnumerator *subviewEnum = [[self subviews] objectEnumerator];
    UIView *subview = nil;
    int i = 0;
    while ((subview = [subviewEnum nextObject])) {
      [inCoder encodeObject:subview 
                     forKey:[NSString stringWithFormat:@"ViewSubView %d", i]];
      i = i + 1;
    }
  }
}

//  Returns whether gtm_unitTestEncodeState should recurse into subviews
//
//  Returns:
//    should gtm_unitTestEncodeState pick up subview state.
- (BOOL)gtm_shouldEncodeStateForSubviews {
  return YES;
}

- (BOOL)gtm_shouldEncodeStateForSublayersOfLayer:(CALayer*)layer {
  return NO;
}
@end