1// Copyright 2013 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package pretty 16 17import ( 18 "bytes" 19 "strings" 20 "testing" 21) 22 23func TestFormat(t *testing.T) { 24 tests := []struct { 25 desc string 26 node node 27 28 // All strings have a leading newline trimmed before comparison: 29 normal string 30 diffable string 31 }{ 32 { 33 desc: "string", 34 node: stringVal("zaphod"), 35 normal: `"zaphod"`, 36 diffable: `"zaphod"`, 37 }, 38 { 39 desc: "raw", 40 node: rawVal("42"), 41 normal: `42`, 42 diffable: `42`, 43 }, 44 { 45 desc: "keyvals", 46 node: keyvals{ 47 {"name", stringVal("zaphod")}, 48 {"age", rawVal("42")}, 49 }, 50 normal: ` 51{name: "zaphod", 52 age: 42}`, 53 diffable: ` 54{ 55 name: "zaphod", 56 age: 42, 57}`, 58 }, 59 { 60 desc: "empty list", 61 node: list{}, 62 normal: ` 63[]`, 64 diffable: ` 65[ 66]`, 67 }, 68 { 69 desc: "empty nested list", 70 node: list{list{}}, 71 normal: ` 72[[]]`, 73 diffable: ` 74[ 75 [ 76 ], 77]`, 78 }, 79 { 80 desc: "list", 81 node: list{ 82 stringVal("zaphod"), 83 rawVal("42"), 84 }, 85 normal: ` 86["zaphod", 87 42]`, 88 diffable: ` 89[ 90 "zaphod", 91 42, 92]`, 93 }, 94 { 95 desc: "empty keyvals", 96 node: keyvals{}, 97 normal: ` 98{}`, 99 diffable: ` 100{ 101}`, 102 }, 103 { 104 desc: "empty nested keyvals", 105 node: keyvals{{"k", keyvals{}}}, 106 normal: ` 107{k: {}}`, 108 diffable: ` 109{ 110 k: { 111 }, 112}`, 113 }, 114 { 115 desc: "nested", 116 node: list{ 117 stringVal("first"), 118 list{rawVal("1"), rawVal("2"), rawVal("3")}, 119 keyvals{ 120 {"trillian", keyvals{ 121 {"race", stringVal("human")}, 122 {"age", rawVal("36")}, 123 }}, 124 {"zaphod", keyvals{ 125 {"occupation", stringVal("president of the galaxy")}, 126 {"features", stringVal("two heads")}, 127 }}, 128 }, 129 keyvals{}, 130 }, 131 normal: ` 132["first", 133 [1, 134 2, 135 3], 136 {trillian: {race: "human", 137 age: 36}, 138 zaphod: {occupation: "president of the galaxy", 139 features: "two heads"}}, 140 {}]`, 141 diffable: ` 142[ 143 "first", 144 [ 145 1, 146 2, 147 3, 148 ], 149 { 150 trillian: { 151 race: "human", 152 age: 36, 153 }, 154 zaphod: { 155 occupation: "president of the galaxy", 156 features: "two heads", 157 }, 158 }, 159 { 160 }, 161]`, 162 }, 163 { 164 desc: "recursive", 165 node: target{1, keyvals{ 166 {"Value", rawVal("1")}, 167 {"Next", keyvals{ 168 {"Value", rawVal("2")}, 169 {"Next", keyvals{ 170 {"Value", rawVal("3")}, 171 {"Next", ref{1}}, 172 }}, 173 }}, 174 }}, 175 normal: ` 176<#1> {Value: 1, 177 Next: {Value: 2, 178 Next: {Value: 3, 179 Next: <see #1>}}}`, 180 diffable: ` 181<#1> { 182 Value: 1, 183 Next: { 184 Value: 2, 185 Next: { 186 Value: 3, 187 Next: <see #1>, 188 }, 189 }, 190}`, 191 }, 192 { 193 desc: "print in order", 194 node: list{ 195 target{2, keyvals{ 196 {"Next", ref{1}}, 197 }}, 198 target{1, keyvals{ 199 {"Next", ref{2}}, 200 }}, 201 }, 202 normal: ` 203[<#1> {Next: <see #2>}, 204 <#2> {Next: <see #1>}]`, 205 diffable: ` 206[ 207 <#1> { 208 Next: <see #2>, 209 }, 210 <#2> { 211 Next: <see #1>, 212 }, 213]`, 214 }, 215 } 216 217 normal := &Config{} 218 diffable := &Config{Diffable: true} 219 for _, test := range tests { 220 // For readability, we have a newline that won't be there in the output 221 test.normal = strings.TrimPrefix(test.normal, "\n") 222 test.diffable = strings.TrimPrefix(test.diffable, "\n") 223 224 buf := new(bytes.Buffer) 225 newFormatter(normal, buf).write(test.node) 226 if got, want := buf.String(), test.normal; got != want { 227 t.Errorf("%s: normal rendendered incorrectly\ngot:\n%s\nwant:\n%s", test.desc, got, want) 228 } 229 buf.Reset() 230 231 newFormatter(diffable, buf).write(test.node) 232 if got, want := buf.String(), test.diffable; got != want { 233 t.Errorf("%s: diffable rendendered incorrectly\ngot:\n%s\nwant:\n%s", test.desc, got, want) 234 } 235 } 236} 237 238func TestCompactString(t *testing.T) { 239 tests := []struct { 240 node 241 compact string 242 }{ 243 { 244 stringVal("abc"), 245 "abc", 246 }, 247 { 248 rawVal("2"), 249 "2", 250 }, 251 { 252 list{ 253 rawVal("2"), 254 rawVal("3"), 255 }, 256 "[2,3]", 257 }, 258 { 259 keyvals{ 260 {"name", stringVal("zaphod")}, 261 {"age", rawVal("42")}, 262 }, 263 `{name:"zaphod",age:42}`, 264 }, 265 { 266 list{ 267 list{ 268 rawVal("0"), 269 rawVal("1"), 270 rawVal("2"), 271 rawVal("3"), 272 }, 273 list{ 274 rawVal("1"), 275 rawVal("2"), 276 rawVal("3"), 277 rawVal("0"), 278 }, 279 list{ 280 rawVal("2"), 281 rawVal("3"), 282 rawVal("0"), 283 rawVal("1"), 284 }, 285 }, 286 `[[0,1,2,3],[1,2,3,0],[2,3,0,1]]`, 287 }, 288 } 289 290 for _, test := range tests { 291 if got, want := new(formatter).compactString(test.node), test.compact; got != want { 292 t.Errorf("%#v: compact = %q, want %q", test.node, got, want) 293 } 294 } 295} 296 297func TestShortList(t *testing.T) { 298 cfg := &Config{ 299 ShortList: 16, 300 } 301 302 tests := []struct { 303 node 304 want string 305 }{ 306 { 307 list{ 308 list{ 309 rawVal("0"), 310 rawVal("1"), 311 rawVal("2"), 312 rawVal("3"), 313 }, 314 list{ 315 rawVal("1"), 316 rawVal("2"), 317 rawVal("3"), 318 rawVal("0"), 319 }, 320 list{ 321 rawVal("2"), 322 rawVal("3"), 323 rawVal("0"), 324 rawVal("1"), 325 }, 326 }, 327 `[[0,1,2,3], 328 [1,2,3,0], 329 [2,3,0,1]]`, 330 }, 331 } 332 333 for _, test := range tests { 334 buf := new(bytes.Buffer) 335 newFormatter(cfg, buf).write(test.node) 336 if got, want := buf.String(), test.want; got != want { 337 t.Errorf("%#v:\ngot:\n%s\nwant:\n%s", test.node, got, want) 338 } 339 } 340} 341 342var benchNode = keyvals{ 343 {"list", list{ 344 rawVal("0"), 345 rawVal("1"), 346 rawVal("2"), 347 rawVal("3"), 348 }}, 349 {"keyvals", keyvals{ 350 {"a", stringVal("b")}, 351 {"c", stringVal("e")}, 352 {"d", stringVal("f")}, 353 }}, 354} 355 356func benchOpts(b *testing.B, cfg *Config) { 357 buf := new(bytes.Buffer) 358 newFormatter(cfg, buf).write(benchNode) 359 b.SetBytes(int64(buf.Len())) 360 b.ResetTimer() 361 362 for i := 0; i < b.N; i++ { 363 buf.Reset() 364 newFormatter(cfg, buf).write(benchNode) 365 } 366} 367 368func BenchmarkWriteDefault(b *testing.B) { benchOpts(b, DefaultConfig) } 369func BenchmarkWriteShortList(b *testing.B) { benchOpts(b, &Config{ShortList: 16}) } 370func BenchmarkWriteCompact(b *testing.B) { benchOpts(b, &Config{Compact: true}) } 371func BenchmarkWriteDiffable(b *testing.B) { benchOpts(b, &Config{Diffable: true}) } 372