| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| |
| |
| // Unit-test the base64 encoder. |
| |
| #include "pagespeed/kernel/base/basictypes.h" |
| #include "pagespeed/kernel/base/base64_util.h" |
| #include "pagespeed/kernel/base/gtest.h" |
| #include "pagespeed/kernel/base/string.h" |
| #include "pagespeed/kernel/base/string_util.h" |
| |
| namespace { |
| |
| const char chinese_data[] = "中华网,中华,中国,中文网,中国新闻,香港新闻," |
| "国际新闻,中文新闻,新闻,港台新闻,两会,嫦娥一号"; |
| const int chinese_size = STATIC_STRLEN(chinese_data); |
| |
| // Also test some binary data, including embedded nulls, 2^7-1, 2^8-1 |
| const char binary_data[] = "\0\1\2\3\4\5\6\7\10\0\177\176\175\377\376"; |
| const int binary_size = STATIC_STRLEN(binary_data); |
| |
| class Codec { |
| public: |
| virtual ~Codec() {} |
| virtual void encode(const GoogleString& in, GoogleString* out) const = 0; |
| virtual bool decode(const GoogleString& in, GoogleString* out) const = 0; |
| }; |
| |
| class WebSafeBase64Codec : public Codec { |
| public: |
| virtual void encode(const GoogleString& in, GoogleString* out) const { |
| net_instaweb::Web64Encode(in, out); |
| } |
| virtual bool decode(const GoogleString& in, GoogleString* out) const { |
| return net_instaweb::Web64Decode(in, out); |
| } |
| }; |
| |
| class MimeBase64Codec : public Codec { |
| public: |
| virtual void encode(const GoogleString& in, GoogleString* out) const { |
| net_instaweb::Mime64Encode(in, out); |
| } |
| virtual bool decode(const GoogleString& in, GoogleString* out) const { |
| return net_instaweb::Mime64Decode(in, out); |
| } |
| }; |
| |
| } // namespace |
| |
| namespace net_instaweb { |
| |
| class Base64Test : public testing::Test { |
| protected: |
| Base64Test() |
| : chinese_(chinese_data, chinese_size), |
| binary_(binary_data, binary_size), |
| web64_codec_(), |
| mime64_codec_() { |
| } |
| |
| void TestWeb64(const Codec &codec, const GoogleString& input) { |
| GoogleString encoded, decoded; |
| codec.encode(input, &encoded); |
| ASSERT_TRUE(codec.decode(encoded, &decoded)); |
| EXPECT_EQ(input, decoded); |
| } |
| |
| // Tests that attempts to decode a string that is not properly base64 |
| // encoded will gracefully fail (Web64Decode returns false) rather than |
| // crash or produce invalid output. corrupt_char must be a character |
| // that is not in the base64 char-set. |
| // |
| // If the 'index' is specified as a negative number, it will be taken |
| // as an offset from the end of the string. |
| void TestCorrupt(const Codec &codec, |
| const GoogleString& input, char corrupt_char, int index) { |
| GoogleString encoded, decoded; |
| codec.encode(input, &encoded); |
| if (index < 0) { |
| index = encoded.size() + index; |
| } |
| encoded[index] = corrupt_char; |
| ASSERT_FALSE(codec.decode(encoded, &decoded)); |
| } |
| |
| GoogleString chinese_; |
| GoogleString binary_; |
| WebSafeBase64Codec web64_codec_; |
| MimeBase64Codec mime64_codec_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(Base64Test); |
| }; |
| |
| TEST_F(Base64Test, Chinese) { |
| TestWeb64(web64_codec_, chinese_); |
| TestWeb64(mime64_codec_, chinese_); |
| } |
| |
| TEST_F(Base64Test, Binary) { |
| TestWeb64(web64_codec_, binary_); |
| TestWeb64(mime64_codec_, binary_); |
| } |
| |
| TEST_F(Base64Test, CorruptFirst) { |
| TestCorrupt(web64_codec_, chinese_, '@', 0); |
| TestCorrupt(mime64_codec_, chinese_, '@', 0); |
| } |
| |
| TEST_F(Base64Test, CorruptMiddle) { |
| TestCorrupt(web64_codec_, chinese_, ':', chinese_.size() / 2); |
| TestCorrupt(mime64_codec_, chinese_, ':', chinese_.size() / 2); |
| } |
| |
| TEST_F(Base64Test, CorruptEnd) { |
| // I wanted to put the '/' as the last character, but it turns out |
| // that encoders may put '=' characters in to pad to a multiple of |
| // 4 bytes, and the decoder stops decoding when it gets to the first |
| // pad character, so changing "==" to "=/" has no effect. |
| TestCorrupt(web64_codec_, chinese_, '/', -4); |
| TestCorrupt(mime64_codec_, chinese_, '_', -4); |
| } |
| |
| } // namespace net_instaweb |