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 (at) 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 44 namespace google { 45 namespace protobuf { 46 namespace io { 47 namespace { 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 53 TEST(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 61 TEST(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 86 TEST(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 114 TEST(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 150 TEST(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 171 TEST(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 224 TEST(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 236 TEST(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