assertEquals($type, $event['name'], "Event $type for " . print_r($event, true));
        if (is_array($expects)) {
            $this->assertEquals($expects, $event['data'], "Event $type should equal " . print_r($expects, true) . ': ' . print_r($event, true));
        } else {
            $this->assertEquals($expects, $event['data'][0], "Event $type should equal $expects: " . print_r($event, true));
        }
    }
    /**
     * Assert that a given event is 'error'.
     */
    public function assertEventError($event)
    {
        $this->assertEquals('error', $event['name'], 'Expected error for event: ' . print_r($event, true));
    }
    /**
     * Asserts that all of the tests are good.
     *
     * This loops through a map of tests/expectations and runs a few assertions on each test.
     *
     * Checks:
     * - depth (if depth is > 0)
     * - event name
     * - matches on event 0.
     */
    protected function isAllGood($name, $depth, $tests, $debug = false)
    {
        foreach ($tests as $try => $expects) {
            if ($debug) {
                fprintf(STDOUT, "%s expects %s\n", $try, print_r($expects, true));
            }
            $e = $this->parse($try);
            if ($depth > 0) {
                $this->assertEquals($depth, $e->depth(), "Expected depth $depth for test $try." . print_r($e, true));
            }
            $this->assertEventEquals($name, $expects, $e->get(0));
        }
    }
    // ================================================================
    // Utility functions.
    // ================================================================
    public function testParse()
    {
        list($tok, $events) = $this->createTokenizer('');
        $tok->parse();
        $e1 = $events->get(0);
        $this->assertEquals(1, $events->Depth());
        $this->assertEquals('eof', $e1['name']);
    }
    public function testWhitespace()
    {
        $spaces = '    ';
        list($tok, $events) = $this->createTokenizer($spaces);
        $tok->parse();
        $this->assertEquals(2, $events->depth());
        $e1 = $events->get(0);
        $this->assertEquals('text', $e1['name']);
        $this->assertEquals($spaces, $e1['data'][0]);
    }
    public function testCharacterReference()
    {
        $good = array(
            '&' => '&',
            '<' => '<',
            '&' => '&',
            '&' => '&',
        );
        $this->isAllGood('text', 2, $good);
        // Test with broken charref
        $str = '&foo';
        $events = $this->parse($str);
        $e1 = $events->get(0);
        $this->assertEquals('error', $e1['name']);
        $str = 'oo';
        $events = $this->parse($str);
        $e1 = $events->get(0);
        $this->assertEquals('error', $e1['name']);
        $str = 'foo';
        $events = $this->parse($str);
        $e1 = $events->get(0);
        $this->assertEquals('error', $e1['name']);
        // FIXME: Once the text processor is done, need to verify that the
        // tokens are transformed correctly into text.
    }
    public function testBogusComment()
    {
        $bogus = array(
            '+this is a bogus comment. +>',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            ' Hello World',
        );
        foreach ($bogus as $str) {
            $events = $this->parse($str);
            $this->assertEventError($events->get(0));
            $this->assertEventEquals('comment', $str, $events->get(1));
        }
    }
    public function testEndTag()
    {
        $succeed = array(
            '' => 'a',
            '' => 'test',
            '' => 'test',
            '' => 'thisisthetagthatdoesntenditjustgoesonandonmyfriend',
            // See 8.2.4.10, which requires this and does not say error.
            '' => 'aisAllGood('endTag', 2, $succeed);
        // Recoverable failures
        $fail = array(
            '' => 'a',
            '' => 'a',
            '' => 'a',
            '' => 'a',
            ' 'a',
        );
        foreach ($fail as $test => $result) {
            $events = $this->parse($test);
            $this->assertEquals(3, $events->depth());
            // Should have triggered an error.
            $this->assertEventError($events->get(0));
            // Should have tried to parse anyway.
            $this->assertEventEquals('endTag', $result, $events->get(1));
        }
        // BogoComments
        $comments = array(
            '>' => '>',
            ' >' => ' >',
            ' a>' => ' a>',
        );
        foreach ($comments as $test => $result) {
            $events = $this->parse($test);
            $this->assertEquals(3, $events->depth());
            // Should have triggered an error.
            $this->assertEventError($events->get(0));
            // Should have tried to parse anyway.
            $this->assertEventEquals('comment', $result, $events->get(1));
        }
    }
    public function testComment()
    {
        $good = array(
            '' => 'easy',
            '' => ' 1 > 0 ',
            '' => ' --$i ',
            '' => '--$i',
            "" => "\nHello World.\na",
            '' => ' ' => '',
            '' => '',
            '' => '',
        );
        foreach ($good as $test => $expects) {
            $events = $this->parse($test);
            $this->assertEventEquals('startTag', 'script', $events->get(0));
            $this->assertEventEquals('text', $expects, $events->get(1));
            $this->assertEventEquals('endTag', 'script', $events->get(2));
        }
        $bad = array(
            ' '&Hello world' => 'Hello world',
        );
        foreach ($bad as $test => $expects) {
            $events = $this->parse($test);
            $this->assertEquals(4, $events->depth(), "Counting events for '$test': " . print_r($events, true));
            $this->assertEventEquals('startTag', 'script', $events->get(0));
            $this->assertEventError($events->get(1));
            $this->assertEventEquals('text', $expects, $events->get(2));
        }
        // Testing case sensitivity
        $events = $this->parse('
b');
        $this->assertEquals(4, $events->depth(), 'Events: ' . print_r($events, true));
        $this->assertEventEquals('text', 'a', $events->get(0));
        $this->assertEventEquals('startTag', 'br', $events->get(1));
        $this->assertEventEquals('text', 'b', $events->get(2));
        $events = $this->parse('Test');
        $this->assertEquals(4, $events->depth(), 'Events: ' . print_r($events, true));
        $this->assertEventEquals('startTag', 'a', $events->get(0));
        $this->assertEventEquals('text', 'Test', $events->get(1));
        $this->assertEventEquals('endTag', 'a', $events->get(2));
        $events = $this->parse('
0
1
'); $this->assertEquals(7, $events->depth(), 'Events: ' . print_r($events, true)); $this->assertEventEquals('startTag', 'p', $events->get(0)); $this->assertEventEquals('text', '0', $events->get(1)); $this->assertEventEquals('endTag', 'p', $events->get(2)); $this->assertEventEquals('startTag', 'p', $events->get(3)); $this->assertEventEquals('text', '1', $events->get(4)); $this->assertEventEquals('endTag', 'p', $events->get(5)); $events = $this->parse('ab'); $this->assertEquals(4, $events->depth(), 'Events: ' . print_r($events, true)); $this->assertEventEquals('text', 'a', $events->get(0)); $this->assertEventEquals('cdata', 'test', $events->get(1)); $this->assertEventEquals('text', 'b', $events->get(2)); $events = $this->parse('ab'); $this->assertEquals(4, $events->depth(), 'Events: ' . print_r($events, true)); $this->assertEventEquals('text', 'a', $events->get(0)); $this->assertEventEquals('comment', 'test', $events->get(1)); $this->assertEventEquals('text', 'b', $events->get(2)); $events = $this->parse('a&b'); $this->assertEquals(2, $events->depth(), 'Events: ' . print_r($events, true)); $this->assertEventEquals('text', 'a&b', $events->get(0)); $events = $this->parse('a²b'); $this->assertEquals(2, $events->depth(), 'Events: ' . print_r($events, true)); $this->assertEventEquals('text', 'a²b', $events->get(0)); } // ================================================================ // Utility functions. // ================================================================ protected function createTokenizer($string, $debug = false) { $eventHandler = new EventStack(); $scanner = new Scanner($string); $scanner->debug = $debug; return array( new Tokenizer($scanner, $eventHandler), $eventHandler, ); } public function parse($string, $debug = false) { list($tok, $events) = $this->createTokenizer($string, $debug); $tok->parse(); return $events; } }