1// Protocol Buffers - Google's data interchange format 2// Copyright 2008 Google Inc. All rights reserved. 3// http://code.google.com/p/protobuf/ 4// 5// Redistribution and use in source and binary forms, with or without 6// modification, are permitted provided that the following conditions are 7// met: 8// 9// * Redistributions of source code must retain the above copyright 10// notice, this list of conditions and the following disclaimer. 11// * Redistributions in binary form must reproduce the above 12// copyright notice, this list of conditions and the following disclaimer 13// in the documentation and/or other materials provided with the 14// distribution. 15// * Neither the name of Google Inc. nor the names of its 16// contributors may be used to endorse or promote products derived from 17// this software without specific prior written permission. 18// 19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31// Author: kenton@google.com (Kenton Varda) 32// Based on original Protocol Buffers design by 33// Sanjay Ghemawat, Jeff Dean, and others. 34 35#include <vector> 36 37#include <google/protobuf/io/printer.h> 38#include <google/protobuf/io/zero_copy_stream_impl.h> 39 40#include <google/protobuf/stubs/common.h> 41#include <google/protobuf/testing/googletest.h> 42#include <gtest/gtest.h> 43 44namespace google { 45namespace protobuf { 46namespace io { 47namespace { 48 49// Each test repeats over several block sizes in order to test both cases 50// where particular writes cross a buffer boundary and cases where they do 51// not. 52 53TEST(Printer, EmptyPrinter) { 54 char buffer[8192]; 55 const int block_size = 100; 56 ArrayOutputStream output(buffer, GOOGLE_ARRAYSIZE(buffer), block_size); 57 Printer printer(&output, '\0'); 58 EXPECT_TRUE(!printer.failed()); 59} 60 61TEST(Printer, BasicPrinting) { 62 char buffer[8192]; 63 64 for (int block_size = 1; block_size < 512; block_size *= 2) { 65 ArrayOutputStream output(buffer, sizeof(buffer), block_size); 66 67 { 68 Printer printer(&output, '\0'); 69 70 printer.Print("Hello World!"); 71 printer.Print(" This is the same line.\n"); 72 printer.Print("But this is a new one.\nAnd this is another one."); 73 74 EXPECT_FALSE(printer.failed()); 75 } 76 77 buffer[output.ByteCount()] = '\0'; 78 79 EXPECT_STREQ("Hello World! This is the same line.\n" 80 "But this is a new one.\n" 81 "And this is another one.", 82 buffer); 83 } 84} 85 86TEST(Printer, WriteRaw) { 87 char buffer[8192]; 88 89 for (int block_size = 1; block_size < 512; block_size *= 2) { 90 ArrayOutputStream output(buffer, sizeof(buffer), block_size); 91 92 { 93 string string_obj = "From an object\n"; 94 Printer printer(&output, '$'); 95 printer.WriteRaw("Hello World!", 12); 96 printer.PrintRaw(" This is the same line.\n"); 97 printer.PrintRaw("But this is a new one.\nAnd this is another one."); 98 printer.WriteRaw("\n", 1); 99 printer.PrintRaw(string_obj); 100 EXPECT_FALSE(printer.failed()); 101 } 102 103 buffer[output.ByteCount()] = '\0'; 104 105 EXPECT_STREQ("Hello World! This is the same line.\n" 106 "But this is a new one.\n" 107 "And this is another one." 108 "\n" 109 "From an object\n", 110 buffer); 111 } 112} 113 114TEST(Printer, VariableSubstitution) { 115 char buffer[8192]; 116 117 for (int block_size = 1; block_size < 512; block_size *= 2) { 118 ArrayOutputStream output(buffer, sizeof(buffer), block_size); 119 120 { 121 Printer printer(&output, '$'); 122 map<string, string> vars; 123 124 vars["foo"] = "World"; 125 vars["bar"] = "$foo$"; 126 vars["abcdefg"] = "1234"; 127 128 printer.Print(vars, "Hello $foo$!\nbar = $bar$\n"); 129 printer.PrintRaw("RawBit\n"); 130 printer.Print(vars, "$abcdefg$\nA literal dollar sign: $$"); 131 132 vars["foo"] = "blah"; 133 printer.Print(vars, "\nNow foo = $foo$."); 134 135 EXPECT_FALSE(printer.failed()); 136 } 137 138 buffer[output.ByteCount()] = '\0'; 139 140 EXPECT_STREQ("Hello World!\n" 141 "bar = $foo$\n" 142 "RawBit\n" 143 "1234\n" 144 "A literal dollar sign: $\n" 145 "Now foo = blah.", 146 buffer); 147 } 148} 149 150TEST(Printer, InlineVariableSubstitution) { 151 char buffer[8192]; 152 153 ArrayOutputStream output(buffer, sizeof(buffer)); 154 155 { 156 Printer printer(&output, '$'); 157 printer.Print("Hello $foo$!\n", "foo", "World"); 158 printer.PrintRaw("RawBit\n"); 159 printer.Print("$foo$ $bar$\n", "foo", "one", "bar", "two"); 160 EXPECT_FALSE(printer.failed()); 161 } 162 163 buffer[output.ByteCount()] = '\0'; 164 165 EXPECT_STREQ("Hello World!\n" 166 "RawBit\n" 167 "one two\n", 168 buffer); 169} 170 171TEST(Printer, Indenting) { 172 char buffer[8192]; 173 174 for (int block_size = 1; block_size < 512; block_size *= 2) { 175 ArrayOutputStream output(buffer, sizeof(buffer), block_size); 176 177 { 178 Printer printer(&output, '$'); 179 map<string, string> vars; 180 181 vars["newline"] = "\n"; 182 183 printer.Print("This is not indented.\n"); 184 printer.Indent(); 185 printer.Print("This is indented\nAnd so is this\n"); 186 printer.Outdent(); 187 printer.Print("But this is not."); 188 printer.Indent(); 189 printer.Print(" And this is still the same line.\n" 190 "But this is indented.\n"); 191 printer.PrintRaw("RawBit has indent at start\n"); 192 printer.PrintRaw("but not after a raw newline\n"); 193 printer.Print(vars, "Note that a newline in a variable will break " 194 "indenting, as we see$newline$here.\n"); 195 printer.Indent(); 196 printer.Print("And this"); 197 printer.Outdent(); 198 printer.Outdent(); 199 printer.Print(" is double-indented\nBack to normal."); 200 201 EXPECT_FALSE(printer.failed()); 202 } 203 204 buffer[output.ByteCount()] = '\0'; 205 206 EXPECT_STREQ( 207 "This is not indented.\n" 208 " This is indented\n" 209 " And so is this\n" 210 "But this is not. And this is still the same line.\n" 211 " But this is indented.\n" 212 " RawBit has indent at start\n" 213 "but not after a raw newline\n" 214 "Note that a newline in a variable will break indenting, as we see\n" 215 "here.\n" 216 " And this is double-indented\n" 217 "Back to normal.", 218 buffer); 219 } 220} 221 222// Death tests do not work on Windows as of yet. 223#ifdef GTEST_HAS_DEATH_TEST 224TEST(Printer, Death) { 225 char buffer[8192]; 226 227 ArrayOutputStream output(buffer, sizeof(buffer)); 228 Printer printer(&output, '$'); 229 230 EXPECT_DEBUG_DEATH(printer.Print("$nosuchvar$"), "Undefined variable"); 231 EXPECT_DEBUG_DEATH(printer.Print("$unclosed"), "Unclosed variable name"); 232 EXPECT_DEBUG_DEATH(printer.Outdent(), "without matching Indent"); 233} 234#endif // GTEST_HAS_DEATH_TEST 235 236TEST(Printer, WriteFailure) { 237 char buffer[16]; 238 239 ArrayOutputStream output(buffer, sizeof(buffer)); 240 Printer printer(&output, '$'); 241 242 // Print 16 bytes to fill the buffer exactly (should not fail). 243 printer.Print("0123456789abcdef"); 244 EXPECT_FALSE(printer.failed()); 245 246 // Try to print one more byte (should fail). 247 printer.Print(" "); 248 EXPECT_TRUE(printer.failed()); 249 250 // Should not crash 251 printer.Print("blah"); 252 EXPECT_TRUE(printer.failed()); 253 254 // Buffer should contain the first 16 bytes written. 255 EXPECT_EQ("0123456789abcdef", string(buffer, sizeof(buffer))); 256} 257 258} // namespace 259} // namespace io 260} // namespace protobuf 261} // namespace google 262