Add GraphQL simple query support.

We add GraphQL query support. For the moment, variables are not supported.
This commit is contained in:
jcamiel 2022-11-21 15:08:03 +01:00
parent 351fe21a93
commit 65350a71bb
No known key found for this signature in database
GPG Key ID: 07FF11CFD55356CC
20 changed files with 725 additions and 554 deletions

View File

@ -0,0 +1,4 @@
curl 'http://localhost:8000/multilines/plain-text' -H 'Content-Type:' --data $'line1\nline2\nline3\n'
curl 'http://localhost:8000/multilines/json' -H 'Content-Type:' --data $'{\n "foo": "bar"\n "baz": 123456\n}\n'
curl 'http://localhost:8000/multilines/xml' -H 'Content-Type:' --data $'<?xml version="1.0"?>\n<catalog>\n <book id="bk101">\n <author>Gambardella, Matthew</author>\n <title>XML Developer\'s Guide</title>\n <genre>Computer</genre>\n <price>44.95</price>\n <publish_date>2000-10-01</publish_date>\n <description>An in-depth look at creating applications\n with XML.</description>\n </book>\n</catalog>\n'
curl 'http://localhost:8000/multilines/graphql' -H 'Content-Type:' --data '{"query":"{\n hero {\n name\n # Queries can have comments!\n friends {\n name\n }\n }\n}\n"}'

View File

@ -1,6 +1,17 @@
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/multilines/plain-text</span></span>
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># In each request, we sent a multiline body and get</span>
<span class="line"></span><span class="comment"># the same body as response. Request body is tested server side</span>
<span class="line"></span><span class="comment"># and we assert the response here.</span>
<span class="line"></span>
<span class="line"><span class="method">POST</span> <span class="url">http://localhost:8000/multilines/plain-text</span></span>
<span class="multiline"><span class="line">```</span>
<span class="line">line1</span>
<span class="line">line2</span>
<span class="line">line3</span>
<span class="line">```</span></span>
</span><span class="response"><span class="line"></span>
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
<span class="line"></span><span class="comment"># Different ways of testing body response:</span>
<span class="line"></span><span class="comment"># with explicit asserts:</span>
<span class="line section-header">[Asserts]</span>
<span class="line"><span class="query-type">body</span> <span class="predicate-type">==</span> <span class="string">"line1\nline2\nline3\n"</span></span>
<span class="line"><span class="query-type">body</span> <span class="predicate-type">==</span> <span class="multiline"><span class="line">```</span>
@ -8,34 +19,34 @@
<span class="line">line2</span>
<span class="line">line3</span>
<span class="line">```</span></span></span>
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
<span class="line"></span>
<span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/multilines/base64</span></span>
</span><span class="response"><span class="line"></span>
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
<span class="multiline"><span class="line">```base64</span>
<span class="line">TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwg</span>
<span class="line">c2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWdu</span>
<span class="line">YSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlzIG5vc3RydWQgZXhlcmNpdGF0</span>
<span class="line">aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1aXAgZXggZWEgY29tbW9kbyBjb25zZXF1</span>
<span class="line">YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBpbiByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2</span>
<span class="line">ZWxpdCBlc3NlIGNpbGx1bSBkb2xvcmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRl</span>
<span class="line">dXIgc2ludCBvY2NhZWNhdCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1</span>
<span class="line">aSBvZmZpY2lhIGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg==</span>
<span class="line"></span><span class="comment"># Or we can just test the body (implicit assert):</span>
<span class="multiline"><span class="line">```</span>
<span class="line">line1</span>
<span class="line">line2</span>
<span class="line">line3</span>
<span class="line">```</span></span>
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
<span class="line"></span>
<span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/multilines/hex</span></span>
</span><span class="response"><span class="line"></span>
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
<span class="multiline"><span class="line">```hex</span>
<span class="line">039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81</span>
<span class="line"><span class="method">POST</span> <span class="url">http://localhost:8000/multilines/json</span></span>
<span class="multiline"><span class="line">```json</span>
<span class="line">{</span>
<span class="line"> "foo": "bar"</span>
<span class="line"> "baz": 123456</span>
<span class="line">}</span>
<span class="line">```</span></span>
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
<span class="line"></span>
<span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/multilines/json</span></span>
</span><span class="response"><span class="line"></span>
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
<span class="line"></span><span class="comment"># Different ways of testing body response:</span>
<span class="line"></span><span class="comment"># with explicit asserts:</span>
<span class="line section-header">[Asserts]</span>
<span class="line"><span class="query-type">body</span> <span class="predicate-type">==</span> <span class="string">"{\n \"foo\": \"bar\"\n \"baz\": 123456\n}\n"</span></span>
<span class="line"><span class="query-type">body</span> <span class="predicate-type">==</span> <span class="multiline"><span class="line">```json</span>
<span class="line">{</span>
<span class="line"> "foo": "bar"</span>
<span class="line"> "baz": 123456</span>
<span class="line">}</span>
<span class="line">```</span></span></span>
<span class="line"></span><span class="comment"># Or we can just test the body (implicit assert):</span>
<span class="multiline"><span class="line">```json</span>
<span class="line">{</span>
<span class="line"> "foo": "bar"</span>
@ -44,28 +55,89 @@
<span class="line">```</span></span>
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
<span class="line"></span>
<span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/multilines/xml</span></span>
</span><span class="response"><span class="line"></span>
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
<span class="line"></span>
<span class="line"><span class="method">POST</span> <span class="url">http://localhost:8000/multilines/xml</span></span>
<span class="multiline"><span class="line">```xml</span>
<span class="line">&lt;?xml version="1.0"?&gt;</span>
<span class="line">&lt;catalog&gt;</span>
<span class="line"> &lt;book id="bk101"&gt;</span>
<span class="line"> &lt;author&gt;Gambardella, Matthew&lt;/author&gt;</span>
<span class="line"> &lt;title&gt;XML Developer's Guide&lt;/title&gt;</span>
<span class="line"> &lt;genre&gt;Computer&lt;/genre&gt;</span>
<span class="line"> &lt;price&gt;44.95&lt;/price&gt;</span>
<span class="line"> &lt;publish_date&gt;2000-10-01&lt;/publish_date&gt;</span>
<span class="line"> &lt;description&gt;An in-depth look at creating applications</span>
<span class="line"> with XML.&lt;/description&gt;</span>
<span class="line"> &lt;/book&gt;</span>
<span class="line"> &lt;book id="bk101"&gt;</span>
<span class="line"> &lt;author&gt;Gambardella, Matthew&lt;/author&gt;</span>
<span class="line"> &lt;title&gt;XML Developer's Guide&lt;/title&gt;</span>
<span class="line"> &lt;genre&gt;Computer&lt;/genre&gt;</span>
<span class="line"> &lt;price&gt;44.95&lt;/price&gt;</span>
<span class="line"> &lt;publish_date&gt;2000-10-01&lt;/publish_date&gt;</span>
<span class="line"> &lt;description&gt;An in-depth look at creating applications</span>
<span class="line"> with XML.&lt;/description&gt;</span>
<span class="line"> &lt;/book&gt;</span>
<span class="line">&lt;/catalog&gt;</span>
<span class="line">```</span></span>
</span><span class="response"><span class="line"></span>
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
<span class="line"></span><span class="comment"># Different ways of testing body response:</span>
<span class="line"></span><span class="comment"># with explicit asserts:</span>
<span class="line section-header">[Asserts]</span>
<span class="line"><span class="query-type">body</span> <span class="predicate-type">==</span> <span class="string">"&lt;?xml version=\"1.0\"?&gt;\n&lt;catalog&gt;\n &lt;book id=\"bk101\"&gt;\n &lt;author&gt;Gambardella, Matthew&lt;/author&gt;\n &lt;title&gt;XML Developer's Guide&lt;/title&gt;\n &lt;genre&gt;Computer&lt;/genre&gt;\n &lt;price&gt;44.95&lt;/price&gt;\n &lt;publish_date&gt;2000-10-01&lt;/publish_date&gt;\n &lt;description&gt;An in-depth look at creating applications\n with XML.&lt;/description&gt;\n &lt;/book&gt;\n&lt;/catalog&gt;\n"</span></span>
<span class="line"><span class="query-type">body</span> <span class="predicate-type">==</span> <span class="multiline"><span class="line">```xml</span>
<span class="line">&lt;?xml version="1.0"?&gt;</span>
<span class="line">&lt;catalog&gt;</span>
<span class="line"> &lt;book id="bk101"&gt;</span>
<span class="line"> &lt;author&gt;Gambardella, Matthew&lt;/author&gt;</span>
<span class="line"> &lt;title&gt;XML Developer's Guide&lt;/title&gt;</span>
<span class="line"> &lt;genre&gt;Computer&lt;/genre&gt;</span>
<span class="line"> &lt;price&gt;44.95&lt;/price&gt;</span>
<span class="line"> &lt;publish_date&gt;2000-10-01&lt;/publish_date&gt;</span>
<span class="line"> &lt;description&gt;An in-depth look at creating applications</span>
<span class="line"> with XML.&lt;/description&gt;</span>
<span class="line"> &lt;/book&gt;</span>
<span class="line">&lt;/catalog&gt;</span>
<span class="line">```</span></span></span>
<span class="line"></span><span class="comment"># Or we can just test the body (implicit assert):</span>
<span class="multiline"><span class="line">```xml</span>
<span class="line">&lt;?xml version="1.0"?&gt;</span>
<span class="line">&lt;catalog&gt;</span>
<span class="line"> &lt;book id="bk101"&gt;</span>
<span class="line"> &lt;author&gt;Gambardella, Matthew&lt;/author&gt;</span>
<span class="line"> &lt;title&gt;XML Developer's Guide&lt;/title&gt;</span>
<span class="line"> &lt;genre&gt;Computer&lt;/genre&gt;</span>
<span class="line"> &lt;price&gt;44.95&lt;/price&gt;</span>
<span class="line"> &lt;publish_date&gt;2000-10-01&lt;/publish_date&gt;</span>
<span class="line"> &lt;description&gt;An in-depth look at creating applications</span>
<span class="line"> with XML.&lt;/description&gt;</span>
<span class="line"> &lt;/book&gt;</span>
<span class="line">&lt;/catalog&gt;</span>
<span class="line">```</span></span>
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
<span class="line"></span>
<span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/multilines/graphql</span></span>
</span><span class="response"><span class="line"></span>
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
<span class="line"></span>
<span class="line"><span class="method">POST</span> <span class="url">http://localhost:8000/multilines/graphql</span></span>
<span class="multiline"><span class="line">```graphql</span>
<span class="line">{</span>
<span class="line"> hero {</span>
<span class="line"> name</span>
<span class="line"> # Queries can have comments!</span>
<span class="line"> friends {</span>
<span class="line"> name</span>
<span class="line"> }</span>
<span class="line"> }</span>
<span class="line">}</span>
<span class="line">```</span></span>
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
<span class="line"></span><span class="comment"># Different ways of testing body response:</span>
<span class="line"></span><span class="comment"># with explicit asserts:</span>
<span class="line section-header">[Asserts]</span>
<span class="line"><span class="query-type">body</span> <span class="predicate-type">==</span> <span class="string">"{\"query\":\"{\\n hero {\\n name\\n # Queries can have comments!\\n friends {\\n name\\n }\\n }\\n}\\n\"}"</span></span>
<span class="line"><span class="query-type">body</span> <span class="predicate-type">==</span> <span class="multiline"><span class="line">```graphql</span>
<span class="line">{</span>
<span class="line"> hero {</span>
<span class="line"> name</span>
<span class="line"> # Queries can have comments!</span>
<span class="line"> friends {</span>
<span class="line"> name</span>
<span class="line"> }</span>
<span class="line"> }</span>
<span class="line">}</span>
<span class="line">```</span></span></span>
<span class="line"></span><span class="comment"># Or we can just test the body (implicit assert):</span>
<span class="multiline"><span class="line">```graphql</span>
<span class="line">{</span>
<span class="line"> hero {</span>

View File

@ -1,6 +1,17 @@
GET http://localhost:8000/multilines/plain-text
# In each request, we sent a multiline body and get
# the same body as response. Request body is tested server side
# and we assert the response here.
POST http://localhost:8000/multilines/plain-text
```
line1
line2
line3
```
HTTP 200
# Different ways of testing body response:
# with explicit asserts:
[Asserts]
body == "line1\nline2\nline3\n"
body == ```
@ -8,34 +19,34 @@ line1
line2
line3
```
GET http://localhost:8000/multilines/base64
HTTP 200
```base64
TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwg
c2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWdu
YSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlzIG5vc3RydWQgZXhlcmNpdGF0
aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1aXAgZXggZWEgY29tbW9kbyBjb25zZXF1
YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBpbiByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2
ZWxpdCBlc3NlIGNpbGx1bSBkb2xvcmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRl
dXIgc2ludCBvY2NhZWNhdCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1
aSBvZmZpY2lhIGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg==
# Or we can just test the body (implicit assert):
```
line1
line2
line3
```
GET http://localhost:8000/multilines/hex
HTTP 200
```hex
039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81
POST http://localhost:8000/multilines/json
```json
{
"foo": "bar"
"baz": 123456
}
```
GET http://localhost:8000/multilines/json
HTTP 200
# Different ways of testing body response:
# with explicit asserts:
[Asserts]
body == "{\n \"foo\": \"bar\"\n \"baz\": 123456\n}\n"
body == ```json
{
"foo": "bar"
"baz": 123456
}
```
# Or we can just test the body (implicit assert):
```json
{
"foo": "bar"
@ -44,28 +55,89 @@ HTTP 200
```
GET http://localhost:8000/multilines/xml
HTTP 200
POST http://localhost:8000/multilines/xml
```xml
<?xml version="1.0"?>
<catalog>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
</catalog>
```
HTTP 200
# Different ways of testing body response:
# with explicit asserts:
[Asserts]
body == "<?xml version=\"1.0\"?>\n<catalog>\n <book id=\"bk101\">\n <author>Gambardella, Matthew</author>\n <title>XML Developer's Guide</title>\n <genre>Computer</genre>\n <price>44.95</price>\n <publish_date>2000-10-01</publish_date>\n <description>An in-depth look at creating applications\n with XML.</description>\n </book>\n</catalog>\n"
body == ```xml
<?xml version="1.0"?>
<catalog>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
</catalog>
```
# Or we can just test the body (implicit assert):
```xml
<?xml version="1.0"?>
<catalog>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
</catalog>
```
GET http://localhost:8000/multilines/graphql
HTTP 200
POST http://localhost:8000/multilines/graphql
```graphql
{
hero {
name
# Queries can have comments!
friends {
name
}
}
}
```
HTTP 200
# Different ways of testing body response:
# with explicit asserts:
[Asserts]
body == "{\"query\":\"{\\n hero {\\n name\\n # Queries can have comments!\\n friends {\\n name\\n }\\n }\\n}\\n\"}"
body == ```graphql
{
hero {
name
# Queries can have comments!
friends {
name
}
}
}
```
# Or we can just test the body (implicit assert):
```graphql
{
hero {

View File

@ -1 +1 @@
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/multilines/plain-text"},"response":{"status":200,"asserts":[{"query":{"type":"body"},"predicate":{"type":"equal","value":"line1\nline2\nline3\n"}},{"query":{"type":"body"},"predicate":{"type":"equal","value":"line1\nline2\nline3\n"}}]}},{"request":{"method":"GET","url":"http://localhost:8000/multilines/base64"},"response":{"status":200,"body":{"type":"base64","value":"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwg\nc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWdu\nYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlzIG5vc3RydWQgZXhlcmNpdGF0\naW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1aXAgZXggZWEgY29tbW9kbyBjb25zZXF1\nYXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBpbiByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2\nZWxpdCBlc3NlIGNpbGx1bSBkb2xvcmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRl\ndXIgc2ludCBvY2NhZWNhdCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1\naSBvZmZpY2lhIGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg==\n"}}},{"request":{"method":"GET","url":"http://localhost:8000/multilines/hex"},"response":{"status":200,"body":{"type":"hex","value":"039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81\n"}}},{"request":{"method":"GET","url":"http://localhost:8000/multilines/json"},"response":{"status":200,"body":{"type":"json","value":"{\n \"foo\": \"bar\"\n \"baz\": 123456\n}\n"}}},{"request":{"method":"GET","url":"http://localhost:8000/multilines/xml"},"response":{"status":200,"body":{"type":"xml","value":"<?xml version=\"1.0\"?>\n<catalog>\n <book id=\"bk101\">\n <author>Gambardella, Matthew</author>\n <title>XML Developer's Guide</title>\n <genre>Computer</genre>\n <price>44.95</price>\n <publish_date>2000-10-01</publish_date>\n <description>An in-depth look at creating applications\n with XML.</description>\n </book>\n</catalog>\n"}}},{"request":{"method":"GET","url":"http://localhost:8000/multilines/graphql"},"response":{"status":200,"body":{"type":"graphql","value":"{\n hero {\n name\n # Queries can have comments!\n friends {\n name\n }\n }\n}\n"}}}]}
{"entries":[{"request":{"method":"POST","url":"http://localhost:8000/multilines/plain-text","body":{"type":"multiline-string","value":"line1\nline2\nline3\n"}},"response":{"status":200,"asserts":[{"query":{"type":"body"},"predicate":{"type":"equal","value":"line1\nline2\nline3\n"}},{"query":{"type":"body"},"predicate":{"type":"equal","value":"line1\nline2\nline3\n"}}],"body":{"type":"multiline-string","value":"line1\nline2\nline3\n"}}},{"request":{"method":"POST","url":"http://localhost:8000/multilines/json","body":{"type":"json","value":"{\n \"foo\": \"bar\"\n \"baz\": 123456\n}\n"}},"response":{"status":200,"asserts":[{"query":{"type":"body"},"predicate":{"type":"equal","value":"{\n \"foo\": \"bar\"\n \"baz\": 123456\n}\n"}},{"query":{"type":"body"},"predicate":{"type":"equal","value":"{\n \"foo\": \"bar\"\n \"baz\": 123456\n}\n"}}],"body":{"type":"json","value":"{\n \"foo\": \"bar\"\n \"baz\": 123456\n}\n"}}},{"request":{"method":"POST","url":"http://localhost:8000/multilines/xml","body":{"type":"xml","value":"<?xml version=\"1.0\"?>\n<catalog>\n <book id=\"bk101\">\n <author>Gambardella, Matthew</author>\n <title>XML Developer's Guide</title>\n <genre>Computer</genre>\n <price>44.95</price>\n <publish_date>2000-10-01</publish_date>\n <description>An in-depth look at creating applications\n with XML.</description>\n </book>\n</catalog>\n"}},"response":{"status":200,"asserts":[{"query":{"type":"body"},"predicate":{"type":"equal","value":"<?xml version=\"1.0\"?>\n<catalog>\n <book id=\"bk101\">\n <author>Gambardella, Matthew</author>\n <title>XML Developer's Guide</title>\n <genre>Computer</genre>\n <price>44.95</price>\n <publish_date>2000-10-01</publish_date>\n <description>An in-depth look at creating applications\n with XML.</description>\n </book>\n</catalog>\n"}},{"query":{"type":"body"},"predicate":{"type":"equal","value":"<?xml version=\"1.0\"?>\n<catalog>\n <book id=\"bk101\">\n <author>Gambardella, Matthew</author>\n <title>XML Developer's Guide</title>\n <genre>Computer</genre>\n <price>44.95</price>\n <publish_date>2000-10-01</publish_date>\n <description>An in-depth look at creating applications\n with XML.</description>\n </book>\n</catalog>\n"}}],"body":{"type":"xml","value":"<?xml version=\"1.0\"?>\n<catalog>\n <book id=\"bk101\">\n <author>Gambardella, Matthew</author>\n <title>XML Developer's Guide</title>\n <genre>Computer</genre>\n <price>44.95</price>\n <publish_date>2000-10-01</publish_date>\n <description>An in-depth look at creating applications\n with XML.</description>\n </book>\n</catalog>\n"}}},{"request":{"method":"POST","url":"http://localhost:8000/multilines/graphql","body":{"type":"graphql","value":"{\n hero {\n name\n # Queries can have comments!\n friends {\n name\n }\n }\n}\n"}},"response":{"status":200,"asserts":[{"query":{"type":"body"},"predicate":{"type":"equal","value":"{\"query\":\"{\\n hero {\\n name\\n # Queries can have comments!\\n friends {\\n name\\n }\\n }\\n}\\n\"}"}},{"query":{"type":"body"},"predicate":{"type":"equal","value":"{\n hero {\n name\n # Queries can have comments!\n friends {\n name\n }\n }\n}\n"}}],"body":{"type":"graphql","value":"{\n hero {\n name\n # Queries can have comments!\n friends {\n name\n }\n }\n}\n"}}}]}

View File

@ -0,0 +1 @@
{"query":"{\n hero {\n name\n # Queries can have comments!\n friends {\n name\n }\n }\n}\n"}

View File

@ -1,68 +1,52 @@
from app import app
from flask import request
@app.route("/multilines/plain-text")
@app.route("/multilines/plain-text", methods=["POST"])
def multilines_plain_text():
return "line1\nline2\nline3\n"
expected_body = "line1\nline2\nline3\n"
body_in = request.data.decode("utf-8")
assert expected_body == body_in
return expected_body
@app.route("/multilines/base64")
def multilines_base64():
return """\
TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwg
c2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWdu
YSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlzIG5vc3RydWQgZXhlcmNpdGF0
aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1aXAgZXggZWEgY29tbW9kbyBjb25zZXF1
YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBpbiByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2
ZWxpdCBlc3NlIGNpbGx1bSBkb2xvcmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRl
dXIgc2ludCBvY2NhZWNhdCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1
aSBvZmZpY2lhIGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg==
"""
@app.route("/multilines/json")
@app.route("/multilines/json", methods=["POST"])
def multilines_json():
return """\
expected_body = """\
{
"foo": "bar"
"baz": 123456
}
"""
body_in = request.data.decode("utf-8")
assert expected_body == body_in
return expected_body
@app.route("/multilines/hex")
def multilines_hex():
return "039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81\n"
@app.route("/multilines/xml")
@app.route("/multilines/xml", methods=["POST"])
def multilines_xml():
return """\
expected_body = """\
<?xml version="1.0"?>
<catalog>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
</catalog>
"""
body_in = request.data.decode("utf-8")
assert expected_body == body_in
return expected_body
@app.route("/multilines/graphql")
@app.route("/multilines/graphql", methods=["POST"])
def multilines_graphql():
return """\
{
hero {
name
# Queries can have comments!
friends {
name
}
}
}
"""
expected_body = r'{"query":"{\n hero {\n name\n # Queries can have comments!\n friends {\n name\n }\n }\n}\n"}'
body_in = request.data.decode("utf-8")
assert expected_body == body_in
return expected_body

View File

@ -23,10 +23,10 @@ use hurl_core::ast::*;
use super::core::{Error, RunnerError};
use super::json::eval_json_value;
use super::template::eval_template;
use super::value::Value;
use crate::http;
use crate::http::ContextDir;
use crate::runner::multiline::eval_multiline;
pub fn eval_body(
body: &Body,
@ -42,9 +42,8 @@ pub fn eval_bytes(
context_dir: &ContextDir,
) -> Result<http::Body, Error> {
match bytes {
// Body::Text
Bytes::MultilineString(MultilineString { value, .. }) => {
let value = eval_template(value, variables)?;
Bytes::MultilineString(value) => {
let value = eval_multiline(value, variables)?;
Ok(http::Body::Text(value))
}
Bytes::Xml { value, .. } => Ok(http::Body::Text(value.clone())),

View File

@ -40,6 +40,7 @@ mod expr;
mod filter;
mod hurl_file;
mod json;
mod multiline;
mod multipart;
mod predicate;
mod predicate_value;

View File

@ -0,0 +1,45 @@
/*
* Hurl (https://hurl.dev)
* Copyright (C) 2022 Orange
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
use crate::runner::template::eval_template;
use crate::runner::{Error, Value};
use hurl_core::ast::{GraphQl, MultilineString, Text};
use serde_json::json;
use std::collections::HashMap;
pub fn eval_multiline(
multiline: &MultilineString,
variables: &HashMap<String, Value>,
) -> Result<String, Error> {
match multiline {
MultilineString::TextOneline(value) => {
let s = eval_template(value, variables)?;
Ok(s)
}
MultilineString::Text(Text { value, .. })
| MultilineString::Json(Text { value, .. })
| MultilineString::Xml(Text { value, .. }) => {
let s = eval_template(value, variables)?;
Ok(s)
}
MultilineString::GraphQl(GraphQl { value, .. }) => {
let query = eval_template(value, variables)?;
let body = json!({ "query": query });
Ok(body.to_string())
}
}
}

View File

@ -17,6 +17,7 @@
*/
use std::collections::HashMap;
use crate::runner::multiline::eval_multiline;
use hurl_core::ast::*;
use super::core::Error;
@ -34,7 +35,7 @@ pub fn eval_predicate_value(
Ok(Value::String(s))
}
PredicateValue::MultilineString(value) => {
let s = eval_template(&value.value, variables)?;
let s = eval_multiline(value, variables)?;
Ok(Value::String(s))
}
PredicateValue::Integer(value) => Ok(Value::Integer(*value)),

View File

@ -19,6 +19,7 @@ use std::collections::HashMap;
use crate::http;
use crate::http::ContextDir;
use crate::runner::multiline::eval_multiline;
use hurl_core::ast::*;
use super::assert::eval_assert;
@ -179,8 +180,8 @@ fn eval_implicit_body_asserts(
source_info: spec_body.space0.source_info.clone(),
}
}
Bytes::MultilineString(MultilineString { value, .. }) => {
let expected = match eval_template(value, variables) {
Bytes::MultilineString(multi) => {
let expected = match eval_multiline(multi, variables) {
Ok(s) => Ok(Value::String(s)),
Err(e) => Err(e),
};
@ -198,7 +199,7 @@ fn eval_implicit_body_asserts(
AssertResult::Body {
actual,
expected,
source_info: value.source_info.clone(),
source_info: multi.value().source_info,
}
}
Bytes::Base64(Base64 {

View File

@ -16,6 +16,7 @@
*
*/
use super::json;
use crate::ast::JsonValue;
///
/// Hurl AST
@ -479,27 +480,41 @@ pub enum PredicateFuncValue {
//
// Primitives
//
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MultilineString {
// FIXME: temporary type until we implement oneline as `foo` instead of ```foo```
TextOneline(Template),
Text(Text),
Json(Text),
Xml(Text),
GraphQl(GraphQl),
}
impl MultilineString {
pub fn value(&self) -> Template {
match self {
MultilineString::TextOneline(template) => template.clone(),
MultilineString::Text(text)
| MultilineString::Json(text)
| MultilineString::Xml(text) => text.value.clone(),
MultilineString::GraphQl(text) => text.value.clone(),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MultilineString {
pub lang: Option<Lang>,
pub struct Text {
pub space: Whitespace,
pub newline: Whitespace,
pub value: Template,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Lang {
pub value: Option<LangValue>,
pub struct GraphQl {
pub space: Whitespace,
pub newline: Whitespace,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum LangValue {
Base64,
Hex,
Json,
Xml,
GraphQl,
pub value: Template,
pub variables: Option<JsonValue>,
}
#[derive(Clone, Debug, PartialEq, Eq)]

View File

@ -128,19 +128,6 @@ impl fmt::Display for CookieAttribute {
}
}
impl fmt::Display for LangValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = match self {
LangValue::Base64 => "base64",
LangValue::Hex => "hex",
LangValue::Json => "json",
LangValue::Xml => "xml",
LangValue::GraphQl => "graphql",
};
write!(f, "{}", s)
}
}
impl fmt::Display for Hex {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(

View File

@ -400,6 +400,7 @@ impl Htmlable for VariableOption {
buffer
}
}
impl Htmlable for VariableDefinition {
fn to_html(&self) -> String {
let mut buffer = String::from("");
@ -626,6 +627,7 @@ impl Htmlable for QueryValue {
buffer
}
}
impl Htmlable for RegexValue {
fn to_html(&self) -> String {
match self {
@ -860,20 +862,21 @@ impl Htmlable for PredicateValue {
impl Htmlable for MultilineString {
fn to_html(&self) -> String {
let mut buffer = "".to_string();
buffer.push_str("<span class=\"multiline\">");
let mut s = "```".to_string();
if let Some(lang) = &self.lang {
if let Some(lang_value) = &lang.value {
s.push_str(format!("{}", lang_value).as_str());
let lang = match self {
MultilineString::TextOneline(_) => {
let s = format!("```{value}```", value = self.value());
let buffer = multilines(&s);
return format!("<span class=\"multiline\">{}</span>", buffer);
}
s.push('\n');
}
s.push_str(self.value.to_string().as_str());
s.push_str("```");
buffer.push_str(multilines(s).as_str());
buffer.push_str("</span>");
buffer
MultilineString::Text(_) => "",
MultilineString::Json(_) => "json",
MultilineString::Xml(_) => "xml",
MultilineString::GraphQl(_) => "graphql",
};
let s = format!("```{lang}\n{value}```", lang = lang, value = self.value());
let buffer = multilines(&s);
format!("<span class=\"multiline\">{}</span>", buffer)
}
}
@ -904,12 +907,12 @@ impl Htmlable for Bytes {
// you should probably define for XML value to be consistent with the other types
fn xml_html(value: &str) -> String {
let mut buffer = String::from("<span class=\"xml\">");
buffer.push_str(multilines(value.to_string()).as_str());
buffer.push_str(multilines(value).as_str());
buffer.push_str("</span>");
buffer
}
fn xml_escape(s: String) -> String {
fn xml_escape(s: &str) -> String {
s.replace('&', "&amp;")
.replace('<', "&lt;")
.replace('>', "&gt;")
@ -919,7 +922,7 @@ fn xml_escape(s: String) -> String {
impl Htmlable for JsonValue {
fn to_html(&self) -> String {
let mut buffer = String::from("<span class=\"json\">");
buffer.push_str(multilines(self.encoded()).as_str());
buffer.push_str(multilines(&self.encoded()).as_str());
buffer.push_str("</span>");
buffer
}
@ -951,7 +954,7 @@ impl Htmlable for LineTerminator {
impl Htmlable for Comment {
fn to_html(&self) -> String {
let mut buffer = String::from("<span class=\"comment\">");
buffer.push_str(format!("#{}", xml_escape(self.value.clone())).as_str());
buffer.push_str(format!("#{}", xml_escape(&self.value)).as_str());
buffer.push_str("</span>");
buffer
}
@ -997,6 +1000,7 @@ impl Htmlable for Regex {
format!("<span class=\"regex\">/{}/</span>", s)
}
}
impl Htmlable for EncodedString {
fn to_html(&self) -> String {
format!("<span class=\"string\">{}</span>", self.encoded)
@ -1013,7 +1017,7 @@ impl Htmlable for Template {
};
s.push_str(elem_str.as_str())
}
xml_escape(s)
xml_escape(&s)
}
}
@ -1065,11 +1069,11 @@ fn encode_html(s: String) -> String {
s.replace('>', "&gt;").replace('<', "&lt;")
}
fn multilines(s: String) -> String {
fn multilines(s: &str) -> String {
regex::Regex::new(r"\n|\r\n")
.unwrap()
.split(s.as_str())
.map(|l| format!("<span class=\"line\">{}</span>", xml_escape(l.to_string())))
.split(s)
.map(|l| format!("<span class=\"line\">{}</span>", xml_escape(l)))
.collect::<Vec<String>>()
.join("\n")
}
@ -1081,34 +1085,28 @@ mod tests {
#[test]
fn test_multiline_string() {
// ``````
let multiline_string = MultilineString {
lang: None,
value: Template {
quotes: false,
elements: vec![TemplateElement::String {
value: "".to_string(),
encoded: "unused".to_string(),
}],
source_info: SourceInfo::new(0, 0, 0, 0),
},
};
let multiline_string = MultilineString::TextOneline(Template {
quotes: false,
elements: vec![TemplateElement::String {
value: "".to_string(),
encoded: "unused".to_string(),
}],
source_info: SourceInfo::new(0, 0, 0, 0),
});
assert_eq!(
multiline_string.to_html(),
"<span class=\"multiline\"><span class=\"line\">``````</span></span>".to_string()
);
// ```hello```
let multiline_string = MultilineString {
lang: None,
value: Template {
quotes: false,
elements: vec![TemplateElement::String {
value: "hello".to_string(),
encoded: "unused".to_string(),
}],
source_info: SourceInfo::new(0, 0, 0, 0),
},
};
let multiline_string = MultilineString::TextOneline(Template {
quotes: false,
elements: vec![TemplateElement::String {
value: "hello".to_string(),
encoded: "unused".to_string(),
}],
source_info: SourceInfo::new(0, 0, 0, 0),
});
assert_eq!(
multiline_string.to_html(),
"<span class=\"multiline\"><span class=\"line\">```hello```</span></span>".to_string()
@ -1118,24 +1116,21 @@ mod tests {
// line1
// line2
// ```
let multiline_string = MultilineString {
lang: Some(Lang {
value: None,
space: Whitespace {
value: "".to_string(),
source_info: SourceInfo {
start: Pos { line: 1, column: 4 },
end: Pos { line: 1, column: 4 },
},
let multiline_string = MultilineString::Text(Text {
space: Whitespace {
value: "".to_string(),
source_info: SourceInfo {
start: Pos { line: 1, column: 4 },
end: Pos { line: 1, column: 4 },
},
newline: Whitespace {
value: "\n".to_string(),
source_info: SourceInfo {
start: Pos { line: 1, column: 4 },
end: Pos { line: 2, column: 1 },
},
},
newline: Whitespace {
value: "\n".to_string(),
source_info: SourceInfo {
start: Pos { line: 1, column: 4 },
end: Pos { line: 2, column: 1 },
},
}),
},
value: Template {
quotes: false,
elements: vec![TemplateElement::String {
@ -1144,7 +1139,7 @@ mod tests {
}],
source_info: SourceInfo::new(0, 0, 0, 0),
},
};
});
assert_eq!(
multiline_string.to_html(),
"<span class=\"multiline\"><span class=\"line\">```</span>\n<span class=\"line\">line1</span>\n<span class=\"line\">line2</span>\n<span class=\"line\">```</span></span>".to_string()
@ -1154,16 +1149,16 @@ mod tests {
#[test]
fn test_multilines() {
assert_eq!(
multilines("{\n \"id\": 1\n}".to_string()),
multilines("{\n \"id\": 1\n}"),
"<span class=\"line\">{</span>\n<span class=\"line\"> \"id\": 1</span>\n<span class=\"line\">}</span>"
);
assert_eq!(
multilines("<?xml version=\"1.0\"?>\n<drink>café</drink>".to_string()),
multilines("<?xml version=\"1.0\"?>\n<drink>café</drink>"),
"<span class=\"line\">&lt;?xml version=\"1.0\"?&gt;</span>\n<span class=\"line\">&lt;drink&gt;café&lt;/drink&gt;</span>"
);
assert_eq!(
multilines("Hello\n".to_string()),
multilines("Hello\n"),
"<span class=\"line\">Hello</span>\n<span class=\"line\"></span>"
);
}
@ -1221,9 +1216,9 @@ mod tests {
#[test]
fn test_xml_escape() {
assert_eq!(xml_escape("hello".to_string()), "hello");
assert_eq!(xml_escape("hello"), "hello");
assert_eq!(
xml_escape("<?xml version=\"1.0\"?>".to_string()),
xml_escape("<?xml version=\"1.0\"?>"),
"&lt;?xml version=\"1.0\"?&gt;"
);
}

View File

@ -167,20 +167,14 @@ mod tests {
fn test_bytes_multilines_error() {
let mut reader = Reader::init("```\nxxx ");
let error = bytes(&mut reader).err().unwrap();
assert_eq!(error.pos, Pos { line: 2, column: 5 });
assert_eq!(
error.inner,
ParseError::Expecting {
value: String::from("```")
}
);
assert_eq!(error.pos, Pos { line: 1, column: 4 });
assert_eq!(error.inner, ParseError::Multiline);
}
#[test]
fn test_bytes_eof() {
let mut reader = Reader::init("");
let error = bytes(&mut reader).err().unwrap();
//println!("{:?}", error);
assert_eq!(
error.inner,
ParseError::Expecting {

View File

@ -26,32 +26,62 @@ pub fn multiline_string(reader: &mut Reader) -> ParseResult<'static, MultilineSt
try_literal("```", reader)?;
let save = reader.state.clone();
match choice(
&[
base64_lang,
hex_lang,
json_lang,
xml_lang,
graphql_lang,
undefined_lang,
],
reader,
) {
Ok(lang) => {
let value = multiline_string_value(reader)?;
Ok(MultilineString {
value,
lang: Some(lang),
})
}
match choice(&[json_text, xml_text, graphql, plain_text], reader) {
Ok(multi) => Ok(multi),
Err(_) => {
reader.state = save;
let value = oneline_string_value(reader)?;
Ok(MultilineString { value, lang: None })
Ok(MultilineString::TextOneline(value))
}
}
}
fn text(lang: &str, reader: &mut Reader) -> ParseResult<'static, Text> {
try_literal(lang, reader)?;
let space = zero_or_more_spaces(reader)?;
let newline = newline(reader)?;
let value = multiline_string_value(reader)?;
Ok(Text {
space,
newline,
value,
})
}
fn json_text(reader: &mut Reader) -> ParseResult<'static, MultilineString> {
let text = text("json", reader)?;
Ok(MultilineString::Json(text))
}
fn xml_text(reader: &mut Reader) -> ParseResult<'static, MultilineString> {
let text = text("xml", reader)?;
Ok(MultilineString::Xml(text))
}
fn graphql(reader: &mut Reader) -> ParseResult<'static, MultilineString> {
try_literal("graphql", reader)?;
let space = zero_or_more_spaces(reader)?;
let newline = newline(reader)?;
let value = multiline_string_value(reader)?;
Ok(MultilineString::GraphQl(GraphQl {
space,
newline,
value,
variables: None,
}))
}
fn plain_text(reader: &mut Reader) -> ParseResult<'static, MultilineString> {
let space = zero_or_more_spaces(reader)?;
let newline = newline(reader)?;
let value = multiline_string_value(reader)?;
Ok(MultilineString::Text(Text {
space,
newline,
value,
}))
}
fn multiline_string_value(reader: &mut Reader) -> ParseResult<'static, Template> {
let mut chars = vec![];
@ -117,159 +147,134 @@ fn oneline_string_value(reader: &mut Reader) -> ParseResult<'static, Template> {
})
}
fn undefined_lang(reader: &mut Reader) -> ParseResult<'static, Lang> {
let space = zero_or_more_spaces(reader)?;
let newline = newline(reader)?;
Ok(Lang {
value: None,
space,
newline,
})
}
fn base64_lang(reader: &mut Reader) -> ParseResult<'static, Lang> {
try_literal("base64", reader)?;
let space = zero_or_more_spaces(reader)?;
let newline = newline(reader)?;
Ok(Lang {
value: Some(LangValue::Base64),
space,
newline,
})
}
fn hex_lang(reader: &mut Reader) -> ParseResult<'static, Lang> {
try_literal("hex", reader)?;
let space = zero_or_more_spaces(reader)?;
let newline = newline(reader)?;
Ok(Lang {
value: Some(LangValue::Hex),
space,
newline,
})
}
fn json_lang(reader: &mut Reader) -> ParseResult<'static, Lang> {
try_literal("json", reader)?;
let space = zero_or_more_spaces(reader)?;
let newline = newline(reader)?;
Ok(Lang {
value: Some(LangValue::Json),
space,
newline,
})
}
fn xml_lang(reader: &mut Reader) -> ParseResult<'static, Lang> {
try_literal("xml", reader)?;
let space = zero_or_more_spaces(reader)?;
let newline = newline(reader)?;
Ok(Lang {
value: Some(LangValue::Xml),
space,
newline,
})
}
fn graphql_lang(reader: &mut Reader) -> ParseResult<'static, Lang> {
try_literal("graphql", reader)?;
let space = zero_or_more_spaces(reader)?;
let newline = newline(reader)?;
Ok(Lang {
value: Some(LangValue::GraphQl),
space,
newline,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_base64_multiline_string_type() {
let mut reader = Reader::init("base64\nxxxx");
fn test_multiline_string_undefined() {
let mut reader = Reader::init("```\nline1\nline2\nline3\n```");
assert_eq!(
base64_lang(&mut reader).unwrap(),
Lang {
value: Some(LangValue::Base64),
multiline_string(&mut reader).unwrap(),
MultilineString::Text(Text {
space: Whitespace {
value: String::from(""),
source_info: SourceInfo::new(1, 7, 1, 7),
value: "".to_string(),
source_info: SourceInfo::new(1, 4, 1, 4),
},
newline: Whitespace {
value: "\n".to_string(),
source_info: SourceInfo::new(1, 7, 2, 1)
}
}
source_info: SourceInfo::new(1, 4, 2, 1),
},
value: Template {
quotes: false,
elements: vec![TemplateElement::String {
value: "line1\nline2\nline3\n".to_string(),
encoded: "line1\nline2\nline3\n".to_string(),
}],
source_info: SourceInfo::new(2, 1, 5, 1),
},
})
);
let mut reader = Reader::init("``` \nline1\nline2\nline3\n```");
assert_eq!(
multiline_string(&mut reader).unwrap(),
MultilineString::Text(Text {
space: Whitespace {
value: " ".to_string(),
source_info: SourceInfo::new(1, 4, 1, 13),
},
newline: Whitespace {
value: "\n".to_string(),
source_info: SourceInfo::new(1, 13, 2, 1),
},
value: Template {
quotes: false,
elements: vec![TemplateElement::String {
value: "line1\nline2\nline3\n".to_string(),
encoded: "line1\nline2\nline3\n".to_string(),
}],
source_info: SourceInfo::new(2, 1, 5, 1),
},
})
);
}
#[test]
fn test_base64_multiline_string_type_with_padding() {
let mut reader = Reader::init("base64 \nxxxx");
fn test_multiline_string_json() {
let mut reader = Reader::init("```json\nline1\nline2\nline3\n```");
assert_eq!(
base64_lang(&mut reader).unwrap(),
Lang {
value: Some(LangValue::Base64),
multiline_string(&mut reader).unwrap(),
MultilineString::Json(Text {
space: Whitespace {
value: String::from(" "),
source_info: SourceInfo::new(1, 7, 1, 13),
value: "".to_string(),
source_info: SourceInfo::new(1, 8, 1, 8),
},
newline: Whitespace {
value: "\n".to_string(),
source_info: SourceInfo::new(1, 13, 2, 1)
}
}
source_info: SourceInfo::new(1, 8, 2, 1),
},
value: Template {
quotes: false,
elements: vec![TemplateElement::String {
value: "line1\nline2\nline3\n".to_string(),
encoded: "line1\nline2\nline3\n".to_string(),
}],
source_info: SourceInfo::new(2, 1, 5, 1),
},
})
);
}
#[test]
fn test_multiline_string_ok() {
let datas = [
(
"```\nline1\nline2\nline3\n```",
None,
"line1\nline2\nline3\n",
),
(
"``` \nline1\nline2\nline3\n```",
None,
"line1\nline2\nline3\n",
),
(
"```base64\nline1\nline2\nline3\n```",
Some(LangValue::Base64),
"line1\nline2\nline3\n",
),
(
"```hex\nline1\nline2\nline3\n```",
Some(LangValue::Hex),
"line1\nline2\nline3\n",
),
(
"```json\nline1\nline2\nline3\n```",
Some(LangValue::Json),
"line1\nline2\nline3\n",
),
(
"```graphql\nline1\nline2\nline3\n```",
Some(LangValue::GraphQl),
"line1\nline2\nline3\n",
),
(
"```graphql \nline1\nline2\nline3\n```",
Some(LangValue::GraphQl),
"line1\nline2\nline3\n",
),
];
fn test_multiline_string_graphql() {
let mut reader = Reader::init("```graphql\nline1\nline2\nline3\n```");
assert_eq!(
multiline_string(&mut reader).unwrap(),
MultilineString::GraphQl(GraphQl {
space: Whitespace {
value: "".to_string(),
source_info: SourceInfo::new(1, 11, 1, 11),
},
newline: Whitespace {
value: "\n".to_string(),
source_info: SourceInfo::new(1, 11, 2, 1),
},
value: Template {
quotes: false,
elements: vec![TemplateElement::String {
value: "line1\nline2\nline3\n".to_string(),
encoded: "line1\nline2\nline3\n".to_string(),
}],
source_info: SourceInfo::new(2, 1, 5, 1),
},
variables: None,
})
);
for (text, lang, value) in datas.iter() {
let mut reader = Reader::init(text);
let multiline = multiline_string(&mut reader).unwrap();
assert_eq!(multiline.lang.unwrap().value, *lang);
assert_eq!(multiline.value.elements[0].to_string(), value.to_string())
}
let mut reader = Reader::init("```graphql \nline1\nline2\nline3\n```");
assert_eq!(
multiline_string(&mut reader).unwrap(),
MultilineString::GraphQl(GraphQl {
space: Whitespace {
value: " ".to_string(),
source_info: SourceInfo::new(1, 11, 1, 17),
},
newline: Whitespace {
value: "\n".to_string(),
source_info: SourceInfo::new(1, 17, 2, 1),
},
value: Template {
quotes: false,
elements: vec![TemplateElement::String {
value: "line1\nline2\nline3\n".to_string(),
encoded: "line1\nline2\nline3\n".to_string(),
}],
source_info: SourceInfo::new(2, 1, 5, 1),
},
variables: None,
})
);
}
#[test]
@ -290,59 +295,50 @@ mod tests {
let mut reader = Reader::init("``````");
assert_eq!(
multiline_string(&mut reader).unwrap(),
MultilineString {
lang: None,
value: Template {
quotes: false,
elements: vec![],
source_info: SourceInfo::new(1, 4, 1, 4),
},
}
MultilineString::TextOneline(Template {
quotes: false,
elements: vec![],
source_info: SourceInfo::new(1, 4, 1, 4),
})
);
let mut reader = Reader::init("```\n```");
assert_eq!(
multiline_string(&mut reader).unwrap(),
MultilineString {
lang: Some(Lang {
value: None,
space: Whitespace {
value: "".to_string(),
source_info: SourceInfo::new(1, 4, 1, 4)
},
newline: Whitespace {
value: "\n".to_string(),
source_info: SourceInfo::new(1, 4, 2, 1)
}
}),
MultilineString::Text(Text {
space: Whitespace {
value: "".to_string(),
source_info: SourceInfo::new(1, 4, 1, 4),
},
newline: Whitespace {
value: "\n".to_string(),
source_info: SourceInfo::new(1, 4, 2, 1),
},
value: Template {
quotes: false,
elements: vec![],
source_info: SourceInfo::new(2, 1, 2, 1),
},
}
})
);
let mut reader = Reader::init("```\r\n```");
assert_eq!(
multiline_string(&mut reader).unwrap(),
MultilineString {
lang: Some(Lang {
value: None,
space: Whitespace {
value: "".to_string(),
source_info: SourceInfo::new(1, 4, 1, 4)
},
newline: Whitespace {
value: "\r\n".to_string(),
source_info: SourceInfo::new(1, 4, 2, 1)
}
}),
MultilineString::Text(Text {
space: Whitespace {
value: "".to_string(),
source_info: SourceInfo::new(1, 4, 1, 4),
},
newline: Whitespace {
value: "\r\n".to_string(),
source_info: SourceInfo::new(1, 4, 2, 1),
},
value: Template {
quotes: false,
elements: vec![],
source_info: SourceInfo::new(2, 1, 2, 1),
},
}
})
);
}
@ -351,17 +347,14 @@ mod tests {
let mut reader = Reader::init("```Hello World!```");
assert_eq!(
multiline_string(&mut reader).unwrap(),
MultilineString {
lang: None,
value: Template {
quotes: false,
elements: vec![TemplateElement::String {
value: "Hello World!".to_string(),
encoded: "Hello World!".to_string(),
}],
source_info: SourceInfo::new(1, 4, 1, 16),
},
}
MultilineString::TextOneline(Template {
quotes: false,
elements: vec![TemplateElement::String {
value: "Hello World!".to_string(),
encoded: "Hello World!".to_string(),
}],
source_info: SourceInfo::new(1, 4, 1, 16),
})
);
}
@ -370,17 +363,14 @@ mod tests {
let mut reader = Reader::init("```base64_inline```");
assert_eq!(
multiline_string(&mut reader).unwrap(),
MultilineString {
lang: None,
value: Template {
quotes: false,
elements: vec![TemplateElement::String {
value: "base64_inline".to_string(),
encoded: "base64_inline".to_string(),
}],
source_info: SourceInfo::new(1, 4, 1, 17),
},
}
MultilineString::TextOneline(Template {
quotes: false,
elements: vec![TemplateElement::String {
value: "base64_inline".to_string(),
encoded: "base64_inline".to_string(),
}],
source_info: SourceInfo::new(1, 4, 1, 17),
})
);
}
@ -389,18 +379,15 @@ mod tests {
let mut reader = Reader::init("```\nline1\nline2\nline3\n```");
assert_eq!(
multiline_string(&mut reader).unwrap(),
MultilineString {
lang: Some(Lang {
value: None,
space: Whitespace {
value: "".to_string(),
source_info: SourceInfo::new(1, 4, 1, 4),
},
newline: Whitespace {
value: "\n".to_string(),
source_info: SourceInfo::new(1, 4, 2, 1),
}
}),
MultilineString::Text(Text {
space: Whitespace {
value: "".to_string(),
source_info: SourceInfo::new(1, 4, 1, 4),
},
newline: Whitespace {
value: "\n".to_string(),
source_info: SourceInfo::new(1, 4, 2, 1),
},
value: Template {
quotes: false,
elements: vec![TemplateElement::String {
@ -409,29 +396,24 @@ mod tests {
}],
source_info: SourceInfo::new(2, 1, 5, 1),
},
}
})
);
}
#[test]
fn test_multiline_string_one_empty_line() {
// one newline
// the value takes the value of the newline??
let mut reader = Reader::init("```\n\n```");
assert_eq!(
multiline_string(&mut reader).unwrap(),
MultilineString {
lang: Some(Lang {
value: None,
space: Whitespace {
value: "".to_string(),
source_info: SourceInfo::new(1, 4, 1, 4),
},
newline: Whitespace {
value: "\n".to_string(),
source_info: SourceInfo::new(1, 4, 2, 1),
}
}),
MultilineString::Text(Text {
space: Whitespace {
value: "".to_string(),
source_info: SourceInfo::new(1, 4, 1, 4),
},
newline: Whitespace {
value: "\n".to_string(),
source_info: SourceInfo::new(1, 4, 2, 1),
},
value: Template {
quotes: false,
elements: vec![TemplateElement::String {
@ -440,25 +422,22 @@ mod tests {
}],
source_info: SourceInfo::new(2, 1, 3, 1),
},
}
})
);
// one cr
// One cr
let mut reader = Reader::init("```\n\r\n````");
assert_eq!(
multiline_string(&mut reader).unwrap(),
MultilineString {
lang: Some(Lang {
value: None,
space: Whitespace {
value: "".to_string(),
source_info: SourceInfo::new(1, 4, 1, 4),
},
newline: Whitespace {
value: "\n".to_string(),
source_info: SourceInfo::new(1, 4, 2, 1),
}
}),
MultilineString::Text(Text {
space: Whitespace {
value: "".to_string(),
source_info: SourceInfo::new(1, 4, 1, 4),
},
newline: Whitespace {
value: "\n".to_string(),
source_info: SourceInfo::new(1, 4, 2, 1),
},
value: Template {
quotes: false,
elements: vec![TemplateElement::String {
@ -467,7 +446,7 @@ mod tests {
}],
source_info: SourceInfo::new(2, 1, 3, 1),
},
}
})
);
}
@ -479,20 +458,15 @@ mod tests {
assert_eq!(
error.inner,
ParseError::Expecting {
value: String::from("```")
value: "```".to_string()
}
);
assert!(error.recoverable);
let mut reader = Reader::init("```\nxxx");
let error = multiline_string(&mut reader).err().unwrap();
assert_eq!(error.pos, Pos { line: 2, column: 4 });
assert_eq!(
error.inner,
ParseError::Expecting {
value: String::from("```")
}
);
assert_eq!(error.pos, Pos { line: 1, column: 4 });
assert_eq!(error.inner, ParseError::Multiline);
assert!(!error.recoverable);
let mut reader = Reader::init("```xxx");
@ -501,7 +475,7 @@ mod tests {
assert_eq!(
error.inner,
ParseError::Expecting {
value: String::from("```")
value: "```".to_string()
}
);
assert!(!error.recoverable);

View File

@ -406,18 +406,15 @@ mod tests {
value: String::from(""),
source_info: SourceInfo::new(2, 1, 2, 1),
},
value: Bytes::MultilineString(MultilineString {
lang: Some(Lang {
value: None,
space: Whitespace {
value: "".to_string(),
source_info: SourceInfo::new(2, 4, 2, 4),
},
newline: Whitespace {
source_info: SourceInfo::new(2, 4, 3, 1),
value: "\n".to_string(),
}
}),
value: Bytes::MultilineString(MultilineString::Text(Text {
space: Whitespace {
value: "".to_string(),
source_info: SourceInfo::new(2, 4, 2, 4),
},
newline: Whitespace {
source_info: SourceInfo::new(2, 4, 3, 1),
value: "\n".to_string(),
},
value: Template {
elements: vec![TemplateElement::String {
value: String::from("Hello World!\n"),
@ -425,8 +422,8 @@ mod tests {
}],
quotes: false,
source_info: SourceInfo::new(3, 1, 4, 1),
},
}),
}
})),
line_terminator0: LineTerminator {
space0: Whitespace {
value: "".to_string(),

View File

@ -141,32 +141,36 @@ impl ToJson for Bytes {
("type".to_string(), JValue::String("xml".to_string())),
("value".to_string(), JValue::String(value.clone())),
]),
Bytes::MultilineString(value) => {
let lang = match &value.lang {
// TODO: check these values. Mayve we want to have the same
// export when using:
//
// ~~~
// GET https://foo.com
// ```base64
// SGVsbG8gd29ybGQ=
// ```
//
// or
//
// ~~~
// GET https://foo.com
// base64,SGVsbG8gd29ybGQ=;
// ~~~
None | Some(Lang { value: None, .. }) => "multiline-string".to_string(),
Some(Lang {
value: Some(lang_value),
..
}) => lang_value.to_string(),
Bytes::MultilineString(multi) => {
// TODO: check these values. Maybe we want to have the same
// export when using:
//
// ~~~
// GET https://foo.com
// ```base64
// SGVsbG8gd29ybGQ=
// ```
//
// or
//
// ~~~
// GET https://foo.com
// base64,SGVsbG8gd29ybGQ=;
// ~~~
let lang = match multi {
MultilineString::TextOneline(_) | MultilineString::Text(_) => {
"multiline-string"
}
MultilineString::Json(_) => "json",
MultilineString::Xml(_) => "xml",
MultilineString::GraphQl(_) => "graphql",
};
JValue::Object(vec![
("type".to_string(), JValue::String(lang)),
("value".to_string(), JValue::String(value.value.to_string())),
("type".to_string(), JValue::String(lang.to_string())),
(
"value".to_string(),
JValue::String(multi.value().to_string()),
),
])
}
}
@ -465,7 +469,7 @@ fn add_predicate_value(attributes: &mut Vec<(String, JValue)>, predicate_value:
fn json_predicate_value(predicate_value: PredicateValue) -> (JValue, Option<String>) {
match predicate_value {
PredicateValue::String(value) => (JValue::String(value.to_string()), None),
PredicateValue::MultilineString(value) => (JValue::String(value.value.to_string()), None),
PredicateValue::MultilineString(value) => (JValue::String(value.value().to_string()), None),
PredicateValue::Integer(value) => (JValue::Number(value.to_string()), None),
PredicateValue::Float(value) => (JValue::Number(value.to_string()), None),
PredicateValue::Bool(value) => (JValue::Boolean(value), None),
@ -485,12 +489,6 @@ fn json_predicate_value(predicate_value: PredicateValue) -> (JValue, Option<Stri
}
}
impl ToJson for MultilineString {
fn to_json(&self) -> JValue {
JValue::String(self.value.to_string())
}
}
impl ToJson for JsonValue {
fn to_json(&self) -> JValue {
match self {

View File

@ -164,7 +164,6 @@ impl Tokenizable for Bytes {
Bytes::Xml { value } => {
tokens.push(Token::String(value.to_string()));
}
// Bytes::MultilineString { value: _ } => {}
Bytes::MultilineString(value) => {
tokens.append(&mut value.tokenize());
}
@ -606,35 +605,27 @@ impl Tokenizable for PredicateValue {
impl Tokenizable for MultilineString {
fn tokenize(&self) -> Vec<Token> {
let lang = match self {
MultilineString::TextOneline(_) => None,
MultilineString::Text(_) => None,
MultilineString::Json(_) => Some("json"),
MultilineString::Xml(_) => Some("xml"),
MultilineString::GraphQl(_) => Some("graphql"),
};
let mut tokens: Vec<Token> = vec![Token::Keyword("```".to_string())];
if let Some(kind) = &self.lang {
tokens.append(&mut kind.tokenize())
if let Some(lang) = lang {
tokens.push(Token::Lang(lang.to_string()));
tokens.push(Token::Whitespace("\n".to_string()));
} else if let MultilineString::Text(..) = self {
tokens.push(Token::Whitespace("\n".to_string()));
}
tokens.append(&mut self.value.tokenize());
tokens.append(&mut self.value().tokenize());
tokens.push(Token::Keyword("```".to_string()));
tokens
}
}
impl Tokenizable for Lang {
fn tokenize(&self) -> Vec<Token> {
let mut tokens: Vec<Token> = vec![];
if let Some(value) = &self.value {
tokens.append(&mut value.tokenize());
}
tokens.append(&mut self.space.tokenize());
tokens.append(&mut self.newline.tokenize());
tokens
}
}
impl Tokenizable for LangValue {
fn tokenize(&self) -> Vec<Token> {
let token = Token::Lang(self.to_string());
vec![token]
}
}
impl Tokenizable for EncodedString {
fn tokenize(&self) -> Vec<Token> {
let mut tokens: Vec<Token> = vec![];

View File

@ -519,9 +519,49 @@ impl Lintable<MultilineString> for MultilineString {
}
fn lint(&self) -> MultilineString {
MultilineString {
lang: None,
value: self.value.lint(),
match self {
MultilineString::TextOneline(value) => MultilineString::TextOneline(value.lint()),
MultilineString::Text(value) => MultilineString::Text(value.lint()),
MultilineString::Json(value) => MultilineString::Json(value.lint()),
MultilineString::Xml(value) => MultilineString::Xml(value.lint()),
MultilineString::GraphQl(value) => MultilineString::GraphQl(value.lint()),
}
}
}
impl Lintable<Text> for Text {
fn errors(&self) -> Vec<Error> {
let errors = vec![];
errors
}
fn lint(&self) -> Text {
let space = empty_whitespace();
let newline = self.newline.clone();
let value = self.value.lint();
Text {
space,
newline,
value,
}
}
}
impl Lintable<GraphQl> for GraphQl {
fn errors(&self) -> Vec<Error> {
let errors = vec![];
errors
}
fn lint(&self) -> GraphQl {
let space = empty_whitespace();
let newline = self.newline.clone();
let value = self.value.lint();
GraphQl {
space,
newline,
value,
variables: None,
}
}
}