diff --git a/plugins/Random.py b/plugins/Random.py index 60ffc1b0c..0825e2949 100644 --- a/plugins/Random.py +++ b/plugins/Random.py @@ -35,6 +35,7 @@ Lots of stuff relating to random numbers. import supybot.plugins as plugins +import time import random import supybot.conf as conf @@ -56,20 +57,28 @@ def configure(advanced): seed = something('What seed?') conf.supybot.plugins.Random.seed.setValue(seed) -class Seed(registry.Value): - def set(self, s): - try: - self.setValue(long(s)) - except ValueError: - raise registry.InvalidRegistryValue, 'Value must be an integer.' +class Seed(registry.Integer): + def __call__(self): + v = registry.Integer.__call__(self) + if not v: + v = int(time.time()) + return v + def serialize(self): + # We do this so if it's 0, it doesn't store a real time. + return str(self.value) + conf.registerPlugin('Random') conf.registerGlobalValue(conf.supybot.plugins.Random, 'seed', Seed(0, """ -Sets the seed of the random number generator. The seen must be a valid -Python integer or long.""")) +Sets the seed of the random number generator. The seed must be a valid +Python integer or long. If the seed is 0, a seed based on the current +time will be used.""")) class Random(callbacks.Privmsg): - rng = random.Random() + def __init__(self): + self.rng = random.Random(self.registryValue('seed')) + super(Random, self).__init__() + def random(self, irc, msg, args): """takes no arguments @@ -89,7 +98,7 @@ class Random(callbacks.Privmsg): seed = long(seed) except ValueError: # It wasn't a valid long! - irc.error(' must be a valid int or long.') + irc.errorInvalid('number', seed) return self.rng.seed(seed) irc.replySuccess() @@ -118,18 +127,20 @@ class Random(callbacks.Privmsg): of arguments given. """ try: - n = int(args.pop(0)) + n = args.pop(0) + n = int(n) except IndexError: # raised by .pop(0) raise callbacks.ArgumentError except ValueError: - irc.error(' must be an integer.') + irc.errorInvalid('number', n) return if n > len(args): irc.error(' must be less than the number ' 'of arguments.') return sample = self.rng.sample(args, n) - irc.reply(utils.commaAndify(map(repr, sample))) + sample.sort() + irc.reply(utils.commaAndify(sample)) def diceroll(self, irc, msg, args): """[] @@ -146,8 +157,7 @@ class Random(callbacks.Privmsg): irc.error('Dice have integer numbers of sides. Use one.') return s = 'rolls a %s' % self.rng.randrange(1, n) - irc.queueMsg(ircmsgs.action(ircutils.replyTo(msg), s)) - raise callbacks.CannotNest + irc.reply(s, action=True) Class = Random diff --git a/test/test_Random.py b/test/test_Random.py new file mode 100644 index 000000000..4c1e12d0d --- /dev/null +++ b/test/test_Random.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +### +# Copyright (c) 2002-2004, Jeremiah Fincher +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +from testsupport import * + +import sets + +iters = 100 +class RandomTestCase(PluginTestCase): + plugins = ('Random',) + def testNoErrors(self): + self.assertNotError('random') + + def testRange(self): + for x in range(iters): + self.assertRegexp('range 1 2', '^(1|2)$') + + def testDiceroll(self): + for x in range(iters): + self.assertActionRegexp('diceroll', '^rolls a (1|2|3|4|5|6)$') + + def testSample(self): + for x in range(iters): + self.assertRegexp('sample 1 a b c', '^(a|b|c)$') + for x in range(iters): + self.assertRegexp('sample 2 a b c', '^(a and b|a and c|b and c)$') + self.assertResponse('sample 3 a b c', 'a, b, and c') + + def testSeed(self): + self.assertNotError('seed 12') + m1 = self.assertNotError('random') + self.assertNotError('seed 13') + m2 = self.assertNotError('random') + self.assertNotError('seed 12') + m3 = self.assertNotError('random') + self.assertEqual(m1, m3) + self.assertNotEqual(m1, m2) + + +# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: +