Merge branch 'develop' into feature/css_selectors
Conflicts: HTMLKit.xcodeproj/project.pbxproj HTMLKit/HTMLNodeFilter.h
This commit is contained in:
@@ -13,7 +13,6 @@
|
||||
#import "HTMLElement.h"
|
||||
#import "HTMLText.h"
|
||||
#import "HTMLComment.h"
|
||||
#import "HTMLNodeTreeEnumerator.h"
|
||||
|
||||
static NSString * const HTML5LibTests = @"html5lib-tests";
|
||||
static NSString * const TreeConstruction = @"tree-construction";
|
||||
@@ -111,7 +110,7 @@ static NSString * const TreeConstruction = @"tree-construction";
|
||||
fragment = [fragment substringFromIndex:@"svg ".length];
|
||||
namespace = HTMLNamespaceSVG;
|
||||
}
|
||||
test.documentFragment = [[HTMLElement alloc] initWithTagName:fragment attributes:nil namespace:namespace];
|
||||
test.documentFragment = [[HTMLElement alloc] initWithTagName:fragment namespace:namespace attributes:nil];
|
||||
} else if ([match hasPrefix:@"#document\n"]) {
|
||||
NSArray *parts = [[match substringFromIndex:@"#document\n".length] componentsSeparatedByString:@"| "];
|
||||
NSArray *nodes = [HTML5LibTreeConstructionTest parseDocument:parts];
|
||||
@@ -245,7 +244,7 @@ NS_INLINE HTMLElement * parseTag(NSString *str)
|
||||
NSString *tagName = parts.count == 2 ? parts[1] : parts[0];
|
||||
HTMLNamespace namespace = parts.count == 1 ? HTMLNamespaceHTML : ([parts[0] isEqualToString:@"math"] ? HTMLNamespaceMathML : HTMLNamespaceSVG);
|
||||
|
||||
HTMLElement *element = [[HTMLElement alloc] initWithTagName:tagName attributes:nil namespace:namespace];
|
||||
HTMLElement *element = [[HTMLElement alloc] initWithTagName:tagName namespace:namespace attributes:nil];
|
||||
return element;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "HTMLNodes.h"
|
||||
#import "HTMLDOM.h"
|
||||
#import "NSString+HTMLKit.h"
|
||||
|
||||
extern uint64_t dispatch_benchmark(size_t count, void (^block)(void));
|
||||
|
||||
@@ -0,0 +1,568 @@
|
||||
//
|
||||
// HTMLKitNodeTreeEnumratorTests.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 28/03/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "HTMLDOM.h"
|
||||
|
||||
@interface HTMLKitNodeIteratorTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation HTMLKitNodeIteratorTests
|
||||
|
||||
#pragma mark - Test DOM
|
||||
|
||||
- (HTMLElement *)div
|
||||
{
|
||||
return [[HTMLElement alloc] initWithTagName:@"div"];
|
||||
}
|
||||
|
||||
- (HTMLElement *)simpleTree
|
||||
{
|
||||
/*
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
*/
|
||||
HTMLElement *div = self.div;
|
||||
[div appendNode:[[HTMLElement alloc] initWithTagName:@"a"]];
|
||||
[div appendNode:[[HTMLElement alloc] initWithTagName:@"b"]];
|
||||
[div appendNode:[[HTMLElement alloc] initWithTagName:@"c"]];
|
||||
return div;
|
||||
}
|
||||
|
||||
- (HTMLElement *)nestedSimpleTree
|
||||
{
|
||||
/*
|
||||
| div
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
*/
|
||||
HTMLElement *div = self.div;
|
||||
[div appendNode:self.simpleTree];
|
||||
[div appendNode:self.simpleTree];
|
||||
return div;
|
||||
}
|
||||
|
||||
- (HTMLElement *)complexTree
|
||||
{
|
||||
/*
|
||||
| div
|
||||
| div
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
| e
|
||||
| f
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
*/
|
||||
HTMLElement *root = self.div;
|
||||
|
||||
HTMLElement *div = self.div;
|
||||
[div appendNode:self.simpleTree];
|
||||
[root appendNode:div];
|
||||
|
||||
HTMLElement *e = [[HTMLElement alloc] initWithTagName:@"e"];
|
||||
[e appendNode:[[HTMLElement alloc] initWithTagName:@"f"]];
|
||||
[root appendNode:e];
|
||||
[root appendNode:self.simpleTree];
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
- (HTMLDocument *)mixedTree
|
||||
{
|
||||
|
||||
/*
|
||||
| doctype
|
||||
| #comment <!-- This is a Comment -->
|
||||
| #comment <!-- This is a second Comment -->
|
||||
| html
|
||||
| #text "This is a Text"
|
||||
| div
|
||||
*/
|
||||
HTMLDocument *document = [HTMLDocument new];
|
||||
document.documentType = [HTMLDocumentType new];;
|
||||
|
||||
HTMLComment *comment = [[HTMLComment alloc] initWithData:@"This is a Comment"];
|
||||
[document appendNode:comment];
|
||||
|
||||
HTMLComment *secondCommnet = [[HTMLComment alloc] initWithData:@"This is a second Comment"];
|
||||
[document appendNode:secondCommnet];
|
||||
|
||||
HTMLElement *root = [[HTMLElement alloc] initWithTagName:@"html"];
|
||||
[document appendNode:root];
|
||||
|
||||
[root appendNode:[[HTMLText alloc] initWithData:@"This is a Text"]];
|
||||
|
||||
[root appendNode:[[HTMLElement alloc] initWithTagName:@"div"]];
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
- (HTMLDocument *)document
|
||||
{
|
||||
NSString *htmlString =
|
||||
@"<!DOCTYPE html>"
|
||||
@"<html>"
|
||||
@"<head>"
|
||||
@"<title>Title</title>"
|
||||
@"</head>"
|
||||
@"<body>"
|
||||
@"<span>Hello<strong>World!</strong><strong>HTML <!-- This is a Comment! --> Kit</strong></span>"
|
||||
@"<p>This is an <em>Important</em> paragraph</p>"
|
||||
@"</body>"
|
||||
@"</html>";
|
||||
|
||||
HTMLDocument *document = [HTMLDocument documentWithString:htmlString];
|
||||
return document;
|
||||
}
|
||||
|
||||
#pragma mark - Test Iterator
|
||||
|
||||
- (void)testNodeIteratorInit
|
||||
{
|
||||
HTMLElement *tree = self.simpleTree;
|
||||
HTMLNodeIterator *iterator = tree.nodeIterator;
|
||||
|
||||
XCTAssertEqualObjects(iterator.root, tree);
|
||||
XCTAssertEqualObjects(iterator.referenceNode, tree);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES);
|
||||
XCTAssertEqualObjects(iterator.filter, nil);
|
||||
XCTAssertEqual(iterator.whatToShow, HTMLNodeFilterShowAll);
|
||||
}
|
||||
|
||||
- (void)testNewIteratorNextNodeShouldBeRoot
|
||||
{
|
||||
HTMLElement *tree = self.simpleTree;
|
||||
HTMLNodeIterator *iterator = tree.nodeIterator;
|
||||
|
||||
XCTAssertEqualObjects(iterator.nextNode, tree);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO);
|
||||
}
|
||||
|
||||
- (void)testNewIteratorPreviousNodeShouldBeNil
|
||||
{
|
||||
HTMLElement *tree = self.simpleTree;
|
||||
HTMLNodeIterator *iterator = tree.nodeIterator;
|
||||
|
||||
XCTAssertEqualObjects(iterator.previousNode, nil);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES);
|
||||
}
|
||||
|
||||
- (void)testNewIteratorPreviousNodeShouldBeNextNode
|
||||
{
|
||||
HTMLElement *tree = self.simpleTree;
|
||||
HTMLNodeIterator *iterator = tree.nodeIterator;
|
||||
|
||||
HTMLNode *node = iterator.nextNode;
|
||||
|
||||
XCTAssertEqualObjects(iterator.previousNode, node);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES);
|
||||
}
|
||||
|
||||
- (void)testNextPreviousIteration
|
||||
{
|
||||
HTMLElement *tree = self.simpleTree;
|
||||
HTMLNodeIterator *iterator = tree.nodeIterator;
|
||||
|
||||
XCTAssertEqualObjects(iterator.previousNode, nil);
|
||||
XCTAssertEqualObjects(iterator.nextNode.name, @"div");
|
||||
XCTAssertEqualObjects(iterator.nextNode.name, @"a");
|
||||
XCTAssertEqualObjects(iterator.previousNode.name, @"a");
|
||||
XCTAssertEqualObjects(iterator.previousNode.name, @"div");
|
||||
XCTAssertEqualObjects(iterator.nextNode.name, @"div");
|
||||
XCTAssertEqualObjects(iterator.nextNode.name, @"a");
|
||||
XCTAssertEqualObjects(iterator.nextNode.name, @"b");
|
||||
XCTAssertEqualObjects(iterator.nextNode.name, @"c");
|
||||
XCTAssertEqualObjects(iterator.previousNode.name, @"c");
|
||||
XCTAssertEqualObjects(iterator.previousNode.name, @"b");
|
||||
XCTAssertEqualObjects(iterator.previousNode.name, @"a");
|
||||
XCTAssertEqualObjects(iterator.previousNode.name, @"div");
|
||||
}
|
||||
|
||||
- (void)testSingleNodeIteration
|
||||
{
|
||||
HTMLElement *div = self.div;
|
||||
NSArray *result = div.nodeIterator.allObjects;
|
||||
NSArray *expected = @[@"div"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testSimpleTreeIteration
|
||||
{
|
||||
HTMLElement *tree = self.simpleTree;
|
||||
NSArray *result = tree.nodeIterator.allObjects;
|
||||
NSArray *expected = @[@"div", @"a", @"b", @"c"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testNestedSimpleTreeIteration
|
||||
{
|
||||
HTMLElement *tree = self.nestedSimpleTree;
|
||||
NSArray *result = tree.nodeIterator.allObjects;
|
||||
NSArray *expected = @[@"div", @"div", @"a", @"b", @"c", @"div", @"a", @"b", @"c"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testComplexTreeIteration
|
||||
{
|
||||
HTMLElement *tree = self.complexTree;
|
||||
NSArray *result = tree.nodeIterator.allObjects;
|
||||
NSArray *expected = @[@"div", @"div",@"div", @"a", @"b", @"c", @"e", @"f", @"div", @"a", @"b", @"c"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
#pragma mark - Test Iterator ShowOptions (WhatToShow)
|
||||
|
||||
- (void)testShowDocument
|
||||
{
|
||||
HTMLDocument *document = self.mixedTree;
|
||||
|
||||
HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowDocument filter:nil];
|
||||
NSArray *result = iterator.allObjects;
|
||||
NSArray *expected = @[@"#document"];
|
||||
XCTAssertEqual(result.count, 1);
|
||||
XCTAssertEqual([result.firstObject class], [HTMLDocument class]);
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testShowDocumentType
|
||||
{
|
||||
HTMLDocument *document = self.mixedTree;
|
||||
|
||||
HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowDocumentType filter:nil];
|
||||
NSArray *result = iterator.allObjects;
|
||||
NSArray *expected = @[@"html"];
|
||||
XCTAssertEqual(result.count, 1);
|
||||
XCTAssertEqual([result.firstObject class], [HTMLDocumentType class]);
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testShowComment
|
||||
{
|
||||
HTMLDocument *document = self.mixedTree;
|
||||
|
||||
HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowComment filter:nil];
|
||||
NSArray *result = iterator.allObjects;
|
||||
NSArray *expected = @[@"#comment", @"#comment"];
|
||||
XCTAssertEqual(result.count, 2);
|
||||
XCTAssertEqual([result[0] class], [HTMLComment class]);
|
||||
XCTAssertEqual([result[1] class], [HTMLComment class]);
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testShowText
|
||||
{
|
||||
HTMLDocument *document = self.mixedTree;
|
||||
|
||||
HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowText filter:nil];
|
||||
NSArray *result = iterator.allObjects;
|
||||
NSArray *expected = @[@"#text"];
|
||||
XCTAssertEqual(result.count, 1);
|
||||
XCTAssertEqual([result.firstObject class], [HTMLText class]);
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testShowElement
|
||||
{
|
||||
HTMLDocument *document = self.mixedTree;
|
||||
|
||||
HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowElement filter:nil];
|
||||
NSArray *result = iterator.allObjects;
|
||||
NSArray *expected = @[@"html", @"div"];
|
||||
XCTAssertEqual(result.count, 2);
|
||||
XCTAssertEqual([result.firstObject class], [HTMLElement class]);
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testShowBitmask
|
||||
{
|
||||
HTMLDocument *document = self.mixedTree;
|
||||
|
||||
HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowElement | HTMLNodeFilterShowText
|
||||
filter:nil];
|
||||
NSArray *result = iterator.allObjects;
|
||||
NSArray *expected = @[@"html", @"#text", @"div"];
|
||||
XCTAssertEqual(result.count, 3);
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
#pragma mark - Test Iterator Filter
|
||||
|
||||
- (void)testNodeFilter
|
||||
{
|
||||
HTMLDocument *document = self.mixedTree;
|
||||
|
||||
HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowAll
|
||||
filterBlock:^HTMLNodeFilterValue(HTMLNode *node) {
|
||||
if (node.nodeType == HTMLNodeComment) {
|
||||
if ([[(HTMLComment *)node data] rangeOfString:@"second"].location != NSNotFound) {
|
||||
return HTMLNodeFilterAccept;
|
||||
}
|
||||
}
|
||||
return HTMLNodeFilterSkip;
|
||||
}];
|
||||
|
||||
NSArray *result = iterator.allObjects;
|
||||
NSArray *expected = @[@"#comment"];
|
||||
XCTAssertEqual(result.count, 1);
|
||||
XCTAssertEqualObjects([result[0] data], @"This is a second Comment");
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
#pragma mark - Test Removing Steps
|
||||
|
||||
/*
|
||||
Test cases for the Removing Steps
|
||||
https://dom.spec.whatwg.org/#interface-nodeiterator
|
||||
|
||||
Following DOM is used:
|
||||
|
||||
| <html>
|
||||
| <head>
|
||||
| <title>
|
||||
| "Title"
|
||||
| <body>
|
||||
| <span>
|
||||
| "Hello"
|
||||
| <strong>
|
||||
| "World!"
|
||||
| <strong>
|
||||
| "HTML "
|
||||
| <!-- This is a Comment! -->
|
||||
| " Kit"
|
||||
| <p>
|
||||
| "This is an "
|
||||
| <em>
|
||||
| "Important"
|
||||
| " paragraph"
|
||||
*/
|
||||
|
||||
static void (^ RemoveThenInsertNode)(HTMLNode *) = ^ (HTMLNode *node) {
|
||||
HTMLNode *parent = node.parentNode;
|
||||
HTMLNode *nextSibling = node.nextSibling;
|
||||
[parent removeChildNode:node];
|
||||
[parent insertNode:node beforeChildNode:nextSibling];
|
||||
};
|
||||
|
||||
static void (^ IterateUpToNode)(HTMLNodeIterator *, HTMLNode *) = ^ (HTMLNodeIterator *iterator, HTMLNode *target) {
|
||||
for(HTMLNode *node = iterator.referenceNode; node && (node != target); node = iterator.nextNode);
|
||||
};
|
||||
|
||||
static HTMLNode * (^ LastDescendant)(HTMLNode *) = ^ HTMLNode * (HTMLNode *node) {
|
||||
while (node.lastChild) {
|
||||
node = node.lastChild;
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
- (void)testThatRemovingRootNodeShouldNotAffectIterator
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNode *node = document.body.firstChild; // <span>
|
||||
|
||||
HTMLNodeIterator *iterator = node.nodeIterator;
|
||||
|
||||
[document.body removeChildNode:node];
|
||||
|
||||
XCTAssertEqualObjects(iterator.root, node);
|
||||
XCTAssertEqualObjects(iterator.referenceNode, node);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES);
|
||||
XCTAssertEqualObjects(iterator.referenceNode.parentNode, nil);
|
||||
}
|
||||
|
||||
- (void)testThatRemovingANonInclusiveAnscestorOfReferenceShouldNotAffectIterator
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNode *body = document.body;
|
||||
|
||||
HTMLNodeIterator *iterator = body.nodeIterator;
|
||||
|
||||
[iterator nextNode]; // Reference node: <body>
|
||||
[iterator nextNode]; // Reference node: <span>
|
||||
|
||||
RemoveThenInsertNode(iterator.root.childNodes[1]); // Remove <p>
|
||||
|
||||
XCTAssertEqualObjects(iterator.root, body);
|
||||
XCTAssertEqualObjects(iterator.referenceNode, body.firstChild);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO);
|
||||
}
|
||||
|
||||
- (void)testThatRemovingReferenceNodeShouldUpdateIterator_NilOldPreviousSibling
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
|
||||
HTMLNodeIterator *iterator = document.body.nodeIterator;
|
||||
|
||||
[iterator nextNode]; // Reference node: <body>
|
||||
|
||||
HTMLNode *node = iterator.nextNode; // Reference node: <span>
|
||||
RemoveThenInsertNode(node); // Remove <span> with old previos sibling being nil
|
||||
|
||||
XCTAssertEqualObjects(iterator.referenceNode, iterator.root);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO);
|
||||
|
||||
HTMLNode *next = iterator.nextNode; // "Hello"
|
||||
XCTAssertEqualObjects(next, iterator.root.firstChild);
|
||||
}
|
||||
|
||||
- (void)testThatRemovingReferenceNodeShouldUpdateIterator_NonNilOldPreviousSibling_NotBeforeReference
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNode *body = document.body;
|
||||
|
||||
HTMLNodeIterator *iterator = body.nodeIterator;
|
||||
|
||||
HTMLNode *node = iterator.root.childNodes[1]; // <p>
|
||||
IterateUpToNode(iterator, node); // Reference node: <p>, pointer-before-reference: NO
|
||||
RemoveThenInsertNode(node); // Remove <p> with old previos sibling being <span>
|
||||
|
||||
XCTAssertEqualObjects(iterator.referenceNode, LastDescendant(body.firstChild));
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO);
|
||||
}
|
||||
|
||||
- (void)testThatRemovingReferenceNodeShouldUpdateIterator_NonNilOldPreviousSibling_BeforeReference
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNode *body = document.body;
|
||||
|
||||
HTMLNodeIterator *iterator = body.nodeIterator;
|
||||
|
||||
HTMLNode *node = iterator.root.childNodes[1]; // <p>
|
||||
IterateUpToNode(iterator, node); // Reference node: <p>, pointer-before-reference: NO
|
||||
[iterator previousNode]; // pointer-before-reference: YES
|
||||
RemoveThenInsertNode(node); // Remove <p> with old previos sibling being <span>
|
||||
|
||||
XCTAssertEqualObjects(iterator.referenceNode, body.firstChild);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES);
|
||||
}
|
||||
|
||||
- (void)testThatRemovingThenReinsertingReferenceNodeAfterNextShouldReturnItAgain
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNodeIterator *iterator = document.body.nodeIterator;
|
||||
|
||||
[iterator nextNode]; // Reference node: <body>
|
||||
|
||||
HTMLNode *node = iterator.nextNode; // <span>
|
||||
RemoveThenInsertNode(node);
|
||||
|
||||
XCTAssertEqualObjects(iterator.referenceNode, iterator.root);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO);
|
||||
|
||||
HTMLNode *next = iterator.nextNode;
|
||||
XCTAssertEqualObjects(next, node);
|
||||
}
|
||||
|
||||
- (void)testThatRemovingThenReinsertingReferenceNodeAfterPreviousShouldReturnItAgain
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNodeIterator *iterator = document.body.nodeIterator;
|
||||
|
||||
[iterator nextNode]; // Reference node: <body>
|
||||
[iterator nextNode]; // Reference node: <span>
|
||||
|
||||
HTMLNode *node = iterator.previousNode; // Reference node: <span>, pointer-before-reference: YES
|
||||
HTMLNode *next = node.nextSibling; // <p>
|
||||
RemoveThenInsertNode(node);
|
||||
|
||||
XCTAssertEqualObjects(iterator.referenceNode, next);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES);
|
||||
|
||||
HTMLNode *previous = iterator.previousNode;
|
||||
XCTAssertEqualObjects(previous, LastDescendant(node));
|
||||
}
|
||||
|
||||
- (void)testThatRemovingParentOfReferenceNodeShouldUpdateIterator_NotBeforeReference
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNode *body = document.body;
|
||||
|
||||
HTMLNodeIterator *iterator = body.nodeIterator;
|
||||
HTMLNode *parent = body.childNodes[1];
|
||||
|
||||
IterateUpToNode(iterator, parent); // Reference node: <p>, pointer-before-reference: NO
|
||||
[iterator nextNode]; // Reference node: "This is an "
|
||||
RemoveThenInsertNode(parent);
|
||||
|
||||
XCTAssertEqualObjects(iterator.referenceNode, LastDescendant(body.firstChild));
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO);
|
||||
}
|
||||
|
||||
- (void)testThatRemovingParentOfReferenceNodeShouldUpdateIterator_BeforeReference
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNode *body = document.body;
|
||||
|
||||
HTMLNodeIterator *iterator = body.nodeIterator;
|
||||
HTMLNode *parent = body.childNodes[1];
|
||||
|
||||
IterateUpToNode(iterator, parent); // Reference node: <p>, pointer-before-reference: NO
|
||||
[iterator nextNode]; // Reference node: "This is an "
|
||||
[iterator previousNode]; // pointer-before-reference: YES
|
||||
RemoveThenInsertNode(parent);
|
||||
|
||||
XCTAssertEqualObjects(iterator.referenceNode, body.firstChild);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES);
|
||||
}
|
||||
|
||||
- (void)testRemoveReferenceNode_NilPreviousSibling_NonNilParentFirstChild
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNode *body = document.body;
|
||||
|
||||
HTMLNodeIterator *iterator = body.nodeIterator;
|
||||
|
||||
[iterator nextNode]; // Reference node: <body>
|
||||
[iterator nextNode]; // Reference node: <span>
|
||||
|
||||
HTMLNode *node = iterator.previousNode; // Reference node: <span>, pointer-before-reference: YES
|
||||
XCTAssertNil(node.previousSibling);
|
||||
XCTAssertNotNil(node.nextSibling);
|
||||
|
||||
HTMLNode *nextSibling = node.nextSibling; // <p>
|
||||
RemoveThenInsertNode(node);
|
||||
|
||||
XCTAssertEqualObjects(iterator.referenceNode, nextSibling);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES);
|
||||
|
||||
HTMLNode *next = iterator.nextNode; // <p>
|
||||
XCTAssertNotEqualObjects(next, node);
|
||||
XCTAssertEqualObjects(next, nextSibling);
|
||||
}
|
||||
|
||||
- (void)testRemoveReferenceNode_NodeAfterOldParentIsOutsideRoot_BeforeReference
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNode *body = document.body;
|
||||
|
||||
body.innerHTML = @"<div><p><a></a></p></div><div></div>";
|
||||
|
||||
HTMLNodeIterator *iterator = body.firstChild.nodeIterator;
|
||||
|
||||
IterateUpToNode(iterator, LastDescendant(body.firstChild)); // Referecne node: <a>
|
||||
HTMLNode *node = [iterator previousNode]; // pointer-before-reference: YES
|
||||
RemoveThenInsertNode(node);
|
||||
|
||||
XCTAssertEqualObjects(iterator.referenceNode, iterator.root.firstChild);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,148 +0,0 @@
|
||||
//
|
||||
// HTMLKitNodeTreeEnumratorTests.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 28/03/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import "HTMLNodes.h"
|
||||
|
||||
@interface HTMLKitNodeTreeEnumratorTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation HTMLKitNodeTreeEnumratorTests
|
||||
|
||||
#pragma mark - Elements
|
||||
|
||||
- (HTMLElement *)div
|
||||
{
|
||||
return [[HTMLElement alloc] initWithTagName:@"div"];
|
||||
}
|
||||
|
||||
- (HTMLElement *)simpleTree
|
||||
{
|
||||
/*
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
*/
|
||||
HTMLElement *div = self.div;
|
||||
[div appendNode:[[HTMLElement alloc] initWithTagName:@"a"]];
|
||||
[div appendNode:[[HTMLElement alloc] initWithTagName:@"b"]];
|
||||
[div appendNode:[[HTMLElement alloc] initWithTagName:@"c"]];
|
||||
return div;
|
||||
}
|
||||
|
||||
- (HTMLElement *)nestedSimpleTree
|
||||
{
|
||||
/*
|
||||
| div
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
*/
|
||||
HTMLElement *div = self.div;
|
||||
[div appendNode:self.simpleTree];
|
||||
[div appendNode:self.simpleTree];
|
||||
return div;
|
||||
}
|
||||
|
||||
- (HTMLElement *)complexTree
|
||||
{
|
||||
/*
|
||||
| div
|
||||
| div
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
| e
|
||||
| f
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
*/
|
||||
HTMLElement *root = self.div;
|
||||
|
||||
HTMLElement *div = self.div;
|
||||
[div appendNode:self.simpleTree];
|
||||
[root appendNode:div];
|
||||
|
||||
HTMLElement *e = [[HTMLElement alloc] initWithTagName:@"e"];
|
||||
[e appendNode:[[HTMLElement alloc] initWithTagName:@"f"]];
|
||||
[root appendNode:e];
|
||||
[root appendNode:self.simpleTree];
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
#pragma mark - Tests
|
||||
|
||||
- (void)testSingle
|
||||
{
|
||||
HTMLElement *div = self.div;
|
||||
NSArray *result = div.treeEnumerator.allObjects;
|
||||
NSArray *expected = @[@"div"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testSimpleTree
|
||||
{
|
||||
HTMLElement *tree = self.simpleTree;
|
||||
NSArray *result = tree.treeEnumerator.allObjects;
|
||||
NSArray *expected = @[@"div", @"a", @"b", @"c"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testSimpleTreeReversed
|
||||
{
|
||||
HTMLElement *tree = self.simpleTree;
|
||||
NSArray *result = tree.reverseTreeEnumerator.allObjects;
|
||||
NSArray *expected = @[@"div", @"c", @"b", @"a"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testNestedSimpleTree
|
||||
{
|
||||
HTMLElement *tree = self.nestedSimpleTree;
|
||||
NSArray *result = tree.treeEnumerator.allObjects;
|
||||
NSArray *expected = @[@"div", @"div", @"a", @"b", @"c", @"div", @"a", @"b", @"c"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testNestedSimpleTreeReversed
|
||||
{
|
||||
HTMLElement *tree = self.nestedSimpleTree;
|
||||
NSArray *result = tree.reverseTreeEnumerator.allObjects;
|
||||
NSArray *expected = @[@"div", @"div", @"c", @"b", @"a", @"div", @"c", @"b", @"a"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testComplexSimpleTree
|
||||
{
|
||||
HTMLElement *tree = self.complexTree;
|
||||
NSArray *result = tree.treeEnumerator.allObjects;
|
||||
NSArray *expected = @[@"div", @"div",@"div", @"a", @"b", @"c", @"e", @"f", @"div", @"a", @"b", @"c"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testComplexSimpleTreeReversed
|
||||
{
|
||||
HTMLElement *tree = self.complexTree;
|
||||
NSArray *result = tree.reverseTreeEnumerator.allObjects;
|
||||
NSArray *expected = @[@"div", @"div", @"c", @"b", @"a", @"e", @"f", @"div", @"div", @"c", @"b", @"a"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "HTMLNodes.h"
|
||||
#import "HTMLDOM.h"
|
||||
|
||||
@interface HTMLKitNodesTests : XCTestCase
|
||||
|
||||
@@ -30,18 +30,17 @@
|
||||
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
|
||||
XCTAssertNotNil(node);
|
||||
XCTAssertEqualObjects(node.name, @"name");
|
||||
XCTAssertEqual(node.type, HTMLNodeElement);
|
||||
XCTAssertEqual(node.nodeType, HTMLNodeElement);
|
||||
XCTAssertNotNil(node.childNodes);
|
||||
XCTAssertEqual(node.childNodes.count, 0);
|
||||
|
||||
XCTAssertNil(node.ownerDocument);
|
||||
XCTAssertNil(node.baseURI);
|
||||
XCTAssertNil(node.parentNode);
|
||||
XCTAssertNil(node.parentElement);
|
||||
XCTAssertNil(node.firstChiledNode);
|
||||
XCTAssertNil(node.lastChildNode);
|
||||
XCTAssertNil(node.firstChild);
|
||||
XCTAssertNil(node.lastChild);
|
||||
XCTAssertNil(node.previousSibling);
|
||||
XCTAssertNil(node.lastChildNode);
|
||||
XCTAssertNil(node.lastChild);
|
||||
}
|
||||
|
||||
- (void)testAppendNode
|
||||
@@ -51,7 +50,7 @@
|
||||
[element appendNode:comment];
|
||||
|
||||
XCTAssertEqual(element.childNodesCount, 1);
|
||||
XCTAssertEqual(element.firstChiledNode, comment);
|
||||
XCTAssertEqual(element.firstChild, comment);
|
||||
|
||||
HTMLElement *firstElement = [HTMLElement new];
|
||||
HTMLElement *secondElement = [HTMLElement new];
|
||||
@@ -60,8 +59,8 @@
|
||||
[element appendNodes:nodes];
|
||||
|
||||
XCTAssertEqual(element.childNodesCount, 3);
|
||||
XCTAssertEqual(element.firstChiledNode, comment);
|
||||
XCTAssertEqual(element.lastChildNode, secondElement);
|
||||
XCTAssertEqual(element.firstChild, comment);
|
||||
XCTAssertEqual(element.lastChild, secondElement);
|
||||
}
|
||||
|
||||
- (void)testPrependNode
|
||||
@@ -74,7 +73,7 @@
|
||||
[element prependNode:comment];
|
||||
|
||||
XCTAssertEqual(element.childNodesCount, 2);
|
||||
XCTAssertEqual(element.firstChiledNode, comment);
|
||||
XCTAssertEqual(element.firstChild, comment);
|
||||
|
||||
HTMLElement *firstElement = [HTMLElement new];
|
||||
HTMLElement *secondElement = [HTMLElement new];
|
||||
@@ -83,8 +82,8 @@
|
||||
[element prependNodes:nodes];
|
||||
|
||||
XCTAssertEqual(element.childNodesCount, 4);
|
||||
XCTAssertEqual(element.firstChiledNode, firstElement);
|
||||
XCTAssertEqual(element.lastChildNode, text);
|
||||
XCTAssertEqual(element.firstChild, firstElement);
|
||||
XCTAssertEqual(element.lastChild, text);
|
||||
}
|
||||
|
||||
- (void)testAppendDocumentFragment
|
||||
@@ -105,10 +104,10 @@
|
||||
|
||||
XCTAssertEqualObjects(firstChild.parentNode, element);
|
||||
XCTAssertEqualObjects(secondChild.parentNode, element);
|
||||
XCTAssertEqualObjects(element.firstChiledNode, comment);
|
||||
XCTAssertEqualObjects(element.firstChiledNode.nextSibling, firstChild);
|
||||
XCTAssertEqualObjects(element.lastChildNode.previousSibling, firstChild);
|
||||
XCTAssertEqualObjects(element.lastChildNode, secondChild);
|
||||
XCTAssertEqualObjects(element.firstChild, comment);
|
||||
XCTAssertEqualObjects(element.firstChild.nextSibling, firstChild);
|
||||
XCTAssertEqualObjects(element.lastChild.previousSibling, firstChild);
|
||||
XCTAssertEqualObjects(element.lastChild, secondChild);
|
||||
}
|
||||
|
||||
- (void)testParentNode
|
||||
@@ -171,20 +170,20 @@
|
||||
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
|
||||
[node appendNode:firstChild];
|
||||
|
||||
XCTAssertEqualObjects(node.firstChiledNode, firstChild);
|
||||
XCTAssertEqualObjects(node.lastChildNode, firstChild);
|
||||
XCTAssertEqualObjects(node.firstChild, firstChild);
|
||||
XCTAssertEqualObjects(node.lastChild, firstChild);
|
||||
|
||||
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
|
||||
[node appendNode:secondChild];
|
||||
|
||||
XCTAssertEqualObjects(node.firstChiledNode, firstChild);
|
||||
XCTAssertEqualObjects(node.lastChildNode, secondChild);
|
||||
XCTAssertEqualObjects(node.firstChild, firstChild);
|
||||
XCTAssertEqualObjects(node.lastChild, secondChild);
|
||||
|
||||
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
|
||||
[node appendNode:thirdChild];
|
||||
|
||||
XCTAssertEqualObjects(node.firstChiledNode, firstChild);
|
||||
XCTAssertEqualObjects(node.lastChildNode, thirdChild);
|
||||
XCTAssertEqualObjects(node.firstChild, firstChild);
|
||||
XCTAssertEqualObjects(node.lastChild, thirdChild);
|
||||
}
|
||||
|
||||
- (void)testNextAndPreviousSiblingNodes
|
||||
@@ -470,4 +469,17 @@
|
||||
XCTAssertEqualObjects(thirdChild.parentNode, newParent);
|
||||
}
|
||||
|
||||
- (void)testElementSetInnerHTML
|
||||
{
|
||||
HTMLElement *element = [[HTMLElement alloc] initWithTagName:@"div"];
|
||||
[element appendNode:[[HTMLElement alloc] initWithTagName:@"img"]];
|
||||
|
||||
[element setInnerHTML:@"<p></p><p></p>"];
|
||||
|
||||
XCTAssertEqual(element.childNodesCount, 2);
|
||||
|
||||
XCTAssertEqualObjects(element.firstChild.asElement.tagName, @"p");
|
||||
XCTAssertEqualObjects([element childNodeAtIndex:1].asElement.tagName, @"p");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
@implementation HTMLKitParserPerformance
|
||||
|
||||
#define HTMLKIT_NO_DOM_CHECKS
|
||||
|
||||
- (void)testParserPerformance
|
||||
{
|
||||
NSString *path = [[NSBundle bundleForClass:self.class] resourcePath];
|
||||
@@ -28,4 +30,6 @@
|
||||
}];
|
||||
}
|
||||
|
||||
#undef HTMLKIT_NO_DOM_CHECKS
|
||||
|
||||
@end
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import "HTML5LibTreeConstructionTest.h"
|
||||
#import "HTMLNodes.h"
|
||||
#import "HTMLDOM.h"
|
||||
#import "HTMLParser.h"
|
||||
|
||||
|
||||
@@ -121,14 +121,14 @@
|
||||
{
|
||||
XCTAssertEqualObjects(actual.name, expected.name, @"Node name mismatch [%@ should be %@]:\n%@",
|
||||
actual.name, expected.name, message);
|
||||
XCTAssert(actual.type == expected.type, @"Node type mismatch [%hd should be %hd]:\n%@",
|
||||
actual.type, expected.type, message);
|
||||
XCTAssert(actual.nodeType == expected.nodeType, @"Node type mismatch [%hd should be %hd]:\n%@",
|
||||
actual.nodeType, expected.nodeType, message);
|
||||
|
||||
if (actual.type != expected.type) {
|
||||
if (actual.nodeType != expected.nodeType) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (actual.type) {
|
||||
switch (actual.nodeType) {
|
||||
case HTMLNodeDocumentType:
|
||||
XCTAssertEqualObjects([(HTMLDocumentType *)actual publicIdentifier], [(HTMLDocumentType *)expected publicIdentifier], @"%@", message);
|
||||
XCTAssertEqualObjects([(HTMLDocumentType *)actual systemIdentifier], [(HTMLDocumentType *)expected systemIdentifier], @"%@", message);
|
||||
|
||||
@@ -0,0 +1,503 @@
|
||||
//
|
||||
// HTMLTreeWalkerTests.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 05/06/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "HTMLTreeWalker.h"
|
||||
#import "HTMLDOM.h"
|
||||
|
||||
@interface HTMLTreeWalkerTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation HTMLTreeWalkerTests
|
||||
|
||||
#pragma mark - Asserts
|
||||
|
||||
#define AssertElementWithId(input, id) \
|
||||
do { \
|
||||
HTMLNode *node = input;\
|
||||
XCTAssertEqual(node.nodeType, HTMLNodeElement);\
|
||||
XCTAssertEqualObjects(node.asElement[@"id"], id);\
|
||||
} while(0)
|
||||
|
||||
#define AssertTextWithValue(input, value) \
|
||||
do { \
|
||||
HTMLNode *node = input;\
|
||||
XCTAssertEqual(node.nodeType, HTMLNodeText);\
|
||||
XCTAssertEqualObjects(node.textContent, value);\
|
||||
} while(0)
|
||||
|
||||
#define AssertCommentWithValue(input, value) \
|
||||
do { \
|
||||
HTMLNode *node = input;\
|
||||
XCTAssertEqual(node.nodeType, HTMLNodeComment);\
|
||||
XCTAssertEqualObjects(node.textContent, value);\
|
||||
} while(0)
|
||||
|
||||
#pragma mark - Tests
|
||||
|
||||
- (void)testTreeWalkerInit
|
||||
{
|
||||
HTMLNode *root = self.basicWalkingDOM;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root];
|
||||
|
||||
XCTAssertNotNil(walker);
|
||||
XCTAssertNotNil(walker.root);
|
||||
XCTAssertNotNil(walker.currentNode);
|
||||
XCTAssertNil(walker.filter);
|
||||
XCTAssertEqual(walker.whatToShow, HTMLNodeFilterShowAll);
|
||||
|
||||
XCTAssertEqualObjects(walker.root, root);
|
||||
XCTAssertEqualObjects(walker.root, walker.currentNode);
|
||||
}
|
||||
|
||||
#pragma mark - Basic Walking
|
||||
|
||||
- (HTMLNode *)basicWalkingDOM
|
||||
{
|
||||
// Tree structure:
|
||||
// #a
|
||||
// |
|
||||
// +----+----+
|
||||
// | |
|
||||
// "b" #c
|
||||
// |
|
||||
// +----+----+
|
||||
// | |
|
||||
// #d <!--j-->
|
||||
// |
|
||||
// +----+----+
|
||||
// | | |
|
||||
// "e" #f "i"
|
||||
// |
|
||||
// +--+--+
|
||||
// | |
|
||||
// "g" <!--h-->
|
||||
|
||||
HTMLElement *div = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"a"}];
|
||||
|
||||
[div appendNode:[[HTMLText alloc] initWithData:@"b"]];
|
||||
|
||||
HTMLElement *c = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"c"}];
|
||||
[div appendNode:c];
|
||||
|
||||
HTMLElement *d = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"d"}];
|
||||
[c appendNode:d];
|
||||
[c appendNode:[[HTMLComment alloc] initWithData:@"j"]];
|
||||
|
||||
[d appendNode:[[HTMLText alloc] initWithData:@"e"]];
|
||||
|
||||
HTMLElement *f = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"f"}];
|
||||
[d appendNode:f];
|
||||
[d appendNode:[[HTMLText alloc] initWithData:@"i"]];
|
||||
|
||||
[f appendNode:[[HTMLText alloc] initWithData:@"g"]];
|
||||
[f appendNode:[[HTMLComment alloc] initWithData:@"h"]];
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
- (void)testBasicWalking
|
||||
{
|
||||
HTMLNode *root = self.basicWalkingDOM;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root];
|
||||
|
||||
HTMLNode *f = root.lastChild.firstChild.childNodes[1];
|
||||
|
||||
AssertElementWithId(walker.currentNode, @"a");
|
||||
XCTAssertNil(walker.parentNode);
|
||||
AssertElementWithId(walker.currentNode, @"a");
|
||||
|
||||
AssertTextWithValue(walker.firstChild, @"b");
|
||||
AssertTextWithValue(walker.currentNode, @"b");
|
||||
|
||||
AssertElementWithId(walker.nextSibling, @"c");
|
||||
AssertElementWithId(walker.currentNode, @"c");
|
||||
|
||||
AssertCommentWithValue(walker.lastChild, @"j");
|
||||
AssertCommentWithValue(walker.currentNode, @"j");
|
||||
|
||||
AssertElementWithId(walker.previousSibling, @"d");
|
||||
AssertElementWithId(walker.currentNode, @"d");
|
||||
|
||||
AssertTextWithValue(walker.nextNode, @"e");
|
||||
AssertTextWithValue(walker.currentNode, @"e");
|
||||
|
||||
AssertElementWithId(walker.parentNode, @"d");
|
||||
AssertElementWithId(walker.currentNode, @"d");
|
||||
|
||||
AssertElementWithId(walker.previousNode, @"c");
|
||||
AssertElementWithId(walker.currentNode, @"c");
|
||||
|
||||
XCTAssertNil(walker.nextSibling);
|
||||
AssertElementWithId(walker.currentNode, @"c");
|
||||
|
||||
walker.currentNode = f;
|
||||
XCTAssertEqualObjects(walker.currentNode, f);
|
||||
}
|
||||
|
||||
#pragma mark - Current Node
|
||||
|
||||
- (HTMLDocument *)currentNodeDOM
|
||||
{
|
||||
HTMLDocument *document = [HTMLDocument documentWithString:
|
||||
@"<div id='first'><p><a></a></p></div>"
|
||||
@"<div id='second'><p><b></b></p</div>"];
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
- (void)testThatTreeWalkerParentHasNoEffectCurrentNodeWhenParentIsNotUnderRoot
|
||||
{
|
||||
HTMLDocument *document = self.currentNodeDOM;
|
||||
HTMLNode *first = document.body.firstChild;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:first
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:nil];
|
||||
|
||||
AssertElementWithId(walker.currentNode, @"first");
|
||||
XCTAssertNil(walker.parentNode);
|
||||
AssertElementWithId(walker.currentNode, @"first");
|
||||
}
|
||||
|
||||
- (void)testThatSettingCurrentNodeToNodesNotUnderRootIsHandledCorrectly
|
||||
{
|
||||
HTMLDocument *document = self.currentNodeDOM;
|
||||
HTMLNode *first = document.body.firstChild;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:first
|
||||
showOptions:HTMLNodeFilterShowElement|HTMLNodeFilterShowComment
|
||||
filter:nil];
|
||||
walker.currentNode = document.documentElement;
|
||||
XCTAssertNil(walker.parentNode);
|
||||
XCTAssertEqualObjects(walker.currentNode, document.documentElement);
|
||||
|
||||
walker.currentNode = document.documentElement;
|
||||
XCTAssertEqualObjects(walker.nextNode, document.documentElement.firstChild);
|
||||
XCTAssertEqualObjects(walker.currentNode, document.documentElement.firstChild);
|
||||
|
||||
walker.currentNode = document.documentElement;
|
||||
XCTAssertNil(walker.previousNode);
|
||||
XCTAssertEqualObjects(walker.currentNode, document.documentElement);
|
||||
|
||||
walker.currentNode = document.documentElement;
|
||||
XCTAssertEqualObjects(walker.firstChild, document.documentElement.firstChild);
|
||||
XCTAssertEqualObjects(walker.currentNode, document.documentElement.firstChild);
|
||||
|
||||
walker.currentNode = document.documentElement;
|
||||
XCTAssertEqualObjects(walker.lastChild, document.documentElement.lastChild);
|
||||
XCTAssertEqualObjects(walker.currentNode, document.documentElement.lastChild);
|
||||
|
||||
walker.currentNode = document.documentElement;
|
||||
XCTAssertNil(walker.nextSibling);
|
||||
XCTAssertEqualObjects(walker.currentNode, document.documentElement);
|
||||
|
||||
walker.currentNode = document.documentElement;
|
||||
XCTAssertNil(walker.previousSibling);
|
||||
XCTAssertEqualObjects(walker.currentNode, document.documentElement);
|
||||
}
|
||||
|
||||
#pragma mark - Filter
|
||||
|
||||
- (HTMLElement *)filterBasicDOM
|
||||
{
|
||||
HTMLElement *root = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"root"}];
|
||||
|
||||
HTMLElement *a1 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"A1"}];
|
||||
HTMLElement *b1 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"B1"}];
|
||||
HTMLElement *b2 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"B2"}];
|
||||
|
||||
[root appendNode:a1];
|
||||
[a1 appendNode:b1];
|
||||
[a1 appendNode:b2];
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
- (void)testTreeWalkerNilFilter
|
||||
{
|
||||
HTMLElement *root = self.filterBasicDOM;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:nil];
|
||||
|
||||
AssertElementWithId(walker.currentNode, @"root");
|
||||
AssertElementWithId(walker.firstChild, @"A1");
|
||||
AssertElementWithId(walker.currentNode, @"A1");
|
||||
AssertElementWithId(walker.nextNode, @"B1");
|
||||
AssertElementWithId(walker.currentNode, @"B1");
|
||||
}
|
||||
|
||||
- (void)testTreeWalkerWithFilter
|
||||
{
|
||||
HTMLElement *root = self.filterBasicDOM;
|
||||
|
||||
id<HTMLNodeFilter> filter = [HTMLNodeFilterBlock filterWithBlock:^HTMLNodeFilterValue(HTMLNode *node) {
|
||||
if ([node.asElement[@"id"] isEqualToString:@"B1"]) {
|
||||
return HTMLNodeFilterSkip;
|
||||
}
|
||||
return HTMLNodeFilterAccept;
|
||||
}];
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
AssertElementWithId(walker.currentNode, @"root");
|
||||
AssertElementWithId(walker.firstChild, @"A1");
|
||||
AssertElementWithId(walker.currentNode, @"A1");
|
||||
AssertElementWithId(walker.nextNode, @"B2");
|
||||
AssertElementWithId(walker.currentNode, @"B2");
|
||||
}
|
||||
|
||||
#pragma mark - Filter Skip
|
||||
|
||||
- (HTMLElement *)filterDOM
|
||||
{
|
||||
HTMLElement *root = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"root"}];
|
||||
|
||||
HTMLElement *a1 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"A1"}];
|
||||
HTMLElement *b1 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"B1"}];
|
||||
HTMLElement *b2 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"B2"}];
|
||||
HTMLElement *b3 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"B3"}];
|
||||
HTMLElement *c1 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"C1"}];
|
||||
|
||||
[root appendNode:a1];
|
||||
[a1 appendNode:b1];
|
||||
[a1 appendNode:b2];
|
||||
[a1 appendNode:b3];
|
||||
[b1 appendNode:c1];
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
- (id<HTMLNodeFilter>)skipB1Filter
|
||||
{
|
||||
id<HTMLNodeFilter> filter = [HTMLNodeFilterBlock filterWithBlock:^HTMLNodeFilterValue(HTMLNode *node) {
|
||||
if ([node.asElement[@"id"] isEqualToString:@"B1"]) {
|
||||
return HTMLNodeFilterSkip;
|
||||
}
|
||||
return HTMLNodeFilterAccept;
|
||||
}];
|
||||
return filter;
|
||||
}
|
||||
|
||||
- (id<HTMLNodeFilter>)skipB2Filter
|
||||
{
|
||||
id<HTMLNodeFilter> filter = [HTMLNodeFilterBlock filterWithBlock:^HTMLNodeFilterValue(HTMLNode *node) {
|
||||
if ([node.asElement[@"id"] isEqualToString:@"B2"]) {
|
||||
return HTMLNodeFilterSkip;
|
||||
}
|
||||
return HTMLNodeFilterAccept;
|
||||
}];
|
||||
return filter;
|
||||
}
|
||||
|
||||
- (id<HTMLNodeFilter>)rejectB1Filter
|
||||
{
|
||||
id<HTMLNodeFilter> filter = [HTMLNodeFilterBlock filterWithBlock:^HTMLNodeFilterValue(HTMLNode *node) {
|
||||
if ([node.asElement[@"id"] isEqualToString:@"B1"]) {
|
||||
return HTMLNodeFilterReject;
|
||||
}
|
||||
return HTMLNodeFilterAccept;
|
||||
}];
|
||||
return filter;
|
||||
}
|
||||
|
||||
- (id<HTMLNodeFilter>)rejectB2Filter
|
||||
{
|
||||
id<HTMLNodeFilter> filter = [HTMLNodeFilterBlock filterWithBlock:^HTMLNodeFilterValue(HTMLNode *node) {
|
||||
if ([node.asElement[@"id"] isEqualToString:@"B2"]) {
|
||||
return HTMLNodeFilterReject;
|
||||
}
|
||||
return HTMLNodeFilterAccept;
|
||||
}];
|
||||
return filter;
|
||||
}
|
||||
|
||||
static HTMLElement * (^ FindElementById)(HTMLNode *, NSString *) = ^ HTMLElement * (HTMLNode *root, NSString *id) {
|
||||
for (HTMLNode *node in [root nodeIteratorWithShowOptions:HTMLNodeFilterShowElement filter:nil]) {
|
||||
if ([node.asElement[@"id"] isEqualToString:id]) {
|
||||
return node.asElement;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
};
|
||||
|
||||
- (void)testThatFilterSkipsNextNode
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.skipB1Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
AssertElementWithId(walker.nextNode, @"A1");
|
||||
AssertElementWithId(walker.nextNode, @"C1");
|
||||
AssertElementWithId(walker.nextNode, @"B2");
|
||||
AssertElementWithId(walker.nextNode, @"B3");
|
||||
}
|
||||
|
||||
- (void)testThatFilterSkipsFirstChild
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.skipB1Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
AssertElementWithId(walker.firstChild, @"A1");
|
||||
AssertElementWithId(walker.firstChild, @"C1");
|
||||
}
|
||||
|
||||
- (void)testThatFilterSkipsNextSibling
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.skipB2Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
AssertElementWithId(walker.firstChild, @"A1");
|
||||
AssertElementWithId(walker.firstChild, @"B1");
|
||||
AssertElementWithId(walker.nextSibling, @"B3");
|
||||
}
|
||||
|
||||
- (void)testThatFilterSkipsParentNode
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.skipB1Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
walker.currentNode = FindElementById(root, @"C1");
|
||||
AssertElementWithId(walker.parentNode, @"A1");
|
||||
}
|
||||
|
||||
- (void)testThatFilterSkipsPreviousSibling
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.skipB2Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
walker.currentNode = FindElementById(root, @"B3");
|
||||
AssertElementWithId(walker.previousSibling, @"B1");
|
||||
}
|
||||
|
||||
- (void)testThatFilterSkipsPreviousNode
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.skipB1Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
walker.currentNode = FindElementById(root, @"B3");
|
||||
AssertElementWithId(walker.previousNode, @"B2");
|
||||
AssertElementWithId(walker.previousNode, @"C1");
|
||||
AssertElementWithId(walker.previousNode, @"A1");
|
||||
}
|
||||
|
||||
#pragma mark - Filter Reject
|
||||
|
||||
- (void)testThatFilterRejectsNextNode
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.rejectB1Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
AssertElementWithId(walker.nextNode, @"A1");
|
||||
AssertElementWithId(walker.nextNode, @"B2");
|
||||
AssertElementWithId(walker.nextNode, @"B3");
|
||||
}
|
||||
|
||||
- (void)testThatFilterRejectsFirstChild
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.rejectB1Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
AssertElementWithId(walker.firstChild, @"A1");
|
||||
AssertElementWithId(walker.firstChild, @"B2");
|
||||
}
|
||||
|
||||
- (void)testThatFilterRejectsNextSibling
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.rejectB2Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
AssertElementWithId(walker.firstChild, @"A1");
|
||||
AssertElementWithId(walker.firstChild, @"B1");
|
||||
AssertElementWithId(walker.nextSibling, @"B3");
|
||||
}
|
||||
|
||||
- (void)testThatFilterRejectsParentNode
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.rejectB1Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
walker.currentNode = FindElementById(root, @"C1");
|
||||
AssertElementWithId(walker.parentNode, @"A1");
|
||||
}
|
||||
|
||||
- (void)testThatFilterRejectsPreviousSibling
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.rejectB2Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
walker.currentNode = FindElementById(root, @"B3");
|
||||
AssertElementWithId(walker.previousSibling, @"B1");
|
||||
}
|
||||
|
||||
- (void)testThatFilterRejectsPreviousNode
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.rejectB1Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
walker.currentNode = FindElementById(root, @"B3");
|
||||
AssertElementWithId(walker.previousNode, @"B2");
|
||||
AssertElementWithId(walker.previousNode, @"A1");
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user