import pytest
from collections import OrderedDict
from calculate.templates.format.ldap_format import LDAPFormat


@pytest.mark.ldap
class TestParsingMethods:
    def test_if_logiclines_method_takes_text_with_lines_that_starts_whit_space_symbols__it_returns_joined_lines(self):
        with open(
                './tests/templates/format/testfiles/ldap/logic_lines_test.txt',
                'r') as input_file:
            input_text = input_file.read()

        output_lines = ['First string of test file.',
                        'Second string of test file.',
                        'Third string of test file.',
                        'Fourth string of test file.']

        ldap_object = LDAPFormat('', '/path/to/template')
        input_lines = ldap_object._get_list_of_logic_lines(input_text)
        assert input_lines == output_lines

    def test_if_input_doc_contains_some_type_sections_with_plain_directives__object_dictionary_contains_correct_dictionary_with_directives_values_and_comments(self):
        document_text = '''
include		/etc/openldap/schema/samba.schema
include		/etc/openldap/schema/mail.schema

loglevel	0
allow		bind_v2
modulepath	/usr/lib/openldap/openldap

database	bdb

checkpoint	1024    5
suffix		"dc=calculate"
cachesize	10000
sizelimit	unlimited
directory	/var/lib/openldap-data
rootdn		"cn=ldaproot,dc=calculate"'''

        global_section = OrderedDict({'#': [],
                                     ('', 'include',
                                      '/etc/openldap/schema/samba.schema'):
                                     [''],
                                     ('', 'include',
                                      '/etc/openldap/schema/mail.schema'):
                                     [''],
                                     ('', 'loglevel'): ['0'],
                                     ('', 'allow'): ['bind_v2'],
                                     ('', 'modulepath'):
                                     ['/usr/lib/openldap/openldap']})

        database_section = OrderedDict({('', 'checkpoint'): ['1024    5'],
                                       ('', 'suffix'): ['"dc=calculate"'],
                                       ('', 'cachesize'): ['10000'],
                                       ('', 'sizelimit'): ['unlimited'],
                                       ('', 'directory'):
                                       ['/var/lib/openldap-data'],
                                       ('', 'rootdn'):
                                       ['"cn=ldaproot,dc=calculate"']})

        result = OrderedDict({('', 'global'): global_section,
                              ('', 'database', 'bdb'): database_section})

        ldap_object = LDAPFormat(document_text, '/path/to/template')
        assert ldap_object._document_dictionary == result

    def test_if_input_document_contains_access_to_directive__the_object_s_dictionary_contains_correct_dictionary_with_list_of_access_to_parameters_and_comments(self):
        document_text = '''
database	bdb
# Comment1
# Comment2
access to attrs=userPassword
    by dn="cn=ldapadmin,dc=calculate" write
    by dn="ou=Samba,ou=Services,dc=calculate" write
    by self read
    by * auth

# Comment3
access to * by * read
            '''
        access_1 = OrderedDict({'#': ['# Comment1', '# Comment2'],
                               ('', '*'):
                               ['auth'],
                               ('', 'self'):
                               ['read'],
                               ('', 'dn="ou=Samba,ou=Services,dc=calculate"'):
                               ['write'],
                               ('', 'dn="cn=ldapadmin,dc=calculate"'):
                               ['write']})

        access_2 = OrderedDict({'#': ['# Comment3'],
                               ('', '*'): ['read']})

        database_section = OrderedDict({('', 'access to',
                                         'attrs=userPassword'):
                                       access_1,
                                       ('', 'access to', '*'):
                                       access_2})

        result = OrderedDict({('', 'global'): OrderedDict(),
                              ('', 'database', 'bdb'): database_section})

        ldap_object = LDAPFormat(document_text, '/path/to/template')
        assert ldap_object._document_dictionary == result

    def test_if_input_document_contains_syncrepl_directive__the_object_s_dictionary_contains_correct_dictionary_with_list_of_syncrepl_parameters_and_comments(self):
        document_text = '''
# Comment1
# Comment2
syncrepl rid=123
    provider=ldap://provider.example.com:389
    type=refreshOnly
    interval=01:00:00:00
    searchbase="dc=example,dc=com"
            '''

        syncrepl_dictionary = OrderedDict({('', 'provider'):
                                          ['ldap://provider.example.com:389'],
                                          ('', 'type'):
                                          ['refreshOnly'],
                                          ('', 'interval'):
                                          ['01:00:00:00'],
                                          ('', 'searchbase'):
                                          ['"dc=example,dc=com"']})

        global_section = OrderedDict({'#': ['# Comment1', '# Comment2'],
                                     ('', 'syncrepl', 'rid=123'):
                                     syncrepl_dictionary})

        result = OrderedDict({('', 'global'): global_section})

        ldap_object = LDAPFormat(document_text, '/path/to/template')
        assert ldap_object._document_dictionary == result

    def test_if_input_document_contains_index_directives__the_object_s_dictionary_contains_correct_dictionary_with_index_elements_and_comments(self):
        document_text = '''
# Comment for global

index	objectClass	eq
# Comment for index
index	cn		pres,sub,eq
index	sn		pres,sub,eq
index	uid		pres,sub,eq

database	bdb
# Comment1
# Comment2
index	uidNumber	eq
index	gidNumber	eq
index	default		sub'''

        global_section = OrderedDict({'#': ['# Comment for global'],
                                     ('', 'index', 'objectClass'): ['eq'],
                                     ('', 'index', 'cn'):
                                     ['# Comment for index', 'pres,sub,eq'],
                                     ('', 'index', 'sn'): ['pres,sub,eq'],
                                     ('', 'index', 'uid'): ['pres,sub,eq']})

        database_section = OrderedDict({('', 'index', 'uidNumber'):
                                       ['# Comment1', '# Comment2', 'eq'],
                                       ('', 'index', 'gidNumber'): ['eq'],
                                       ('', 'index', 'default'): ['sub']})

        result = OrderedDict({('', 'global'): global_section,
                              ('', 'database', 'bdb'): database_section})

        ldap_object = LDAPFormat(document_text, '/path/to/template')
        assert ldap_object._document_dictionary == result

    def test_if_input_document_contains_comments_to_type_sections__the_object_s_dictionary_collect_them(self):
        document_text = '''
# Comment1
loglevel	0
allow		bind_v2
modulepath	/usr/lib/openldap/openldap

# Comment2
database	bdb
# Comment3
checkpoint	1024    5
suffix		"dc=calculate"
cachesize	10000'''

        global_section = OrderedDict({'#': ['# Comment1'],
                                     ('', 'loglevel'): ['0'],
                                     ('', 'allow'): ['bind_v2'],
                                     ('', 'modulepath'):
                                     ['/usr/lib/openldap/openldap']})

        database_section = OrderedDict({'#': ['# Comment2'],
                                       ('', 'checkpoint'):
                                       ['# Comment3',
                                        '1024    5'],
                                       ('', 'suffix'): ['"dc=calculate"'],
                                       ('', 'cachesize'): ['10000']})

        result = OrderedDict({('', 'global'): global_section,
                              ('', 'database', 'bdb'): database_section})

        ldap_object = LDAPFormat(document_text, '/path/to/template')
        assert ldap_object._document_dictionary == result

    def test_if_input_doc_contains_some_type_sections_with_plain_directives_and_action_marks__object_dictionary_contains_correct_dictionary_with_directives_values_and_comments(self):
        document_text = '''
!include		/etc/openldap/schema/samba.schema
-include		/etc/openldap/schema/mail.schema

-backend hdb
modulepath	/usr/lib/openldap/openldap

!database	bdb

checkpoint	1024    5
!directory	/var/lib/openldap-data
!rootdn
-allow

# Comment1
!index	uidNumber	eq
-index	gidNumber	eq

# Comment for index
!index	cn
!index	sn

'''

        global_section = OrderedDict({'#': [],
                                     ('!', 'include',
                                      '/etc/openldap/schema/samba.schema'):
                                     [''],
                                     ('-', 'include',
                                      '/etc/openldap/schema/mail.schema'):
                                     ['']})

        backend_section = OrderedDict({('', 'modulepath'):
                                       ['/usr/lib/openldap/openldap']})

        database_section = OrderedDict({('', 'checkpoint'): ['1024    5'],
                                       ('!', 'directory'):
                                       ['/var/lib/openldap-data'],
                                       ('!', 'rootdn'): [],
                                       ('!', 'index', 'uidNumber'):
                                       ['# Comment1', 'eq'],
                                       ('-', 'index', 'gidNumber'): ['eq'],
                                       ('!', 'index', 'cn'):
                                       ['# Comment for index'],
                                       ('!', 'index', 'sn'):
                                       []})

        result = OrderedDict({('', 'global'): global_section,
                              ('-', 'backend', 'hdb'): backend_section,
                              ('!', 'database', 'bdb'): database_section})

        ldap_object = LDAPFormat(document_text, '/path/to/template')
        assert ldap_object._document_dictionary == result

    def test_if_template_text_contains_some_access_to_constuctions_with_same_what_value_and_without_action_marks_for_whole_constructions__they_join_in_one_access_to_construction(self):
        document_text = '''
# Unix
access to attrs=sambaLMPassword,sambaNTPassword
    by dn="ou=Unix,ou=Services,dc=calculate" write

# Newval
access to attrs=sambaLMPassword,sambaNTPassword
    by dn="cn=newval, dc=calculate" read

# Mail
access to attrs=sambaLMPassword,sambaNTPassword
    by dn="ou=Mail,ou=Services,dc=calculate" read

# Jabber
access to attrs=sambaLMPassword,sambaNTPassword
    by dn="ou=Jabber,ou=Services,dc=calculate" read
        '''

        access = OrderedDict({('', 'dn="ou=Unix,ou=Services,dc=calculate"'):
                              ['write'],
                              ('', 'dn="cn=newval, dc=calculate"'):
                              ['read'],
                              ('', 'dn="ou=Mail,ou=Services,dc=calculate"'):
                              ['read'],
                              ('', 'dn="ou=Jabber,ou=Services,dc=calculate"'):
                              ['read']})

        global_section = OrderedDict({('', 'access to',
                                      'attrs=sambaLMPassword,sambaNTPassword'):
                                      access})

        result = OrderedDict({('', 'global'): global_section})

        ldap_object = LDAPFormat(document_text, '/path/to/template',
                                 ignore_comments=True)
        assert ldap_object._document_dictionary == result

    def test_if_input_document_contains_syncrepl_and_access_to_constructions_with_action_marks__object_dictionary_contains_correct_dictionary_with_action_marks(self):
        document_text = '''
# Comment
!syncrepl rid=123
    provider=ldap://provider.example.com:389
    type=refreshOnly
    interval=01:00:00:00
    searchbase="dc=example,dc=com"

# Comment1
!syncrepl rid=001

database	bdb
# Comment2
!access to attrs=userPassword
    by dn="cn=ldapadmin,dc=calculate" write
    by !dn="ou=Samba,ou=Services,dc=calculate" write
    by self read
    by * auth

# Comment3
!access to dn.base="cn=proxyuser,dc=calculate"
'''

        access_1 = OrderedDict({'#': ['# Comment2'],
                               ('', '*'):
                               ['auth'],
                               ('', 'self'):
                               ['read'],
                               ('!', 'dn="ou=Samba,ou=Services,dc=calculate"'):
                               ['write'],
                               ('', 'dn="cn=ldapadmin,dc=calculate"'):
                               ['write']})

        syncrepl_dictionary = OrderedDict({('', 'provider'):
                                          ['ldap://provider.example.com:389'],
                                          ('', 'type'):
                                          ['refreshOnly'],
                                          ('', 'interval'):
                                          ['01:00:00:00'],
                                          ('', 'searchbase'):
                                          ['"dc=example,dc=com"']})

        global_section = OrderedDict({'#': ['# Comment'],
                                     ('!', 'syncrepl', 'rid=123'):
                                     syncrepl_dictionary,
                                     ('!', 'syncrepl', 'rid=001'):
                                     OrderedDict({'#': ['# Comment1']})})

        database_section = OrderedDict({('!', 'access to',
                                         'attrs=userPassword'):
                                       access_1,
                                       ('!', 'access to',
                                        'dn.base="cn=proxyuser,dc=calculate"'):
                                       OrderedDict({'#': ['# Comment3']})})

        result = OrderedDict({('', 'global'): global_section,
                              ('', 'database', 'bdb'): database_section})

        ldap_object = LDAPFormat(document_text, '/path/to/template')
        assert ldap_object._document_dictionary == result

    def test_joining_documents_1(self):
        with open('./tests/templates/format/testfiles/ldap/original.conf',
                  'r') as original_file:
            original_text = original_file.read()
            ldap_original_object = LDAPFormat(original_text,
                                              '/path/to/template')

        with open('./tests/templates/format/testfiles/ldap/template.conf',
                  'r') as template_file:
            template_text = template_file.read()
            ldap_template_object = LDAPFormat(template_text,
                                              '/path/to/template',
                                              ignore_comments=True)

        ldap_original_object.join_template(ldap_template_object)

        with open('./tests/templates/format/testfiles/ldap/result.conf',
                  'r') as result_file:
            result_text = result_file.read()

        assert ldap_original_object.document_text == result_text

    def test_if_input_documents_are_an_original_document_without_calculate_header_and_a_template_and_the_add_header_flag_is_set__the_format_object_joins_an_original_document_and_a_template_and_adds_the_calculate_header(self):
        original_text = '''
include		/etc/openldap/schema/mail.schema

loglevel	0
allow		bind_v2
modulepath	/usr/lib/openldap/openldap

database	bdb

checkpoint	1024    5
suffix		"dc=calculate"
'''

        template_text = '''
!include		/etc/openldap/schema/mail.schema
database	bdb
!suffix		"dc=calculate"
'''

        join_result = '''#-------------------------------------------------------------------------------
# Modified by Calculate Utilities 4.0
# Processed template files:
# /path/to/template
#-------------------------------------------------------------------------------
loglevel    0
allow    bind_v2
modulepath    /usr/lib/openldap/openldap

database bdb
checkpoint    1024    5

'''

        original_object = LDAPFormat(original_text, '/path/to/template',
                                     add_header=True)
        template_object = LDAPFormat(template_text, '/path/to/template')
        original_object.join_template(template_object)
        assert original_object.document_text == join_result

    def test_if_input_documents_are_an_original_document_with_calculate_header_and_a_template_the_add_header_flag_is_set_and_the_already_changed_flag_is_not_set__the_format_object_removes_calculate_header_from_original_document__joins_an_original_document_and_a_template_and_adds_the_calculate_header(self):
        original_text = '''#-------------------------------------------------------------------------------
# Modified by Calculate Utilities 4.0
# Processed template files:
# /path/to/ancient/template
#-------------------------------------------------------------------------------
include		/etc/openldap/schema/mail.schema

loglevel	0
allow		bind_v2
modulepath	/usr/lib/openldap/openldap

database	bdb

checkpoint	1024    5
suffix		"dc=calculate"
'''

        template_text = '''
!include		/etc/openldap/schema/mail.schema
database	bdb
!suffix		"dc=calculate"
'''

        join_result = '''#-------------------------------------------------------------------------------
# Modified by Calculate Utilities 4.0
# Processed template files:
# /path/to/template
#-------------------------------------------------------------------------------
loglevel    0
allow    bind_v2
modulepath    /usr/lib/openldap/openldap

database bdb
checkpoint    1024    5

'''

        original_object = LDAPFormat(original_text, '/path/to/template',
                                     add_header=True)
        template_object = LDAPFormat(template_text, '/path/to/template')
        original_object.join_template(template_object)
        assert original_object.document_text == join_result

    def test_if_input_documents_are_an_original_document_with_calculate_header_and_a_template_the_add_header_flag_is_set_and_the_already_changed_flag_is_set__the_format_object_joins_an_original_document_and_a_template_and_adds_the_calculate_header_with_a_template_paths_from_the_old_header_and_paths_to_a_current_template(self):
        original_text = '''#-------------------------------------------------------------------------------
# Modified by Calculate Utilities 4.0
# Processed template files:
# /path/to/ancient/template
#-------------------------------------------------------------------------------
include		/etc/openldap/schema/mail.schema

loglevel	0
allow		bind_v2
modulepath	/usr/lib/openldap/openldap

database	bdb

checkpoint	1024    5
suffix		"dc=calculate"
'''

        template_text = '''
!include		/etc/openldap/schema/mail.schema
database	bdb
!suffix		"dc=calculate"
'''

        join_result = '''#-------------------------------------------------------------------------------
# Modified by Calculate Utilities 4.0
# Processed template files:
# /path/to/ancient/template
# /path/to/template
#-------------------------------------------------------------------------------
loglevel    0
allow    bind_v2
modulepath    /usr/lib/openldap/openldap

database bdb
checkpoint    1024    5

'''

        original_object = LDAPFormat(original_text, '/path/to/template',
                                     add_header=True, already_changed=True)
        template_object = LDAPFormat(template_text, '/path/to/template')
        original_object.join_template(template_object)
        print(original_object.document_text)
        assert original_object.document_text == join_result
