diff options
Diffstat (limited to 'tests/Commons/Base64_test.cpp')
-rw-r--r-- | tests/Commons/Base64_test.cpp | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/tests/Commons/Base64_test.cpp b/tests/Commons/Base64_test.cpp new file mode 100644 index 0000000..afa1a1c --- /dev/null +++ b/tests/Commons/Base64_test.cpp @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ +/** + * @file Base64_test.cpp + * @author Grzegorz Rynkowski (g.rynkowski@samsung.com) + * @brief This file contains tests for Base64 + */ + +#include <Commons/Base64.h> +#include <Commons/Exception.h> +#include <dpl/log/secure_log.h> +#include <dpl/test/test_runner.h> +#include <cstring> +#include <memory> +#include <random> +#include <set> +#include <string> +#include <type_traits> + +using namespace WrtDeviceApis::Commons; + +namespace { +struct TextPair { + TextPair(std::string&& decoded_, std::string&& encoded_) + { + std::swap(decoded_, decoded); + std::swap(encoded_, encoded); + } + std::string decoded, encoded; + + static const std::vector<TextPair>& examples() + { + static std::vector<TextPair> vec = { + TextPair( + "Man is distinguished, not only by his reason, but by this sing" + "ular passion from other animals, which is a lust of the mind, " + "that by a perseverance of delight in the continued and indefat" + "igable generation of knowledge, exceeds the short vehemence of" + " any carnal pleasure.", + "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIG" + "J1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxz" + "LCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZX" + "ZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0" + "aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG" + "9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="), + TextPair("f", "Zg=="), + TextPair("fo" , "Zm8="), + TextPair("foo" , "Zm9v"), + TextPair("foob" , "Zm9vYg=="), + TextPair("fooba" , "Zm9vYmE=") + }; + return vec; + } +}; + +template<typename T> +std::unique_ptr<T[]> convertStringToPtr(const std::string& str) +{ + static_assert(std::is_same<unsigned char, T>::value + || std::is_same<char, T>::value, + "std::string is able convert into char[] or unsigned char[]"); + std::unique_ptr<T[]> textCopy(new T[str.length() + 1]); + std::memcpy(textCopy.get(), str.c_str(), str.length() + 1); + return std::move(textCopy); +} + +#define CheckEncodeMsg(original_, encoded_, msg) { \ + std::string original(original_), encoded(encoded_); \ + std::string methodResult = Base64::encode( \ + convertStringToPtr<unsigned char>(original).get(), \ + original.length()); \ + if (!(methodResult == encoded)) { \ + WrtLogD("Encoded text = \"%s\"", encoded.c_str()); \ + WrtLogD("Base64::encode() = \"%s\"", methodResult.c_str()); \ + RUNNER_ASSERT(false); \ + } \ +} +#define CheckEncode(original, encoded) CheckEncodeMsg(original, encoded, "") + +#define CheckDecodeMsg(encoded_, decoded_, msg) { \ + std::string encoded(encoded_), decoded(decoded_); \ + std::string methodResult = Base64::decode(encoded); \ + if (!(methodResult == decoded)) { \ + WrtLogD("Decoded text = \"%s\"", decoded.c_str()); \ + WrtLogD("Base64::decode() = \"%s\"", methodResult.c_str()); \ + RUNNER_ASSERT(methodResult == decoded); \ + } \ +} +#define CheckDecode(original, decoded) CheckDecodeMsg(original, decoded, "") + +const std::set<char> base64chars = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; + +} // unnamed namespace + + +RUNNER_TEST_GROUP_INIT(Base64) + +/* +Name: base64_test_encode +Description: Tests encoding of examples +Expected: Base64::encode should encode examples correctly. +*/ +RUNNER_TEST(base64_test_encode) +{ + for (auto& i : TextPair::examples()) + CheckEncode(i.decoded, i.encoded); +} + +/* +Name: base64_test_encode_empty +Description: Tests encoding of empty string +Expected: Base64::encode should return empty string too +*/ +RUNNER_TEST(base64_test_encode_empty) +{ + CheckEncodeMsg("", "", "Encoded of empty string should be empty too."); +} + +/* +Name: base64_test_decode +Description: Tests decoding of examples +Expected: Base64::encode should decode examples correctly. +*/ +RUNNER_TEST(base64_test_decode) +{ + for (auto& i : TextPair::examples()) + CheckDecode(i.encoded, i.decoded); +} + +/* +Name: base64_test_decode_empty +Description: Tests decoding of empty string +Expected: Base64::decode should return empty string too +*/ +RUNNER_TEST(base64_test_decode_empty) +{ + CheckDecodeMsg("", "", "Decoded of empty string should be empty too."); +} + +/* +Name: base64_test_decode_only_pads +Description: Tests decoding of string with only pads +Expected: Base64::decode should return empty string +*/ +RUNNER_TEST(base64_test_decode_only_pads) +{ + CheckDecodeMsg("====", "", + "Decoded string with only pads should produce empty string"); +} + +/* +Name: base64_test_decode_invalid_length +Description: Tests decoding of string with invalid length +Expected: Base64::decode should throw exception +*/ +RUNNER_TEST(base64_test_decode_invalid_length) +{ + for (auto& example : TextPair::examples()) { + for (int i = 1; i <= 3; ++i) { + std::string encodedWithInvalideLength = + example.encoded.substr(0, example.encoded.size() - i); + Try { + Base64::decode(encodedWithInvalideLength); + RUNNER_ASSERT_MSG(false, + "For invalid length method should throw exception."); + } Catch (InvalidArgumentException) { + // Test pass - nothing to do + } Catch (DPL::Exception) { + RUNNER_ASSERT_MSG(false, "Unknown exception."); + } + } + } +} + +/* +Name: base64_test_decode_invalid_valid_char +Description: Tests decoding of string with all ASCII characters +Expected: Base64::decode should throw exception for characters that aren't + in alphabet of Base64. +*/ +RUNNER_TEST(base64_test_decode_invalid_valid_char) +{ + std::random_device rd; + std::mt19937 gen(rd()); + + for (const TextPair& ex : TextPair::examples()) + { + for (char character = 1; character != 0; ++character) + { + if('=' == character) + continue; + + std::string encodedWithNewChar( + [&]()->std::string // return string with invalide character + { + std::size_t lastPosition = ex.encoded.find('='); + lastPosition = (std::string::npos == lastPosition) + ? ex.encoded.length()-1 : lastPosition - 1; + std::uniform_int_distribution<> dis(0, lastPosition); + + int randomPosition = dis(gen); + std::unique_ptr<char[]> tmp = + convertStringToPtr<char>(ex.encoded); + tmp.get()[randomPosition] = character; + return std::string(tmp.get()); + }()); + + bool found = (base64chars.find(character) != base64chars.end()); + Try { + Base64::decode(encodedWithNewChar); + if (!found) { + WrtLogD("Before = \"%s\"", ex.encoded.c_str()); + WrtLogD("After = \"%s\"", encodedWithNewChar.c_str()); + } + RUNNER_ASSERT_MSG(found, "For invalid character(" + << static_cast<int>(character) << "|'" << character + << "') method should throw exception."); + } Catch (InvalidArgumentException) { + if (found) { + WrtLogD("Before = \"%s\"", ex.encoded.c_str()); + WrtLogD("After = \"%s\"", encodedWithNewChar.c_str()); + } + RUNNER_ASSERT_MSG(!found, "For valid character(" + << static_cast<int>(character) << "|'" << character + << "') the exception shouldn't be threw."); + } Catch (DPL::Exception) { + RUNNER_ASSERT_MSG(false, "Unknown exception."); + } + } + } +} |