/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */

package net.ranides.assira.text;

import com.google.caliper.SimpleBenchmark;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.ranides.assira.generic.Function;
import org.junit.Test;
import static org.junit.Assert.*;

/**
 *
 * @author ranides
 */
@SuppressWarnings({
    "PMD.AvoidDuplicateLiterals",
    "PMD.TooManyDifferentMethods"
})
public class StringUtilsTest {

    @Test
    public void testRemoveChars() {
        String expected = "HelloWorld!";

        assertEquals(expected, StringUtils.remove("Hello World!", " ") );
        assertEquals(expected, StringUtils.remove("Hello World !", " ") );
        assertEquals(expected, StringUtils.remove("Hello World !  ", " ") );
        assertEquals(expected, StringUtils.remove("Hello   World !  ", " ") );
        assertEquals(expected, StringUtils.remove("  Hello   World !  ", " ") );
        assertEquals(expected, StringUtils.remove("   HelloWorld!", " ") );

    }

    @Test
    public void testLTrim() {
        assertEquals( "abcd",       StringUtils.ltrim("abcd") );
        assertEquals( "abcd  ",     StringUtils.ltrim("abcd  ") );
        assertEquals( "abcd",       StringUtils.ltrim(" abcd") );
        assertEquals( "abcd",       StringUtils.ltrim("   abcd") );
        assertEquals( "abcd ",      StringUtils.ltrim("   abcd ") );
        assertEquals( "d  abcd ",   StringUtils.ltrim(" d  abcd ") );
        assertEquals( "",           StringUtils.ltrim("   ") );
    }

    @Test
    public void testRTrim() {
        assertEquals( "abcd",       StringUtils.rtrim("abcd") );
        assertEquals( "  abcd",     StringUtils.rtrim("  abcd") );
        assertEquals( "abcd",       StringUtils.rtrim("abcd ") );
        assertEquals( "abcd",       StringUtils.rtrim("abcd   ") );
        assertEquals( " abcd",      StringUtils.rtrim(" abcd   ") );
        assertEquals( " abcd  d",   StringUtils.rtrim(" abcd  d") );
        assertEquals( "",           StringUtils.ltrim("   ") );
    }

    @Test
    public void testNCopies() {

        CharSequence seq = StringUtils.nCopies(4, "quick");
        CharSequence sub = seq.subSequence(4, 16);

        assertEquals( 20, seq.length() );
        assertEquals( 'c', seq.charAt(3) );
        assertEquals( 'c', seq.charAt(8) );
        assertEquals( 'c', seq.charAt(13) );
        assertEquals( 'c', seq.charAt(18) );
        assertEquals( 'k', seq.charAt(19) );

        assertEquals( 12, sub.length() );
        assertEquals( 'k', sub.charAt(0) );
        assertEquals( 'q', sub.charAt(1) );
        assertEquals( 'k', sub.charAt(5) );
        assertEquals( 'k', sub.charAt(10) );

        assertTrue(true);
    }

    @Test
    public void testBetween() {
        assertEquals("lo wo", StringUtils.between("hello world!", "el", "rl"));
        assertEquals("lo wo", StringUtils.between("hello world!", "el", "r"));
        assertEquals("lo wo", StringUtils.between("hello world!", "l", "rl"));
        assertEquals(" w", StringUtils.between("hello world!", "o", "o"));
        assertEquals("world!", StringUtils.between("hello world!", "lo ", null));
        assertEquals("hello", StringUtils.between("hello world!", null, " wo"));
        
        assertEquals("", StringUtils.between("hello world!", "not", "rl"));
        assertEquals("", StringUtils.between("hello world!", "he", "not"));
        
        assertEquals("", StringUtils.between("hello world!", null, "not"));
        assertEquals("", StringUtils.between("hello world!", "not", null));
    }
    
    @Test
    public void testReplaceCC() {
        String text = "quick brown dog in the fog";
        assertEquals("quick br.wn d.g in the f.g", StringUtils.replace(text, 'o', '.'));
    }
    
    @Test
    public void testReplaceCS() {
        String text = "quick brown dog in the fog";
        assertEquals("quick br()wn d()g in the f()g", StringUtils.replace(text, 'o', "()") );
        assertSame(text, StringUtils.replace(text, 'a', "()"));
        
        assertSame("", StringUtils.replace("", 'z', "Q"));
        assertSame("", StringUtils.replace(null, 'z', "Q") );
        
        String empty = new String("");
        assertSame(empty, StringUtils.replace(empty, 'z', "Q"));
    }
    
    @Test
    public void testReplacePattern() {
        String text = "quick b<ro>wn <d>og in <the> fog";
        Pattern pattern = Pattern.compile("<([a-z]+)>");
        String out = StringUtils.replace(text, pattern, new Function<String, Matcher>(){
            @Override
            public String apply(Matcher source) {
                return source.group(1);
            }
        });
        assertEquals("quick brown dog in the fog", out);
    }
    
    @Test
    public void testCamelize() {
        assertEquals("", StringUtils.camelize(""));
        assertEquals("", StringUtils.camelize("_"));
        assertEquals("", StringUtils.camelize("___"));
        
        assertEquals("hello", StringUtils.camelize("hello"));
        assertEquals("hello", StringUtils.camelize("hello_"));
        assertEquals("hello", StringUtils.camelize("_hello"));
        assertEquals("hello", StringUtils.camelize("___hello"));
        
        assertEquals("helloWorld", StringUtils.camelize("hello_world"));
        assertEquals("helloWorld", StringUtils.camelize("hello_world_"));
        assertEquals("helloWorld", StringUtils.camelize("hello___world__"));
        assertEquals("helloWorld", StringUtils.camelize("_hello___world__"));
        assertEquals("helloWorld", StringUtils.camelize("___hello___world__"));
        
        assertEquals("helloŁabędziu", StringUtils.camelize("heLLo_łabĘDziu"));
    }
    
    @Test
    public void testUncamelize() {
        assertEquals("", StringUtils.uncamelize(""));
        
        assertEquals("hello", StringUtils.uncamelize("hello"));
        assertEquals("hello", StringUtils.uncamelize("Hello"));
        
        assertEquals("hello_world", StringUtils.uncamelize("helloWorld"));
        assertEquals("hello_world", StringUtils.uncamelize("HelloWorld"));
        assertEquals("hello_a_t_world", StringUtils.uncamelize("HelloATWorld"));
        
        assertEquals("hello_łabędziu", StringUtils.uncamelize("HelloŁabędziu"));
        assertEquals("hello_łab_ę_dziu", StringUtils.uncamelize("HelloŁabĘDziu"));
    }
    
    @Test
    public void testCapitalize() {
        assertEquals("", StringUtils.capitalize(""));
        assertEquals("H", StringUtils.capitalize("h"));
        assertEquals("Hello", StringUtils.capitalize("hello"));
        assertEquals("HelloWorLD", StringUtils.capitalize("helloWorLD"));
        assertEquals("HelloWorLD", StringUtils.capitalize("HelloWorLD"));
    }
    
    @Test
    public void testUncapitalize() {
        assertEquals("", StringUtils.uncapitalize(""));
        assertEquals("h", StringUtils.uncapitalize("H"));
        assertEquals("hello", StringUtils.uncapitalize("Hello"));
        assertEquals("helloWorLD", StringUtils.uncapitalize("HelloWorLD"));
        assertEquals("helloWorLD", StringUtils.uncapitalize("helloWorLD"));
    }
    
    @Test
    public void testClip() {
        assertEquals("", StringUtils.clip("hello", 0));
        assertEquals("", StringUtils.clip("hello", -10));
        assertEquals("hel", StringUtils.clip("hello", 3));
        assertEquals("hello", StringUtils.clip("hello", 5));
        assertEquals("hello", StringUtils.clip("hello", 15));
    }
    
    @Test
    public void testCondense() {
        assertEquals("hello world", StringUtils.condense("hello worrrld", 'r'));
        assertEquals("hello world", StringUtils.condense("hello world", 'r'));
        assertEquals("helo world", StringUtils.condense("hello world", 'l'));
        assertEquals(".hello.world.", StringUtils.condense("....hello....world....", '.'));
    }
    
    @Test
    public void testFind() {
        String text = "quick brown (dog) in the fog.";
        
        assertEquals(null, StringUtils.find("", "dog") );
        assertEquals("", StringUtils.find("", "") );
        assertEquals("", StringUtils.find(text, "") );
        
        assertEquals("dog", StringUtils.find(text, "(dog)") );
        assertEquals(null, StringUtils.find(text, "(dog) in") );
        assertEquals("(dog) in", StringUtils.find(text, "\\(dog\\) in") );
    }
    
    
    @Test
    public void testJoinArray() {
        String[] array0 = {};
        String[] array1 = {"a"};
        String[] array2 = {"a","b"};
        String[] array3 = {"a","b","c"};
        String[] array5 = {"a","b","c","d","e"};
        
        assertEquals("",      StringUtils.join(array0));
        assertEquals("a",     StringUtils.join(array1));
        assertEquals("ab",    StringUtils.join(array2));
        assertEquals("abc",   StringUtils.join(array3));
        assertEquals("abcde", StringUtils.join(array5));
        
        assertEquals("",          StringUtils.join(array0, "-"));
        assertEquals("a",         StringUtils.join(array1, "-"));
        assertEquals("a-b",       StringUtils.join(array2, "-"));
        assertEquals("a-b-c",     StringUtils.join(array3, "-"));
        assertEquals("a-b-c-d-e", StringUtils.join(array5, "-"));
    }
    
    @Test
    public void testJoinList() {
        List<String> list0 = Arrays.asList();
        List<String> list1 = Arrays.asList("a");
        List<String> list2 = Arrays.asList("a","b");
        List<String> list3 = Arrays.asList("a","b","c");
        List<String> list5 = Arrays.asList("a","b","c","d","e");
        
        assertEquals("",      StringUtils.join(list0));
        assertEquals("a",     StringUtils.join(list1));
        assertEquals("ab",    StringUtils.join(list2));
        assertEquals("abc",   StringUtils.join(list3));
        assertEquals("abcde", StringUtils.join(list5));
        
        assertEquals("",          StringUtils.join(list0, "-"));
        assertEquals("a",         StringUtils.join(list1, "-"));
        assertEquals("a-b",       StringUtils.join(list2, "-"));
        assertEquals("a-b-c",     StringUtils.join(list3, "-"));
        assertEquals("a-b-c-d-e", StringUtils.join(list5, "-"));
        
    }
    
    @Test
    public void testJoinIterable() {
        Iterable<String> iterable0 = asRawIterable(Arrays.<String>asList());
        Iterable<String> iterable1 = asRawIterable(Arrays.asList("a"));
        Iterable<String> iterable2 = asRawIterable(Arrays.asList("a","b"));
        Iterable<String> iterable3 = asRawIterable(Arrays.asList("a","b","c"));
        Iterable<String> iterable5 = asRawIterable(Arrays.asList("a","b","c","d","e"));
        
        assertEquals("",      StringUtils.join(iterable0));
        assertEquals("a",     StringUtils.join(iterable1));
        assertEquals("ab",    StringUtils.join(iterable2));
        assertEquals("abc",   StringUtils.join(iterable3));
        assertEquals("abcde", StringUtils.join(iterable5));
        
        assertEquals("",          StringUtils.join(iterable0, "-"));
        assertEquals("a",         StringUtils.join(iterable1, "-"));
        assertEquals("a-b",       StringUtils.join(iterable2, "-"));
        assertEquals("a-b-c",     StringUtils.join(iterable3, "-"));
        assertEquals("a-b-c-d-e", StringUtils.join(iterable5, "-"));
        
    }
    
    private Iterable<String> asRawIterable(final List<String> values) {
        return new Iterable<String>() {
            @Override
            public Iterator<String> iterator() {
                return values.iterator();
            }
        };
    }
    
    @Test
    public void testLCommon() {
        assertEquals("",   lcommon() );
        assertEquals("z",  lcommon("z") );
        assertEquals("z",  lcommon("z","z") );
        assertEquals("z",  lcommon("z","za") );
        assertEquals("z",  lcommon("ze","za") );
        assertEquals("",   lcommon("re","za") );
        
        assertEquals("r",   lcommon("re","rea", "rsu", "ret") );
        assertEquals("re",  lcommon("rea","reo", "rei", "ree") );
        assertEquals("",    lcommon("rea","reo", "rei", "dea") );
        assertEquals("",    lcommon("rea","reo", "rei", "") );
    }
    
    @Test
    public void testLCommonTrim() {
        assertEquals( Arrays.asList(), lcommonTrim());
        assertEquals( Arrays.asList(""), lcommonTrim("") );
        assertEquals( Arrays.asList(""), lcommonTrim("r") );
        assertEquals( Arrays.asList("",""), lcommonTrim("z","z") );
        assertEquals( Arrays.asList("","a"), lcommonTrim("z","za") );
        assertEquals( Arrays.asList("e","a"), lcommonTrim("ze","za") );
        assertEquals(
            Arrays.asList("ent", "am", "oom", ""),   
            lcommonTrim("zent", "zam", "zoom", "z")
        );
        assertEquals(
            Arrays.asList("zent", "zam", "zoom", ""),   
            lcommonTrim("zent", "zam", "zoom", "")
        );
        assertEquals(
            Arrays.asList("zent", "zam", "zoom", "tau"),   
            lcommonTrim("zent", "zam", "zoom", "tau")
        );
    }
    
    private String lcommon(String... values) {
        return StringUtils.lcommon(Arrays.asList(values));
    }
    
    private List<String> lcommonTrim(String... values) {
        return StringUtils.lcommonTrim(Arrays.asList(values));
    }
    
    @Test
    public void testRPadd() {
        assertEquals("", StringUtils.rpadd("", '.', 0) );
        assertEquals(".", StringUtils.rpadd("", '.', 1) );
        assertEquals(".....", StringUtils.rpadd("", '.', 5) );
        
        assertEquals("ret", StringUtils.rpadd("ret", '.', 0) );
        assertEquals("ret", StringUtils.rpadd("ret", '.', 1) );
        assertEquals("ret", StringUtils.rpadd("ret", '.', 3) );
        assertEquals("..ret", StringUtils.rpadd("ret", '.', 5) );
    }
    
    @Test
    public void testLPadd() {
        assertEquals("", StringUtils.lpadd("", '.', 0) );
        assertEquals(".", StringUtils.lpadd("", '.', 1) );
        assertEquals(".....", StringUtils.lpadd("", '.', 5) );
        
        assertEquals("ret", StringUtils.lpadd("ret", '.', 0) );
        assertEquals("ret", StringUtils.lpadd("ret", '.', 1) );
        assertEquals("ret", StringUtils.lpadd("ret", '.', 3) );
        assertEquals("ret..", StringUtils.lpadd("ret", '.', 5) );
    }
    
    @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 testRemoveSuffix() {
        assertEquals("", StringUtils.removeSuffix("", "EOS"));
        assertEquals("", StringUtils.removeSuffix("EOS", "EOS"));
        assertEquals("", StringUtils.removeSuffix("", ""));
        assertEquals("text", StringUtils.removeSuffix("text", ""));
        
        assertEquals("EOSt", StringUtils.removeSuffix("EOSt", "EOS"));
        assertEquals("EOSter", StringUtils.removeSuffix("EOSter", "EOS"));
        assertEquals("t", StringUtils.removeSuffix("tEOS", "EOS"));
        assertEquals("ter", StringUtils.removeSuffix("terEOS", "EOS"));
        
        assertEquals("Et", StringUtils.removeSuffix("Et", "E"));
        assertEquals("Eter", StringUtils.removeSuffix("Eter", "E"));
        assertEquals("t", StringUtils.removeSuffix("tE", "E"));
        assertEquals("ter", StringUtils.removeSuffix("terE", "E"));
    }
    
    @Test
    public void testRemovePrefix() {
        assertEquals("", StringUtils.removePrefix("", "EOS"));
        assertEquals("", StringUtils.removePrefix("EOS", "EOS"));
        assertEquals("", StringUtils.removePrefix("", ""));
        assertEquals("text", StringUtils.removePrefix("text", ""));
        
        assertEquals("tEOS", StringUtils.removePrefix("tEOS", "EOS"));
        assertEquals("terEOS", StringUtils.removePrefix("terEOS", "EOS"));
        assertEquals("t", StringUtils.removePrefix("EOSt", "EOS"));
        assertEquals("ter", StringUtils.removePrefix("EOSter", "EOS"));
        
        assertEquals("tE", StringUtils.removePrefix("tE", "E"));
        assertEquals("terE", StringUtils.removePrefix("terE", "E"));
        assertEquals("t", StringUtils.removePrefix("Et", "E"));
        assertEquals("ter", StringUtils.removePrefix("Eter", "E"));
    }

}
