text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Author: kenton@google.com (Kenton Varda)

#include <google/protobuf/stubs/strutil.h>

#include <locale.h>

#include <google/protobuf/stubs/stl_util.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>

#ifdef _WIN32
#define snprintf _snprintf
#endif

namespace google {
namespace protobuf {
namespace {

// TODO(kenton):  Copy strutil tests from google3?

TEST(StringUtilityTest, ImmuneToLocales) {
  // Remember the old locale.
  char* old_locale_cstr = setlocale(LC_NUMERIC, NULL);
  ASSERT_TRUE(old_locale_cstr != NULL);
  string old_locale = old_locale_cstr;

  // Set the locale to "C".
  ASSERT_TRUE(setlocale(LC_NUMERIC, "C") != NULL);

  EXPECT_EQ("1.5", SimpleDtoa(1.5));
  EXPECT_EQ("1.5", SimpleFtoa(1.5));

  if (setlocale(LC_NUMERIC, "es_ES") == NULL &&
      setlocale(LC_NUMERIC, "es_ES.utf8") == NULL) {
    // Some systems may not have the desired locale available.
    GOOGLE_LOG(WARNING)
      << "Couldn't set locale to es_ES.  Skipping this test.";
  } else {
    EXPECT_EQ("1.5", SimpleDtoa(1.5));
    EXPECT_EQ("1.5", SimpleFtoa(1.5));
  }

  // Return to original locale.
  setlocale(LC_NUMERIC, old_locale.c_str());
}

#define EXPECT_EQ_ARRAY(len, x, y, msg)                     \
  for (int j = 0; j < len; ++j) {                           \
    EXPECT_EQ(x[j], y[j]) << "" # x << " != " # y           \
                          << " byte " << j << ": " << msg;  \
  }

static struct {
  int plain_length;
  const char* plaintext;
  const char* cyphertext;
} base64_tests[] = {
  // Empty string.
  { 0, "", ""},

  // Basic bit patterns;
  // values obtained with "echo -n '...' | uuencode -m test"

  { 1, "\000", "AA==" },
  { 1, "\001", "AQ==" },
  { 1, "\002", "Ag==" },
  { 1, "\004", "BA==" },
  { 1, "\010", "CA==" },
  { 1, "\020", "EA==" },
  { 1, "\040", "IA==" },
  { 1, "\100", "QA==" },
  { 1, "\200", "gA==" },

  { 1, "\377", "/w==" },
  { 1, "\376", "/g==" },
  { 1, "\375", "/Q==" },
  { 1, "\373", "+w==" },
  { 1, "\367", "9w==" },
  { 1, "\357", "7w==" },
  { 1, "\337", "3w==" },
  { 1, "\277", "vw==" },
  { 1, "\177", "fw==" },
  { 2, "\000\000", "AAA=" },
  { 2, "\000\001", "AAE=" },
  { 2, "\000\002", "AAI=" },
  { 2, "\000\004", "AAQ=" },
  { 2, "\000\010", "AAg=" },
  { 2, "\000\020", "ABA=" },
  { 2, "\000\040", "ACA=" },
  { 2, "\000\100", "AEA=" },
  { 2, "\000\200", "AIA=" },
  { 2, "\001\000", "AQA=" },
  { 2, "\002\000", "AgA=" },
  { 2, "\004\000", "BAA=" },
  { 2, "\010\000", "CAA=" },
  { 2, "\020\000", "EAA=" },
  { 2, "\040\000", "IAA=" },
  { 2, "\100\000", "QAA=" },
  { 2, "\200\000", "gAA=" },

  { 2, "\377\377", "//8=" },
  { 2, "\377\376", "//4=" },
  { 2, "\377\375", "//0=" },
  { 2, "\377\373", "//s=" },
  { 2, "\377\367", "//c=" },
  { 2, "\377\357", "/+8=" },
  { 2, "\377\337", "/98=" },
  { 2, "\377\277", "/78=" },
  { 2, "\377\177", "/38=" },
  { 2, "\376\377", "/v8=" },
  { 2, "\375\377", "/f8=" },
  { 2, "\373\377", "+/8=" },
  { 2, "\367\377", "9/8=" },
  { 2, "\357\377", "7/8=" },
  { 2, "\337\377", "3/8=" },
  { 2, "\277\377", "v/8=" },
  { 2, "\177\377", "f/8=" },

  { 3, "\000\000\000", "AAAA" },
  { 3, "\000\000\001", "AAAB" },
  { 3, "\000\000\002", "AAAC" },
  { 3, "\000\000\004", "AAAE" },
  { 3, "\000\000\010", "AAAI" },
  { 3, "\000\000\020", "AAAQ" },
  { 3, "\000\000\040", "AAAg" },
  { 3, "\000\000\100", "AABA" },
  { 3, "\000\000\200", "AACA" },
  { 3, "\000\001\000", "AAEA" },
  { 3, "\000\002\000", "AAIA" },
  { 3, "\000\004\000", "AAQA" },
  { 3, "\000\010\000", "AAgA" },
  { 3, "\000\020\000", "ABAA" },
  { 3, "\000\040\000", "ACAA" },
  { 3, "\000\100\000", "AEAA" },
  { 3, "\000\200\000", "AIAA" },
  { 3, "\001\000\000", "AQAA" },
  { 3, "\002\000\000", "AgAA" },
  { 3, "\004\000\000", "BAAA" },
  { 3, "\010\000\000", "CAAA" },
  { 3, "\020\000\000", "EAAA" },
  { 3, "\040\000\000", "IAAA" },
  { 3, "\100\000\000", "QAAA" },
  { 3, "\200\000\000", "gAAA" },

  { 3, "\377\377\377", "////" },
  { 3, "\377\377\376", "///+" },
  { 3, "\377\377\375", "///9" },
  { 3, "\377\377\373", "///7" },
  { 3, "\377\377\367", "///3" },
  { 3, "\377\377\357", "///v" },
  { 3, "\377\377\337", "///f" },
  { 3, "\377\377\277", "//+/" },
  { 3, "\377\377\177", "//9/" },
  { 3, "\377\376\377", "//7/" },
  { 3, "\377\375\377", "//3/" },
  { 3, "\377\373\377", "//v/" },
  { 3, "\377\367\377", "//f/" },
  { 3, "\377\357\377", "/+//" },
  { 3, "\377\337\377", "/9//" },
  { 3, "\377\277\377", "/7//" },
  { 3, "\377\177\377", "/3//" },
  { 3, "\376\377\377", "/v//" },
  { 3, "\375\377\377", "/f//" },
  { 3, "\373\377\377", "+///" },
  { 3, "\367\377\377", "9///" },
  { 3, "\357\377\377", "7///" },
  { 3, "\337\377\377", "3///" },
  { 3, "\277\377\377", "v///" },
  { 3, "\177\377\377", "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)

  { 2, "\243\361", "o/E=" },
  { 2, "\024\167", "FHc=" },
  { 2, "\313\252", "y6o=" },
  { 2, "\046\041", "JiE=" },
  { 2, "\145\236", "ZZ4=" },
  { 2, "\254\325", "rNU=" },
  { 2, "\061\330", "Mdg=" },
  { 2, "\245\032", "pRo=" },
  { 2, "\006\000", "BgA=" },
  { 2, "\375\131", "/Vk=" },
  { 2, "\303\210", "w4g=" },
  { 2, "\040\037", "IB8=" },
  { 2, "\261\372", "sfo=" },
  { 2, "\335\014", "3Qw=" },
  { 2, "\233\217", "m48=" },
  { 2, "\373\056", "+y4=" },
  { 2, "\247\232", "p5o=" },
  { 2, "\107\053", "Rys=" },
  { 2, "\204\077", "hD8=" },
  { 2, "\276\211", "vok=" },
  { 2, "\313\110", "y0g=" },
  { 2, "\363\376", "8/4=" },
  { 2, "\251\234", "qZw=" },
  { 2, "\103\262", "Q7I=" },
  { 2, "\142\312", "Yso=" },
  { 2, "\067\211", "N4k=" },
  { 2, "\220\001", "kAE=" },
  { 2, "\152\240", "aqA=" },
  { 2, "\367\061", "9zE=" },
  { 2, "\133\255", "W60=" },
  { 2, "\176\035", "fh0=" },
  { 2, "\032\231", "Gpk=" },

  { 3, "\013\007\144", "Cwdk" },
  { 3, "\030\112\106", "GEpG" },
  { 3, "\047\325\046", "J9Um" },
  { 3, "\310\160\022", "yHAS" },
  { 3, "\131\100\237", "WUCf" },
  { 3, "\064\342\134", "NOJc" },
  { 3, "\010\177\004", "CH8E" },
  { 3, "\345\147\205", "5WeF" },
  { 3, "\300\343\360", "wOPw" },
  { 3, "\061\240\201", "MaCB" },
  { 3, "\225\333\044", "ldsk" },
  { 3, "\215\137\352", "jV/q" },
  { 3, "\371\147\160", "+Wdw" },
  { 3, "\030\320\051", "GNAp" },
  { 3, "\044\174\241", "JHyh" },
  { 3, "\260\127\037", "sFcf" },
  { 3, "\111\045\033", "SSUb" },
  { 3, "\202\114\107", "gkxH" },
  { 3, "\057\371\042", "L/ki" },
  { 3, "\223\247\244", "k6ek" },
  { 3, "\047\216\144", "J45k" },
  { 3, "\203\070\327", "gzjX" },
  { 3, "\247\140\072", "p2A6" },
  { 3, "\124\115\116", "VE1O" },
  { 3, "\157\162\050", "b3Io" },
  { 3, "\357\223\004", "75ME" },
  { 3, "\052\117\156", "Kk9u" },
  { 3, "\347\154\000", "52wA" },
  { 3, "\303\012\142", "wwpi" },
  { 3, "\060\035\362", "MB3y" },
  { 3, "\130\226\361", "WJbx" },
  { 3, "\173\013\071", "ews5" },
  { 3, "\336\004\027", "3gQX" },
  { 3, "\357\366\234", "7/ac" },
  { 3, "\353\304\111", "68RJ" },
  { 3, "\024\264\131", "FLRZ" },
  { 3, "\075\114\251", "PUyp" },
  { 3, "\315\031\225", "zRmV" },
  { 3, "\154\201\276", "bIG+" },
  { 3, "\200\066\072", "gDY6" },
  { 3, "\142\350\267", "Yui3" },
  { 3, "\033\000\166", "GwB2" },
  { 3, "\210\055\077", "iC0/" },
  { 3, "\341\037\124", "4R9U" },
  { 3, "\161\103\152", "cUNq" },
  { 3, "\270\142\131", "uGJZ" },
  { 3, "\337\076\074", "3z48" },
  { 3, "\375\106\362", "/Uby" },
  { 3, "\227\301\127", "l8FX" },
  { 3, "\340\002\234", "4AKc" },
  { 3, "\121\064\033", "UTQb" },
  { 3, "\157\134\143", "b1xj" },
  { 3, "\247\055\327", "py3X" },
  { 3, "\340\142\005", "4GIF" },
  { 3, "\060\260\143", "MLBj" },
  { 3, "\075\203\170", "PYN4" },
  { 3, "\143\160\016", "Y3AO" },
  { 3, "\313\013\063", "ywsz" },
  { 3, "\174\236\135", "fJ5d" },
  { 3, "\103\047\026", "QycW" },
  { 3, "\365\005\343", "9QXj" },
  { 3, "\271\160\223", "uXCT" },
  { 3, "\362\255\172", "8q16" },
  { 3, "\113\012\015", "SwoN" },

  // various lengths, generated by this python script:
  //
  // from 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, "",                           "" },
  {  1, "a",                          "YQ==" },
  {  2, "ab",                         "YWI=" },
  {  3, "abc",                        "YWJj" },
  {  4, "abcd",                       "YWJjZA==" },
  {  5, "abcde",                      "YWJjZGU=" },
  {  6, "abcdef",                     "YWJjZGVm" },
  {  7, "abcdefg",                    "YWJjZGVmZw==" },
  {  8, "abcdefgh",                   "YWJjZGVmZ2g=" },
  {  9, "abcdefghi",                  "YWJjZGVmZ2hp" },
  { 10, "abcdefghij",                 "YWJjZGVmZ2hpag==" },
  { 11, "abcdefghijk",                "YWJjZGVmZ2hpams=" },
  { 12, "abcdefghijkl",               "YWJjZGVmZ2hpamts" },
  { 13, "abcdefghijklm",              "YWJjZGVmZ2hpamtsbQ==" },
  { 14, "abcdefghijklmn",             "YWJjZGVmZ2hpamtsbW4=" },
  { 15, "abcdefghijklmno",            "YWJjZGVmZ2hpamtsbW5v" },
  { 16, "abcdefghijklmnop",           "YWJjZGVmZ2hpamtsbW5vcA==" },
  { 17, "abcdefghijklmnopq",          "YWJjZGVmZ2hpamtsbW5vcHE=" },
  { 18, "abcdefghijklmnopqr",         "YWJjZGVmZ2hpamtsbW5vcHFy" },
  { 19, "abcdefghijklmnopqrs",        "YWJjZGVmZ2hpamtsbW5vcHFycw==" },
  { 20, "abcdefghijklmnopqrst",       "YWJjZGVmZ2hpamtsbW5vcHFyc3Q=" },
  { 21, "abcdefghijklmnopqrstu",      "YWJjZGVmZ2hpamtsbW5vcHFyc3R1" },
  { 22, "abcdefghijklmnopqrstuv",     "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dg==" },
  { 23, "abcdefghijklmnopqrstuvw",    "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnc=" },
  { 24, "abcdefghijklmnopqrstuvwx",   "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4" },
  { 25, "abcdefghijklmnopqrstuvwxy",  "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eQ==" },
  { 26, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=" },
};

static struct {
  const char* plaintext;
  const char* cyphertext;
} base64_strings[] = {
  // Some google quotes
  // Cyphertext created with "uuencode (GNU sharutils) 4.6.3"
  // (Note that we're testing the websafe encoding, though, so if
  // you add messages, be sure to run "tr -- '+/' '-_'" on the output)
  { "I was always good at math and science, and I never realized "
    "that was unusual or somehow undesirable. So one of the things "
    "I care a lot about is helping to remove that stigma, "
    "to show girls that you can be feminine, you can like the things "
    "that girls like, but you can also be really good at technology. "
    "You can be really good at building things."
    " - Marissa Meyer, Newsweek, 2010-12-22" "\n",

    "SSB3YXMgYWx3YXlzIGdvb2QgYXQgbWF0aCBhbmQgc2NpZW5jZSwgYW5kIEkg"
    "bmV2ZXIgcmVhbGl6ZWQgdGhhdCB3YXMgdW51c3VhbCBvciBzb21laG93IHVu"
    "ZGVzaXJhYmxlLiBTbyBvbmUgb2YgdGhlIHRoaW5ncyBJIGNhcmUgYSBsb3Qg"
    "YWJvdXQgaXMgaGVscGluZyB0byByZW1vdmUgdGhhdCBzdGlnbWEsIHRvIHNo"
    "b3cgZ2lybHMgdGhhdCB5b3UgY2FuIGJlIGZlbWluaW5lLCB5b3UgY2FuIGxp"
    "a2UgdGhlIHRoaW5ncyB0aGF0IGdpcmxzIGxpa2UsIGJ1dCB5b3UgY2FuIGFs"
    "c28gYmUgcmVhbGx5IGdvb2QgYXQgdGVjaG5vbG9neS4gWW91IGNhbiBiZSBy"
    "ZWFsbHkgZ29vZCBhdCBidWlsZGluZyB0aGluZ3MuIC0gTWFyaXNzYSBNZXll"
    "ciwgTmV3c3dlZWssIDIwMTAtMTItMjIK" },

  { "Typical first year for a new cluster: "
    "~0.5 overheating "
    "~1 PDU failure "
    "~1 rack-move "
    "~1 network rewiring "
    "~20 rack failures "
    "~5 racks go wonky "
    "~8 network maintenances "
    "~12 router reloads "
    "~3 router failures "
    "~dozens of minor 30-second blips for dns "
    "~1000 individual machine failures "
    "~thousands of hard drive failures "
    "slow disks, bad memory, misconfigured machines, flaky machines, etc."
    " - Jeff Dean, The Joys of Real Hardware" "\n",

    "VHlwaWNhbCBmaXJzdCB5ZWFyIGZvciBhIG5ldyBjbHVzdGVyOiB-MC41IG92"
    "ZXJoZWF0aW5nIH4xIFBEVSBmYWlsdXJlIH4xIHJhY2stbW92ZSB-MSBuZXR3"
    "b3JrIHJld2lyaW5nIH4yMCByYWNrIGZhaWx1cmVzIH41IHJhY2tzIGdvIHdv"
    "bmt5IH44IG5ldHdvcmsgbWFpbnRlbmFuY2VzIH4xMiByb3V0ZXIgcmVsb2Fk"
    "cyB-MyByb3V0ZXIgZmFpbHVyZXMgfmRvemVucyBvZiBtaW5vciAzMC1zZWNv"
    "bmQgYmxpcHMgZm9yIGRucyB-MTAwMCBpbmRpdmlkdWFsIG1hY2hpbmUgZmFp"
    "bHVyZXMgfnRob3VzYW5kcyBvZiBoYXJkIGRyaXZlIGZhaWx1cmVzIHNsb3cg"
    "ZGlza3MsIGJhZCBtZW1vcnksIG1pc2NvbmZpZ3VyZWQgbWFjaGluZXMsIGZs"
    "YWt5IG1hY2hpbmVzLCBldGMuIC0gSmVmZiBEZWFuLCBUaGUgSm95cyBvZiBS"
    "ZWFsIEhhcmR3YXJlCg" },

  { "I'm the head of the webspam team at Google.  "
    "That means that if you type your name into Google and get porn back, "
    "it's my fault. Unless you're a porn star, in which case porn is a "
    "completely reasonable response."
    " - Matt Cutts, Google Plus" "\n",

    "SSdtIHRoZSBoZWFkIG9mIHRoZSB3ZWJzcGFtIHRlYW0gYXQgR29vZ2xlLiAg"
    "VGhhdCBtZWFucyB0aGF0IGlmIHlvdSB0eXBlIHlvdXIgbmFtZSBpbnRvIEdv"
    "b2dsZSBhbmQgZ2V0IHBvcm4gYmFjaywgaXQncyBteSBmYXVsdC4gVW5sZXNz"
    "IHlvdSdyZSBhIHBvcm4gc3RhciwgaW4gd2hpY2ggY2FzZSBwb3JuIGlzIGEg"
    "Y29tcGxldGVseSByZWFzb25hYmxlIHJlc3BvbnNlLiAtIE1hdHQgQ3V0dHMs"
    "IEdvb2dsZSBQbHVzCg" },

  { "It will still be a long time before machines approach human intelligence. "
    "But luckily, machines don't actually have to be intelligent; "
    "they just have to fake it. Access to a wealth of information, "
    "combined with a rudimentary decision-making capacity, "
    "can often be almost as useful. Of course, the results are better yet "
    "when coupled with intelligence. A reference librarian with access to "
    "a good search engine is a formidable tool."
    " - Craig Silverstein, Siemens Pictures of the Future, Spring 2004" "\n",

    "SXQgd2lsbCBzdGlsbCBiZSBhIGxvbmcgdGltZSBiZWZvcmUgbWFjaGluZXMg"
    "YXBwcm9hY2ggaHVtYW4gaW50ZWxsaWdlbmNlLiBCdXQgbHVja2lseSwgbWFj"
    "aGluZXMgZG9uJ3QgYWN0dWFsbHkgaGF2ZSB0byBiZSBpbnRlbGxpZ2VudDsg"
    "dGhleSBqdXN0IGhhdmUgdG8gZmFrZSBpdC4gQWNjZXNzIHRvIGEgd2VhbHRo"
    "IG9mIGluZm9ybWF0aW9uLCBjb21iaW5lZCB3aXRoIGEgcnVkaW1lbnRhcnkg"
    "ZGVjaXNpb24tbWFraW5nIGNhcGFjaXR5LCBjYW4gb2Z0ZW4gYmUgYWxtb3N0"
    "IGFzIHVzZWZ1bC4gT2YgY291cnNlLCB0aGUgcmVzdWx0cyBhcmUgYmV0dGVy"
    "IHlldCB3aGVuIGNvdXBsZWQgd2l0aCBpbnRlbGxpZ2VuY2UuIEEgcmVmZXJl"
    "bmNlIGxpYnJhcmlhbiB3aXRoIGFjY2VzcyB0byBhIGdvb2Qgc2VhcmNoIGVu"
    "Z2luZSBpcyBhIGZvcm1pZGFibGUgdG9vbC4gLSBDcmFpZyBTaWx2ZXJzdGVp"
    "biwgU2llbWVucyBQaWN0dXJlcyBvZiB0aGUgRnV0dXJlLCBTcHJpbmcgMjAw"
    "NAo" },

  // Degenerate edge case
  { "",
    "" },
};

TEST(Base64, EscapeAndUnescape) {
  // Check the short strings; this tests the math (and boundaries)
  for (int i = 0; i < sizeof(base64_tests) / sizeof(base64_tests[0]); ++i) {
    char encode_buffer[100];
    int encode_length;
    char decode_buffer[100];
    int decode_length;
    int cypher_length;
    string decode_str;

    const unsigned char* unsigned_plaintext =
      reinterpret_cast<const unsigned char*>(base64_tests[i].plaintext);

    StringPiece plaintext(base64_tests[i].plaintext,
                          base64_tests[i].plain_length);

    cypher_length = strlen(base64_tests[i].cyphertext);

    // The basic escape function:
    memset(encode_buffer, 0, sizeof(encode_buffer));
    encode_length = Base64Escape(unsigned_plaintext,
                                 base64_tests[i].plain_length,
                                 encode_buffer,
                                 sizeof(encode_buffer));
    //    Is it of the expected length?
    EXPECT_EQ(encode_length, cypher_length);
    // Would it have been okay to allocate only CalculateBase64EscapeLen()?
    EXPECT_EQ(CalculateBase64EscapedLen(base64_tests[i].plain_length),
              encode_length);

    //    Is it the expected encoded value?
    ASSERT_STREQ(encode_buffer, base64_tests[i].cyphertext);

    // If we encode it into a buffer of exactly the right length...
    memset(encode_buffer, 0, sizeof(encode_buffer));
    encode_length = Base64Escape(unsigned_plaintext,
                                          base64_tests[i].plain_length,
                                          encode_buffer,
                                          cypher_length);
    //    Is it still of the expected length?
    EXPECT_EQ(encode_length, cypher_length);

    //    And is the value still correct?  (i.e., not losing the last byte)
    EXPECT_STREQ(encode_buffer, base64_tests[i].cyphertext);

    // If we decode it back:
    decode_str.clear();
    EXPECT_TRUE(Base64Unescape(
        StringPiece(encode_buffer, cypher_length), &decode_str));

    //    Is it of the expected length?
    EXPECT_EQ(base64_tests[i].plain_length, decode_str.length());

    //    Is it the expected decoded value?
    EXPECT_EQ(plaintext, decode_str);

    // Let's try with a pre-populated string.
    string encoded("this junk should be ignored");
    Base64Escape(string(base64_tests[i].plaintext,
                        base64_tests[i].plain_length),
                 &encoded);
    EXPECT_EQ(encoded, string(encode_buffer, cypher_length));

    string decoded("this junk should be ignored");
    EXPECT_TRUE(Base64Unescape(
        StringPiece(encode_buffer, cypher_length), &decoded));
    EXPECT_EQ(decoded.size(), base64_tests[i].plain_length);
    EXPECT_EQ_ARRAY(decoded.size(), decoded, base64_tests[i].plaintext, i);

    // Our decoder treats the padding '=' characters at the end as
    // optional (but if there are any, there must be the correct
    // number of them.)  If encode_buffer has any, run some additional
    // tests that fiddle with them.
    char* first_equals = strchr(encode_buffer, '=');
    if (first_equals) {
      // How many equals signs does the string start with?
      int equals = (*(first_equals+1) == '=') ? 2 : 1;

      // Try chopping off the equals sign(s) entirely.  The decoder
      // should still be okay with this.
      string decoded2("this junk should also be ignored");
      *first_equals = '\0';
      EXPECT_TRUE(Base64Unescape(
          StringPiece(encode_buffer, first_equals - encode_buffer), &decoded2));
      EXPECT_EQ(decoded.size(), base64_tests[i].plain_length);
      EXPECT_EQ_ARRAY(decoded.size(), decoded, base64_tests[i].plaintext, i);

      // Now test chopping off the equals sign(s) and adding
      // whitespace.  Our decoder should still accept this.
      decoded2.assign("this junk should be ignored");
      *first_equals = ' ';
      *(first_equals+1) = '\0';
      EXPECT_TRUE(Base64Unescape(
          StringPiece(encode_buffer, first_equals - encode_buffer + 1),
          &decoded2));
      EXPECT_EQ(decoded.size(), base64_tests[i].plain_length);
      EXPECT_EQ_ARRAY(decoded.size(), decoded, base64_tests[i].plaintext, i);

      // Now stick a bad character at the end of the string.  The decoder
      // should refuse this string.
      decoded2.assign("this junk should be ignored");
      *first_equals = '?';
      *(first_equals+1) = '\0';
      EXPECT_TRUE(
          !Base64Unescape(
              StringPiece(encode_buffer, first_equals - encode_buffer + 1),
              &decoded2));

      int len;

      // Test whitespace mixed with the padding.  (eg "AA = = ")  The
      // decoder should accept this.
      if (equals == 2) {
        snprintf(first_equals, 6, " = = ");
        len = first_equals - encode_buffer + 5;
      } else {
        snprintf(first_equals, 6, " = ");
        len = first_equals - encode_buffer + 3;
      }
      decoded2.assign("this junk should be ignored");
      EXPECT_TRUE(
          Base64Unescape(StringPiece(encode_buffer, len), &decoded2));
      EXPECT_EQ(decoded.size(), base64_tests[i].plain_length);
      EXPECT_EQ_ARRAY(decoded.size(), decoded, base64_tests[i].plaintext, i);

      // Test whitespace mixed with the padding, but with the wrong
      // number of equals signs (eg "AA = ").  The decoder should
      // refuse these strings.
      if (equals == 1) {
        snprintf(first_equals, 6, " = = ");
        len = first_equals - encode_buffer + 5;
      } else {
        snprintf(first_equals, 6, " = ");
        len = first_equals - encode_buffer + 3;
      }
      EXPECT_TRUE(
          !Base64Unescape(StringPiece(encode_buffer, len), &decoded2));
    }

    // Cool! the basic Base64 encoder/decoder works.
    // Let's try the alternate alphabet: tr -- '+/' '-_'

    char websafe[100];
    memset(websafe, 0, sizeof(websafe));
    strncpy(websafe, base64_tests[i].cyphertext, cypher_length);
    for (int c = 0; c < sizeof(websafe); ++c) {
      if ('+' == websafe[c]) { websafe[c] = '-'; }
      if ('/' == websafe[c]) { websafe[c] = '_'; }
    }

    // The websafe escape function:
    memset(encode_buffer, 0, sizeof(encode_buffer));
    encode_length = WebSafeBase64Escape(unsigned_plaintext,
                                                 base64_tests[i].plain_length,
                                                 encode_buffer,
                                                 sizeof(encode_buffer),
                                                 true);
    //    Is it of the expected length?
    EXPECT_EQ(encode_length, cypher_length);
    EXPECT_EQ(
        CalculateBase64EscapedLen(base64_tests[i].plain_length, true),
        encode_length);

    //    Is it the expected encoded value?
    EXPECT_STREQ(encode_buffer, websafe);

    //    If we encode it into a buffer of exactly the right length...
    memset(encode_buffer, 0, sizeof(encode_buffer));
    encode_length = WebSafeBase64Escape(unsigned_plaintext,
                                                 base64_tests[i].plain_length,
                                                 encode_buffer,
                                                 cypher_length,
                                                 true);
    //    Is it still of the expected length?
    EXPECT_EQ(encode_length, cypher_length);

    //    And is the value still correct?  (i.e., not losing the last byte)
    EXPECT_STREQ(encode_buffer, websafe);

    //    Let's try the string version of the encoder
    encoded = "this junk should be ignored";
    WebSafeBase64Escape(
        unsigned_plaintext, base64_tests[i].plain_length,
        &encoded, true);
    EXPECT_EQ(encoded.size(), cypher_length);
    EXPECT_STREQ(encoded.c_str(), websafe);

    //    If we decode it back:
    memset(decode_buffer, 0, sizeof(decode_buffer));
    decode_length = WebSafeBase64Unescape(encode_buffer,
                                                   cypher_length,
                                                   decode_buffer,
                                                   sizeof(decode_buffer));

    //    Is it of the expected length?
    EXPECT_EQ(decode_length, base64_tests[i].plain_length);

    //    Is it the expected decoded value?
    EXPECT_EQ(0,
              memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));

    //    If we decode it into a buffer of exactly the right length...
    memset(decode_buffer, 0, sizeof(decode_buffer));
    decode_length = WebSafeBase64Unescape(encode_buffer,
                                                   cypher_length,
                                                   decode_buffer,
                                                   decode_length);

    //    Is it still of the expected length?
    EXPECT_EQ(decode_length, base64_tests[i].plain_length);

    //    And is it the expected decoded value?
    EXPECT_EQ(0,
              memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));

    // Try using '.' for the pad character.
    for (int c = cypher_length - 1; c >= 0 && '=' == encode_buffer[c]; --c) {
      encode_buffer[c] = '.';
    }

    // If we decode it back:
    memset(decode_buffer, 0, sizeof(decode_buffer));
    decode_length = WebSafeBase64Unescape(encode_buffer,
                                                   cypher_length,
                                                   decode_buffer,
                                                   sizeof(decode_buffer));

    // Is it of the expected length?
    EXPECT_EQ(decode_length, base64_tests[i].plain_length);

    // Is it the expected decoded value?
    EXPECT_EQ(0,
              memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));

    // If we decode it into a buffer of exactly the right length...
    memset(decode_buffer, 0, sizeof(decode_buffer));
    decode_length = WebSafeBase64Unescape(encode_buffer,
                                                   cypher_length,
                                                   decode_buffer,
                                                   decode_length);

    // Is it still of the expected length?
    EXPECT_EQ(decode_length, base64_tests[i].plain_length);

    // And is it the expected decoded value?
    EXPECT_EQ(0,
              memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));

    // Let's try the string version of the decoder
    decoded = "this junk should be ignored";
    EXPECT_TRUE(WebSafeBase64Unescape(
        StringPiece(encode_buffer, cypher_length), &decoded));
    EXPECT_EQ(decoded.size(), base64_tests[i].plain_length);
    EXPECT_EQ_ARRAY(decoded.size(), decoded, base64_tests[i].plaintext, i);

    // Okay! the websafe Base64 encoder/decoder works.
    // Let's try the unpadded version

    for (int c = 0; c < sizeof(websafe); ++c) {
      if ('=' == websafe[c]) {
        websafe[c] = '\0';
        cypher_length = c;
        break;
      }
    }

    // The websafe escape function:
    memset(encode_buffer, 0, sizeof(encode_buffer));
    encode_length = WebSafeBase64Escape(unsigned_plaintext,
                                                 base64_tests[i].plain_length,
                                                 encode_buffer,
                                                 sizeof(encode_buffer),
                                                 false);
    //    Is it of the expected length?
    EXPECT_EQ(encode_length, cypher_length);
    EXPECT_EQ(
        CalculateBase64EscapedLen(base64_tests[i].plain_length, false),
        encode_length);

    //    Is it the expected encoded value?
    EXPECT_STREQ(encode_buffer, websafe);

    //    If we encode it into a buffer of exactly the right length...
    memset(encode_buffer, 0, sizeof(encode_buffer));
    encode_length = WebSafeBase64Escape(unsigned_plaintext,
                                                 base64_tests[i].plain_length,
                                                 encode_buffer,
                                                 cypher_length,
                                                 false);
    //    Is it still of the expected length?
    EXPECT_EQ(encode_length, cypher_length);

    //    And is the value still correct?  (i.e., not losing the last byte)
    EXPECT_STREQ(encode_buffer, websafe);

    // Let's try the (other) string version of the encoder
    string plain(base64_tests[i].plaintext, base64_tests[i].plain_length);
    encoded = "this junk should be ignored";
    WebSafeBase64Escape(plain, &encoded);
    EXPECT_EQ(encoded.size(), cypher_length);
    EXPECT_STREQ(encoded.c_str(), websafe);

    //    If we decode it back:
    memset(decode_buffer, 0, sizeof(decode_buffer));
    decode_length = WebSafeBase64Unescape(encode_buffer,
                                                   cypher_length,
                                                   decode_buffer,
                                                   sizeof(decode_buffer));

    //    Is it of the expected length?
    EXPECT_EQ(decode_length, base64_tests[i].plain_length);

    //    Is it the expected decoded value?
    EXPECT_EQ(0,
              memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));

    //    If we decode it into a buffer of exactly the right length...
    memset(decode_buffer, 0, sizeof(decode_buffer));
    decode_length = WebSafeBase64Unescape(encode_buffer,
                                                   cypher_length,
                                                   decode_buffer,
                                                   decode_length);

    //    Is it still of the expected length?
    EXPECT_EQ(decode_length, base64_tests[i].plain_length);

    //    And is it the expected decoded value?
    EXPECT_EQ(0,
              memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));

    // Let's try the string version of the decoder
    decoded = "this junk should be ignored";
    EXPECT_TRUE(WebSafeBase64Unescape(
        StringPiece(encode_buffer, cypher_length), &decoded));
    EXPECT_EQ(decoded.size(), base64_tests[i].plain_length);
    EXPECT_EQ_ARRAY(decoded.size(), decoded, base64_tests[i].plaintext, i);

    // This value works.  Try the next.
  }

  // Now try the long strings, this tests the streaming
  for (int i = 0; i < sizeof(base64_strings) / sizeof(base64_strings[0]);
       ++i) {
    const unsigned char* unsigned_plaintext =
      reinterpret_cast<const unsigned char*>(base64_strings[i].plaintext);
    int plain_length = strlen(base64_strings[i].plaintext);
    int cypher_length = strlen(base64_strings[i].cyphertext);
    vector<char> buffer(cypher_length+1);
    int encode_length = WebSafeBase64Escape(unsigned_plaintext,
                                                     plain_length,
                                                     &buffer[0],
                                                     buffer.size(),
                                                     false);
    EXPECT_EQ(cypher_length, encode_length);
    EXPECT_EQ(
        CalculateBase64EscapedLen(plain_length, false), encode_length);
    buffer[ encode_length ] = '\0';
    EXPECT_STREQ(base64_strings[i].cyphertext, &buffer[0]);
  }

  // Verify the behavior when decoding bad data
  {
    const char* bad_data = "ab-/";
    string buf;
    EXPECT_FALSE(Base64Unescape(StringPiece(bad_data), &buf));
    EXPECT_TRUE(!WebSafeBase64Unescape(bad_data, &buf));
    EXPECT_TRUE(buf.empty());
  }
}

}  // anonymous namespace
}  // namespace protobuf
}  // namespace google


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Author: laszlocsomor@google.com (Laszlo Csomor)
//
// This file contains the declarations for Windows implementations of
// commonly used POSIX functions such as open(2) and access(2), as well
// as macro definitions for flags of these functions.
//
// By including this file you'll redefine open/access/etc. to
// ::google::protobuf::internal::win32::{open/access/etc.}.
// Make sure you don't include a header that attempts to redeclare or
// redefine these functions, that'll lead to confusing compilation
// errors. It's best to #include this file as the last one to ensure that.
//
// This file is only used on Windows, it's empty on other platforms.

#ifndef GOOGLE_PROTOBUF_STUBS_IO_WIN32_H__
#define GOOGLE_PROTOBUF_STUBS_IO_WIN32_H__

#if defined(_WIN32)

#include <string>
#include <google/protobuf/stubs/port.h>

// Compilers on Windows other than MSVC (e.g. Cygwin, MinGW32) define the
// following functions already, except for mkdir.
namespace google {
namespace protobuf {
namespace internal {
namespace win32 {

LIBPROTOBUF_EXPORT FILE* fopen(const char* path, const char* mode);
LIBPROTOBUF_EXPORT int access(const char* path, int mode);
LIBPROTOBUF_EXPORT int chdir(const char* path);
LIBPROTOBUF_EXPORT int close(int fd);
LIBPROTOBUF_EXPORT int dup(int fd);
LIBPROTOBUF_EXPORT int dup2(int fd1, int fd2);
LIBPROTOBUF_EXPORT int mkdir(const char* path, int _mode);
LIBPROTOBUF_EXPORT int open(const char* path, int flags, int mode = 0);
LIBPROTOBUF_EXPORT int read(int fd, void* buffer, size_t size);
LIBPROTOBUF_EXPORT int setmode(int fd, int mode);
LIBPROTOBUF_EXPORT int stat(const char* path, struct _stat* buffer);
LIBPROTOBUF_EXPORT int write(int fd, const void* buffer, size_t size);
LIBPROTOBUF_EXPORT std::wstring testonly_utf8_to_winpath(const char* path);

namespace strings {

// Convert from UTF-16 to Active-Code-Page-encoded or to UTF-8-encoded text.
LIBPROTOBUF_EXPORT bool wcs_to_mbs(
    const wchar_t* s, std::string* out, bool outUtf8);

// Convert from Active-Code-Page-encoded or UTF-8-encoded text to UTF-16.
LIBPROTOBUF_EXPORT bool mbs_to_wcs(
    const char* s, std::wstring* out, bool inUtf8);

// Convert from UTF-8-encoded text to UTF-16.
LIBPROTOBUF_EXPORT bool utf8_to_wcs(const char* input, std::wstring* out);

// Convert from UTF-16-encoded text to UTF-8.
LIBPROTOBUF_EXPORT bool wcs_to_utf8(const wchar_t* input, std::string* out);

}  // namespace strings

}  // namespace win32
}  // namespace internal
}  // namespace protobuf
}  // namespace google

#ifndef W_OK
#define W_OK 02  // not defined by MSVC for whatever reason
#endif

#ifndef F_OK
#define F_OK 00  // not defined by MSVC for whatever reason
#endif

#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif

#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif

#endif  // defined(_WIN32)

#endif  // GOOGLE_PROTOBUF_STUBS_IO_WIN32_H__

mime_type: text/plain


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <google/protobuf/stubs/stringpiece.h>

#include <iterator>
#include <map>
#include <string>
#include <utility>
#include <vector>

#include <google/protobuf/testing/googletest.h>
#include <google/protobuf/stubs/hash.h>
#include <gtest/gtest.h>

namespace google {
namespace protobuf {
namespace {
TEST(StringPiece, Ctor) {
  {
    // Null.
    StringPiece s10;
    EXPECT_TRUE(s10.data() == NULL);
    EXPECT_EQ(0, s10.length());
  }

  {
    // const char* without length.
    const char* hello = "hello";
    StringPiece s20(hello);
    EXPECT_TRUE(s20.data() == hello);
    EXPECT_EQ(5, s20.length());

    // const char* with length.
    StringPiece s21(hello, 4);
    EXPECT_TRUE(s21.data() == hello);
    EXPECT_EQ(4, s21.length());

    // Not recommended, but valid C++
    StringPiece s22(hello, 6);
    EXPECT_TRUE(s22.data() == hello);
    EXPECT_EQ(6, s22.length());
  }

  {
    // std::string.
    std::string hola = "hola";
    StringPiece s30(hola);
    EXPECT_TRUE(s30.data() == hola.data());
    EXPECT_EQ(4, s30.length());

    // std::string with embedded '\0'.
    hola.push_back('\0');
    hola.append("h2");
    hola.push_back('\0');
    StringPiece s31(hola);
    EXPECT_TRUE(s31.data() == hola.data());
    EXPECT_EQ(8, s31.length());
  }

#if defined(HAS_GLOBAL_STRING)
  {
    // ::string
    string bonjour = "bonjour";
    StringPiece s40(bonjour);
    EXPECT_TRUE(s40.data() == bonjour.data());
    EXPECT_EQ(7, s40.length());
  }
#endif

  // TODO(mec): StringPiece(StringPiece x, int pos);
  // TODO(mec): StringPiece(StringPiece x, int pos, int len);
  // TODO(mec): StringPiece(const StringPiece&);
}

TEST(StringPiece, STLComparator) {
  string s1("foo");
  string s2("bar");
  string s3("baz");

  StringPiece p1(s1);
  StringPiece p2(s2);
  StringPiece p3(s3);

  typedef std::map<StringPiece, int> TestMap;
  TestMap map;

  map.insert(std::make_pair(p1, 0));
  map.insert(std::make_pair(p2, 1));
  map.insert(std::make_pair(p3, 2));
  EXPECT_EQ(map.size(), 3);

  TestMap::const_iterator iter = map.begin();
  EXPECT_EQ(iter->second, 1);
  ++iter;
  EXPECT_EQ(iter->second, 2);
  ++iter;
  EXPECT_EQ(iter->second, 0);
  ++iter;
  EXPECT_TRUE(iter == map.end());

  TestMap::iterator new_iter = map.find("zot");
  EXPECT_TRUE(new_iter == map.end());

  new_iter = map.find("bar");
  EXPECT_TRUE(new_iter != map.end());

  map.erase(new_iter);
  EXPECT_EQ(map.size(), 2);

  iter = map.begin();
  EXPECT_EQ(iter->second, 2);
  ++iter;
  EXPECT_EQ(iter->second, 0);
  ++iter;
  EXPECT_TRUE(iter == map.end());
}

TEST(StringPiece, ComparisonOperators) {
#define COMPARE(result, op, x, y) \
  EXPECT_EQ(result, StringPiece((x)) op StringPiece((y))); \
  EXPECT_EQ(result, StringPiece((x)).compare(StringPiece((y))) op 0)

  COMPARE(true, ==, "",   "");
  COMPARE(true, ==, "", NULL);
  COMPARE(true, ==, NULL, "");
  COMPARE(true, ==, "a",  "a");
  COMPARE(true, ==, "aa", "aa");
  COMPARE(false, ==, "a",  "");
  COMPARE(false, ==, "",   "a");
  COMPARE(false, ==, "a",  "b");
  COMPARE(false, ==, "a",  "aa");
  COMPARE(false, ==, "aa", "a");

  COMPARE(false, !=, "",   "");
  COMPARE(false, !=, "a",  "a");
  COMPARE(false, !=, "aa", "aa");
  COMPARE(true, !=, "a",  "");
  COMPARE(true, !=, "",   "a");
  COMPARE(true, !=, "a",  "b");
  COMPARE(true, !=, "a",  "aa");
  COMPARE(true, !=, "aa", "a");

  COMPARE(true, <, "a",  "b");
  COMPARE(true, <, "a",  "aa");
  COMPARE(true, <, "aa", "b");
  COMPARE(true, <, "aa", "bb");
  COMPARE(false, <, "a",  "a");
  COMPARE(false, <, "b",  "a");
  COMPARE(false, <, "aa", "a");
  COMPARE(false, <, "b",  "aa");
  COMPARE(false, <, "bb", "aa");

  COMPARE(true, <=, "a",  "a");
  COMPARE(true, <=, "a",  "b");
  COMPARE(true, <=, "a",  "aa");
  COMPARE(true, <=, "aa", "b");
  COMPARE(true, <=, "aa", "bb");
  COMPARE(false, <=, "b",  "a");
  COMPARE(false, <=, "aa", "a");
  COMPARE(false, <=, "b",  "aa");
  COMPARE(false, <=, "bb", "aa");

  COMPARE(false, >=, "a",  "b");
  COMPARE(false, >=, "a",  "aa");
  COMPARE(false, >=, "aa", "b");
  COMPARE(false, >=, "aa", "bb");
  COMPARE(true, >=, "a",  "a");
  COMPARE(true, >=, "b",  "a");
  COMPARE(true, >=, "aa", "a");
  COMPARE(true, >=, "b",  "aa");
  COMPARE(true, >=, "bb", "aa");

  COMPARE(false, >, "a",  "a");
  COMPARE(false, >, "a",  "b");
  COMPARE(false, >, "a",  "aa");
  COMPARE(false, >, "aa", "b");
  COMPARE(false, >, "aa", "bb");
  COMPARE(true, >, "b",  "a");
  COMPARE(true, >, "aa", "a");
  COMPARE(true, >, "b",  "aa");
  COMPARE(true, >, "bb", "aa");

  string x;
  for (int i = 0; i < 256; i++) {
    x += 'a';
    string y = x;
    COMPARE(true, ==, x, y);
    for (int j = 0; j < i; j++) {
      string z = x;
      z[j] = 'b';       // Differs in position 'j'
      COMPARE(false, ==, x, z);
      COMPARE(true, <, x, z);
      COMPARE(true, >, z, x);
      if (j + 1 < i) {
        z[j + 1] = 'A';  // Differs in position 'j+1' as well
        COMPARE(false, ==, x, z);
        COMPARE(true, <, x, z);
        COMPARE(true, >, z, x);
        z[j + 1] = 'z';  // Differs in position 'j+1' as well
        COMPARE(false, ==, x, z);
        COMPARE(true, <, x, z);
        COMPARE(true, >, z, x);
      }
    }
  }

#undef COMPARE
}

TEST(StringPiece, STL1) {
  const StringPiece a("abcdefghijklmnopqrstuvwxyz");
  const StringPiece b("abc");
  const StringPiece c("xyz");
  const StringPiece d("foobar");
  const StringPiece e;
  string temp("123");
  temp += '\0';
  temp += "456";
  const StringPiece f(temp);

  EXPECT_EQ(a[6], 'g');
  EXPECT_EQ(b[0], 'a');
  EXPECT_EQ(c[2], 'z');
  EXPECT_EQ(f[3], '\0');
  EXPECT_EQ(f[5], '5');

  EXPECT_EQ(*d.data(), 'f');
  EXPECT_EQ(d.data()[5], 'r');
  EXPECT_TRUE(e.data() == NULL);

  EXPECT_EQ(*a.begin(), 'a');
  EXPECT_EQ(*(b.begin() + 2), 'c');
  EXPECT_EQ(*(c.end() - 1), 'z');

  EXPECT_EQ(*a.rbegin(), 'z');
  EXPECT_EQ(*(b.rbegin() + 2), 'a');
  EXPECT_EQ(*(c.rend() - 1), 'x');
  EXPECT_TRUE(a.rbegin() + 26 == a.rend());

  EXPECT_EQ(a.size(), 26);
  EXPECT_EQ(b.size(), 3);
  EXPECT_EQ(c.size(), 3);
  EXPECT_EQ(d.size(), 6);
  EXPECT_EQ(e.size(), 0);
  EXPECT_EQ(f.size(), 7);

  EXPECT_TRUE(!d.empty());
  EXPECT_TRUE(d.begin() != d.end());
  EXPECT_TRUE(d.begin() + 6 == d.end());

  EXPECT_TRUE(e.empty());
  EXPECT_TRUE(e.begin() == e.end());

  EXPECT_GE(a.max_size(), a.capacity());
  EXPECT_GE(a.capacity(), a.size());

  char buf[4] = { '%', '%', '%', '%' };
  EXPECT_EQ(a.copy(buf, 4), 4);
  EXPECT_EQ(buf[0], a[0]);
  EXPECT_EQ(buf[1], a[1]);
  EXPECT_EQ(buf[2], a[2]);
  EXPECT_EQ(buf[3], a[3]);
  EXPECT_EQ(a.copy(buf, 3, 7), 3);
  EXPECT_EQ(buf[0], a[7]);
  EXPECT_EQ(buf[1], a[8]);
  EXPECT_EQ(buf[2], a[9]);
  EXPECT_EQ(buf[3], a[3]);
  EXPECT_EQ(c.copy(buf, 99), 3);
  EXPECT_EQ(buf[0], c[0]);
  EXPECT_EQ(buf[1], c[1]);
  EXPECT_EQ(buf[2], c[2]);
  EXPECT_EQ(buf[3], a[3]);
}

// Separated from STL1() because some compilers produce an overly
// large stack frame for the combined function.
TEST(StringPiece, STL2) {
  const StringPiece a("abcdefghijklmnopqrstuvwxyz");
  const StringPiece b("abc");
  const StringPiece c("xyz");
  StringPiece d("foobar");
  const StringPiece e;
  const StringPiece f("123" "\0" "456", 7);

  d.clear();
  EXPECT_EQ(d.size(), 0);
  EXPECT_TRUE(d.empty());
  EXPECT_TRUE(d.data() == NULL);
  EXPECT_TRUE(d.begin() == d.end());

  EXPECT_EQ(StringPiece::npos, string::npos);

  EXPECT_EQ(a.find(b), 0);
  EXPECT_EQ(a.find(b, 1), StringPiece::npos);
  EXPECT_EQ(a.find(c), 23);
  EXPECT_EQ(a.find(c, 9), 23);
  EXPECT_EQ(a.find(c, StringPiece::npos), StringPiece::npos);
  EXPECT_EQ(b.find(c), StringPiece::npos);
  EXPECT_EQ(b.find(c, StringPiece::npos), StringPiece::npos);
  EXPECT_EQ(a.find(d), 0);
  EXPECT_EQ(a.find(e), 0);
  EXPECT_EQ(a.find(d, 12), 12);
  EXPECT_EQ(a.find(e, 17), 17);
  StringPiece g("xx not found bb");
  EXPECT_EQ(a.find(g), StringPiece::npos);
  // empty string nonsense
  EXPECT_EQ(d.find(b), StringPiece::npos);
  EXPECT_EQ(e.find(b), StringPiece::npos);
  EXPECT_EQ(d.find(b, 4), StringPiece::npos);
  EXPECT_EQ(e.find(b, 7), StringPiece::npos);

  size_t empty_search_pos = string().find(string());
  EXPECT_EQ(d.find(d), empty_search_pos);
  EXPECT_EQ(d.find(e), empty_search_pos);
  EXPECT_EQ(e.find(d), empty_search_pos);
  EXPECT_EQ(e.find(e), empty_search_pos);
  EXPECT_EQ(d.find(d, 4), string().find(string(), 4));
  EXPECT_EQ(d.find(e, 4), string().find(string(), 4));
  EXPECT_EQ(e.find(d, 4), string().find(string(), 4));
  EXPECT_EQ(e.find(e, 4), string().find(string(), 4));

  EXPECT_EQ(a.find('a'), 0);
  EXPECT_EQ(a.find('c'), 2);
  EXPECT_EQ(a.find('z'), 25);
  EXPECT_EQ(a.find('$'), StringPiece::npos);
  EXPECT_EQ(a.find('\0'), StringPiece::npos);
  EXPECT_EQ(f.find('\0'), 3);
  EXPECT_EQ(f.find('3'), 2);
  EXPECT_EQ(f.find('5'), 5);
  EXPECT_EQ(g.find('o'), 4);
  EXPECT_EQ(g.find('o', 4), 4);
  EXPECT_EQ(g.find('o', 5), 8);
  EXPECT_EQ(a.find('b', 5), StringPiece::npos);
  // empty string nonsense
  EXPECT_EQ(d.find('\0'), StringPiece::npos);
  EXPECT_EQ(e.find('\0'), StringPiece::npos);
  EXPECT_EQ(d.find('\0', 4), StringPiece::npos);
  EXPECT_EQ(e.find('\0', 7), StringPiece::npos);
  EXPECT_EQ(d.find('x'), StringPiece::npos);
  EXPECT_EQ(e.find('x'), StringPiece::npos);
  EXPECT_EQ(d.find('x', 4), StringPiece::npos);
  EXPECT_EQ(e.find('x', 7), StringPiece::npos);

  EXPECT_EQ(a.rfind(b), 0);
  EXPECT_EQ(a.rfind(b, 1), 0);
  EXPECT_EQ(a.rfind(c), 23);
  EXPECT_EQ(a.rfind(c, 22), StringPiece::npos);
  EXPECT_EQ(a.rfind(c, 1), StringPiece::npos);
  EXPECT_EQ(a.rfind(c, 0), StringPiece::npos);
  EXPECT_EQ(b.rfind(c), StringPiece::npos);
  EXPECT_EQ(b.rfind(c, 0), StringPiece::npos);
  EXPECT_EQ(a.rfind(d), a.as_string().rfind(string()));
  EXPECT_EQ(a.rfind(e), a.as_string().rfind(string()));
  EXPECT_EQ(a.rfind(d, 12), 12);
  EXPECT_EQ(a.rfind(e, 17), 17);
  EXPECT_EQ(a.rfind(g), StringPiece::npos);
  EXPECT_EQ(d.rfind(b), StringPiece::npos);
  EXPECT_EQ(e.rfind(b), StringPiece::npos);
  EXPECT_EQ(d.rfind(b, 4), StringPiece::npos);
  EXPECT_EQ(e.rfind(b, 7), StringPiece::npos);
  // empty string nonsense
  EXPECT_EQ(d.rfind(d, 4), string().rfind(string()));
  EXPECT_EQ(e.rfind(d, 7), string().rfind(string()));
  EXPECT_EQ(d.rfind(e, 4), string().rfind(string()));
  EXPECT_EQ(e.rfind(e, 7), string().rfind(string()));
  EXPECT_EQ(d.rfind(d), string().rfind(string()));
  EXPECT_EQ(e.rfind(d), string().rfind(string()));
  EXPECT_EQ(d.rfind(e), string().rfind(string()));
  EXPECT_EQ(e.rfind(e), string().rfind(string()));

  EXPECT_EQ(g.rfind('o'), 8);
  EXPECT_EQ(g.rfind('q'), StringPiece::npos);
  EXPECT_EQ(g.rfind('o', 8), 8);
  EXPECT_EQ(g.rfind('o', 7), 4);
  EXPECT_EQ(g.rfind('o', 3), StringPiece::npos);
  EXPECT_EQ(f.rfind('\0'), 3);
  EXPECT_EQ(f.rfind('\0', 12), 3);
  EXPECT_EQ(f.rfind('3'), 2);
  EXPECT_EQ(f.rfind('5'), 5);
  // empty string nonsense
  EXPECT_EQ(d.rfind('o'), StringPiece::npos);
  EXPECT_EQ(e.rfind('o'), StringPiece::npos);
  EXPECT_EQ(d.rfind('o', 4), StringPiece::npos);
  EXPECT_EQ(e.rfind('o', 7), StringPiece::npos);

  EXPECT_EQ(a.find_first_of(b), 0);
  EXPECT_EQ(a.find_first_of(b, 0), 0);
  EXPECT_EQ(a.find_first_of(b, 1), 1);
  EXPECT_EQ(a.find_first_of(b, 2), 2);
  EXPECT_EQ(a.find_first_of(b, 3), StringPiece::npos);
  EXPECT_EQ(a.find_first_of(c), 23);
  EXPECT_EQ(a.find_first_of(c, 23), 23);
  EXPECT_EQ(a.find_first_of(c, 24), 24);
  EXPECT_EQ(a.find_first_of(c, 25), 25);
  EXPECT_EQ(a.find_first_of(c, 26), StringPiece::npos);
  EXPECT_EQ(g.find_first_of(b), 13);
  EXPECT_EQ(g.find_first_of(c), 0);
  EXPECT_EQ(a.find_first_of(f), StringPiece::npos);
  EXPECT_EQ(f.find_first_of(a), StringPiece::npos);
  // empty string nonsense
  EXPECT_EQ(a.find_first_of(d), StringPiece::npos);
  EXPECT_EQ(a.find_first_of(e), StringPiece::npos);
  EXPECT_EQ(d.find_first_of(b), StringPiece::npos);
  EXPECT_EQ(e.find_first_of(b), StringPiece::npos);
  EXPECT_EQ(d.find_first_of(d), StringPiece::npos);
  EXPECT_EQ(e.find_first_of(d), StringPiece::npos);
  EXPECT_EQ(d.find_first_of(e), StringPiece::npos);
  EXPECT_EQ(e.find_first_of(e), StringPiece::npos);

  EXPECT_EQ(a.find_first_not_of(b), 3);
  EXPECT_EQ(a.find_first_not_of(c), 0);
  EXPECT_EQ(b.find_first_not_of(a), StringPiece::npos);
  EXPECT_EQ(c.find_first_not_of(a), StringPiece::npos);
  EXPECT_EQ(f.find_first_not_of(a), 0);
  EXPECT_EQ(a.find_first_not_of(f), 0);
  EXPECT_EQ(a.find_first_not_of(d), 0);
  EXPECT_EQ(a.find_first_not_of(e), 0);
  // empty string nonsense
  EXPECT_EQ(d.find_first_not_of(a), StringPiece::npos);
  EXPECT_EQ(e.find_first_not_of(a), StringPiece::npos);
  EXPECT_EQ(d.find_first_not_of(d), StringPiece::npos);
  EXPECT_EQ(e.find_first_not_of(d), StringPiece::npos);
  EXPECT_EQ(d.find_first_not_of(e), StringPiece::npos);
  EXPECT_EQ(e.find_first_not_of(e), StringPiece::npos);

  StringPiece h("====");
  EXPECT_EQ(h.find_first_not_of('='), StringPiece::npos);
  EXPECT_EQ(h.find_first_not_of('=', 3), StringPiece::npos);
  EXPECT_EQ(h.find_first_not_of('\0'), 0);
  EXPECT_EQ(g.find_first_not_of('x'), 2);
  EXPECT_EQ(f.find_first_not_of('\0'), 0);
  EXPECT_EQ(f.find_first_not_of('\0', 3), 4);
  EXPECT_EQ(f.find_first_not_of('\0', 2), 2);
  // empty string nonsense
  EXPECT_EQ(d.find_first_not_of('x'), StringPiece::npos);
  EXPECT_EQ(e.find_first_not_of('x'), StringPiece::npos);
  EXPECT_EQ(d.find_first_not_of('\0'), StringPiece::npos);
  EXPECT_EQ(e.find_first_not_of('\0'), StringPiece::npos);

  //  StringPiece g("xx not found bb");
  StringPiece i("56");
  EXPECT_EQ(h.find_last_of(a), StringPiece::npos);
  EXPECT_EQ(g.find_last_of(a), g.size()-1);
  EXPECT_EQ(a.find_last_of(b), 2);
  EXPECT_EQ(a.find_last_of(c), a.size()-1);
  EXPECT_EQ(f.find_last_of(i), 6);
  EXPECT_EQ(a.find_last_of('a'), 0);
  EXPECT_EQ(a.find_last_of('b'), 1);
  EXPECT_EQ(a.find_last_of('z'), 25);
  EXPECT_EQ(a.find_last_of('a', 5), 0);
  EXPECT_EQ(a.find_last_of('b', 5), 1);
  EXPECT_EQ(a.find_last_of('b', 0), StringPiece::npos);
  EXPECT_EQ(a.find_last_of('z', 25), 25);
  EXPECT_EQ(a.find_last_of('z', 24), StringPiece::npos);
  EXPECT_EQ(f.find_last_of(i, 5), 5);
  EXPECT_EQ(f.find_last_of(i, 6), 6);
  EXPECT_EQ(f.find_last_of(a, 4), StringPiece::npos);
  // empty string nonsense
  EXPECT_EQ(f.find_last_of(d), StringPiece::npos);
  EXPECT_EQ(f.find_last_of(e), StringPiece::npos);
  EXPECT_EQ(f.find_last_of(d, 4), StringPiece::npos);
  EXPECT_EQ(f.find_last_of(e, 4), StringPiece::npos);
  EXPECT_EQ(d.find_last_of(d), StringPiece::npos);
  EXPECT_EQ(d.find_last_of(e), StringPiece::npos);
  EXPECT_EQ(e.find_last_of(d), StringPiece::npos);
  EXPECT_EQ(e.find_last_of(e), StringPiece::npos);
  EXPECT_EQ(d.find_last_of(f), StringPiece::npos);
  EXPECT_EQ(e.find_last_of(f), StringPiece::npos);
  EXPECT_EQ(d.find_last_of(d, 4), StringPiece::npos);
  EXPECT_EQ(d.find_last_of(e, 4), StringPiece::npos);
  EXPECT_EQ(e.find_last_of(d, 4), StringPiece::npos);
  EXPECT_EQ(e.find_last_of(e, 4), StringPiece::npos);
  EXPECT_EQ(d.find_last_of(f, 4), StringPiece::npos);
  EXPECT_EQ(e.find_last_of(f, 4), StringPiece::npos);

  EXPECT_EQ(a.find_last_not_of(b), a.size()-1);
  EXPECT_EQ(a.find_last_not_of(c), 22);
  EXPECT_EQ(b.find_last_not_of(a), StringPiece::npos);
  EXPECT_EQ(b.find_last_not_of(b), StringPiece::npos);
  EXPECT_EQ(f.find_last_not_of(i), 4);
  EXPECT_EQ(a.find_last_not_of(c, 24), 22);
  EXPECT_EQ(a.find_last_not_of(b, 3), 3);
  EXPECT_EQ(a.find_last_not_of(b, 2), StringPiece::npos);
  // empty string nonsense
  EXPECT_EQ(f.find_last_not_of(d), f.size()-1);
  EXPECT_EQ(f.find_last_not_of(e), f.size()-1);
  EXPECT_EQ(f.find_last_not_of(d, 4), 4);
  EXPECT_EQ(f.find_last_not_of(e, 4), 4);
  EXPECT_EQ(d.find_last_not_of(d), StringPiece::npos);
  EXPECT_EQ(d.find_last_not_of(e), StringPiece::npos);
  EXPECT_EQ(e.find_last_not_of(d), StringPiece::npos);
  EXPECT_EQ(e.find_last_not_of(e), StringPiece::npos);
  EXPECT_EQ(d.find_last_not_of(f), StringPiece::npos);
  EXPECT_EQ(e.find_last_not_of(f), StringPiece::npos);
  EXPECT_EQ(d.find_last_not_of(d, 4), StringPiece::npos);
  EXPECT_EQ(d.find_last_not_of(e, 4), StringPiece::npos);
  EXPECT_EQ(e.find_last_not_of(d, 4), StringPiece::npos);
  EXPECT_EQ(e.find_last_not_of(e, 4), StringPiece::npos);
  EXPECT_EQ(d.find_last_not_of(f, 4), StringPiece::npos);
  EXPECT_EQ(e.find_last_not_of(f, 4), StringPiece::npos);

  EXPECT_EQ(h.find_last_not_of('x'), h.size() - 1);
  EXPECT_EQ(h.find_last_not_of('='), StringPiece::npos);
  EXPECT_EQ(b.find_last_not_of('c'), 1);
  EXPECT_EQ(h.find_last_not_of('x', 2), 2);
  EXPECT_EQ(h.find_last_not_of('=', 2), StringPiece::npos);
  EXPECT_EQ(b.find_last_not_of('b', 1), 0);
  // empty string nonsense
  EXPECT_EQ(d.find_last_not_of('x'), StringPiece::npos);
  EXPECT_EQ(e.find_last_not_of('x'), StringPiece::npos);
  EXPECT_EQ(d.find_last_not_of('\0'), StringPiece::npos);
  EXPECT_EQ(e.find_last_not_of('\0'), StringPiece::npos);

  EXPECT_EQ(a.substr(0, 3), b);
  EXPECT_EQ(a.substr(23), c);
  EXPECT_EQ(a.substr(23, 3), c);
  EXPECT_EQ(a.substr(23, 99), c);
  EXPECT_EQ(a.substr(0), a);
  EXPECT_EQ(a.substr(3, 2), "de");
  // empty string nonsense
  EXPECT_EQ(a.substr(99, 2), e);
  EXPECT_EQ(d.substr(99), e);
  EXPECT_EQ(d.substr(0, 99), e);
  EXPECT_EQ(d.substr(99, 99), e);
  // use of npos
  EXPECT_EQ(a.substr(0, StringPiece::npos), a);
  EXPECT_EQ(a.substr(23, StringPiece::npos), c);
  EXPECT_EQ(a.substr(StringPiece::npos, 0), e);
  EXPECT_EQ(a.substr(StringPiece::npos, 1), e);
  EXPECT_EQ(a.substr(StringPiece::npos, StringPiece::npos), e);

  // Substring constructors.
  EXPECT_EQ(StringPiece(a, 0, 3), b);
  EXPECT_EQ(StringPiece(a, 23), c);
  EXPECT_EQ(StringPiece(a, 23, 3), c);
  EXPECT_EQ(StringPiece(a, 23, 99), c);
  EXPECT_EQ(StringPiece(a, 0), a);
  EXPECT_EQ(StringPiece(a, 3, 2), "de");
  // empty string nonsense
  EXPECT_EQ(StringPiece(d, 0, 99), e);
  // Verify that they work taking an actual string, not just a StringPiece.
  string a2 = a.as_string();
  EXPECT_EQ(StringPiece(a2, 0, 3), b);
  EXPECT_EQ(StringPiece(a2, 23), c);
  EXPECT_EQ(StringPiece(a2, 23, 3), c);
  EXPECT_EQ(StringPiece(a2, 23, 99), c);
  EXPECT_EQ(StringPiece(a2, 0), a);
  EXPECT_EQ(StringPiece(a2, 3, 2), "de");
}

TEST(StringPiece, Custom) {
  StringPiece a("foobar");
  string s1("123");
  s1 += '\0';
  s1 += "456";
  StringPiece b(s1);
  StringPiece e;
  string s2;

  // CopyToString
  a.CopyToString(&s2);
  EXPECT_EQ(s2.size(), 6);
  EXPECT_EQ(s2, "foobar");
  b.CopyToString(&s2);
  EXPECT_EQ(s2.size(), 7);
  EXPECT_EQ(s1, s2);
  e.CopyToString(&s2);
  EXPECT_TRUE(s2.empty());

  // AppendToString
  s2.erase();
  a.AppendToString(&s2);
  EXPECT_EQ(s2.size(), 6);
  EXPECT_EQ(s2, "foobar");
  a.AppendToString(&s2);
  EXPECT_EQ(s2.size(), 12);
  EXPECT_EQ(s2, "foobarfoobar");

  // starts_with
  EXPECT_TRUE(a.starts_with(a));
  EXPECT_TRUE(a.starts_with("foo"));
  EXPECT_TRUE(a.starts_with(e));
  EXPECT_TRUE(b.starts_with(s1));
  EXPECT_TRUE(b.starts_with(b));
  EXPECT_TRUE(b.starts_with(e));
  EXPECT_TRUE(e.starts_with(""));
  EXPECT_TRUE(!a.starts_with(b));
  EXPECT_TRUE(!b.starts_with(a));
  EXPECT_TRUE(!e.starts_with(a));

  // ends with
  EXPECT_TRUE(a.ends_with(a));
  EXPECT_TRUE(a.ends_with("bar"));
  EXPECT_TRUE(a.ends_with(e));
  EXPECT_TRUE(b.ends_with(s1));
  EXPECT_TRUE(b.ends_with(b));
  EXPECT_TRUE(b.ends_with(e));
  EXPECT_TRUE(e.ends_with(""));
  EXPECT_TRUE(!a.ends_with(b));
  EXPECT_TRUE(!b.ends_with(a));
  EXPECT_TRUE(!e.ends_with(a));

  // remove_prefix
  StringPiece c(a);
  c.remove_prefix(3);
  EXPECT_EQ(c, "bar");
  c = a;
  c.remove_prefix(0);
  EXPECT_EQ(c, a);
  c.remove_prefix(c.size());
  EXPECT_EQ(c, e);

  // remove_suffix
  c = a;
  c.remove_suffix(3);
  EXPECT_EQ(c, "foo");
  c = a;
  c.remove_suffix(0);
  EXPECT_EQ(c, a);
  c.remove_suffix(c.size());
  EXPECT_EQ(c, e);

  // set
  c.set("foobar", 6);
  EXPECT_EQ(c, a);
  c.set("foobar", 0);
  EXPECT_EQ(c, e);
  c.set("foobar", 7);
  EXPECT_NE(c, a);

  c.set("foobar");
  EXPECT_EQ(c, a);

  c.set(static_cast<const void*>("foobar"), 6);
  EXPECT_EQ(c, a);
  c.set(static_cast<const void*>("foobar"), 0);
  EXPECT_EQ(c, e);
  c.set(static_cast<const void*>("foobar"), 7);
  EXPECT_NE(c, a);

  // as_string
  string s3(a.as_string().c_str(), 7);
  EXPECT_EQ(c, s3);
  string s4(e.as_string());
  EXPECT_TRUE(s4.empty());

  // ToString
  {
    string s5(a.ToString().c_str(), 7);
    EXPECT_EQ(c, s5);
    string s6(e.ToString());
    EXPECT_TRUE(s6.empty());
  }

  // Consume
  a.set("foobar");
  EXPECT_TRUE(a.Consume("foo"));
  EXPECT_EQ(a, "bar");
  EXPECT_FALSE(a.Consume("foo"));
  EXPECT_FALSE(a.Consume("barbar"));
  EXPECT_FALSE(a.Consume("ar"));
  EXPECT_EQ(a, "bar");

  a.set("foobar");
  EXPECT_TRUE(a.ConsumeFromEnd("bar"));
  EXPECT_EQ(a, "foo");
  EXPECT_FALSE(a.ConsumeFromEnd("bar"));
  EXPECT_FALSE(a.ConsumeFromEnd("foofoo"));
  EXPECT_FALSE(a.ConsumeFromEnd("fo"));
  EXPECT_EQ(a, "foo");
}

TEST(StringPiece, Contains) {
  StringPiece a("abcdefg");
  StringPiece b("abcd");
  StringPiece c("efg");
  StringPiece d("gh");
  EXPECT_TRUE(a.contains(b));
  EXPECT_TRUE(a.contains(c));
  EXPECT_TRUE(!a.contains(d));
}

TEST(StringPiece, NULLInput) {
  // we used to crash here, but now we don't.
  StringPiece s(NULL);
  EXPECT_EQ(s.data(), (const char*)NULL);
  EXPECT_EQ(s.size(), 0);

  s.set(NULL);
  EXPECT_EQ(s.data(), (const char*)NULL);
  EXPECT_EQ(s.size(), 0);

  // .ToString() on a StringPiece with NULL should produce the empty string.
  EXPECT_EQ("", s.ToString());
  EXPECT_EQ("", s.as_string());
}

TEST(StringPiece, Comparisons2) {
  StringPiece abc("abcdefghijklmnopqrstuvwxyz");

  // check comparison operations on strings longer than 4 bytes.
  EXPECT_EQ(abc, StringPiece("abcdefghijklmnopqrstuvwxyz"));
  EXPECT_EQ(abc.compare(StringPiece("abcdefghijklmnopqrstuvwxyz")), 0);

  EXPECT_LT(abc, StringPiece("abcdefghijklmnopqrstuvwxzz"));
  EXPECT_LT(abc.compare(StringPiece("abcdefghijklmnopqrstuvwxzz")), 0);

  EXPECT_GT(abc, StringPiece("abcdefghijklmnopqrstuvwxyy"));
  EXPECT_GT(abc.compare(StringPiece("abcdefghijklmnopqrstuvwxyy")), 0);

  // starts_with
  EXPECT_TRUE(abc.starts_with(abc));
  EXPECT_TRUE(abc.starts_with("abcdefghijklm"));
  EXPECT_TRUE(!abc.starts_with("abcdefguvwxyz"));

  // ends_with
  EXPECT_TRUE(abc.ends_with(abc));
  EXPECT_TRUE(!abc.ends_with("abcdefguvwxyz"));
  EXPECT_TRUE(abc.ends_with("nopqrstuvwxyz"));
}

TEST(ComparisonOpsTest, StringCompareNotAmbiguous) {
  EXPECT_EQ("hello", string("hello"));
  EXPECT_LT("hello", string("world"));
}

TEST(ComparisonOpsTest, HeterogenousStringPieceEquals) {
  EXPECT_EQ(StringPiece("hello"), string("hello"));
  EXPECT_EQ("hello", StringPiece("hello"));
}

TEST(FindOneCharTest, EdgeCases) {
  StringPiece a("xxyyyxx");

  // Set a = "xyyyx".
  a.remove_prefix(1);
  a.remove_suffix(1);

  EXPECT_EQ(0, a.find('x'));
  EXPECT_EQ(0, a.find('x', 0));
  EXPECT_EQ(4, a.find('x', 1));
  EXPECT_EQ(4, a.find('x', 4));
  EXPECT_EQ(StringPiece::npos, a.find('x', 5));

  EXPECT_EQ(4, a.rfind('x'));
  EXPECT_EQ(4, a.rfind('x', 5));
  EXPECT_EQ(4, a.rfind('x', 4));
  EXPECT_EQ(0, a.rfind('x', 3));
  EXPECT_EQ(0, a.rfind('x', 0));

  // Set a = "yyy".
  a.remove_prefix(1);
  a.remove_suffix(1);

  EXPECT_EQ(StringPiece::npos, a.find('x'));
  EXPECT_EQ(StringPiece::npos, a.rfind('x'));
}

#ifdef PROTOBUF_HAS_DEATH_TEST
#ifndef NDEBUG
TEST(NonNegativeLenTest, NonNegativeLen) {
  EXPECT_DEATH(StringPiece("xyz", -1), "len >= 0");
}
#endif  // ndef DEBUG
#endif  // PROTOBUF_HAS_DEATH_TEST

}  // namespace
}  // namespace protobuf
}  // namespace google


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2014 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Fast memory copying and comparison routines.
//   strings::fastmemcmp_inlined() replaces memcmp()
//   strings::memcpy_inlined() replaces memcpy()
//   strings::memeq(a, b, n) replaces memcmp(a, b, n) == 0
//
// strings::*_inlined() routines are inline versions of the
// routines exported by this module.  Sometimes using the inlined
// versions is faster.  Measure before using the inlined versions.
//
// Performance measurement:
//   strings::fastmemcmp_inlined
//     Analysis: memcmp, fastmemcmp_inlined, fastmemcmp
//     2012-01-30

#ifndef GOOGLE_PROTOBUF_STUBS_FASTMEM_H_
#define GOOGLE_PROTOBUF_STUBS_FASTMEM_H_

#include <stddef.h>
#include <stdio.h>
#include <string.h>

#include <google/protobuf/stubs/common.h>

namespace google {
namespace protobuf {
namespace internal {

// Return true if the n bytes at a equal the n bytes at b.
// The regions are allowed to overlap.
//
// The performance is similar to the performance memcmp(), but faster for
// moderately-sized inputs, or inputs that share a common prefix and differ
// somewhere in their last 8 bytes. Further optimizations can be added later
// if it makes sense to do so.:w
inline bool memeq(const char* a, const char* b, size_t n) {
  size_t n_rounded_down = n & ~static_cast<size_t>(7);
  if (GOOGLE_PREDICT_FALSE(n_rounded_down == 0)) {  // n <= 7
    return memcmp(a, b, n) == 0;
  }
  // n >= 8
  uint64 u = GOOGLE_UNALIGNED_LOAD64(a) ^ GOOGLE_UNALIGNED_LOAD64(b);
  uint64 v = GOOGLE_UNALIGNED_LOAD64(a + n - 8) ^ GOOGLE_UNALIGNED_LOAD64(b + n - 8);
  if ((u | v) != 0) {  // The first or last 8 bytes differ.
    return false;
  }
  a += 8;
  b += 8;
  n = n_rounded_down - 8;
  if (n > 128) {
    // As of 2012, memcmp on x86-64 uses a big unrolled loop with SSE2
    // instructions, and while we could try to do something faster, it
    // doesn't seem worth pursuing.
    return memcmp(a, b, n) == 0;
  }
  for (; n >= 16; n -= 16) {
    uint64 x = GOOGLE_UNALIGNED_LOAD64(a) ^ GOOGLE_UNALIGNED_LOAD64(b);
    uint64 y = GOOGLE_UNALIGNED_LOAD64(a + 8) ^ GOOGLE_UNALIGNED_LOAD64(b + 8);
    if ((x | y) != 0) {
      return false;
    }
    a += 16;
    b += 16;
  }
  // n must be 0 or 8 now because it was a multiple of 8 at the top of the loop.
  return n == 0 || GOOGLE_UNALIGNED_LOAD64(a) == GOOGLE_UNALIGNED_LOAD64(b);
}

inline int fastmemcmp_inlined(const char *a, const char *b, size_t n) {
  if (n >= 64) {
    return memcmp(a, b, n);
  }
  const char* a_limit = a + n;
  while (a + sizeof(uint64) <= a_limit &&
         GOOGLE_UNALIGNED_LOAD64(a) == GOOGLE_UNALIGNED_LOAD64(b)) {
    a += sizeof(uint64);
    b += sizeof(uint64);
  }
  if (a + sizeof(uint32) <= a_limit &&
      GOOGLE_UNALIGNED_LOAD32(a) == GOOGLE_UNALIGNED_LOAD32(b)) {
    a += sizeof(uint32);
    b += sizeof(uint32);
  }
  while (a < a_limit) {
    int d =
        static_cast<int>(static_cast<uint32>(*a++) - static_cast<uint32>(*b++));
    if (d) return d;
  }
  return 0;
}

// The standard memcpy operation is slow for variable small sizes.
// This implementation inlines the optimal realization for sizes 1 to 16.
// To avoid code bloat don't use it in case of not performance-critical spots,
// nor when you don't expect very frequent values of size <= 16.
inline void memcpy_inlined(char *dst, const char *src, size_t size) {
  // Compiler inlines code with minimal amount of data movement when third
  // parameter of memcpy is a constant.
  switch (size) {
    case  1: memcpy(dst, src, 1); break;
    case  2: memcpy(dst, src, 2); break;
    case  3: memcpy(dst, src, 3); break;
    case  4: memcpy(dst, src, 4); break;
    case  5: memcpy(dst, src, 5); break;
    case  6: memcpy(dst, src, 6); break;
    case  7: memcpy(dst, src, 7); break;
    case  8: memcpy(dst, src, 8); break;
    case  9: memcpy(dst, src, 9); break;
    case 10: memcpy(dst, src, 10); break;
    case 11: memcpy(dst, src, 11); break;
    case 12: memcpy(dst, src, 12); break;
    case 13: memcpy(dst, src, 13); break;
    case 14: memcpy(dst, src, 14); break;
    case 15: memcpy(dst, src, 15); break;
    case 16: memcpy(dst, src, 16); break;
    default: memcpy(dst, src, size); break;
  }
}

}  // namespace internal
}  // namespace protobuf
}  // namespace google

#endif  // GOOGLE_PROTOBUF_STUBS_FASTMEM_H_


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <google/protobuf/stubs/time.h>

#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>

namespace google {
namespace protobuf {
namespace internal {
namespace {
static const int64 kSecondsPerDay = 3600 * 24;

// For DateTime, tests will mostly focuse on the date part because that's
// the tricky one.
int64 CreateTimestamp(int year, int month, int day) {
  DateTime time;
  time.year = year;
  time.month = month;
  time.day = day;
  time.hour = time.minute = time.second = 0;
  int64 result;
  GOOGLE_CHECK(DateTimeToSeconds(time, &result));
  // Check that a roundtrip produces the same result.
  GOOGLE_CHECK(SecondsToDateTime(result, &time));
  GOOGLE_CHECK(time.year == year);
  GOOGLE_CHECK(time.month == month);
  GOOGLE_CHECK(time.day == day);
  return result;
}

TEST(DateTimeTest, SimpleTime) {
  DateTime time;
  ASSERT_TRUE(SecondsToDateTime(1, &time));
  EXPECT_EQ(1970, time.year);
  EXPECT_EQ(1, time.month);
  EXPECT_EQ(1, time.day);
  EXPECT_EQ(0, time.hour);
  EXPECT_EQ(0, time.minute);
  EXPECT_EQ(1, time.second);
  int64 seconds;
  ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
  EXPECT_EQ(1, seconds);

  ASSERT_TRUE(SecondsToDateTime(-1, &time));
  EXPECT_EQ(1969, time.year);
  EXPECT_EQ(12, time.month);
  EXPECT_EQ(31, time.day);
  EXPECT_EQ(23, time.hour);
  EXPECT_EQ(59, time.minute);
  EXPECT_EQ(59, time.second);
  ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
  EXPECT_EQ(-1, seconds);

  DateTime start, end;
  start.year = 1;
  start.month = 1;
  start.day = 1;
  start.hour = 0;
  start.minute = 0;
  start.second = 0;
  end.year = 9999;
  end.month = 12;
  end.day = 31;
  end.hour = 23;
  end.minute = 59;
  end.second = 59;
  int64 start_time, end_time;
  ASSERT_TRUE(DateTimeToSeconds(start, &start_time));
  ASSERT_TRUE(DateTimeToSeconds(end, &end_time));
  EXPECT_EQ(315537897599LL, end_time - start_time);
  ASSERT_TRUE(SecondsToDateTime(start_time, &time));
  ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
  EXPECT_EQ(start_time, seconds);
  ASSERT_TRUE(SecondsToDateTime(end_time, &time));
  ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
  EXPECT_EQ(end_time, seconds);
}

TEST(DateTimeTest, DayInMonths) {
  // Check that month boundaries are handled correctly.
  EXPECT_EQ(kSecondsPerDay,
            CreateTimestamp(2015, 1, 1) - CreateTimestamp(2014, 12, 31));
  EXPECT_EQ(kSecondsPerDay,
            CreateTimestamp(2015, 2, 1) - CreateTimestamp(2015, 1, 31));
  EXPECT_EQ(kSecondsPerDay,
            CreateTimestamp(2015, 3, 1) - CreateTimestamp(2015, 2, 28));
  EXPECT_EQ(kSecondsPerDay,
            CreateTimestamp(2015, 4, 1) - CreateTimestamp(2015, 3, 31));
  EXPECT_EQ(kSecondsPerDay,
            CreateTimestamp(2015, 5, 1) - CreateTimestamp(2015, 4, 30));
  EXPECT_EQ(kSecondsPerDay,
            CreateTimestamp(2015, 6, 1) - CreateTimestamp(2015, 5, 31));
  EXPECT_EQ(kSecondsPerDay,
            CreateTimestamp(2015, 7, 1) - CreateTimestamp(2015, 6, 30));
  EXPECT_EQ(kSecondsPerDay,
            CreateTimestamp(2015, 8, 1) - CreateTimestamp(2015, 7, 31));
  EXPECT_EQ(kSecondsPerDay,
            CreateTimestamp(2015, 9, 1) - CreateTimestamp(2015, 8, 31));
  EXPECT_EQ(kSecondsPerDay,
            CreateTimestamp(2015, 10, 1) - CreateTimestamp(2015, 9, 30));
  EXPECT_EQ(kSecondsPerDay,
            CreateTimestamp(2015, 11, 1) - CreateTimestamp(2015, 10, 31));
  EXPECT_EQ(kSecondsPerDay,
            CreateTimestamp(2015, 12, 1) - CreateTimestamp(2015, 11, 30));
  EXPECT_EQ(kSecondsPerDay,
            CreateTimestamp(2016, 1, 1) - CreateTimestamp(2015, 12, 31));
}

TEST(DateTimeTest, LeapYear) {
  // Non-leap year.
  EXPECT_EQ(kSecondsPerDay,
            CreateTimestamp(2015, 3, 1) - CreateTimestamp(2015, 2, 28));
  // Leap year.
  EXPECT_EQ(kSecondsPerDay,
            CreateTimestamp(2016, 3, 1) - CreateTimestamp(2016, 2, 29));
  // Non-leap year.
  EXPECT_EQ(kSecondsPerDay,
            CreateTimestamp(2100, 3, 1) - CreateTimestamp(2100, 2, 28));
  // Leap year.
  EXPECT_EQ(kSecondsPerDay,
            CreateTimestamp(2400, 3, 1) - CreateTimestamp(2400, 2, 29));
}

TEST(DateTimeTest, StringFormat) {
  DateTime start, end;
  start.year = 1;
  start.month = 1;
  start.day = 1;
  start.hour = 0;
  start.minute = 0;
  start.second = 0;
  end.year = 9999;
  end.month = 12;
  end.day = 31;
  end.hour = 23;
  end.minute = 59;
  end.second = 59;
  int64 start_time, end_time;
  ASSERT_TRUE(DateTimeToSeconds(start, &start_time));
  ASSERT_TRUE(DateTimeToSeconds(end, &end_time));

  EXPECT_EQ("0001-01-01T00:00:00Z", FormatTime(start_time, 0));
  EXPECT_EQ("9999-12-31T23:59:59Z", FormatTime(end_time, 0));

  // Make sure the nanoseconds part is formated correctly.
  EXPECT_EQ("1970-01-01T00:00:00.010Z", FormatTime(0, 10000000));
  EXPECT_EQ("1970-01-01T00:00:00.000010Z", FormatTime(0, 10000));
  EXPECT_EQ("1970-01-01T00:00:00.000000010Z", FormatTime(0, 10));
}

TEST(DateTimeTest, ParseString) {
  int64 seconds;
  int32 nanos;
  ASSERT_TRUE(ParseTime("0001-01-01T00:00:00Z", &seconds, &nanos));
  EXPECT_EQ("0001-01-01T00:00:00Z", FormatTime(seconds, nanos));
  ASSERT_TRUE(ParseTime("9999-12-31T23:59:59.999999999Z", &seconds, &nanos));
  EXPECT_EQ("9999-12-31T23:59:59.999999999Z", FormatTime(seconds, nanos));

  // Test time zone offsets.
  ASSERT_TRUE(ParseTime("1970-01-01T00:00:00-08:00", &seconds, &nanos));
  EXPECT_EQ("1970-01-01T08:00:00Z", FormatTime(seconds, nanos));
  ASSERT_TRUE(ParseTime("1970-01-01T00:00:00+08:00", &seconds, &nanos));
  EXPECT_EQ("1969-12-31T16:00:00Z", FormatTime(seconds, nanos));

  // Test nanoseconds.
  ASSERT_TRUE(ParseTime("1970-01-01T00:00:00.01Z", &seconds, &nanos));
  EXPECT_EQ("1970-01-01T00:00:00.010Z", FormatTime(seconds, nanos));
  ASSERT_TRUE(ParseTime("1970-01-01T00:00:00.00001-08:00", &seconds, &nanos));
  EXPECT_EQ("1970-01-01T08:00:00.000010Z", FormatTime(seconds, nanos));
  ASSERT_TRUE(ParseTime("1970-01-01T00:00:00.00000001+08:00", &seconds, &nanos));
  EXPECT_EQ("1969-12-31T16:00:00.000000010Z", FormatTime(seconds, nanos));
  // Fractional parts less than 1 nanosecond will be ignored.
  ASSERT_TRUE(ParseTime("1970-01-01T00:00:00.0123456789Z", &seconds, &nanos));
  EXPECT_EQ("1970-01-01T00:00:00.012345678Z", FormatTime(seconds, nanos));
}

}  // namespace
}  // namespace internal
}  // namespace protobuf
}  // namespace google


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2014 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GOOGLE_PROTOBUF_ATOMIC_SEQUENCE_NUM_H_
#define GOOGLE_PROTOBUF_ATOMIC_SEQUENCE_NUM_H_

#include <google/protobuf/stubs/atomicops.h>

namespace google {
namespace protobuf {
namespace internal {

class SequenceNumber {
 public:
  SequenceNumber() : word_(0) {}

  AtomicWord GetNext() {
    return NoBarrier_AtomicIncrement(&word_, 1) - 1;
  }
 private:
  AtomicWord word_;
};

}  // namespace internal
}  // namespace protobuf
}  // namespace google

#endif  // GOOGLE_PROTOBUF_ATOMIC_SEQUENCE_NUM_H_


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <google/protobuf/stubs/statusor.h>

#include <errno.h>
#include <memory>

#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>

namespace google {
namespace protobuf {
namespace util {
namespace {

class Base1 {
 public:
  virtual ~Base1() {}
  int pad;
};

class Base2 {
 public:
  virtual ~Base2() {}
  int yetotherpad;
};

class Derived : public Base1, public Base2 {
 public:
  virtual ~Derived() {}
  int evenmorepad;
};

class CopyNoAssign {
 public:
  explicit CopyNoAssign(int value) : foo(value) {}
  CopyNoAssign(const CopyNoAssign& other) : foo(other.foo) {}
  int foo;
 private:
  const CopyNoAssign& operator=(const CopyNoAssign&);
};

TEST(StatusOr, TestDefaultCtor) {
  StatusOr<int> thing;
  EXPECT_FALSE(thing.ok());
  EXPECT_EQ(Status::UNKNOWN, thing.status());
}

TEST(StatusOr, TestStatusCtor) {
  StatusOr<int> thing(Status::CANCELLED);
  EXPECT_FALSE(thing.ok());
  EXPECT_EQ(Status::CANCELLED, thing.status());
}

TEST(StatusOr, TestValueCtor) {
  const int kI = 4;
  StatusOr<int> thing(kI);
  EXPECT_TRUE(thing.ok());
  EXPECT_EQ(kI, thing.ValueOrDie());
}

TEST(StatusOr, TestCopyCtorStatusOk) {
  const int kI = 4;
  StatusOr<int> original(kI);
  StatusOr<int> copy(original);
  EXPECT_EQ(original.status(), copy.status());
  EXPECT_EQ(original.ValueOrDie(), copy.ValueOrDie());
}

TEST(StatusOr, TestCopyCtorStatusNotOk) {
  StatusOr<int> original(Status::CANCELLED);
  StatusOr<int> copy(original);
  EXPECT_EQ(original.status(), copy.status());
}

TEST(StatusOr, TestCopyCtorStatusOKConverting) {
  const int kI = 4;
  StatusOr<int>    original(kI);
  StatusOr<double> copy(original);
  EXPECT_EQ(original.status(), copy.status());
  EXPECT_EQ(original.ValueOrDie(), copy.ValueOrDie());
}

TEST(StatusOr, TestCopyCtorStatusNotOkConverting) {
  StatusOr<int>    original(Status::CANCELLED);
  StatusOr<double> copy(original);
  EXPECT_EQ(original.status(), copy.status());
}

TEST(StatusOr, TestAssignmentStatusOk) {
  const int kI = 4;
  StatusOr<int> source(kI);
  StatusOr<int> target;
  target = source;
  EXPECT_EQ(source.status(), target.status());
  EXPECT_EQ(source.ValueOrDie(), target.ValueOrDie());
}

TEST(StatusOr, TestAssignmentStatusNotOk) {
  StatusOr<int> source(Status::CANCELLED);
  StatusOr<int> target;
  target = source;
  EXPECT_EQ(source.status(), target.status());
}

TEST(StatusOr, TestAssignmentStatusOKConverting) {
  const int kI = 4;
  StatusOr<int>    source(kI);
  StatusOr<double> target;
  target = source;
  EXPECT_EQ(source.status(), target.status());
  EXPECT_DOUBLE_EQ(source.ValueOrDie(), target.ValueOrDie());
}

TEST(StatusOr, TestAssignmentStatusNotOkConverting) {
  StatusOr<int>    source(Status::CANCELLED);
  StatusOr<double> target;
  target = source;
  EXPECT_EQ(source.status(), target.status());
}

TEST(StatusOr, TestStatus) {
  StatusOr<int> good(4);
  EXPECT_TRUE(good.ok());
  StatusOr<int> bad(Status::CANCELLED);
  EXPECT_FALSE(bad.ok());
  EXPECT_EQ(Status::CANCELLED, bad.status());
}

TEST(StatusOr, TestValue) {
  const int kI = 4;
  StatusOr<int> thing(kI);
  EXPECT_EQ(kI, thing.ValueOrDie());
}

TEST(StatusOr, TestValueConst) {
  const int kI = 4;
  const StatusOr<int> thing(kI);
  EXPECT_EQ(kI, thing.ValueOrDie());
}

TEST(StatusOr, TestPointerDefaultCtor) {
  StatusOr<int*> thing;
  EXPECT_FALSE(thing.ok());
  EXPECT_EQ(Status::UNKNOWN, thing.status());
}

TEST(StatusOr, TestPointerStatusCtor) {
  StatusOr<int*> thing(Status::CANCELLED);
  EXPECT_FALSE(thing.ok());
  EXPECT_EQ(Status::CANCELLED, thing.status());
}

TEST(StatusOr, TestPointerValueCtor) {
  const int kI = 4;
  StatusOr<const int*> thing(&kI);
  EXPECT_TRUE(thing.ok());
  EXPECT_EQ(&kI, thing.ValueOrDie());
}

TEST(StatusOr, TestPointerCopyCtorStatusOk) {
  const int kI = 0;
  StatusOr<const int*> original(&kI);
  StatusOr<const int*> copy(original);
  EXPECT_EQ(original.status(), copy.status());
  EXPECT_EQ(original.ValueOrDie(), copy.ValueOrDie());
}

TEST(StatusOr, TestPointerCopyCtorStatusNotOk) {
  StatusOr<int*> original(Status::CANCELLED);
  StatusOr<int*> copy(original);
  EXPECT_EQ(original.status(), copy.status());
}

TEST(StatusOr, TestPointerCopyCtorStatusOKConverting) {
  Derived derived;
  StatusOr<Derived*> original(&derived);
  StatusOr<Base2*>   copy(original);
  EXPECT_EQ(original.status(), copy.status());
  EXPECT_EQ(static_cast<const Base2*>(original.ValueOrDie()),
            copy.ValueOrDie());
}

TEST(StatusOr, TestPointerCopyCtorStatusNotOkConverting) {
  StatusOr<Derived*> original(Status::CANCELLED);
  StatusOr<Base2*>   copy(original);
  EXPECT_EQ(original.status(), copy.status());
}

TEST(StatusOr, TestPointerAssignmentStatusOk) {
  const int kI = 0;
  StatusOr<const int*> source(&kI);
  StatusOr<const int*> target;
  target = source;
  EXPECT_EQ(source.status(), target.status());
  EXPECT_EQ(source.ValueOrDie(), target.ValueOrDie());
}

TEST(StatusOr, TestPointerAssignmentStatusNotOk) {
  StatusOr<int*> source(Status::CANCELLED);
  StatusOr<int*> target;
  target = source;
  EXPECT_EQ(source.status(), target.status());
}

TEST(StatusOr, TestPointerAssignmentStatusOKConverting) {
  Derived derived;
  StatusOr<Derived*> source(&derived);
  StatusOr<Base2*>   target;
  target = source;
  EXPECT_EQ(source.status(), target.status());
  EXPECT_EQ(static_cast<const Base2*>(source.ValueOrDie()),
            target.ValueOrDie());
}

TEST(StatusOr, TestPointerAssignmentStatusNotOkConverting) {
  StatusOr<Derived*> source(Status::CANCELLED);
  StatusOr<Base2*>   target;
  target = source;
  EXPECT_EQ(source.status(), target.status());
}

TEST(StatusOr, TestPointerStatus) {
  const int kI = 0;
  StatusOr<const int*> good(&kI);
  EXPECT_TRUE(good.ok());
  StatusOr<const int*> bad(Status::CANCELLED);
  EXPECT_EQ(Status::CANCELLED, bad.status());
}

TEST(StatusOr, TestPointerValue) {
  const int kI = 0;
  StatusOr<const int*> thing(&kI);
  EXPECT_EQ(&kI, thing.ValueOrDie());
}

TEST(StatusOr, TestPointerValueConst) {
  const int kI = 0;
  const StatusOr<const int*> thing(&kI);
  EXPECT_EQ(&kI, thing.ValueOrDie());
}

}  // namespace
}  // namespace util
}  // namespace protobuf
}  // namespace google


text:
// Copyright 2013 Red Hat Inc.  All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Red Hat Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// This file is an internal atomic implementation, use atomicops.h instead.

#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_GENERIC_GCC_H_
#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_GENERIC_GCC_H_

namespace google {
namespace protobuf {
namespace internal {

inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
                                         Atomic32 old_value,
                                         Atomic32 new_value) {
  __atomic_compare_exchange_n(ptr, &old_value, new_value, false,
                              __ATOMIC_RELAXED, __ATOMIC_RELAXED);
  return old_value;
}

inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
                                         Atomic32 new_value) {
  return __atomic_exchange_n(ptr, new_value, __ATOMIC_RELAXED);
}

inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
                                          Atomic32 increment) {
  return __atomic_add_fetch(ptr, increment, __ATOMIC_RELAXED);
}

inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
                                        Atomic32 increment) {
  return __atomic_add_fetch(ptr, increment, __ATOMIC_SEQ_CST);
}

inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
                                       Atomic32 old_value,
                                       Atomic32 new_value) {
  __atomic_compare_exchange_n(ptr, &old_value, new_value, false,
                              __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
  return old_value;
}

inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
                                       Atomic32 old_value,
                                       Atomic32 new_value) {
  __atomic_compare_exchange_n(ptr, &old_value, new_value, false,
                              __ATOMIC_RELEASE, __ATOMIC_ACQUIRE);
  return old_value;
}

inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
  __atomic_store_n(ptr, value, __ATOMIC_RELAXED);
}

inline void MemoryBarrierInternal() {
  __sync_synchronize();
}

inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
  __atomic_store_n(ptr, value, __ATOMIC_SEQ_CST);
}

inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
  __atomic_store_n(ptr, value, __ATOMIC_RELEASE);
}

inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
  return __atomic_load_n(ptr, __ATOMIC_RELAXED);
}

inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
  return __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
}

inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
  return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
}

#ifdef __LP64__

inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
  __atomic_store_n(ptr, value, __ATOMIC_RELEASE);
}

inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
  return __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
}

inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
                                       Atomic64 old_value,
                                       Atomic64 new_value) {
  __atomic_compare_exchange_n(ptr, &old_value, new_value, false,
                              __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
  return old_value;
}

inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
                                         Atomic64 old_value,
                                         Atomic64 new_value) {
  __atomic_compare_exchange_n(ptr, &old_value, new_value, false,
                              __ATOMIC_RELAXED, __ATOMIC_RELAXED);
  return old_value;
}

inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
                                          Atomic64 increment) {
  return __atomic_add_fetch(ptr, increment, __ATOMIC_RELAXED);
}

inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
  __atomic_store_n(ptr, value, __ATOMIC_RELAXED);
}

inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
                                         Atomic64 new_value) {
  return __atomic_exchange_n(ptr, new_value, __ATOMIC_RELAXED);
}

inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
  return __atomic_load_n(ptr, __ATOMIC_RELAXED);
}

#endif // defined(__LP64__)

}  // namespace internal
}  // namespace protobuf
}  // namespace google

#endif  // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_GENERIC_GCC_H_