"""
Test cases for ldaptor.protocols.ldap.ldapfilter module.
"""

from twisted.trial import unittest
from ldaptor.protocols import pureldap
from ldaptor import ldapfilter


class RFC2254Examples(unittest.TestCase):
    def test_cn(self):
        text = '(cn=Babs Jensen)'
        filt = pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
            assertionValue=pureldap.LDAPAssertionValue(value='Babs Jensen'))
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_not_cn(self):
        text = '(!(cn=Tim Howes))'
        filt = pureldap.LDAPFilter_not(
            pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
            assertionValue=pureldap.LDAPAssertionValue(value='Tim Howes')))
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_and_or(self):
        text = '(&(objectClass=Person)(|(sn=Jensen)(cn=Babs J*)))'
        filt = pureldap.LDAPFilter_and(
            [ pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='objectClass'),
            assertionValue=pureldap.LDAPAssertionValue(value='Person')),
              pureldap.LDAPFilter_or([ pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='sn'),
            assertionValue=pureldap.LDAPAssertionValue(value='Jensen')),
                                       pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[ pureldap.LDAPFilter_substrings_initial(value='Babs J')
                         ])
                                       ]),
              ])
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_substrings(self):
        text = '(o=univ*of*mich*)'
        filt = pureldap.LDAPFilter_substrings(
            type='o',
            substrings=[ pureldap.LDAPFilter_substrings_initial(value='univ'),
                         pureldap.LDAPFilter_substrings_any(value='of'),
                         pureldap.LDAPFilter_substrings_any(value='mich'),
                         ])
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)


    def test_extensible_1(self):
        text = '(cn:1.2.3.4.5:=Fred Flintstone)'
        filt = pureldap.LDAPFilter_extensibleMatch(
            type='cn',
            dnAttributes=False,
            matchingRule='1.2.3.4.5',
            matchValue='Fred Flintstone',
            )
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_extensible_2(self):
        text = '(sn:dn:2.4.6.8.10:=Barney Rubble)'
        filt = pureldap.LDAPFilter_extensibleMatch(
            type='sn',
            dnAttributes=True,
            matchingRule='2.4.6.8.10',
            matchValue='Barney Rubble',
            )
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_extensible_3(self):
        text = '(o:dn:=Ace Industry)'
        filt = pureldap.LDAPFilter_extensibleMatch(
            type='o',
            dnAttributes=True,
            matchingRule=None,
            matchValue='Ace Industry',
            )
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_extensible_4(self):
        text = '(:dn:2.4.6.8.10:=Dino)'
        filt = pureldap.LDAPFilter_extensibleMatch(
            type=None,
            dnAttributes=True,
            matchingRule='2.4.6.8.10',
            matchValue='Dino',
            )
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_extensible_5(self):
        text = '(cn:1.2.3.4.5:=Fred Flintstone)'
        filt = pureldap.LDAPFilter_extensibleMatch(
            type='cn',
            dnAttributes=None,
            matchingRule='1.2.3.4.5',
            matchValue='Fred Flintstone',
            )
        self.assertEqual(filt.asText(), text)

    def test_escape_parens(self):
        text = r'(o=Parens R Us \28for all your parenthetical needs\29)'
        filt = pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='o'),
            assertionValue=pureldap.LDAPAssertionValue(value='Parens R Us (for all your parenthetical needs)'))
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_escape_asterisk(self):
        text = r'(cn=*\2A*)'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[ pureldap.LDAPFilter_substrings_any(value='*'),
                         ])
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text.lower())

    def test_escape_backslash(self):
        text = r'(filename=C:\5cMyFile)'
        filt = pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='filename'),
            assertionValue=pureldap.LDAPAssertionValue(value=r'C:\MyFile'))
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_escape_binary(self):
        text = r'(bin=\00\00\00\04)'
        filt = pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='bin'),
            assertionValue=pureldap.LDAPAssertionValue(value='\00\00\00\04'))
        self.assertEqual(ldapfilter.parseFilter(text), filt)

    def test_escape_utf8(self):
        text = r'(sn=Lu\c4\8di\c4\87)'
        filt = pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='sn'),
            assertionValue=pureldap.LDAPAssertionValue(value='Lu\xc4\x8di\xc4\x87'))
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        #self.assertEqual(filt.asText(), text)

class TestValid(unittest.TestCase):
    def test_item_present(self):
        text = r'(cn=*)'
        filt = pureldap.LDAPFilter_present(value='cn')
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_item_simple(self):
        text = r'(cn=foo)'
        filt = pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
            assertionValue=pureldap.LDAPAssertionValue(value='foo'))
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_item_substring_init(self):
        text = r'(cn=foo*)'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
                        ])
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_item_substring_final(self):
        text = r'(cn=*foo)'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_final('foo'),
                        ])
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_item_substring_any(self):
        text = r'(cn=*foo*)'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_any('foo'),
                        ])
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_item_substring_aa(self):
        text = r'(cn=*foo*bar*)'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_any('foo'),
                        pureldap.LDAPFilter_substrings_any('bar'),
                        ])
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_item_substring_ia(self):
        text = r'(cn=foo*bar*)'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
                        pureldap.LDAPFilter_substrings_any('bar'),
                        ])
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_item_substring_iaa(self):
        text = r'(cn=foo*bar*baz*)'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
                        pureldap.LDAPFilter_substrings_any('bar'),
                        pureldap.LDAPFilter_substrings_any('baz'),
                        ])
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_item_substring_if(self):
        text = r'(cn=foo*bar)'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
                        pureldap.LDAPFilter_substrings_final('bar'),
                        ])
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_item_substring_iaf(self):
        text = r'(cn=foo*bar*baz)'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
                        pureldap.LDAPFilter_substrings_any('bar'),
                        pureldap.LDAPFilter_substrings_final('baz'),
                        ])
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_item_substring_iaaf(self):
        text = r'(cn=foo*bar*baz*quux)'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
                        pureldap.LDAPFilter_substrings_any('bar'),
                        pureldap.LDAPFilter_substrings_any('baz'),
                        pureldap.LDAPFilter_substrings_final('quux'),
                        ])
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_item_substring_af(self):
        text = r'(cn=*foo*bar)'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_any('foo'),
                        pureldap.LDAPFilter_substrings_final('bar'),
                        ])
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_item_substring_aaf(self):
        text = r'(cn=*foo*bar*baz)'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_any('foo'),
                        pureldap.LDAPFilter_substrings_any('bar'),
                        pureldap.LDAPFilter_substrings_final('baz'),
                        ])
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_not_item(self):
        text = r'(!(cn=foo))'
        filt = pureldap.LDAPFilter_not(
            pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
            assertionValue=pureldap.LDAPAssertionValue(value='foo')))
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_or_item(self):
        text = r'(|(cn=foo)(cn=bar))'
        filt = pureldap.LDAPFilter_or([
            pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
            assertionValue=pureldap.LDAPAssertionValue(value='foo')),
            pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
            assertionValue=pureldap.LDAPAssertionValue(value='bar')),
            ])
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_and_item(self):
        text = r'(&(cn=foo)(cn=bar))'
        filt = pureldap.LDAPFilter_and([
            pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
            assertionValue=pureldap.LDAPAssertionValue(value='foo')),
            pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
            assertionValue=pureldap.LDAPAssertionValue(value='bar')),
            ])
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_andornot(self):
        text = r'(&(!(|(cn=foo)(cn=bar)))(sn=a*b*c*d))'
        filt = pureldap.LDAPFilter_and([
            pureldap.LDAPFilter_not(
            pureldap.LDAPFilter_or([
            pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
            assertionValue=pureldap.LDAPAssertionValue(value='foo')),
            pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
            assertionValue=pureldap.LDAPAssertionValue(value='bar')),
            ])),
            pureldap.LDAPFilter_substrings(
            type='sn',
            substrings=[pureldap.LDAPFilter_substrings_initial('a'),
                        pureldap.LDAPFilter_substrings_any('b'),
                        pureldap.LDAPFilter_substrings_any('c'),
                        pureldap.LDAPFilter_substrings_final('d'),
                        ])])
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

    def test_whitespace_beforeCloseParen(self):
        text = r'(cn=foo )'
        filt = pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
            assertionValue=pureldap.LDAPAssertionValue(value='foo '))
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)


    def test_whitespace_afterEq(self):
        text = r'(cn= foo)'
        filt = pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
            assertionValue=pureldap.LDAPAssertionValue(value=' foo'))
        self.assertEqual(ldapfilter.parseFilter(text), filt)
        self.assertEqual(filt.asText(), text)

class TestInvalid(unittest.TestCase):
    def test_closeParen_1(self):
        self.assertRaises(ldapfilter.InvalidLDAPFilter,
                          ldapfilter.parseFilter,
                          '(&(|(mail=)@*)(uid=)))(mail=*))')

    def test_closeParen_2(self):
        self.assertRaises(ldapfilter.InvalidLDAPFilter,
                          ldapfilter.parseFilter,
                          '(|(mail=)@*)(uid=)))')

    def test_closeParen_3(self):
        self.assertRaises(ldapfilter.InvalidLDAPFilter,
                          ldapfilter.parseFilter,
                          '(mail=)@*)')

    def test_closeParen_4(self):
        self.assertRaises(ldapfilter.InvalidLDAPFilter,
                          ldapfilter.parseFilter,
                          '(uid=))')


    def test_openParen_1(self):
        self.assertRaises(ldapfilter.InvalidLDAPFilter,
                          ldapfilter.parseFilter,
                          '(&(|(mail=(@*)(uid=())(mail=*))')

    def test_openParen_2(self):
        self.assertRaises(ldapfilter.InvalidLDAPFilter,
                          ldapfilter.parseFilter,
                          '(|(mail=(@*)(uid=())')

    def test_openParen_3(self):
        self.assertRaises(ldapfilter.InvalidLDAPFilter,
                          ldapfilter.parseFilter,
                          '(mail=(@*)')

    def test_openParen_4(self):
        self.assertRaises(ldapfilter.InvalidLDAPFilter,
                          ldapfilter.parseFilter,
                          '(uid=()')

    def test_whitespace_leading(self):
        self.assertRaises(ldapfilter.InvalidLDAPFilter,
                          ldapfilter.parseFilter,
                          r' (cn=foo)')

    def test_whitespace_trailing(self):
        self.assertRaises(ldapfilter.InvalidLDAPFilter,
                          ldapfilter.parseFilter,
                          r'(cn=foo) ')

    def test_whitespace_afterOpenParen(self):
        self.assertRaises(ldapfilter.InvalidLDAPFilter,
                          ldapfilter.parseFilter,
                          r'( cn=foo)')

    def test_whitespace_beforeEq(self):
        self.assertRaises(ldapfilter.InvalidLDAPFilter,
                          ldapfilter.parseFilter,
                          r'(cn =foo)')

class TestMaybeSubstring(unittest.TestCase):
    def test_item_present(self):
        text = r'*'
        filt = pureldap.LDAPFilter_present(value='cn')
        self.assertEqual(ldapfilter.parseMaybeSubstring('cn', text), filt)

    def test_item_simple(self):
        text = r'foo'
        filt = pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
            assertionValue=pureldap.LDAPAssertionValue(value='foo'))
        self.assertEqual(ldapfilter.parseMaybeSubstring('cn', text), filt)

    def test_item_substring_init(self):
        text = r'foo*'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
                        ])
        self.assertEqual(ldapfilter.parseMaybeSubstring('cn', text), filt)

    def test_item_substring_final(self):
        text = r'*foo'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_final('foo'),
                        ])
        self.assertEqual(ldapfilter.parseMaybeSubstring('cn', text), filt)

    def test_item_substring_any(self):
        text = r'*foo*'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_any('foo'),
                        ])
        self.assertEqual(ldapfilter.parseMaybeSubstring('cn', text), filt)

    def test_item_substring_aa(self):
        text = r'*foo*bar*'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_any('foo'),
                        pureldap.LDAPFilter_substrings_any('bar'),
                        ])
        self.assertEqual(ldapfilter.parseMaybeSubstring('cn', text), filt)

    def test_item_substring_ia(self):
        text = r'foo*bar*'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
                        pureldap.LDAPFilter_substrings_any('bar'),
                        ])
        self.assertEqual(ldapfilter.parseMaybeSubstring('cn', text), filt)

    def test_item_substring_iaa(self):
        text = r'foo*bar*baz*'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
                        pureldap.LDAPFilter_substrings_any('bar'),
                        pureldap.LDAPFilter_substrings_any('baz'),
                        ])
        self.assertEqual(ldapfilter.parseMaybeSubstring('cn', text), filt)

    def test_item_substring_if(self):
        text = r'foo*bar'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
                        pureldap.LDAPFilter_substrings_final('bar'),
                        ])
        self.assertEqual(ldapfilter.parseMaybeSubstring('cn', text), filt)

    def test_item_substring_iaf(self):
        text = r'foo*bar*baz'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
                        pureldap.LDAPFilter_substrings_any('bar'),
                        pureldap.LDAPFilter_substrings_final('baz'),
                        ])
        self.assertEqual(ldapfilter.parseMaybeSubstring('cn', text), filt)

    def test_item_substring_iaaf(self):
        text = r'foo*bar*baz*quux'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_initial('foo'),
                        pureldap.LDAPFilter_substrings_any('bar'),
                        pureldap.LDAPFilter_substrings_any('baz'),
                        pureldap.LDAPFilter_substrings_final('quux'),
                        ])
        self.assertEqual(ldapfilter.parseMaybeSubstring('cn', text), filt)

    def test_item_substring_af(self):
        text = r'*foo*bar'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_any('foo'),
                        pureldap.LDAPFilter_substrings_final('bar'),
                        ])
        self.assertEqual(ldapfilter.parseMaybeSubstring('cn', text), filt)

    def test_item_substring_aaf(self):
        text = r'*foo*bar*baz'
        filt = pureldap.LDAPFilter_substrings(
            type='cn',
            substrings=[pureldap.LDAPFilter_substrings_any('foo'),
                        pureldap.LDAPFilter_substrings_any('bar'),
                        pureldap.LDAPFilter_substrings_final('baz'),
                        ])
        self.assertEqual(ldapfilter.parseMaybeSubstring('cn', text), filt)

    def test_escape_simple(self):
        text = r'f\2aoo(bar'
        filt = pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
            assertionValue=pureldap.LDAPAssertionValue(value='f*oo(bar'))
        self.assertEqual(ldapfilter.parseMaybeSubstring('cn', text), filt)

class TestWhitespace(unittest.TestCase):
    def test_escape(self):
        self.assertRaises(ldapfilter.InvalidLDAPFilter,
                          ldapfilter.parseFilter,
                          r'(cn=\ 61)')
