//
//  XTOutputTextParserTests.m
//  TadsTerp
//
//  Created by Rune Berg on 09/04/14.
//  Copyright (c) 2014 Rune Berg. All rights reserved.
//

#import <XCTest/XCTest.h>
#import "XTOutputTextParserHtml.h"
#import "XTHtmlTag.h"
#import "XTHtmlTagA.h"
#import "XTHtmlTagBr.h"
#import "XTHtmlTagTab.h"
#import "XTHtmlTagTitle.h"
#import "XTHtmlTagQ.h"
#import "XTHtmlTagB.h"
#import "XTHtmlTagQuestionMarkT2.h"
#import "XTHtmlTagCenter.h"
#import "XTHtmlWhitespace.h"
#import "XTHtmlQuotedSpace.h"
#import "XTHtmlNonbreakingSpace.h"
#import "XTHtmlTagNoop.h"
#import "XTHtmlTagP.h"
#import "XTHtmlTagI.h"
#import "XTHtmlTagBq.h"
#import "XTHtmlTagFont.h"
#import "XTHtmlTagImg.h"
#import "XTHtmlTagPseudoTest.h"


@interface XTOutputTextParserHtmlTests : XCTestCase

@property XTOutputTextParserHtml *parser;

@end


#define ASSERT_PARSER_STATE(expectedState) \
	XCTAssertEqual(expectedState, self.parser.state);


@implementation XTOutputTextParserHtmlTests

- (void)setUp
{
    [super setUp];
	self.parser = [XTOutputTextParserHtml new];
}

- (void)tearDown
{
    [super tearDown];
}

- (void)testEmptyInput_1
{
	NSArray *elements = [self.parser parse:@""];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
}

- (void)testEmptyInput_2
{
	NSArray *elements = [self.parser parse:@""];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);

	elements = [self.parser parse:@""];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);

	elements = [self.parser parse:@""];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);

	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
}

- (void)testOnlyRegularText_1
{
	NSArray *elements = [self.parser parse:@"a"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	[self assertRegularTextIn:elements[0] withValue:@"a"];
	
	elements = [self.parser parse:@"a>"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	[self assertRegularTextIn:elements[0] withValue:@"a>"];
	
	elements = [self.parser parse:@"abc"];
	XCTAssertEqual(0, elements.count);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"abc"];
}

- (void)testOnlyRegularText_2
{
	NSArray *elements = [self.parser parse:@"a"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	elements = [self.parser parse:@"b"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	elements = [self.parser parse:@"cd"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	[self assertRegularTextIn:elements[0] withValue:@"abcd"];
}

- (void)testOnlySingleWhitespaceChar
{
	NSArray *elements = [self.parser parse:@" "];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	[self assertWhitespaceIn:elements[0] withText:@" "];

	elements = [self.parser parse:@"\n"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	[self assertWhitespaceIn:elements[0] withText:@"\n"];
	
	elements = [self.parser parse:@"\t"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	[self assertWhitespaceIn:elements[0] withText:@"\t"];
}

- (void)testCollapsingWhitespaceChars_1
{
	NSArray *elements = [self.parser parse:@"  "];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	[self assertWhitespaceIn:elements[0] withText:@"  "];

	elements = [self.parser parse:@" "];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	[self assertWhitespaceIn:elements[0] withText:@" "];
	
	elements = [self.parser parse:@"    "];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	[self assertWhitespaceIn:elements[0] withText:@"    "];

	elements = [self.parser parse:@" \t"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	[self assertWhitespaceIn:elements[0] withText:@" \t"];
	
	elements = [self.parser parse:@"\t "];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	[self assertWhitespaceIn:elements[0] withText:@"\t "];
	
	elements = [self.parser parse:@" \n"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	[self assertWhitespaceIn:elements[0] withText:@" \n"];
	
	elements = [self.parser parse:@"\n \t"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	[self assertWhitespaceIn:elements[0] withText:@"\n \t"];
	
	elements = [self.parser parse:@"\n\n"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	[self assertWhitespaceIn:elements[0] withText:@"\n\n"];
	
	elements = [self.parser parse:@"\t\t"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	[self assertWhitespaceIn:elements[0] withText:@"\t\t"];
	
	elements = [self.parser parse:@" \n\t\n  \t "];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	[self assertWhitespaceIn:elements[0] withText:@" \n\t\n  \t "];
}

- (void)testCollapsingWhitespaceChars_2
{
	NSArray *elements = [self.parser parse:@" "];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser parse:@" "];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser parse:@"\t"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser parse:@"\n"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	[self assertWhitespaceIn:elements[0] withText:@"  \t\n"];
}

- (void)testMixOfTextAndWhitespace
{
	NSArray *elements = [self.parser parse:@"a "];
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"a"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertWhitespaceIn:elements[0] withText:@" "];
	
	elements = [self.parser parse:@" z"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(1, elements.count);
	[self assertWhitespaceIn:elements[0] withText:@" "];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"z"];
	
	elements = [self.parser parse:@"zz b"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"zz"];
	[self assertWhitespaceIn:elements[1] withText:@" "];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"b"];
	
	elements = [self.parser parse:@" cv  xy"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(3, elements.count);
	[self assertWhitespaceIn:elements[0] withText:@" "];
	[self assertRegularTextIn:elements[1] withValue:@"cv"];
	[self assertWhitespaceIn:elements[2] withText:@"  "];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"xy"];
	
	elements = [self.parser parse:@"a bc  def  \nGG\th"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(8, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"a"];
	[self assertWhitespaceIn:elements[1] withText:@" "];
	[self assertRegularTextIn:elements[2] withValue:@"bc"];
	[self assertWhitespaceIn:elements[3] withText:@"  "];
	[self assertRegularTextIn:elements[4] withValue:@"def"];
	[self assertWhitespaceIn:elements[5] withText:@"  \n"];
	[self assertRegularTextIn:elements[6] withValue:@"GG"];
	[self assertWhitespaceIn:elements[7] withText:@"\t"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"h"];
}

- (void)testXTHtmlNonbreakingSpace
{
	NSArray *elements;
	
	elements = [self.parser parse:@"&#160;"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertNonbreakingSpaceIn:elements[0]];
	
	elements = [self.parser parse:@"&#160;&nbsp;&#xA0;"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(3, elements.count);
	[self assertNonbreakingSpaceIn:elements[0]];
	[self assertNonbreakingSpaceIn:elements[1]];
	[self assertNonbreakingSpaceIn:elements[2]];
	
	elements = [self.parser parse:@"a&#160;b"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(3, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"a"];
	[self assertNonbreakingSpaceIn:elements[1]];
	[self assertRegularTextIn:elements[2] withValue:@"b"];
}

- (void)testQuotedSpace
{
	NSArray *elements;
	
	elements = [self.parser parse:@"&#21;"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertQuotedSpaceIn:elements[0]];
	
	elements = [self.parser parse:@"&#21;&#21;&#21;"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(3, elements.count);
	[self assertQuotedSpaceIn:elements[0]];
	[self assertQuotedSpaceIn:elements[1]];
	[self assertQuotedSpaceIn:elements[2]];
	
	elements = [self.parser parse:@"a&#21;"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"a"];
	[self assertQuotedSpaceIn:elements[1]];
	
	elements = [self.parser parse:@"&#21;a"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(2, elements.count);
	[self assertQuotedSpaceIn:elements[0]];
	[self assertRegularTextIn:elements[1] withValue:@"a"];
	
	elements = [self.parser parse:@"ab&#21;c"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(3, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"ab"];
	[self assertQuotedSpaceIn:elements[1]];
	[self assertRegularTextIn:elements[2] withValue:@"c"];
	
	elements = [self.parser parse:@"ab&#21;cd&#21;&#21;ef&#21;"];
	XCTAssertEqual(0, elements.count);
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(7, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"ab"];
	[self assertQuotedSpaceIn:elements[1]];
	[self assertRegularTextIn:elements[2] withValue:@"cd"];
	[self assertQuotedSpaceIn:elements[3]];
	[self assertQuotedSpaceIn:elements[4]];
	[self assertRegularTextIn:elements[5] withValue:@"ef"];
	[self assertQuotedSpaceIn:elements[6]];
	
	elements = [self.parser parse:@"&#21; "];
	XCTAssertEqual(1, elements.count);
	[self assertQuotedSpaceIn:elements[0]];
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertWhitespaceIn:elements[0] withText:@" "];
	
	elements = [self.parser parse:@" &#21;"];
	XCTAssertEqual(1, elements.count);
	[self assertWhitespaceIn:elements[0] withText:@" "];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertQuotedSpaceIn:elements[0]];
	
	elements = [self.parser parse:@"  &#21; "];
	XCTAssertEqual(2, elements.count);
	[self assertWhitespaceIn:elements[0] withText:@"  "];
	[self assertQuotedSpaceIn:elements[1]];
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	[self assertWhitespaceIn:elements[0] withText:@" "];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	
	elements = [self.parser parse:@" a  &#21;&#21; &#21;b &#21; "];
	XCTAssertEqual(10, elements.count);
	[self assertWhitespaceIn:elements[0] withText:@" "];
	[self assertRegularTextIn:elements[1] withValue:@"a"];
	[self assertWhitespaceIn:elements[2] withText:@"  "];
	[self assertQuotedSpaceIn:elements[3]];
	[self assertQuotedSpaceIn:elements[4]];
	[self assertWhitespaceIn:elements[5] withText:@" "];
	[self assertQuotedSpaceIn:elements[6]];
	[self assertRegularTextIn:elements[7] withValue:@"b"];
	[self assertWhitespaceIn:elements[8] withText:@" "];
	[self assertQuotedSpaceIn:elements[9]];
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	[self assertWhitespaceIn:elements[0] withText:@" "];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
}

- (void)testOnlyStandaloneTag
{
	NSArray *elements = [self.parser parse:@"<br>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	XTHtmlTagTitle *tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(0, tag.attributes.count);
	XCTAssertFalse(tag.closing);
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);

	elements = [self.parser parse:@"<BR>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(0, tag.attributes.count);
	XCTAssertFalse(tag.closing);
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"<bR>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(0, tag.attributes.count);
	XCTAssertFalse(tag.closing);
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"<bR >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(0, tag.attributes.count);
	XCTAssertFalse(tag.closing);
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"<bR  >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(0, tag.attributes.count);
	XCTAssertFalse(tag.closing);
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"</br>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(0, tag.attributes.count);
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"</br >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(0, tag.attributes.count);
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"<br/>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(0, tag.attributes.count);
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"<br />"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(0, tag.attributes.count);
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"<br/ >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(0, tag.attributes.count);
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"<br / >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(0, tag.attributes.count);
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
}

- (void)testStandaloneTagMixedWithRegularText
{
	NSArray *elements = [self.parser parse:@"abc<br>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"abc"];
	XTHtmlTagTitle *tag = elements[1];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(0, tag.attributes.count);
	XCTAssertFalse(tag.closing);
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(0, elements.count);

	elements = [self.parser parse:@"<br>a"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(0, tag.attributes.count);
	XCTAssertFalse(tag.closing);
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"a"];
}

- (void)testOnlyStandaloneTagWithSingleAttribute
{
	NSArray *elements = [self.parser parse:@"<br height=2>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	XTHtmlTagBr *tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqualObjects(@"2", [tag attributeAsString:@"height"]);
	XCTAssertEqual(2, [tag attributeAsUInt:@"height"]);
	XCTAssertFalse(tag.closing);

	elements = [self.parser parse:@"<br HEIGHT=2>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqualObjects(@"2", [tag attributeAsString:@"height"]);
	XCTAssertEqual(2, [tag attributeAsUInt:@"height"]);
	XCTAssertFalse(tag.closing);
	
	elements = [self.parser parse:@"<br HEIghT=2>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqualObjects(@"2", [tag attributeAsString:@"HEIGHT"]);
	XCTAssertEqual(2, [tag attributeAsUInt:@"hEIght"]);
	XCTAssertFalse(tag.closing);

	elements = [self.parser parse:@"<BR HEIGHT=0>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqualObjects(@"0", [tag attributeAsString:@"HEIGHT"]);
	XCTAssertEqual(0, [tag attributeAsUInt:@"HEIGHT"]);
	XCTAssertFalse(tag.closing);

	elements = [self.parser parse:@"<BR HEIGHT=>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"HEIGHT"]);
	XCTAssertEqual(0, [tag attributeAsUInt:@"HEIGHT"]);
	XCTAssertFalse(tag.closing);
	
	elements = [self.parser parse:@"<BR HEIGHT=/>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"HEIGHT"]);
	XCTAssertEqual(0, [tag attributeAsUInt:@"HEIGHT"]);
	XCTAssertFalse(tag.closing);
	
	elements = [self.parser parse:@"<BR HEIGHT= />"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"HEIGHT"]);
	XCTAssertEqual(0, [tag attributeAsUInt:@"HEIGHT"]);
	XCTAssertFalse(tag.closing);
	
	elements = [self.parser parse:@"<BR HEIGHT=/ >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"HEIGHT"]);
	XCTAssertEqual(0, [tag attributeAsUInt:@"HEIGHT"]);
	XCTAssertFalse(tag.closing);
	
	elements = [self.parser parse:@"<BR HEIGHT=\\>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"HEIGHT"]);
	XCTAssertEqual(0, [tag attributeAsUInt:@"HEIGHT"]);
	XCTAssertFalse(tag.closing);
	
	elements = [self.parser parse:@"<BR HEIGHT=2 />"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqualObjects(@"2", [tag attributeAsString:@"HEIGHT"]);
	XCTAssertEqual(2, [tag attributeAsUInt:@"HEIGHT"]);
	XCTAssertFalse(tag.closing);
	
	elements = [self.parser parse:@"<BR HEIGHT=3 / >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqualObjects(@"3", [tag attributeAsString:@"HEIGHT"]);
	XCTAssertEqual(3, [tag attributeAsUInt:@"HEIGHT"]);
	XCTAssertFalse(tag.closing);
	
	elements = [self.parser parse:@"<BR HEIGHT=7 \\>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqualObjects(@"7", [tag attributeAsString:@"HEIGHT"]);
	XCTAssertEqual(7, [tag attributeAsUInt:@"HEIGHT"]);
	XCTAssertFalse(tag.closing);
	
	elements = [self.parser parse:@"<BR HEIGHT=0 />"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqualObjects(@"0", [tag attributeAsString:@"HEIGHT"]);
	XCTAssertEqual(0, [tag attributeAsUInt:@"HEIGHT"]);
	XCTAssertFalse(tag.closing);
	
	elements = [self.parser parse:@"<BR HEIGHT=0 \\>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqualObjects(@"0", [tag attributeAsString:@"HEIGHT"]);
	XCTAssertEqual(0, [tag attributeAsUInt:@"HEIGHT"]);
	XCTAssertFalse(tag.closing);
	
	elements = [self.parser parse:@"<BR HEIGHT=5 \\ >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqualObjects(@"5", [tag attributeAsString:@"HEIGHT"]);
	XCTAssertEqual(5, [tag attributeAsUInt:@"HEIGHT"]);
	XCTAssertFalse(tag.closing);
}

//-------- Test HTML attribute handling ----------

- (void)testEmptyAttributes
{
	NSArray *elements = [self.parser parse:@"<font size>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	XTHtmlTag *tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"size"]);

	elements = [self.parser parse:@"<font size/>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"size"]);
	
	elements = [self.parser parse:@"<font size />"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"size"]);
	
	elements = [self.parser parse:@"<font size/ >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"size"]);
	
	elements = [self.parser parse:@"<font size / >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"size"]);

	elements = [self.parser parse:@"<font size\\>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"size"]);
	
	elements = [self.parser parse:@"<font size \\>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"size"]);
	
	elements = [self.parser parse:@"<font size\\ >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"size"]);
	
	elements = [self.parser parse:@"<font size \\ >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"size"]);
	
	elements = [self.parser parse:@"<font size color=>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(2, tag.attributes.count);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"size"]);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"color"]);
	
	elements = [self.parser parse:@"<font size color= bgcolor= >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(3, tag.attributes.count);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"size"]);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"color"]);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"bgcolor"]);
	
	elements = [self.parser parse:@"<font size=2 size=3>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"3", [tag attributeAsString:@"size"]);
	
	elements = [self.parser parse:@"<font size=2 size=  >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"size"]);
	
	elements = [self.parser parse:@"<font size=2 color=>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(2, tag.attributes.count);
	XCTAssertEqualObjects(@"2", [tag attributeAsString:@"size"]);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"color"]);
	
	elements = [self.parser parse:@"<font size=2 color>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(2, tag.attributes.count);
	XCTAssertEqualObjects(@"2", [tag attributeAsString:@"size"]);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"color"]);
	
	elements = [self.parser parse:@"<font size=2 color >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(2, tag.attributes.count);
	XCTAssertEqualObjects(@"2", [tag attributeAsString:@"size"]);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"color"]);
	
	elements = [self.parser parse:@"<font size color=green >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(2, tag.attributes.count);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"size"]);
	XCTAssertEqualObjects(@"green", [tag attributeAsString:@"coLOR"]);
}

- (void)testUnquotedAttributes
{
	NSArray *elements = [self.parser parse:@"<font size=6>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	XTHtmlTag *tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"6", [tag attributeAsString:@"size"]);

	elements = [self.parser parse:@"<font size=+5 bgcolor=white color=green>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(3, tag.attributes.count);
	XCTAssertEqualObjects(@"+5", [tag attributeAsString:@"size"]);
	XCTAssertEqualObjects(@"white", [tag attributeAsString:@"bgcolor"]);
	XCTAssertEqualObjects(@"green", [tag attributeAsString:@"color"]);
}

- (void)testUnquotedAttributeValueWithForwardSlash
{
	self.parser.printBrokenHtmlMarkup = NO;
	
	NSArray *elements = [self.parser parse:@"<img src=../image.gif>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	XTHtmlTag *tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagImg class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"../image.gif", [tag attributeAsString:@"src"]);

	elements = [self.parser parse:@"<img src=..\\image.gif>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagImg class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"..\\image.gif", [tag attributeAsString:@"src"]);
	
	elements = [self.parser parse:@"<img src=../image.gif/>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagImg class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"../image.gif/", [tag attributeAsString:@"src"]);
}

- (void)testSingleQuotedAttribute
{
	NSArray *elements = [self.parser parse:@"<br height='2'>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	XTHtmlTagBr *tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"2", [tag attributeAsString:@"height"]);
	XCTAssertEqual(2, [tag attributeAsUInt:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];

	elements = [self.parser parse:@"<br HEIGHT=''>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];
	
	elements = [self.parser parse:@"<br HEIGHT=' '>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@" ", [tag attributeAsString:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];
	
	elements = [self.parser parse:@"<br HEIGHT=' 2 '>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@" 2 ", [tag attributeAsString:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];
	
	elements = [self.parser parse:@"<br HEIGHT='\"23\"'>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"\"23\"", [tag attributeAsString:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];
	
	elements = [self.parser parse:@"<br HEIGHT='\"'>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"\"", [tag attributeAsString:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];
	
	elements = [self.parser parse:@"<br HEIGHT='\"\"'>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"\"\"", [tag attributeAsString:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];
	
	elements = [self.parser parse:@"<br HEIGHT='\"\"' muups='98'>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(2, tag.attributes.count);
	XCTAssertEqualObjects(@"\"\"", [tag attributeAsString:@"height"]);
	XCTAssertEqualObjects(@"98", [tag attributeAsString:@"muups"]);
	XCTAssertFalse(tag.closing);
	
	//test "/" and "/>" inside single quotes:
	
	elements = [self.parser parse:@"<br HEIGHT='/'>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"/", [tag attributeAsString:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];
	
	elements = [self.parser parse:@"<br HEIGHT='>'>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@">", [tag attributeAsString:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];
	
	elements = [self.parser parse:@"<br HEIGHT='/>'>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"/>", [tag attributeAsString:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];
}

- (void)testDoubleQuotedAttribute
{
	NSArray *elements = [self.parser parse:@"<br height=\"2\">"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	XTHtmlTagBr *tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"2", [tag attributeAsString:@"height"]);
	XCTAssertEqual(2, [tag attributeAsUInt:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];

	elements = [self.parser parse:@"<br HEIGHT=\"\">"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"", [tag attributeAsString:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];

	elements = [self.parser parse:@"<br HEIGHT=\"  \">"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"  ", [tag attributeAsString:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];
	
	elements = [self.parser parse:@"<br HEIGHT=\" 2 \">"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@" 2 ", [tag attributeAsString:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];
	
	elements = [self.parser parse:@"<br HEIGHT=\"'23'\">"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"'23'", [tag attributeAsString:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];
	
	elements = [self.parser parse:@"<br HEIGHT=\"'\">"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"'", [tag attributeAsString:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];
	
	elements = [self.parser parse:@"<br HEIGHT=\"''\">"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"''", [tag attributeAsString:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];

	// test "/" and "/>" inside double quotes:
	
	elements = [self.parser parse:@"<br HEIGHT=\"/\">"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"/", [tag attributeAsString:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];
	
	elements = [self.parser parse:@"<br HEIGHT=\">\">"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@">", [tag attributeAsString:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];
	
	elements = [self.parser parse:@"<br HEIGHT=\"/>\">"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"/>", [tag attributeAsString:@"height"]);
	XCTAssertFalse(tag.closing);
	[self.parser resetForNextCommand];
}

- (void)testCharEntitiesInAttribute
{
	NSArray *elements = [self.parser parse:@"<font size=+&#51;>+3</font>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(3, elements.count);
	XTHtmlTag *tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"+3", [tag attributeAsString:@"size"]);
	XCTAssertFalse(tag.closing);
	[self assertRegularTextIn:elements[1] withValue:@"+3"];
	tag = elements[2];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertTrue(tag.closing);
	XCTAssertEqual(0, tag.attributes.count);
	[self.parser resetForNextCommand];

	elements = [self.parser parse:@"<font size='&#43;&#51;'>+3</font>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(3, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqualObjects(@"+3", [tag attributeAsString:@"size"]);
	XCTAssertFalse(tag.closing);
	[self assertRegularTextIn:elements[1] withValue:@"+3"];
	tag = elements[2];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertTrue(tag.closing);
	[self.parser resetForNextCommand];

	elements = [self.parser parse:@"<font size=\"+&#51;\">&#43;3</font>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(3, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqualObjects(@"+3", [tag attributeAsString:@"size"]);
	XCTAssertFalse(tag.closing);
	[self assertRegularTextIn:elements[1] withValue:@"+3"];
	tag = elements[2];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertTrue(tag.closing);
	[self.parser resetForNextCommand];

	elements = [self.parser parse:@"<font size='+&#51;' mii=\"&#51;&#51;\" zzk=&#51;>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class] closing:NO];
	XCTAssertEqualObjects(@"+3", [tag attributeAsString:@"size"]);
	XCTAssertEqualObjects(@"33", [tag attributeAsString:@"mii"]);
	XCTAssertEqualObjects(@"3", [tag attributeAsString:@"zzk"]);
	[self.parser resetForNextCommand];
}

//----------- Test ???? --------------

- (void)testWhitespaceAfterOpeningTag
{
	NSArray *elements = [self.parser parse:@"<br> ab c<b>de "];
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	XCTAssertEqual(7, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagBr class]];
	[self assertWhitespaceIn:elements[1] withText:@" "];
	[self assertRegularTextIn:elements[2] withValue:@"ab"];
	[self assertWhitespaceIn:elements[3] withText:@" "];
	[self assertRegularTextIn:elements[4] withValue:@"c"];
	[self assertHtmlTagIn:elements[5] withClass:[XTHtmlTagB class]];
	[self assertRegularTextIn:elements[6] withValue:@"de"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertWhitespaceIn:elements[0] withText:@" "];

	elements = [self.parser parse:@"<br height=2> ab c <br height=\"2\">  de "];
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	XCTAssertEqual(9, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagBr class]];
	[self assertWhitespaceIn:elements[1] withText:@" "];
	[self assertRegularTextIn:elements[2] withValue:@"ab"];
	[self assertWhitespaceIn:elements[3] withText:@" "];
	[self assertRegularTextIn:elements[4] withValue:@"c"];
	[self assertWhitespaceIn:elements[5] withText:@" "];
	[self assertHtmlTagIn:elements[6] withClass:[XTHtmlTagBr class]];
	[self assertWhitespaceIn:elements[7] withText:@"  "];
	[self assertRegularTextIn:elements[8] withValue:@"de"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertWhitespaceIn:elements[0] withText:@" "];
}

- (void)testWhitespaceAfterClosingTag
{
	NSArray *elements = [self.parser parse:@"<b> ab c</b> de "];
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	XCTAssertEqual(8, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagB class]];
	[self assertWhitespaceIn:elements[1] withText:@" "];
	[self assertRegularTextIn:elements[2] withValue:@"ab"];
	[self assertWhitespaceIn:elements[3] withText:@" "];
	[self assertRegularTextIn:elements[4] withValue:@"c"];
	[self assertHtmlTagIn:elements[5] withClass:[XTHtmlTagB class]];
	[self assertWhitespaceIn:elements[6] withText:@" "];
	[self assertRegularTextIn:elements[7] withValue:@"de"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertWhitespaceIn:elements[0] withText:@" "];

	elements = [self.parser parse:@"ab<br/>   cd"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(3, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"ab"];
	[self assertHtmlTagIn:elements[1] withClass:[XTHtmlTagBr class]];
	[self assertWhitespaceIn:elements[2] withText:@"   "];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"cd"];
}

- (void)testWhitespaceAfterClosingTagWhenUnknownTag
{
	self.parser.printBrokenHtmlMarkup = YES;
	NSArray *elements = [self.parser parse:@"Please type <uu href=Help>HELP</uu> for instructions"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(10, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"Please"];
	[self assertWhitespaceIn:elements[1] withText:@" "];
	[self assertRegularTextIn:elements[2] withValue:@"type"];
	[self assertWhitespaceIn:elements[3] withText:@" "];
	[self assertRegularTextIn:elements[4] withValue:@"<uu href=Help>"];
	[self assertRegularTextIn:elements[5] withValue:@"HELP"];
	[self assertRegularTextIn:elements[6] withValue:@"</uu>"];
	[self assertWhitespaceIn:elements[7] withText:@" "];
	[self assertRegularTextIn:elements[8] withValue:@"for"];
	[self assertWhitespaceIn:elements[9] withText:@" "];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"instructions"];
	[self.parser resetForNextCommand];

	self.parser.printBrokenHtmlMarkup = NO;
	elements = [self.parser parse:@"Please type <uu href=Help>HELP</uu> for instructions"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(8, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"Please"];
	[self assertWhitespaceIn:elements[1] withText:@" "];
	[self assertRegularTextIn:elements[2] withValue:@"type"];
	[self assertWhitespaceIn:elements[3] withText:@" "];
	[self assertRegularTextIn:elements[4] withValue:@"HELP"];
	[self assertWhitespaceIn:elements[5] withText:@" "];
	[self assertRegularTextIn:elements[6] withValue:@"for"];
	[self assertWhitespaceIn:elements[7] withText:@" "];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"instructions"];
}

- (void)testOpenTag
{
	NSArray *elements = [self.parser parse:@"<i>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagI class] closing:NO];
	
	elements = [self.parser parse:@"<bq>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagBq class] closing:NO];
	
	elements = [self.parser parse:@"<bq >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagBq class] closing:NO];
}

- (void)testCloseTag
{
	NSArray *elements = [self.parser parse:@"</bq>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagBq class] closing:YES];
	
	elements = [self.parser parse:@"</bq >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagBq class] closing:YES];
	
	elements = [self.parser parse:@"<\\bq>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagBq class] closing:YES];
	
	elements = [self.parser parse:@"<\\bq >"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagBq class] closing:YES];
}

//-------- Test broken HTML tag handling ----------

- (void)testBrokenHtmlTag_afterTagStart_print
{
	self.parser.printBrokenHtmlMarkup = YES;

	NSArray *elements = [self.parser parse:@"io< more asas<b>bold?"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"io"];
	[self assertRegularTextIn:elements[1] withValue:@"< more asas<b>"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"bold?"];
}

- (void)testBrokenHtmlTag_afterTagStart_suppress
{
	self.parser.printBrokenHtmlMarkup = NO;
	
	NSArray *elements = [self.parser parse:@"io< more asas<b>bold?"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"io"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"bold?"];
}

- (void)testIllegalCharInStateAfterStart_print
{
	self.parser.printBrokenHtmlMarkup = YES;

	NSArray *elements = [self.parser parse:@"<<x"];
	ASSERT_PARSER_STATE(XT_HTML_IN_MISFORMED_TAG);
	XCTAssertEqual(0, elements.count);
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_IN_MISFORMED_TAG);
	XCTAssertEqual(0, elements.count);
	elements = [self.parser parse:@"moo>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"<<xmoo>"];
}

- (void)testIllegalCharInStateAfterStart_suppress
{
	self.parser.printBrokenHtmlMarkup = NO;
	
	NSArray *elements = [self.parser parse:@"<<x"];
	ASSERT_PARSER_STATE(XT_HTML_IN_MISFORMED_TAG);
	XCTAssertEqual(0, elements.count);
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_IN_MISFORMED_TAG);
	XCTAssertEqual(0, elements.count);
	elements = [self.parser parse:@"moo>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(0, elements.count);
}

- (void)testBrokenHtmlTag_inTagName_print
{
	self.parser.printBrokenHtmlMarkup = YES;
	NSArray *elements = [self.parser parse:@"mm<h( s=2>rest"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"mm"];
	[self assertRegularTextIn:elements[1] withValue:@"<h( s=2>"];
	elements = [self.parser flush];
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"rest"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
}

- (void)testBrokenHtmlTag_inTagName_suppress
{
	self.parser.printBrokenHtmlMarkup = NO;
	NSArray *elements = [self.parser parse:@"mm<h( s=2>rest"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"mm"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"rest"];
	
}

- (void)testBrokenHtmlTag_afterTagName_print
{
	self.parser.printBrokenHtmlMarkup = YES;
	NSArray *elements = [self.parser parse:@"mm<h . huh>rest"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"mm"];
	[self assertRegularTextIn:elements[1] withValue:@"<h . huh>"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"rest"];
}

- (void)testBrokenHtmlTag_afterTagName_suppress
{
	self.parser.printBrokenHtmlMarkup = NO;
	NSArray *elements = [self.parser parse:@"mm<h . huh>rest"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"mm"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"rest"];
}

- (void)testBrokenHtmlTag_atClosingSlash_print
{
	self.parser.printBrokenHtmlMarkup = YES;
	NSArray *elements = [self.parser parse:@"m<br/.>K"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"m"];
	[self assertRegularTextIn:elements[1] withValue:@"<br/.>"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"K"];
}

- (void)testBrokenHtmlTag_atClosingSlash_suppress
{
	self.parser.printBrokenHtmlMarkup = NO;
	NSArray *elements = [self.parser parse:@"m<br/.>K"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"m"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"K"];
}

- (void)testBrokenHtmlTag_inAttributeName_print
{
	self.parser.printBrokenHtmlMarkup = YES;
	NSArray *elements = [self.parser parse:@"m<p w. mu>pp"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"m"];
	[self assertRegularTextIn:elements[1] withValue:@"<p w. mu>"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"pp"];
}

- (void)testBrokenHtmlTag_inAttributeName_suppress
{
	self.parser.printBrokenHtmlMarkup = NO;
	NSArray *elements = [self.parser parse:@"m<p w. mu>pp"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"m"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"pp"];
}

- (void)testBrokenHtmlTag_startingAttributeName_print
{
	self.parser.printBrokenHtmlMarkup = YES;
	NSArray *elements = [self.parser parse:@"m<p w== mu>pp"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"m"];
	[self assertRegularTextIn:elements[1] withValue:@"<p w== mu>"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"pp"];
}

- (void)testBrokenHtmlTag_startingAttributeName_suppress
{
	self.parser.printBrokenHtmlMarkup = NO;
	NSArray *elements = [self.parser parse:@"m<p w== mu>pp"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"m"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"pp"];
}

- (void)testBrokenHtmlTag_inUnquotedAttributeValue_print
{
	self.parser.printBrokenHtmlMarkup = YES;
	NSArray *elements = [self.parser parse:@"m<p w=x< mu>pp"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"m"];
	[self assertRegularTextIn:elements[1] withValue:@"<p w=x< mu>"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"pp"];
}

- (void)testBrokenHtmlTag_inUnquotedAttributeValue_suppress
{
	self.parser.printBrokenHtmlMarkup = NO;
	NSArray *elements = [self.parser parse:@"m>c<p w=x< mu>s"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"m>c"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"s"];
}

//-------- Test pseudo-tags --------------

- (void)testPseudoTagOpen
{
	NSArray *elements = [self.parser parse:@"<.pseudotest>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagPseudoTest class] closing:NO];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(0, elements.count);
}

- (void)testPseudoTagClose
{
	NSArray *elements = [self.parser parse:@"<./pseudotest>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagPseudoTest class] closing:YES];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(0, elements.count);
}

- (void)testPseudoTagClose2
{
	NSArray *elements = [self.parser parse:@"<.\\pseudotest>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagPseudoTest class] closing:YES];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(0, elements.count);
}

- (void)testBrokenPseudoTag_print
{
	self.parser.printBrokenHtmlMarkup = YES;
	NSArray *elements = [self.parser parse:@"ab<. pseudotest>cd"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"ab"];
	[self assertRegularTextIn:elements[1] withValue:@"<. pseudotest>"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"cd"];
}

- (void)testBrokenPseudoTag_suppress
{
	self.parser.printBrokenHtmlMarkup = NO;
	NSArray *elements = [self.parser parse:@"ab<. pseudotest>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"ab"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(0, elements.count);
}

- (void)testPseudoTagsIgnored_print
{
	self.parser.printBrokenHtmlMarkup = YES;
	NSArray *elements = [self.parser parse:@"1<.P0>2<.commandsep>3<.convend>4<.roomname>5<.roomdesc>6<.announceObj>7<.convstay>8<.topics>9" \
						                    "<.parser>10<.inputline>11<.commandbegin>12<.a>13<.statusroom>14<.statusscore>15<.commandint>16<.convnode>17" \
											"<.p>18<.notification>19<.roompara>20<.assume>21"
						 ];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(40, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"1"];
	[self assertRegularTextIn:elements[1] withValue:@"<.P0>"];
	[self assertRegularTextIn:elements[2] withValue:@"2"];
	[self assertRegularTextIn:elements[3] withValue:@"<.commandsep>"];
	[self assertRegularTextIn:elements[4] withValue:@"3"];
	[self assertRegularTextIn:elements[5] withValue:@"<.convend>"];
	[self assertRegularTextIn:elements[6] withValue:@"4"];
	[self assertRegularTextIn:elements[7] withValue:@"<.roomname>"];
	[self assertRegularTextIn:elements[8] withValue:@"5"];
	[self assertRegularTextIn:elements[9] withValue:@"<.roomdesc>"];
	[self assertRegularTextIn:elements[10] withValue:@"6"];
	[self assertRegularTextIn:elements[11] withValue:@"<.announceObj>"];
	[self assertRegularTextIn:elements[12] withValue:@"7"];
	[self assertRegularTextIn:elements[13] withValue:@"<.convstay>"];
	[self assertRegularTextIn:elements[14] withValue:@"8"];
	[self assertRegularTextIn:elements[15] withValue:@"<.topics>"];
	[self assertRegularTextIn:elements[16] withValue:@"9"];
	[self assertRegularTextIn:elements[17] withValue:@"<.parser>"];
	[self assertRegularTextIn:elements[18] withValue:@"10"];
	[self assertRegularTextIn:elements[19] withValue:@"<.inputline>"];
	[self assertRegularTextIn:elements[20] withValue:@"11"];
	[self assertRegularTextIn:elements[21] withValue:@"<.commandbegin>"];
	[self assertRegularTextIn:elements[22] withValue:@"12"];
	[self assertRegularTextIn:elements[23] withValue:@"<.a>"];
	[self assertRegularTextIn:elements[24] withValue:@"13"];
	[self assertRegularTextIn:elements[25] withValue:@"<.statusroom>"];
	[self assertRegularTextIn:elements[26] withValue:@"14"];
	[self assertRegularTextIn:elements[27] withValue:@"<.statusscore>"];
	[self assertRegularTextIn:elements[28] withValue:@"15"];
	[self assertRegularTextIn:elements[29] withValue:@"<.commandint>"];
	[self assertRegularTextIn:elements[30] withValue:@"16"];
	[self assertRegularTextIn:elements[31] withValue:@"<.convnode>"];
	[self assertRegularTextIn:elements[32] withValue:@"17"];
	[self assertRegularTextIn:elements[33] withValue:@"<.p>"];
	[self assertRegularTextIn:elements[34] withValue:@"18"];
	[self assertRegularTextIn:elements[35] withValue:@"<.notification>"];
	[self assertRegularTextIn:elements[36] withValue:@"19"];
	[self assertRegularTextIn:elements[37] withValue:@"<.roompara>"];
	[self assertRegularTextIn:elements[38] withValue:@"20"];
	[self assertRegularTextIn:elements[39] withValue:@"<.assume>"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"21"];
}

- (void)testPseudoTagsIgnored_suppress
{
	self.parser.printBrokenHtmlMarkup = NO;
	NSArray *elements = [self.parser parse:@"1<./P0>2<./commandsep>3<./convend>4<./roomname>5<./roomdesc>6<./announceObj>7<./convstay>8<./topics>9" \
						 "<./parser>10<./inputline>11<./commandbegin>12<./a>13<./statusroom>14<./statusscore>15<./commandint>16<./convnode>17" \
						 "<./p>18<./notification>19<./roompara>20<./assume>21"
						 ];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(20, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"1"];
	[self assertRegularTextIn:elements[1] withValue:@"2"];
	[self assertRegularTextIn:elements[2] withValue:@"3"];
	[self assertRegularTextIn:elements[3] withValue:@"4"];
	[self assertRegularTextIn:elements[4] withValue:@"5"];
	[self assertRegularTextIn:elements[5] withValue:@"6"];
	[self assertRegularTextIn:elements[6] withValue:@"7"];
	[self assertRegularTextIn:elements[7] withValue:@"8"];
	[self assertRegularTextIn:elements[8] withValue:@"9"];
	[self assertRegularTextIn:elements[9] withValue:@"10"];
	[self assertRegularTextIn:elements[10] withValue:@"11"];
	[self assertRegularTextIn:elements[11] withValue:@"12"];
	[self assertRegularTextIn:elements[12] withValue:@"13"];
	[self assertRegularTextIn:elements[13] withValue:@"14"];
	[self assertRegularTextIn:elements[14] withValue:@"15"];
	[self assertRegularTextIn:elements[15] withValue:@"16"];
	[self assertRegularTextIn:elements[16] withValue:@"17"];
	[self assertRegularTextIn:elements[17] withValue:@"18"];
	[self assertRegularTextIn:elements[18] withValue:@"19"];
	[self assertRegularTextIn:elements[19] withValue:@"20"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"21"];
}

//-------- Test fixes for specific bugs etc. ----------

- (void)testUnexpectedCharAfterTagStartDarkAngel
{
	NSArray *elements = [self.parser parse:@"<a href=\"http\">How<\\a>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(3, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagA class]];
	[self assertRegularTextIn:elements[1] withValue:@"How"];
	[self assertHtmlTagIn:elements[2] withClass:[XTHtmlTagA class]];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(0, elements.count);
}

- (void)testGoldenSkullParchmentIndentBug
{
	NSArray *elements = [self.parser parse:@"cave<BR> Se gyrent"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(5, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"cave"];
	[self assertHtmlTagIn:elements[1] withClass:[XTHtmlTagBr class]];
	[self assertWhitespaceIn:elements[2] withText:@" "];
	[self assertRegularTextIn:elements[3] withValue:@"Se"];
	[self assertWhitespaceIn:elements[4] withText:@" "];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"gyrent"];
}

- (void)testTads2GameIntro
{
	NSArray *elements = [self.parser parse:@"reg1"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(0, elements.count);
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"reg1"];

	elements = [self.parser parse:@"<?T2>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagQuestionMarkT2 class]];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(0, elements.count);

	elements = [self.parser parse:@"REG2"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(0, elements.count);
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"REG2"];
}

- (void)testAllHopeAbandonMissingNewlineBug
{
	NSArray *elements = [self.parser parse:@"[Press a key to continue...]<br>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(10, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"[Press"];
	[self assertWhitespaceIn:elements[1] withText:@" "];
	[self assertRegularTextIn:elements[2] withValue:@"a"];
	[self assertWhitespaceIn:elements[3] withText:@" "];
	[self assertRegularTextIn:elements[4] withValue:@"key"];
	[self assertWhitespaceIn:elements[5] withText:@" "];
	[self assertRegularTextIn:elements[6] withValue:@"to"];
	[self assertWhitespaceIn:elements[7] withText:@" "];
	[self assertRegularTextIn:elements[8] withValue:@"continue...]"];
	XTHtmlTag *tag = elements[9];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];

	elements = [self.parser parse:@"<BR HEIGHT=0>\n"];
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];

	elements = [self.parser parse:@"<BR>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(2, elements.count);
	[self assertWhitespaceIn:elements[0] withText:@"\n"];
	tag = elements[1];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];

	elements = [self.parser parse:@"<BR HEIGHT=0>\n"];
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];

	elements = [self.parser parse:@"<b>The Breakfast Queue</b><br>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(9, elements.count);
	[self assertWhitespaceIn:elements[0] withText:@"\n"];
	tag = elements[1];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagB class]];
	XCTAssertFalse(tag.closing);
	[self assertRegularTextIn:elements[2] withValue:@"The"];
	[self assertWhitespaceIn:elements[3] withText:@" "];
	[self assertRegularTextIn:elements[4] withValue:@"Breakfast"];
	[self assertWhitespaceIn:elements[5] withText:@" "];
	[self assertRegularTextIn:elements[6] withValue:@"Queue"];
	tag = elements[7];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagB class]];
	XCTAssertTrue(tag.closing);
	tag = elements[8];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
}

- (void)testTillDeathSpaceAfterTabBug
{
	NSArray *elements =
		[self.parser parse:@"<TAB MULTIPLE=4>ABOUT<TAB MULTIPLE=4><TAB MULTIPLE=4> - Show some background"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(11, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagTab class]];
	[self assertRegularTextIn:elements[1] withValue:@"ABOUT"];
	[self assertHtmlTagIn:elements[2] withClass:[XTHtmlTagTab class]];
	[self assertHtmlTagIn:elements[3] withClass:[XTHtmlTagTab class]];
	[self assertWhitespaceIn:elements[4] withText:@" "];
	[self assertRegularTextIn:elements[5] withValue:@"-"];
	[self assertWhitespaceIn:elements[6] withText:@" "];
	[self assertRegularTextIn:elements[7] withValue:@"Show"];
	[self assertWhitespaceIn:elements[8] withText:@" "];
	[self assertRegularTextIn:elements[9] withValue:@"some"];
	[self assertWhitespaceIn:elements[10] withText:@" "];
	
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"background"];
}

- (void)testBeetmongerInitLocExtraNewlineBug
{
	XTHtmlTag *tag;
	NSArray *elements;
	
	elements = [self.parser parse:@"<TAB MULTIPLE=4>Text"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagTab class]];

	elements = [self.parser parse:@" "];
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"Text"];

	elements = [self.parser parse:@"MoreText"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(1, elements.count);
	[self assertWhitespaceIn:elements[0] withText:@" "];

	elements = [self.parser parse:@"\n"];
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"MoreText"];

	elements = [self.parser parse:@"<BR HEIGHT=0>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(2, elements.count);
	[self assertWhitespaceIn:elements[0] withText:@"\n"];
	tag = elements[1];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	
	elements = [self.parser parse:@"<TAB MULTIPLE=4>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagTab class]];

	elements = [self.parser parse:@"\n"];
	ASSERT_PARSER_STATE(XT_HTML_IN_WHITESPACE);
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"<BR HEIGHT=0>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(2, elements.count);
	[self assertWhitespaceIn:elements[0] withText:@"\n"];
	tag = elements[1];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	
	elements = [self.parser parse:@"<BR HEIGHT=0>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	
	elements = [self.parser parse:@"<TAB MULTIPLE=4>EvenMoreText"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagTab class]];

	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"EvenMoreText"];
}

- (void)testDoubleQuotedFontFaceBug
{
	NSArray *elements = [self.parser parse:@"<FONT FACE=\"Courier\">"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	XTHtmlTagTitle *tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"Courier", [tag attributeAsString:@"FACE"]);
	XCTAssertEqualObjects(@"Courier", [tag attributeAsString:@"face"]);
	XCTAssertEqualObjects(@"Courier", [tag attributeAsString:@"FacE"]);

	elements = [self.parser parse:@"<Font Face='Courier'>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"Courier", [tag attributeAsString:@"FACE"]);
	XCTAssertEqualObjects(@"Courier", [tag attributeAsString:@"face"]);
	XCTAssertEqualObjects(@"Courier", [tag attributeAsString:@"Face"]);
	
	elements = [self.parser parse:@"<Font Face=Courier>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagFont class]];
	XCTAssertEqual(1, tag.attributes.count);
	XCTAssertEqualObjects(@"Courier", [tag attributeAsString:@"FACE"]);
	XCTAssertEqualObjects(@"Courier", [tag attributeAsString:@"face"]);
	XCTAssertEqualObjects(@"Courier", [tag attributeAsString:@"Face"]);
}


- (void)testGameTitle
{
	NSArray *elements = [self.parser parse:@"<title>The Game</title>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(5, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagTitle class] closing:NO];
	[self assertRegularTextIn:elements[1] withValue:@"The"];
	[self assertWhitespaceIn:elements[2] withText:@" "];
	[self assertRegularTextIn:elements[3] withValue:@"Game"];
	[self assertHtmlTagIn:elements[4] withClass:[XTHtmlTagTitle class] closing:YES];

	elements = [self.parser parse:@"<br>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagBr class] closing:NO];
	XCTAssertEqual(0, ((XTHtmlTag*)elements[0]).attributes.count);
}

- (void)testTwoStandaloneTagsInSameString
{
	NSArray *elements = [self.parser parse:@"<br height=2><br>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(2, elements.count);
	XTHtmlTagBr *tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(2, [tag attributeAsUInt:@"height"]);
	XCTAssertFalse(tag.closing);
	tag = elements[1];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertEqual(0, tag.attributes.count);
	XCTAssertFalse(tag.closing);
}

- (void)testTwoStandaloneTagsInDifferentStrings
{
	NSArray *elements = [self.parser parse:@"<br height=2>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	XTHtmlTagBr *tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertFalse(tag.closing);
	XCTAssertEqual(2, [tag attributeAsUInt:@"height"]);

	elements = [self.parser parse:@"<br>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagBr class]];
	XCTAssertFalse(tag.closing);
	XCTAssertEqual(0, tag.attributes.count);
}

- (void)testFlushUnusedTagText_1a
{
	NSArray *elements = [self.parser parse:@"<"];
	ASSERT_PARSER_STATE(XT_HTML_AFTER_TAG_START);
	XCTAssertEqual(0, elements.count);
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);

	elements = [self.parser parse:@"b>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	XTHtmlTagB *tag = elements[0];
	[self assertHtmlTagIn:tag withClass:[XTHtmlTagB class]];
}

- (void)testFlushUnusedTagText_1b
{
	NSArray *elements = [self.parser parse:@"<br"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TAG_NAME);
	XCTAssertEqual(0, elements.count);

	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_IN_TAG_NAME);
	XCTAssertEqual(0, elements.count);
}

- (void)testFlushUnusedTagText_1c
{
	NSArray *elements = [self.parser parse:@"<b/"];
	ASSERT_PARSER_STATE(XT_HTML_AT_CLOSING_SLASH);
	XCTAssertEqual(0, elements.count);

	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_AT_CLOSING_SLASH);
	XCTAssertEqual(0, elements.count);
}

- (void)testFlushUnusedTagText_2
{
	NSArray *elements = [self.parser parse:@" <br"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TAG_NAME);
	XCTAssertEqual(1, elements.count);
	[self assertWhitespaceIn:elements[0] withText:@" "];

	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_IN_TAG_NAME);
	XCTAssertEqual(0, elements.count);
}

- (void)testFlushUnusedTagText_3
{
	NSArray *elements = [self.parser parse:@"xy<br"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TAG_NAME);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"xy"];

	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_IN_TAG_NAME);
	XCTAssertEqual(0, elements.count);
}

- (void)testUnknownTag_suppress
{
	self.parser.printBrokenHtmlMarkup = NO;

	NSArray *elements = [self.parser parse:@"<bongo>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(0, elements.count);
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"<bongo foo bar>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(0, elements.count);
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(0, elements.count);

	elements = [self.parser parse:@"a<bongo>cd"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"a"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"cd"];

	elements = [self.parser parse:@"ab<bongo ff m>cd<br>ef<pooba"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TAG_NAME);
	XCTAssertEqual(4, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"ab"];
	[self assertRegularTextIn:elements[1] withValue:@"cd"];
	[self assertHtmlTagIn:elements[2] withClass:[XTHtmlTagBr class]];
	[self assertRegularTextIn:elements[3] withValue:@"ef"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_IN_TAG_NAME);
	XCTAssertEqual(0, elements.count);
}

- (void)testUnknownTag_print
{
	self.parser.printBrokenHtmlMarkup = YES;
	
	NSArray *elements = [self.parser parse:@"<bongo>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"<bongo>"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"<bongo foo bar>"];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"<bongo foo bar>"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"a<bongo>cd"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TEXT);
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"a"];
	[self assertRegularTextIn:elements[1] withValue:@"<bongo>"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"cd"];
	
	elements = [self.parser parse:@"ab<bongo ff m>cd<br>ef<pooba"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TAG_NAME);
	XCTAssertEqual(5, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"ab"];
	[self assertRegularTextIn:elements[1] withValue:@"<bongo ff m>"];
	[self assertRegularTextIn:elements[2] withValue:@"cd"];
	[self assertHtmlTagIn:elements[3] withClass:[XTHtmlTagBr class]];
	[self assertRegularTextIn:elements[4] withValue:@"ef"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_IN_TAG_NAME);
	XCTAssertEqual(0, elements.count);
}

- (void)test_GoldenSkull_extraNewlineAfterAboutIssue
{
	NSArray *elements = [self.parser parse:@"<CENTER> <IMG SRC=\"title.jpg\"> </CENTER> <P> <BLOCKQUOTE> <FONT"];
	ASSERT_PARSER_STATE(XT_HTML_IN_TAG_NAME);
	XCTAssertEqual(10, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagCenter class] closing:NO];
	[self assertWhitespaceIn:elements[1] withText:@" "];
	[self assertHtmlTagIn:elements[2] withClass:[XTHtmlTagImg class] closing:NO];
	[self assertWhitespaceIn:elements[3] withText:@" "];
	[self assertHtmlTagIn:elements[4] withClass:[XTHtmlTagCenter class] closing:YES];
	[self assertWhitespaceIn:elements[5] withText:@" "];
	[self assertHtmlTagIn:elements[6] withClass:[XTHtmlTagP class] closing:NO];
	[self assertWhitespaceIn:elements[7] withText:@" "];
	[self assertHtmlTagIn:elements[8] withClass:[XTHtmlTagBlockQuote class] closing:NO];
	[self assertWhitespaceIn:elements[9] withText:@" "];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_HTML_IN_TAG_NAME);
	XCTAssertEqual(0, elements.count);
}

- (void)test_aTag_empty_bug
{
	NSArray *elements = [self.parser parse:@"<a HREF=\"http://www.tads.org\">TADS</a>"];
	XCTAssertEqual(3, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagA class] closing:NO];
	XTHtmlTagA *tag = elements[0];
	XCTAssertEqualObjects(@"http://www.tads.org", [tag attributeAsString:@"href"]);
	[self assertRegularTextIn:elements[1] withValue:@"TADS"];
	[self assertHtmlTagIn:elements[2] withClass:[XTHtmlTagA class] closing:YES];
}

//------------- Supports functions for tests -------------------

//TODO make macros instead, so we can see which tests fail!

- (void)assertRegularTextIn:(id)obj withValue:(NSString *)string
{
	XCTAssertTrue([obj isKindOfClass:[NSString class]]);
	XCTAssertEqualObjects(string, obj);
}

- (void)assertHtmlTagIn:(id)obj withClass:(Class)class
{
	if (! [obj isKindOfClass:class]) {
		int brkpt = 1;
	}
	XCTAssertTrue([obj isKindOfClass:class]);
}

/*
- (void)assertHtmlTagIn:(XTHtmlTag *)tag hasAttributeNamed:(NSString *)name withValue:(NSString *)value
{
	XCTAssertNotNil(tag);
	XCTAssertEqualObjects(tag.attributes[name], value);
}*/

- (void)assertHtmlTagIn:(id)obj withClass:(Class)class closing:(BOOL)closing
{
	XCTAssertTrue([obj isKindOfClass:class] && ((XTHtmlTag *)obj).closing == closing);
}

- (void)assertWhitespaceIn:(id)obj withText:(NSString *)text
{
	XTHtmlWhitespace *ws = ([obj isKindOfClass:[XTHtmlWhitespace class]] ? (XTHtmlWhitespace *)obj : nil);
	
	XCTAssertTrue(ws != nil && [text isEqualToString:ws.text]);
}

- (void)assertQuotedSpaceIn:(id)obj
{
	XTHtmlQuotedSpace *qs = ([obj isKindOfClass:[XTHtmlQuotedSpace class]] ? (XTHtmlQuotedSpace *)obj : nil);
	
	XCTAssertTrue(qs != nil);
}

- (void)assertNonbreakingSpaceIn:(id)obj
{
	XTHtmlNonbreakingSpace *nbs = ([obj isKindOfClass:[XTHtmlNonbreakingSpace class]] ? (XTHtmlNonbreakingSpace *)obj : nil);
	
	XCTAssertTrue(nbs != nil);
}

@end
