Files
pyrad3/tests/test_dictionary.py
2020-08-17 09:19:04 +02:00

413 lines
10 KiB
Python

# Copyright 2020 Istvan Ruzman
# SPDX-License-Identifier: MIT OR Apache-2.0
from io import StringIO
import pytest
from pyrad3.dictionary import Dictionary, ParseError
@pytest.mark.parametrize(
"filename", ["dictionaries/self_recursive", "dictionaries/mutual_recursive"]
)
def test_dictionary_recursion(filename):
with pytest.raises(ParseError):
Dictionary("tests/" + filename)
@pytest.mark.parametrize(
"line",
[
"$INCLUDE",
"BEGIN-VENDOR",
"END-VENDOR",
"VENDOR",
"VENDOR NAME",
"ATTRIBUTE",
"ATTRIBUTE NAME",
"VALUE",
"VALUE ATTRNAME",
"VALUE ATTRNAME VALUENAME",
],
)
def test_lines_missing_tokens(line):
dictionary = StringIO(line)
with pytest.raises(ParseError):
Dictionary("", dictionary)
def test_invalid_token():
dictionary = StringIO("invalid_token")
with pytest.raises(ParseError):
Dictionary("", dictionary)
@pytest.mark.parametrize(
"vendor",
[
"VENDOR test 1234",
"VENDOR test 1234 format=1,1",
"VENDOR test 1234 format=2,2",
"VENDOR test 1234 format=1,2",
"VENDOR test 1234 format=4,2",
"VENDOR test 1234 format=4,0",
"VENDOR WiMAX 1234 format=1,1,c",
],
)
def test_valid_vendor_definitions(vendor):
dictionary = StringIO(vendor)
Dictionary("", dictionary)
def test_closing_wrong_vendor():
dictionary = StringIO(
"VENDOR TEST-VENDOR 1234\n"
"BEGIN-VENDOR TEST-VENDOR\n"
"END-VENDOR WRONG-VENDOR"
)
with pytest.raises(ParseError):
Dictionary("", dictionary)
def test_nested_vendor():
dictionary = StringIO(
"VENDOR TEST-VENDOR1 1234\n"
"VENDOR TEST-VENDOR2 1235\n"
"BEGIN-VENDOR TEST-VENDOR1\n"
"BEGIN-VENDOR TEST-VENDOR2"
)
with pytest.raises(ParseError):
Dictionary("", dictionary)
def test_begin_vendor_without_definition():
dictionary = StringIO("BEGIN-VENDOR TEST-VENDOR")
with pytest.raises(ParseError):
Dictionary("", dictionary)
@pytest.mark.parametrize(
"vendor",
[
"VENDOR test 1234 1,1",
"VENDOR test 1234 format=3,1",
"VENDOR test 1234 format=2",
"VENDOR test 1234 format=1,2,c",
"VENDOR test 1234 format=1,9",
"VENDOR test 1234 format=4,4 suffix",
"VENDOR test 1234 format=a,b suffix",
],
)
def test_invalid_vendor_definitions(vendor):
dictionary = StringIO(vendor)
with pytest.raises(ParseError):
Dictionary("", dictionary)
@pytest.mark.parametrize(
"number",
[
"ATTRIBUTE NAME 0x01 byte",
"ATTRIBUTE NAME 0x0001 byte",
"ATTRIBUTE NAME 0o123 byte",
"ATTRIBUTE NAME 5 byte",
],
)
def test_valid_attribute_numbers(number):
dictionary = StringIO(number)
Dictionary("", dictionary)
@pytest.mark.parametrize(
"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")
with pytest.raises(ParseError):
Dictionary("", dictionary)
@pytest.mark.parametrize("type_length", [1, 2, 4])
def test_attribute_number_limits(type_length):
too_big = 2 ** (8 * type_length)
max_value = too_big - 1
dictionary = StringIO(
f"VENDOR TEST 1234 format={type_length},1\n"
"BEGIN-VENDOR TEST\n"
f"ATTRIBUTE TEST {max_value} byte\n"
"END-VENDOR TEST\n"
)
Dictionary("", dictionary)
dictionary = StringIO(
f"VENDOR TEST 1234 format={type_length},1\n"
"BEGIN-VENDOR TEST\n"
f"ATTRIBUTE TEST {too_big} byte\n"
"END-VENDOR TEST\n"
)
with pytest.raises(ParseError):
Dictionary("", dictionary)
def test_invalid_attr_type():
dictionary = StringIO("ATTRIBUTE NAME 2 invalid")
with pytest.raises(ParseError):
Dictionary("", dictionary)
@pytest.mark.parametrize("value", ["1", "0x1", "0o1"])
def test_value_definition(value):
dictionary = StringIO(
"ATTRIBUTE TEST-ATTRIBUTE 1 byte\n"
f"VALUE TEST-ATTRIBUTE TEST-VALUE {value}"
)
Dictionary("", dictionary)
@pytest.mark.parametrize(
"value_num, attr_type",
[
(0, "byte"),
(255, "byte"),
(0, "short"),
(2 ** 16 - 1, "short"),
(0, "integer"),
(2 ** 32 - 1, "integer"),
((-(2 ** 31)), "signed"),
(2 ** 31 - 1, "signed"),
(0, "integer64"),
(2 ** 64 - 1, "integer64"),
],
)
def test_value_number_within_limit(value_num, attr_type):
dictionary = StringIO(
f"ATTRIBUTE TEST-ATTRIBUTE 1 {attr_type}\n"
f"VALUE TEST-ATTRIBUTE TEST-VALUE {value_num}"
)
Dictionary("", dictionary)
dictionary = StringIO(
"VENDOR TEST-VENDOR 1234\n"
"BEGIN-VENDOR TEST-VENDOR\n"
f"ATTRIBUTE TEST-ATTRIBUTE 1 {attr_type}\n"
f"VALUE TEST-ATTRIBUTE TEST-VALUE {value_num}\n"
"END-VENDOR TEST-VEDNOR"
)
@pytest.mark.parametrize(
"value_num, attr_type",
[
(-1, "byte"),
(256, "byte"),
(-1, "short"),
(2 ** 16, "short"),
(-1, "integer"),
(2 ** 32, "integer"),
(2 ** 31, "signed"),
((-(2 ** 31)) - 1, "signed"),
(-1, "integer64"),
(2 ** 64, "integer64"),
],
)
def test_value_number_out_of_limit(value_num, attr_type):
dictionary = StringIO(
f"ATTRIBUTE TEST-ATTRIBUTE 1 {attr_type}\n"
f"VALUE TEST-ATTRIBUTE TEST-VALUE {value_num}"
)
with pytest.raises(ParseError):
Dictionary("", dictionary)
dictionary = StringIO(
"VENDOR TEST-VENDOR 1234\n"
"BEGIN-VENDOR TEST-VENDOR\n"
f"ATTRIBUTE TEST-ATTRIBUTE 1 {attr_type}\n"
f"VALUE TEST-ATTRIBUTE TEST-VALUE {value_num}\n"
"END-VENDOR TEST-VEDNOR"
)
with pytest.raises(ParseError):
Dictionary("", dictionary)
@pytest.mark.parametrize(
"datatype",
[
"string",
"octets",
"abinary",
"byte",
"short",
"integer",
"signed",
"integer64",
"ipaddr",
"ipv4prefix",
"ipv6addr",
"ipv6prefix",
"combo-ip",
"ifid",
"ether",
"concat",
"tlv",
"extended",
"long-extended",
"evs",
],
)
def test_all_datatypes_rfc_space(datatype):
dictionary = StringIO(f"ATTRIBUTE TEST-ATTRIBUTE 1 {datatype}\n")
Dictionary("", dictionary)
@pytest.mark.parametrize(
"datatype",
[
"string",
"octets",
"abinary",
"byte",
"short",
"integer",
"signed",
"integer64",
"ipaddr",
"ipv4prefix",
"ipv6addr",
"ipv6prefix",
"combo-ip",
"ifid",
"ether",
"tlv",
],
)
def test_valid_datatypes_in_vendor_space(datatype):
dictionary = StringIO(
"VENDOR TEST 1234\n"
"BEGIN-VENDOR TEST\n"
f"ATTRIBUTE TEST-ATTRIBUTE 1 {datatype}\n"
"END-VENDOR TEST\n"
)
Dictionary("", dictionary)
@pytest.mark.parametrize(
"datatype", ["concat", "extended", "long-extended", "evs"]
)
def test_invalid_datatypes_in_vendor_space(datatype):
dictionary = StringIO(
"VENDOR TEST 1234\n"
"BEGIN-VENDOR TEST\n"
f"ATTRIBUTE TEST-ATTRIBUTE 1 {datatype}\n"
"END-VENDOR TEST\n"
)
with pytest.raises(ParseError):
Dictionary("", dictionary)
@pytest.mark.parametrize(
"invalid_number",
["ABCD", "-1", "inf", "INF", "-INF", "0.1", "2e4", "2.5e3"],
)
def test_invalid_value_numbers(invalid_number):
dictionary = StringIO(
f"ATTRIBUTE TEST-ATTRIBUTE 1 integer\n"
f"VALUE TEST-ATTRIBUTE TEST-VALUE {invalid_number}"
)
with pytest.raises(ParseError):
Dictionary("", dictionary)
def test_value_for_non_existing_attribute():
dictionary = StringIO("VALUE ATTRNAME VALUENAME 1234")
with pytest.raises(ParseError):
Dictionary("", dictionary)
@pytest.mark.parametrize(
"datatype",
[
"string",
"octets",
"abinary",
"ipaddr",
"ipv4prefix",
"ipv6addr",
"ipv6prefix",
"combo-ip",
"ifid",
"ether",
"tlv",
],
)
def test_value_for_wrong_datatype(datatype):
dictionary = StringIO(
f"ATTRIBUTE NAME 123 {datatype}\n" "VALUE NAME VNAME 256"
)
with pytest.raises(ParseError):
Dictionary("", dictionary)
def test_unimplemented_tlvs():
dictionary = StringIO("BEGIN-TLV")
with pytest.raises(NotImplementedError):
Dictionary("", dictionary)
dictionary = StringIO("END-TLV")
with pytest.raises(NotImplementedError):
Dictionary("", dictionary)
@pytest.mark.parametrize("flag", [1, 2, 3])
def test_valid_attribute_encrpytion_flags(flag):
dictionary = StringIO(f"ATTRIBUTE NAME 123 octets encrypt={flag}")
Dictionary("", dictionary)
@pytest.mark.parametrize("flag", ["0.1", "0", "4", "0x1", "0o2", "user", ""])
def test_invalid_attribute_encrpytion_flags(flag):
dictionary = StringIO(f"ATTRIBUTE NAME 123 octets encrypt={flag}")
with pytest.raises(ParseError):
Dictionary("", dictionary)
def test_has_tag_flag():
dictionary = StringIO("ATTRIBUTE NAME 123 octets has_tag")
Dictionary("", dictionary)
@pytest.mark.parametrize("invalid_flag", ["blablub", "encrypt=2=2", "concat"])
def test_invalid_attribute_flags(invalid_flag):
dictionary = StringIO(f"ATTRIBUTE NAME 123 octets {invalid_flag}")
with pytest.raises(ParseError):
Dictionary("", dictionary)
@pytest.mark.parametrize(
"attribute", ["RFC-ATTRIBUTE", "VENDOR-ATTRIBUTE", 7, (26, 5555, 7)]
)
def test_get_attributes_from_dictionaries(attribute):
dictionary = StringIO(
"ATTRIBUTE RFC-ATTRIBUTE 7 integer\n"
"VENDOR TEST-VENDOR 5555\n"
"BEGIN-VENDOR TEST-VENDOR\n"
"ATTRIBUTE VENDOR-ATTRIBUTE 7 integer\n"
"END-VENDOR TEST-VENDOR"
)
dd = Dictionary("", dictionary)
_ = dd[attribute]
@pytest.mark.parametrize(
"attribute", ["RFC-ATTRIBUTE1", 8, (26, 5556, 7), (26, 5555, 8)]
)
def test_get_nonexisting_attributes_from_dictionaries(attribute):
dictionary = StringIO(
"ATTRIBUTE RFC-ATTRIBUTE 7 integer\n"
"VENDOR TEST-VENDOR 5555\n"
"BEGIN-VENDOR TEST-VENDOR\n"
"ATTRIBUTE VENDOR-ATTRIBUTE 7 integer\n"
"END-VENDOR TEST-VENDOR"
)
dd = Dictionary("", dictionary)
with pytest.raises(KeyError):
_ = dd[attribute]