diff --git a/ProxyStubGenerator/StubGenerator.py b/ProxyStubGenerator/StubGenerator.py index 7eaf8394..2cb9bdff 100755 --- a/ProxyStubGenerator/StubGenerator.py +++ b/ProxyStubGenerator/StubGenerator.py @@ -1630,24 +1630,22 @@ def _EmitAssignment(p): elif p.is_dynamic_array: obj_name = p.name - if not p.suppress_type: - if p.optional: - obj_name = Normalize(obj_name + "Object__") - emit.Line("%s %s{};" % (p.optional.type_name, obj_name)) - else: - emit.Line("%s %s{};" % (p.type_name, obj_name)) + if p.optional: + obj_name = Normalize(p.name + "Object__") + emit.Line("%s %s{};" % (p.optional.type_name, obj_name)) + elif not p.suppress_type: + emit.Line("%s %s{};" % (p.type_name, obj_name)) length = EmitParam(interface, p.length, Normalize("%sSize" % obj_name)) ReadParameter(length) CheckRange(p, ("%s" % length.as_rvalue)) - emit.Line("%s.reserve(%s);" % (p.as_rvalue, length.as_rvalue)) - + emit.Line("%s.reserve(%s);" % (obj_name, length.as_rvalue)) index = chr(ord('i') + p.name.count('Item')) element = EmitParam(interface, p.element, Normalize(obj_name + "Item"), parent=p) emit.Line("for (%s %s = 0; %s < %s; %s++) {" % (p.length.type_name, index, index, length.as_rvalue, index)) emit.IndentInc() ReadParameter(element) - emit.Line("%s.push_back(std::move(%s));" % (p.as_rvalue, element.as_rvalue)) + emit.Line("%s.push_back(std::move(%s));" % (obj_name, element.as_rvalue)) emit.IndentDec() emit.Line("}") @@ -2320,18 +2318,33 @@ def ReadParameter(p, no_array=False, suppress_type=True): elif p.is_dynamic_array: length = EmitLength(interface, p.length, Normalize(p.name + "Size")) element = EmitParam(interface, p.element, Normalize(p.name + "Item"), parent=p) + + obj_name = p.as_rvalue + + if p.optional: + obj_name = Normalize(p.name + "Object__") + emit.Line("%s %s{};" % (p.optional.type_name, obj_name)) + emit.Line("%s{};" % (length.temporary_no_cv)) ReadParameter(length) - emit.Line("%s.reserve(%s);" % (p.as_rvalue, length.as_rvalue)) + + if not p.optional: + emit.Line("%s.clear();" % (p.as_rvalue)) + + emit.Line("%s.reserve(%s);" % (obj_name, length.as_rvalue)) + index = chr(ord('i') + p.name.count('Item')) emit.Line("for (%s %s = 0; %s < %s; %s++) {" % (p.length.type_name, index, index, length.as_rvalue, index)) emit.IndentInc() emit.Line("%s{};" % (element.temporary_no_cv)) ReadParameter(element) - emit.Line("%s.push_back(std::move(%s));" % (p.as_rvalue, element.as_rvalue)) + emit.Line("%s.push_back(std::move(%s));" % (obj_name, element.as_rvalue)) emit.IndentDec() emit.Line("}") + if p.optional: + emit.Line("%s = std::move(%s);" % (p.name, obj_name)) + elif p.is_buffer: CheckFrame(p) CheckSize(p) @@ -2385,6 +2398,11 @@ def _EmitAssignment(p): if p.optional and (not p.is_array or no_array): emit.IndentDec() emit.Line("}") + emit.Line("else {") + emit.IndentInc() + emit.Line("%s = %s();" % (p.name, p.type_name)) + emit.IndentDec() + emit.Line("}") if EMIT_TRACES: emit.Line('fprintf(stderr, "*** [%s proxy] ENTER: %s()\\n");' % (interface_name, method.name)) diff --git a/tests/FunctionalTests/common/implementations/TestOptionalsImpl.cpp b/tests/FunctionalTests/common/implementations/TestOptionalsImpl.cpp index 42fe0b5f..f3e7d3cf 100644 --- a/tests/FunctionalTests/common/implementations/TestOptionalsImpl.cpp +++ b/tests/FunctionalTests/common/implementations/TestOptionalsImpl.cpp @@ -120,6 +120,101 @@ namespace TestImplementation { return Core::ERROR_NONE; } + Core::hresult ProcessOptionalVector( + const Core::OptionalType>& input, + Core::OptionalType>& output) override + { + if (input.IsSet() == true) { + std::vector data; + data.resize(input.Value().size()); + std::transform(input.Value().begin(), input.Value().end(), data.begin(), [](uint8_t x) { + return static_cast(x * 2); + }); + output = std::move(data); + } + else { + output = Core::OptionalType>(); + } + return Core::ERROR_NONE; + } + + Core::hresult ProcessOptionalInlineVector( + Core::OptionalType>& data, + const bool unset) override + { + if (data.IsSet() == true) { + if (unset == true) { + data = Core::OptionalType>(); + } + else { + std::for_each(data.Value().begin(), data.Value().end(), [](uint8_t& num) { + num *= 2; + }); + } + } + return Core::ERROR_NONE; + } + + Core::hresult ProcessOptionalVectorInOptionalStruct( + const Core::OptionalType& input, + Core::OptionalType& output) override + { + if (input.IsSet() == true) { + Compound cp; + cp.magic = input.Value().magic; + cp.optionalMagic = input.Value().optionalMagic; + cp.data.resize(input.Value().data.size()); + + std::transform(input.Value().data.begin(), input.Value().data.end(), cp.data.begin(), [](uint8_t x) { + return static_cast(x * 2); + }); + + if (input.Value().optionalData.IsSet() == true) { + std::vector data; + data.resize(input.Value().optionalData.Value().size()); + std::transform(input.Value().optionalData.Value().begin(), input.Value().optionalData.Value().end(), data.begin(), [](uint8_t x) { + return static_cast(x * 2); + }); + + cp.optionalData = std::move(data); + } + + output = std::move(cp); + } + else { + output = Core::OptionalType(); + } + return Core::ERROR_NONE; + } + + Core::hresult ProcessOptionalVectorInOptionalInlineStruct( + Core::OptionalType& data, + const bool unset) override + { + if (data.IsSet() == true) { + + if ((data.Value().optionalMagic.IsSet() == true) && (unset == true)) { + data.Value().optionalMagic = Core::OptionalType(); + } + + std::for_each(data.Value().data.begin(), data.Value().data.end(), [](uint8_t& num) { + num *= 2; + }); + + if (data.Value().optionalData.IsSet() == true) { + if (unset == true) { + data.Value().optionalData = Core::OptionalType>(); + } + else { + std::for_each(data.Value().optionalData.Value().begin(), data.Value().optionalData.Value().end(), [](uint8_t& num) { + num *= 2; + }); + } + } + } + return Core::ERROR_NONE; + } + Core::hresult AllOptional( const Core::OptionalType& a, const Core::OptionalType& b, diff --git a/tests/FunctionalTests/common/interfaces/ITestOptionals.h b/tests/FunctionalTests/common/interfaces/ITestOptionals.h index f88862ec..27758555 100644 --- a/tests/FunctionalTests/common/interfaces/ITestOptionals.h +++ b/tests/FunctionalTests/common/interfaces/ITestOptionals.h @@ -31,6 +31,13 @@ namespace FunctionalTest { struct EXTERNAL ITestOptionals : virtual public Core::IUnknown { enum { ID = ID_TEST_OPTIONALS }; + struct Compound { + string magic; + Core::OptionalType optionalMagic; + std::vector data /* @restrict:8 */; + Core::OptionalType> optionalData /* @restrict:8 */; + }; + // ===== Optional input parameters ===== // @brief Add two numbers. When b is not set it defaults to 0. @@ -130,6 +137,30 @@ namespace FunctionalTest { const uint16_t maxOutputSize, uint16_t& written /* @out */) = 0; + // ===== Optional vectors ===== + + // @brief Process an input vector into an output vector. + virtual Core::hresult ProcessOptionalVector( + const Core::OptionalType>& input /* @restrict:8 */, + Core::OptionalType>& output /* @out @restrict:8 */) = 0; + + // @brief Process an input vector into same output vector. + // @param unset Change a set optional to unset + virtual Core::hresult ProcessOptionalInlineVector( + Core::OptionalType>& data /* @inout @restrict:8 */, + const bool unset) = 0; + + // @brief Process vector in a struct + virtual Core::hresult ProcessOptionalVectorInOptionalStruct( + const Core::OptionalType& input, + Core::OptionalType& output /* @out */) = 0; + + // @brief Process a vector in a struct to the same struct + // @param unset Change a set optional to unset + virtual Core::hresult ProcessOptionalVectorInOptionalInlineStruct( + Core::OptionalType& data /* @inout*/, + const bool unset) = 0; + // ===== Edge cases ===== // @brief Compute a result from up to three optional unsigned integers. diff --git a/tests/FunctionalTests/comrpc/tests/TestOptionals.cpp b/tests/FunctionalTests/comrpc/tests/TestOptionals.cpp index 647069b1..c997b720 100644 --- a/tests/FunctionalTests/comrpc/tests/TestOptionals.cpp +++ b/tests/FunctionalTests/comrpc/tests/TestOptionals.cpp @@ -196,6 +196,194 @@ TEST_F(TestOptionals, ProcessOptionalBuffer_NoOutput) { EXPECT_EQ(written, 0u); } +// ===== Optional vector ===== + +TEST_F(TestOptionals, ProcessOptionalVector_Set) { + // Set optional vector round trip. + std::vector input{ 1,2,3,4 }; + Core::OptionalType> optOutput; + Core::OptionalType> optInput; + optInput = input; + ASSERT_EQ(_proxy->ProcessOptionalVector(optInput, optOutput), Core::ERROR_NONE); + ASSERT_EQ(optOutput.IsSet(), true); + ASSERT_EQ(optOutput.Value().size(), input.size()); + if (optOutput.Value().size() == input.size()) { + // process multiplies by 2 + for (uint8_t i = 0; i < input.size(); i++) { + EXPECT_EQ(optOutput.Value()[i], input[i]*2); + } + } +} + +TEST_F(TestOptionals, ProcessOptionalVector_Unset) { + // Unset optional vector round trip. + Core::OptionalType> optOutput; + Core::OptionalType> optInput; + ASSERT_EQ(_proxy->ProcessOptionalVector(optInput, optOutput), Core::ERROR_NONE); + EXPECT_EQ(optOutput.IsSet(), false); +} + +TEST_F(TestOptionals, ProcessOptionalInlineVector_Set) { + // Set optional vector round trip to the same vector parameter. + std::vector data{ 1,2,3,4 }; + Core::OptionalType> optData; + optData = data; // copy! + ASSERT_EQ(_proxy->ProcessOptionalInlineVector(optData, false), Core::ERROR_NONE); + ASSERT_EQ(optData.IsSet(), true); + ASSERT_EQ(optData.Value().size(), data.size()); + if (optData.Value().size() == data.size()) { + // process multiplies by 2 + for (uint8_t i = 0; i < data.size(); i++) { + EXPECT_EQ(optData.Value()[i], data[i]*2); + } + } +} + +TEST_F(TestOptionals, ProcessOptionalInlineVector_Unset) { + // Unset optional vector round trip to the same vector parameter. + Core::OptionalType> optData; + ASSERT_EQ(_proxy->ProcessOptionalInlineVector(optData, false), Core::ERROR_NONE); + EXPECT_EQ(optData.IsSet(), false); +} + +TEST_F(TestOptionals, ProcessOptionalInlineVector_SetToUnset) { + // Set optional vector change into unset in the same vector parameter. + std::vector data{ 1,2,3,4 }; + Core::OptionalType> optData; + optData = data; + ASSERT_EQ(_proxy->ProcessOptionalInlineVector(optData, true /* change setbit! */), Core::ERROR_NONE); + EXPECT_EQ(optData.IsSet(), false); +} + +TEST_F(TestOptionals, ProcessOptionalVectorInStruct_Set) { + // Set optional vector in a struct round trip. + ITestOptionals::Compound data; + data.magic = "hokus"; + data.optionalMagic = "pokus"; + data.data = { 1,2,3,4 }; + data.optionalData = { 11,12,13,14 }; + Core::OptionalType optOutput; + Core::OptionalType optInput; + optInput = data; // copy! + ASSERT_EQ(_proxy->ProcessOptionalVectorInOptionalStruct(optInput, optOutput), Core::ERROR_NONE); + ASSERT_EQ(optOutput.IsSet(), true); + EXPECT_EQ(optOutput.Value().magic, data.magic); + ASSERT_EQ(optOutput.Value().optionalMagic.IsSet(), true); + EXPECT_EQ(optOutput.Value().optionalMagic.Value(), data.optionalMagic.Value()); + ASSERT_EQ(optOutput.Value().data.size(), data.data.size()); + if (optOutput.Value().data.size() == data.data.size()) { + // process multiplies by 2 + for (uint8_t i = 0; i < data.data.size(); i++) { + EXPECT_EQ(optOutput.Value().data[i], data.data[i]*2); + } + } + ASSERT_EQ(optOutput.Value().optionalData.IsSet(), true); + ASSERT_EQ(optOutput.Value().optionalData.Value().size(), data.optionalData.Value().size()); + if (optOutput.Value().optionalData.Value().size() == data.optionalData.Value().size()) { + // process multiplies by 2 + for (uint8_t i = 0; i < data.optionalData.Value().size(); i++) { + EXPECT_EQ(optOutput.Value().optionalData.Value()[i], data.optionalData.Value()[i]*2); + } + } +} + +TEST_F(TestOptionals, ProcessOptionalVectorInStruct_Unset) { + // Unset optional vector in a struct round trip. + ITestOptionals::Compound data; + data.magic = "hokus"; + data.data = { 1,2,3,4 }; + Core::OptionalType optOutput; + Core::OptionalType optInput; + optInput = data; + ASSERT_EQ(_proxy->ProcessOptionalVectorInOptionalStruct(optInput, optOutput), Core::ERROR_NONE); + ASSERT_EQ(optOutput.IsSet(), true); + EXPECT_EQ(optOutput.Value().magic, data.magic); + ASSERT_EQ(optOutput.Value().optionalMagic.IsSet(), false); + ASSERT_EQ(optOutput.Value().data.size(), data.data.size()); + if (optOutput.Value().data.size() == data.data.size()) { + // process multiplies by 2 + for (uint8_t i = 0; i < data.data.size(); i++) { + EXPECT_EQ(optOutput.Value().data[i], data.data[i]*2); + } + } + ASSERT_EQ(optOutput.Value().optionalData.IsSet(), false); +} + +TEST_F(TestOptionals, ProcessOptionalInlineVectorInStruct_Set) { + // Set optional vector in a struct round trip to the same vector parameter. + ITestOptionals::Compound data; + data.magic = "hokus"; + data.optionalMagic = "pokus"; + data.data = { 1,2,3,4 }; + data.optionalData = { 11,12,13,14 }; + Core::OptionalType optData; + optData = data; // copy! + ASSERT_EQ(_proxy->ProcessOptionalVectorInOptionalInlineStruct(optData, false), Core::ERROR_NONE); + ASSERT_EQ(optData.IsSet(), true); + EXPECT_EQ(optData.Value().magic, data.magic); + ASSERT_EQ(optData.Value().optionalMagic.IsSet(), true); + EXPECT_EQ(optData.Value().optionalMagic.Value(), data.optionalMagic.Value()); + ASSERT_EQ(optData.Value().data.size(), data.data.size()); + if (optData.Value().data.size() == data.data.size()) { + // process multiplies by 2 + for (uint8_t i = 0; i < data.data.size(); i++) { + EXPECT_EQ(optData.Value().data[i], data.data[i]*2); + } + } + ASSERT_EQ(optData.Value().optionalData.IsSet(), true); + ASSERT_EQ(optData.Value().optionalData.Value().size(), data.optionalData.Value().size()); + if (optData.Value().optionalData.Value().size() == data.optionalData.Value().size()) { + // process multiplies by 2 + for (uint8_t i = 0; i < data.optionalData.Value().size(); i++) { + EXPECT_EQ(optData.Value().optionalData.Value()[i], data.optionalData.Value()[i]*2); + } + } +} + +TEST_F(TestOptionals, ProcessOptionalInlineVectorInStruct_Unset) { + // Unset optional vector in a struct round trip to the same vector parameter. + ITestOptionals::Compound data; + data.magic = "hokus"; + data.data = { 1,2,3,4 }; + Core::OptionalType optData; + optData = data; // copy! + ASSERT_EQ(_proxy->ProcessOptionalVectorInOptionalInlineStruct(optData, false), Core::ERROR_NONE); + ASSERT_EQ(optData.IsSet(), true); + EXPECT_EQ(optData.Value().magic, data.magic); + ASSERT_EQ(optData.Value().optionalMagic.IsSet(), false); + ASSERT_EQ(optData.Value().data.size(), data.data.size()); + if (optData.Value().data.size() == data.data.size()) { + // process multiplies by 2 + for (uint8_t i = 0; i < data.data.size(); i++) { + EXPECT_EQ(optData.Value().data[i], data.data[i]*2); + } + } + ASSERT_EQ(optData.Value().optionalData.IsSet(), false); +} + +TEST_F(TestOptionals, ProcessOptionalInlineVectorInStruct_SetToUnset) { + // Set optional vector in a struct change to unset in the same vector parameter. + ITestOptionals::Compound data; + data.magic = "hokus"; + data.optionalMagic = "pokus"; + data.data = { 1,2,3,4 }; + data.optionalData = { 11,12,13,14 }; + Core::OptionalType optData; + optData = data; // copy! + ASSERT_EQ(_proxy->ProcessOptionalVectorInOptionalInlineStruct(optData, true /* change setbit! */), Core::ERROR_NONE); + ASSERT_EQ(optData.IsSet(), true); + EXPECT_EQ(optData.Value().magic, data.magic); + ASSERT_EQ(optData.Value().optionalMagic.IsSet(), false); + ASSERT_EQ(optData.Value().data.size(), data.data.size()); + if (optData.Value().data.size() == data.data.size()) { + // process multiplies by 2 + for (uint8_t i = 0; i < data.data.size(); i++) { + EXPECT_EQ(optData.Value().data[i], data.data[i]*2); + } + } + ASSERT_EQ(optData.Value().optionalData.IsSet(), false); +} + // ===== AllOptional ===== TEST_F(TestOptionals, AllOptional_AllUnset) {