1// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 2package reader 3 4import ( 5 "strings" 6 "testing" 7) 8 9func TestCanReadTagValues(t *testing.T) { 10 sText := ` 11Tag1: Value1 12Tag2: Value2 13 14Tag3: <text>line 1 15 line 2</text> 16# Comment 17Tag4: Value4 18Tag5: Value 5 19` 20 sReader := strings.NewReader(sText) 21 22 tvPairList, err := ReadTagValues(sReader) 23 if err != nil { 24 t.Errorf("got error when calling ReadTagValues: %v", err) 25 } 26 if len(tvPairList) != 5 { 27 t.Fatalf("expected len(tvPairList) to be 5, got %d", len(tvPairList)) 28 } 29 if tvPairList[0].Tag != "Tag1" { 30 t.Errorf("expected tvPairList[0].Tag to be Tag1, got %s", tvPairList[0].Tag) 31 } 32 if tvPairList[0].Value != "Value1" { 33 t.Errorf("expected tvPairList[0].Value to be Value1, got %s", tvPairList[0].Value) 34 } 35 if tvPairList[1].Tag != "Tag2" { 36 t.Errorf("expected tvPairList[1].Tag to be Tag2, got %s", tvPairList[1].Tag) 37 } 38 if tvPairList[1].Value != "Value2" { 39 t.Errorf("expected tvPairList[1].Value to be Value2, got %s", tvPairList[1].Value) 40 } 41 if tvPairList[2].Tag != "Tag3" { 42 t.Errorf("expected tvPairList[2].Tag to be Tag3, got %s", tvPairList[2].Tag) 43 } 44 if tvPairList[2].Value != "line 1\n line 2" { 45 t.Errorf("expected tvPairList[2].Value to be line 1\n line 2, got %s", tvPairList[2].Value) 46 } 47 if tvPairList[3].Tag != "Tag4" { 48 t.Errorf("expected tvPairList[3].Tag to be Tag4, got %s", tvPairList[3].Tag) 49 } 50 if tvPairList[3].Value != "Value4" { 51 t.Errorf("expected tvPairList[3].Value to be Value4, got %s", tvPairList[3].Value) 52 } 53 if tvPairList[4].Tag != "Tag5" { 54 t.Errorf("expected tvPairList[4].Tag to be Tag5, got %s", tvPairList[4].Tag) 55 } 56 if tvPairList[4].Value != "Value 5" { 57 t.Errorf("expected tvPairList[4].Value to be Value 5, got %s", tvPairList[4].Value) 58 } 59} 60 61func TestCanGetTVListWithFinalize(t *testing.T) { 62 reader := &tvReader{} 63 err := reader.readNextLine("Tag:value") 64 if err != nil { 65 t.Errorf("got error when calling readNextLine: %v", err) 66 } 67 tvList, err := reader.finalize() 68 if err != nil { 69 t.Errorf("got error when calling finalize: %v", err) 70 } 71 if len(tvList) != 1 || tvList[0].tag != "Tag" || tvList[0].value != "value" { 72 t.Errorf("got invalid tag/value list: %v", tvList) 73 } 74} 75 76func TestCanGetTVListIncludingMultilineWithFinalize(t *testing.T) { 77 reader := &tvReader{} 78 err := reader.readNextLine("Tag:<text>value") 79 if err != nil { 80 t.Errorf("got error when calling readNextLine: %v", err) 81 } 82 err = reader.readNextLine("rest of value</text>") 83 if err != nil { 84 t.Errorf("got error when calling readNextLine: %v", err) 85 } 86 tvList, err := reader.finalize() 87 if err != nil { 88 t.Errorf("got error when calling finalize: %v", err) 89 } 90 if len(tvList) != 1 || tvList[0].tag != "Tag" || tvList[0].value != "value\nrest of value" { 91 t.Errorf("got invalid tag/value list: %v", tvList) 92 } 93} 94 95func TestCannotFinalizeIfInMidtextState(t *testing.T) { 96 reader := &tvReader{} 97 err := reader.readNextLine("Tag:<text>value") 98 if err != nil { 99 t.Errorf("got error when calling readNextLine: %v", err) 100 } 101 _, err = reader.finalize() 102 if err == nil { 103 t.Errorf("should have gotten error when calling finalize midtext") 104 } 105} 106 107func TestCurrentLineIncreasesOnEachReadCall(t *testing.T) { 108 reader := &tvReader{} 109 err := reader.readNextLine("Tag:value") 110 if err != nil { 111 t.Errorf("got error when calling readNextLine: %v", err) 112 } 113 if reader.currentLine != 1 { 114 t.Errorf("expected %d for currentLine, got %d", 1, reader.currentLine) 115 } 116 117 reader.currentLine = 23 118 err = reader.readNextLine("Tag:value") 119 if err != nil { 120 t.Errorf("got error when calling readNextLine: %v", err) 121 } 122 if reader.currentLine != 24 { 123 t.Errorf("expected %d for currentLine, got %d", 23, reader.currentLine) 124 } 125} 126 127func TestReadyCanReadSingleTagValue(t *testing.T) { 128 reader := &tvReader{} 129 err := reader.readNextLine("Tag:value") 130 if err != nil { 131 t.Errorf("got error when calling readNextLine: %v", err) 132 } 133 if len(reader.tvList) != 1 || reader.tvList[0].tag != "Tag" || reader.tvList[0].value != "value" { 134 t.Errorf("got invalid tag/value list: %v", reader.tvList) 135 } 136 if reader.currentLine != 1 { 137 t.Errorf("expected %d for currentLine, got %d", 1, reader.currentLine) 138 } 139 if reader.currentTag != "" { 140 t.Errorf("expected empty string for currentTag, got %s", reader.currentTag) 141 } 142 if reader.currentValue != "" { 143 t.Errorf("expected empty string for currentValue, got %s", reader.currentValue) 144 } 145} 146 147func TestReadyCanStripWhitespaceFromValue(t *testing.T) { 148 reader := &tvReader{} 149 err := reader.readNextLine("Tag: value ") 150 if err != nil { 151 t.Errorf("got error when calling readNextLine: %v", err) 152 } 153 if len(reader.tvList) != 1 || reader.tvList[0].tag != "Tag" || reader.tvList[0].value != "value" { 154 t.Errorf("got invalid tag/value list: %v", reader.tvList) 155 } 156} 157 158func TestReadyCannotReadLineWithNoColon(t *testing.T) { 159 reader := &tvReader{} 160 err := reader.readNextLine("No colon should be an error") 161 if err == nil { 162 t.Errorf("should have gotten error when calling readNextLine") 163 } 164} 165 166func TestReadyTextTagSwitchesToMidtext(t *testing.T) { 167 reader := &tvReader{} 168 err := reader.readNextLine("Tag: <text>This begins a multiline value") 169 if err != nil { 170 t.Errorf("got error when calling readNextLine: %v", err) 171 } 172 if len(reader.tvList) != 0 { 173 t.Errorf("expected empty tag/value list, got %v", reader.tvList) 174 } 175 if !reader.midtext { 176 t.Errorf("expected midtext to be true, got false") 177 } 178 if reader.currentLine != 1 { 179 t.Errorf("expected %d for currentLine, got %d", 1, reader.currentLine) 180 } 181 if reader.currentTag != "Tag" { 182 t.Errorf("expected %s for currentTag, got %s", "Tag", reader.currentTag) 183 } 184 if reader.currentValue != "This begins a multiline value\n" { 185 t.Errorf("expected %s for currentValue, got %s", "This begins a multiline value\n", reader.currentValue) 186 } 187} 188 189func TestReadyTextTagAndClosingTagInOneLineFinishesRead(t *testing.T) { 190 reader := &tvReader{} 191 err := reader.readNextLine("Tag: <text>Just one line</text>") 192 if err != nil { 193 t.Errorf("got error when calling readNextLine: %v", err) 194 } 195 if len(reader.tvList) != 1 || reader.tvList[0].tag != "Tag" || reader.tvList[0].value != "Just one line" { 196 t.Errorf("got invalid tag/value list: %v", reader.tvList) 197 } 198 if reader.midtext { 199 t.Errorf("expected midtext to be false, got true") 200 } 201 if reader.currentLine != 1 { 202 t.Errorf("expected %d for currentLine, got %d", 1, reader.currentLine) 203 } 204 if reader.currentTag != "" { 205 t.Errorf("expected empty string for currentTag, got %s", reader.currentTag) 206 } 207 if reader.currentValue != "" { 208 t.Errorf("expected empty string for currentValue, got %s", reader.currentValue) 209 } 210} 211 212func TestCanReadMultilineTextAcrossThreeLines(t *testing.T) { 213 reader := &tvReader{} 214 err := reader.readNextLine("Tag: <text>This value") 215 if err != nil { 216 t.Errorf("got error when calling readNextLine: %v", err) 217 } 218 err = reader.readNextLine("is three") 219 if err != nil { 220 t.Errorf("got error when calling readNextLine: %v", err) 221 } 222 err = reader.readNextLine("lines long</text>") 223 if err != nil { 224 t.Errorf("got error when calling readNextLine: %v", err) 225 } 226 227 if len(reader.tvList) != 1 || reader.tvList[0].tag != "Tag" || reader.tvList[0].value != "This value\nis three\nlines long" { 228 t.Errorf("got invalid tag/value list: %v", reader.tvList) 229 } 230 if reader.midtext { 231 t.Errorf("expected midtext to be false, got true") 232 } 233 if reader.currentLine != 3 { 234 t.Errorf("expected %d for currentLine, got %d", 3, reader.currentLine) 235 } 236 if reader.currentTag != "" { 237 t.Errorf("expected empty string for currentTag, got %s", reader.currentTag) 238 } 239 if reader.currentValue != "" { 240 t.Errorf("expected empty string for currentValue, got %s", reader.currentValue) 241 } 242} 243 244func TestMidtextContinuesIfNoClosingText(t *testing.T) { 245 reader := &tvReader{} 246 reader.midtext = true 247 reader.currentLine = 1 248 reader.currentTag = "Multiline" 249 reader.currentValue = "First line\n" 250 251 err := reader.readNextLine("Second line") 252 if err != nil { 253 t.Errorf("got error when calling readNextLine: %v", err) 254 } 255 256 if len(reader.tvList) != 0 { 257 t.Errorf("expected empty tag/value list, got %v", reader.tvList) 258 } 259 if !reader.midtext { 260 t.Errorf("expected midtext to be true, got false") 261 } 262 if reader.currentLine != 2 { 263 t.Errorf("expected %d for currentLine, got %d", 2, reader.currentLine) 264 } 265 if reader.currentTag != "Multiline" { 266 t.Errorf("expected %s for currentTag, got %s", "Multiline", reader.currentTag) 267 } 268 if reader.currentValue != "First line\nSecond line\n" { 269 t.Errorf("expected %s for currentValue, got %s", "First line\nSecond line\n", reader.currentValue) 270 } 271} 272 273func TestMidtextFinishesIfReachingClosingText(t *testing.T) { 274 reader := &tvReader{} 275 reader.midtext = true 276 reader.currentLine = 1 277 reader.currentTag = "Multiline" 278 reader.currentValue = "First line\n" 279 280 err := reader.readNextLine("Second line</text>") 281 if err != nil { 282 t.Errorf("got error when calling readNextLine: %v", err) 283 } 284 285 if len(reader.tvList) != 1 || reader.tvList[0].tag != "Multiline" || reader.tvList[0].value != "First line\nSecond line" { 286 t.Errorf("got invalid tag/value list: %v", reader.tvList) 287 } 288 if reader.midtext { 289 t.Errorf("expected midtext to be false, got true") 290 } 291 if reader.currentLine != 2 { 292 t.Errorf("expected %d for currentLine, got %d", 2, reader.currentLine) 293 } 294 if reader.currentTag != "" { 295 t.Errorf("expected empty string for currentTag, got %s", reader.currentTag) 296 } 297 if reader.currentValue != "" { 298 t.Errorf("expected empty string for currentValue, got %s", reader.currentValue) 299 } 300} 301 302func TestReadyIgnoresCommentLines(t *testing.T) { 303 reader := &tvReader{} 304 err := reader.readNextLine("# this is a comment") 305 if err != nil { 306 t.Errorf("got error when calling readNextLine: %v", err) 307 } 308 309 if len(reader.tvList) != 0 { 310 t.Errorf("expected empty tag/value list, got %v", reader.tvList) 311 } 312 if reader.midtext { 313 t.Errorf("expected midtext to be false, got true") 314 } 315 if reader.currentLine != 1 { 316 t.Errorf("expected %d for currentLine, got %d", 1, reader.currentLine) 317 } 318 if reader.currentTag != "" { 319 t.Errorf("expected empty string for currentTag, got %s", reader.currentTag) 320 } 321 if reader.currentValue != "" { 322 t.Errorf("expected empty string for currentValue, got %s", reader.currentValue) 323 } 324} 325 326func TestMidtextIncludesCommentLines(t *testing.T) { 327 reader := &tvReader{} 328 reader.midtext = true 329 reader.currentLine = 1 330 reader.currentTag = "Multiline" 331 reader.currentValue = "First line\n" 332 333 err := reader.readNextLine("# This is part of multiline text") 334 if err != nil { 335 t.Errorf("got error when calling readNextLine: %v", err) 336 } 337 338 if len(reader.tvList) != 0 { 339 t.Errorf("expected empty tag/value list, got %v", reader.tvList) 340 } 341 if !reader.midtext { 342 t.Errorf("expected midtext to be true, got false") 343 } 344 if reader.currentLine != 2 { 345 t.Errorf("expected %d for currentLine, got %d", 2, reader.currentLine) 346 } 347 if reader.currentTag != "Multiline" { 348 t.Errorf("expected %s for currentTag, got %s", "Multiline", reader.currentTag) 349 } 350 if reader.currentValue != "First line\n# This is part of multiline text\n" { 351 t.Errorf("expected %s for currentValue, got %s", "First line\n# This is part of multiline text\n", reader.currentValue) 352 } 353} 354 355func TestReadyIgnoresEmptyLines(t *testing.T) { 356 reader := &tvReader{} 357 err := reader.readNextLine("") 358 if err != nil { 359 t.Errorf("got error when calling readNextLine: %v", err) 360 } 361 362 if len(reader.tvList) != 0 { 363 t.Errorf("expected empty tag/value list, got %v", reader.tvList) 364 } 365 if reader.midtext { 366 t.Errorf("expected midtext to be false, got true") 367 } 368 if reader.currentLine != 1 { 369 t.Errorf("expected %d for currentLine, got %d", 1, reader.currentLine) 370 } 371 if reader.currentTag != "" { 372 t.Errorf("expected empty string for currentTag, got %s", reader.currentTag) 373 } 374 if reader.currentValue != "" { 375 t.Errorf("expected empty string for currentValue, got %s", reader.currentValue) 376 } 377} 378 379func TestMidtextIncludesEmptyLines(t *testing.T) { 380 reader := &tvReader{} 381 reader.midtext = true 382 reader.currentLine = 1 383 reader.currentTag = "Multiline" 384 reader.currentValue = "First line\n" 385 386 err := reader.readNextLine("") 387 if err != nil { 388 t.Errorf("got error when calling readNextLine: %v", err) 389 } 390 391 if len(reader.tvList) != 0 { 392 t.Errorf("expected empty tag/value list, got %v", reader.tvList) 393 } 394 if !reader.midtext { 395 t.Errorf("expected midtext to be true, got false") 396 } 397 if reader.currentLine != 2 { 398 t.Errorf("expected %d for currentLine, got %d", 2, reader.currentLine) 399 } 400 if reader.currentTag != "Multiline" { 401 t.Errorf("expected %s for currentTag, got %s", "Multiline", reader.currentTag) 402 } 403 if reader.currentValue != "First line\n\n" { 404 t.Errorf("expected %s for currentValue, got %s", "First line\n\n", reader.currentValue) 405 } 406} 407 408func TestReadyIgnoresWhitespaceOnlyLines(t *testing.T) { 409 reader := &tvReader{} 410 err := reader.readNextLine(" \t\t\t ") 411 if err != nil { 412 t.Errorf("got error when calling readNextLine: %v", err) 413 } 414 415 if len(reader.tvList) != 0 { 416 t.Errorf("expected empty tag/value list, got %v", reader.tvList) 417 } 418 if reader.midtext { 419 t.Errorf("expected midtext to be false, got true") 420 } 421 if reader.currentLine != 1 { 422 t.Errorf("expected %d for currentLine, got %d", 1, reader.currentLine) 423 } 424 if reader.currentTag != "" { 425 t.Errorf("expected empty string for currentTag, got %s", reader.currentTag) 426 } 427 if reader.currentValue != "" { 428 t.Errorf("expected empty string for currentValue, got %s", reader.currentValue) 429 } 430} 431 432func TestMidtextIncludesWhitespaceOnlyLines(t *testing.T) { 433 reader := &tvReader{} 434 reader.midtext = true 435 reader.currentLine = 1 436 reader.currentTag = "Multiline" 437 reader.currentValue = "First line\n" 438 439 err := reader.readNextLine(" \t\t ") 440 if err != nil { 441 t.Errorf("got error when calling readNextLine: %v", err) 442 } 443 444 if len(reader.tvList) != 0 { 445 t.Errorf("expected empty tag/value list, got %v", reader.tvList) 446 } 447 if !reader.midtext { 448 t.Errorf("expected midtext to be true, got false") 449 } 450 if reader.currentLine != 2 { 451 t.Errorf("expected %d for currentLine, got %d", 2, reader.currentLine) 452 } 453 if reader.currentTag != "Multiline" { 454 t.Errorf("expected %s for currentTag, got %s", "Multiline", reader.currentTag) 455 } 456 if reader.currentValue != "First line\n \t\t \n" { 457 t.Errorf("expected %s for currentValue, got %s", "First line\n \t\t \n", reader.currentValue) 458 } 459} 460 461func TestReadyIgnoresSpacesBeforeTag(t *testing.T) { 462 reader := &tvReader{} 463 err := reader.readNextLine(" \t Tag:value") 464 if err != nil { 465 t.Errorf("got error when calling readNextLine: %v", err) 466 } 467 if len(reader.tvList) != 1 || reader.tvList[0].tag != "Tag" || reader.tvList[0].value != "value" { 468 t.Errorf("got invalid tag/value list: %v", reader.tvList) 469 } 470 if reader.currentLine != 1 { 471 t.Errorf("expected %d for currentLine, got %d", 1, reader.currentLine) 472 } 473 if reader.currentTag != "" { 474 t.Errorf("expected empty string for currentTag, got %s", reader.currentTag) 475 } 476 if reader.currentValue != "" { 477 t.Errorf("expected empty string for currentValue, got %s", reader.currentValue) 478 } 479} 480 481func TestReadyIgnoresSpacesBeforeCommentLines(t *testing.T) { 482 reader := &tvReader{} 483 err := reader.readNextLine(" \t\t # this is a comment") 484 if err != nil { 485 t.Errorf("got error when calling readNextLine: %v", err) 486 } 487 488 if len(reader.tvList) != 0 { 489 t.Errorf("expected empty tag/value list, got %v", reader.tvList) 490 } 491 if reader.midtext { 492 t.Errorf("expected midtext to be false, got true") 493 } 494 if reader.currentLine != 1 { 495 t.Errorf("expected %d for currentLine, got %d", 1, reader.currentLine) 496 } 497 if reader.currentTag != "" { 498 t.Errorf("expected empty string for currentTag, got %s", reader.currentTag) 499 } 500 if reader.currentValue != "" { 501 t.Errorf("expected empty string for currentValue, got %s", reader.currentValue) 502 } 503} 504 505func TestReadyIgnoresSpacesBetweenTagAndColon(t *testing.T) { 506 reader := &tvReader{} 507 err := reader.readNextLine("Tag \t :value") 508 if err != nil { 509 t.Errorf("got error when calling readNextLine: %v", err) 510 } 511 if len(reader.tvList) != 1 || reader.tvList[0].tag != "Tag" || reader.tvList[0].value != "value" { 512 t.Errorf("got invalid tag/value list: %v", reader.tvList) 513 } 514 if reader.currentLine != 1 { 515 t.Errorf("expected %d for currentLine, got %d", 1, reader.currentLine) 516 } 517 if reader.currentTag != "" { 518 t.Errorf("expected empty string for currentTag, got %s", reader.currentTag) 519 } 520 if reader.currentValue != "" { 521 t.Errorf("expected empty string for currentValue, got %s", reader.currentValue) 522 } 523} 524 525func TestReadyIgnoresSpacesBetweenColonAndValue(t *testing.T) { 526 reader := &tvReader{} 527 err := reader.readNextLine("Tag: \t value") 528 if err != nil { 529 t.Errorf("got error when calling readNextLine: %v", err) 530 } 531 if len(reader.tvList) != 1 || reader.tvList[0].tag != "Tag" || reader.tvList[0].value != "value" { 532 t.Errorf("got invalid tag/value list: %v", reader.tvList) 533 } 534 if reader.currentLine != 1 { 535 t.Errorf("expected %d for currentLine, got %d", 1, reader.currentLine) 536 } 537 if reader.currentTag != "" { 538 t.Errorf("expected empty string for currentTag, got %s", reader.currentTag) 539 } 540 if reader.currentValue != "" { 541 t.Errorf("expected empty string for currentValue, got %s", reader.currentValue) 542 } 543} 544 545func TestReadyIgnoresSpacesAfterEndOfValue(t *testing.T) { 546 reader := &tvReader{} 547 err := reader.readNextLine("Tag:value \t ") 548 if err != nil { 549 t.Errorf("got error when calling readNextLine: %v", err) 550 } 551 if len(reader.tvList) != 1 || reader.tvList[0].tag != "Tag" || reader.tvList[0].value != "value" { 552 t.Errorf("got invalid tag/value list: %v", reader.tvList) 553 } 554 if reader.currentLine != 1 { 555 t.Errorf("expected %d for currentLine, got %d", 1, reader.currentLine) 556 } 557 if reader.currentTag != "" { 558 t.Errorf("expected empty string for currentTag, got %s", reader.currentTag) 559 } 560 if reader.currentValue != "" { 561 t.Errorf("expected empty string for currentValue, got %s", reader.currentValue) 562 } 563} 564