"""Tests for association.AcceptorRequestor."""

import logging
import time
import threading

import pytest

from pynetdicom import (
    AE, VerificationPresentationContexts, PYNETDICOM_IMPLEMENTATION_UID,
    PYNETDICOM_IMPLEMENTATION_VERSION, build_context
)
from pynetdicom.association import ServiceUser, Association
from pynetdicom.pdu_primitives import (
    A_ASSOCIATE, MaximumLengthNotification, ImplementationClassUIDNotification,
    ImplementationVersionNameNotification, SCP_SCU_RoleSelectionNegotiation,
    UserIdentityNegotiation, SOPClassExtendedNegotiation,
    SOPClassCommonExtendedNegotiation, AsynchronousOperationsWindowNegotiation
)
from pynetdicom.sop_class import VerificationSOPClass

from .dummy_c_scp import DummyVerificationSCP, DummyBaseSCP


LOGGER = logging.getLogger('pynetdicom')
LOGGER.setLevel(logging.CRITICAL)
#LOGGER.setLevel(logging.DEBUG)


class TestServiceUserAcceptor(object):
    """Tests for ServiceUser as acceptor."""
    def setup(self):
        self.assoc = Association(AE(), mode='requestor')

        primitive = A_ASSOCIATE()
        primitive.application_context_name = '1.2.840.10008.3.1.1.1'
        primitive.calling_ae_title = b'LOCAL_AE_TITLE  '
        primitive.called_ae_title = b'REMOTE_AE_TITLE '
        primitive.result = 0x00
        primitive.result_source = 0x01

        # Presentation Contexts
        cx = build_context('1.2.840.10008.1.1')
        cx.context_id = 1
        primitive.presentation_context_definition_results_list = [cx]

        # User Information items
        item = MaximumLengthNotification()
        item.maximum_length_received = 16383
        primitive.user_information = [item]

        item = ImplementationClassUIDNotification()
        item.implementation_class_uid = '1.2.3'
        primitive.user_information.append(item)

        self.primitive_ac = primitive

        primitive = A_ASSOCIATE()
        primitive.result = 0x01
        primitive.result_source = 0x01
        primitive.diagnostic = 0x01
        self.primitive_rj = primitive

    def test_init(self):
        """Test new ServiceUser as acceptor."""
        user = ServiceUser(self.assoc, mode='acceptor')

        assert user.primitive is None
        assert user.ae_title == b''
        assert user.port is None
        assert user.address == ''
        assert user._contexts == []
        assert user.mode == 'acceptor'
        assert user.maximum_length == 16382
        assert user.extended_negotiation == []
        assert user.implementation_class_uid == PYNETDICOM_IMPLEMENTATION_UID

        assert len(user.user_information) == 2

    def test_bad_mode(self):
        """Test bad mode raises exception."""
        with pytest.raises(ValueError, match=r"The 'mode' must be either"):
            ServiceUser(None, 'something')

    def test_no_implementation_class_uid(self):
        """Test correct return if no class UID."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user._user_info = []
        assert user.implementation_class_uid is None

    def test_no_maximum_len(self):
        """Test correct reutrn if no maximum length."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user._user_info = []
        assert user.maximum_length is None

    def test_accepted_common(self):
        """Test accepted_common_extended works correctly."""
        user = ServiceUser(self.assoc, 'acceptor')

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']

        user._common_ext = {item.sop_class_uid : item}

        out = user.accepted_common_extended
        assert out[item.sop_class_uid] == (
            item.service_class_uid,
            item.related_general_sop_class_identification
        )

    def test_assignment(self):
        """Test that assignment works OK,"""
        user = ServiceUser(self.assoc, mode='acceptor')

        assert user.primitive is None
        assert user.ae_title == b''
        assert user.port is None
        assert user.address == ''
        assert user._contexts == []
        assert user.mode == 'acceptor'
        assert user.maximum_length == 16382
        assert user.extended_negotiation == []
        assert user.implementation_class_uid == PYNETDICOM_IMPLEMENTATION_UID

        user.ae_title = b'TEST_AE_TITLE'
        user.port = 11112
        user.address = '127.9.9.1'
        user._contexts = [1]
        user.maximum_length = 16383

        assert user.ae_title == b'TEST_AE_TITLE'
        assert user.port == 11112
        assert user.address == '127.9.9.1'
        assert user._contexts == [1]
        assert user.maximum_length == 16383

    def test_mode_assignment_raises(self):
        """Test that assigning mode after init raises exception."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.mode == 'acceptor'
        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.mode = 'requestor'

        assert user.mode == 'acceptor'

    def test_minimal_ac(self):
        """Test access with a miminal allowed A-ASSOCIATE (ac) primitive."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac

        assert user.writeable is False
        assert user.primitive == self.primitive_ac
        assert user.mode == 'acceptor'
        assert user.maximum_length == 16383
        assert user.implementation_class_uid == '1.2.3'
        assert user.implementation_version_name is None
        assert user.asynchronous_operations == (1, 1)
        assert user.role_selection == {}
        assert user.sop_class_common_extended == {}
        assert user.sop_class_extended == {}
        assert user.user_identity is None

    def test_minimal_rj(self):
        """Test access with a miminal allowed A-ASSOCIATE (rj) primitive."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_rj

        assert user.writeable is False
        assert user.primitive == self.primitive_rj
        assert user.mode == 'acceptor'
        assert user.maximum_length is None
        assert user.implementation_class_uid is None
        assert user.implementation_version_name is None
        assert user.asynchronous_operations == (1, 1)
        assert user.role_selection == {}
        assert user.sop_class_common_extended == {}
        assert user.sop_class_extended == {}
        assert user.user_identity is None

    def test_full(self):
        """Test access with a maximum allowed A-ASSOCIATE primitive."""
        user = ServiceUser(self.assoc, mode='acceptor')

        item = ImplementationVersionNameNotification()
        item.implementation_version_name = 'VERSION_1'
        self.primitive_ac.user_information.append(item)

        for uid in ['1.2', '3.4']:
            item = SCP_SCU_RoleSelectionNegotiation()
            item.sop_class_uid = uid
            item.scu_role = False
            item.scp_role = True
            self.primitive_ac.user_information.append(item)

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        self.primitive_ac.user_information.append(item)

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        self.primitive_ac.user_information.append(item)

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        self.primitive_ac.user_information.append(item)

        user.primitive = self.primitive_ac

        assert user.maximum_length == 16383
        assert user.implementation_class_uid == '1.2.3'
        assert user.implementation_version_name == b'VERSION_1'
        assert user.asynchronous_operations == (2, 3)

        roles = user.role_selection
        assert len(roles) == 2
        role = roles['1.2']
        assert role.scu_role is False
        assert role.scp_role is True

        classes = user.sop_class_extended
        assert len(classes) == 1
        assert classes['1.2.3'] == b'SOME DATA'

        assert user.sop_class_common_extended == {}

        item = user.user_identity
        assert item.user_identity_type == 0x01
        assert item.primary_field == b'username'

    def test_info(self):
        """Test the .info propoerty"""
        user = ServiceUser(self.assoc, mode='acceptor')
        info = user.info

        assert info['port'] is None
        assert info['mode'] == 'acceptor'
        assert info['address'] == ''
        assert info['ae_title'] == b''
        with pytest.raises(KeyError):
            info['pdv_size']

        user.primitive = self.primitive_ac
        assert user.info['pdv_size'] == 16383

    def test_primitive_assignment_raises(self):
        """Test trying to set primitive parameters raises exception."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac

        assert user.primitive == self.primitive_ac
        assert user.mode == 'acceptor'

        msg = r"Can't set the Maximum Length after negotiation has started"
        with pytest.raises(RuntimeError, match=msg):
            user.maximum_length = 16382

        msg = (
            r"Can't set the Implementation Class UID after negotiation "
            r"has started"
        )
        with pytest.raises(RuntimeError, match=msg):
            user.implementation_class_uid = '1.2.3'

        msg = (
            r"Can't set the Implementation Version Name after negotiation "
            r"has started"
        )
        with pytest.raises(RuntimeError, match=msg):
            user.implementation_version_name = '1.2.3'

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.asynchronous_operations = (1, 1)

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.role_selection = {}

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.sop_class_common_extended = {}

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.sop_class_extended = {}

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.user_identity = 'test'

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.extended_negotiation = []

    def test_add_neg_pre(self):
        """Test adding negotiation items."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[UserIdentityNegotiation]
        assert len(user.extended_negotiation) == 2
        assert len(user.user_information) == 4

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SCP_SCU_RoleSelectionNegotiation]
        assert len(user.extended_negotiation) == 3
        assert len(user.user_information) == 5

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SOPClassExtendedNegotiation]
        assert len(user.extended_negotiation) == 4
        assert len(user.user_information) == 6

    def test_add_neg_pre_raises(self):
        """Test that exception is raised if bad item added."""
        user = ServiceUser(self.assoc, mode='acceptor')

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        bad = MaximumLengthNotification()
        bad.maximum_length_received = 12
        msg = r"'item' is not a valid extended negotiation item"
        with pytest.raises(TypeError, match=msg):
            user.add_negotiation_item(bad)

        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_add_neg_post_raises(self):
        """Test adding items after negotiation."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3

        msg = r"Can't add extended negotiation items after negotiation "
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

        assert item not in user.extended_negotiation
        assert item not in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

    def test_async_ops_pre(self):
        """Test getting async ops item prior to negotiation."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True
        assert user.asynchronous_operations == (1, 1)  # default
        assert user.extended_negotiation == []

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)

        assert user.asynchronous_operations == (2, 3)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_async_ops_post(self):
        """Test getting async ops item after negotiation."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False
        assert user.asynchronous_operations == (1, 1)  # default
        assert user.extended_negotiation == []

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.primitive.user_information.append(item)
        assert user.asynchronous_operations == (2, 3)
        assert user.extended_negotiation == [item]
        assert item in user.extended_negotiation
        assert item not in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_ext_neg_pre(self):
        """Test extended_negotiation only returns negotiation items."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True
        assert user.extended_negotiation == []
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)

        assert item in user.extended_negotiation
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_ext_neg_post(self):
        """Test extended_negotiation only returns negotiation items."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False
        assert user.extended_negotiation == []
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.primitive.user_information.append(item)

        assert item in user.extended_negotiation
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_get_contexts_pre(self):
        """Test get_contexts prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True

        cxs = user.get_contexts('supported')
        assert len(cxs) == 0

        user.supported_contexts = [build_context('1.2.840.10008.1.1')]
        cxs = user.get_contexts('supported')
        assert len(cxs) == 1
        assert cxs[0].abstract_syntax == '1.2.840.10008.1.1'

    def test_get_contexts_pre_raises(self):
        """Test get_contexts prior to association raises if bad type."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True

        msg = r"Invalid 'cx_type', must be 'supported'"
        with pytest.raises(ValueError, match=msg):
            user.get_contexts('requested')

    def test_get_contexts_post(self):
        """Test get_contexts after association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False

        cxs = user.get_contexts('supported')
        assert len(cxs) == 0

        cxs = user.get_contexts('pcdrl')
        assert len(cxs) == 1
        assert cxs[0].abstract_syntax == '1.2.840.10008.1.1'

    def test_get_contexts_post_raises(self):
        """Test get_contexts after association raises if bad type."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False

        msg = r"Invalid 'cx_type', must be 'supported' or 'pcdrl'"
        with pytest.raises(ValueError, match=msg):
            user.get_contexts('requested')

        with pytest.raises(ValueError, match=msg):
            user.get_contexts('pcdl')

    def test_impl_class_pre(self):
        """Test implementation_class_uid prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True
        assert user.implementation_class_uid == PYNETDICOM_IMPLEMENTATION_UID
        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationClassUIDNotification):
                assert item.implementation_class_uid == (
                    PYNETDICOM_IMPLEMENTATION_UID
                )
                class_items.append(item)

        assert len(class_items) == 1

        user.implementation_class_uid = '1.2.3'
        assert user.implementation_class_uid == '1.2.3'
        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationClassUIDNotification):
                assert item.implementation_class_uid == (
                    '1.2.3'
                )
                class_items.append(item)

        assert len(class_items) == 1

    def test_impl_class_post(self):
        """Test implementation_class_uid after association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False
        assert user.implementation_class_uid == '1.2.3'

        msg = r"Can't set the Implementation Class UID after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.implementation_class_uid = '1.2.3.4'

        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationClassUIDNotification):
                assert item.implementation_class_uid == '1.2.3'
                class_items.append(item)

        assert len(class_items) == 1

    def test_impl_version_pre(self):
        """Test implementation_version_name prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True
        assert user.implementation_version_name is None

        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationVersionNameNotification):
                class_items.append(item)

        assert len(class_items) == 0

        ref = b'12345ABCDE123456'
        user.implementation_version_name = ref
        assert user.implementation_version_name == ref

        class_items = []
        user.implementation_version_name = ref
        for item in user.user_information:
            if isinstance(item, ImplementationVersionNameNotification):
                class_items.append(item)
                assert user.implementation_version_name == ref

        assert len(class_items) == 1

    def test_impl_version_post(self):
        """Test implementation_version_name after association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False
        assert user.implementation_version_name is None

        ref = b'12345ABCDE123456'
        msg = r"Can't set the Implementation Version Name after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.implementation_version_name = ref

        item = ImplementationVersionNameNotification()
        item.implementation_version_name = ref
        user.primitive.user_information.append(item)

        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationVersionNameNotification):
                assert item.implementation_version_name == ref
                class_items.append(item)

        assert len(class_items) == 1

    def test_is_acceptor(self):
        """Test is_acceptor"""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.is_acceptor is True

    def test_is_requestor(self):
        """Test is_requestor"""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.is_requestor is False

    def test_max_length_pre(self):
        """Test maximum_length prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True

        assert user.maximum_length == 16382
        class_items = []
        for item in user.user_information:
            if isinstance(item, MaximumLengthNotification):
                assert item.maximum_length_received == 16382
                class_items.append(item)

        assert len(class_items) == 1

        user.maximum_length = 45
        assert user.maximum_length == 45
        class_items = []
        for item in user.user_information:
            if isinstance(item, MaximumLengthNotification):
                assert item.maximum_length_received == 45
                class_items.append(item)

        assert len(class_items) == 1

    def test_max_length_post(self):
        """Test maximum_length after association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False
        assert user.maximum_length == 16383

        msg = r"Can't set the Maximum Length after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.maximum_length = 45

        class_items = []
        for item in user.user_information:
            if isinstance(item, MaximumLengthNotification):
                assert item.maximum_length_received == 16383
                class_items.append(item)

        assert len(class_items) == 1

    def test_requested_cx_pre(self):
        """Test requested_contexts prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True

        msg = r"Invalid 'cx_type', must be 'supported'"
        with pytest.raises(ValueError, match=msg):
            user.requested_contexts

        msg = (
            r"'requested_contexts' can only be set for the association "
            r"requestor"
        )
        with pytest.raises(AttributeError, match=msg):
            user.requested_contexts = [build_context('1.2.3')]

    def test_requested_cx_post(self):
        """Test requested_contexts after association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False

        msg = r"Invalid 'cx_type', must be 'supported' or 'pcdrl'"
        with pytest.raises(ValueError, match=msg):
            user.requested_contexts

        msg = r"Can't set the requested presentation contexts after"
        with pytest.raises(RuntimeError, match=msg):
            user.requested_contexts = [build_context('1.2.3')]

    def test_rm_neg_pre(self):
        """Test removing negotiation items."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3

        # Test removing non-existent item
        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Test removing existent item
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Repeat for UserIdentity
        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[UserIdentityNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Repeat for Role Selection
        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SCP_SCU_RoleSelectionNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Repeat for SOP Class Extended
        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SOPClassExtendedNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Try removing unknown type
        msg = r"'item' is not a valid extended negotiation item"
        with pytest.raises(TypeError, match=msg):
            user.remove_negotiation_item(1234)

    def test_rm_neg_post_raises(self):
        """Test adding items after negotiation."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.primitive.user_information.append(item)

        msg = r"Can't remove extended negotiation items after negotiation "
        with pytest.raises(RuntimeError, match=msg):
            user.remove_negotiation_item(item)

        assert item in user.extended_negotiation
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_reset_neg_pre(self):
        """Test reset_negotiation_items prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Test with no items
        user.reset_negotiation_items()
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.add_negotiation_item(item)

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)

        assert len(user.extended_negotiation) == 4
        assert len(user.user_information) == 6

        user.reset_negotiation_items()
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert len(user._ext_neg.keys()) == 4

    def test_reset_neg_post_raises(self):
        """Test reset_negotiation_items after association raises."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.primitive.user_information.append(item)

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.primitive.user_information.append(item)

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.primitive.user_information.append(item)

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.primitive.user_information.append(item)

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.primitive.user_information.append(item)

        assert len(user.extended_negotiation) == 4
        assert len(user.user_information) == 7

        msg = r"Can't reset the extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.reset_negotiation_items()

        assert len(user.extended_negotiation) == 4
        assert len(user.user_information) == 7

    def test_role_pre(self):
        """Test role_selection prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.role_selection == {}

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SCP_SCU_RoleSelectionNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.role_selection['1.2.3'] == item

    def test_role_post(self):
        """Test role_selection prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.role_selection == {}

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.primitive.user_information.append(item)
        assert item in user.extended_negotiation
        assert item not in user._ext_neg[SCP_SCU_RoleSelectionNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.role_selection['1.2.3'] == item

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_sop_ext_pre(self):
        """Test sop_class_extended prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.sop_class_extended == {}

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SOPClassExtendedNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.sop_class_extended['1.2.3'] == (
            item.service_class_application_information
        )

    def test_sop_ext_post(self):
        """Test sop_class_extended prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.sop_class_extended == {}

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.primitive.user_information.append(item)
        assert item in user.extended_negotiation
        assert item not in user._ext_neg[SOPClassExtendedNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.sop_class_extended['1.2.3'] == (
            item.service_class_application_information
        )

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_sop_common_pre(self):
        """Test sop_class_common_extended prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.sop_class_common_extended == {}

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']

        msg = r"'item' is not a valid extended negotiation item"
        with pytest.raises(TypeError, match=msg):
            user.add_negotiation_item(item)

        assert item not in user.extended_negotiation
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        assert user.sop_class_common_extended == {}

    def test_sop_common_post(self):
        """Test sop_class_common_extended prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.sop_class_common_extended == {}

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.primitive.user_information.append(item)
        assert item not in user.extended_negotiation
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 3

        assert user.sop_class_common_extended == {}

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_supported_cx_pre(self):
        """Test supported_contexts prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True
        assert user.supported_contexts == []

        cx_a = build_context('1.2.3')
        cx_b = build_context('1.2.3.4')
        user.supported_contexts = [cx_a, cx_b]

        assert len(user.supported_contexts) == 2
        assert cx_a in user.supported_contexts
        assert cx_b in user.supported_contexts

    def test_supported_cx_post(self):
        """Test supported_contexts after association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False
        assert user.supported_contexts == []

        cx_a = build_context('1.2.3')
        msg = r"Can't set the supported presentation contexts after"
        with pytest.raises(RuntimeError, match=msg):
            user.supported_contexts = [build_context('1.2.3')]

        assert user.supported_contexts == []

    def test_user_id_pre(self):
        """Test user_identity prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.user_identity is None

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[UserIdentityNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.user_identity == item

    def test_user_id_post(self):
        """Test user_identity prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.user_identity is None

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.primitive.user_information.append(item)
        assert item in user.extended_negotiation
        assert item not in user._ext_neg[UserIdentityNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.user_identity == item

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_user_info_pre(self):
        """Test user_information prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert len(user.user_information) == 2

        user.implementation_version_name = 'VERSION_1'
        item = user.user_information[2]
        assert isinstance(item, ImplementationVersionNameNotification)
        assert item.implementation_version_name == b'VERSION_1'
        assert len(user.user_information) == 3

        for uid in ['1.2', '3.4']:
            item = SCP_SCU_RoleSelectionNegotiation()
            item.sop_class_uid = uid
            item.scu_role = False
            item.scp_role = True
            user.add_negotiation_item(item)
            assert item in user.user_information

        assert len(user.user_information) == 5

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)
        assert item in user.user_information
        assert len(user.user_information) == 6

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)
        assert item in user.user_information
        assert len(user.user_information) == 7

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)
        assert item in user.user_information
        assert len(user.user_information) == 8

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']

        msg = r"'item' is not a valid extended negotiation item"
        with pytest.raises(TypeError, match=msg):
            user.add_negotiation_item(item)

        assert item not in user.user_information
        assert len(user.user_information) == 8

    def test_user_info_post(self):
        """Test user_information prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert len(user.user_information) == 2

        item = ImplementationVersionNameNotification()
        item.implementation_version_name = 'VERSION_1'
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 3

        for uid in ['1.2', '3.4']:
            item = SCP_SCU_RoleSelectionNegotiation()
            item.sop_class_uid = uid
            item.scu_role = False
            item.scp_role = True
            user.primitive.user_information.append(item)
            assert item in user.user_information

        assert len(user.user_information) == 5

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 6

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 7

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 8

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 9

    def test_writeable(self):
        """Test writeable."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True
        user.primitive = self.primitive_ac
        assert user.writeable is False


class TestServiceUserRequestor(object):
    """Tests for ServiceUser as requestor."""
    def setup(self):
        self.assoc = Association(AE(), mode='requestor')

        primitive = A_ASSOCIATE()
        primitive.application_context_name = '1.2.840.10008.3.1.1.1'
        primitive.calling_ae_title = b'LOCAL_AE_TITLE  '
        primitive.called_ae_title = b'REMOTE_AE_TITLE '
        primitive.calling_presentation_address = ('127.0.0.1', 11112)
        primitive.called_presentation_address = ('127.0.0.2', 11113)

        # Presentation Contexts
        cx = build_context('1.2.840.10008.1.1')
        cx.context_id = 1
        primitive.presentation_context_definition_list = [cx]

        # User Information items
        item = MaximumLengthNotification()
        item.maximum_length_received = 16382
        primitive.user_information = [item]

        item = ImplementationClassUIDNotification()
        item.implementation_class_uid = '1.2.3'
        primitive.user_information.append(item)

        self.primitive = primitive

    def test_init(self):
        """Test new ServiceUser as requestor."""
        user = ServiceUser(self.assoc, mode='requestor')

        assert user.primitive is None
        assert user.ae_title == b''
        assert user.port is None
        assert user.address == ''
        assert user._contexts == []
        assert user.mode == 'requestor'
        assert user.maximum_length == 16382
        assert user.implementation_class_uid == PYNETDICOM_IMPLEMENTATION_UID
        assert user.extended_negotiation == []

        assert len(user.user_information) == 2

    def test_assignment(self):
        """Test that assignment works OK,"""
        user = ServiceUser(self.assoc, mode='requestor')

        assert user.primitive is None
        assert user.ae_title == b''
        assert user.port is None
        assert user.address == ''
        assert user._contexts == []
        assert user.mode == 'requestor'
        assert user.maximum_length == 16382
        assert user.extended_negotiation == []
        assert user.implementation_class_uid == PYNETDICOM_IMPLEMENTATION_UID

        user.ae_title = b'TEST_AE_TITLE'
        user.port = 11112
        user.address = '127.9.9.1'
        user._contexts = [1]
        user.maximum_length = 16383

        assert user.ae_title == b'TEST_AE_TITLE'
        assert user.port == 11112
        assert user.address == '127.9.9.1'
        assert user._contexts == [1]
        assert user.maximum_length == 16383

    def test_mode_assignment_raises(self):
        """Test that assigning mode after init raises exception."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.mode == 'requestor'
        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.mode = 'acceptor'

        assert user.mode == 'requestor'

    def test_minimal(self):
        """Test access with a miminal allowed A-ASSOCIATE primitive."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive

        assert user.primitive == self.primitive
        assert user.mode == 'requestor'
        assert user.maximum_length == 16382
        assert user.implementation_class_uid == '1.2.3'
        assert user.implementation_version_name is None
        assert user.asynchronous_operations == (1, 1)
        assert user.role_selection == {}
        assert user.sop_class_common_extended == {}
        assert user.sop_class_extended == {}
        assert user.user_identity is None

    def test_full(self):
        """Test access with a maximum allowed A-ASSOCIATE primitive."""
        user = ServiceUser(self.assoc, mode='requestor')

        item = ImplementationVersionNameNotification()
        item.implementation_version_name = 'VERSION_1'
        self.primitive.user_information.append(item)

        for uid in ['1.2', '3.4']:
            item = SCP_SCU_RoleSelectionNegotiation()
            item.sop_class_uid = uid
            item.scu_role = False
            item.scp_role = True
            self.primitive.user_information.append(item)

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        self.primitive.user_information.append(item)

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        self.primitive.user_information.append(item)

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        self.primitive.user_information.append(item)

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        self.primitive.user_information.append(item)

        user.primitive = self.primitive

        assert user.maximum_length == 16382
        assert user.implementation_class_uid == '1.2.3'
        assert user.implementation_version_name == b'VERSION_1'
        assert user.asynchronous_operations == (2, 3)

        roles = user.role_selection
        assert len(roles) == 2
        role = roles['1.2']
        assert role.scu_role is False
        assert role.scp_role is True

        classes = user.sop_class_extended
        assert len(classes) == 1
        assert classes['1.2.3'] == b'SOME DATA'

        classes = user.sop_class_common_extended
        assert len(classes) == 1
        assert classes['1.2.3'].service_class_uid == '2.3.4'
        assert classes['1.2.3'].related_general_sop_class_identification == [
            '1.3.4'
        ]

        item = user.user_identity
        assert item.user_identity_type == 0x01
        assert item.primary_field == b'username'

    def test_info(self):
        """Test the .info propoerty"""
        user = ServiceUser(self.assoc, mode='requestor')
        info = user.info

        assert info['port'] is None
        assert info['mode'] == 'requestor'
        assert info['address'] == ''
        assert info['ae_title'] == b''
        with pytest.raises(KeyError):
            info['pdv_size']

        user.primitive = self.primitive
        assert user.info['pdv_size'] == 16382

    def test_primitive_assignment_raises(self):
        """Test trying to set primitive parameters raises exception."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive

        assert user.primitive == self.primitive
        assert user.mode == 'requestor'

        msg = r"Can't set the Maximum Length after negotiation has started"
        with pytest.raises(RuntimeError, match=msg):
            user.maximum_length = 16382

        msg = (
            r"Can't set the Implementation Class UID after negotiation "
            r"has started"
        )
        with pytest.raises(RuntimeError, match=msg):
            user.implementation_class_uid = '1.2.3'

        msg = (
            r"Can't set the Implementation Version Name after negotiation "
            r"has started"
        )
        with pytest.raises(RuntimeError, match=msg):
            user.implementation_version_name = '1.2.3'

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.asynchronous_operations = (1, 1)

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.role_selection = {}

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.sop_class_common_extended = {}

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.sop_class_extended = {}

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.user_identity = 'test'

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.extended_negotiation = []

    def test_accepted_common_raises(self):
        """Test trying to get the accepted common ext items raises."""
        user = ServiceUser(self.assoc, mode='requestor')

        msg = (
            r"'accepted_common_extended' is only available for the "
            r"'acceptor'"
        )
        with pytest.raises(RuntimeError, match=msg):
            user.accepted_common_extended()

    def test_add_neg_pre(self):
        """Test adding negotiation items."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[UserIdentityNegotiation]
        assert len(user.extended_negotiation) == 2
        assert len(user.user_information) == 4

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SCP_SCU_RoleSelectionNegotiation]
        assert len(user.extended_negotiation) == 3
        assert len(user.user_information) == 5

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SOPClassExtendedNegotiation]
        assert len(user.extended_negotiation) == 4
        assert len(user.user_information) == 6

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SOPClassCommonExtendedNegotiation]
        assert len(user.extended_negotiation) == 5
        assert len(user.user_information) == 7

    def test_add_neg_pre_raises(self):
        """Test that exception is raised if bad item added."""
        user = ServiceUser(self.assoc, mode='requestor')

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        bad = MaximumLengthNotification()
        bad.maximum_length_received = 12
        msg = r"'item' is not a valid extended negotiation item"
        with pytest.raises(TypeError, match=msg):
            user.add_negotiation_item(bad)

        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_add_neg_post_raises(self):
        """Test adding items after negotiation."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3

        msg = r"Can't add extended negotiation items after negotiation "
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

        assert item not in user.extended_negotiation
        assert item not in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

    def test_async_ops_pre(self):
        """Test getting async ops item prior to negotiation."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True
        assert user.asynchronous_operations == (1, 1)  # default
        assert user.extended_negotiation == []

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)

        assert user.asynchronous_operations == (2, 3)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_async_ops_post(self):
        """Test getting async ops item after negotiation."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False
        assert user.asynchronous_operations == (1, 1)  # default
        assert user.extended_negotiation == []

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        self.primitive.user_information.append(item)
        assert user.asynchronous_operations == (2, 3)
        assert user.extended_negotiation == [item]
        assert item in user.extended_negotiation
        assert item not in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_ext_neg_pre(self):
        """Test extended_negotiation only returns negotiation items."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True
        assert user.extended_negotiation == []
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)

        assert item in user.extended_negotiation
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_ext_neg_post(self):
        """Test extended_negotiation only returns negotiation items."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False
        assert user.extended_negotiation == []
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        self.primitive.user_information.append(item)

        assert item in user.extended_negotiation
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_get_contexts_pre(self):
        """Test get_contexts prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True

        cxs = user.get_contexts('requested')
        assert len(cxs) == 0

        user.requested_contexts = [build_context('1.2.840.10008.1.1')]
        cxs = user.get_contexts('requested')
        assert len(cxs) == 1
        assert cxs[0].abstract_syntax == '1.2.840.10008.1.1'

    def test_get_contexts_pre_raises(self):
        """Test get_contexts prior to association raises if bad type."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True

        msg = r"Invalid 'cx_type', must be 'requested'"
        with pytest.raises(ValueError, match=msg):
            user.get_contexts('supported')

    def test_get_contexts_post(self):
        """Test get_contexts after association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False

        cxs = user.get_contexts('requested')
        assert len(cxs) == 0

        cxs = user.get_contexts('pcdl')
        assert len(cxs) == 1
        assert cxs[0].abstract_syntax == '1.2.840.10008.1.1'

    def test_get_contexts_post_raises(self):
        """Test get_contexts after association raises if bad type."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False

        msg = r"Invalid 'cx_type', must be 'requested' or 'pcdl'"
        with pytest.raises(ValueError, match=msg):
            user.get_contexts('supported')

        with pytest.raises(ValueError, match=msg):
            user.get_contexts('pcdrl')

    def test_impl_class_pre(self):
        """Test implementation_class_uid prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True
        assert user.implementation_class_uid == PYNETDICOM_IMPLEMENTATION_UID
        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationClassUIDNotification):
                assert item.implementation_class_uid == (
                    PYNETDICOM_IMPLEMENTATION_UID
                )
                class_items.append(item)

        assert len(class_items) == 1

        user.implementation_class_uid = '1.2.3'
        assert user.implementation_class_uid == '1.2.3'
        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationClassUIDNotification):
                assert item.implementation_class_uid == (
                    '1.2.3'
                )
                class_items.append(item)

        assert len(class_items) == 1

    def test_impl_class_post(self):
        """Test implementation_class_uid after association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False
        assert user.implementation_class_uid == '1.2.3'

        msg = r"Can't set the Implementation Class UID after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.implementation_class_uid = '1.2.3.4'

        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationClassUIDNotification):
                assert item.implementation_class_uid == '1.2.3'
                class_items.append(item)

        assert len(class_items) == 1

    def test_impl_version_pre(self):
        """Test implementation_version_name prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True
        assert user.implementation_version_name is None

        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationVersionNameNotification):
                class_items.append(item)

        assert len(class_items) == 0

        ref = b'12345ABCDE123456'
        user.implementation_version_name = ref
        assert user.implementation_version_name == ref

        class_items = []
        user.implementation_version_name = ref
        for item in user.user_information:
            if isinstance(item, ImplementationVersionNameNotification):
                class_items.append(item)
                assert user.implementation_version_name == ref

        assert len(class_items) == 1

    def test_impl_version_post(self):
        """Test implementation_version_name after association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False
        assert user.implementation_version_name is None

        ref = b'12345ABCDE123456'
        msg = r"Can't set the Implementation Version Name after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.implementation_version_name = ref

        item = ImplementationVersionNameNotification()
        item.implementation_version_name = ref
        self.primitive.user_information.append(item)

        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationVersionNameNotification):
                assert item.implementation_version_name == ref
                class_items.append(item)

        assert len(class_items) == 1

    def test_is_acceptor(self):
        """Test is_acceptor"""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.is_acceptor is False

    def test_is_requestor(self):
        """Test is_requestor"""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.is_requestor is True

    def test_max_length_pre(self):
        """Test maximum_length prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True

        assert user.maximum_length == 16382
        class_items = []
        for item in user.user_information:
            if isinstance(item, MaximumLengthNotification):
                assert item.maximum_length_received == 16382
                class_items.append(item)

        assert len(class_items) == 1

        user.maximum_length = 45
        assert user.maximum_length == 45
        class_items = []
        for item in user.user_information:
            if isinstance(item, MaximumLengthNotification):
                assert item.maximum_length_received == 45
                class_items.append(item)

        assert len(class_items) == 1

    def test_max_length_post(self):
        """Test maximum_length after association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False
        assert user.maximum_length == 16382

        msg = r"Can't set the Maximum Length after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.maximum_length = 45

        class_items = []
        for item in user.user_information:
            if isinstance(item, MaximumLengthNotification):
                assert item.maximum_length_received == 16382
                class_items.append(item)

        assert len(class_items) == 1

    def test_requested_cx_pre(self):
        """Test requested_contexts prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True
        assert user.requested_contexts == []

        cx_a = build_context('1.2.3')
        cx_b = build_context('1.2.3.4')
        user.requested_contexts = [cx_a, cx_b]

        assert len(user.requested_contexts) == 2
        assert cx_a in user.requested_contexts
        assert cx_b in user.requested_contexts

    def test_requested_cx_post(self):
        """Test requested_contexts after association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False
        assert user.requested_contexts == []

        cx_a = build_context('1.2.3')
        msg = r"Can't set the requested presentation contexts after"
        with pytest.raises(RuntimeError, match=msg):
            user.requested_contexts = [build_context('1.2.3')]

        assert user.requested_contexts == []

    def test_rm_neg_pre(self):
        """Test removing negotiation items."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3

        # Test removing non-existent item
        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Test removing existent item
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Repeat for UserIdentity
        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[UserIdentityNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Repeat for Role Selection
        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SCP_SCU_RoleSelectionNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Repeat for SOP Class Extended
        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SOPClassExtendedNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Repeat for SOP Class Common
        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SOPClassCommonExtendedNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Try removing unknown type
        msg = r"'item' is not a valid extended negotiation item"
        with pytest.raises(TypeError, match=msg):
            user.remove_negotiation_item(1234)

    def test_rm_neg_post_raises(self):
        """Test adding items after negotiation."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        self.primitive.user_information.append(item)

        msg = r"Can't remove extended negotiation items after negotiation "
        with pytest.raises(RuntimeError, match=msg):
            user.remove_negotiation_item(item)

        assert item in user.extended_negotiation
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_reset_neg_pre(self):
        """Test reset_negotiation_items prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Test with no items
        user.reset_negotiation_items()
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.add_negotiation_item(item)

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.add_negotiation_item(item)

        assert len(user.extended_negotiation) == 5
        assert len(user.user_information) == 7

        user.reset_negotiation_items()
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert len(user._ext_neg.keys()) == 5

    def test_reset_neg_post_raises(self):
        """Test reset_negotiation_items after association raises."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.primitive.user_information.append(item)

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.primitive.user_information.append(item)

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.primitive.user_information.append(item)

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.primitive.user_information.append(item)

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.primitive.user_information.append(item)

        assert len(user.extended_negotiation) == 5
        assert len(user.user_information) == 7

        msg = r"Can't reset the extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.reset_negotiation_items()

        assert len(user.extended_negotiation) == 5
        assert len(user.user_information) == 7

    def test_role_pre(self):
        """Test role_selection prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.role_selection == {}

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SCP_SCU_RoleSelectionNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.role_selection['1.2.3'] == item

    def test_role_post(self):
        """Test role_selection prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.role_selection == {}

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.primitive.user_information.append(item)
        assert item in user.extended_negotiation
        assert item not in user._ext_neg[SCP_SCU_RoleSelectionNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.role_selection['1.2.3'] == item

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_sop_ext_pre(self):
        """Test sop_class_extended prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.sop_class_extended == {}

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SOPClassExtendedNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.sop_class_extended['1.2.3'] == (
            item.service_class_application_information
        )

    def test_sop_ext_post(self):
        """Test sop_class_extended prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.sop_class_extended == {}

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.primitive.user_information.append(item)
        assert item in user.extended_negotiation
        assert item not in user._ext_neg[SOPClassExtendedNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.sop_class_extended['1.2.3'] == (
            item.service_class_application_information
        )

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_sop_common_pre(self):
        """Test sop_class_common_extended prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.sop_class_common_extended == {}

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SOPClassCommonExtendedNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.sop_class_common_extended['1.2.3'] == item

    def test_sop_common_post(self):
        """Test sop_class_common_extended prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.sop_class_common_extended == {}

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.primitive.user_information.append(item)
        assert item in user.extended_negotiation
        assert item not in user._ext_neg[SOPClassCommonExtendedNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.sop_class_common_extended['1.2.3'] == item

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_supported_cx_pre(self):
        """Test supported_contexts prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True

        msg = r"Invalid 'cx_type', must be 'requested'"
        with pytest.raises(ValueError, match=msg):
            assert user.supported_contexts == []

        msg = (
            r"'supported_contexts' can only be set for the association "
            r"acceptor"
        )
        with pytest.raises(AttributeError, match=msg):
            user.supported_contexts = 'bluh'

    def test_supported_cx_post(self):
        """Test supported_contexts after association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False

        msg = r"Invalid 'cx_type', must be 'requested' or 'pcdl'"
        with pytest.raises(ValueError, match=msg):
            assert user.supported_contexts == []

    def test_user_id_pre(self):
        """Test user_identity prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.user_identity is None

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[UserIdentityNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.user_identity == item

    def test_user_id_post(self):
        """Test user_identity prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.user_identity is None

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.primitive.user_information.append(item)
        assert item in user.extended_negotiation
        assert item not in user._ext_neg[UserIdentityNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.user_identity == item

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_user_info_pre(self):
        """Test user_information prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert len(user.user_information) == 2

        user.implementation_version_name = 'VERSION_1'
        item = user.user_information[2]
        assert isinstance(item, ImplementationVersionNameNotification)
        assert item.implementation_version_name == b'VERSION_1'
        assert len(user.user_information) == 3

        for uid in ['1.2', '3.4']:
            item = SCP_SCU_RoleSelectionNegotiation()
            item.sop_class_uid = uid
            item.scu_role = False
            item.scp_role = True
            user.add_negotiation_item(item)
            assert item in user.user_information

        assert len(user.user_information) == 5

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)
        assert item in user.user_information
        assert len(user.user_information) == 6

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)
        assert item in user.user_information
        assert len(user.user_information) == 7

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)
        assert item in user.user_information
        assert len(user.user_information) == 8

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.add_negotiation_item(item)
        assert item in user.user_information
        assert len(user.user_information) == 9

    def test_user_info_post(self):
        """Test user_information prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert len(user.user_information) == 2

        item = ImplementationVersionNameNotification()
        item.implementation_version_name = 'VERSION_1'
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 3

        for uid in ['1.2', '3.4']:
            item = SCP_SCU_RoleSelectionNegotiation()
            item.sop_class_uid = uid
            item.scu_role = False
            item.scp_role = True
            user.primitive.user_information.append(item)
            assert item in user.user_information

        assert len(user.user_information) == 5

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 6

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 7

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 8

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 9

    def test_writeable(self):
        """Test writeable."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True
        user.primitive = self.primitive
        assert user.writeable is False

"""Tests for association.AcceptorRequestor."""

import logging
import time
import threading

import pytest

from pynetdicom import (
    AE, VerificationPresentationContexts, PYNETDICOM_IMPLEMENTATION_UID,
    PYNETDICOM_IMPLEMENTATION_VERSION, build_context
)
from pynetdicom.association import ServiceUser, Association
from pynetdicom.pdu_primitives import (
    A_ASSOCIATE, MaximumLengthNotification, ImplementationClassUIDNotification,
    ImplementationVersionNameNotification, SCP_SCU_RoleSelectionNegotiation,
    UserIdentityNegotiation, SOPClassExtendedNegotiation,
    SOPClassCommonExtendedNegotiation, AsynchronousOperationsWindowNegotiation
)
from pynetdicom.sop_class import VerificationSOPClass

from .dummy_c_scp import DummyVerificationSCP, DummyBaseSCP


LOGGER = logging.getLogger('pynetdicom')
LOGGER.setLevel(logging.CRITICAL)
#LOGGER.setLevel(logging.DEBUG)


class TestServiceUserAcceptor(object):
    """Tests for ServiceUser as acceptor."""
    def setup(self):
        self.assoc = Association(AE(), mode='requestor')

        primitive = A_ASSOCIATE()
        primitive.application_context_name = '1.2.840.10008.3.1.1.1'
        primitive.calling_ae_title = b'LOCAL_AE_TITLE  '
        primitive.called_ae_title = b'REMOTE_AE_TITLE '
        primitive.result = 0x00
        primitive.result_source = 0x01

        # Presentation Contexts
        cx = build_context('1.2.840.10008.1.1')
        cx.context_id = 1
        primitive.presentation_context_definition_results_list = [cx]

        # User Information items
        item = MaximumLengthNotification()
        item.maximum_length_received = 16383
        primitive.user_information = [item]

        item = ImplementationClassUIDNotification()
        item.implementation_class_uid = '1.2.3'
        primitive.user_information.append(item)

        self.primitive_ac = primitive

        primitive = A_ASSOCIATE()
        primitive.result = 0x01
        primitive.result_source = 0x01
        primitive.diagnostic = 0x01
        self.primitive_rj = primitive

    def test_init(self):
        """Test new ServiceUser as acceptor."""
        user = ServiceUser(self.assoc, mode='acceptor')

        assert user.primitive is None
        assert user.ae_title == b''
        assert user.port is None
        assert user.address == ''
        assert user._contexts == []
        assert user.mode == 'acceptor'
        assert user.maximum_length == 16382
        assert user.extended_negotiation == []
        assert user.implementation_class_uid == PYNETDICOM_IMPLEMENTATION_UID

        assert len(user.user_information) == 2

    def test_bad_mode(self):
        """Test bad mode raises exception."""
        with pytest.raises(ValueError, match=r"The 'mode' must be either"):
            ServiceUser(None, 'something')

    def test_no_implementation_class_uid(self):
        """Test correct return if no class UID."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user._user_info = []
        assert user.implementation_class_uid is None

    def test_no_maximum_len(self):
        """Test correct reutrn if no maximum length."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user._user_info = []
        assert user.maximum_length is None

    def test_accepted_common(self):
        """Test accepted_common_extended works correctly."""
        user = ServiceUser(self.assoc, 'acceptor')

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']

        user._common_ext = {item.sop_class_uid : item}

        out = user.accepted_common_extended
        assert out[item.sop_class_uid] == (
            item.service_class_uid,
            item.related_general_sop_class_identification
        )

    def test_assignment(self):
        """Test that assignment works OK,"""
        user = ServiceUser(self.assoc, mode='acceptor')

        assert user.primitive is None
        assert user.ae_title == b''
        assert user.port is None
        assert user.address == ''
        assert user._contexts == []
        assert user.mode == 'acceptor'
        assert user.maximum_length == 16382
        assert user.extended_negotiation == []
        assert user.implementation_class_uid == PYNETDICOM_IMPLEMENTATION_UID

        user.ae_title = b'TEST_AE_TITLE'
        user.port = 11112
        user.address = '127.9.9.1'
        user._contexts = [1]
        user.maximum_length = 16383

        assert user.ae_title == b'TEST_AE_TITLE'
        assert user.port == 11112
        assert user.address == '127.9.9.1'
        assert user._contexts == [1]
        assert user.maximum_length == 16383

    def test_mode_assignment_raises(self):
        """Test that assigning mode after init raises exception."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.mode == 'acceptor'
        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.mode = 'requestor'

        assert user.mode == 'acceptor'

    def test_minimal_ac(self):
        """Test access with a miminal allowed A-ASSOCIATE (ac) primitive."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac

        assert user.writeable is False
        assert user.primitive == self.primitive_ac
        assert user.mode == 'acceptor'
        assert user.maximum_length == 16383
        assert user.implementation_class_uid == '1.2.3'
        assert user.implementation_version_name is None
        assert user.asynchronous_operations == (1, 1)
        assert user.role_selection == {}
        assert user.sop_class_common_extended == {}
        assert user.sop_class_extended == {}
        assert user.user_identity is None

    def test_minimal_rj(self):
        """Test access with a miminal allowed A-ASSOCIATE (rj) primitive."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_rj

        assert user.writeable is False
        assert user.primitive == self.primitive_rj
        assert user.mode == 'acceptor'
        assert user.maximum_length is None
        assert user.implementation_class_uid is None
        assert user.implementation_version_name is None
        assert user.asynchronous_operations == (1, 1)
        assert user.role_selection == {}
        assert user.sop_class_common_extended == {}
        assert user.sop_class_extended == {}
        assert user.user_identity is None

    def test_full(self):
        """Test access with a maximum allowed A-ASSOCIATE primitive."""
        user = ServiceUser(self.assoc, mode='acceptor')

        item = ImplementationVersionNameNotification()
        item.implementation_version_name = 'VERSION_1'
        self.primitive_ac.user_information.append(item)

        for uid in ['1.2', '3.4']:
            item = SCP_SCU_RoleSelectionNegotiation()
            item.sop_class_uid = uid
            item.scu_role = False
            item.scp_role = True
            self.primitive_ac.user_information.append(item)

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        self.primitive_ac.user_information.append(item)

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        self.primitive_ac.user_information.append(item)

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        self.primitive_ac.user_information.append(item)

        user.primitive = self.primitive_ac

        assert user.maximum_length == 16383
        assert user.implementation_class_uid == '1.2.3'
        assert user.implementation_version_name == b'VERSION_1'
        assert user.asynchronous_operations == (2, 3)

        roles = user.role_selection
        assert len(roles) == 2
        role = roles['1.2']
        assert role.scu_role is False
        assert role.scp_role is True

        classes = user.sop_class_extended
        assert len(classes) == 1
        assert classes['1.2.3'] == b'SOME DATA'

        assert user.sop_class_common_extended == {}

        item = user.user_identity
        assert item.user_identity_type == 0x01
        assert item.primary_field == b'username'

    def test_info(self):
        """Test the .info propoerty"""
        user = ServiceUser(self.assoc, mode='acceptor')
        info = user.info

        assert info['port'] is None
        assert info['mode'] == 'acceptor'
        assert info['address'] == ''
        assert info['ae_title'] == b''
        with pytest.raises(KeyError):
            info['pdv_size']

        user.primitive = self.primitive_ac
        assert user.info['pdv_size'] == 16383

    def test_primitive_assignment_raises(self):
        """Test trying to set primitive parameters raises exception."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac

        assert user.primitive == self.primitive_ac
        assert user.mode == 'acceptor'

        msg = r"Can't set the Maximum Length after negotiation has started"
        with pytest.raises(RuntimeError, match=msg):
            user.maximum_length = 16382

        msg = (
            r"Can't set the Implementation Class UID after negotiation "
            r"has started"
        )
        with pytest.raises(RuntimeError, match=msg):
            user.implementation_class_uid = '1.2.3'

        msg = (
            r"Can't set the Implementation Version Name after negotiation "
            r"has started"
        )
        with pytest.raises(RuntimeError, match=msg):
            user.implementation_version_name = '1.2.3'

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.asynchronous_operations = (1, 1)

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.role_selection = {}

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.sop_class_common_extended = {}

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.sop_class_extended = {}

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.user_identity = 'test'

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.extended_negotiation = []

    def test_add_neg_pre(self):
        """Test adding negotiation items."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[UserIdentityNegotiation]
        assert len(user.extended_negotiation) == 2
        assert len(user.user_information) == 4

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SCP_SCU_RoleSelectionNegotiation]
        assert len(user.extended_negotiation) == 3
        assert len(user.user_information) == 5

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SOPClassExtendedNegotiation]
        assert len(user.extended_negotiation) == 4
        assert len(user.user_information) == 6

    def test_add_neg_pre_raises(self):
        """Test that exception is raised if bad item added."""
        user = ServiceUser(self.assoc, mode='acceptor')

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        bad = MaximumLengthNotification()
        bad.maximum_length_received = 12
        msg = r"'item' is not a valid extended negotiation item"
        with pytest.raises(TypeError, match=msg):
            user.add_negotiation_item(bad)

        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_add_neg_post_raises(self):
        """Test adding items after negotiation."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3

        msg = r"Can't add extended negotiation items after negotiation "
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

        assert item not in user.extended_negotiation
        assert item not in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

    def test_async_ops_pre(self):
        """Test getting async ops item prior to negotiation."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True
        assert user.asynchronous_operations == (1, 1)  # default
        assert user.extended_negotiation == []

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)

        assert user.asynchronous_operations == (2, 3)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_async_ops_post(self):
        """Test getting async ops item after negotiation."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False
        assert user.asynchronous_operations == (1, 1)  # default
        assert user.extended_negotiation == []

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.primitive.user_information.append(item)
        assert user.asynchronous_operations == (2, 3)
        assert user.extended_negotiation == [item]
        assert item in user.extended_negotiation
        assert item not in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_ext_neg_pre(self):
        """Test extended_negotiation only returns negotiation items."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True
        assert user.extended_negotiation == []
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)

        assert item in user.extended_negotiation
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_ext_neg_post(self):
        """Test extended_negotiation only returns negotiation items."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False
        assert user.extended_negotiation == []
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.primitive.user_information.append(item)

        assert item in user.extended_negotiation
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_get_contexts_pre(self):
        """Test get_contexts prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True

        cxs = user.get_contexts('supported')
        assert len(cxs) == 0

        user.supported_contexts = [build_context('1.2.840.10008.1.1')]
        cxs = user.get_contexts('supported')
        assert len(cxs) == 1
        assert cxs[0].abstract_syntax == '1.2.840.10008.1.1'

    def test_get_contexts_pre_raises(self):
        """Test get_contexts prior to association raises if bad type."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True

        msg = r"Invalid 'cx_type', must be 'supported'"
        with pytest.raises(ValueError, match=msg):
            user.get_contexts('requested')

    def test_get_contexts_post(self):
        """Test get_contexts after association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False

        cxs = user.get_contexts('supported')
        assert len(cxs) == 0

        cxs = user.get_contexts('pcdrl')
        assert len(cxs) == 1
        assert cxs[0].abstract_syntax == '1.2.840.10008.1.1'

    def test_get_contexts_post_raises(self):
        """Test get_contexts after association raises if bad type."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False

        msg = r"Invalid 'cx_type', must be 'supported' or 'pcdrl'"
        with pytest.raises(ValueError, match=msg):
            user.get_contexts('requested')

        with pytest.raises(ValueError, match=msg):
            user.get_contexts('pcdl')

    def test_impl_class_pre(self):
        """Test implementation_class_uid prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True
        assert user.implementation_class_uid == PYNETDICOM_IMPLEMENTATION_UID
        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationClassUIDNotification):
                assert item.implementation_class_uid == (
                    PYNETDICOM_IMPLEMENTATION_UID
                )
                class_items.append(item)

        assert len(class_items) == 1

        user.implementation_class_uid = '1.2.3'
        assert user.implementation_class_uid == '1.2.3'
        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationClassUIDNotification):
                assert item.implementation_class_uid == (
                    '1.2.3'
                )
                class_items.append(item)

        assert len(class_items) == 1

    def test_impl_class_post(self):
        """Test implementation_class_uid after association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False
        assert user.implementation_class_uid == '1.2.3'

        msg = r"Can't set the Implementation Class UID after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.implementation_class_uid = '1.2.3.4'

        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationClassUIDNotification):
                assert item.implementation_class_uid == '1.2.3'
                class_items.append(item)

        assert len(class_items) == 1

    def test_impl_version_pre(self):
        """Test implementation_version_name prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True
        assert user.implementation_version_name is None

        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationVersionNameNotification):
                class_items.append(item)

        assert len(class_items) == 0

        ref = b'12345ABCDE123456'
        user.implementation_version_name = ref
        assert user.implementation_version_name == ref

        class_items = []
        user.implementation_version_name = ref
        for item in user.user_information:
            if isinstance(item, ImplementationVersionNameNotification):
                class_items.append(item)
                assert user.implementation_version_name == ref

        assert len(class_items) == 1

    def test_impl_version_post(self):
        """Test implementation_version_name after association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False
        assert user.implementation_version_name is None

        ref = b'12345ABCDE123456'
        msg = r"Can't set the Implementation Version Name after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.implementation_version_name = ref

        item = ImplementationVersionNameNotification()
        item.implementation_version_name = ref
        user.primitive.user_information.append(item)

        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationVersionNameNotification):
                assert item.implementation_version_name == ref
                class_items.append(item)

        assert len(class_items) == 1

    def test_is_acceptor(self):
        """Test is_acceptor"""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.is_acceptor is True

    def test_is_requestor(self):
        """Test is_requestor"""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.is_requestor is False

    def test_max_length_pre(self):
        """Test maximum_length prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True

        assert user.maximum_length == 16382
        class_items = []
        for item in user.user_information:
            if isinstance(item, MaximumLengthNotification):
                assert item.maximum_length_received == 16382
                class_items.append(item)

        assert len(class_items) == 1

        user.maximum_length = 45
        assert user.maximum_length == 45
        class_items = []
        for item in user.user_information:
            if isinstance(item, MaximumLengthNotification):
                assert item.maximum_length_received == 45
                class_items.append(item)

        assert len(class_items) == 1

    def test_max_length_post(self):
        """Test maximum_length after association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False
        assert user.maximum_length == 16383

        msg = r"Can't set the Maximum Length after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.maximum_length = 45

        class_items = []
        for item in user.user_information:
            if isinstance(item, MaximumLengthNotification):
                assert item.maximum_length_received == 16383
                class_items.append(item)

        assert len(class_items) == 1

    def test_requested_cx_pre(self):
        """Test requested_contexts prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True

        msg = r"Invalid 'cx_type', must be 'supported'"
        with pytest.raises(ValueError, match=msg):
            user.requested_contexts

        msg = (
            r"'requested_contexts' can only be set for the association "
            r"requestor"
        )
        with pytest.raises(AttributeError, match=msg):
            user.requested_contexts = [build_context('1.2.3')]

    def test_requested_cx_post(self):
        """Test requested_contexts after association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False

        msg = r"Invalid 'cx_type', must be 'supported' or 'pcdrl'"
        with pytest.raises(ValueError, match=msg):
            user.requested_contexts

        msg = r"Can't set the requested presentation contexts after"
        with pytest.raises(RuntimeError, match=msg):
            user.requested_contexts = [build_context('1.2.3')]

    def test_rm_neg_pre(self):
        """Test removing negotiation items."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3

        # Test removing non-existent item
        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Test removing existent item
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Repeat for UserIdentity
        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[UserIdentityNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Repeat for Role Selection
        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SCP_SCU_RoleSelectionNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Repeat for SOP Class Extended
        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SOPClassExtendedNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Try removing unknown type
        msg = r"'item' is not a valid extended negotiation item"
        with pytest.raises(TypeError, match=msg):
            user.remove_negotiation_item(1234)

    def test_rm_neg_post_raises(self):
        """Test adding items after negotiation."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.primitive.user_information.append(item)

        msg = r"Can't remove extended negotiation items after negotiation "
        with pytest.raises(RuntimeError, match=msg):
            user.remove_negotiation_item(item)

        assert item in user.extended_negotiation
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_reset_neg_pre(self):
        """Test reset_negotiation_items prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Test with no items
        user.reset_negotiation_items()
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.add_negotiation_item(item)

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)

        assert len(user.extended_negotiation) == 4
        assert len(user.user_information) == 6

        user.reset_negotiation_items()
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert len(user._ext_neg.keys()) == 4

    def test_reset_neg_post_raises(self):
        """Test reset_negotiation_items after association raises."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.primitive.user_information.append(item)

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.primitive.user_information.append(item)

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.primitive.user_information.append(item)

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.primitive.user_information.append(item)

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.primitive.user_information.append(item)

        assert len(user.extended_negotiation) == 4
        assert len(user.user_information) == 7

        msg = r"Can't reset the extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.reset_negotiation_items()

        assert len(user.extended_negotiation) == 4
        assert len(user.user_information) == 7

    def test_role_pre(self):
        """Test role_selection prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.role_selection == {}

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SCP_SCU_RoleSelectionNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.role_selection['1.2.3'] == item

    def test_role_post(self):
        """Test role_selection prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.role_selection == {}

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.primitive.user_information.append(item)
        assert item in user.extended_negotiation
        assert item not in user._ext_neg[SCP_SCU_RoleSelectionNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.role_selection['1.2.3'] == item

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_sop_ext_pre(self):
        """Test sop_class_extended prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.sop_class_extended == {}

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SOPClassExtendedNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.sop_class_extended['1.2.3'] == (
            item.service_class_application_information
        )

    def test_sop_ext_post(self):
        """Test sop_class_extended prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.sop_class_extended == {}

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.primitive.user_information.append(item)
        assert item in user.extended_negotiation
        assert item not in user._ext_neg[SOPClassExtendedNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.sop_class_extended['1.2.3'] == (
            item.service_class_application_information
        )

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_sop_common_pre(self):
        """Test sop_class_common_extended prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.sop_class_common_extended == {}

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']

        msg = r"'item' is not a valid extended negotiation item"
        with pytest.raises(TypeError, match=msg):
            user.add_negotiation_item(item)

        assert item not in user.extended_negotiation
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        assert user.sop_class_common_extended == {}

    def test_sop_common_post(self):
        """Test sop_class_common_extended prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.sop_class_common_extended == {}

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.primitive.user_information.append(item)
        assert item not in user.extended_negotiation
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 3

        assert user.sop_class_common_extended == {}

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_supported_cx_pre(self):
        """Test supported_contexts prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True
        assert user.supported_contexts == []

        cx_a = build_context('1.2.3')
        cx_b = build_context('1.2.3.4')
        user.supported_contexts = [cx_a, cx_b]

        assert len(user.supported_contexts) == 2
        assert cx_a in user.supported_contexts
        assert cx_b in user.supported_contexts

    def test_supported_cx_post(self):
        """Test supported_contexts after association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert user.writeable is False
        assert user.supported_contexts == []

        cx_a = build_context('1.2.3')
        msg = r"Can't set the supported presentation contexts after"
        with pytest.raises(RuntimeError, match=msg):
            user.supported_contexts = [build_context('1.2.3')]

        assert user.supported_contexts == []

    def test_user_id_pre(self):
        """Test user_identity prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.user_identity is None

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[UserIdentityNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.user_identity == item

    def test_user_id_post(self):
        """Test user_identity prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.user_identity is None

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.primitive.user_information.append(item)
        assert item in user.extended_negotiation
        assert item not in user._ext_neg[UserIdentityNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.user_identity == item

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_user_info_pre(self):
        """Test user_information prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert len(user.user_information) == 2

        user.implementation_version_name = 'VERSION_1'
        item = user.user_information[2]
        assert isinstance(item, ImplementationVersionNameNotification)
        assert item.implementation_version_name == b'VERSION_1'
        assert len(user.user_information) == 3

        for uid in ['1.2', '3.4']:
            item = SCP_SCU_RoleSelectionNegotiation()
            item.sop_class_uid = uid
            item.scu_role = False
            item.scp_role = True
            user.add_negotiation_item(item)
            assert item in user.user_information

        assert len(user.user_information) == 5

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)
        assert item in user.user_information
        assert len(user.user_information) == 6

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)
        assert item in user.user_information
        assert len(user.user_information) == 7

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)
        assert item in user.user_information
        assert len(user.user_information) == 8

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']

        msg = r"'item' is not a valid extended negotiation item"
        with pytest.raises(TypeError, match=msg):
            user.add_negotiation_item(item)

        assert item not in user.user_information
        assert len(user.user_information) == 8

    def test_user_info_post(self):
        """Test user_information prior to association."""
        user = ServiceUser(self.assoc, mode='acceptor')
        user.primitive = self.primitive_ac
        assert len(user.user_information) == 2

        item = ImplementationVersionNameNotification()
        item.implementation_version_name = 'VERSION_1'
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 3

        for uid in ['1.2', '3.4']:
            item = SCP_SCU_RoleSelectionNegotiation()
            item.sop_class_uid = uid
            item.scu_role = False
            item.scp_role = True
            user.primitive.user_information.append(item)
            assert item in user.user_information

        assert len(user.user_information) == 5

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 6

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 7

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 8

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 9

    def test_writeable(self):
        """Test writeable."""
        user = ServiceUser(self.assoc, mode='acceptor')
        assert user.writeable is True
        user.primitive = self.primitive_ac
        assert user.writeable is False


class TestServiceUserRequestor(object):
    """Tests for ServiceUser as requestor."""
    def setup(self):
        self.assoc = Association(AE(), mode='requestor')

        primitive = A_ASSOCIATE()
        primitive.application_context_name = '1.2.840.10008.3.1.1.1'
        primitive.calling_ae_title = b'LOCAL_AE_TITLE  '
        primitive.called_ae_title = b'REMOTE_AE_TITLE '
        primitive.calling_presentation_address = ('127.0.0.1', 11112)
        primitive.called_presentation_address = ('127.0.0.2', 11113)

        # Presentation Contexts
        cx = build_context('1.2.840.10008.1.1')
        cx.context_id = 1
        primitive.presentation_context_definition_list = [cx]

        # User Information items
        item = MaximumLengthNotification()
        item.maximum_length_received = 16382
        primitive.user_information = [item]

        item = ImplementationClassUIDNotification()
        item.implementation_class_uid = '1.2.3'
        primitive.user_information.append(item)

        self.primitive = primitive

    def test_init(self):
        """Test new ServiceUser as requestor."""
        user = ServiceUser(self.assoc, mode='requestor')

        assert user.primitive is None
        assert user.ae_title == b''
        assert user.port is None
        assert user.address == ''
        assert user._contexts == []
        assert user.mode == 'requestor'
        assert user.maximum_length == 16382
        assert user.implementation_class_uid == PYNETDICOM_IMPLEMENTATION_UID
        assert user.extended_negotiation == []

        assert len(user.user_information) == 2

    def test_assignment(self):
        """Test that assignment works OK,"""
        user = ServiceUser(self.assoc, mode='requestor')

        assert user.primitive is None
        assert user.ae_title == b''
        assert user.port is None
        assert user.address == ''
        assert user._contexts == []
        assert user.mode == 'requestor'
        assert user.maximum_length == 16382
        assert user.extended_negotiation == []
        assert user.implementation_class_uid == PYNETDICOM_IMPLEMENTATION_UID

        user.ae_title = b'TEST_AE_TITLE'
        user.port = 11112
        user.address = '127.9.9.1'
        user._contexts = [1]
        user.maximum_length = 16383

        assert user.ae_title == b'TEST_AE_TITLE'
        assert user.port == 11112
        assert user.address == '127.9.9.1'
        assert user._contexts == [1]
        assert user.maximum_length == 16383

    def test_mode_assignment_raises(self):
        """Test that assigning mode after init raises exception."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.mode == 'requestor'
        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.mode = 'acceptor'

        assert user.mode == 'requestor'

    def test_minimal(self):
        """Test access with a miminal allowed A-ASSOCIATE primitive."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive

        assert user.primitive == self.primitive
        assert user.mode == 'requestor'
        assert user.maximum_length == 16382
        assert user.implementation_class_uid == '1.2.3'
        assert user.implementation_version_name is None
        assert user.asynchronous_operations == (1, 1)
        assert user.role_selection == {}
        assert user.sop_class_common_extended == {}
        assert user.sop_class_extended == {}
        assert user.user_identity is None

    def test_full(self):
        """Test access with a maximum allowed A-ASSOCIATE primitive."""
        user = ServiceUser(self.assoc, mode='requestor')

        item = ImplementationVersionNameNotification()
        item.implementation_version_name = 'VERSION_1'
        self.primitive.user_information.append(item)

        for uid in ['1.2', '3.4']:
            item = SCP_SCU_RoleSelectionNegotiation()
            item.sop_class_uid = uid
            item.scu_role = False
            item.scp_role = True
            self.primitive.user_information.append(item)

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        self.primitive.user_information.append(item)

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        self.primitive.user_information.append(item)

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        self.primitive.user_information.append(item)

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        self.primitive.user_information.append(item)

        user.primitive = self.primitive

        assert user.maximum_length == 16382
        assert user.implementation_class_uid == '1.2.3'
        assert user.implementation_version_name == b'VERSION_1'
        assert user.asynchronous_operations == (2, 3)

        roles = user.role_selection
        assert len(roles) == 2
        role = roles['1.2']
        assert role.scu_role is False
        assert role.scp_role is True

        classes = user.sop_class_extended
        assert len(classes) == 1
        assert classes['1.2.3'] == b'SOME DATA'

        classes = user.sop_class_common_extended
        assert len(classes) == 1
        assert classes['1.2.3'].service_class_uid == '2.3.4'
        assert classes['1.2.3'].related_general_sop_class_identification == [
            '1.3.4'
        ]

        item = user.user_identity
        assert item.user_identity_type == 0x01
        assert item.primary_field == b'username'

    def test_info(self):
        """Test the .info propoerty"""
        user = ServiceUser(self.assoc, mode='requestor')
        info = user.info

        assert info['port'] is None
        assert info['mode'] == 'requestor'
        assert info['address'] == ''
        assert info['ae_title'] == b''
        with pytest.raises(KeyError):
            info['pdv_size']

        user.primitive = self.primitive
        assert user.info['pdv_size'] == 16382

    def test_primitive_assignment_raises(self):
        """Test trying to set primitive parameters raises exception."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive

        assert user.primitive == self.primitive
        assert user.mode == 'requestor'

        msg = r"Can't set the Maximum Length after negotiation has started"
        with pytest.raises(RuntimeError, match=msg):
            user.maximum_length = 16382

        msg = (
            r"Can't set the Implementation Class UID after negotiation "
            r"has started"
        )
        with pytest.raises(RuntimeError, match=msg):
            user.implementation_class_uid = '1.2.3'

        msg = (
            r"Can't set the Implementation Version Name after negotiation "
            r"has started"
        )
        with pytest.raises(RuntimeError, match=msg):
            user.implementation_version_name = '1.2.3'

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.asynchronous_operations = (1, 1)

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.role_selection = {}

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.sop_class_common_extended = {}

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.sop_class_extended = {}

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.user_identity = 'test'

        with pytest.raises(AttributeError, match=r"can't set attribute"):
            user.extended_negotiation = []

    def test_accepted_common_raises(self):
        """Test trying to get the accepted common ext items raises."""
        user = ServiceUser(self.assoc, mode='requestor')

        msg = (
            r"'accepted_common_extended' is only available for the "
            r"'acceptor'"
        )
        with pytest.raises(RuntimeError, match=msg):
            user.accepted_common_extended()

    def test_add_neg_pre(self):
        """Test adding negotiation items."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[UserIdentityNegotiation]
        assert len(user.extended_negotiation) == 2
        assert len(user.user_information) == 4

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SCP_SCU_RoleSelectionNegotiation]
        assert len(user.extended_negotiation) == 3
        assert len(user.user_information) == 5

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SOPClassExtendedNegotiation]
        assert len(user.extended_negotiation) == 4
        assert len(user.user_information) == 6

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SOPClassCommonExtendedNegotiation]
        assert len(user.extended_negotiation) == 5
        assert len(user.user_information) == 7

    def test_add_neg_pre_raises(self):
        """Test that exception is raised if bad item added."""
        user = ServiceUser(self.assoc, mode='requestor')

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        bad = MaximumLengthNotification()
        bad.maximum_length_received = 12
        msg = r"'item' is not a valid extended negotiation item"
        with pytest.raises(TypeError, match=msg):
            user.add_negotiation_item(bad)

        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_add_neg_post_raises(self):
        """Test adding items after negotiation."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3

        msg = r"Can't add extended negotiation items after negotiation "
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

        assert item not in user.extended_negotiation
        assert item not in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

    def test_async_ops_pre(self):
        """Test getting async ops item prior to negotiation."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True
        assert user.asynchronous_operations == (1, 1)  # default
        assert user.extended_negotiation == []

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)

        assert user.asynchronous_operations == (2, 3)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_async_ops_post(self):
        """Test getting async ops item after negotiation."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False
        assert user.asynchronous_operations == (1, 1)  # default
        assert user.extended_negotiation == []

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        self.primitive.user_information.append(item)
        assert user.asynchronous_operations == (2, 3)
        assert user.extended_negotiation == [item]
        assert item in user.extended_negotiation
        assert item not in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_ext_neg_pre(self):
        """Test extended_negotiation only returns negotiation items."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True
        assert user.extended_negotiation == []
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)

        assert item in user.extended_negotiation
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_ext_neg_post(self):
        """Test extended_negotiation only returns negotiation items."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False
        assert user.extended_negotiation == []
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        self.primitive.user_information.append(item)

        assert item in user.extended_negotiation
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_get_contexts_pre(self):
        """Test get_contexts prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True

        cxs = user.get_contexts('requested')
        assert len(cxs) == 0

        user.requested_contexts = [build_context('1.2.840.10008.1.1')]
        cxs = user.get_contexts('requested')
        assert len(cxs) == 1
        assert cxs[0].abstract_syntax == '1.2.840.10008.1.1'

    def test_get_contexts_pre_raises(self):
        """Test get_contexts prior to association raises if bad type."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True

        msg = r"Invalid 'cx_type', must be 'requested'"
        with pytest.raises(ValueError, match=msg):
            user.get_contexts('supported')

    def test_get_contexts_post(self):
        """Test get_contexts after association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False

        cxs = user.get_contexts('requested')
        assert len(cxs) == 0

        cxs = user.get_contexts('pcdl')
        assert len(cxs) == 1
        assert cxs[0].abstract_syntax == '1.2.840.10008.1.1'

    def test_get_contexts_post_raises(self):
        """Test get_contexts after association raises if bad type."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False

        msg = r"Invalid 'cx_type', must be 'requested' or 'pcdl'"
        with pytest.raises(ValueError, match=msg):
            user.get_contexts('supported')

        with pytest.raises(ValueError, match=msg):
            user.get_contexts('pcdrl')

    def test_impl_class_pre(self):
        """Test implementation_class_uid prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True
        assert user.implementation_class_uid == PYNETDICOM_IMPLEMENTATION_UID
        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationClassUIDNotification):
                assert item.implementation_class_uid == (
                    PYNETDICOM_IMPLEMENTATION_UID
                )
                class_items.append(item)

        assert len(class_items) == 1

        user.implementation_class_uid = '1.2.3'
        assert user.implementation_class_uid == '1.2.3'
        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationClassUIDNotification):
                assert item.implementation_class_uid == (
                    '1.2.3'
                )
                class_items.append(item)

        assert len(class_items) == 1

    def test_impl_class_post(self):
        """Test implementation_class_uid after association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False
        assert user.implementation_class_uid == '1.2.3'

        msg = r"Can't set the Implementation Class UID after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.implementation_class_uid = '1.2.3.4'

        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationClassUIDNotification):
                assert item.implementation_class_uid == '1.2.3'
                class_items.append(item)

        assert len(class_items) == 1

    def test_impl_version_pre(self):
        """Test implementation_version_name prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True
        assert user.implementation_version_name is None

        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationVersionNameNotification):
                class_items.append(item)

        assert len(class_items) == 0

        ref = b'12345ABCDE123456'
        user.implementation_version_name = ref
        assert user.implementation_version_name == ref

        class_items = []
        user.implementation_version_name = ref
        for item in user.user_information:
            if isinstance(item, ImplementationVersionNameNotification):
                class_items.append(item)
                assert user.implementation_version_name == ref

        assert len(class_items) == 1

    def test_impl_version_post(self):
        """Test implementation_version_name after association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False
        assert user.implementation_version_name is None

        ref = b'12345ABCDE123456'
        msg = r"Can't set the Implementation Version Name after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.implementation_version_name = ref

        item = ImplementationVersionNameNotification()
        item.implementation_version_name = ref
        self.primitive.user_information.append(item)

        class_items = []
        for item in user.user_information:
            if isinstance(item, ImplementationVersionNameNotification):
                assert item.implementation_version_name == ref
                class_items.append(item)

        assert len(class_items) == 1

    def test_is_acceptor(self):
        """Test is_acceptor"""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.is_acceptor is False

    def test_is_requestor(self):
        """Test is_requestor"""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.is_requestor is True

    def test_max_length_pre(self):
        """Test maximum_length prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True

        assert user.maximum_length == 16382
        class_items = []
        for item in user.user_information:
            if isinstance(item, MaximumLengthNotification):
                assert item.maximum_length_received == 16382
                class_items.append(item)

        assert len(class_items) == 1

        user.maximum_length = 45
        assert user.maximum_length == 45
        class_items = []
        for item in user.user_information:
            if isinstance(item, MaximumLengthNotification):
                assert item.maximum_length_received == 45
                class_items.append(item)

        assert len(class_items) == 1

    def test_max_length_post(self):
        """Test maximum_length after association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False
        assert user.maximum_length == 16382

        msg = r"Can't set the Maximum Length after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.maximum_length = 45

        class_items = []
        for item in user.user_information:
            if isinstance(item, MaximumLengthNotification):
                assert item.maximum_length_received == 16382
                class_items.append(item)

        assert len(class_items) == 1

    def test_requested_cx_pre(self):
        """Test requested_contexts prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True
        assert user.requested_contexts == []

        cx_a = build_context('1.2.3')
        cx_b = build_context('1.2.3.4')
        user.requested_contexts = [cx_a, cx_b]

        assert len(user.requested_contexts) == 2
        assert cx_a in user.requested_contexts
        assert cx_b in user.requested_contexts

    def test_requested_cx_post(self):
        """Test requested_contexts after association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False
        assert user.requested_contexts == []

        cx_a = build_context('1.2.3')
        msg = r"Can't set the requested presentation contexts after"
        with pytest.raises(RuntimeError, match=msg):
            user.requested_contexts = [build_context('1.2.3')]

        assert user.requested_contexts == []

    def test_rm_neg_pre(self):
        """Test removing negotiation items."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3

        # Test removing non-existent item
        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Test removing existent item
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[AsynchronousOperationsWindowNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Repeat for UserIdentity
        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[UserIdentityNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Repeat for Role Selection
        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SCP_SCU_RoleSelectionNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Repeat for SOP Class Extended
        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SOPClassExtendedNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Repeat for SOP Class Common
        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SOPClassCommonExtendedNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        user.remove_negotiation_item(item)
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Try removing unknown type
        msg = r"'item' is not a valid extended negotiation item"
        with pytest.raises(TypeError, match=msg):
            user.remove_negotiation_item(1234)

    def test_rm_neg_post_raises(self):
        """Test adding items after negotiation."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        self.primitive.user_information.append(item)

        msg = r"Can't remove extended negotiation items after negotiation "
        with pytest.raises(RuntimeError, match=msg):
            user.remove_negotiation_item(item)

        assert item in user.extended_negotiation
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

    def test_reset_neg_pre(self):
        """Test reset_negotiation_items prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        # Test with no items
        user.reset_negotiation_items()
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.add_negotiation_item(item)

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.add_negotiation_item(item)

        assert len(user.extended_negotiation) == 5
        assert len(user.user_information) == 7

        user.reset_negotiation_items()
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert len(user._ext_neg.keys()) == 5

    def test_reset_neg_post_raises(self):
        """Test reset_negotiation_items after association raises."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.primitive.user_information.append(item)

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.primitive.user_information.append(item)

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.primitive.user_information.append(item)

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.primitive.user_information.append(item)

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.primitive.user_information.append(item)

        assert len(user.extended_negotiation) == 5
        assert len(user.user_information) == 7

        msg = r"Can't reset the extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.reset_negotiation_items()

        assert len(user.extended_negotiation) == 5
        assert len(user.user_information) == 7

    def test_role_pre(self):
        """Test role_selection prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.role_selection == {}

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SCP_SCU_RoleSelectionNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.role_selection['1.2.3'] == item

    def test_role_post(self):
        """Test role_selection prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.role_selection == {}

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.3'
        item.scu_role = True
        item.scp_role = True
        user.primitive.user_information.append(item)
        assert item in user.extended_negotiation
        assert item not in user._ext_neg[SCP_SCU_RoleSelectionNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.role_selection['1.2.3'] == item

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_sop_ext_pre(self):
        """Test sop_class_extended prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.sop_class_extended == {}

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SOPClassExtendedNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.sop_class_extended['1.2.3'] == (
            item.service_class_application_information
        )

    def test_sop_ext_post(self):
        """Test sop_class_extended prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.sop_class_extended == {}

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.primitive.user_information.append(item)
        assert item in user.extended_negotiation
        assert item not in user._ext_neg[SOPClassExtendedNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.sop_class_extended['1.2.3'] == (
            item.service_class_application_information
        )

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_sop_common_pre(self):
        """Test sop_class_common_extended prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.sop_class_common_extended == {}

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[SOPClassCommonExtendedNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.sop_class_common_extended['1.2.3'] == item

    def test_sop_common_post(self):
        """Test sop_class_common_extended prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.sop_class_common_extended == {}

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.primitive.user_information.append(item)
        assert item in user.extended_negotiation
        assert item not in user._ext_neg[SOPClassCommonExtendedNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.sop_class_common_extended['1.2.3'] == item

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_supported_cx_pre(self):
        """Test supported_contexts prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True

        msg = r"Invalid 'cx_type', must be 'requested'"
        with pytest.raises(ValueError, match=msg):
            assert user.supported_contexts == []

        msg = (
            r"'supported_contexts' can only be set for the association "
            r"acceptor"
        )
        with pytest.raises(AttributeError, match=msg):
            user.supported_contexts = 'bluh'

    def test_supported_cx_post(self):
        """Test supported_contexts after association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert user.writeable is False

        msg = r"Invalid 'cx_type', must be 'requested' or 'pcdl'"
        with pytest.raises(ValueError, match=msg):
            assert user.supported_contexts == []

    def test_user_id_pre(self):
        """Test user_identity prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.user_identity is None

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)
        assert item in user.extended_negotiation
        assert item in user._ext_neg[UserIdentityNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.user_identity == item

    def test_user_id_post(self):
        """Test user_identity prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert len(user.extended_negotiation) == 0
        assert len(user.user_information) == 2
        assert user.user_identity is None

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.primitive.user_information.append(item)
        assert item in user.extended_negotiation
        assert item not in user._ext_neg[UserIdentityNegotiation]
        assert len(user.extended_negotiation) == 1
        assert len(user.user_information) == 3

        assert user.user_identity == item

        msg = r"Can't add extended negotiation items after negotiation"
        with pytest.raises(RuntimeError, match=msg):
            user.add_negotiation_item(item)

    def test_user_info_pre(self):
        """Test user_information prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert len(user.user_information) == 2

        user.implementation_version_name = 'VERSION_1'
        item = user.user_information[2]
        assert isinstance(item, ImplementationVersionNameNotification)
        assert item.implementation_version_name == b'VERSION_1'
        assert len(user.user_information) == 3

        for uid in ['1.2', '3.4']:
            item = SCP_SCU_RoleSelectionNegotiation()
            item.sop_class_uid = uid
            item.scu_role = False
            item.scp_role = True
            user.add_negotiation_item(item)
            assert item in user.user_information

        assert len(user.user_information) == 5

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.add_negotiation_item(item)
        assert item in user.user_information
        assert len(user.user_information) == 6

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.add_negotiation_item(item)
        assert item in user.user_information
        assert len(user.user_information) == 7

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.add_negotiation_item(item)
        assert item in user.user_information
        assert len(user.user_information) == 8

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.add_negotiation_item(item)
        assert item in user.user_information
        assert len(user.user_information) == 9

    def test_user_info_post(self):
        """Test user_information prior to association."""
        user = ServiceUser(self.assoc, mode='requestor')
        user.primitive = self.primitive
        assert len(user.user_information) == 2

        item = ImplementationVersionNameNotification()
        item.implementation_version_name = 'VERSION_1'
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 3

        for uid in ['1.2', '3.4']:
            item = SCP_SCU_RoleSelectionNegotiation()
            item.sop_class_uid = uid
            item.scu_role = False
            item.scp_role = True
            user.primitive.user_information.append(item)
            assert item in user.user_information

        assert len(user.user_information) == 5

        item = AsynchronousOperationsWindowNegotiation()
        item.maximum_number_operations_invoked = 2
        item.maximum_number_operations_performed = 3
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 6

        item = UserIdentityNegotiation()
        item.user_identity_type = 0x01
        item.positive_response_requested = True
        item.primary_field = b'username'
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 7

        item = SOPClassExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_application_information = b'SOME DATA'
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 8

        item = SOPClassCommonExtendedNegotiation()
        item.sop_class_uid = '1.2.3'
        item.service_class_uid = '2.3.4'
        item.related_general_sop_class_identification = ['1.3.4']
        user.primitive.user_information.append(item)
        assert item in user.user_information
        assert len(user.user_information) == 9

    def test_writeable(self):
        """Test writeable."""
        user = ServiceUser(self.assoc, mode='requestor')
        assert user.writeable is True
        user.primitive = self.primitive
        assert user.writeable is False

Tests for association.AcceptorRequestor. #LOGGER.setLevel(logging.DEBUG) Tests for ServiceUser as acceptor. # Presentation Contexts # User Information items Test new ServiceUser as acceptor. Test bad mode raises exception. Test correct return if no class UID. Test correct reutrn if no maximum length. Test accepted_common_extended works correctly. Test that assignment works OK, Test that assigning mode after init raises exception. Test access with a miminal allowed A-ASSOCIATE (ac) primitive. Test access with a miminal allowed A-ASSOCIATE (rj) primitive. Test access with a maximum allowed A-ASSOCIATE primitive. Test the .info propoerty Test trying to set primitive parameters raises exception. Test adding negotiation items. Test that exception is raised if bad item added. Test adding items after negotiation. Test getting async ops item prior to negotiation. # default Test getting async ops item after negotiation. # default Test extended_negotiation only returns negotiation items. Test extended_negotiation only returns negotiation items. Test get_contexts prior to association. Test get_contexts prior to association raises if bad type. Test get_contexts after association. Test get_contexts after association raises if bad type. Test implementation_class_uid prior to association. Test implementation_class_uid after association. Test implementation_version_name prior to association. Test implementation_version_name after association. Test is_acceptor Test is_requestor Test maximum_length prior to association. Test maximum_length after association. Test requested_contexts prior to association. Test requested_contexts after association. Test removing negotiation items. # Test removing non-existent item # Test removing existent item # Repeat for UserIdentity # Repeat for Role Selection # Repeat for SOP Class Extended # Try removing unknown type Test adding items after negotiation. Test reset_negotiation_items prior to association. # Test with no items Test reset_negotiation_items after association raises. Test role_selection prior to association. Test role_selection prior to association. Test sop_class_extended prior to association. Test sop_class_extended prior to association. Test sop_class_common_extended prior to association. Test sop_class_common_extended prior to association. Test supported_contexts prior to association. Test supported_contexts after association. Test user_identity prior to association. Test user_identity prior to association. Test user_information prior to association. Test user_information prior to association. Test writeable. Tests for ServiceUser as requestor. # Presentation Contexts # User Information items Test new ServiceUser as requestor. Test that assignment works OK, Test that assigning mode after init raises exception. Test access with a miminal allowed A-ASSOCIATE primitive. Test access with a maximum allowed A-ASSOCIATE primitive. Test the .info propoerty Test trying to set primitive parameters raises exception. Test trying to get the accepted common ext items raises. Test adding negotiation items. Test that exception is raised if bad item added. Test adding items after negotiation. Test getting async ops item prior to negotiation. # default Test getting async ops item after negotiation. # default Test extended_negotiation only returns negotiation items. Test extended_negotiation only returns negotiation items. Test get_contexts prior to association. Test get_contexts prior to association raises if bad type. Test get_contexts after association. Test get_contexts after association raises if bad type. Test implementation_class_uid prior to association. Test implementation_class_uid after association. Test implementation_version_name prior to association. Test implementation_version_name after association. Test is_acceptor Test is_requestor Test maximum_length prior to association. Test maximum_length after association. Test requested_contexts prior to association. Test requested_contexts after association. Test removing negotiation items. # Test removing non-existent item # Test removing existent item # Repeat for UserIdentity # Repeat for Role Selection # Repeat for SOP Class Extended # Repeat for SOP Class Common # Try removing unknown type Test adding items after negotiation. Test reset_negotiation_items prior to association. # Test with no items Test reset_negotiation_items after association raises. Test role_selection prior to association. Test role_selection prior to association. Test sop_class_extended prior to association. Test sop_class_extended prior to association. Test sop_class_common_extended prior to association. Test sop_class_common_extended prior to association. Test supported_contexts prior to association. Test supported_contexts after association. Test user_identity prior to association. Test user_identity prior to association. Test user_information prior to association. Test user_information prior to association. Test writeable.