def test_apply_modes_channel_add_remove(self): c = self.p.channels['#'] = Channel(self.p, name='#') self.p.apply_modes('#', [('+i', None)]) self.assertEqual(c.modes, {('i', None)}) self.p.apply_modes('#', [('+n', None), ('-i', None)]) self.assertEqual(c.modes, {('n', None)}) c = self.p.channels['#Magic'] = Channel(self.p, name='#Magic') self.p.apply_modes('#Magic', [('+m', None), ('+n', None), ('+i', None)]) self.assertEqual(c.modes, {('m', None), ('n', None), ('i', None)}, "Modes should be added") self.p.apply_modes('#Magic', [('-i', None), ('-n', None)]) self.assertEqual(c.modes, {('m', None)}, "Modes should be removed")
def test_apply_modes_channel_remove_nonexistent(self): c = self.p.channels['#abc'] = Channel(self.p, name='#abc') self.p.apply_modes('#abc', [('+t', None)]) self.assertEqual(c.modes, {('t', None)}) self.p.apply_modes('#abc', [('-n', None), ('-i', None)]) self.assertEqual(c.modes, {('t', None)})
def test_parse_modes_channel_rfc(self): # These are basic tests that only use RFC 1459 defined modes. # IRCds supporting more complex modes can define new test cases if needed. u = self._make_user('testuser', uid='100') c = self.p.channels['#testruns'] = Channel(self.p, name='#testruns') self.assertEqual(self.p.parse_modes('#testruns', ['+m']), [('+m', None)]) self.assertEqual(self.p.parse_modes('#testruns', ['+l', '3']), [('+l', '3')]) self.assertEqual(self.p.parse_modes('#testruns', ['+ntl', '59']), [('+n', None), ('+t', None), ('+l', '59')]) self.assertEqual(self.p.parse_modes('#testruns', ['+k-n', 'test']), [('+k', 'test'), ('-n', None)]) self.assertEqual( self.p.parse_modes('#testruns', ['+o', '102']), # unknown UID []) c.users.add(u) u.channels.add(c) self.assertEqual(self.p.parse_modes('#testruns', ['+o', '100']), [('+o', '100')]) self.assertEqual(self.p.parse_modes('#testruns', ['+vip', '100']), [('+v', '100'), ('+i', None), ('+p', None)])
def test_parse_modes_channel_key(self): c = self.p.channels['#pylink'] = Channel(self.p, name='#pylink') c.modes = {('k', 'foobar')} modes = self.p.parse_modes('#pylink', ['-k', 'foobar']) self.assertEqual(modes, [('-k', 'foobar')], "Parse result should include -k") modes = self.p.parse_modes('#pylink', ['-k', 'aBcDeF']) self.assertEqual(modes, [], "Incorrect key removal should be ignored") modes = self.p.parse_modes('#pylink', ['+k', 'aBcDeF']) self.assertEqual(modes, [('+k', 'aBcDeF')], "Parse result should include +k (replace key)") # Mismatched case - treat this as remove # Some IRCds allow this (Unreal, P10), others do not (InspIRCd). However, if such a message # makes actually its way to us it is most likely valid. # Note: Charybdis and ngIRCd do -k * removal instead so this case will never happen there modes = self.p.parse_modes('#pylink', ['-k', 'FooBar']) self.assertEqual(modes, [('-k', 'foobar')], "Parse result should include -k (different case)") modes = self.p.parse_modes('#pylink', ['-k', '*']) self.assertEqual(modes, [('-k', 'foobar')], "Parse result should include -k (-k *)")
def test_parse_modes_channel_ban_complex(self): c = self.p.channels['#testruns'] = Channel(self.p, name='#testruns') self.assertEqual( # add first ban, but don't remove second because it doesn't exist self.p.parse_modes('#testruns', ['+b-b', '*!*@test1', '*!*@test2']), [('+b', '*!*@test1')], "First ban should have been added, and second ignored" ) self.p.apply_modes('#testruns', [('+b', '*!*@test1')]) self.assertEqual( # remove first ban because it matches case self.p.parse_modes('#testruns', ['-b', '*!*@test1']), [('-b', '*!*@test1')], "First ban should have been removed (same case)" ) self.assertEqual( # remove first ban despite different case self.p.parse_modes('#testruns', ['-b', '*!*@TEST1']), [('-b', '*!*@test1')], "First ban should have been removed (different case)" ) self.p.apply_modes('#testruns', [('+b', '*!*@Test2')]) self.assertEqual( # remove second ban despite different case self.p.parse_modes('#testruns', ['-b', '*!*@test2']), [('-b', '*!*@Test2')], "Second ban should have been removed (different case)" )
def test_reverse_modes_cycle_arguments(self): # All of these cases are ugly, sometimes unsetting modes that don't exist... c = self.p.channels['#weirdstuff'] = Channel(self.p, name='#weirdstuff') out = self.p.reverse_modes('#weirdstuff', '+l-l 30') self.assertEqual(out, '-l') out = self.p.reverse_modes('#weirdstuff', '-l+l 30') self.assertEqual(out, '-l') out = self.p.reverse_modes('#weirdstuff', '+k-k aaaaaaaaaaaa aaaaaaaaaaaa') self.assertEqual(out, '-k aaaaaaaaaaaa') out = self.p.reverse_modes('#weirdstuff', '-k+k aaaaaaaaaaaa aaaaaaaaaaaa') self.assertEqual(out, '-k aaaaaaaaaaaa') c.modes = {('l', '555'), ('k', 'NO-PLEASE')} out = self.p.reverse_modes('#weirdstuff', '+l-l 30') self.assertEqual(out, '+l 555') out = self.p.reverse_modes('#weirdstuff', '-l+l 30') self.assertEqual(out, '+l 555') out = self.p.reverse_modes('#weirdstuff', '+k-k aaaaaaaaaaaa aaaaaaaaaaaa') self.assertEqual(out, '+k NO-PLEASE') out = self.p.reverse_modes('#weirdstuff', '-k+k aaaaaaaaaaaa aaaaaaaaaaaa') self.assertEqual(out, '+k NO-PLEASE')
def test_reverse_modes_bans(self): c = self.p.channels['#foobar'] = Channel(self.p, name='#foobar') c.modes = {('t', None), ('n', None), ('b', '*!*@example.com')} out = self.p.reverse_modes('#foobar', [('+b', '*!*@test')]) self.assertEqual(out, [('-b', '*!*@test')], "non-existent ban should be removed") out = self.p.reverse_modes('#foobar', '+b *!*@example.com') self.assertEqual(out, '+', "+b existing ban should be no-op") out = self.p.reverse_modes('#foobar', '+b *!*@Example.com') self.assertEqual(out, '+', "Should ignore attempt to change case of ban mode") out = self.p.reverse_modes('#foobar', '-b *!*@example.com') self.assertEqual(out, '+b *!*@example.com', "-b existing ban should reset it") out = self.p.reverse_modes('#foobar', '-b *!*@Example.com') self.assertEqual( out, '+b *!*@example.com', "-b existing ban should reset it using original case") out = self.p.reverse_modes('#foobar', '-b *!*@*') self.assertEqual(out, '+', "Removing non-existent ban is no-op") out = self.p.reverse_modes('#foobar', '+bbbm 1 2 3') self.assertEqual(out, '-bbbm 1 2 3')
def test_reverse_modes_simple(self): c = self.p.channels['#foobar'] = Channel(self.p, name='#foobar') c.modes = {('m', None), ('n', None)} # This function supports both strings and mode lists # Base cases for inp in {'', '+', '-'}: self.assertEqual(self.p.reverse_modes('#foobar', inp), '+') out = self.p.reverse_modes('#foobar', []) self.assertEqual(out, []) # One simple out = self.p.reverse_modes('#foobar', '+t') self.assertEqual(out, '-t') out = self.p.reverse_modes('#foobar', [('+t', None)]) self.assertEqual(out, [('-t', None)]) out = self.p.reverse_modes('#foobar', '+m') self.assertEqual(out, '+', 'Calling reverse_modes() on an already set mode is a no-op') out = self.p.reverse_modes('#foobar', [('+m', None)]) self.assertEqual(out, [], 'Calling reverse_modes() on an already set mode is a no-op') out = self.p.reverse_modes('#foobar', [('-i', None)]) self.assertEqual(out, [], 'Calling reverse_modes() on non-existent mode is a no-op')
def test_parse_modes_channel_rfc2(self): # These are basic tests that only use RFC 1459 defined modes. # IRCds supporting more complex modes can define new test cases if needed. c = self.p.channels['#testruns'] = Channel(self.p, name='#testruns') # Note: base case is not defined and raises AssertionError self.assertEqual( self.p.parse_modes('#testruns', ['+m']), # add modes [('+m', None)]) self.assertEqual( self.p.parse_modes('#testruns', ['-tn']), # remove modes [('-t', None), ('-n', None)]) self.assertEqual( self.p.parse_modes('#TESTRUNS', ['-tn']), # different case target [('-t', None), ('-n', None)]) self.assertEqual( self.p.parse_modes('#testruns', ['+l', '3']), # modes w/ arguments [('+l', '3')]) self.assertEqual( self.p.parse_modes('#testruns', ['+nlt', '59']), # combination [('+n', None), ('+l', '59'), ('+t', None)]) self.assertEqual( self.p.parse_modes('#testruns', ['+k-n', 'test']), # swapping +/- [('+k', 'test'), ('-n', None)]) self.assertEqual( self.p.parse_modes('#testruns', ['n-s']), # sloppy syntax [('+n', None), ('-s', None)]) self.assertEqual( self.p.parse_modes('#testruns', ['+bmi', '*[email protected]']), [('+b', '*[email protected]'), ('+m', None), ('+i', None)])
def test_apply_modes_channel_ban_multiple(self): c = self.p.channels['#Magic'] = Channel(self.p, name='#Magic') self.p.apply_modes('#Magic', [('+b', '*!*@test.host'), ('+b', '*!*@best.host'), ('+b', '*!*@guest.host')]) self.assertEqual(c.modes, {('b', '*!*@test.host'), ('b', '*!*@best.host'), ('b', '*!*@guest.host')}, "Bans should be added") self.p.apply_modes('#Magic', [('-b', '*!*@best.host'), ('-b', '*!*@guest.host'), ('-b', '*!*@test.host')]) self.assertEqual(c.modes, set(), "Bans should be removed")
def test_get_friendly_name(self): u = self._make_user('lorem', 'testUID', ident='ipsum', host='sit.amet') s = self.p.servers['mySID'] = Server(self.p, None, 'irc.example.org') c = self.p._channels['#abc'] = Channel('#abc') self.assertEqual(self.p.get_friendly_name(u.uid), 'lorem') self.assertEqual(self.p.get_friendly_name('#abc'), '#abc') self.assertEqual(self.p.get_friendly_name('mySID'), 'irc.example.org')
def test_apply_modes_channel_limit(self): c = self.p.channels['#abc'] = Channel(self.p, name='#abc') self.p.apply_modes('#abc', [('+t', None), ('+l', '30')]) self.assertEqual(c.modes, {('t', None), ('l', '30')}) self.p.apply_modes('#abc', [('+l', '55')]) self.assertEqual(c.modes, {('t', None), ('l', '55')}) self.p.apply_modes('#abc', [('-l', None)]) self.assertEqual(c.modes, {('t', None)})
def test_apply_modes_channel_simple(self): c = self.p.channels['#'] = Channel(self.p, name='#') self.p.apply_modes('#', [('+m', None)]) self.assertEqual(c.modes, {('m', None)}) self.p.apply_modes('#', []) # No-op self.assertEqual(c.modes, {('m', None)}) self.p.apply_modes('#', [('-m', None)]) self.assertFalse(c.modes) # assert is empty
def test_reverse_modes_cycle_bans(self): c = self.p.channels['#weirdstuff'] = Channel(self.p, name='#weirdstuff') c.modes = {('t', None), ('n', None), ('b', '*!*@test.host')} out = self.p.reverse_modes('#weirdstuff', '+b-b *!*@test.host *!*@test.host') # +- cycle existing ban self.assertEqual(out, '+b *!*@test.host') out = self.p.reverse_modes('#weirdstuff', '-b+b *!*@test.host *!*@test.host') # -+ cycle existing ban self.assertEqual(out, '+b *!*@test.host') # Ugly but OK out = self.p.reverse_modes('#weirdstuff', '+b-b *!*@* *!*@*') # +- cycle existing ban self.assertEqual(out, '-b *!*@*') out = self.p.reverse_modes('#weirdstuff', '-b+b *!*@* *!*@*') # -+ cycle existing ban self.assertEqual(out, '-b *!*@*') # Ugly but OK
def test_reverse_modes_cycle_simple(self): c = self.p.channels['#weirdstuff'] = Channel(self.p, name='#weirdstuff') c.modes = {('t', None), ('n', None)} out = self.p.reverse_modes('#weirdstuff', '+n-n') # +- cycle existing mode self.assertEqual(out, '+n') out = self.p.reverse_modes('#weirdstuff', '-n+n') # -+ cycle existing mode self.assertEqual(out, '+n') # Ugly but OK out = self.p.reverse_modes('#weirdstuff', '+m-m') # +- cycle non-existent mode self.assertEqual(out, '-m') out = self.p.reverse_modes('#weirdstuff', '-m+m') # -+ cycle non-existent mode self.assertEqual(out, '-m') # Ugly but OK
def test_reverse_modes_prefixmodes(self): c = self.p.channels['#foobar'] = Channel(self.p, name='#foobar') c.modes = {('t', None), ('n', None)} u = self._make_user('nick', uid='user') u.channels.add(c) c.users.add(u) c.prefixmodes['op'].add(u.uid) out = self.p.reverse_modes('#foobar', '-o user') self.assertEqual(out, '+o user') out = self.p.reverse_modes('#foobar', '+o user') self.assertEqual(out, '+') out = self.p.reverse_modes('#foobar', '+ov user user') self.assertEqual(out, '-v user') # ignore +o out = self.p.reverse_modes('#foobar', '-ovt user user') self.assertEqual(out, '+ot user') # ignore -v
def test_apply_modes_channel_mode_cycle(self): c = self.p.channels['#Magic'] = Channel(self.p, name='#Magic') self.p.apply_modes('#Magic', [('+b', '*!*@example.net'), ('-b', '*!*@example.net')]) self.assertEqual(c.modes, set(), "Ban should have been removed (same case)") self.p.apply_modes('#Magic', [('+b', '*!*@example.net'), ('-b', '*!*@Example.net')]) self.assertEqual(c.modes, set(), "Ban should have been removed (different case)") u = self._make_user('nick', uid='user') c.users.add(u.uid) u.channels.add(c) self.p.apply_modes('#Magic', [('+o', 'user'), ('-o', 'user')]) self.assertEqual(c.modes, set(), "No prefixmodes should have been set") self.assertFalse(c.is_op('user')) self.assertFalse(c.get_prefix_modes('user'))
def test_apply_modes_channel_ban(self): c = self.p.channels['#Magic'] = Channel(self.p, name='#Magic') self.p.apply_modes('#Magic', [('+b', '*!*@test.host'), ('+b', '*!*@best.host')]) self.assertEqual(c.modes, {('b', '*!*@test.host'), ('b', '*!*@best.host')}, "Bans should be added") # This should be a no-op self.p.apply_modes('#Magic', [('-b', '*!*non-existent')]) self.assertEqual(c.modes, {('b', '*!*@test.host'), ('b', '*!*@best.host')}, "Trying to unset non-existent ban should be no-op") # Simple removal self.p.apply_modes('#Magic', [('-b', '*!*@test.host')]) self.assertEqual(c.modes, {('b', '*!*@best.host')}, "Ban on *!*@test.host be removed (same case as original)") # Removal but different case than original self.p.apply_modes('#Magic', [('-b', '*!*@BEST.HOST')]) self.assertFalse(c.modes, "Ban on *!*@best.host should be removed (different case)")
def test_reverse_modes_limit(self): c = self.p.channels['#foobar'] = Channel(self.p, name='#foobar') c.modes = {('t', None), ('n', None), ('l', '50')} out = self.p.reverse_modes('#foobar', [('+l', '100')]) self.assertEqual(out, [('+l', '50')], "Setting +l should reset original mode") out = self.p.reverse_modes('#foobar', [('-l', None)]) self.assertEqual(out, [('+l', '50')], "Unsetting +l should reset original mode") out = self.p.reverse_modes('#foobar', [('+l', '50')]) self.assertEqual(out, [], "Setting +l with original value is no-op") c.modes.clear() out = self.p.reverse_modes('#foobar', [('+l', '111'), ('+m', None)]) self.assertEqual(out, [('-l', None), ('-m', None)], "Setting +l on channel without it should remove")
def test_parse_modes_prefixmodes_rfc(self): c = self.p.channels['#testruns'] = Channel(self.p, name='#testruns') self.assertEqual( self.p.parse_modes('#testruns', ['+ov', '102', '101']), # unknown UIDs are ignored [] ) u = self._make_user('test100', uid='100') c.users.add(u) u.channels.add(c) self.assertEqual( self.p.parse_modes('#testruns', ['+o', '100']), [('+o', '100')] ) self.assertEqual( self.p.parse_modes('#testruns', ['+vip', '100']), [('+v', '100'), ('+i', None), ('+p', None)] ) self.assertEqual( self.p.parse_modes('#testruns', ['-o+bn', '100', '*[email protected]']), [('-o', '100'), ('+b', '*[email protected]'), ('+n', None)] ) self.assertEqual( # 2nd user missing self.p.parse_modes('#testruns', ['+oovv', '100', '102', '100', '102']), [('+o', '100'), ('+v', '100')] ) u2 = self._make_user('test102', uid='102') c.users.add(u2) u2.channels.add(c) self.assertEqual( # two users interleaved self.p.parse_modes('#testruns', ['+oovv', '100', '102', '100', '102']), [('+o', '100'), ('+o', '102'), ('+v', '100'), ('+v', '102')] ) self.assertEqual( # Mode cycle self.p.parse_modes('#testruns', ['+o-o', '100', '100']), [('+o', '100'), ('-o', '100')] )
def test_apply_modes_channel_prefixmodes(self): # Make some users c = self.p.channels['#staff'] = Channel(self.p, name='#staff') u1 = self._make_user('user100', uid='100') u2 = self._make_user('user101', uid='101') c.users.add(u1.uid) u1.channels.add(c) c.users.add(u2.uid) u2.channels.add(c) # Set modes self.p.apply_modes('#staff', [('+o', '100'), ('+v', '101'), ('+t', None)]) self.assertEqual(c.modes, {('t', None)}) # State checks, lots of them... TODO: move this into Channel class tests self.assertTrue(c.is_op('100')) self.assertTrue(c.is_op_plus('100')) self.assertFalse(c.is_halfop('100')) self.assertTrue(c.is_halfop_plus('100')) self.assertFalse(c.is_voice('100')) self.assertTrue(c.is_voice_plus('100')) self.assertEqual(c.get_prefix_modes('100'), ['op']) self.assertTrue(c.is_voice('101')) self.assertTrue(c.is_voice_plus('101')) self.assertFalse(c.is_halfop('101')) self.assertFalse(c.is_halfop_plus('101')) self.assertFalse(c.is_op('101')) self.assertFalse(c.is_op_plus('101')) self.assertEqual(c.get_prefix_modes('101'), ['voice']) self.assertFalse(c.prefixmodes['owner']) self.assertFalse(c.prefixmodes['admin']) self.assertEqual(c.prefixmodes['op'], {'100'}) self.assertFalse(c.prefixmodes['halfop']) self.assertEqual(c.prefixmodes['voice'], {'101'}) self.p.apply_modes('#staff', [('-o', '100')]) self.assertEqual(c.modes, {('t', None)}) self.assertFalse(c.get_prefix_modes('100')) self.assertEqual(c.get_prefix_modes('101'), ['voice'])
def test_reverse_modes_cycle_prefixmodes(self): # All of these cases are ugly, sometimes unsetting modes that don't exist... c = self.p.channels['#weirdstuff'] = Channel(self.p, name='#weirdstuff') u = self._make_user('nick', uid='user') u.channels.add(c) c.users.add(u) # user not already opped out = self.p.reverse_modes('#weirdstuff', '+o-o user user') self.assertEqual(out, '-o user') out = self.p.reverse_modes('#weirdstuff', '-o+o user user') self.assertEqual(out, '-o user') c.prefixmodes['op'].add(u.uid) # user was opped out = self.p.reverse_modes('#weirdstuff', '+o-o user user') self.assertEqual(out, '+o user') out = self.p.reverse_modes('#weirdstuff', '-o+o user user') self.assertEqual(out, '+o user')
def test_parse_modes_channel_prefixmode_has_nick(self): c = self.p.channels['#'] = Channel(self.p, name='#') u = self._make_user('mynick', uid='myuid') c.users.add(u) u.channels.add(c) self.assertEqual(self.p.parse_modes('#', ['+o', 'myuid']), [('+o', 'myuid')], "+o on UID should be registered") self.assertEqual(self.p.parse_modes('#', ['+o', 'mynick']), [('+o', 'myuid')], "+o on nick should be registered") self.assertEqual(self.p.parse_modes('#', ['+o', 'MyUiD']), [], "+o on wrong case UID should be ignored") self.assertEqual(self.p.parse_modes('#', ['+o', 'MyNick']), [('+o', 'myuid')], "+o on different case nick should be registered") self.assertEqual(self.p.parse_modes('#', ['-o', 'myuid']), [('-o', 'myuid')], "-o on UID should be registered") self.assertEqual(self.p.parse_modes('#', ['-o', 'mynick']), [('-o', 'myuid')], "-o on nick should be registered")
def test_parse_modes_channel_ban_cycle(self): c = self.p.channels['#testruns'] = Channel(self.p, name='#testruns') self.assertEqual( self.p.parse_modes('#testruns', ['+b-b', '*!*@example.com', '*!*@example.com']), [('+b', '*!*@example.com'), ('-b', '*!*@example.com')], "Cycling a ban +b-b should remove it") self.assertEqual( self.p.parse_modes('#testruns', ['-b+b', '*!*@example.com', '*!*@example.com']), [('+b', '*!*@example.com')], "Cycling a ban -b+b should add it") self.assertEqual( self.p.parse_modes('#testruns', ['+b-b', '*!*@example.com', '*!*@Example.com']), [('+b', '*!*@example.com'), ('-b', '*!*@example.com')], "Cycling a ban +b-b should remove it (different case)") self.assertEqual( self.p.parse_modes('#testruns', ['+b-b', '*!*@Example.com', '*!*@example.com']), [('+b', '*!*@Example.com'), ('-b', '*!*@Example.com')], "Cycling a ban +b-b should remove it (different case)")
def test_apply_modes_channel_key(self): c = self.p.channels['#pylink'] = Channel(self.p, name='#pylink') self.p.apply_modes('#pylink', [('+k', 'password123'), ('+s', None)]) self.assertEqual(c.modes, {('s', None), ('k', 'password123')}) self.p.apply_modes('#pylink', [('+k', 'qwerty')]) self.assertEqual(c.modes, {('s', None), ('k', 'qwerty')}) self.p.apply_modes('#pylink', [('-k', 'abcdef')]) # Trying to remove with wrong key is a no-op self.assertEqual(c.modes, {('s', None), ('k', 'qwerty')}) self.p.apply_modes('#pylink', [('-k', 'qwerty')]) self.assertEqual(c.modes, {('s', None)}) self.p.apply_modes('#pylink', [('+k', 'qwerty')]) self.assertEqual(c.modes, {('s', None), ('k', 'qwerty')}) self.p.apply_modes('#pylink', [('-k', 'QWERTY')]) # Remove with different case self.assertEqual(c.modes, {('s', None)}) self.p.apply_modes('#pylink', [('+k', '12345')]) # Replace existing key self.assertEqual(c.modes, {('s', None), ('k', '12345')})
def test_reverse_modes_multi(self): c = self.p.channels['#foobar'] = Channel(self.p, name='#foobar') c.modes = {('t', None), ('n', None)} # reverse_modes should ignore modes that were already set out = self.p.reverse_modes('#foobar', '+nt') self.assertEqual(out, '+') out = self.p.reverse_modes('#foobar', [('+m', None), ('+i', None)]) self.assertEqual(out, [('-m', None), ('-i', None)]) out = self.p.reverse_modes('#foobar', '+mint') self.assertEqual(out, '-mi') # Ignore +nt since it already exists out = self.p.reverse_modes('#foobar', '+m-t') self.assertEqual(out, '-m+t') out = self.p.reverse_modes('#foobar', '+mn-t') self.assertEqual(out, '-m+t') out = self.p.reverse_modes('#foobar', [('+m', None), ('+n', None), ('-t', None)]) self.assertEqual(out, [('-m', None), ('+t', None)])