Test simple ReST conversion to JSON

Added initial tests to cover simple httpdomain conversion to JSON.
This commit is contained in:
Russell Sim 2015-08-08 15:15:12 +10:00
parent bfd623cc0a
commit b95d3176d7
6 changed files with 305 additions and 10 deletions

View File

@ -18,9 +18,14 @@
"""
"""
from __future__ import unicode_literals
import logging
from docutils import writers, nodes
import docutils.core
import docutils.utils
from docutils import frontend
from docutils.parsers.rst import directives
from docutils.parsers.rst import Directive
@ -110,6 +115,12 @@ class JSONTranslator(nodes.GenericNodeVisitor):
"""Default node depart method."""
self.node_stack.pop()
def visit_system_message(self, node):
pass
def depart_system_message(self, node):
pass
def visit_Text(self, node):
self.text += node.astext()
@ -123,6 +134,12 @@ class JSONTranslator(nodes.GenericNodeVisitor):
def depart_literal(self, node):
pass
def visit_literal_block(self, node):
self.text += '```\n'
def depart_literal_block(self, node):
self.text += '\n```\n'
def visit_bullet_list(self, node):
self.bullet_stack.append('*')
@ -466,7 +483,7 @@ class Resource(Directive):
method = None
required_arguments = 0
required_arguments = 1
optional_arguments = 0
has_content = True
final_argument_whitespace = True
@ -547,12 +564,16 @@ class Resource(Directive):
self.state.nested_parse(self.content, self.content_offset, node)
fields = self.transform_fields()
# This is the first line of the definition.
url = self.arguments[0]
node.insert(0, resource_url(url, url))
if not node.children:
return [node]
if node[0].tagname == 'system_message':
logger.error(node[0].astext())
node.remove(node[0])
# This is the first line of the definition.
url = node[0].astext()
node[0].replace_self(resource_url(url, url))
# Method
node.insert(1, resource_method(self.method, self.method))
@ -663,3 +684,16 @@ class SwaggerTag(Directive):
directives.register_directive('swagger:tag', SwaggerTag)
class error_writer(object):
def write(self, line):
logger.warning(line.strip())
def publish_string(string):
settings_overrides = {'warning_stream': error_writer()}
return docutils.core.publish_string(
string, writer=JSONWriter(),
settings_overrides=settings_overrides)

View File

@ -9,6 +9,7 @@ app = {
'root': 'fairy_slipper.controllers.root.RootController',
'modules': ['fairy_slipper'],
'static_root': '%(confdir)s/../../public',
'api_doc': '%(confdir)s/../../api_doc',
'template_path': '%(confdir)s/../templates',
'debug': True,
'errors': {

View File

@ -27,7 +27,7 @@ Tests for `fairy_slipper` module.
from fairy_slipper.tests import base
class TestFairy_slipper(base.TestCase):
class TestFairySlipper(base.TestCase):
def test_something(self):
pass

View File

@ -29,11 +29,7 @@ class TestRootController(FunctionalTest):
def test_search(self):
response = self.app.post('/', params={'q': 'RestController'})
assert response.status_int == 302
assert response.headers['Location'] == (
'http://pecan.readthedocs.org/en/latest/search.html'
'?q=RestController'
)
assert response.status_int == 200
def test_get_not_found(self):
response = self.app.get('/a/bogus/url', expect_errors=True)

View File

@ -0,0 +1,263 @@
# Copyright (c) 2015 Russell Sim <russell.sim@gmail.com>
#
# All Rights Reserved.
#
# 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.
from __future__ import unicode_literals
from unittest import TestCase
import docutils.core
from fairy_slipper import rest
from fairy_slipper.rest import JSONWriter
def minimal_method_json(consumes=[],
description='',
method='get',
parameters=[],
produces=[],
responses={},
summary='',
tags=[],
title=''):
return dict(consumes=consumes,
description=description,
method=method,
parameters=parameters,
produces=produces,
responses=responses,
summary=summary,
tags=tags,
title=title)
class TestReSTMethod(TestCase):
def test_no_path(self):
rst = """
.. http:get::
"""
json = rest.publish_string(rst)
assert json == {'paths': {}, 'tags': []}
def test_path_with_body(self):
rst = """
.. http:get:: /path
body
"""
json = rest.publish_string(rst)
assert json == {'paths':
{'/path': [
minimal_method_json(description='body\n\n')]},
'tags': []}
def test_minimal(self):
rst = """
.. http:%s:: /path
"""
for method in ['get', 'post', 'put', 'patch',
'options', 'head', 'delete', 'copy']:
json = docutils.core.publish_string(
rst % method, writer=JSONWriter())
assert json == {'paths':
{'/path': [
minimal_method_json(method=method)]},
'tags': []}
def test_body_literal(self):
rst = """
.. http:get:: /path
literal block::
banana
1
2
3
"""
json = rest.publish_string(rst)
assert json == {'paths':
{'/path':
[minimal_method_json(description='''literal block:
```
banana
1
2
3
```
''')]},
'tags': []}
def test_synopsis(self):
rst = """
.. http:get:: /path
:synopsis: Some description of the operation
"""
json = rest.publish_string(rst)
assert json == {'paths':
{'/path':
[minimal_method_json(
summary='Some description of the operation')]},
'tags': []}
def test_title(self):
rst = """
.. http:get:: /path
:title: Path Thing
"""
json = rest.publish_string(rst)
assert json == {'paths':
{'/path':
[minimal_method_json(title='Path Thing')]},
'tags': []}
def test_method_tags(self):
rst = """
.. http:get:: /path
:tag: cool-tag
:tag: cool-tag1
"""
json = rest.publish_string(rst)
assert json == {'paths':
{'/path':
[minimal_method_json(
tags=['cool-tag', 'cool-tag1'])]},
'tags': []}
def test_produces(self):
rst = """
.. http:get:: /path
:produces: application/json
:produces: text/plain
"""
json = rest.publish_string(rst)
assert json == {'paths':
{'/path':
[minimal_method_json(
produces=['application/json',
'text/plain'])]},
'tags': []}
def test_accepts(self):
rst = """
.. http:get:: /path
:accepts: application/json
:accepts: text/plain
"""
json = rest.publish_string(rst)
assert json == {'paths':
{'/path':
[minimal_method_json(
consumes=['application/json',
'text/plain'])]},
'tags': []}
def test_parameter(self):
rst = """
.. http:get:: /path
:parameter thing: A parameter something.
"""
json = rest.publish_string(rst)
assert json == {'paths':
{'/path':
[minimal_method_json(
parameters=[{
'description': u'A parameter something.',
'in': 'path',
'name': u'thing',
'required': True,
'type': 'string'}])]},
'tags': []}
def test_response_example(self):
rst = """
.. http:get:: /path
:responseexample 200: example.json
"""
json = rest.publish_string(rst)
assert json == {'paths':
{'/path':
[minimal_method_json(
responses={'200':
{'description': '',
'examples':
{'application/json':
{'$ref':
'example.json'}}}})]},
'tags': []}
def test_statuscode(self):
rst = """
.. http:get:: /path
:statuscode 200: Success! Yeah!
"""
json = rest.publish_string(rst)
assert json == {'paths':
{'/path':
[minimal_method_json(
responses={'200':
{'description': 'Success! Yeah!'}})]},
'tags': []}
class TestReSTTag(TestCase):
def test_synopsis(self):
rst = """
.. swagger:tag:: my-tag
:synopsis: Interesting things!
"""
json = rest.publish_string(rst)
assert json == {'paths': {},
'tags': [{'name': 'my-tag',
'description': '',
'summary': 'Interesting things!'}]}
def test_description(self):
rst = """
.. swagger:tag:: my-tag
body
"""
json = rest.publish_string(rst)
assert json == {'paths': {},
'tags': [{'name': 'my-tag',
'description': 'body\n\n',
'summary': ''}]}

View File

@ -13,3 +13,4 @@ oslotest>=1.2.0 # Apache-2.0
testrepository>=0.0.18
testscenarios>=0.4
testtools>=0.9.36,!=1.2.0
pytest