From 901b54cb8e26d473408112dafebdbf09d75fdcc3 Mon Sep 17 00:00:00 2001 From: wenlong12 Date: Sun, 23 Apr 2023 11:51:42 +0800 Subject: [PATCH] =?UTF-8?q?ProtoEncoder=E6=A1=86=E6=9E=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=20Signed-off-by:wenlong12=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: wenlong12 --- build/protoc.sh | 12 + bundle.json | 3 +- device/plugins/api/src/writer_adapter.cpp | 2 +- device/plugins/api/src/writer_adapter.h | 2 +- device/services/ipc/BUILD.gn | 21 + .../include/proto_encoder_plugin_generator.h | 39 + .../services/ipc/src/proto_encoder_plugin.cpp | 23 + .../src/proto_encoder_plugin_generator.cpp | 409 ++++ interfaces/kits/plugin_module_api.h | 84 +- proto_encoder/BUILD.gn | 38 + proto_encoder/example/example.proto | 77 + proto_encoder/include/base_message.h | 431 +++++ proto_encoder/include/varint_encode.h | 117 ++ proto_encoder/src/base_message.cpp | 222 +++ proto_encoder/src/varint_encode.cpp | 24 + proto_encoder/test/BUILD.gn | 101 + .../test/unittest/base_message_unittest.cpp | 1639 +++++++++++++++++ .../test/unittest/varint_encode_unittest.cpp | 319 ++++ 18 files changed, 3558 insertions(+), 5 deletions(-) create mode 100755 device/services/ipc/include/proto_encoder_plugin_generator.h create mode 100755 device/services/ipc/src/proto_encoder_plugin.cpp create mode 100755 device/services/ipc/src/proto_encoder_plugin_generator.cpp create mode 100755 proto_encoder/BUILD.gn create mode 100755 proto_encoder/example/example.proto create mode 100755 proto_encoder/include/base_message.h create mode 100755 proto_encoder/include/varint_encode.h create mode 100755 proto_encoder/src/base_message.cpp create mode 100755 proto_encoder/src/varint_encode.cpp create mode 100755 proto_encoder/test/BUILD.gn create mode 100755 proto_encoder/test/unittest/base_message_unittest.cpp create mode 100755 proto_encoder/test/unittest/varint_encode_unittest.cpp diff --git a/build/protoc.sh b/build/protoc.sh index db991fb90..d24a40a39 100755 --- a/build/protoc.sh +++ b/build/protoc.sh @@ -21,6 +21,9 @@ OHOS_X64_OUT=$PROJECT_TOP/$2/ LIBCXX_X64_OUT=$PROJECT_TOP/$1/ndk/libcxx/linux_x86_64 SUBSYS_X64_OUT=$PROJECT_TOP/$2/developtools/profiler PROTOC=$PROJECT_TOP/$2/developtools/profiler/protoc +OPT_PLUGIN_PATH=$PROJECT_TOP/$2/developtools/profiler/protoencoder_plugin +OPT_PLUGIN=--plugin=protoc-gen-opt=$PROJECT_TOP/$2/developtools/profiler/protoencoder_plugin +OPT_OUT=--opt_out PYTHON_SHELL=$THIS_DIR/make_standard_proto.py # shell path TMP=$2 PROTO_OUT_DIR="$PROJECT_TOP/${TMP%/*}/$3" # path of the new proto file @@ -56,5 +59,14 @@ do done PARAMS_ALL="$PARAMS_SRC $PARAMS_STANDARD" # add new argument list to old argument list +# avoid conflict, param4=--plugin* means ipc plugin, generate encode file if opt plugin exist +if [[ "$4" != --plugin* ]]; then + if [ -f "$OPT_PLUGIN_PATH" ]; then + echo "generate protobuf optimize code OPT_PLUGIN = $OPT_PLUGIN" + echo "optimize EXEC: LD_LIBRARY_PATH=$LIBCXX_X64_OUT:$SUBSYS_X64_OUT $PROTOC $OPT_PLUGIN $OPT_OUT $5 $PARAMS_ALL" + LD_LIBRARY_PATH=$LIBCXX_X64_OUT:$SUBSYS_X64_OUT exec $PROTOC $OPT_PLUGIN $OPT_OUT $5 $PARAMS_ALL + fi +fi + echo "EXEC: LD_LIBRARY_PATH=$LIBCXX_X64_OUT:$SUBSYS_X64_OUT $PROTOC $PARAMS_ALL" LD_LIBRARY_PATH=$LIBCXX_X64_OUT:$SUBSYS_X64_OUT exec $PROTOC $PARAMS_ALL diff --git a/bundle.json b/bundle.json index 29541db25..8d20b03f6 100644 --- a/bundle.json +++ b/bundle.json @@ -82,7 +82,8 @@ "//developtools/profiler/device:fuzztest", "//developtools/profiler/device:unittest", "//developtools/profiler/interfaces/kits/test:unittest", - "//developtools/profiler/hidebug/test/unittest:unittest" + "//developtools/profiler/hidebug/test/unittest:unittest", + "//developtools/profiler/proto_encoder/test:unittest" ] } } diff --git a/device/plugins/api/src/writer_adapter.cpp b/device/plugins/api/src/writer_adapter.cpp index 4402143e5..228492c37 100644 --- a/device/plugins/api/src/writer_adapter.cpp +++ b/device/plugins/api/src/writer_adapter.cpp @@ -38,7 +38,7 @@ const WriterStruct* WriterAdapter::GetStruct() return &writerStruct_; } -long WriterAdapter::WriteFunc(WriterStruct* writer, const void* data, size_t size) +long WriterAdapter::WriteFunc(WriterStruct* writer, const char* data, size_t size) { static_assert(offsetof(WriterAdapter, writerStruct_) == 0, "unexpected alignment of writerStruct_!"); WriterAdapter* writerAdaptor = reinterpret_cast(writer); // 转成 WriterAdapter* diff --git a/device/plugins/api/src/writer_adapter.h b/device/plugins/api/src/writer_adapter.h index 862cbb88b..0de858065 100644 --- a/device/plugins/api/src/writer_adapter.h +++ b/device/plugins/api/src/writer_adapter.h @@ -31,7 +31,7 @@ public: WriterPtr GetWriter(); private: - static long WriteFunc(WriterStruct* writer, const void* data, size_t size); + static long WriteFunc(WriterStruct* writer, const char* data, size_t size); static bool FlushFunc(WriterStruct* writer); private: diff --git a/device/services/ipc/BUILD.gn b/device/services/ipc/BUILD.gn index c92c5b8f4..b7cb292c0 100644 --- a/device/services/ipc/BUILD.gn +++ b/device/services/ipc/BUILD.gn @@ -69,3 +69,24 @@ ohos_executable("protoc_gen_ipc") { subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}" part_name = "${OHOS_PROFILER_PART_NAME}" } + +ohos_executable("protoencoder_plugin") { + sources = [ + "src/proto_encoder_plugin.cpp", + "src/proto_encoder_plugin_generator.cpp", + ] + + include_dirs = [ + "include", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}", + ] + public_configs = [ "${OHOS_PROFILER_DIR}/device/base:hiprofiler_test_config" ] + deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc_lib(${host_toolchain})", + ] + install_enable = false + subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}" + part_name = "${OHOS_PROFILER_PART_NAME}" +} diff --git a/device/services/ipc/include/proto_encoder_plugin_generator.h b/device/services/ipc/include/proto_encoder_plugin_generator.h new file mode 100755 index 000000000..80afec4d7 --- /dev/null +++ b/device/services/ipc/include/proto_encoder_plugin_generator.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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. + */ + +#ifndef PROTO_ENCODER_GENERATOR_H +#define PROTO_ENCODER_GENERATOR_H + +#include +#include +#include +#include "google/protobuf/compiler/code_generator.h" +#include "google/protobuf/compiler/plugin.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/io/coded_stream.h" +#include "google/protobuf/io/zero_copy_stream.h" +#include + +class ProtoEncoderGenerator : public google::protobuf::compiler::CodeGenerator { +public: + ProtoEncoderGenerator(); + ~ProtoEncoderGenerator(); + bool Generate(const google::protobuf::FileDescriptor* file, + const std::string& parameter, + google::protobuf::compiler::GeneratorContext* context, + std::string* error) const override; +}; + +#endif diff --git a/device/services/ipc/src/proto_encoder_plugin.cpp b/device/services/ipc/src/proto_encoder_plugin.cpp new file mode 100755 index 000000000..0e20541ea --- /dev/null +++ b/device/services/ipc/src/proto_encoder_plugin.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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. + */ + +#include +#include "proto_encoder_plugin_generator.h" + +int main(int argc, char* argv[]) +{ + ProtoEncoderGenerator generator; + return google::protobuf::compiler::PluginMain(argc, argv, &generator); +} diff --git a/device/services/ipc/src/proto_encoder_plugin_generator.cpp b/device/services/ipc/src/proto_encoder_plugin_generator.cpp new file mode 100755 index 000000000..23947c185 --- /dev/null +++ b/device/services/ipc/src/proto_encoder_plugin_generator.cpp @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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. + */ + +#include "proto_encoder_plugin_generator.h" + +using google::protobuf::FileDescriptor; +using google::protobuf::EnumDescriptor; +using google::protobuf::Descriptor; +using google::protobuf::io::Printer; +using google::protobuf::EnumValueDescriptor; +using google::protobuf::FieldDescriptor; + +class OptGeneratorImpl { +public: + explicit OptGeneratorImpl(const FileDescriptor* file) : fileContent_(file), printer_(nullptr) {} + + std::string GetPrefix(std::string fileName) + { + std::string prefix = ""; + for (size_t i = 0; i < fileName.length(); i++) { + if (fileName.c_str()[i] == '.') { + break; + } + prefix += fileName.c_str()[i]; + } + return prefix; + } + + std::string SetNames(std::string fileName, std::string packageName) + { + fileName_ = fileName; + packageName_ = packageName + "::"; + headFileName_ = ""; + + for (size_t i = 0; i < fileName.length(); i++) { + if (fileName.c_str()[i] == '.') { + break; + } + headFileName_ += fileName.c_str()[i]; + } + baseName_ = SwapName(headFileName_); + return headFileName_; + } + std::string SwapName(std::string s) + { + std::string ret = ""; + bool b = true; + for (size_t i = 0; i < s.length(); i++) { + char c = s[i]; + if (c == '_') { + b = true; + } else if (b && c >= 'a' && c <= 'z') { + ret += (c + 'A' - 'a'); + b = false; + } else { + ret += c; + } + } + return ret; + } + + std::string Tolowercase(const std::string& s) + { + std::string str = s; + std::transform(str.begin(), str.end(), str.begin(), [](char& c) { + return std::tolower(c); + }); + return str; + } + + void GenHeader() + { + GenPrefix(); + GenerateEnum(); + GenerateClass(); + GenSurfix(); + } + void GenPrefix() + { + printer_->Print("// Generated by protoencoder plugin.\n"); + printer_->Print("#pragma once\n"); + printer_->Print("#include \"base_message.h\"\n"); + + for (int i = 0; i < fileContent_->dependency_count(); ++i) { + printer_->Print("#include \"@name@.pbencoder.h\"\n", "name", + GetPrefix(fileContent_->dependency(i)->name())); + } + + printer_->Print("namespace OHOS {\n"); + printer_->Print("namespace Developtools {\n"); + printer_->Print("namespace Profiler {\n"); + printer_->Print("namespace ProtoEncoder {\n"); + } + void GenerateEnum() + { + for (int i = 0; i < fileContent_->enum_type_count(); ++i) { + printer_->Print("enum @class@ : uint32_t {\n", "class", fileContent_->enum_type(i)->name()); + printer_->Indent(); + + for (int j = 0; j < fileContent_->enum_type(i)->value_count(); ++j) { + const EnumValueDescriptor* value = fileContent_->enum_type(i)->value(j); + const std::string value_name = value->name(); + printer_->Print("@name@ = @number@,\n", "name", value_name, "number", + std::to_string(value->number())); + } + printer_->Outdent(); + printer_->Print("};\n"); + } + } + void GenerateClass() + { + // forward declaration + for (int i = 0; i < fileContent_->message_type_count(); ++i) { + const Descriptor* message = fileContent_->message_type(i); + printer_->Print("class @name@;\n", "name", message->name()); + } + + for (int i = 0; i < fileContent_->message_type_count(); ++i) { + const Descriptor* message = fileContent_->message_type(i); + for (int j = 0; j < message->nested_type_count(); ++j) { + const Descriptor* nestmessage = message->nested_type(j); + printer_->Print( + "class @name@ : public BaseMessage {\n" + " public:\n", + "name", nestmessage->name()); + printer_->Indent(); + printer_->Print("@name@() = default;\n", "name", nestmessage->name()); + printer_->Print( + "explicit @name@(RandomWriteCtx* writeCtx, MessageStack* subMessageStack = nullptr) : BaseMessage(writeCtx, subMessageStack) {}\n", + "name", nestmessage->name()); + GenerateFieldsID(nestmessage); + GenerateFunction(nestmessage); + printer_->Outdent(); + printer_->Print("};\n\n"); + } + + printer_->Print( + "class @name@ : public BaseMessage {\n" + " public:\n", + "name", message->name()); + printer_->Indent(); + printer_->Print("@name@() = default;\n", "name", message->name()); + printer_->Print( + "explicit @name@(RandomWriteCtx* writeCtx, MessageStack* subMessageStack = nullptr) : BaseMessage(writeCtx, subMessageStack) {}\n", + "name", message->name()); + GenerateFieldsID(message); + GenerateFunction(message); + printer_->Outdent(); + printer_->Print("};\n\n"); + } + } + + void GenerateFieldsID(const Descriptor* message) + { + for (int i = 0; i < message->field_count(); ++i) { + const FieldDescriptor* field = message->field(i); + printer_->Print("static const uint32_t FIELDID_@name@ = @id@;\n", + "name", field->name(), "id", std::to_string(field->number())); + } + } + + void GenerateFunction(const Descriptor* message) + { + // field->is_repeated() + for (int i = 0; i < message->field_count(); ++i) { + const FieldDescriptor* field = message->field(i); + if (field->type() == FieldDescriptor::TYPE_MESSAGE) { + printer_->Print("inline @typename@* @mora@_@name@()\n", + "mora", field->is_repeated()?"add":"mutable", + "typename", field->message_type()->name(), + "name", Tolowercase(field->name())); + printer_->Print("{\n"); + printer_->Indent(); + printer_->Print("return AddSubMessage<@typename@>(FIELDID_@name@);\n", + "typename", field->message_type()->name(), + "name", field->name()); + printer_->Outdent(); + printer_->Print("}\n"); + } else if (field->type() == FieldDescriptor::TYPE_BYTES) { + printer_->Print("inline void set_@name@(const void* bytes, uint32_t size)\n", + "name", Tolowercase(field->name())); + printer_->Print("{\n"); + printer_->Indent(); + printer_->Print("AddBytes(FIELDID_@name@, bytes, size);\n", "name", field->name()); + printer_->Outdent(); + printer_->Print("}\n"); + printer_->Print("void set_@name@(GetDataCallback getData)\n", "name", Tolowercase(field->name())); + printer_->Print("{\n"); + printer_->Indent(); + printer_->Print("return AddBytesByCallBack(FIELDID_@name@, getData);\n", "name", field->name()); + printer_->Outdent(); + printer_->Print("}\n"); + printer_->Print("inline RandomWriteCtx* startAdd_@name@()\n", "name", Tolowercase(field->name())); + printer_->Print("{\n"); + printer_->Indent(); + printer_->Print("return StartAddBytes(FIELDID_@name@);\n", "name", field->name()); + printer_->Outdent(); + printer_->Print("}\n"); + printer_->Print("inline void finishAdd_@name@(int32_t size)\n", "name", Tolowercase(field->name())); + printer_->Print("{\n"); + printer_->Indent(); + printer_->Print("return FinishAddBytes(size);\n", "name", field->name()); + printer_->Outdent(); + printer_->Print("}\n"); + } else if (field->type() == FieldDescriptor::TYPE_STRING) { + printer_->Print("inline void @sora@_@name@(const std::string& str)\n", + "sora", field->is_repeated()?"add":"set", + "name", Tolowercase(field->name())); + printer_->Print("{\n"); + printer_->Indent(); + printer_->Print("AddBytes(FIELDID_@name@, str.data(), str.size());\n", "name", field->name()); + printer_->Outdent(); + printer_->Print("}\n"); + printer_->Print("inline void @sora@_@name@(std::string&& str)\n", + "sora", field->is_repeated()?"add":"set", + "name", Tolowercase(field->name())); + printer_->Print("{\n"); + printer_->Indent(); + printer_->Print("AddBytes(FIELDID_@name@, str.data(), str.size());\n", "name", field->name()); + printer_->Outdent(); + printer_->Print("}\n"); + printer_->Print("inline void @sora@_@name@(const char* str)\n", + "sora", field->is_repeated()?"add":"set", + "name", Tolowercase(field->name())); + printer_->Print("{\n"); + printer_->Indent(); + printer_->Print("AddBytes(FIELDID_@name@, str, strlen(str));\n", "name", field->name()); + printer_->Outdent(); + printer_->Print("}\n"); + printer_->Print("inline void @sora@_@name@(const char* str, uint32_t len)\n", + "sora", field->is_repeated()?"add":"set", + "name", Tolowercase(field->name())); + printer_->Print("{\n"); + printer_->Indent(); + printer_->Print("AddBytes(FIELDID_@name@, str, len);\n", "name", field->name()); + printer_->Outdent(); + printer_->Print("}\n"); + } else { + // varint, fix32, fix64 + printer_->Print("inline void @sora@_@name@(@paramtype@ v)\n", + "sora", field->is_repeated()?"add":"set", "name", Tolowercase(field->name()), + "paramtype", GetParamType(field)); + printer_->Print("{\n"); + printer_->Indent(); + printer_->Print("@type@(FIELDID_@name@, v);\n", "type", + GetInnerType(field), "name", field->name()); + printer_->Outdent(); + printer_->Print("}\n"); + // packed + if (!field->is_repeated()) { + continue; + } + if (field->type() == FieldDescriptor::TYPE_SINT32 || + field->type() == FieldDescriptor::TYPE_SINT64) { + perror("repeated signed(zigzag) fields are not supported in libprotobuf\n"); + continue; + } + if (!field->is_packed()) { + continue; + } + printer_->Print("inline void add_@name@(const @paramtype@* array, uint32_t size)\n", + "name", Tolowercase(field->name()), + "paramtype", GetParamType(field)); + printer_->Print("{\n"); + printer_->Indent(); + printer_->Print("@type@(FIELDID_@name@, array, size);\n", + "type", GetInnerType(field, true), "name", field->name()); + printer_->Outdent(); + printer_->Print("}\n"); + + printer_->Print("inline void add_@name@(const std::vector<@paramtype@>& array)\n", + "name", Tolowercase(field->name()), + "paramtype", GetParamType(field)); + printer_->Print("{\n"); + printer_->Indent(); + printer_->Print("@type@(FIELDID_@name@, array.data(), array.size());\n", + "type", GetInnerType(field, true), "name", field->name()); + printer_->Outdent(); + printer_->Print("}\n"); + } + } + } + std::string GetParamType(const FieldDescriptor* field) + { + switch (field->type()) { + case FieldDescriptor::TYPE_BOOL: + return "bool"; + case FieldDescriptor::TYPE_ENUM: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_FIXED32: + return "uint32_t"; + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_SFIXED32: + return "int32_t"; + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_SFIXED64: + return "int64_t"; + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_FIXED64: + return "uint64_t"; + case FieldDescriptor::TYPE_DOUBLE: + return "double"; + case FieldDescriptor::TYPE_FLOAT: + return "float"; + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_BYTES: + return ""; + default: + return ""; + } + return ""; + } + + std::string GetInnerType(const FieldDescriptor* field, bool packed = false) + { + switch (field->type()) { + case FieldDescriptor::TYPE_BOOL: + case FieldDescriptor::TYPE_ENUM: + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_UINT64: + return packed?"AddPackedVarint":"AddVarint"; + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_SINT64: + return "AddZigZagVarint"; + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_SFIXED64: + case FieldDescriptor::TYPE_DOUBLE: + return packed?"AddPackedFixed":"AddFixed64"; + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_FLOAT: + return packed?"AddPackedFixed":"AddFixed32"; + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_BYTES: + return ""; + } + return ""; + } + void CollectContext() + { + return; + } + void GenSurfix() + { + printer_->Print("} // namespace ProtoEncoder\n"); + printer_->Print("} // namespace Profiler\n"); + printer_->Print("} // namespace Developtools\n"); + printer_->Print("} // namespace OHOS\n"); + } + void SetPrinter(Printer* stub_h_printer) + { + printer_ = stub_h_printer; + } +private: + std::string fileName_ = ""; + std::string baseName_ = ""; + std::string packageName_ = ""; + std::string headFileName_ = ""; + //std::string header_ = ""; + std::vector namespaces_; + const FileDescriptor* const fileContent_; + std::vector stack; + std::vector enums_; + Printer* printer_; +}; + +ProtoEncoderGenerator::ProtoEncoderGenerator() {} + +ProtoEncoderGenerator::~ProtoEncoderGenerator() {} + +bool ProtoEncoderGenerator::Generate(const google::protobuf::FileDescriptor* file, + const std::string& parameter, + google::protobuf::compiler::GeneratorContext* context, + std::string* error) const +{ + auto pcsp = std::make_shared(file); + std::string base_name = pcsp->SetNames(file->name(), file->package()); + std::unique_ptr<::google::protobuf::io::ZeroCopyOutputStream> header_output(context->Open(base_name + + ".pbencoder.h")); + std::unique_ptr<::google::protobuf::io::ZeroCopyOutputStream> source_output(context->Open(base_name + + ".pbencoder.cc")); + Printer h_printer(header_output.get(), '@'); + pcsp->SetPrinter(&h_printer); + pcsp->GenHeader(); + + Printer cc_printer(source_output.get(), '@'); + cc_printer.Print("// empty\n"); + return true; +} diff --git a/interfaces/kits/plugin_module_api.h b/interfaces/kits/plugin_module_api.h index b71157f16..71cb27dbf 100644 --- a/interfaces/kits/plugin_module_api.h +++ b/interfaces/kits/plugin_module_api.h @@ -58,6 +58,49 @@ typedef int (*PluginSessionStartCallback)(const uint8_t* configData, uint32_t co */ typedef int (*PluginReportResultCallback)(uint8_t* bufferData, uint32_t bufferSize); +typedef struct RandomWriteCtx RandomWriteCtx; + +/** + * @brief get memory of the specified length + * @param size : The byte counts to be used + * @param memory : output current target memory pointer + * @param offset : output current offset relative to the head of writing + * @return : Return true for success and false for failure + */ +typedef bool (*GetMemoryFunc)(RandomWriteCtx* ctx, uint32_t size, uint8_t** memory, uint32_t* offset); + +/** + * @brief seek to the specified offset for writing + * @param offset : offset relative to the head of writing + * @return : Return true for success and false for failure + */ +typedef bool (*SeekFunc)(RandomWriteCtx* ctx, uint32_t offset); + +/** + * RandomWriteCtx : type definition, random write context. + */ +struct RandomWriteCtx { + /** + * get the memory and current offset. + */ + GetMemoryFunc getMemory; + + /** + * seek for writing. + */ + SeekFunc seek; +}; + +/** + * @brief interface type of Plugin result reporting interface type + * The plugin reports the bytes data by randomWrite() directly, + * or constructor proto_encoder message by randomWrite(), + * the message class code is generated by protoc using proto file. + * @param randomWrite: random write context + * @return size that has been reproted, -1 when reprot faild. + */ +typedef int32_t (*PluginReportResultOptimizeCallback)(RandomWriteCtx* randomWrite); + /** * @brief interface type of plugin session stop, * Called when stopping plugin sessions @@ -84,7 +127,7 @@ typedef struct WriterStruct WriterStruct; * @param size : The byte counts in the data buffer * @return : Return the number of bytes written for success, and returns -1 for failure */ -typedef long (*WriteFuncPtr)(WriterStruct* writer, const void* data, size_t size); +typedef long (*WriteFuncPtr)(WriterStruct* writer, const char* data, size_t size); /** * @brief flush : interface type @@ -93,7 +136,23 @@ typedef long (*WriteFuncPtr)(WriterStruct* writer, const void* data, size_t size typedef bool (*FlushFuncPtr)(WriterStruct* writer); /** - * WriterStruct : type definition, containing two function pointers. + * @brief StartReport interface type + * @return : Return RandomWriteCtx for success, null for failure + * The plugin reports the bytes data by RandomWriteCtx directly, + * or constructor proto_encoder message by RandomWriteCtx, + * the message class code is generated by protoc using proto file. + */ +typedef RandomWriteCtx* (*StartReportFuncPtr)(WriterStruct* writer); + +/** + * @brief FinishReport interface type + * @param size : The byte counts of data reported + * @return + */ +typedef void (*FinishReportFuncPtr)(WriterStruct* writer, int32_t size); + +/** + * WriterStruct : type definition. */ struct WriterStruct { /** @@ -105,6 +164,21 @@ struct WriterStruct { * flush function pointer,point to the actual flush function. */ FlushFuncPtr flush; + + /** + * startMessage function pointer, point to the actual startMessage function. + */ + StartReportFuncPtr startReport; + + /** + * finishMessage function pointer, point to the actual finishMessage function. + */ + FinishReportFuncPtr finishReport; + + /** + * data encoding method, true is protobuf, false is protoencoder, default is true for UT. + */ + bool protobufSerialize = true; }; /** @@ -149,6 +223,12 @@ struct PluginModuleCallbacks { * report plugin basic data */ PluginReportBasicDataCallback onReportBasicDataCallback = 0; + + /** + * Data reporting callback optimized and it is used to connect the + * polling reporting results of plugin management framework. + */ + PluginReportResultOptimizeCallback onPluginReportResultOptimize; }; /** diff --git a/proto_encoder/BUILD.gn b/proto_encoder/BUILD.gn new file mode 100755 index 000000000..7fbda2a87 --- /dev/null +++ b/proto_encoder/BUILD.gn @@ -0,0 +1,38 @@ +# Copyright (C) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License 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. + +import("//build/ohos.gni") +import("//developtools/profiler/device/base/config.gni") + +config("proto_encoder_config") { + include_dirs = [ + "include", + "//third_party/bounds_checking_function/include", + "${OHOS_PROFILER_DIR}/interfaces/kits", + ] +} + +ohos_source_set("proto_encoder_source") { + output_name = "proto_encoder" + sources = [ + "src/base_message.cpp", + "src/varint_encode.cpp", + ] + public_configs = [ + ":proto_encoder_config", + "${OHOS_PROFILER_DIR}/device/base:hiprofiler_test_config", + ] + public_deps = [ "//third_party/bounds_checking_function:libsec_static" ] + subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}" + part_name = "${OHOS_PROFILER_PART_NAME}" +} diff --git a/proto_encoder/example/example.proto b/proto_encoder/example/example.proto new file mode 100755 index 000000000..75c1b37a0 --- /dev/null +++ b/proto_encoder/example/example.proto @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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. + */ + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +enum NUM { + ZERO = 0; + ONE = 1; + TWO = 2; + THREE = 3; + FOUR = 4; +} + +message SubMessage { + int32 vint_int32 = 1; + int64 vint_int64 = 2; + uint32 vint_uint32 = 3; + uint64 vint_uint64 = 4; +} + +message ExampleMessage { + // https://developers.google.com/protocol-buffers/docs/encoding + // ID Name Used For + // 0 VARINT int32, int64, uint32, uint64, sint32, sint64, bool, enum + int32 vint_int32 = 1; + int64 vint_int64 = 2; + uint32 vint_uint32 = 3; + uint64 vint_uint64 = 4; + sint32 vint_sint32 = 5; + sint64 vint_sint64 = 6; + bool vint_bool = 7; + NUM vint_enum = 8; + + // 1 I64 fixed64, sfixed64, double + fixed64 I64_fixed64 = 11; + sfixed64 I64_sfixed64 = 12; + double I64_double = 13; + + // 2 LEN string, bytes, embedded messages, packed repeated fields + string LEN_string = 21; + bytes LEN_bytes = 22; // maybe need identified by protoC + SubMessage LEN_sub = 23; + // repeated sint32 repeated_signed_vint = 24; // repeated signed(zigzag) not supported in libprotobuf + repeated int32 LEN_repeated_packed_signed_vint = 25; // [packed = true] + repeated uint32 LEN_repeated_packed_unsigned_vint = 26; // [packed = true] + repeated fixed64 LEN_repeated_packed_fixed = 27; // [packed = true] + repeated SubMessage repeated_LEN_sub = 28; + + // 5 I32 fixed32, sfixed32, float + fixed32 I32_fixed32 = 51; + sfixed32 I32_sfixed32 = 52; + float I32_float = 53; + + // 6 oneof + oneof oneoffield { + fixed64 oneof_fixed64 = 61; + string oneof_string = 62; + SubMessage oneof_sub = 63; + } + + repeated ExampleMessage repeated_Example = 100; + +} diff --git a/proto_encoder/include/base_message.h b/proto_encoder/include/base_message.h new file mode 100755 index 000000000..57aa99831 --- /dev/null +++ b/proto_encoder/include/base_message.h @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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. + */ +#ifndef BASE_MESSAGE_H +#define BASE_MESSAGE_H +#include +#include + +#include "securec.h" +#include "varint_encode.h" +// for struct RandomWriteCtx +#include "plugin_module_api.h" + +namespace OHOS { +namespace Developtools { +namespace Profiler { +namespace ProtoEncoder { +// https://developers.google.com/protocol-buffers/docs/encoding +// ID Name Used For +// 0 VARINT int32, int64, uint32, uint64, sint32, sint64, bool, enum +// 1 I64 fixed64, sfixed64, double +// 2 LEN string, bytes, embedded messages, packed repeated fields +// 3 SGROUP group start (deprecated) +// 4 EGROUP group end (deprecated) +// 5 I32 fixed32, sfixed32, float +enum ProtoMessageType : uint32_t { + VARINT = 0, + I64 = 1, + LEN = 2, + I32 = 5, +}; + +constexpr uint8_t FIELDID_SHIFT = 3; +constexpr uint8_t SIZE_FIXED32 = 4; +constexpr uint8_t SIZE_FIXED64 = 8; +constexpr uint8_t SIZE_RESERVED_LEN = 4; + +class MessagePool; + +class BaseMessage { +public: + BaseMessage() + { + Reset(nullptr, nullptr); + } + + explicit BaseMessage(RandomWriteCtx* writeCtx, MessagePool* subMessageStack = nullptr) + { + Reset(writeCtx, subMessageStack); + } + + ~BaseMessage() + { + if (isWriting_) { + Finish(); + } + } + + void Reset(RandomWriteCtx* writeCtx = nullptr, MessagePool* subMessageStack = nullptr) + { + if (subMessage_ != nullptr) { + FinishSubMessage(); + } + + writeCtx_ = writeCtx; + subMessageStack_ = subMessageStack; + backfillOffset_ = 0; + if (writeCtx == nullptr) { + // can not write + isWriting_ = false; + size_ = -1; + return; + } + size_ = 0; + isWriting_ = true; + } + + // return current size of message has wrote, < 0 if writing failed + inline int32_t Size() + { + return size_; + } + + // finish message and return size of message, < 0 if writing failed + inline int32_t Finish() + { + if (!isWriting_) { + return size_; + } + + if (subMessage_ != nullptr) { + FinishSubMessage(); + } + + isWriting_ = false; + return size_; + } + + // ID Name Used For + // 5 I32 fixed32, sfixed32, float + template + void AddFixed32(uint32_t fieldId, T v) + { + static_assert(sizeof(T) == SIZE_FIXED32, "AddFixed32: T is not 32 bits"); + if (subMessage_ != nullptr) { + FinishSubMessage(); + } + if (!isWriting_) { + return; + } + + uint8_t* fieldMemory = nullptr; + uint32_t fieldOffset = 0; + // max field size = varint(fieldId + type) + Fixed32(v) + if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_FIXED32, + &fieldMemory, &fieldOffset)) { + Drop(); + return; + } + + uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::I32); + // T must be little-endian + if (memcpy_s(fieldMemory + tagSize, SIZE_FIXED32, &v, SIZE_FIXED32) != EOK) { + Drop(); + return; + } + + writeCtx_->seek(writeCtx_, fieldOffset + tagSize + SIZE_FIXED32); + size_ += tagSize + SIZE_FIXED32; + } + + // ID Name Used For + // 1 I64 fixed64, sfixed64, double + template + void AddFixed64(uint32_t fieldId, T v) + { + static_assert(sizeof(T) == SIZE_FIXED64, "AddFixed64: T is not 64 bits"); + if (subMessage_ != nullptr) { + FinishSubMessage(); + } + if (!isWriting_) { + return; + } + + uint8_t* fieldMemory = nullptr; + uint32_t fieldOffset = 0; + // max field size = varint(fieldId + type) + Fixed64(v) + if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_FIXED64, + &fieldMemory, &fieldOffset)) { + Drop(); + return; + } + + uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::I64); + // T must be little-endian + if (memcpy_s(fieldMemory + tagSize, SIZE_FIXED64, &v, SIZE_FIXED64) != EOK) { + Drop(); + return; + } + + writeCtx_->seek(writeCtx_, fieldOffset + tagSize + SIZE_FIXED64); + size_ += tagSize + SIZE_FIXED64; + } + + // ID Name Used For(unsigned and 'intN' varint) + // 0 VARINT int32, int64, uint32, uint64, bool, enum + template + void AddVarint(uint32_t fieldId, T v) + { + if (subMessage_ != nullptr) { + FinishSubMessage(); + } + if (!isWriting_) { + return; + } + + uint8_t* fieldMemory = nullptr; + uint32_t fieldOffset = 0; + // max field size = varint(fieldId + type) + varint(v) + if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + VARINT_ENCODE_MAX_SIZE, + &fieldMemory, &fieldOffset)) { + Drop(); + return; + } + + uint32_t fieldSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::VARINT); + fieldSize += EncodeVarint(fieldMemory + fieldSize, v); + writeCtx_->seek(writeCtx_, fieldOffset + fieldSize); + size_ += fieldSize; + } + + // ID Name Used For('sintN' varint, ZigZag encode) + // 0 VARINT sint32, sint64 + template + void AddZigZagVarint(uint32_t fieldId, T v) + { + if (subMessage_ != nullptr) { + FinishSubMessage(); + } + if (!isWriting_) { + return; + } + + uint8_t* fieldMemory = nullptr; + uint32_t fieldOffset = 0; + // max field size = varint(fieldId + type) + varint(v) + if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + VARINT_ENCODE_MAX_SIZE, + &fieldMemory, &fieldOffset)) { + Drop(); + return; + } + + uint32_t fieldSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::VARINT); + fieldSize += EncodeZigZagVarint(fieldMemory + fieldSize, v); + writeCtx_->seek(writeCtx_, fieldOffset + fieldSize); + size_ += fieldSize; + } + + // ID Name Used For + // 2 LEN bytes, string + void AddBytes(uint32_t fieldId, const void* data, uint32_t dataSize); + + // add customize data, return RandomWriteCtx pointer, caller implement: + // RandomWriteCtx* writeCtx = StartAddBytes(); + // 1, write data by writeCtx->write() directly; + // 2, constructor Message object by writeCtx, and fill data by method of Message + // FinishAddBytes(size); + RandomWriteCtx* StartAddBytes(uint32_t fieldId); + void FinishAddBytes(int32_t size); + + // get data by getData(), implement in getData() function: + // 1, write data by randomWriteCtx->write() directly; + // 2, constructor Message object by randomWriteCtx, and fill data by method of Message + using GetDataCallback = std::function; + void AddBytesByCallBack(uint32_t fieldId, GetDataCallback getData); + + // ID Name Used For + // 2 LEN embedded messages + template + T* AddSubMessage(uint32_t fieldId) + { + static_assert(std::is_base_of::value, + "SubMessage must be a derived class of BaseMessage"); + static_assert(sizeof(T) == sizeof(BaseMessage), + "Size of SubMessage class must be equal to BaseMessage"); + if (subMessage_ != nullptr) { + FinishSubMessage(); + } + if (!isWriting_) { + // return message self pointer for business, + // business can call message->set_XXX() without checking message is nullptr + return static_cast(this); + } + + uint8_t* fieldMemory = nullptr; + // varint(fieldId) + varint(len) + if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN, + &fieldMemory, &backfillOffset_)) { + Drop(); + return static_cast(this); + } + + uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN); + backfillOffset_ += tagSize; + size_ += tagSize; + // reserve length space + writeCtx_->seek(writeCtx_, backfillOffset_ + SIZE_RESERVED_LEN); + if (!AllocateSubMessage()) { + Drop(); + return static_cast(this); + } + return static_cast(subMessage_); + } + + // ID Name Used For + // 2 LEN packed repeated fields(unsigned and 'intN' varint) + template + inline void AddPackedVarint(uint32_t fieldId, const T* array, uint32_t arrayCount) + { + if (arrayCount == 0) { + return; + } + if (subMessage_ != nullptr) { + FinishSubMessage(); + } + if (!isWriting_) { + return; + } + + uint32_t maxLen = 0; + uint32_t lenSize = GetPackedVarintLenSize(arrayCount, sizeof(T), maxLen); + if (lenSize == 0) { + Drop(); + return; + } + + uint8_t* fieldMemory = nullptr; + uint32_t fieldOffset = 0; + // varint(fieldId) + lenSize + maxLen + if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + lenSize + maxLen, + &fieldMemory, &fieldOffset)) { + Drop(); + return; + } + + uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN); + // encode array of varint first + uint32_t dataSize = 0; + uint8_t* pData = fieldMemory + tagSize + lenSize; + for (uint32_t i = 0; i < arrayCount; i++) { + dataSize += EncodeVarint(pData + dataSize, *array); + array++; + } + // varint(Length) + EncodeVarintPadding(fieldMemory + tagSize, dataSize, lenSize); + size_ += tagSize + lenSize + dataSize; + // seek to tail + writeCtx_->seek(writeCtx_, fieldOffset + tagSize + lenSize + dataSize); + } + + // ID Name Used For + // 2 LEN packed repeated fields(I32 and I64) + template + inline void AddPackedFixed(uint32_t fieldId, const T* array, uint32_t arrayCount) + { + static_assert(sizeof(T) == SIZE_FIXED32 || sizeof(T) == SIZE_FIXED64, + "AddPackedFixed: T is not 32 or 64 bits"); + if (arrayCount == 0) { + return; + } + if (subMessage_ != nullptr) { + FinishSubMessage(); + } + if (!isWriting_) { + return; + } + + uint32_t dataSize = arrayCount * sizeof(T); + uint8_t* fieldMemory = nullptr; + uint32_t fieldOffset = 0; + // varint(fieldId) + varint(dataSize) + dataSize + if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN + dataSize, + &fieldMemory, &fieldOffset)) { + Drop(); + return; + } + + uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN); + tagSize += EncodeVarint(fieldMemory + tagSize, dataSize); + if (memcpy_s(fieldMemory + tagSize, dataSize, array, dataSize) != EOK) { + Drop(); + return; + } + + size_ += tagSize + dataSize; + // seek to tail + writeCtx_->seek(writeCtx_, fieldOffset + tagSize + dataSize); + } + +private: + RandomWriteCtx* writeCtx_ = nullptr; + MessagePool* subMessageStack_ = nullptr; + BaseMessage* subMessage_ = nullptr; + int32_t size_ = 0; + uint32_t backfillOffset_ = 0; + bool isWriting_ = true; // false when Finish() or Drop() + + bool AllocateSubMessage(); + void FinishSubMessage(); + + inline void Drop() + { + isWriting_ = false; + size_ = -1; + return; + } +}; + +constexpr uint32_t DEFAULT_SUBMESSAGE_DEPTH = 10; +// MessagePool is cache of the BaseMessage's submessage, avoid new and delete multiple times +// ONE BaseMessage corresponds to ONE MessagePool +class MessagePool { +public: + explicit MessagePool(uint32_t depth = DEFAULT_SUBMESSAGE_DEPTH) + { + Reset(depth); + } + + inline void Reset(uint32_t depth = DEFAULT_SUBMESSAGE_DEPTH) + { + messageCache_.resize(depth); + cursor_ = 0; + } + + BaseMessage* Get() + { + if (cursor_ < messageCache_.size()) { + return &messageCache_[cursor_++]; + } else { + auto& msg = messageCache_.emplace_back(); + cursor_++; + return &msg; + } + } + + inline void Release() + { + if (cursor_ > 0) { + cursor_--; + } + } +private: + std::vector messageCache_; + uint32_t cursor_ = 0; +}; +} // namespace ProtoEncoder +} // namespace Profiler +} // namespace Developtools +} // namespace OHOS +#endif // BASE_MESSAGE_H diff --git a/proto_encoder/include/varint_encode.h b/proto_encoder/include/varint_encode.h new file mode 100755 index 000000000..1357c15b1 --- /dev/null +++ b/proto_encoder/include/varint_encode.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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. + */ +#ifndef VARINT_ENCODE_H +#define VARINT_ENCODE_H +#include +#include +#include +#include + +namespace OHOS { +namespace Developtools { +namespace Profiler { +namespace ProtoEncoder { +constexpr uint32_t VARINT32_SIZE = 4; +constexpr uint32_t VARINT32_ENCODE_SIZE = 5; +constexpr uint32_t VARINT64_SIZE = 8; +constexpr uint32_t VARINT64_ENCODE_SIZE = 10; +constexpr uint32_t VARINT_ENCODE_MAX_SIZE = VARINT64_ENCODE_SIZE; + +constexpr uint32_t VARINT_MAX_1BYTE = (1u << (7 * 1)) - 1; +constexpr uint32_t VARINT_MAX_2BYTE = (1u << (7 * 2)) - 1; +constexpr uint32_t VARINT_MAX_3BYTE = (1u << (7 * 3)) - 1; +constexpr uint32_t VARINT_MAX_4BYTE = (1u << (7 * 4)) - 1; + +constexpr uint8_t VARINT_PAYLOAD_BITS = 7; +constexpr uint8_t VARINT_MASK_PAYLOAD = 0x7F; +constexpr uint8_t VARINT_MASK_MSB = 0x80; + +inline uint32_t GetPackedVarintLenSize(uint32_t itemCount, uint32_t itemSize, uint32_t& len) +{ + len = itemCount; + if (itemSize == VARINT32_SIZE) { + len = itemCount * VARINT32_ENCODE_SIZE; + } else if (itemSize == VARINT64_SIZE) { + len = itemCount * VARINT64_ENCODE_SIZE; + } // else bool is 1 byte + + const uint32_t one = 1; + const uint32_t two = 2; + const uint32_t three = 3; + const uint32_t four = 4; + if (len <= VARINT_MAX_1BYTE) { + return one; + } else if (len <= VARINT_MAX_2BYTE) { + return two; + } else if (len <= VARINT_MAX_3BYTE) { + return three; + } else if (len <= VARINT_MAX_4BYTE) { + return four; + } + + return 0; // illegal, too large +} + +template +inline typename std::make_unsigned::type EncodeZigZag(T v) +{ + if (v >= 0) { + return ((typename std::make_unsigned::type)(v) << 1); + } + + return ((typename std::make_unsigned::type)(~v) << 1) + 1; +} + +template +inline uint32_t EncodeVarint(uint8_t* buf, T v) +{ + // https://developers.google.com/protocol-buffers/docs/encoding + // Unsigned Integers and Signed Integers(intN) + uint64_t value = (uint64_t)v; + uint32_t size = 0; + while (value > (uint64_t)VARINT_MAX_1BYTE) { + buf[size] = (VARINT_MASK_PAYLOAD & value) | VARINT_MASK_MSB; + size++; + value >>= VARINT_PAYLOAD_BITS; + } + buf[size] = (VARINT_MASK_PAYLOAD & value); + size++; + + return size; +} + +template +inline uint32_t EncodeZigZagVarint(uint8_t* buf, T v) +{ + return EncodeVarint(buf, EncodeZigZag(v)); +} + +template +inline void EncodeVarintPadding(uint8_t* buf, T v, uint32_t paddingSize) +{ + uint32_t size = 0; + paddingSize--; + while (size < paddingSize) { + buf[size] = (VARINT_MASK_PAYLOAD & v) | VARINT_MASK_MSB; + size++; + v >>= VARINT_PAYLOAD_BITS; + } + buf[size] = (VARINT_MASK_PAYLOAD & v); +} +} // namespace ProtoEncoder +} // namespace Profiler +} // namespace Developtools +} // namespace OHOS +#endif // VARINT_ENCODE_H diff --git a/proto_encoder/src/base_message.cpp b/proto_encoder/src/base_message.cpp new file mode 100755 index 000000000..1f0bcb021 --- /dev/null +++ b/proto_encoder/src/base_message.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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. + */ +#include "base_message.h" + +#include "securec.h" +#include "varint_encode.h" + +namespace OHOS { +namespace Developtools { +namespace Profiler { +namespace ProtoEncoder { +bool BaseMessage::AllocateSubMessage() +{ + if (subMessageStack_ == nullptr) { + subMessage_ = new (std::nothrow) BaseMessage(writeCtx_); + } else { + subMessage_ = subMessageStack_->Get(); + } + + if (subMessage_ == nullptr) { + return false; + } + subMessage_->Reset(writeCtx_, subMessageStack_); + return true; +} + +void BaseMessage::FinishSubMessage() +{ + int32_t subSize = subMessage_->Finish(); + if (subMessageStack_ == nullptr) { + delete subMessage_; + } else { + subMessageStack_->Release(); + } + subMessage_ = nullptr; + if (subSize < 0) { + Drop(); + return; + } + + uint8_t* fieldMemory = nullptr; + // backfill length + writeCtx_->seek(writeCtx_, backfillOffset_); + if (!writeCtx_->getMemory(writeCtx_, SIZE_RESERVED_LEN, + &fieldMemory, &backfillOffset_)) { + Drop(); + return; + } + + if (subSize == 0) { + // reduce the size + *fieldMemory = 0; + writeCtx_->seek(writeCtx_, backfillOffset_ + 1); + size_++; + return; + } + + // varint(Length) + EncodeVarintPadding(fieldMemory, subSize, SIZE_RESERVED_LEN); + size_ += SIZE_RESERVED_LEN + subSize; + // seek to tail + writeCtx_->seek(writeCtx_, backfillOffset_ + SIZE_RESERVED_LEN + subSize); +} + +void BaseMessage::AddBytes(uint32_t fieldId, const void* data, uint32_t dataSize) +{ + if (subMessage_ != nullptr) { + FinishSubMessage(); + } + if (!isWriting_) { + return; + } + + uint8_t* fieldMemory = nullptr; + uint32_t fieldOffset = 0; + // max field size = varint(fieldId + type) + varint(dataSize) + dataSize + if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN + dataSize, + &fieldMemory, &fieldOffset)) { + Drop(); + return; + } + + uint32_t fieldSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN); + fieldSize += EncodeVarint(fieldMemory + fieldSize, dataSize); + if (dataSize != 0) { + if (memcpy_s(fieldMemory + fieldSize, dataSize, data, dataSize) != EOK) { + Drop(); + return; + } + } + fieldSize += dataSize; + size_ += fieldSize; + // seek to tail + writeCtx_->seek(writeCtx_, fieldOffset + fieldSize); +} + +RandomWriteCtx* BaseMessage::StartAddBytes(uint32_t fieldId) +{ + if (subMessage_ != nullptr) { + FinishSubMessage(); + } + if (!isWriting_) { + // finished or dropped + return nullptr; + } + + uint8_t* fieldMemory = nullptr; + // max field size = varint(fieldId + type) + varint(len) + if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN, + &fieldMemory, &backfillOffset_)) { + Drop(); + return nullptr; + } + + uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN); + backfillOffset_ += tagSize; + size_ += tagSize; + // reserve length space + writeCtx_->seek(writeCtx_, backfillOffset_ + SIZE_RESERVED_LEN); + return writeCtx_; +} + +void BaseMessage::FinishAddBytes(int32_t size) +{ + if (size < 0) { + Drop(); + return; + } + + uint8_t* fieldMemory = nullptr; + // backfill length + writeCtx_->seek(writeCtx_, backfillOffset_); + if (!writeCtx_->getMemory(writeCtx_, SIZE_RESERVED_LEN, &fieldMemory, &backfillOffset_)) { + Drop(); + return; + } + + if (size == 0) { + // reduce the size + *fieldMemory = 0; + writeCtx_->seek(writeCtx_, backfillOffset_ + 1); + size_++; + return; + } + + // varint(Length) + EncodeVarintPadding(fieldMemory, size, SIZE_RESERVED_LEN); + size_ += SIZE_RESERVED_LEN + size; + // seek to tail + writeCtx_->seek(writeCtx_, backfillOffset_ + SIZE_RESERVED_LEN + size); +} + +void BaseMessage::AddBytesByCallBack(uint32_t fieldId, GetDataCallback getData) +{ + if (!getData) { + return; + } + + if (subMessage_ != nullptr) { + FinishSubMessage(); + } + if (!isWriting_) { + return; + } + + uint8_t* fieldMemory = nullptr; + uint32_t fieldOffset = 0; + // max field size = varint(fieldId + type) + varint(len) + if (!writeCtx_->getMemory(writeCtx_, VARINT_ENCODE_MAX_SIZE + SIZE_RESERVED_LEN, + &fieldMemory, &fieldOffset)) { + Drop(); + return; + } + + uint32_t tagSize = EncodeVarint(fieldMemory, (fieldId << FIELDID_SHIFT) | ProtoMessageType::LEN); + fieldOffset += tagSize; + size_ += tagSize; + // reserve length space + writeCtx_->seek(writeCtx_, fieldOffset + SIZE_RESERVED_LEN); + + int32_t dataSize = getData(writeCtx_); + if (dataSize < 0) { + Drop(); + return; + } + + // backfill length + writeCtx_->seek(writeCtx_, fieldOffset); + if (!writeCtx_->getMemory(writeCtx_, SIZE_RESERVED_LEN, &fieldMemory, &fieldOffset)) { + Drop(); + return; + } + + if (dataSize == 0) { + // reduce the size + *fieldMemory = 0; + writeCtx_->seek(writeCtx_, fieldOffset + 1); + size_++; + return; + } + + EncodeVarintPadding(fieldMemory, dataSize, SIZE_RESERVED_LEN); + size_ += SIZE_RESERVED_LEN + dataSize; + // seek to tail + writeCtx_->seek(writeCtx_, fieldOffset + SIZE_RESERVED_LEN + dataSize); +} +} // namespace ProtoEncoder +} // namespace Profiler +} // namespace Developtools +} // namespace OHOS diff --git a/proto_encoder/src/varint_encode.cpp b/proto_encoder/src/varint_encode.cpp new file mode 100755 index 000000000..6a560cdbc --- /dev/null +++ b/proto_encoder/src/varint_encode.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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. + */ +#include "varint_encode.h" + +namespace OHOS { +namespace Developtools { +namespace Profiler { +namespace ProtoEncoder { +} // namespace ProtoEncoder +} // namespace Profiler +} // namespace Developtools +} // namespace OHOS diff --git a/proto_encoder/test/BUILD.gn b/proto_encoder/test/BUILD.gn new file mode 100755 index 000000000..ee3f10f42 --- /dev/null +++ b/proto_encoder/test/BUILD.gn @@ -0,0 +1,101 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License 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. + +import("//build/test.gni") +import("//developtools/profiler/device/base/config.gni") +import("//developtools/profiler/protos/protos.gni") + +module_output_path = "${OHOS_PROFILER_TEST_MODULE_OUTPUT_PATH}/proto_encoder" +config("module_private_config") { + visibility = [ ":*" ] +} + +protos_dir = "../example/" +protos_root_dir = rebase_path(protos_dir, root_build_dir) +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(protos_dir, "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) + +protos_defines = [ "$protos_dir" + "example.proto" ] +example_codegen_all = [] +foreach(proto, protos_defines) { + name = get_path_info(proto, "name") + example_codegen_all += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + "$proto_out_dir/$name.pbencoder.h", + "$proto_out_dir/$name.pbencoder.cc", + ] +} + +action("proto_gen_source") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = protos_defines + outputs = example_codegen_all + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "$proto_rel_out_dir", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + "$protos_root_dir", + ] + args += rebase_path(sources, root_build_dir) + deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_PROFILER_DIR}/device/services/ipc:protoencoder_plugin(${host_toolchain})", + ] +} + + +ohos_source_set("proto_example_source") { + deps = [ + ":proto_gen_source", + ] + include_dirs = [ "$proto_out_dir" ] + sources = example_codegen_all + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}" + part_name = "${OHOS_PROFILER_PART_NAME}" +} + +ohos_unittest("proto_encoder_ut") { + module_out_path = module_output_path + sources = [ + "unittest/base_message_unittest.cpp", + "unittest/varint_encode_unittest.cpp", + ] + deps = [ + ":proto_example_source", + "../:proto_encoder_source", + "//third_party/googletest:gtest_main", + ] + include_dirs = [ + "../include", + "../example", + "//third_party/googletest/googletest/include/gtest", + "$proto_out_dir", + ] + + configs = [ ":module_private_config" ] + subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}" + part_name = "${OHOS_PROFILER_PART_NAME}" +} + +group("unittest") { + testonly = true + deps = [ ":proto_encoder_ut" ] +} diff --git a/proto_encoder/test/unittest/base_message_unittest.cpp b/proto_encoder/test/unittest/base_message_unittest.cpp new file mode 100755 index 000000000..d7702dc45 --- /dev/null +++ b/proto_encoder/test/unittest/base_message_unittest.cpp @@ -0,0 +1,1639 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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. + */ +#include +#include +#include +#include + +#include "base_message.h" +#include "example.pb.h" +#include "example.pbencoder.h" + +namespace OHOS { +namespace Developtools { +namespace Profiler { +using namespace testing::ext; + +constexpr uint32_t SIZE_BUFFER = 1024 * 1024; +static uint8_t g_buf[SIZE_BUFFER] = {0}; +static uint32_t g_writePos = 0; + +bool GetMemory(RandomWriteCtx* ctx, uint32_t size, uint8_t** memory, uint32_t* offset) +{ + if (g_writePos + size > sizeof(g_buf)) { + return false; + } + + *memory = &g_buf[g_writePos]; + *offset = g_writePos; + return true; +} + +bool Seek(RandomWriteCtx* ctx, uint32_t offset) +{ + if (offset >= sizeof(g_buf)) { + return false; + } + + g_writePos = offset; + return true; +} + +static RandomWriteCtx g_writeCtx = {GetMemory, Seek}; + +class BaseMessageUnittest : public ::testing::Test { +public: + static void SetUpTestCase() {}; + static void TearDownTestCase() {}; + + void SetUp() + { + g_writePos = 0; + } + void TearDown() {}; +}; + +HWTEST_F(BaseMessageUnittest, Size, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_int32(1); + msgOpt.set_vint_int64(1); + msgOpt.set_vint_uint32(1); + msgOpt.set_vint_uint64(1); + msgOpt.set_vint_sint32(1); + msgOpt.set_vint_sint64(1); + msgOpt.set_vint_bool(true); + msgOpt.set_vint_enum(ProtoEncoder::NUM::ONE); + ASSERT_EQ(g_writePos, (uint32_t)msgOpt.Size()); + + const std::string str = "this is test."; + msgOpt.set_len_string(str); + msgOpt.set_len_bytes(str.data(), str.size()); + ASSERT_EQ(g_writePos, (uint32_t)msgOpt.Size()); + + ProtoEncoder::SubMessage* msgSub = msgOpt.mutable_len_sub(); + ASSERT_TRUE(msgSub != nullptr); + msgSub->set_vint_int32(1); + msgSub->set_vint_int64(1); + msgSub->set_vint_uint32(1); + msgSub->set_vint_uint64(1); + // has not backfill the length of subMessage + ASSERT_GT(g_writePos, (uint32_t)msgOpt.Size()); + + msgOpt.set_i64_fixed64(1); + msgOpt.set_i64_sfixed64(1); + msgOpt.set_i64_double(1); + ASSERT_EQ(g_writePos, (uint32_t)msgOpt.Size()); +} + +HWTEST_F(BaseMessageUnittest, SetVarintInt32, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_int32(0); + printf("set_vint_int32(0):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_int32(), 0); + + // min + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_int32(std::numeric_limits::min()); + printf("set_vint_int32(%" PRId32 "):\n", std::numeric_limits::min()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_int32(), std::numeric_limits::min()); + + // max + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_int32(std::numeric_limits::max()); + printf("set_vint_int32(%" PRId32 "):\n", std::numeric_limits::max()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_int32(), std::numeric_limits::max()); +} + +HWTEST_F(BaseMessageUnittest, SetVarintInt64, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_int64(0); + printf("set_vint_int64(0):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_int64(), 0); + + // min + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_int64(std::numeric_limits::min()); + printf("set_vint_int64(%" PRId64 "):\n", std::numeric_limits::max()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_int64(), std::numeric_limits::min()); + + // max + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_int64(std::numeric_limits::max()); + printf("set_vint_int64(%" PRId64 "):\n", std::numeric_limits::max()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_int64(), std::numeric_limits::max()); +} + +HWTEST_F(BaseMessageUnittest, SetVarintUint32, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_uint32(0); + printf("set_vint_uint32(0):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_uint32(), (uint32_t)0); + + // min + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_uint32(std::numeric_limits::min()); + printf("set_vint_uint32(%" PRIu32 "):\n", std::numeric_limits::min()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_uint32(), std::numeric_limits::min()); + + // max + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_uint32(std::numeric_limits::max()); + printf("set_vint_uint32(%" PRIu32 "):\n", std::numeric_limits::max()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_uint32(), std::numeric_limits::max()); +} + +HWTEST_F(BaseMessageUnittest, SetVarintUint64, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_uint64(0); + printf("set_vint_uint64(0):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_uint64(), (uint64_t)0); + + // min + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_uint64(std::numeric_limits::min()); + printf("set_vint_uint64(%" PRIu64 "):\n", std::numeric_limits::min()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_uint64(), std::numeric_limits::min()); + + // max + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_uint64(std::numeric_limits::max()); + printf("set_vint_uint64(%" PRIu64 "):\n", std::numeric_limits::max()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_uint64(), std::numeric_limits::max()); +} + +HWTEST_F(BaseMessageUnittest, SetVarintSint32, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_sint32(0); + printf("set_vint_sint32(0):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_sint32(), (int32_t)0); + + // min + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_sint32(std::numeric_limits::min()); + printf("set_vint_sint32(%" PRId32 "):\n", std::numeric_limits::min()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_sint32(), std::numeric_limits::min()); + + // max + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_sint32(std::numeric_limits::max()); + printf("set_vint_sint32(%" PRId32 "):\n", std::numeric_limits::max()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_sint32(), std::numeric_limits::max()); +} + +HWTEST_F(BaseMessageUnittest, SetVarintSint64, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_sint64(0); + printf("set_vint_sint64(0):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_sint64(), (int64_t)0); + + // min + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_sint64(std::numeric_limits::min()); + printf("set_vint_sint64(%" PRId64 "):\n", std::numeric_limits::min()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_sint64(), std::numeric_limits::min()); + + // max + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_sint64(std::numeric_limits::max()); + printf("set_vint_sint64(%" PRId64 "):\n", std::numeric_limits::max()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_sint64(), std::numeric_limits::max()); +} + +HWTEST_F(BaseMessageUnittest, SetVarintBool, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + // min + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_bool(std::numeric_limits::min()); + printf("set_vint_bool(%d):\n", std::numeric_limits::min()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_bool(), std::numeric_limits::min()); + + // max + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_bool(std::numeric_limits::max()); + printf("set_vint_bool(%d):\n", std::numeric_limits::max()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_bool(), std::numeric_limits::max()); +} + +HWTEST_F(BaseMessageUnittest, SetVarintEnum, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + // min + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_enum(ProtoEncoder::NUM::ZERO); + printf("set_vint_enum(%d):\n", static_castProtoEncoder::NUM::ZERO); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_enum(), static_castProtoEncoder::NUM::ZERO); + + // max + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_enum(ProtoEncoder::NUM::FOUR); + printf("set_vint_enum(%d):\n", static_castProtoEncoder::NUM::FOUR); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_enum(), static_castProtoEncoder::NUM::FOUR); +} + +HWTEST_F(BaseMessageUnittest, SetFixed64, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_i64_fixed64(0); + printf("set_i64_fixed64(0):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.i64_fixed64(), (uint64_t)0); + + // min + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_i64_fixed64(std::numeric_limits::min()); + printf("set_i64_fixed64(%" PRIu64 "):\n", std::numeric_limits::min()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.i64_fixed64(), std::numeric_limits::min()); + + // max + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_i64_fixed64(std::numeric_limits::max()); + printf("set_i64_fixed64(%" PRIu64 "):\n", std::numeric_limits::max()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.i64_fixed64(), std::numeric_limits::max()); +} + +HWTEST_F(BaseMessageUnittest, SetSfixed64, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_i64_sfixed64(0); + printf("set_i64_sfixed64(0):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.i64_sfixed64(), (int64_t)0); + + // min + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_i64_sfixed64(std::numeric_limits::min()); + printf("set_i64_sfixed64(%" PRId64 "):\n", std::numeric_limits::min()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.i64_sfixed64(), std::numeric_limits::min()); + + // max + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_i64_sfixed64(std::numeric_limits::max()); + printf("set_i64_sfixed64(%" PRId64 "):\n", std::numeric_limits::max()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.i64_sfixed64(), std::numeric_limits::max()); +} + +HWTEST_F(BaseMessageUnittest, SetDouble, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_i64_double(0); + printf("set_i64_double(0):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.i64_double(), (double)0); + + // min + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_i64_double(std::numeric_limits::min()); + printf("set_i64_double(%e):\n", std::numeric_limits::min()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.i64_double(), std::numeric_limits::min()); + + // max + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_i64_double(std::numeric_limits::max()); + printf("set_i64_double(%e):\n", std::numeric_limits::max()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.i64_double(), std::numeric_limits::max()); +} + +HWTEST_F(BaseMessageUnittest, SetFixed32, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_i32_fixed32(0); + printf("set_i32_fixed32(0):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.i32_fixed32(), (uint32_t)0); + + // min + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_i32_fixed32(std::numeric_limits::min()); + printf("set_i32_fixed32(%" PRIu32 "):\n", std::numeric_limits::min()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.i32_fixed32(), std::numeric_limits::min()); + + // max + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_i32_fixed32(std::numeric_limits::max()); + printf("set_i32_fixed32(%" PRIu32 "):\n", std::numeric_limits::max()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.i32_fixed32(), std::numeric_limits::max()); +} + +HWTEST_F(BaseMessageUnittest, SetSfixed32, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_i32_sfixed32(0); + printf("set_i32_sfixed32(0):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.i32_sfixed32(), (int32_t)0); + + // min + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_i32_sfixed32(std::numeric_limits::min()); + printf("set_i32_sfixed32(%" PRId32 "):\n", std::numeric_limits::min()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.i32_sfixed32(), std::numeric_limits::min()); + + // max + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_i32_sfixed32(std::numeric_limits::max()); + printf("set_i32_sfixed32(%" PRId32 "):\n", std::numeric_limits::max()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.i32_sfixed32(), std::numeric_limits::max()); +} + +HWTEST_F(BaseMessageUnittest, SetFloat, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_i32_float(0); + printf("set_i32_float(0):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.i32_float(), (float)0); + + // min + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_i32_float(std::numeric_limits::min()); + printf("set_i32_float(%e):\n", std::numeric_limits::min()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.i32_float(), std::numeric_limits::min()); + + // max + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_i32_float(std::numeric_limits::max()); + printf("set_i32_float(%e):\n", std::numeric_limits::max()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.i32_float(), std::numeric_limits::max()); +} + +HWTEST_F(BaseMessageUnittest, SetString, TestSize.Level1) +{ + const std::string emptyStr = ""; + const std::string str = "this is test."; + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_len_string(emptyStr); + printf("set_len_string(empty string):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + // data of g_buf should is "AA 01 00" + const int32_t emptyStrFieldLen = 3; + ASSERT_EQ(msgOpt.Size(), emptyStrFieldLen); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.len_string(), emptyStr); + + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_len_string(str); + printf("set_len_string(string: %s):\n", str.c_str()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.len_string(), str); + + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_len_string(str.c_str()); + printf("set_len_string(char*: %s):\n", str.c_str()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.len_string(), str); +} + +HWTEST_F(BaseMessageUnittest, SetSubMessage, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + // empty + g_writeCtx.seek(&g_writeCtx, 0); + ProtoEncoder::SubMessage* subMsgOpt = msgOpt.mutable_len_sub(); + ASSERT_TRUE(subMsgOpt != nullptr); + msgOpt.set_vint_int32(std::numeric_limits::min()); + printf("mutable_len_sub: nothing:\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_TRUE(msgProtobuf.has_len_sub()); + + // min + g_writeCtx.seek(&g_writeCtx, 0); + subMsgOpt = msgOpt.mutable_len_sub(); + ASSERT_TRUE(subMsgOpt != nullptr); + subMsgOpt->set_vint_int32(std::numeric_limits::min()); + subMsgOpt->set_vint_int64(std::numeric_limits::min()); + subMsgOpt->set_vint_uint32(std::numeric_limits::min()); + subMsgOpt->set_vint_uint64(std::numeric_limits::min()); + + msgOpt.set_vint_int32(std::numeric_limits::min()); + printf("mutable_len_sub: min:\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_TRUE(msgProtobuf.has_len_sub()); + SubMessage subMsgProtobuf = msgProtobuf.len_sub(); + ASSERT_EQ(subMsgProtobuf.vint_int32(), std::numeric_limits::min()); + ASSERT_EQ(subMsgProtobuf.vint_int64(), std::numeric_limits::min()); + ASSERT_EQ(subMsgProtobuf.vint_uint32(), std::numeric_limits::min()); + ASSERT_EQ(subMsgProtobuf.vint_uint64(), std::numeric_limits::min()); + + // max + g_writeCtx.seek(&g_writeCtx, 0); + subMsgOpt = msgOpt.mutable_len_sub(); + ASSERT_TRUE(subMsgOpt != nullptr); + subMsgOpt->set_vint_int32(std::numeric_limits::max()); + subMsgOpt->set_vint_int64(std::numeric_limits::max()); + subMsgOpt->set_vint_uint32(std::numeric_limits::max()); + subMsgOpt->set_vint_uint64(std::numeric_limits::max()); + + msgOpt.set_vint_int32(std::numeric_limits::min()); + printf("mutable_len_sub: max:\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_TRUE(msgProtobuf.has_len_sub()); + subMsgProtobuf = msgProtobuf.len_sub(); + ASSERT_EQ(subMsgProtobuf.vint_int32(), std::numeric_limits::max()); + ASSERT_EQ(subMsgProtobuf.vint_int64(), std::numeric_limits::max()); + ASSERT_EQ(subMsgProtobuf.vint_uint32(), std::numeric_limits::max()); + ASSERT_EQ(subMsgProtobuf.vint_uint64(), std::numeric_limits::max()); +} + +HWTEST_F(BaseMessageUnittest, SetOneOf, TestSize.Level1) +{ + const std::string str = "this is test."; + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + // oneof_fixed64 + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_oneof_fixed64(std::numeric_limits::max()); + printf("set_oneof_fixed64(%" PRIu64"):\n", std::numeric_limits::max()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.oneof_fixed64(), std::numeric_limits::max()); + + // oneof_sub + ProtoEncoder::SubMessage* subMsgOpt = msgOpt.mutable_oneof_sub(); + ASSERT_TRUE(subMsgOpt != nullptr); + subMsgOpt->set_vint_int32(std::numeric_limits::max()); + subMsgOpt->set_vint_int64(std::numeric_limits::max()); + subMsgOpt->set_vint_uint32(std::numeric_limits::max()); + subMsgOpt->set_vint_uint64(std::numeric_limits::max()); + msgOpt.set_i32_fixed32(0); + printf("mutable_oneof_sub: max:\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_TRUE(msgProtobuf.has_oneof_sub()); + SubMessage subMsgProtobuf = msgProtobuf.oneof_sub(); + ASSERT_EQ(subMsgProtobuf.vint_int32(), std::numeric_limits::max()); + ASSERT_EQ(subMsgProtobuf.vint_int64(), std::numeric_limits::max()); + ASSERT_EQ(subMsgProtobuf.vint_uint32(), std::numeric_limits::max()); + ASSERT_EQ(subMsgProtobuf.vint_uint64(), std::numeric_limits::max()); + + // oneof_string + msgOpt.set_oneof_string(str); + printf("set_oneof_string(%s):\n", str.c_str()); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.oneof_string(), str); + + // last one wins + ASSERT_NE(msgProtobuf.oneof_fixed64(), std::numeric_limits::max()); + ASSERT_FALSE(msgProtobuf.has_oneof_sub()); +} + +HWTEST_F(BaseMessageUnittest, SetRepeatedPackedVarintSigned, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + const int32_t array[] = {0, 1, + std::numeric_limits::min(), + std::numeric_limits::max()}; + std::vector vec; + vec.emplace_back(0); + vec.emplace_back(1); + vec.emplace_back(std::numeric_limits::min()); + vec.emplace_back(std::numeric_limits::max()); + + // vector + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.add_len_repeated_packed_signed_vint(vec); + printf("add_len_repeated_packed_signed_vint(vector):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + int count = msgProtobuf.len_repeated_packed_signed_vint_size(); + ASSERT_EQ(count, static_castvec.size()); + for (int i = 0; i < count; i++) { + ASSERT_EQ(msgProtobuf.len_repeated_packed_signed_vint(i), vec[i]); + } + + // array + msgOpt.add_len_repeated_packed_signed_vint(array, sizeof(array) / sizeof(array[0])); + printf("add_len_repeated_packed_signed_vint(array):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + int countAll = msgProtobuf.len_repeated_packed_signed_vint_size(); + ASSERT_EQ(countAll, static_cast(vec.size() + sizeof(array) / sizeof(array[0]))); + for (int i = 0; i < count; i++) { + ASSERT_EQ(msgProtobuf.len_repeated_packed_signed_vint(i), vec[i]); + } + for (int i = count; i < countAll; i++) { + ASSERT_EQ(msgProtobuf.len_repeated_packed_signed_vint(i), array[i - count]); + } +} + +HWTEST_F(BaseMessageUnittest, SetRepeatedPackedVarintUnsigned, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + const uint32_t array[] = {0, 1, + std::numeric_limits::min(), + std::numeric_limits::max()}; + std::vector vec; + vec.emplace_back(0); + vec.emplace_back(1); + vec.emplace_back(std::numeric_limits::min()); + vec.emplace_back(std::numeric_limits::max()); + + // vector + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.add_len_repeated_packed_unsigned_vint(vec); + printf("add_len_repeated_packed_unsigned_vint(vec):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + int count = msgProtobuf.len_repeated_packed_unsigned_vint_size(); + ASSERT_EQ(count, static_castvec.size()); + for (int i = 0; i < count; i++) { + ASSERT_EQ(msgProtobuf.len_repeated_packed_unsigned_vint(i), vec[i]); + } + + // array + msgOpt.add_len_repeated_packed_unsigned_vint(array, sizeof(array) / sizeof(array[0])); + printf("add_len_repeated_packed_unsigned_vint(array):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + int countAll = msgProtobuf.len_repeated_packed_unsigned_vint_size(); + ASSERT_EQ(countAll, static_cast(vec.size() + sizeof(array) / sizeof(array[0]))); + for (int i = 0; i < count; i++) { + ASSERT_EQ(msgProtobuf.len_repeated_packed_unsigned_vint(i), vec[i]); + } + for (int i = count; i < countAll; i++) { + ASSERT_EQ(msgProtobuf.len_repeated_packed_unsigned_vint(i), array[i - count]); + } +} + +HWTEST_F(BaseMessageUnittest, SetRepeatedPackedFixed64, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + const uint64_t array[] = {0, 1, + std::numeric_limits::min(), + std::numeric_limits::max()}; + std::vector vec; + vec.emplace_back(0); + vec.emplace_back(1); + vec.emplace_back(std::numeric_limits::min()); + vec.emplace_back(std::numeric_limits::max()); + + // vector + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.add_len_repeated_packed_fixed(vec); + printf("add_len_repeated_packed_fixed(vec):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + int count = msgProtobuf.len_repeated_packed_fixed_size(); + ASSERT_EQ(count, static_castvec.size()); + for (int i = 0; i < count; i++) { + ASSERT_EQ(msgProtobuf.len_repeated_packed_fixed(i), vec[i]); + } + + // array + msgOpt.add_len_repeated_packed_fixed(array, sizeof(array) / sizeof(array[0])); + printf("add_len_repeated_packed_fixed(array):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + int countAll = msgProtobuf.len_repeated_packed_fixed_size(); + ASSERT_EQ(countAll, static_cast(vec.size() + sizeof(array) / sizeof(array[0]))); + for (int i = 0; i < count; i++) { + ASSERT_EQ(msgProtobuf.len_repeated_packed_fixed(i), vec[i]); + } + for (int i = count; i < countAll; i++) { + ASSERT_EQ(msgProtobuf.len_repeated_packed_fixed(i), array[i - count]); + } +} + +static const char BYTES_DATA[] = {0x00, 0x01, 0x02, 0xFD, 0xFE, 0xFF}; + +HWTEST_F(BaseMessageUnittest, SetBytes, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_len_bytes(BYTES_DATA, sizeof(BYTES_DATA)); + printf("set_len_bytes(void*, size_t):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.len_bytes(), std::string(&BYTES_DATA[0], sizeof(BYTES_DATA))); +} + +HWTEST_F(BaseMessageUnittest, SetBytesCallback, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + // bytes stram + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_len_bytes( + [](RandomWriteCtx* ctx) -> int32_t { + uint8_t* memory = nullptr; + uint32_t offset = 0; + if (ctx->getMemory(ctx, sizeof(BYTES_DATA), &memory, &offset)) { + if (memcpy_s(memory, sizeof(BYTES_DATA), BYTES_DATA, sizeof(BYTES_DATA)) == EOK) { + ctx->seek(ctx, offset + sizeof(BYTES_DATA)); + return sizeof(BYTES_DATA); + } + } + return 0; + }); + printf("set_len_bytes(CallbackFunc(bytes)):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.len_bytes(), std::string(&BYTES_DATA[0], sizeof(BYTES_DATA))); + + // protobufOpt message + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_len_bytes( + [](RandomWriteCtx* ctx) -> int32_t { + ProtoEncoder::SubMessage subMsg(ctx); + subMsg.set_vint_int32(std::numeric_limits::max()); + subMsg.set_vint_int64(std::numeric_limits::max()); + subMsg.set_vint_uint32(std::numeric_limits::max()); + subMsg.set_vint_uint64(std::numeric_limits::max()); + return subMsg.Finish(); + }); + printf("set_len_bytes(CallbackFunc(message)):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + auto& bytes = msgProtobuf.len_bytes(); + SubMessage subMsgProtobuf; + ASSERT_TRUE(subMsgProtobuf.ParseFromArray(bytes.data(), bytes.size())); + ASSERT_EQ(subMsgProtobuf.vint_int32(), std::numeric_limits::max()); + ASSERT_EQ(subMsgProtobuf.vint_int64(), std::numeric_limits::max()); + ASSERT_EQ(subMsgProtobuf.vint_uint32(), std::numeric_limits::max()); + ASSERT_EQ(subMsgProtobuf.vint_uint64(), std::numeric_limits::max()); +} + +HWTEST_F(BaseMessageUnittest, AddBytes, TestSize.Level1) +{ + const char data[] = {0x00, 0x01, 0x02, 0xFD, 0xFE, 0xFF}; + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + // bytes stram + g_writeCtx.seek(&g_writeCtx, 0); + RandomWriteCtx* writeCtx = msgOpt.startAdd_len_bytes(); + uint8_t* memory = nullptr; + uint32_t offset = 0; + if (writeCtx->getMemory(writeCtx, sizeof(data), &memory, &offset)) { + if (memcpy_s(memory, sizeof(data), data, sizeof(data)) != EOK) { + writeCtx->seek(writeCtx, offset + sizeof(data)); + } + } + msgOpt.finishAdd_len_bytes(sizeof(data)); + printf("Add_LEN_bytes(Customize(bytes)):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.len_bytes(), std::string(&data[0], sizeof(data))); + + // protobufOpt message + g_writeCtx.seek(&g_writeCtx, 0); + writeCtx = msgOpt.startAdd_len_bytes(); + ProtoEncoder::SubMessage subMsg(writeCtx); + subMsg.set_vint_int32(std::numeric_limits::max()); + subMsg.set_vint_int64(std::numeric_limits::max()); + subMsg.set_vint_uint32(std::numeric_limits::max()); + subMsg.set_vint_uint64(std::numeric_limits::max()); + msgOpt.finishAdd_len_bytes(subMsg.Finish()); + printf("Add_LEN_bytes(Customize(message)):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + auto& bytes = msgProtobuf.len_bytes(); + SubMessage subMsgProtobuf; + ASSERT_TRUE(subMsgProtobuf.ParseFromArray(bytes.data(), bytes.size())); + ASSERT_EQ(subMsgProtobuf.vint_int32(), std::numeric_limits::max()); + ASSERT_EQ(subMsgProtobuf.vint_int64(), std::numeric_limits::max()); + ASSERT_EQ(subMsgProtobuf.vint_uint32(), std::numeric_limits::max()); + ASSERT_EQ(subMsgProtobuf.vint_uint64(), std::numeric_limits::max()); +} + +HWTEST_F(BaseMessageUnittest, SetAll, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_vint_int32(1); + msgOpt.set_vint_int64(1); + msgOpt.set_vint_uint32(1); + msgOpt.set_vint_uint64(1); + msgOpt.set_vint_sint32(1); + msgOpt.set_vint_sint64(1); + msgOpt.set_vint_bool(true); + msgOpt.set_vint_enum(ProtoEncoder::NUM::ONE); + msgOpt.set_i64_fixed64(1); + msgOpt.set_i64_sfixed64(1); + msgOpt.set_i64_double(1); + + const std::string str = "this is test."; + msgOpt.set_len_string(str); + msgOpt.set_len_bytes(BYTES_DATA, sizeof(BYTES_DATA)); + + ProtoEncoder::SubMessage* msgSub = msgOpt.mutable_len_sub(); + ASSERT_TRUE(msgSub != nullptr); + msgSub->set_vint_int32(1); + msgSub->set_vint_int64(1); + msgSub->set_vint_uint32(1); + msgSub->set_vint_uint64(1); + + const int32_t arraySigned[] = {0, 1, + std::numeric_limits::min(), + std::numeric_limits::max()}; + std::vector vecSigned; + vecSigned.emplace_back(0); + vecSigned.emplace_back(1); + vecSigned.emplace_back(std::numeric_limits::min()); + vecSigned.emplace_back(std::numeric_limits::max()); + msgOpt.add_len_repeated_packed_signed_vint(vecSigned); + msgOpt.add_len_repeated_packed_signed_vint(arraySigned, sizeof(arraySigned) / sizeof(arraySigned[0])); + + const uint32_t arrayUnsigned[] = {0, 1, + std::numeric_limits::min(), + std::numeric_limits::max()}; + std::vector vecUnsigned; + vecUnsigned.emplace_back(0); + vecUnsigned.emplace_back(1); + vecUnsigned.emplace_back(std::numeric_limits::min()); + vecUnsigned.emplace_back(std::numeric_limits::max()); + msgOpt.add_len_repeated_packed_unsigned_vint(vecUnsigned); + msgOpt.add_len_repeated_packed_unsigned_vint(arrayUnsigned, sizeof(arrayUnsigned) / sizeof(arrayUnsigned[0])); + + const uint64_t arrayFixed[] = {0, 1, + std::numeric_limits::min(), + std::numeric_limits::max()}; + std::vector vecFixed; + vecFixed.emplace_back(0); + vecFixed.emplace_back(1); + vecFixed.emplace_back(std::numeric_limits::min()); + vecFixed.emplace_back(std::numeric_limits::max()); + msgOpt.add_len_repeated_packed_fixed(vecFixed); + msgOpt.add_len_repeated_packed_fixed(arrayFixed, sizeof(arrayFixed) / sizeof(arrayFixed[0])); + + msgOpt.set_i32_fixed32(1); + msgOpt.set_i32_sfixed32(1); + msgOpt.set_i32_float(1); + + msgOpt.set_oneof_fixed64(1); + msgOpt.set_oneof_string(str); + msgSub = msgOpt.mutable_oneof_sub(); + ASSERT_TRUE(msgSub != nullptr); + msgSub->set_vint_int32(1); + msgSub->set_vint_int64(1); + msgSub->set_vint_uint32(1); + msgSub->set_vint_uint64(1); + + ASSERT_EQ((uint32_t)msgOpt.Finish(), g_writePos); + printf("SetAll size(%" PRIu32 "):\n", g_writePos); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + // check result by protobuf + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + + ASSERT_EQ(msgProtobuf.vint_int32(), (int32_t)1); + ASSERT_EQ(msgProtobuf.vint_int64(), (int64_t)1); + ASSERT_EQ(msgProtobuf.vint_uint32(), (uint32_t)1); + ASSERT_EQ(msgProtobuf.vint_uint64(), (uint64_t)1); + ASSERT_EQ(msgProtobuf.vint_sint32(), (int32_t)1); + ASSERT_EQ(msgProtobuf.vint_sint64(), (int64_t)1); + ASSERT_EQ(msgProtobuf.vint_sint32(), (int32_t)1); + ASSERT_TRUE(msgProtobuf.vint_bool()); + ASSERT_EQ(msgProtobuf.vint_enum(), NUM::ONE); + + ASSERT_EQ(msgProtobuf.i64_fixed64(), (uint64_t)1); + ASSERT_EQ(msgProtobuf.i64_sfixed64(), (int64_t)1); + ASSERT_EQ(msgProtobuf.i64_double(), (double)1); + + ASSERT_EQ(msgProtobuf.len_string(), str); + ASSERT_EQ(msgProtobuf.len_bytes(), std::string(&BYTES_DATA[0], sizeof(BYTES_DATA))); + + ASSERT_TRUE(msgProtobuf.has_len_sub()); + SubMessage subMsgProtobuf = msgProtobuf.len_sub(); + ASSERT_EQ(subMsgProtobuf.vint_int32(), (int32_t)1); + ASSERT_EQ(subMsgProtobuf.vint_int64(), (int64_t)1); + ASSERT_EQ(subMsgProtobuf.vint_uint32(), (uint32_t)1); + ASSERT_EQ(subMsgProtobuf.vint_uint64(), (uint64_t)1); + + int countAll = msgProtobuf.len_repeated_packed_signed_vint_size(); + ASSERT_EQ(countAll, static_cast(vecSigned.size() + sizeof(arraySigned) / sizeof(arraySigned[0]))); + for (size_t i = 0; i < vecSigned.size(); i++) { + ASSERT_EQ(msgProtobuf.len_repeated_packed_signed_vint(i), vecSigned[i]); + } + for (size_t i = vecSigned.size(); i < static_castcountAll; i++) { + ASSERT_EQ(msgProtobuf.len_repeated_packed_signed_vint(i), arraySigned[i - vecSigned.size()]); + } + + countAll = msgProtobuf.len_repeated_packed_unsigned_vint_size(); + ASSERT_EQ(countAll, static_cast(vecUnsigned.size() + sizeof(arrayUnsigned) / sizeof(arrayUnsigned[0]))); + for (size_t i = 0; i < vecUnsigned.size(); i++) { + ASSERT_EQ(msgProtobuf.len_repeated_packed_unsigned_vint(i), vecUnsigned[i]); + } + for (size_t i = vecUnsigned.size(); i < static_castcountAll; i++) { + ASSERT_EQ(msgProtobuf.len_repeated_packed_unsigned_vint(i), arrayUnsigned[i - vecUnsigned.size()]); + } + + countAll = msgProtobuf.len_repeated_packed_fixed_size(); + ASSERT_EQ(countAll, static_cast(vecFixed.size() + sizeof(arrayFixed) / sizeof(arrayFixed[0]))); + for (size_t i = 0; i < vecFixed.size(); i++) { + ASSERT_EQ(msgProtobuf.len_repeated_packed_fixed(i), vecFixed[i]); + } + for (size_t i = vecFixed.size(); i < static_castcountAll; i++) { + ASSERT_EQ(msgProtobuf.len_repeated_packed_fixed(i), arrayFixed[i - vecFixed.size()]); + } + + ASSERT_EQ(msgProtobuf.i32_fixed32(), (uint32_t)1); + ASSERT_EQ(msgProtobuf.i32_sfixed32(), (int32_t)1); + ASSERT_EQ(msgProtobuf.i32_float(), (float)1); + + // last one wins + ASSERT_NE(msgProtobuf.oneof_fixed64(), (uint64_t)1); + ASSERT_NE(msgProtobuf.oneof_string(), str); + ASSERT_TRUE(msgProtobuf.has_oneof_sub()); + subMsgProtobuf = msgProtobuf.oneof_sub(); + ASSERT_EQ(subMsgProtobuf.vint_int32(), (int32_t)1); + ASSERT_EQ(subMsgProtobuf.vint_int64(), (int64_t)1); + ASSERT_EQ(subMsgProtobuf.vint_uint32(), (uint32_t)1); + ASSERT_EQ(subMsgProtobuf.vint_uint64(), (uint64_t)1); +} + +HWTEST_F(BaseMessageUnittest, SubMessageLen0, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + ExampleMessage msgProtobuf; + + // empty + g_writeCtx.seek(&g_writeCtx, 0); + ProtoEncoder::SubMessage* subMsgOpt = msgOpt.mutable_len_sub(); + ASSERT_TRUE(subMsgOpt != nullptr); + msgOpt.set_vint_int32(std::numeric_limits::min()); + printf("sub message length is 0:\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_TRUE(msgProtobuf.has_len_sub()); + + g_writeCtx.seek(&g_writeCtx, 0); + int subMsgOptRepeatedCount = 0; + ProtoEncoder::SubMessage* subMsgOptRepeated = msgOpt.add_repeated_len_sub(); + ASSERT_TRUE(subMsgOptRepeated != nullptr); + subMsgOptRepeatedCount++; + msgOpt.set_vint_int32(std::numeric_limits::min()); + printf("repeated sub message length is 0:\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.repeated_len_sub_size(), subMsgOptRepeatedCount); + + subMsgOptRepeated = msgOpt.add_repeated_len_sub(); + ASSERT_TRUE(subMsgOptRepeated != nullptr); + subMsgOptRepeatedCount++; + subMsgOptRepeated->set_vint_int32(1); + msgOpt.set_vint_int32(std::numeric_limits::min()); + printf("repeated sub message length > 0:\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.repeated_len_sub_size(), subMsgOptRepeatedCount); + + // set bytes by callback + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.set_len_bytes( + [](RandomWriteCtx* randomWriteCtx) -> int32_t { + return 0; + }); + printf("set_len_bytes(CallbackFunc(len = 0)):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.len_bytes(), std::string("")); + + // add bytes + g_writeCtx.seek(&g_writeCtx, 0); + msgOpt.startAdd_len_bytes(); + msgOpt.finishAdd_len_bytes(0); + printf("Add_LEN_bytes(len = 0):\n"); + for (uint32_t i = 0; i < g_writePos; i++) { + printf("%02X ", g_buf[i]); + } + printf("\n"); + + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.len_bytes(), std::string("")); +} + +HWTEST_F(BaseMessageUnittest, AutoFinishSubMessage, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + + ASSERT_TRUE(msgOpt.add_repeated_example() != nullptr); + msgOpt.set_i32_fixed32(1); + ASSERT_TRUE(msgOpt.add_repeated_example() != nullptr); + msgOpt.set_i64_fixed64(1); + ASSERT_TRUE(msgOpt.add_repeated_example() != nullptr); + msgOpt.set_vint_uint32(1); + ASSERT_TRUE(msgOpt.add_repeated_example() != nullptr); + msgOpt.set_vint_sint32(1); + ASSERT_TRUE(msgOpt.add_repeated_example() != nullptr); + msgOpt.set_len_string("\n"); + ASSERT_TRUE(msgOpt.add_repeated_example() != nullptr); + ASSERT_TRUE(msgOpt.mutable_len_sub() != nullptr); + ASSERT_TRUE(msgOpt.add_repeated_example() != nullptr); + ASSERT_TRUE(msgOpt.startAdd_len_bytes() != nullptr); + msgOpt.finishAdd_len_bytes(0); + ASSERT_TRUE(msgOpt.add_repeated_example() != nullptr); + msgOpt.set_len_bytes( + [](RandomWriteCtx* randomWriteCtx) -> int32_t { + return 0; + }); + ASSERT_TRUE(msgOpt.add_repeated_example() != nullptr); + std::vector arraySint32(1, -1); + msgOpt.add_len_repeated_packed_signed_vint(arraySint32); + ASSERT_TRUE(msgOpt.add_repeated_example() != nullptr); + std::vector arrayUint32(1, 1); + msgOpt.add_len_repeated_packed_unsigned_vint(arrayUint32); + ASSERT_TRUE(msgOpt.add_repeated_example() != nullptr); + std::vector arrayfint64(1, 1); + msgOpt.add_len_repeated_packed_fixed(arrayfint64); + + ExampleMessage msgProtobuf; + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_GT(msgProtobuf.repeated_example_size(), 0); +} + +HWTEST_F(BaseMessageUnittest, WriteFailedDrop, TestSize.Level1) +{ + RandomWriteCtx writeCtx = { + [](RandomWriteCtx*, uint32_t, uint8_t**, uint32_t*) -> bool { return false; }, + [](RandomWriteCtx*, uint32_t) -> bool { return false; } + }; + + std::unique_ptr msgOpt = + std::make_unique(&writeCtx); + msgOpt->set_i32_fixed32(1); + ASSERT_EQ(msgOpt->Finish(), (int32_t)-1); + + msgOpt = std::make_unique(&writeCtx); + msgOpt->set_i64_fixed64(1); + ASSERT_EQ(msgOpt->Finish(), (int32_t)-1); + + msgOpt = std::make_unique(&writeCtx); + msgOpt->set_vint_uint32(1); + ASSERT_EQ(msgOpt->Finish(), (int32_t)-1); + + msgOpt = std::make_unique(&writeCtx); + msgOpt->set_vint_sint32(1); + ASSERT_EQ(msgOpt->Finish(), (int32_t)-1); + + msgOpt = std::make_unique(&writeCtx); + msgOpt->set_len_string("\n"); + ASSERT_EQ(msgOpt->Finish(), (int32_t)-1); + + msgOpt = std::make_unique(&writeCtx); + ASSERT_TRUE(msgOpt->mutable_len_sub() != nullptr); + ASSERT_EQ(msgOpt->Finish(), (int32_t)-1); + + msgOpt = std::make_unique(&writeCtx); + ASSERT_TRUE(msgOpt->startAdd_len_bytes() == nullptr); + ASSERT_EQ(msgOpt->Finish(), (int32_t)-1); + + msgOpt = std::make_unique(&writeCtx); + msgOpt->set_len_bytes( + [](RandomWriteCtx* randomWriteCtx) -> int32_t { + return 0; + }); + ASSERT_EQ(msgOpt->Finish(), (int32_t)-1); + + std::vector arraySint32(1, -1); + msgOpt = std::make_unique(&writeCtx); + msgOpt->add_len_repeated_packed_signed_vint(arraySint32); + ASSERT_EQ(msgOpt->Finish(), (int32_t)-1); + + std::vector arrayUint32(1, 1); + msgOpt = std::make_unique(&writeCtx); + msgOpt->add_len_repeated_packed_unsigned_vint(arrayUint32); + ASSERT_EQ(msgOpt->Finish(), (int32_t)-1); + + msgOpt = std::make_unique(&writeCtx); + std::vector arrayfint64(1, 1); + msgOpt->add_len_repeated_packed_fixed(arrayfint64); + ASSERT_EQ(msgOpt->Finish(), (int32_t)-1); +} + +HWTEST_F(BaseMessageUnittest, NoWrite, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(nullptr); + + msgOpt.set_i32_fixed32(1); + msgOpt.set_i64_fixed64(1); + msgOpt.set_vint_uint32(1); + msgOpt.set_vint_sint32(1); + msgOpt.set_len_string("\n"); + ASSERT_TRUE(msgOpt.startAdd_len_bytes() == nullptr); + msgOpt.set_len_bytes(nullptr); + msgOpt.set_len_bytes( + [](RandomWriteCtx* randomWriteCtx) -> int32_t { + return 0; + }); + + // arrayCount is 0 + msgOpt.add_len_repeated_packed_signed_vint(nullptr, 0); + msgOpt.add_len_repeated_packed_unsigned_vint(nullptr, 0); + msgOpt.add_len_repeated_packed_fixed(nullptr, 0); + std::vector arraySint32(1, -1); + msgOpt.add_len_repeated_packed_signed_vint(arraySint32); + std::vector arrayUint32(1, 1); + msgOpt.add_len_repeated_packed_unsigned_vint(arrayUint32); + std::vector arrayfint64(1, 1); + msgOpt.add_len_repeated_packed_fixed(arrayfint64); + ASSERT_EQ(msgOpt.Finish(), (int32_t)-1); +} + +HWTEST_F(BaseMessageUnittest, SubMessageAlwaysAvailabe, TestSize.Level1) +{ + ProtoEncoder::ExampleMessage msgOpt(nullptr); + + ProtoEncoder::SubMessage* subMsgOpt = msgOpt.mutable_len_sub(); + ASSERT_TRUE(subMsgOpt != nullptr); + subMsgOpt->set_vint_int32(1); + subMsgOpt->set_vint_int64(1); + subMsgOpt->set_vint_uint32(1); + subMsgOpt->set_vint_uint64(1); + ASSERT_EQ(subMsgOpt->Finish(), (int32_t)-1); + + ProtoEncoder::ExampleMessage* nested1 = msgOpt.add_repeated_example(); + ASSERT_TRUE(nested1 != nullptr); + ProtoEncoder::ExampleMessage* nested2 = nested1->add_repeated_example(); + ASSERT_TRUE(nested2 != nullptr); + ProtoEncoder::ExampleMessage* nested3 = nested2->add_repeated_example(); + ASSERT_TRUE(nested3 != nullptr); + + ASSERT_EQ(nested3->Finish(), (int32_t)-1); + ASSERT_EQ(nested2->Finish(), (int32_t)-1); + ASSERT_EQ(nested1->Finish(), (int32_t)-1); + + msgOpt.set_vint_int32(1); + ASSERT_EQ(msgOpt.Finish(), (int32_t)-1); +} + +HWTEST_F(BaseMessageUnittest, MessagePool, TestSize.Level1) +{ + ProtoEncoder::MessagePool msgStack; + ProtoEncoder::BaseMessage* pMsg = msgStack.Get(); + ASSERT_TRUE(pMsg != nullptr); + + msgStack.Reset(0); + pMsg = msgStack.Get(); + ASSERT_TRUE(pMsg != nullptr); + + const uint32_t testRepeat = 1000; + const uint32_t testDepth = 5; + msgStack.Reset(testDepth); + for (uint32_t i = 0; i < testRepeat; i++) { + pMsg = msgStack.Get(); + ASSERT_TRUE(pMsg != nullptr); + msgStack.Release(); + } + + for (uint32_t i = 0; i < testRepeat; i++) { + for (uint32_t i = 0; i < testDepth; i++) { + pMsg = msgStack.Get(); + ASSERT_TRUE(pMsg != nullptr); + } + for (uint32_t i = 0; i < testDepth; i++) { + msgStack.Release(); + } + } + + for (uint32_t i = 0; i < testRepeat; i++) { + pMsg = msgStack.Get(); + ASSERT_TRUE(pMsg != nullptr); + } + for (uint32_t i = 0; i < testRepeat; i++) { + msgStack.Release(); + } + + msgStack.Reset(1); + for (uint32_t i = 0; i < testDepth; i++) { + pMsg = msgStack.Get(); + ASSERT_TRUE(pMsg != nullptr); + } + ProtoEncoder::ExampleMessage* pExampleMsg = static_cast(pMsg); + g_writeCtx.seek(&g_writeCtx, 0); + pExampleMsg->Reset(&g_writeCtx); + pExampleMsg->set_vint_int32(1); + ExampleMessage msgProtobuf; + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_EQ(msgProtobuf.vint_int32(), (int32_t)1); + + msgStack.Reset(1); + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx, &msgStack); + g_writeCtx.seek(&g_writeCtx, 0); + ProtoEncoder::SubMessage* subMsgOpt = msgOpt.mutable_len_sub(); + ASSERT_TRUE(subMsgOpt != nullptr); + msgOpt.set_vint_int32(1); + ASSERT_TRUE(msgProtobuf.ParseFromArray(g_buf, g_writePos)); + ASSERT_TRUE(msgProtobuf.has_len_sub()); + ASSERT_EQ(msgProtobuf.vint_int32(), (int32_t)1); +} + +// reference from https://perfetto.dev/docs/design-docs/protozero +// For the full code of the benchmark see /src/protozero/test/protozero_benchmark.cc +const int TEST_TIMES = 1000 * 100; +uint64_t g_fakeInputSimple[] = {0x12345678, + 0x90ABCDEF, + 0x11111111, + 0xFFFFFFFF, + 0x6666666666666666ULL, + 0x6666666666666666ULL, + 0x6666666666666666ULL, + 0x0066666666666666ULL}; + +HWTEST_F(BaseMessageUnittest, ProtobufferSimple, TestSize.Level1) +{ + for (int count = 0; count < TEST_TIMES; count++) { + int index = 0; + ExampleMessage msgProtobuf; + + msgProtobuf.set_vint_int32(static_cast(g_fakeInputSimple[index++])); + msgProtobuf.set_vint_uint32(static_cast(g_fakeInputSimple[index++])); + msgProtobuf.set_vint_int64(static_cast(g_fakeInputSimple[index++])); + msgProtobuf.set_vint_uint64(static_cast(g_fakeInputSimple[index++])); + msgProtobuf.set_len_string(reinterpret_cast(&g_fakeInputSimple[index++])); + + msgProtobuf.SerializeToArray(&g_buf[0], SIZE_BUFFER); + } + printf("%d times\n", TEST_TIMES); +} + +HWTEST_F(BaseMessageUnittest, ProtoEncoderSimple, TestSize.Level1) +{ + for (int count = 0; count < TEST_TIMES; count++) { + int index = 0; + g_writeCtx.seek(&g_writeCtx, 0); + + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + + msgOpt.set_vint_int32(static_cast(g_fakeInputSimple[index++])); + msgOpt.set_vint_uint32(static_cast(g_fakeInputSimple[index++])); + msgOpt.set_vint_int64(static_cast(g_fakeInputSimple[index++])); + msgOpt.set_vint_uint64(static_cast(g_fakeInputSimple[index++])); + msgOpt.set_len_string(reinterpret_cast(&g_fakeInputSimple[index++])); + + msgOpt.Finish(); + } + printf("%d times\n", TEST_TIMES); +} + +HWTEST_F(BaseMessageUnittest, ProtobufferNested, TestSize.Level1) +{ + for (int count = 0; count < TEST_TIMES; count++) { + int index = 0; + ExampleMessage msgProtobuf; + + msgProtobuf.set_vint_int32(static_cast(g_fakeInputSimple[index++])); + msgProtobuf.set_vint_uint32(static_cast(g_fakeInputSimple[index++])); + msgProtobuf.set_vint_int64(static_cast(g_fakeInputSimple[index++])); + msgProtobuf.set_vint_uint64(static_cast(g_fakeInputSimple[index++])); + msgProtobuf.set_len_string(reinterpret_cast(&g_fakeInputSimple[index++])); + // fisrt nested + ExampleMessage* nested1 = msgProtobuf.add_repeated_example(); + index = 0; + nested1->set_vint_int32(static_cast(g_fakeInputSimple[index++])); + nested1->set_vint_uint32(static_cast(g_fakeInputSimple[index++])); + nested1->set_vint_int64(static_cast(g_fakeInputSimple[index++])); + nested1->set_vint_uint64(static_cast(g_fakeInputSimple[index++])); + nested1->set_len_string(reinterpret_cast(&g_fakeInputSimple[index++])); + // second nested + ExampleMessage* nested2 = nested1->add_repeated_example(); + index = 0; + nested2->set_vint_int32(static_cast(g_fakeInputSimple[index++])); + nested2->set_vint_uint32(static_cast(g_fakeInputSimple[index++])); + nested2->set_vint_int64(static_cast(g_fakeInputSimple[index++])); + nested2->set_vint_uint64(static_cast(g_fakeInputSimple[index++])); + nested2->set_len_string(reinterpret_cast(&g_fakeInputSimple[index++])); + // third nested + ExampleMessage* nested3 = nested2->add_repeated_example(); + index = 0; + nested3->set_vint_int32(static_cast(g_fakeInputSimple[index++])); + nested3->set_vint_uint32(static_cast(g_fakeInputSimple[index++])); + nested3->set_vint_int64(static_cast(g_fakeInputSimple[index++])); + nested3->set_vint_uint64(static_cast(g_fakeInputSimple[index++])); + nested3->set_len_string(reinterpret_cast(&g_fakeInputSimple[index++])); + + msgProtobuf.SerializeToArray(&g_buf[0], SIZE_BUFFER); + } + printf("%d times\n", TEST_TIMES); +} + +HWTEST_F(BaseMessageUnittest, ProtoEncoderNested, TestSize.Level1) +{ + for (int count = 0; count < TEST_TIMES; count++) { + int index = 0; + g_writeCtx.seek(&g_writeCtx, 0); + + ProtoEncoder::ExampleMessage msgOpt(&g_writeCtx); + + msgOpt.set_vint_int32(static_cast(g_fakeInputSimple[index++])); + msgOpt.set_vint_uint32(static_cast(g_fakeInputSimple[index++])); + msgOpt.set_vint_int64(static_cast(g_fakeInputSimple[index++])); + msgOpt.set_vint_uint64(static_cast(g_fakeInputSimple[index++])); + msgOpt.set_len_string(reinterpret_cast(&g_fakeInputSimple[index++])); + // fisrt nested + ProtoEncoder::ExampleMessage* nested1 = msgOpt.add_repeated_example(); + index = 0; + nested1->set_vint_int32(static_cast(g_fakeInputSimple[index++])); + nested1->set_vint_uint32(static_cast(g_fakeInputSimple[index++])); + nested1->set_vint_int64(static_cast(g_fakeInputSimple[index++])); + nested1->set_vint_uint64(static_cast(g_fakeInputSimple[index++])); + nested1->set_len_string(reinterpret_cast(&g_fakeInputSimple[index++])); + // second nested + ProtoEncoder::ExampleMessage* nested2 = nested1->add_repeated_example(); + index = 0; + nested2->set_vint_int32(static_cast(g_fakeInputSimple[index++])); + nested2->set_vint_uint32(static_cast(g_fakeInputSimple[index++])); + nested2->set_vint_int64(static_cast(g_fakeInputSimple[index++])); + nested2->set_vint_uint64(static_cast(g_fakeInputSimple[index++])); + nested2->set_len_string(reinterpret_cast(&g_fakeInputSimple[index++])); + // third nested + ProtoEncoder::ExampleMessage* nested3 = nested2->add_repeated_example(); + index = 0; + nested3->set_vint_int32(static_cast(g_fakeInputSimple[index++])); + nested3->set_vint_uint32(static_cast(g_fakeInputSimple[index++])); + nested3->set_vint_int64(static_cast(g_fakeInputSimple[index++])); + nested3->set_vint_uint64(static_cast(g_fakeInputSimple[index++])); + nested3->set_len_string(reinterpret_cast(&g_fakeInputSimple[index++])); + + msgOpt.Finish(); + } + printf("%d times\n", TEST_TIMES); +} +} // namespace Profiler +} // namespace Developtools +} // namespace OHOS diff --git a/proto_encoder/test/unittest/varint_encode_unittest.cpp b/proto_encoder/test/unittest/varint_encode_unittest.cpp new file mode 100755 index 000000000..ddd57a79d --- /dev/null +++ b/proto_encoder/test/unittest/varint_encode_unittest.cpp @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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. + */ +#include +#include +#include +#include + +#include "varint_encode.h" + +namespace OHOS { +namespace Developtools { +namespace Profiler { +using namespace testing::ext; +using namespace ProtoEncoder; + +class VarintEncodeUnittest : public ::testing::Test { +public: + static void SetUpTestCase() {}; + static void TearDownTestCase() {}; + + void SetUp() {}; + void TearDown() {}; + + const uint32_t two = 2; + const uint32_t three = 3; + const uint32_t four = 4; +}; + +HWTEST_F(VarintEncodeUnittest, GetPackedVarintLenSize, TestSize.Level1) +{ + uint32_t len = 0; + uint32_t itemCount = 0; + uint32_t itemSize = sizeof(char); + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)1); + EXPECT_EQ(len, (uint32_t)0); + + itemSize = sizeof(int32_t); + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)1); + EXPECT_EQ(len, itemCount * itemSize); + + itemSize = sizeof(int64_t); + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)1); + EXPECT_EQ(len, itemCount * itemSize); + + itemSize = sizeof(char); + itemCount = VARINT_MAX_1BYTE; + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)1); + EXPECT_EQ(len, itemCount * itemSize); + + itemCount++; + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), two); + EXPECT_EQ(len, itemCount * itemSize); + + itemCount = VARINT_MAX_2BYTE; + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), two); + EXPECT_EQ(len, itemCount * itemSize); + + itemCount++; + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), three); + EXPECT_EQ(len, itemCount * itemSize); + + itemCount = VARINT_MAX_3BYTE; + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), three); + EXPECT_EQ(len, itemCount * itemSize); + + itemCount++; + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), four); + EXPECT_EQ(len, itemCount * itemSize); + + itemCount = VARINT_MAX_4BYTE; + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), four); + EXPECT_EQ(len, itemCount * itemSize); + + itemCount++; + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)0); + EXPECT_EQ(len, itemCount * itemSize); + + itemSize = sizeof(int32_t); + itemCount = VARINT_MAX_1BYTE / (itemSize + 1); + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)1); + EXPECT_EQ(len, itemCount * (itemSize + 1)); + + itemCount++; + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), two); + EXPECT_EQ(len, itemCount * (itemSize + 1)); + + itemCount = VARINT_MAX_2BYTE / (itemSize + 1); + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), two); + EXPECT_EQ(len, itemCount * (itemSize + 1)); + + itemCount++; + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), three); + EXPECT_EQ(len, itemCount * (itemSize + 1)); + + itemCount = VARINT_MAX_3BYTE / (itemSize + 1); + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), three); + EXPECT_EQ(len, itemCount * (itemSize + 1)); + + itemCount++; + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), four); + EXPECT_EQ(len, itemCount * (itemSize + 1)); + + itemCount = VARINT_MAX_4BYTE / (itemSize + 1); + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), four); + EXPECT_EQ(len, itemCount * (itemSize + 1)); + + itemCount++; + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)0); + EXPECT_EQ(len, itemCount * (itemSize + 1)); + + itemSize = sizeof(int64_t); + itemCount = VARINT_MAX_1BYTE / (itemSize + two); + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)1); + EXPECT_EQ(len, itemCount * (itemSize + two)); + + itemCount++; + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), two); + EXPECT_EQ(len, itemCount * (itemSize + two)); + + itemCount = VARINT_MAX_2BYTE / (itemSize + two); + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), two); + EXPECT_EQ(len, itemCount * (itemSize + two)); + + itemCount++; + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), three); + EXPECT_EQ(len, itemCount * (itemSize + two)); + + itemCount = VARINT_MAX_3BYTE / (itemSize + two); + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), three); + EXPECT_EQ(len, itemCount * (itemSize + two)); + + itemCount++; + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), four); + EXPECT_EQ(len, itemCount * (itemSize + two)); + + itemCount = VARINT_MAX_4BYTE / (itemSize + two); + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), four); + EXPECT_EQ(len, itemCount * (itemSize + two)); + + itemCount++; + EXPECT_EQ(GetPackedVarintLenSize(itemCount, itemSize, len), (uint32_t)0); + EXPECT_EQ(len, itemCount * (itemSize + two)); +} + +HWTEST_F(VarintEncodeUnittest, EncodeZigZag, TestSize.Level1) +{ + int8_t signed8 = 0; + EXPECT_EQ(EncodeZigZag(signed8), (uint8_t)0); + signed8 = -1; + EXPECT_EQ(EncodeZigZag(signed8), (uint8_t)1); + signed8 = 1; + EXPECT_EQ(EncodeZigZag(signed8), (uint8_t)(signed8 * two)); + std::srand(std::time(nullptr)); + int rand = std::rand(); + signed8 = static_castrand; + if (signed8 >= 0) { + // n are encoded as 2 * n + EXPECT_EQ(EncodeZigZag(signed8), (uint8_t)(signed8 * two)); + } else { + // -n are encoded as 2 * n + 1 + EXPECT_EQ(EncodeZigZag(signed8), (uint8_t)(-signed8 - 1 + -signed8)); + } + signed8 = std::numeric_limits::min(); + EXPECT_EQ(EncodeZigZag(signed8), std::numeric_limits::max()); + signed8 = std::numeric_limits::max(); + EXPECT_EQ(EncodeZigZag(signed8), std::numeric_limits::max() - 1); + + int32_t signed32 = 0; + EXPECT_EQ(EncodeZigZag(signed32), (uint32_t)0); + signed32 = -1; + EXPECT_EQ(EncodeZigZag(signed32), (uint32_t)1); + signed32 = 1; + EXPECT_EQ(EncodeZigZag(signed32), (uint32_t)(signed32 * two)); + std::srand(rand); + rand = std::rand(); + signed32 = static_castrand; + if (signed32 >= 0) { + // n are encoded as 2 * n + EXPECT_EQ(EncodeZigZag(signed32), (uint32_t)(signed32 * two)); + } else { + // -n are encoded as 2 * n + 1 + EXPECT_EQ(EncodeZigZag(signed32), (uint32_t)(-signed32 - 1 + -signed32)); + } + signed32 = std::numeric_limits::min(); + EXPECT_EQ(EncodeZigZag(signed32), std::numeric_limits::max()); + signed32 = std::numeric_limits::max(); + EXPECT_EQ(EncodeZigZag(signed32), std::numeric_limits::max() - 1); + + int64_t signed64 = 0; + EXPECT_EQ(EncodeZigZag(signed64), (uint64_t)0); + signed64 = -1; + EXPECT_EQ(EncodeZigZag(signed64), (uint64_t)1); + signed64 = 1; + EXPECT_EQ(EncodeZigZag(signed64), (uint64_t)(signed64 * two)); + std::srand(rand); + rand = std::rand(); + signed64 = static_castrand; + if (signed64 >= 0) { + // n are encoded as 2 * n + EXPECT_EQ(EncodeZigZag(signed64), (uint64_t)(signed64 * two)); + } else { + // -n are encoded as 2 * n + 1 + EXPECT_EQ(EncodeZigZag(signed64), (uint64_t)(-signed64 - 1 + -signed64)); + } + signed64 = std::numeric_limits::min(); + EXPECT_EQ(EncodeZigZag(signed64), std::numeric_limits::max()); + signed64 = std::numeric_limits::max(); + EXPECT_EQ(EncodeZigZag(signed64), std::numeric_limits::max() - 1); +} + +bool CompareBytes(const uint8_t* a, const uint8_t* b, size_t size) +{ + for (size_t i = 0; i < size; i++) { + if (a[i] != b[i]) { + return false; + } + } + return true; +} + +const uint8_t ENCODE_BYTES_MIN_BOOL[] = {0x00}; +const uint8_t ENCODE_BYTES_MAX_BOOL[] = {0x01}; +const uint8_t ENCODE_BYTES_MIN_S8[] = {0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01}; +const uint8_t ENCODE_BYTES_MAX_S8[] = {0x7F}; +const uint8_t ENCODE_BYTES_MIN_U8[] = {0x00}; +const uint8_t ENCODE_BYTES_MAX_U8[] = {0xFF, 0x01}; +const uint8_t ENCODE_BYTES_MIN_S32[] = {0x80, 0x80, 0x80, 0x80, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x01}; +const uint8_t ENCODE_BYTES_MAX_S32[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x07}; +const uint8_t ENCODE_BYTES_MIN_U32[] = {0x00}; +const uint8_t ENCODE_BYTES_MAX_U32[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x0F}; +const uint8_t ENCODE_BYTES_MIN_S64[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01}; +const uint8_t ENCODE_BYTES_MAX_S64[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}; +const uint8_t ENCODE_BYTES_MIN_U64[] = {0x00}; +const uint8_t ENCODE_BYTES_MAX_U64[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01}; + +HWTEST_F(VarintEncodeUnittest, EncodeVarint, TestSize.Level1) +{ + uint8_t buf[VARINT_ENCODE_MAX_SIZE] = {0}; + bool b = std::numeric_limits::min(); + EXPECT_EQ(EncodeVarint(buf, b), (uint32_t)sizeof(ENCODE_BYTES_MIN_BOOL)); + EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_BOOL, sizeof(ENCODE_BYTES_MIN_BOOL))); + b = std::numeric_limits::max(); + EXPECT_EQ(EncodeVarint(buf, b), (uint32_t)sizeof(ENCODE_BYTES_MAX_BOOL)); + EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_BOOL, sizeof(ENCODE_BYTES_MAX_BOOL))); + + int8_t s8 = std::numeric_limits::min(); + EXPECT_EQ(EncodeVarint(buf, s8), (uint32_t)sizeof(ENCODE_BYTES_MIN_S8)); + EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_S8, sizeof(ENCODE_BYTES_MIN_S8))); + s8 = std::numeric_limits::max(); + EXPECT_EQ(EncodeVarint(buf, s8), (uint32_t)sizeof(ENCODE_BYTES_MAX_S8)); + EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_S8, sizeof(ENCODE_BYTES_MAX_S8))); + + uint8_t u8 = std::numeric_limits::min(); + EXPECT_EQ(EncodeVarint(buf, u8), (uint32_t)sizeof(ENCODE_BYTES_MIN_U8)); + EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_U8, sizeof(ENCODE_BYTES_MIN_U8))); + u8 = std::numeric_limits::max(); + EXPECT_EQ(EncodeVarint(buf, u8), (uint32_t)sizeof(ENCODE_BYTES_MAX_U8)); + EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_U8, sizeof(ENCODE_BYTES_MAX_U8))); + + int32_t s32 = std::numeric_limits::min(); + EXPECT_EQ(EncodeVarint(buf, s32), (uint32_t)sizeof(ENCODE_BYTES_MIN_S32)); + EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_S32, sizeof(ENCODE_BYTES_MIN_S32))); + s32 = std::numeric_limits::max(); + EXPECT_EQ(EncodeVarint(buf, s32), (uint32_t)sizeof(ENCODE_BYTES_MAX_S32)); + EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_S32, sizeof(ENCODE_BYTES_MAX_S32))); + + uint32_t u32 = std::numeric_limits::min(); + EXPECT_EQ(EncodeVarint(buf, u32), (uint32_t)sizeof(ENCODE_BYTES_MIN_U32)); + EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_U32, sizeof(ENCODE_BYTES_MIN_U32))); + u32 = std::numeric_limits::max(); + EXPECT_EQ(EncodeVarint(buf, u32), (uint32_t)sizeof(ENCODE_BYTES_MAX_U32)); + EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_U32, sizeof(ENCODE_BYTES_MAX_U32))); + + int64_t s64 = std::numeric_limits::min(); + EXPECT_EQ(EncodeVarint(buf, s64), (uint32_t)sizeof(ENCODE_BYTES_MIN_S64)); + EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_S64, sizeof(ENCODE_BYTES_MIN_S64))); + s64 = std::numeric_limits::max(); + EXPECT_EQ(EncodeVarint(buf, s64), (uint32_t)sizeof(ENCODE_BYTES_MAX_S64)); + EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_S64, sizeof(ENCODE_BYTES_MAX_S64))); + + uint64_t u64 = std::numeric_limits::min(); + EXPECT_EQ(EncodeVarint(buf, u64), (uint32_t)sizeof(ENCODE_BYTES_MIN_U64)); + EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MIN_U64, sizeof(ENCODE_BYTES_MIN_U64))); + u64 = std::numeric_limits::max(); + EXPECT_EQ(EncodeVarint(buf, u64), (uint32_t)sizeof(ENCODE_BYTES_MAX_U64)); + EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_U64, sizeof(ENCODE_BYTES_MAX_U64))); +} + +HWTEST_F(VarintEncodeUnittest, EncodeVarintPadding, TestSize.Level1) +{ + const uint8_t paddingByte = 0x80; + uint8_t buf[VARINT_ENCODE_MAX_SIZE] = {0}; + uint64_t u64 = 1; + EncodeVarintPadding(buf, u64, VARINT_ENCODE_MAX_SIZE); + uint32_t i = 1; + while (i < VARINT_ENCODE_MAX_SIZE - 1) { + EXPECT_EQ(buf[i++], paddingByte); + } + EXPECT_EQ(buf[i], (uint8_t)0); + + u64 = std::numeric_limits::max(); + EncodeVarintPadding(buf, u64, VARINT_ENCODE_MAX_SIZE); + EXPECT_TRUE(CompareBytes(buf, ENCODE_BYTES_MAX_U64, sizeof(ENCODE_BYTES_MAX_U64))); +} +} // namespace Profiler +} // namespace Developtools +} // namespace OHOS