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

#import <XCTest/XCTest.h>
#import "XTOutputTextParserPlain.h"
#import "XTHtmlTagQuestionMarkT2.h"


@interface XTOutputTextParserPlainTests : XCTestCase

@property XTOutputTextParserPlain *parser;

@end


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


@implementation XTOutputTextParserPlainTests

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

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

//---------- Plain text ----------

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

- (void)testPlainText
{
    NSArray *elements;
    
	elements = [self.parser parse:@"a"];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"a"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"ab"];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"ab"];
	elements = [self.parser flush];
	
	elements = [self.parser parse:@"ab.XYS"];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"ab.XYS"];
	elements = [self.parser flush];
}

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

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

- (void)testNewlines
{
    NSArray *elements;
    
	elements = [self.parser parse:@"\n"];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"\n"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(0, elements.count);
 
	elements = [self.parser parse:@"\n\n"];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"\n"];
    [self assertRegularTextIn:elements[1] withValue:@"\n"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"\n\n\n"];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(3, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"\n"];
    [self assertRegularTextIn:elements[1] withValue:@"\n"];
    [self assertRegularTextIn:elements[2] withValue:@"\n"];
	elements = [self.parser flush];
}

- (void)testMixOfPlainWsNewlines
{
    NSArray *elements;

	//---  text <-> ws
	
    elements = [self.parser parse:@"a "];
    ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
    XCTAssertEqual(2, elements.count);
    [self assertRegularTextIn:elements[0] withValue:@"a"];
    [self assertRegularTextIn:elements[1] withValue:@" "];
    elements = [self.parser flush];
	
	elements = [self.parser parse:@" a"];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@" "];
	[self assertRegularTextIn:elements[1] withValue:@"a"];
	elements = [self.parser flush];

	elements = [self.parser parse:@"a b c "];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(6, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"a"];
	[self assertRegularTextIn:elements[1] withValue:@" "];
	[self assertRegularTextIn:elements[2] withValue:@"b"];
	[self assertRegularTextIn:elements[3] withValue:@" "];
	[self assertRegularTextIn:elements[4] withValue:@"c"];
	[self assertRegularTextIn:elements[5] withValue:@" "];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(0, elements.count);

	elements = [self.parser parse:@" a1    b22  c33"];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(6, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@" "];
	[self assertRegularTextIn:elements[1] withValue:@"a1"];
	[self assertRegularTextIn:elements[2] withValue:@"    "];
	[self assertRegularTextIn:elements[3] withValue:@"b22"];
	[self assertRegularTextIn:elements[4] withValue:@"  "];
	[self assertRegularTextIn:elements[5] withValue:@"c33"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(0, elements.count);
	
	//---  text <-> newline
	
	elements = [self.parser parse:@"a\n"];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"a"];
	[self assertRegularTextIn:elements[1] withValue:@"\n"];
	elements = [self.parser flush];
	
	elements = [self.parser parse:@"\na"];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"\n"];
	[self assertRegularTextIn:elements[1] withValue:@"a"];
	elements = [self.parser flush];

	elements = [self.parser parse:@"A\nB\nC\n\nDE\n"];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(9, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"A"];
	[self assertRegularTextIn:elements[1] withValue:@"\n"];
	[self assertRegularTextIn:elements[2] withValue:@"B"];
	[self assertRegularTextIn:elements[3] withValue:@"\n"];
	[self assertRegularTextIn:elements[4] withValue:@"C"];
	[self assertRegularTextIn:elements[5] withValue:@"\n"];
	[self assertRegularTextIn:elements[6] withValue:@"\n"];
	[self assertRegularTextIn:elements[7] withValue:@"DE"];
	[self assertRegularTextIn:elements[8] withValue:@"\n"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(0, elements.count);
	
	//---  ws <-> newline

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

	elements = [self.parser parse:@"  \n \n\n\n  \n   \n"];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(10, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"  "];
	[self assertRegularTextIn:elements[1] withValue:@"\n"];
	[self assertRegularTextIn:elements[2] withValue:@" "];
	[self assertRegularTextIn:elements[3] withValue:@"\n"];
	[self assertRegularTextIn:elements[4] withValue:@"\n"];
	[self assertRegularTextIn:elements[5] withValue:@"\n"];
	[self assertRegularTextIn:elements[6] withValue:@"  "];
	[self assertRegularTextIn:elements[7] withValue:@"\n"];
	[self assertRegularTextIn:elements[8] withValue:@"   "];
	[self assertRegularTextIn:elements[9] withValue:@"\n"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(0, elements.count);
	
	//---  monkey time

	elements = [self.parser parse:@"a b cd e   fgh  i\nj"];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(13, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"a"];
	[self assertRegularTextIn:elements[1] withValue:@" "];
	[self assertRegularTextIn:elements[2] withValue:@"b"];
	[self assertRegularTextIn:elements[3] withValue:@" "];
	[self assertRegularTextIn:elements[4] withValue:@"cd"];
	[self assertRegularTextIn:elements[5] withValue:@" "];
	[self assertRegularTextIn:elements[6] withValue:@"e"];
	[self assertRegularTextIn:elements[7] withValue:@"   "];
	[self assertRegularTextIn:elements[8] withValue:@"fgh"];
	[self assertRegularTextIn:elements[9] withValue:@"  "];
	[self assertRegularTextIn:elements[10] withValue:@"i"];
	[self assertRegularTextIn:elements[11] withValue:@"\n"];
	[self assertRegularTextIn:elements[12] withValue:@"j"];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(0, elements.count);

	elements = [self.parser parse:@"\nA\n \nBC  \n \n DE\n\n  F "];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(17, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"\n"];
	[self assertRegularTextIn:elements[1] withValue:@"A"];
	[self assertRegularTextIn:elements[2] withValue:@"\n"];
	[self assertRegularTextIn:elements[3] withValue:@" "];
	[self assertRegularTextIn:elements[4] withValue:@"\n"];
	[self assertRegularTextIn:elements[5] withValue:@"BC"];
	[self assertRegularTextIn:elements[6] withValue:@"  "];
	[self assertRegularTextIn:elements[7] withValue:@"\n"];
	[self assertRegularTextIn:elements[8] withValue:@" "];
	[self assertRegularTextIn:elements[9] withValue:@"\n"];
	[self assertRegularTextIn:elements[10] withValue:@" "];
	[self assertRegularTextIn:elements[11] withValue:@"DE"];
	[self assertRegularTextIn:elements[12] withValue:@"\n"];
	[self assertRegularTextIn:elements[13] withValue:@"\n"];
	[self assertRegularTextIn:elements[14] withValue:@"  "];
	[self assertRegularTextIn:elements[15] withValue:@"F"];
	[self assertRegularTextIn:elements[16] withValue:@" "];
	elements = [self.parser flush];
	ASSERT_PARSER_STATE(XT_PLAIN_INITIAL);
	XCTAssertEqual(0, elements.count);
}

//TODO assert state:

//---------- <?T2> ----------

- (void)testQT2
{
	NSArray *elements = [self.parser parse:@"<?T2>"];
	XCTAssertEqual(1, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagQuestionMarkT2 class]];
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);

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

- (void)testQT2MixedWithPlaintext
{
	NSArray *elements = [self.parser parse:@"ab<?T2>c"];
	XCTAssertEqual(3, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"ab"];
	[self assertHtmlTagIn:elements[1] withClass:[XTHtmlTagQuestionMarkT2 class]];
	[self assertRegularTextIn:elements[2] withValue:@"c"];
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);

	elements = [self.parser parse:@"a<?t2>bc"];
	XCTAssertEqual(3, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"a"];
	[self assertHtmlTagIn:elements[1] withClass:[XTHtmlTagQuestionMarkT2 class]];
	[self assertRegularTextIn:elements[2] withValue:@"bc"];
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
}

- (void)testQT2InSeveralParts
{
	NSArray *elements = [self.parser parse:@"ab<?"];
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"ab"];
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);

	elements = [self.parser parse:@"T2"];
	XCTAssertEqual(0, elements.count);
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@">c"];
	XCTAssertEqual(2, elements.count);
	[self assertHtmlTagIn:elements[0] withClass:[XTHtmlTagQuestionMarkT2 class]];
	[self assertRegularTextIn:elements[1] withValue:@"c"];
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
}

- (void)testQT2Aborted
{
	NSArray *elements = [self.parser parse:@"a<b"];
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"a"];
	[self assertRegularTextIn:elements[1] withValue:@"<b"];
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"a<?b"];
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"a"];
	[self assertRegularTextIn:elements[1] withValue:@"<?b"];
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"a<?Tb"];
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"a"];
	[self assertRegularTextIn:elements[1] withValue:@"<?Tb"];
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"a<?T2b"];
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"a"];
	[self assertRegularTextIn:elements[1] withValue:@"<?T2b"];
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
	
	elements = [self.parser parse:@"a<?T2 b"];
	XCTAssertEqual(4, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"a"];
	[self assertRegularTextIn:elements[1] withValue:@"<?T2"];
	[self assertRegularTextIn:elements[2] withValue:@" "];
	[self assertRegularTextIn:elements[3] withValue:@"b"];
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
}

//---------- <?T3> ----------

// Don't care - T3 never uses this parser

//---------- Misc. ----------

- (void)testUnknownTag
{
	NSArray *elements = [self.parser parse:@"<working>"];
	XCTAssertEqual(2, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"<w"];
	[self assertRegularTextIn:elements[1] withValue:@"orking>"];
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);

	elements = [self.parser parse:@"<>"];
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"<>"];
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
}

- (void)testBadMachineIntroBulkBug
{
	NSArray *elements = [self.parser parse:@"<Constructor38 report power_level>"];
	XCTAssertEqual(6, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"<C"];
	[self assertRegularTextIn:elements[1] withValue:@"onstructor38"];
	[self assertRegularTextIn:elements[2] withValue:@" "];
	[self assertRegularTextIn:elements[3] withValue:@"report"];
	[self assertRegularTextIn:elements[4] withValue:@" "];
	[self assertRegularTextIn:elements[5] withValue:@"power_level>"];
	
	elements = [self.parser parse:@"\n"];
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"\n"];
	
	elements = [self.parser parse:@"\n"];
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"\n"];
	
	elements = [self.parser parse:@"\n"];
	XCTAssertEqual(1, elements.count);
	[self assertRegularTextIn:elements[0] withValue:@"\n"];
	
	elements = [self.parser flush];
	XCTAssertEqual(0, elements.count);
}

//--------- Private support functions ---------

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

- (void)assertHtmlTagIn:(id)obj withClass:(Class)class
{
	XCTAssertTrue([obj isKindOfClass:class]);
}

@end
