Browse Source

Usando pytest (setup e testes antigos convertidos)

producao
Marcio Mazza 10 years ago
parent
commit
64cbe9f0a9
  1. 2
      pytest.ini
  2. 8
      setup.py
  3. 671
      sigi/apps/diagnosticos/templatetags/smart_if.py
  4. 166
      sigi/apps/diagnosticos/templatetags/test_smart_if.py
  5. 2
      sigi/settings/base.py
  6. 16
      sigi/settings/test.py

2
pytest.ini

@ -0,0 +1,2 @@
[pytest]
DJANGO_SETTINGS_MODULE=sigi.settings.test

8
setup.py

@ -0,0 +1,8 @@
# py.test precisa deste arquivo para que o projeto seja instalado no virtualenv com:
# "pip install -e ."
# vide http://pytest-django.readthedocs.org/en/latest/faq.html#i-see-an-error-saying-could-not-import-myproject-settings
#
from distutils.core import setup
setup(name='sigi', version='2.x')

671
sigi/apps/diagnosticos/templatetags/smart_if.py

@ -1,412 +1,259 @@
""" """
A smarter {% if %} tag for django templates. A smarter {% if %} tag for django templates.
While retaining current Django functionality, it also handles equality, While retaining current Django functionality, it also handles equality,
greater than and less than operators. Some common case examples:: greater than and less than operators. Some common case examples::
{% if articles|length >= 5 %}...{% endif %} {% if articles|length >= 5 %}...{% endif %}
{% if "ifnotequal tag" != "beautiful" %}...{% endif %} {% if "ifnotequal tag" != "beautiful" %}...{% endif %}
""" """
import unittest from django import template
from django import template
register = template.Library()
register = template.Library()
#==============================================================================
#============================================================================== # Calculation objects
# Calculation objects #==============================================================================
#==============================================================================
class BaseCalc(object):
class BaseCalc(object):
def __init__(self, var1, var2=None, negate=False):
def __init__(self, var1, var2=None, negate=False): self.var1 = var1
self.var1 = var1 self.var2 = var2
self.var2 = var2 self.negate = negate
self.negate = negate
def resolve(self, context):
def resolve(self, context): try:
try: var1, var2 = self.resolve_vars(context)
var1, var2 = self.resolve_vars(context) outcome = self.calculate(var1, var2)
outcome = self.calculate(var1, var2) except:
except: outcome = False
outcome = False if self.negate:
if self.negate: return not outcome
return not outcome return outcome
return outcome
def resolve_vars(self, context):
def resolve_vars(self, context): var2 = self.var2 and self.var2.resolve(context)
var2 = self.var2 and self.var2.resolve(context) return self.var1.resolve(context), var2
return self.var1.resolve(context), var2
def calculate(self, var1, var2):
def calculate(self, var1, var2): raise NotImplementedError()
raise NotImplementedError()
class Or(BaseCalc):
class Or(BaseCalc):
def calculate(self, var1, var2):
def calculate(self, var1, var2): return var1 or var2
return var1 or var2
class And(BaseCalc):
class And(BaseCalc):
def calculate(self, var1, var2):
def calculate(self, var1, var2): return var1 and var2
return var1 and var2
class Equals(BaseCalc):
class Equals(BaseCalc):
def calculate(self, var1, var2):
def calculate(self, var1, var2): return var1 == var2
return var1 == var2
class Greater(BaseCalc):
class Greater(BaseCalc):
def calculate(self, var1, var2):
def calculate(self, var1, var2): return var1 > var2
return var1 > var2
class GreaterOrEqual(BaseCalc):
class GreaterOrEqual(BaseCalc):
def calculate(self, var1, var2):
def calculate(self, var1, var2): return var1 >= var2
return var1 >= var2
class In(BaseCalc):
class In(BaseCalc):
def calculate(self, var1, var2):
def calculate(self, var1, var2): return var1 in var2
return var1 in var2
OPERATORS = {
#============================================================================== '=': (Equals, True),
# Tests '==': (Equals, True),
#============================================================================== '!=': (Equals, False),
'>': (Greater, True),
class TestVar(object): '>=': (GreaterOrEqual, True),
'<=': (Greater, False),
""" '<': (GreaterOrEqual, False),
A basic self-resolvable object similar to a Django template variable. Used 'or': (Or, True),
to assist with tests. 'and': (And, True),
""" 'in': (In, True),
}
def __init__(self, value): BOOL_OPERATORS = ('or', 'and')
self.value = value
def resolve(self, context): class IfParser(object):
return self.value error_class = ValueError
def __init__(self, tokens):
class SmartIfTests(unittest.TestCase): self.tokens = tokens
def setUp(self): def _get_tokens(self):
self.true = TestVar(True) return self._tokens
self.false = TestVar(False)
self.high = TestVar(9000) def _set_tokens(self, tokens):
self.low = TestVar(1) self._tokens = tokens
self.len = len(tokens)
def assertCalc(self, calc, context=None): self.pos = 0
"""
Test a calculation is True, also checking the inverse "negate" case. tokens = property(_get_tokens, _set_tokens)
"""
context = context or {} def parse(self):
self.assert_(calc.resolve(context)) if self.at_end():
calc.negate = not calc.negate raise self.error_class('No variables provided.')
self.assertFalse(calc.resolve(context)) var1 = self.get_bool_var()
while not self.at_end():
def assertCalcFalse(self, calc, context=None): op, negate = self.get_operator()
""" var2 = self.get_bool_var()
Test a calculation is False, also checking the inverse "negate" case. var1 = op(var1, var2, negate=negate)
""" return var1
context = context or {}
self.assertFalse(calc.resolve(context)) def get_token(self, eof_message=None, lookahead=False):
calc.negate = not calc.negate negate = True
self.assert_(calc.resolve(context)) token = None
pos = self.pos
def test_or(self): while token is None or token == 'not':
self.assertCalc(Or(self.true)) if pos >= self.len:
self.assertCalcFalse(Or(self.false)) if eof_message is None:
self.assertCalc(Or(self.true, self.true)) raise self.error_class()
self.assertCalc(Or(self.true, self.false)) raise self.error_class(eof_message)
self.assertCalc(Or(self.false, self.true)) token = self.tokens[pos]
self.assertCalcFalse(Or(self.false, self.false)) negate = not negate
pos += 1
def test_and(self): if not lookahead:
self.assertCalc(And(self.true, self.true)) self.pos = pos
self.assertCalcFalse(And(self.true, self.false)) return token, negate
self.assertCalcFalse(And(self.false, self.true))
self.assertCalcFalse(And(self.false, self.false)) def at_end(self):
return self.pos >= self.len
def test_equals(self):
self.assertCalc(Equals(self.low, self.low)) def create_var(self, value):
self.assertCalcFalse(Equals(self.low, self.high)) raise NotImplementedError()
def test_greater(self): def get_bool_var(self):
self.assertCalc(Greater(self.high, self.low)) """
self.assertCalcFalse(Greater(self.low, self.low)) Returns either a variable by itself or a non-boolean operation (such as
self.assertCalcFalse(Greater(self.low, self.high)) ``x == 0`` or ``x < 0``).
def test_greater_or_equal(self): This is needed to keep correct precedence for boolean operations (i.e.
self.assertCalc(GreaterOrEqual(self.high, self.low)) ``x or x == 0`` should be ``x or (x == 0)``, not ``(x or x) == 0``).
self.assertCalc(GreaterOrEqual(self.low, self.low)) """
self.assertCalcFalse(GreaterOrEqual(self.low, self.high)) var = self.get_var()
if not self.at_end():
def test_in(self): op_token = self.get_token(lookahead=True)[0]
list_ = TestVar([1, 2, 3]) if isinstance(op_token, basestring) and (op_token not in
invalid_list = TestVar(None) BOOL_OPERATORS):
self.assertCalc(In(self.low, list_)) op, negate = self.get_operator()
self.assertCalcFalse(In(self.low, invalid_list)) return op(var, self.get_var(), negate=negate)
return var
def test_parse_bits(self):
var = IfParser([True]).parse() def get_var(self):
self.assert_(var.resolve({})) token, negate = self.get_token('Reached end of statement, still '
var = IfParser([False]).parse() 'expecting a variable.')
self.assertFalse(var.resolve({})) if isinstance(token, basestring) and token in OPERATORS:
raise self.error_class('Expected variable, got operator (%s).' %
var = IfParser([False, 'or', True]).parse() token)
self.assert_(var.resolve({})) var = self.create_var(token)
if negate:
var = IfParser([False, 'and', True]).parse() return Or(var, negate=True)
self.assertFalse(var.resolve({})) return var
var = IfParser(['not', False, 'and', 'not', False]).parse() def get_operator(self):
self.assert_(var.resolve({})) token, negate = self.get_token('Reached end of statement, still '
'expecting an operator.')
var = IfParser(['not', 'not', True]).parse() if not isinstance(token, basestring) or token not in OPERATORS:
self.assert_(var.resolve({})) raise self.error_class('%s is not a valid operator.' % token)
if self.at_end():
var = IfParser([1, '=', 1]).parse() raise self.error_class('No variable provided after "%s".' % token)
self.assert_(var.resolve({})) op, true = OPERATORS[token]
if not true:
var = IfParser([1, 'not', '=', 1]).parse() negate = not negate
self.assertFalse(var.resolve({})) return op, negate
var = IfParser([1, 'not', 'not', '=', 1]).parse()
self.assert_(var.resolve({})) #==============================================================================
# Actual templatetag code.
var = IfParser([1, '!=', 1]).parse() #==============================================================================
self.assertFalse(var.resolve({}))
class TemplateIfParser(IfParser):
var = IfParser([3, '>', 2]).parse() error_class = template.TemplateSyntaxError
self.assert_(var.resolve({}))
def __init__(self, parser, *args, **kwargs):
var = IfParser([1, '<', 2]).parse() self.template_parser = parser
self.assert_(var.resolve({})) return super(TemplateIfParser, self).__init__(*args, **kwargs)
var = IfParser([2, 'not', 'in', [2, 3]]).parse() def create_var(self, value):
self.assertFalse(var.resolve({})) return self.template_parser.compile_filter(value)
var = IfParser([1, 'or', 1, '=', 2]).parse()
self.assert_(var.resolve({})) class SmartIfNode(template.Node):
def test_boolean(self): def __init__(self, var, nodelist_true, nodelist_false=None):
var = IfParser([True, 'and', True, 'and', True]).parse() self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
self.assert_(var.resolve({})) self.var = var
var = IfParser([False, 'or', False, 'or', True]).parse()
self.assert_(var.resolve({})) def render(self, context):
var = IfParser([True, 'and', False, 'or', True]).parse() if self.var.resolve(context):
self.assert_(var.resolve({})) return self.nodelist_true.render(context)
var = IfParser([False, 'or', True, 'and', True]).parse() if self.nodelist_false:
self.assert_(var.resolve({})) return self.nodelist_false.render(context)
return ''
var = IfParser([True, 'and', True, 'and', False]).parse()
self.assertFalse(var.resolve({})) def __repr__(self):
var = IfParser([False, 'or', False, 'or', False]).parse() return "<Smart If node>"
self.assertFalse(var.resolve({}))
var = IfParser([False, 'or', True, 'and', False]).parse() def __iter__(self):
self.assertFalse(var.resolve({})) for node in self.nodelist_true:
var = IfParser([False, 'and', True, 'or', False]).parse() yield node
self.assertFalse(var.resolve({})) if self.nodelist_false:
for node in self.nodelist_false:
def test_invalid(self): yield node
self.assertRaises(ValueError, IfParser(['not']).parse)
self.assertRaises(ValueError, IfParser(['==']).parse) def get_nodes_by_type(self, nodetype):
self.assertRaises(ValueError, IfParser([1, 'in']).parse) nodes = []
self.assertRaises(ValueError, IfParser([1, '>', 'in']).parse) if isinstance(self, nodetype):
self.assertRaises(ValueError, IfParser([1, '==', 'not', 'not']).parse) nodes.append(self)
self.assertRaises(ValueError, IfParser([1, 2]).parse) nodes.extend(self.nodelist_true.get_nodes_by_type(nodetype))
if self.nodelist_false:
nodes.extend(self.nodelist_false.get_nodes_by_type(nodetype))
OPERATORS = { return nodes
'=': (Equals, True),
'==': (Equals, True),
'!=': (Equals, False), @register.tag('if')
'>': (Greater, True), def smart_if(parser, token):
'>=': (GreaterOrEqual, True), """
'<=': (Greater, False), A smarter {% if %} tag for django templates.
'<': (GreaterOrEqual, False),
'or': (Or, True), While retaining current Django functionality, it also handles equality,
'and': (And, True), greater than and less than operators. Some common case examples::
'in': (In, True),
} {% if articles|length >= 5 %}...{% endif %}
BOOL_OPERATORS = ('or', 'and') {% if "ifnotequal tag" != "beautiful" %}...{% endif %}
Arguments and operators _must_ have a space between them, so
class IfParser(object): ``{% if 1>2 %}`` is not a valid smart if tag.
error_class = ValueError
All supported operators are: ``or``, ``and``, ``in``, ``=`` (or ``==``),
def __init__(self, tokens): ``!=``, ``>``, ``>=``, ``<`` and ``<=``.
self.tokens = tokens """
bits = token.split_contents()[1:]
def _get_tokens(self): var = TemplateIfParser(parser, bits).parse()
return self._tokens nodelist_true = parser.parse(('else', 'endif'))
token = parser.next_token()
def _set_tokens(self, tokens): if token.contents == 'else':
self._tokens = tokens nodelist_false = parser.parse(('endif',))
self.len = len(tokens) parser.delete_first_token()
self.pos = 0 else:
nodelist_false = None
tokens = property(_get_tokens, _set_tokens) return SmartIfNode(var, nodelist_true, nodelist_false)
def parse(self):
if self.at_end():
raise self.error_class('No variables provided.')
var1 = self.get_bool_var()
while not self.at_end():
op, negate = self.get_operator()
var2 = self.get_bool_var()
var1 = op(var1, var2, negate=negate)
return var1
def get_token(self, eof_message=None, lookahead=False):
negate = True
token = None
pos = self.pos
while token is None or token == 'not':
if pos >= self.len:
if eof_message is None:
raise self.error_class()
raise self.error_class(eof_message)
token = self.tokens[pos]
negate = not negate
pos += 1
if not lookahead:
self.pos = pos
return token, negate
def at_end(self):
return self.pos >= self.len
def create_var(self, value):
return TestVar(value)
def get_bool_var(self):
"""
Returns either a variable by itself or a non-boolean operation (such as
``x == 0`` or ``x < 0``).
This is needed to keep correct precedence for boolean operations (i.e.
``x or x == 0`` should be ``x or (x == 0)``, not ``(x or x) == 0``).
"""
var = self.get_var()
if not self.at_end():
op_token = self.get_token(lookahead=True)[0]
if isinstance(op_token, basestring) and (op_token not in
BOOL_OPERATORS):
op, negate = self.get_operator()
return op(var, self.get_var(), negate=negate)
return var
def get_var(self):
token, negate = self.get_token('Reached end of statement, still '
'expecting a variable.')
if isinstance(token, basestring) and token in OPERATORS:
raise self.error_class('Expected variable, got operator (%s).' %
token)
var = self.create_var(token)
if negate:
return Or(var, negate=True)
return var
def get_operator(self):
token, negate = self.get_token('Reached end of statement, still '
'expecting an operator.')
if not isinstance(token, basestring) or token not in OPERATORS:
raise self.error_class('%s is not a valid operator.' % token)
if self.at_end():
raise self.error_class('No variable provided after "%s".' % token)
op, true = OPERATORS[token]
if not true:
negate = not negate
return op, negate
#==============================================================================
# Actual templatetag code.
#==============================================================================
class TemplateIfParser(IfParser):
error_class = template.TemplateSyntaxError
def __init__(self, parser, *args, **kwargs):
self.template_parser = parser
return super(TemplateIfParser, self).__init__(*args, **kwargs)
def create_var(self, value):
return self.template_parser.compile_filter(value)
class SmartIfNode(template.Node):
def __init__(self, var, nodelist_true, nodelist_false=None):
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
self.var = var
def render(self, context):
if self.var.resolve(context):
return self.nodelist_true.render(context)
if self.nodelist_false:
return self.nodelist_false.render(context)
return ''
def __repr__(self):
return "<Smart If node>"
def __iter__(self):
for node in self.nodelist_true:
yield node
if self.nodelist_false:
for node in self.nodelist_false:
yield node
def get_nodes_by_type(self, nodetype):
nodes = []
if isinstance(self, nodetype):
nodes.append(self)
nodes.extend(self.nodelist_true.get_nodes_by_type(nodetype))
if self.nodelist_false:
nodes.extend(self.nodelist_false.get_nodes_by_type(nodetype))
return nodes
@register.tag('if')
def smart_if(parser, token):
"""
A smarter {% if %} tag for django templates.
While retaining current Django functionality, it also handles equality,
greater than and less than operators. Some common case examples::
{% if articles|length >= 5 %}...{% endif %}
{% if "ifnotequal tag" != "beautiful" %}...{% endif %}
Arguments and operators _must_ have a space between them, so
``{% if 1>2 %}`` is not a valid smart if tag.
All supported operators are: ``or``, ``and``, ``in``, ``=`` (or ``==``),
``!=``, ``>``, ``>=``, ``<`` and ``<=``.
"""
bits = token.split_contents()[1:]
var = TemplateIfParser(parser, bits).parse()
nodelist_true = parser.parse(('else', 'endif'))
token = parser.next_token()
if token.contents == 'else':
nodelist_false = parser.parse(('endif',))
parser.delete_first_token()
else:
nodelist_false = None
return SmartIfNode(var, nodelist_true, nodelist_false)
if __name__ == '__main__':
unittest.main()

166
sigi/apps/diagnosticos/templatetags/test_smart_if.py

@ -0,0 +1,166 @@
# -*- coding: utf-8 -*-
import pytest
from smart_if import Or, And, Equals, Greater, GreaterOrEqual, In, IfParser
class TestVar(object):
"""
A basic self-resolvable object similar to a Django template variable. Used
to assist with tests.
"""
def __init__(self, value):
self.value = value
def resolve(self, context):
return self.value
class TestIfParser(IfParser):
def create_var(self, value):
return TestVar(value)
class ValueHolder(object):
pass
VALORES = ValueHolder()
VALORES.true = TestVar(True)
VALORES.false = TestVar(False)
VALORES.high = TestVar(9000)
VALORES.low = TestVar(1)
def assertCalc(calc, context=None):
"""
Test a calculation is True, also checking the inverse "negate" case.
"""
context = context or {}
assert calc.resolve(context)
calc.negate = not calc.negate
assert not calc.resolve(context)
def assertCalcFalse(calc, context=None):
"""
Test a calculation is False, also checking the inverse "negate" case.
"""
context = context or {}
assert not calc.resolve(context)
calc.negate = not calc.negate
assert calc.resolve(context)
def test_or():
assertCalc(Or(VALORES.true))
assertCalcFalse(Or(VALORES.false))
assertCalc(Or(VALORES.true, VALORES.true))
assertCalc(Or(VALORES.true, VALORES.false))
assertCalc(Or(VALORES.false, VALORES.true))
assertCalcFalse(Or(VALORES.false, VALORES.false))
def test_and():
assertCalc(And(VALORES.true, VALORES.true))
assertCalcFalse(And(VALORES.true, VALORES.false))
assertCalcFalse(And(VALORES.false, VALORES.true))
assertCalcFalse(And(VALORES.false, VALORES.false))
def test_equals():
assertCalc(Equals(VALORES.low, VALORES.low))
assertCalcFalse(Equals(VALORES.low, VALORES.high))
def test_greater():
assertCalc(Greater(VALORES.high, VALORES.low))
assertCalcFalse(Greater(VALORES.low, VALORES.low))
assertCalcFalse(Greater(VALORES.low, VALORES.high))
def test_greater_or_equal():
assertCalc(GreaterOrEqual(VALORES.high, VALORES.low))
assertCalc(GreaterOrEqual(VALORES.low, VALORES.low))
assertCalcFalse(GreaterOrEqual(VALORES.low, VALORES.high))
def test_in():
list_ = TestVar([1, 2, 3])
invalid_list = TestVar(None)
assertCalc(In(VALORES.low, list_))
assertCalcFalse(In(VALORES.low, invalid_list))
def test_parse_bits():
var = TestIfParser([True]).parse()
assert var.resolve({})
var = TestIfParser([False]).parse()
assert not var.resolve({})
var = TestIfParser([False, 'or', True]).parse()
assert var.resolve({})
var = TestIfParser([False, 'and', True]).parse()
assert not var.resolve({})
var = TestIfParser(['not', False, 'and', 'not', False]).parse()
assert var.resolve({})
var = TestIfParser(['not', 'not', True]).parse()
assert var.resolve({})
var = TestIfParser([1, '=', 1]).parse()
assert var.resolve({})
var = TestIfParser([1, 'not', '=', 1]).parse()
assert not var.resolve({})
var = TestIfParser([1, 'not', 'not', '=', 1]).parse()
assert var.resolve({})
var = TestIfParser([1, '!=', 1]).parse()
assert not var.resolve({})
var = TestIfParser([3, '>', 2]).parse()
assert var.resolve({})
var = TestIfParser([1, '<', 2]).parse()
assert var.resolve({})
var = TestIfParser([2, 'not', 'in', [2, 3]]).parse()
assert not var.resolve({})
var = TestIfParser([1, 'or', 1, '=', 2]).parse()
assert var.resolve({})
def test_boolean():
var = TestIfParser([True, 'and', True, 'and', True]).parse()
assert var.resolve({})
var = TestIfParser([False, 'or', False, 'or', True]).parse()
assert var.resolve({})
var = TestIfParser([True, 'and', False, 'or', True]).parse()
assert var.resolve({})
var = TestIfParser([False, 'or', True, 'and', True]).parse()
assert var.resolve({})
var = TestIfParser([True, 'and', True, 'and', False]).parse()
assert not var.resolve({})
var = TestIfParser([False, 'or', False, 'or', False]).parse()
assert not var.resolve({})
var = TestIfParser([False, 'or', True, 'and', False]).parse()
assert not var.resolve({})
var = TestIfParser([False, 'and', True, 'or', False]).parse()
assert not var.resolve({})
def test_invalid():
pytest.raises(ValueError, TestIfParser(['not']).parse)
pytest.raises(ValueError, TestIfParser(['==']).parse)
pytest.raises(ValueError, TestIfParser([1, 'in']).parse)
pytest.raises(ValueError, TestIfParser([1, '>', 'in']).parse)
pytest.raises(ValueError, TestIfParser([1, '==', 'not', 'not']).parse)
pytest.raises(ValueError, TestIfParser([1, 2]).parse)

2
sigi/settings/base.py

@ -111,3 +111,5 @@ MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/' MEDIA_URL = '/media/'
SESSION_EXPIRE_AT_BROWSER_CLOSE = True SESSION_EXPIRE_AT_BROWSER_CLOSE = True
TEST_RUNNER = None

16
sigi/settings/test.py

@ -0,0 +1,16 @@
from base import *
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '0$ip1fb5xtq%a=)-k_4r^(#jn0t^@+*^kihkxkozg-mip7+w3+'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'sigi_test',
'USER': 'sigi',
'PASSWORD': 'sigi',
'HOST': 'localhost',
'PORT': '5432',
}
}
Loading…
Cancel
Save