From d45292a84a4ec8e960dbf5296acdeab1cfe8bdff Mon Sep 17 00:00:00 2001 From: Geoffrey Grosenbach Date: Sat, 31 Jan 2009 15:52:47 -0800 Subject: [PATCH] First import --- .gitattributes | 1 + .gitignore | 16 + Classes/HppleAppDelegate.h | 18 + Classes/HppleAppDelegate.m | 29 + GTMDefines.h | 166 +++++ GTMIPhoneUnitTestDelegate.h | 29 + GTMIPhoneUnitTestDelegate.m | 160 +++++ GTMIPhoneUnitTestMain.m | 33 + GTMSenTestCase.h | 1004 ++++++++++++++++++++++++++++++ GTMSenTestCase.m | 211 +++++++ Hpple.xcodeproj/project.pbxproj | 446 +++++++++++++ Hpple_Prefix.pch | 8 + Info.plist | 30 + LICENSE.txt | 22 + MainWindow.xib | 180 ++++++ README.markdown | 46 ++ TFHpple.h | 45 ++ TFHpple.m | 73 +++ TFHppleElement.h | 54 ++ TFHppleElement.m | 91 +++ TFHppleHTMLTest.m | 119 ++++ Test-Info.plist | 22 + UnitTesting/RunIPhoneUnitTest.sh | 24 + UnitTesting/TestData/index.html | 622 ++++++++++++++++++ XPathQuery.h | 10 + XPathQuery.m | 184 ++++++ main.m | 17 + 27 files changed, 3660 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 Classes/HppleAppDelegate.h create mode 100644 Classes/HppleAppDelegate.m create mode 100644 GTMDefines.h create mode 100644 GTMIPhoneUnitTestDelegate.h create mode 100644 GTMIPhoneUnitTestDelegate.m create mode 100644 GTMIPhoneUnitTestMain.m create mode 100644 GTMSenTestCase.h create mode 100644 GTMSenTestCase.m create mode 100755 Hpple.xcodeproj/project.pbxproj create mode 100644 Hpple_Prefix.pch create mode 100644 Info.plist create mode 100644 LICENSE.txt create mode 100644 MainWindow.xib create mode 100644 README.markdown create mode 100644 TFHpple.h create mode 100644 TFHpple.m create mode 100644 TFHppleElement.h create mode 100644 TFHppleElement.m create mode 100644 TFHppleHTMLTest.m create mode 100644 Test-Info.plist create mode 100755 UnitTesting/RunIPhoneUnitTest.sh create mode 100644 UnitTesting/TestData/index.html create mode 100644 XPathQuery.h create mode 100644 XPathQuery.m create mode 100644 main.m diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..fdbd29f --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.pbxproj -crlf -diff -merge diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..814fdb2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# http://shanesbrain.net/2008/7/9/using-xcode-with-git +# xcode noise +build/* +*.pbxuser +*.mode1v3 + +# old skool +.svn + +# osx noise +.DS_Store +profile + +# Emacs +*.h# + diff --git a/Classes/HppleAppDelegate.h b/Classes/HppleAppDelegate.h new file mode 100644 index 0000000..b93adb8 --- /dev/null +++ b/Classes/HppleAppDelegate.h @@ -0,0 +1,18 @@ +// +// HppleAppDelegate.h +// Hpple +// +// Created by Geoffrey Grosenbach on 1/31/09. +// Copyright Topfunky Corporation 2009. All rights reserved. +// + +#import + +@interface HppleAppDelegate : NSObject { + UIWindow *window; +} + +@property (nonatomic, retain) IBOutlet UIWindow *window; + +@end + diff --git a/Classes/HppleAppDelegate.m b/Classes/HppleAppDelegate.m new file mode 100644 index 0000000..bf79127 --- /dev/null +++ b/Classes/HppleAppDelegate.m @@ -0,0 +1,29 @@ +// +// HppleAppDelegate.m +// Hpple +// +// Created by Geoffrey Grosenbach on 1/31/09. +// Copyright Topfunky Corporation 2009. All rights reserved. +// + +#import "HppleAppDelegate.h" + +@implementation HppleAppDelegate + +@synthesize window; + + +- (void)applicationDidFinishLaunching:(UIApplication *)application { + + // Override point for customization after application launch + [window makeKeyAndVisible]; +} + + +- (void)dealloc { + [window release]; + [super dealloc]; +} + + +@end diff --git a/GTMDefines.h b/GTMDefines.h new file mode 100644 index 0000000..32ae642 --- /dev/null +++ b/GTMDefines.h @@ -0,0 +1,166 @@ +// +// 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 + +#endif // _GTMDevLog + +// Declared here so that it can easily be used for logging tracking if +// necessary. See GTMUnitTestDevLog.h for details. +@class NSString; +extern void _GTMUnittestDevLog(NSString *format, ...); + +#ifndef _GTMDevAssert +// 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 // _GTMDevAssert + +// _GTMCompileAssert +// _GTMCompileAssert is an assert that is meant to fire at compile time if you +// want to check things at compile instead of runtime. For example if you +// want to check that a wchar is 4 bytes instead of 2 you would use +// _GTMCompileAssert(sizeof(wchar_t) == 4, wchar_t_is_4_bytes_on_OS_X) +// Note that the second "arg" is not in quotes, and must be a valid processor +// symbol in it's own right (no spaces, punctuation etc). + +// Wrapping this in an #ifndef allows external groups to define their own +// compile time assert scheme. +#ifndef _GTMCompileAssert +// We got this technique from here: +// http://unixjunkie.blogspot.com/2007/10/better-compile-time-asserts_29.html + +#define _GTMCompileAssertSymbolInner(line, msg) _GTMCOMPILEASSERT ## line ## __ ## msg +#define _GTMCompileAssertSymbol(line, msg) _GTMCompileAssertSymbolInner(line, msg) +#define _GTMCompileAssert(test, msg) \ + typedef char _GTMCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ] +#endif // _GTMCompileAssert + +// ============================================================================ + +// ---------------------------------------------------------------------------- +// 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 --git a/GTMIPhoneUnitTestDelegate.h b/GTMIPhoneUnitTestDelegate.h new file mode 100644 index 0000000..21ba84c --- /dev/null +++ b/GTMIPhoneUnitTestDelegate.h @@ -0,0 +1,29 @@ +// +// GTMIPhoneUnitTestDelegate.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. +// + +// Application delegate that runs all test methods in registered classes +// extending SenTestCase. The application is terminated afterwards. +// You can also run the tests directly from your application by invoking +// gtm_runTests and clean up, restore data, etc. before the application +// terminates. +@interface GTMIPhoneUnitTestDelegate : NSObject +// Runs through all the registered classes and runs test methods on any +// that are subclasses of SenTestCase. Prints results and run time to +// the default output. +- (void)runTests; +@end diff --git a/GTMIPhoneUnitTestDelegate.m b/GTMIPhoneUnitTestDelegate.m new file mode 100644 index 0000000..28d2fe0 --- /dev/null +++ b/GTMIPhoneUnitTestDelegate.m @@ -0,0 +1,160 @@ +// +// GTMIPhoneUnitTestDelegate.m +// +// 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. +// + +#import "GTMIPhoneUnitTestDelegate.h" + +#import "GTMDefines.h" +#if !GTM_IPHONE_SDK +#error GTMIPhoneUnitTestDelegate for iPhone only +#endif +#import +#import +#import +#import "GTMSenTestCase.h" + +// Used for sorting methods below +static int MethodSort(const void *a, const void *b) { + const char *nameA = sel_getName(method_getName(*(Method*)a)); + const char *nameB = sel_getName(method_getName(*(Method*)b)); + return strcmp(nameA, nameB); +} + +@interface UIApplication (iPhoneUnitTestAdditions) +// "Private" method that we need +- (void)terminate; +@end + +@implementation GTMIPhoneUnitTestDelegate + +// Return YES if class is subclass (1 or more generations) of SenTestCase +- (BOOL)isTestFixture:(Class)aClass { + BOOL iscase = NO; + Class testCaseClass = [SenTestCase class]; + Class superclass; + for (superclass = aClass; + !iscase && superclass; + superclass = class_getSuperclass(superclass)) { + iscase = superclass == testCaseClass ? YES : NO; + } + return iscase; +} + +// Run through all the registered classes and run test methods on any +// that are subclasses of SenTestCase. Terminate the application upon +// test completion. +- (void)applicationDidFinishLaunching:(UIApplication *)application { + [self runTests]; + // Using private call to end our tests + [[UIApplication sharedApplication] terminate]; +} + +// Run through all the registered classes and run test methods on any +// that are subclasses of SenTestCase. Print results and run time to +// the default output. +- (void)runTests { + int count = objc_getClassList(NULL, 0); + Class *classes = (Class*)malloc(sizeof(Class) * count); + _GTMDevAssert(classes, @"Couldn't allocate class list"); + objc_getClassList(classes, count); + int suiteSuccesses = 0; + int suiteFailures = 0; + int suiteTotal = 0; + NSString *suiteName = [[NSBundle mainBundle] bundlePath]; + NSDate *suiteStartDate = [NSDate date]; + NSString *suiteStartString = [NSString stringWithFormat:@"Test Suite '%@' started at %@\n", + suiteName, suiteStartDate]; + fputs([suiteStartString UTF8String], stderr); + fflush(stderr); + for (int i = 0; i < count; ++i) { + Class currClass = classes[i]; + if ([self isTestFixture:currClass]) { + NSDate *fixtureStartDate = [NSDate date]; + NSString *fixtureName = NSStringFromClass(currClass); + NSString *fixtureStartString = [NSString stringWithFormat:@"Test Suite '%@' started at %@\n", + fixtureName, fixtureStartDate]; + int fixtureSuccesses = 0; + int fixtureFailures = 0; + int fixtureTotal = 0; + fputs([fixtureStartString UTF8String], stderr); + fflush(stderr); + id testcase = [[currClass alloc] init]; + _GTMDevAssert(testcase, @"Unable to instantiate Test Suite: '%@'\n", + fixtureName); + unsigned int methodCount; + Method *methods = class_copyMethodList(currClass, &methodCount); + // Sort our methods so they are called in Alphabetical order just + // because we can. + qsort(methods, methodCount, sizeof(Method), MethodSort); + for (size_t j = 0; j < methodCount; ++j) { + Method currMethod = methods[j]; + SEL sel = method_getName(currMethod); + const char *name = sel_getName(sel); + // If it starts with test, run it. + if (strstr(name, "test") == name) { + fixtureTotal += 1; + BOOL failed = NO; + NSDate *caseStartDate = [NSDate date]; + @try { + [testcase performTest:sel]; + } @catch (NSException *exception) { + failed = YES; + } + if (failed) { + fixtureFailures += 1; + } else { + fixtureSuccesses += 1; + } + NSTimeInterval caseEndTime = [[NSDate date] timeIntervalSinceDate:caseStartDate]; + NSString *caseEndString = [NSString stringWithFormat:@"Test Case '-[%@ %s]' %s (%0.3f seconds).\n", + fixtureName, name, + failed ? "failed" : "passed", caseEndTime]; + fputs([caseEndString UTF8String], stderr); + fflush(stderr); + } + } + if (methods) { + free(methods); + } + [testcase release]; + NSDate *fixtureEndDate = [NSDate date]; + NSTimeInterval fixtureEndTime = [fixtureEndDate timeIntervalSinceDate:fixtureStartDate]; + NSString *fixtureEndString = [NSString stringWithFormat:@"Test Suite '%@' finished at %@.\n" + "Executed %d tests, with %d failures (%d unexpected) in %0.3f (%0.3f) seconds\n", + fixtureName, fixtureEndDate, fixtureTotal, + fixtureFailures, fixtureFailures, + fixtureEndTime, fixtureEndTime]; + + fputs([fixtureEndString UTF8String], stderr); + fflush(stderr); + suiteTotal += fixtureTotal; + suiteSuccesses += fixtureSuccesses; + suiteFailures += fixtureFailures; + } + } + NSDate *suiteEndDate = [NSDate date]; + NSTimeInterval suiteEndTime = [suiteEndDate timeIntervalSinceDate:suiteStartDate]; + NSString *suiteEndString = [NSString stringWithFormat:@"Test Suite '%@' finished at %@.\n" + "Executed %d tests, with %d failures (%d unexpected) in %0.3f (%0.3f) seconds\n", + suiteName, suiteEndDate, suiteTotal, + suiteFailures, suiteFailures, + suiteEndTime, suiteEndTime]; + fputs([suiteEndString UTF8String], stderr); + fflush(stderr); +} + +@end diff --git a/GTMIPhoneUnitTestMain.m b/GTMIPhoneUnitTestMain.m new file mode 100644 index 0000000..2a0a70d --- /dev/null +++ b/GTMIPhoneUnitTestMain.m @@ -0,0 +1,33 @@ +// +// GTMIPhoneUnitTestMain.m +// +// 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. +// + +#import "GTMDefines.h" +#if !GTM_IPHONE_SDK + #error GTMIPhoneUnitTestMain for iPhone only +#endif +#import + +// Creates an application that runs all tests from classes extending +// SenTestCase, outputs results and test run time, and terminates right +// afterwards. +int main(int argc, char *argv[]) { + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + int retVal = UIApplicationMain(argc, argv, nil, @"GTMIPhoneUnitTestDelegate"); + [pool release]; + return retVal; +} diff --git a/GTMSenTestCase.h b/GTMSenTestCase.h new file mode 100644 index 0000000..5f7856c --- /dev/null +++ b/GTMSenTestCase.h @@ -0,0 +1,1004 @@ +// +// GTMSenTestCase.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. +// + +// Portions of this file fall under the following license, marked with +// SENTE_BEGIN - SENTE_END +// +// Copyright (c) 1997-2005, Sen:te (Sente SA). All rights reserved. +// +// Use of this source code is governed by the following license: +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// (1) Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL Sente SA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Note: this license is equivalent to the FreeBSD license. +// +// This notice may not be removed from this file. + +// Some extra test case macros that would have been convenient for SenTestingKit +// to provide. I didn't stick GTM in front of the Macro names, so that they would +// be easy to remember. + +#import "GTMDefines.h" + +#if (!GTM_IPHONE_SDK) +#import +#else +#import +NSString *STComposeString(NSString *, ...); +#endif + +// Generates a failure when a1 != noErr +// Args: +// a1: should be either an OSErr or an OSStatus +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertNoErr(a1, description, ...) \ +do { \ + @try {\ + OSStatus a1value = (a1); \ + if (a1value != noErr) { \ + NSString *_expression = [NSString stringWithFormat:@"Expected noErr, got %ld for (%s)", a1value, #a1]; \ + if (description) { \ + _expression = [NSString stringWithFormat:@"%@: %@", _expression, STComposeString(description, ##__VA_ARGS__)]; \ + } \ + [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:_expression]]; \ + } \ + }\ + @catch (id anException) {\ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == noErr fails", #a1] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:STComposeString(description, ##__VA_ARGS__)]]; \ + }\ +} while(0) + +// Generates a failure when a1 != a2 +// Args: +// a1: received value. Should be either an OSErr or an OSStatus +// a2: expected value. Should be either an OSErr or an OSStatus +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertErr(a1, a2, description, ...) \ +do { \ + @try {\ + OSStatus a1value = (a1); \ + OSStatus a2value = (a2); \ + if (a1value != a2value) { \ + NSString *_expression = [NSString stringWithFormat:@"Expected %s(%ld) but got %ld for (%s)", #a2, a2value, a1value, #a1]; \ + if (description) { \ + _expression = [NSString stringWithFormat:@"%@: %@", _expression, STComposeString(description, ##__VA_ARGS__)]; \ + } \ + [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:_expression]]; \ + } \ + }\ + @catch (id anException) {\ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == noErr fails", #a1] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:STComposeString(description, ##__VA_ARGS__)]]; \ + }\ +} while(0) + + +// Generates a failure when a1 is NULL +// Args: +// a1: should be a pointer (use STAssertNotNil for an object) +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertNotNULL(a1, description, ...) \ +do { \ + @try {\ + const void* a1value = (a1); \ + if (a1value == NULL) { \ + NSString *_expression = [NSString stringWithFormat:@"(%s) != NULL", #a1]; \ + if (description) { \ + _expression = [NSString stringWithFormat:@"%@: %@", _expression, STComposeString(description, ##__VA_ARGS__)]; \ + } \ + [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:_expression]]; \ + } \ + }\ + @catch (id anException) {\ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) != NULL fails", #a1] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:STComposeString(description, ##__VA_ARGS__)]]; \ + }\ +} while(0) + +// Generates a failure when a1 is not NULL +// Args: +// a1: should be a pointer (use STAssertNil for an object) +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertNULL(a1, description, ...) \ +do { \ + @try {\ + const void* a1value = (a1); \ + if (a1value != NULL) { \ + NSString *_expression = [NSString stringWithFormat:@"(%s) == NULL", #a1]; \ + if (description) { \ + _expression = [NSString stringWithFormat:@"%@: %@", _expression, STComposeString(description, ##__VA_ARGS__)]; \ + } \ + [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:_expression]]; \ + } \ + }\ + @catch (id anException) {\ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == NULL fails", #a1] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:STComposeString(description, ##__VA_ARGS__)]]; \ + }\ +} while(0) + +// Generates a failure when a1 is unequal to a2. This test is for C scalars, +// structs and unions. +// Args: +// a1: argument 1 +// a2: argument 2 +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertNotEquals(a1, a2, description, ...) \ +do { \ + @try {\ + if (@encode(__typeof__(a1)) != @encode(__typeof__(a2))) { \ + [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:[@"Type mismatch -- " stringByAppendingString:STComposeString(description, ##__VA_ARGS__)]]]; \ + } else { \ + __typeof__(a1) a1value = (a1); \ + __typeof__(a2) a2value = (a2); \ + NSValue *a1encoded = [NSValue value:&a1value withObjCType:@encode(__typeof__(a1))]; \ + NSValue *a2encoded = [NSValue value:&a2value withObjCType:@encode(__typeof__(a2))]; \ + if ([a1encoded isEqualToValue:a2encoded]) { \ + NSString *_expression = [NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2]; \ + if (description) { \ + _expression = [NSString stringWithFormat:@"%@: %@", _expression, STComposeString(description, ##__VA_ARGS__)]; \ + } \ + [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:_expression]]; \ + } \ + } \ + } \ + @catch (id anException) {\ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:STComposeString(description, ##__VA_ARGS__)]]; \ + }\ +} while(0) + +// Generates a failure when a1 is equal to a2. This test is for objects. +// Args: +// a1: argument 1. object. +// a2: argument 2. object. +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertNotEqualObjects(a1, a2, desc, ...) \ +do { \ + @try {\ + id a1value = (a1); \ + id a2value = (a2); \ + if ( (@encode(__typeof__(a1value)) == @encode(id)) && \ + (@encode(__typeof__(a2value)) == @encode(id)) && \ + ![(id)a1value isEqual:(id)a2value] ) continue; \ + NSString *_expression = [NSString stringWithFormat:@"%s('%@') != %s('%@')", #a1, [a1 description], #a2, [a2 description]]; \ + if (desc) { \ + _expression = [NSString stringWithFormat:@"%@: %@", _expression, STComposeString(desc, ##__VA_ARGS__)]; \ + } \ + [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:_expression]]; \ + }\ + @catch (id anException) {\ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat: @"(%s) != (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:STComposeString(desc, ##__VA_ARGS__)]]; \ + }\ +} while(0) + +// Generates a failure when a1 is not 'op' to a2. This test is for C scalars. +// Args: +// a1: argument 1 +// a2: argument 2 +// op: operation +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertOperation(a1, a2, op, description, ...) \ +do { \ + @try {\ + if (@encode(__typeof__(a1)) != @encode(__typeof__(a2))) { \ + [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:[@"Type mismatch -- " stringByAppendingString:STComposeString(description, ##__VA_ARGS__)]]]; \ + } else { \ + __typeof__(a1) a1value = (a1); \ + __typeof__(a2) a2value = (a2); \ + if (!(a1value op a2value)) { \ + double a1DoubleValue = a1value; \ + double a2DoubleValue = a2value; \ + NSString *_expression = [NSString stringWithFormat:@"%s (%lg) %s %s (%lg)", #a1, a1DoubleValue, #op, #a2, a2DoubleValue]; \ + if (description) { \ + _expression = [NSString stringWithFormat:@"%@: %@", _expression, STComposeString(description, ##__VA_ARGS__)]; \ + } \ + [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:_expression]]; \ + } \ + } \ + } \ + @catch (id anException) {\ + [self failWithException:[NSException \ + failureInRaise:[NSString stringWithFormat:@"(%s) %s (%s)", #a1, #op, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:STComposeString(description, ##__VA_ARGS__)]]; \ + }\ +} while(0) + +// Generates a failure when a1 is not > a2. This test is for C scalars. +// Args: +// a1: argument 1 +// a2: argument 2 +// op: operation +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertGreaterThan(a1, a2, description, ...) \ + STAssertOperation(a1, a2, >, description, ##__VA_ARGS__) + +// Generates a failure when a1 is not >= a2. This test is for C scalars. +// Args: +// a1: argument 1 +// a2: argument 2 +// op: operation +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertGreaterThanOrEqual(a1, a2, description, ...) \ + STAssertOperation(a1, a2, >=, description, ##__VA_ARGS__) + +// Generates a failure when a1 is not < a2. This test is for C scalars. +// Args: +// a1: argument 1 +// a2: argument 2 +// op: operation +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertLessThan(a1, a2, description, ...) \ + STAssertOperation(a1, a2, <, description, ##__VA_ARGS__) + +// Generates a failure when a1 is not <= a2. This test is for C scalars. +// Args: +// a1: argument 1 +// a2: argument 2 +// op: operation +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertLessThanOrEqual(a1, a2, description, ...) \ + STAssertOperation(a1, a2, <=, description, ##__VA_ARGS__) + +// Generates a failure when string a1 is not equal to string a2. This call +// differs from STAssertEqualObjects in that strings that are different in +// composition (precomposed vs decomposed) will compare equal if their final +// representation is equal. +// ex O + umlaut decomposed is the same as O + umlaut composed. +// Args: +// a1: string 1 +// a2: string 2 +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertEqualStrings(a1, a2, description, ...) \ +do { \ + @try {\ + id a1value = (a1); \ + id a2value = (a2); \ + if (a1value == a2value) continue; \ + if ([a1value isKindOfClass:[NSString class]] && \ + [a2value isKindOfClass:[NSString class]] && \ + [a1value compare:a2value options:0] == NSOrderedSame) continue; \ + [self failWithException:[NSException failureInEqualityBetweenObject: a1value \ + andObject: a2value \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(description, ##__VA_ARGS__)]]; \ + }\ + @catch (id anException) {\ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat: @"(%s) == (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:STComposeString(description, ##__VA_ARGS__)]]; \ + }\ +} while(0) + +// Generates a failure when string a1 is equal to string a2. This call +// differs from STAssertEqualObjects in that strings that are different in +// composition (precomposed vs decomposed) will compare equal if their final +// representation is equal. +// ex O + umlaut decomposed is the same as O + umlaut composed. +// Args: +// a1: string 1 +// a2: string 2 +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertNotEqualStrings(a1, a2, description, ...) \ +do { \ + @try {\ + id a1value = (a1); \ + id a2value = (a2); \ + if ([a1value isKindOfClass:[NSString class]] && \ + [a2value isKindOfClass:[NSString class]] && \ + [a1value compare:a2value options:0] != NSOrderedSame) continue; \ + [self failWithException:[NSException failureInEqualityBetweenObject: a1value \ + andObject: a2value \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(description, ##__VA_ARGS__)]]; \ + }\ + @catch (id anException) {\ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat: @"(%s) != (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:STComposeString(description, ##__VA_ARGS__)]]; \ + }\ +} while(0) + +// Generates a failure when c-string a1 is not equal to c-string a2. +// Args: +// a1: string 1 +// a2: string 2 +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertEqualCStrings(a1, a2, description, ...) \ +do { \ + @try {\ + const char* a1value = (a1); \ + const char* a2value = (a2); \ + if (a1value == a2value) continue; \ + if (strcmp(a1value, a2value) == 0) continue; \ + [self failWithException:[NSException failureInEqualityBetweenObject: [NSString stringWithUTF8String:a1value] \ + andObject: [NSString stringWithUTF8String:a2value] \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(description, ##__VA_ARGS__)]]; \ + }\ + @catch (id anException) {\ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat: @"(%s) == (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:STComposeString(description, ##__VA_ARGS__)]]; \ + }\ +} while(0) + +// Generates a failure when c-string a1 is equal to c-string a2. +// Args: +// a1: string 1 +// a2: string 2 +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertNotEqualCStrings(a1, a2, description, ...) \ +do { \ + @try {\ + const char* a1value = (a1); \ + const char* a2value = (a2); \ + if (strcmp(a1value, a2value) != 0) continue; \ + [self failWithException:[NSException failureInEqualityBetweenObject: [NSString stringWithUTF8String:a1value] \ + andObject: [NSString stringWithUTF8String:a2value] \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(description, ##__VA_ARGS__)]]; \ + }\ + @catch (id anException) {\ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat: @"(%s) != (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:STComposeString(description, ##__VA_ARGS__)]]; \ + }\ +} while(0) + +#if GTM_IPHONE_SDK + +// SENTE_BEGIN +/*" Generates a failure when !{ [a1 isEqualTo:a2] } is false + (or one is nil and the other is not). + _{a1 The object on the left.} + _{a2 The object on the right.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertEqualObjects(a1, a2, description, ...) \ +do { \ + @try {\ + id a1value = (a1); \ + id a2value = (a2); \ + if (a1value == a2value) continue; \ + if ( (@encode(__typeof__(a1value)) == @encode(id)) && \ + (@encode(__typeof__(a2value)) == @encode(id)) && \ + [(id)a1value isEqual: (id)a2value] ) continue; \ + [self failWithException:[NSException failureInEqualityBetweenObject: a1value \ + andObject: a2value \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(description, ##__VA_ARGS__)]]; \ + }\ + @catch (id anException) {\ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat: @"(%s) == (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:STComposeString(description, ##__VA_ARGS__)]]; \ + }\ +} while(0) + + +/*" Generates a failure when a1 is not equal to a2. This test is for + C scalars, structs and unions. + _{a1 The argument on the left.} + _{a2 The argument on the right.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertEquals(a1, a2, description, ...) \ +do { \ + @try {\ + if (@encode(__typeof__(a1)) != @encode(__typeof__(a2))) { \ + [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:[@"Type mismatch -- " stringByAppendingString:STComposeString(description, ##__VA_ARGS__)]]]; \ + } else { \ + __typeof__(a1) a1value = (a1); \ + __typeof__(a2) a2value = (a2); \ + NSValue *a1encoded = [NSValue value:&a1value withObjCType: @encode(__typeof__(a1))]; \ + NSValue *a2encoded = [NSValue value:&a2value withObjCType: @encode(__typeof__(a2))]; \ + if (![a1encoded isEqualToValue:a2encoded]) { \ + [self failWithException:[NSException failureInEqualityBetweenValue: a1encoded \ + andValue: a2encoded \ + withAccuracy: nil \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(description, ##__VA_ARGS__)]]; \ + } \ + } \ + } \ + @catch (id anException) {\ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat: @"(%s) == (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:STComposeString(description, ##__VA_ARGS__)]]; \ + }\ +} while(0) + +#define STAbsoluteDifference(left,right) (MAX(left,right)-MIN(left,right)) + + +/*" Generates a failure when a1 is not equal to a2 within + or - accuracy is false. + This test is for scalars such as floats and doubles where small differences + could make these items not exactly equal, but also works for all scalars. + _{a1 The scalar on the left.} + _{a2 The scalar on the right.} + _{accuracy The maximum difference between a1 and a2 for these values to be + considered equal.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ + +#define STAssertEqualsWithAccuracy(a1, a2, accuracy, description, ...) \ +do { \ + @try {\ + if (@encode(__typeof__(a1)) != @encode(__typeof__(a2))) { \ + [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:[@"Type mismatch -- " stringByAppendingString:STComposeString(description, ##__VA_ARGS__)]]]; \ + } else { \ + __typeof__(a1) a1value = (a1); \ + __typeof__(a2) a2value = (a2); \ + __typeof__(accuracy) accuracyvalue = (accuracy); \ + if (STAbsoluteDifference(a1value, a2value) > accuracyvalue) { \ + NSValue *a1encoded = [NSValue value:&a1value withObjCType:@encode(__typeof__(a1))]; \ + NSValue *a2encoded = [NSValue value:&a2value withObjCType:@encode(__typeof__(a2))]; \ + NSValue *accuracyencoded = [NSValue value:&accuracyvalue withObjCType:@encode(__typeof__(accuracy))]; \ + [self failWithException:[NSException failureInEqualityBetweenValue: a1encoded \ + andValue: a2encoded \ + withAccuracy: accuracyencoded \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(description, ##__VA_ARGS__)]]; \ + } \ + } \ + } \ + @catch (id anException) {\ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat: @"(%s) == (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:STComposeString(description, ##__VA_ARGS__)]]; \ + }\ +} while(0) + + + +/*" Generates a failure unconditionally. + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STFail(description, ...) \ +[self failWithException:[NSException failureInFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(description, ##__VA_ARGS__)]] + + + +/*" Generates a failure when a1 is not nil. + _{a1 An object.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertNil(a1, description, ...) \ +do { \ + @try {\ + id a1value = (a1); \ + if (a1value != nil) { \ + NSString *_a1 = [NSString stringWithUTF8String: #a1]; \ + NSString *_expression = [NSString stringWithFormat:@"((%@) == nil)", _a1]; \ + [self failWithException:[NSException failureInCondition: _expression \ + isTrue: NO \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(description, ##__VA_ARGS__)]]; \ + } \ + }\ + @catch (id anException) {\ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat: @"(%s) == nil fails", #a1] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:STComposeString(description, ##__VA_ARGS__)]]; \ + }\ +} while(0) + + +/*" Generates a failure when a1 is nil. + _{a1 An object.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertNotNil(a1, description, ...) \ +do { \ + @try {\ + id a1value = (a1); \ + if (a1value == nil) { \ + NSString *_a1 = [NSString stringWithUTF8String: #a1]; \ + NSString *_expression = [NSString stringWithFormat:@"((%@) != nil)", _a1]; \ + [self failWithException:[NSException failureInCondition: _expression \ + isTrue: NO \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(description, ##__VA_ARGS__)]]; \ + } \ + }\ + @catch (id anException) {\ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat: @"(%s) != nil fails", #a1] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:STComposeString(description, ##__VA_ARGS__)]]; \ + }\ +} while(0) + + +/*" Generates a failure when expression evaluates to false. + _{expr The expression that is tested.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertTrue(expr, description, ...) \ +do { \ + BOOL _evaluatedExpression = (expr);\ + if (!_evaluatedExpression) {\ + NSString *_expression = [NSString stringWithUTF8String: #expr];\ + [self failWithException:[NSException failureInCondition: _expression \ + isTrue: NO \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while (0) + + +/*" Generates a failure when expression evaluates to false and in addition will + generate error messages if an exception is encountered. + _{expr The expression that is tested.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertTrueNoThrow(expr, description, ...) \ +do { \ + @try {\ + BOOL _evaluatedExpression = (expr);\ + if (!_evaluatedExpression) {\ + NSString *_expression = [NSString stringWithUTF8String: #expr];\ + [self failWithException:[NSException failureInCondition: _expression \ + isTrue: NO \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(description, ##__VA_ARGS__)]]; \ + } \ + } \ + @catch (id anException) {\ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat: @"(%s) ", #expr] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:STComposeString(description, ##__VA_ARGS__)]]; \ + }\ +} while (0) + + +/*" Generates a failure when the expression evaluates to true. + _{expr The expression that is tested.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertFalse(expr, description, ...) \ +do { \ + BOOL _evaluatedExpression = (expr);\ + if (_evaluatedExpression) {\ + NSString *_expression = [NSString stringWithUTF8String: #expr];\ + [self failWithException:[NSException failureInCondition: _expression \ + isTrue: YES \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while (0) + + +/*" Generates a failure when the expression evaluates to true and in addition + will generate error messages if an exception is encountered. + _{expr The expression that is tested.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertFalseNoThrow(expr, description, ...) \ +do { \ + @try {\ + BOOL _evaluatedExpression = (expr);\ + if (_evaluatedExpression) {\ + NSString *_expression = [NSString stringWithUTF8String: #expr];\ + [self failWithException:[NSException failureInCondition: _expression \ + isTrue: YES \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(description, ##__VA_ARGS__)]]; \ + } \ + } \ + @catch (id anException) {\ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat: @"!(%s) ", #expr] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:STComposeString(description, ##__VA_ARGS__)]]; \ + }\ +} while (0) + + +/*" Generates a failure when expression does not throw an exception. + _{expression The expression that is evaluated.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent. +"*/ +#define STAssertThrows(expr, description, ...) \ +do { \ + @try { \ + (expr);\ + } \ + @catch (id anException) { \ + continue; \ + }\ + [self failWithException:[NSException failureInRaise: [NSString stringWithUTF8String:#expr] \ + exception: nil \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(description, ##__VA_ARGS__)]]; \ +} while (0) + + +/*" Generates a failure when expression does not throw an exception of a + specific class. + _{expression The expression that is evaluated.} + _{specificException The specified class of the exception.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertThrowsSpecific(expr, specificException, description, ...) \ +do { \ + @try { \ + (expr);\ + } \ + @catch (specificException *anException) { \ + continue; \ + }\ + @catch (id anException) {\ + NSString *_descrip = STComposeString(@"(Expected exception: %@) %@", NSStringFromClass([specificException class]), description);\ + [self failWithException:[NSException failureInRaise: [NSString stringWithUTF8String:#expr] \ + exception: anException \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(_descrip, ##__VA_ARGS__)]]; \ + continue; \ + }\ + NSString *_descrip = STComposeString(@"(Expected exception: %@) %@", NSStringFromClass([specificException class]), description);\ + [self failWithException:[NSException failureInRaise: [NSString stringWithUTF8String:#expr] \ + exception: nil \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(_descrip, ##__VA_ARGS__)]]; \ +} while (0) + + +/*" Generates a failure when expression does not throw an exception of a + specific class with a specific name. Useful for those frameworks like + AppKit or Foundation that throw generic NSException w/specific names + (NSInvalidArgumentException, etc). + _{expression The expression that is evaluated.} + _{specificException The specified class of the exception.} + _{aName The name of the specified exception.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} + +"*/ +#define STAssertThrowsSpecificNamed(expr, specificException, aName, description, ...) \ +do { \ + @try { \ + (expr);\ + } \ + @catch (specificException *anException) { \ + if ([aName isEqualToString: [anException name]]) continue; \ + NSString *_descrip = STComposeString(@"(Expected exception: %@ (name: %@)) %@", NSStringFromClass([specificException class]), aName, description);\ + [self failWithException: \ + [NSException failureInRaise: [NSString stringWithUTF8String:#expr] \ + exception: anException \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(_descrip, ##__VA_ARGS__)]]; \ + continue; \ + }\ + @catch (id anException) {\ + NSString *_descrip = STComposeString(@"(Expected exception: %@) %@", NSStringFromClass([specificException class]), description);\ + [self failWithException: \ + [NSException failureInRaise: [NSString stringWithUTF8String:#expr] \ + exception: anException \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(_descrip, ##__VA_ARGS__)]]; \ + continue; \ + }\ + NSString *_descrip = STComposeString(@"(Expected exception: %@) %@", NSStringFromClass([specificException class]), description);\ + [self failWithException: \ + [NSException failureInRaise: [NSString stringWithUTF8String:#expr] \ + exception: nil \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(_descrip, ##__VA_ARGS__)]]; \ +} while (0) + + +/*" Generates a failure when expression does throw an exception. + _{expression The expression that is evaluated.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertNoThrow(expr, description, ...) \ +do { \ + @try { \ + (expr);\ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise: [NSString stringWithUTF8String:#expr] \ + exception: anException \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(description, ##__VA_ARGS__)]]; \ + }\ +} while (0) + + +/*" Generates a failure when expression does throw an exception of the specitied + class. Any other exception is okay (i.e. does not generate a failure). + _{expression The expression that is evaluated.} + _{specificException The specified class of the exception.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertNoThrowSpecific(expr, specificException, description, ...) \ +do { \ + @try { \ + (expr);\ + } \ + @catch (specificException *anException) { \ + [self failWithException:[NSException failureInRaise: [NSString stringWithUTF8String:#expr] \ + exception: anException \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(description, ##__VA_ARGS__)]]; \ + }\ + @catch (id anythingElse) {\ + ; \ + }\ +} while (0) + + +/*" Generates a failure when expression does throw an exception of a + specific class with a specific name. Useful for those frameworks like + AppKit or Foundation that throw generic NSException w/specific names + (NSInvalidArgumentException, etc). + _{expression The expression that is evaluated.} + _{specificException The specified class of the exception.} + _{aName The name of the specified exception.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} + +"*/ +#define STAssertNoThrowSpecificNamed(expr, specificException, aName, description, ...) \ +do { \ + @try { \ + (expr);\ + } \ + @catch (specificException *anException) { \ + if ([aName isEqualToString: [anException name]]) { \ + NSString *_descrip = STComposeString(@"(Expected exception: %@ (name: %@)) %@", NSStringFromClass([specificException class]), aName, description);\ + [self failWithException: \ + [NSException failureInRaise: [NSString stringWithUTF8String:#expr] \ + exception: anException \ + inFile: [NSString stringWithUTF8String:__FILE__] \ + atLine: __LINE__ \ + withDescription: STComposeString(_descrip, ##__VA_ARGS__)]]; \ + } \ + continue; \ + }\ + @catch (id anythingElse) {\ + ; \ + }\ +} while (0) + + + +@interface NSException (GTMSenTestAdditions) ++ (NSException *)failureInFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ...; ++ (NSException *)failureInCondition:(NSString *)condition + isTrue:(BOOL)isTrue + inFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ...; ++ (NSException *)failureInEqualityBetweenObject:(id)left + andObject:(id)right + inFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ...; ++ (NSException *)failureInEqualityBetweenValue:(NSValue *)left + andValue:(NSValue *)right + withAccuracy:(NSValue *)accuracy + inFile:(NSString *)filename + atLine:(int) ineNumber + withDescription:(NSString *)formatString, ...; ++ (NSException *)failureInRaise:(NSString *)expression + inFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ...; ++ (NSException *)failureInRaise:(NSString *)expression + exception:(NSException *)exception + inFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ...; +@end + +// SENTE_END + +@interface NSObject (GTMSenTestAdditions) +- (void)failWithException:(NSException*)exception; +@end + +@interface SenTestCase : NSObject { + SEL currentSelector_; +} + +- (void)setUp; +- (void)invokeTest; +- (void)tearDown; +- (void)performTest:(SEL)sel; +@end + +CF_EXPORT NSString * const SenTestFailureException; + +#endif // GTM_IPHONE_SDK + +// All unittest cases in GTM should inherit from GTMTestCase. It makes sure +// to set up our logging system correctly to verify logging calls. +// See GTMUnitTestDevLog.h for details +@interface GTMTestCase : SenTestCase +@end diff --git a/GTMSenTestCase.m b/GTMSenTestCase.m new file mode 100644 index 0000000..f8d7ff3 --- /dev/null +++ b/GTMSenTestCase.m @@ -0,0 +1,211 @@ +// +// GTMSenTestCase.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" + +#if GTM_IPHONE_SDK + +#import + +@implementation NSException (GTMSenTestAdditions) + ++ (NSException *)failureInFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ... { + va_list vl; + va_start(vl, formatString); + NSString *reason = [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + reason = [NSString stringWithFormat:@"%@:%d: error: %@", filename, lineNumber, reason]; + return [NSException exceptionWithName:SenTestFailureException + reason:reason + userInfo:nil]; +} + ++ (NSException *)failureInCondition:(NSString *)condition + isTrue:(BOOL)isTrue + inFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ... { + va_list vl; + va_start(vl, formatString); + NSString *reason = [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + reason = [NSString stringWithFormat:@"condition '%@' is %s : %@", + condition, isTrue ? "TRUE" : "FALSE", reason]; + return [self failureInFile:filename atLine:lineNumber withDescription:reason]; +} + ++ (NSException *)failureInEqualityBetweenObject:(id)left + andObject:(id)right + inFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ... { + va_list vl; + va_start(vl, formatString); + NSString *reason = [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + reason = [NSString stringWithFormat:@"%@ != %@ : %@", + left, right, reason]; + return [self failureInFile:filename atLine:lineNumber withDescription:reason]; +} + ++ (NSException *)failureInEqualityBetweenValue:(NSValue *)left + andValue:(NSValue *)right + withAccuracy:(NSValue *)accuracy + inFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ... { + va_list vl; + va_start(vl, formatString); + NSString *reason = [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + reason = [NSString stringWithFormat:@"%@ != %@ with accuracy %@ : %@", + left, right, accuracy, reason]; + return [self failureInFile:filename atLine:lineNumber withDescription:reason]; +} + ++ (NSException *)failureInRaise:(NSString *)expression + inFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ... { + va_list vl; + va_start(vl, formatString); + NSString *reason = [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + reason = [NSString stringWithFormat:@"failure in raise %@ : %@", + expression, reason]; + return [self failureInFile:filename atLine:lineNumber withDescription:reason]; +} + ++ (NSException *)failureInRaise:(NSString *)expression + exception:(NSException *)exception + inFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ... { + va_list vl; + va_start(vl, formatString); + NSString *reason = [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + reason = [NSString stringWithFormat:@"failure in raise %@ (%@) : %@", + expression, exception, reason]; + return [self failureInFile:filename atLine:lineNumber withDescription:reason]; +} + +@end + +@implementation NSObject (GTMSenTestAdditions) +- (void)failWithException:(NSException*)exception { + [exception raise]; +} + +@end + +NSString *STComposeString(NSString *formatString, ...) { + NSString *reason = @""; + if (formatString) { + va_list vl; + va_start(vl, formatString); + reason = [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + } + return reason; +} + +NSString * const SenTestFailureException = @"SenTestFailureException"; + +@interface SenTestCase (SenTestCasePrivate) +// our method of logging errors +- (void)printError:(NSString *)error; +@end + +@implementation SenTestCase +- (void)setUp { +} + +- (void)performTest:(SEL)sel { + currentSelector_ = sel; + @try { + [self invokeTest]; + } @catch (NSException *exception) { + [self printError:[exception reason]]; + [exception raise]; + } +} + +- (void)printError:(NSString *)error { + if ([error rangeOfString:@"error:"].location == NSNotFound) { + fprintf(stderr, "error: %s\n", [error UTF8String]); + } else { + fprintf(stderr, "%s\n", [error UTF8String]); + } + fflush(stderr); +} + +- (void)invokeTest { + NSException *e = nil; + @try { + // Wrap things in autorelease pools because they may + // have an STMacro in their dealloc which may get called + // when the pool is cleaned up + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + @try { + [self setUp]; + @try { + [self performSelector:currentSelector_]; + } @catch (NSException *exception) { + e = [exception retain]; + [self printError:[exception reason]]; + } + [self tearDown]; + } @catch (NSException *exception) { + e = [exception retain]; + [self printError:[exception reason]]; + } + [pool release]; + } @catch (NSException *exception) { + e = [exception retain]; + [self printError:[exception reason]]; + } + if (e) { + [e autorelease]; + [e raise]; + } +} + +- (void)tearDown { +} +@end + +#endif + +@implementation GTMTestCase : SenTestCase +- (void) invokeTest { + Class devLogClass = NSClassFromString(@"GTMUnitTestDevLog"); + if (devLogClass) { + [devLogClass performSelector:@selector(enableTracking)]; + [devLogClass performSelector:@selector(verifyNoMoreLogsExpected)]; + + } + [super invokeTest]; + if (devLogClass) { + [devLogClass performSelector:@selector(verifyNoMoreLogsExpected)]; + [devLogClass performSelector:@selector(disableTracking)]; + } +} +@end diff --git a/Hpple.xcodeproj/project.pbxproj b/Hpple.xcodeproj/project.pbxproj new file mode 100755 index 0000000..7d606bf --- /dev/null +++ b/Hpple.xcodeproj/project.pbxproj @@ -0,0 +1,446 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 1D3623260D0F684500981E51 /* HppleAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* HppleAppDelegate.m */; }; + 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; + 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; + 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; + 288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765FC0DF74451002DB57D /* CoreGraphics.framework */; }; + 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28AD733E0D9D9553002E5188 /* MainWindow.xib */; }; + 75D785D30F34E06F00173CB6 /* GTMSenTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 75D785CE0F34E06F00173CB6 /* GTMSenTestCase.m */; }; + 75D785D40F34E06F00173CB6 /* GTMIPhoneUnitTestMain.m in Sources */ = {isa = PBXBuildFile; fileRef = 75D785D00F34E06F00173CB6 /* GTMIPhoneUnitTestMain.m */; }; + 75D785D50F34E06F00173CB6 /* GTMIPhoneUnitTestDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 75D785D10F34E06F00173CB6 /* GTMIPhoneUnitTestDelegate.m */; }; + 75D785FA0F34E1D400173CB6 /* TFHppleHTMLTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 75D785F90F34E1D400173CB6 /* TFHppleHTMLTest.m */; }; + 75D786010F34E2FE00173CB6 /* TFHpple.m in Sources */ = {isa = PBXBuildFile; fileRef = 75D786000F34E2FE00173CB6 /* TFHpple.m */; }; + 75D786020F34E2FE00173CB6 /* TFHpple.m in Sources */ = {isa = PBXBuildFile; fileRef = 75D786000F34E2FE00173CB6 /* TFHpple.m */; }; + 75D786330F34E89200173CB6 /* XPathQuery.m in Sources */ = {isa = PBXBuildFile; fileRef = 75D786310F34E89200173CB6 /* XPathQuery.m */; }; + 75D786340F34E89200173CB6 /* XPathQuery.m in Sources */ = {isa = PBXBuildFile; fileRef = 75D786310F34E89200173CB6 /* XPathQuery.m */; }; + 75D786360F34E8A600173CB6 /* libxml2.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 75D786350F34E8A600173CB6 /* libxml2.2.dylib */; }; + 75D786370F34E8A600173CB6 /* libxml2.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 75D786350F34E8A600173CB6 /* libxml2.2.dylib */; }; + 75D786930F34F14500173CB6 /* TFHppleElement.m in Sources */ = {isa = PBXBuildFile; fileRef = 75D786920F34F14500173CB6 /* TFHppleElement.m */; }; + 75D786940F34F14500173CB6 /* TFHppleElement.m in Sources */ = {isa = PBXBuildFile; fileRef = 75D786920F34F14500173CB6 /* TFHppleElement.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 1D3623240D0F684500981E51 /* HppleAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HppleAppDelegate.h; sourceTree = ""; }; + 1D3623250D0F684500981E51 /* HppleAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HppleAppDelegate.m; sourceTree = ""; }; + 1D6058910D05DD3D006BFB54 /* Hpple.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Hpple.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 288765FC0DF74451002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 28AD733E0D9D9553002E5188 /* MainWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; + 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 32CA4F630368D1EE00C91783 /* Hpple_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Hpple_Prefix.pch; sourceTree = ""; }; + 75D785A30F34DFB000173CB6 /* Test.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; name = Test.app; path = "build/Debug-iphoneos/Test.app"; sourceTree = ""; }; + 75D785A50F34DFB000173CB6 /* Test-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Test-Info.plist"; sourceTree = ""; }; + 75D785CE0F34E06F00173CB6 /* GTMSenTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMSenTestCase.m; sourceTree = ""; }; + 75D785CF0F34E06F00173CB6 /* GTMSenTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMSenTestCase.h; sourceTree = ""; }; + 75D785D00F34E06F00173CB6 /* GTMIPhoneUnitTestMain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMIPhoneUnitTestMain.m; sourceTree = ""; }; + 75D785D10F34E06F00173CB6 /* GTMIPhoneUnitTestDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMIPhoneUnitTestDelegate.m; sourceTree = ""; }; + 75D785D20F34E06F00173CB6 /* GTMIPhoneUnitTestDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMIPhoneUnitTestDelegate.h; sourceTree = ""; }; + 75D785D60F34E07D00173CB6 /* GTMDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMDefines.h; sourceTree = ""; }; + 75D785F90F34E1D400173CB6 /* TFHppleHTMLTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TFHppleHTMLTest.m; sourceTree = ""; }; + 75D785FF0F34E2FE00173CB6 /* TFHpple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TFHpple.h; sourceTree = ""; }; + 75D786000F34E2FE00173CB6 /* TFHpple.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TFHpple.m; sourceTree = ""; }; + 75D786310F34E89200173CB6 /* XPathQuery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XPathQuery.m; sourceTree = ""; }; + 75D786320F34E89200173CB6 /* XPathQuery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XPathQuery.h; sourceTree = ""; }; + 75D786350F34E8A600173CB6 /* libxml2.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.2.dylib; path = usr/lib/libxml2.2.dylib; sourceTree = SDKROOT; }; + 75D786910F34F14500173CB6 /* TFHppleElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TFHppleElement.h; sourceTree = ""; }; + 75D786920F34F14500173CB6 /* TFHppleElement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TFHppleElement.m; sourceTree = ""; }; + 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, + 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, + 288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */, + 75D786360F34E8A600173CB6 /* libxml2.2.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 75D785A10F34DFB000173CB6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 75D786370F34E8A600173CB6 /* libxml2.2.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 080E96DDFE201D6D7F000001 /* Classes */ = { + isa = PBXGroup; + children = ( + 1D3623240D0F684500981E51 /* HppleAppDelegate.h */, + 1D3623250D0F684500981E51 /* HppleAppDelegate.m */, + ); + path = Classes; + sourceTree = ""; + }; + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 1D6058910D05DD3D006BFB54 /* Hpple.app */, + 75D785A30F34DFB000173CB6 /* Test.app */, + ); + name = Products; + sourceTree = ""; + }; + 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { + isa = PBXGroup; + children = ( + 75D7859E0F34DF4800173CB6 /* Test */, + 75D7859D0F34DF1D00173CB6 /* Hpple */, + 080E96DDFE201D6D7F000001 /* Classes */, + 29B97315FDCFA39411CA2CEA /* Other Sources */, + 29B97317FDCFA39411CA2CEA /* Resources */, + 29B97323FDCFA39411CA2CEA /* Frameworks */, + 19C28FACFE9D520D11CA2CBB /* Products */, + 75D785A50F34DFB000173CB6 /* Test-Info.plist */, + ); + name = CustomTemplate; + sourceTree = ""; + }; + 29B97315FDCFA39411CA2CEA /* Other Sources */ = { + isa = PBXGroup; + children = ( + 32CA4F630368D1EE00C91783 /* Hpple_Prefix.pch */, + 29B97316FDCFA39411CA2CEA /* main.m */, + 75D786350F34E8A600173CB6 /* libxml2.2.dylib */, + ); + name = "Other Sources"; + sourceTree = ""; + }; + 29B97317FDCFA39411CA2CEA /* Resources */ = { + isa = PBXGroup; + children = ( + 28AD733E0D9D9553002E5188 /* MainWindow.xib */, + 8D1107310486CEB800E47090 /* Info.plist */, + ); + name = Resources; + sourceTree = ""; + }; + 29B97323FDCFA39411CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, + 1D30AB110D05D00D00671497 /* Foundation.framework */, + 288765FC0DF74451002DB57D /* CoreGraphics.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 75D7859D0F34DF1D00173CB6 /* Hpple */ = { + isa = PBXGroup; + children = ( + 75D786300F34E89200173CB6 /* XPath */, + 75D785FF0F34E2FE00173CB6 /* TFHpple.h */, + 75D786000F34E2FE00173CB6 /* TFHpple.m */, + 75D786910F34F14500173CB6 /* TFHppleElement.h */, + 75D786920F34F14500173CB6 /* TFHppleElement.m */, + ); + name = Hpple; + sourceTree = ""; + }; + 75D7859E0F34DF4800173CB6 /* Test */ = { + isa = PBXGroup; + children = ( + 75D785A90F34DFBE00173CB6 /* GTM */, + 75D785F90F34E1D400173CB6 /* TFHppleHTMLTest.m */, + ); + name = Test; + sourceTree = ""; + }; + 75D785A90F34DFBE00173CB6 /* GTM */ = { + isa = PBXGroup; + children = ( + 75D785D60F34E07D00173CB6 /* GTMDefines.h */, + 75D785CE0F34E06F00173CB6 /* GTMSenTestCase.m */, + 75D785CF0F34E06F00173CB6 /* GTMSenTestCase.h */, + 75D785D00F34E06F00173CB6 /* GTMIPhoneUnitTestMain.m */, + 75D785D10F34E06F00173CB6 /* GTMIPhoneUnitTestDelegate.m */, + 75D785D20F34E06F00173CB6 /* GTMIPhoneUnitTestDelegate.h */, + ); + name = GTM; + sourceTree = ""; + }; + 75D786300F34E89200173CB6 /* XPath */ = { + isa = PBXGroup; + children = ( + 75D786310F34E89200173CB6 /* XPathQuery.m */, + 75D786320F34E89200173CB6 /* XPathQuery.h */, + ); + name = XPath; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 1D6058900D05DD3D006BFB54 /* Hpple */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "Hpple" */; + buildPhases = ( + 1D60588D0D05DD3D006BFB54 /* Resources */, + 1D60588E0D05DD3D006BFB54 /* Sources */, + 1D60588F0D05DD3D006BFB54 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Hpple; + productName = Hpple; + productReference = 1D6058910D05DD3D006BFB54 /* Hpple.app */; + productType = "com.apple.product-type.application"; + }; + 75D785A20F34DFB000173CB6 /* Test */ = { + isa = PBXNativeTarget; + buildConfigurationList = 75D785A80F34DFB100173CB6 /* Build configuration list for PBXNativeTarget "Test" */; + buildPhases = ( + 75D7859F0F34DFB000173CB6 /* Resources */, + 75D785A00F34DFB000173CB6 /* Sources */, + 75D785A10F34DFB000173CB6 /* Frameworks */, + 75D785DA0F34E0CB00173CB6 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Test; + productName = Test; + productReference = 75D785A30F34DFB000173CB6 /* Test.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Hpple" */; + compatibilityVersion = "Xcode 3.1"; + hasScannedForEncodings = 1; + mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 1D6058900D05DD3D006BFB54 /* Hpple */, + 75D785A20F34DFB000173CB6 /* Test */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 1D60588D0D05DD3D006BFB54 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 75D7859F0F34DFB000173CB6 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 75D785DA0F34E0CB00173CB6 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/UnitTesting/RunIPhoneUnitTest.sh\""; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 1D60588E0D05DD3D006BFB54 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1D60589B0D05DD56006BFB54 /* main.m in Sources */, + 1D3623260D0F684500981E51 /* HppleAppDelegate.m in Sources */, + 75D786010F34E2FE00173CB6 /* TFHpple.m in Sources */, + 75D786330F34E89200173CB6 /* XPathQuery.m in Sources */, + 75D786930F34F14500173CB6 /* TFHppleElement.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 75D785A00F34DFB000173CB6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 75D785D30F34E06F00173CB6 /* GTMSenTestCase.m in Sources */, + 75D785D40F34E06F00173CB6 /* GTMIPhoneUnitTestMain.m in Sources */, + 75D785D50F34E06F00173CB6 /* GTMIPhoneUnitTestDelegate.m in Sources */, + 75D785FA0F34E1D400173CB6 /* TFHppleHTMLTest.m in Sources */, + 75D786020F34E2FE00173CB6 /* TFHpple.m in Sources */, + 75D786340F34E89200173CB6 /* XPathQuery.m in Sources */, + 75D786940F34F14500173CB6 /* TFHppleElement.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1D6058940D05DD3E006BFB54 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Geoffrey Grosenbach"; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Hpple_Prefix.pch; + INFOPLIST_FILE = Info.plist; + PRODUCT_NAME = Hpple; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "CD1F1B03-3E48-4552-ABEF-FDFFFA2F6956"; + }; + name = Debug; + }; + 1D6058950D05DD3E006BFB54 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Hpple_Prefix.pch; + INFOPLIST_FILE = Info.plist; + PRODUCT_NAME = Hpple; + }; + name = Release; + }; + 75D785A60F34DFB100173CB6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/UIKit.framework/Headers/UIKit.h"; + INFOPLIST_FILE = "Test-Info.plist"; + INSTALL_PATH = "$(HOME)/Applications"; + OTHER_LDFLAGS = ( + "-framework", + Foundation, + "-framework", + UIKit, + ); + PREBINDING = NO; + PRODUCT_NAME = Test; + SDKROOT = iphoneos2.2.1; + }; + name = Debug; + }; + 75D785A70F34DFB100173CB6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/UIKit.framework/Headers/UIKit.h"; + INFOPLIST_FILE = "Test-Info.plist"; + INSTALL_PATH = "$(HOME)/Applications"; + OTHER_LDFLAGS = ( + "-framework", + Foundation, + "-framework", + UIKit, + ); + PREBINDING = NO; + PRODUCT_NAME = Test; + SDKROOT = iphoneos2.2.1; + ZERO_LINK = NO; + }; + name = Release; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Geoffrey Grosenbach"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.sdk/usr/include/libxml2; + ONLY_ACTIVE_ARCH = YES; + PREBINDING = NO; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "CD1F1B03-3E48-4552-ABEF-FDFFFA2F6956"; + SDKROOT = iphoneos2.2.1; + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = iphoneos2.2.1; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "Hpple" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1D6058940D05DD3E006BFB54 /* Debug */, + 1D6058950D05DD3E006BFB54 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 75D785A80F34DFB100173CB6 /* Build configuration list for PBXNativeTarget "Test" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 75D785A60F34DFB100173CB6 /* Debug */, + 75D785A70F34DFB100173CB6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Hpple" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + C01FCF5008A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/Hpple_Prefix.pch b/Hpple_Prefix.pch new file mode 100644 index 0000000..68f0697 --- /dev/null +++ b/Hpple_Prefix.pch @@ -0,0 +1,8 @@ +// +// Prefix header for all source files of the 'Hpple' target in the 'Hpple' project +// + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/Info.plist b/Info.plist new file mode 100644 index 0000000..80f6fe0 --- /dev/null +++ b/Info.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.topfunky.${PRODUCT_NAME:identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + NSMainNibFile + MainWindow + + diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..8adbad2 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (c) 2009 Topfunky Corporation, http://topfunky.com + +MIT LICENSE + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/MainWindow.xib b/MainWindow.xib new file mode 100644 index 0000000..7367a3c --- /dev/null +++ b/MainWindow.xib @@ -0,0 +1,180 @@ + + + + 528 + 9E17 + 672 + 949.33 + 352.00 + + YES + + + + YES + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + YES + + IBFilesOwner + + + IBFirstResponder + + + + + 1316 + + {320, 480} + + + 1 + MSAxIDEAA + + NO + NO + + + + + + YES + + + delegate + + + + 4 + + + + window + + + + 5 + + + + + YES + + 0 + + YES + + + + + + 2 + + + YES + + + + + -1 + + + RmlsZSdzIE93bmVyA + + + 3 + + + + + -2 + + + + + + + YES + + YES + -1.CustomClassName + -2.CustomClassName + 2.IBAttributePlaceholdersKey + 2.IBEditorWindowLastContentRect + 2.IBPluginDependency + 3.CustomClassName + 3.IBPluginDependency + + + YES + UIApplication + UIResponder + + YES + + YES + + + YES + + + {{438, 320}, {320, 480}} + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + HppleAppDelegate + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + YES + + YES + + + YES + + + + + YES + + YES + + + YES + + + + 9 + + + + YES + + HppleAppDelegate + NSObject + + window + UIWindow + + + IBProjectSource + Classes/HppleAppDelegate.h + + + + HppleAppDelegate + NSObject + + IBUserSource + + + + + + 0 + Hpple.xcodeproj + 3 + + diff --git a/README.markdown b/README.markdown new file mode 100644 index 0000000..091f17d --- /dev/null +++ b/README.markdown @@ -0,0 +1,46 @@ +# DESCRIPTION + +Hpple: A nice Objective-C wrapper on the XPathQuery library for parsing HTML. + +Inspired by why the lucky stiff's [Hpricot](http://github.com/why/hpricot/tree/master). + +# AUTHOR + +Geoffrey Grosenbach, [Topfunky Corporation](http://topfunky.com) and [PeepCode Screencasts](http://peepcode.com). + +# FEATURES + +* Easy searching by XPath (CSS selectors are planned) +* Parses HTML (XML coming soon) +* Easy access to tag content, name, and attributes. + +# INSTALLATION + +* Open your XCode project and the Hpple project. +* Drag the "Hpple" directory to your project. +* Add the libxml2.2.dylib framework to your project and search paths as described at [Cocoa with Love](http://cocoawithlove.com/2008/10/using-libxml2-for-parsing-and-xpath.html) + +More documentation and short screencast coming soon... + +# USAGE + +See TFHppleHTMLTest.m in the Hpple project for samples. + +
+#import "Hpple.h"
+
+NSData * data      = [NSData dataWithContentsOfFile:@"index.html"];
+NSArray * elements = [doc search:@"//a[@class='sponsor']"];
+
+TFHppleElement * element = [elements objectAtIndex:0];
+[e content];              // Tag's innerHTML
+[e tagName];              // "a"
+[e attributes];           // NSDictionary of href, class, id, etc.
+[e objectForKey:@"href"]; // Easy access to single attribute
+
+
+ +# TODO + +* Internal error catching and messages +* CSS3 selectors in addition to XPath diff --git a/TFHpple.h b/TFHpple.h new file mode 100644 index 0000000..4ee0c7d --- /dev/null +++ b/TFHpple.h @@ -0,0 +1,45 @@ +// +// TFHpple.h +// Hpple +// +// Created by Geoffrey Grosenbach on 1/31/09. +// +// Copyright (c) 2009 Topfunky Corporation, http://topfunky.com +// +// MIT LICENSE +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +#import + +#import "TFHppleElement.h" + +@interface TFHpple : NSObject { + NSData * data; +} + +- (id) initWithHTMLData:(NSData *)theData; +- (NSArray *) search:(NSString *)xPathOrCSS; +- (TFHppleElement *) at:(NSString *)xPathOrCSS; + +@property (retain) NSData * data; + +@end diff --git a/TFHpple.m b/TFHpple.m new file mode 100644 index 0000000..251fd8e --- /dev/null +++ b/TFHpple.m @@ -0,0 +1,73 @@ +// +// TFHpple.m +// Hpple +// +// Created by Geoffrey Grosenbach on 1/31/09. +// +// Copyright (c) 2009 Topfunky Corporation, http://topfunky.com +// +// MIT LICENSE +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "TFHpple.h" +#import "XPathQuery.h" + +@implementation TFHpple + +@synthesize data; + +- (void) dealloc +{ + [data release]; + + [super dealloc]; +} + +- (id) initWithHTMLData:(NSData *)theData +{ + if (!(self = [super init])) + return nil; + + self.data = theData; + + return self; +} + +- (NSArray *) search:(NSString *)xPathOrCSS +{ + NSArray * detailNodes = PerformHTMLXPathQuery(data, xPathOrCSS); + + NSMutableArray * hppleElements = [NSMutableArray array]; + for (id node in detailNodes) + { + TFHppleElement * e = [[TFHppleElement alloc] initWithNode:node]; + [hppleElements addObject:e]; + [e release]; + } + return hppleElements; +} + +- (TFHppleElement *) at:(NSString *)xPathOrCSS +{ + return [[self search:xPathOrCSS] objectAtIndex:0]; +} + +@end diff --git a/TFHppleElement.h b/TFHppleElement.h new file mode 100644 index 0000000..11de176 --- /dev/null +++ b/TFHppleElement.h @@ -0,0 +1,54 @@ +// +// TFHppleElement.h +// Hpple +// +// Created by Geoffrey Grosenbach on 1/31/09. +// +// Copyright (c) 2009 Topfunky Corporation, http://topfunky.com +// +// MIT LICENSE +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + + +@interface TFHppleElement : NSObject { + NSDictionary * node; +} + +- (id) initWithNode:(NSDictionary *) theNode; + +// Returns this tag's innerHTML content. +- (NSString *) content; + +// Returns the name of the current tag, such as "h3". +- (NSString *) tagName; + +// Returns tag attributes with name as key and content as value. +// href = 'http://peepcode.com' +// class = 'highlight' +- (NSDictionary *) attributes; + +// Provides easy access to the content of a specific attribute, +// such as 'href' or 'class'. +- (NSString *) objectForKey:(NSString *) theKey; + +@end diff --git a/TFHppleElement.m b/TFHppleElement.m new file mode 100644 index 0000000..cb4460c --- /dev/null +++ b/TFHppleElement.m @@ -0,0 +1,91 @@ +// +// TFHppleElement.m +// Hpple +// +// Created by Geoffrey Grosenbach on 1/31/09. +// +// Copyright (c) 2009 Topfunky Corporation, http://topfunky.com +// +// MIT LICENSE +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +#import "TFHppleElement.h" + +NSString * const TFHppleNodeContentKey = @"nodeContent"; +NSString * const TFHppleNodeNameKey = @"nodeName"; +NSString * const TFHppleNodeAttributeArrayKey = @"nodeAttributeArray"; +NSString * const TFHppleNodeAttributeNameKey = @"attributeName"; + +@implementation TFHppleElement + +- (void) dealloc +{ + [node release]; + + [super dealloc]; +} + +- (id) initWithNode:(NSDictionary *) theNode +{ + if (!(self = [super init])) + return nil; + + [theNode retain]; + node = theNode; + + return self; +} + + +- (NSString *) content +{ + return [node objectForKey:TFHppleNodeContentKey]; +} + + +- (NSString *) tagName +{ + return [node objectForKey:TFHppleNodeNameKey]; +} + +- (NSDictionary *) attributes +{ + NSMutableDictionary * translatedAttributes = [NSMutableDictionary dictionary]; + for (NSDictionary * attributeDict in [node objectForKey:TFHppleNodeAttributeArrayKey]) + { + [translatedAttributes setObject:[attributeDict objectForKey:TFHppleNodeContentKey] + forKey:[attributeDict objectForKey:TFHppleNodeAttributeNameKey]]; + } + return translatedAttributes; +} + +- (NSString *) objectForKey:(NSString *) theKey +{ + return [[self attributes] objectForKey:theKey]; +} + +- (id) description +{ + return [node description]; +} + +@end diff --git a/TFHppleHTMLTest.m b/TFHppleHTMLTest.m new file mode 100644 index 0000000..1c2ae78 --- /dev/null +++ b/TFHppleHTMLTest.m @@ -0,0 +1,119 @@ +// +// TFHppleTest.m +// Hpple +// +// Created by Geoffrey Grosenbach on 1/31/09. +// +// Copyright (c) 2009 Topfunky Corporation, http://topfunky.com +// +// MIT LICENSE +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +#import "GTMSenTestCase.h" +#import "TFHpple.h" + +#define TEST_HTML_DOCUMENT_PATH @"UnitTesting/TestData/index.html" + +@interface TFHppleHTMLTest : GTMTestCase +{ + TFHpple * doc; +} +@end + +@implementation TFHppleHTMLTest + +- (void) dealloc { [super dealloc]; } + +- (void) setUp +{ + NSData * data = [NSData dataWithContentsOfFile:TEST_HTML_DOCUMENT_PATH]; + doc = [[TFHpple alloc] initWithHTMLData:data]; +} + +- (void) tearDown +{ + [doc release]; +} + +- (void) testInitializesWithHTMLData +{ + STAssertNotNil(doc.data, nil); + STAssertEqualObjects([doc className], @"TFHpple", nil); +} + +// doc.search("//p[@class='posted']") +- (void) testSearchesWithXPath +{ + NSArray * a = [doc search:@"//a[@class='sponsor']"]; + STAssertEquals((int)[a count], 2, nil); + + TFHppleElement * e = [a objectAtIndex:0]; + STAssertEqualObjects([e className], @"TFHppleElement", nil); +} + +- (void) testFindsFirstElementAtXPath +{ + TFHppleElement * e = [doc at:@"//a[@class='sponsor']"]; + + STAssertEqualObjects([e content], @"RailsMachine", nil); + STAssertEqualObjects([e tagName], @"a", nil); +} + +- (void) testSearchesByNestedXPath +{ + NSArray * a = [doc search:@"//div[@class='column']//strong"]; + STAssertEquals((int)[a count], 5, nil); + + TFHppleElement * e = [a objectAtIndex:0]; + STAssertEqualObjects([e content], @"PeepCode", nil); +} + +- (void) testPopulatesAttributes +{ + TFHppleElement * e = [doc at:@"//a[@class='sponsor']"]; + + STAssertEqualObjects([[e attributes] className], @"NSCFDictionary", nil); + STAssertEqualObjects([[e attributes] objectForKey:@"href"], @"http://railsmachine.com/", nil); +} + +- (void) testProvidesEasyAccessToAttributes +{ + TFHppleElement * e = [doc at:@"//a[@class='sponsor']"]; + + STAssertEqualObjects([e objectForKey:@"href"], @"http://railsmachine.com/", nil); +} + +// doc.at("body")['onload'] + + +// (doc/"#elementID").inner_html + + +// (doc/"#elementID").to_html + +// doc.at("div > div:nth(1)").css_path + +// doc.at("div > div:nth(1)").xpath + + + +@end diff --git a/Test-Info.plist b/Test-Info.plist new file mode 100644 index 0000000..1d48abf --- /dev/null +++ b/Test-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.topfunky.${PRODUCT_NAME:identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSMainNibFile + MainWindow + + diff --git a/UnitTesting/RunIPhoneUnitTest.sh b/UnitTesting/RunIPhoneUnitTest.sh new file mode 100755 index 0000000..50709d3 --- /dev/null +++ b/UnitTesting/RunIPhoneUnitTest.sh @@ -0,0 +1,24 @@ +#!/bin/sh +# RunIPhoneUnitTest.sh +# 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. +# +# Runs all unittests through the iPhone simulator + +export DYLD_ROOT_PATH="$SDKROOT" +export DYLD_FRAMEWORK_PATH="$CONFIGURATION_BUILD_DIR" +export IPHONE_SIMULATOR_ROOT="$SDKROOT" +export CFFIXED_USER_HOME="$USER_LIBRARY_DIR/Application Support/iPhone Simulator/User" +"$TARGET_BUILD_DIR/$EXECUTABLE_PATH" -RegisterForSystemEvents +exit 0 diff --git a/UnitTesting/TestData/index.html b/UnitTesting/TestData/index.html new file mode 100644 index 0000000..6001460 --- /dev/null +++ b/UnitTesting/TestData/index.html @@ -0,0 +1,622 @@ + + + + + Professional Screencast Tutorials | PeepCode Screencasts for Web Developers and Alpha Geeks + + + + + + + + + + +
+
+

PeepCode

+ +

+ Meet-merb-pdf-draft +

+

PeepCode Screencasts are a high-intensity way to learn Ruby on Rails website development.

+ + +

Experienced developers have said that PeepCode is “fantastic and the price is a steal.” Designer/developers have said they are “exactly the type of instruction I need to pick up new things and understand how they work.” Others have said they are “phenomenal”, “quality” and “totally worth more to me than $9!”

+ + +

A new hour-long video screencast is released each month. Rails from Scratch Part I and II are available now.

+ + +

Buy a single episode or subscribe today! Team and site licenses are also available.

+ + +
    +
  • Full downloads…no DRM or restrictive browser-only viewing.
  • +
  • Every episode available in iPod format for viewing on the road.
  • +
  • Full source code provided with every episode.
  • +
  • Chapter track on most screencasts for easy navigation.
  • +
  • Cutting-edge topics
  • +
  • Bulk purchases available for companies or teams.
  • +
  • Some screencasts available in Ogg Theora format (currently available for Git, Rails from Scratch Part I and Part II).
  • +
+ + +

Do you have a coupon code? Login or signup and enter it on your account page.

+ + +

Speedy Delivery!

+ + +

We’ve upgraded our bandwidth and have implemented a new download system that should be much faster than the old one. Try it out and let us know how it works for you.

+ + +

Suggestions

+ + +

Topic suggestions are welcome via email or at our suggestion box.

+ + +

T-Shirts

+ + +

PeepCode t-shirts are now available! Get yours at RubyRags! For Men and Women.

+
+
+ Rails101 + + +

+ Free Samples +

+ +

+ What People Are Saying About PeepCode +

+
+ “PeepCode is awesome!” + + Tim O'Reilly, O'Reilly Media + +
+
+ “These things are fantastic and the price is a steal. I strongly urge you to support this effort and buy the episodes. What a terrific way to learn!” + + Scott Barron, Rails Core Committer + +
+
+ “The quality and content of the screencasts + are phenomenal...PeepCode is the first referral I give friends looking to dive into specific topics.” + + Shai Shefer + +
+
+ “PeepCode on productivity raises the bar, way higher than it's ever been before.” + + Giles Bowkett + +
+
+ “[The Haml and Sass screencast was] very helpful. I've been wanting to learn both of these for a long time. I personally learn faster with screencasts and this one gave me a good jumping off point.” + + Matthew Nichols, Co-Founder of TagCow + +
+

+ → More Reviews +

+
+
+ Rspec + + +

+ Have a Coupon? +

+

+ Login or signup and enter the code on your account page. If it is still valid you will be able to browse the list of products and redeem an episode. +

+ +
+
+ + + + + + diff --git a/XPathQuery.h b/XPathQuery.h new file mode 100644 index 0000000..86e22d7 --- /dev/null +++ b/XPathQuery.h @@ -0,0 +1,10 @@ +// +// XPathQuery.h +// FuelFinder +// +// Created by Matt Gallagher on 4/08/08. +// Copyright 2008 __MyCompanyName__. All rights reserved. +// + +NSArray *PerformHTMLXPathQuery(NSData *document, NSString *query); +NSArray *PerformXMLXPathQuery(NSData *document, NSString *query); \ No newline at end of file diff --git a/XPathQuery.m b/XPathQuery.m new file mode 100644 index 0000000..e80107f --- /dev/null +++ b/XPathQuery.m @@ -0,0 +1,184 @@ +// +// XPathQuery.m +// FuelFinder +// +// Created by Matt Gallagher on 4/08/08. +// Copyright 2008 __MyCompanyName__. All rights reserved. +// + +#import "XPathQuery.h" + +#import +#import +#import +#import +#import + +NSDictionary *DictionaryForNode(xmlNodePtr currentNode, NSMutableDictionary *parentResult) +{ + NSMutableDictionary *resultForNode = [NSMutableDictionary dictionary]; + + if (currentNode->name) + { + NSString *currentNodeContent = + [NSString stringWithCString:(const char *)currentNode->name encoding:NSUTF8StringEncoding]; + [resultForNode setObject:currentNodeContent forKey:@"nodeName"]; + } + + if (currentNode->content && currentNode->content != (xmlChar *)-1) + { + NSString *currentNodeContent = + [NSString stringWithCString:(const char *)currentNode->content encoding:NSUTF8StringEncoding]; + + if ([[resultForNode objectForKey:@"nodeName"] isEqual:@"text"] && parentResult) + { + [parentResult + setObject: + [currentNodeContent + stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] + forKey:@"nodeContent"]; + return nil; + } + + [resultForNode setObject:currentNodeContent forKey:@"nodeContent"]; + } + + xmlAttr *attribute = currentNode->properties; + if (attribute) + { + NSMutableArray *attributeArray = [NSMutableArray array]; + while (attribute) + { + NSMutableDictionary *attributeDictionary = [NSMutableDictionary dictionary]; + NSString *attributeName = + [NSString stringWithCString:(const char *)attribute->name encoding:NSUTF8StringEncoding]; + if (attributeName) + { + [attributeDictionary setObject:attributeName forKey:@"attributeName"]; + } + + if (attribute->children) + { + NSDictionary *childDictionary = DictionaryForNode(attribute->children, attributeDictionary); + if (childDictionary) + { + [attributeDictionary setObject:childDictionary forKey:@"attributeContent"]; + } + } + + if ([attributeDictionary count] > 0) + { + [attributeArray addObject:attributeDictionary]; + } + attribute = attribute->next; + } + + if ([attributeArray count] > 0) + { + [resultForNode setObject:attributeArray forKey:@"nodeAttributeArray"]; + } + } + + xmlNodePtr childNode = currentNode->children; + if (childNode) + { + NSMutableArray *childContentArray = [NSMutableArray array]; + while (childNode) + { + NSDictionary *childDictionary = DictionaryForNode(childNode, resultForNode); + if (childDictionary) + { + [childContentArray addObject:childDictionary]; + } + childNode = childNode->next; + } + if ([childContentArray count] > 0) + { + [resultForNode setObject:childContentArray forKey:@"nodeChildArray"]; + } + } + + return resultForNode; +} + +NSArray *PerformXPathQuery(xmlDocPtr doc, NSString *query) +{ + xmlXPathContextPtr xpathCtx; + xmlXPathObjectPtr xpathObj; + + /* Create xpath evaluation context */ + xpathCtx = xmlXPathNewContext(doc); + if(xpathCtx == NULL) + { + NSLog(@"Unable to create XPath context."); + return nil; + } + + /* Evaluate xpath expression */ + xpathObj = xmlXPathEvalExpression((xmlChar *)[query cStringUsingEncoding:NSUTF8StringEncoding], xpathCtx); + if(xpathObj == NULL) { + NSLog(@"Unable to evaluate XPath."); + return nil; + } + + xmlNodeSetPtr nodes = xpathObj->nodesetval; + if (!nodes) + { + NSLog(@"Nodes was nil."); + return nil; + } + + NSMutableArray *resultNodes = [NSMutableArray array]; + for (NSInteger i = 0; i < nodes->nodeNr; i++) + { + NSDictionary *nodeDictionary = DictionaryForNode(nodes->nodeTab[i], nil); + if (nodeDictionary) + { + [resultNodes addObject:nodeDictionary]; + } + } + + /* Cleanup */ + xmlXPathFreeObject(xpathObj); + xmlXPathFreeContext(xpathCtx); + + return resultNodes; +} + +NSArray *PerformHTMLXPathQuery(NSData *document, NSString *query) +{ + xmlDocPtr doc; + + /* Load XML document */ + doc = htmlReadMemory([document bytes], [document length], "", NULL, HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR); + + if (doc == NULL) + { + NSLog(@"Unable to parse."); + return nil; + } + + NSArray *result = PerformXPathQuery(doc, query); + xmlFreeDoc(doc); + + return result; +} + +NSArray *PerformXMLXPathQuery(NSData *document, NSString *query) +{ + xmlDocPtr doc; + + /* Load XML document */ + doc = xmlReadMemory([document bytes], [document length], "", NULL, XML_PARSE_RECOVER); + + if (doc == NULL) + { + NSLog(@"Unable to parse."); + return nil; + } + + NSArray *result = PerformXPathQuery(doc, query); + xmlFreeDoc(doc); + + return result; +} diff --git a/main.m b/main.m new file mode 100644 index 0000000..bae17b4 --- /dev/null +++ b/main.m @@ -0,0 +1,17 @@ +// +// main.m +// Hpple +// +// Created by Geoffrey Grosenbach on 1/31/09. +// Copyright Topfunky Corporation 2009. All rights reserved. +// + +#import + +int main(int argc, char *argv[]) { + + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + int retVal = UIApplicationMain(argc, argv, nil, nil); + [pool release]; + return retVal; +}