mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-11-20 01:19:26 +01:00
Add Todo in the new plugin format.
The db format has been changed to a single flat file per user.
This commit is contained in:
parent
07814fc808
commit
9f6fcf260f
1
plugins/Todo/README.txt
Normal file
1
plugins/Todo/README.txt
Normal file
@ -0,0 +1 @@
|
||||
Insert a description of your plugin here, with any notes, etc. about using it.
|
61
plugins/Todo/__init__.py
Normal file
61
plugins/Todo/__init__.py
Normal file
@ -0,0 +1,61 @@
|
||||
###
|
||||
# Copyright (c) 2003-2005, Daniel DiPaolo
|
||||
# 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.
|
||||
###
|
||||
|
||||
"""
|
||||
The Todo plugin allows registered users to keep their own personal list of
|
||||
tasks to do, with an optional priority for each.
|
||||
"""
|
||||
|
||||
import supybot
|
||||
import supybot.world as world
|
||||
|
||||
# Use this for the version of this plugin. You may wish to put a CVS keyword
|
||||
# in here if you're keeping the plugin in CVS or some similar system.
|
||||
__version__ = "%%VERSION%%"
|
||||
|
||||
__author__ = supybot.authors.strike
|
||||
|
||||
# This is a dictionary mapping supybot.Author instances to lists of
|
||||
# contributions.
|
||||
__contributors__ = {}
|
||||
|
||||
import config
|
||||
import plugin
|
||||
reload(plugin) # In case we're being reloaded.
|
||||
# Add more reloads here if you add third-party modules and want them to be
|
||||
# reloaded when this plugin is reloaded. Don't forget to import them as well!
|
||||
|
||||
if world.testing:
|
||||
import test
|
||||
|
||||
Class = plugin.Class
|
||||
configure = config.configure
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
48
plugins/Todo/config.py
Normal file
48
plugins/Todo/config.py
Normal file
@ -0,0 +1,48 @@
|
||||
###
|
||||
# Copyright (c) 2003-2005, Daniel DiPaolo
|
||||
# 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.
|
||||
###
|
||||
|
||||
import supybot.conf as conf
|
||||
import supybot.registry as registry
|
||||
|
||||
def configure(advanced):
|
||||
# This will be called by supybot to configure this module. advanced is
|
||||
# a bool that specifies whether the user identified himself as an advanced
|
||||
# user or not. You should effect your configuration by manipulating the
|
||||
# registry as appropriate.
|
||||
from supybot.questions import expect, anything, something, yn
|
||||
conf.registerPlugin('Todo', True)
|
||||
|
||||
|
||||
Todo = conf.registerPlugin('Todo')
|
||||
# This is where your configuration variables (if any) should go. For example:
|
||||
# conf.registerGlobalValue(Todo, 'someConfigVariableName',
|
||||
# registry.Boolean(False, """Help for someConfigVariableName."""))
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78
|
265
plugins/Todo/plugin.py
Normal file
265
plugins/Todo/plugin.py
Normal file
@ -0,0 +1,265 @@
|
||||
###
|
||||
# Copyright (c) 2003-2005, Daniel DiPaolo
|
||||
# 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.
|
||||
###
|
||||
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import fnmatch
|
||||
import operator
|
||||
|
||||
import supybot.dbi as dbi
|
||||
import supybot.conf as conf
|
||||
import supybot.utils as utils
|
||||
from supybot.commands import *
|
||||
import supybot.plugins as plugins
|
||||
import supybot.ircutils as ircutils
|
||||
import supybot.callbacks as callbacks
|
||||
|
||||
class TodoRecord(dbi.Record):
|
||||
__fields__ = [
|
||||
'priority',
|
||||
'at',
|
||||
'task',
|
||||
'active',
|
||||
]
|
||||
|
||||
dataDir = conf.supybot.directories.data
|
||||
|
||||
class FlatTodoDb(object):
|
||||
def __init__(self):
|
||||
self.directory = dataDir.dirize('Todo')
|
||||
if not os.path.exists(self.directory):
|
||||
os.mkdir(self.directory)
|
||||
self.dbs = {}
|
||||
|
||||
def _getDb(self, uid):
|
||||
dbfile = os.path.join(self.directory, str(uid))
|
||||
if uid not in self.dbs:
|
||||
self.dbs[uid] = dbi.DB(dbfile, Record=TodoRecord)
|
||||
return self.dbs[uid]
|
||||
|
||||
def close(self):
|
||||
for db in self.dbs.itervalues():
|
||||
db.close()
|
||||
|
||||
def get(self, uid, tid):
|
||||
db = self._getDb(uid)
|
||||
return db.get(tid)
|
||||
|
||||
def getTodos(self, uid):
|
||||
db = self._getDb(uid)
|
||||
L = [R for R in db.select(lambda r: r.active)]
|
||||
if not L:
|
||||
raise dbi.NoRecordError
|
||||
return L
|
||||
|
||||
def add(self, priority, now, uid, task):
|
||||
db = self._getDb(uid)
|
||||
return db.add(TodoRecord(priority=priority, at=now,
|
||||
task=task, active=True))
|
||||
|
||||
def remove(self, uid, tid):
|
||||
db = self._getDb(uid)
|
||||
t = db.get(tid)
|
||||
t.active = False
|
||||
db.set(tid, t)
|
||||
|
||||
def select(self, uid, criteria):
|
||||
db = self._getDb(uid)
|
||||
def match(todo):
|
||||
for p in criteria:
|
||||
if not p(todo.task):
|
||||
return False
|
||||
return True
|
||||
todos = db.select(lambda t: match(t))
|
||||
if not todos:
|
||||
raise dbi.NoRecordError
|
||||
return todos
|
||||
|
||||
def setpriority(self, uid, tid, priority):
|
||||
db = self._getDb(uid)
|
||||
t = db.get(tid)
|
||||
t.priority = priority
|
||||
db.set(tid, t)
|
||||
|
||||
def change(self, uid, tid, replacer):
|
||||
db = self._getDb(uid)
|
||||
t = db.get(tid)
|
||||
t.task = replacer(t.task)
|
||||
db.set(tid, t)
|
||||
|
||||
class Todo(callbacks.Plugin):
|
||||
def __init__(self, irc):
|
||||
self.__parent = super(Todo, self)
|
||||
self.__parent.__init__(irc)
|
||||
self.db = FlatTodoDb()
|
||||
|
||||
def die(self):
|
||||
self.__parent.die()
|
||||
self.db.close()
|
||||
|
||||
def _shrink(self, s):
|
||||
return utils.str.ellipsisify(s, 50)
|
||||
|
||||
def todo(self, irc, msg, args, user, taskid):
|
||||
"""[<username> [<task id>]|<task id>]
|
||||
|
||||
Retrieves a task for the given task id. If no task id is given, it
|
||||
will return a list of task ids that that user has added to their todo
|
||||
list.
|
||||
"""
|
||||
# List the active tasks for the given user
|
||||
if not taskid:
|
||||
try:
|
||||
tasks = self.db.getTodos(user.id)
|
||||
utils.sortBy(operator.attrgetter('priority'), tasks)
|
||||
tasks = [format('#%i: %s', t.id, self._shrink(t.task))
|
||||
for t in tasks]
|
||||
Todo = 'Todo'
|
||||
if len(tasks) != 1:
|
||||
Todo = 'Todos'
|
||||
irc.reply(format('%s for %s: %L',
|
||||
Todo, user.name, tasks))
|
||||
except dbi.NoRecordError:
|
||||
irc.reply('That user has no todos.')
|
||||
return
|
||||
# Reply with the user's task
|
||||
else:
|
||||
try:
|
||||
t = self.db.get(user.id, taskid)
|
||||
if t.active:
|
||||
active = 'Active'
|
||||
else:
|
||||
active = 'Inactive'
|
||||
if t.priority:
|
||||
t.task += format(', priority: %i', t.priority)
|
||||
at = time.strftime(conf.supybot.reply.format.time(),
|
||||
time.localtime(t.at))
|
||||
s = format('%s todo for %s: %s (Added at %s)',
|
||||
active, user.name, t.task, at)
|
||||
irc.reply(s)
|
||||
except dbi.NoRecordError:
|
||||
irc.errorInvalid('task id', taskid)
|
||||
todo = wrap(todo, [first('otherUser', 'user'), additional(('id', 'task'))])
|
||||
|
||||
def add(self, irc, msg, args, user, optlist, text, now):
|
||||
"""[--priority=<num>] <text>
|
||||
|
||||
Adds <text> as a task in your own personal todo list. The optional
|
||||
priority argument allows you to set a task as a high or low priority.
|
||||
Any integer is valid.
|
||||
"""
|
||||
priority = 0
|
||||
for (option, arg) in optlist:
|
||||
if option == 'priority':
|
||||
priority = arg
|
||||
todoId = self.db.add(priority, now, user.id, text)
|
||||
irc.replySuccess(format('(Todo #%i added)', todoId))
|
||||
add = wrap(add, ['user', getopts({'priority': ('int', 'priority')}),
|
||||
'text', 'now'])
|
||||
|
||||
def remove(self, irc, msg, args, user, tasks):
|
||||
"""<task id> [<task id> ...]
|
||||
|
||||
Removes <task id> from your personal todo list.
|
||||
"""
|
||||
invalid = []
|
||||
for taskid in tasks:
|
||||
try:
|
||||
self.db.get(user.id, taskid)
|
||||
except dbi.NoRecordError:
|
||||
invalid.append(taskid)
|
||||
if invalid and len(invalid) == 1:
|
||||
irc.error(format('Task %i could not be removed either because '
|
||||
'that id doesn\'t exist or it has been removed '
|
||||
'already.', invalid[0]))
|
||||
elif invalid:
|
||||
irc.error(format('No tasks were removed because the following '
|
||||
'tasks could not be removed: %L.', invalid))
|
||||
else:
|
||||
for taskid in tasks:
|
||||
self.db.remove(user.id, taskid)
|
||||
irc.replySuccess()
|
||||
remove = wrap(remove, ['user', many(('id', 'task'))])
|
||||
|
||||
def search(self, irc, msg, args, user, optlist, globs):
|
||||
"""[--{regexp} <value>] [<glob> <glob> ...]
|
||||
|
||||
Searches your todos for tasks matching <glob>. If --regexp is given,
|
||||
its associated value is taken as a regexp and matched against the
|
||||
tasks.
|
||||
"""
|
||||
if not optlist and not globs:
|
||||
raise callbacks.ArgumentError
|
||||
criteria = []
|
||||
for (option, arg) in optlist:
|
||||
if option == 'regexp':
|
||||
criteria.append(arg.search)
|
||||
for glob in globs:
|
||||
glob = fnmatch.translate(glob)
|
||||
criteria.append(re.compile(glob[:-1]).search)
|
||||
try:
|
||||
tasks = self.db.select(user.id, criteria)
|
||||
L = [format('#%i: %s', t.id, self._shrink(t.task)) for t in tasks]
|
||||
irc.reply(format('%L', L))
|
||||
except dbi.NoRecordError:
|
||||
irc.reply('No tasks matched that query.')
|
||||
search = wrap(search,
|
||||
['user', getopts({'regexp': 'regexpMatcher'}), any('glob')])
|
||||
|
||||
def setpriority(self, irc, msg, args, user, id, priority):
|
||||
"""<id> <priority>
|
||||
|
||||
Sets the priority of the todo with the given id to the specified value.
|
||||
"""
|
||||
try:
|
||||
self.db.setpriority(user.id, id, priority)
|
||||
irc.replySuccess()
|
||||
except dbi.NoRecordError:
|
||||
irc.errorInvalid('task id', id)
|
||||
setpriority = wrap(setpriority,
|
||||
['user', ('id', 'task'), ('int', 'priority')])
|
||||
|
||||
def change(self, irc, msg, args, user, id, replacer):
|
||||
"""<task id> <regexp>
|
||||
|
||||
Modify the task with the given id using the supplied regexp.
|
||||
"""
|
||||
try:
|
||||
self.db.change(user.id, id, replacer)
|
||||
irc.replySuccess()
|
||||
except dbi.NoRecordError:
|
||||
irc.errorInvalid('task id', id)
|
||||
change = wrap(change, ['user', ('id', 'task'), 'regexpReplacer'])
|
||||
|
||||
|
||||
Class = Todo
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
135
plugins/Todo/test.py
Normal file
135
plugins/Todo/test.py
Normal file
@ -0,0 +1,135 @@
|
||||
###
|
||||
# Copyright (c) 2003-2005, Daniel DiPaolo
|
||||
# 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 supybot.test import *
|
||||
|
||||
class TodoTestCase(PluginTestCase):
|
||||
plugins = ('Todo', 'User')
|
||||
_user1 = 'foo!bar@baz'
|
||||
_user2 = 'bar!foo@baz'
|
||||
def setUp(self):
|
||||
PluginTestCase.setUp(self)
|
||||
# Create a valid user to use
|
||||
self.prefix = self._user2
|
||||
self.assertNotError('register testy oom')
|
||||
self.prefix = self._user1
|
||||
self.assertNotError('register tester moo')
|
||||
|
||||
def testTodo(self):
|
||||
# Should not error, but no tasks yet.
|
||||
self.assertNotError('todo')
|
||||
self.assertRegexp('todo', 'has no Todos')
|
||||
# Add a task
|
||||
self.assertNotError('todo add wash my car')
|
||||
self.assertRegexp('todo', '#1: wash my car')
|
||||
# Check that task
|
||||
self.assertRegexp('todo 1',
|
||||
'Todo for tester: wash my car \(Added .*?\)')
|
||||
# Check that it lists all my tasks when given my name
|
||||
self.assertResponse('todo tester',
|
||||
'Todo for tester: #1: wash my car')
|
||||
# Check pluralization
|
||||
self.assertNotError('todo add moo')
|
||||
self.assertRegexp('todo tester',
|
||||
'Todos for tester: #1: wash my car and #2: moo')
|
||||
# Check error
|
||||
self.assertError('todo asfas')
|
||||
self.assertRegexp('todo asfas',
|
||||
'Error: \'asfas\' is not a valid task')
|
||||
# Check priority sorting
|
||||
self.assertNotError('todo setpriority 1 100')
|
||||
self.assertNotError('todo setpriority 2 10')
|
||||
self.assertRegexp('todo', '#2: moo and #1: wash my car')
|
||||
|
||||
def testAddtodo(self):
|
||||
self.assertNotError('todo add code a new plugin')
|
||||
self.assertNotError('todo add --priority=1000 fix all bugs')
|
||||
|
||||
def testRemovetodo(self):
|
||||
self.nick = 'testy'
|
||||
self.prefix = self._user2
|
||||
self.assertNotError('todo add do something')
|
||||
self.assertNotError('todo add do something else')
|
||||
self.assertNotError('todo add do something again')
|
||||
self.assertNotError('todo remove 1')
|
||||
self.assertNotError('todo 1')
|
||||
self.nick = 'tester'
|
||||
self.prefix = self._user1
|
||||
self.assertNotError('todo add make something')
|
||||
self.assertNotError('todo add make something else')
|
||||
self.assertNotError('todo add make something again')
|
||||
self.assertNotError('todo remove 1 3')
|
||||
self.assertRegexp('todo 1', r'Inactive')
|
||||
self.assertRegexp('todo 3', r'Inactive')
|
||||
self.assertNotError('todo')
|
||||
|
||||
def testSearchtodo(self):
|
||||
self.assertNotError('todo add task number one')
|
||||
self.assertRegexp('todo search task*', '#1: task number one')
|
||||
self.assertRegexp('todo search number', '#1: task number one')
|
||||
self.assertNotError('todo add task number two is much longer than'
|
||||
' task number one')
|
||||
self.assertRegexp('todo search task*',
|
||||
'#1: task number one and #2: task number two is '
|
||||
'much longer than task number...')
|
||||
self.assertError('todo search --regexp s/bustedregex')
|
||||
self.assertRegexp('todo search --regexp m/task/',
|
||||
'#1: task number one and #2: task number two is '
|
||||
'much longer than task number...')
|
||||
|
||||
def testSetPriority(self):
|
||||
self.assertNotError('todo add --priority=1 moo')
|
||||
self.assertRegexp('todo 1',
|
||||
'moo, priority: 1 \(Added at .*?\)')
|
||||
self.assertNotError('setpriority 1 50')
|
||||
self.assertRegexp('todo 1',
|
||||
'moo, priority: 50 \(Added at .*?\)')
|
||||
self.assertNotError('setpriority 1 0')
|
||||
self.assertRegexp('todo 1', 'moo \(Added at .*?\)')
|
||||
|
||||
def testChangeTodo(self):
|
||||
self.assertNotError('todo add moo')
|
||||
self.assertError('todo change 1 asdfas')
|
||||
self.assertError('todo change 1 m/asdfaf//')
|
||||
self.assertNotError('todo change 1 s/moo/foo/')
|
||||
self.assertRegexp('todo 1', 'Todo for tester: foo \(Added .*?\)')
|
||||
|
||||
def testActiveInactiveTodo(self):
|
||||
self.assertNotError('todo add foo')
|
||||
self.assertNotError('todo add bar')
|
||||
self.assertRegexp('todo 1', 'Active')
|
||||
self.assertRegexp('todo 2', 'Active')
|
||||
self.assertNotError('todo remove 1')
|
||||
self.assertRegexp('todo 1', 'Inactive')
|
||||
self.assertRegexp('todo 2', 'Active')
|
||||
self.assertNotError('todo remove 2')
|
||||
self.assertRegexp('todo 2', 'Inactive')
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
Loading…
Reference in New Issue
Block a user