aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libpathod/language/actions.py4
-rw-r--r--libpathod/language/base.py9
-rw-r--r--libpathod/language/http.py3
-rw-r--r--libpathod/language/message.py13
-rw-r--r--test/test_language_actions.py5
-rw-r--r--test/test_language_base.py5
-rw-r--r--test/test_language_http.py8
7 files changed, 46 insertions, 1 deletions
diff --git a/libpathod/language/actions.py b/libpathod/language/actions.py
index e86394a0..f5b828fe 100644
--- a/libpathod/language/actions.py
+++ b/libpathod/language/actions.py
@@ -45,6 +45,8 @@ class _Action(base.Token):
class PauseAt(_Action):
+ unique_name = None
+
def __init__(self, offset, seconds):
_Action.__init__(self, offset)
self.seconds = seconds
@@ -93,6 +95,8 @@ class DisconnectAt(_Action):
class InjectAt(_Action):
+ unique_name = None
+
def __init__(self, offset, value):
_Action.__init__(self, offset)
self.value = value
diff --git a/libpathod/language/base.py b/libpathod/language/base.py
index 3773fde1..2a9e4ed3 100644
--- a/libpathod/language/base.py
+++ b/libpathod/language/base.py
@@ -77,6 +77,15 @@ class Token(object):
"""
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):
"""
Resolves this token to ready it for transmission. This means that
diff --git a/libpathod/language/http.py b/libpathod/language/http.py
index 070cc5f4..daee7e54 100644
--- a/libpathod/language/http.py
+++ b/libpathod/language/http.py
@@ -46,6 +46,8 @@ class Method(base.OptionsOrValue):
class _HeaderMixin(object):
+ unique_name = None
+
def format_header(self, key, value):
return [key, ": ", value, "\r\n"]
@@ -166,6 +168,7 @@ class _HTTPMessage(message.Message):
class Response(_HTTPMessage):
+ unique_name = None
comps = (
Body,
Header,
diff --git a/libpathod/language/message.py b/libpathod/language/message.py
index b5ef7045..dbc0cfdd 100644
--- a/libpathod/language/message.py
+++ b/libpathod/language/message.py
@@ -1,5 +1,5 @@
import abc
-from . import actions
+from . import actions, exceptions
LOG_TRUNCATE = 1024
@@ -9,6 +9,17 @@ class Message(object):
logattrs = []
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
def toks(self, klass):
diff --git a/test/test_language_actions.py b/test/test_language_actions.py
index 7676fb72..b7361dff 100644
--- a/test/test_language_actions.py
+++ b/test/test_language_actions.py
@@ -8,6 +8,11 @@ def parse_request(s):
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:
def test_parse_response(self):
a = language.parse_response("400:d0").actions[0]
diff --git a/test/test_language_base.py b/test/test_language_base.py
index bd67c010..404b302d 100644
--- a/test/test_language_base.py
+++ b/test/test_language_base.py
@@ -310,6 +310,11 @@ class TBoolean(base.Boolean):
name = "test"
+def test_unique_name():
+ b = TBoolean(True)
+ assert b.unique_name
+
+
class test_boolean():
e = TBoolean.expr()
assert e.parseString("test")[0].value
diff --git a/test/test_language_http.py b/test/test_language_http.py
index a7313bfb..17bce802 100644
--- a/test/test_language_http.py
+++ b/test/test_language_http.py
@@ -342,3 +342,11 @@ def test_pathodspec_freeze():
)
assert e.freeze({})
assert e.values({})
+
+
+def test_unique_components():
+ tutils.raises(
+ "multiple body clauses",
+ language.parse_response,
+ "400:b@1:b@1"
+ )