import pytest
from collections import OrderedDict
from calculate.templates.format.dovecot_format import DovecotFormat


@pytest.mark.dovecot
class TestParsingMethods:
    def test_if_input_document_contains_just_few_parameter_lines__the_initialised_object_contains_correct_dictionary(self):
        document_text = '''auth_default_realm = domain.com
        auth_mechanisms = plain login

        !include conf.d/imap.conf
        !include_try passwords.conf

        auth_realms = domain.com domain2.com
        '''

        result = OrderedDict({('', 'auth_default_realm'):
                              ['domain.com'],
                              ('', 'auth_mechanisms'):
                              ['plain login'],
                              ('', '!include', 'conf.d/imap.conf'):
                              [''],
                              ('', '!include_try', 'passwords.conf'):
                              [''],
                              ('', 'auth_realms'):
                              ['domain.com domain2.com']
                              })

        dovecot_object = DovecotFormat(document_text, '/path/to/template')
        assert dovecot_object._document_dictionary == result

    def test_if_input_document_contains_some_block_of_parameters__the_initialised_object_contains_correct_dictionary(self):
        document_text = '''
    section optional_name {
        section_setting_key = section_setting_value
        subsection optional_subname {
            subkey = subvalue
        }
    }

    local 127.0.0.2 {
        key = 127.0.0.2
    }
        '''
        subsection = OrderedDict({('', 'subkey'): ['subvalue']})
        section = OrderedDict({('', 'section_setting_key'):
                               ['section_setting_value'],
                               ('', 'subsection', 'optional_subname'):
                               subsection})
        local = OrderedDict({('', 'key'): ['127.0.0.2']})
        result = OrderedDict({('', 'section', 'optional_name'):
                              section,
                              ('', 'local', '127.0.0.2'):
                              local})

        dovecot_object = DovecotFormat(document_text, '/path/to/template')
        assert dovecot_object._document_dictionary == result

    def test_if_input_document_contains_some_blocks_with_similar_names__the_blocks_join_recursively(self):
        document_text = '''
    section optional_name {
        section_setting_key = section_setting_value
        subsection optional_subname {
            subkey = subvalue
        }
    }

    local 127.0.0.2 {
        key = 127.0.0.2
    }

    section optional_name {
        subsection optional_subname {
            otherkey = value
        }
    }

    local 127.0.0.2 {
        key = 127.0.0.2
        subsect name {
            param = no
        }
    }
    '''

        subsection = OrderedDict({('', 'subkey'): ['subvalue'],
                                  ('', 'otherkey'): ['value']})
        section = OrderedDict({('', 'section_setting_key'):
                               ['section_setting_value'],
                               ('', 'subsection', 'optional_subname'):
                               subsection})
        sub_sect = OrderedDict({('', 'param'): ['no']})
        local = OrderedDict({('', 'key'): ['127.0.0.2'],
                             ('', 'subsect', 'name'): sub_sect})
        result = OrderedDict({('', 'section', 'optional_name'):
                              section,
                              ('', 'local', '127.0.0.2'):
                              local})

        dovecot_object = DovecotFormat(document_text, '/path/to/template')
        assert dovecot_object._document_dictionary == result

    def test_if_input_document_contains_blocks_and_parameters_with_action_marks__the_key_tuples_of_object_s_dictionary_have_it_as_its_first_element(self):
        document_text = '''
    !auth_mechanisms = plain login

    !!include conf.d/imap.conf

    section optional_name {
        !section_setting_key = section_setting_value
        -subsection optional_subname {
            subkey = subvalue
        }
    }

    !local 127.0.0.2 {
        key = 127.0.0.2
    }
        '''

        subsection = OrderedDict({('', 'subkey'): ['subvalue']})
        section = OrderedDict({('!', 'section_setting_key'):
                               ['section_setting_value'],
                               ('-', 'subsection', 'optional_subname'):
                               subsection})
        local = OrderedDict({('', 'key'): ['127.0.0.2']})
        result = OrderedDict({('!', 'auth_mechanisms'):
                              ['plain login'],
                              ('!', '!include', 'conf.d/imap.conf'):
                              [''],
                              ('', 'section', 'optional_name'):
                              section,
                              ('!', 'local', '127.0.0.2'):
                              local})

        dovecot_object = DovecotFormat(document_text, '/path/to/template')
        assert dovecot_object._document_dictionary == result

    def test_if_parameters_and_blocks_in_input_document_has_some_comments__the_comments_will_be_collected_in_the_list_of_parameter_value_or_with_special_key_in_block_dictionary(self):
        document_text = '''
    # Comment 1
    auth_mechanisms = plain login

    # Comment 2
    !include conf.d/imap.conf

    # Comment 3
    section optional_name {
        section_setting_key = section_setting_value
        # Comment in the block.
        subsection optional_subname {
            # Comment
            subkey = subvalue
        }
    }
        '''

        subsection = OrderedDict({'#': ['# Comment in the block.'],
                                  ('', 'subkey'): ['# Comment', 'subvalue']})
        section = OrderedDict({'#': ['# Comment 3'],
                               ('', 'section_setting_key'):
                               ['section_setting_value'],
                               ('', 'subsection', 'optional_subname'):
                               subsection})
        result = OrderedDict({('', 'auth_mechanisms'):
                              ['# Comment 1', 'plain login'],
                              ('', '!include', 'conf.d/imap.conf'):
                              ['# Comment 2', ''],
                              ('', 'section', 'optional_name'):
                              section})

        dovecot_object = DovecotFormat(document_text, '/path/to/template')
        assert dovecot_object._document_dictionary == result

    def test_if_the_IgnoreComments_flag_is_set__the_parser_ignores_all_comments(self):
        document_text = '''
    # Comment 1
    auth_mechanisms = plain login

    # Comment 2
    !include conf.d/imap.conf

    # Comment 3
    section optional_name {
        section_setting_key = section_setting_value
        # Comment in the block.
        subsection optional_subname {
            # Comment
            subkey = subvalue
        }
    }
        '''

        subsection = OrderedDict({('', 'subkey'): ['subvalue']})
        section = OrderedDict({('', 'section_setting_key'):
                               ['section_setting_value'],
                               ('', 'subsection', 'optional_subname'):
                               subsection})
        result = OrderedDict({('', 'auth_mechanisms'):
                              ['plain login'],
                              ('', '!include', 'conf.d/imap.conf'):
                              [''],
                              ('', 'section', 'optional_name'):
                              section})

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

    def test_if_input_document_contains_parameters_to_delete_without_values_or_with_empty_block__the_document_object_contains_dictionary_with_item_to_delete(self):
        document_text = '''
    !auth_mechanisms
    !auth_realms =

    section optional_name {
        !section_setting_key
        !subsection optional_subname {
        }
    }

    !local 127.0.0.2 {
    }
        '''

        section = OrderedDict({('!', 'section_setting_key'): [''],
                               ('!', 'subsection', 'optional_subname'):
                               OrderedDict()})
        result = OrderedDict({('!', 'auth_mechanisms'):
                              [''],
                              ('!', 'auth_realms'):
                              [''],
                              ('', 'section', 'optional_name'):
                              section,
                              ('!', 'local', '127.0.0.2'):
                              OrderedDict()})

        dovecot_object = DovecotFormat(document_text, '/path/to/template')
        assert dovecot_object._document_dictionary == result

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

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

        dovecot_original_object.join_template(dovecot_template_object)

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

        assert dovecot_original_object.document_text == result_text

    def test_make_template(self):
        document_1 = '''auth_default_realm = domain.com
auth_mechanisms = plain login
# Log unsuccessful authentication attempts and the reasons why they failed.
auth_verbose = no

dict {
acl = mysql:/usr/local/etc/dovecot/shared-folders.conf
}

namespace inbox {
  # These mailboxes are widely used and could perhaps be created automatically:
  mailbox Drafts {
    special_use = \\Drafts
  }
}

!include auth-passwdfile.conf.ext'''

        document_2 = '''auth_realms = domain.com domain2.com

auth_verbose_passwords = no

auth_default_realm = other_domain.com

# Log unsuccessful authentication attempts and the reasons why they failed.
auth_verbose = yes

dict {
    acl = mysql:/etc/dovecot/shared-folders.conf

    sqlquota = mysql:/usr/local/etc/dovecot/quota.conf
}

namespace inbox {
    # These mailboxes are widely used and could perhaps be created automatically:
    mailbox Drafts {
        special_use = \\Drafts
    }

    mailbox Junk {
        special_use = \\Junk
    }
}
!include auth-checkpassword.conf.ext

'''

        document_1_object = DovecotFormat(document_1, '/path/to/template',
                                          join_before=True)
        document_2_object = DovecotFormat(document_2, '/path/to/template')
        template = document_1_object.make_template(document_2_object)
        document_1_object.join_template(template)
        assert document_1_object.document_text == document_2

    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 = '''
section optional_name {
    section_setting_key = section_setting_value
    subsection optional_subname {
        subkey = subvalue
    }
}
'''

        template_text = '''
section optional_name {
    !section_setting_key
}
'''

        join_result = '''#-------------------------------------------------------------------------------
# Modified by Calculate Utilities 4.0
# Processed template files:
# /path/to/template
#-------------------------------------------------------------------------------
section optional_name {
    subsection optional_subname {
        subkey = subvalue
    }
}
'''

        original_object = DovecotFormat(original_text, '/path/to/template',
                                        add_header=True)
        template_object = DovecotFormat(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
#-------------------------------------------------------------------------------
section optional_name {
    section_setting_key = section_setting_value
    subsection optional_subname {
        subkey = subvalue
    }
}
'''

        template_text = '''
section optional_name {
    !section_setting_key
}
'''

        join_result = '''#-------------------------------------------------------------------------------
# Modified by Calculate Utilities 4.0
# Processed template files:
# /path/to/template
#-------------------------------------------------------------------------------
section optional_name {
    subsection optional_subname {
        subkey = subvalue
    }
}
'''

        original_object = DovecotFormat(original_text, '/path/to/template',
                                        add_header=True)
        template_object = DovecotFormat(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
#-------------------------------------------------------------------------------
section optional_name {
    section_setting_key = section_setting_value
    subsection optional_subname {
        subkey = subvalue
    }
}
'''

        template_text = '''
section optional_name {
    !section_setting_key
    subsection optional_subname {
        subkey = subvalue
    }
}
'''

        join_result = '''#-------------------------------------------------------------------------------
# Modified by Calculate Utilities 4.0
# Processed template files:
# /path/to/ancient/template
# /path/to/template
#-------------------------------------------------------------------------------
section optional_name {
    subsection optional_subname {
        subkey = subvalue
    }
}
'''

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