Introduce and enfoce uniqueness constraints for language components

This commit is contained in:
Aldo Cortesi 2015-05-17 10:43:30 +12:00
parent 2ee60783b6
commit e4feba5433
7 changed files with 46 additions and 1 deletions

View File

@ -45,6 +45,8 @@ class _Action(base.Token):
class PauseAt(_Action): class PauseAt(_Action):
unique_name = None
def __init__(self, offset, seconds): def __init__(self, offset, seconds):
_Action.__init__(self, offset) _Action.__init__(self, offset)
self.seconds = seconds self.seconds = seconds
@ -93,6 +95,8 @@ class DisconnectAt(_Action):
class InjectAt(_Action): class InjectAt(_Action):
unique_name = None
def __init__(self, offset, value): def __init__(self, offset, value):
_Action.__init__(self, offset) _Action.__init__(self, offset)
self.value = value self.value = value

View File

@ -77,6 +77,15 @@ class Token(object):
""" """
return None return None
@property
def unique_name(self):
"""
Controls uniqueness constraints for tokens. No two tokens with the
same name will be allowed. If no uniquness should be applied, this
should be None.
"""
return self.__class__.__name__
def resolve(self, settings, msg): def resolve(self, settings, msg):
""" """
Resolves this token to ready it for transmission. This means that Resolves this token to ready it for transmission. This means that

View File

@ -46,6 +46,8 @@ class Method(base.OptionsOrValue):
class _HeaderMixin(object): class _HeaderMixin(object):
unique_name = None
def format_header(self, key, value): def format_header(self, key, value):
return [key, ": ", value, "\r\n"] return [key, ": ", value, "\r\n"]
@ -166,6 +168,7 @@ class _HTTPMessage(message.Message):
class Response(_HTTPMessage): class Response(_HTTPMessage):
unique_name = None
comps = ( comps = (
Body, Body,
Header, Header,

View File

@ -1,5 +1,5 @@
import abc import abc
from . import actions from . import actions, exceptions
LOG_TRUNCATE = 1024 LOG_TRUNCATE = 1024
@ -9,6 +9,17 @@ class Message(object):
logattrs = [] logattrs = []
def __init__(self, tokens): def __init__(self, tokens):
track = set([])
for i in tokens:
if i.unique_name:
if i.unique_name in track:
raise exceptions.ParseException(
"Message has multiple %s clauses, "
"but should only have one." % i.unique_name,
0, 0
)
else:
track.add(i.unique_name)
self.tokens = tokens self.tokens = tokens
def toks(self, klass): def toks(self, klass):

View File

@ -8,6 +8,11 @@ def parse_request(s):
return language.parse_requests(s)[0] return language.parse_requests(s)[0]
def test_unique_name():
assert not actions.PauseAt(0, "f").unique_name
assert actions.DisconnectAt(0).unique_name
class TestDisconnects: class TestDisconnects:
def test_parse_response(self): def test_parse_response(self):
a = language.parse_response("400:d0").actions[0] a = language.parse_response("400:d0").actions[0]

View File

@ -310,6 +310,11 @@ class TBoolean(base.Boolean):
name = "test" name = "test"
def test_unique_name():
b = TBoolean(True)
assert b.unique_name
class test_boolean(): class test_boolean():
e = TBoolean.expr() e = TBoolean.expr()
assert e.parseString("test")[0].value assert e.parseString("test")[0].value

View File

@ -342,3 +342,11 @@ def test_pathodspec_freeze():
) )
assert e.freeze({}) assert e.freeze({})
assert e.values({}) assert e.values({})
def test_unique_components():
tutils.raises(
"multiple body clauses",
language.parse_response,
"400:b@1:b@1"
)