// Copyright 2017 The Abseil Authors.
//
// 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
//
// https://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 "absl/strings/escaping.h"
#include <array>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <initializer_list>
#include <memory>
#include <string>
#include <vector>
#include "gtest/gtest.h"
#include "absl/log/check.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/internal/escaping_test_common.h"
#include "absl/strings/string_view.h"
namespace {
struct epair {
std::string escaped;
std::string unescaped;
};
TEST(CEscape, EscapeAndUnescape) {
const std::string inputs[] = {
std::string(
"foo\nxx\r\b\0023" ),
std::string(
"" ),
std::string(
"abc" ),
std::string(
"\1chad_rules" ),
std::string(
"\1arnar_drools" ),
std::string(
"xxxx\r\t'\" \\
"),
std::string(
"\0xx\0" , 4),
std::string(
"\x01\x31" ),
std::string(
"abc\xb\x42\141bc" ),
std::string(
"123\1\x31\x32\x33" ),
std::string(
"\xc1\xca\x1b\x62\x19o\xcc\x04" ),
std::string(
"\\\" \xe8\xb0\xb7\xe6\xad\x8c\\\
" is Google\\\'s Chinese name" ),
};
// Do this twice, once for octal escapes and once for hex escapes.
for (
int kind = 0; kind < 4; kind++) {
for (
const std::string& original : inputs) {
std::string escaped;
switch (kind) {
case 0:
escaped = absl::CEscape(original);
break ;
case 1:
escaped = absl::CHexEscape(original);
break ;
case 2:
escaped = absl::Utf8SafeCEscape(original);
break ;
case 3:
escaped = absl::Utf8SafeCHexEscape(original);
break ;
}
std::string unescaped_str;
EXPECT_TRUE(absl::CUnescape(escaped, &unescaped_str));
EXPECT_EQ(unescaped_str, original);
unescaped_str.erase();
std::string error;
EXPECT_TRUE(absl::CUnescape(escaped, &unescaped_str, &error));
EXPECT_EQ(error,
"" );
// Check in-place unescaping
std::string s = escaped;
EXPECT_TRUE(absl::CUnescape(s, &s));
ASSERT_EQ(s, original);
}
}
// Check that all possible two character strings can be escaped then
// unescaped successfully.
for (
int char0 = 0; char0 < 256; char0++) {
for (
int char1 = 0; char1 < 256; char1++) {
char chars[2];
chars[0] = char0;
chars[1] = char1;
std::string s(chars, 2);
std::string escaped = absl::CHexEscape(s);
std::string unescaped;
EXPECT_TRUE(absl::CUnescape(escaped, &unescaped));
EXPECT_EQ(s, unescaped);
}
}
}
TEST(CEscape, BasicEscaping) {
epair oct_values[] = {
{
"foo\\rbar\\nbaz\\t" ,
"foo\rbar\nbaz\t" },
{
"\\'full of \\\" sound\\\
" and \\\" fury\\\
"\\'" ,
"'full of \" sound\
" and \" fury\
"'" },
{
"signi\\\\fying\\\\ nothing\\\\" ,
"signi\\fying\\ nothing\\" },
{
"\\010\\t\\n\\013\\014\\r" ,
"\010\011\012\013\014\015" }
};
epair hex_values[] = {
{
"ubik\\rubik\\nubik\\t" ,
"ubik\rubik\nubik\t" },
{
"I\\\'ve just seen a \\\" face\\\
"" ,
"I've just seen a \" face\
"" },
{
"hel\\\\ter\\\\skel\\\\ter\\\\" ,
"hel\\ter\\skel\\ter\\" },
{
"\\x08\\t\\n\\x0b\\x0c\\r" ,
"\010\011\012\013\014\015" }
};
epair utf8_oct_values[] = {
{
"\xe8\xb0\xb7\xe6\xad\x8c\\r\xe8\xb0\xb7\xe6\xad\x8c\\nbaz\\t" ,
"\xe8\xb0\xb7\xe6\xad\x8c\r\xe8\xb0\xb7\xe6\xad\x8c\nbaz\t" },
{
"\\\" \xe8\xb0\xb7\xe6\xad\x8c\\\
" is Google\\\'s Chinese name" ,
"\" \xe8\xb0\xb7\xe6\xad\x8c\
" is Google\'s Chinese name" },
{
"\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\xab\\\\are\\\\Japanese\\\\chars\\\\" ,
"\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\xab\\are\\Japanese\\chars\\" },
{
"\xed\x81\xac\xeb\xa1\xac\\010\\t\\n\\013\\014\\r" ,
"\xed\x81\xac\xeb\xa1\xac\010\011\012\013\014\015" }
};
epair utf8_hex_values[] = {
{
"\x20\xe4\xbd\xa0\\t\xe5\xa5\xbd,\\r!\\n" ,
"\x20\xe4\xbd\xa0\t\xe5\xa5\xbd,\r!\n" },
{
"\xe8\xa9\xa6\xe9\xa8\x93\\\' means \\\" test\\\
"" ,
"\xe8\xa9\xa6\xe9\xa8\x93\' means \" test\
"" },
{
"\\\\\xe6\x88\x91\\\\:\\\\\xe6\x9d\xa8\xe6\xac\xa2\\\\" ,
"\\\xe6\x88\x91\\:\\\xe6\x9d\xa8\xe6\xac\xa2\\" },
{
"\xed\x81\xac\xeb\xa1\xac\\x08\\t\\n\\x0b\\x0c\\r" ,
"\xed\x81\xac\xeb\xa1\xac\010\011\012\013\014\015" }
};
for (
const epair& val : oct_values) {
std::string escaped = absl::CEscape(val.unescaped);
EXPECT_EQ(escaped, val.escaped);
}
for (
const epair& val : hex_values) {
std::string escaped = absl::CHexEscape(val.unescaped);
EXPECT_EQ(escaped, val.escaped);
}
for (
const epair& val : utf8_oct_values) {
std::string escaped = absl::Utf8SafeCEscape(val.unescaped);
EXPECT_EQ(escaped, val.escaped);
}
for (
const epair& val : utf8_hex_values) {
std::string escaped = absl::Utf8SafeCHexEscape(val.unescaped);
EXPECT_EQ(escaped, val.escaped);
}
}
TEST(Unescape, BasicFunction) {
epair tests[] =
{{
"" ,
"" },
{
"\\u0030" ,
"0" },
{
"\\u00A3" ,
"\xC2\xA3" },
{
"\\u22FD" ,
"\xE2\x8B\xBD" },
{
"\\U00010000" ,
"\xF0\x90\x80\x80" },
{
"\\U0010FFFD" ,
"\xF4\x8F\xBF\xBD" }};
for (
const epair& val : tests) {
std::string out;
EXPECT_TRUE(absl::CUnescape(val.escaped, &out));
EXPECT_EQ(out, val.unescaped);
}
std::string bad[] = {
"\\u1" ,
// too short
"\\U1" ,
// too short
"\\Uffffff" ,
// exceeds 0x10ffff (largest Unicode)
"\\U00110000" ,
// exceeds 0x10ffff (largest Unicode)
"\\uD835" ,
// surrogate character (D800-DFFF)
"\\U0000DD04" ,
// surrogate character (D800-DFFF)
"\\777" ,
// exceeds 0xff
"\\xABCD" };
// exceeds 0xff
for (
const std::string& e : bad) {
std::string error;
std::string out;
EXPECT_FALSE(absl::CUnescape(e, &out, &error));
EXPECT_FALSE(error.empty());
out.erase();
EXPECT_FALSE(absl::CUnescape(e, &out));
}
}
class CUnescapeTest :
public testing::Test {
protected :
static const char kStringWithMultipleOctalNulls[];
static const char kStringWithMultipleHexNulls[];
static const char kStringWithMultipleUnicodeNulls[];
std::string result_string_;
};
const char CUnescapeTest::kStringWithMultipleOctalNulls[] =
"\\0\\n" // null escape \0 plus newline
"0\\n" // just a number 0 (not a null escape) plus newline
"\\00\\12" // null escape \00 plus octal newline code
"\\000" ;
// null escape \000
// This has the same ingredients as kStringWithMultipleOctalNulls
// but with \x hex escapes instead of octal escapes.
const char CUnescapeTest::kStringWithMultipleHexNulls[] =
"\\x0\\n"
"0\\n"
"\\x00\\xa"
"\\x000" ;
const char CUnescapeTest::kStringWithMultipleUnicodeNulls[] =
"\\u0000\\n" // short-form (4-digit) null escape plus newline
"0\\n" // just a number 0 (not a null escape) plus newline
"\\U00000000" ;
// long-form (8-digit) null escape
TEST_F(CUnescapeTest, Unescapes1CharOctalNull) {
std::string original_string =
"\\0" ;
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
EXPECT_EQ(std::string(
"\0" , 1), result_string_);
}
TEST_F(CUnescapeTest, Unescapes2CharOctalNull) {
std::string original_string =
"\\00" ;
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
EXPECT_EQ(std::string(
"\0" , 1), result_string_);
}
TEST_F(CUnescapeTest, Unescapes3CharOctalNull) {
std::string original_string =
"\\000" ;
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
EXPECT_EQ(std::string(
"\0" , 1), result_string_);
}
TEST_F(CUnescapeTest, Unescapes1CharHexNull) {
std::string original_string =
"\\x0" ;
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
EXPECT_EQ(std::string(
"\0" , 1), result_string_);
}
TEST_F(CUnescapeTest, Unescapes2CharHexNull) {
std::string original_string =
"\\x00" ;
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
EXPECT_EQ(std::string(
"\0" , 1), result_string_);
}
TEST_F(CUnescapeTest, Unescapes3CharHexNull) {
std::string original_string =
"\\x000" ;
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
EXPECT_EQ(std::string(
"\0" , 1), result_string_);
}
TEST_F(CUnescapeTest, Unescapes4CharUnicodeNull) {
std::string original_string =
"\\u0000" ;
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
EXPECT_EQ(std::string(
"\0" , 1), result_string_);
}
TEST_F(CUnescapeTest, Unescapes8CharUnicodeNull) {
std::string original_string =
"\\U00000000" ;
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
EXPECT_EQ(std::string(
"\0" , 1), result_string_);
}
TEST_F(CUnescapeTest, UnescapesMultipleOctalNulls) {
std::string original_string(kStringWithMultipleOctalNulls);
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
// All escapes, including newlines and null escapes, should have been
// converted to the equivalent characters.
EXPECT_EQ(std::string(
"\0\n"
"0\n"
"\0\n"
"\0" ,
7),
result_string_);
}
TEST_F(CUnescapeTest, UnescapesMultipleHexNulls) {
std::string original_string(kStringWithMultipleHexNulls);
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
EXPECT_EQ(std::string(
"\0\n"
"0\n"
"\0\n"
"\0" ,
7),
result_string_);
}
TEST_F(CUnescapeTest, UnescapesMultipleUnicodeNulls) {
std::string original_string(kStringWithMultipleUnicodeNulls);
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
EXPECT_EQ(std::string(
"\0\n"
"0\n"
"\0" ,
5),
result_string_);
}
static struct {
absl::string_view plaintext;
absl::string_view cyphertext;
}
const base64_tests[] = {
// Empty string.
{{
"" , 0}, {
"" , 0}},
{{nullptr, 0},
{
"" , 0}},
// if length is zero, plaintext ptr must be ignored!
// Basic bit patterns;
// values obtained with "echo -n '...' | uuencode -m test"
{{
"\000" , 1},
"AA==" },
{{
"\001" , 1},
"AQ==" },
{{
"\002" , 1},
"Ag==" },
{{
"\004" , 1},
"BA==" },
{{
"\010" , 1},
"CA==" },
{{
"\020" , 1},
"EA==" },
{{
"\040" , 1},
"IA==" },
{{
"\100" , 1},
"QA==" },
{{
"\200" , 1},
"gA==" },
{{
"\377" , 1},
"/w==" },
{{
"\376" , 1},
"/g==" },
{{
"\375" , 1},
"/Q==" },
{{
"\373" , 1},
"+w==" },
{{
"\367" , 1},
"9w==" },
{{
"\357" , 1},
"7w==" },
{{
"\337" , 1},
"3w==" },
{{
"\277" , 1},
"vw==" },
{{
"\177" , 1},
"fw==" },
{{
"\000\000" , 2},
"AAA=" },
{{
"\000\001" , 2},
"AAE=" },
{{
"\000\002" , 2},
"AAI=" },
{{
"\000\004" , 2},
"AAQ=" },
{{
"\000\010" , 2},
"AAg=" },
{{
"\000\020" , 2},
"ABA=" },
{{
"\000\040" , 2},
"ACA=" },
{{
"\000\100" , 2},
"AEA=" },
{{
"\000\200" , 2},
"AIA=" },
{{
"\001\000" , 2},
"AQA=" },
{{
"\002\000" , 2},
"AgA=" },
{{
"\004\000" , 2},
"BAA=" },
{{
"\010\000" , 2},
"CAA=" },
{{
"\020\000" , 2},
"EAA=" },
{{
"\040\000" , 2},
"IAA=" },
{{
"\100\000" , 2},
"QAA=" },
{{
"\200\000" , 2},
"gAA=" },
{{
"\377\377" , 2},
"//8="},
{{
"\377\376" , 2},
"//4="},
{{
"\377\375" , 2},
"//0="},
{{
"\377\373" , 2},
"//s="},
{{
"\377\367" , 2},
"//c="},
{{
"\377\357" , 2},
"/+8=" },
{{
"\377\337" , 2},
"/98=" },
{{
"\377\277" , 2},
"/78=" },
{{
"\377\177" , 2},
"/38=" },
{{
"\376\377" , 2},
"/v8=" },
{{
"\375\377" , 2},
"/f8=" },
{{
"\373\377" , 2},
"+/8=" },
{{
"\367\377" , 2},
"9/8=" },
{{
"\357\377" , 2},
"7/8=" },
{{
"\337\377" , 2},
"3/8=" },
{{
"\277\377" , 2},
"v/8=" },
{{
"\177\377" , 2},
"f/8=" },
{{
"\000\000\000" , 3},
"AAAA" },
{{
"\000\000\001" , 3},
"AAAB" },
{{
"\000\000\002" , 3},
"AAAC" },
{{
"\000\000\004" , 3},
"AAAE" },
{{
"\000\000\010" , 3},
"AAAI" },
{{
"\000\000\020" , 3},
"AAAQ" },
{{
"\000\000\040" , 3},
"AAAg" },
{{
"\000\000\100" , 3},
"AABA" },
{{
"\000\000\200" , 3},
"AACA" },
{{
"\000\001\000" , 3},
"AAEA" },
{{
"\000\002\000" , 3},
"AAIA" },
{{
"\000\004\000" , 3},
"AAQA" },
{{
"\000\010\000" , 3},
"AAgA" },
{{
"\000\020\000" , 3},
"ABAA" },
{{
"\000\040\000" , 3},
"ACAA" },
{{
"\000\100\000" , 3},
"AEAA" },
{{
"\000\200\000" , 3},
"AIAA" },
{{
"\001\000\000" , 3},
"AQAA" },
{{
"\002\000\000" , 3},
"AgAA" },
{{
"\004\000\000" , 3},
"BAAA" },
{{
"\010\000\000" , 3},
"CAAA" },
{{
"\020\000\000" , 3},
"EAAA" },
{{
"\040\000\000" , 3},
"IAAA" },
{{
"\100\000\000" , 3},
"QAAA" },
{{
"\200\000\000" , 3},
"gAAA" },
{{
"\377\377\377" , 3},
"////"},
{{
"\377\377\376" , 3},
"///+"},
{{
"\377\377\375" , 3},
"///9"},
{{
"\377\377\373" , 3},
"///7"},
{{
"\377\377\367" , 3},
"///3"},
{{
"\377\377\357" , 3},
"///v"},
{{
"\377\377\337" , 3},
"///f"},
{{
"\377\377\277" , 3},
"//+/"},
{{
"\377\377\177" , 3},
"//9/"},
{{
"\377\376\377" , 3},
"//7/"},
{{
"\377\375\377" , 3},
"//3/"},
{{
"\377\373\377" , 3},
"//v/"},
{{
"\377\367\377" , 3},
"//f/"},
{{
"\377\357\377" , 3},
"/+//"},
{{
"\377\337\377" , 3},
"/9//"},
{{
"\377\277\377" , 3},
"/7//"},
{{
"\377\177\377" , 3},
"/3//"},
{{
"\376\377\377" , 3},
"/v//"},
{{
"\375\377\377" , 3},
"/f//"},
{{
"\373\377\377" , 3},
"+///"},
{{
"\367\377\377" , 3},
"9///"},
{{
"\357\377\377" , 3},
"7///"},
{{
"\337\377\377" , 3},
"3///"},
{{
"\277\377\377" , 3},
"v///"},
{{
"\177\377\377" , 3},
"f///"},
// Random numbers: values obtained with
//
// #! /bin/bash
// dd bs=$1 count=1 if=/dev/random of=/tmp/bar.random
// od -N $1 -t o1 /tmp/bar.random
// uuencode -m test < /tmp/bar.random
//
// where $1 is the number of bytes (2, 3)
{{
"\243\361" , 2},
"o/E=" },
{{
"\024\167" , 2},
"FHc=" },
{{
"\313\252" , 2},
"y6o=" },
{{
"\046\041" , 2},
"JiE=" },
{{
"\145\236" , 2},
"ZZ4=" },
{{
"\254\325" , 2},
"rNU=" },
{{
"\061\330" , 2},
"Mdg=" },
{{
"\245\032" , 2},
"pRo=" },
{{
"\006\000" , 2},
"BgA=" },
{{
"\375\131" , 2},
"/Vk=" },
{{
"\303\210" , 2},
"w4g=" },
{{
"\040\037" , 2},
"IB8=" },
{{
"\261\372" , 2},
"sfo=" },
{{
"\335\014" , 2},
"3Qw=" },
{{
"\233\217" , 2},
"m48=" },
{{
"\373\056" , 2},
"+y4=" },
{{
"\247\232" , 2},
"p5o=" },
{{
"\107\053" , 2},
"Rys=" },
{{
"\204\077" , 2},
"hD8=" },
{{
"\276\211" , 2},
"vok=" },
{{
"\313\110" , 2},
"y0g=" },
{{
"\363\376" , 2},
"8/4=" },
{{
"\251\234" , 2},
"qZw=" },
{{
"\103\262" , 2},
"Q7I=" },
{{
"\142\312" , 2},
"Yso=" },
{{
"\067\211" , 2},
"N4k=" },
{{
"\220\001" , 2},
"kAE=" },
{{
"\152\240" , 2},
"aqA=" },
{{
"\367\061" , 2},
"9zE=" },
{{
"\133\255" , 2},
"W60=" },
{{
"\176\035" , 2},
"fh0=" },
{{
"\032\231" , 2},
"Gpk=" },
{{
"\013\007\144" , 3},
"Cwdk" },
{{
"\030\112\106" , 3},
"GEpG" },
{{
"\047\325\046" , 3},
"J9Um" },
{{
"\310\160\022" , 3},
"yHAS" },
{{
"\131\100\237" , 3},
"WUCf" },
{{
"\064\342\134" , 3},
"NOJc" },
{{
"\010\177\004" , 3},
"CH8E" },
{{
"\345\147\205" , 3},
"5WeF" },
{{
"\300\343\360" , 3},
"wOPw" },
{{
"\061\240\201" , 3},
"MaCB" },
{{
"\225\333\044" , 3},
"ldsk" },
{{
"\215\137\352" , 3},
"jV/q" },
{{
"\371\147\160" , 3},
"+Wdw" },
{{
"\030\320\051" , 3},
"GNAp" },
{{
"\044\174\241" , 3},
"JHyh" },
{{
"\260\127\037" , 3},
"sFcf" },
{{
"\111\045\033" , 3},
"SSUb" },
{{
"\202\114\107" , 3},
"gkxH" },
{{
"\057\371\042" , 3},
"L/ki" },
{{
"\223\247\244" , 3},
"k6ek" },
{{
"\047\216\144" , 3},
"J45k" },
{{
"\203\070\327" , 3},
"gzjX" },
{{
"\247\140\072" , 3},
"p2A6" },
{{
"\124\115\116" , 3},
"VE1O" },
{{
"\157\162\050" , 3},
"b3Io" },
{{
"\357\223\004" , 3},
"75ME" },
{{
"\052\117\156" , 3},
"Kk9u" },
{{
"\347\154\000" , 3},
"52wA" },
{{
"\303\012\142" , 3},
"wwpi" },
{{
"\060\035\362" , 3},
"MB3y" },
{{
"\130\226\361" , 3},
"WJbx" },
{{
"\173\013\071" , 3},
"ews5" },
{{
"\336\004\027" , 3},
"3gQX" },
{{
"\357\366\234" , 3},
"7/ac" },
{{
"\353\304\111" , 3},
"68RJ" },
{{
"\024\264\131" , 3},
"FLRZ" },
{{
"\075\114\251" , 3},
"PUyp" },
{{
"\315\031\225" , 3},
"zRmV" },
{{
"\154\201\276" , 3},
"bIG+" },
{{
"\200\066\072" , 3},
"gDY6" },
{{
"\142\350\267" , 3},
"Yui3" },
{{
"\033\000\166" , 3},
"GwB2" },
{{
"\210\055\077" , 3},
"iC0/" },
{{
"\341\037\124" , 3},
"4R9U" },
{{
"\161\103\152" , 3},
"cUNq" },
{{
"\270\142\131" , 3},
"uGJZ" },
{{
"\337\076\074" , 3},
"3z48" },
{{
"\375\106\362" , 3},
"/Uby" },
{{
"\227\301\127" , 3},
"l8FX" },
{{
"\340\002\234" , 3},
"4AKc" },
{{
"\121\064\033" , 3},
"UTQb" },
{{
"\157\134\143" , 3},
"b1xj" },
{{
"\247\055\327" , 3},
"py3X" },
{{
"\340\142\005" , 3},
"4GIF" },
{{
"\060\260\143" , 3},
"MLBj" },
{{
"\075\203\170" , 3},
"PYN4" },
{{
"\143\160\016" , 3},
"Y3AO" },
{{
"\313\013\063" , 3},
"ywsz" },
{{
"\174\236\135" , 3},
"fJ5d" },
{{
"\103\047\026" , 3},
"QycW" },
{{
"\365\005\343" , 3},
"9QXj" },
{{
"\271\160\223" , 3},
"uXCT" },
{{
"\362\255\172" , 3},
"8q16" },
{{
"\113\012\015" , 3},
"SwoN" },
// various lengths, generated by this python script:
//
// from std::string import lowercase as lc
// for i in range(27):
// print '{ %2d, "%s",%s "%s" },' % (i, lc[:i], ' ' * (26-i),
// lc[:i].encode('base64').strip())
{{
"" , 0}, {
"" , 0}},
{
"a" ,
"YQ==" },
{
"ab" ,
"YWI=" },
{
"abc" ,
"YWJj" },
{
"abcd" ,
"YWJjZA==" },
{
"abcde" ,
"YWJjZGU=" },
{
"abcdef" ,
"YWJjZGVm" },
{
"abcdefg" ,
"YWJjZGVmZw==" },
{
"abcdefgh" ,
"YWJjZGVmZ2g=" },
{
"abcdefghi" ,
"YWJjZGVmZ2hp" },
{
"abcdefghij" ,
"YWJjZGVmZ2hpag==" },
{
"abcdefghijk" ,
"YWJjZGVmZ2hpams=" },
{
"abcdefghijkl" ,
"YWJjZGVmZ2hpamts" },
{
"abcdefghijklm" ,
"YWJjZGVmZ2hpamtsbQ==" },
{
"abcdefghijklmn" ,
"YWJjZGVmZ2hpamtsbW4=" },
{
"abcdefghijklmno" ,
"YWJjZGVmZ2hpamtsbW5v" },
{
"abcdefghijklmnop" ,
"YWJjZGVmZ2hpamtsbW5vcA==" },
{
"abcdefghijklmnopq" ,
"YWJjZGVmZ2hpamtsbW5vcHE=" },
{
"abcdefghijklmnopqr" ,
"YWJjZGVmZ2hpamtsbW5vcHFy" },
{
"abcdefghijklmnopqrs" ,
"YWJjZGVmZ2hpamtsbW5vcHFycw==" },
{
"abcdefghijklmnopqrst" ,
"YWJjZGVmZ2hpamtsbW5vcHFyc3Q=" },
{
"abcdefghijklmnopqrstu" ,
"YWJjZGVmZ2hpamtsbW5vcHFyc3R1" },
{
"abcdefghijklmnopqrstuv" ,
"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dg==" },
{
"abcdefghijklmnopqrstuvw" ,
"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnc=" },
{
"abcdefghijklmnopqrstuvwx" ,
"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4" },
{
"abcdefghijklmnopqrstuvwxy" ,
"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eQ==" },
{
"abcdefghijklmnopqrstuvwxyz" ,
"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=" },
};
template <
typename StringType>
void TestEscapeAndUnescape() {
// Check the short strings; this tests the math (and boundaries)
for (
const auto & tc : base64_tests) {
// Test plain base64.
StringType encoded(
"this junk should be ignored" );
absl::Base64Escape(tc.plaintext, &encoded);
EXPECT_EQ(encoded, tc.cyphertext);
EXPECT_EQ(absl::Base64Escape(tc.plaintext), tc.cyphertext);
StringType decoded(
"this junk should be ignored" );
EXPECT_TRUE(absl::Base64Unescape(encoded, &decoded));
EXPECT_EQ(decoded, tc.plaintext);
StringType websafe_with_padding(tc.cyphertext);
for (
unsigned int c = 0; c < websafe_with_padding.size(); ++c) {
if (
'+' == websafe_with_padding[c]) websafe_with_padding[c] =
'-' ;
if (
'/' == websafe_with_padding[c]) websafe_with_padding[c] =
'_' ;
// Intentionally keeping padding aka '='.
}
// Test plain websafe (aka without padding).
StringType websafe(websafe_with_padding);
for (
unsigned int c = 0; c < websafe.size(); ++c) {
if (
'=' == websafe[c]) {
websafe.resize(c);
break ;
}
}
encoded =
"this junk should be ignored" ;
absl::WebSafeBase64Escape(tc.plaintext, &encoded);
EXPECT_EQ(encoded, websafe);
EXPECT_EQ(absl::WebSafeBase64Escape(tc.plaintext), websafe);
decoded =
"this junk should be ignored" ;
EXPECT_TRUE(absl::WebSafeBase64Unescape(websafe, &decoded));
EXPECT_EQ(decoded, tc.plaintext);
}
// Now try the long strings, this tests the streaming
for (
const auto & tc : absl::strings_internal::base64_strings()) {
StringType buffer;
absl::WebSafeBase64Escape(tc.plaintext, &buffer);
EXPECT_EQ(tc.cyphertext, buffer);
EXPECT_EQ(absl::WebSafeBase64Escape(tc.plaintext), tc.cyphertext);
}
// Verify the behavior when decoding bad data
{
absl::string_view data_set[] = {
"ab-/" , absl::string_view(
"\0bcd" , 4),
absl::string_view(
"abc.\0" , 5)};
for (absl::string_view bad_data : data_set) {
StringType buf;
EXPECT_FALSE(absl::Base64Unescape(bad_data, &buf));
EXPECT_FALSE(absl::WebSafeBase64Unescape(bad_data, &buf));
EXPECT_TRUE(buf.empty());
}
}
}
TEST(Base64, EscapeAndUnescape) {
TestEscapeAndUnescape<std::string>();
}
TEST(Base64, Padding) {
// Padding is optional.
// '.' is an acceptable padding character, just like '='.
std::initializer_list<absl::string_view> good_padding = {
"YQ" ,
"YQ==" ,
"YQ=." ,
"YQ.=" ,
"YQ.." ,
};
for (absl::string_view b64 : good_padding) {
std::string decoded;
EXPECT_TRUE(absl::Base64Unescape(b64, &decoded));
EXPECT_EQ(decoded,
"a" );
std::string websafe_decoded;
EXPECT_TRUE(absl::WebSafeBase64Unescape(b64, &websafe_decoded));
EXPECT_EQ(websafe_decoded,
"a" );
}
std::initializer_list<absl::string_view> bad_padding = {
"YQ=" ,
"YQ." ,
"YQ===" ,
"YQ==." ,
"YQ=.=" ,
"YQ=.." ,
"YQ.==" ,
"YQ.=." ,
"YQ..=" ,
"YQ..." ,
"YQ====" ,
"YQ...." ,
"YQ=====" ,
"YQ....." ,
};
for (absl::string_view b64 : bad_padding) {
std::string decoded;
EXPECT_FALSE(absl::Base64Unescape(b64, &decoded));
std::string websafe_decoded;
EXPECT_FALSE(absl::WebSafeBase64Unescape(b64, &websafe_decoded));
}
}
TEST(Base64, DISABLED_HugeData) {
const size_t kSize = size_t(3) * 1000 * 1000 * 1000;
static_assert(kSize % 3 == 0,
"kSize must be divisible by 3" );
const std::string huge(kSize,
'x' );
std::string escaped;
absl::Base64Escape(huge, &escaped);
// Generates the string that should match a base64 encoded "xxx..." string.
// "xxx" in base64 is "eHh4".
std::string expected_encoding;
expected_encoding.reserve(kSize / 3 * 4);
for (size_t i = 0; i < kSize / 3; ++i) {
expected_encoding.append(
"eHh4" );
}
EXPECT_EQ(expected_encoding, escaped);
std::string unescaped;
EXPECT_TRUE(absl::Base64Unescape(escaped, &unescaped));
EXPECT_EQ(huge, unescaped);
}
TEST(Escaping, HexStringToBytesBackToHex) {
std::string bytes, hex;
constexpr absl::string_view kTestHexLower =
"1c2f0032f40123456789abcdef" ;
constexpr absl::string_view kTestHexUpper =
"1C2F0032F40123456789ABCDEF" ;
constexpr absl::string_view kTestBytes = absl::string_view(
"\x1c\x2f\x00\x32\xf4\x01\x23\x45\x67\x89\xab\xcd\xef" , 13);
EXPECT_TRUE(absl::HexStringToBytes(kTestHexLower, &bytes));
EXPECT_EQ(bytes, kTestBytes);
EXPECT_TRUE(absl::HexStringToBytes(kTestHexUpper, &bytes));
EXPECT_EQ(bytes, kTestBytes);
hex = absl::BytesToHexString(kTestBytes);
EXPECT_EQ(hex, kTestHexLower);
// Same buffer.
// We do not care if this works since we do not promise it in the contract.
// The purpose of this test is to to see if the program will crash or if
// sanitizers will catch anything.
bytes = std::string(kTestHexUpper);
(
void )absl::HexStringToBytes(bytes, &bytes);
// Length not a multiple of two.
EXPECT_FALSE(absl::HexStringToBytes(
"1c2f003" , &bytes));
// Not hex.
EXPECT_FALSE(absl::HexStringToBytes(
"1c2f00ft" , &bytes));
// Empty input.
bytes =
"abc" ;
EXPECT_TRUE(absl::HexStringToBytes(
"" , &bytes));
EXPECT_EQ(
"" , bytes);
// Results in empty output.
}
TEST(HexAndBack, HexStringToBytes_and_BytesToHexString) {
std::string hex_mixed =
"0123456789abcdefABCDEF" ;
std::string bytes_expected =
"\x01\x23\x45\x67\x89\xab\xcd\xef\xAB\xCD\xEF" ;
std::string hex_only_lower =
"0123456789abcdefabcdef" ;
std::string bytes_result = absl::HexStringToBytes(hex_mixed);
EXPECT_EQ(bytes_expected, bytes_result);
std::string prefix_valid = hex_mixed +
"?" ;
std::string prefix_valid_result = absl::HexStringToBytes(
absl::string_view(prefix_valid.data(), prefix_valid.size() - 1));
EXPECT_EQ(bytes_expected, prefix_valid_result);
std::string infix_valid =
"?" + hex_mixed +
"???" ;
std::string infix_valid_result = absl::HexStringToBytes(
absl::string_view(infix_valid.data() + 1, hex_mixed.size()));
EXPECT_EQ(bytes_expected, infix_valid_result);
std::string hex_result = absl::BytesToHexString(bytes_expected);
EXPECT_EQ(hex_only_lower, hex_result);
}
}
// namespace
Messung V0.5 C=78 H=92 G=84
¤ Dauer der Verarbeitung: 0.6 Sekunden
¤
*© Formatika GbR, Deutschland