/* * Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file 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.amazonaws.services.dynamodbv2.datamodeling.internal; import static com.amazonaws.services.dynamodbv2.datamodeling.internal.AttributeValueMarshaller.marshall; import static com.amazonaws.services.dynamodbv2.datamodeling.internal.AttributeValueMarshaller.unmarshall; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.junit.Assert; import org.junit.Test; import com.amazonaws.services.dynamodbv2.model.AttributeValue; import com.amazonaws.util.Base64; public class AttributeValueMarshallerTest { @Test(expected=IllegalArgumentException.class) public void testEmpty() { AttributeValue av = new AttributeValue(); marshall(av); } @Test public void testNumber() { AttributeValue av = new AttributeValue().withN("1337"); assertEquals(av, unmarshall(marshall(av))); } @Test public void testString() { AttributeValue av = new AttributeValue().withS("1337"); assertEquals(av, unmarshall(marshall(av))); } @Test public void testByteBuffer() { AttributeValue av = new AttributeValue().withB(ByteBuffer.wrap(new byte[] {0, 1, 2, 3, 4, 5})); assertEquals(av, unmarshall(marshall(av))); } // We can't use straight .equals for comparison because Attribute Values represents Sets // as Lists and so incorrectly does an ordered comparison @Test public void testNumberS() { AttributeValue av = new AttributeValue().withNS(Collections.unmodifiableList(Arrays.asList("1337", "1", "5"))); assertEquals(av, unmarshall(marshall(av))); } @Test public void testNumberSOrdering() { AttributeValue av1 = new AttributeValue().withNS(Collections.unmodifiableList(Arrays.asList("1337", "1", "5"))); AttributeValue av2 = new AttributeValue().withNS(Collections.unmodifiableList(Arrays.asList("1", "5", "1337"))); assertEquals(av1, av2); ByteBuffer buff1 = marshall(av1); ByteBuffer buff2 = marshall(av2); Assert.assertEquals(buff1, buff2); } @Test public void testStringS() { AttributeValue av = new AttributeValue().withSS(Collections.unmodifiableList(Arrays.asList("Bob", "Ann", "5"))); assertEquals(av, unmarshall(marshall(av))); } @Test public void testStringSOrdering() { AttributeValue av1 = new AttributeValue().withSS(Collections.unmodifiableList(Arrays.asList("Bob", "Ann", "5"))); AttributeValue av2 = new AttributeValue().withSS(Collections.unmodifiableList(Arrays.asList("Ann", "Bob", "5"))); assertEquals(av1, av2); ByteBuffer buff1 = marshall(av1); ByteBuffer buff2 = marshall(av2); Assert.assertEquals(buff1, buff2); } @Test public void testByteBufferS() { AttributeValue av = new AttributeValue().withBS(Collections.unmodifiableList( Arrays.asList(ByteBuffer.wrap(new byte[] {0, 1, 2, 3, 4, 5}), ByteBuffer.wrap(new byte[] {5, 4, 3, 2, 1, 0, 0, 0, 5, 6, 7})))); assertEquals(av, unmarshall(marshall(av))); } @Test public void testByteBufferSOrdering() { AttributeValue av1 = new AttributeValue().withBS(Collections.unmodifiableList( Arrays.asList(ByteBuffer.wrap(new byte[] {0, 1, 2, 3, 4, 5}), ByteBuffer.wrap(new byte[] {5, 4, 3, 2, 1, 0, 0, 0, 5, 6, 7})))); AttributeValue av2 = new AttributeValue().withBS(Collections.unmodifiableList( Arrays.asList(ByteBuffer.wrap(new byte[] {5, 4, 3, 2, 1, 0, 0, 0, 5, 6, 7}), ByteBuffer.wrap(new byte[] {0, 1, 2, 3, 4, 5}) ))); assertEquals(av1, av2); ByteBuffer buff1 = marshall(av1); ByteBuffer buff2 = marshall(av2); Assert.assertEquals(buff1, buff2); } @Test public void testBoolTrue() { AttributeValue av = new AttributeValue().withBOOL(Boolean.TRUE); assertEquals(av, unmarshall(marshall(av))); } @Test public void testBoolFalse() { AttributeValue av = new AttributeValue().withBOOL(Boolean.FALSE); assertEquals(av, unmarshall(marshall(av))); } @Test public void testNULL() { AttributeValue av = new AttributeValue().withNULL(Boolean.TRUE); assertEquals(av, unmarshall(marshall(av))); } @Test(expected = NullPointerException.class) public void testActualNULL() { unmarshall(marshall(null)); } @Test public void testEmptyList() { AttributeValue av = new AttributeValue().withL(); assertEquals(av, unmarshall(marshall(av))); } @Test public void testListOfString() { AttributeValue av = new AttributeValue().withL(new AttributeValue().withS("StringValue") ); assertEquals(av, unmarshall(marshall(av))); } @Test public void testList() { AttributeValue av = new AttributeValue().withL( new AttributeValue().withS("StringValue"), new AttributeValue().withN("1000"), new AttributeValue().withBOOL(Boolean.TRUE)); assertEquals(av, unmarshall(marshall(av))); } @Test public void testListWithNull() { final AttributeValue av = new AttributeValue().withL( new AttributeValue().withS("StringValue"), new AttributeValue().withN("1000"), new AttributeValue().withBOOL(Boolean.TRUE), null); try { marshall(av); Assert.fail("Unexpected success"); } catch (final NullPointerException npe) { Assert.assertEquals("Encountered null list entry value while marshalling attribute value {L: [{S: StringValue,}, {N: 1000,}, {BOOL: true}, null],}", npe.getMessage()); } } @Test public void testListDuplicates() { AttributeValue av = new AttributeValue().withL( new AttributeValue().withN("1000"), new AttributeValue().withN("1000"), new AttributeValue().withN("1000"), new AttributeValue().withN("1000")); AttributeValue result = unmarshall(marshall(av)); assertEquals(av, result); Assert.assertEquals(4, result.getL().size()); } @Test public void testComplexList() { final List<AttributeValue> list1 = Arrays.asList( new AttributeValue().withS("StringValue"), new AttributeValue().withN("1000"), new AttributeValue().withBOOL(Boolean.TRUE)); final List<AttributeValue> list22 = Arrays.asList( new AttributeValue().withS("AWS"), new AttributeValue().withN("-3700"), new AttributeValue().withBOOL(Boolean.FALSE)); final List<AttributeValue> list2 = Arrays.asList( new AttributeValue().withL(list22), new AttributeValue().withNULL(Boolean.TRUE)); AttributeValue av = new AttributeValue().withL( new AttributeValue().withS("StringValue1"), new AttributeValue().withL(list1), new AttributeValue().withN("50"), new AttributeValue().withL(list2)); assertEquals(av, unmarshall(marshall(av))); } @Test public void testEmptyMap() { Map<String,AttributeValue> map = new HashMap<String,AttributeValue>(); AttributeValue av = new AttributeValue().withM(map); assertEquals(av, unmarshall(marshall(av))); } @Test public void testSimpleMap() { Map<String, AttributeValue> map = new HashMap<String,AttributeValue>(); map.put("KeyValue", new AttributeValue().withS("ValueValue")); AttributeValue av = new AttributeValue().withM(map); assertEquals(av, unmarshall(marshall(av))); } @Test public void testSimpleMapWithNull() { final Map<String, AttributeValue> map = new HashMap<String,AttributeValue>(); map.put("KeyValue", new AttributeValue().withS("ValueValue")); map.put("NullKeyValue", null); final AttributeValue av = new AttributeValue().withM(map); try { marshall(av); Assert.fail("Unexpected success"); } catch (final NullPointerException npe) { Assert.assertEquals("Encountered null map value for key NullKeyValue while marshalling attribute value {M: {KeyValue={S: ValueValue,}, NullKeyValue=null},}", npe.getMessage()); } } @Test public void testMapOrdering() { LinkedHashMap<String, AttributeValue> m1 = new LinkedHashMap<String, AttributeValue>(); LinkedHashMap<String, AttributeValue> m2 = new LinkedHashMap<String, AttributeValue>(); m1.put("Value1", new AttributeValue().withN("1")); m1.put("Value2", new AttributeValue().withBOOL(Boolean.TRUE)); m2.put("Value2", new AttributeValue().withBOOL(Boolean.TRUE)); m2.put("Value1", new AttributeValue().withN("1")); AttributeValue av1 = new AttributeValue().withM(m1); AttributeValue av2 = new AttributeValue().withM(m2); ByteBuffer buff1 = marshall(av1); ByteBuffer buff2 = marshall(av2); Assert.assertEquals(buff1, buff2); assertEquals(av1, unmarshall(buff1)); assertEquals(av1, unmarshall(buff2)); assertEquals(av2, unmarshall(buff1)); assertEquals(av2, unmarshall(buff2)); } @Test public void testComplexMap() { AttributeValue av = buildComplexAttributeValue(); assertEquals(av, unmarshall(marshall(av))); } // This test ensures that an AttributeValue marshalled by an older // version of this library still unmarshalls correctly. It also // ensures that old and new marshalling is identical. @Test public void testVersioningCompatibility() { AttributeValue newObject = buildComplexAttributeValue(); byte[] oldBytes = Base64.decode(COMPLEX_ATTRIBUTE_MARSHALLED); byte[] newBytes = marshall(newObject).array(); Assert.assertArrayEquals(oldBytes, newBytes); AttributeValue oldObject = unmarshall(ByteBuffer.wrap(oldBytes)); assertEquals(oldObject, newObject); } private static final String COMPLEX_ATTRIBUTE_MARSHALLED = "AE0AAAADAHM" + "AAAAJSW5uZXJMaXN0AEwAAAAGAHMAAAALQ29tcGxleExpc3QAbgAAAAE1AGIAA" + "AAGAAECAwQFAEwAAAAFAD8BAAAAAABMAAAAAQA/AABNAAAAAwBzAAAABFBpbms" + "AcwAAAAVGbG95ZABzAAAABFRlc3QAPwEAcwAAAAdWZXJzaW9uAG4AAAABMQAAA" + "E0AAAADAHMAAAAETGlzdABMAAAABQBuAAAAATUAbgAAAAE0AG4AAAABMwBuAAA" + "AATIAbgAAAAExAHMAAAADTWFwAE0AAAABAHMAAAAGTmVzdGVkAD8BAHMAAAAEV" + "HJ1ZQA/AQBzAAAACVNpbmdsZU1hcABNAAAAAQBzAAAAA0ZPTwBzAAAAA0JBUgB" + "zAAAACVN0cmluZ1NldABTAAAAAwAAAANiYXIAAAADYmF6AAAAA2Zvbw=="; private static AttributeValue buildComplexAttributeValue() { Map<String, AttributeValue> floydMap = new HashMap<String, AttributeValue>(); floydMap.put("Pink", new AttributeValue().withS("Floyd")); floydMap.put("Version", new AttributeValue().withN("1")); floydMap.put("Test", new AttributeValue().withBOOL(Boolean.TRUE)); List<AttributeValue> floydList = Arrays.asList( new AttributeValue().withBOOL(Boolean.TRUE), new AttributeValue().withNULL(Boolean.TRUE), new AttributeValue().withNULL(Boolean.TRUE), new AttributeValue().withL(new AttributeValue().withBOOL(Boolean.FALSE)), new AttributeValue().withM(floydMap) ); List<AttributeValue> nestedList = Arrays.asList( new AttributeValue().withN("5"), new AttributeValue().withN("4"), new AttributeValue().withN("3"), new AttributeValue().withN("2"), new AttributeValue().withN("1") ); Map<String, AttributeValue> nestedMap = new HashMap<String, AttributeValue>(); nestedMap.put("True", new AttributeValue().withBOOL(Boolean.TRUE)); nestedMap.put("List", new AttributeValue().withL(nestedList)); nestedMap.put("Map", new AttributeValue().withM( Collections.singletonMap("Nested", new AttributeValue().withBOOL(Boolean.TRUE)))); List<AttributeValue> innerList = Arrays.asList( new AttributeValue().withS("ComplexList"), new AttributeValue().withN("5"), new AttributeValue().withB(ByteBuffer.wrap(new byte[] {0, 1, 2, 3, 4, 5})), new AttributeValue().withL(floydList), new AttributeValue().withNULL(Boolean.TRUE), new AttributeValue().withM(nestedMap) ); AttributeValue av = new AttributeValue(); av.addMEntry("SingleMap", new AttributeValue().withM( Collections.singletonMap("FOO", new AttributeValue().withS("BAR")))); av.addMEntry("InnerList", new AttributeValue().withL(innerList)); av.addMEntry("StringSet", new AttributeValue().withSS("foo", "bar", "baz")); return av; } private void assertEquals(AttributeValue o1, AttributeValue o2) { Assert.assertEquals(o1.getB(), o2.getB()); assertSetsEqual(o1.getBS(), o2.getBS()); Assert.assertEquals(o1.getN(), o2.getN()); assertSetsEqual(o1.getNS(), o2.getNS()); Assert.assertEquals(o1.getS(), o2.getS()); assertSetsEqual(o1.getSS(), o2.getSS()); Assert.assertEquals(o1.getBOOL(), o2.getBOOL()); Assert.assertEquals(o1.getNULL(), o2.getNULL()); if (o1.getL() != null) { Assert.assertNotNull(o2.getL()); final List<AttributeValue> l1 = o1.getL(); final List<AttributeValue> l2 = o2.getL(); Assert.assertEquals(l1.size(), l2.size()); for (int x = 0; x < l1.size(); ++x) { assertEquals(l1.get(x), l2.get(x)); } } if (o1.getM() != null) { Assert.assertNotNull(o2.getM()); final Map<String, AttributeValue> m1 = o1.getM(); final Map<String, AttributeValue> m2 = o2.getM(); Assert.assertEquals(m1.size(), m2.size()); for (Map.Entry<String, AttributeValue> entry : m1.entrySet()) { assertEquals(entry.getValue(), m2.get(entry.getKey())); } } } private <T> void assertSetsEqual(Collection<T> c1, Collection<T> c2) { Assert.assertFalse(c1 == null ^ c2 == null); if (c1 != null) { Set<T> s1 = new HashSet<T>(c1); Set<T> s2 = new HashSet<T>(c2); Assert.assertEquals(s1, s2); } } }