Package com.linkedin.data.template

Source Code of com.linkedin.data.template.TestMapTemplate$FooRecord

/*
   Copyright (c) 2012 LinkedIn Corp.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package com.linkedin.data.template;


import com.linkedin.data.ByteString;
import com.linkedin.data.DataComplex;
import com.linkedin.data.DataList;
import com.linkedin.data.DataMap;
import com.linkedin.data.TestUtil;
import com.linkedin.data.schema.DataSchema;
import com.linkedin.data.schema.MapDataSchema;
import com.linkedin.data.schema.RecordDataSchema;
import java.lang.reflect.Constructor;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.testng.annotations.Test;

import static com.linkedin.data.TestUtil.asMap;
import static com.linkedin.data.TestUtil.noCommonDataComplex;
import static com.linkedin.data.TestUtil.out;
import static org.testng.Assert.*;

/**
* Unit tests for map {@link DataTemplate}'s.
*
* @author slim
*/
public class TestMapTemplate
{
  static <E> void assertCollectionEquals(Collection<E> c1, Collection<E> c2)
  {
    assertTrue(c1.containsAll(c2));
    assertTrue(c2.containsAll(c1));
  }

  public static <MapTemplate extends AbstractMapTemplate<E>, E>
  void testMap(Class<MapTemplate> templateClass,
               MapDataSchema schema,
               Map<String, E> input,
               Map<String, E> adds)
  {
    try
    {
      Exception exc = null;

      // constructor and putall
      MapTemplate map1 = templateClass.newInstance();
      map1.putAll(input);
      assertEquals(map1, input);

      /*
      Constructor[] constructors = templateClass.getConstructors();
      for (Constructor c : constructors)
      {
        out.println(c);
      }
      */
      try
      {
        int size = input.size();

        // constructor(int capacity)
        Constructor<MapTemplate> capacityConstructor = templateClass.getConstructor(int.class);
        MapTemplate map = capacityConstructor.newInstance(input.size());
        assertEquals(map, Collections.emptyMap());
        map.putAll(input);
        assertEquals(input, map);
        map.clear();
        assertEquals(size, input.size());

        // constructor(int capacity, float loadFactor)
        Constructor<MapTemplate> loadFactorConstructor = templateClass.getConstructor(int.class, float.class);
        map = loadFactorConstructor.newInstance(input.size(), input.size() * 1.4f);
        assertEquals(map, Collections.emptyMap());
        map.putAll(input);
        assertEquals(input, map);
        map.clear();
        assertEquals(size, input.size());

        // constructor(Map<String, E>)
        Constructor<MapTemplate> mapConstructor = templateClass.getConstructor(Map.class);
        map = mapConstructor.newInstance(input);
        assertEquals(input, map);
        map.clear();
        assertEquals(size, input.size());

        // constructor(DataMap)
        Constructor<MapTemplate> dataMapConstructor = templateClass.getConstructor(DataMap.class);
        map = dataMapConstructor.newInstance(map1.data());
        assertEquals(map1, map);
        assertEquals(input, map);
        map.clear();
        assertEquals(map1, map);
      }
      catch (Exception e)
      {
        assertSame(e, null);
      }

      // test wrapping
      map1.clear();
      map1.putAll(input);
      DataMap dataMap2 = new DataMap();
      MapTemplate map2 = DataTemplateUtil.wrap(dataMap2, schema, templateClass);
      for (Map.Entry<String, E> e : input.entrySet())
      {
        E v = e.getValue();
        Object o;
        if (v instanceof DataTemplate)
        {
          o = ((DataTemplate<?>) v).data();
        }
        else if (v instanceof Enum)
        {
          o = v.toString();
        }
        else
        {
          o = v;
        }
        dataMap2.put(e.getKey(), o);
        assertEquals(map2.hashCode(), dataMap2.hashCode());
      }
      assertEquals(map1, map2);
      MapTemplate map2a = DataTemplateUtil.wrap(dataMap2, templateClass);
      assertEquals(map1, map2a);
      assertSame(map2a.data(), map2.data());

      // valueClass()
      assertSame(map1.valueClass(), input.values().iterator().next().getClass());

      // equals(), hashCode()
      map1.clear();
      map1.putAll(input);
      assertTrue(map1.equals(map1));
      assertTrue(map1.equals(input));
      assertFalse(map1.equals(null));
      assertFalse(map1.equals(adds));
      assertFalse(map1.equals(new HashMap<String,E>()));
      map2.clear();
      Map<String,E> hashMap2 = new HashMap<String,E>();
      List<Map.Entry<String,E>> inputList = new ArrayList<Map.Entry<String, E>>(input.entrySet());
      int lastHash = 0;
      for (int i = 0; i < inputList.size(); ++i)
      {
        Map.Entry<String,E> entry = inputList.get(i);
        map2.put(entry.getKey(), entry.getValue());
        hashMap2.put(entry.getKey(), entry.getValue());

        if (i == (inputList.size() - 1))
        {
          assertTrue(map1.equals(map2));
          assertTrue(map1.equals(hashMap2));
        }
        else
        {
          assertFalse(map1.equals(map2));
          assertFalse(map1.equals(hashMap2));
        }

        int newHash = map2.hashCode();
        if (i > 0)
        {
          assertFalse(lastHash == newHash);
        }

        lastHash = newHash;
      }

      // schema()
      MapDataSchema schema1 = map1.schema();
      assertTrue(schema1 != null);
      assertEquals(schema1.getType(), DataSchema.Type.MAP);
      assertEquals(schema1, schema);

      // get(Object key), put(K key, V value, containsKey(Object key), containsValue(Object value), toString
      MapTemplate map3 = templateClass.newInstance();
      for (Map.Entry<String, E> e : input.entrySet())
      {
        String key = e.getKey();
        E value = e.getValue();
        E replaced = map3.put(key, value);
        assertTrue(replaced == null);
        E got = map3.get(key);
        assertTrue(got != null);
        assertEquals(value, got);
        assertSame(value, got);
        assertTrue(map3.containsKey(key));
        assertTrue(map3.containsValue(value));
        assertTrue(map3.toString().contains(key + "=" + value));
      }
      assertNull(map3.get(null));
      assertNull(map3.get(1));
      assertNull(map3.get(new Object()));
      assertNull(map3.get("not found"));

      assertEquals(map3, input);
      Iterator<Map.Entry<String, E>> e2 = adds.entrySet().iterator();
      for (Map.Entry<String, E> e : input.entrySet())
      {
        if (e2.hasNext() == false)
          break;
        E newValue = e2.next().getValue();
        String key = e.getKey();
        E value = e.getValue();
        assertTrue(map3.containsKey(key));
        assertTrue(map3.containsValue(value));
        E replaced = map3.put(key, newValue);
        assertTrue(replaced != null);
        assertEquals(replaced, value);
        assertSame(replaced, value);
        assertTrue(map3.containsKey(key));
        assertTrue(map3.containsValue(newValue));
        assertTrue(map3.toString().contains(key));
        assertTrue(map3.toString().contains(newValue.toString()));
      }

      // put(String key, E value) with replacement of existing value
      map3.clear();
      String testKey = "testKey";
      E lastValue = null;
      for (Map.Entry<String, E> e : input.entrySet())
      {
        E putResult = map3.put(testKey, e.getValue());
        if (lastValue != null)
        {
          assertEquals(putResult, lastValue);
        }
        lastValue = e.getValue();
      }

      // remove(Object key), containsKey(Object key), containsValue(Object value)
      MapTemplate map4 = templateClass.newInstance();
      map4.putAll(input);
      int map4Size = map4.size();
      for (Map.Entry<String, E> e : input.entrySet())
      {
        String key = e.getKey();
        E value = e.getValue();
        assertTrue(map4.containsKey(key));
        assertTrue(map4.containsValue(value));
        E removed = map4.remove(key);
        assertTrue(removed != null);
        assertEquals(value, removed);
        assertSame(value, removed);
        assertFalse(map4.containsKey(key));
        assertFalse(map4.containsValue(value));
        map4Size--;
        assertEquals(map4Size, map4.size());
      }
      assertTrue(map4.isEmpty());
      assertTrue(map4.size() == 0);
      assertFalse(map4.containsValue(null));
      assertFalse(map4.containsValue(new StringArray()));

      // clone and copy return types
      TestDataTemplateUtil.assertCloneAndCopyReturnType(templateClass);

      // clone
      exc = null;
      map4 = templateClass.newInstance();
      map4.putAll(input);
      try
      {
        exc = null;
        @SuppressWarnings("unchecked")
        MapTemplate map4Clone = (MapTemplate) map4.clone();
        assertTrue(map4Clone.getClass() == templateClass);
        assertEquals(map4Clone, map4);
        assertTrue(map4Clone != map4);
        for (Map.Entry<String, Object> entry : map4.data().entrySet())
        {
          if (entry.getValue() instanceof DataComplex)
          {
            assertSame(map4Clone.data().get(entry.getKey()), entry.getValue());
          }
        }
        String key = map4Clone.keySet().iterator().next();
        map4Clone.remove(key);
        assertEquals(map4Clone.size(), map4.size() - 1);
        assertFalse(map4Clone.equals(map4));
        assertTrue(map4.entrySet().containsAll(map4Clone.entrySet()));
        map4.remove(key);
        assertEquals(map4Clone, map4);
      }
      catch (CloneNotSupportedException e)
      {
        exc = e;
      }
      assert(exc == null);

      //copy
      MapTemplate map4a = templateClass.newInstance();
      map4a.putAll(input);
      try
      {
        @SuppressWarnings("unchecked")
        MapTemplate map4aCopy = (MapTemplate) map4a.copy();
        assertTrue(map4aCopy.getClass() == templateClass);
        assertEquals(map4a, map4aCopy);
        boolean hasComplex = false;
        for (Map.Entry<String, Object> entry : map4a.data().entrySet())
        {
          if (entry.getValue() instanceof DataComplex)
          {
            assertNotSame(map4aCopy.data().get(entry.getKey()), entry.getValue());
            hasComplex = true;
          }
        }
        assertTrue(DataTemplate.class.isAssignableFrom(map4a._valueClass) == false || hasComplex);
        assertTrue(noCommonDataComplex(map4a.data(), map4aCopy.data()));
        boolean mutated = false;
        for (Object value : map4aCopy.data().values())
        {
          if (value instanceof DataComplex)
          {
            mutated |= TestUtil.mutateDataComplex((DataComplex) value);
          }
        }
        assertEquals(mutated, hasComplex);
        if (mutated)
        {
          assertNotEquals(map4aCopy, map4a);
        }
        else
        {
          assertEquals(map4aCopy, map4a);
          String key = map4aCopy.keySet().iterator().next();
          map4aCopy.remove(key);
          assertFalse(map4aCopy.containsKey(key));
          assertTrue(map4a.containsKey(key));
        }
      }
      catch (CloneNotSupportedException e)
      {
        exc = e;
      }
      assert(exc == null);

      // entrySet, keySet, values, clear
      MapTemplate map5 = templateClass.newInstance();
      map5.putAll(input);
      assertEquals(map5.entrySet(), input.entrySet());
      assertCollectionEquals(map5.entrySet(), input.entrySet());
      assertEquals(map5.keySet(), input.keySet());
      assertCollectionEquals(map5.keySet(), input.keySet());
      assertCollectionEquals(map5.values(), input.values());

      assertEquals(map5.size(), input.size());
      assertFalse(map5.isEmpty());
      map5.clear();
      assertEquals(map5.size(), 0);
      assertTrue(map5.isEmpty());

      map5.putAll(adds);
      assertEquals(map5.entrySet(), adds.entrySet());
      assertEquals(map5.keySet(), adds.keySet());
      assertCollectionEquals(map5.values(), adds.values());

      assertEquals(map5.size(), adds.size());
      assertFalse(map5.isEmpty());
      map5.clear();
      assertEquals(map5.size(), 0);
      assertTrue(map5.isEmpty());

      // entrySet contains
      MapTemplate map6 = templateClass.newInstance();
      Set<Map.Entry<String, E>> entrySet6 = map6.entrySet();
      for (Map.Entry<String, E> e : input.entrySet())
      {
        assertFalse(entrySet6.contains(e));
        map6.put(e.getKey(), e.getValue());
        assertTrue(entrySet6.contains(e));
      }
      for (Map.Entry<String, E> e : adds.entrySet())
      {
        assertFalse(entrySet6.contains(e));
      }
      assertFalse(entrySet6.contains(null));
      assertFalse(entrySet6.contains(1));
      assertFalse(entrySet6.contains(new Object()));
      assertFalse(entrySet6.contains(new AbstractMap.SimpleEntry<String, Object>(null, null)));
      assertFalse(entrySet6.contains(new AbstractMap.SimpleEntry<String, Object>("xxxx", null)));
      assertFalse(entrySet6.contains(new AbstractMap.SimpleEntry<String, Object>("xxxx", "xxxx")));
      assertFalse(entrySet6.contains(new AbstractMap.SimpleEntry<String, Object>("xxxx", new Object())));

      // entrySet iterator
      for (Map.Entry<String, E> e : map6.entrySet())
      {
        assertTrue(map6.containsKey(e.getKey()));
        assertTrue(map6.containsValue(e.getValue()));
      }
      try
      {
        exc = null;
        map6.entrySet().iterator().remove();
      }
      catch (Exception e)
      {
        exc = e;
      }
      assertTrue(exc != null);
      assertTrue(exc instanceof UnsupportedOperationException);

      // entrySet containsAll
      assertTrue(map6.entrySet().containsAll(input.entrySet()));
      assertTrue(input.entrySet().containsAll(map6.entrySet()));

      // entrySet add
      for (Map.Entry<String, E> e : input.entrySet())
      {
        try
        {
          exc = null;
          entrySet6.add(e);
        }
        catch (Exception ex)
        {
          exc = ex;
        }
        assertTrue(exc != null);
        assertTrue(exc instanceof UnsupportedOperationException);
      }

      // entrySet remove
      for (Map.Entry<String, E> e : input.entrySet())
      {
        try
        {
          exc = null;
          entrySet6.remove(e);
        }
        catch (Exception ex)
        {
          exc = ex;
        }
        assertTrue(exc != null);
        assertTrue(exc instanceof UnsupportedOperationException);
      }

      Object invalidEntries[] = { null, 1, new Object() };
      for (Object e : invalidEntries)
      {
        try
        {
          exc = null;
          entrySet6.remove(e);
        }
        catch (Exception ex)
        {
          exc = ex;
        }
        assertTrue(exc != null);
        assertTrue(exc instanceof UnsupportedOperationException);
      }

      // entrySet addAll
      try
      {
        exc = null;
        entrySet6.addAll(adds.entrySet());
      }
      catch (Exception ex)
      {
        exc = ex;
      }
      assertTrue(exc != null);
      assertTrue(exc instanceof UnsupportedOperationException);

      // entrySet clear
      try
      {
        exc = null;
        entrySet6.clear();
      }
      catch (Exception ex)
      {
        exc = ex;
      }
      assertTrue(exc != null);
      assertTrue(exc instanceof UnsupportedOperationException);

      // entrySet removeAll
      Collection<?> collectionsToRemove[] = { adds.entrySet(), Collections.emptySet() };
      for (Collection<?> c : collectionsToRemove)
      {
        try
        {
          exc = null;
          entrySet6.removeAll(c);
        }
        catch (Exception ex)
        {
          exc = ex;
        }
        assertTrue(exc != null);
        assertTrue(exc instanceof UnsupportedOperationException);
      }

      // entrySet retainAll
      try
      {
        exc = null;
        entrySet6.retainAll(adds.entrySet());
      }
      catch (Exception ex)
      {
        exc = ex;
      }
      assertTrue(exc != null);
      assertTrue(exc instanceof UnsupportedOperationException);

      // entrySet equals, isEmpty
      MapTemplate map7 = templateClass.newInstance();
      MapTemplate map8 = templateClass.newInstance();
      map8.putAll(input);
      Set<Map.Entry<String, E>> entrySet7 = map7.entrySet();
      assertTrue(entrySet7.isEmpty());
      Map<String, E> hashMap7 = new HashMap<String, E>();
      lastHash = 0;
      for (int i = 0; i < inputList.size(); ++i)
      {
        Map.Entry<String,E> entry = inputList.get(i);
        map7.put(entry.getKey(), entry.getValue());
        hashMap7.put(entry.getKey(), entry.getValue());

        if (i == (inputList.size() - 1))
        {
          assertTrue(entrySet7.equals(map8.entrySet()));
        }
        else
        {
          assertFalse(entrySet7.equals(map8.entrySet()));
          assertTrue(entrySet7.equals(hashMap7.entrySet()));
        }
        assertTrue(entrySet7.toString().contains(entry.getKey()));
        assertTrue(entrySet7.toString().contains(entry.getValue().toString()));

        int newHash = entrySet7.hashCode();
        if (i > 0)
        {
          assertFalse(lastHash == newHash);
        }

        lastHash = newHash;

        assertFalse(entrySet7.isEmpty());
      }
      assertTrue(entrySet7.equals(input.entrySet()));
      assertFalse(map7.entrySet().equals(null));
      assertFalse(map7.entrySet().equals(new Object()));

      // test Map.Entry.set()
      MapTemplate map9 = templateClass.newInstance();
      map9.putAll(input);
      lastValue = null;
      for (Map.Entry<String, E> e : map9.entrySet())
      {
        E value = e.getValue();
        if (lastValue != null)
        {
          exc = null;
          try
          {
            E ret = e.setValue(lastValue);
            /* CowMap entrySet() returns unmodifiable view.
               This may change if don't use CowMap to back DataMap.
            assertEquals(ret, value);
            assertEquals(e.getValue(), lastValue);
            assertEquals(map9.get(e.getKey()), lastValue);
            */
          }
          catch (Exception ex)
          {
            exc = ex;
          }
          assertTrue(exc instanceof UnsupportedOperationException);
        }
        lastValue = value;
      }
    }
    catch (IllegalAccessException exc)
    {
      fail("Unexpected exception", exc);
    }
    catch (InstantiationException exc)
    {
      fail("Unexpected exception", exc);
    }
  }

  public <MapTemplate extends AbstractMapTemplate<E>, E>
  void testMapBadInput(Class<MapTemplate> templateClass,
                       MapDataSchema schema,
                       Map<String, E> good,
                       Map<String, Object> badInput,
                       Map<String, Object> badOutput)
  {

    MapTemplate mapTemplateBad = null;
    try
    {
      mapTemplateBad = templateClass.newInstance();
    }
    catch (IllegalAccessException exc)
    {
      fail("Unexpected exception", exc);
    }
    catch (InstantiationException exc)
    {
      fail("Unexpected exception", exc);
    }

    Exception exc = null;
    DataMap badDataMap = new DataMap();

    @SuppressWarnings("unchecked")
    Map<String, E> badIn = (Map<String, E>) badInput;

    // put(String key, E element)
    for (Map.Entry<String, E> entry : badIn.entrySet())
    {
      exc = null;
      E value = entry.getValue();
      try
      {
        mapTemplateBad.put(entry.getKey(), value);
      }
      catch (Exception e)
      {
        exc = e;
      }
      assertTrue(exc != null);
      assertTrue(value == null || exc instanceof ClassCastException);
      assertTrue(value != null || exc instanceof NullPointerException);
    }

    // putAll(Collection<E> c)
    try
    {
      exc = null;
      mapTemplateBad.putAll(badIn);
    }
    catch (Exception e)
    {
      exc = e;
    }
    assertTrue(exc != null);
    assertTrue(exc instanceof ClassCastException);

    badDataMap.clear();
    badDataMap.putAll(badOutput);
    MapTemplate badWrappedMapTemplate = DataTemplateUtil.wrap(badDataMap, schema, templateClass);

    // Get bad
    for (String key : badOutput.keySet())
    {
      try
      {
        exc = null;
        badWrappedMapTemplate.get(key);
      }
      catch (Exception e)
      {
        exc = e;
      }
      assertTrue(exc != null);
      assertTrue(exc instanceof TemplateOutputCastException);
    }

    // Set returns bad
    badDataMap.clear();
    badDataMap.putAll(badOutput);
    assertEquals(badWrappedMapTemplate.size(), badOutput.size());
    for (String key : badOutput.keySet())
    {
      try
      {
        exc = null;
        badWrappedMapTemplate.put(key, good.get(good.keySet().iterator().next()));
      }
      catch (Exception e)
      {
        exc = e;
      }
      assertTrue(exc != null);
      assertTrue(exc instanceof TemplateOutputCastException);
    }

    // Remove returns bad
    badDataMap.clear();
    badDataMap.putAll(badOutput);
    assertEquals(badWrappedMapTemplate.size(), badOutput.size());
    for (String key : badOutput.keySet())
    {
      try
      {
        exc = null;
        badWrappedMapTemplate.remove(key);
      }
      catch (Exception e)
      {
        exc = e;
      }
      assertTrue(exc != null);
      assertTrue(exc instanceof TemplateOutputCastException);
    }

    // entrySet returns bad
    badDataMap.clear();
    badDataMap.putAll(badOutput);
    for (Map.Entry<String, E> entry : badWrappedMapTemplate.entrySet())
    {
      try
      {
        exc = null;
        entry.getValue();
      }
      catch (Exception e)
      {
        exc = e;
      }
      assertTrue(exc != null);
      assertTrue(exc instanceof TemplateOutputCastException);
    }
  }

  @SuppressWarnings("unchecked")
  public <MapTemplate extends AbstractMapTemplate<E>, E extends Number>
  void testNumberMap(Class<MapTemplate> templateClass,
                     MapDataSchema schema,
                     Map<String, E> castTo,
                     Map<String, ? extends Number> castFrom)
  {
    try
    {
      // test insert non-native, converted to element type on set
      MapTemplate map1 = templateClass.newInstance();
      map1.putAll((Map<String, E>) castFrom);
      for (String i : castFrom.keySet())
      {
        assertEquals(castTo.get(i), map1.get(i));
        assertEquals(map1.data().get(i), castTo.get(i));
      }

      // test underlying is non-native, convert on get to element type on get.
      DataMap dataList2 = new DataMap(castFrom);
      MapTemplate map2 = DataTemplateUtil.wrap(dataList2, schema, templateClass);
      for (String i : castTo.keySet())
      {
        assertSame(dataList2.get(i), castFrom.get(i));
        assertEquals(castTo.get(i), map2.get(i));
      }

      // test entrySet, convert on access to element type
      int lastHash = 0;
      boolean first = true;
      for (Map.Entry<String, E> e : map2.entrySet())
      {
        String key = e.getKey();
        E castToValue = castTo.get(key);
        assertEquals(e.getValue(), castToValue);
        assertTrue(e.equals(new AbstractMap.SimpleEntry<String,E>(key, castToValue)));
        assertFalse(e.equals(null));
        assertFalse(e.equals(new Object()));

        String eToString = e.toString();
        assertEquals(eToString, key + "=" + castToValue.toString());

        // hashCode
        int newHash = e.hashCode();
        if (!first)
        {
          assertTrue(lastHash != newHash);
        }

        first = false;
        lastHash = newHash;
      }
    }
    catch (IllegalAccessException exc)
    {
      fail("Unexpected exception", exc);
    }
    catch (InstantiationException exc)
    {
      fail("Unexpected exception", exc);
    }
  }

  @Test
  public void testBooleanMap()
  {
    MapDataSchema schema = (MapDataSchema) DataTemplateUtil.parseSchema("{ \"type\" : \"map\", \"values\" : \"boolean\" }");

    Map<String, Boolean> input = asMap("true", true, "false", false);
    Map<String, Boolean> adds = asMap("thirteen", true, "seventeen", false, "nineteen", true);
    Map<String, Object> badInput = asMap("integer", 99, "long", 999L, "float", 88.0f, "double", 888.0, "string", "hello",
                                         "bytes", ByteString.empty(),
                                         "object", new Object(),
                                         "null", null,
                                         "array", new StringArray(),
                                         "record", new FooRecord());
    Map<String, Object> badOutput = asMap("integer", 99, "long", 999L, "float", 88.0f, "double", 888.0, "string", "hello",
                                          "bytes", ByteString.empty(),
                                          "map", new DataMap(),
                                          "list", new DataList());

    testMap(BooleanMap.class, schema, input, adds);
    testMapBadInput(BooleanMap.class, schema, input, badInput, badOutput);
  }

  @Test
  public void testIntegerMap()
  {
    MapDataSchema schema = (MapDataSchema) DataTemplateUtil.parseSchema("{ \"type\" : \"map\", \"values\" : \"int\" }");

    Map<String, Integer> input = asMap("one", 1, "three", 3, "five", 5, "seven", 7, "eleven", 11);
    Map<String, Integer> adds = asMap("thirteen", 13, "seventeen", 17, "nineteen", 19);
    Map<String, Object> badInput = asMap("boolean", true, "string", "hello",
                                         "bytes", ByteString.empty(),
                                         "object", new Object(),
                                         "null", null,
                                         "array", new StringArray(),
                                         "record", new FooRecord());
    Map<String, Object> badOutput = asMap("boolean", true, "string", "hello",
                                          "bytes", ByteString.empty(),
                                          "map", new DataMap(),
                                          "list", new DataList());

    testMap(IntegerMap.class, schema, input, adds);
    testMapBadInput(IntegerMap.class, schema, input, badInput, badOutput);

    Map<String, ? extends Number> castFrom = asMap("one", 1L, "three", 3.0f, "five", 5.0, "seven", 7, "eleven", 11);
    testNumberMap(IntegerMap.class, schema, input, castFrom);
  }

  @Test
  public void testLongMap()
  {
    MapDataSchema schema = (MapDataSchema) DataTemplateUtil.parseSchema("{ \"type\" : \"map\", \"values\" : \"long\" }");

    Map<String, Long> input = asMap("one", 1L, "three", 3L, "five", 5L, "seven", 7L, "eleven", 11L);
    Map<String, Long> adds = asMap("thirteen", 13L, "seventeen", 17L, "nineteen", 19L);
    Map<String, Object> badInput = asMap("boolean", true, "string", "hello",
                                         "bytes", ByteString.empty(),
                                         "object", new Object(),
                                         "null", null,
                                         "array", new StringArray(),
                                         "record", new FooRecord());
    Map<String, Object> badOutput = asMap("boolean", true, "string", "hello",
                                          "bytes", ByteString.empty(),
                                          "map", new DataMap(),
                                          "list", new DataList());

    testMap(LongMap.class, schema, input, adds);
    testMapBadInput(LongMap.class, schema, input, badInput, badOutput);

    Map<String, ? extends Number> castFrom = asMap("one", 1, "three", 3.0f, "five", 5.0, "seven", 7, "eleven", 11);
    testNumberMap(LongMap.class, schema, input, castFrom);
  }

  @Test
  public void testFloatMap()
  {
    MapDataSchema schema = (MapDataSchema) DataTemplateUtil.parseSchema("{ \"type\" : \"map\", \"values\" : \"float\" }");

    Map<String, Float> input = asMap("one", 1.0f, "three", 3.0f, "five", 5.0f, "seven", 7.0f, "eleven", 11.0f);
    Map<String, Float> adds = asMap("thirteen", 13.0f, "seventeen", 17.0f, "nineteen", 19.0f);
    Map<String, Object> badInput = asMap("boolean", true, "string", "hello",
                                         "bytes", ByteString.empty(),
                                         "object", new Object(),
                                         "null", null,
                                         "array", new StringArray(),
                                         "record", new FooRecord());
    Map<String, Object> badOutput = asMap("boolean", true, "string", "hello",
                                          "bytes", ByteString.empty(),
                                          "map", new DataMap(),
                                          "list", new DataList());

    testMap(FloatMap.class, schema, input, adds);
    testMapBadInput(FloatMap.class, schema, input, badInput, badOutput);

    Map<String, ? extends Number> castFrom = asMap("one", 1, "three", 3L, "five", 5.0, "seven", 7, "eleven", 11);
    testNumberMap(FloatMap.class, schema, input, castFrom);
  }

  @Test
  public void testDoubleMap()
  {
    MapDataSchema schema = (MapDataSchema) DataTemplateUtil.parseSchema("{ \"type\" : \"map\", \"values\" : \"double\" }");

    Map<String, Double> input = asMap("one", 1.0, "three", 3.0, "five", 5.0, "seven", 7.0, "eleven", 11.0);
    Map<String, Double> adds = asMap("thirteen", 13.0, "seventeen", 17.0, "nineteen", 19.0);
    Map<String, Object> badInput = asMap("boolean", true, "string", "hello",
                                         "bytes", ByteString.empty(),
                                         "object", new Object(),
                                         "null", null,
                                         "array", new StringArray(),
                                         "record", new FooRecord());
    Map<String, Object> badOutput = asMap("boolean", true, "string", "hello",
                                          "bytes", ByteString.empty(),
                                          "map", new DataMap(),
                                          "list", new DataList());

    testMap(DoubleMap.class, schema, input, adds);
    testMapBadInput(DoubleMap.class, schema, input, badInput, badOutput);

    Map<String, ? extends Number> castFrom = asMap("one", 1, "three", 3L, "five", 5.0f, "seven", 7, "eleven", 11);
    testNumberMap(DoubleMap.class, schema, input, castFrom);
  }

  @Test
  public void testStringMap()
  {
    MapDataSchema schema = (MapDataSchema) DataTemplateUtil.parseSchema("{ \"type\" : \"map\", \"values\" : \"string\" }");

    Map<String, String> input = asMap("one", "1", "three", "3", "five", "5", "seven", "7", "eleven", "11");
    Map<String, String> adds = asMap("thirteen", "13", "seventeen", "17", "nineteen", "19");
    Map<String, Object> badInput = asMap("boolean", true, "integer", 99, "long", 999L, "float", 88.0f, "double", 888.0,
                                         "bytes", ByteString.empty(),
                                         "object", new Object(),
                                         "null", null,
                                         "array", new StringArray(),
                                         "record", new FooRecord());
    Map<String, Object> badOutput = asMap("boolean", true, "integer", 99, "long", 999L, "float", 88.0f, "double", 888.0,
                                          "bytes", ByteString.empty(),
                                          "map", new DataMap(),
                                          "list", new DataList());

    testMap(StringMap.class, schema, input, adds);
    testMapBadInput(StringMap.class, schema, input, badInput, badOutput);
  }

  @Test
  public void testBytesMap()
  {
    MapDataSchema schema = (MapDataSchema) DataTemplateUtil.parseSchema("{ \"type\" : \"map\", \"values\" : \"bytes\" }");

    Map<String, ByteString> input = asMap("one", ByteString.copyAvroString("1", false), "three", ByteString.copyAvroString("3", false), "five", ByteString.copyAvroString("5", false), "seven", ByteString.copyAvroString("7", false), "eleven", ByteString.copyAvroString("11", false));
    Map<String, ByteString> adds = asMap("thirteen", ByteString.copyAvroString("13", false), "seventeen", ByteString.copyAvroString("17", false), "nineteen", ByteString.copyAvroString("19", false));
    Map<String, Object> badInput = asMap("boolean", true, "integer", 99, "long", 999L, "float", 88.0f, "double", 888.0,
                                         "data", "\u0100",
                                         "object", new Object(),
                                         "null", null,
                                         "array", new StringArray(),
                                         "record", new FooRecord());
    Map<String, Object> badOutput = asMap("boolean", true, "integer", 99, "long", 999L, "float", 88.0f, "double", 888.0,
                                          "data", "\u0100",
                                          "map", new DataMap(),
                                          "list", new DataList());

    testMap(BytesMap.class, schema, input, adds);
    testMapBadInput(BytesMap.class, schema, input, badInput, badOutput);
  }

  public static enum Fruits
  {
    APPLE, ORANGE, BANANA, GRAPES, PINEAPPLE
  }

  public static class EnumMapTemplate extends com.linkedin.data.template.DirectMapTemplate<Fruits>
  {
    public static final MapDataSchema SCHEMA = (MapDataSchema) DataTemplateUtil.parseSchema("{ \"type\" : \"map\", \"values\" : { \"type\" : \"enum\", \"name\" : \"Fruits\", \"symbols\" : [ \"APPLE\", \"ORANGE\", \"BANANA\", \"GRAPES\", \"PINEAPPLE\" ] } }");
    public EnumMapTemplate()
    {
      this(new DataMap());
    }
    public EnumMapTemplate(int capacity)
    {
      this(new DataMap(capacity));
    }
    public EnumMapTemplate(int capacity, float loadFactor)
    {
      this(new DataMap(capacity, loadFactor));
    }
    public EnumMapTemplate(Map<String, Fruits> map)
    {
      this(newDataMapOfSize(map.size()));
      putAll(map);
    }
    public EnumMapTemplate(DataMap map)
    {
      super(map, SCHEMA, Fruits.class, String.class);
    }
    @Override
    public EnumMapTemplate clone() throws CloneNotSupportedException
    {
      return (EnumMapTemplate) super.clone();
    }
    @Override
    public EnumMapTemplate copy() throws CloneNotSupportedException
    {
      return (EnumMapTemplate) super.copy();
    }
  }

  @Test
  public void testEnumMap()
  {
    Map<String, Fruits> input = asMap("apple", Fruits.APPLE, "orange", Fruits.ORANGE, "banana", Fruits.BANANA); // must be unique
    Map<String, Fruits> adds = asMap("grapes", Fruits.GRAPES, "pineapple", Fruits.PINEAPPLE);
    Map<String, Object> badInput = asMap("boolean", true, "integer", 1, "long", 2L, "float", 3.0f, "double", 4.0, "string", "hello",
                                         "bytes", ByteString.empty(),
                                         "object", new Object(),
                                         "null", null,
                                         "array", new StringArray(),
                                         "record", new FooRecord());
    Map<String, Object> badOutput = asMap("boolean", true, "integer", 1, "long", 2L, "float", 3.0f, "double", 4.0, "string", "hello",
                                          "bytes", ByteString.empty(),
                                          "map", new DataMap(),
                                          "list", new DataList());

    testMap(EnumMapTemplate.class, EnumMapTemplate.SCHEMA, input, adds);
    testMapBadInput(EnumMapTemplate.class, EnumMapTemplate.SCHEMA, input, badInput, badOutput);
  }

  public static class MapOfStringMapTemplate extends WrappingMapTemplate<StringMap>
  {
    public static final MapDataSchema SCHEMA = (MapDataSchema) DataTemplateUtil.parseSchema("{ \"type\" : \"map\", \"values\" : { \"type\" : \"map\", \"values\" : \"string\" } }");
    public MapOfStringMapTemplate()
    {
      this(new DataMap());
    }
    public MapOfStringMapTemplate(int capacity)
    {
      this(new DataMap(capacity));
    }
    public MapOfStringMapTemplate(int capacity, float loadFactor)
    {
      this(new DataMap(capacity, loadFactor));
    }
    public MapOfStringMapTemplate(Map<String, StringMap> map)
    {
      this(newDataMapOfSize(map.size()));
      putAll(map);
    }
    public MapOfStringMapTemplate(DataMap map)
    {
      super(map, SCHEMA, StringMap.class);
    }
    @Override
    public MapOfStringMapTemplate clone() throws CloneNotSupportedException
    {
      return (MapOfStringMapTemplate) super.clone();
    }
    @Override
    public MapOfStringMapTemplate copy() throws CloneNotSupportedException
    {
      return (MapOfStringMapTemplate) super.copy();
    }
  }

  @Test
  public void testMapOfStringMap()
  {
    Map<String, StringMap> input = new HashMap<String, StringMap>();
    for (int i = 0; i < 5; ++i)
    {
      String key = "input" + i;
      input.put(key, new StringMap());
      input.get(key).put("subinput" + i, "subinputvalue" + i);
    }
    Map<String, StringMap> adds = new HashMap<String, StringMap>();
    for (int i = 0; i < 5; ++i)
    {
      String key = "add" + i;
      adds.put(key, new StringMap());
      adds.get(key).put("subadd" + i, "subaddvalue" + i);
    }
    Map<String, Object> badInput = asMap("boolean", true, "integer", 1, "long", 2L, "float", 3.0f, "double", 4.0, "string", "hello",
                                         "bytes", ByteString.empty(),
                                         "object", new Object(),
                                         "null", null,
                                         "array", new StringArray(),
                                         "record", new FooRecord());
    Map<String, Object> badOutput = asMap("boolean", true, "integer", 1, "long", 2L, "float", 3.0f, "double", 4.0, "string", "hello",
                                          "bytes", ByteString.empty(),
                                          "list", new DataList());

    testMap(MapOfStringMapTemplate.class, MapOfStringMapTemplate.SCHEMA, input, adds);
    testMapBadInput(MapOfStringMapTemplate.class, MapOfStringMapTemplate.SCHEMA, input, badInput, badOutput);
  }

  public static class FooRecord extends RecordTemplate
  {
    public static final RecordDataSchema SCHEMA = (RecordDataSchema) DataTemplateUtil.parseSchema("{ \"type\" : \"record\", \"name\" : \"Foo\", \"fields\" : [ { \"name\" : \"bar\", \"type\" : \"string\" } ] }");
    public static final RecordDataSchema.Field FIELD_bar = SCHEMA.getField("bar");

    public FooRecord()
    {
      super(new DataMap(), SCHEMA);
    }
    public FooRecord(DataMap map)
    {
      super(map, SCHEMA);
    }

    public String getBar(GetMode mode)
    {
      return obtainDirect(FIELD_bar, String.class, mode);
    }

    public void removeBar()
    {
      remove(FIELD_bar);
    }

    public void setBar(String value)
    {
      putDirect(FIELD_bar, String.class, value);
    }

    @Override
    public FooRecord clone() throws CloneNotSupportedException
    {
      return (FooRecord) super.clone();
    }

    @Override
    public FooRecord copy() throws CloneNotSupportedException
    {
      return (FooRecord) super.copy();
    }
  }

  public static class FooRecordMap extends WrappingMapTemplate<FooRecord>
  {
    public static final MapDataSchema SCHEMA = (MapDataSchema) DataTemplateUtil.parseSchema("{ \"type\" : \"map\", \"values\" : { \"type\" : \"record\", \"name\" : \"Foo\", \"fields\" : [ { \"name\" : \"bar\", \"type\" : \"string\" } ] } }");
    public FooRecordMap()
    {
      this(new DataMap());
    }
    public FooRecordMap(int capacity)
    {
      this(new DataMap(capacity));
    }
    public FooRecordMap(int capacity, float loadFactor)
    {
      this(new DataMap(capacity, loadFactor));
    }
    public FooRecordMap(Map<String, FooRecord> map)
    {
      this(newDataMapOfSize(map.size()));
      putAll(map);
    }
    public FooRecordMap(DataMap map)
    {
      super(map, SCHEMA, FooRecord.class);
    }
    @Override
    public FooRecordMap clone() throws CloneNotSupportedException
    {
      return (FooRecordMap) super.clone();
    }
    @Override
    public FooRecordMap copy() throws CloneNotSupportedException
    {
      return (FooRecordMap) super.copy();
    }
  }

  @Test
  public void testFooRecordMap()
  {
    Map<String, FooRecord> input = new HashMap<String, FooRecord>();
    for (int i = 0; i < 5; ++i)
    {
      String key = "input" + i;
      input.put(key, new FooRecord());
      input.get(key).setBar("subinputvalue" + i);
    }
    Map<String, FooRecord> adds = new HashMap<String, FooRecord>();
    for (int i = 0; i < 5; ++i)
    {
      String key = "add" + i;
      adds.put(key, new FooRecord());
      adds.get(key).setBar("subaddvalue" + i);
    }
    Map<String, Object> badInput = asMap("boolean", true, "integer", 1, "long", 2L, "float", 3.0f, "double", 4.0, "string", "hello",
                                         "bytes", ByteString.empty(),
                                         "object", new Object(),
                                         "null", null,
                                         "array", new StringArray());
    Map<String, Object> badOutput = asMap("boolean", true, "integer", 1, "long", 2L, "float", 3.0f, "double", 4.0, "string", "hello",
                                          "bytes", ByteString.empty(),
                                          "list", new DataList());

    testMap(FooRecordMap.class, FooRecordMap.SCHEMA, input, adds);
    testMapBadInput(FooRecordMap.class, FooRecordMap.SCHEMA, input, badInput, badOutput);
  }

  public <E> void dump(Set<Map.Entry<String,E>> set)
  {
    for (Map.Entry<String,E> entry : set)
    {
      Object k = entry.getKey();
      Object v = entry.getValue();
      out.println(k + "(" + k.getClass() + ") = " + v + " (" + v.getClass() + ") " + entry.hashCode());
    }
  }

  protected static class PrimitiveLegacyMap<T> extends DirectMapTemplate<T>
  {
    public PrimitiveLegacyMap(DataMap map, MapDataSchema schema, Class<T> valuesClass)
    {
      super(map, schema, valuesClass);
      assertSame(_dataClass, valuesClass);
    }
  }

  protected static class EnumLegacyMap extends DirectMapTemplate<Fruits>
  {
    public static final MapDataSchema SCHEMA = (MapDataSchema) DataTemplateUtil.parseSchema("{ \"type\" : \"map\", \"values\" : { \"type\" : \"enum\", \"name\" : \"Fruits\", \"symbols\" : [ \"APPLE\", \"ORANGE\", \"BANANA\", \"GRAPES\", \"PINEAPPLE\" ] } }");
    public EnumLegacyMap(DataMap map)
    {
      super(map, SCHEMA, Fruits.class);
      assertSame(_dataClass, String.class);
    }
  }

  @Test
  public void testLegacyConstructor()
  {
    Map<String, Class<?>> primitiveStringToClassMap = asMap(
      "int", Integer.class,
      "long", Long.class,
      "float", Float.class,
      "double", Double.class,
      "boolean", Boolean.class,
      "string", String.class);
    for (Map.Entry<String, Class<?>> e : primitiveStringToClassMap.entrySet())
    {
      MapDataSchema schema = (MapDataSchema) DataTemplateUtil.parseSchema("{ \"type\" : \"map\", \"values\" : \"" + e.getKey() + "\" }");
      @SuppressWarnings("unchecked")
      PrimitiveLegacyMap<?> map = new PrimitiveLegacyMap<Object>(new DataMap(), schema, (Class)e.getValue());
    }
    EnumLegacyMap enumMap = new EnumLegacyMap(new DataMap());
  }
}
TOP

Related Classes of com.linkedin.data.template.TestMapTemplate$FooRecord

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.