tizen 2.4 release
[framework/web/wrt-plugins-common.git] / tests / Commons / Base64_test.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /**
17  * @file    Base64_test.cpp
18  * @author  Grzegorz Rynkowski (g.rynkowski@samsung.com)
19  * @brief   This file contains tests for Base64
20  */
21
22 #include <Commons/Base64.h>
23 #include <Commons/Exception.h>
24 #include <dpl/log/secure_log.h>
25 #include <dpl/test/test_runner.h>
26 #include <cstring>
27 #include <memory>
28 #include <random>
29 #include <set>
30 #include <string>
31 #include <type_traits>
32
33 using namespace WrtDeviceApis::Commons;
34
35 namespace {
36 struct TextPair {
37     TextPair(std::string&& decoded_, std::string&& encoded_)
38     {
39         std::swap(decoded_, decoded);
40         std::swap(encoded_, encoded);
41     }
42     std::string decoded, encoded;
43
44     static const std::vector<TextPair>& examples()
45     {
46         static std::vector<TextPair> vec = {
47                 TextPair(
48                 "Man is distinguished, not only by his reason, but by this sing"
49                 "ular passion from other animals, which is a lust of the mind, "
50                 "that by a perseverance of delight in the continued and indefat"
51                 "igable generation of knowledge, exceeds the short vehemence of"
52                 " any carnal pleasure.",
53                 "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIG"
54                 "J1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxz"
55                 "LCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZX"
56                 "ZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0"
57                 "aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG"
58                 "9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="),
59                 TextPair("f", "Zg=="),
60                 TextPair("fo" , "Zm8="),
61                 TextPair("foo" , "Zm9v"),
62                 TextPair("foob" , "Zm9vYg=="),
63                 TextPair("fooba" , "Zm9vYmE=")
64         };
65         return vec;
66     }
67 };
68
69 template<typename T>
70 std::unique_ptr<T[]> convertStringToPtr(const std::string& str)
71 {
72     static_assert(std::is_same<unsigned char, T>::value
73                 || std::is_same<char, T>::value,
74             "std::string is able convert into char[] or unsigned char[]");
75     std::unique_ptr<T[]> textCopy(new T[str.length() + 1]);
76     std::memcpy(textCopy.get(), str.c_str(), str.length() + 1);
77     return std::move(textCopy);
78 }
79
80 #define CheckEncodeMsg(original_, encoded_, msg) {                             \
81     std::string original(original_), encoded(encoded_);                        \
82     std::string methodResult = Base64::encode(                                 \
83                     convertStringToPtr<unsigned char>(original).get(),         \
84                     original.length());                                        \
85     if (!(methodResult == encoded)) {                                          \
86         _D("Encoded text     = \"%s\"", encoded.c_str());                 \
87         _D("Base64::encode() = \"%s\"", methodResult.c_str());            \
88         RUNNER_ASSERT(false);                                                  \
89     }                                                                          \
90 }
91 #define CheckEncode(original, encoded) CheckEncodeMsg(original, encoded, "")
92
93 #define CheckDecodeMsg(encoded_, decoded_, msg) {                              \
94     std::string encoded(encoded_), decoded(decoded_);                          \
95     std::string methodResult = Base64::decode(encoded);                        \
96     if (!(methodResult == decoded)) {                                          \
97         _D("Decoded text     = \"%s\"", decoded.c_str());                 \
98         _D("Base64::decode() = \"%s\"", methodResult.c_str());            \
99         RUNNER_ASSERT(methodResult == decoded);                                \
100     }                                                                          \
101 }
102 #define CheckDecode(original, decoded) CheckDecodeMsg(original, decoded, "")
103
104 const std::set<char> base64chars = {
105         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
106         'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
107         'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
108         'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
109         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
110
111 } // unnamed namespace
112
113
114 RUNNER_TEST_GROUP_INIT(Base64)
115
116 /*
117 Name: base64_test_encode
118 Description: Tests encoding of examples
119 Expected: Base64::encode should encode examples correctly.
120 */
121 RUNNER_TEST(base64_test_encode)
122 {
123     for (auto& i : TextPair::examples())
124         CheckEncode(i.decoded, i.encoded);
125 }
126
127 /*
128 Name: base64_test_encode_empty
129 Description: Tests encoding of empty string
130 Expected: Base64::encode should return empty string too
131 */
132 RUNNER_TEST(base64_test_encode_empty)
133 {
134     CheckEncodeMsg("", "", "Encoded of empty string should be empty too.");
135 }
136
137 /*
138 Name: base64_test_decode
139 Description: Tests decoding of examples
140 Expected: Base64::encode should decode examples correctly.
141 */
142 RUNNER_TEST(base64_test_decode)
143 {
144     for (auto& i : TextPair::examples())
145         CheckDecode(i.encoded, i.decoded);
146 }
147
148 /*
149 Name: base64_test_decode_empty
150 Description: Tests decoding of empty string
151 Expected: Base64::decode should return empty string too
152 */
153 RUNNER_TEST(base64_test_decode_empty)
154 {
155     CheckDecodeMsg("", "", "Decoded of empty string should be empty too.");
156 }
157
158 /*
159 Name: base64_test_decode_only_pads
160 Description: Tests decoding of string with only pads
161 Expected: Base64::decode should return empty string
162 */
163 RUNNER_TEST(base64_test_decode_only_pads)
164 {
165     CheckDecodeMsg("====", "",
166             "Decoded string with only pads should produce empty string");
167 }
168
169 /*
170 Name: base64_test_decode_invalid_length
171 Description: Tests decoding of string with invalid length
172 Expected: Base64::decode should throw exception
173 */
174 RUNNER_TEST(base64_test_decode_invalid_length)
175 {
176     for (auto& example : TextPair::examples()) {
177         for (int i = 1; i <= 3; ++i) {
178             std::string encodedWithInvalideLength =
179                     example.encoded.substr(0, example.encoded.size() - i);
180             Try {
181                 Base64::decode(encodedWithInvalideLength);
182                 RUNNER_ASSERT_MSG(false,
183                         "For invalid length method should throw exception.");
184             } Catch (InvalidArgumentException) {
185                 // Test pass - nothing to do
186             } Catch (DPL::Exception) {
187                 RUNNER_ASSERT_MSG(false, "Unknown exception.");
188             }
189         }
190     }
191 }
192
193 /*
194 Name: base64_test_decode_invalid_valid_char
195 Description: Tests decoding of string with all ASCII characters
196 Expected: Base64::decode should throw exception for characters that aren't
197     in alphabet of Base64.
198 */
199 RUNNER_TEST(base64_test_decode_invalid_valid_char)
200 {
201     std::random_device rd;
202     std::mt19937 gen(rd());
203
204     for (const TextPair& ex : TextPair::examples())
205     {
206         for (char character = 1; character != 0; ++character)
207         {
208             if('=' == character)
209                 continue;
210
211             std::string encodedWithNewChar(
212                     [&]()->std::string // return string with invalide character
213                     {
214                         std::size_t lastPosition = ex.encoded.find('=');
215                         lastPosition = (std::string::npos == lastPosition)
216                                 ? ex.encoded.length()-1 : lastPosition - 1;
217                         std::uniform_int_distribution<> dis(0, lastPosition);
218
219                         int randomPosition = dis(gen);
220                         std::unique_ptr<char[]> tmp =
221                                 convertStringToPtr<char>(ex.encoded);
222                         tmp.get()[randomPosition] = character;
223                         return std::string(tmp.get());
224                     }());
225
226             bool found = (base64chars.find(character) != base64chars.end());
227             Try {
228                 Base64::decode(encodedWithNewChar);
229                 if (!found) {
230                     _D("Before = \"%s\"", ex.encoded.c_str());
231                     _D("After  = \"%s\"", encodedWithNewChar.c_str());
232                 }
233                 RUNNER_ASSERT_MSG(found, "For invalid character("
234                         << static_cast<int>(character) << "|'" << character
235                         << "') method should throw exception.");
236             } Catch (InvalidArgumentException) {
237                 if (found) {
238                     _D("Before = \"%s\"", ex.encoded.c_str());
239                     _D("After  = \"%s\"", encodedWithNewChar.c_str());
240                 }
241                 RUNNER_ASSERT_MSG(!found, "For valid character("
242                         << static_cast<int>(character) << "|'" << character
243                         << "') the exception shouldn't be threw.");
244             } Catch (DPL::Exception) {
245                 RUNNER_ASSERT_MSG(false, "Unknown exception.");
246             }
247         }
248     }
249 }