TEST(DictionarySerializationTest, MultiByteLength) { AmfDictionary d(true, false); for(int i = 0; i < 300; ++i) d.insert(AmfInteger(i), AmfInteger(i)); // for simplicity, only test header and total length v8 expected { 0x11, 0x84, 0x59, 0x00 }; v8 actual(d.serialize()); v8 header(actual.begin(), actual.begin() + 4); ASSERT_EQ(2166, actual.size()); ASSERT_EQ(expected, header); }
TEST(ObjectSerializationTest, DynamicSealedNamedObject) { AmfObjectTraits traits("de.ventero.AmfTest", true, false); AmfObject obj(traits); obj.addSealedProperty("sealedProp", AmfDouble(3.14159)); obj.addDynamicProperty("dynamicProp", AmfInteger(17)); isEqual(v8 { 0x0a, // AMF_OBJECT 0x1b, // 0b11011, U29O-traits, dynamic, 1 sealed property // class-name UTF-8-vr "de.ventero.AmfTest" 0x25, 0x64, 0x65, 0x2e, 0x76, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x2e, 0x41, 0x6d, 0x66, 0x54, 0x65, 0x73, 0x74, // sealed property names // UTF-8-vr "sealedProp" 0x15, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x70, // sealed property values // AmfDouble 3.14159 0x05, 0x40, 0x09, 0x21, 0xf9, 0xf0, 0x1b, 0x86, 0x6e, // dynamic members // UTF-8-vr dynamicProp 0x17, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x50, 0x72, 0x6f, 0x70, // AmfInteger 17 0x04, 0x11, // end of dynamic members 0x01 }, obj); }
TEST(SerializationContext, Clear) { SerializationContext ctx; // Verify the context is initially empty. ASSERT_THROW(ctx.getString(0), std::out_of_range); ASSERT_THROW(ctx.getTraits(0), std::out_of_range); ASSERT_THROW(ctx.getObject<AmfNull>(0), std::out_of_range); // Add a few objects. ctx.addString("foo"); ctx.addString("bar"); ctx.addTraits(AmfObjectTraits("asd", false, false)); ctx.addTraits(AmfObjectTraits("foobar", false, false)); ctx.addTraits(AmfObjectTraits("qux", true, false)); ctx.addObject(AmfInteger(17)); ctx.addObject(AmfDouble(1.0)); ASSERT_NO_THROW(ctx.getString(1)); ASSERT_NO_THROW(ctx.getTraits(2)); ASSERT_NO_THROW(ctx.getObject<AmfDouble>(1)); // Clear and check that it's empty again. ctx.clear(); ASSERT_THROW(ctx.getString(0), std::out_of_range); ASSERT_THROW(ctx.getTraits(0), std::out_of_range); ASSERT_THROW(ctx.getObject<AmfNull>(0), std::out_of_range); }
TEST(SerializerTest, SingleValue) { Serializer s; s << AmfInteger(0xffffffe); v8 expected { 0x04, 0xBF, 0xFF, 0xFF, 0xFE }; ASSERT_EQ(expected, s.data()); }
TEST(DictionaryDeserialization, IntegerKeys) { AmfDictionary d(false, false); d.insert(AmfInteger(3), AmfBool(false)); v8 data { 0x11, 0x03, 0x00, 0x04, 0x03, 0x02, }; deserialize(d, data, 0); d = AmfDictionary(false, false); d.insert(AmfInteger(-16384), AmfString("foo")); data = { 0x11, 0x03, 0x00, 0x04, 0xFF, 0xFF, 0xC0, 0x00, 0x06, 0x07, 0x66, 0x6F, 0x6F }; deserialize(d, data, 0); }
TEST(ArraySerializationTest, AssociativeOnlyArray) { std::map<std::string, AmfInteger> sparse; sparse["bar"] = AmfInteger(17); sparse["foo"] = AmfInteger(0); AmfArray array(std::vector<AmfInteger> { }, sparse); isEqual(v8 { 0x09, // AMF_ARRAY 0x01, // 0 dense elements // assoc-values 0x07, 0x62, 0x61, 0x72, // UTF-8-vr "bar" 0x04, 0x11, // AmfInteger 17 0x07, 0x66, 0x6f, 0x6f, // UTF-8-vr "foo" 0x04, 0x00, // AmfInteger 0 0x01 // end of assoc-values }, array); }
TEST(DictionaryDeserialization, BoolKeys) { AmfDictionary d(false, false); d.insert(AmfBool(false), AmfInteger(3)); v8 data { 0x11, 0x03, 0x00, 0x02, 0x04, 0x03, 0xff, 0xff }; deserialize(d, data, 2); }
TEST(SerializationContext, Pointer) { SerializationContext ctx; ASSERT_THROW(ctx.getPointer<AmfInteger>(0), std::out_of_range); ctx.addPointer(AmfItemPtr(AmfNull())); ASSERT_EQ(AmfNull(), ctx.getPointer<AmfNull>(0).as<AmfNull>()); ASSERT_EQ(AmfNull(), ctx.getObject<AmfNull>(0)); ASSERT_THROW(ctx.getPointer<AmfInteger>(0), std::invalid_argument); ASSERT_THROW(ctx.getObject<AmfInteger>(0), std::invalid_argument); ASSERT_THROW(ctx.getPointer<AmfNull>(1), std::out_of_range); ASSERT_THROW(ctx.getObject<AmfNull>(1), std::out_of_range); ctx.addObject(AmfInteger(11)); ASSERT_EQ(AmfNull(), ctx.getPointer<AmfNull>(0).as<AmfNull>()); ASSERT_EQ(AmfInteger(11), ctx.getPointer<AmfInteger>(1).as<AmfInteger>()); ASSERT_EQ(AmfInteger(11), ctx.getObject<AmfInteger>(1)); ASSERT_THROW(ctx.getPointer<AmfDouble>(1), std::invalid_argument); ASSERT_THROW(ctx.getObject<AmfDouble>(1), std::invalid_argument); }
TEST(DictionarySerializationTest, MultipleKeys) { AmfDictionary d(true, false); d.insert(AmfInteger(3), AmfBool(false)); d.insert(AmfInteger(-16384), AmfString("foo")); consistsOf(std::vector<v8> { { // header 0x11, // AMF_DICTIONARY 0x05, // 2 elements 0x00, // no weak keys }, { // "3" = false 0x06, 0x03, 0x33, 0x02, }, { // "-16384" = "foo" 0x06, 0x0D, 0x2D, 0x31, 0x36, 0x33, 0x38, 0x34, 0x06, 0x07, 0x66, 0x6F, 0x6F } }, d.serialize()); }
TEST(DictionaryEquality, SimpleValues) { AmfDictionary d0(true), d1(true), d2(false); d0.insert(AmfInteger(0), AmfString("foo")); d1.insert(AmfInteger(0), AmfString("foo")); d2.insert(AmfInteger(0), AmfString("foo")); EXPECT_EQ(d0, d1); EXPECT_NE(d0, d2); d0.insert(AmfString("qux"), AmfByteArray(v8 { 0x00 })); EXPECT_NE(d0, d1); d1.insert(AmfString("qux"), AmfByteArray(v8 { 0x00 })); EXPECT_EQ(d0, d1); d0.insert(AmfNull(), AmfUndefined()); d1.insert(AmfUndefined(), AmfNull()); EXPECT_NE(d0, d1); d0.insert(AmfUndefined(), AmfNull()); d1.insert(AmfNull(), AmfUndefined()); EXPECT_EQ(d0, d1); }
TEST(SerializerTest, MultipleMixedValues) { Serializer s; s << AmfDouble(0.5) << AmfInteger(0x3ff) << AmfString("bar") << AmfNull(); v8 expected { 0x05, 0x3F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x87, 0x7F, 0x06, 0x07, 0x62, 0x61, 0x72, 0x01 }; ASSERT_EQ(expected, s.data()); }
TEST(DictionarySerializationTest, IntegerAsStringKeys) { AmfDictionary d(true, false); d.insert(AmfInteger(3), AmfBool(false)); isEqual(v8 { 0x11, // AMF_DICTIONARY 0x03, // 1 element 0x00, // no weak keys 0x06, 0x03, 0x33, // AmfInteger 3 serialized as AmfString "3" 0x02 // AmfBool false }, d); d = AmfDictionary(true, false); d.insert(AmfInteger(-16384), AmfString("foo")); isEqual(v8 { 0x11, // AMF_DICTIONARY 0x03, // 1 element 0x00, // no weak keys 0x06, 0x0D, 0x2D, 0x31, 0x36, 0x33, 0x38, 0x34, 0x06, 0x07, 0x66, 0x6F, 0x6F }, d); }
TEST(DictionarySerializationTest, IntegerKeys) { AmfDictionary d(false, false); d.insert(AmfInteger(3), AmfBool(false)); isEqual(v8 { 0x11, // AMF_DICTIONARY 0x03, // 1 element 0x00, // no weak keys 0x04, 0x03, // AmfInteger 3 0x02 // AmfBool false }, d); d = AmfDictionary(false, false); d.insert(AmfInteger(-16384), AmfString("foo")); isEqual(v8 { 0x11, // AMF_DICTIONARY 0x03, // 1 element 0x00, // no weak keys 0x04, 0xFF, 0xFF, 0xC0, 0x00, 0x06, 0x07, 0x66, 0x6F, 0x6F }, d); }
TEST(ObjectSerializationTest, NonTraitCtor) { AmfObject obj; obj.addSealedProperty("sealedProp", AmfInteger(0x7b)); isEqual(v8 { 0x0a, // AMF_OBJECT 0x13, // U29O-traits, not dynamic, 1 sealed prop 0x01, // class-name "" // UTF-8-vr "sealedProp" 0x15, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x70, // sealed property value // AmfInteger 0x7b 0x04, 0x7b // no dynamic members }, obj); obj = AmfObject("foo", true, false); obj.addSealedProperty("sealedProp", AmfInteger(0x7b)); obj.addDynamicProperty("dynamicProp", AmfString("dyn")); isEqual(v8 { 0x0a, // AMF_OBJECT 0x1b, // U29O-traits, dynamic, 1 sealed prop // class-name UTF-8-vr "foo" 0x07, 0x66, 0x6f, 0x6f, // UTF-8-vr "sealedProp" 0x15, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x70, // sealed property value // AmfInteger 0x7b 0x04, 0x7b, // 1 dynamic member // UTF-8-vr "dynamicProp" 0x17, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x50, 0x72, 0x6f, 0x70, // AmfString "dyn" 0x06, 0x07, 0x64, 0x79, 0x6e, // end of dynamic members 0x01 }, obj); }
TEST(DictionarySerializationTest, ToggleAsString) { AmfDictionary d(true, false); d.insert(AmfBool(false), AmfInteger(3)); isEqual({ 0x11, 0x03, 0x00, 0x06, 0x0B, 0x66, 0x61, 0x6C, 0x73, 0x65, 0x04, 0x03 }, d); d.asString = false; isEqual({ 0x11, 0x03, 0x00, 0x02, 0x04, 0x03 }, d); }
TEST(DictionarySerializationTest, OverwriteKeys) { AmfDictionary d(true, false); d.insert(AmfBool(false), AmfInteger(3)); isEqual({ 0x11, 0x03, 0x00, 0x06, 0x0B, 0x66, 0x61, 0x6C, 0x73, 0x65, 0x04, 0x03 }, d); d.insert(AmfBool(false), AmfString("foo")); isEqual({ 0x11, 0x03, 0x00, 0x06, 0x0B, 0x66, 0x61, 0x6C, 0x73, 0x65, 0x06, 0x07, 0x66, 0x6f, 0x6f }, d); }
TEST(DictionaryDeserialization, ObjectKeys) { AmfDictionary d(false, false); d.insert(AmfObject("", true, false), AmfString("foo")); v8 data { 0x11, 0x03, 0x00, 0x0a, 0x0b, 0x01, 0x01, 0x06, 0x07, 0x66, 0x6f, 0x6f }; deserialize(d, data, 0); d = AmfDictionary(false, false); AmfObject o("", true, false); o.addDynamicProperty("bar", AmfInteger(1)); d.insert(o, AmfString("foo")); data = { 0x11, 0x03, 0x00, 0x0a, 0x0b, 0x01, 0x07, 0x62, 0x61, 0x72, 0x04, 0x01, 0x01, 0x06, 0x07, 0x66, 0x6f, 0x6f }; deserialize(d, data, 0); }
TEST(ArraySerializationTest, AssociativeDenseArray) { std::map<std::string, AmfInteger> sparse; sparse["sparseVal"] = AmfInteger(0xbeef); AmfArray array(std::vector<AmfString> { AmfString("foobar") }, sparse); isEqual(v8 { 0x09, // AMF_ARRAY 0x03, // 1 dense element // assoc-values // UTF-8-vr "sparseVal" 0x13, 0x73, 0x70, 0x61, 0x72, 0x73, 0x65, 0x56, 0x61, 0x6c, // AmfInteger 0xbeef 0x04, 0x82, 0xfd, 0x6f, 0x01, // end of assoc-values // dense elements // AmfString "foobar" 0x06, 0x0d, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72, }, array); }
TEST(DictionarySerializationTest, Clear) { AmfDictionary d(false, true); d.insert(AmfBool(true), AmfInteger(17)); d.clear(); isEqual(v8 { 0x11, 0x01, // no elements 0x01 // weak keys }, d); d.insert(AmfBool(false), AmfDouble(17.0)); isEqual(v8 { 0x11, 0x03, // 1 element 0x01, // weak keys 0x02, // AmfBool false 0x05, 0x40, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // AmfDouble 17.0 }, d); }
TEST(SerializationContext, Item) { SerializationContext ctx; // Verify no objects are stored yet. ASSERT_THROW(ctx.getObject<AmfNull>(0), std::out_of_range); // Add one. ctx.addObject(AmfNull()); ASSERT_EQ(AmfNull(), ctx.getObject<AmfNull>(0)); ASSERT_THROW(ctx.getObject<AmfInteger>(0), std::invalid_argument); // Another one. AmfInteger i(17); ctx.addObject(i); ASSERT_EQ(AmfNull(), ctx.getObject<AmfNull>(0)); ASSERT_EQ(i, ctx.getObject<AmfInteger>(1)); // Verify that a copy is made. i.value = 21; ASSERT_EQ(AmfInteger(17), ctx.getObject<AmfInteger>(1)); }
TEST(DictionarySerializationTest, NumberKeys) { AmfDictionary d(false, true); d.insert(AmfDouble(-0.5), AmfInteger(3)); isEqual(v8 { 0x11, 0x03, // 1 element 0x01, // weak keys 0x05, 0xBF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // AmfDouble -0.5 0x04, 0x03 // AmfInteger 3 }, d); d = AmfDictionary(false, false); d.insert(AmfDouble(1.2345678912345e+35), AmfArray()); isEqual(v8 { 0x11, 0x03, // 1 element 0x00, // no weak keys 0x05, 0x47, 0x37, 0xC6, 0xE3, 0xC0, 0x32, 0xF7, 0x20, // AmfDouble 1.2345678912345e+35 0x09, 0x01, 0x01 // empty AmfArray }, d); }
TEST(ObjectSerializationTest, SerializeOnlyPropsInTraits) { AmfObjectTraits traits("", false, false); AmfObject obj(traits); obj.addSealedProperty("sealedProp", AmfInteger(0x05ffeffe)); // this should not be serialized as it's not part of the trait attributes obj.sealedProperties["unusedProp"] = AmfString("unused").serialize(); isEqual(v8 { 0x0a, // AMF_OBJECT 0x13, // 0b10011, U29O-traits, not dynamic, 1 sealed property 0x01, // class-name "" (anonymous object) // sealed property names // UTF-8-vr "sealedProp" 0x15, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x70, // sealed property values // AmfInteger 0x05ffeffe 0x04, 0x97, 0xff, 0xef, 0xfe // no dynamic members }, obj); }
TEST(DictionarySerializationTest, NumberAsStringKeys) { AmfDictionary d(true, true); d.insert(AmfDouble(-0.5), AmfInteger(3)); isEqual(v8 { 0x11, 0x03, // 1 element 0x01, // weak keys 0x06, 0x09, 0x2D, 0x30, 0x2E, 0x35, // AmfString "-0.5" 0x04, 0x03 // AmfInteger 3 }, d); d = AmfDictionary(true, false); d.insert(AmfDouble(1.2345678912345e+35), AmfArray()); isEqual(v8 { 0x11, 0x03, // 1 element 0x00, // no weak keys // AmfString "1.2345678912345e+35" 0x06, 0x27, 0x31, 0x2e, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x31, 0x32, 0x33, 0x34, 0x35, 0x65, 0x2b, 0x33, 0x35, 0x09, 0x01, 0x01 // empty AmfArray }, d); }
TEST(DictionaryDeserialization, ObjectsCorrectReferenceOrder) { // circular object reference to d is index 0 -> { 0x0a, 0x02 } == o AmfDictionary d(false, false); AmfObject o("", true, false); o.addDynamicProperty("bar", AmfInteger(1)); d.insert(o, AmfString("foo")); d.insert(AmfString("qux"), o); v8 data { 0x11, 0x05, 0x00, // key 1 0x0a, 0x0b, 0x01, 0x07, 0x62, 0x61, 0x72, 0x04, 0x01, 0x01, // value 1 0x06, 0x07, 0x66, 0x6f, 0x6f, // key 2 0x06, 0x07, 0x71, 0x75, 0x78, // value 2 0x0a, 0x02 }; deserialize(d, data, 0); }
TEST(DeserializerTest, Integer) { deserializesTo(AmfInteger(0x7e), { 0x04, 0x7e }); deserializesTo(AmfInteger(0x7e), { 0x04, 0x7e, 0x04 }, 1); deserializesTo(AmfInteger(0xffffffe), { 0x04, 0xbf, 0xff, 0xff, 0xfe }); }