# HG changeset patch # User Jens Alfke # Date 1212354104 25200 # Node ID c59dec0889900265db5eef5a1e3f9df916f18240 # Parent 66b870428f85ff3caf98cb6b041dfd5bc4a0c968 * Made Test.h work with regular C99 without GCC extensions. * Copied the necessary Google Toolbox source files into the project, so users don't have to download an additional library. diff -r 66b870428f85 -r c59dec088990 GoogleToolboxSubset/GTMDefines.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GoogleToolboxSubset/GTMDefines.h Sun Jun 01 14:01:44 2008 -0700 @@ -0,0 +1,138 @@ +// +// GTMDefines.h +// +// Copyright 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. +// + +// ============================================================================ + +// ---------------------------------------------------------------------------- +// CPP symbols that can be overridden in a prefix to control how the toolbox +// is compiled. +// ---------------------------------------------------------------------------- + + +// GTMHTTPFetcher will support logging by default but only hook its input +// stream support for logging when requested. You can control the inclusion of +// the code by providing your own definitions for these w/in a prefix header. +// +#ifndef GTM_HTTPFETCHER_ENABLE_LOGGING +# define GTM_HTTPFETCHER_ENABLE_LOGGING 1 +#endif // GTM_HTTPFETCHER_ENABLE_LOGGING +#ifndef GTM_HTTPFETCHER_ENABLE_INPUTSTREAM_LOGGING +# define GTM_HTTPFETCHER_ENABLE_INPUTSTREAM_LOGGING 0 +#endif // GTM_HTTPFETCHER_ENABLE_INPUTSTREAM_LOGGING + + +// _GTMDevLog & _GTMDevAssert +// +// _GTMDevLog & _GTMDevAssert are meant to be a very lightweight shell for +// developer level errors. This implementation simply macros to NSLog/NSAssert. +// It is not intended to be a general logging/reporting system. +// +// Please see http://code.google.com/p/google-toolbox-for-mac/wiki/DevLogNAssert +// for a little more background on the usage of these macros. +// +// _GTMDevLog log some error/problem in debug builds +// _GTMDevAssert assert if conditon isn't met w/in a method/function +// in all builds. +// +// To replace this system, just provide different macro definitions in your +// prefix header. Remember, any implementation you provide *must* be thread +// safe since this could be called by anything in what ever situtation it has +// been placed in. +// + +// We only define the simple macros if nothing else has defined this. +#ifndef _GTMDevLog + +#ifdef DEBUG + #define _GTMDevLog(...) NSLog(__VA_ARGS__) +#else + #define _GTMDevLog(...) do { } while (0) +#endif + +// we directly invoke the NSAssert handler so we can pass on the varargs +// (NSAssert doesn't have a macro we can use that takes varargs) +#if !defined(NS_BLOCK_ASSERTIONS) +#define _GTMDevAssert(condition, ...) \ + do { \ + if (!(condition)) { \ + [[NSAssertionHandler currentHandler] \ + handleFailureInFunction:[NSString stringWithCString:__PRETTY_FUNCTION__] \ + file:[NSString stringWithCString:__FILE__] \ + lineNumber:__LINE__ \ + description:__VA_ARGS__]; \ + } \ + } while(0) +#else // !defined(NS_BLOCK_ASSERTIONS) +#define _GTMDevAssert(condition, ...) do { } while (0) +#endif // !defined(NS_BLOCK_ASSERTIONS) + +#endif // _GTMDevLog + +// ============================================================================ + +// ---------------------------------------------------------------------------- +// CPP symbols defined based on the project settings so the GTM code has +// simple things to test against w/o scattering the knowledge of project +// setting through all the code. +// ---------------------------------------------------------------------------- + +// Provide a single constant CPP symbol that all of GTM uses for ifdefing +// iPhone code. +#include +#if TARGET_OS_IPHONE // iPhone SDK + // For iPhone specific stuff + #define GTM_IPHONE_SDK 1 +#else + // For MacOS specific stuff + #define GTM_MACOS_SDK 1 +#endif + +// To simplify support for 64bit (and Leopard in general), we provide the type +// defines for non Leopard SDKs +#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 + // NSInteger/NSUInteger and Max/Mins + #ifndef NSINTEGER_DEFINED + #if __LP64__ || NS_BUILD_32_LIKE_64 + typedef long NSInteger; + typedef unsigned long NSUInteger; + #else + typedef int NSInteger; + typedef unsigned int NSUInteger; + #endif + #define NSIntegerMax LONG_MAX + #define NSIntegerMin LONG_MIN + #define NSUIntegerMax ULONG_MAX + #define NSINTEGER_DEFINED 1 + #endif // NSINTEGER_DEFINED + // CGFloat + #ifndef CGFLOAT_DEFINED + #if defined(__LP64__) && __LP64__ + // This really is an untested path (64bit on Tiger?) + typedef double CGFloat; + #define CGFLOAT_MIN DBL_MIN + #define CGFLOAT_MAX DBL_MAX + #define CGFLOAT_IS_DOUBLE 1 + #else /* !defined(__LP64__) || !__LP64__ */ + typedef float CGFloat; + #define CGFLOAT_MIN FLT_MIN + #define CGFLOAT_MAX FLT_MAX + #define CGFLOAT_IS_DOUBLE 0 + #endif /* !defined(__LP64__) || !__LP64__ */ + #define CGFLOAT_DEFINED 1 + #endif // CGFLOAT_DEFINED +#endif // MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 diff -r 66b870428f85 -r c59dec088990 GoogleToolboxSubset/GTMNSData+zlib.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GoogleToolboxSubset/GTMNSData+zlib.h Sun Jun 01 14:01:44 2008 -0700 @@ -0,0 +1,84 @@ +// +// GTMNSData+zlib.h +// +// 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 +#import "GTMDefines.h" + +/// Helpers for dealing w/ zlib inflate/deflate calls. +@interface NSData (GTMZLibAdditions) + +/// Return an autoreleased NSData w/ the result of gzipping the bytes. +// +// Uses the default compression level. ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length; + +/// Return an autoreleased NSData w/ the result of gzipping the payload of |data|. +// +// Uses the default compression level. ++ (NSData *)gtm_dataByGzippingData:(NSData *)data; + +/// Return an autoreleased NSData w/ the result of gzipping the bytes using |level| compression level. +// +// |level| can be 1-9, any other values will be clipped to that range. ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level; + +/// Return an autoreleased NSData w/ the result of gzipping the payload of |data| using |level| compression level. ++ (NSData *)gtm_dataByGzippingData:(NSData *)data + compressionLevel:(int)level; + +// NOTE: deflate is *NOT* gzip. deflate is a "zlib" stream. pick which one +// you really want to create. (the inflate api will handle either) + +/// Return an autoreleased NSData w/ the result of deflating the bytes. +// +// Uses the default compression level. ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length; + +/// Return an autoreleased NSData w/ the result of deflating the payload of |data|. +// +// Uses the default compression level. ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data; + +/// Return an autoreleased NSData w/ the result of deflating the bytes using |level| compression level. +// +// |level| can be 1-9, any other values will be clipped to that range. ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level; + +/// Return an autoreleased NSData w/ the result of deflating the payload of |data| using |level| compression level. ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data + compressionLevel:(int)level; + + +/// Return an autoreleased NSData w/ the result of decompressing the bytes. +// +// The bytes to decompress can be zlib or gzip payloads. ++ (NSData *)gtm_dataByInflatingBytes:(const void *)bytes + length:(NSUInteger)length; + +/// Return an autoreleased NSData w/ the result of decompressing the payload of |data|. +// +// The data to decompress can be zlib or gzip payloads. ++ (NSData *)gtm_dataByInflatingData:(NSData *)data; + +@end diff -r 66b870428f85 -r c59dec088990 GoogleToolboxSubset/GTMNSData+zlib.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GoogleToolboxSubset/GTMNSData+zlib.m Sun Jun 01 14:01:44 2008 -0700 @@ -0,0 +1,267 @@ +// +// GTMNSData+zlib.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 "GTMNSData+zlib.h" +#import +#import "GTMDefines.h" + +#define kChunkSize 1024 + +@interface NSData (GTMZlibAdditionsPrivate) ++ (NSData *)gtm_dataByCompressingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level + useGzip:(BOOL)useGzip; +@end + +@implementation NSData (GTMZlibAdditionsPrivate) ++ (NSData *)gtm_dataByCompressingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level + useGzip:(BOOL)useGzip { + if (!bytes || !length) { + return nil; + } + + // TODO: support 64bit inputs + // avail_in is a uInt, so if length > UINT_MAX we actually need to loop + // feeding the data until we've gotten it all in. not supporting this + // at the moment. + _GTMDevAssert(length <= UINT_MAX, @"Currently don't support >32bit lengths"); + + if (level == Z_DEFAULT_COMPRESSION) { + // the default value is actually outside the range, so we have to let it + // through specifically. + } else if (level < Z_BEST_SPEED) { + level = Z_BEST_SPEED; + } else if (level > Z_BEST_COMPRESSION) { + level = Z_BEST_COMPRESSION; + } + + z_stream strm; + bzero(&strm, sizeof(z_stream)); + + int windowBits = 15; // the default + int memLevel = 8; // the default + if (useGzip) { + windowBits += 16; // enable gzip header instead of zlib header + } + int retCode; + if ((retCode = deflateInit2(&strm, level, Z_DEFLATED, windowBits, + memLevel, Z_DEFAULT_STRATEGY)) != Z_OK) { + // COV_NF_START - no real way to force this in a unittest (we guard all args) + _GTMDevLog(@"Failed to init for deflate w/ level %d, error %d", + level, retCode); + return nil; + // COV_NF_END + } + + // hint the size at 1/4 the input size + NSMutableData *result = [NSMutableData dataWithCapacity:(length/4)]; + unsigned char output[kChunkSize]; + + // setup the input + strm.avail_in = (unsigned int)length; + strm.next_in = (unsigned char*)bytes; + + // loop to collect the data + do { + // update what we're passing in + strm.avail_out = kChunkSize; + strm.next_out = output; + retCode = deflate(&strm, Z_FINISH); + if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) { + // COV_NF_START - no real way to force this in a unittest + // (in inflate, we can feed bogus/truncated data to test, but an error + // here would be some internal issue w/in zlib, and there isn't any real + // way to test it) + _GTMDevLog(@"Error trying to deflate some of the payload, error %d", + retCode); + deflateEnd(&strm); + return nil; + // COV_NF_END + } + // collect what we got + unsigned gotBack = kChunkSize - strm.avail_out; + if (gotBack > 0) { + [result appendBytes:output length:gotBack]; + } + + } while (retCode == Z_OK); + + // if the loop exits, we used all input and the stream ended + _GTMDevAssert(strm.avail_in == 0, + @"thought we finished deflate w/o using all input, %u bytes left", + strm.avail_in); + _GTMDevAssert(retCode == Z_STREAM_END, + @"thought we finished deflate w/o getting a result of stream end, code %d", + retCode); + + // clean up + deflateEnd(&strm); + + return result; +} // gtm_dataByCompressingBytes:length:compressionLevel:useGzip: + + +@end + + +@implementation NSData (GTMZLibAdditions) + ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length { + return [self gtm_dataByCompressingBytes:bytes + length:length + compressionLevel:Z_DEFAULT_COMPRESSION + useGzip:YES]; +} // gtm_dataByGzippingBytes:length: + ++ (NSData *)gtm_dataByGzippingData:(NSData *)data { + return [self gtm_dataByCompressingBytes:[data bytes] + length:[data length] + compressionLevel:Z_DEFAULT_COMPRESSION + useGzip:YES]; +} // gtm_dataByGzippingData: + ++ (NSData *)gtm_dataByGzippingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level { + return [self gtm_dataByCompressingBytes:bytes + length:length + compressionLevel:level + useGzip:YES]; +} // gtm_dataByGzippingBytes:length:level: + ++ (NSData *)gtm_dataByGzippingData:(NSData *)data + compressionLevel:(int)level { + return [self gtm_dataByCompressingBytes:[data bytes] + length:[data length] + compressionLevel:level + useGzip:YES]; +} // gtm_dataByGzippingData:level: + ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length { + return [self gtm_dataByCompressingBytes:bytes + length:length + compressionLevel:Z_DEFAULT_COMPRESSION + useGzip:NO]; +} // gtm_dataByDeflatingBytes:length: + ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data { + return [self gtm_dataByCompressingBytes:[data bytes] + length:[data length] + compressionLevel:Z_DEFAULT_COMPRESSION + useGzip:NO]; +} // gtm_dataByDeflatingData: + ++ (NSData *)gtm_dataByDeflatingBytes:(const void *)bytes + length:(NSUInteger)length + compressionLevel:(int)level { + return [self gtm_dataByCompressingBytes:bytes + length:length + compressionLevel:level + useGzip:NO]; +} // gtm_dataByDeflatingBytes:length:level: + ++ (NSData *)gtm_dataByDeflatingData:(NSData *)data + compressionLevel:(int)level { + return [self gtm_dataByCompressingBytes:[data bytes] + length:[data length] + compressionLevel:level + useGzip:NO]; +} // gtm_dataByDeflatingData:level: + ++ (NSData *)gtm_dataByInflatingBytes:(const void *)bytes + length:(NSUInteger)length { + if (!bytes || !length) { + return nil; + } + + // TODO: support 64bit inputs + // avail_in is a uInt, so if length > UINT_MAX we actually need to loop + // feeding the data until we've gotten it all in. not supporting this + // at the moment. + _GTMDevAssert(length <= UINT_MAX, @"Currently don't support >32bit lengths"); + + z_stream strm; + bzero(&strm, sizeof(z_stream)); + + // setup the input + strm.avail_in = (unsigned int)length; + strm.next_in = (unsigned char*)bytes; + + int windowBits = 15; // 15 to enable any window size + windowBits += 32; // and +32 to enable zlib or gzip header detection. + int retCode; + if ((retCode = inflateInit2(&strm, windowBits)) != Z_OK) { + // COV_NF_START - no real way to force this in a unittest (we guard all args) + _GTMDevLog(@"Failed to init for inflate, error %d", retCode); + return nil; + // COV_NF_END + } + + // hint the size at 4x the input size + NSMutableData *result = [NSMutableData dataWithCapacity:(length*4)]; + unsigned char output[kChunkSize]; + + // loop to collect the data + do { + // update what we're passing in + strm.avail_out = kChunkSize; + strm.next_out = output; + retCode = inflate(&strm, Z_NO_FLUSH); + if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) { + _GTMDevLog(@"Error trying to inflate some of the payload, error %d", + retCode); + inflateEnd(&strm); + return nil; + } + // collect what we got + unsigned gotBack = kChunkSize - strm.avail_out; + if (gotBack > 0) { + [result appendBytes:output length:gotBack]; + } + + } while (retCode == Z_OK); + + // make sure there wasn't more data tacked onto the end of a valid compressed + // stream. + if (strm.avail_in != 0) { + _GTMDevLog(@"thought we finished inflate w/o using all input, %u bytes left", + strm.avail_in); + result = nil; + } + // the only way out of the loop was by hitting the end of the stream + _GTMDevAssert(retCode == Z_STREAM_END, + @"thought we finished inflate w/o getting a result of stream end, code %d", + retCode); + + // clean up + inflateEnd(&strm); + + return result; +} // gtm_dataByInflatingBytes:length: + ++ (NSData *)gtm_dataByInflatingData:(NSData *)data { + return [self gtm_dataByInflatingBytes:[data bytes] + length:[data length]]; +} // gtm_dataByInflatingData: + +@end diff -r 66b870428f85 -r c59dec088990 Test.h --- a/Test.h Sat May 31 11:26:17 2008 -0700 +++ b/Test.h Sun Jun 01 14:01:44 2008 -0700 @@ -66,6 +66,7 @@ IN_SEGMENT_NORETURN(Logging) {_AssertFailed(nil, _name, __FILE__, __LINE__,\ #COND,##MSG,NULL);} } }while(0) +// AssertEqual is for Obj-C objects #define AssertEqual(VAL,EXPECTED) do{ id _val = VAL, _expected = EXPECTED;\ Assert(_val==_expected || [_val isEqual: _expected], @"Unexpected value for %s: %@ (expected %@)", #VAL,_val,_expected); \ }while(0) @@ -74,11 +75,10 @@ }while(0) // AssertEq is for scalars (int, float...) -// Note: "typeof()" builtin function requires settingn C language dialect to GNU99. -#define AssertEq(VAL,EXPECTED) do{ typeof(VAL) _val = VAL; typeof(EXPECTED) _expected = EXPECTED;\ +#define AssertEq(VAL,EXPECTED) do{ __typeof(VAL) _val = VAL; __typeof(EXPECTED) _expected = EXPECTED;\ Assert(_val==_expected, @"Unexpected value for %s: %@ (expected %@)", #VAL,$object(_val),$object(_expected)); \ }while(0) -#define CAssertEq(VAL,EXPECTED) do{ typeof(VAL) _val = VAL; typeof(EXPECTED) _expected = EXPECTED;\ +#define CAssertEq(VAL,EXPECTED) do{ __typeof(VAL) _val = VAL; __typeof(EXPECTED) _expected = EXPECTED;\ CAssert(_val==_expected, @"Unexpected value for %s: %@ (expected %@)", #VAL,$object(_val),$object(_expected)); \ }while(0)