package com.github.rschmitt.dynamicobject;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.List;

import static org.junit.Assert.assertEquals;

public class TaggedReaderTest {
    @Before
    public void setup() {
        DynamicObject.registerType(DumbClass.class, new DumbClassTranslator());
    }

    @After
    public void teardown() {
        DynamicObject.deregisterType(DumbClass.class);
    }

    @Test
    public void roundTrip() {
        String edn = "{:dumb [#MyDumbClass{:version 1, :str \"str\"}]}";

        DumbClassHolder deserialized = DynamicObject.deserialize(edn, DumbClassHolder.class);
        String serialized = DynamicObject.serialize(deserialized);

        assertEquals(edn, serialized);
        assertEquals(new DumbClass(1, "str"), deserialized.dumb().get(0));
    }
}

// This is a DynamicObject that contains a regular POJO.
interface DumbClassHolder extends DynamicObject<DumbClassHolder> {
    List<DumbClass> dumb();
}

// This is a translation class that functions as an Edn reader/writer for its associated POJO.
class DumbClassTranslator extends EdnTranslator<DumbClass> {
    @Override
    public DumbClass read(Object obj) {
        DumbClassProxy proxy = DynamicObject.wrap(obj, DumbClassProxy.class);
        return new DumbClass(proxy.version(), proxy.str());
    }

    @Override
    public String write(DumbClass obj) {
        return String.format("{:version %d, :str \"%s\"}", obj.getVersion(), obj.getStr());
    }

    @Override
    public String getTag() {
        return "MyDumbClass"; // This is deliberately different from the class name.
    }

    interface DumbClassProxy extends DynamicObject<DumbClassProxy> {
        long version();
        String str();
    }
}

// This is a POJO that has no knowledge of Edn.
class DumbClass {
    private final long version;
    private final String str;

    DumbClass(long version, String str) {
        this.version = version;
        this.str = str;
    }

    public long getVersion() {
        return version;
    }

    public String getStr() {
        return str;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        DumbClass dumbClass = (DumbClass) o;

        return version == dumbClass.version && str.equals(dumbClass.str);
    }

    @Override
    public int hashCode() {
        int result = (int) (version ^ (version >>> 32));
        result = 31 * result + str.hashCode();
        return result;
    }

    @Override
    public String toString() {
        throw new UnsupportedOperationException("I'm a useless legacy toString() method that doesn't produce Edn!");
    }
}

@@ -130,24 +130,63 @@
 util.List;%0A%0A
+import static java.lang.String.format;%0A
 import stati
@@ -251,16 +251,107 @@
 rTest %7B%0A
+    private static final String EDN = %22%7B:dumb %5B#MyDumbClass%7B:version 1, :str %5C%22str%5C%22%7D%5D%7D%22;%0A%0A
     @Bef
@@ -613,82 +613,8 @@
 ) %7B%0A
-        String edn = %22%7B:dumb %5B#MyDumbClass%7B:version 1, :str %5C%22str%5C%22%7D%5D%7D%22;%0A%0A
     
@@ -633,28 +633,22 @@
 sHolder 
-deserialized
+holder
  = Dynam
@@ -668,19 +668,19 @@
 rialize(
-edn
+EDN
 , DumbCl
@@ -689,32 +689,33 @@
 sHolder.class);%0A
+%0A
         String s
@@ -750,28 +750,22 @@
 rialize(
-deserialized
+holder
 );%0A%0A    
@@ -785,11 +785,11 @@
 als(
-edn
+EDN
 , se
@@ -849,33 +849,342 @@
 %22), 
-deserialized.dumb().get(0
+holder.dumb().get(0));%0A    %7D%0A%0A    @Test%0A    public void prettyPrint() %7B%0A        DumbClassHolder holder = DynamicObject.deserialize(EDN, DumbClassHolder.class);%0A        String expectedFormattedString = format(%22%7B:dumb %5B#MyDumbClass%7B:version 1, :str %5C%22str%5C%22%7D%5D%7D%25n%22);%0A        assertEquals(expectedFormattedString, holder.toFormattedString(
 ));%0A
@@ -1772,23 +1772,16 @@
  return 
-String.
 format(%22

Add a test for pprint w/ registered types