From ca662bf6cc3c0885b0686ba89f25413a542ee02d Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 14 Dec 2019 16:24:47 -0800 Subject: [PATCH] fixup data decode --- src/dataencode.cpp | 16 +++- test/testdata.cpp | 209 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 191 insertions(+), 34 deletions(-) diff --git a/src/dataencode.cpp b/src/dataencode.cpp index 3589528..bfa0d31 100644 --- a/src/dataencode.cpp +++ b/src/dataencode.cpp @@ -242,7 +242,7 @@ void to_wire_field(Buffer& buf, const FieldDesc* desc, const std::shared_ptroffset+1u, desc->next_offset)) { auto cdesc = desc + top.member_indicies[off]; - std::shared_ptr cstore(store, store.get()+off); + std::shared_ptr cstore(store, store.get()+off); // TODO avoid shared_ptr/aliasing here if(cdesc->code!=TypeCode::Struct) to_wire_field(buf, cdesc, cstore); } @@ -454,7 +454,7 @@ void from_wire_field(Buffer& buf, TypeStore& ctxt, const FieldDesc* desc, const // serialize entire sub-structure for(auto off : range(desc->offset+1u, desc->next_offset)) { auto cdesc = desc + top.member_indicies[off]; - std::shared_ptr cstore(store, store.get()+off); + std::shared_ptr cstore(store, store.get()+off); // TODO avoid shared_ptr/aliasing here if(cdesc->code!=TypeCode::Struct) from_wire_field(buf, ctxt, cdesc, cstore); } @@ -529,12 +529,16 @@ void from_wire_field(Buffer& buf, TypeStore& ctxt, const FieldDesc* desc, const TypeDeserContext dc{*descs, ctxt}; from_wire(buf, dc); + if(!buf.good()) + return; if(descs->empty()) { fld = Value(); return; } else { + FieldDesc_calculate_offset(descs->data()); + std::shared_ptr stype(descs, descs->data()); // alias fld = Value::Helper::build(stype); @@ -613,12 +617,11 @@ void from_wire_field(Buffer& buf, TypeStore& ctxt, const FieldDesc* desc, const elem = Value::Helper::build(stype, store, desc); from_wire_full(buf, ctxt, elem); - return; } else { // invalid selector buf.fault(); - break; + return; } } } @@ -637,7 +640,12 @@ void from_wire_field(Buffer& buf, TypeStore& ctxt, const FieldDesc* desc, const TypeDeserContext dc{*descs, ctxt}; from_wire(buf, dc); + if(!buf.good()) + return; + if(!descs->empty()) { + FieldDesc_calculate_offset(descs->data()); + std::shared_ptr stype(descs, descs->data()); // alias elem = Value::Helper::build(stype, store, desc); diff --git a/test/testdata.cpp b/test/testdata.cpp index 8879a45..699f2b7 100644 --- a/test/testdata.cpp +++ b/test/testdata.cpp @@ -42,6 +42,15 @@ void testToBytes(bool be, Fn&& fn, const char(&expect)[N]) testBytes(buf, expect); } +template +void testFromBytes(bool be, const char(&input)[N], Fn&& fn) +{ + std::vector buf(input, input+N-1); + FixedBuf S(be, buf); + fn(S); + testCase(S.good() && S.empty())<<"Deserialize \""<(), 0xdeadbeef); + } + + { + TypeStore ctxt; + auto val = nt::NTScalar{TypeCode::UInt32}.build().create(); + testFromBytes(true, "\x02 \x01\x0bhello world\x00\x00\x00\xab", + [&val, &ctxt](Buffer& buf) { + from_wire_valid(buf, ctxt, val); + }); + testOk1(!val["value"].isMarked()); + testOk1(!!val["timeStamp.nanoseconds"].isMarked()); + testOk1(!!val["alarm.message"].isMarked()); + testEq(val["value"].as(), 0u); + testEq(val["timeStamp.nanoseconds"].as(), 0xab); + testEq(val["alarm.message"].as(), "hello world"); + } + +} + +TypeDef simpledef(TypeCode::Struct, "simple_t", { + Member(TypeCode::Float64A, "value"), + Member(TypeCode::Struct, "timeStamp", "time_t", { + Member(TypeCode::UInt64, "secondsPastEpoch"), + Member(TypeCode::UInt32, "nanoseconds"), + }), + Member(TypeCode::Struct, "arbitrary", { + Member(TypeCode::StructA, "sarr", { + Member(TypeCode::UInt32, "value"), + }), + }), + Member(TypeCode::Any, "any"), + Member(TypeCode::AnyA, "anya"), + Member(TypeCode::Union, "choice", { + Member(TypeCode::Float32, "a"), + Member(TypeCode::String, "b"), + }), + Member(TypeCode::UnionA, "achoice", { + Member(TypeCode::String, "x"), + Member(TypeCode::String, "y"), + }), + }); + void testSerialize2() { testDiag("%s", __func__); - TypeDef def(TypeCode::Struct, "simple_t", { - Member(TypeCode::Float64A, "value"), - Member(TypeCode::Struct, "timeStamp", "time_t", { - Member(TypeCode::UInt64, "secondsPastEpoch"), - Member(TypeCode::UInt32, "nanoseconds"), - }), - Member(TypeCode::Struct, "arbitrary", { - Member(TypeCode::StructA, "sarr", { - Member(TypeCode::UInt32, "value"), - }), - }), - Member(TypeCode::Any, "any"), - Member(TypeCode::AnyA, "anya"), - Member(TypeCode::Union, "choice", { - Member(TypeCode::Float32, "a"), - Member(TypeCode::String, "b"), - }), - Member(TypeCode::UnionA, "achoice", { - Member(TypeCode::String, "x"), - Member(TypeCode::String, "y"), - }), - }); - { - auto val = def.create(); + auto val = simpledef.create(); auto fld = val["arbitrary.sarr"]; shared_array arr(3); @@ -122,7 +183,7 @@ void testSerialize2() } { - auto val = def.create(); + auto val = simpledef.create(); val["choice->b"] = "test"; testOk1(!!val["choice"].isMarked()); @@ -133,7 +194,7 @@ void testSerialize2() } { - auto val = def.create(); + auto val = simpledef.create(); auto fld = val["achoice"]; shared_array arr(3); @@ -152,7 +213,7 @@ void testSerialize2() // Any { - auto val = def.create(); + auto val = simpledef.create(); auto v = TypeDef(TypeCode::UInt32).create(); v = 0x600df00d; @@ -166,7 +227,7 @@ void testSerialize2() // Any { - auto val = def.create(); + auto val = simpledef.create(); val["any"].mark(); testToBytes(true, [&val](Buffer& buf) { @@ -176,7 +237,7 @@ void testSerialize2() // Any[] { - auto val = def.create(); + auto val = simpledef.create(); auto fld = val["anya"]; shared_array arr(3); @@ -195,13 +256,101 @@ void testSerialize2() } } +void testDeserialize2() +{ + testDiag("%s", __func__); + + { + TypeStore ctxt; + auto val = simpledef.create(); + testFromBytes(true, "\x01@\x03\x01\xde\xad\xbe\xef\x01\x1b\xad\xfa\xce\x00", + [&val, &ctxt](Buffer& buf) { + from_wire_valid(buf, ctxt, val); + }); + testOk1(!val["value"].isMarked()); + testOk1(!!val["arbitrary.sarr"].isMarked()); + testEq(val["arbitrary.sarr"].as>().size(), 3u*sizeof(Value)); + testEq(val["arbitrary.sarr[0]value"].as(), 0xdeadbeef); + testEq(val["arbitrary.sarr[1]value"].as(), 0x1badface); + testEq(val["arbitrary.sarr[2]value"].type(), TypeCode::Null); + } + + { + TypeStore ctxt; + auto val = simpledef.create(); + testFromBytes(true, "\x02\x00\x02\x01\x04test", + [&val, &ctxt](Buffer& buf) { + from_wire_valid(buf, ctxt, val); + }); + testOk1(!val["value"].isMarked()); + testOk1(!!val["choice"].isMarked()); + testEq(val["choice"].as(), "test"); + } + + { + TypeStore ctxt; + auto val = simpledef.create(); + testFromBytes(true, "\x02\x00\x04\x03\x01\x00\x04theX\x01\x01\x04theY\x00", + [&val, &ctxt](Buffer& buf) { + from_wire_valid(buf, ctxt, val); + }); + testOk1(!val["value"].isMarked()); + testOk1(!!val["achoice"].isMarked()); + testEq(val["achoice"].as>().size(), 3u*sizeof(Value)); + testEq(val["achoice[0]"].as(), "theX"); + testEq(val["achoice[1]"].as(), "theY"); + testEq(val["achoice[2]"].type(), TypeCode::Null); + } + + { + TypeStore ctxt; + auto val = simpledef.create(); + testFromBytes(true, "\x01\x80\x26\x60\x0d\xf0\x0d", + [&val, &ctxt](Buffer& buf) { + from_wire_valid(buf, ctxt, val); + }); + testOk1(!val["value"].isMarked()); + testOk1(!!val["any"].isMarked()); + testEq(val["any"].as(), 0x600df00d); + } + + { + TypeStore ctxt; + auto val = simpledef.create(); + testFromBytes(true, "\x01\x80\xff", + [&val, &ctxt](Buffer& buf) { + from_wire_valid(buf, ctxt, val); + }); + testOk1(!val["value"].isMarked()); + testOk1(!!val["any"].isMarked()); + //testEq(val["any"].type(), TypeCode::Null); determine type _inside_ Any? + } + + { + TypeStore ctxt; + auto val = simpledef.create(); + testFromBytes(true, "\x02\x00\x01\x03\x01\x26\x00\x00\x00\x7b\x01\x80\x00\x01\x01q\x60\x04theq\x00", + [&val, &ctxt](Buffer& buf) { + from_wire_valid(buf, ctxt, val); + }); + testOk1(!val["value"].isMarked()); + testOk1(!!val["anya"].isMarked()); + testEq(val["anya"].as>().size(), 3u*sizeof(Value)); + testEq(val["anya[0]"].as(), 0x7b); + testEq(val["anya[1]q"].as(), "theq"); + testEq(val["anya[2]"].type(), TypeCode::Null); + } +} + } // namespace MAIN(testdata) { - testPlan(12); + testPlan(58); testSerialize1(); + testDeserialize1(); testSerialize2(); + testDeserialize2(); cleanup_for_valgrind(); return testDone(); }