// Copyright 2006 Google Inc. // All Rights Reserved // // Unit test for xmltoken.js. // // Author: Junji Takagi // Test if regexp matches the str and RegExp.exec returns exactly the match. function assertOk(comment, regexp, str, match) { assertNotNull(comment, regexp.exec(str)); assertEquals(comment, regexp.exec(str)[0], match); assertTrue(comment, regexp.test(str)); } // Test if regexp doesn't match the str. function assertNg(comment, regexp, str) { assertNull(comment, regexp.exec(str)); assertFalse(comment, regexp.test(str)); } // Concat chars in various way and test them with regexp. function doTestXmlName(comment, regexp, okFirstChars, ngFirstChars, okSecondChars, ngSecondChars) { var okSecondString = okSecondChars.join(''); for (var i = 0; i < okFirstChars.length; i++) { assertOk(comment + ' with ok #' + i, regexp, okFirstChars[i], okFirstChars[i]); assertOk(comment + ' with ok #' + i + ' + oks', regexp, okFirstChars[i] + okSecondString, okFirstChars[i] + okSecondString); for (var j = 0; j < okSecondChars.length; j++) { assertOk(comment + ' with ok #' + i + ' + ok #' + j, regexp, okFirstChars[i] + okSecondChars[j], okFirstChars[i] + okSecondChars[j]); assertOk(comment + ' with ok #' + i + ' + ok #' + j + ' + oks', regexp, okFirstChars[i] + okSecondChars[j] + okSecondString, okFirstChars[i] + okSecondChars[j] + okSecondString); var k = (i + j) % ngSecondChars.length; assertOk(comment + ' with ' + 'ok #' + i + ' + ok #' + j + ' + ng #' + k, regexp, okFirstChars[i] + okSecondChars[j] + ngSecondChars[k], okFirstChars[i] + okSecondChars[j]); } var j = i % ngSecondChars.length; assertOk(comment + ' with ok #' + i + ' + ng #' + j, regexp, okFirstChars[i] + ngSecondChars[j], okFirstChars[i]); assertOk(comment + ' with ok #' + i + ' + oks + ng #' + j, regexp, okFirstChars[i] + okSecondString + ngSecondChars[j], okFirstChars[i] + okSecondString); } for (var i = 0; i < ngFirstChars.length; i++) { assertNg(comment + ' with ng #' + i, regexp, ngFirstChars[i]); // It doesn't make sense to test with ngFirstChars[i] + okSecondChars[j]. for (var j = 0; j < ngSecondChars.length; j++) { assertNg(comment + ' with ng #' + i + ' + ng #' + j, regexp, ngFirstChars[i] + ngSecondChars[j]); } } } // Test REGEXP_UNICODE to make sure the browser supports Unicode in RegExp. function testRegexpUnicode() { assertTrue('REGEXP_UNICODE', REGEXP_UNICODE); } // Test XML10_VERSION_INFO and XML11_VERSION_INFO. // Also test XML_S and XML_EQ. function testXmlVersionInfo() { var okVersion10 = [ ' version="1.0"', ' version = "1.0"', '\tversion\t\t=\t\t\t"1.0"', '\rversion\r\r=\r\r\r"1.0"', '\nversion\n\n=\n\n\n"1.0"', '\r\nversion\r\n\r\n=\r\n\r\n\r\n"1.0"', '\n\rversion\n\r\n\r=\n\r\n\r\n\r"1.0"', ' \t\r\n \t\n\rversion \r\t\n \r\n\t= \n\t\r \n\r\t"1.0"', " version='1.0'", " version = '1.0'", "\tversion\t\t=\t\t\t'1.0'", "\rversion\r\r=\r\r\r'1.0'", "\nversion\n\n=\n\n\n'1.0'", "\r\nversion\r\n\r\n=\r\n\r\n\r\n'1.0'", "\n\rversion\n\r\n\r=\n\r\n\r\n\r'1.0'", "\t \r\n\t \n\rversion\t\r \n\t\r\n =\t\n \r\t\n\r '1.0'" ]; var ngVersion10 = [ 'version="1.0"', // Must start with space char ' Version="1.0"', // Must be lower letter ' VERSION="1.0"', // Must be lower letter ' version"1.0"', // Must have '=' ' version "1.0"', // Must have '=' ' version\t"1.0"', // Must have '=' ' version+"1.0"', // Must have '=' ' version-"1.0"', // Must have '=' ' version=1.0', // Must be quoted ' version="1.1"', // Must be '1.0' ' version="1"', // Must be '1.0' ' version="10"', // Must be '1.0' ' version="100"', // Must be '1.0' ' version="1-0"', // Must be '1.0' ' version="1_0"' // Must be '1.0' ]; var okVersion11 = [ ' version="1.1"', ' version = "1.1"', '\tversion\t\t=\t\t\t"1.1"', '\rversion\r\r=\r\r\r"1.1"', '\nversion\n\n=\n\n\n"1.1"', '\r\nversion\r\n\r\n=\r\n\r\n\r\n"1.1"', '\n\rversion\n\r\n\r=\n\r\n\r\n\r"1.1"', '\r \t\n\r \n\tversion\r\t \n\r\t\n =\r\n \t\r\n\t "1.1"', " version='1.1'", " version = '1.1'", "\tversion\t\t=\t\t\t'1.1'", "\rversion\r\r=\r\r\r'1.1'", "\nversion\n\n=\n\n\n'1.1'", "\r\nversion\r\n\r\n=\r\n\r\n\r\n'1.1'", "\n\rversion\n\r\n\r=\n\r\n\r\n\r'1.1'", "\n \t\r\n \r\tversion\n\t \r\n\t\r =\n\r \t\n\r\t '1.1'" ]; var ngVersion11 = [ 'version="1.1"', // Must start with space char ' Version="1.1"', // Must be lower letter ' VERSION="1.1"', // Must be lower letter ' version"1.1"', // Must have '=' ' version "1.1"', // Must have '=' ' version\t"1.1"', // Must have '=' ' version+"1.1"', // Must have '=' ' version-"1.1"', // Must have '=' ' version=1.1', // Must be quoted ' version="1.0"', // Must be '1.1' ' version="1"', // Must be '1.1' ' version="11"', // Must be '1.1' ' version="111"', // Must be '1.1' ' version="1-1"', // Must be '1.1' ' version="1_1"' // Must be '1.1' ]; var regexp = new RegExp(XML10_VERSION_INFO); for (var i = 0; i < okVersion10.length; i++) { assertOk('XML10_VERSION_INFO with ok #' + i, regexp, okVersion10[i], okVersion10[i]); } for (var i = 0; i < ngVersion10.length; i++) { assertNg('XML10_VERSION_INFO with ng #' + i, regexp, ngVersion10[i]); } var regexp = new RegExp(XML11_VERSION_INFO); for (var i = 0; i < okVersion11.length; i++) { assertOk('XML11_VERSION_INFO with ok #' + i, regexp, okVersion11[i], okVersion11[i]); } for (var i = 0; i < ngVersion11.length; i++) { assertNg('XML11_VERSION_INFO with ng #' + i, regexp, ngVersion11[i]); } } // Test XML_CHAR_REF. function testXmlCharRef() { var okCharRef = [ '�', ' ', ' ', // ' ' '"', // '"' '&', // '&' ''', // "'" '<', // "<" '>', // ">" 'A', // "A" 'd', '✏', '𐀀', '�', '�', '�', // Pi, until all 0-9 appears '�', ' ', ' ', '', ' ', '', ' ', // ' ' '"', // '"' '&', // '&' ''', // "'" '<', // "<" '>', // ">" 'A', // "A" 'ª', // Both upper letter '»', // Start with upper letter, end with lower letter 'Ì', // Start with lower letter, end with upper letter 'Ý', // Both lower letter 'Ā', '香', 'ꪪ', '￿', '�', '�', '�' ]; var ngCharRef = [ '&0;', // Must start with '&#' '#0;', // Must start with '&#' 'x0;', // Must start with '&#' '&#;', // Must have one or more digit '&#/;', // Must be 0-9 ('/' is a char before '0') '�', // Must end with ';' ' ', // Must end with ';' '�:', // Must end with ';' ' :', // Must end with ';' '&# 0;', // Must not have a space char '� ;', // Must not have a space char '&# 0 ;', // Must not have space chars '&#A;', // Must not have A-Fa-f '&#F;', // Must not have A-Fa-f '�A;', // Must not have A-Fa-f ' F;', // Must not have A-Fa-f '�F;', // Must not have A-Fa-f ' A;', // Must not have A-Fa-f '&#:;', // Must be 0-9 (':' is a char after '9') '&#x;', // Must have one or more xdigit '&#x/;', // Must be 0-9A-Fa-f ('/' is a char before '0') '�', // Must end with ';' ' ', // Must end with ';' ' ', // Must end with ';' '', // Must end with ';' ' ', // Must end with ';' '', // Must end with ';' '�:', // Must end with ';' ' :', // Must end with ';' ' :', // Must end with ';' ':', // Must end with ';' ' :', // Must end with ';' ':', // Must end with ';' '&#x 0', // Must not have a space char '� ', // Must not have a space char '&#x 0 ', // Must not have space chars '&#x:;', // Must be 0-9A-Fa-f (':' is a char after '9') '&#x@;', // Must be 0-9A-Fa-f ('@' is a char before 'A') '&#xG;', // Must be 0-9A-Fa-f '&#x`;', // Must be 0-9A-Fa-f ('`' is a char before 'a') '&#xg;' // Must be 0-9A-Fa-f ]; var regexp = new RegExp(XML_CHAR_REF); for (var i = 0; i < okCharRef.length; i++) { assertOk('XML_CHAR_REF with ok #' + i, regexp, okCharRef[i], okCharRef[i]); } for (var i = 0; i < ngCharRef.length; i++) { assertNg('XML_CHAR_REF with ng #' + i, regexp, ngCharRef[i]); } } // Test XML10_ENTITY_REF and XML11_ENTITY_REF. // Also test XML10_NAME and XML11_NAME a little bit. function testXmlEntityRef() { var okEntityRef = [ '<', // XML predefined entity '>', // XML predefined entity '&', // XML predefined entity '&aps;', // XML predefined entity '"', // XML predefined entity ' ', // HTML entity (picked up as a real world example) '©', // HTML entity '®', // HTML entity 'À', // HTML entity, starts with upper letter 'Ð', // HTML entity, all upper letter '⇐', // HTML entity, starts with lower letter, has upper letter '∴', // HTML entity, has digit '&foo;', // Just an entity name '&:foo;', // Entity name can start with ':' '&_foo;', // Entity name can start with '_' '&foo-bar.baz:quux_;', // Entity name can have '-', '.', ':' or '_' '&\u30a8\u30f3\u30c6\u30a3\u30c6\u30a3\u540d;' // Japanese entity name ]; var ngEntityRef = [ 'lt;', // Must start with '&' '>', // Must end with ';' '& amp;', // Must not have a space char '&aps ;', // Must not have a space char '& quot ;', // Must not have space chars '&-foo;', // Entity name must not start with '-' '&.foo;' // Entity name must not start with '.' ]; var edgeEntityRef = [ // Invalid XML10_ENTITY_REF but valid XML11_ENTITY_REF '&\u0131\u0132;', '&\u0132\u0133;', '&\u0133\u0134;', '&\u0131\u0132\u0133\u0134;', '&\u3001\u3030\u4d00\u9fff\ufffd;', ]; var regexp10 = new RegExp(XML10_ENTITY_REF); for (var i = 0; i < okEntityRef.length; i++) { assertOk('XML10_ENTITY_REF with ok #' + i, regexp10, okEntityRef[i], okEntityRef[i]); } for (var i = 0; i < ngEntityRef.length; i++) { assertNg('XML10_ENTITY_REF with ng #' + i, regexp10, ngEntityRef[i]); } var regexp11 = new RegExp(XML11_ENTITY_REF); for (var i = 0; i < okEntityRef.length; i++) { assertOk('XML11_ENTITY_REF with ok #' + i, regexp11, okEntityRef[i], okEntityRef[i]); } for (var i = 0; i < ngEntityRef.length; i++) { assertNg('XML11_ENTITY_REF with ng #' + i, regexp11, ngEntityRef[i]); } for (var i = 0; i < edgeEntityRef.length; i++) { assertNg('XML10_ENTITY_REF with edge #' + i, regexp10, edgeEntityRef[i]); assertOk('XML11_ENTITY_REF with edge #' + i, regexp11, edgeEntityRef[i], edgeEntityRef[i]); } } // Test XML10_NAME including XML10_LETTER, XML10_NAME_CHAR, XML10_BASE_CHAR, // XML10_IDEOGRAPHIC, XML10_DIGIT, XML10_COMBINING_CHAR and XML10_EXTENDER. function testXml10Name() { var okFirstChars = [ '\u003a', // ':' '\u0041', // 'A' : XML10_BASE_CHAR '\u005a', // 'Z' : XML10_BASE_CHAR '\u005f', // '_' '\u0061', // 'a' : XML10_BASE_CHAR '\u007a', // 'z' : XML10_BASE_CHAR '\u00c0', // XML10_BASE_CHAR '\u00d6', // XML10_BASE_CHAR '\u00d8', // XML10_BASE_CHAR '\u00f6', // XML10_BASE_CHAR '\u00f8', // XML10_BASE_CHAR '\u00ff', // XML10_BASE_CHAR '\u0100', // XML10_BASE_CHAR '\u4e00', // XML10_IDEOGRAPHIC '\u9fa5', // XML10_IDEOGRAPHIC '\uac00', // XML10_BASE_CHAR '\ud7a3' // XML10_BASE_CHAR ]; var ngFirstChars = [ '\u002d', // '-' '\u002e', // '.' '\u0030', // '0' : First char of XML10_DIGIT '\u0039', // '9' : XML10_DIGIT '\u003b', // ';' : Non XML10_BASE_CHAR '\u0040', // '@' : Non XML10_BASE_CHAR '\u005b', // '[' : Non XML10_BASE_CHAR '\u005e', // '^' : Non XML10_BASE_CHAR '\u0060', // '`' : Non XML10_BASE_CHAR '\u007b', // '{' : Non XML10_BASE_CHAR '\u00b7', // First char of XML10_EXTENDER '\u00bf', // Non XML10_BASE_CHAR '\u00d7', // Non XML10_BASE_CHAR '\u00f7', // Non XML10_BASE_CHAR '\u0300', // First char of XML10_COMBINING_CHAR '\u0660', // XML10_DIGIT '\u0f29', // Last char of XML10_DIGIT '\u309a', // Last char of XML10_COMBINING_CHAR '\u30fe', // Last char of XML10_EXTENDER '\u4dff', // Edge char for XML10_IDEOGRAPHIC '\u9fa6', // Edge char for XML10_IDEOGRAPHIC '\uabff', // Edge char for XML10_BASE_CHAR '\ud7a4' // Edge char for XML10_BASE_CHAR ]; var okSecondChars = [ '\u002d', // '-' '\u002e', // '.' '\u0030', // '0' : XML10_DIGIT '\u0039', // '9' : XML10_DIGIT '\u003a', // ':' '\u0041', // 'A' : XML10_BASE_CHAR '\u005a', // 'Z' : XML10_BASE_CHAR '\u005f', // '_' '\u0061', // 'a' : XML10_BASE_CHAR '\u007a', // 'z' : XML10_BASE_CHAR '\u00b7', // XML10_EXTENDER '\u00c0', // XML10_BASE_CHAR '\u00d6', // XML10_BASE_CHAR '\u00d8', // XML10_BASE_CHAR '\u00f6', // XML10_BASE_CHAR '\u00f8', // XML10_BASE_CHAR '\u00ff', // XML10_BASE_CHAR '\u0100', // XML10_BASE_CHAR '\u0300', // XML10_COMBINING_CHAR '\u0660', // XML10_DIGIT '\u0f29', // XML10_DIGIT '\u309a', // XML10_COMBINING_CHAR '\u30fe', // XML10_EXTENDER '\u4e00', // XML10_IDEOGRAPHIC '\u9fa5', // XML10_IDEOGRAPHIC '\uac00', // XML10_BASE_CHAR '\ud7a3' // XML10_BASE_CHAR ]; var ngSecondChars = [ '\u0040', // '@' : Non XML10_BASE_CHAR '\u005b', // '[' : Non XML10_BASE_CHAR '\u0060', // '`' : Non XML10_BASE_CHAR '\u007b', // '{' : Non XML10_BASE_CHAR '\u00b6', // Edge char for XML10_EXTENDER '\u00bf', // Non XML10_BASE_CHAR '\u00d7', // Non XML10_BASE_CHAR '\u00f7', // Non XML10_BASE_CHAR '\u02ff', // Edge char for XML10_COMBINING_CHAR '\u309b', // Edge char for XML10_COMBINING_CHAR '\u30ff', // Edge char for XML10_EXTENDER '\u4dff', // Edge char for XML10_IDEOGRAPHIC '\u9fa6', // Edge char for XML10_IDEOGRAPHIC '\uabff', // Edge char for XML10_BASE_CHAR '\ud7a4' // Edge char for XML10_BASE_CHAR ]; doTestXmlName('XML10_NAME', new RegExp(XML10_NAME), okFirstChars, ngFirstChars, okSecondChars, ngSecondChars); } // Test strings for testXml10Attribute() and testXml11Attribute(). var okAttValues = [ '""', '"foo"', '"<foobar"', '"foo<bar"', '"foobar<"', '">foobar"', '"foo>bar"', '"foobar>"', '"&foobar"', '"foo&bar"', '"foobar&"', '""foobar"', '"foo"bar"', '"foobar""', '"\'foobar"', '"foo\'bar"', '"foobar\'"', '"<&"'\'"', '"foo"', // "foo" '"foo"', // "foo" '"<foo>"', // "" '"&:foo;"', '"&_foo;"', '"&foo-bar.baz:quux_;"', '"foo&\u30a8\u30f3\u30c6\u30a3\u30c6\u30a3\u540d;bar"', "''", "'foo'", "'<foobar'", "'foo<bar'", "'foobar<'", "'>foobar'", "'foo>bar'", "'foobar>'", "'&foobar'", "'foo&bar'", "'foobar&'", "''foobar'", "'foo'bar'", "'foobar''", "'\"foobar'", "'foo\"bar'", "'foobar\"'", "'<>&"'\"'", "'foo'", // 'foo' "'foo'", // 'foo' "'<foo>'", // '' "'&:foo;'", "'&_foo;'", "'&foo-bar.baz:quux_;'", "'foo&\u30a8\u30f3\u30c6\u30a3\u30c6\u30a3\u540d;bar'" ]; var ngAttValues = [ '', 'foo', // Must start with '"', end with '"' 'foo"', // Must start with '"' '"foo', // Must end with '"' '"foo\'', // Must end with '"' '"