<?php
/**
 * Unicode Normalizer
 *
 * PHP version 5
 *
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * + Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * + Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.
 * + The names of its contributors may not be used to endorse or
 * promote products derived from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @category  Internationalization
 * @package   I18N_UnicodeNormalizer
 * @author    Michel Corne <mcorne@yahoo.com>
 * @copyright 2007 Michel Corne
 * @license   http://www.opensource.org/licenses/bsd-license.php The BSD License
 * @version   SVN: $Id: StringTest.php 38 2007-07-23 11:42:30Z mcorne $
 * @link      http://pear.php.net/package/I18N_UnicodeNormalizer
 */
// Call tests_UnicodeNormalizer_StringTest::main() if this source file is executed directly.
if (!defined("PHPUnit_MAIN_METHOD")) {
    define("PHPUnit_MAIN_METHOD", "tests_UnicodeNormalizer_StringTest::main");
}

require_once "PHPUnit/Framework/TestCase.php";
require_once "PHPUnit/Framework/TestSuite.php";

require_once 'I18N/UnicodeNormalizer/String.php';

/**
 * Test class for I18N_UnicodeNormalizer_String.
 * Generated by PHPUnit_Util_Skeleton on 2007-05-16 at 14:31:25.
 *
 * @category  Internationalization
 * @package   I18N_UnicodeNormalizer
 * @author    Michel Corne <mcorne@yahoo.com>
 * @copyright 2007 Michel Corne
 * @license   http://www.opensource.org/licenses/bsd-license.php The BSD License
 * @version   Release: @package_version@
 * @link      http://pear.php.net/package/I18N_UnicodeNormalizer
 */
class tests_UnicodeNormalizer_StringTest extends PHPUnit_Framework_TestCase
{
    /**
     * The I18N_UnicodeNormalizer_String class instance
     *
     * @var    object 
     * @access private
     */
    private $string;

    /**
     * Runs the test methods of this class.
     *
     * @access public
     * @static
     */
    public static function main()
    {
        require_once "PHPUnit/TextUI/TestRunner.php";

        $suite = new PHPUnit_Framework_TestSuite("I18N_UnicodeNormalizer_StringTest");
        $result = PHPUnit_TextUI_TestRunner::run($suite);
    }

    /**
     * Sets up the fixture, for example, open a network connection.
     * This method is called before a test is executed.
     *
     * @access protected
     */
    protected function setUp()
    {
        $this->string = new I18N_UnicodeNormalizer_String;
    }

    /**
     * Tears down the fixture, for example, close a network connection.
     * This method is called after a test is executed.
     *
     * @access protected
     */
    protected function tearDown()
    {
    }

    /**
     * Tests dec2ucn()
     *
     * @access public
     */
    public function testDec2ucn()
    {
        // format: <hexadecimal integer value>, <expected hexadecimal value in UCN format>
        $test = array(// /
            array(0, '\u0000'),
            array(0x30, '\u0030'),
            array(0xFFFF, '\uFFFF'),
            array(0x10000, '\U00010000'),
            array(0x123456, '\U00123456'),
            array(0xFFFFFFFF, '\UFFFFFFFF'),
            );

        foreach($test as $idx => $values) {
            list($int, $expected) = $values;
            $this->assertEquals($expected, $this->string->dec2ucn($int), 'test line #' . $idx);
        }
    }

    /**
     * Tests char2unicode()
     *
     * @access public
     */
    public function testChar2unicode()
    {
        // format: <UTF-8 character>, <expected Unicode code point in UCN format>
        $test = array(// /
            array(0, '\u0000'),
            array("\x7F", '\u007F'),
            array(0xC280, '\u0080'),
            array("\xDF\xBF", '\u07FF'),
            array(0xE0A080, '\u0800'),
            array("\xEF\xBF\xBF", '\uFFFF'),
            array("\xF0\x90\x80\x80", '\U00010000'), // integer beyond 0x80000000 must be handled as a string
            array("\xF4\x8F\xBF\xBF", '\U0010FFFF'),
            array("\xF8\xA0\x10\x10", '?'), // error: \U00110000 is out of range
            array("\x0\x0\x0\x0\x0", '?'), // error: more than 4 bytes
            array('a', '\u0061'),
            );

        foreach($test as $idx => $values) {
            list($char, $expected) = $values;
            $this->assertEquals($expected, $this->string->char2unicode($char), 'test line #' . $idx);
        }
    }

    /**
     * Tests unicode2char()
     *
     * @access public
     */
    public function testUnicode2char()
    {
        // format: <Unicode code point in hexadecimal>, <expected UTF-8 character>
        $test = array(// /
            array('\u0000', "\x0"),
            array('0x007F', "\x7F"),
            array('0080', "\xC2\x80"),
            array(0x7FF, "\xDF\xBF"),
            array('\u0800', "\xE0\xA0\x80"),
            array('\uFFFF', "\xEF\xBF\xBF"),
            // integer beyond 0x80000000 are handle as a string a must be packed for testing
            array('\U00010000', "\xF0\x90\x80\x80"),
            array('\U0010FFFF', "\xF4\x8F\xBF\xBF"),
            // error: out of range
            array('\U00110000', '?'),
            );

        foreach($test as $idx => $values) {
            list($unicode, $expected) = $values;
            $this->assertEquals($expected, $this->string->unicode2char($unicode), 'test line #' . $idx);
        }
    }

    /**
     * Tests getChar()
     *
     * @access public
     */
    public function testGetChar()
    {
        $chars = array(// /
            "\x61", // a 1-byte character: letter a
            "\xC3\xA0", // a 2-byte character: letter a with grave
            "\xE1\xB8\x81", // a 3-byte character: letter a with ring below
            "\xF0\x90\x80\x81", // a 4-byte character: a linear B syllable
            "\xF8\x80\x80\x80\x80", // error: an invalid 5-byte character
            "\x90", // error: an invalid byte
            );
        // builds the Unicode string
        $string = implode('', $chars);
        $length = strlen($string);
        // format: <string>, <length>, <position>, <expected-char>, <expected-position>, <lookahead>
        $test = array(// /
            array($string, $length, 0, $chars[0], 1, false), // expecting the first character
            array($string, $length, 1, $chars[1], 3, false), // expecting the second character
            array($string, $length, 3, $chars[2], 6, false), // expecting the third character
            array($string, $length, 6, $chars[3], 10, false), // expecting the fourth character
            // error: the first byte of a 5-byte character is out of range
            array($string, $length, 10, '?', 11, false),
            // error: the lone second byte of a multi-byte character not expected
            array($string, $length, 11, '?', 12, false),
            array($string, $length, 15, '?', 16, false), // error: byte out of range
            array($string, $length, 16, false, 16, false), // error: no more character to get
            array('', 0, 0, false, 0, false), // error: empty string
            // lookahead: expecting the first character but no change of position
            array($string, $length, 0, $chars[0], 0, true),
            );

        foreach($test as $idx => $values) {
            list($string, $length, $pos, $expectedChar, $expectedPos, $lookahead) = $values;
            $char = $this->string->getChar($string, $pos, $length, $lookahead);
            $this->assertEquals($expectedPos, $pos, 'test line #' . $idx);
            $this->assertEquals($expectedChar, $char, 'test line #' . $idx);
        }
    }

    /**
     * Tests split()
     *
     * @access public
     */
    public function testSplit()
    {
        $chars = array(// /
            "\x61", // a 1-byte character: letter a
            "\xC3\xA0", // a 2-byte character: letter a with grave
            "\xE1\xB8\x81", // a 3-byte character: letter a with ring below
            "\xF0\x90\x80\x81", // a 4-byte character: a linear B syllable
            // error: an invalid 5-byte character and an invalid lone byte: splitted as one character
            "\xF8\x80\x80\x80\x80\x90",
            );
        // builds the Unicode string
        $string = implode('', $chars);
        $this->assertEquals($this->string->split($string), $chars);
    }

    /**
     * Tests string2unicode()
     *
     * @access public
     */
    public function testString2unicode()
    {
        $chars = array(// /
            "\x61", // a 1-byte character: letter a
            "\xC3\xA0", // a 2-byte character: letter a with grave
            "\xE1\xB8\x81", // a 3-byte character: letter a with ring below
            "\xF0\x90\x80\x81", // a 4-byte character: a linear B syllable
            );
        // builds the Unicode string
        $string = implode('', $chars);
        $this->assertEquals($this->string->string2unicode($string), '\u0061\u00E0\u1E01\U00010001');
    }

    /**
     * Tests unicode2string()
     *
     * @access public
     */
    public function testUnicode2string()
    {
        $chars = array(// /
            "\x61", // a 1-byte character: letter a
            "\xC3\xA0", // a 2-byte character: letter a with grave
            "\xE1\xB8\x81", // a 3-byte character: letter a with ring below
            "\xF0\x90\x80\x81", // a 4-byte character: a linear B syllable
            );
        // builds the Unicode string
        $string = implode('', $chars);
        $this->assertEquals($this->string->unicode2string('\u0061\u00E0\u1E01\U00010001'), $string);
        $this->assertEquals($this->string->unicode2string('061 00E0\x1E01U00010001'), $string);
    }
}
// Call tests_UnicodeNormalizer_StringTest::main() if this source file is executed directly.
if (PHPUnit_MAIN_METHOD == "tests_UnicodeNormalizer_StringTest::main") {
    tests_UnicodeNormalizer_StringTest::main();
}

?>
