Jelajahi Sumber

tests (80)

FIX: StringUtils#compile - error handling, escape of "
FIX: StringUtils#commonSuffix
Ranides Atterwim 10 tahun lalu
induk
melakukan
53c437d3d7

+ 49 - 40
assira/src/main/java/net/ranides/assira/text/StringUtils.java

@@ -42,6 +42,7 @@ public final class StringUtils {
     private static final char[] C_ESC_SEQ	= new char[]{'\033','['};
 	private static final char[] C_ESC		= new char[]{'\033'};
 	private static final char[] C_SLASH		= new char[]{'\\'};
+	private static final char[] C_QUOTE		= new char[]{'"'};
 	private static final char[] C_BKSPACE	= new char[]{'\b'};
 	private static final char[] C_FORM		= new char[]{'\f'};
 	private static final char[] C_TAB		= new char[]{'\t'};
@@ -221,47 +222,55 @@ public final class StringUtils {
     
     private static void processEsc(CharStreamer<CharsType> stream) {
         if( stream.end() ) {
-            stream.close();
-            return;
+            throw new IllegalArgumentException("unclosed escape sequence");
         } 
         
         char code = stream.get();
-        
-        if('n'==code) {
-            stream.flush();
-            stream.send(CharsType.STR, C_NL);
-        } 
-        else if('r'==code) {
-            stream.flush();
-            stream.send(CharsType.STR, C_CR);
-        } 
-        else if('t'==code) {
-            stream.flush();
-            stream.send(CharsType.STR, C_TAB);
-        } 
-        else if('f'==code) {
-            stream.flush();
-            stream.send(CharsType.STR, C_FORM);
-        } 
-        else if('b'==code) {
-            stream.flush();
-            stream.send(CharsType.STR, C_BKSPACE);
-        } 
-        else if('\\'==code) {
-            stream.flush();
-            stream.send(CharsType.STR, C_SLASH);
-        } 
-        else if('e'==code) {
-            stream.flush();
-            stream.send(CharsType.STR, C_ESC);
-        } 
-        else if('^'==code) {
-            stream.flush();
-            stream.send(CharsType.STR, C_ESC_SEQ);
+        switch(code) {
+            case 'n':
+                stream.flush();
+                stream.send(CharsType.STR, C_NL);
+                break;
+            case 'r':
+                stream.flush();
+                stream.send(CharsType.STR, C_CR);
+                break;
+            case 't':
+                stream.flush();
+                stream.send(CharsType.STR, C_TAB);
+                break;
+            case 'f':
+                stream.flush();
+                stream.send(CharsType.STR, C_FORM);
+                break;
+            case 'b':
+                stream.flush();
+                stream.send(CharsType.STR, C_BKSPACE);
+                break;
+            case '\\':
+                stream.flush();
+                stream.send(CharsType.STR, C_SLASH);
+                break;
+            case '"':
+                stream.flush();
+                stream.send(CharsType.STR, C_QUOTE);
+                break;
+            case 'e':
+                stream.flush();
+                stream.send(CharsType.STR, C_ESC);
+                break;
+            case '^':
+                stream.flush();
+                stream.send(CharsType.STR, C_ESC_SEQ);
+                break;
+            default:
+                if(Character.isDigit(code)) {
+                    processOct(stream);
+                } else {
+                    throw new IllegalArgumentException("unknown escape sequence: '\\" + code+"'");
+                }
+                break;
         } 
-        else if(Character.isDigit(code)) {
-            processOct(stream);
-        }    
     }
 	
     
@@ -642,10 +651,10 @@ public final class StringUtils {
 		int as = a.length();
 		int bs = b.length();
         int n = Math.min(as, bs);
-        for(int i=0; i<n; i++) {
-            if( a.charAt(as-i)!=b.charAt(bs-i) ) { return a.substring(as-i,i); }
+        for(int i=1; i<=n; i++) {
+            if( a.charAt(as-i)!=b.charAt(bs-i) ) { return a.substring(as-(i-1), as); }
         }
-        return a.substring(as-n,n);
+        return a.substring(as-n, as);
     }
 	
 	public static String commonSuffix(Collection<String> values) {

+ 65 - 2
assira/src/test/java/net/ranides/assira/text/StringUtilsBenchmark.java

@@ -15,10 +15,17 @@ import net.ranides.assira.junit.BenchmarkRunner;
 /**
  * Benchmark for StringUtils.
  * 
- *  CC: CBuilder + count    = 100
+ * uncamelize
  *  2C: CBuilder            =  61
- *  RE: regex               = 870
+ *  CC: CBuilder + count    = 100
  *  2B: StringBuilder       = 103
+ *  RE: regex               = 870
+ * 
+ * replace
+ *    : assira              = 29
+ *  AC: Apache Commons      = 37
+ *  RE: String.replace      = 95
+ *  
  * 
  * StringBuilder is slower because it checks (on every append) if reallocation is needed
  * 
@@ -92,6 +99,39 @@ public class StringUtilsBenchmark extends SimpleBenchmark {
         return ret;
     }
     
+    public int timeReplace(int reps) {
+        String[] array = text(100, 100);
+        int ret = 0;
+        for(int i=0; i<reps; i++) {
+            for(String s : array) {
+                ret += StringUtils.replace(s, 'a', "abc").charAt(99);
+            }
+        }
+        return ret;
+    }
+    
+    public int timeReplaceRE(int reps) {
+        String[] array = text(100, 100);
+        int ret = 0;
+        for(int i=0; i<reps; i++) {
+            for(String s : array) {
+                ret += s.replace(String.valueOf('a'), "abc").charAt(99);
+            }
+        }
+        return ret;
+    }
+    
+    public int timeReplaceAC(int reps) {
+        String[] array = text(100, 100);
+        int ret = 0;
+        for(int i=0; i<reps; i++) {
+            for(String s : array) {
+                ret += replaceApache(s, String.valueOf('a'), "abc").charAt(99);
+            }
+        }
+        return ret;
+    }
+    
     // count + CBuilder
     static String uncamelizeCC(String value) {
         int u = countUpper(value);
@@ -235,6 +275,29 @@ public class StringUtilsBenchmark extends SimpleBenchmark {
         }
         return r;
     }
+    
+    static String replaceApache(String text, String searchString, String replacement) {
+        if (text.isEmpty() || searchString.isEmpty()) {
+            return text;
+        }
+        int start = 0;
+        int end = text.indexOf(searchString, start);
+        if (end == -1) {
+            return text;
+        }
+        int replLength = searchString.length();
+        int increase = replacement.length() - replLength;
+        increase = increase < 0 ? 0 : increase;
+        increase *= 16;
+        StringBuilder buf = new StringBuilder(text.length() + increase);
+        while (end != -1) {
+            buf.append(text.substring(start, end)).append(replacement);
+            start = end + replLength;
+            end = text.indexOf(searchString, start);
+        }
+        buf.append(text.substring(start));
+        return buf.toString();
+    }
 
     public static void main(String[] args) {
         BenchmarkRunner.run(StringUtilsBenchmark.class);

+ 361 - 5
assira/src/test/java/net/ranides/assira/text/StringUtilsTest.java

@@ -6,11 +6,13 @@
  */
 package net.ranides.assira.text;
 
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
 import java.util.Arrays;
 import java.util.regex.Pattern;
-import net.ranides.assira.collection.lists.NativeArrayList;
+import static net.ranides.assira.junit.NewAssert.*;
 import org.junit.Test;
-import static org.junit.Assert.*;
 
 /**
  *
@@ -28,18 +30,48 @@ public class StringUtilsTest {
 		assertEquals("\"abc\"", StringUtils.quote("abc"));
 		assertEquals("\"\\\"abc\\\"\"", StringUtils.quote("\"abc\""));
 		assertEquals("\"a\\\"bc\"", StringUtils.quote("a\"bc"));
+        
+        assertEquals( "\"a\\\"bc c:\\\\v\"", StringUtils.quote("a\"bc c:\\v") );
+        assertEquals( "\"a\\\"bc c:\\\\vdata\b \"", StringUtils.quote("a\"bc c:\\vdata\b ") );
+        assertEquals( "\"a\\\"bc c:\\\\vdata\\\\\b \"", StringUtils.quote("a\"bc c:\\vdata\\\b ") );
 	}
 	
 	@Test
 	public void testUnquote() {
 		assertEquals("", StringUtils.unquote(""));
-		assertEquals("", StringUtils.unquote("\"\""));
-		
+        assertEquals("a", StringUtils.unquote("a") );
 		assertEquals("abc", StringUtils.unquote("abc"));
+        
+        assertEquals("", StringUtils.unquote("\"\""));
+        assertEquals("a", StringUtils.unquote("\"a\"") );
 		assertEquals("abc", StringUtils.unquote("\"abc\""));
+        
 		assertEquals("\"abc\"", StringUtils.unquote("\"\\\"abc\\\"\""));
 		assertEquals("a\"bc", StringUtils.unquote("\"a\\\"bc\""));
 		assertEquals("a\\\"bc", StringUtils.unquote("a\\\"bc"));
+        
+        
+        assertEquals("abc \\hello",     StringUtils.unquote("\"abc \\hello\"") );
+        assertEquals("abc \\hello",     StringUtils.unquote("\"abc \\\\hello\"") );
+        assertEquals("abc \"hello",     StringUtils.unquote("\"abc \\\\\"hello\"") );
+        assertEquals("abc \\ \"hello",  StringUtils.unquote("\"abc \\\\ \"hello\"") );
+        assertEquals("abc \\ \"hello",  StringUtils.unquote("\"abc \\\\ \\\"hello\"") );
+        assertEquals("abc \\\"hello",   StringUtils.unquote("\"abc \\\\\\\"hello\"") );
+        
+        // invalid, ale niech będzie test takiej sytuacji. 
+        // nie-escape'owane " po prostu zostawiamy
+        assertEquals("abc \\\"\"hello",   StringUtils.unquote("\"abc \\\\\\\"\"hello\"") );
+        assertEquals("abc \\\"\"he\"llo",   StringUtils.unquote("\"abc \\\\\\\"\"he\"llo\"") );
+        
+        assertThrows(IllegalArgumentException.class, ()->{
+            StringUtils.unquote("\"");
+        });
+        assertThrows(IllegalArgumentException.class, ()->{
+            StringUtils.unquote("abc\"");
+        });
+        assertThrows(IllegalArgumentException.class, ()->{
+            StringUtils.unquote("\"abc");
+        });
 	}
 	
 	@Test
@@ -52,11 +84,38 @@ public class StringUtilsTest {
 		assertEquals(Arrays.asList("a", "bc", "d"), StringUtils.split("a   bc   d  "));
 		
 		assertEquals(Arrays.asList("a", "bc q", "d"), StringUtils.split("a   \"bc q\"   d  "));
+		assertEquals(Arrays.asList("a", "bc \" q", "d"), StringUtils.split("a   \"bc \\\" q\"   d  "));
 	}
 	
 	@Test
 	public void testCompile() {
-		assertEquals("Hello \\ ' \" \r \n \t \b \f \033 \033[ \066 world", StringUtils.compile("Hello \\\\ ' \" \\r \\n \\t \\b \\f \\e \\^ \\066 world"));
+        // kody \r \t \f \n \b
+        assertEquals("\r \t \f \n \b", StringUtils.compile("\\r \\t \\f \\n \\b"));
+        
+        // kod \\
+        assertEquals("c:\\win32\\new\n", StringUtils.compile("c:\\\\win32\\\\new\\n"));
+        
+        // kody dodatkowe \e \^
+        assertEquals("escape \033 \033[ seqence", StringUtils.compile("escape \\e \\^ seqence"));
+        
+        // poprawne sekwencje OCT
+        assertEquals("N\077A\042C", StringUtils.compile("N\\077A\\042C"));
+        
+        // sprawdzenie niepoprawnych sekwencji OCT
+        assertEquals("N\23T\779", StringUtils.compile("N\\23T\\779"));
+        
+        // cudzysłów
+        assertEquals("hello \" world", StringUtils.compile("hello \\\" world"));
+        
+        assertThrows(IllegalArgumentException.class, ()->{
+            StringUtils.compile("hello \\\" world\\");
+        });
+        assertThrows(IllegalArgumentException.class, ()->{
+            StringUtils.compile("hello \\ world");
+        });
+        assertThrows(IllegalArgumentException.class, ()->{
+            StringUtils.compile("hello \\z world");
+        });
 	}
 	
 	@Test
@@ -146,6 +205,7 @@ public class StringUtilsTest {
 	@Test
 	public void testReplaceChar() {
         assertEquals("", StringUtils.replace("", '#', '$'));
+        assertEquals("", StringUtils.replace("", '#', "$"));
         
 		assertEquals("A=$1 B=$2 C=$3", StringUtils.replace("A=#1 B=#2 C=#3", '#', '$'));
 		
@@ -231,11 +291,24 @@ public class StringUtilsTest {
     @Test
     public void testEncodeURL() {
         assertEquals("hello%3Aworld%3Fparam%3D5", StringUtils.encodeURL("hello:world?param=5"));
+        
+        assertEquals("hello%3Aworld%3Fparam%3D5", StringUtils.encodeURL("hello:world?param=5", new FCharset("UTF-8")));
+        
+        assertThrows(AssertionError.class, ()->{
+            StringUtils.encodeURL("hello:world?param=5", new FCharset("UFC888"));
+        });
+        
     }
     
     @Test
     public void testDecodeURL() {
         assertEquals("hello:world?param=5", StringUtils.decodeURL("hello%3Aworld%3Fparam%3D5"));
+        
+        assertEquals("hello:world?param=5", StringUtils.decodeURL("hello%3Aworld%3Fparam%3D5", new FCharset("UTF-8")));
+        
+        assertThrows(AssertionError.class, ()->{
+            StringUtils.decodeURL("hello%3Aworld%3Fparam%3D5", new FCharset("UFC888"));
+        });
     }
 	
 	@Test
@@ -268,5 +341,288 @@ public class StringUtilsTest {
         assertEquals("open_usb_port_name", StringUtils.uncamelize("openUSBPortName"));
     }
     
+    @Test
+    public void testClip() {
+        assertEquals("", StringUtils.clip("", 0));
+        assertEquals("", StringUtils.clip("", 3));
+        assertEquals("", StringUtils.clip("", -2));
+        
+        assertEquals("", StringUtils.clip("hello", 0));
+        assertEquals("", StringUtils.clip("hello", -2));
+        
+        assertEquals("he", StringUtils.clip("he", 3));
+        assertEquals("hel", StringUtils.clip("hello", 3));
+    }
+    
+    @Test
+    public void testLPadd() {
+        assertEquals("", StringUtils.lpadd("", '-', 0));
+        assertEquals("---", StringUtils.lpadd("", '-', 3));
+        assertEquals("", StringUtils.lpadd("", '-', -2));
+        
+        assertEquals("hello", StringUtils.lpadd("hello", '-', 0));
+        assertEquals("hello", StringUtils.lpadd("hello", '-', 3));
+        assertEquals("hello", StringUtils.lpadd("hello", '-', 5));
+        
+        assertEquals("hello-", StringUtils.lpadd("hello", '-', 6));
+        assertEquals("hello--", StringUtils.lpadd("hello", '-', 7));
+    }
+    
+    @Test
+    public void testRPadd() {
+        assertEquals("", StringUtils.rpadd("", '-', 0));
+        assertEquals("---", StringUtils.rpadd("", '-', 3));
+        assertEquals("", StringUtils.rpadd("", '-', -2));
+        
+        assertEquals("hello", StringUtils.rpadd("hello", '-', 0));
+        assertEquals("hello", StringUtils.rpadd("hello", '-', 3));
+        assertEquals("hello", StringUtils.rpadd("hello", '-', 5));
+        
+        assertEquals("-hello", StringUtils.rpadd("hello", '-', 6));
+        assertEquals("--hello", StringUtils.rpadd("hello", '-', 7));
+    }
+    
+    @Test
+    public void testCommonPrefix() {
+        assertEquals("",   StringUtils.commonPrefix(Arrays.asList()) );
+        assertEquals("z",  StringUtils.commonPrefix(Arrays.asList("z")) );
+        assertEquals("z",  StringUtils.commonPrefix(Arrays.asList("z","z")) );
+        assertEquals("z",  StringUtils.commonPrefix(Arrays.asList("z","za")) );
+        assertEquals("z",  StringUtils.commonPrefix(Arrays.asList("ze","za")) );
+        assertEquals("",   StringUtils.commonPrefix(Arrays.asList("re","za")) );
+        
+        assertEquals("r",   StringUtils.commonPrefix(Arrays.asList("re","rea", "rsu", "ret")) );
+        assertEquals("re",  StringUtils.commonPrefix(Arrays.asList("rea","reo", "rei", "ree")) );
+        assertEquals("",    StringUtils.commonPrefix(Arrays.asList("rea","reo", "rei", "dea")) );
+        assertEquals("",    StringUtils.commonPrefix(Arrays.asList("rea","reo", "rei", "")) );
+    }
+    
+    @Test
+    public void testCommonSuffix() {
+        assertEquals("",   StringUtils.commonSuffix(Arrays.asList()) );
+        assertEquals("z",  StringUtils.commonSuffix(Arrays.asList("z")) );
+        assertEquals("z",  StringUtils.commonSuffix(Arrays.asList("z","z")) );
+        assertEquals("z",  StringUtils.commonSuffix(Arrays.asList("z","az")) );
+        assertEquals("z",  StringUtils.commonSuffix(Arrays.asList("az","z")) );
+        
+        assertEquals("rit",  StringUtils.commonSuffix(Arrays.asList("rit","rit")) );
+        assertEquals("rit",  StringUtils.commonSuffix(Arrays.asList("arit","rit")) );
+        assertEquals("rit",  StringUtils.commonSuffix(Arrays.asList("rit","arit")) );
+
+        assertEquals("ri", StringUtils.commonSuffix("eri","ari") );
+        assertEquals("ri", StringUtils.commonSuffix("teri","mari") );
+        
+        assertEquals("i", StringUtils.commonSuffix(Arrays.asList("ri","zi")) );
+        assertEquals("ri", StringUtils.commonSuffix(Arrays.asList("eri","ari")) );
+        assertEquals("ri", StringUtils.commonSuffix(Arrays.asList("teri","mari")) );
+        
+        assertEquals("r",   StringUtils.commonSuffix(Arrays.asList("er", "aer", "usr", "ter")) );
+        assertEquals("er",  StringUtils.commonSuffix(Arrays.asList("aer","oer", "ier", "eer")) );
+        assertEquals("",    StringUtils.commonSuffix(Arrays.asList("aer","oer", "ier", "aed")) );
+        assertEquals("",    StringUtils.commonSuffix(Arrays.asList("aer","oer", "ier", "")) );
+    }
+    
+    @Test
+    public void testReverse() {
+        assertEquals("", StringUtils.reverse(""));
+        assertEquals("a", StringUtils.reverse("a"));
+        assertEquals("ba", StringUtils.reverse("ab"));
+        assertEquals("cba", StringUtils.reverse("abc"));
+        assertEquals("edcba", StringUtils.reverse("abcde"));
+    }
+    
+    @Test
+    public void testBefore() {
+        assertEquals("", StringUtils.before("", "r"));
+        assertEquals("", StringUtils.before("hello", ""));
+        assertEquals("", StringUtils.before("hello", "r"));
+        assertEquals("", StringUtils.before("hello", "he"));
+        
+        assertEquals("he", StringUtils.before("hello", "ll"));
+        assertEquals("hell", StringUtils.before("hello", "o"));
+        assertEquals("he", StringUtils.before("hello", "l"));
+    }
+    
+    @Test
+    public void testAfter() {
+        assertEquals("", StringUtils.after("", "r"));
+        assertEquals("", StringUtils.after("hello", "r"));
+        assertEquals("", StringUtils.after("hello", "lo"));
+        
+        assertEquals("hello", StringUtils.after("hello", ""));
+        
+        assertEquals("ord", StringUtils.after("hellord", "ll"));
+        assertEquals("llord", StringUtils.after("hellord", "e"));
+        assertEquals("lord", StringUtils.after("hellord", "l"));
+    }
+    
+    @Test
+    public void testBetweenB() {
+        assertEquals("", StringUtils.between("", null, "r"));
+        assertEquals("", StringUtils.between("hello", null, ""));
+        assertEquals("", StringUtils.between("hello", null, "r"));
+        assertEquals("", StringUtils.between("hello", null, "he"));
+        
+        assertEquals("he", StringUtils.between("hello", null, "ll"));
+        assertEquals("hell", StringUtils.between("hello", null, "o"));
+        assertEquals("he", StringUtils.between("hello", null, "l"));
+    }
+    
+    @Test
+    public void testBetweenA() {
+        assertEquals("", StringUtils.between("", "r", null));
+        assertEquals("", StringUtils.between("hello", "r", null));
+        assertEquals("", StringUtils.between("hello", "lo", null));
+        
+        assertEquals("hello", StringUtils.between("hello", "", null));
+        
+        assertEquals("ord", StringUtils.between("hellord", "ll", null));
+        assertEquals("llord", StringUtils.between("hellord", "e", null));
+        assertEquals("lord", StringUtils.between("hellord", "l", null));
+    }
+    
+    @Test
+    public void testBetween() {
+        assertEquals("", StringUtils.between("", "", ""));
+        assertEquals("", StringUtils.between("hellord", "a", "rd"));
+        assertEquals("", StringUtils.between("hellord", "he", "q"));
+        
+        assertEquals("llo", StringUtils.between("hellord", "he", "rd"));
+        assertEquals("l", StringUtils.between("hellord", "el", "ord"));
+        
+        assertEquals("", StringUtils.between("hello world", "l", "l"));
+        assertEquals(" w", StringUtils.between("hello world", "o", "o"));
+    }
 	
+    @Test
+    public void testRaw() {
+        assertEquals("some unique", StringUtils.raw(/*some unique*/));
+        assertEquals("hello world!", StringUtils.raw(/*hello world!*/));
+        assertEquals("", StringUtils.raw(/**/));
+        assertEquals("\"hello\\world\"", StringUtils.raw(/*"hello\world"*/));
+        assertEquals( String.format("a%nb%nc"), StringUtils.raw(
+/*a
+b
+c*/
+        ));
+    }
+    
+    @Test
+    public void testWrap() {
+        assertTrue("Hel".contentEquals(StringUtils.wrap("Hel".toCharArray())));
+        assertTrue("Hel".contentEquals(StringUtils.wrap("Hello".toCharArray(),0,3)) );
+        assertTrue("l".contentEquals(StringUtils.wrap("Hello".toCharArray(),2,3)) );
+        assertTrue("llo".contentEquals(StringUtils.wrap("Hello".toCharArray(),2,5)) );
+    }
+    
+    @Test
+    public void testRepeat() {
+        assertTrue("...".contentEquals(StringUtils.repeat(3,'.')));
+        assertTrue(".....".contentEquals(StringUtils.repeat(16,'.').subSequence(3, 8)));
+        
+        assertTrue("rerere".contentEquals(StringUtils.repeat(3,"re")));
+        
+        assertTrue("arvarvar".contentEquals(StringUtils.repeat(4,"var").subSequence(4, 12)));
+        assertTrue("arvarvarv".contentEquals(StringUtils.repeat(5,"var").subSequence(4, 13)));
+        
+        assertThrows(ArrayIndexOutOfBoundsException.class, ()->{
+            StringUtils.repeat(4,"var").subSequence(4, 13).toString();
+        });
+    }
+    
+    @Test
+    public void testIsEmpty() {
+        assertTrue(StringUtils.isEmpty(""));
+        assertTrue(StringUtils.isEmpty(null));
+        
+        assertFalse(StringUtils.isEmpty(" "));
+        assertFalse(StringUtils.isEmpty("."));
+        assertFalse(StringUtils.isEmpty(".."));
+    }
+    
+    @Test
+    public void testIsBlank() {
+        assertTrue(StringUtils.isBlank(""));
+        assertTrue(StringUtils.isBlank(null));
+        
+        assertTrue(StringUtils.isBlank(" "));
+        assertTrue(StringUtils.isBlank("    \t "));
+        
+        assertFalse(StringUtils.isBlank("."));
+        assertFalse(StringUtils.isBlank(".."));
+        assertFalse(StringUtils.isBlank(" . . "));
+    }
+    
+    @Test
+    public void testIndexOf() {
+        assertEquals(0, StringUtils.indexOf("hel", "hel"));
+        assertEquals(0, StringUtils.indexOf("hello", "hel"));
+        
+        assertEquals(0, StringUtils.indexOf("hello", ""));
+        assertEquals(0, StringUtils.indexOf("", ""));
+        assertTrue( StringUtils.indexOf("", "q")<0 );
+        
+        assertEquals(5, StringUtils.indexOf("hello world", " w"));
+        assertEquals(5, StringUtils.indexOf("hello world", " "));
+        
+        assertEquals(10, StringUtils.indexOf("hello world", "d"));
+        assertEquals(8, StringUtils.indexOf("hello world", "rld"));
+        assertEquals(2, StringUtils.indexOf("hello world", "l"));
+        
+        assertTrue( StringUtils.indexOf("hello world", "q")<0 );
+        assertTrue( StringUtils.indexOf("hello world", "we")<0 );
+        assertTrue( StringUtils.indexOf("hello world", "lda")<0 );
+    }
+    
+    @Test
+    public void testContains() {
+        assertTrue(StringUtils.contains("hel", "hel"));
+        assertTrue(StringUtils.contains("hello", "hel"));
+        
+        assertTrue(StringUtils.contains("hello", ""));
+        assertTrue(StringUtils.contains("", ""));
+        assertFalse(StringUtils.contains("", "q"));
+        
+        assertTrue(StringUtils.contains("hello world", " w"));
+        assertTrue(StringUtils.contains("hello world", " "));
+        
+        assertTrue(StringUtils.contains("hello world", "d"));
+        assertTrue(StringUtils.contains("hello world", "rld"));
+        assertTrue(StringUtils.contains("hello world", "l"));
+        
+        assertFalse(StringUtils.contains("hello world", "q"));
+        assertFalse(StringUtils.contains("hello world", "we"));
+        assertFalse(StringUtils.contains("hello world", "lda"));
+    }
+    
+    @Test
+    public void testSize() {
+        assertEquals(0, StringUtils.length(null));
+        assertEquals(0, StringUtils.length(""));
+        assertEquals(1, StringUtils.length(" "));
+        assertEquals(5, StringUtils.length("hello"));
+    }
+    
+    private static final class FCharset extends Charset {
+
+        public FCharset(String name) {
+            super(name, new String[0]);
+        }
+
+        @Override
+        public boolean contains(Charset cs) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public CharsetDecoder newDecoder() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public CharsetEncoder newEncoder() {
+            throw new UnsupportedOperationException();
+        }
+        
+    }
 }