/* * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.google.gwt.emultest.java.lang; import com.google.gwt.core.client.JavaScriptException; import com.google.gwt.junit.client.GWTTestCase; import com.google.gwt.testing.TestUtils; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.Locale; /** * TODO: COMPILER OPTIMIZATIONS HAVE MADE THIS TEST NOT ACTUALLY TEST ANYTHING! * NEED A VERSION THAT DOESN'T USE STATICALLY DETERMINABLE STRINGS! * * See individual method TODOs for ones that still need work -- the ones without * comments are already protected against optimization. */ public class StringTest extends GWTTestCase { @Override public String getModuleName() { return "com.google.gwt.emultest.EmulSuite"; } public void testCharAt() { assertEquals(hideFromCompiler("abc").charAt(1), 'b'); } public void testCodePoint() { String testPlain = hideFromCompiler("CAT"); String testUnicode = hideFromCompiler("C\uD801\uDF00T"); assertEquals("CAT", new String(new int[] {'C', 'A', 'T'}, 0, 3)); assertEquals("C\uD801\uDF00T", new String(new int[] {'C', 67328, 'T'}, 0, 3)); assertEquals("\uD801\uDF00", new String(new int[] {'C', 67328, 'T'}, 1, 1)); assertEquals(65, testPlain.codePointAt(1)); assertEquals("codePointAt fails on surrogate pair", 67328, testUnicode.codePointAt(1)); assertEquals(65, testPlain.codePointBefore(2)); assertEquals("codePointBefore fails on surrogate pair", 67328, testUnicode.codePointBefore(3)); assertEquals("codePointCount(plain): ", 3, testPlain.codePointCount(0, 3)); assertEquals("codePointCount(unicode): ", 3, testUnicode.codePointCount(0, 4)); assertEquals(1, testPlain.codePointCount(1, 2)); assertEquals(1, testUnicode.codePointCount(1, 2)); assertEquals(2, testUnicode.codePointCount(2, 4)); assertEquals(1, testUnicode.offsetByCodePoints(0, 1)); assertEquals("offsetByCodePoints(1,1): ", 3, testUnicode.offsetByCodePoints(1, 1)); assertEquals("offsetByCodePoints(2,1): ", 3, testUnicode.offsetByCodePoints(2, 1)); assertEquals(4, testUnicode.offsetByCodePoints(3, 1)); assertEquals(1, testUnicode.offsetByCodePoints(2, -1)); assertEquals(1, testUnicode.offsetByCodePoints(3, -1)); assertEquals("offsetByCodePoints(4.-1): ", 3, testUnicode.offsetByCodePoints(4, -1)); assertEquals(0, testUnicode.offsetByCodePoints(3, -2)); /* * The next line contains a Unicode character outside the base multilingual * plane -- it may not show properly depending on your fonts, etc. The * character is the Gothic letter Faihu, or U+10346. We use it to verify * that multi-char UTF16 characters are handled properly. * * In Windows 2000, registry changes are required to support non-BMP * characters (or surrogates in general) -- surrogates are not supported * before Win2k and they are enabled by default in WinXP and later. * * [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows * NT\CurrentVersion\LanguagePack] SURROGATE=(REG_DWORD)0x00000002 * * [HKEY_CURRENT_USER\Software\Microsoft\Internet * Explorer\International\Scripts\42] IEFixedFontName=[Surrogate Font Face * Name] IEPropFontName=[Surrogate Font Face Name] */ String nonBmpChar = hideFromCompiler("𐍆"); assertEquals("\uD800\uDF46", nonBmpChar); assertEquals(0x10346, nonBmpChar.codePointAt(0)); assertEquals(2, nonBmpChar.length()); assertEquals(1, nonBmpChar.codePointCount(0, 2)); } public void testCompareTo() { assertEquals(0, hideFromCompiler("a").compareTo("a")); assertEquals(-1, hideFromCompiler("a").compareTo("b")); assertEquals(1, hideFromCompiler("b").compareTo("a")); try { returnNull().compareTo(""); fail(); } catch (NullPointerException e) { // expected } catch (JavaScriptException e) { // expected } try { returnNull().compareTo(returnNull()); fail(); } catch (NullPointerException e) { // expected } catch (JavaScriptException e) { // expected } } @SuppressWarnings("ReturnValueIgnored") public void testConcat() { String abc = String.valueOf(new char[] {'a', 'b', 'c'}); String def = String.valueOf(new char[] {'d', 'e', 'f'}); String empty = String.valueOf(new char[] {}); assertEquals("abcdef", abc + def); assertEquals("abcdef", abc.concat(def)); assertEquals("", empty.concat(empty)); char c = def.charAt(0); String s = abc; assertEquals("abcd", abc + 'd'); assertEquals("abcd", abc + c); assertEquals("abcd", s + 'd'); assertEquals("abcd", s + c); s += c; assertEquals("abcd", s); try { returnNull().concat(""); fail(); } catch (NullPointerException e) { // expected } catch (JavaScriptException e) { // expected } try { hideFromCompiler("").concat(returnNull()); fail(); } catch (NullPointerException e) { // expected } catch (JavaScriptException e) { // expected } } public void testConstructor() { char[] chars = {'a', 'b', 'c', 'd', 'e', 'f'}; String constant = String.valueOf(new char[] {'a', 'b', 'c', 'd', 'e', 'f'}); String shortString = String.valueOf(new char[] {'c', 'd', 'e'}); assertEquals(constant, new String(hideFromCompiler(constant))); assertEquals(constant, new String(chars), constant); assertEquals(shortString, new String(chars, 2, 3), shortString); assertEquals("", new String(hideFromCompiler(""))); assertEquals("", new String(new String(new String(new String( hideFromCompiler("")))))); assertEquals("", new String(new char[] {})); StringBuffer buf = new StringBuffer(); buf.append('c'); buf.append('a'); buf.append('t'); assertEquals("cat", new String(buf)); StringBuilder sb = new StringBuilder(); sb.append('c'); sb.append('a'); sb.append('t'); assertEquals("cat", new String(sb)); sb = new StringBuilder(); sb.appendCodePoint(0x21); assertEquals("\u0021", new String(sb)); sb = new StringBuilder(); sb.appendCodePoint(0x10400); assertEquals("\uD801\uDC00", new String(sb)); try { new String(returnNull()); } catch (NullPointerException e) { // expected } catch (JavaScriptException e) { // expected } try { new String(hideFromCompiler((StringBuilder) null)); } catch (NullPointerException e) { // expected } catch (JavaScriptException e) { // expected } } public void testConstructorBytes() { byte bytes[] = new byte[] { 'a', 'b', 'c', 'd', 'e', 'f' }; String str = new String(bytes); assertEquals("abcdef", str); str = new String(bytes, 1, 3); assertEquals("bcd", str); try { new String(bytes, 1, 6); assertTrue("Should have thrown IOOB in Development Mode", !TestUtils.isJvm()); } catch (IndexOutOfBoundsException expected) { } try { new String(bytes, -1, 2); assertTrue("Should have thrown IOOB in Development Mode", !TestUtils.isJvm()); } catch (IndexOutOfBoundsException expected) { } try { new String(bytes, 6, 2); assertTrue("Should have thrown IOOB in Development Mode", !TestUtils.isJvm()); } catch (IndexOutOfBoundsException expected) { } } public void testConstructorLatin1() throws UnsupportedEncodingException { internalTestConstructorLatin1("ISO-8859-1"); internalTestConstructorLatin1("iso-8859-1"); } private void internalTestConstructorLatin1(String encoding) throws UnsupportedEncodingException { byte bytes[] = new byte[] { (byte) 0xE0, (byte) 0xDF, (byte) 0xE7, (byte) 0xD0, (byte) 0xE9, 'f' }; String str = new String(bytes, encoding); assertEquals("àßçÐéf", str); str = new String(bytes, 1, 3, encoding); assertEquals("ßçÐ", str); try { new String(bytes, 1, 6, encoding); assertTrue("Should have thrown IOOB in Development Mode", !TestUtils.isJvm()); } catch (IndexOutOfBoundsException expected) { } try { new String(bytes, -1, 2, encoding); assertTrue("Should have thrown IOOB in Development Mode", !TestUtils.isJvm()); } catch (IndexOutOfBoundsException expected) { } try { new String(bytes, 6, 2, encoding); assertTrue("Should have thrown IOOB in Development Mode", !TestUtils.isJvm()); } catch (IndexOutOfBoundsException expected) { } try { new String(bytes, 1, 6, Charset.forName(encoding)); assertTrue("Should have thrown IOOB in Development Mode", !TestUtils.isJvm()); } catch (IndexOutOfBoundsException expected) { } try { new String(bytes, -1, 2, Charset.forName(encoding)); assertTrue("Should have thrown IOOB in Development Mode", !TestUtils.isJvm()); } catch (IndexOutOfBoundsException expected) { } try { new String(bytes, 6, 2, Charset.forName(encoding)); assertTrue("Should have thrown IOOB in Development Mode", !TestUtils.isJvm()); } catch (IndexOutOfBoundsException expected) { } } public void testConstructorUtf8() throws UnsupportedEncodingException { internalTestConstructorUtf8("UTF-8"); internalTestConstructorUtf8("utf-8"); } private void internalTestConstructorUtf8(String encoding) throws UnsupportedEncodingException { byte bytes[] = new byte[] { (byte) 0xC3, (byte) 0xA0, (byte) 0xC3, (byte) 0x9F, (byte) 0xC3, (byte) 0xA7, (byte) 0xC3, (byte) 0x90, (byte) 0xC3, (byte) 0xA9, 'f' }; String str = new String(bytes, encoding); assertEquals("àßçÐéf", str); str = new String(bytes, 2, 6, encoding); assertEquals("ßçÐ", str); try { new String(bytes, 2, 12, encoding); assertTrue("Should have thrown IOOB in Development Mode", !TestUtils.isJvm()); } catch (IndexOutOfBoundsException expected) { } try { new String(bytes, -1, 2, encoding); assertTrue("Should have thrown IOOB in Development Mode", !TestUtils.isJvm()); } catch (IndexOutOfBoundsException expected) { } try { new String(bytes, 12, 2, encoding); assertTrue("Should have thrown IOOB in Development Mode", !TestUtils.isJvm()); } catch (IndexOutOfBoundsException expected) { } try { new String(bytes, 2, 12, Charset.forName(encoding)); assertTrue("Should have thrown IOOB in Development Mode", !TestUtils.isJvm()); } catch (IndexOutOfBoundsException expected) { } try { new String(bytes, -1, 2, Charset.forName(encoding)); assertTrue("Should have thrown IOOB in Development Mode", !TestUtils.isJvm()); } catch (IndexOutOfBoundsException expected) { } try { new String(bytes, 12, 2, Charset.forName(encoding)); assertTrue("Should have thrown IOOB in Development Mode", !TestUtils.isJvm()); } catch (IndexOutOfBoundsException expected) { } } public void testContains() { // at the beginning assertTrue(hideFromCompiler("abcdef").contains("ab")); assertTrue(hideFromCompiler("abcdef").contains(new StringBuffer("ab"))); // at the end assertTrue(hideFromCompiler("abcdef").contains("ef")); assertTrue(hideFromCompiler("abcdef").contains(new StringBuffer("ef"))); // in the middle assertTrue(hideFromCompiler("abcdef").contains("cd")); assertTrue(hideFromCompiler("abcdef").contains(new StringBuffer("cd"))); // the same assertTrue(hideFromCompiler("abcdef").contains("abcdef")); assertTrue(hideFromCompiler("abcdef").contains(new StringBuffer("abcdef"))); // not present assertFalse(hideFromCompiler("abcdef").contains("z")); assertFalse(hideFromCompiler("abcdef").contains(new StringBuffer("z"))); } public void testEndsWith() { String haystack = "abcdefghi"; assertTrue("a", haystack.endsWith("defghi")); assertTrue("b", haystack.endsWith(haystack)); assertFalse("c", haystack.endsWith(haystack + "j")); } public void testEquals() { assertFalse(hideFromCompiler("ABC").equals("abc")); assertFalse(hideFromCompiler("abc").equals("ABC")); assertTrue(hideFromCompiler("abc").equals("abc")); assertTrue(hideFromCompiler("ABC").equals("ABC")); assertFalse(hideFromCompiler("AbC").equals("aBC")); assertFalse(hideFromCompiler("AbC").equals("aBC")); assertTrue(hideFromCompiler("").equals("")); assertFalse(hideFromCompiler("").equals(null)); try { returnNull().equals("other"); fail(); } catch (NullPointerException e) { // expected } catch (JavaScriptException e) { // expected } try { returnNull().equals(returnNull()); fail(); } catch (NullPointerException e) { // expected } catch (JavaScriptException e) { // expected } } public void testEqualsIgnoreCase() { assertTrue(hideFromCompiler("ABC").equalsIgnoreCase("abc")); assertTrue(hideFromCompiler("abc").equalsIgnoreCase("ABC")); assertTrue(hideFromCompiler("abc").equalsIgnoreCase("abc")); assertTrue(hideFromCompiler("ABC").equalsIgnoreCase("ABC")); assertTrue(hideFromCompiler("AbC").equalsIgnoreCase("aBC")); assertTrue(hideFromCompiler("AbC").equalsIgnoreCase("aBC")); assertTrue(hideFromCompiler("").equalsIgnoreCase("")); assertFalse(hideFromCompiler("").equalsIgnoreCase(null)); try { returnNull().equalsIgnoreCase("other"); fail(); } catch (NullPointerException e) { // expected } catch (JavaScriptException e) { // expected } try { returnNull().equalsIgnoreCase(returnNull()); fail(); } catch (NullPointerException e) { // expected } catch (JavaScriptException e) { // expected } } public void testGetBytesAscii() { // Simple ASCII should get through any standard encoding (EBCDIC users, // you're out of luck). String str = "This is a simple ASCII string"; byte[] bytes = str.getBytes(); assertEquals(str.length(), bytes.length); for (int i = 0; i < str.length(); ++i) { assertEquals((byte) str.charAt(i), bytes[i]); } } public void testGetBytesLatin1() throws UnsupportedEncodingException { internalTestGetBytesLatin1("ISO-8859-1"); internalTestGetBytesLatin1("iso-8859-1"); } private void internalTestGetBytesLatin1(String encoding) throws UnsupportedEncodingException { // Contains only ISO-Latin-1 characters. String str = "Îñtérñåtîöñålîzåtîöñ"; byte[] bytes = str.getBytes(encoding); assertEquals(str.length(), bytes.length); for (int i = 0; i < str.length(); ++i) { assertEquals("latin1 byte " + i + " differs", (byte) str.charAt(i), bytes[i]); } } public void testGetBytesUtf8() throws UnsupportedEncodingException { internalTestGetBytesUtf8("UTF-8"); internalTestGetBytesUtf8("utf-8"); } private void internalTestGetBytesUtf8(String encoding) throws UnsupportedEncodingException { // Test a range of characters getting encoded to UTF8 in 1-2 bytes. char[] chars = new char[384]; for (int i = 0; i < chars.length; ++i) { chars[i] = (char) i; } String str = String.copyValueOf(chars); byte[] bytes = str.getBytes(encoding); assertEquals(640, bytes.length); for (int i = 0; i < 128; ++i) { assertEquals("Position " + i, i, bytes[i]); } for (int i = 128; i < chars.length; ++i) { byte first = bytes[2 * i - 128]; byte second = bytes[2 * i - 127]; char ch = str.charAt(i); assertEquals("byte " + i + " differs", ch, ((first & 31) << 6) | (second & 63)); } // non-BMP characters, all take 4 UTF8 bytes. int firstCodePoint = 0x100000; int numChars = chars.length / 2; for (int i = 0; i < numChars; ++i) { Character.toChars(firstCodePoint + i, chars, 2 * i); } str = String.copyValueOf(chars); bytes = str.getBytes(encoding); assertEquals(4 * numChars, bytes.length); for (int i = 0; i < numChars; ++i) { assertEquals("1st byte of " + i, (byte) 0xF4, bytes[4 * i]); assertEquals("2nd byte of " + i, (byte) 0x80, bytes[4 * i + 1]); assertEquals("3rd byte of " + i, (byte) 0x80 + ((i >> 6) & 63), bytes[4 * i + 2]); assertEquals("4th byte of " + i, (byte) 0x80 + (i & 63), bytes[4 * i + 3]); } } /** * Tests hashing with strings. * * The specific strings used in this test used to trigger failures because we * use a JavaScript object as a hash map to cache the computed hash codes. * This conflicts with built-in properties defined on objects -- see issue * #631. * */ public void testHashCode() { String[] testStrings = { "watch", "unwatch", "toString", "toSource", "eval", "valueOf", "constructor", "__proto__", "polygenelubricants", "xy", "x", "" }; int[] javaHashes = { 112903375, -274141738, -1776922004, -1781441930, 3125404, 231605032, -1588406278, 2139739112, Integer.MIN_VALUE, 3841, 120, 0 }; for (int i = 0; i < testStrings.length; ++i) { String testString = testStrings[i]; int expectedHash = javaHashes[i]; // verify that the hash codes of these strings match their java // counterparts assertEquals("Unexpected hash for string " + testString, expectedHash, testString.hashCode()); /* * Verify that the resulting hash code is numeric, since this is not * enforced in Production Mode. */ String str = Integer.toString(expectedHash); for (int j = 0; j < str.length(); ++j) { char ch = str.charAt(j); assertTrue("Bad character '" + ch + "' (U+0" + Integer.toHexString(ch) + ")", ch == '-' || ch == ' ' || Character.isDigit(ch)); } // get hashes again to verify the values are constant for a given string assertEquals(expectedHash, testStrings[i].hashCode()); } try { returnNull().hashCode(); fail(); } catch (NullPointerException e) { // expected } catch (JavaScriptException e) { // expected } } public void testIndexOf() { String haystack = "abcdefghi"; assertEquals(haystack.indexOf("q"), -1); assertEquals(haystack.indexOf('q'), -1); assertEquals(haystack.indexOf("a"), 0); assertEquals(haystack.indexOf('a'), 0); assertEquals(haystack.indexOf('a', 1), -1); assertEquals(haystack.indexOf("bc"), 1); assertEquals(haystack.indexOf(""), 0); try { returnNull().indexOf(""); fail(); } catch (NullPointerException e) { // expected } catch (JavaScriptException e) { // expected } } @SuppressWarnings("ReturnValueIgnored") public void testIntern() { String s1 = String.valueOf(new char[] {'a', 'b', 'c', 'd', 'e', 'f'}); String s2 = String.valueOf(new char[] {'a', 'b', 'c', 'd', 'e', 'f'}); assertTrue("strings not equal", s1.equals(s2)); assertSame("interns are not the same reference", s1.intern(), s2.intern()); try { returnNull().intern(); fail(); } catch (NullPointerException e) { // expected } catch (JavaScriptException e) { // expected } } public void testLastIndexOf() { String x = "abcdeabcdef"; assertEquals(9, x.lastIndexOf("e")); assertEquals(10, x.lastIndexOf("f")); assertEquals(-1, x.lastIndexOf("f", 1)); } public void testLength() { String abc = String.valueOf(new char[] {'a', 'b', 'c'}); assertEquals(3, abc.length()); String str = "x"; for (int i = 0; i < 16; i++) { str = str + str; } assertEquals(1 << 16, str.length()); String cat = String.valueOf(new char[] {'C', '\uD801', '\uDF00', 'T'}); assertEquals(4, cat.length()); } public void testLowerCase() { assertEquals("abc", hideFromCompiler("AbC").toLowerCase()); assertEquals("abc", hideFromCompiler("abc").toLowerCase()); assertEquals("", hideFromCompiler("").toLowerCase()); assertEquals("abc", hideFromCompiler("AbC").toLowerCase(Locale.US)); assertEquals("abc", hideFromCompiler("abc").toLowerCase(Locale.US)); assertEquals("", hideFromCompiler("").toLowerCase(Locale.US)); assertEquals("abc", hideFromCompiler("AbC").toLowerCase(Locale.getDefault())); assertEquals("abc", hideFromCompiler("abc").toLowerCase(Locale.getDefault())); assertEquals("", hideFromCompiler("").toLowerCase(Locale.getDefault())); } public void testMatch() { assertFalse("1f", hideFromCompiler("abbbbcd").matches("b*")); assertFalse("2f", hideFromCompiler("abbbbcd").matches("b+")); assertTrue("3t", hideFromCompiler("abbbbcd").matches("ab*bcd")); assertTrue("4t", hideFromCompiler("abbbbcd").matches("ab+cd")); assertTrue("5t", hideFromCompiler("abbbbcd").matches("ab+bcd")); assertFalse("6f", hideFromCompiler("abbbbcd").matches("")); assertTrue("7t", hideFromCompiler("abbbbcd").matches("a.*d")); assertFalse("8f", hideFromCompiler("abbbbcd").matches("a.*e")); // issue #7736 assertTrue("9t.1", hideFromCompiler("").matches("(|none)")); assertTrue("9t.2", hideFromCompiler("none").matches("(|none)")); assertFalse("9f.1", hideFromCompiler("ab").matches("(|none)")); assertFalse("9f.2", hideFromCompiler("anoneb").matches("(|none)")); assertTrue("10t", hideFromCompiler("none").matches("^(|none)$")); assertFalse("10f", hideFromCompiler("abbbbcd").matches("^b*$")); assertTrue("11t.1", hideFromCompiler("").matches("|none")); assertTrue("11t.2", hideFromCompiler("none").matches("|none")); assertFalse("11f.1", hideFromCompiler("ab").matches("|none")); assertFalse("11f.2", hideFromCompiler("anoneb").matches("|none")); assertTrue("12t", hideFromCompiler("none").matches("^|none$")); } public void testNull() { { assertNull(returnNull()); String a = returnNull() + returnNull(); assertEquals("nullnull", a); String s = returnNull(); s += returnNull(); assertEquals("nullnull", s); } // Same tests allowing the compiler to propagate constants. { String a = null + (String) null; assertEquals("nullnull", a); String s = null; s += null; assertEquals("nullnull", s); } } public void testRegionMatches() { String test = String.valueOf(new char[] {'a', 'b', 'c', 'd', 'e', 'f'}); assertTrue(test.regionMatches(1, "bcd", 0, 3)); assertTrue(test.regionMatches(1, "bcdx", 0, 3)); assertFalse(test.regionMatches(1, "bcdx", 0, 4)); assertFalse(test.regionMatches(1, "bcdx", 1, 3)); assertTrue(test.regionMatches(true, 0, "XAbCd", 1, 4)); assertTrue(test.regionMatches(true, 1, "BcD", 0, 3)); assertTrue(test.regionMatches(true, 1, "bCdx", 0, 3)); assertFalse(test.regionMatches(true, 1, "bCdx", 0, 4)); assertFalse(test.regionMatches(true, 1, "bCdx", 1, 3)); assertTrue(test.regionMatches(true, 0, "xaBcd", 1, 4)); test = test.toUpperCase(Locale.ROOT); assertTrue(test.regionMatches(true, 0, "XAbCd", 1, 4)); assertTrue(test.regionMatches(true, 1, "BcD", 0, 3)); assertTrue(test.regionMatches(true, 1, "bCdx", 0, 3)); assertFalse(test.regionMatches(true, 1, "bCdx", 0, 4)); assertFalse(test.regionMatches(true, 1, "bCdx", 1, 3)); assertTrue(test.regionMatches(true, 0, "xaBcd", 1, 4)); try { test.regionMatches(-1, null, -1, -1); fail(); } catch (NullPointerException expected) { // NPE must be thrown before any range checks } try { test.regionMatches(true, -1, null, -1, -1); fail(); } catch (NullPointerException expected) { // NPE must be thrown before any range checks } } public void testReplace() { String axax = String.valueOf(new char[] {'a', 'x', 'a', 'x'}); String aaaa = String.valueOf(new char[] {'a', 'a', 'a', 'a'}); assertEquals("aaaa", axax.replace('x', 'a')); assertEquals("aaaa", aaaa.replace('x', 'a')); for (char from = 32; from < 250; ++from) { char to = (char) (from + 5); assertEquals(toS(to), toS(from).replace(from, to)); } for (char to = 32; to < 250; ++to) { char from = (char) (to + 5); assertEquals(toS(to), toS(from).replace(from, to)); } // issue 1480 String exampleXd = String.valueOf(new char[] { 'e', 'x', 'a', 'm', 'p', 'l', 'e', ' ', 'x', 'd'}); assertEquals("example xd", exampleXd.replace('\r', ' ').replace('\n', ' ')); String dogFood = String.valueOf(new char[] { 'd', 'o', 'g', '\u0120', 'f', 'o', 'o', 'd'}); assertEquals("dog food", dogFood.replace('\u0120', ' ')); String testStr = String.valueOf(new char[] { '\u1111', 'B', '\u1111', 'B', '\u1111', 'B'}); assertEquals("ABABAB", testStr.replace('\u1111', 'A')); } public void testReplaceAll() { String regex = hideFromCompiler("*[").replaceAll( "([/\\\\\\.\\*\\+\\?\\|\\(\\)\\[\\]\\{\\}])", "\\\\$1"); assertEquals("\\*\\[", regex); String replacement = hideFromCompiler("\\").replaceAll("\\\\", "\\\\\\\\").replaceAll( "\\$", "\\\\$"); assertEquals("\\\\", replacement); assertEquals("+1", hideFromCompiler("*[1").replaceAll(regex, "+")); String x1 = String.valueOf(new char[] { 'x', 'x', 'x', 'a', 'b', 'c', 'x', 'x', 'd', 'e', 'x', 'f'}); assertEquals("abcdef", x1.replaceAll("x*", "")); String x2 = String.valueOf(new char[] { '1', 'a', 'b', 'c', '1', '2', '3', 'd', 'e', '1', '2', '3', '4', 'f'}); assertEquals("1\\1abc123\\123de1234\\1234f", x2.replaceAll("([1234]+)", "$1\\\\$1")); String x3 = String.valueOf(new char[] {'x', ' ', ' ', 'x'}); assertEquals("\n \n", x3.replaceAll("x", "\n")); String x4 = String.valueOf(new char[] {'\n', ' ', ' ', '\n'}); assertEquals("x x", x4.replaceAll("\\\n", "x")); String x5 = String.valueOf(new char[] {'x'}); assertEquals("x\"\\", x5.replaceAll("x", "\\x\\\"\\\\")); assertEquals("$$x$", x5.replaceAll("(x)", "\\$\\$$1\\$")); } public void testReplaceString() { assertEquals("foobar", hideFromCompiler("bazbar").replace("baz", "foo")); assertEquals("$0bar", hideFromCompiler("foobar").replace("foo", "$0")); assertEquals("$1bar", hideFromCompiler("foobar").replace("foo", "$1")); assertEquals("\\$1bar", hideFromCompiler("foobar").replace("foo", "\\$1")); assertEquals("\\1", hideFromCompiler("*[)1").replace("*[)", "\\")); // issue 2363 assertEquals("cb", hideFromCompiler("$ab").replace("$a", "c")); assertEquals("cb", hideFromCompiler("^ab").replace("^a", "c")); // test JS replacement characters assertEquals("a$$b", hideFromCompiler("a[x]b").replace("[x]", "$$")); assertEquals("a$1b", hideFromCompiler("a[x]b").replace("[x]", "$1")); assertEquals("a$`b", hideFromCompiler("a[x]b").replace("[x]", "$`")); assertEquals("a$'b", hideFromCompiler("a[x]b").replace("[x]", "$'")); } public void testSplit() { compareList("fullSplit", new String[] {"abc", "", "", "de", "f"}, hideFromCompiler("abcxxxdexfxx").split("x")); String booAndFoo = hideFromCompiler("boo:and:foo"); compareList("2:", new String[] {"boo", "and:foo"}, booAndFoo.split(":", 2)); compareList("5:", new String[] {"boo", "and", "foo"}, booAndFoo.split(":", 5)); compareList("-2:", new String[] {"boo", "and", "foo"}, booAndFoo.split(":", -2)); compareList("5o", new String[] {"b", "", ":and:f", "", ""}, booAndFoo.split("o", 5)); compareList("-2o", new String[] {"b", "", ":and:f", "", ""}, booAndFoo.split("o", -2)); compareList("0o", new String[] {"b", "", ":and:f"}, booAndFoo.split("o", 0)); compareList("0:", new String[] {"boo", "and", "foo"}, booAndFoo.split(":", 0)); // issue 2742 compareList("issue2742", new String[] {}, hideFromCompiler("/").split("/", 0)); // Splitting an empty string should result in an array containing a single // empty string. String[] s = "".split(","); assertTrue(s != null); assertTrue(s.length == 1); assertTrue(s[0] != null); assertTrue(s[0].length() == 0); } public void testSplit_emptyExpr() { // TODO(rluble): implement JDK8 string.split semantics and fix test. String[] expected = (TestUtils.getJdkVersion() > 7) ? new String[] {"a", "b", "c", "x", "x", "d", "e", "x", "f", "x"} : new String[] {"", "a", "b", "c", "x", "x", "d", "e", "x", "f", "x"}; compareList("emptyRegexSplit", expected, "abcxxdexfx".split("")); } public void testStartsWith() { String haystack = "abcdefghi"; assertTrue(haystack.startsWith("abc")); assertTrue(haystack.startsWith("bc", 1)); assertTrue(haystack.startsWith(haystack)); assertFalse(haystack.startsWith(haystack + "j")); } public void testSubstring() { assertEquals("cd", hideFromCompiler("abcdefghi").substring(2, 4)); assertEquals("bc", hideFromCompiler("abcdef").substring(1, 3)); assertEquals("bcdef", hideFromCompiler("abcdef").substring(1)); } public void testToCharArray() { char[] a1 = "abc".toCharArray(); char[] a2 = new char[] {'a', 'b', 'c'}; for (int i = 0; i < a1.length; i++) { assertEquals(a1[i], a2[i]); } } public void testToString() { String str = hideFromCompiler("abc"); assertSame("str same as str.toString()", str, str.toString()); // that one is mostly to debug how the code gets compiled to JS. assertEquals("concat with str.toString()", "0abcd", "0" + str.toString() + "d"); // issue 4301 Object s = hideFromCompiler("abc"); assertSame("s same as s.toString()", s, s.toString()); } /* * TODO: needs rewriting to avoid compiler optimizations. */ public void testTrim() { trimRightAssertEquals("abc", " \t abc \n "); trimRightAssertEquals("abc", "abc"); trimRightAssertSame("abc", "abc"); String s = '\u0023' + "hi"; trimRightAssertSame(s, s); trimRightAssertEquals("abc", " abc"); trimRightAssertEquals("abc", "abc "); trimRightAssertEquals("", ""); trimRightAssertEquals("", " \t "); // Check for removal of nulls; trim treats nulls as if they are whitespace. // See issue 8534. trimRightAssertEquals("abc", "\0\0\0 abc"); trimRightAssertEquals("abc", "abc\0\0\0"); trimRightAssertEquals("abc", "abc \0\0\0"); trimRightAssertEquals("abc", " \0 \0 \0" + "abc"); trimRightAssertEquals("abc \0 a", " abc \0 a"); trimRightAssertEquals("abc \0 a", " abc \0 a \0"); trimRightAssertEquals("abc \0 a", " abc \0 a \0 "); trimRightAssertEquals("\u0021\u0020abc", "\u0019\u0017\u0021\u0020abc\u0019\u0017\u0018 "); trimRightAssertEquals("\u0021 abc", "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009" + "\n" + "\u000b\u000c" + "\r" + "\u000e\u000f" + "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019" + "\u001A\u001b\u001c\u001d\u001e\u001f\u0020\u0021 " + "abc"); // JavaScript would trim \u2029 and other unicode whitespace type characters; but Java wont trimRightAssertEquals("\u2029abc\u00a0","\u2029abc\u00a0"); } public void testUpperCase() { assertEquals("ABC", hideFromCompiler("AbC").toUpperCase()); assertEquals("ABC", hideFromCompiler("abc").toUpperCase()); assertEquals("", hideFromCompiler("").toUpperCase()); assertEquals("ABC", hideFromCompiler("AbC").toUpperCase(Locale.US)); assertEquals("ABC", hideFromCompiler("abc").toUpperCase(Locale.US)); assertEquals("", hideFromCompiler("").toUpperCase(Locale.US)); assertEquals("ABC", hideFromCompiler("AbC").toUpperCase(Locale.getDefault())); assertEquals("ABC", hideFromCompiler("abc").toUpperCase(Locale.getDefault())); assertEquals("", hideFromCompiler("").toUpperCase(Locale.getDefault())); } /* * TODO: needs rewriting to avoid compiler optimizations. */ public void testValueOf() { assertTrue(String.valueOf(C.FLOAT_VALUE).startsWith(C.FLOAT_STRING)); assertEquals(C.INT_STRING, String.valueOf(C.INT_VALUE)); assertEquals(C.LONG_STRING, String.valueOf(C.LONG_VALUE)); assertTrue(String.valueOf(C.DOUBLE_VALUE).startsWith(C.DOUBLE_STRING)); assertEquals(C.CHAR_STRING, String.valueOf(C.CHAR_VALUE)); assertEquals(C.CHAR_ARRAY_STRING, String.valueOf(C.CHAR_ARRAY_VALUE)); assertEquals( C.CHAR_ARRAY_STRING_SUB, String.valueOf(C.CHAR_ARRAY_VALUE, 1, 4)); assertEquals(C.FALSE_STRING, String.valueOf(C.FALSE_VALUE)); assertEquals(C.TRUE_STRING, String.valueOf(C.TRUE_VALUE)); assertEquals(C.getLargeCharArrayString(), String.valueOf(C.getLargeCharArrayValue())); } /** * Helper method for testTrim to avoid compiler optimizations. * * TODO: insufficient, compiler now inlines. */ public void trimRightAssertEquals(String left, String right) { assertEquals(left, right.trim()); } /** * Helper method for testTrim to avoid compiler optimizations. * * TODO: insufficient, compiler now inlines. */ public void trimRightAssertSame(String left, String right) { assertSame(left, right.trim()); } private void compareList(String category, String[] desired, String[] got) { assertEquals(category + " length", desired.length, got.length); for (int i = 0; i < desired.length; i++) { assertEquals(category + " " + i, desired[i], got[i]); } } private <T> T hideFromCompiler(T value) { if (Math.random() < -1) { // Can never happen, but fools the compiler enough not to optimize this call. fail(); } return value; } private String returnNull() { return hideFromCompiler(null); } private String toS(char from) { return Character.toString(from); } }