1/*
2 * Copyright (C) 2017 The Android Open Source Project
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#include <utils/Log.h>
17
18#include "gtest/gtest.h"
19
20#include <media/stagefright/foundation/ABuffer.h>
21#include <media/stagefright/foundation/AString.h>
22#include <media/stagefright/foundation/AStringUtils.h>
23#include <media/stagefright/foundation/base64.h>
24
25#include <utils/RefBase.h>
26#include <utils/String8.h>
27
28namespace {
29const android::String8 kBase64Padding("=");
30};
31
32namespace android {
33
34class Base64Test : public ::testing::Test {
35};
36
37void verifyDecode(const AString* expected, const AString* in) {
38    size_t numTests = 0;
39    while (!expected[numTests].empty())
40        ++numTests;
41
42    for (size_t i = 0; i < numTests; ++i) {
43        // Since android::decodeBase64() requires padding characters,
44        // add them so length of encoded text is exactly a multiple of 4.
45        int remainder = in[i].size() % 4;
46        String8 paddedText(in[i].c_str());
47        if (remainder > 0) {
48            for (int i = 0; i < 4 - remainder; ++i) {
49                paddedText.append(kBase64Padding);
50            }
51        }
52        sp<ABuffer> result = decodeBase64(AString(paddedText.string()));
53
54        ASSERT_EQ(AStringUtils::Compare(expected[i].c_str(),
55                reinterpret_cast<char*>(result->data()),
56                expected[i].size(), false), 0);
57    }
58}
59
60void verifyEncode(const AString* expected, const AString* in) {
61    size_t numTests = 0;
62    while (!expected[numTests].empty())
63        ++numTests;
64
65    AString out = AString("");
66    for (size_t i = 0; i < numTests; ++i) {
67        encodeBase64Url(in[i].c_str(), in[i].size(), &out);
68
69        ASSERT_EQ(AStringUtils::Compare(expected[i].c_str(), out.c_str(),
70                expected[i].size(), false), 0);
71    }
72}
73
74TEST_F(Base64Test, TestDecodeBase64) {
75    const AString base64[] = {
76        AString("SGVsbG8gRnJpZW5kIQ"),
77        AString("R29vZCBkYXkh"),
78        AString("")  // string to signal end of array
79    };
80
81    const AString clearText[] = {
82        AString("Hello Friend!"),
83        AString("Good day!"),
84        AString("")
85    };
86
87    verifyDecode(clearText, base64);
88}
89
90TEST_F(Base64Test, TestDecodeBase64Url) {
91    const AString base64Url[] = {
92        AString("SGVsbG8gRnJpZW5kICE-Pw"),
93        AString("SGVsbG8gRnJpZW5kICE_"),
94        AString("SGVsbG8gPz4-IEZyaWVuZCA_Pg"),
95        AString("")
96    };
97
98    const AString clearText[] = {
99        AString("Hello Friend !>?"),
100        AString("Hello Friend !?"),
101        AString("Hello ?>> Friend ?>"),
102        AString("")
103    };
104
105    verifyDecode(clearText, base64Url);
106}
107
108TEST_F(Base64Test, TestDecodeMalformedBase64) {
109    const AString base64Url[] = {
110        AString("1?GawgguFyGrWKav7AX4VKUg"),  // fail on parsing
111        AString("GawgguFyGrWKav7AX4V???"),    // fail on length not multiple of 4
112        AString("GawgguFyGrWKav7AX4VKUg"),    // ditto
113    };
114
115    for (size_t i = 0; i < 3; ++i) {
116        sp<ABuffer> result = decodeBase64(AString(base64Url[i]));
117        EXPECT_TRUE(result == nullptr);
118    }
119}
120
121TEST_F(Base64Test, TestEncodeBase64) {
122    const AString clearText[] = {
123        AString("Hello Friend!"),
124        AString("Good day!"),
125        AString("")
126    };
127
128    const AString base64[] = {
129        AString("SGVsbG8gRnJpZW5kIQ=="),
130        AString("R29vZCBkYXkh"),
131        AString("")
132    };
133
134    verifyEncode(base64, clearText);
135}
136
137TEST_F(Base64Test, TestEncodeBase64Url) {
138    const AString clearText[] = {
139        AString("Hello Friend !>?"),
140        AString("Hello Friend !?"),
141        AString("Hello ?>> Friend ?>"),
142        AString("")
143    };
144
145    const AString base64Url[] = {
146        AString("SGVsbG8gRnJpZW5kICE-Pw=="),
147        AString("SGVsbG8gRnJpZW5kICE_"),
148        AString("SGVsbG8gPz4-IEZyaWVuZCA_Pg"),
149        AString("")
150    };
151
152    verifyEncode(base64Url, clearText);
153}
154
155} // namespace android
156