package org.luaj.vm2; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import junit.framework.TestCase; import org.luaj.vm2.lib.jse.JsePlatform; public class StringTest extends TestCase { protected void setUp() throws Exception { JsePlatform.standardGlobals(); } public void testToInputStream() throws IOException { LuaString str = LuaString.valueOf("Hello"); InputStream is = str.toInputStream(); assertEquals( 'H', is.read() ); assertEquals( 'e', is.read() ); assertEquals( 2, is.skip( 2 ) ); assertEquals( 'o', is.read() ); assertEquals( -1, is.read() ); assertTrue( is.markSupported() ); is.reset(); assertEquals( 'H', is.read() ); is.mark( 4 ); assertEquals( 'e', is.read() ); is.reset(); assertEquals( 'e', is.read() ); LuaString substr = str.substring( 1, 4 ); assertEquals( 3, substr.length() ); is.close(); is = substr.toInputStream(); assertEquals( 'e', is.read() ); assertEquals( 'l', is.read() ); assertEquals( 'l', is.read() ); assertEquals( -1, is.read() ); is = substr.toInputStream(); is.reset(); assertEquals( 'e', is.read() ); } private static final String userFriendly( String s ) { StringBuffer sb = new StringBuffer(); for ( int i=0, n=s.length(); i= 0x80 ) { sb.append( "\\u"+Integer.toHexString(0x10000+c).substring(1) ); } else { sb.append( (char) c ); } } return sb.toString(); } public void testUtf820482051() throws UnsupportedEncodingException { int i = 2048; char[] c = { (char) (i+0), (char) (i+1), (char) (i+2), (char) (i+3) }; String before = new String(c)+" "+i+"-"+(i+4); LuaString ls = LuaString.valueOf(before); String after = ls.tojstring(); assertEquals( userFriendly( before ), userFriendly( after ) ); } public void testUtf8() { for ( int i=4; i<0xffff; i+=4 ) { char[] c = { (char) (i+0), (char) (i+1), (char) (i+2), (char) (i+3) }; String before = new String(c)+" "+i+"-"+(i+4); LuaString ls = LuaString.valueOf(before); String after = ls.tojstring(); assertEquals( userFriendly( before ), userFriendly( after ) ); } char[] c = { (char) (1), (char) (2), (char) (3) }; String before = new String(c)+" 1-3"; LuaString ls = LuaString.valueOf(before); String after = ls.tojstring(); assertEquals( userFriendly( before ), userFriendly( after ) ); } public void testSpotCheckUtf8() throws UnsupportedEncodingException { byte[] bytes = {(byte)194,(byte)160,(byte)194,(byte)161,(byte)194,(byte)162,(byte)194,(byte)163,(byte)194,(byte)164}; String expected = new String(bytes, "UTF8"); String actual = LuaString.valueOf(bytes).tojstring(); char[] d = actual.toCharArray(); assertEquals(160, d[0]); assertEquals(161, d[1]); assertEquals(162, d[2]); assertEquals(163, d[3]); assertEquals(164, d[4]); assertEquals(expected, actual); } public void testNullTerminated() { char[] c = { 'a', 'b', 'c', '\0', 'd', 'e', 'f' }; String before = new String(c); LuaString ls = LuaString.valueOf(before); String after = ls.tojstring(); assertEquals( userFriendly( "abc\0def" ), userFriendly( after ) ); } public void testRecentStringsCacheDifferentHashcodes() { final byte[] abc = {'a', 'b', 'c' }; final byte[] xyz = {'x', 'y', 'z' }; final LuaString abc1 = LuaString.valueOf(abc); final LuaString xyz1 = LuaString.valueOf(xyz); final LuaString abc2 = LuaString.valueOf(abc); final LuaString xyz2 = LuaString.valueOf(xyz); final int mod = LuaString.RECENT_STRINGS_CACHE_SIZE; assertTrue(abc1.hashCode() % mod != xyz1.hashCode() % mod); assertSame(abc1, abc2); assertSame(xyz1, xyz2); } public void testRecentStringsCacheHashCollisionCacheHit() { final byte[] abc = {'a', 'b', 'c' }; final byte[] lyz = {'l', 'y', 'z' }; // chosen to have hash collision with 'abc' final LuaString abc1 = LuaString.valueOf(abc); final LuaString abc2 = LuaString.valueOf(abc); // in cache: 'abc' final LuaString lyz1 = LuaString.valueOf(lyz); final LuaString lyz2 = LuaString.valueOf(lyz); // in cache: 'lyz' final int mod = LuaString.RECENT_STRINGS_CACHE_SIZE; assertEquals(abc1.hashCode() % mod, lyz1.hashCode() % mod); assertNotSame(abc1, lyz1); assertFalse(abc1.equals(lyz1)); assertSame(abc1, abc2); assertSame(lyz1, lyz2); } public void testRecentStringsCacheHashCollisionCacheMiss() { final byte[] abc = {'a', 'b', 'c' }; final byte[] lyz = {'l', 'y', 'z' }; // chosen to have hash collision with 'abc' final LuaString abc1 = LuaString.valueOf(abc); final LuaString lyz1 = LuaString.valueOf(lyz); // in cache: 'abc' final LuaString abc2 = LuaString.valueOf(abc); // in cache: 'lyz' final LuaString lyz2 = LuaString.valueOf(lyz); // in cache: 'abc' final int mod = LuaString.RECENT_STRINGS_CACHE_SIZE; assertEquals(abc1.hashCode() % mod, lyz1.hashCode() % mod); assertNotSame(abc1, lyz1); assertFalse(abc1.equals(lyz1)); assertNotSame(abc1, abc2); assertNotSame(lyz1, lyz2); } public void testRecentStringsLongStrings() { byte[] abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".getBytes(); assertTrue(abc.length > LuaString.RECENT_STRINGS_MAX_LENGTH); LuaString abc1 = LuaString.valueOf(abc); LuaString abc2 = LuaString.valueOf(abc); assertNotSame(abc1, abc2); } public void testRecentStringsUsingJavaStrings() { final String abc = "abc"; final String lyz = "lyz"; // chosen to have hash collision with 'abc' final String xyz = "xyz"; final LuaString abc1 = LuaString.valueOf(abc); final LuaString abc2 = LuaString.valueOf(abc); final LuaString lyz1 = LuaString.valueOf(lyz); final LuaString lyz2 = LuaString.valueOf(lyz); final LuaString xyz1 = LuaString.valueOf(xyz); final LuaString xyz2 = LuaString.valueOf(xyz); final int mod = LuaString.RECENT_STRINGS_CACHE_SIZE; assertEquals(abc1.hashCode() % mod, lyz1.hashCode() % mod); assertFalse(abc1.hashCode() % mod == xyz1.hashCode() % mod); assertSame(abc1, abc2); assertSame(lyz1, lyz2); assertSame(xyz1, xyz2); final LuaString abc3 = LuaString.valueOf(abc); final LuaString lyz3 = LuaString.valueOf(lyz); final LuaString xyz3 = LuaString.valueOf(xyz); final LuaString abc4 = LuaString.valueOf(abc); final LuaString lyz4 = LuaString.valueOf(lyz); final LuaString xyz4 = LuaString.valueOf(xyz); assertNotSame(abc3, abc4); // because of hash collision assertNotSame(lyz3, lyz4); // because of hash collision assertSame(xyz3, xyz4); // because hashes do not collide } public void testLongSubstringGetsOldBacking() { LuaString src = LuaString.valueOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); LuaString sub1 = src.substring(10, 40); assertSame(src.m_bytes, sub1.m_bytes); assertEquals(sub1.m_offset, 10); assertEquals(sub1.m_length, 30); } public void testShortSubstringGetsNewBacking() { LuaString src = LuaString.valueOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); LuaString sub1 = src.substring(10, 20); LuaString sub2 = src.substring(10, 20); assertEquals(sub1.m_offset, 0); assertEquals(sub1.m_length, 10); assertSame(sub1, sub2); assertFalse(src.m_bytes == sub1.m_bytes); } public void testShortSubstringOfVeryLongStringGetsNewBacking() { LuaString src = LuaString.valueOf( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ); LuaString sub1 = src.substring(10, 50); LuaString sub2 = src.substring(10, 50); assertEquals(sub1.m_offset, 0); assertEquals(sub1.m_length, 40); assertFalse(sub1 == sub2); assertFalse(src.m_bytes == sub1.m_bytes); } public void testIndexOfByteInSubstring() { LuaString str = LuaString.valueOf("abcdef:ghi"); LuaString sub = str.substring(2, 10); assertEquals(10, str.m_length); assertEquals(8, sub.m_length); assertEquals(0, str.m_offset); assertEquals(2, sub.m_offset); assertEquals(6, str.indexOf((byte) ':', 0)); assertEquals(6, str.indexOf((byte) ':', 2)); assertEquals(6, str.indexOf((byte) ':', 6)); assertEquals(-1, str.indexOf((byte) ':', 7)); assertEquals(-1, str.indexOf((byte) ':', 9)); assertEquals(9, str.indexOf((byte) 'i', 0)); assertEquals(9, str.indexOf((byte) 'i', 2)); assertEquals(9, str.indexOf((byte) 'i', 9)); assertEquals(-1, str.indexOf((byte) 'z', 0)); assertEquals(-1, str.indexOf((byte) 'z', 2)); assertEquals(-1, str.indexOf((byte) 'z', 9)); assertEquals(4, sub.indexOf((byte) ':', 0)); assertEquals(4, sub.indexOf((byte) ':', 2)); assertEquals(4, sub.indexOf((byte) ':', 4)); assertEquals(-1, sub.indexOf((byte) ':', 5)); assertEquals(-1, sub.indexOf((byte) ':', 7)); assertEquals(7, sub.indexOf((byte) 'i', 0)); assertEquals(7, sub.indexOf((byte) 'i', 2)); assertEquals(7, sub.indexOf((byte) 'i', 7)); assertEquals(-1, sub.indexOf((byte) 'z', 0)); assertEquals(-1, sub.indexOf((byte) 'z', 2)); assertEquals(-1, sub.indexOf((byte) 'z', 7)); } public void testIndexOfPatternInSubstring() { LuaString str = LuaString.valueOf("abcdef:ghi"); LuaString sub = str.substring(2, 10); assertEquals(10, str.m_length); assertEquals(8, sub.m_length); assertEquals(0, str.m_offset); assertEquals(2, sub.m_offset); LuaString pat = LuaString.valueOf(":"); LuaString i = LuaString.valueOf("i"); LuaString xyz = LuaString.valueOf("xyz"); assertEquals(6, str.indexOf(pat, 0)); assertEquals(6, str.indexOf(pat, 2)); assertEquals(6, str.indexOf(pat, 6)); assertEquals(-1, str.indexOf(pat, 7)); assertEquals(-1, str.indexOf(pat, 9)); assertEquals(9, str.indexOf(i, 0)); assertEquals(9, str.indexOf(i, 2)); assertEquals(9, str.indexOf(i, 9)); assertEquals(-1, str.indexOf(xyz, 0)); assertEquals(-1, str.indexOf(xyz, 2)); assertEquals(-1, str.indexOf(xyz, 9)); assertEquals(4, sub.indexOf(pat, 0)); assertEquals(4, sub.indexOf(pat, 2)); assertEquals(4, sub.indexOf(pat, 4)); assertEquals(-1, sub.indexOf(pat, 5)); assertEquals(-1, sub.indexOf(pat, 7)); assertEquals(7, sub.indexOf(i, 0)); assertEquals(7, sub.indexOf(i, 2)); assertEquals(7, sub.indexOf(i, 7)); assertEquals(-1, sub.indexOf(xyz, 0)); assertEquals(-1, sub.indexOf(xyz, 2)); assertEquals(-1, sub.indexOf(xyz, 7)); } public void testLastIndexOfPatternInSubstring() { LuaString str = LuaString.valueOf("abcdef:ghi"); LuaString sub = str.substring(2, 10); assertEquals(10, str.m_length); assertEquals(8, sub.m_length); assertEquals(0, str.m_offset); assertEquals(2, sub.m_offset); LuaString pat = LuaString.valueOf(":"); LuaString i = LuaString.valueOf("i"); LuaString xyz = LuaString.valueOf("xyz"); assertEquals(6, str.lastIndexOf(pat)); assertEquals(9, str.lastIndexOf(i)); assertEquals(-1, str.lastIndexOf(xyz)); assertEquals(4, sub.lastIndexOf(pat)); assertEquals(7, sub.lastIndexOf(i)); assertEquals(-1, sub.lastIndexOf(xyz)); } public void testIndexOfAnyInSubstring() { LuaString str = LuaString.valueOf("abcdef:ghi"); LuaString sub = str.substring(2, 10); assertEquals(10, str.m_length); assertEquals(8, sub.m_length); assertEquals(0, str.m_offset); assertEquals(2, sub.m_offset); LuaString ghi = LuaString.valueOf("ghi"); LuaString ihg = LuaString.valueOf("ihg"); LuaString ijk = LuaString.valueOf("ijk"); LuaString kji= LuaString.valueOf("kji"); LuaString xyz = LuaString.valueOf("xyz"); LuaString ABCdEFGHIJKL = LuaString.valueOf("ABCdEFGHIJKL"); LuaString EFGHIJKL = ABCdEFGHIJKL.substring(4, 12); LuaString CdEFGHIJ = ABCdEFGHIJKL.substring(2, 10); assertEquals(4, EFGHIJKL.m_offset); assertEquals(2, CdEFGHIJ.m_offset); assertEquals(7, str.indexOfAny(ghi)); assertEquals(7, str.indexOfAny(ihg)); assertEquals(9, str.indexOfAny(ijk)); assertEquals(9, str.indexOfAny(kji)); assertEquals(-1, str.indexOfAny(xyz)); assertEquals(3, str.indexOfAny(CdEFGHIJ)); assertEquals(-1, str.indexOfAny(EFGHIJKL)); assertEquals(5, sub.indexOfAny(ghi)); assertEquals(5, sub.indexOfAny(ihg)); assertEquals(7, sub.indexOfAny(ijk)); assertEquals(7, sub.indexOfAny(kji)); assertEquals(-1, sub.indexOfAny(xyz)); assertEquals(1, sub.indexOfAny(CdEFGHIJ)); assertEquals(-1, sub.indexOfAny(EFGHIJKL)); } public void testMatchShortPatterns() { LuaValue[] args = { LuaString.valueOf("%bxy") }; LuaString _ = LuaString.valueOf(""); LuaString a = LuaString.valueOf("a"); LuaString ax = LuaString.valueOf("ax"); LuaString axb = LuaString.valueOf("axb"); LuaString axby = LuaString.valueOf("axby"); LuaString xbya = LuaString.valueOf("xbya"); LuaString bya = LuaString.valueOf("bya"); LuaString xby = LuaString.valueOf("xby"); LuaString axbya = LuaString.valueOf("axbya"); LuaValue nil = LuaValue.NIL; assertEquals(nil, _.invokemethod("match", args)); assertEquals(nil, a.invokemethod("match", args)); assertEquals(nil, ax.invokemethod("match", args)); assertEquals(nil, axb.invokemethod("match", args)); assertEquals(xby, axby.invokemethod("match", args)); assertEquals(xby, xbya.invokemethod("match", args)); assertEquals(nil, bya.invokemethod("match", args)); assertEquals(xby, xby.invokemethod("match", args)); assertEquals(xby, axbya.invokemethod("match", args)); assertEquals(xby, axbya.substring(0,4).invokemethod("match", args)); assertEquals(nil, axbya.substring(0,3).invokemethod("match", args)); assertEquals(xby, axbya.substring(1,5).invokemethod("match", args)); assertEquals(nil, axbya.substring(2,5).invokemethod("match", args)); } }