Skip to content

Commit

Permalink
more command word handling with tests
Browse files Browse the repository at this point in the history
  • Loading branch information
tmaybe committed Apr 21, 2015
1 parent d6f79f6 commit ee29a07
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 24 deletions.
61 changes: 37 additions & 24 deletions gloss/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
from datetime import datetime
import json

STATS_CMDS = (u'stats',)
RECENT_CMDS = (u'learnings',)
HELP_CMDS = (u'help', u'?')
SET_CMDS = (u'=',)
DELETE_CMDS = (u'delete',)

'''
values posted by Slack:
token: the authenticaton token from Slack; available in the integration settings.
Expand Down Expand Up @@ -146,7 +152,15 @@ def query_definition(term):
'''
return Definition.query.filter(func.lower(Definition.term) == func.lower(term)).first()

def get_definition_and_response(command_text, user_name, channel_id, private_response):
def get_command_action_and_params(command_text):
''' Parse the passed string for a command action and parameters
'''
command_components = command_text.split(' ')
command_action = command_components[0].lower()
command_params = u' '.join(command_components[1:])
return command_action, command_params

def query_definition_and_get_response(command_text, user_name, channel_id, private_response):
''' Get the definition for the passed term and return the appropriate responses
'''
# query the definition
Expand Down Expand Up @@ -178,9 +192,14 @@ def set_definition_and_get_response(command_params, user_name):
set_term = set_components[0].strip()
set_value = set_components[1].strip() if len(set_components) > 1 else u''

if len(set_components) != 2 or u'=' not in command_params or not set_term or not set_value:
# reject poorly formed set commands
if u'=' not in command_params or not set_term or not set_value:
return u'Sorry, but *Gloss Bot* didn\'t understand your command. You can set definitions like this: */gloss EW = Eligibility Worker*', 200

# reject attempts to set reserved terms
if set_term.lower() in STATS_CMDS + RECENT_CMDS + HELP_CMDS:
return u'Sorry, but *Gloss Bot* can\'t set a definition for *{}* because it\'s a reserved term.'.format(set_term)

# check the database to see if the term's already defined
entry = query_definition(set_term)
if entry:
Expand Down Expand Up @@ -233,35 +252,29 @@ def index():
command_text = full_text

# if the text is a single word that's not a single-word command, treat it as a get
if command_text.count(u' ') is 0 and len(command_text) > 0 and command_text not in [u'stats', u'learnings', u'help', u'?', u'=']:
return get_definition_and_response(command_text, user_name, channel_id, False)
if command_text.count(u' ') is 0 and len(command_text) > 0 and \
command_text.lower() not in STATS_CMDS + RECENT_CMDS + HELP_CMDS + SET_CMDS:
return query_definition_and_get_response(command_text, user_name, channel_id, False)

# was a command passed?
command_components = command_text.split(' ')
command_action = command_components[0]
command_params = u' '.join(command_components[1:])

# if the text contains an '=' and it's not trying to set the definition for a
# single-word command, treat it as a set
if '=' in command_text and command_action not in [u'stats', u'learnings']:
# if the text contains an '=', treat it as a 'set' command
if '=' in command_text:
return set_definition_and_get_response(command_text, user_name)

# we'll respond privately if the text is prefixed with 'shh' (or any number of s followed by any number of h)
# this means that Glossary Bot can't define SHH (Sonic Hedge Hog) or SSH (Secure SHell)
# or SH (Ovarian Stromal Hyperthecosis)
# we'll respond privately if the text is prefixed with 'shh ' (or any number of s followed by any number of h)
shh_pattern = compile(r'^s+h+ ')
private_response = shh_pattern.match(command_text)
if private_response:
# strip the 'shh' from the command text
command_text = shh_pattern.sub('', command_text)
command_components = command_text.split(' ')
command_action = command_components[0]
command_params = u' '.join(command_components[1:])

# extract the command action and parameters
command_action, command_params = get_command_action_and_params(command_text)

#
# DELETE definition
#

if command_action == u'delete':
if command_action in DELETE_CMDS:
delete_term = command_params

# verify that the definition is in the database
Expand All @@ -282,14 +295,14 @@ def index():
# HELP
#

if command_action == u'help' or command_action == u'?' or command_text == u'' or command_text == u' ':
if command_action in HELP_CMDS or command_text == u'' or command_text == u' ':
return u'*/gloss <term>* to show the definition for a term\n*/gloss <term> = <definition>* to set the definition for a term\n*/gloss delete <term>* to delete the definition for a term\n*/gloss help* to see this message\n*/gloss stats* to show usage statistics\n*/gloss learnings* to show recently defined terms\n*/gloss shh <command>* to get a private response\n<https://github.com/codeforamerica/glossary-bot/issues|report bugs and request features>', 200

#
# STATS
#

if command_action == u'stats':
if command_action in STATS_CMDS:
stats_newline = u'I have {}'.format(get_stats())
stats_comma = sub(u'\n', u', ', stats_newline)
if not private_response:
Expand All @@ -304,10 +317,10 @@ def index():
return stats_comma, 200

#
# LEARNINGS
# LEARNINGS/RECENT
#

if command_action == u'learnings':
if command_action in RECENT_CMDS:
sort_order = u''
if command_params == u'random':
sort_order = command_params
Expand All @@ -328,4 +341,4 @@ def index():
#

# check the definition
return get_definition_and_response(command_text, user_name, channel_id, private_response)
return query_definition_and_get_response(command_text, user_name, channel_id, private_response)
82 changes: 82 additions & 0 deletions tests/test_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,26 @@ def test_reset_definition(self):
self.assertEqual(definition_check.term, u'EW')
self.assertEqual(definition_check.definition, u'Egg Weathervane')

def test_set_same_word_with_different_capitalization(self):
''' We can't set different definitions for the same word by using different cases
'''
robo_response = self.post_command(u'lower case = NOT UPPER CASE')
self.assertEqual(robo_response.status_code, 200)
self.assertTrue(u'has set the definition' in robo_response.data)

filter = Definition.term == u'lower case'
definition_check = self.db.session.query(Definition).filter(filter).first()
self.assertIsNotNone(definition_check)
self.assertEqual(definition_check.term, u'lower case')
self.assertEqual(definition_check.definition, u'NOT UPPER CASE')

robo_response = self.post_command(u'LOWER CASE = really not upper case')
self.assertEqual(robo_response.status_code, 200)
self.assertTrue(u'overwriting the previous entry' in robo_response.data)

robo_response = self.post_command(u'shh lower case')
self.assertTrue(u'LOWER CASE: really not upper case' in robo_response.data)

def test_set_identical_definition(self):
''' Correct response for setting an identical definition for an existing term
'''
Expand All @@ -122,6 +142,68 @@ def test_set_identical_definition(self):
robo_response = self.post_command(u'EW = Eligibility Worker')
self.assertTrue(u'already knows that the definition for' in robo_response.data)

def test_set_command_word_definitions(self):
''' We can successfull set and get definitions for unreserved command words.
'''
robo_response = self.post_command(u'SHH = Sonic Hedge Hog')
self.assertEqual(robo_response.status_code, 200)
self.assertTrue(u'has set the definition' in robo_response.data)

filter = Definition.term == u'SHH'
definition_check = self.db.session.query(Definition).filter(filter).first()
self.assertIsNotNone(definition_check)
self.assertEqual(definition_check.term, u'SHH')
self.assertEqual(definition_check.definition, u'Sonic Hedge Hog')

robo_response = self.post_command(u'SSH = Secure SHell')
self.assertEqual(robo_response.status_code, 200)
self.assertTrue(u'has set the definition' in robo_response.data)

filter = Definition.term == u'SSH'
definition_check = self.db.session.query(Definition).filter(filter).first()
self.assertIsNotNone(definition_check)
self.assertEqual(definition_check.term, u'SSH')
self.assertEqual(definition_check.definition, u'Secure SHell')

robo_response = self.post_command(u'Delete = Remove or Obliterate')
self.assertEqual(robo_response.status_code, 200)
self.assertTrue(u'has set the definition' in robo_response.data)

filter = Definition.term == u'Delete'
definition_check = self.db.session.query(Definition).filter(filter).first()
self.assertIsNotNone(definition_check)
self.assertEqual(definition_check.term, u'Delete')
self.assertEqual(definition_check.definition, u'Remove or Obliterate')

robo_response = self.post_command(u'help me = I\'m in hell')
self.assertEqual(robo_response.status_code, 200)
self.assertTrue(u'has set the definition' in robo_response.data)

filter = Definition.term == u'help me'
definition_check = self.db.session.query(Definition).filter(filter).first()
self.assertIsNotNone(definition_check)
self.assertEqual(definition_check.term, u'help me')
self.assertEqual(definition_check.definition, u'I\'m in hell')

def test_failed_set_command_word_definitions(self):
''' We can't successfully set and get definitions for reserved command words.
'''
robo_response = self.post_command(u'Stats = Statistics')
self.assertEqual(robo_response.status_code, 200)
self.assertTrue(u'because it\'s a reserved term' in robo_response.data)

robo_response = self.post_command(u'help = aid')
self.assertEqual(robo_response.status_code, 200)
self.assertTrue(u'because it\'s a reserved term' in robo_response.data)

robo_response = self.post_command(u'LeArNiNgS = recently')
self.assertEqual(robo_response.status_code, 200)
self.assertTrue(u'because it\'s a reserved term' in robo_response.data)

robo_response = self.post_command(u'? = riddle me this')
self.assertEqual(robo_response.status_code, 200)
self.assertTrue(u'because it\'s a reserved term' in robo_response.data)

def test_get_definition(self):
''' We can succesfully set and get a definition from the bot
'''
Expand Down

0 comments on commit ee29a07

Please sign in to comment.