Changeset 7854
- Timestamp:
- 06/19/10 20:46:04 (2 years ago)
- Location:
- trunk/WysiwygPlugin
- Files:
-
- 8 edited
-
lib/Foswiki/Plugins/WysiwygPlugin/Constants.pm (modified) (7 diffs)
-
lib/Foswiki/Plugins/WysiwygPlugin/HTML2TML.pm (modified) (3 diffs)
-
lib/Foswiki/Plugins/WysiwygPlugin/HTML2TML/Node.pm (modified) (1 diff)
-
lib/Foswiki/Plugins/WysiwygPlugin/Handlers.pm (modified) (13 diffs)
-
test/unit/WysiwygPlugin/BrowserEditorInterface.pm (modified) (16 diffs)
-
test/unit/WysiwygPlugin/BrowserTranslatorTests.pm (modified) (9 diffs)
-
test/unit/WysiwygPlugin/TranslatorTests.pm (modified) (2 diffs)
-
test/unit/WysiwygPlugin/WysiwygPluginTests.pm (modified) (14 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/WysiwygPlugin/lib/Foswiki/Plugins/WysiwygPlugin/Constants.pm
r7644 r7854 4 4 use strict; 5 5 use warnings; 6 7 use Encode; 6 8 7 9 # HTML elements that are strictly block type, as defined by … … 203 205 ############ Encodings ############### 204 206 205 # Mapping high-bit characters from unicode back to iso-8859-1206 # (a.k.a Windows 1252 a.k.a "ANSI") - http://www.alanwood.net/demos/ansi.html207 our %unicode2HighBit = (208 chr(8364) => chr(128),209 chr(8218) => chr(130),210 chr(402) => chr(131),211 chr(8222) => chr(132),212 chr(8230) => chr(133),213 chr(8224) => chr(134),214 chr(8225) => chr(135),215 chr(710) => chr(136),216 chr(8240) => chr(137),217 chr(352) => chr(138),218 chr(8249) => chr(139),219 chr(338) => chr(140),220 chr(381) => chr(142),221 chr(8216) => chr(145),222 chr(8217) => chr(146),223 chr(8220) => chr(147),224 chr(8221) => chr(148),225 chr(8226) => chr(149),226 chr(8211) => chr(150),227 chr(8212) => chr(151),228 chr(732) => chr(152),229 chr(8482) => chr(153),230 chr(353) => chr(154),231 chr(8250) => chr(155),232 chr(339) => chr(156),233 chr(382) => chr(158),234 chr(376) => chr(159),235 );236 237 # Reverse mapping238 our %highBit2Unicode = map { $unicode2HighBit{$_} => $_ } keys %unicode2HighBit;239 240 our $unicode2HighBitChars = join( '', keys %unicode2HighBit );241 our $highBit2UnicodeChars = join( '', keys %highBit2Unicode );242 207 our $encoding; 243 208 … … 246 211 $encoding = 247 212 Encode::resolve_alias( $Foswiki::cfg{Site}{CharSet} || 'iso-8859-1' ); 213 214 $encoding = 'windows-1252' if $encoding =~ /^iso-8859-1$/i; 248 215 } 249 216 return $encoding; 250 217 } 251 218 252 # Map selected unicode characters back to high-bit chars if 253 # iso-8859-1 is selected. This is required because the same characters 254 # have different code points in unicode and iso-8859-1. For example, 255 # € is 128 in iso-8859-1 and 8364 in unicode. 256 sub mapUnicode2HighBit { 257 if ( encoding() eq 'iso-8859-1' ) { 258 259 # Map unicode back to iso-8859 high-bit chars 260 $_[0] =~ s/([$unicode2HighBitChars])/$unicode2HighBit{$1}/ge; 261 } 262 } 263 264 # Map selected high-bit chars to unicode if 265 # iso-8859-1 is selected. 266 sub mapHighBit2Unicode { 267 if ( encoding() eq 'iso-8859-1' ) { 268 269 # Map unicode back to iso-8859 high-bit chars 270 $_[0] =~ s/([$highBit2UnicodeChars])/$highBit2Unicode{$1}/ge; 219 my $siteCharsetRepresentable; 220 221 # Convert characters (unicode codepoints) that cannot be represented in 222 # the site charset to entities. Prefer named entities to numeric entities. 223 sub convertNotRepresentabletoEntity { 224 if ( encoding() =~ /^utf-?8/ ) { 225 # UTF-8 can represent all characters, so no entities needed 226 } 227 else { 228 unless ($siteCharsetRepresentable) { 229 # Produce a string of unicode characters that contains all of the 230 # characters representable in the site charset 231 $siteCharsetRepresentable = ''; 232 for my $code (0 .. 255) { 233 my $unicodeChar = Encode::decode(encoding(), chr($code), Encode::FB_PERLQQ); 234 if ($unicodeChar =~ /^\\x/) { 235 # code is not valid, so skip it 236 } 237 else { 238 # Escape codes in the standard ASCII range, as necessary, 239 # to avoid special interpretation by perl 240 $unicodeChar = quotemeta($unicodeChar) if ord($unicodeChar) <= 127; 241 242 $siteCharsetRepresentable .= $unicodeChar; 243 } 244 } 245 } 246 247 require HTML::Entities; 248 $_[0] = HTML::Entities::encode_entities($_[0], "^$siteCharsetRepresentable"); 249 # All characters that cannot be represented in the site charset are now encoded as entities 250 # Named entities are used if available, otherwise numeric entities, 251 # because named entities produce more readable TML 271 252 } 272 253 } … … 284 265 Oslash Ugrave Uacute Ucirc Uuml Yacute THORN szlig 285 266 agrave aacute acirc atilde auml aring aelig ccedil 286 egrave eacute ecirc umligrave iacute icirc iuml267 egrave eacute ecirc euml igrave iacute icirc iuml 287 268 eth ntilde ograve oacute ocirc otilde ouml divide 288 269 oslash ugrave uacute ucirc uuml yacute thorn yuml … … 292 273 our $safe_entities; 293 274 294 # Get a hash that maps the safe entities values to characters 295 # in the site charset. 275 # Get a hash that maps the safe entities values to unicode characters 296 276 sub safeEntities { 297 277 unless ($safe_entities) { … … 301 281 my $unicode = HTML::Entities::decode_entities("&$entity;"); 302 282 303 # Map unicode back to iso-8859 high-bit chars if required 304 mapUnicode2HighBit($unicode); 305 $safe_entities->{$entity} = Encode::encode( encoding(), $unicode ); 283 $safe_entities->{"$entity"} = $unicode; 306 284 } 307 285 } … … 325 303 } 326 304 305 # Allow the unit tests to force re-initialisation of 306 # %Foswiki::cfg-dependent cached data 307 sub reinitialiseForTesting { 308 undef $encoding; 309 undef $siteCharsetRepresentable; 310 } 311 327 312 # Create shorter alias for other modules 328 313 no strict 'refs'; -
trunk/WysiwygPlugin/lib/Foswiki/Plugins/WysiwygPlugin/HTML2TML.pm
r7737 r7854 92 92 =cut 93 93 94 sub debugEncode { 95 my $text = shift; 96 $text = WC::debugEncode($text); 97 $text =~ s/([^\x20-\x7E])/sprintf '\\x{%X}', ord($1)/ge; 98 return $text; 99 } 100 94 101 sub convert { 95 102 my ( $this, $text, $options ) = @_; … … 101 108 if ( $options->{very_clean} ); 102 109 103 # If the text is UTF8-encoded we have to decode it first, otherwise 104 # the HTML parser will barf. 110 # $text is octets, encoded as per the $Foswiki::cfg{Site}{CharSet} 111 #print STDERR "input [". debugEncode($text). "]\n\n"; 112 113 # Convert (safe) named entities back to the 114 # site charset. Numeric entities are mapped straight to the 115 # corresponding code point unless their value overflow. 116 # HTML::Entities::_decode_entities converts numeric entities 117 # to Unicode codepoints, so first convert the text to Unicode 118 # characters 105 119 if ( WC::encoding() =~ /^utf-?8/ ) { 120 # text is already UTF-8, so just decode 106 121 $text = Encode::decode_utf8($text); 107 122 } 123 else { 124 # convert to unicode codepoints 125 $text = Encode::decode(WC::encoding(), $text); 126 } 127 # $text is now Unicode characters 128 #print STDERR "unicoded [". debugEncode($text). "]\n\n"; 129 130 # Make sure that & < > ' and " remain encoded, because the parser depends 131 # on it. The safe-entities does not include the corresponding named 132 # entities, so convert numeric entities for these characters to the named 133 # entity. 134 $text =~ s/\&\#38;/\&/go; 135 $text =~ s/\&\#x26;/\&/goi; 136 $text =~ s/\&\#60;/\</go; 137 $text =~ s/\&\#x3c;/\</goi; 138 $text =~ s/\&\#62;/\>/go; 139 $text =~ s/\&\#x3e;/\>/goi; 140 $text =~ s/\&\#39;/\'/go; 141 $text =~ s/\&\#x27;/\'/goi; 142 $text =~ s/\&\#34;/\"/go; 143 $text =~ s/\&\#x22;/\"/goi; 144 145 require HTML::Entities; 146 HTML::Entities::_decode_entities( $text, WC::safeEntities() ); 147 #print STDERR "decodedent[". debugEncode($text). "]\n\n"; 148 149 # HTML::Entities::_decode_entities is NOT aware of the site charset 150 # so it converts numeric entities to characters willy-nilly. 151 # Some of those were entities in the first place because the 152 # site character set cannot represent them. 153 # Convert them back to entities: 154 WC::convertNotRepresentabletoEntity($text); 155 #print STDERR "notrep2ent[". debugEncode($text). "]\n\n"; 156 157 # $text is now Unicode characters that are representable 158 # in the site charset. Convert to the site charset: 159 if ( WC::encoding() =~ /^utf-?8/ ) { 160 # nothing to do, already in unicode 161 } 162 else { 163 $text = Encode::encode(WC::encoding(), $text); 164 } 165 #print STDERR "sitechrset[". debugEncode($text). "]\n\n"; 108 166 109 167 # get rid of nasties … … 120 178 $text = $this->{stackTop}->rootGenerate($opts); 121 179 180 #print STDERR "parsed [". debugEncode($text). "]\n\n"; 181 122 182 # If the site charset is UTF8, we need to recode 123 183 if ( WC::encoding() =~ /^utf-?8/ ) { 124 184 $text = Encode::encode_utf8($text); 125 } 126 127 # Convert (safe) named entities back to the 128 # site charset. Numeric entities are mapped straight to the 129 # corresponding code point unless their value overflow. 130 require HTML::Entities; 131 HTML::Entities::_decode_entities( $text, WC::safeEntities() ); 132 133 # After decoding entities, we have to map unicode characters 134 # back to high bit 135 WC::mapUnicode2HighBit($text); 136 185 #print STDERR "re-encoded[". debugEncode($text). "]\n\n"; 186 } 187 188 # $text is octets, encoded as per the $Foswiki::cfg{Site}{CharSet} 137 189 return $text; 138 190 } -
trunk/WysiwygPlugin/lib/Foswiki/Plugins/WysiwygPlugin/HTML2TML/Node.pm
r7737 r7854 227 227 my ( $this, $opts ) = @_; 228 228 229 #print STDERR "Raw [", WC::debugEncode($this->stringify()), " \n\n";229 #print STDERR "Raw [", WC::debugEncode($this->stringify()), "]\n\n"; 230 230 $this->cleanParseTree(); 231 231 -
trunk/WysiwygPlugin/lib/Foswiki/Plugins/WysiwygPlugin/Handlers.pm
r7813 r7854 129 129 return unless $query; 130 130 131 if ( $Foswiki::cfg{Site}{CharSet}132 && $Foswiki::cfg{Site}{CharSet} =~ /^utf-?8$/i )133 {134 135 # If the site charset is utf-8, then form POSTs (such as the one136 # that got us here) are utf-8 encoded. we have to decode to prevent137 # the HTML parser from going tits up when it sees utf-8 in the data.138 $text = Encode::decode_utf8($text);139 }140 141 131 return 142 132 unless defined( $query->param('wysiwyg_edit') ) … … 155 145 sub TranslateHTML2TML { 156 146 my ( $text, $topic, $web ) = @_; 147 # $text must be in encoded in the site charset 148 ASSERT( $text !~ /[^\x00-\xff]/, 149 "only octets expected in input to TranslateHTML2TML" ) 150 if DEBUG; 157 151 158 152 unless ($html2tml) { … … 183 177 $text =~ s/\s+$/\n/s; 184 178 179 ASSERT( $text !~ /[^\x00-\xff]/, 180 "only octets expected in topic text output from TranslateHTML2TML" ) 181 if DEBUG; 185 182 return $top . $text . $bottom; 186 183 } … … 493 490 my ( $text, $web, $topic, @extraConvertOptions ) = @_; 494 491 492 ASSERT( $text !~ /[^\x00-\xff]/, 493 "only octets expected in input to TranslateTML2HTML" ) 494 if DEBUG; 495 495 496 # Translate the topic text to pure HTML. 496 497 unless ($Foswiki::Plugins::WysiwygPlugin::tml2html) { … … 499 500 new Foswiki::Plugins::WysiwygPlugin::TML2HTML(); 500 501 } 501 return$Foswiki::Plugins::WysiwygPlugin::tml2html->convert(502 my $html = $Foswiki::Plugins::WysiwygPlugin::tml2html->convert( 502 503 $_[0], 503 504 { … … 510 511 } 511 512 ); 513 ASSERT( $html !~ /[^\x00-\xff]/, 514 "only octets expected in output from TranslateTML2HTML" ) 515 if DEBUG; 516 return $html; 512 517 } 513 518 … … 589 594 my ($text) = @_; 590 595 591 # $text is supposed to contain octets that are a valid UTF-8 encoding. 596 #print STDERR "octets in [". WC::debugEncode($text). "]\n\n"; 597 # $text is supposed to contain octets that are valid UTF-8. 592 598 # $text should certainly not have any codes above 255. 593 599 ASSERT( $text !~ /[^\x00-\xff]/, … … 595 601 if DEBUG; 596 602 597 # $text might contain octets that are not a valid UTF-8 encoding603 # $text might contain octets that are not valid UTF-8 598 604 # because it came from the browser, and so it might be hostile content. 599 605 # Encode::FB_PERLQQ makes decode_utf8 convert invalid octet sequences … … 603 609 604 610 # $text now contains unicode characters 605 606 WC::mapUnicode2HighBit($text); 607 608 if ( $Foswiki::cfg{Site}{CharSet} ) { 609 $text = Encode::encode( $Foswiki::cfg{Site}{CharSet}, 610 $text, Encode::FB_PERLQQ ); 611 612 # $text is now encoded as per the site charset. 613 # For UTF-8 - that means octets. 614 615 # SMELL: The use of Encode::FB_PERLQQ is probably incorrect here. 616 # If {Site}{CharSet} is set to 'iso-8859-1' then wide characters 617 # (with codes greater than 256) which cannot be represented in 618 # iso-5589-1 are encoded as perl escapes e.g. \x{03b1}. 619 # Encode::FB_HTMLCREF would be far better, as characters that 620 # cannot be represented in the specified site character set 621 # would be converted to HTML entities e.g. α 622 } 623 624 # SMELL: if {Site}{CharSet} is blank (which is the default) 625 # then $text may contain wide characters. 626 # Thus, $text is NOT encoded in the SiteCharSet! 611 #print STDERR "as utf-8 [". WC::debugEncode($text). "]\n\n"; 612 613 if ( WC::encoding() =~ /^utf-?8/ ) { 614 $text = Encode::encode_utf8($text); 615 } 616 else { 617 # The site charset is a non-UTF-8 8-bit charset 618 619 WC::convertNotRepresentabletoEntity($text); 620 # All characters that cannot be represented in the site charset are now encoded as entities 621 # Named entities are used if available, otherwise numeric entities, 622 # because named entities produce more readable TML 623 624 # Encode $text in the site charset 625 # The Encode::FB_HTMLCREF should not be needed, as all characters in $text 626 # are supposed to be representable in the site charset. 627 $text = Encode::encode( WC::encoding(), 628 $text, Encode::FB_HTMLCREF ); 629 } 630 631 # $text is now encoded as per the site charset. 632 # For UTF-8 - that means octets. 633 # For non-UTF8, Unicode characters that cannot be represented in the site charset 634 # are converted to HTML entities (preferring named entities to numeric entities) 627 635 628 636 # The return value is supposed to be according to the currently selected … … 632 640 "only octets expected in return value for RESTParameter2SiteCharSet" ) 633 641 if DEBUG; 642 #print STDERR "octets out [". WC::debugEncode($text). "]\n\n"; 634 643 return $text; 635 644 } … … 642 651 sub returnRESTResult { 643 652 my ( $response, $status, $text ) = @_; 644 645 if ( $Foswiki::cfg{Site}{CharSet} ) { 646 $text = Encode::decode( $Foswiki::cfg{Site}{CharSet}, 647 $text, Encode::FB_PERLQQ ); 648 } 649 650 WC::mapHighBit2Unicode($text); 653 ASSERT( $text !~ /[^\x00-\xff]/, 654 "only octets expected in input to returnRESTResult" ) 655 if DEBUG; 656 657 $text = Encode::decode( WC::encoding(), 658 $text, Encode::FB_HTMLCREF ); 659 660 #print STDERR "unicodechr[". WC::debugEncode($text). "]\n\n"; 651 661 652 662 $text = Encode::encode_utf8($text); … … 730 740 } 731 741 my $html = Foswiki::Func::getCgiQuery()->param('text'); 742 #print STDERR "param [". Foswiki::Plugins::WysiwygPlugin::HTML2TML::debugEncode($html). "]\n\n"; 732 743 733 744 $html = RESTParameter2SiteCharSet($html); 745 #print STDERR "paraminSC [". Foswiki::Plugins::WysiwygPlugin::HTML2TML::debugEncode($html). "]\n\n"; 734 746 735 747 $html =~ s/<!--$SECRET_ID-->//go; … … 744 756 } 745 757 ); 758 #print STDERR "tml inSc [". Foswiki::Plugins::WysiwygPlugin::HTML2TML::debugEncode($tml). "]\n\n"; 746 759 747 760 returnRESTResult( $response, 200, $tml ); -
trunk/WysiwygPlugin/test/unit/WysiwygPlugin/BrowserEditorInterface.pm
r7644 r7854 8 8 9 9 use Scalar::Util; 10 11 sub _DEBUG {0}; 10 12 11 13 my $editFrameLocator = "css=iframe#topic_ifr"; … … 14 16 my $editTextareaLocator = "css=textarea#topic"; 15 17 my $editCancelButtonLocator = "css=input#cancel"; 18 my $editSaveButtonLocator = "css=input#save"; 16 19 17 20 # This must match the text in foswiki_tiny.js … … 34 37 _editorMode => {}, 35 38 _interactions => 0, 39 _web => undef, 40 _topic => undef, 36 41 }, 37 42 $class … … 45 50 sub init { 46 51 my $this = shift; 52 print STDERR "BrowserEditorInterface::init()\n" if _DEBUG; 47 53 48 54 if ( not $this->{_initWebPreferences} ) { … … 79 85 sub finish { 80 86 my $this = shift; 87 print STDERR "BrowserEditorInterface::finish()\n" if _DEBUG; 88 81 89 for my $browser ( keys %{ $this->{_editorModeForBrowser} } ) { 82 90 $this->{_test}->selectBrowser($browser); … … 97 105 sub editorMode { 98 106 my $this = shift; 107 print STDERR "BrowserEditorInterface::editorMode()\n" if _DEBUG; 99 108 if ( 100 109 exists $this->{_editorModeForBrowser} … … 113 122 my $web = shift; 114 123 my $topic = shift; 124 print STDERR "BrowserEditorInterface::openWysiwygEditor()\n" if _DEBUG; 125 $this->{_web} = $web; 126 $this->{_topic} = $topic; 115 127 116 128 $this->cancelEdit() … … 135 147 sub cancelEdit { 136 148 my $this = shift; 149 print STDERR "BrowserEditorInterface::cancelEdit()\n" if _DEBUG; 137 150 138 151 return … … 143 156 $this->{_test}->selenium->click($editCancelButtonLocator); 144 157 158 $this->{_web} = undef; 159 $this->{_topic} = undef; 145 160 delete $this->{_editorModeForBrowser}->{ $this->{_test}->browserName() }; 146 161 } 147 162 163 sub save { 164 my $this = shift; 165 print STDERR "BrowserEditorInterface::save()\n" if _DEBUG; 166 167 $this->{_test}->assert(0, "editor not open") 168 unless exists $this->{_editorModeForBrowser} 169 ->{ $this->{_test}->browserName() }; 170 171 $this->selectTopFrame(); 172 $this->{_test}->selenium->click_ok($editSaveButtonLocator); 173 $this->{_test}->{selenium}->wait_for_page_to_load( $this->{_test}->{selenium_timeout} ); 174 175 my $postSaveLocation = $this->{_test}->{selenium}->get_location(); 176 my $viewUrl = Foswiki::Func::getScriptUrl( $this->{_web}, $this->{_topic}, 'view'); 177 $this->{_test}->assert_matches(qr/\Q$viewUrl\E$/, $postSaveLocation); 178 179 $this->{_web} = undef; 180 $this->{_topic} = undef; 181 delete $this->{_editorModeForBrowser}->{ $this->{_test}->browserName() }; 182 } 183 148 184 sub selectWysiwygEditorFrame { 149 185 my $this = shift; 186 print STDERR "BrowserEditorInterface::selectWysiwygEditorFrame()\n" if _DEBUG; 150 187 $this->{_test}->selenium->select_frame_ok($editFrameLocator); 151 188 } … … 153 190 sub selectTopFrame { 154 191 my $this = shift; 192 print STDERR "BrowserEditorInterface::selectTopFrame()\n" if _DEBUG; 155 193 $this->{_test}->selenium->select_frame_ok("relative=top"); 156 194 } … … 159 197 my $this = shift; 160 198 my $text = shift; 199 print STDERR "BrowserEditorInterface::setWikitextEditorContent()\n" if _DEBUG; 161 200 $this->{_test}->type( $editTextareaLocator, $text ); 162 201 … … 166 205 sub getWikitextEditorContent { 167 206 my $this = shift; 207 print STDERR "BrowserEditorInterface::getWikitextEditorContent()\n" if _DEBUG; 168 208 return $this->{_test}->selenium->get_value($editTextareaLocator); 169 209 } … … 172 212 my $this = shift; 173 213 my $text = shift; 214 print STDERR "BrowserEditorInterface::setWysiwygEditorContent()\n" if _DEBUG; 174 215 175 216 $this->selectWysiwygEditorFrame(); … … 202 243 sub getWysiwygEditorContent { 203 244 my $this = shift; 245 print STDERR "BrowserEditorInterface::getWysiwygEditorContent()\n" if _DEBUG; 204 246 205 247 $this->selectWysiwygEditorFrame(); … … 213 255 sub selectWikitextMode { 214 256 my $this = shift; 257 print STDERR "BrowserEditorInterface::selectWikitextMode()\n" if _DEBUG; 215 258 return 216 259 if $this->{_editorModeForBrowser}->{ $this->{_test}->browserName() } eq … … 248 291 sub selectWysiwygMode { 249 292 my $this = shift; 293 print STDERR "BrowserEditorInterface::selectWysiwygMode()\n" if _DEBUG; 250 294 return 251 295 if $this->{_editorModeForBrowser}->{ $this->{_test}->browserName() } eq -
trunk/WysiwygPlugin/test/unit/WysiwygPlugin/BrowserTranslatorTests.pm
r7794 r7854 5 5 package BrowserTranslatorTests; 6 6 7 use Encode; 8 7 9 use FoswikiSeleniumTestCase; 8 10 use TranslatorBase; … … 12 14 use Foswiki::Func; 13 15 use Foswiki::Plugins::WysiwygPlugin::Handlers; 16 use Foswiki::Plugins::WysiwygPlugin::Constants; 14 17 15 18 # The following big table contains all the testcases. These are … … 71 74 name => 'Item1798', 72 75 exec => $TranslatorBase::ROUNDTRIP, 73 tml => << HERE,76 tml => <<'HERE', 74 77 | [[LegacyTopic1]] | Main.SomeGuy | 75 78 %SEARCH{"legacy" nonoise="on" format="| [[\$topic]] | [[\$wikiname]] |"}% 76 79 HERE 77 html => << THERE,80 html => <<'THERE', 78 81 <table cellspacing="1" cellpadding="0" border="1"> 79 82 <tr><td><span class="WYSIWYG_LINK">[[LegacyTopic1]]</span></td><td><span class="WYSIWYG_LINK">Main.SomeGuy</span></td></tr> … … 86 89 exec => $TranslatorBase::ROUNDTRIP, 87 90 tml => '♀', 88 finaltml => chr(9792),91 finaltml => _siteCharsetIsUTF8() ? chr(9792) : '♀', 89 92 }, 90 93 { … … 94 97 finaltml => 'α', 95 98 }, 99 100 # This test's finaltml is correct for ISO-8859-1 and ISO-8859-15, 101 # but not necessarily any other charsets 102 ( ( not $Foswiki::cfg{Site}{CharSet} or 103 $Foswiki::cfg{Site}{CharSet} =~ /^iso-8859-15?$/i) 104 ? { 105 name => 'safeNamedEntity', 106 exec => $TranslatorBase::ROUNDTRIP, 107 tml => 'Å', 108 finaltml => chr(0xC5), 109 } 110 : () ), 111 96 112 { 97 113 name => 'namedEntity', … … 197 213 198 214 { # Copied on 29 April 2010 from 199 # http://merlin.lavrsen.dk/foswiki10/bin/view/Myweb/NewLineEatingTest215 # http://merlin.lavrsen.dk/foswiki10/bin/view/Myweb/NewLineEatingTest 200 216 # and then split into multiple tests to make analysing the result managable 201 217 name => 'KennethsNewLineEatingTest1', … … 406 422 ]; 407 423 424 sub _siteCharsetIsUTF8 { 425 Foswiki::Plugins::WysiwygPlugin::Constants::reinitialiseForTesting(); 426 return Foswiki::Plugins::WysiwygPlugin::Constants::encoding() =~ /^utf-?8/; 427 } 428 408 429 sub new { 409 430 my $self = shift()->SUPER::new( 'BrowserTranslator', @_ ); … … 412 433 413 434 return $self; 435 } 436 437 sub set_up { 438 my $this = shift; 439 $this->SUPER::set_up(); 440 441 Foswiki::Plugins::WysiwygPlugin::Constants::reinitialiseForTesting(); 414 442 } 415 443 … … 432 460 $this->SUPER::DESTROY if $this->can('SUPER::DESTROY'); 433 461 } 462 463 # Item9170 464 sub verify_editSaveTopicWithUnnamedUnicodeEntity { 465 my $this = shift; 466 467 $this->{editor}->init(); 468 469 # Close the editor because this tests uses a different topic 470 if ( $this->{editor}->editorMode() ) { 471 $this->{editor}->cancelEdit(); 472 } 473 474 # \x{eb} is representable in 8-bit charsets. 475 # In iso-8859-1 it is e-with-umluat, or ë 476 # ♀ is a valid unicode character without a 477 # common entity name 478 my $testText = "A \x{eb} B ♀ C"; 479 my $expectedText = $testText; 480 if ( _siteCharsetIsUTF8() ) { 481 $expectedText =~ s/\&\#x(\w+);/chr(hex($1))/ge; 482 $testText = Encode::encode_utf8($testText); 483 $expectedText = Encode::encode_utf8($expectedText); 484 } 485 486 # Create the test topic 487 my $topicName = $this->{test_topic}."For9170"; 488 my $topicObject = Foswiki::Meta->new( 489 $this->{session}, 490 $this->{test_web}, 491 $topicName, 492 "Before${testText}After\n"); 493 $topicObject->save(); 494 495 # Open the test topic in the wysiwyg editor 496 $this->{editor} 497 ->openWysiwygEditor( $this->{test_web}, $topicName ); 498 499 # Write rubbish over the topic, which will be overwritten on save 500 $topicObject->text("Rubbish"); 501 $topicObject->save(); 502 undef $topicObject; 503 504 # Save from the editor 505 $this->{editor}->save(); 506 507 # Reload the topic and check that the content is as expected 508 $topicObject = Foswiki::Meta->new( 509 $this->{session}, 510 $this->{test_web}, 511 $topicName); 512 513 my $text = $topicObject->text(); 514 515 # Isolate the portion of interest 516 $text =~ s/.*Before//ms or $this->assert(0, $text); 517 $text =~ s/After.*//ms or $this->assert(0, $text); 518 519 # Showtime: 520 for ($expectedText, $text) { 521 s/([^\x20-\x7e])/sprintf "\\x{%X}", ord($1)/ge; 522 } 523 $this->assert_str_equals($expectedText, $text); 524 } 525 434 526 435 527 sub compareTML_HTML { -
trunk/WysiwygPlugin/test/unit/WysiwygPlugin/TranslatorTests.pm
r7754 r7854 1988 1988 }, 1989 1989 { 1990 exec => $TML2HTML , # SMELL fails these:$HTML2TML | $ROUNDTRIP,1991 name => 'entity InsideSticky',1990 exec => $TML2HTML | $HTML2TML | $ROUNDTRIP, 1991 name => 'entityWithNoNameInsideSticky', 1992 1992 tml => <<'GLUED', 1993 1993 <sticky>♀</sticky> … … 1998 1998 </p> 1999 1999 STUCK 2000 },2000 }, 2001 2001 { 2002 2002 exec => $TML2HTML | $HTML2TML | $ROUNDTRIP, -
trunk/WysiwygPlugin/test/unit/WysiwygPlugin/WysiwygPluginTests.pm
r7644 r7854 17 17 use Carp; 18 18 19 my @unicodeCodepointsForWindows1252 = ( 20 21 # From http://www.alanwood.net/demos/ansi.html 22 # unicode windows-1252 23 8364, # 128 24 8218, # 130 25 402, # 131 26 8222, # 132 27 8230, # 133 28 8224, # 134 29 8225, # 135 30 710, # 136 31 8240, # 137 32 352, # 138 33 8249, # 139 34 338, # 140 35 381, # 142 36 8216, # 145 37 8217, # 146 38 8220, # 147 39 8221, # 148 40 8226, # 149 41 8211, # 150 42 8212, # 151 43 732, # 152 44 8482, # 153 45 353, # 154 46 8250, # 155 47 339, # 156 48 382, # 158 49 376, # 159 50 ); 51 19 52 my $UI_FN; 20 53 … … 29 62 $this->SUPER::set_up(); 30 63 $UI_FN ||= $this->getUIFn('save'); 64 65 Foswiki::Plugins::WysiwygPlugin::Constants::reinitialiseForTesting(); 31 66 32 67 $Foswiki::cfg{Plugins}{WysiwygPlugin}{Enabled} = 1; … … 59 94 } 60 95 61 sub save_test {96 sub save_testCharsetCodesRange { 62 97 my ( $this, $charset, $firstchar, $lastchar ) = @_; 63 64 $Foswiki::cfg{Site}{CharSet} = $charset; 98 my @test; 99 for ( my $i = $firstchar ; $i <= $lastchar ; $i++ ) { 100 push( @test, Encode::decode( _perlEncodeCharset($charset), chr($i) ) ); 101 } 102 my $text = join( '', @test ) . "."; 103 104 $this->save_test( $charset, $text, $text ); 105 } 106 107 sub save_testUnicodeCodepointsRange { 108 my ( $this, $charset, $firstchar, $lastchar ) = @_; 65 109 66 110 my @test; … … 69 113 } 70 114 my $text = join( '', @test ) . "."; 71 my $t = $charset ? Encode::encode( $charset, $text ) : $text; 115 116 $this->save_test( $charset, $text, $text ); 117 } 118 119 sub _perlEncodeCharset { 120 my $charset = shift; 121 122 # The default encoding is 'iso-8859-1' 123 # Foswiki treats that encoding like windows-1252 124 # Perl's Encode library treats the differently 125 $charset = 'windows-1252' if not $charset or $charset eq 'iso-8859-1'; 126 return $charset; 127 } 128 129 # $input and $expectedOutput contain unicode codepoints; 130 # they are wide characters, NOT utf-8 encoded 131 sub save_test { 132 my ( $this, $charset, $input, $expectedOutput ) = @_; 133 134 # Is this enough? Regexes are inited before we get here, aren't they? 135 $Foswiki::cfg{Site}{CharSet} = $charset; 136 137 my $t = 138 $charset 139 ? Encode::encode( _perlEncodeCharset($charset), $input ) 140 : $input; 141 my $e = 142 $charset 143 ? Encode::encode( _perlEncodeCharset($charset), $expectedOutput ) 144 : $expectedOutput; 72 145 73 146 my $query = new Unit::Request( … … 108 181 $out =~ s/\s*$//s; 109 182 110 $this->assert( $ t eq $out, "'" . anal($out) . "' !=\n'" . anal($t) . "'" );111 } 112 113 sub TML2HTML_test {183 $this->assert( $e eq $out, "'" . anal($out) . "' !=\n'" . anal($e) . "'" ); 184 } 185 186 sub TML2HTML_testCharsetCodesRange { 114 187 my ( $this, $charset, $firstchar, $lastchar ) = @_; 115 116 # Is this enough? Regexes are inited before we get here, aren't they? 117 $Foswiki::cfg{Site}{CharSet} = $charset; 188 my @test; 189 for ( my $i = $firstchar ; $i <= $lastchar ; $i++ ) { 190 push( @test, Encode::decode( _perlEncodeCharset($charset), chr($i) ) ); 191 } 192 my $text = join( '', @test ) . "."; 193 194 $this->TML2HTML_test( $charset, $text, $text ); 195 } 196 197 sub TML2HTML_testUnicodeCodepointsRange { 198 my ( $this, $charset, $firstchar, $lastchar ) = @_; 118 199 119 200 my @test; … … 122 203 } 123 204 my $text = join( '', @test ) . "."; 205 206 $this->TML2HTML_test( $charset, $text, $text ); 207 } 208 209 # $input and $expectedOutput contain unicode codepoints; 210 # they are wide characters, NOT utf-8 encoded 211 sub TML2HTML_test { 212 my ( $this, $charset, $input, $expectedOutput ) = @_; 213 214 # Is this enough? Regexes are inited before we get here, aren't they? 215 $Foswiki::cfg{Site}{CharSet} = $charset; 216 124 217 my $query = new Unit::Request( 125 218 { … … 127 220 128 221 # REST parameters are always UTF8 encoded 129 'text' => [ Encode::encode_utf8($ text) ],222 'text' => [ Encode::encode_utf8($input) ], 130 223 } 131 224 ); … … 133 226 134 227 my $foswiki = new Foswiki( 'guest', $query ); 135 $foswiki->{response}->charset($charset) if $charset; 228 $foswiki->{response}->charset($charset) 229 if $charset; # why? REST responses are supposed to be UTF-8 encoded 136 230 137 231 my ( $out, $result ) = $this->captureWithKey( … … 155 249 156 250 my $id = "<!--$Foswiki::Plugins::WysiwygPlugin::Handlers::SECRET_ID-->"; 157 $this->assert( $out =~ s/^\s*$id<p>\s*//s, anal($out) ); 158 $out =~ s/\s*<\/p>\s*$//s; 159 160 require Foswiki::Plugins::WysiwygPlugin::Constants; 161 Foswiki::Plugins::WysiwygPlugin::Constants::mapUnicode2HighBit($out); 162 163 $this->assert( $text eq $out, 164 "'" . anal($out) . "' !=\n'" . anal($text) . "'" ); 251 $this->assert( $out =~ s/^\s*$id<p>[ \t\n]*//s, anal($out) ); 252 $out =~ s/[ \t\n]*<\/p>\s*$//s; 253 254 $this->assert( $expectedOutput eq $out, 255 "'" . anal($out) . "' !=\n'" . anal($expectedOutput) . "'" ); 165 256 $foswiki->finish(); 166 257 } 167 258 168 sub HTML2TML_test {259 sub HTML2TML_testCharsetCodesRange { 169 260 my ( $this, $charset, $firstchar, $lastchar ) = @_; 170 171 # Is this enough? Regexes are inited before we get here, aren't they? 172 $Foswiki::cfg{Site}{CharSet} = $charset; 261 my @test; 262 for ( my $i = $firstchar ; $i <= $lastchar ; $i++ ) { 263 push( @test, Encode::decode( _perlEncodeCharset($charset), chr($i) ) ); 264 } 265 my $text = join( '', @test ) . "."; 266 267 $this->HTML2TML_test( $charset, $text, $text ); 268 } 269 270 sub HTML2TML_testUnicodeCodepointsRange { 271 my ( $this, $charset, $firstchar, $lastchar ) = @_; 173 272 174 273 my @test; … … 177 276 } 178 277 my $text = join( '', @test ) . "."; 278 279 $this->HTML2TML_test( $charset, $text, $text ); 280 } 281 282 # $input and $expectedOutput contain unicode codepoints; 283 # they are wide characters, NOT utf-8 encoded 284 sub HTML2TML_test { 285 my ( $this, $charset, $input, $expectedOutput ) = @_; 286 287 # Is this enough? Regexes are inited before we get here, aren't they? 288 $Foswiki::cfg{Site}{CharSet} = $charset; 289 179 290 my $query = new Unit::Request( 180 291 { … … 182 293 183 294 # REST parameters are always UTF8 encoded 184 'text' => [ Encode::encode_utf8($ text) ],295 'text' => [ Encode::encode_utf8($input) ], 185 296 } 186 297 ); 187 298 $query->method('GET'); 188 299 my $foswiki = new Foswiki( 'guest', $query ); 189 $foswiki->{response}->charset($charset) if $charset; 300 $foswiki->{response}->charset($charset) 301 if $charset; # why? REST responses are supposed to be UTF-8 encoded 190 302 191 303 my ( $out, $result ) = $this->captureWithKey( … … 208 320 $out = Encode::decode_utf8($out); 209 321 210 require Foswiki::Plugins::WysiwygPlugin::Constants;211 Foswiki::Plugins::WysiwygPlugin::Constants::mapUnicode2HighBit($out);212 213 322 $out =~ s/\s*$//s; 214 323 215 $this->assert_str_equals( $ text, $out,216 "'" . anal($out) . "' !=\n'" . anal($ text) . "'" );324 $this->assert_str_equals( $expectedOutput, $out, 325 "'" . anal($out) . "' !=\n'" . anal($expectedOutput) . "'" ); 217 326 $foswiki->finish(); 218 327 } … … 221 330 sub test_restTML2HTML_undef { 222 331 my $this = shift; 223 $this->TML2HTML_test( undef, 127, 255 ); 332 $this->TML2HTML_testUnicodeCodepointsRange( undef, 160, 255 ); 333 334 # Browsers commonly treat iso-8859-1 as if it is windows-1252 335 # and so does Foswiki 336 my $unicodeOfWindows1252 = 337 join( '', map { chr($_) } @unicodeCodepointsForWindows1252 ); 338 339 $this->TML2HTML_test( undef, $unicodeOfWindows1252, $unicodeOfWindows1252 ); 340 341 $this->TML2HTML_test( undef, chr(0x3B1) . chr(0x2640), 'α♀' ); 224 342 } 225 343 226 344 sub test_restTML2HTML_iso_8859_1 { 227 345 my $this = shift; 228 $this->TML2HTML_test( 'iso-8859-1', 127, 255 ); 346 $this->TML2HTML_testUnicodeCodepointsRange( 'iso-8859-1', 160, 255 ); 347 348 # Browsers commonly treat iso-8859-1 as if it is windows-1252 349 # and so does Foswiki 350 my $unicodeOfWindows1252 = 351 join( '', map { chr($_) } @unicodeCodepointsForWindows1252 ); 352 353 $this->TML2HTML_test( 'iso-8859-1', $unicodeOfWindows1252, 354 $unicodeOfWindows1252 ); 355 356 $this->TML2HTML_test( 'iso-8859-1', chr(0x3B1) . chr(0x2640), 357 'α♀' ); 358 } 359 360 sub test_restTML2HTML_iso_8859_7 { 361 my $this = shift; 362 363 $this->TML2HTML_testCharsetCodesRange( 'iso-8859-7', 160, 173 ); 364 $this->TML2HTML_testCharsetCodesRange( 'iso-8859-7', 175, 209 ); 365 $this->TML2HTML_testCharsetCodesRange( 'iso-8859-7', 211, 254 ); 229 366 } 230 367 231 368 sub test_restTML2HTML_iso_8859_15 { 232 369 my $this = shift; 233 $this->TML2HTML_test( 'iso-8859-15', 127, 163 ); 234 $this->TML2HTML_test( 'iso-8859-15', 169, 179 ); 235 $this->TML2HTML_test( 'iso-8859-15', 181, 183 ); 236 $this->TML2HTML_test( 'iso-8859-15', 191, 255 ); 370 $this->TML2HTML_testUnicodeCodepointsRange( 'iso-8859-15', 127, 163 ); 371 $this->TML2HTML_testUnicodeCodepointsRange( 'iso-8859-15', 169, 179 ); 372 $this->TML2HTML_testUnicodeCodepointsRange( 'iso-8859-15', 181, 183 ); 373 $this->TML2HTML_testUnicodeCodepointsRange( 'iso-8859-15', 191, 255 ); 374 375 # These are the codes that are different to iso-8859-1, and thus 376 # different to unicode 377 for my $code ( 0xA4, 0xA6, 0xA8, 0xB4, 0xBC, 0xBD, 0xBE ) { 378 $this->TML2HTML_testCharsetCodesRange( 'iso-8859-15', $code, $code ); 379 } 237 380 } 238 381 239 382 sub test_restTML2HTML_utf_8 { 240 383 my $this = shift; 241 $this->TML2HTML_test ( 'utf-8', 127, 300 );242 $this->TML2HTML_test ( 'utf-8', 301, 400 );243 $this->TML2HTML_test ( 'utf-8', 401, 500 );384 $this->TML2HTML_testUnicodeCodepointsRange( 'utf-8', 127, 300 ); 385 $this->TML2HTML_testUnicodeCodepointsRange( 'utf-8', 301, 400 ); 386 $this->TML2HTML_testUnicodeCodepointsRange( 'utf-8', 401, 500 ); 244 387 245 388 # Chinese 246 $this->TML2HTML_test ( 'utf-8', 8000, 9000 );389 $this->TML2HTML_testUnicodeCodepointsRange( 'utf-8', 8000, 9000 ); 247 390 } 248 391 249 392 sub test_restHTML2TML_undef { 250 393 my $this = shift; 251 $this->HTML2TML_test( undef, 127, 255 ); 394 $this->HTML2TML_testUnicodeCodepointsRange( undef, 160, 255 ); 395 396 # Browsers commonly treat iso-8859-1 as if it is windows-1252 397 # and so does Foswiki 398 my $unicodeOfWindows1252 = 399 join( '', map { chr($_) } @unicodeCodepointsForWindows1252 ); 400 401 $this->HTML2TML_test( undef, $unicodeOfWindows1252, $unicodeOfWindows1252 ); 252 402 } 253 403 254 404 sub test_restHTML2TML_iso_8859_1 { 255 405 my $this = shift; 256 $this->HTML2TML_test( 'iso-8859-1', 127, 255 ); 406 $this->HTML2TML_testUnicodeCodepointsRange( 'iso-8859-1', 160, 255 ); 407 408 # Browsers commonly treat iso-8859-1 as if it is windows-1252 409 # and so does Foswiki 410 my $unicodeOfWindows1252 = 411 join( '', map { chr($_) } @unicodeCodepointsForWindows1252 ); 412 413 $this->HTML2TML_test( 'iso-8859-1', $unicodeOfWindows1252, 414 $unicodeOfWindows1252 ); 415 } 416 417 sub test_restHTML2TML_iso_8859_7 { 418 my $this = shift; 419 420 $this->HTML2TML_testCharsetCodesRange( 'iso-8859-7', 160, 173 ); 421 $this->HTML2TML_testCharsetCodesRange( 'iso-8859-7', 175, 209 ); 422 $this->HTML2TML_testCharsetCodesRange( 'iso-8859-7', 211, 254 ); 257 423 } 258 424 259 425 sub test_restHTML2TML_iso_8859_15 { 260 426 my $this = shift; 261 $this->HTML2TML_test( 'iso-8859-15', 127, 163 ); 262 $this->HTML2TML_test( 'iso-8859-15', 169, 179 ); 263 $this->HTML2TML_test( 'iso-8859-15', 181, 183 ); 264 $this->HTML2TML_test( 'iso-8859-15', 191, 255 ); 427 $this->HTML2TML_testUnicodeCodepointsRange( 'iso-8859-15', 127, 163 ); 428 $this->HTML2TML_testUnicodeCodepointsRange( 'iso-8859-15', 169, 179 ); 429 $this->HTML2TML_testUnicodeCodepointsRange( 'iso-8859-15', 181, 183 ); 430 $this->HTML2TML_testUnicodeCodepointsRange( 'iso-8859-15', 191, 255 ); 431 432 # These are the codes that are different to iso-8859-1, and thus 433 # different to unicode 434 for my $code ( 0xA4, 0xA6, 0xA8, 0xB4, 0xBC, 0xBD, 0xBE ) { 435 $this->HTML2TML_testCharsetCodesRange( 'iso-8859-15', $code, $code ); 436 } 265 437 } 266 438 267 439 sub test_restHTML2TML_utf_8 { 268 440 my $this = shift; 269 $this->HTML2TML_test ( 'utf-8', 127, 300 );270 $this->HTML2TML_test ( 'utf-8', 301, 400 );271 $this->HTML2TML_test ( 'utf-8', 401, 500 );441 $this->HTML2TML_testUnicodeCodepointsRange( 'utf-8', 127, 300 ); 442 $this->HTML2TML_testUnicodeCodepointsRange( 'utf-8', 301, 400 ); 443 $this->HTML2TML_testUnicodeCodepointsRange( 'utf-8', 401, 500 ); 272 444 273 445 # Chinese 274 $this->HTML2TML_test ( 'utf-8', 8000, 9000 );446 $this->HTML2TML_testUnicodeCodepointsRange( 'utf-8', 8000, 9000 ); 275 447 } 276 448 277 449 sub test_save_undef { 278 450 my $this = shift; 279 $this->save_test( undef, 127, 255 ); 451 $this->save_testUnicodeCodepointsRange( undef, 127, 128 ); 452 $this->save_testUnicodeCodepointsRange( undef, 130, 140 ); 453 $this->save_testUnicodeCodepointsRange( undef, 142, 142 ); 454 $this->save_testUnicodeCodepointsRange( undef, 145, 156 ); 455 $this->save_testUnicodeCodepointsRange( undef, 158, 255 ); 280 456 } 281 457 282 458 sub test_save_iso_8859_1 { 283 459 my $this = shift; 284 $this->save_test( 'iso-8859-1', 127, 255 ); 460 $this->save_testUnicodeCodepointsRange( 'iso-8859-1', 160, 255 ); 461 462 # Browsers commonly treat iso-8859-1 as if it is windows-1252 463 # and so does Foswiki 464 my $unicodeOfWindows1252 = 465 join( '', map { chr($_) } @unicodeCodepointsForWindows1252 ); 466 467 $this->save_test( 'iso-8859-1', $unicodeOfWindows1252, 468 $unicodeOfWindows1252 ); 469 } 470 471 sub test_save_iso_8859_7 { 472 my $this = shift; 473 474 $this->save_testCharsetCodesRange( 'iso-8859-7', 160, 173 ); 475 $this->save_testCharsetCodesRange( 'iso-8859-7', 175, 209 ); 476 $this->save_testCharsetCodesRange( 'iso-8859-7', 211, 254 ); 285 477 } 286 478 287 479 sub test_save_iso_8859_15 { 288 480 my $this = shift; 289 $this->save_test( 'iso-8859-15', 127, 163 ); 290 $this->save_test( 'iso-8859-15', 169, 179 ); 291 $this->save_test( 'iso-8859-15', 181, 183 ); 292 $this->save_test( 'iso-8859-15', 191, 255 ); 481 $this->save_testUnicodeCodepointsRange( 'iso-8859-15', 127, 163 ); 482 $this->save_testUnicodeCodepointsRange( 'iso-8859-15', 169, 179 ); 483 $this->save_testUnicodeCodepointsRange( 'iso-8859-15', 181, 183 ); 484 $this->save_testUnicodeCodepointsRange( 'iso-8859-15', 191, 255 ); 485 486 # These are the codes that are different to iso-8859-1, and thus 487 # different to unicode 488 for my $code ( 0xA4, 0xA6, 0xA8, 0xB4, 0xBC, 0xBD, 0xBE ) { 489 $this->save_testCharsetCodesRange( 'iso-8859-15', $code, $code ); 490 } 293 491 } 294 492 295 493 sub test_save_utf_8a { 296 494 my $this = shift; 297 $this->save_test ( 'utf-8', 127, 300 );495 $this->save_testUnicodeCodepointsRange( 'utf-8', 127, 300 ); 298 496 } 299 497 300 498 sub test_save_utf_8b { 301 499 my $this = shift; 302 $this->save_test ( 'utf-8', 301, 400 );500 $this->save_testUnicodeCodepointsRange( 'utf-8', 301, 400 ); 303 501 } 304 502 305 503 sub test_save_utf_8d { 306 504 my $this = shift; 307 $this->save_test ( 'utf-8', 401, 500 );505 $this->save_testUnicodeCodepointsRange( 'utf-8', 401, 500 ); 308 506 } 309 507 … … 312 510 313 511 # Chinese 314 $this->save_test ( 'utf-8', 8000, 9000 );512 $this->save_testUnicodeCodepointsRange( 'utf-8', 8000, 9000 ); 315 513 } 316 514
Note: See TracChangeset
for help on using the changeset viewer.
