// // HTMLKitMutationAlgorithmsTests.m // HTMLKit // // Created by Iska on 27/04/15. // Copyright (c) 2015 BrainCookie. All rights reserved. // #import #import "HTMLDOM.h" #import "NSString+HTMLKit.h" extern uint64_t dispatch_benchmark(size_t count, void (^block)(void)); @interface HTMLKitMutationAlgorithmsTests : XCTestCase @end @implementation HTMLKitMutationAlgorithmsTests - (void)testValidParentNodeWhenAppending { HTMLElement *element = [[HTMLElement alloc] initWithTagName:@"div"]; id parent = [HTMLDocument new]; XCTAssertNoThrow([parent appendNode:element]); parent = [HTMLDocumentFragment new]; XCTAssertNoThrow([parent appendNode:element]); parent = [HTMLElement new]; XCTAssertNoThrow([parent appendNode:element]); parent = [HTMLTemplate new]; XCTAssertNoThrow([parent appendNode:element]); parent = [HTMLDocumentType new]; XCTAssertThrows([parent appendNode:element]); parent = [HTMLComment new]; XCTAssertThrows([parent appendNode:element]); parent = [HTMLText new]; XCTAssertThrows([parent appendNode:element]); } - (void)testValidParentNodeWhenInserting { HTMLElement *element = [[HTMLElement alloc] initWithTagName:@"div"]; id parent = [HTMLDocument new]; XCTAssertNoThrow([parent insertNode:element beforeChildNode:nil]); parent = [HTMLDocumentFragment new]; XCTAssertNoThrow([parent insertNode:element beforeChildNode:nil]); parent = [HTMLElement new]; XCTAssertNoThrow([parent insertNode:element beforeChildNode:nil]); parent = [HTMLTemplate new]; XCTAssertNoThrow([parent insertNode:element beforeChildNode:nil]); parent = [HTMLDocumentType new]; XCTAssertThrows([parent insertNode:element beforeChildNode:nil]); parent = [HTMLComment new]; XCTAssertThrows([parent insertNode:element beforeChildNode:nil]); parent = [HTMLText new]; XCTAssertThrows([parent insertNode:element beforeChildNode:nil]); } - (void)testValidChildNodeWhenInserting { HTMLElement *div = [[HTMLElement alloc] initWithTagName:@"div"]; HTMLElement *p = [[HTMLElement alloc] initWithTagName:@"p"]; [div appendNode:p]; HTMLElement *table = [[HTMLElement alloc] initWithTagName:@"table"]; XCTAssertNoThrow([div insertNode:table beforeChildNode:p]); [div removeChildNode:p]; HTMLElement *section = [[HTMLElement alloc] initWithTagName:@"section"]; XCTAssertThrows([div insertNode:section beforeChildNode:p]); } - (void)testValidChildNodeWhenReplacing { HTMLElement *div = [[HTMLElement alloc] initWithTagName:@"div"]; HTMLElement *p = [[HTMLElement alloc] initWithTagName:@"p"]; [div appendNode:p]; HTMLElement *table = [[HTMLElement alloc] initWithTagName:@"table"]; XCTAssertNoThrow([div replaceChildNode:p withNode:table]); XCTAssertThrows([div replaceChildNode:p withNode:[HTMLComment new]]); } - (void)testValidChildNodeWhenRemoving { HTMLElement *div = [[HTMLElement alloc] initWithTagName:@"div"]; HTMLElement *p = [[HTMLElement alloc] initWithTagName:@"p"]; [div appendNode:p]; XCTAssertNoThrow([div removeChildNode:p]); XCTAssertThrows([div removeChildNode:p]); } - (void)testValidInsertedNode { HTMLDocument *document = [HTMLDocument new]; XCTAssertNoThrow([document appendNode:[HTMLDocumentFragment new]]); XCTAssertNoThrow([document appendNode:[HTMLDocumentType new]]); XCTAssertNoThrow([document appendNode:[HTMLElement new]]); HTMLElement *element = [HTMLElement new]; XCTAssertNoThrow([element appendNode:[HTMLTemplate new]]); XCTAssertNoThrow([element appendNode:[HTMLComment new]]); XCTAssertNoThrow([element appendNode:[HTMLText new]]); } - (void)testValidParentForDoctype { HTMLDocumentType *doctype = [HTMLDocumentType new]; XCTAssertNoThrow([[HTMLDocument new] appendNode:doctype]); XCTAssertThrows([[HTMLDocumentFragment new] appendNode:doctype]); XCTAssertThrows([[HTMLDocumentType new] appendNode:doctype]); XCTAssertThrows([[HTMLElement new] appendNode:doctype]); XCTAssertThrows([[HTMLTemplate new] appendNode:doctype]); XCTAssertThrows([[HTMLComment new] appendNode:doctype]); XCTAssertThrows([[HTMLText new] appendNode:doctype]); } - (void)testValidParentForText { HTMLText *text = [HTMLText new]; XCTAssertThrows([[HTMLDocument new] appendNode:text]); XCTAssertThrows([[HTMLDocumentType new] appendNode:text]); XCTAssertThrows([[HTMLComment new] appendNode:text]); XCTAssertThrows([[HTMLText new] appendNode:text]); XCTAssertNoThrow([[HTMLDocumentFragment new] appendNode:text]); XCTAssertNoThrow([[HTMLElement new] appendNode:text]); XCTAssertNoThrow([[HTMLTemplate new] appendNode:text]); } - (void)testValidDocumentFragmentInsertionIntoDocument { HTMLDocument *document = [HTMLDocument new]; HTMLDocumentFragment *fragment = [[HTMLDocumentFragment alloc] initWithDocument:document]; void (^ reset)() = ^ { [fragment removeAllChildNodes]; [document removeAllChildNodes]; }; /** * Fragment has a Text node child */ [fragment appendNode:[HTMLText new]]; XCTAssertThrows([document appendNode:fragment]); /** * Fragment has more than one Element child */ reset(); [fragment appendNode:[HTMLElement new]]; [fragment appendNode:[HTMLElement new]]; XCTAssertThrows([document appendNode:fragment]); /** * Fragment has one node child * Document has an Element child */ reset(); [fragment appendNode:[HTMLElement new]]; [document appendNode:[HTMLElement new]]; XCTAssertThrows([document appendNode:fragment]); /** * Fragment has one node child * "before child" is a Doctype */ reset(); HTMLDocumentType *doctype = [HTMLDocumentType new]; [fragment appendNode:[HTMLElement new]]; [document appendNode:doctype]; XCTAssertThrows([document insertNode:fragment beforeChildNode:doctype]); /** * Fragment has one node child * "before child" is following a Doctype */ reset(); HTMLComment *doctypePreviousSibling = [HTMLComment new]; [fragment appendNode:[HTMLElement new]]; [document appendNode:doctypePreviousSibling]; [document appendNode:doctype]; XCTAssertThrows([document insertNode:fragment beforeChildNode:doctypePreviousSibling]); } - (void)testValidElementInsertionIntoDocument { HTMLDocument *document = [HTMLDocument new]; HTMLElement *element = [HTMLElement new]; void (^ reset)() = ^ { [element removeAllChildNodes]; [document removeAllChildNodes]; }; /** * Document has an Element child */ [document appendNode:[HTMLElement new]]; XCTAssertThrows([document appendNode:element]); /** * "before child" is a Doctype */ reset(); HTMLDocumentType *doctype = [HTMLDocumentType new]; [document appendNode:doctype]; XCTAssertThrows([document insertNode:element beforeChildNode:doctype]); /** * Doctype is following the "before child" */ reset(); HTMLComment *doctypePreviousSibling = [HTMLComment new]; [document appendNode:doctypePreviousSibling]; [document appendNode:doctype]; XCTAssertThrows([document insertNode:element beforeChildNode:doctypePreviousSibling]); } - (void)testValidDoctypeInsertionIntoDocument { HTMLDocument *document = [HTMLDocument new]; HTMLDocumentType *doctype = [HTMLDocumentType new]; void (^ reset)() = ^ { [document removeAllChildNodes]; }; /** * Document has a Doctype child */ [document appendNode:[HTMLDocumentType new]]; XCTAssertThrows([document appendNode:doctype]); /** * An Element is preceding the "before child" */ reset(); HTMLComment *secondChild = [HTMLComment new]; [document appendNode:[HTMLElement new]]; [document appendNode:secondChild]; XCTAssertThrows([document insertNode:doctype beforeChildNode:secondChild]); /** * Document has an Element child */ reset(); [document appendNode:[HTMLElement new]]; XCTAssertThrows([document appendNode:doctype]); } - (void)testValidDocumentFragmentReplacementIntoDocument { HTMLDocument *document = [HTMLDocument new]; HTMLComment *child = [HTMLComment new]; HTMLDocumentFragment *replacement = [[HTMLDocumentFragment alloc] initWithDocument:document]; void (^ reset)() = ^ { [replacement removeAllChildNodes]; [document removeAllChildNodes]; [document appendNode:child]; }; /** * Replacement Fragment has a Text node child */ [replacement appendNode:[HTMLText new]]; XCTAssertThrows([document replaceChildNode:child withNode:replacement]); /** * Replacement Fragment has more than one Element child */ reset(); [replacement appendNode:[HTMLElement new]]; [replacement appendNode:[HTMLElement new]]; XCTAssertThrows([document replaceChildNode:child withNode:replacement]); /** * Replacement Fragment has one Element child * Document has an Element child that is not the Replacement */ reset(); [replacement appendNode:[HTMLElement new]]; [document appendNode:[HTMLElement new]]; XCTAssertThrows([document replaceChildNode:child withNode:replacement]); /** * Replacement Fragment has one Element child * Doctype is following the child node */ reset(); HTMLDocumentType *doctype = [HTMLDocumentType new]; [replacement appendNode:[HTMLElement new]]; [document appendNode:doctype]; XCTAssertThrows([document replaceChildNode:child withNode:replacement]); } - (void)testValidElementReplacementIntoDocument { HTMLDocument *document = [HTMLDocument new]; HTMLComment *child = [HTMLComment new]; HTMLElement *replacement = [HTMLElement new]; void (^ reset)() = ^ { [replacement removeAllChildNodes]; [document removeAllChildNodes]; [document appendNode:child]; }; /** * Docment has an Element child that is not replacement */ [document appendNode:[HTMLElement new]]; XCTAssertThrows([document replaceChildNode:child withNode:replacement]); /** * Doctype is following the child node */ reset(); HTMLDocumentType *doctype = [HTMLDocumentType new]; [document appendNode:doctype]; XCTAssertThrows([document replaceChildNode:child withNode:replacement]); } - (void)testValidDoctypeReplacementIntoDocument { HTMLDocument *document = [HTMLDocument new]; HTMLComment *child = [HTMLComment new]; HTMLDocumentType *replacement = [HTMLDocumentType new]; void (^ reset)() = ^ { [replacement removeAllChildNodes]; [document removeAllChildNodes]; [document appendNode:child]; }; /** * Docment has an Doctype child that is not replacement */ [document appendNode:[HTMLDocumentType new]]; XCTAssertThrows([document replaceChildNode:child withNode:replacement]); /** * An Element is preceding the child node */ reset(); [document insertNode:[HTMLElement new] beforeChildNode:child]; XCTAssertThrows([document replaceChildNode:child withNode:replacement]); } @end