// // HTMLRangeTests.m // HTMLKit // // Created by Iska on 29/12/16. // Copyright © 2016 BrainCookie. All rights reserved. // #import #import "HTMLDOM.h" #import "HTMLNode+Private.h" #import "HTMLRange+Private.h" #import "HTMLKitTestUtil.h" #define BodyOf(doc) doc.body.innerHTML #define InnerHTML(str) [HTMLDocument documentWithString:str].body.innerHTML #define DoubleQuote(str) [str stringByReplacingOccurrencesOfString:@"'" withString:@"\""] @interface HTMLRangeTests : XCTestCase { HTMLDocument *_document; HTMLElement *_h1; HTMLElement *_p; HTMLElement *_div1; HTMLElement *_div2; HTMLText *_title; HTMLText *_paragraphText; HTMLText *_firstText; HTMLText *_secondText; HTMLComment *_firstComment; HTMLComment *_secondComment; } @end @implementation HTMLRangeTests #pragma mark - Setup - (void)setUp { [super setUp]; [self setupDocument]; } - (void)setupDocument { // HTML:

Title

Hello

First textSecond text
<--Second comment-->
// DOM: // // | // +------------+-----------+ // | | | //

// | | | // "Title" "Hello" | // | // +--------+----------+ // | | //
// | // +-----------------+-----------------+ // | | | // "First text" "Second text" _h1 = [[HTMLElement alloc] initWithTagName:@"h1" attributes:@{@"id": @"h1"}]; _p = [[HTMLElement alloc] initWithTagName:@"p" attributes:@{@"id": @"p"}]; _div1 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"div1"}]; _div2 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"div2"}]; _title = [[HTMLText alloc] initWithData:@"Title"]; _paragraphText = [[HTMLText alloc] initWithData:@"Hello"]; _firstText = [[HTMLText alloc] initWithData:@"First text"]; _secondText = [[HTMLText alloc] initWithData:@"Second text"]; _firstComment = [[HTMLComment alloc] initWithData:@"First comment"]; _secondComment = [[HTMLComment alloc] initWithData:@"Second comment"]; [_h1 appendNode:_title]; [_p appendNode:_paragraphText]; [_div1 appendNodes:@[_div2, _secondComment]]; [_div2 appendNodes:@[_firstText, _firstComment, _secondText]]; _document = [HTMLDocument documentWithString:@""]; [_document.body appendNodes:@[_h1, _p, _div1]]; } #pragma mark - Tests - (void)testInitRange { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; XCTAssertEqualObjects(range.startContainer, _document); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _document); XCTAssertEqual(range.endOffset, 0); } - (void)testSetStartBoundary { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; XCTAssertThrows([range setStartNode:[HTMLElement new] startOffset:0], @"Cannot set boundary to a node outside of the range's document"); XCTAssertThrows([range setStartNode:[HTMLDocumentType new] startOffset:0], @"DOCTYPE as range boundary is invalid"); XCTAssertThrows([range setStartNode:_firstText startOffset:_firstText.length + 1], @"Offset is outside the boundary node"); //

Title

Hello

First textSecond text
// | // collapsed range [range setStartNode:_paragraphText startOffset:4]; XCTAssertEqualObjects(range.startContainer, _paragraphText); XCTAssertEqual(range.startOffset, 4); XCTAssertEqualObjects(range.endContainer, _paragraphText); XCTAssertEqual(range.endOffset, 4); //

Title

Hello

First textSecond text
// |______________| // s e [range setStartNode:_title startOffset:2]; XCTAssertEqualObjects(range.startContainer, _title); XCTAssertEqual(range.startOffset, 2); XCTAssertEqualObjects(range.endContainer, _paragraphText); XCTAssertEqual(range.endOffset, 4); } - (void)testSetEndBoundary { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; XCTAssertThrows([range setEndNode:[HTMLDocumentType new] endOffset: 0], @"DOCTYPE as range boundary is invalid"); XCTAssertThrows([range setEndNode:_firstText endOffset:_firstText.length + 1], @"Offset is outside the boundary node"); // ....

Title

Hello

First textSecond text
// |____________________| // s e [range setEndNode:_title endOffset:4]; XCTAssertEqualObjects(range.startContainer, _document); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _title); XCTAssertEqual(range.endOffset, 4); //

Title

Hello

First textSecond text
// |_| // s e [range setStartNode:_title startOffset:3]; XCTAssertEqualObjects(range.startContainer, _title); XCTAssertEqual(range.startOffset, 3); XCTAssertEqualObjects(range.endContainer, _title); XCTAssertEqual(range.endOffset, 4); //

Title

Hello

First textSecond text
// | // collapsed range [range setEndNode:_title endOffset:0]; XCTAssertEqualObjects(range.startContainer, _title); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _title); XCTAssertEqual(range.endOffset, 0); } - (void)testSetStartBeforeNode { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; //

Title

Hello

First textSecond text
// |___| // s e [range setStartNode:_paragraphText startOffset:0]; [range setEndNode:_paragraphText endOffset:4]; //

Title

Hello

First textSecond text
// (p, 0)->|_____| // s e [range setStartBeforeNode:_paragraphText]; XCTAssertEqualObjects(range.startContainer, _p); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _paragraphText); XCTAssertEqual(range.endOffset, 4); //

Title

Hello

First textSecond text
// |___| // s e [range setStartNode:_paragraphText startOffset:0]; [range setEndNode:_paragraphText endOffset:4]; //

Title

Hello

First textSecond text
// (body, 1)->|_____| // s e [range setStartBeforeNode:_p]; XCTAssertEqualObjects(range.startContainer, _document.body); XCTAssertEqual(range.startOffset, 1); XCTAssertEqualObjects(range.endContainer, _paragraphText); XCTAssertEqual(range.endOffset, 4); //

Title

Hello

First textSecond text
// |___| // s e [range setStartNode:_paragraphText startOffset:0]; [range setEndNode:_paragraphText endOffset:4]; //

Title

Hello

First textSecond text
//(body, 0)->|__________________| // s e [range setStartBeforeNode:_h1]; XCTAssertEqualObjects(range.startContainer, _document.body); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _paragraphText); XCTAssertEqual(range.endOffset, 4); //

Title

Hello

First textSecond text
// |____________________| // s e [range setStartNode:_firstText startOffset:_firstText.length]; [range setEndNode:_secondText endOffset:0]; //

Title

Hello

First textSecond text
// (div1, 0)->|________________________________| // s e [range setStartBeforeNode:_div2]; XCTAssertEqualObjects(range.startContainer, _div1); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _secondText); XCTAssertEqual(range.endOffset, 0); //

Title

Hello

First textSecond text
// |____________________| // s e [range setStartNode:_firstText startOffset:_firstText.length]; [range setEndNode:_secondText endOffset:0]; //

Title

Hello

First textSecond text
// (body, 2)->|_____________________________________| // s e [range setStartBeforeNode:_div1]; XCTAssertEqualObjects(range.startContainer, _document.body); XCTAssertEqual(range.startOffset, 2); XCTAssertEqualObjects(range.endContainer, _secondText); XCTAssertEqual(range.endOffset, 0); } - (void)testSetStartAfterNode { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; //

Title

Hello

First textSecond text
// |___| // s e [range setStartNode:_paragraphText startOffset:0]; [range setEndNode:_paragraphText endOffset:4]; //

Title

Hello

First textSecond text
// (p, 1)->| // collapsed range [range setStartAfterNode:_paragraphText]; XCTAssertEqualObjects(range.startContainer, _p); XCTAssertEqual(range.startOffset, 1); XCTAssertEqualObjects(range.endContainer, _p); XCTAssertEqual(range.endOffset, 1); //

Title

Hello

First textSecond text
// |___| // s e [range setStartNode:_paragraphText startOffset:0]; [range setEndNode:_paragraphText endOffset:4]; //

Title

Hello

First textSecond text
// (body, 2)->| // collapsed range [range setStartAfterNode:_p]; XCTAssertEqualObjects(range.startContainer, _document.body); XCTAssertEqual(range.startOffset, 2); XCTAssertEqualObjects(range.endContainer, _document.body); XCTAssertEqual(range.endOffset, 2); //

Title

Hello

First textSecond text
// |___| // s e [range setStartNode:_paragraphText startOffset:0]; [range setEndNode:_paragraphText endOffset:4]; //

Title

Hello

First textSecond text
// (body, 1)->|_____| // s e [range setStartAfterNode:_h1]; XCTAssertEqualObjects(range.startContainer, _document.body); XCTAssertEqual(range.startOffset, 1); XCTAssertEqualObjects(range.endContainer, _paragraphText); XCTAssertEqual(range.endOffset, 4); //

Title

Hello

First textSecond text
// |____________________| // s e [range setStartNode:_firstText startOffset:_firstText.length]; [range setEndNode:_secondText endOffset:0]; //

Title

Hello

First textSecond text
// (div1, 1)->| // collapsed range [range setStartAfterNode:_div2]; XCTAssertEqualObjects(range.startContainer, _div1); XCTAssertEqual(range.startOffset, 1); XCTAssertEqualObjects(range.endContainer, _div1); XCTAssertEqual(range.endOffset, 1); //

Title

Hello

First textSecond text
// |____________________| // s e [range setStartNode:_firstText startOffset:_firstText.length]; [range setEndNode:_secondText endOffset:0]; //

Title

Hello

First textSecond text
// (_div2, 1)->|___________________| // s e [range setStartAfterNode:_firstText]; XCTAssertEqualObjects(range.startContainer, _div2); XCTAssertEqual(range.startOffset, 1); XCTAssertEqualObjects(range.endContainer, _secondText); XCTAssertEqual(range.endOffset, 0); } - (void)testSetEndBeforeNode { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; //

Title

Hello

First textSecond text
// |___| // s e [range setStartNode:_paragraphText startOffset:0]; [range setEndNode:_paragraphText endOffset:4]; //

Title

Hello

First textSecond text
// (p, 0)->| // collapsed range [range setEndBeforeNode:_paragraphText]; XCTAssertEqualObjects(range.startContainer, _p); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _p); XCTAssertEqual(range.endOffset, 0); //

Title

Hello

First textSecond text
// |___| // s e [range setStartNode:_paragraphText startOffset:0]; [range setEndNode:_paragraphText endOffset:4]; //

Title

Hello

First textSecond text
// (body, 1)->| // collapsed range [range setEndBeforeNode:_p]; XCTAssertEqualObjects(range.startContainer, _document.body); XCTAssertEqual(range.startOffset, 1); XCTAssertEqualObjects(range.endContainer, _document.body); XCTAssertEqual(range.endOffset, 1); //

Title

Hello

First textSecond text
// |___| // s e [range setStartNode:_paragraphText startOffset:0]; [range setEndNode:_paragraphText endOffset:4]; //

Title

Hello

First textSecond text
//(body, 0)->| // collapsed range [range setEndBeforeNode:_h1]; XCTAssertEqualObjects(range.startContainer, _document.body); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _document.body); XCTAssertEqual(range.endOffset, 0); //

Title

Hello

First textSecond text
// |_____________________________| // s e [range setStartNode:_firstText startOffset:0]; [range setEndNode:_secondText endOffset:0]; //

Title

Hello

First textSecond text
// |__________|<-(div2, 1) // s e [range setEndBeforeNode:_firstComment]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _div2); XCTAssertEqual(range.endOffset, 1); //

Title

Hello

First textSecond text
// |______________________| // s e [range setStartNode:_firstText startOffset:_firstText.length]; [range setEndNode:_secondText endOffset:2]; //

Title

Hello

First textSecond text
// |___________________|<-(div1, 2) // s e [range setEndBeforeNode:_secondText]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, _firstText.length); XCTAssertEqualObjects(range.endContainer, _div2); XCTAssertEqual(range.endOffset, 2); } - (void)testSetEndAfterNode { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; //

Title

Hello

First textSecond text
// |___| // s e [range setStartNode:_paragraphText startOffset:0]; [range setEndNode:_paragraphText endOffset:4]; //

Title

Hello

First textSecond text
// |____|<-(p, 1) // s e [range setEndAfterNode:_paragraphText]; XCTAssertEqualObjects(range.startContainer, _paragraphText); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _p); XCTAssertEqual(range.endOffset, 1); //

Title

Hello

First textSecond text
// |___| // s e [range setStartNode:_paragraphText startOffset:0]; [range setEndNode:_paragraphText endOffset:4]; //

Title

Hello

First textSecond text
// |_______________|<-(body, 2) // s e [range setEndAfterNode:_p]; XCTAssertEqualObjects(range.startContainer, _paragraphText); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _document.body); XCTAssertEqual(range.endOffset, 2); //

Title

Hello

First textSecond text
// |___| // s e [range setStartNode:_paragraphText startOffset:0]; [range setEndNode:_paragraphText endOffset:4]; //

Title

Hello

First textSecond text
// (body, 1)->| // collapsed range [range setEndAfterNode:_h1]; XCTAssertEqualObjects(range.startContainer, _document.body); XCTAssertEqual(range.startOffset, 1); XCTAssertEqualObjects(range.endContainer, _document.body); XCTAssertEqual(range.endOffset, 1); //

Title

Hello

First textSecond text
// |____________________| // s e [range setStartNode:_firstText startOffset:_firstText.length]; [range setEndNode:_secondText endOffset:0]; //

Title

Hello

First textSecond text
// |______________________________________|<-(div1, 1) // s e [range setEndAfterNode:_div2]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, _firstText.length); XCTAssertEqualObjects(range.endContainer, _div1); XCTAssertEqual(range.endOffset, 1); //

Title

Hello

First textSecond text
// |____________________| // s e [range setStartNode:_firstText startOffset:_firstText.length]; [range setEndNode:_secondText endOffset:0]; //

Title

Hello

First textSecond text
// |__________________|<-(div2, 2) // s e [range setEndAfterNode:_firstComment]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, _firstText.length); XCTAssertEqualObjects(range.endContainer, _div2); XCTAssertEqual(range.endOffset, 2); } - (void)testIsCollapsed { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; XCTAssertTrue(range.isCollapsed); [range setEndNode:_title endOffset:1]; XCTAssertFalse(range.isCollapsed); [range setStartNode:_title startOffset:1]; XCTAssertTrue(range.isCollapsed); } - (void)testCollapseToStart { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; //

Title

Hello

First textSecond text
<--Second comment-->
// |______________| // s e [range setStartNode:_title startOffset:2]; [range setEndNode:_paragraphText endOffset:4]; [range collapseToStart]; XCTAssertEqualObjects(range.startContainer, _title); XCTAssertEqual(range.startOffset, 2); XCTAssertEqualObjects(range.endContainer, _title); XCTAssertEqual(range.endOffset, 2); XCTAssertTrue(range.isCollapsed); } - (void)testCollapseToEnd { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; //

Title

Hello

First textSecond text
<--Second comment-->
// |______________| // s e [range setStartNode:_title startOffset:2]; [range setEndNode:_paragraphText endOffset:4]; [range collapseToEnd]; XCTAssertEqualObjects(range.startContainer, _paragraphText); XCTAssertEqual(range.startOffset, 4); XCTAssertEqualObjects(range.endContainer, _paragraphText); XCTAssertEqual(range.endOffset, 4); XCTAssertTrue(range.isCollapsed); } - (void)testSelectNode { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; //

Title

Hello

First textSecond text
<--Second comment-->
// ---------- [range selectNode:_firstText]; XCTAssertEqualObjects(range.startContainer, _div2); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _div2); XCTAssertEqual(range.endOffset, 1); //

Title

Hello

First textSecond text
<--Second comment-->
// -------------------- [range selectNode:_firstComment]; XCTAssertEqualObjects(range.startContainer, _div2); XCTAssertEqual(range.startOffset, 1); XCTAssertEqualObjects(range.endContainer, _div2); XCTAssertEqual(range.endOffset, 2); //

Title

Hello

First textSecond text
<--Second comment-->
// ----------------------------------------------------------------------------------- [range selectNode:_div1]; XCTAssertEqualObjects(range.startContainer, _document.body); XCTAssertEqual(range.startOffset, 2); XCTAssertEqualObjects(range.endContainer, _document.body); XCTAssertEqual(range.endOffset, 3); //

Title

Hello

First textSecond text
<--Second comment-->
// ---------------------------------------------------- [range selectNode:_div2]; XCTAssertEqualObjects(range.startContainer, _div1); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _div1); XCTAssertEqual(range.endOffset, 1); //

Title

Hello

First textSecond text
<--Second comment-->
// -------------------- [range selectNode:_secondComment]; XCTAssertEqualObjects(range.startContainer, _div1); XCTAssertEqual(range.startOffset, 1); XCTAssertEqualObjects(range.endContainer, _div1); XCTAssertEqual(range.endOffset, 2); //

Title

Hello

First textSecond text
<--Second comment-->
// -------------- [range selectNode:_h1]; XCTAssertEqualObjects(range.startContainer, _document.body); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _document.body); XCTAssertEqual(range.endOffset, 1); } - (void)testSelectNodeContents { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; //

Title

Hello

First textSecond text
<--Second comment-->
// ---------- [range selectNodeContents:_firstText]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _firstText); XCTAssertEqual(range.endOffset, _firstText.length); //

Title

Hello

First textSecond text
<--Second comment-->
// ------------- [range selectNodeContents:_firstComment]; XCTAssertEqualObjects(range.startContainer, _firstComment); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _firstComment); XCTAssertEqual(range.endOffset, _firstComment.length); //

Title

Hello

First textSecond text
<--Second comment-->
// ------------------------------------------------------------------------ [range selectNodeContents:_div1]; XCTAssertEqualObjects(range.startContainer, _div1); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _div1); XCTAssertEqual(range.endOffset, 2); //

Title

Hello

First textSecond text
<--Second comment-->
// ----------------------------------------- [range selectNodeContents:_div2]; XCTAssertEqualObjects(range.startContainer, _div2); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _div2); XCTAssertEqual(range.endOffset, 3); //

Title

Hello

First textSecond text
<--Second comment-->
// -------------- [range selectNodeContents:_secondComment]; XCTAssertEqualObjects(range.startContainer, _secondComment); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _secondComment); XCTAssertEqual(range.endOffset, _secondComment.length); //

Title

Hello

First textSecond text
<--Second comment-->
// ----- [range selectNodeContents:_h1]; XCTAssertEqualObjects(range.startContainer, _h1); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _h1); XCTAssertEqual(range.endOffset, 1); } - (void)testCompareBoundaries { HTMLRange *range1 = [[HTMLRange alloc] initWithDocument:_document]; HTMLRange *range2 = [[HTMLRange alloc] initWithDocument:_document]; //

Title

Hello

First textSecond text
<--Second comment-->
// ---------- [range1 selectNode:_firstText]; //

Title

Hello

First textSecond text
<--Second comment-->
// ----------- [range2 selectNode:_secondText]; XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodStartToStart sourceRange:range2] == NSOrderedAscending); XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodStartToEnd sourceRange:range2] == NSOrderedAscending); XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodEndToEnd sourceRange:range2] == NSOrderedAscending); XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodEndToStart sourceRange:range2] == NSOrderedAscending); //

Title

Hello

First textSecond text
<--Second comment-->
// ---------- [range1 selectNode:_firstText]; //

Title

Hello

First textSecond text
<--Second comment-->
// -------------------- [range2 selectNode:_firstComment]; XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodStartToStart sourceRange:range2] == NSOrderedAscending); XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodStartToEnd sourceRange:range2] == NSOrderedSame); XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodEndToEnd sourceRange:range2] == NSOrderedAscending); XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodEndToStart sourceRange:range2] == NSOrderedAscending); //

Title

Hello

First textSecond text
<--Second comment-->
// ---------- [range1 selectNode:_firstText]; //

Title

Hello

First textSecond text
<--Second comment-->
// ---------------------------------------------------- [range2 selectNode:_div2]; XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodStartToStart sourceRange:range2] == NSOrderedDescending); XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodStartToEnd sourceRange:range2] == NSOrderedDescending); XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodEndToEnd sourceRange:range2] == NSOrderedAscending); XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodEndToStart sourceRange:range2] == NSOrderedAscending); //

Title

Hello

First textSecond text
<--Second comment-->
// ----------- [range1 selectNode:_secondText]; //

Title

Hello

First textSecond text
<--Second comment-->
// ---------------------------------------------------- [range2 selectNode:_div2]; XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodStartToStart sourceRange:range2] == NSOrderedDescending); XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodStartToEnd sourceRange:range2] == NSOrderedDescending); XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodEndToEnd sourceRange:range2] == NSOrderedAscending); XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodEndToStart sourceRange:range2] == NSOrderedAscending); //

Title

Hello

First textSecond text
<--Second comment-->
// ----------------------------------------------------------------------------------- [range1 selectNode:_div1]; //

Title

Hello

First textSecond text
<--Second comment-->
// ---------------------------------------------------- [range2 selectNode:_div2]; XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodStartToStart sourceRange:range2] == NSOrderedAscending); XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodStartToEnd sourceRange:range2] == NSOrderedDescending); XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodEndToEnd sourceRange:range2] == NSOrderedDescending); XCTAssertTrue([range1 compareBoundaryPoints:HTMLRangeComparisonMethodEndToStart sourceRange:range2] == NSOrderedAscending); } - (void)testContainmentAndComparisons { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; /*********** Compare ***********/ //

Title

Hello

First textSecond text
<--Second comment-->
// ---------------------------------------------------- [range selectNode:_div2]; XCTAssertTrue([range comparePoint:_div1 offset:0] == NSOrderedSame); //

Title

Hello

First textSecond text
<--Second comment-->
// ----------------------------------------- [range selectNodeContents:_div2]; XCTAssertTrue([range comparePoint:_div1 offset:0] == NSOrderedAscending); //

Title

Hello

First textSecond text
<--Second comment-->
// ----- [range selectNodeContents:_p]; XCTAssertTrue([range comparePoint:_div1 offset:0] == NSOrderedDescending); //

Title

Hello

First textSecond text
<--Second comment-->
// ------------ [range selectNode:_p]; XCTAssertTrue([range comparePoint:_document.body offset:0] == NSOrderedAscending); //

Title

Hello

First textSecond text
<--Second comment-->
// ------------ [range selectNode:_p]; XCTAssertTrue([range comparePoint:_document.body offset:1] == NSOrderedSame); //

Title

Hello

First textSecond text
<--Second comment-->
// ------------ [range selectNode:_p]; XCTAssertTrue([range comparePoint:_document.body offset:2] == NSOrderedSame); //

Title

Hello

First textSecond text
<--Second comment-->
// ------------ [range selectNode:_p]; XCTAssertTrue([range comparePoint:_document.body offset:3] == NSOrderedDescending); //

Title

Hello

First textSecond text
<--Second comment-->
// ------------- [range selectNodeContents:_firstComment]; XCTAssertTrue([range comparePoint:_firstComment offset:0] == NSOrderedSame); //

Title

Hello

First textSecond text
<--Second comment-->
// ------------- [range selectNodeContents:_firstComment]; XCTAssertTrue([range comparePoint:_firstComment offset:3] == NSOrderedSame); /*********** Contains ***********/ //

Title

Hello

First textSecond text
<--Second comment-->
// ---------------------------------------------------- [range selectNode:_div2]; XCTAssertTrue([range containsPoint:_div1 offset:0]); //

Title

Hello

First textSecond text
<--Second comment-->
// ------------ [range selectNode:_p]; XCTAssertTrue([range containsPoint:_document.body offset:1]); //

Title

Hello

First textSecond text
<--Second comment-->
// ------------ [range selectNode:_p]; XCTAssertTrue([range containsPoint:_document.body offset:2]); //

Title

Hello

First textSecond text
<--Second comment-->
// ------------- [range selectNodeContents:_firstComment]; XCTAssertTrue([range containsPoint:_firstComment offset:3]); } - (void)testIntersections { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; XCTAssertFalse([range intersectsNode:[HTMLText new]]); XCTAssertTrue([range intersectsNode:_document]); //

Title

Hello

First textSecond text
<--Second comment-->
// ------------ [range selectNode:_p]; XCTAssertFalse([range intersectsNode:_h1]); XCTAssertTrue([range intersectsNode:_p]); XCTAssertFalse([range intersectsNode:_div1]); //

Title

Hello

First textSecond text
<--Second comment-->
// ----------------- [range selectNode:_p]; [range setEndAfterNode:_div1]; XCTAssertFalse([range intersectsNode:_h1]); XCTAssertTrue([range intersectsNode:_p]); XCTAssertTrue([range intersectsNode:_div1]); //

Title

Hello

First textSecond text
<--Second comment-->
// --------------------------- [range selectNode:_firstComment]; [range setEndAfterNode:_secondText]; XCTAssertTrue([range intersectsNode:_div2]); XCTAssertFalse([range intersectsNode:_firstText]); XCTAssertTrue([range intersectsNode:_firstComment]); XCTAssertTrue([range intersectsNode:_secondText]); } - (void)testThatCharacterDataMutationsUpdateRangeCorrectly { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; //

Title

Hello

First textSecond text
<--Second comment-->
// |________| [range selectNodeContents:_firstText]; //

Title

Hello

First text New TextSecond text
<--Second comment-->
// |________| [_firstText appendData:@" New Text"]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _firstText); XCTAssertEqual(range.endOffset, 10); //

Title

Hello

New text New TextSecond text
<--Second comment-->
// |______| [_firstText replaceDataInRange:NSMakeRange(0, 5) withData:@"New"]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _firstText); XCTAssertEqual(range.endOffset, 8); //

Title

Hello

New TextSecond text
<--Second comment-->
// | [_firstText setData:@"New Text"]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _firstText); XCTAssertEqual(range.endOffset, 0); //

Title

Hello

New TextSecond text
<--Second comment-->
// |______| [range selectNodeContents:_firstText]; //

Title

Hello

NewTextSecond text
<--Second comment-->
// |_____| [_firstText deleteDataInRange:NSMakeRange(3, 1)]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _firstText); XCTAssertEqual(range.endOffset, 7); //

Title

Hello

NewNewTextSecond text
<--Second comment-->
// |________| [_firstText insertData:@"New" atOffset:3]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _firstText); XCTAssertEqual(range.endOffset, 10); //

Title

Hello

NewNewTextSecond text
<--Second comment-->
// |_____| [range setStartNode:_firstText startOffset:3]; //

Title

Hello

PrefixNewNewTextSecond text
<--Second comment-->
// |_____| [_firstText insertData:@"Prefix" atOffset:0]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 9); XCTAssertEqualObjects(range.endContainer, _firstText); XCTAssertEqual(range.endOffset, 16); //

Title

Hello

PrefixNewTextSecond text
<--Second comment-->
// |_____| [_firstText deleteDataInRange:NSMakeRange(6, 3)]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 6); XCTAssertEqualObjects(range.endContainer, _firstText); XCTAssertEqual(range.endOffset, 13); //

Title

Hello

PreABCDTextSecond text
<--Second comment-->
// |______| [_firstText replaceDataInRange:NSMakeRange(3, 6) withData:@"ABCD"]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 3); XCTAssertEqualObjects(range.endContainer, _firstText); XCTAssertEqual(range.endOffset, 11); //

Title

Hello

Pre TextSecond text
<--Second comment-->
// |___| [_firstText replaceDataInRange:NSMakeRange(3, 4) withData:@" "]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 3); XCTAssertEqualObjects(range.endContainer, _firstText); XCTAssertEqual(range.endOffset, 8); } - (void)testThatCharacterDataMutationsUpdateRangeCorrectly_DifferentBoundaries { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; //

Title

Hello

First textSecond text
<--Second comment-->
// |___________________________| [range setStartNode:_firstText startOffset:5]; [range setEndNode:_secondText endOffset:3]; //

Title

Hello

First text New TextSecond text
<--Second comment-->
// |____________________________________| [_firstText appendData:@" New Text"]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 5); XCTAssertEqualObjects(range.endContainer, _secondText); XCTAssertEqual(range.endOffset, 3); //

Title

Hello

New text New TextSecond text
<--Second comment-->
// |______________________________________| [_firstText replaceDataInRange:NSMakeRange(0, 5) withData:@"New"]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _secondText); XCTAssertEqual(range.endOffset, 3); //

Title

Hello

New TextSecond text
<--Second comment-->
// |_____________________________| [_firstText setData:@"New Text"]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _secondText); XCTAssertEqual(range.endOffset, 3); //

Title

Hello

NewTextSecond text
<--Second comment-->
// |____________________________| [_firstText deleteDataInRange:NSMakeRange(3, 1)]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _secondText); XCTAssertEqual(range.endOffset, 3); //

Title

Hello

NewNewTextSecond text
<--Second comment-->
// |_______________________________| [_firstText insertData:@"New" atOffset:3]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _secondText); XCTAssertEqual(range.endOffset, 3); //

Title

Hello

NewNewTextSecond text
<--Second comment-->
// |____________________________| [range setStartNode:_firstText startOffset:3]; //

Title

Hello

PrefixNewNewTextSecond text
<--Second comment-->
// |____________________________| [_firstText insertData:@"Prefix" atOffset:0]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 9); XCTAssertEqualObjects(range.endContainer, _secondText); XCTAssertEqual(range.endOffset, 3); //

Title

Hello

PrefixNewTextSecond text
<--Second comment-->
// |____________________________| [_firstText deleteDataInRange:NSMakeRange(6, 3)]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 6); XCTAssertEqualObjects(range.endContainer, _secondText); XCTAssertEqual(range.endOffset, 3); //

Title

Hello

PreABCDTextSecond text
<--Second comment-->
// |_____________________________| [_firstText replaceDataInRange:NSMakeRange(3, 6) withData:@"ABCD"]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 3); XCTAssertEqualObjects(range.endContainer, _secondText); XCTAssertEqual(range.endOffset, 3); //

Title

Hello

Pre TextSecond text
<--Second comment-->
// |__________________________| [_firstText replaceDataInRange:NSMakeRange(3, 4) withData:@" "]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 3); XCTAssertEqualObjects(range.endContainer, _secondText); XCTAssertEqual(range.endOffset, 3); //

Title

Hello

Pre TextPrefixSecond text
<--Second comment-->
// |________________________________| [_secondText insertData:@"Prefix" atOffset:0]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 3); XCTAssertEqualObjects(range.endContainer, _secondText); XCTAssertEqual(range.endOffset, 9); //

Title

Hello

Pre TextPrefixSecond text
<--Second comment-->
// |___________________| [_firstComment setData:@"X"]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 3); XCTAssertEqualObjects(range.endContainer, _secondText); XCTAssertEqual(range.endOffset, 9); } - (void)testThatTextSplitUpdateRangeCorrectly_BeforeStartTextNode { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; //

Title

Hello

First textSecond text
<--Second comment-->
// |________| [range selectNodeContents:_firstText]; //

Title

Hello

First textSecond text
<--Second comment-->
// ^________| HTMLText *split = [_firstText splitTextAtOffset:0]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, split); XCTAssertEqual(range.endOffset, 10); } - (void)testThatTextSplitUpdateRangeCorrectly_AfterEndTextNode { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; //

Title

Hello

First textSecond text
<--Second comment-->
// |________| [range selectNodeContents:_firstText]; //

Title

Hello

First textSecond text
<--Second comment-->
// |________^ [_firstText splitTextAtOffset:_firstText.length]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, _firstText); XCTAssertEqual(range.endOffset, 10); } - (void)testThatTextSplitUpdateRangeCorrectly_MidleSameTextNode { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; //

Title

Hello

First textSecond text
<--Second comment-->
// |________| [range selectNodeContents:_firstText]; //

Title

Hello

First textSecond text
<--Second comment-->
// |____^___| HTMLText *split = [_firstText splitTextAtOffset:6]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 0); XCTAssertEqualObjects(range.endContainer, split); XCTAssertEqual(range.endOffset, 4); } - (void)testThatTextSplitUpdateRangeCorrectly_MidleDifferentTextNodes { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; //

Title

Hello

First textSecond text
<--Second comment-->
// |______________________________| [range setStartNode:_firstText startOffset:2]; [range setEndNode:_secondText endOffset:3]; //

Title

Hello

First textSecond text
<--Second comment-->
// |____^__________________________| [_firstText splitTextAtOffset:6]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 2); XCTAssertEqualObjects(range.endContainer, _secondText); XCTAssertEqual(range.endOffset, 3); } - (void)testThatTextSplitUpdateRangeCorrectly_BeforeStartDifferentTextNodes { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; //

Title

Hello

First textSecond text
<--Second comment-->
// |______________________________| [range setStartNode:_firstText startOffset:6]; [range setEndNode:_secondText endOffset:3]; //

Title

Hello

First textSecond text
<--Second comment-->
// ^ |__________________________| HTMLText *split = [_firstText splitTextAtOffset:2]; XCTAssertEqualObjects(range.startContainer, split); XCTAssertEqual(range.startOffset, 4); XCTAssertEqualObjects(range.endContainer, _secondText); XCTAssertEqual(range.endOffset, 3); } - (void)testThatTextSplitUpdateRangeCorrectly_BeforeEndDifferentTextNodes { HTMLRange *range = [[HTMLRange alloc] initWithDocument:_document]; //

Title

Hello

First textSecond text
<--Second comment-->
// |_______________________________| [range setStartNode:_firstText startOffset:6]; [range setEndNode:_secondText endOffset:4]; //

Title

Hello

First textSecond text
<--Second comment-->
// |_____________________________^_| HTMLText *split = [_secondText splitTextAtOffset:2]; XCTAssertEqualObjects(range.startContainer, _firstText); XCTAssertEqual(range.startOffset, 6); XCTAssertEqualObjects(range.endContainer, split); XCTAssertEqual(range.endOffset, 2); } #pragma mark - Editing - (HTMLDocument *)editingDocument { //
//
//

This is a text

//

Hello

//
//

World

//
//

Another text

//
//
//
// | // +---------------+---------------+ // | | | //

// | | | // +--------+-------+ "World"

// | | | //

+-----+-----+ // | | | | // +-------+-------+ "Hello" "Another" // | | | // "This " " text" | // | "Text" // "is a" // // return [HTMLDocument documentWithString: @"

" @"

This is a text

Hello

" @"

World

" @"

Another text

" @"
"]; } #pragma mark - Delete Contents - (void)testDeleteContents_SameTextNode { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:1]; HTMLNode *end = [document querySelector:@"#P1"].firstChild; [range setEndNode:end endOffset:4]; [range deleteContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

T is a text

Hello

" @"

World

" @"

Another text

" @"
")); } - (void)testDeleteContents_SameTextNode_Selected { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *node = [document querySelector:@"#P1"].firstChild; [range selectNode:node]; [range deleteContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

is a text

Hello

" @"

World

" @"

Another text

" @"
")); XCTAssertEqual([document querySelector:@"#P1"].childNodesCount, 2); } - (void)testDeleteContents_SameTextNode_SelectedContents { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *node = [document querySelector:@"#P1"].firstChild; [range selectNodeContents:node]; [range deleteContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

is a text

Hello

" @"

World

" @"

Another text

" @"
")); XCTAssertEqual([document querySelector:@"#P1"].childNodesCount, 3); XCTAssertEqual([document querySelector:@"#P1"].firstChild.nodeType, HTMLNodeText); } - (void)testDeleteContents_DifferentTextNodesOfSingleParent { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:3]; HTMLNode *end = [document querySelector:@"#P1"].lastChild; [range setEndNode:end endOffset:2]; [range deleteContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

Thiext

Hello

" @"

World

" @"

Another text

" @"
")); } - (void)testDeleteContents_DifferentTextNodesOfDifferentParents { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:3]; HTMLNode *end = [document querySelector:@"#P2"].lastChild; [range setEndNode:end endOffset:4]; [range deleteContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

Thi

o

" @"

World

" @"

Another text

" @"
")); } - (void)testDeleteContents_DifferentTextNodesOfDifferentParents_HavingContainedNodesInBetween { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:3]; HTMLNode *end = [document querySelector:@"#P4"].firstChild; [range setEndNode:end endOffset:2]; [range deleteContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

Thi

" @"

other text

" @"
")); } - (void)testDeleteContents_SameContainerNode { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"]; [range setStartNode:start startOffset:0]; HTMLNode *end = [document querySelector:@"#P1"]; [range setEndNode:end endOffset:2]; [range deleteContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

text

Hello

" @"

World

" @"

Another text

" @"
")); } - (void)testDeleteContents_SameContainerNode_Selected { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *node = [document querySelector:@"#P1"]; [range selectNode:node]; [range deleteContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

Hello

" @"

World

" @"

Another text

" @"
")); } - (void)testDeleteContents_SameContainerNode_SelectedContents { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *node = [document querySelector:@"#P1"]; [range selectNodeContents:node]; [range deleteContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

Hello

" @"

World

" @"

Another text

" @"
")); } - (void)testDeleteContents_StartContainerIsCommonRoot { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#D1"]; [range setStartNode:start startOffset:0]; HTMLNode *end = [document querySelector:@"#P2"].firstChild; [range setEndNode:end endOffset:2]; [range deleteContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

llo

" @"

World

" @"

Another text

" @"
")); } - (void)testDeleteContents_EndContainerIsCommonRoot { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:1]; HTMLNode *end = [document querySelector:@"#D1"]; [range setEndNode:end endOffset:1]; [range deleteContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

T

Hello

" @"

World

" @"

Another text

" @"
")); } #pragma mark - Clone Contents - (void)testCloneContents_SameTextNode { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:1]; HTMLNode *end = [document querySelector:@"#P1"].firstChild; [range setEndNode:end endOffset:4]; HTMLDocumentFragment *fragment = [range cloneContents]; XCTAssertEqualObjects(fragment.innerHTML, @"his"); XCTAssertEqual(fragment.childNodesCount, 1); XCTAssertEqual(fragment.firstChild.nodeType, HTMLNodeText); } - (void)testCloneContents_SameTextNode_Selected { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *node = [document querySelector:@"#P1"].firstChild; [range selectNode:node]; HTMLDocumentFragment *fragment = [range cloneContents]; XCTAssertEqualObjects(fragment.innerHTML, @"This "); XCTAssertEqual(fragment.childNodesCount, 1); XCTAssertEqual(fragment.firstChild.nodeType, HTMLNodeText); } - (void)testCloneContents_SameTextNode_SelectedContents { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *node = [document querySelector:@"#P1"].firstChild; [range selectNodeContents:node]; HTMLDocumentFragment *fragment = [range cloneContents]; XCTAssertEqualObjects(fragment.innerHTML, @"This "); XCTAssertEqual(fragment.childNodesCount, 1); XCTAssertEqual(fragment.firstChild.nodeType, HTMLNodeText); } - (void)testCloneContents_DifferentTextNodesOfSingleParent { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:3]; HTMLNode *end = [document querySelector:@"#P1"].lastChild; [range setEndNode:end endOffset:2]; HTMLDocumentFragment *fragment = [range cloneContents]; XCTAssertEqualObjects(fragment.innerHTML, @"s is a t"); } - (void)testCloneContents_DifferentTextNodesOfDifferentParents { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:3]; HTMLNode *end = [document querySelector:@"#P2"].lastChild; [range setEndNode:end endOffset:4]; HTMLDocumentFragment *fragment = [range cloneContents]; XCTAssertEqualObjects(fragment.innerHTML, DoubleQuote(@"

s is a text

Hell

")); } - (void)testCloneContents_DifferentTextNodesOfDifferentParents_HavingContainedNodesInBetween { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:3]; HTMLNode *end = [document querySelector:@"#P4"].firstChild; [range setEndNode:end endOffset:2]; HTMLDocumentFragment *fragment = [range cloneContents]; XCTAssertEqualObjects(fragment.innerHTML, DoubleQuote(@"

s is a text

Hello

" @"

World

" @"

An

")); } - (void)testCloneContents_SameContainerNode { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"]; [range setStartNode:start startOffset:0]; HTMLNode *end = [document querySelector:@"#P1"]; [range setEndNode:end endOffset:2]; HTMLDocumentFragment *fragment = [range cloneContents]; XCTAssertEqualObjects(fragment.innerHTML, @"This is a"); } - (void)testCloneContents_SameContainerNode_Selected { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *node = [document querySelector:@"#P1"]; [range selectNode:node]; HTMLDocumentFragment *fragment = [range cloneContents]; XCTAssertEqualObjects(fragment.innerHTML, DoubleQuote(@"

This is a text

")); } - (void)testCloneContents_SameContainerNode_SelectedContents { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *node = [document querySelector:@"#P1"]; [range selectNodeContents:node]; HTMLDocumentFragment *fragment = [range cloneContents]; XCTAssertEqualObjects(fragment.innerHTML, DoubleQuote(@"This is a text")); } - (void)testCloneContents_StartContainerIsCommonRoot { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#D1"]; [range setStartNode:start startOffset:0]; HTMLNode *end = [document querySelector:@"#P2"].firstChild; [range setEndNode:end endOffset:2]; HTMLDocumentFragment *fragment = [range cloneContents]; XCTAssertEqualObjects(fragment.innerHTML, DoubleQuote(@"

This is a text

He

")); } - (void)testCloneContents_EndContainerIsCommonRoot { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:1]; HTMLNode *end = [document querySelector:@"#D1"]; [range setEndNode:end endOffset:1]; HTMLDocumentFragment *fragment = [range cloneContents]; XCTAssertEqualObjects(fragment.innerHTML, DoubleQuote(@"

his is a text

")); } #pragma mark - Extract Contents - (void)testExtractContents_SameTextNode { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:1]; HTMLNode *end = [document querySelector:@"#P1"].firstChild; [range setEndNode:end endOffset:4]; HTMLDocumentFragment *fragment = [range extractContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

T is a text

Hello

" @"

World

" @"

Another text

" @"
")); XCTAssertEqualObjects(fragment.innerHTML, @"his"); XCTAssertEqual(fragment.childNodesCount, 1); XCTAssertEqual(fragment.firstChild.nodeType, HTMLNodeText); } - (void)testExtractContents_SameTextNode_Selected { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *node = [document querySelector:@"#P1"].firstChild; [range selectNode:node]; HTMLDocumentFragment *fragment = [range extractContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

is a text

Hello

" @"

World

" @"

Another text

" @"
")); XCTAssertEqual([document querySelector:@"#P1"].childNodesCount, 2); XCTAssertEqualObjects(fragment.innerHTML, @"This "); XCTAssertEqual(fragment.childNodesCount, 1); XCTAssertEqual(fragment.firstChild.nodeType, HTMLNodeText); } - (void)testExtractContents_SameTextNode_SelectedContents { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *node = [document querySelector:@"#P1"].firstChild; [range selectNodeContents:node]; HTMLDocumentFragment *fragment = [range extractContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

is a text

Hello

" @"

World

" @"

Another text

" @"
")); XCTAssertEqual([document querySelector:@"#P1"].childNodesCount, 3); XCTAssertEqual([document querySelector:@"#P1"].firstChild.nodeType, HTMLNodeText); XCTAssertEqualObjects(fragment.innerHTML, @"This "); XCTAssertEqual(fragment.childNodesCount, 1); XCTAssertEqual(fragment.firstChild.nodeType, HTMLNodeText); } - (void)testExtractContents_DifferentTextNodesOfSingleParent { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:3]; HTMLNode *end = [document querySelector:@"#P1"].lastChild; [range setEndNode:end endOffset:2]; HTMLDocumentFragment *fragment = [range extractContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

Thiext

Hello

" @"

World

" @"

Another text

" @"
")); XCTAssertEqualObjects(fragment.innerHTML, @"s is a t"); } - (void)testExtractContents_DifferentTextNodesOfDifferentParents { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:3]; HTMLNode *end = [document querySelector:@"#P2"].lastChild; [range setEndNode:end endOffset:4]; HTMLDocumentFragment *fragment = [range extractContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

Thi

o

" @"

World

" @"

Another text

" @"
")); XCTAssertEqualObjects(fragment.innerHTML, DoubleQuote(@"

s is a text

Hell

")); } - (void)testExtractContents_DifferentTextNodesOfDifferentParents_HavingContainedNodesInBetween { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:3]; HTMLNode *end = [document querySelector:@"#P4"].firstChild; [range setEndNode:end endOffset:2]; HTMLDocumentFragment *fragment = [range extractContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

Thi

" @"

other text

" @"
")); XCTAssertEqualObjects(fragment.innerHTML, DoubleQuote(@"

s is a text

Hello

" @"

World

" @"

An

")); } - (void)testExtractContents_SameContainerNode { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"]; [range setStartNode:start startOffset:0]; HTMLNode *end = [document querySelector:@"#P1"]; [range setEndNode:end endOffset:2]; HTMLDocumentFragment *fragment = [range extractContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

text

Hello

" @"

World

" @"

Another text

" @"
")); XCTAssertEqualObjects(fragment.innerHTML, @"This is a"); } - (void)testExtractContents_SameContainerNode_Selected { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *node = [document querySelector:@"#P1"]; [range selectNode:node]; HTMLDocumentFragment *fragment = [range extractContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

Hello

" @"

World

" @"

Another text

" @"
")); XCTAssertEqualObjects(fragment.innerHTML, DoubleQuote(@"

This is a text

")); } - (void)testExtractContents_SameContainerNode_SelectedContents { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *node = [document querySelector:@"#P1"]; [range selectNodeContents:node]; HTMLDocumentFragment *fragment = [range extractContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

Hello

" @"

World

" @"

Another text

" @"
")); XCTAssertEqualObjects(fragment.innerHTML, DoubleQuote(@"This is a text")); } - (void)testExtractContents_StartContainerIsCommonRoot { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#D1"]; [range setStartNode:start startOffset:0]; HTMLNode *end = [document querySelector:@"#P2"].firstChild; [range setEndNode:end endOffset:2]; HTMLDocumentFragment *fragment = [range extractContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

llo

" @"

World

" @"

Another text

" @"
")); XCTAssertEqualObjects(fragment.innerHTML, DoubleQuote(@"

This is a text

He

")); } - (void)testExtractContents_EndContainerIsCommonRoot { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:1]; HTMLNode *end = [document querySelector:@"#D1"]; [range setEndNode:end endOffset:1]; HTMLDocumentFragment *fragment = [range extractContents]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

T

Hello

" @"

World

" @"

Another text

" @"
")); XCTAssertEqualObjects(fragment.innerHTML, DoubleQuote(@"

his is a text

")); } #pragma mark - Insertion & Surround - (void)testInsertNode_InvalidNode { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:2]; HTMLNode *end = [document querySelector:@"#P1"].lastChild; [range setEndNode:end endOffset:5]; XCTAssertThrows([range insertNode:start]); HTMLComment *comment = [[HTMLComment alloc] initWithData:@"data"]; [[document querySelector:@"#D1"] appendNode: comment]; [range setStartNode:comment startOffset:2]; XCTAssertThrows([range insertNode:end]); } - (void)testInsertNode_TextNodeStart_Begin { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:0]; HTMLNode *end = [document querySelector:@"#P1"].lastChild; [range setEndNode:end endOffset:5]; HTMLElement *div = [[HTMLElement alloc] initWithTagName:@"div"]; [div appendNodes:@[ [[HTMLText alloc] initWithData:@"TEXT"], [[HTMLElement alloc] initWithTagName:@"a"]]]; [range insertNode:div]; XCTAssertEqualObjects(BodyOf(document), DoubleQuote(@"
" @"

TEXT
This is a text

Hello

" @"

World

" @"

Another text

" @"
")); } - (void)testInsertNode_TextNodeStart_Middle { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:2]; HTMLNode *end = [document querySelector:@"#P1"].lastChild; [range setEndNode:end endOffset:5]; HTMLElement *div = [[HTMLElement alloc] initWithTagName:@"div"]; [div appendNodes:@[ [[HTMLText alloc] initWithData:@"TEXT"], [[HTMLElement alloc] initWithTagName:@"a"]]]; [range insertNode:div]; XCTAssertEqualObjects(BodyOf(document), DoubleQuote(@"
" @"

Th

TEXT
is is a text

Hello

" @"

World

" @"

Another text

" @"
")); } - (void)testInsertNode_NonTextNodeStart_Begin { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"]; [range setStartNode:start startOffset:0]; HTMLNode *end = [document querySelector:@"#P1"].lastChild; [range setEndNode:end endOffset:5]; HTMLElement *div = [[HTMLElement alloc] initWithTagName:@"div"]; [div appendNodes:@[ [[HTMLText alloc] initWithData:@"TEXT"], [[HTMLElement alloc] initWithTagName:@"a"]]]; [range insertNode:div]; XCTAssertEqualObjects(BodyOf(document), DoubleQuote(@"
" @"

TEXT
This is a text

Hello

" @"

World

" @"

Another text

" @"
")); } - (void)testInsertNode_NonTextNodeStart_Middle { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"]; [range setStartNode:start startOffset:2]; HTMLNode *end = [document querySelector:@"#P1"].lastChild; [range setEndNode:end endOffset:5]; HTMLElement *div = [[HTMLElement alloc] initWithTagName:@"div"]; [div appendNodes:@[ [[HTMLText alloc] initWithData:@"TEXT"], [[HTMLElement alloc] initWithTagName:@"a"]]]; [range insertNode:div]; XCTAssertEqualObjects(BodyOf(document), DoubleQuote(@"
" @"

This is a

TEXT
text

Hello

" @"

World

" @"

Another text

" @"
")); } - (void)testInsertNode_NonTextNodeStart_DifferentParents { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#D1"]; [range setStartNode:start startOffset:1]; HTMLNode *end = [document querySelector:@"#P3"].firstChild; [range setEndNode:end endOffset:4]; HTMLElement *div = [[HTMLElement alloc] initWithTagName:@"div"]; [div appendNodes:@[ [[HTMLText alloc] initWithData:@"TEXT"], [[HTMLElement alloc] initWithTagName:@"a"]]]; [range insertNode:div]; XCTAssertEqualObjects(BodyOf(document), DoubleQuote(@"
" @"

This is a text

TEXT

Hello

" @"

World

" @"

Another text

" @"
")); } - (void)testSurroundContents_InvalidNode { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:2]; HTMLNode *end = [document querySelector:@"#P1"].lastChild; [range setEndNode:end endOffset:5]; XCTAssertThrows([range surroundContents:[HTMLDocumentType new]]); XCTAssertThrows([range surroundContents:[HTMLDocument new]]); XCTAssertThrows([range surroundContents:[[HTMLDocumentFragment alloc] initWithDocument:document]]); } - (void)testSurroundContents_PartiallySelectedAncestors { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:2]; HTMLNode *end = [document querySelector:@"#P3"].lastChild; [range setEndNode:end endOffset:3]; HTMLElement *span = [[HTMLElement alloc] initWithTagName:@"span"]; XCTAssertThrows([range surroundContents:span]); start = [document querySelector:@"#D1"]; [range setStartNode:start startOffset:0]; end = [document querySelector:@"#D2"]; [range setEndNode:end endOffset:1]; XCTAssertThrows([range surroundContents:span]); } - (void)testSurroundContents_TextNodes { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:2]; HTMLNode *end = [document querySelector:@"#P1"].lastChild; [range setEndNode:end endOffset:3]; HTMLElement *span = [[HTMLElement alloc] initWithTagName:@"span"]; [range surroundContents:span]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

This is a text

Hello

" @"

World

" @"

Another text

" @"
")); } - (void)testSurroundContents_NonTextNodes { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"]; [range setStartNode:start startOffset:0]; HTMLNode *end = [document querySelector:@"#P1"]; [range setEndNode:end endOffset:2]; HTMLElement *span = [[HTMLElement alloc] initWithTagName:@"span"]; [range surroundContents:span]; XCTAssertEqualObjects(BodyOf(document), InnerHTML( @"
" @"

This is a text

Hello

" @"

World

" @"

Another text

" @"
")); } #pragma mark - Stringifier - (void)testRangeStringifier { HTMLDocument *document = self.editingDocument; HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; HTMLNode *start = [document querySelector:@"#P1"].firstChild; [range setStartNode:start startOffset:2]; HTMLNode *end = [document querySelector:@"#P1"].lastChild; [range setEndNode:end endOffset:3]; XCTAssertEqualObjects([range textContent], @"is is a te"); start = [document querySelector:@"#P1"]; [range setStartNode:start startOffset:0]; end = [document querySelector:@"#P1"]; [range setEndNode:end endOffset:2]; XCTAssertEqualObjects([range textContent], @"This is a"); start = [document querySelector:@"#D1"]; [range setStartNode:start startOffset:0]; end = [document querySelector:@"#D1"]; [range setEndNode:end endOffset:1]; XCTAssertEqualObjects([range textContent], @"This is a text"); start = [document querySelector:@"#D1"]; [range setStartNode:start startOffset:0]; end = [document querySelector:@"#D1"]; [range setEndNode:end endOffset:2]; XCTAssertEqualObjects([range textContent], @"This is a textHello"); start = [document querySelector:@"#D1"]; [range setStartNode:start startOffset:0]; end = [document querySelector:@"#D2"]; [range setEndNode:end endOffset:0]; XCTAssertEqualObjects([range textContent], @"This is a textHelloWorld"); start = [document querySelector:@"#D1"]; [range setStartNode:start startOffset:0]; end = [document querySelector:@"#D2"]; [range setEndNode:end endOffset:1]; XCTAssertEqualObjects([range textContent], @"This is a textHelloWorldAnother text"); } #pragma mark - Bug Fixes - (void)testBugFix_Issue_5 { HTMLDocument *document = [HTMLDocument documentWithString:@"
  • 1
  • 2"]; NSHashTable *ranges = [HTMLKitTestUtil ivarForInstacne:document name:@"_ranges"]; XCTAssertTrue([ranges isKindOfClass:[NSHashTable class]]); // range should be autoreleased, deallocated and detached after autoreleasepool @autoreleasepool { HTMLRange *range = [[HTMLRange alloc] initWithDocument:document]; [range cloneContents]; XCTAssertEqual(1, ranges.count); } XCTAssertEqual(0, ranges.count); } @end