Repository: python-tap/tappy

Issue:
Additional newlines added in YAML blocks for multi-line strings
Hello!

I've observed that `_extract_yaml_block()` performs `"\n".join(raw_yaml)` without having stripped the newline character in each possible line, resulting in unwanted empty lines when parsing multi-line strings in YAML blocks.

I'll give an example. With this file:

```python
#!/usr/bin/python3

import tap.parser

tap_input = """TAP version 13
1..2
ok 1 A passing test
   ---
   message: test
   severity: fail
   output: |+
     this is a multiline
     string but with tap
     somehow blank lines
     are added to it.
"""
parser = tap.parser.Parser()

for i, l in enumerate(parser.parse_text(tap_input)):
    if i == 2:
        print("{!r}".format(l.yaml_block["output"].splitlines()))
```

The output is:

```
['', 'this is a multiline', '', 'string but with tap', '', 'somehow blank lines', '', 'are added to it.']
```

Where as I expected:

```
['this is a multiline', 'string but with tap', 'somehow blank lines', 'are added to it.']
```

I will submit a PR shortly.

Discussion:
codecov-io: # [Codecov](https://codecov.io/gh/python-tap/tappy/pull/112?src=pr&el=h1) Report
> Merging [#112](https://codecov.io/gh/python-tap/tappy/pull/112?src=pr&el=desc) into [master](https://codecov.io/gh/python-tap/tappy/commit/015c21c1a98b88f23844a44e346604f2398b11d5&el=desc) will **not change** coverage.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/python-tap/tappy/pull/112/graphs/tree.svg?width=650&height=150&src=pr&token=ULVfoGuR2p)](https://codecov.io/gh/python-tap/tappy/pull/112?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##            master      #112   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           12        12           
  Lines          599       600    +1     
=========================================
+ Hits           599       600    +1     
```


| [Impacted Files](https://codecov.io/gh/python-tap/tappy/pull/112?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [tap/parser.py](https://codecov.io/gh/python-tap/tappy/pull/112/diff?src=pr&el=tree#diff-dGFwL3BhcnNlci5weQ==) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/python-tap/tappy/pull/112?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/python-tap/tappy/pull/112?src=pr&el=footer). Last update [015c21c...05c6b82](https://codecov.io/gh/python-tap/tappy/pull/112?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/AUTHORS b/AUTHORS
index e87e3b8..3735496 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -3,6 +3,7 @@ tappy was originally created by Matt Layman.
 Contributors
 ------------
 
+* Adeodato Simó
 * Andrew McNamara
 * Chris Clarke
 * Erik Cederstrand
diff --git a/docs/releases.rst b/docs/releases.rst
index dd80f97..7f708c7 100644
--- a/docs/releases.rst
+++ b/docs/releases.rst
@@ -5,6 +5,7 @@ Version 3.1, To Be Released
 ---------------------------
 
 * Add support for Python 3.8.
+* Fix parsing of multi-line strings in YAML blocks (#111)
 
 Version 3.0, Released January 10, 2020
 --------------------------------------
diff --git a/tap/parser.py b/tap/parser.py
index 637436b..2f28bd8 100644
--- a/tap/parser.py
+++ b/tap/parser.py
@@ -181,7 +181,8 @@ WARNING: Optional imports not found, TAP 13 output will be
         try:
             next(fh)
             while indent_match.match(fh.peek()):
-                raw_yaml.append(next(fh).replace(indent, "", 1))
+                yaml_line = next(fh).replace(indent, "", 1)
+                raw_yaml.append(yaml_line.rstrip("\n"))
                 # check for the end and stop adding yaml if encountered
                 if self.yaml_block_end.match(fh.peek()):
                     next(fh)


Test patch:
diff --git a/tap/tests/test_parser.py b/tap/tests/test_parser.py
index 431297a..ac8f3d3 100644
--- a/tap/tests/test_parser.py
+++ b/tap/tests/test_parser.py
@@ -348,7 +348,12 @@ class TestParser(unittest.TestCase):
                  got:
                    - foo
                  expect:
-                   - bar"""
+                   - bar
+               output: |-
+                 a multiline string
+                 must be handled properly
+                 even with | pipes
+                 | here > and: there"""
         )
         parser = Parser()
         lines = []
@@ -358,20 +363,21 @@ class TestParser(unittest.TestCase):
 
         if have_yaml:
             converted_yaml = yaml.safe_load(
-                u"""
+                u'''
                message: test
                severity: fail
                data:
                  got:
                    - foo
                  expect:
-                   - bar"""
+                   - bar
+               output: "a multiline string\\nmust be handled properly\\neven with | pipes\\n| here > and: there"'''
             )
             self.assertEqual(3, len(lines))
             self.assertEqual(13, lines[0].version)
             self.assertEqual(converted_yaml, lines[2].yaml_block)
         else:
-            self.assertEqual(11, len(lines))
+            self.assertEqual(16, len(lines))
             self.assertEqual(13, lines[0].version)
             for l in list(range(3, 11)):
                 self.assertEqual("unknown", lines[l].category)