diff --git a/.gitignore b/.gitignore index 52a671d..9a8589d 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,5 @@ build/ **/.DS_Store +# vscode +.vscode/ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e8ad7d0..ffbbed4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,6 +2,8 @@ add_library(${OATPP_THIS_MODULE_NAME} oatpp-postgresql/mapping/type/Uuid.cpp oatpp-postgresql/mapping/type/Uuid.hpp + oatpp-postgresql/mapping/type/ByteArray.cpp + oatpp-postgresql/mapping/type/ByteArray.hpp oatpp-postgresql/mapping/Deserializer.cpp oatpp-postgresql/mapping/Deserializer.hpp oatpp-postgresql/mapping/Oid.hpp diff --git a/src/oatpp-postgresql/Executor.cpp b/src/oatpp-postgresql/Executor.cpp index 5bc94d2..c3fb68b 100644 --- a/src/oatpp-postgresql/Executor.cpp +++ b/src/oatpp-postgresql/Executor.cpp @@ -138,14 +138,16 @@ Executor::Executor(const std::shared_ptr>& connec , m_resultMapper(std::make_shared()) { m_defaultTypeResolver->addKnownClasses({ - Uuid::Class::CLASS_ID + Uuid::Class::CLASS_ID, + ByteArray::Class::CLASS_ID }); } std::shared_ptr Executor::createTypeResolver() { auto typeResolver = std::make_shared(); typeResolver->addKnownClasses({ - Uuid::Class::CLASS_ID + Uuid::Class::CLASS_ID, + ByteArray::Class::CLASS_ID }); return typeResolver; } diff --git a/src/oatpp-postgresql/Types.hpp b/src/oatpp-postgresql/Types.hpp index f00c666..9a520b9 100644 --- a/src/oatpp-postgresql/Types.hpp +++ b/src/oatpp-postgresql/Types.hpp @@ -26,6 +26,7 @@ #define oatpp_postgresql_Types_hpp #include "mapping/type/Uuid.hpp" +#include "mapping/type/ByteArray.hpp" namespace oatpp { namespace postgresql { @@ -34,6 +35,11 @@ namespace oatpp { namespace postgresql { */ typedef oatpp::data::mapping::type::Primitive Uuid; +/** + * ByteArray as oatpp-postgresql type. + */ +typedef oatpp::postgresql::mapping::type::ByteArray ByteArray; + }} #endif // oatpp_postgresql_Types_hpp diff --git a/src/oatpp-postgresql/mapping/Deserializer.cpp b/src/oatpp-postgresql/mapping/Deserializer.cpp index 01bc982..0489456 100644 --- a/src/oatpp-postgresql/mapping/Deserializer.cpp +++ b/src/oatpp-postgresql/mapping/Deserializer.cpp @@ -75,7 +75,7 @@ Deserializer::Deserializer() { //// setDeserializerMethod(postgresql::mapping::type::__class::Uuid::CLASS_ID, &Deserializer::deserializeUuid); - + setDeserializerMethod(postgresql::mapping::type::__class::ByteArray::CLASS_ID, &Deserializer::deserializeByteArray); } void Deserializer::setDeserializerMethod(const data::mapping::type::ClassId& classId, DeserializerMethod method) { @@ -268,6 +268,7 @@ const oatpp::Type* Deserializer::guessAnyType(const InData& data) { case INT2OID: return oatpp::Int16::Class::getType(); case INT4OID: return oatpp::Int32::Class::getType(); case INT8OID: return oatpp::Int64::Class::getType(); + case BYTEAOID: return oatpp::postgresql::ByteArray::Class::getType(); case FLOAT4OID: return oatpp::Float32::Class::getType(); case FLOAT8OID: return oatpp::Float64::Class::getType(); @@ -286,6 +287,8 @@ const oatpp::Type* Deserializer::guessAnyType(const InData& data) { case INT2ARRAYOID: return generateMultidimensionalArrayType(data); case INT4ARRAYOID: return generateMultidimensionalArrayType(data); case INT8ARRAYOID: return generateMultidimensionalArrayType(data); + case BYTEAARRAYOID: + return generateMultidimensionalArrayType(data); case FLOAT4ARRAYOID: return generateMultidimensionalArrayType(data); case FLOAT8ARRAYOID: return generateMultidimensionalArrayType(data); @@ -333,6 +336,15 @@ oatpp::Void Deserializer::deserializeUuid(const Deserializer* _this, const InDat } +oatpp::Void Deserializer::deserializeByteArray(const Deserializer*, const InData &data, const Type*) { + + if (data.isNull || data.size == 0) { + return postgresql::ByteArray(); + } + + return postgresql::ByteArray((p_uint8)data.data, data.size); +} + oatpp::Void Deserializer::deserializeSubArray(const Type* type, ArrayDeserializationMeta& meta, v_int32 dimension) diff --git a/src/oatpp-postgresql/mapping/Deserializer.hpp b/src/oatpp-postgresql/mapping/Deserializer.hpp index 2f52c84..a2d54ad 100644 --- a/src/oatpp-postgresql/mapping/Deserializer.hpp +++ b/src/oatpp-postgresql/mapping/Deserializer.hpp @@ -108,6 +108,8 @@ class Deserializer { static oatpp::Void deserializeUuid(const Deserializer* _this, const InData& data, const Type* type); + static oatpp::Void deserializeByteArray(const Deserializer *_this, const InData &data, const Type *type); + template static const oatpp::Type* generateMultidimensionalArrayType(const InData& data) { diff --git a/src/oatpp-postgresql/mapping/Serializer.cpp b/src/oatpp-postgresql/mapping/Serializer.cpp index ab4c623..2f106d9 100644 --- a/src/oatpp-postgresql/mapping/Serializer.cpp +++ b/src/oatpp-postgresql/mapping/Serializer.cpp @@ -73,7 +73,7 @@ void Serializer::setSerializerMethods() { //// setSerializerMethod(postgresql::mapping::type::__class::Uuid::CLASS_ID, &Serializer::serializeUuid); - + setSerializerMethod(postgresql::mapping::type::__class::ByteArray::CLASS_ID, &Serializer::serializeByteArray); } void Serializer::setTypeOidMethods() { @@ -126,6 +126,8 @@ void Serializer::setTypeOidMethods() { setTypeOidMethod(postgresql::mapping::type::__class::Uuid::CLASS_ID, &Serializer::getTypeOid); setArrayTypeOidMethod(postgresql::mapping::type::__class::Uuid::CLASS_ID, &Serializer::getTypeOid); + setTypeOidMethod(postgresql::mapping::type::__class::ByteArray::CLASS_ID, &Serializer::getTypeOid); + setArrayTypeOidMethod(postgresql::mapping::type::__class::ByteArray::CLASS_ID, &Serializer::getTypeOid); } void Serializer::setSerializerMethod(const data::mapping::type::ClassId& classId, SerializerMethod method) { @@ -462,6 +464,21 @@ void Serializer::serializeUuid(const Serializer* _this, OutputData& outData, con } } +void Serializer::serializeByteArray(const Serializer *_this, OutputData &outData, const oatpp::Void &polymorph) { + + (void)_this; + + if (polymorph) { + auto v = polymorph.cast(); + outData.data = (char*)(v->data()); + outData.dataSize = static_cast(v->size()); + outData.dataFormat = 1; + outData.oid = BYTEAARRAYOID; + } else { + serNull(outData); + } +} + const oatpp::Type* Serializer::getArrayItemTypeAndDimensions(const oatpp::Void& polymorph, std::vector& dimensions) { oatpp::Void curr = polymorph; diff --git a/src/oatpp-postgresql/mapping/Serializer.hpp b/src/oatpp-postgresql/mapping/Serializer.hpp index 575e875..479b138 100644 --- a/src/oatpp-postgresql/mapping/Serializer.hpp +++ b/src/oatpp-postgresql/mapping/Serializer.hpp @@ -111,6 +111,8 @@ class Serializer { static void serializeUuid(const Serializer* _this, OutputData& outData, const oatpp::Void& polymorph); + static void serializeByteArray(const Serializer *_this, OutputData &outData, const oatpp::Void &polymorph); + struct ArraySerializationMeta { const Serializer* _this; diff --git a/src/oatpp-postgresql/mapping/type/ByteArray.cpp b/src/oatpp-postgresql/mapping/type/ByteArray.cpp new file mode 100644 index 0000000..c144f88 --- /dev/null +++ b/src/oatpp-postgresql/mapping/type/ByteArray.cpp @@ -0,0 +1,87 @@ +/*************************************************************************** + * + * Project _____ __ ____ _ _ + * ( _ ) /__\ (_ _)_| |_ _| |_ + * )(_)( /(__)\ )( (_ _)(_ _) + * (_____)(__)(__)(__) |_| |_| + * + * + * Copyright 2018-present + * + * 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 "ByteArray.hpp" + +#include "oatpp/core/data/stream/BufferStream.hpp" +#include "oatpp/encoding/Base64.hpp" +#include "oatpp/encoding/Hex.hpp" + +namespace oatpp { +namespace postgresql { +namespace mapping { +namespace type { + +namespace __class { +const ClassId ByteArray::CLASS_ID("oatpp::postgresql::ByteArray"); +} + +ByteArray::ByteArray(const std::shared_ptr> &ptr, const _oatpp_Type *const valueType) + : oatpp::data::mapping::type::ObjectWrapper, __class::ByteArray>(ptr) { + if (type::__class::ByteArray::getType() != valueType) { + throw std::runtime_error("Value type does not match"); + } +} + +ByteArray ByteArray::fromHexEncodedString(const String &hexEncodedString) { + const v_buff_usize expected_bytes_number = hexEncodedString->size() / 2; + + data::stream::BufferOutputStream stream(default_buffer_size); + encoding::Hex::decode(&stream, hexEncodedString->data(), hexEncodedString->size(), true); + if (stream.getCurrentPosition() != expected_bytes_number) { + throw std::invalid_argument("[oatpp::postgresql::mapping::type::ByteArray::fromHexEncodedString(String)]:" + "Error. Invalid string."); + } + + return ByteArray((const v_uint8 *)stream.getData(), expected_bytes_number); +} + +ByteArray ByteArray::fromBase64EncodedString(const String &base64EncodedString) { + const auto tb = encoding::Base64::decode(base64EncodedString); + return ByteArray(reinterpret_cast(tb->data()), tb->size()); +} + +String toBase64EncodedString(const ByteArray &arr) { + + if (arr->empty()) { + return String(); + } + return encoding::Base64::encode(arr->data(), arr->size()); +} + +String toHexEncodedString(const ByteArray &arr) { + + if (arr->empty()) { + return String(); + } + + oatpp::data::stream::BufferOutputStream stream(ByteArray::default_buffer_size); + encoding::Hex::encode(&stream, arr->data(), arr->size()); + + return stream.toString(); +} +} // namespace type +} // namespace mapping +} // namespace postgresql +} // namespace oatpp diff --git a/src/oatpp-postgresql/mapping/type/ByteArray.hpp b/src/oatpp-postgresql/mapping/type/ByteArray.hpp new file mode 100644 index 0000000..6d9c3ec --- /dev/null +++ b/src/oatpp-postgresql/mapping/type/ByteArray.hpp @@ -0,0 +1,191 @@ +/*************************************************************************** + * + * Project _____ __ ____ _ _ + * ( _ ) /__\ (_ _)_| |_ _| |_ + * )(_)( /(__)\ )( (_ _)(_ _) + * (_____)(__)(__)(__) |_| |_| + * + * + * Copyright 2018-present + * + * 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 oatpp_data_mapping_type_ByteArray_hpp +#define oatpp_data_mapping_type_ByteArray_hpp + +#include "oatpp/core/Types.hpp" +#include "oatpp/core/data/mapping/type/Primitive.hpp" +#include "oatpp/core/data/mapping/type/Type.hpp" + +#include +#include +#include +#include +#include + +namespace oatpp { +namespace postgresql { +namespace mapping { +namespace type { + +namespace __class { + +/** + * ByteArray Class. + */ +class ByteArray { + public: + /** + * Class Id + */ + static const ClassId CLASS_ID; + + static Type *getType() { + static Type type(CLASS_ID); + return &type; + } +}; +} // namespace __class + +/** + * Mapping - enables ByteArray is &id:type::ObjectWrapper; over `std::vector`; + */ +class ByteArray : public oatpp::data::mapping::type::ObjectWrapper, __class::ByteArray> { + using ObjectWrapper::ObjectWrapper; + using _oatpp_Type = oatpp::data::mapping::type::Type; + + public: + static constexpr v_buff_usize default_buffer_size = 1024U; + + ByteArray() = default; + ~ByteArray() = default; + + ByteArray(const std::shared_ptr> &ptr, const _oatpp_Type *const valueType); + + explicit ByteArray(v_buff_usize size) + : oatpp::data::mapping::type::ObjectWrapper, __class::ByteArray>( + std::make_shared>(size, 0)) {} + + ByteArray(const v_uint8 *data, v_buff_usize size) + : oatpp::data::mapping::type::ObjectWrapper, __class::ByteArray>( + std::make_shared>(data, data + size * sizeof(v_uint8))) {} + + ByteArray(std::initializer_list ilist) + : oatpp::data::mapping::type::ObjectWrapper, __class::ByteArray>( + std::make_shared>(ilist)) {} + + ByteArray &operator=(std::initializer_list ilist) { + this->m_ptr = std::make_shared>(ilist); + return *this; + } + + ByteArray(const ByteArray &other) = default; + inline ByteArray &operator=(const ByteArray &other) { + m_ptr = other.m_ptr; + return *this; + } + + ByteArray(ByteArray &&other) = default; + inline ByteArray &operator=(ByteArray &&other) noexcept { + m_ptr = std::move(other.m_ptr); + return *this; + } + + /** + * @brief Creates ByteArray from the HEX encoded string + * + * @return ByteArray + */ + static ByteArray fromHexEncodedString(const String &hexEncodedString); + + /** + * @brief Creates ByteArray from the Base64 encoded string + * + * @return ByteArray + */ + static ByteArray fromBase64EncodedString(const String &base64EncodedString); + + /** + * @brief Create a shared object of empty ByteArray + * + * @return ByteArray + */ + static ByteArray createShared() { return std::make_shared>(); } + + /** + * @brief Get constant reference to underlying container + * + * @return const std::vector& + */ + const std::vector &operator*() const { + assert(this->m_ptr); + return this->m_ptr.operator*(); + } + + inline ByteArray &operator=(const std::vector &str) { + m_ptr = std::make_shared>(str); + return *this; + } + + inline ByteArray &operator=(std::vector &&str) { + m_ptr = std::make_shared>(std::move(str)); + return *this; + } + + inline bool operator==(const std::vector &str) const { + if (!m_ptr) { + return false; + } + return *m_ptr == str; + } + + inline bool operator!=(const std::vector &str) const { return !operator==(str); } + + inline bool operator==(const ByteArray &other) const { + if (!m_ptr) { + return !other.m_ptr; + } + + if (!other.m_ptr) { + return false; + } + return *m_ptr == *other.m_ptr; + } + + inline bool operator!=(const ByteArray &other) const { return !operator==(other); } +}; + +/** + * @brief Converts ByteArray to the base64 encoded string + * + * @param b input ByteArray to convert to Base64 encoded string + * @return String + */ +String toBase64EncodedString(const ByteArray &b); + +/** + * @brief Converts ByteArray to the string of symbols representing hex-encoded bytes + * + * @param b input ByteArray to convert to HEX encoded string + * @return String + */ +String toHexEncodedString(const ByteArray &b); + +} // namespace type +} // namespace mapping +} // namespace postgresql +} // namespace oatpp + +#endif // oatpp_data_mapping_type_ByteArray_hpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ba2892a..1928e52 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -24,6 +24,10 @@ add_executable(module-tests oatpp-postgresql/types/IntTest.hpp oatpp-postgresql/types/CharacterTest.cpp oatpp-postgresql/types/CharacterTest.hpp + oatpp-postgresql/types/ByteArrayTest.cpp + oatpp-postgresql/types/ByteArrayTest.hpp + oatpp-postgresql/types/ByteArrayTypeTest.cpp + oatpp-postgresql/types/ByteArrayTypeTest.hpp oatpp-postgresql/tests.cpp ) diff --git a/test/oatpp-postgresql/migration/ByteArrayTest.sql b/test/oatpp-postgresql/migration/ByteArrayTest.sql new file mode 100644 index 0000000..ca88b4f --- /dev/null +++ b/test/oatpp-postgresql/migration/ByteArrayTest.sql @@ -0,0 +1,5 @@ +DROP TABLE IF EXISTS test_bytearray; + +CREATE TABLE test_bytearray ( + f_bytea bytea +); diff --git a/test/oatpp-postgresql/tests.cpp b/test/oatpp-postgresql/tests.cpp index 504ce2b..1d3e4a9 100644 --- a/test/oatpp-postgresql/tests.cpp +++ b/test/oatpp-postgresql/tests.cpp @@ -2,8 +2,10 @@ #include "ql_template/ParserTest.hpp" #include "types/ArrayTest.hpp" -#include "types/IntTest.hpp" +#include "types/ByteArrayTest.hpp" +#include "types/ByteArrayTypeTest.hpp" #include "types/FloatTest.hpp" +#include "types/IntTest.hpp" #include "types/InterpretationTest.hpp" #include "types/CharacterTest.hpp" @@ -42,7 +44,8 @@ void runTests() { OATPP_RUN_TEST(oatpp::test::postgresql::types::ArrayTest); OATPP_RUN_TEST(oatpp::test::postgresql::types::InterpretationTest); OATPP_RUN_TEST(oatpp::test::postgresql::types::CharacterTest); - + OATPP_RUN_TEST(oatpp::test::postgresql::types::ByteArrayTypeTest); + OATPP_RUN_TEST(oatpp::test::postgresql::types::ByteArrayTest); } } diff --git a/test/oatpp-postgresql/types/ByteArrayTest.cpp b/test/oatpp-postgresql/types/ByteArrayTest.cpp new file mode 100644 index 0000000..a108c08 --- /dev/null +++ b/test/oatpp-postgresql/types/ByteArrayTest.cpp @@ -0,0 +1,154 @@ +/*************************************************************************** + * + * Project _____ __ ____ _ _ + * ( _ ) /__\ (_ _)_| |_ _| |_ + * )(_)( /(__)\ )( (_ _)(_ _) + * (_____)(__)(__)(__) |_| |_| + * + * + * Copyright 2018-present + * + * 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 "ByteArrayTest.hpp" + +#include "oatpp-postgresql/Types.hpp" +#include "oatpp-postgresql/orm.hpp" +#include "oatpp/parser/json/mapping/ObjectMapper.hpp" + +#include +#include +#include + +namespace oatpp { +namespace test { +namespace postgresql { +namespace types { + +namespace { + +#include OATPP_CODEGEN_BEGIN(DTO) + +class MyByteArrayRow : public oatpp::DTO { + + DTO_INIT(MyByteArrayRow, DTO); + + DTO_FIELD(oatpp::postgresql::ByteArray, f_bytea); +}; + +#include OATPP_CODEGEN_END(DTO) + +#include OATPP_CODEGEN_BEGIN(DbClient) + +class MyClient : public oatpp::orm::DbClient { + public: + MyClient(const std::shared_ptr &executor) : oatpp::orm::DbClient(executor) { + + executeQuery("DROP TABLE IF EXISTS oatpp_schema_version_ByteArrayTest;", {}); + + oatpp::orm::SchemaMigration migration(executor, "ByteArrayTest"); + migration.addFile(1, TEST_DB_MIGRATION "ByteArrayTest.sql"); + migration.migrate(); + + auto version = executor->getSchemaVersion("ByteArrayTest"); + OATPP_LOGD("DbClient", "Migration - OK. Version=%d.", version); + } + + QUERY(insertBytearrayValues, + "INSERT INTO test_bytearray " + "(f_bytea) " + "VALUES " + "(:f_bytea);", + PREPARE(true), PARAM(oatpp::postgresql::ByteArray, f_bytea)) + + QUERY(selectAllBytearray, "SELECT f_bytea FROM test_bytearray") +}; + +#include OATPP_CODEGEN_END(DbClient) + +} // namespace + +void ByteArrayTest::onRun() { + + OATPP_LOGI(TAG, "DB-URL='%s'", TEST_DB_URL); + + auto connectionProvider = std::make_shared(TEST_DB_URL); + auto executor = std::make_shared(connectionProvider); + auto client = MyClient(executor); + + const auto one_element_byte_array = oatpp::postgresql::ByteArray({0xAA}); + const auto two_elements_byte_array = oatpp::postgresql::ByteArray({0xAA, 0xBB}); + const auto three_elements_byte_array = oatpp::postgresql::ByteArray({0xDE, 0xAD, 0xBE}); + const auto four_elements_byte_array = oatpp::postgresql::ByteArray({0xDE, 0xAD, 0xBE, 0xEF}); + + { + auto connection = client.getConnection(); + + client.insertBytearrayValues(oatpp::postgresql::ByteArray(), connection); + client.insertBytearrayValues(one_element_byte_array, connection); + client.insertBytearrayValues(two_elements_byte_array, connection); + client.insertBytearrayValues(three_elements_byte_array, connection); + client.insertBytearrayValues(four_elements_byte_array, connection); + } + + { + auto res = client.selectAllBytearray(); + if (res->isSuccess()) { + OATPP_LOGD(TAG, "OK, knownCount=%d, hasMore=%d", res->getKnownCount(), res->hasMoreToFetch()); + } else { + auto message = res->getErrorMessage(); + OATPP_LOGD(TAG, "Error, message=%s", message->c_str()); + } + + auto dataset = res->fetch>>(); + + OATPP_ASSERT(dataset->size() == 5); + + { + const auto &row = dataset[0]; + OATPP_ASSERT(row->f_bytea == oatpp::postgresql::ByteArray()); + } + + { + const auto &row = dataset[1]; + + OATPP_ASSERT(row->f_bytea->size() == one_element_byte_array->size()); + OATPP_ASSERT(*(row->f_bytea) == *(one_element_byte_array)); + } + { + const auto &row = dataset[2]; + + OATPP_ASSERT(row->f_bytea->size() == two_elements_byte_array->size()); + OATPP_ASSERT(*(row->f_bytea) == *(two_elements_byte_array)); + } + { + const auto &row = dataset[3]; + + OATPP_ASSERT(row->f_bytea->size() == three_elements_byte_array->size()); + OATPP_ASSERT(*(row->f_bytea) == *(three_elements_byte_array)); + } + { + const auto &row = dataset[4]; + + OATPP_ASSERT(row->f_bytea->size() == four_elements_byte_array->size()); + OATPP_ASSERT(*(row->f_bytea) == *(four_elements_byte_array)); + } + } +} + +} // namespace types +} // namespace postgresql +} // namespace test +} // namespace oatpp diff --git a/test/oatpp-postgresql/types/ByteArrayTest.hpp b/test/oatpp-postgresql/types/ByteArrayTest.hpp new file mode 100644 index 0000000..3c6cca5 --- /dev/null +++ b/test/oatpp-postgresql/types/ByteArrayTest.hpp @@ -0,0 +1,46 @@ +/*************************************************************************** + * + * Project _____ __ ____ _ _ + * ( _ ) /__\ (_ _)_| |_ _| |_ + * )(_)( /(__)\ )( (_ _)(_ _) + * (_____)(__)(__)(__) |_| |_| + * + * + * Copyright 2018-present + * + * 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 oatpp_test_postgresql_types_ByteArrayTest_hpp +#define oatpp_test_postgresql_types_ByteArrayTest_hpp + +#include "oatpp-test/UnitTest.hpp" + +namespace oatpp { +namespace test { +namespace postgresql { +namespace types { + +class ByteArrayTest : public UnitTest { + public: + ByteArrayTest() : UnitTest("TEST[postgresql::types::ByteArrayTest]") {} + void onRun() override; +}; + +} // namespace types +} // namespace postgresql +} // namespace test +} // namespace oatpp + +#endif // oatpp_test_postgresql_types_ByteArrayTest_hpp diff --git a/test/oatpp-postgresql/types/ByteArrayTypeTest.cpp b/test/oatpp-postgresql/types/ByteArrayTypeTest.cpp new file mode 100644 index 0000000..afd4c02 --- /dev/null +++ b/test/oatpp-postgresql/types/ByteArrayTypeTest.cpp @@ -0,0 +1,286 @@ +/*************************************************************************** + * + * Project _____ __ ____ _ _ + * ( _ ) /__\ (_ _)_| |_ _| |_ + * )(_)( /(__)\ )( (_ _)(_ _) + * (_____)(__)(__)(__) |_| |_| + * + * + * Copyright 2018-present + * + * 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 "ByteArrayTypeTest.hpp" + +#include "oatpp-postgresql/Types.hpp" + +#include + +namespace oatpp { +namespace test { +namespace postgresql { +namespace types { + +void ByteArrayTypeTest::onRun() { + + { + OATPP_LOGI(TAG, "test default constructor..."); + oatpp::postgresql::ByteArray array; + + OATPP_ASSERT(!array); + OATPP_ASSERT(array == nullptr); + + OATPP_ASSERT(array.get() == nullptr); + OATPP_ASSERT(array.getValueType() == oatpp::postgresql::ByteArray::Class::getType()); + + OATPP_LOGI(TAG, "OK"); + } + + { + OATPP_LOGI(TAG, "test empty ilist constructor..."); + oatpp::postgresql::ByteArray array({}); + + OATPP_ASSERT(array); + OATPP_ASSERT(array != nullptr); + OATPP_ASSERT(array->size() == 0); + + OATPP_ASSERT(array.get() != nullptr); + OATPP_ASSERT(array.getValueType() == oatpp::postgresql::ByteArray::Class::getType()); + OATPP_LOGI(TAG, "OK"); + } + + { + OATPP_LOGI(TAG, "test constructor from shared_ptr to empty vector..."); + oatpp::postgresql::ByteArray array(std::make_shared>()); + + OATPP_ASSERT(array); + OATPP_ASSERT(array != nullptr); + OATPP_ASSERT(array->size() == 0); + + OATPP_ASSERT(array.get() != nullptr); + OATPP_ASSERT(array.getValueType() == oatpp::postgresql::ByteArray::Class::getType()); + OATPP_LOGI(TAG, "OK"); + } + + { + OATPP_LOGI(TAG, "test constructor from shared_ptr to non-empty vector..."); + std::vector v = {0xA, 0xB, 0xC, 0xD}; + oatpp::postgresql::ByteArray array(std::make_shared>(v)); + + OATPP_ASSERT(array); + OATPP_ASSERT(array != nullptr); + OATPP_ASSERT(array->size() == v.size()); + + OATPP_ASSERT(array.get() != nullptr); + OATPP_ASSERT(array.getValueType() == oatpp::postgresql::ByteArray::Class::getType()); + + OATPP_ASSERT(array->at(0) == v.at(0)); + OATPP_ASSERT(array->at(v.size() - 1) == v.at(v.size() - 1)); + + OATPP_LOGI(TAG, "OK"); + } + + { + OATPP_LOGI(TAG, "test assign operator with non-empty vector..."); + oatpp::postgresql::ByteArray array = {0xA, 0xB, 0xC, 0xD}; + const auto arr_size = 4U; + + OATPP_ASSERT(array); + OATPP_ASSERT(array != nullptr); + OATPP_ASSERT(array->size() == arr_size); + + OATPP_ASSERT(array.get() != nullptr); + OATPP_ASSERT(array.getValueType() == oatpp::postgresql::ByteArray::Class::getType()); + + OATPP_ASSERT(array->at(0) == 0xA); + OATPP_ASSERT(array->at(arr_size - 1) == 0xD); + + OATPP_LOGI(TAG, "OK"); + } + + { + OATPP_LOGI(TAG, "test constructor creating some buffer initialized with zeroes..."); + const auto buf_size = 11U; + oatpp::postgresql::ByteArray array(buf_size); + + OATPP_ASSERT(array); + OATPP_ASSERT(array != nullptr); + OATPP_ASSERT(array->size() == buf_size); + + OATPP_ASSERT(array.get() != nullptr); + OATPP_ASSERT(array.getValueType() == oatpp::postgresql::ByteArray::Class::getType()); + + for (auto i = 0; i < buf_size; i++) { + OATPP_ASSERT(array->at(i) == 0); + } + + OATPP_LOGI(TAG, "OK"); + } + + { + OATPP_LOGI(TAG, "test constructor creating converting data from some array..."); + const auto buf_size = 5U; + constexpr std::array buffer = {0x1, 0x2, 0x3, 0x4, 0x5}; + oatpp::postgresql::ByteArray array(buffer.data(), buf_size); + + OATPP_ASSERT(array); + OATPP_ASSERT(array != nullptr); + OATPP_ASSERT(array->size() == buf_size); + + OATPP_ASSERT(array.get() != nullptr); + OATPP_ASSERT(array.getValueType() == oatpp::postgresql::ByteArray::Class::getType()); + + for (auto i = 0; i < buf_size; i++) { + OATPP_ASSERT(array->at(i) == i + 1); + } + + OATPP_LOGI(TAG, "OK"); + } + + { + OATPP_LOGI(TAG, "test createShared()..."); + auto array = oatpp::postgresql::ByteArray::createShared(); + + OATPP_ASSERT(array); + OATPP_ASSERT(array != nullptr); + OATPP_ASSERT(array->size() == 0); + + OATPP_ASSERT(array.get() != nullptr); + OATPP_ASSERT(array.getValueType() == oatpp::postgresql::ByteArray::Class::getType()); + OATPP_LOGI(TAG, "OK"); + } + + { + OATPP_LOGI(TAG, "test copy-assignment operator..."); + oatpp::postgresql::ByteArray array1({}); + oatpp::postgresql::ByteArray array2; + + array2 = array1; + + OATPP_ASSERT(array1); + OATPP_ASSERT(array2); + + OATPP_ASSERT(array1->size() == 0); + OATPP_ASSERT(array2->size() == 0); + + OATPP_ASSERT(array1.get() == array2.get()); + + array2->push_back(0xA); + + OATPP_ASSERT(array1->size() == 1); + OATPP_ASSERT(array2->size() == 1); + OATPP_ASSERT(array2->at(0) == 0xA); + OATPP_ASSERT(array1->at(0) == 0xA); + + std::vector v2{0xB, 0xC}; + array2 = v2; + + OATPP_ASSERT(array1->size() == 1); + OATPP_ASSERT(array2->size() == 2); + + OATPP_ASSERT(array2->at(0) == 0xB); + OATPP_ASSERT(array2->at(1) == 0xC); + OATPP_LOGI(TAG, "OK"); + } + + { + OATPP_LOGI(TAG, "test move-assignment operator..."); + oatpp::postgresql::ByteArray array1({}); + oatpp::postgresql::ByteArray array2; + OATPP_ASSERT(!array2); + + array2 = std::move(array1); + + OATPP_ASSERT(!array1); + OATPP_ASSERT(array2); + OATPP_LOGI(TAG, "OK"); + } + + { + OATPP_LOGI(TAG, "test toHexEncodedString method..."); + oatpp::postgresql::ByteArray array1( + {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}); + + OATPP_ASSERT(array1); + OATPP_ASSERT(array1->size() == 16); + + const auto s1 = toHexEncodedString(array1); + OATPP_LOGI(TAG, "arr.toHexEncodedString returned %s", s1->c_str()); + OATPP_ASSERT(oatpp::String("000102030405060708090A0B0C0D0E0F") == s1); + + oatpp::postgresql::ByteArray array2( + {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}); + + OATPP_ASSERT(array2); + OATPP_ASSERT(array2->size() == 16); + + const auto s2 = toHexEncodedString(array2); + OATPP_LOGI(TAG, "arr.toHexEncodedString returned %s", s2->c_str()); + OATPP_ASSERT(oatpp::String("AABBCCDDEEFF060708090A0B0C0D0E0F") == s2); + } + + { + OATPP_LOGI(TAG, "test fromHexEncodedString method..."); + const std::vector ba_result = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}; + const auto in_string = oatpp::String("000102030405060708090A0B0C0D0E0F"); + + const auto a = oatpp::postgresql::ByteArray::fromHexEncodedString(in_string); + + OATPP_ASSERT(a); + OATPP_ASSERT(a->size() == 16); + OATPP_ASSERT(a == ba_result); + } + + { + OATPP_LOGI(TAG, "test toBase64EncodedString method..."); + oatpp::postgresql::ByteArray array1( + {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}); + + OATPP_ASSERT(array1); + OATPP_ASSERT(array1->size() == 16); + + const auto s1 = toBase64EncodedString(array1); + OATPP_LOGI(TAG, "arr.toBase64EncodedString returned %s", s1->c_str()); + OATPP_ASSERT(oatpp::String("AAECAwQFBgcICQoLDA0ODw==") == s1); + + oatpp::postgresql::ByteArray array2({0xAA, 0xBB, 0xCC, 0xDD, 0xEE}); + + OATPP_ASSERT(array2); + OATPP_ASSERT(array2->size() == 5); + + const auto s2 = toBase64EncodedString(array2); + OATPP_LOGI(TAG, "arr.toBase64EncodedString returned %s", s2->c_str()); + OATPP_ASSERT(oatpp::String("qrvM3e4=") == s2); + } + + { + OATPP_LOGI(TAG, "test fromBase64EncodedString method..."); + const std::vector ba_result = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}; + const auto in_string = oatpp::String("AAECAwQFBgcICQoLDA0ODw=="); + + const auto a = oatpp::postgresql::ByteArray::fromBase64EncodedString(in_string); + + OATPP_ASSERT(a); + OATPP_ASSERT(a->size() == ba_result.size()); + OATPP_ASSERT(a == ba_result); + } +} + +} // namespace types +} // namespace postgresql +} // namespace test +} // namespace oatpp diff --git a/test/oatpp-postgresql/types/ByteArrayTypeTest.hpp b/test/oatpp-postgresql/types/ByteArrayTypeTest.hpp new file mode 100644 index 0000000..93a684d --- /dev/null +++ b/test/oatpp-postgresql/types/ByteArrayTypeTest.hpp @@ -0,0 +1,46 @@ +/*************************************************************************** + * + * Project _____ __ ____ _ _ + * ( _ ) /__\ (_ _)_| |_ _| |_ + * )(_)( /(__)\ )( (_ _)(_ _) + * (_____)(__)(__)(__) |_| |_| + * + * + * Copyright 2018-present + * + * 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 oatpp_test_core_data_mapping_type_ByteArrayTypeTest_hpp +#define oatpp_test_core_data_mapping_type_ByteArrayTypeTest_hpp + +#include "oatpp-test/UnitTest.hpp" + +namespace oatpp { +namespace test { +namespace postgresql { +namespace types { + +class ByteArrayTypeTest : public UnitTest { + public: + ByteArrayTypeTest() : UnitTest("TEST[oatpp::test::postgresql::types::ByteArrayTypeTest]") {} + void onRun() override; +}; + +} // namespace types +} // namespace postgresql +} // namespace test +} // namespace oatpp + +#endif /* oatpp_test_core_data_mapping_type_ByteArrayTypeTest_hpp */