diff --git a/test/testdata.cpp b/test/testdata.cpp index fbcbb52..4fc6b57 100644 --- a/test/testdata.cpp +++ b/test/testdata.cpp @@ -19,413 +19,6 @@ using namespace pvxs; namespace { -template -testCase -testBytes(const std::vector& actual, const char(&buf)[N]) -{ - bool ok = actual.size()==(N-1) && std::equal(actual.begin(), - actual.end(), - (const uint8_t*)buf); - - testCase ret(ok); - ret<<"Expect: \""< -void testToBytes(bool be, Fn&& fn, const char(&expect)[N]) -{ - std::vector buf; - VectorOutBuf S(be, buf); - fn(S); - buf.resize(buf.size()-S.size()); - 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(), 0xabu); - 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 testSimpleDef() -{ - testDiag("%s", __func__); - - auto val = simpledef.create(); - - testEq(std::string(SB()<<"\n"< 10 [10] - any -> 7 [7] - anya -> 8 [8] - arbitrary -> 5 [5] - arbitrary.sarr -> 6 [6] - choice -> 9 [9] - timeStamp -> 2 [2] - timeStamp.nanoseconds -> 4 [4] - timeStamp.secondsPastEpoch -> 3 [3] - value -> 1 [1] - value : 1 [1] - timeStamp : 2 [2] - arbitrary : 5 [5] - any : 7 [7] - anya : 8 [8] - choice : 9 [9] - achoice : 10 [10] -[1] double[] parent=[0] [1:2) -[2] struct time_t parent=[0] [2:5) - nanoseconds -> 2 [4] - secondsPastEpoch -> 1 [3] - secondsPastEpoch : 1 [3] - nanoseconds : 2 [4] -[3] uint64_t parent=[2] [3:4) -[4] uint32_t parent=[2] [4:5) -[5] struct parent=[0] [5:7) - sarr -> 1 [6] - sarr : 1 [6] -[6] struct[] parent=[5] [6:7) - [0] struct parent=[0] [0:2) - value -> 1 [1] - value : 1 [1] - [1] uint32_t parent=[0] [1:2) -[7] any parent=[0] [7:8) -[8] any[] parent=[0] [8:9) -[9] union parent=[0] [9:10) - a -> 0 [0] - b -> 1 [1] - a : 0 [0] - [0] float parent=[0] [0:1) - b : 1 [1] - [0] string parent=[0] [0:1) -[10] union[] parent=[0] [10:11) - [0] union parent=[0] [0:1) - x -> 0 [0] - y -> 1 [1] - x : 0 [0] - [0] string parent=[0] [0:1) - y : 1 [1] - [0] string parent=[0] [0:1) -)out")<<"Actual:\n"< arr(3); - arr[0] = fld.allocMember(); - arr[1] = fld.allocMember(); - // leave [2] as null - arr[0]["value"] = 0xdeadbeef; - arr[1]["value"] = 0x1badface; - - fld = arr.freeze().castTo(); - - testToBytes(true, [&val](Buffer& buf) { - to_wire_valid(buf, val); - }, "\x01@\x03\x01\xde\xad\xbe\xef\x01\x1b\xad\xfa\xce\x00"); - } - - { - auto val = simpledef.create(); - - val["choice->b"] = "test"; - testOk1(!!val["choice"].isMarked()); - - testToBytes(true, [&val](Buffer& buf) { - to_wire_valid(buf, val); - }, "\x02\x00\x02\x01\x04test"); - } - - { - auto val = simpledef.create(); - - auto fld = val["achoice"]; - shared_array arr(3); - arr[0] = fld.allocMember(); - arr[1] = fld.allocMember(); - // leave [2] as null - arr[0]["->x"] = "theX"; - arr[1]["->y"] = "theY"; - - fld = arr.freeze().castTo(); - - testToBytes(true, [&val](Buffer& buf) { - to_wire_valid(buf, val); - }, "\x02\x00\x04\x03\x01\x00\x04theX\x01\x01\x04theY\x00"); - } - - // Any - { - auto val = simpledef.create(); - - auto v = TypeDef(TypeCode::UInt32).create(); - v = 0x600df00d; - - val["any"].from(v); - - testToBytes(true, [&val](Buffer& buf) { - to_wire_valid(buf, val); - }, "\x01\x80\x26\x60\x0d\xf0\x0d"); - } - - // Any - { - auto val = simpledef.create(); - val["any"].mark(); - - testToBytes(true, [&val](Buffer& buf) { - to_wire_valid(buf, val); - }, "\x01\x80\xff"); - } - - // Any[] - { - auto val = simpledef.create(); - - auto fld = val["anya"]; - shared_array arr(3); - arr[0] = TypeDef(TypeCode::UInt32).create(); - arr[1] = TypeDef(TypeCode::Struct, {Member(TypeCode::String, "q")}).create(); - // leave [2] as null - - arr[0] = 0x7b; - arr[1]["q"] = "theq"; - - fld = arr.freeze().castTo(); - - testToBytes(true, [&val](Buffer& buf) { - to_wire_valid(buf, val); - }, "\x02\x00\x01\x03\x01\x26\x00\x00\x00\x7b\x01\x80\x00\x01\x01q\x60\x04theq\x00"); - } -} - -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(), 0x1badfaceu); - 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(), 0x600df00du); - } - - { - 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(), 0x7bu); - testEq(val["anya[1].q"].as(), "theq"); - testEq(val["anya[2]"].type(), TypeCode::Null); - } -} - -void testDeserialize3() -{ - testDiag("%s", __func__); - - { - TypeStore ctxt; - Value val; - testFromBytes(false, "\xfd\x02\x00\x80\x00\x01\x06\x72\x65\x63\x6f\x72\x64\xfd\x03\x00\x80\x00" - "\x01\x08\x5f\x6f\x70\x74\x69\x6f\x6e\x73\xfd\x04\x00\x80\x00\x02\x09\x71" - "\x75\x65\x75\x65\x53\x69\x7a\x65\x60\x08\x70\x69\x70\x65\x6c\x69\x6e\x65" - "\x60\x01\x34\x04\x74\x72\x75\x65" -, - [&val, &ctxt](Buffer& buf) { - from_wire_type_value(buf, ctxt, val); - }); - testShow()<(), "true"); - testEq(val["record._options.queueSize"].as(), "4"); - } -} - void testTraverse() { testDiag("%s", __func__); @@ -583,13 +176,7 @@ void testPvRequest() MAIN(testdata) { - testPlan(82); - testSerialize1(); - testDeserialize1(); - testSimpleDef(); - testSerialize2(); - testDeserialize2(); - testDeserialize3(); + testPlan(20); testTraverse(); testAssign(); testName(); diff --git a/test/testxcode.cpp b/test/testxcode.cpp index 2ef69d0..b5cc110 100644 --- a/test/testxcode.cpp +++ b/test/testxcode.cpp @@ -9,6 +9,7 @@ #include #include +#include #include "dataimpl.h" #include "pvaproto.h" @@ -16,6 +17,414 @@ namespace { using namespace pvxs; using namespace pvxs::impl; + +template +testCase +testBytes(const std::vector& actual, const char(&buf)[N]) +{ + bool ok = actual.size()==(N-1) && std::equal(actual.begin(), + actual.end(), + (const uint8_t*)buf); + + testCase ret(ok); + ret<<"Expect: \""< +void testToBytes(bool be, Fn&& fn, const char(&expect)[N]) +{ + std::vector buf; + VectorOutBuf S(be, buf); + fn(S); + buf.resize(buf.size()-S.size()); + 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(), 0xabu); + 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 testSimpleDef() +{ + testDiag("%s", __func__); + + auto val = simpledef.create(); + + testEq(std::string(SB()<<"\n"< 10 [10] + any -> 7 [7] + anya -> 8 [8] + arbitrary -> 5 [5] + arbitrary.sarr -> 6 [6] + choice -> 9 [9] + timeStamp -> 2 [2] + timeStamp.nanoseconds -> 4 [4] + timeStamp.secondsPastEpoch -> 3 [3] + value -> 1 [1] + value : 1 [1] + timeStamp : 2 [2] + arbitrary : 5 [5] + any : 7 [7] + anya : 8 [8] + choice : 9 [9] + achoice : 10 [10] +[1] double[] parent=[0] [1:2) +[2] struct time_t parent=[0] [2:5) + nanoseconds -> 2 [4] + secondsPastEpoch -> 1 [3] + secondsPastEpoch : 1 [3] + nanoseconds : 2 [4] +[3] uint64_t parent=[2] [3:4) +[4] uint32_t parent=[2] [4:5) +[5] struct parent=[0] [5:7) + sarr -> 1 [6] + sarr : 1 [6] +[6] struct[] parent=[5] [6:7) + [0] struct parent=[0] [0:2) + value -> 1 [1] + value : 1 [1] + [1] uint32_t parent=[0] [1:2) +[7] any parent=[0] [7:8) +[8] any[] parent=[0] [8:9) +[9] union parent=[0] [9:10) + a -> 0 [0] + b -> 1 [1] + a : 0 [0] + [0] float parent=[0] [0:1) + b : 1 [1] + [0] string parent=[0] [0:1) +[10] union[] parent=[0] [10:11) + [0] union parent=[0] [0:1) + x -> 0 [0] + y -> 1 [1] + x : 0 [0] + [0] string parent=[0] [0:1) + y : 1 [1] + [0] string parent=[0] [0:1) +)out")<<"Actual:\n"< arr(3); + arr[0] = fld.allocMember(); + arr[1] = fld.allocMember(); + // leave [2] as null + arr[0]["value"] = 0xdeadbeef; + arr[1]["value"] = 0x1badface; + + fld = arr.freeze().castTo(); + + testToBytes(true, [&val](Buffer& buf) { + to_wire_valid(buf, val); + }, "\x01@\x03\x01\xde\xad\xbe\xef\x01\x1b\xad\xfa\xce\x00"); + } + + { + auto val = simpledef.create(); + + val["choice->b"] = "test"; + testOk1(!!val["choice"].isMarked()); + + testToBytes(true, [&val](Buffer& buf) { + to_wire_valid(buf, val); + }, "\x02\x00\x02\x01\x04test"); + } + + { + auto val = simpledef.create(); + + auto fld = val["achoice"]; + shared_array arr(3); + arr[0] = fld.allocMember(); + arr[1] = fld.allocMember(); + // leave [2] as null + arr[0]["->x"] = "theX"; + arr[1]["->y"] = "theY"; + + fld = arr.freeze().castTo(); + + testToBytes(true, [&val](Buffer& buf) { + to_wire_valid(buf, val); + }, "\x02\x00\x04\x03\x01\x00\x04theX\x01\x01\x04theY\x00"); + } + + // Any + { + auto val = simpledef.create(); + + auto v = TypeDef(TypeCode::UInt32).create(); + v = 0x600df00d; + + val["any"].from(v); + + testToBytes(true, [&val](Buffer& buf) { + to_wire_valid(buf, val); + }, "\x01\x80\x26\x60\x0d\xf0\x0d"); + } + + // Any + { + auto val = simpledef.create(); + val["any"].mark(); + + testToBytes(true, [&val](Buffer& buf) { + to_wire_valid(buf, val); + }, "\x01\x80\xff"); + } + + // Any[] + { + auto val = simpledef.create(); + + auto fld = val["anya"]; + shared_array arr(3); + arr[0] = TypeDef(TypeCode::UInt32).create(); + arr[1] = TypeDef(TypeCode::Struct, {Member(TypeCode::String, "q")}).create(); + // leave [2] as null + + arr[0] = 0x7b; + arr[1]["q"] = "theq"; + + fld = arr.freeze().castTo(); + + testToBytes(true, [&val](Buffer& buf) { + to_wire_valid(buf, val); + }, "\x02\x00\x01\x03\x01\x26\x00\x00\x00\x7b\x01\x80\x00\x01\x01q\x60\x04theq\x00"); + } +} + +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(), 0x1badfaceu); + 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(), 0x600df00du); + } + + { + 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(), 0x7bu); + testEq(val["anya[1].q"].as(), "theq"); + testEq(val["anya[2]"].type(), TypeCode::Null); + } +} + +void testDeserialize3() +{ + testDiag("%s", __func__); + + { + TypeStore ctxt; + Value val; + testFromBytes(false, "\xfd\x02\x00\x80\x00\x01\x06\x72\x65\x63\x6f\x72\x64\xfd\x03\x00\x80\x00" + "\x01\x08\x5f\x6f\x70\x74\x69\x6f\x6e\x73\xfd\x04\x00\x80\x00\x02\x09\x71" + "\x75\x65\x75\x65\x53\x69\x7a\x65\x60\x08\x70\x69\x70\x65\x6c\x69\x6e\x65" + "\x60\x01\x34\x04\x74\x72\x75\x65" +, + [&val, &ctxt](Buffer& buf) { + from_wire_type_value(buf, ctxt, val); + }); + testShow()<(), "true"); + testEq(val["record._options.queueSize"].as(), "4"); + } +} + void testDecode1() { testDiag("%s", __func__); @@ -491,7 +900,13 @@ void testEmptyRequest() MAIN(testxcode) { - testPlan(34); + testPlan(96); + testSerialize1(); + testDeserialize1(); + testSimpleDef(); + testSerialize2(); + testDeserialize2(); + testDeserialize3(); testDecode1(); testXCodeNTScalar(); testXCodeNTNDArray();