add: initial evs support
This commit is contained in:
@@ -7,6 +7,7 @@ Classes and Types to parse and represent a RADIUS dictionary.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from contextlib import suppress
|
||||
from os.path import dirname, isabs, join, normpath
|
||||
from typing import IO, Dict, Generator, List, Optional, Sequence, Tuple, Union
|
||||
|
||||
@@ -16,11 +17,11 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
INTEGER_TYPES: Dict[str, Tuple[int, int]] = {
|
||||
"byte": (0, 255),
|
||||
"short": (0, 2 ** 16 - 1),
|
||||
"signed": (-(2 ** 31), 2 ** 31 - 1),
|
||||
"integer": (0, 2 ** 32 - 1),
|
||||
"integer64": (0, 2 ** 64 - 1),
|
||||
"BYTE": (0, 255),
|
||||
"SHORT": (0, 2 ** 16 - 1),
|
||||
"SIGNED": (-(2 ** 31), 2 ** 31 - 1),
|
||||
"INTEGER": (0, 2 ** 32 - 1),
|
||||
"INTEGER64": (0, 2 ** 64 - 1),
|
||||
}
|
||||
|
||||
|
||||
@@ -111,6 +112,7 @@ class Dictionary:
|
||||
self.attrindex: Dict[Union[str, int, Tuple[int, ...]], Attribute] = {}
|
||||
self.rfc_vendor = Vendor("RFC", 0, 1, 1, False, {})
|
||||
self.cur_vendor = self.rfc_vendor
|
||||
self.evs: Dict[str, List[int]] = {}
|
||||
if __dictio is not None:
|
||||
loader = dict_parser(dictionary, __dictio)
|
||||
else:
|
||||
@@ -120,11 +122,12 @@ class Dictionary:
|
||||
def read_dictionary(self, reader: Generator[Tuple[int, List[str]], None, None]):
|
||||
"""Read and parse a (Free)RADIUS dictionary."""
|
||||
self.filestack: List[str] = []
|
||||
cur_evs: List[int] = []
|
||||
for line_num, tokens in reader:
|
||||
key = tokens[0]
|
||||
if key == "ATTRIBUTE":
|
||||
# logging is done within the method
|
||||
self._parse_attribute(tokens, line_num)
|
||||
self._parse_attribute(tokens, line_num, cur_evs)
|
||||
elif key == "VALUE":
|
||||
# logging is done within the method
|
||||
self._parse_value(tokens, line_num)
|
||||
@@ -140,10 +143,11 @@ class Dictionary:
|
||||
self._parse_vendor(tokens, line_num)
|
||||
LOG.info("Register vendor %s", tokens[1])
|
||||
elif key == "BEGIN-VENDOR":
|
||||
self._parse_begin_vendor(tokens, line_num)
|
||||
cur_evs = self._parse_begin_vendor(tokens, line_num)
|
||||
LOG.info("Open Vendor section %s", tokens[1])
|
||||
elif key == "END-VENDOR":
|
||||
self._parse_end_vendor(tokens, line_num)
|
||||
cur_evs = []
|
||||
LOG.info("Close Vendor section %s", tokens[1])
|
||||
elif key == "BEGIN-TLV":
|
||||
raise NotImplementedError(
|
||||
@@ -164,73 +168,93 @@ class Dictionary:
|
||||
vendor_name = tokens[1]
|
||||
vendor_id = int(tokens[2], 0)
|
||||
continuation = False
|
||||
t_len, l_len = 1, 1
|
||||
|
||||
# Parse optional vendor specification
|
||||
try:
|
||||
with suppress(IndexError):
|
||||
vendor_format = tokens[3].split("=")
|
||||
if vendor_format[0] != "format":
|
||||
if vendor_format[0] == "format":
|
||||
try:
|
||||
vendor_format = vendor_format[1].split(",")
|
||||
t_len, l_len = (int(a) for a in vendor_format[:2])
|
||||
if t_len not in [1, 2, 4]:
|
||||
raise ParseError(
|
||||
filename,
|
||||
f'Invalid type length definition "{t_len}" for vendor {vendor_name}',
|
||||
line_num,
|
||||
)
|
||||
if l_len not in [0, 1, 2]:
|
||||
raise ParseError(
|
||||
filename,
|
||||
f'Invalid length definition "{l_len}" for vendor {vendor_name}',
|
||||
line_num,
|
||||
)
|
||||
with suppress(IndexError):
|
||||
if vendor_format[2] == "c":
|
||||
if not vendor_name.upper() == "WIMAX":
|
||||
# Not sure why, but FreeRADIUS has this limit,
|
||||
# so we just do the same cause they know better than me
|
||||
raise ParseError(
|
||||
filename,
|
||||
"continuation-bit is only supported for WiMAX",
|
||||
line_num,
|
||||
)
|
||||
continuation = True
|
||||
except IndexError as exc:
|
||||
raise ParseError(
|
||||
filename,
|
||||
f"Invalid format definition for vendor {vendor_name}",
|
||||
line_num,
|
||||
) from exc
|
||||
except ValueError as exc:
|
||||
raise ParseError(
|
||||
filename,
|
||||
f"Syntax error in specification for vendor {vendor_name}",
|
||||
line_num,
|
||||
) from exc
|
||||
else:
|
||||
raise ParseError(
|
||||
filename,
|
||||
f"Unknown option {vendor_format[0]} for vendor definition",
|
||||
line_num,
|
||||
)
|
||||
try:
|
||||
vendor_format = vendor_format[1].split(",")
|
||||
t_len, l_len = (int(a) for a in vendor_format[:2])
|
||||
if t_len not in [1, 2, 4]:
|
||||
raise ParseError(
|
||||
filename,
|
||||
f'Invalid type length definition "{t_len}" for vendor {vendor_name}',
|
||||
line_num,
|
||||
)
|
||||
if l_len not in [0, 1, 2]:
|
||||
raise ParseError(
|
||||
filename,
|
||||
f'Invalid length definition "{l_len}" for vendor {vendor_name}',
|
||||
line_num,
|
||||
)
|
||||
try:
|
||||
if vendor_format[2] == "c":
|
||||
if not vendor_name.upper() == "WIMAX":
|
||||
# Not sure why, but FreeRADIUS has this limit,
|
||||
# so we just do the same cause they know better than me
|
||||
raise ParseError(
|
||||
filename,
|
||||
"continuation-bit is only supported for WiMAX",
|
||||
line_num,
|
||||
)
|
||||
continuation = True
|
||||
except IndexError:
|
||||
pass
|
||||
except ValueError as exc:
|
||||
raise ParseError(
|
||||
filename,
|
||||
f"Syntax error in specification for vendor {vendor_name}",
|
||||
line_num,
|
||||
) from exc
|
||||
except IndexError:
|
||||
# no format definition
|
||||
t_len, l_len = 1, 1
|
||||
|
||||
vendor = Vendor(vendor_name, vendor_id, t_len, l_len, continuation, {})
|
||||
self.vendor_lookup_id_by_name[vendor_name] = vendor_id
|
||||
self.vendor[vendor_id] = vendor
|
||||
|
||||
def _parse_begin_vendor(self, tokens: Sequence[str], line_num: int):
|
||||
def _parse_begin_vendor(self, tokens: Sequence[str], line_num: int) -> List[int]:
|
||||
"""Parse the BEGIN-VENDOR line of (Free)RADIUS dictionaries."""
|
||||
filename = self.filestack[-1]
|
||||
evs = []
|
||||
if self.cur_vendor != self.rfc_vendor:
|
||||
raise ParseError(
|
||||
filename,
|
||||
"vendor-begin sections are not allowed to be nested",
|
||||
line_num,
|
||||
)
|
||||
if len(tokens) != 2:
|
||||
|
||||
if len(tokens) not in [2, 3]:
|
||||
raise ParseError(
|
||||
filename,
|
||||
"Incorrect number of tokens for begin-vendor statement",
|
||||
line_num,
|
||||
)
|
||||
|
||||
with suppress(IndexError):
|
||||
vendor_format = tokens[2].split("=")
|
||||
if vendor_format[0] != "format":
|
||||
raise ParseError(
|
||||
filename, f"Invalid token {tokens[3]} for vendor begin", line_num
|
||||
)
|
||||
if vendor_format[1].upper() in self.evs:
|
||||
try:
|
||||
evs = self.evs[vendor_format[1].upper()]
|
||||
except KeyError as exc:
|
||||
raise ParseError(
|
||||
filename, f"Unknown EVS {vendor_format[1]}", line_num
|
||||
) from exc
|
||||
|
||||
try:
|
||||
vendor_id = self.vendor_lookup_id_by_name[tokens[1]]
|
||||
self.cur_vendor = self.vendor[vendor_id]
|
||||
@@ -240,6 +264,7 @@ class Dictionary:
|
||||
f"Unknown vendor {tokens[1]} in begin-vendor statement",
|
||||
line_num,
|
||||
) from exc
|
||||
return evs
|
||||
|
||||
def _parse_end_vendor(self, tokens: Sequence[str], line_num: int):
|
||||
"""Parse the END-VENDOR line of (Free)RADIUS dictionaries."""
|
||||
@@ -299,10 +324,12 @@ class Dictionary:
|
||||
|
||||
return has_tag, encrypt
|
||||
|
||||
def _parse_attribute_code(self, attr_code: str, line_num: int) -> List[int]:
|
||||
def _parse_attribute_code(
|
||||
self, attr_code: str, line_num: int, evs: List[int]
|
||||
) -> List[int]:
|
||||
filename = self.filestack[-1]
|
||||
tlength = self.cur_vendor.tlength
|
||||
codes = []
|
||||
codes = evs.copy()
|
||||
for code in attr_code.split("."):
|
||||
try:
|
||||
code_num = _parse_number(code)
|
||||
@@ -325,7 +352,7 @@ class Dictionary:
|
||||
codes.append(code_num)
|
||||
return codes
|
||||
|
||||
def _parse_attribute(self, tokens: Sequence[str], line_num: int):
|
||||
def _parse_attribute(self, tokens: Sequence[str], line_num: int, evs: List[int]):
|
||||
"""Parse an ATTRIBUTE line of (Free)RADIUS dictionaries."""
|
||||
filename = self.filestack[-1]
|
||||
if not len(tokens) in [4, 5]:
|
||||
@@ -348,7 +375,7 @@ class Dictionary:
|
||||
line_num,
|
||||
)
|
||||
|
||||
codes = self._parse_attribute_code(attr_code, line_num)
|
||||
codes = self._parse_attribute_code(attr_code, line_num, evs)
|
||||
|
||||
# TODO: Do we some explicit handling of tlvs?
|
||||
# if len(codes) > 1:
|
||||
@@ -358,13 +385,13 @@ class Dictionary:
|
||||
|
||||
base_datatype = datatype.split("[")[0].replace("-", "")
|
||||
try:
|
||||
attribute_type = Datatype[base_datatype]
|
||||
attribute_type = Datatype[base_datatype.upper()]
|
||||
except KeyError as exc:
|
||||
raise ParseError(filename, f"Illegal type: {datatype}", line_num) from exc
|
||||
|
||||
attribute = Attribute(
|
||||
name,
|
||||
codes[-1],
|
||||
codes, # [-1],
|
||||
attribute_type,
|
||||
{},
|
||||
has_tag,
|
||||
@@ -377,6 +404,11 @@ class Dictionary:
|
||||
)
|
||||
self.cur_vendor.attrs[attrcode] = attribute
|
||||
|
||||
if datatype == "evs":
|
||||
if not isinstance(attrcode, tuple):
|
||||
raise ParseError(filename, "evs must be a tlv", line_num)
|
||||
self.evs[name.upper()] = list(attrcode)
|
||||
|
||||
if self.cur_vendor != self.rfc_vendor:
|
||||
codes = [26, self.cur_vendor.code] + codes
|
||||
LOG.info(
|
||||
@@ -433,8 +465,7 @@ class Dictionary:
|
||||
except KeyError as exc:
|
||||
raise ParseError(
|
||||
filename,
|
||||
f"only attributes with integer typed datatypes can have"
|
||||
f"value definitions {attribute.datatype}",
|
||||
f"only attributes with integer typed datatypes can have value definitions {attribute.datatype}",
|
||||
line_num,
|
||||
) from exc
|
||||
attribute.values[value] = key
|
||||
|
||||
@@ -10,7 +10,7 @@ we don't support them (yet).
|
||||
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum, IntEnum, auto
|
||||
from typing import Dict, Tuple, Union
|
||||
from typing import Dict, List, Tuple, Union
|
||||
|
||||
|
||||
class Code(IntEnum):
|
||||
@@ -78,7 +78,7 @@ class Attribute: # pylint: disable=too-many-instance-attributes
|
||||
"""RADIUS Attribute definition"""
|
||||
|
||||
name: str
|
||||
code: int
|
||||
code: Union[int, List[int]]
|
||||
datatype: Datatype
|
||||
values: Dict[Union[int, str], Union[int, str]]
|
||||
has_tag: bool = False
|
||||
|
||||
@@ -40,44 +40,6 @@ ATTRIBUTE RFC-SPACE-TAGGED-COMBOIP 114 comboip has_tag
|
||||
ATTRIBUTE RFC-SPACE-TAGGED-IFID 115 ifid has_tag
|
||||
ATTRIBUTE RFC-SPACE-TAGGED-ETHER 116 ether has_tag
|
||||
|
||||
# TODO How are EVS meant to be specified?
|
||||
# ATTRIBUTE VENDOR10-EVS-TYPE-STRING 19.21.1234.1 string
|
||||
# ATTRIBUTE VENDOR10-EVS-TYPE-OCTETS 19.21.1234.2 octets
|
||||
# ATTRIBUTE VENDOR10-EVS-TYPE-DATE 19.21.1234.3 date
|
||||
# ATTRIBUTE VENDOR10-EVS-TYPE-ABINARY 19.21.1234.4 abinary
|
||||
# ATTRIBUTE VENDOR10-EVS-TYPE-BYTE 19.21.1234.5 byte
|
||||
# ATTRIBUTE VENDOR10-EVS-TYPE-SHORT 19.21.1234.6 short
|
||||
# ATTRIBUTE VENDOR10-EVS-TYPE-INTEGER 19.21.1234.7 integer
|
||||
# ATTRIBUTE VENDOR10-EVS-TYPE-SIGNED 19.21.1234.8 signed
|
||||
# ATTRIBUTE VENDOR10-EVS-TYPE-INTEGER64 19.21.1234.9 integer64
|
||||
# ATTRIBUTE VENDOR10-EVS-TYPE-IPADDR 19.21.1234.10 ipaddr
|
||||
# ATTRIBUTE VENDOR10-EVS-TYPE-IPV4PREFIX 19.21.1234.11 ipv4prefix
|
||||
# ATTRIBUTE VENDOR10-EVS-TYPE-IPV6ADDR 19.21.1234.12 ipv6addr
|
||||
# ATTRIBUTE VENDOR10-EVS-TYPE-IPV6PREFIX 19.21.1234.13 ipv6prefix
|
||||
# ATTRIBUTE VENDOR10-EVS-TYPE-COMBOIP 19.21.1234.14 comboip
|
||||
# ATTRIBUTE VENDOR10-EVS-TYPE-IFID 19.21.1234.15 ifid
|
||||
# ATTRIBUTE VENDOR10-EVS-TYPE-ETHER 19.21.1234.16 ether
|
||||
# ATTRIBUTE VENDOR10-EVS-TYPE-TLV 19.21.1234.18 tlv
|
||||
#
|
||||
# ATTRIBUTE VENDOR10-LONG-EVS-TYPE-STRING 20.21.1234.1 string
|
||||
# ATTRIBUTE VENDOR10-LONG-EVS-TYPE-OCTETS 20.21.1234.2 octets
|
||||
# ATTRIBUTE VENDOR10-LONG-EVS-TYPE-DATE 20.21.1234.3 date
|
||||
# ATTRIBUTE VENDOR10-LONG-EVS-TYPE-ABINARY 20.21.1234.4 abinary
|
||||
# ATTRIBUTE VENDOR10-LONG-EVS-TYPE-BYTE 20.21.1234.5 byte
|
||||
# ATTRIBUTE VENDOR10-LONG-EVS-TYPE-SHORT 20.21.1234.6 short
|
||||
# ATTRIBUTE VENDOR10-LONG-EVS-TYPE-INTEGER 20.21.1234.7 integer
|
||||
# ATTRIBUTE VENDOR10-LONG-EVS-TYPE-SIGNED 20.21.1234.8 signed
|
||||
# ATTRIBUTE VENDOR10-LONG-EVS-TYPE-INTEGER64 20.21.1234.9 integer64
|
||||
# ATTRIBUTE VENDOR10-LONG-EVS-TYPE-IPADDR 20.21.1234.10 ipaddr
|
||||
# ATTRIBUTE VENDOR10-LONG-EVS-TYPE-IPV4PREFIX 20.21.1234.11 ipv4prefix
|
||||
# ATTRIBUTE VENDOR10-LONG-EVS-TYPE-IPV6ADDR 20.21.1234.12 ipv6addr
|
||||
# ATTRIBUTE VENDOR10-LONG-EVS-TYPE-IPV6PREFIX 20.21.1234.13 ipv6prefix
|
||||
# ATTRIBUTE VENDOR10-LONG-EVS-TYPE-COMBOIP 20.21.1234.14 comboip
|
||||
# ATTRIBUTE VENDOR10-LONG-EVS-TYPE-IFID 20.21.1234.15 ifid
|
||||
# ATTRIBUTE VENDOR10-LONG-EVS-TYPE-ETHER 20.21.1234.16 ether
|
||||
# ATTRIBUTE VENDOR10-LONG-EVS-TYPE-TLV 20.21.1234.18 tlv
|
||||
|
||||
|
||||
VENDOR TEST10 1234 format=1,0
|
||||
|
||||
BEGIN-VENDOR TEST10
|
||||
@@ -118,6 +80,47 @@ ATTRIBUTE VENDOR10-TAGGED-ETHER 116 ether has_tag
|
||||
|
||||
END-VENDOR TEST10
|
||||
|
||||
BEGIN-VENDOR TEST10 format=RFC-SPACE-TYPE-EVS
|
||||
ATTRIBUTE VENDOR10-EVS-TYPE-STRING 19.21.1234.1 string
|
||||
ATTRIBUTE VENDOR10-EVS-TYPE-OCTETS 19.21.1234.2 octets
|
||||
ATTRIBUTE VENDOR10-EVS-TYPE-DATE 19.21.1234.3 date
|
||||
ATTRIBUTE VENDOR10-EVS-TYPE-ABINARY 19.21.1234.4 abinary
|
||||
ATTRIBUTE VENDOR10-EVS-TYPE-BYTE 19.21.1234.5 byte
|
||||
ATTRIBUTE VENDOR10-EVS-TYPE-SHORT 19.21.1234.6 short
|
||||
ATTRIBUTE VENDOR10-EVS-TYPE-INTEGER 19.21.1234.7 integer
|
||||
ATTRIBUTE VENDOR10-EVS-TYPE-SIGNED 19.21.1234.8 signed
|
||||
ATTRIBUTE VENDOR10-EVS-TYPE-INTEGER64 19.21.1234.9 integer64
|
||||
ATTRIBUTE VENDOR10-EVS-TYPE-IPADDR 19.21.1234.10 ipaddr
|
||||
ATTRIBUTE VENDOR10-EVS-TYPE-IPV4PREFIX 19.21.1234.11 ipv4prefix
|
||||
ATTRIBUTE VENDOR10-EVS-TYPE-IPV6ADDR 19.21.1234.12 ipv6addr
|
||||
ATTRIBUTE VENDOR10-EVS-TYPE-IPV6PREFIX 19.21.1234.13 ipv6prefix
|
||||
ATTRIBUTE VENDOR10-EVS-TYPE-COMBOIP 19.21.1234.14 comboip
|
||||
ATTRIBUTE VENDOR10-EVS-TYPE-IFID 19.21.1234.15 ifid
|
||||
ATTRIBUTE VENDOR10-EVS-TYPE-ETHER 19.21.1234.16 ether
|
||||
ATTRIBUTE VENDOR10-EVS-TYPE-TLV 19.21.1234.18 tlv
|
||||
END-VENDOR
|
||||
|
||||
BEGIN-VENDOR TEST10 format=RFC-SPACE-TYPE-EVS
|
||||
ATTRIBUTE VENDOR10-LONG-EVS-TYPE-STRING 20.21.1234.1 string
|
||||
ATTRIBUTE VENDOR10-LONG-EVS-TYPE-OCTETS 20.21.1234.2 octets
|
||||
ATTRIBUTE VENDOR10-LONG-EVS-TYPE-DATE 20.21.1234.3 date
|
||||
ATTRIBUTE VENDOR10-LONG-EVS-TYPE-ABINARY 20.21.1234.4 abinary
|
||||
ATTRIBUTE VENDOR10-LONG-EVS-TYPE-BYTE 20.21.1234.5 byte
|
||||
ATTRIBUTE VENDOR10-LONG-EVS-TYPE-SHORT 20.21.1234.6 short
|
||||
ATTRIBUTE VENDOR10-LONG-EVS-TYPE-INTEGER 20.21.1234.7 integer
|
||||
ATTRIBUTE VENDOR10-LONG-EVS-TYPE-SIGNED 20.21.1234.8 signed
|
||||
ATTRIBUTE VENDOR10-LONG-EVS-TYPE-INTEGER64 20.21.1234.9 integer64
|
||||
ATTRIBUTE VENDOR10-LONG-EVS-TYPE-IPADDR 20.21.1234.10 ipaddr
|
||||
ATTRIBUTE VENDOR10-LONG-EVS-TYPE-IPV4PREFIX 20.21.1234.11 ipv4prefix
|
||||
ATTRIBUTE VENDOR10-LONG-EVS-TYPE-IPV6ADDR 20.21.1234.12 ipv6addr
|
||||
ATTRIBUTE VENDOR10-LONG-EVS-TYPE-IPV6PREFIX 20.21.1234.13 ipv6prefix
|
||||
ATTRIBUTE VENDOR10-LONG-EVS-TYPE-COMBOIP 20.21.1234.14 comboip
|
||||
ATTRIBUTE VENDOR10-LONG-EVS-TYPE-IFID 20.21.1234.15 ifid
|
||||
ATTRIBUTE VENDOR10-LONG-EVS-TYPE-ETHER 20.21.1234.16 ether
|
||||
ATTRIBUTE VENDOR10-LONG-EVS-TYPE-TLV 20.21.1234.18 tlv
|
||||
END-VENDOR
|
||||
|
||||
|
||||
VENDOR TEST11 1235 format=1,1
|
||||
|
||||
BEGIN-VENDOR TEST11
|
||||
|
||||
@@ -119,7 +119,8 @@ def test_valid_attribute_numbers(number):
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"invalid_number", ["1000", "ABCD", "-1", "inf", "INF", "-INF", "2e4", "2.5e3"],
|
||||
"invalid_number",
|
||||
["1000", "ABCD", "-1", "inf", "INF", "-INF", "2e4", "2.5e3"],
|
||||
)
|
||||
def test_invalid_attribute_numbers(invalid_number):
|
||||
dictionary = StringIO(f"ATTRIBUTE NAME {invalid_number} integer64")
|
||||
@@ -247,7 +248,6 @@ def test_value_number_out_of_limit(value_num, attr_type):
|
||||
"tlv",
|
||||
"extended",
|
||||
"long-extended",
|
||||
"evs",
|
||||
],
|
||||
)
|
||||
def test_all_datatypes_rfc_space(datatype):
|
||||
@@ -255,6 +255,11 @@ def test_all_datatypes_rfc_space(datatype):
|
||||
Dictionary("", dictionary)
|
||||
|
||||
|
||||
def test_evs_datatype():
|
||||
dictionary = StringIO("ATTRIBUTE TEST-ATTRIBUTE 1.10 evs\n")
|
||||
Dictionary("", dictionary)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"datatype",
|
||||
[
|
||||
@@ -299,7 +304,8 @@ def test_invalid_datatypes_in_vendor_space(datatype):
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"invalid_number", ["ABCD", "-1", "inf", "INF", "-INF", "0.1", "2e4", "2.5e3"],
|
||||
"invalid_number",
|
||||
["ABCD", "-1", "inf", "INF", "-INF", "0.1", "2e4", "2.5e3"],
|
||||
)
|
||||
def test_invalid_value_numbers(invalid_number):
|
||||
dictionary = StringIO(
|
||||
@@ -401,3 +407,16 @@ def test_get_nonexisting_attributes_from_dictionaries(attribute):
|
||||
dd = Dictionary("", dictionary)
|
||||
with pytest.raises(KeyError):
|
||||
_ = dd[attribute]
|
||||
|
||||
|
||||
def test_extended_evs():
|
||||
dictionary = StringIO(
|
||||
"ATTRIBUTE RFC-EXTENDED 10 extended\n"
|
||||
"ATTRIBUTE RFC-EXTENDED-EVS 10.20 evs\n"
|
||||
"VENDOR TEST-VENDOR 1234\n"
|
||||
"BEGIN-VENDOR TEST-VENDOR format=RFC-EXTENDED-EVS\n"
|
||||
"ATTRIBUTE VENDOR-ATTRIBUTE 10 integer\n"
|
||||
"END-VENDOR TEST-VENDOR"
|
||||
)
|
||||
dd = Dictionary("", dictionary)
|
||||
assert dd["VENDOR-ATTRIBUTE"].code == [10, 20, 10]
|
||||
|
||||
Reference in New Issue
Block a user