package io.norberg.automatter.jackson;

import static com.fasterxml.jackson.databind.PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import java.io.IOException;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;

public class AutoMatterModuleTest {

  static final Foo FOO = new FooBuilder().a(17).b("foobar").aCamelCaseField(true).build();

  static final WithInner.Bar BAR = new BarBuilder().a(17).b("foobar").aCamelCaseField(true).build();

  static final WithInner.PublicBar PUBLIC_BAR =
      new PublicBarBuilder().a(17).b("foobar").aCamelCaseField(true).build();

  static WithCollections WITH_COLLECTIONS = new WithCollectionsBuilder().build();

  ObjectMapper mapper;

  @Before
  public void setUp() {
    mapper = new ObjectMapper().registerModule(new AutoMatterModule());
  }

  @Test
  public void testDefault() throws IOException {
    final String json = mapper.writeValueAsString(FOO);
    final Foo parsed = mapper.readValue(json, Foo.class);
    assertThat(parsed, is(FOO));
  }

  @Test
  public void testInner() throws IOException {
    final String json = mapper.writeValueAsString(BAR);
    final WithInner.Bar parsed = mapper.readValue(json, WithInner.Bar.class);
    assertThat(parsed, is(BAR));
  }

  @Test
  public void testPublicInner() throws IOException {
    final String json = mapper.writeValueAsString(PUBLIC_BAR);
    final WithInner.PublicBar parsed = mapper.readValue(json, WithInner.PublicBar.class);
    assertThat(parsed, is(PUBLIC_BAR));
  }

  @SuppressWarnings("deprecation")
  @Test
  public void testUnderScoreNamingStrategy() throws IOException {
    mapper.setPropertyNamingStrategy(CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
    final String json = mapper.writeValueAsString(FOO);
    final JsonNode tree = mapper.readTree(json);
    assertThat(tree.has("a_camel_case_field"), is(true));
    final Foo parsed = mapper.readValue(json, Foo.class);
    assertThat(parsed, is(FOO));
  }

  @Test
  public void testSnakeCaseNamingStrategy() throws IOException {
    Assume.assumeTrue(
        mapper.version().getMajorVersion() == 2 && mapper.version().getMinorVersion() >= 7);
    mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
    final String json = mapper.writeValueAsString(FOO);
    final JsonNode tree = mapper.readTree(json);
    assertThat(tree.has("a_camel_case_field"), is(true));
    final Foo parsed = mapper.readValue(json, Foo.class);
    assertThat(parsed, is(FOO));
  }

  @Test
  public void testExplicitJsonProperty() throws IOException {
    final String json = mapper.writeValueAsString(FOO);
    final JsonNode tree = mapper.readTree(json);
    assertThat(tree.has("foobar"), is(true));
    final Foo parsed = mapper.readValue(json, Foo.class);
    assertThat(parsed, is(FOO));
  }

  @Test
  public void testEmptyCollections() throws Exception {
    final String json = mapper.writeValueAsString(WITH_COLLECTIONS);
    final WithCollections parsed = mapper.readValue(json, WithCollections.class);
    assertThat(parsed, is(WITH_COLLECTIONS));
    assertThat(parsed.list().isEmpty(), is(true));
    assertThat(parsed.set().isEmpty(), is(true));
    assertThat(parsed.map().isEmpty(), is(true));
  }

  @Test
  public void testDefaultEmptyCollections() throws Exception {
    final String json = "{}";
    final WithCollections parsed = mapper.readValue(json, WithCollections.class);
    assertThat(parsed, is(WITH_COLLECTIONS));
    assertThat(parsed.list().isEmpty(), is(true));
    assertThat(parsed.set().isEmpty(), is(true));
    assertThat(parsed.map().isEmpty(), is(true));
  }
}

@@ -1268,32 +1268,267 @@
  is(FOO));%0A  %7D%0A%0A
+  @Test%0A  public void explicitRootType() throws IOException %7B%0A    final String json = mapper.writerFor(Foo.class).writeValueAsString(FOO);%0A    final Foo parsed = mapper.readValue(json, Foo.class);%0A    assertThat(parsed, is(FOO));%0A  %7D%0A%0A
   @Test%0A  public

add failing test for serializing with explicit root type