From 93401e4054735aee6efcd79efaee7b0767cd8690 Mon Sep 17 00:00:00 2001 From: iska Date: Sat, 30 Jan 2016 14:12:45 +0100 Subject: [PATCH 01/18] Update badges in README.md --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 306588e..949d8a9 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,15 @@ # HTMLKit -![HTMLKit Logo](HTMLKit.png) +![HTMLKit Logo](https://raw.githubusercontent.com/iabudiab/HTMLKit/master/HTMLKit.png) An Objective-C framework for your everyday HTML needs. -[![Build Status](https://travis-ci.org/iabudiab/HTMLKit.svg?branch=develop)](https://travis-ci.org/iabudiab/HTMLKit) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![License MIT](https://img.shields.io/badge/license-MIT-4481C7.svg)](https://opensource.org/licenses/MIT) +[![Build Status](https://img.shields.io/travis/iabudiab/HTMLKit/develop.svg?style=flat)](https://travis-ci.org/iabudiab/HTMLKit) +[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) +[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/HTMLKit.svg?style=flat)](https://cocoapods.org/pods/HTMLKit) +[![CocoaDocs](https://img.shields.io/cocoapods/metrics/doc-percent/HTMLKit.svg?style=flat)](http://cocoadocs.org/docsets/HTMLKit) +[![Platform](https://img.shields.io/cocoapods/p/HTMLKit.svg?style=flat)](http://cocoadocs.org/docsets/HTMLKit) +[![License MIT](https://img.shields.io/badge/license-MIT-4481C7.svg?style=flat)](https://opensource.org/licenses/MIT) # Quick Overview From 75138cc35fda0e4d23e06b7da567203674ba4099 Mon Sep 17 00:00:00 2001 From: iska Date: Mon, 1 Feb 2016 22:07:43 +0100 Subject: [PATCH 02/18] Add CHANGELOG.md --- CHANGELOG.md | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 6 +++- 2 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..b8b2249 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,98 @@ +# Change Log + +## [0.9.1](https://github.com/iabudiab/HTMLKit/releases/tag/0.3.0) + +Released on 2016.01.29 + +### Added + +- Travis-CI integration. +- CocoaPods spec. + + +### Changed + +- Warnings are treated as errors. + +### Fixed + +- Warnings related to format specifier and loss of precision due to NS(U)-integer usage. +- Replaced `@returns` with `@return` throughout the documentation to play nicely with Jazzy. +- Some README examples used Swift syntax. + +## [0.9.0](https://github.com/iabudiab/HTMLKit/releases/tag/0.3.0) + +Released on 2015.12.23 + +This is the first public release of `HTMLKit`. + +### Added + +- `iOS` & `OSX` Frameworks. +- Source code documentation. +- CSS Selectors extension (analogous to jQuery selectors). +- `DOMTokenList` for malipulating `HTMLElements` attributes as a list, e.g. `class`. +- Handling for `` elements in the Parser implementation. + - Updated HTML5Lib-Tests submodule (56c435f) +- Xcode Playground with Swift documentation. + +### Removed + +- Unused namespaces. +- Historical node types. + + +### Fixed + +- `lt`, `gt` & `eq` CSS Selectors method declarations. + +## [0.3.0](https://github.com/iabudiab/HTMLKit/releases/tag/0.3.0) + +Released on 2015.11.29 + +### Added + +- CSS3 Selectors support. +- Nullability annotations. +- `HTMLNode` properties for previous and next sibling elements. +- `HTMLNode` methods for accessing child elements (analogous to child nodes). +- `NSCharacterSet` category for HTML-related character sets. + +### Fixed + +- `InputStreaReader`'s reconsume-logic that is required by the CSS Parser. + +## [0.2.0](https://github.com/iabudiab/HTMLKit/releases/tag/0.1.0) + +Released on 2015.06.06 + +### Added + +- `HTMLDocument` methods to access `root`, `head` & `body` elements. +- `innerHTML` implementation for the `HTMLElement`. +- `HTMLNode` methods to append, prepend, check containment and descendancy of nodes. +- `HTMLNode` methods to enumerate child nodes. +- Implementations for `NodeIterator` and `NodeFilter` +- Implementation for `TreeWalker` +- Validation for DOM manipulations. +- Tests for the DOM implementation. + +### Changed + +- `type` property renamed to `nodeType` in `HTMLNode`. +- `firstChildNode` and `lastChildNode` renamed to `firtChild` and `lastChild` in `HTMLNode`. + +### Removed + +- `baseURI` proeprty from `HTMLNode` +- `HTMLNodeTreeEnumerator` is superseded by the `HTMLNodeIterator`. + +## [0.1.0](https://github.com/iabudiab/HTMLKit/releases/tag/0.1.0) + +Released on 2015.04.20 + +### Added + +- Initial release. +- Initial DOM implementation. +- Tokenizer and Parser pass all [HTML5Lib](https://github.com/html5lib/html5lib-tests) tokenizer and tree construction tests except for `` elements. diff --git a/README.md b/README.md index 949d8a9..d35e88d 100644 --- a/README.md +++ b/README.md @@ -219,6 +219,10 @@ CSSSelector *myAwesomeSelector = namedBlockSelector(@"myAwesomeSelector", ^BOOL notParagraphAndNotDiv = [firstDivElement elementsMatchingSelector:myAwesomeSelector]; ``` +# Change Log + +See the [CHANGELOG.md](CHANGELOG.md) for more info. + # License -HTMLKit is available under the MIT license. See the LICENSE file for more info. +HTMLKit is available under the MIT license. See the [LICENSE](LICENSE) file for more info. From 1af25abadbe68572d889af69c8d674cfa28e5d61 Mon Sep 17 00:00:00 2001 From: iska Date: Thu, 31 Mar 2016 13:11:23 +0200 Subject: [PATCH 03/18] Fix tags links in the CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8b2249..5763c0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log -## [0.9.1](https://github.com/iabudiab/HTMLKit/releases/tag/0.3.0) +## [0.9.1](https://github.com/iabudiab/HTMLKit/releases/tag/0.9.1) Released on 2016.01.29 @@ -20,7 +20,7 @@ Released on 2016.01.29 - Replaced `@returns` with `@return` throughout the documentation to play nicely with Jazzy. - Some README examples used Swift syntax. -## [0.9.0](https://github.com/iabudiab/HTMLKit/releases/tag/0.3.0) +## [0.9.0](https://github.com/iabudiab/HTMLKit/releases/tag/0.9.0) Released on 2015.12.23 From c9d72646bc5fec7d10f059314efa913dc976ce54 Mon Sep 17 00:00:00 2001 From: iska Date: Sun, 10 Apr 2016 16:48:31 +0200 Subject: [PATCH 04/18] Update htlm5lib-tests to include Blink changes Commit: 193fa43bd66e9f0c416b6e2b358711644c5f55d6 --- HTMLKitTests/html5lib-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HTMLKitTests/html5lib-tests b/HTMLKitTests/html5lib-tests index 56c435f..193fa43 160000 --- a/HTMLKitTests/html5lib-tests +++ b/HTMLKitTests/html5lib-tests @@ -1 +1 @@ -Subproject commit 56c435f033d3cb052e216747beb4251c7eaeb5c9 +Subproject commit 193fa43bd66e9f0c416b6e2b358711644c5f55d6 From 432df997b3866d80907ed10b262b10ee68ea3df4 Mon Sep 17 00:00:00 2001 From: iska Date: Mon, 11 Apr 2016 01:12:40 +0200 Subject: [PATCH 05/18] Add simple tests observer class for failure reporting --- HTMLKit.xcodeproj/project.pbxproj | 8 +++ HTMLKitTests/HTMLKitTestObserver.h | 24 +++++++++ HTMLKitTests/HTMLKitTestObserver.m | 86 ++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 HTMLKitTests/HTMLKitTestObserver.h create mode 100644 HTMLKitTests/HTMLKitTestObserver.m diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj index ca55b51..1e8c80f 100644 --- a/HTMLKit.xcodeproj/project.pbxproj +++ b/HTMLKit.xcodeproj/project.pbxproj @@ -40,6 +40,8 @@ 625A14CF19C7829400AD0C32 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 625A14CD19C7829400AD0C32 /* InfoPlist.strings */; }; 625D0F031C2717DE00D7BEB0 /* HTMLNode+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 625D0F011C2717DE00D7BEB0 /* HTMLNode+Private.h */; }; 625D0F041C2717DE00D7BEB0 /* HTMLNode+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 625D0F011C2717DE00D7BEB0 /* HTMLNode+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 625EE4571CBAA41D00F2CC8E /* HTMLKitTestObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 625EE4561CBAA41D00F2CC8E /* HTMLKitTestObserver.m */; }; + 625EE4581CBAA41D00F2CC8E /* HTMLKitTestObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 625EE4561CBAA41D00F2CC8E /* HTMLKitTestObserver.m */; }; 628AF6301BC99A6C00496128 /* CSSNthExpressionsParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 628AF62E1BC99A6C00496128 /* CSSNthExpressionsParserTests.m */; }; 62D8345A19FB1AC4009205A9 /* HTML5LibTokenizerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 62D8345819FB1AC4009205A9 /* HTML5LibTokenizerTest.m */; }; 62EC7AE71AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 62EC7AE51AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m */; }; @@ -393,6 +395,8 @@ 625A150619C78ABA00AD0C32 /* HTMLInputStreamReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLInputStreamReader.h; sourceTree = ""; }; 625A150719C78ABA00AD0C32 /* HTMLInputStreamReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLInputStreamReader.m; sourceTree = ""; }; 625D0F011C2717DE00D7BEB0 /* HTMLNode+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "HTMLNode+Private.h"; sourceTree = ""; }; + 625EE4551CBAA41D00F2CC8E /* HTMLKitTestObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLKitTestObserver.h; sourceTree = ""; }; + 625EE4561CBAA41D00F2CC8E /* HTMLKitTestObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitTestObserver.m; sourceTree = ""; }; 626652F81C03D30F00C3F121 /* HTMLKitErrorDomain.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLKitErrorDomain.h; sourceTree = ""; }; 6279F87119E17DC700F12EE5 /* HTMLParserInsertionModes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLParserInsertionModes.h; sourceTree = ""; }; 6279F87219E1808D00F12EE5 /* HTMLElement.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.objc; fileEncoding = 4; path = HTMLElement.h; sourceTree = ""; }; @@ -653,6 +657,8 @@ 624E1A2D1B1D1C8A00E66AAC /* Structures */, 62FF516C1C0A430A009BFDFE /* Selectors */, 625A14CB19C7829400AD0C32 /* Supporting Files */, + 625EE4551CBAA41D00F2CC8E /* HTMLKitTestObserver.h */, + 625EE4561CBAA41D00F2CC8E /* HTMLKitTestObserver.m */, ); name = Tests; path = HTMLKitTests; @@ -1153,6 +1159,7 @@ 6239755B1AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m in Sources */, 62F658711BD83C8E0045F137 /* CSSNThExpressionSelectorTests.m in Sources */, 623CAF9E1AD88BEA00E34C32 /* HTMLKitParserPerformance.m in Sources */, + 625EE4571CBAA41D00F2CC8E /* HTMLKitTestObserver.m in Sources */, 6247171D1B2240B800C11912 /* HTMLTreeWalkerTests.m in Sources */, 62EC7AE71AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m in Sources */, 624AB31B1B050A4D00F3830D /* CSSAttributeSelectorTests.m in Sources */, @@ -1233,6 +1240,7 @@ 62ECBFCB1C0B6E2E00AF847B /* HTMLKitTokenizerTests.m in Sources */, 62ECBFCC1C0B6E2E00AF847B /* HTMLKitTokenizerPerformance.m in Sources */, 62ECBFCD1C0B6E2E00AF847B /* HTML5LibTreeConstructionTest.m in Sources */, + 625EE4581CBAA41D00F2CC8E /* HTMLKitTestObserver.m in Sources */, 62ECBFCE1C0B6E2E00AF847B /* HTMLKitTreeConstructionTests.m in Sources */, 62ECBFCF1C0B6E2E00AF847B /* HTMLKitParserPerformance.m in Sources */, 62ECBFD01C0B6E2E00AF847B /* HTMLKitNodeIteratorTests.m in Sources */, diff --git a/HTMLKitTests/HTMLKitTestObserver.h b/HTMLKitTests/HTMLKitTestObserver.h new file mode 100644 index 0000000..c9cd28f --- /dev/null +++ b/HTMLKitTests/HTMLKitTestObserver.h @@ -0,0 +1,24 @@ +// +// HTMLKitTestObserver.h +// HTMLKit +// +// Created by Iska on 10/04/16. +// Copyright © 2016 BrainCookie. All rights reserved. +// + +#import + +@interface HTMLKitTestReport : NSObject +@property (assign, readonly) NSUInteger totalCount; +@property (assign, readonly) NSUInteger failureCount; +@property (copy, readonly) NSString *failureReport; +@end + +@interface HTMLKitTestObserver : NSObject + +- (instancetype)initWithName:(NSString *)name; + +- (void)addCaseForHTML5LibTestWithInput:(NSString *)input; +- (HTMLKitTestReport *)generateReport; + +@end diff --git a/HTMLKitTests/HTMLKitTestObserver.m b/HTMLKitTests/HTMLKitTestObserver.m new file mode 100644 index 0000000..37210b2 --- /dev/null +++ b/HTMLKitTests/HTMLKitTestObserver.m @@ -0,0 +1,86 @@ +// +// HTMLKitTestObserver.m +// HTMLKit +// +// Created by Iska on 10/04/16. +// Copyright © 2016 BrainCookie. All rights reserved. +// + +#import "HTMLKitTestObserver.h" + +#pragma mark - HTMLKitTestReport + +@interface HTMLKitTestReport () +@property (assign) NSUInteger totalCount; +@property (assign) NSUInteger failureCount; +@property (copy) NSString *failureReport; +@end + +@implementation HTMLKitTestReport +@synthesize totalCount, failureCount, failureReport; +@end + +#pragma mark - HTMLKitTestObserver + +@interface HTMLKitTestObserver () +{ + NSString *_name; + NSMutableArray *_cases; + NSMutableDictionary *_currentCase; +} +@end + +@implementation HTMLKitTestObserver + +- (instancetype)initWithName:(NSString *)name +{ + self = [super init]; + if (self) { + _name = [name copy]; + _cases = [NSMutableArray new]; + } + return self; +} + + +- (void)addCaseForHTML5LibTestWithInput:(NSString *)input +{ + _currentCase = [NSMutableDictionary new]; + _currentCase[@"input"] = input; + _currentCase[@"status"] = @"Passed"; + [_cases addObject:_currentCase]; +} + +- (void)testCase:(XCTestCase *)testCase didFailWithDescription:(NSString *)description inFile:(NSString *)filePath atLine:(NSUInteger)lineNumber +{ + _currentCase[@"status"] = @"Failed"; +} + +- (HTMLKitTestReport *)generateReport +{ + NSMutableString *reportDescription = [NSMutableString string]; + + NSIndexSet *failedIndexes = [_cases indexesOfObjectsPassingTest:^BOOL(NSDictionary *testCase, NSUInteger idx, BOOL * _Nonnull stop) { + return [testCase[@"status"] isEqualToString:@"Failed"]; + }]; + + NSArray *failedTests = [_cases objectsAtIndexes:failedIndexes]; + + NSUInteger totalCount = _cases.count; + NSUInteger failureCount = failedTests.count; + + [reportDescription appendFormat:@"HTML5Lib test file: [%@] - failed: [%lu] out of [%lu] total tests\n", _name, failureCount, _cases.count]; + + for (NSDictionary *testCase in failedTests) { + [reportDescription appendFormat:@"Failed test for input: %@\n", testCase[@"input"]]; + } + + HTMLKitTestReport *report = [HTMLKitTestReport new]; + report.totalCount = totalCount; + report.failureCount = failureCount; + report.failureReport = reportDescription; + + return report; +} + +@end From 1e07acd032a6e5d0731a03d44070d1b83b906983 Mon Sep 17 00:00:00 2001 From: iska Date: Mon, 11 Apr 2016 01:13:24 +0200 Subject: [PATCH 06/18] Use tests observer in the HTMLKit Tree Construction tests --- HTMLKitTests/HTMLKitTreeConstructionTests.m | 22 ++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/HTMLKitTests/HTMLKitTreeConstructionTests.m b/HTMLKitTests/HTMLKitTreeConstructionTests.m index d8de4be..4a8a87a 100644 --- a/HTMLKitTests/HTMLKitTreeConstructionTests.m +++ b/HTMLKitTests/HTMLKitTreeConstructionTests.m @@ -8,6 +8,7 @@ #import +#import "HTMLKitTestObserver.h" #import "HTML5LibTreeConstructionTest.h" #import "HTMLDOM.h" #import "HTMLParser.h" @@ -26,6 +27,10 @@ #pragma mark - HTML5Lib Test Suite @interface HTMLKitTreeConstructionTests : XCTestCase +{ + HTMLKitTestObserver *_observer; +} + @property (nonatomic, strong) NSString *testName; @property (nonatomic, strong) NSArray *testsList; @end @@ -76,8 +81,23 @@ } - (NSString *)description +#pragma mark - Setup + +- (void)setUp { - return self.name; + _observer = [[HTMLKitTestObserver alloc] initWithName:self.testName]; + [[XCTestObservationCenter sharedTestObservationCenter] addTestObserver:_observer]; + + [super setUp]; +} + +- (void)tearDown +{ + HTMLKitTestReport *testReport = [_observer generateReport]; + XCTAssertTrue(testReport.failureCount == 0, @"%@", testReport.failureReport); + + [[XCTestObservationCenter sharedTestObservationCenter] removeTestObserver:_observer]; + [super tearDown]; } #pragma mark - Tests From 0b2681f8a873d8650704ee51d37f9bb6341df157 Mon Sep 17 00:00:00 2001 From: iska Date: Mon, 11 Apr 2016 01:14:15 +0200 Subject: [PATCH 07/18] Generate HTMLKit's Tree Construction tests dynamically for better failure reporting TODO: refactor dynamic tests generation into helper class/method --- HTMLKitTests/HTMLKitTreeConstructionTests.m | 46 ++++++++++++--------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/HTMLKitTests/HTMLKitTreeConstructionTests.m b/HTMLKitTests/HTMLKitTreeConstructionTests.m index 4a8a87a..befef66 100644 --- a/HTMLKitTests/HTMLKitTreeConstructionTests.m +++ b/HTMLKitTests/HTMLKitTreeConstructionTests.m @@ -7,6 +7,7 @@ // #import +#import #import "HTMLKitTestObserver.h" #import "HTML5LibTreeConstructionTest.h" @@ -50,37 +51,40 @@ + (void)addTestCaseForTestFile:(NSString *)testFile withTests:(NSArray *)tests toTestSuite:(XCTestSuite *)suite { - NSArray *allInvocations = [self testInvocations]; - for (NSInvocation *invocation in allInvocations) { - XCTestCase *testCase = [[self alloc] initWithInvocation:invocation - testName:testFile - tests:tests]; - [suite addTest:testCase]; - } + IMP implementation = imp_implementationWithBlock(^ (HTMLKitTreeConstructionTests *instance){ + [instance runTests]; + }); + const char *types = [[NSString stringWithFormat:@"%s%s%s", @encode(id), @encode(id), @encode(SEL)] UTF8String]; + + NSString *testName = [testFile.stringByDeletingPathExtension stringByReplacingOccurrencesOfString:@"-" withString:@"_"]; + NSString *selectorName = [NSString stringWithFormat:@"testPareser__%@", testName]; + SEL selector = NSSelectorFromString(selectorName); + class_addMethod(self, selector, implementation, types); + + NSMethodSignature *signature = [self instanceMethodSignatureForSelector:selector]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; + invocation.selector = selector; + + XCTestCase *testCase = [[self alloc] initWithInvocation:invocation tests:tests]; + [suite addTest:testCase]; } #pragma mark - Instance -- (instancetype)initWithInvocation:(NSInvocation *)invocation - testName:(NSString *)testName - tests:(NSArray *)tests +- (instancetype)initWithInvocation:(NSInvocation *)invocation tests:(NSArray *)tests { self = [super initWithInvocation:invocation]; if (self) { - _testName = testName; _testsList = tests; } return self; } -- (NSString *)name +- (NSString *)description { - NSInvocation *invocation = [self invocation]; - NSString *title = self.testName.stringByDeletingPathExtension; - return [NSString stringWithFormat:@"-[%@ %@_%@]", self.class, NSStringFromSelector(invocation.selector), title]; + return self.name; } -- (NSString *)description #pragma mark - Setup - (void)setUp @@ -102,13 +106,15 @@ #pragma mark - Tests -- (void)testParser +- (void)runTests { for (HTML5LibTreeConstructionTest *test in self.testsList) { + NSString *testInput = test.data; + + [_observer addCaseForHTML5LibTestWithInput:testInput]; + + HTMLParser *parser = [[HTMLParser alloc] initWithString:testInput]; HTMLElement *contextElement = test.documentFragment; - - HTMLParser *parser = [[HTMLParser alloc] initWithString:test.data]; - NSArray *actual = nil; if (contextElement == nil) { actual = [parser parseDocument].childNodes.array; From 4441b7decd7ed089d2c0065437505dde0207bd7a Mon Sep 17 00:00:00 2001 From: iska Date: Mon, 11 Apr 2016 01:18:33 +0200 Subject: [PATCH 08/18] Generate HTMLKit's Tokenizer tests dynamically for better failure reporting TODO: refactor dynamic tests generation into helper class/method --- HTMLKitTests/HTMLKitTokenizerTests.m | 32 +++++++++++++++++----------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/HTMLKitTests/HTMLKitTokenizerTests.m b/HTMLKitTests/HTMLKitTokenizerTests.m index 76e7545..7845f8a 100644 --- a/HTMLKitTests/HTMLKitTokenizerTests.m +++ b/HTMLKitTests/HTMLKitTokenizerTests.m @@ -7,6 +7,8 @@ // #import +#import + #import "HTML5LibTokenizerTest.h" #import "HTMLTokenizer.h" @@ -50,24 +52,30 @@ + (void)addTestCaseForTestFile:(NSString *)testFile withTests:(NSArray *)tests toTestSuite:(XCTestSuite *)suite { - NSArray *allInvocations = [self testInvocations]; - for (NSInvocation *invocation in allInvocations) { - XCTestCase *testCase = [[self alloc] initWithInvocation:invocation - testName:testFile - tests:tests]; - [suite addTest:testCase]; - } + IMP implementation = imp_implementationWithBlock(^ (HTMLKitTokenizerTests *instance){ + [instance runTests]; + }); + const char *types = [[NSString stringWithFormat:@"%s%s%s", @encode(id), @encode(id), @encode(SEL)] UTF8String]; + + NSString *testName = [testFile.stringByDeletingPathExtension stringByReplacingOccurrencesOfString:@"-" withString:@"_"]; + NSString *selectorName = [NSString stringWithFormat:@"testTokenizer__%@", testName]; + SEL selector = NSSelectorFromString(selectorName); + class_addMethod(self, selector, implementation, types); + + NSMethodSignature *signature = [self instanceMethodSignatureForSelector:selector]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; + invocation.selector = selector; + + XCTestCase *testCase = [[self alloc] initWithInvocation:invocation tests:tests]; + [suite addTest:testCase]; } #pragma mark - Instance -- (instancetype)initWithInvocation:(NSInvocation *)invocation - testName:(NSString *)testName - tests:(NSArray *)tests +- (instancetype)initWithInvocation:(NSInvocation *)invocation tests:(NSArray *)tests { self = [super initWithInvocation:invocation]; if (self) { - _testName = testName; _testsList = tests; } return self; @@ -87,7 +95,7 @@ #pragma mark - Tests -- (void)testTokenizer +- (void)runTests { for (HTML5LibTokenizerTest *test in self.testsList) { From 58b60dd390dbf070049846f576732df82dd42258 Mon Sep 17 00:00:00 2001 From: iska Date: Mon, 11 Apr 2016 23:37:16 +0200 Subject: [PATCH 09/18] Add test utility class for adding test cases dynamically at runtime --- HTMLKit.xcodeproj/project.pbxproj | 8 +++++ HTMLKitTests/HTML5LibTokenizerTest.h | 2 +- HTMLKitTests/HTML5LibTokenizerTest.m | 4 +-- HTMLKitTests/HTMLKitTestObserver.m | 2 +- HTMLKitTests/HTMLKitTestUtil.h | 15 +++++++++ HTMLKitTests/HTMLKitTestUtil.m | 29 ++++++++++++++++++ HTMLKitTests/HTMLKitTokenizerTests.m | 34 +++++---------------- HTMLKitTests/HTMLKitTreeConstructionTests.m | 27 +++++----------- 8 files changed, 70 insertions(+), 51 deletions(-) create mode 100644 HTMLKitTests/HTMLKitTestUtil.h create mode 100644 HTMLKitTests/HTMLKitTestUtil.m diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj index 1e8c80f..5667236 100644 --- a/HTMLKit.xcodeproj/project.pbxproj +++ b/HTMLKit.xcodeproj/project.pbxproj @@ -42,6 +42,8 @@ 625D0F041C2717DE00D7BEB0 /* HTMLNode+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 625D0F011C2717DE00D7BEB0 /* HTMLNode+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; 625EE4571CBAA41D00F2CC8E /* HTMLKitTestObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 625EE4561CBAA41D00F2CC8E /* HTMLKitTestObserver.m */; }; 625EE4581CBAA41D00F2CC8E /* HTMLKitTestObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 625EE4561CBAA41D00F2CC8E /* HTMLKitTestObserver.m */; }; + 625EE45B1CBB171300F2CC8E /* HTMLKitTestUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 625EE45A1CBB171300F2CC8E /* HTMLKitTestUtil.m */; }; + 625EE45C1CBB171300F2CC8E /* HTMLKitTestUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 625EE45A1CBB171300F2CC8E /* HTMLKitTestUtil.m */; }; 628AF6301BC99A6C00496128 /* CSSNthExpressionsParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 628AF62E1BC99A6C00496128 /* CSSNthExpressionsParserTests.m */; }; 62D8345A19FB1AC4009205A9 /* HTML5LibTokenizerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 62D8345819FB1AC4009205A9 /* HTML5LibTokenizerTest.m */; }; 62EC7AE71AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 62EC7AE51AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m */; }; @@ -397,6 +399,8 @@ 625D0F011C2717DE00D7BEB0 /* HTMLNode+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "HTMLNode+Private.h"; sourceTree = ""; }; 625EE4551CBAA41D00F2CC8E /* HTMLKitTestObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLKitTestObserver.h; sourceTree = ""; }; 625EE4561CBAA41D00F2CC8E /* HTMLKitTestObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitTestObserver.m; sourceTree = ""; }; + 625EE4591CBB171300F2CC8E /* HTMLKitTestUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLKitTestUtil.h; sourceTree = ""; }; + 625EE45A1CBB171300F2CC8E /* HTMLKitTestUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitTestUtil.m; sourceTree = ""; }; 626652F81C03D30F00C3F121 /* HTMLKitErrorDomain.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLKitErrorDomain.h; sourceTree = ""; }; 6279F87119E17DC700F12EE5 /* HTMLParserInsertionModes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLParserInsertionModes.h; sourceTree = ""; }; 6279F87219E1808D00F12EE5 /* HTMLElement.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.objc; fileEncoding = 4; path = HTMLElement.h; sourceTree = ""; }; @@ -659,6 +663,8 @@ 625A14CB19C7829400AD0C32 /* Supporting Files */, 625EE4551CBAA41D00F2CC8E /* HTMLKitTestObserver.h */, 625EE4561CBAA41D00F2CC8E /* HTMLKitTestObserver.m */, + 625EE4591CBB171300F2CC8E /* HTMLKitTestUtil.h */, + 625EE45A1CBB171300F2CC8E /* HTMLKitTestUtil.m */, ); name = Tests; path = HTMLKitTests; @@ -1175,6 +1181,7 @@ 624FC37B1AE591D80015DDF9 /* HTMLKitNodesTests.m in Sources */, 621FBE5B1BDAD68700BC9555 /* CSSSelectorParserTests.m in Sources */, 621FBE5E1BDAD90200BC9555 /* CSSCombinatorSelectorTests.m in Sources */, + 625EE45B1CBB171300F2CC8E /* HTMLKitTestUtil.m in Sources */, 628AF6301BC99A6C00496128 /* CSSNthExpressionsParserTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1256,6 +1263,7 @@ 62ECBFD91C0B6E2E00AF847B /* CSSTypeSelectorTests.m in Sources */, 62ECBFDA1C0B6E2E00AF847B /* CSSAttributeSelectorTests.m in Sources */, 62ECBFDB1C0B6E2E00AF847B /* CSSNThExpressionSelectorTests.m in Sources */, + 625EE45C1CBB171300F2CC8E /* HTMLKitTestUtil.m in Sources */, 62ECBFDC1C0B6E2E00AF847B /* CSSCombinatorSelectorTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/HTMLKitTests/HTML5LibTokenizerTest.h b/HTMLKitTests/HTML5LibTokenizerTest.h index 893973d..7fefe44 100644 --- a/HTMLKitTests/HTML5LibTokenizerTest.h +++ b/HTMLKitTests/HTML5LibTokenizerTest.h @@ -10,7 +10,7 @@ @interface HTML5LibTokenizerTest : NSObject -@property (nonatomic, copy) NSString *testName; +@property (nonatomic, copy) NSString *testFile; @property (nonatomic, copy) NSString *title; @property (nonatomic, copy) NSString *input; @property (nonatomic, strong) NSArray *output; diff --git a/HTMLKitTests/HTML5LibTokenizerTest.m b/HTMLKitTests/HTML5LibTokenizerTest.m index e5a09e9..f864634 100644 --- a/HTMLKitTests/HTML5LibTokenizerTest.m +++ b/HTMLKitTests/HTML5LibTokenizerTest.m @@ -39,7 +39,7 @@ static NSString * const TOKENIZER = @"tokenizer"; + (NSArray *)loadTestsWithFileAtPath:(NSString *)filePath { - NSString *testName = filePath.lastPathComponent.stringByDeletingLastPathComponent; + NSString *testFile = filePath.lastPathComponent; NSString *json = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; NSData *data = [json dataUsingEncoding:NSUTF8StringEncoding]; @@ -52,7 +52,7 @@ static NSString * const TOKENIZER = @"tokenizer"; for (NSDictionary *test in jsonTests) { HTML5LibTokenizerTest *html5libTest = [[HTML5LibTokenizerTest alloc] initWithTestDictionary:test]; - html5libTest.testName = testName; + html5libTest.testFile = testFile; [tests addObject:html5libTest]; } return tests; diff --git a/HTMLKitTests/HTMLKitTestObserver.m b/HTMLKitTests/HTMLKitTestObserver.m index 37210b2..fc81acf 100644 --- a/HTMLKitTests/HTMLKitTestObserver.m +++ b/HTMLKitTests/HTMLKitTestObserver.m @@ -69,7 +69,7 @@ NSUInteger totalCount = _cases.count; NSUInteger failureCount = failedTests.count; - [reportDescription appendFormat:@"HTML5Lib test file: [%@] - failed: [%lu] out of [%lu] total tests\n", _name, failureCount, _cases.count]; + [reportDescription appendFormat:@"HTML5Lib test %@ failed [%lu] out of [%lu] total tests\n", _name, failureCount, _cases.count]; for (NSDictionary *testCase in failedTests) { [reportDescription appendFormat:@"Failed test for input: %@\n", testCase[@"input"]]; diff --git a/HTMLKitTests/HTMLKitTestUtil.h b/HTMLKitTests/HTMLKitTestUtil.h new file mode 100644 index 0000000..47abfae --- /dev/null +++ b/HTMLKitTests/HTMLKitTestUtil.h @@ -0,0 +1,15 @@ +// +// HTMLKitTestUtil.h +// HTMLKit +// +// Created by Iska on 11/04/16. +// Copyright © 2016 BrainCookie. All rights reserved. +// + +#import + +@interface HTMLKitTestUtil : NSObject + ++ (NSInvocation *)addTestToClass:(Class)cls withName:(NSString *)name block:(id)block; + +@end diff --git a/HTMLKitTests/HTMLKitTestUtil.m b/HTMLKitTests/HTMLKitTestUtil.m new file mode 100644 index 0000000..ac43bee --- /dev/null +++ b/HTMLKitTests/HTMLKitTestUtil.m @@ -0,0 +1,29 @@ +// +// HTMLKitTestUtil.m +// HTMLKit +// +// Created by Iska on 11/04/16. +// Copyright © 2016 BrainCookie. All rights reserved. +// + +#import "HTMLKitTestUtil.h" +#import + +@implementation HTMLKitTestUtil + ++ (NSInvocation *)addTestToClass:(Class)cls withName:(NSString *)name block:(id)block +{ + IMP implementation = imp_implementationWithBlock(block); + const char *types = [[NSString stringWithFormat:@"%s%s%s", @encode(id), @encode(id), @encode(SEL)] UTF8String]; + + SEL selector = NSSelectorFromString(name); + class_addMethod(cls, selector, implementation, types); + + NSMethodSignature *signature = [cls instanceMethodSignatureForSelector:selector]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; + invocation.selector = selector; + + return invocation; +} + +@end diff --git a/HTMLKitTests/HTMLKitTokenizerTests.m b/HTMLKitTests/HTMLKitTokenizerTests.m index 7845f8a..b11d918 100644 --- a/HTMLKitTests/HTMLKitTokenizerTests.m +++ b/HTMLKitTests/HTMLKitTokenizerTests.m @@ -7,10 +7,10 @@ // #import -#import + +#import "HTMLKitTestUtil.h" #import "HTML5LibTokenizerTest.h" - #import "HTMLTokenizer.h" #import "HTMLTokenizerStates.h" #import "HTMLTokens.h" @@ -32,7 +32,6 @@ #pragma mark - HTML5Lib Test Suite @interface HTMLKitTokenizerTests : XCTestCase -@property (nonatomic, strong) NSString *testName; @property (nonatomic, strong) NSArray *testsList; @end @@ -52,19 +51,12 @@ + (void)addTestCaseForTestFile:(NSString *)testFile withTests:(NSArray *)tests toTestSuite:(XCTestSuite *)suite { - IMP implementation = imp_implementationWithBlock(^ (HTMLKitTokenizerTests *instance){ - [instance runTests]; - }); - const char *types = [[NSString stringWithFormat:@"%s%s%s", @encode(id), @encode(id), @encode(SEL)] UTF8String]; - NSString *testName = [testFile.stringByDeletingPathExtension stringByReplacingOccurrencesOfString:@"-" withString:@"_"]; - NSString *selectorName = [NSString stringWithFormat:@"testTokenizer__%@", testName]; - SEL selector = NSSelectorFromString(selectorName); - class_addMethod(self, selector, implementation, types); + testName = [NSString stringWithFormat:@"testTokenizer__%@", testName]; - NSMethodSignature *signature = [self instanceMethodSignatureForSelector:selector]; - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; - invocation.selector = selector; + NSInvocation *invocation = [HTMLKitTestUtil addTestToClass:self withName:testName block:^ (HTMLKitTokenizerTests *instance){ + [instance runTests]; + }]; XCTestCase *testCase = [[self alloc] initWithInvocation:invocation tests:tests]; [suite addTest:testCase]; @@ -81,18 +73,6 @@ return self; } -- (NSString *)name -{ - NSInvocation *invocation = [self invocation]; - NSString *title = self.testName.stringByDeletingPathExtension; - return [NSString stringWithFormat:@"-[%@ %@_%@]", self.class, NSStringFromSelector(invocation.selector), title]; -} - -- (NSString *)description -{ - return self.name; -} - #pragma mark - Tests - (void)runTests @@ -109,7 +89,7 @@ NSArray *tokens = tokenizer.allObjects; NSString *message = [NSString stringWithFormat:@"HTML5Lib test in file: \'%@\' Title: '%@'\nInput: '%@'\nExpected:\n%@\nActual:\n%@\n", - self.testName, + test.testFile, test.title, test.input, expectedTokens, diff --git a/HTMLKitTests/HTMLKitTreeConstructionTests.m b/HTMLKitTests/HTMLKitTreeConstructionTests.m index befef66..f001278 100644 --- a/HTMLKitTests/HTMLKitTreeConstructionTests.m +++ b/HTMLKitTests/HTMLKitTreeConstructionTests.m @@ -7,7 +7,8 @@ // #import -#import + +#import "HTMLKitTestUtil.h" #import "HTMLKitTestObserver.h" #import "HTML5LibTreeConstructionTest.h" @@ -31,8 +32,6 @@ { HTMLKitTestObserver *_observer; } - -@property (nonatomic, strong) NSString *testName; @property (nonatomic, strong) NSArray *testsList; @end @@ -51,19 +50,12 @@ + (void)addTestCaseForTestFile:(NSString *)testFile withTests:(NSArray *)tests toTestSuite:(XCTestSuite *)suite { - IMP implementation = imp_implementationWithBlock(^ (HTMLKitTreeConstructionTests *instance){ - [instance runTests]; - }); - const char *types = [[NSString stringWithFormat:@"%s%s%s", @encode(id), @encode(id), @encode(SEL)] UTF8String]; - NSString *testName = [testFile.stringByDeletingPathExtension stringByReplacingOccurrencesOfString:@"-" withString:@"_"]; - NSString *selectorName = [NSString stringWithFormat:@"testPareser__%@", testName]; - SEL selector = NSSelectorFromString(selectorName); - class_addMethod(self, selector, implementation, types); + testName = [NSString stringWithFormat:@"testPareser__%@", testName]; - NSMethodSignature *signature = [self instanceMethodSignatureForSelector:selector]; - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; - invocation.selector = selector; + NSInvocation *invocation = [HTMLKitTestUtil addTestToClass:self withName:testName block:^ (HTMLKitTreeConstructionTests *instance){ + [instance runTests]; + }]; XCTestCase *testCase = [[self alloc] initWithInvocation:invocation tests:tests]; [suite addTest:testCase]; @@ -80,16 +72,11 @@ return self; } -- (NSString *)description -{ - return self.name; -} - #pragma mark - Setup - (void)setUp { - _observer = [[HTMLKitTestObserver alloc] initWithName:self.testName]; + _observer = [[HTMLKitTestObserver alloc] initWithName:self.name]; [[XCTestObservationCenter sharedTestObservationCenter] addTestObserver:_observer]; [super setUp]; From 6967798823f5ff4cb425b9cda360392d77a83f05 Mon Sep 17 00:00:00 2001 From: iska Date: Sun, 15 May 2016 01:31:34 +0200 Subject: [PATCH 10/18] Update html5lib-tests to latest commit as of 2016.05.15 Commit: b2f4f5844192ed097bd7993dfb0bcbd4c7a4aeb0 --- HTMLKitTests/html5lib-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HTMLKitTests/html5lib-tests b/HTMLKitTests/html5lib-tests index 193fa43..b2f4f58 160000 --- a/HTMLKitTests/html5lib-tests +++ b/HTMLKitTests/html5lib-tests @@ -1 +1 @@ -Subproject commit 193fa43bd66e9f0c416b6e2b358711644c5f55d6 +Subproject commit b2f4f5844192ed097bd7993dfb0bcbd4c7a4aeb0 From a01f1c1c5b7b54f31021288e23d936e4ac75c82b Mon Sep 17 00:00:00 2001 From: iska Date: Sun, 15 May 2016 01:33:41 +0200 Subject: [PATCH 11/18] Remove handling for and Everybody else is doing it, so why can't we? See: https://github.com/whatwg/html/pull/1095 is not only deprecated, it is completely removed from the spec html5lib-tests: f99e2cb1851de9674519a220a1ccb3174b8cb846 --- HTMLKit/HTMLParser.m | 46 -------------------------------------------- 1 file changed, 46 deletions(-) diff --git a/HTMLKit/HTMLParser.m b/HTMLKit/HTMLParser.m index 8558282..88e3737 100644 --- a/HTMLKit/HTMLParser.m +++ b/HTMLKit/HTMLParser.m @@ -1378,52 +1378,6 @@ [self emitParseError:@"Image Start Tag Token with tagname should be . Don't ask."]; token.tagName = @"img"; [self reprocessToken:token]; - } else if ([tagName isEqualToString:@"isindex"]) { - [self emitParseError:@"Unexpected start tag in "]; - if (_formElementPointer != nil && ![_stackOfOpenElements containsElementWithTagName:@"template"]) { - return; - } - _framesetOkFlag = NO; - if ([_stackOfOpenElements hasElementInButtonScopeWithTagName:@"p"]) { - [self closePElement]; - } - - HTMLStartTagToken *formToken = [[HTMLStartTagToken alloc] initWithTagName:@"form"]; - HTMLElement *form = [self insertElementForToken:formToken]; - if (![_stackOfOpenElements containsElementWithTagName:@"template"]) { - _formElementPointer = form; - } - NSString *action = token.attributes[@"action"]; - if (action != nil) { - form.attributes[@"action"] = action; - } - - HTMLStartTagToken *hrToken = [[HTMLStartTagToken alloc] initWithTagName:@"hr"]; - [self insertElementForToken:hrToken]; - - [_stackOfOpenElements popCurrentNode]; - [self reconstructActiveFormattingElements]; - - HTMLStartTagToken *labelToken = [[HTMLStartTagToken alloc] initWithTagName:@"label"]; - [self insertElementForToken:labelToken]; - - NSString *prompt = token.attributes[@"prompt"] ?: @"This is a searchable index. Enter search keywords: "; - [self insertCharacters:prompt]; - - NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithDictionary:token.attributes]; - attributes[@"name"] = @"isindex"; - [attributes removeObjectForKey:@"action"]; - [attributes removeObjectForKey:@"prompt"]; - - HTMLStartTagToken *inputToken = [[HTMLStartTagToken alloc] initWithTagName:@"input" attributes:attributes]; - [self insertElementForToken:inputToken]; - [_stackOfOpenElements popCurrentNode]; - - [_stackOfOpenElements popCurrentNode]; - [self insertElementForToken:hrToken]; - [_stackOfOpenElements popCurrentNode]; - [_stackOfOpenElements popCurrentNode]; - _formElementPointer = nil; } else if ([tagName isEqualToString:@"textarea"]) { [self insertElementForToken:token]; _ignoreNextLineFeedCharacterToken = YES; From b0bad5068f239eed593c97cd64f44215194ed497 Mon Sep 17 00:00:00 2001 From: iska Date: Sun, 15 May 2016 03:40:23 +0200 Subject: [PATCH 12/18] Update parsing logic for and elements The current spec (2016.05.15) is missing the instruction to "reconstruct the active formatting elements" to match the handling of the