package com.dampcake.bencode;

import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Locale;
import java.util.concurrent.ConcurrentSkipListMap;

import static com.dampcake.bencode.Assert.assertThrows;
import static org.junit.Assert.assertEquals;

/**
 * Unit tests for BencodeOutputStream.
 *
 * @author Adam Peck
 */
@RunWith(Parameterized.class)
public class BencodeOutputStreamTest {

    private static Locale startLocale = Locale.getDefault();

    @Parameterized.Parameter
    public Locale testLocale;

    @AfterClass
    public static void restore() throws Exception {
        Locale.setDefault(startLocale);
    }

    @Parameterized.Parameters(name = "{index}: {0}")
    public static Collection<Object[]> data() {
        LinkedList<Object[]> res = new LinkedList<Object[]>();
        for (Locale locale : Locale.getAvailableLocales()) {
            res.add(new Object[] {locale});
        }
        return res;
    }

    private ByteArrayOutputStream out;
    private BencodeOutputStream instance;

    @Before
    public void setUp() {
        Locale.setDefault(testLocale);

        out = new ByteArrayOutputStream();
        instance = new BencodeOutputStream(out);
    }

    @Test
    public void testConstructorNullStream() throws Exception {
        new BencodeOutputStream(null);
    }

    @Test(expected = NullPointerException.class)
    public void testConstructorNullCharset() throws Exception {
        new BencodeOutputStream(out, null);
    }

    @Test
    public void testWriteString() throws Exception {
        instance.writeString("Hello World!");

        assertEquals("12:Hello World!", new String(out.toByteArray(), instance.getCharset()));
    }

    @Test
    public void testWriteStringEmpty() throws Exception {
        instance.writeString("");

        assertEquals("0:", new String(out.toByteArray(), instance.getCharset()));
    }

    @Test
    public void testWriteStringNull() throws Exception {
        assertThrows(NullPointerException.class, new Runnable() {
            public void run() throws Exception {
                instance.writeString(null);
            }
        });

        assertEquals(0, out.toByteArray().length);
    }

    @Test
    public void testWriteNumber() throws Exception {
        instance.writeNumber(123456);

        assertEquals("i123456e", new String(out.toByteArray(), instance.getCharset()));
    }

    @Test
    public void testWriteNumberDecimal() throws Exception {
        instance.writeNumber(123.456);

        assertEquals("i123e", new String(out.toByteArray(), instance.getCharset()));
    }

    @Test
    public void testWriteNumberNull() throws Exception {
        assertThrows(NullPointerException.class, new Runnable() {
            public void run() throws Exception {
                instance.writeNumber(null);
            }
        });

        assertEquals(0, out.toByteArray().length);
    }

    @Test
    public void testWriteList() throws Exception {
        instance.writeList(new ArrayList<Object>() {{
            add("Hello");
            add("World!");
            add(new ArrayList<Object>() {{
                add(123);
                add(456);
            }});
        }});

        assertEquals("l5:Hello6:World!li123ei456eee", new String(out.toByteArray(), instance.getCharset()));
    }

    @Test
    public void testWriteListEmpty() throws Exception {
        instance.writeList(new ArrayList<Object>());

        assertEquals("le", new String(out.toByteArray(), instance.getCharset()));
    }

    @Test
    public void testWriteListNullItem() throws Exception {
        assertThrows(NullPointerException.class, new Runnable() {
            public void run() throws Exception {
                instance.writeList(new ArrayList<Object>() {{
                    add("Hello");
                    add("World!");
                    add(new ArrayList<Object>() {{
                        add(null);
                        add(456);
                    }});
                }});
            }
        });

        assertEquals(0, out.toByteArray().length);
    }

    @Test
    public void testWriteListNull() throws Exception {
        assertThrows(NullPointerException.class, new Runnable() {
            public void run() throws Exception {
                instance.writeList(null);
            }
        });

        assertEquals(0, out.toByteArray().length);
    }

    @Test
    @SuppressWarnings("unchecked")
    public void testWriteDictionary() throws Exception {
        instance.writeDictionary(new HashMap<Object, Object>() {{
            put("string", "value");
            put("number", 123456);
            put("list", new ArrayList<Object>() {{
                add("list-item-1");
                add("list-item-2");
            }});
            put("dict", new ConcurrentSkipListMap() {{
                put(123, "test");
                put(456, "thing");
            }});
        }});

        assertEquals("d4:dictd3:1234:test3:4565:thinge4:listl11:list-item-111:list-item-2e6:numberi123456e6:string5:valuee",
                new String(out.toByteArray(), instance.getCharset()));
    }

    @Test
    public void testWriteDictionaryEmpty() throws Exception {
        instance.writeDictionary(new HashMap<Object, Object>());

        assertEquals("de", new String(out.toByteArray(), instance.getCharset()));
    }

    @Test
    public void testWriteDictionaryKeyCastException() throws Exception {
        assertThrows(ClassCastException.class, new Runnable() {
            public void run() throws Exception {
                instance.writeDictionary(new HashMap<Object, Object>() {{
                    put("string", "value");
                    put(123, "number-key");
                }});
            }
        });

        assertEquals(0, out.toByteArray().length);
    }

    @Test
    public void testWriteDictionaryNull() throws Exception {
        assertThrows(NullPointerException.class, new Runnable() {
            public void run() throws Exception {
                instance.writeDictionary(null);
            }
        });

        assertEquals(0, out.toByteArray().length);
    }
}

@@ -28,37 +28,8 @@
 e;%0A%0A
-import org.junit.AfterClass;%0A
 impo
@@ -75,81 +75,8 @@
 est;
-%0Aimport org.junit.runner.RunWith;%0Aimport org.junit.runners.Parameterized;
 %0A%0Aim
@@ -160,98 +160,15 @@
 til.
-Collection;%0Aimport java.util.HashMap;%0Aimport java.util.LinkedList;%0Aimport java.util.Locale
+HashMap
 ;%0Aim
@@ -394,38 +394,8 @@
  */%0A
-@RunWith(Parameterized.class)%0A
 publ
@@ -434,551 +434,8 @@
  %7B%0A%0A
-    private static Locale startLocale = Locale.getDefault();%0A%0A    @Parameterized.Parameter%0A    public Locale testLocale;%0A%0A    @AfterClass%0A    public static void restore() throws Exception %7B%0A        Locale.setDefault(startLocale);%0A    %7D%0A%0A    @Parameterized.Parameters(name = %22%7Bindex%7D: %7B0%7D%22)%0A    public static Collection%3CObject%5B%5D%3E data() %7B%0A        LinkedList%3CObject%5B%5D%3E res = new LinkedList%3CObject%5B%5D%3E();%0A        for (Locale locale : Locale.getAvailableLocales()) %7B%0A            res.add(new Object%5B%5D %7Blocale%7D);%0A        %7D%0A        return res;%0A    %7D%0A%0A
     
@@ -554,48 +554,8 @@
 ) %7B%0A
-        Locale.setDefault(testLocale);%0A%0A
     

Remove locale dependant tests. String.format required these, but now that we are using StringBuffer locale will have no impact.