Child test comment
\n' -@skip_if(sqlalchemy_missing, 'needs sqlalchemy') -@with_support() -def test_voting(support): - session = Session() - nodes = session.query(Node).all() - node = nodes[0] - - comment = support.get_data(node.id)['comments'][0] - - def check_rating(val): - data = support.get_data(node.id) - comment = data['comments'][0] - assert comment['rating'] == val, '%s != %s' % (comment['rating'], val) - - support.process_vote(comment['id'], 'user_one', '1') - support.process_vote(comment['id'], 'user_two', '1') - support.process_vote(comment['id'], 'user_three', '1') - check_rating(3) - support.process_vote(comment['id'], 'user_one', '-1') - check_rating(1) - support.process_vote(comment['id'], 'user_one', '0') - check_rating(2) - - # Make sure a vote with value > 1 or < -1 can't be cast. - raises(ValueError, support.process_vote, comment['id'], 'user_one', '2') - raises(ValueError, support.process_vote, comment['id'], 'user_one', '-2') - - # Make sure past voting data is associated with comments when they are - # fetched. - data = support.get_data(str(node.id), username='user_two') - comment = data['comments'][0] - assert comment['vote'] == 1, '%s != 1' % comment['vote'] - - -@skip_if(sqlalchemy_missing, 'needs sqlalchemy') -@with_support() -def test_proposals(support): - session = Session() - node = session.query(Node).first() - - data = support.get_data(node.id) - - source = data['source'] - proposal = source[:5] + source[10:15] + 'asdf' + source[15:] - - support.add_comment('Proposal comment', - node_id=node.id, - proposal=proposal) - - @skip_if(sqlalchemy_missing, 'needs sqlalchemy') @with_support() def test_user_delete_comments(support): @@ -185,8 +135,8 @@ def test_user_delete_comments(support): comment = get_comment() assert comment['username'] == 'user_one' # Make sure other normal users can't delete someone elses comments. - raises(UserNotAuthorizedError, support.delete_comment, - comment['id'], username='user_two') + with pytest.raises(UserNotAuthorizedError): + support.delete_comment(comment['id'], username='user_two') # Now delete the comment using the correct username. support.delete_comment(comment['id'], username='user_one') comment = get_comment() @@ -194,40 +144,6 @@ def test_user_delete_comments(support): assert comment['text'] == '[deleted]' -@skip_if(sqlalchemy_missing, 'needs sqlalchemy') -@with_support() -def test_moderator_delete_comments(support): - def get_comment(): - session = Session() - node = session.query(Node).first() - session.close() - return support.get_data(node.id, moderator=True)['comments'][1] - - comment = get_comment() - support.delete_comment(comment['id'], username='user_two', - moderator=True) - raises(IndexError, get_comment) - - -@skip_if(sqlalchemy_missing, 'needs sqlalchemy') -@with_support() -def test_update_username(support): - support.update_username('user_two', 'new_user_two') - session = Session() - comments = session.query(Comment).\ - filter(Comment.username == 'user_two').all() - assert len(comments) == 0 - votes = session.query(CommentVote).\ - filter(CommentVote.username == 'user_two').all() - assert len(votes) == 0 - comments = session.query(Comment).\ - filter(Comment.username == 'new_user_two').all() - assert len(comments) == 1 - votes = session.query(CommentVote).\ - filter(CommentVote.username == 'new_user_two').all() - assert len(votes) == 0 - - called = False @@ -250,8 +166,10 @@ def test_moderation(support): # Make sure the moderation_callback is called. assert called # Make sure the user must be a moderator. - raises(UserNotAuthorizedError, support.accept_comment, accepted['id']) - raises(UserNotAuthorizedError, support.delete_comment, deleted['id']) + with pytest.raises(UserNotAuthorizedError): + support.accept_comment(accepted['id']) + with pytest.raises(UserNotAuthorizedError): + support.delete_comment(deleted['id']) support.accept_comment(accepted['id'], moderator=True) support.delete_comment(deleted['id'], moderator=True) comments = support.get_data(node.id)['comments'] @@ -260,6 +178,93 @@ def test_moderation(support): assert len(comments) == 1 +@skip_if(sqlalchemy_missing, 'needs sqlalchemy') +@with_support() +def test_moderator_delete_comments(support): + def get_comment(): + session = Session() + node = session.query(Node).first() + session.close() + return support.get_data(node.id, moderator=True)['comments'][1] + + comment = get_comment() + support.delete_comment(comment['id'], username='user_two', + moderator=True) + with pytest.raises(IndexError): + get_comment() + + +@skip_if(sqlalchemy_missing, 'needs sqlalchemy') +@with_support() +def test_update_username(support): + support.update_username('user_two', 'new_user_two') + session = Session() + comments = session.query(Comment).\ + filter(Comment.username == 'user_two').all() + assert len(comments) == 0 + votes = session.query(CommentVote).\ + filter(CommentVote.username == 'user_two').all() + assert len(votes) == 0 + comments = session.query(Comment).\ + filter(Comment.username == 'new_user_two').all() + assert len(comments) == 1 + votes = session.query(CommentVote).\ + filter(CommentVote.username == 'new_user_two').all() + assert len(votes) == 0 + + +@skip_if(sqlalchemy_missing, 'needs sqlalchemy') +@with_support() +def test_proposals(support): + session = Session() + node = session.query(Node).first() + + data = support.get_data(node.id) + + source = data['source'] + proposal = source[:5] + source[10:15] + 'asdf' + source[15:] + + support.add_comment('Proposal comment', + node_id=node.id, + proposal=proposal) + + +@skip_if(sqlalchemy_missing, 'needs sqlalchemy') +@with_support() +def test_voting(support): + session = Session() + nodes = session.query(Node).all() + node = nodes[0] + + comment = support.get_data(node.id)['comments'][0] + + def check_rating(val): + data = support.get_data(node.id) + comment = data['comments'][0] + assert comment['rating'] == val, '%s != %s' % (comment['rating'], val) + + support.process_vote(comment['id'], 'user_one', '1') + support.process_vote(comment['id'], 'user_two', '1') + support.process_vote(comment['id'], 'user_three', '1') + check_rating(3) + support.process_vote(comment['id'], 'user_one', '-1') + check_rating(1) + support.process_vote(comment['id'], 'user_one', '0') + check_rating(2) + + # Make sure a vote with value > 1 or < -1 can't be cast. + with pytest.raises(ValueError): + support.process_vote(comment['id'], 'user_one', '2') + with pytest.raises(ValueError): + support.process_vote(comment['id'], 'user_one', '-2') + + # Make sure past voting data is associated with comments when they are + # fetched. + data = support.get_data(str(node.id), username='user_two') + comment = data['comments'][0] + assert comment['vote'] == 1, '%s != 1' % comment['vote'] + + def test_differ(): source = 'Lorem ipsum dolor sit amet,\nconsectetur adipisicing elit,\n' \ 'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.' diff --git a/tests/test_writer_latex.py b/tests/test_writer_latex.py index 72eb7ed2a..33803299b 100644 --- a/tests/test_writer_latex.py +++ b/tests/test_writer_latex.py @@ -11,7 +11,7 @@ from __future__ import print_function from sphinx.writers.latex import rstdim_to_latexdim -from util import raises +import pytest def test_rstdim_to_latexdim(): @@ -32,5 +32,6 @@ def test_rstdim_to_latexdim(): assert rstdim_to_latexdim('.5em') == '.5em' # unknown values (it might be generated by 3rd party extension) - raises(ValueError, rstdim_to_latexdim, 'unknown') + with pytest.raises(ValueError): + rstdim_to_latexdim('unknown') assert rstdim_to_latexdim('160.0unknown') == '160.0unknown' diff --git a/tests/util.py b/tests/util.py index 13366a1da..8f2d1ff9a 100644 --- a/tests/util.py +++ b/tests/util.py @@ -10,14 +10,13 @@ import os import re import sys -import tempfile import warnings from functools import wraps from xml.etree import ElementTree -from six import StringIO, string_types +from six import string_types -from nose import tools, SkipTest +import pytest from docutils import nodes from docutils.parsers.rst import directives, roles @@ -27,16 +26,17 @@ from sphinx.builders.latex import LaTeXBuilder from sphinx.theming import Theme from sphinx.ext.autodoc import AutoDirective from sphinx.pycode import ModuleAnalyzer +from sphinx.deprecation import RemovedInSphinx17Warning -from path import path, repr_as # NOQA +from path import path __all__ = [ - 'rootdir', 'tempdir', 'raises', 'raises_msg', - 'skip_if', 'skip_unless', 'skip_unless_importable', 'Struct', - 'ListOutput', 'TestApp', 'with_app', 'gen_with_app', - 'path', 'with_tempdir', - 'sprint', 'remove_unicode_literals', + 'rootdir', 'tempdir', + 'skip_unless_importable', 'Struct', + 'SphinxTestApp', + 'path', + 'remove_unicode_literals', ] @@ -44,36 +44,6 @@ rootdir = path(os.path.dirname(__file__) or '.').abspath() tempdir = path(os.environ['SPHINX_TEST_TEMPDIR']).abspath() -def _excstr(exc): - if type(exc) is tuple: - return str(tuple(map(_excstr, exc))) - return exc.__name__ - - -def raises(exc, func, *args, **kwds): - """Raise AssertionError if ``func(*args, **kwds)`` does not raise *exc*.""" - try: - func(*args, **kwds) - except exc: - pass - else: - raise AssertionError('%s did not raise %s' % - (func.__name__, _excstr(exc))) - - -def raises_msg(exc, msg, func, *args, **kwds): - """Raise AssertionError if ``func(*args, **kwds)`` does not raise *exc*, - and check if the message contains *msg*. - """ - try: - func(*args, **kwds) - except exc as err: - assert msg in str(err), "\"%s\" not in \"%s\"" % (msg, err) - else: - raise AssertionError('%s did not raise %s' % - (func.__name__, _excstr(exc))) - - def assert_re_search(regex, text, flags=0): if not re.search(regex, text, flags): assert False, '%r did not match %r' % (regex, text) @@ -118,43 +88,14 @@ def assert_node(node, cls=None, xpath="", **kwargs): 'The node%s[%s] is not %r: %r' % (xpath, key, value, node[key]) -try: - from nose.tools import assert_in, assert_not_in -except ImportError: - def assert_in(x, thing, msg=''): - if x not in thing: - assert False, msg or '%r is not in %r' % (x, thing) - - def assert_not_in(x, thing, msg=''): - if x in thing: - assert False, msg or '%r is in %r' % (x, thing) - - -def skip_if(condition, msg=None): - """Decorator to skip test if condition is true.""" - def deco(test): - @tools.make_decorator(test) - def skipper(*args, **kwds): - if condition: - raise SkipTest(msg or 'conditional skip') - return test(*args, **kwds) - return skipper - return deco - - -def skip_unless(condition, msg=None): - """Decorator to skip test if condition is false.""" - return skip_if(not condition, msg) - - def skip_unless_importable(module, msg=None): """Decorator to skip test if module is not importable.""" try: __import__(module) except ImportError: - return skip_if(True, msg) + return pytest.mark.skipif(True, reason=(msg or 'conditional skip')) else: - return skip_if(False, msg) + return pytest.mark.skipif(False, reason=(msg or 'conditional skip')) def etree_parse(path): @@ -168,22 +109,7 @@ class Struct(object): self.__dict__.update(kwds) -class ListOutput(object): - """ - File-like object that collects written text in a list. - """ - def __init__(self, name): - self.name = name - self.content = [] - - def reset(self): - del self.content[:] - - def write(self, text): - self.content.append(text) - - -class TestApp(application.Sphinx): +class SphinxTestApp(application.Sphinx): """ A subclass of :class:`Sphinx` that runs on the test root, with some better default values for the initialization parameters. @@ -222,10 +148,6 @@ class TestApp(application.Sphinx): doctreedir.makedirs() if confoverrides is None: confoverrides = {} - if status is None: - status = StringIO() - if warning is None: - warning = ListOutput('stderr') # if warningiserror is None: warningiserror = False @@ -263,59 +185,6 @@ class TestApp(application.Sphinx): return '<%s buildername=%r>' % (self.__class__.__name__, self.builder.name) -def with_app(*args, **kwargs): - """ - Make a TestApp with args and kwargs, pass it to the test and clean up - properly. - """ - def generator(func): - @wraps(func) - def deco(*args2, **kwargs2): - status, warning = StringIO(), StringIO() - kwargs['status'] = status - kwargs['warning'] = warning - app = TestApp(*args, **kwargs) - try: - func(app, status, warning, *args2, **kwargs2) - finally: - app.cleanup() - return deco - return generator - - -def gen_with_app(*args, **kwargs): - """ - Decorate a test generator to pass a TestApp as the first argument to the - test generator when it's executed. - """ - def generator(func): - @wraps(func) - def deco(*args2, **kwargs2): - status, warning = StringIO(), StringIO() - kwargs['status'] = status - kwargs['warning'] = warning - app = TestApp(*args, **kwargs) - try: - for item in func(app, status, warning, *args2, **kwargs2): - yield item - finally: - app.cleanup() - return deco - return generator - - -def with_tempdir(func): - def new_func(*args, **kwds): - new_tempdir = path(tempfile.mkdtemp(dir=tempdir)) - func(new_tempdir, *args, **kwds) - new_func.__name__ = func.__name__ - return new_func - - -def sprint(*args): - sys.stderr.write(' '.join(map(str, args)) + '\n') - - _unicode_literals_re = re.compile(r'u(".*?")|u(\'.*?\')') @@ -333,3 +202,163 @@ def find_files(root, suffix=None): def strip_escseq(text): return re.sub('\x1b.*?m', '', text) + + +# ############################################# +# DEPRECATED implementations + +import tempfile +from six import StringIO + + +def gen_with_app(*args, **kwargs): + """ + **DEPRECATED**: use pytest.mark.parametrize instead. + + Decorate a test generator to pass a SphinxTestApp as the first argument to + the test generator when it's executed. + """ + def generator(func): + @wraps(func) + def deco(*args2, **kwargs2): + status, warning = StringIO(), StringIO() + kwargs['status'] = status + kwargs['warning'] = warning + app = SphinxTestApp(*args, **kwargs) + try: + for item in func(app, status, warning, *args2, **kwargs2): + yield item + finally: + app.cleanup() + return deco + return generator + + +def skip_if(condition, msg=None): + """ + **DEPRECATED**: use pytest.mark.skipif instead. + + Decorator to skip test if condition is true. + """ + return pytest.mark.skipif(condition, reason=(msg or 'conditional skip')) + + +def skip_unless(condition, msg=None): + """ + **DEPRECATED**: use pytest.mark.skipif instead. + + Decorator to skip test if condition is false. + """ + return pytest.mark.skipif(not condition, reason=(msg or 'conditional skip')) + + +def with_tempdir(func): + """ + **DEPRECATED**: use tempdir fixture instead. + """ + return func + + +def raises(exc, func, *args, **kwds): + """ + **DEPRECATED**: use pytest.raises instead. + + Raise AssertionError if ``func(*args, **kwds)`` does not raise *exc*. + """ + with pytest.raises(exc): + func(*args, **kwds) + + +def raises_msg(exc, msg, func, *args, **kwds): + """ + **DEPRECATED**: use pytest.raises instead. + + Raise AssertionError if ``func(*args, **kwds)`` does not raise *exc*, + and check if the message contains *msg*. + """ + with pytest.raises(exc) as excinfo: + func(*args, **kwds) + assert msg in str(excinfo.value) + + +def assert_true(v1, msg=''): + """ + **DEPRECATED**: use assert instead. + """ + assert v1, msg + + +def assert_equal(v1, v2, msg=''): + """ + **DEPRECATED**: use assert instead. + """ + assert v1 == v2, msg + + +def assert_in(x, thing, msg=''): + """ + **DEPRECATED**: use assert instead. + """ + if x not in thing: + assert False, msg or '%r is not in %r' % (x, thing) + + +def assert_not_in(x, thing, msg=''): + """ + **DEPRECATED**: use assert instead. + """ + if x in thing: + assert False, msg or '%r is in %r' % (x, thing) + + +class ListOutput(object): + """ + File-like object that collects written text in a list. + """ + def __init__(self, name): + self.name = name + self.content = [] + + def reset(self): + del self.content[:] + + def write(self, text): + self.content.append(text) + + +# **DEPRECATED**: use pytest.skip instead. +SkipTest = pytest.skip.Exception + + +class _DeprecationWrapper(object): + def __init__(self, mod, deprecated): + self._mod = mod + self._deprecated = deprecated + + def __getattr__(self, attr): + if attr in self._deprecated: + obj, instead = self._deprecated[attr] + warnings.warn("tests/util.py::%s is deprecated and will be " + "removed in Sphinx 1.7, please use %s instead." + % (attr, instead), + RemovedInSphinx17Warning, stacklevel=2) + return obj + return getattr(self._mod, attr) + + +sys.modules[__name__] = _DeprecationWrapper(sys.modules[__name__], dict( # type: ignore + with_app=(pytest.mark.sphinx, 'pytest.mark.sphinx'), + TestApp=(SphinxTestApp, 'SphinxTestApp'), + gen_with_app=(gen_with_app, 'pytest.mark.parametrize'), + skip_if=(skip_if, 'pytest.skipif'), + skip_unless=(skip_unless, 'pytest.skipif'), + with_tempdir=(with_tempdir, 'tmpdir pytest fixture'), + raises=(raises, 'pytest.raises'), + raises_msg=(raises_msg, 'pytest.raises'), + assert_true=(assert_true, 'assert'), + assert_equal=(assert_equal, 'assert'), + assert_in=(assert_in, 'assert'), + assert_not_in=(assert_not_in, 'assert'), + ListOutput=(ListOutput, 'StringIO'), + SkipTest=(SkipTest, 'pytest.skip'), +))