EVS decoding should be mostly working now. We do not have any tests yet, because it is unclear to me how EVS is defined in dictionaries.
404 lines
11 KiB
Python
404 lines
11 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
|
|
from pyrad3.types import Encrypt
|
|
|
|
|
|
@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}")
|
|
rad_dict = Dictionary("", dictionary)
|
|
assert rad_dict.attrindex[123].encrypt == Encrypt(flag)
|
|
|
|
|
|
@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")
|
|
rad_dict = Dictionary("", dictionary)
|
|
assert rad_dict.attrindex[123].has_tag
|
|
|
|
|
|
@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]
|