% Regression tests for Scapy regarding fields

############
############
+ Tests on basic fields

#= Field class
#~ core field
#Field("foo", None, fmt="H").i2m(None,0xabcdef)
#assert( _ == b"\xcd\xef" )
#Field("foo", None, fmt="<I").i2m(None,0x12cdef)
#assert( _ == b"\xef\xcd\x12\x00" )
#Field("foo", None, fmt="B").addfield(None, "FOO", 0x12)
#assert( _ == b"FOO\x12" )
#Field("foo", None, fmt="I").getfield(None, b"\x12\x34\x56\x78ABCD")
#assert( _ == ("ABCD",0x12345678) )
#
#= ConditionnalField class
#~ core field
#False


= Simple tests

assert LELongField("test", None).addfield(None, b"", 0x44434241) == b'ABCD\x00\x00\x00\x00'

= MACField class
~ core field
m = MACField("foo", None)
r = m.i2m(None, None)
r
assert r == b"\x00\x00\x00\x00\x00\x00"
r = m.getfield(None, b"\xc0\x01\xbe\xef\xba\xbeABCD")
r
assert r == (b"ABCD","c0:01:be:ef:ba:be") 
r = m.addfield(None, b"FOO", "c0:01:be:ef:ba:be")
r
assert(r == b"FOO\xc0\x01\xbe\xef\xba\xbe" )

= SourceMACField, ARPSourceMACField
conf.route.add(net="1.2.3.4/32", dev=conf.iface)
p = Ether() / ARP(pdst="1.2.3.4")
assert p.src == p.hwsrc == p[ARP].hwsrc == get_if_hwaddr(conf.iface)
conf.route.delt(net="1.2.3.4/32")

= IPField class
~ core field

i = IPField("foo", None)
r = i.i2m(None, "1.2.3.4")
r
assert r == b"\x01\x02\x03\x04"
r = i.i2m(None, "255.255.255.255")
r
assert r == b"\xff\xff\xff\xff"
r = i.m2i(None, b"\x01\x02\x03\x04")
r
assert r == "1.2.3.4"
r = i.getfield(None, b"\x01\x02\x03\x04ABCD")
r
assert r == (b"ABCD","1.2.3.4")
r = i.addfield(None, b"FOO", "1.2.3.4")
r
assert r == b"FOO\x01\x02\x03\x04"

= SourceIPField
~ core field
defaddr = conf.route.route('0.0.0.0')[1]
class Test(Packet): fields_desc = [SourceIPField("sourceip", None)]

assert Test().sourceip == defaddr
assert Test(raw(Test())).sourceip == defaddr

assert IP(dst="0.0.0.0").src == defaddr
assert IP(raw(IP(dst="0.0.0.0"))).src == defaddr
assert IP(dst="0.0.0.0/31").src == defaddr
assert IP(raw(IP(dst="0.0.0.0/31"))).src == defaddr


#= ByteField
#~ core field
#b = ByteField("foo", None)
#b.i2m("
#b.getfield

= ThreeBytesField
~ field threebytesfield

class TestThreeBytesField(Packet):
    fields_desc = [ 
        X3BytesField('test1', None),
        ThreeBytesField('test2', None),
        LEX3BytesField('test3', None),
        LEThreeBytesField('test4', None),
    ]

p = TestThreeBytesField(test1=0x123456, test2=123456, test3=0xfedbca, test4=567890)
assert(raw(p) == b'\x12\x34\x56\x01\xe2\x40\xca\xdb\xfe\x52\xaa\x08')
print(p.sprintf('%test1% %test2% %test3% %test4%'))
assert(p.sprintf('%test1% %test2% %test3% %test4%') == '0x123456 123456 0xfedbca 567890')

############
############
+ Tests on ActionField

= Creation of a layer with ActionField
~ field actionfield

from __future__ import print_function

class TestAction(Packet):
    __slots__ = ["_val", "_fld", "_priv1", "_priv2"]
    name = "TestAction"
    fields_desc = [ ActionField(ByteField("tst", 3), "my_action", priv1=1, priv2=2) ]
    def __init__(self, *args, **kargs):
        self._val, self._fld, self._priv1, self._priv2 = None, None, None, None
        super(TestAction, self).__init__(*args, **kargs)
    def my_action(self, val, fld, priv1, priv2):
        print("Action (%i)!" % val)
        self._val, self._fld, self._priv1, self._priv2 = val, fld, priv1, priv2

= Triggering action
~ field actionfield

t = TestAction()
assert(t._val == t._fld == t._priv1 == t._priv2 == None)
t.tst=42
assert(t._priv1 == 1)
assert(t._priv2 == 2)
assert(t._val == 42)


############
############
+ Tests on FieldLenField

= Creation of a layer with FieldLenField
~ field 
class TestFLenF(Packet):
    fields_desc = [ FieldLenField("len", None, length_of="str", fmt="B", adjust=lambda pkt,x:x+1),
                    StrLenField("str", "default", length_from=lambda pkt:pkt.len-1,) ]

= Assembly of an empty packet
~ field
p = TestFLenF()
p
r = raw(p)
r
r == b"\x08default"

= Assembly of non empty packet
~ field
p = TestFLenF(str="123")
p
r = raw(p)
r
r == b"\x04123"

= Disassembly
~ field
p = TestFLenF(b"\x04ABCDEFGHIJKL")
p
p.len == 4 and p.str == b"ABC" and Raw in p


= BitFieldLenField test
~ field
class TestBFLenF(Packet):
    fields_desc = [ BitFieldLenField("len", None, 4, length_of="str" , adjust=lambda pkt,x:x+1),
                    BitField("nothing",0xfff, 12),
                    StrLenField("str", "default", length_from=lambda pkt:pkt.len-1, ) ]

a=TestBFLenF()
r = raw(a)
r
assert r == b"\x8f\xffdefault"

a.str=""
r = raw(a)
r
assert r == b"\x1f\xff"

p = TestBFLenF(b"\x1f\xff@@")
p
assert p.len == 1 and p.str == b"" and Raw in p and p[Raw].load == b"@@"

p = TestBFLenF(b"\x6f\xffabcdeFGH")
p
assert p.len == 6 and p.str == b"abcde" and Raw in p and p[Raw].load == b"FGH"



############
############
+ Tests on FieldListField

= Creation of a layer
~ field
class TestFLF(Packet):
    name="test"
    fields_desc = [ FieldLenField("len", None, count_of="lst", fmt="B"),
                    FieldListField("lst", None, IntField("elt",0), count_from=lambda pkt:pkt.len)
                   ]

= Assembly of an empty packet
~ field
a = TestFLF()
raw(a)

= Assembly of a non-empty packet
~ field
a = TestFLF()
a.lst = [7,65539]
ls(a)
r = raw(a)
r
import struct
r == struct.pack("!BII", 2,7,65539)

= Disassemble
~ field
import struct
p = TestFLF(b"\x00\x11\x12")
p
assert p.len == 0 and Raw in p and p[Raw].load == b"\x11\x12"
p = TestFLF(struct.pack("!BIII",3,1234,2345,12345678))
p
assert p.len == 3 and p.lst == [1234,2345,12345678]

= Manipulate
~ field
a = TestFLF(lst=[4])
r = raw(a)
r
assert r == b"\x01\x00\x00\x00\x04"
a.lst.append(1234)
TestFLF(raw(a))
a.show2()
a.len=7
r = raw(a)
assert r == b"\x07\x00\x00\x00\x04\x00\x00\x04\xd2"
a.len=2
a.lst=[1,2,3,4,5]
p = TestFLF(raw(a))
p
assert Raw in p and p[Raw].load == b'\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x05'


############
############
+ PacketListField 

= Create a layer
~ field lengthfield
class TestPLF(Packet):
    name="test"
    fields_desc=[ FieldLenField("len", None, count_of="plist"),
                  PacketListField("plist", None, IP, count_from=lambda pkt:pkt.len,) ]

= Test the PacketListField assembly
~ field lengthfield
x=TestPLF()
r = raw(x)
r
r == b"\x00\x00"

= Test the PacketListField assembly 2
~ field lengthfield
x=TestPLF()
x.plist=[IP()/TCP(), IP()/UDP()]
r = raw(x)
r
r.startswith(b'\x00\x02E')

= Test disassembly
~ field lengthfield
x=TestPLF(plist=[IP()/TCP(seq=1234567), IP()/UDP()])
p = TestPLF(raw(x))
p
p.show()
IP in p and TCP in p and UDP in p and p[TCP].seq == 1234567

= Nested PacketListField
~ field lengthfield
y=IP()/TCP(seq=111111)/TestPLF(plist=[IP()/TCP(seq=222222),IP()/UDP()])
p = TestPLF(plist=[y,IP()/TCP(seq=333333)])
p
p.show()
IP in p and TCP in p and UDP in p and p[TCP].seq == 111111 and p[TCP:2].seq==222222 and p[TCP:3].seq == 333333

############
############
+ PacketListField tests

= Create a layer
~ field lengthfield
class TestPLF(Packet):
    name="test"
    fields_desc=[ FieldLenField("len", None, count_of="plist"),
                  PacketListField("plist", None, IP, count_from=lambda pkt:pkt.len) ]

= Test the PacketListField assembly
~ field lengthfield
x=TestPLF()
r = raw(x)
r
r == b"\x00\x00"

= Test the PacketListField assembly 2
~ field lengthfield
x=TestPLF()
x.plist=[IP()/TCP(), IP()/UDP()]
r = raw(x)
r
r.startswith(b'\x00\x02E')

= Test disassembly
~ field lengthfield
x=TestPLF(plist=[IP()/TCP(seq=1234567), IP()/UDP()])
p = TestPLF(raw(x))
p
p.show()
IP in p and TCP in p and UDP in p and p[TCP].seq == 1234567

= Nested PacketListField
~ field lengthfield
y=IP()/TCP(seq=111111)/TestPLF(plist=[IP()/TCP(seq=222222),IP()/UDP()])
p = TestPLF(plist=[y,IP()/TCP(seq=333333)])
p
p.show()
IP in p and TCP in p and UDP in p and p[TCP].seq == 111111 and p[TCP:2].seq==222222 and p[TCP:3].seq == 333333

= Complex packet
~ field lengthfield ccc
class TestPkt(Packet):
    fields_desc = [ ByteField("f1",65),
                    ShortField("f2",0x4244) ]
    def extract_padding(self, p):
        return "", p

class TestPLF2(Packet):
    fields_desc = [ FieldLenField("len1", None, count_of="plist", fmt="H",
                                  adjust=lambda pkt, x: x + 2),
                    FieldLenField("len2", None, length_of="plist", fmt="I",
                                  adjust=lambda pkt, x: (x + 1) // 2),
                    PacketListField("plist", None, TestPkt,
                                    length_from=lambda x: (x.len2 * 2) // 3 * 3) ]

a=TestPLF2()
r = raw(a)
r
assert r == b"\x00\x02\x00\x00\x00\x00"

a.plist=[TestPkt(),TestPkt(f1=100)] 
r = raw(a)
r
assert r == b'\x00\x04\x00\x00\x00\x03ABDdBD'

a /= "123456"
b = TestPLF2(raw(a))
b.show()
assert(b.len1 == 4 and b.len2 == 3)
assert(b[TestPkt].f1 == 65 and b[TestPkt].f2 == 0x4244)
assert(b[TestPkt:2].f1 == 100)
assert(Raw in b and b[Raw].load == b"123456")

a.plist.append(TestPkt(f1=200))
b = TestPLF2(raw(a))
b.show()
assert(b.len1 == 5 and b.len2 == 5)
assert(b[TestPkt].f1 == 65 and b[TestPkt].f2 == 0x4244)
assert(b[TestPkt:2].f1 == 100)
assert(b[TestPkt:3].f1 == 200)
assert(b.getlayer(TestPkt,4) is None)
assert(Raw in b and b[Raw].load == b"123456")
hexdiff(a,b)
assert( raw(a) == raw(b) )

############
############
+ Tests on TCPOptionsField

= Test calls on TCPOptionsField.getfield

assert TCPOptionsField("test", "").getfield(TCP(dataofs=0), "") == ('', [])


############
############
+ PacketListField tests

= Create a layer
~ field lengthfield
class TestPLF(Packet):
    name="test"
    fields_desc=[ FieldLenField("len", None, count_of="plist"),
                  PacketListField("plist", None, IP, count_from=lambda pkt:pkt.len) ]

= Test the PacketListField assembly
~ field lengthfield
x=TestPLF()
r = raw(x)
r
r == b"\x00\x00"

= Test the PacketListField assembly 2
~ field lengthfield
x=TestPLF()
x.plist=[IP()/TCP(), IP()/UDP()]
r = raw(x)
r
r.startswith(b'\x00\x02E')

= Test disassembly
~ field lengthfield
x=TestPLF(plist=[IP()/TCP(seq=1234567), IP()/UDP()])
p = TestPLF(raw(x))
p
p.show()
IP in p and TCP in p and UDP in p and p[TCP].seq == 1234567

= Nested PacketListField
~ field lengthfield
y=IP()/TCP(seq=111111)/TestPLF(plist=[IP()/TCP(seq=222222),IP()/UDP()])
p = TestPLF(plist=[y,IP()/TCP(seq=333333)])
p
p.show()
IP in p and TCP in p and UDP in p and p[TCP].seq == 111111 and p[TCP:2].seq==222222 and p[TCP:3].seq == 333333

= Complex packet
~ field lengthfield ccc
class TestPkt(Packet):
    fields_desc = [ ByteField("f1",65),
                    ShortField("f2",0x4244) ]
    def extract_padding(self, p):
        return "", p

class TestPLF2(Packet):
    fields_desc = [ FieldLenField("len1", None, count_of="plist",fmt="H",
                                  adjust=lambda pkt,x: x + 2),
                    FieldLenField("len2", None, length_of="plist", fmt="I",
                                  adjust=lambda pkt, x: (x + 1) // 2),
                    PacketListField("plist", None, TestPkt,
                                    length_from=lambda x: (x.len2 * 2) // 3 *3) ]

a=TestPLF2()
r = raw(a)
r
assert r == b"\x00\x02\x00\x00\x00\x00"

a.plist=[TestPkt(),TestPkt(f1=100)] 
r = raw(a)
r
assert r == b'\x00\x04\x00\x00\x00\x03ABDdBD'

a /= "123456"
b = TestPLF2(raw(a))
b.show()
assert(b.len1 == 4 and b.len2 == 3)
assert(b[TestPkt].f1 == 65 and b[TestPkt].f2 == 0x4244)
assert(b[TestPkt:2].f1 == 100)
assert(Raw in b and b[Raw].load == b"123456")

a.plist.append(TestPkt(f1=200))
b = TestPLF2(raw(a))
b.show()
assert(b.len1 == 5 and b.len2 == 5)
assert(b[TestPkt].f1 == 65 and b[TestPkt].f2 == 0x4244)
assert(b[TestPkt:2].f1 == 100)
assert(b[TestPkt:3].f1 == 200)
assert(b.getlayer(TestPkt,4) is None)
assert(Raw in b and b[Raw].load == b"123456")
hexdiff(a,b)
assert( raw(a) == raw(b) )

= Create layers for heterogeneous PacketListField
~ field lengthfield
TestPLFH1 = type('TestPLFH1', (Packet,), {
    'name': 'test1',
    'fields_desc': [ByteField('data', 0)],
    'guess_payload_class': lambda self, p: conf.padding_layer,
    }
)
TestPLFH2 = type('TestPLFH2', (Packet,), {
    'name': 'test2',
    'fields_desc': [ShortField('data', 0)],
    'guess_payload_class': lambda self, p: conf.padding_layer,
    }
)
class TestPLFH3(Packet):
    name = 'test3'
    fields_desc = [
        PacketListField(
            'data', [],
            next_cls_cb=lambda pkt, lst, p, remain: pkt.detect_next_packet(lst, p, remain)
        )
    ]
    def detect_next_packet(self, lst, p, remain):
        if len(remain) < 3:
            return None
        if isinstance(p, type(None)):
            return TestPLFH1
        if p.data & 3 == 1:
            return TestPLFH1
        if p.data & 3 == 2:
            return TestPLFH2
        return None

= Test heterogeneous PacketListField
~ field lengthfield

p = TestPLFH3(b'\x02\x01\x01\xc1\x02\x80\x04toto')
assert(isinstance(p.data[0], TestPLFH1))
assert(p.data[0].data == 0x2)
assert(isinstance(p.data[1], TestPLFH2))
assert(p.data[1].data == 0x101)
assert(isinstance(p.data[2], TestPLFH1))
assert(p.data[2].data == 0xc1)
assert(isinstance(p.data[3], TestPLFH1))
assert(p.data[3].data == 0x2)
assert(isinstance(p.data[4], TestPLFH2))
assert(p.data[4].data == 0x8004)
assert(isinstance(p.payload, conf.raw_layer))
assert(p.payload.load == b'toto')

p = TestPLFH3(b'\x02\x01\x01\xc1\x02\x80\x02to')
assert(isinstance(p.data[0], TestPLFH1))
assert(p.data[0].data == 0x2)
assert(isinstance(p.data[1], TestPLFH2))
assert(p.data[1].data == 0x101)
assert(isinstance(p.data[2], TestPLFH1))
assert(p.data[2].data == 0xc1)
assert(isinstance(p.data[3], TestPLFH1))
assert(p.data[3].data == 0x2)
assert(isinstance(p.data[4], TestPLFH2))
assert(p.data[4].data == 0x8002)
assert(isinstance(p.payload, conf.raw_layer))
assert(p.payload.load == b'to')

= Create layers for heterogeneous PacketListField with memory
~ field lengthfield
TestPLFH4 = type('TestPLFH4', (Packet,), {
    'name': 'test4',
    'fields_desc': [ByteField('data', 0)],
    'guess_payload_class': lambda self, p: conf.padding_layer,
    }
)
TestPLFH5 = type('TestPLFH5', (Packet,), {
    'name': 'test5',
    'fields_desc': [ShortField('data', 0)],
    'guess_payload_class': lambda self, p: conf.padding_layer,
    }
)
class TestPLFH6(Packet):
    __slots__ = ['_memory']
    name = 'test6'
    fields_desc = [
        PacketListField(
            'data', [],
            next_cls_cb=lambda pkt, lst, p, remain: pkt.detect_next_packet(lst, p, remain)
        )
    ]
    def detect_next_packet(self, lst, p, remain):
        if isinstance(p, type(None)):
            self._memory = [TestPLFH4] * 3 + [TestPLFH5]
        try:
            return self._memory.pop(0)
        except IndexError:
            return None

= Test heterogeneous PacketListField with memory
~ field lengthfield

p = TestPLFH6(b'\x01\x02\x03\xc1\x02toto')
assert(isinstance(p.data[0], TestPLFH4))
assert(p.data[0].data == 0x1)
assert(isinstance(p.data[1], TestPLFH4))
assert(p.data[1].data == 0x2)
assert(isinstance(p.data[2], TestPLFH4))
assert(p.data[2].data == 0x3)
assert(isinstance(p.data[3], TestPLFH5))
assert(p.data[3].data == 0xc102)
assert(isinstance(p.payload, conf.raw_layer))
assert(p.payload.load == b'toto')


############
############
+ Tests on MultiFlagsField

= Test calls on MultiFlagsField.any2i
~ multiflagsfield

import collections
MockPacket = collections.namedtuple('MockPacket', ['type'])

f = MultiFlagsField('flags', set(), 3, {
        0: {
            0: MultiFlagsEntry('A', 'OptionA'),
            1: MultiFlagsEntry('B', 'OptionB'),
        },
        1: {
            0: MultiFlagsEntry('+', 'Plus'),
            1: MultiFlagsEntry('*', 'Star'),
        },
    },
    depends_on=lambda x: x.type
)

mp = MockPacket(0)
x = f.any2i(mp, set())
assert(isinstance(x, set))
assert(len(x) == 0)
x = f.any2i(mp, {'A'})
assert(isinstance(x, set))
assert(len(x) == 1)
assert('A' in x)
assert('B' not in x)
assert('+' not in x)
x = f.any2i(mp, {'A', 'B'})
assert(isinstance(x, set))
assert(len(x) == 2)
assert('A' in x)
assert('B' in x)
assert('+' not in x)
assert('*' not in x)
x = f.any2i(mp, 3)
assert(isinstance(x, set))
assert(len(x) == 2)
assert('A' in x)
assert('B' in x)
assert('+' not in x)
assert('*' not in x)
x = f.any2i(mp, 7)
assert(isinstance(x, set))
assert(len(x) == 3)
assert('A' in x)
assert('B' in x)
assert('bit 2' in x)
assert('+' not in x)
assert('*' not in x)
mp = MockPacket(1)
x = f.any2i(mp, {'+', '*'})
assert(isinstance(x, set))
assert(len(x) == 2)
assert('+' in x)
assert('*' in x)
assert('A' not in x)
assert('B' not in x)
try:
    x = f.any2i(mp, {'A'})
    ret = False
except AssertionError:
    ret = True

assert(ret)
#Following test demonstrate a non-sensical yet acceptable usage :(
x = f.any2i(None, {'Toto'})
assert('Toto' in x)

= Test calls on MultiFlagsField.i2m
~ multiflagsfield

import collections
MockPacket = collections.namedtuple('MockPacket', ['type'])

f = MultiFlagsField('flags', set(), 3, {
        0: {
            0: MultiFlagsEntry('A', 'OptionA'),
            1: MultiFlagsEntry('B', 'OptionB'),
        },
        1: {
            0: MultiFlagsEntry('+', 'Plus'),
            1: MultiFlagsEntry('*', 'Star'),
        },
    },
    depends_on=lambda x: x.type
)

mp = MockPacket(0)
x = f.i2m(mp, set())
assert(isinstance(x, six.integer_types))
assert(x == 0)
x = f.i2m(mp, {'A'})
assert(isinstance(x, six.integer_types))
assert(x == 1)
x = f.i2m(mp, {'A', 'B'})
assert(isinstance(x, six.integer_types))
assert(x == 3)
x = f.i2m(mp, {'A', 'B', 'bit 2'})
assert(isinstance(x, six.integer_types))
assert(x == 7)
try:
    x = f.i2m(mp, {'+'})
    ret = False
except:
    ret = True

assert(ret)

= Test calls on MultiFlagsField.m2i
~ multiflagsfield

import collections
MockPacket = collections.namedtuple('MockPacket', ['type'])

f = MultiFlagsField('flags', set(), 3, {
        0: {
            0: MultiFlagsEntry('A', 'OptionA'),
            1: MultiFlagsEntry('B', 'OptionB'),
        },
        1: {
            0: MultiFlagsEntry('+', 'Plus'),
            1: MultiFlagsEntry('*', 'Star'),
        },
    },
    depends_on=lambda x: x.type
)

mp = MockPacket(0)
x = f.m2i(mp, 2)
assert(isinstance(x, set))
assert(len(x) == 1)
assert('B' in x)
assert('A' not in x)
assert('*' not in x)

x = f.m2i(mp, 7)
assert(isinstance(x, set))
assert('B' in x)
assert('A' in x)
assert('bit 2' in x)
assert('*' not in x)
assert('+' not in x)
x = f.m2i(mp, 0)
assert(len(x) == 0)
mp = MockPacket(1)
x = f.m2i(mp, 2)
assert(isinstance(x, set))
assert(len(x) == 1)
assert('*' in x)
assert('+' not in x)
assert('B' not in x)

= Test calls on MultiFlagsField.i2repr
~ multiflagsfield

import collections, re
MockPacket = collections.namedtuple('MockPacket', ['type'])

f = MultiFlagsField('flags', set(), 3, {
        0: {
            0: MultiFlagsEntry('A', 'OptionA'),
            1: MultiFlagsEntry('B', 'OptionB'),
        },
        1: {
            0: MultiFlagsEntry('+', 'Plus'),
            1: MultiFlagsEntry('*', 'Star'),
        },
    },
    depends_on=lambda x: x.type
)

mp = MockPacket(0)
x = f.i2repr(mp, {'A', 'B'})
assert(re.match(r'^.*OptionA \(A\).*$', x) is not None)
assert(re.match(r'^.*OptionB \(B\).*$', x) is not None)
mp = MockPacket(1)
x = f.i2repr(mp, {'*', '+', 'bit 2'})
assert(re.match(r'^.*Star \(\*\).*$', x) is not None)
assert(re.match(r'^.*Plus \(\+\).*$', x) is not None)
assert(re.match(r'^.*bit 2.*$', x) is not None)

############
############
+ EnumField tests

= EnumField tests initialization

# Basic EnumField
f = EnumField('test', 0, {0: 'Foo', 1: 'Bar'})
# Reverse i2s/s2i
rf = EnumField('test', 0, {'Foo': 0, 'Bar': 1})
# EnumField initialized with a list
lf = EnumField('test', 0, ['Foo', 'Bar'])
# EnumField with i2s_cb/s2i_cb
fcb = EnumField('test', 0, (
        lambda x: 'Foo' if x == 0 else 'Bar' if 1 <= x <= 10 else repr(x),
        lambda x: 0 if x == 'Foo' else 1 if x == 'Bar' else int(x),
    )
)

def expect_exception(e, c):
    try:
        eval(c)
        return False
    except e:
        return True


= EnumField.any2i_one
~ field enumfield

assert(f.any2i_one(None, 'Foo') == 0)
assert(f.any2i_one(None, 'Bar') == 1)
assert(f.any2i_one(None, 2) == 2)
expect_exception(KeyError, 'f.any2i_one(None, "Baz")')

assert(rf.any2i_one(None, 'Foo') == 0)
assert(rf.any2i_one(None, 'Bar') == 1)
assert(rf.any2i_one(None, 2) == 2)
expect_exception(KeyError, 'rf.any2i_one(None, "Baz")')

assert(lf.any2i_one(None, 'Foo') == 0)
assert(lf.any2i_one(None, 'Bar') == 1)
assert(lf.any2i_one(None, 2) == 2)
expect_exception(KeyError, 'lf.any2i_one(None, "Baz")')

assert(fcb.any2i_one(None, 'Foo') == 0)
assert(fcb.any2i_one(None, 'Bar') == 1)
assert(fcb.any2i_one(None, 5) == 5)
expect_exception(ValueError, 'fcb.any2i_one(None, "Baz")')

True

= EnumField.any2i
~ field enumfield

assert(f.any2i(None, 'Foo') == 0)
assert(f.any2i(None, 'Bar') == 1)
assert(f.any2i(None, 2) == 2)
expect_exception(KeyError, 'f.any2i(None, "Baz")')
assert(f.any2i(None, ['Foo', 'Bar', 2]) == [0, 1, 2])

assert(rf.any2i(None, 'Foo') == 0)
assert(rf.any2i(None, 'Bar') == 1)
assert(rf.any2i(None, 2) == 2)
expect_exception(KeyError, 'rf.any2i(None, "Baz")')
assert(rf.any2i(None, ['Foo', 'Bar', 2]) == [0, 1, 2])

assert(lf.any2i(None, 'Foo') == 0)
assert(lf.any2i(None, 'Bar') == 1)
assert(lf.any2i(None, 2) == 2)
expect_exception(KeyError, 'lf.any2i(None, "Baz")')
assert(lf.any2i(None, ['Foo', 'Bar', 2]) == [0, 1, 2])

assert(fcb.any2i(None, 'Foo') == 0)
assert(fcb.any2i(None, 'Bar') == 1)
assert(fcb.any2i(None, 5) == 5)
expect_exception(ValueError, 'fcb.any2i(None, "Baz")')
assert(f.any2i(None, ['Foo', 'Bar', 5]) == [0, 1, 5])

True

= EnumField.i2repr_one
~ field enumfield

assert(f.i2repr_one(None, 0) == 'Foo')
assert(f.i2repr_one(None, 1) == 'Bar')
expect_exception(KeyError, 'f.i2repr_one(None, 2)')

assert(rf.i2repr_one(None, 0) == 'Foo')
assert(rf.i2repr_one(None, 1) == 'Bar')
expect_exception(KeyError, 'rf.i2repr_one(None, 2)')

assert(lf.i2repr_one(None, 0) == 'Foo')
assert(lf.i2repr_one(None, 1) == 'Bar')
expect_exception(KeyError, 'lf.i2repr_one(None, 2)')

assert(fcb.i2repr_one(None, 0) == 'Foo')
assert(fcb.i2repr_one(None, 1) == 'Bar')
assert(fcb.i2repr_one(None, 5) == 'Bar')
assert(fcb.i2repr_one(None, 11) == repr(11))

conf.noenum.add(f, rf, lf, fcb)

assert(f.i2repr_one(None, 0) == repr(0))
assert(f.i2repr_one(None, 1) == repr(1))
assert(f.i2repr_one(None, 2) == repr(2))

assert(rf.i2repr_one(None, 0) == repr(0))
assert(rf.i2repr_one(None, 1) == repr(1))
assert(rf.i2repr_one(None, 2) == repr(2))

assert(lf.i2repr_one(None, 0) == repr(0))
assert(lf.i2repr_one(None, 1) == repr(1))
assert(lf.i2repr_one(None, 2) == repr(2))

assert(fcb.i2repr_one(None, 0) == repr(0))
assert(fcb.i2repr_one(None, 1) == repr(1))
assert(fcb.i2repr_one(None, 5) == repr(5))
assert(fcb.i2repr_one(None, 11) == repr(11))

conf.noenum.remove(f, rf, lf, fcb)

assert(f.i2repr_one(None, RandNum(0, 10)) == '<RandNum>')
assert(rf.i2repr_one(None, RandNum(0, 10)) == '<RandNum>')
assert(lf.i2repr_one(None, RandNum(0, 10)) == '<RandNum>')
assert(fcb.i2repr_one(None, RandNum(0, 10)) == '<RandNum>')

True

= EnumField.i2repr
~ field enumfield

assert(f.i2repr(None, 0) == 'Foo')
assert(f.i2repr(None, 1) == 'Bar')
expect_exception(KeyError, 'f.i2repr(None, 2)')
assert(f.i2repr(None, [0, 1]) == ['Foo', 'Bar'])

assert(rf.i2repr(None, 0) == 'Foo')
assert(rf.i2repr(None, 1) == 'Bar')
expect_exception(KeyError, 'rf.i2repr(None, 2)')
assert(rf.i2repr(None, [0, 1]) == ['Foo', 'Bar'])

assert(lf.i2repr(None, 0) == 'Foo')
assert(lf.i2repr(None, 1) == 'Bar')
expect_exception(KeyError, 'lf.i2repr(None, 2)')
assert(lf.i2repr(None, [0, 1]) == ['Foo', 'Bar'])

assert(fcb.i2repr(None, 0) == 'Foo')
assert(fcb.i2repr(None, 1) == 'Bar')
assert(fcb.i2repr(None, 5) == 'Bar')
assert(fcb.i2repr(None, 11) == repr(11))
assert(fcb.i2repr(None, [0, 1, 5, 11]) == ['Foo', 'Bar', 'Bar', repr(11)])

conf.noenum.add(f, rf, lf, fcb)

assert(f.i2repr(None, 0) == repr(0))
assert(f.i2repr(None, 1) == repr(1))
assert(f.i2repr(None, 2) == repr(2))
assert(f.i2repr(None, [0, 1, 2]) == [repr(0), repr(1), repr(2)])

assert(rf.i2repr(None, 0) == repr(0))
assert(rf.i2repr(None, 1) == repr(1))
assert(rf.i2repr(None, 2) == repr(2))
assert(rf.i2repr(None, [0, 1, 2]) == [repr(0), repr(1), repr(2)])

assert(lf.i2repr(None, 0) == repr(0))
assert(lf.i2repr(None, 1) == repr(1))
assert(lf.i2repr(None, 2) == repr(2))
assert(lf.i2repr(None, [0, 1, 2]) == [repr(0), repr(1), repr(2)])

assert(fcb.i2repr(None, 0) == repr(0))
assert(fcb.i2repr(None, 1) == repr(1))
assert(fcb.i2repr(None, 5) == repr(5))
assert(fcb.i2repr(None, 11) == repr(11))
assert(fcb.i2repr(None, [0, 1, 5, 11]) == [repr(0), repr(1), repr(5), repr(11)])

conf.noenum.remove(f, rf, lf, fcb)

assert(f.i2repr_one(None, RandNum(0, 10)) == '<RandNum>')
assert(rf.i2repr_one(None, RandNum(0, 10)) == '<RandNum>')
assert(lf.i2repr_one(None, RandNum(0, 10)) == '<RandNum>')
assert(fcb.i2repr_one(None, RandNum(0, 10)) == '<RandNum>')

True

############
############
+ CharEnumField tests

= Building expect_exception handler
~ field charenumfield

def expect_exception(e, c):
    try:
        eval(c)
        return False
    except e:
        return True


= CharEnumField tests initialization
~ field charenumfield

fc = CharEnumField('test', 'f', {'f': 'Foo', 'b': 'Bar'})
fcb = CharEnumField('test', 'a', (
    lambda x: 'Foo' if x == 'a' else 'Bar' if x == 'b' else 'Baz',
    lambda x: 'a' if x == 'Foo' else 'b' if x == 'Bar' else ''
))

True

= CharEnumField.any2i_one
~ field charenumfield

assert(fc.any2i_one(None, 'Foo') == 'f')
assert(fc.any2i_one(None, 'Bar') == 'b')
expect_exception(KeyError, 'fc.any2i_one(None, "Baz")')

assert(fcb.any2i_one(None, 'Foo') == 'a')
assert(fcb.any2i_one(None, 'Bar') == 'b')
assert(fcb.any2i_one(None, 'Baz') == '')

True

############
############
+ XByteEnumField tests

= Building expect_exception handler
~ field xbyteenumfield

def expect_exception(e, c):
    try:
        eval(c)
        return False
    except e:
        return True


= XByteEnumField tests initialization
~ field xbyteenumfield

f = XByteEnumField('test', 0, {0: 'Foo', 1: 'Bar'})
fcb = XByteEnumField('test', 0, (
    lambda x: 'Foo' if x == 0 else 'Bar' if x == 1 else lhex(x),
    lambda x: x
))

True

= XByteEnumField.i2repr_one
~ field xbyteenumfield

assert(f.i2repr_one(None, 0) == 'Foo')
assert(f.i2repr_one(None, 1) == 'Bar')
assert(f.i2repr_one(None, 0xff) == '0xff')

assert(f.i2repr_one(None, 0) == 'Foo')
assert(f.i2repr_one(None, 1) == 'Bar')
assert(f.i2repr_one(None, 0xff) == '0xff')

True

= XByteEnumField update tests initialization
~ field xbyteenumfield
enum = ObservableDict({0: 'Foo', 1: 'Bar'})
f = XByteEnumField('test', 0, enum)
fcb = XByteEnumField('test', 0, (
    lambda x: 'Foo' if x == 0 else 'Bar' if x == 1 else lhex(x),
    lambda x: x
))

True

= XByteEnumField.i2repr_one with update
~ field xbyteenumfield

assert(f.i2repr_one(None, 0) == 'Foo')
assert(f.i2repr_one(None, 1) == 'Bar')
assert(f.i2repr_one(None, 2) == '0x2')
assert(f.i2repr_one(None, 0xff) == '0xff')

assert(f.i2repr_one(None, 0) == 'Foo')
assert(f.i2repr_one(None, 1) == 'Bar')
assert(f.i2repr_one(None, 2) == '0x2')
assert(f.i2repr_one(None, 0xff) == '0xff')

del enum[1]
enum[2] = 'Baz'

assert(f.i2repr_one(None, 0) == 'Foo')
assert(f.i2repr_one(None, 1) == '0x1')
assert(f.i2repr_one(None, 2) == 'Baz')
assert(f.i2repr_one(None, 0xff) == '0xff')

assert(f.i2repr_one(None, 0) == 'Foo')
assert(f.i2repr_one(None, 1) == '0x1')
assert(f.i2repr_one(None, 2) == 'Baz')
assert(f.i2repr_one(None, 0xff) == '0xff')

True

############
############
+ XShortEnumField tests

= Building expect_exception handler
~ field xshortenumfield

def expect_exception(e, c):
    try:
        eval(c)
        return False
    except e:
        return True


= XShortEnumField tests initialization
~ field xshortenumfield

f = XShortEnumField('test', 0, {0: 'Foo', 1: 'Bar'})
fcb = XShortEnumField('test', 0, (
    lambda x: 'Foo' if x == 0 else 'Bar' if x == 1 else lhex(x),
    lambda x: x
))

True

= XShortEnumField.i2repr_one
~ field xshortenumfield

assert(f.i2repr_one(None, 0) == 'Foo')
assert(f.i2repr_one(None, 1) == 'Bar')
assert(f.i2repr_one(None, 0xff) == '0xff')

assert(f.i2repr_one(None, 0) == 'Foo')
assert(f.i2repr_one(None, 1) == 'Bar')
assert(f.i2repr_one(None, 0xff) == '0xff')

True

= XShortEnumField update tests initialization
~ field xshortenumfield
enum = ObservableDict({0: 'Foo', 1: 'Bar'})
f = XShortEnumField('test', 0, enum)
fcb = XShortEnumField('test', 0, (
    lambda x: 'Foo' if x == 0 else 'Bar' if x == 1 else lhex(x),
    lambda x: x
))

True

= XShortEnumField.i2repr_one with update
~ field xshortenumfield

assert(f.i2repr_one(None, 0) == 'Foo')
assert(f.i2repr_one(None, 1) == 'Bar')
assert(f.i2repr_one(None, 2) == '0x2')
assert(f.i2repr_one(None, 0xff) == '0xff')

assert(f.i2repr_one(None, 0) == 'Foo')
assert(f.i2repr_one(None, 1) == 'Bar')
assert(f.i2repr_one(None, 2) == '0x2')
assert(f.i2repr_one(None, 0xff) == '0xff')

del enum[1]
enum[2] = 'Baz'

assert(f.i2repr_one(None, 0) == 'Foo')
assert(f.i2repr_one(None, 1) == '0x1')
assert(f.i2repr_one(None, 2) == 'Baz')
assert(f.i2repr_one(None, 0xff) == '0xff')

assert(f.i2repr_one(None, 0) == 'Foo')
assert(f.i2repr_one(None, 1) == '0x1')
assert(f.i2repr_one(None, 2) == 'Baz')
assert(f.i2repr_one(None, 0xff) == '0xff')

True

############
############
+ DNSStrField tests

= Raise exception - test data

dnsf = DNSStrField("test", "")
assert(dnsf.getfield(None, b"\x01x\x00") == (b"", b"x."))

try:
    dnsf.getfield(None, b"\xc0\xff")
    assert(False)
except (Scapy_Exception, IndexError):
    pass

+ YesNoByteField

= default usage

yn_bf = YesNoByteField('test', 0x00)
assert(yn_bf.i2repr(None, 0x00) == 'no')
assert(yn_bf.i2repr(None, 0x01) == 'yes')
assert(yn_bf.i2repr(None, 0x02) == 'yes')
assert(yn_bf.i2repr(None, 0xff) == 'yes')

= inverted yes - no (scalar config)
yn_bf = YesNoByteField('test', 0x00, config={'yes': 0x00, 'no': 0x01})
assert(yn_bf.i2repr(None, 0x00) == 'yes')
assert(yn_bf.i2repr(None, 0x01) == 'no')
assert(yn_bf.i2repr(None, 0x02) == 2)
assert(yn_bf.i2repr(None, 0xff) == 255)

= inverted yes - no (range config)
yn_bf = YesNoByteField('test', 0x00, config={'yes': 0x00, 'no': (0x01, 0xff)})
assert(yn_bf.i2repr(None, 0x00) == 'yes')
assert(yn_bf.i2repr(None, 0x01) == 'no')
assert(yn_bf.i2repr(None, 0x02) == 'no')
assert(yn_bf.i2repr(None, 0xff) == 'no')

= yes - no (using sets)
yn_bf = YesNoByteField('test', 0x00, config={'yes': [0x00, 0x02], 'no': [0x01, 0x04, 0xff]})
assert(yn_bf.i2repr(None, 0x00) == 'yes')
assert(yn_bf.i2repr(None, 0x01) == 'no')
assert(yn_bf.i2repr(None, 0x02) == 'yes')
assert(yn_bf.i2repr(None, 0x03) == 3)
assert(yn_bf.i2repr(None, 0x04) == 'no')
assert(yn_bf.i2repr(None, 0x05) == 5)
assert(yn_bf.i2repr(None, 0xff) == 'no')

= yes, no and invalid
yn_bf = YesNoByteField('test', 0x00, config={'no': 0x00, 'yes': 0x01, 'invalid': (0x02, 0xff)})
assert(yn_bf.i2repr(None, 0x00) == 'no')
assert(yn_bf.i2repr(None, 0x01) == 'yes')
assert(yn_bf.i2repr(None, 0x02) == 'invalid')
assert(yn_bf.i2repr(None, 0xff) == 'invalid')

= invalid scalar spec

try:
    YesNoByteField('test', 0x00, config={'no': 0x00, 'yes': 256})
    assert(False)
except FieldValueRangeException:
    pass

= invalid range spec - invalid length

try:
    YesNoByteField('test', 0x00, config={'no': 0x00, 'yes': (0x00, 0x02, 0x02)})
    assert(False)
except FieldAttributeException:
    pass

= invalid range spec - invalid value

try:
    YesNoByteField('test', 0x00, config={'no': 0x00, 'yes': (0x100, 0x01)})
    assert(False)
except FieldValueRangeException:
    pass

try:
    YesNoByteField('test', 0x00, config={'no': 0x00, 'yes': (0x00, 0x100)})
    assert(False)
except FieldValueRangeException:
    pass

= invalid set spec - invalid value

try:
    YesNoByteField('test', 0x00, config={'no': 0x00, 'yes': [0x01, 0x101]})
    assert(False)
except FieldValueRangeException:
    pass

= FlasgField - Python incompatible name

assert Dot11().FCfield.to_DS is False

########
########
+ MultipleTypeField

= Test initialization order

class DebugPacket(Packet):
    fields_desc = [
        ByteEnumField("atyp", 0x1, {0x1: "IPv4", 0x3: "DNS", 0x4: "IPv6"}),
        MultipleTypeField(
            [
                # IPv4
                (IPField("addr", "0.0.0.0"), lambda pkt: pkt.atyp == 0x1),
                # DNS
                (DNSStrField("addr", ""), lambda pkt: pkt.atyp == 0x3),
                # IPv6
                (IP6Field("addr", "::"), lambda pkt: pkt.atyp == 0x4),
            ],
            StrField("addr", "")
        ),
    ]

= Default order

a = DebugPacket(atyp=0x3, addr="scapy.net")
a = DebugPacket(raw(a))
assert a.addr == b"scapy.net."

= Reversed order

a = DebugPacket(addr="scapy.net", atyp=0x3)
a = DebugPacket(raw(a))
assert a.addr == b"scapy.net."

