Skip to content
This repository has been archived by the owner on Sep 8, 2024. It is now read-only.

Commit

Permalink
Merge pull request #2838 from forslund/test/get_response-tests
Browse files Browse the repository at this point in the history
get response tests
  • Loading branch information
krisgesling committed Mar 10, 2021
2 parents f54300d + 3a6ca30 commit 3679eb1
Show file tree
Hide file tree
Showing 6 changed files with 254 additions and 18 deletions.
2 changes: 1 addition & 1 deletion mycroft/skills/mycroft_skill/mycroft_skill.py
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ def ask_selection(self, options, dialog='',
else:
num = extract_number(resp, self.lang, ordinals=True)
resp = None
if num and num < len(options):
if num and num <= len(options):
resp = options[num - 1]
else:
resp = match
Expand Down
9 changes: 9 additions & 0 deletions test/unittests/mocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@
__CONFIG = LocalConf(DEFAULT_CONFIG)


class AnyCallable:
"""Class matching any callable.
Useful for assert_called_with arguments.
"""
def __eq__(self, other):
return callable(other)


def base_config():
"""Base config used when mocking.
Expand Down
10 changes: 1 addition & 9 deletions test/unittests/skills/test_common_play_skill.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,7 @@
from mycroft.messagebus import Message
from mycroft.skills.common_play_skill import CommonPlaySkill, CPSMatchLevel
from mycroft.skills.audioservice import AudioService


class AnyCallable:
"""Class matching any callable.
Useful for assert_called_with arguments.
"""
def __eq__(self, other):
return callable(other)
from test.unittests.mocks import AnyCallable


class TestCommonPlay(TestCase):
Expand Down
9 changes: 1 addition & 8 deletions test/unittests/skills/test_common_query_skill.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,7 @@
from mycroft.skills.common_query_skill import (CommonQuerySkill, CQSMatchLevel,
CQSVisualMatchLevel,
handles_visuals)


class AnyCallable:
"""Class matching any callable.
Useful for assert_called_with arguments.
"""
def __eq__(self, other):
return callable(other)
from test.unittests.mocks import AnyCallable


class TestCommonQuerySkill(TestCase):
Expand Down
241 changes: 241 additions & 0 deletions test/unittests/skills/test_mycroft_skill_get_response.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
"""Tests for the mycroft skill's get_response variations."""

from os.path import dirname, join
from threading import Thread
import time
from unittest import TestCase, mock

from mycroft import MycroftSkill
from mycroft.messagebus import Message

from test.unittests.mocks import base_config, AnyCallable


def create_converse_responder(response, skill):
"""Create a function to inject a response into the converse method.
The function waits for the converse method to be replaced by the
_wait_response logic and afterwards injects the provided response.
Arguments:
response (str): Sentence to inject.
skill (MycroftSkill): skill to monitor.
"""
default_converse = skill.converse
converse_return = None

def wait_for_new_converse():
"""Wait until there is a new converse handler then send sentence.
"""
nonlocal converse_return
start_time = time.monotonic()
while time.monotonic() < start_time + 5:
if skill.converse != default_converse:
skill.converse([response])
break

time.sleep(0.1)

return wait_for_new_converse


@mock.patch('mycroft.skills.mycroft_skill.mycroft_skill.Configuration')
def create_skill(mock_conf, lang='en-us'):
mock_conf.get.return_value = base_config()
skill = MycroftSkill(name='test_skill')
bus = mock.Mock()
skill.bind(bus)
skill.config_core['lang'] = lang
skill.load_data_files(join(dirname(__file__), 'test_skill'))
return skill


class TestMycroftSkillWaitResponse(TestCase):
def test_wait(self):
"""Ensure that _wait_response() returns the response from converse."""
skill = create_skill()

expected_response = 'Yes I do, very much'

converser = Thread(target=create_converse_responder(expected_response,
skill))
converser.start()
validator = mock.Mock()
validator.return_value = True
is_cancel = mock.Mock()
is_cancel.return_value = False
on_fail = mock.Mock()

response = skill._wait_response(is_cancel, validator, on_fail, 1)
self.assertEqual(response, expected_response)
converser.join()

def test_wait_cancel(self):
"""Test that a matching cancel function cancels the wait."""
skill = create_skill()

converser = Thread(target=create_converse_responder('cancel', skill))
converser.start()
validator = mock.Mock()
validator.return_value = False
on_fail = mock.Mock()

def is_cancel(utterance):
return utterance == 'cancel'

response = skill._wait_response(is_cancel, validator, on_fail, 1)
self.assertEqual(response, None)
converser.join()


class TestMycroftSkillGetResponse(TestCase):
def test_get_response(self):
"""Test response using a dialog file."""
skill = create_skill()
skill._wait_response = mock.Mock()
skill.speak_dialog = mock.Mock()

expected_response = 'ice creamr please'
skill._wait_response.return_value = expected_response
response = skill.get_response('what do you want')
self.assertEqual(response, expected_response)
self.assertTrue(skill.speak_dialog.called)

def test_get_response_text(self):
"""Assert that text is used if no dialog exists."""
skill = create_skill()
skill._wait_response = mock.Mock()
skill.speak_dialog = mock.Mock()

expected_response = 'green'
skill._wait_response.return_value = expected_response
response = skill.get_response('tell me a color')
self.assertEqual(response, expected_response)
self.assertTrue(skill.speak_dialog.called)
skill.speak_dialog.assert_called_with('tell me a color',
{},
expect_response=True,
wait=True)

def test_get_response_no_dialog(self):
"""Check that when no dialog/text is provided listening is triggered.
"""
skill = create_skill()
skill._wait_response = mock.Mock()
skill.speak_dialog = mock.Mock()

expected_response = 'ice creamr please'
skill._wait_response.return_value = expected_response
response = skill.get_response()
self.assertEqual(response, expected_response)
self.assertFalse(skill.speak_dialog.called)
self.assertTrue(skill.bus.emit.called)
sent_message = skill.bus.emit.call_args[0][0]
self.assertEqual(sent_message.msg_type, 'mycroft.mic.listen')

def test_get_response_validator(self):
"""Ensure validator is passed on."""
skill = create_skill()
skill._wait_response = mock.Mock()
skill.speak_dialog = mock.Mock()

def validator(*args, **kwargs):
return True

expected_response = 'ice creamr please'
skill._wait_response.return_value = expected_response
response = skill.get_response('what do you want',
validator=validator)
skill._wait_response.assert_called_with(AnyCallable(), validator,
AnyCallable(), -1)


class TestMycroftSkillAskYesNo(TestCase):
def test_ask_yesno_no(self):
"""Check that a negative response is interpreted as a no."""
skill = create_skill()
skill.get_response = mock.Mock()
skill.get_response.return_value = 'nope'

response = skill.ask_yesno('Do you like breakfast')
self.assertEqual(response, 'no')

def test_ask_yesno_yes(self):
"""Check that an affirmative response is interpreted as a yes."""
skill = create_skill()
skill.get_response = mock.Mock()
skill.get_response.return_value = 'yes'

response = skill.ask_yesno('Do you like breakfast')
self.assertEqual(response, 'yes')

def test_ask_yesno_other(self):
"""Check that non yes no response gets returned."""
skill = create_skill()
skill.get_response = mock.Mock()
skill.get_response.return_value = 'I am a fish'

response = skill.ask_yesno('Do you like breakfast')
self.assertEqual(response, 'I am a fish')

def test_ask_yesno_german(self):
"""Check that when the skill is set to german it responds to "ja"."""
skill = create_skill(lang='de-de')
skill.get_response = mock.Mock()
skill.get_response.return_value = 'ja'

response = skill.ask_yesno('Do you like breakfast')
self.assertEqual(response, 'yes')


class TestMycroftAskSelection(TestCase):
def test_selection_number(self):
"""Test selection by number."""
skill = create_skill()
skill.speak = mock.Mock()
skill.get_response = mock.Mock()

skill.get_response.return_value = 'the third'

options = ['a balloon', 'an octopus', 'a piano']
response = skill.ask_selection(options, 'which is better')
self.assertEqual(options[2], response)

# Assert that the spoken sentence contains all options.
spoken_sentence = skill.speak.call_args[0][0]
for opt in options:
self.assertTrue(opt in spoken_sentence)

def test_selection_last(self):
"""Test selection by "last"."""
skill = create_skill()
skill.speak = mock.Mock()
skill.get_response = mock.Mock()

skill.get_response.return_value = 'last one'

options = ['a balloon', 'an octopus', 'a piano']
response = skill.ask_selection(options, 'which is better')
self.assertEqual(options[2], response)

# Assert that the spoken sentence contains all options.
spoken_sentence = skill.speak.call_args[0][0]
for opt in options:
self.assertTrue(opt in spoken_sentence)

def test_selection_name(self):
"""Test selection by name."""
skill = create_skill()
skill.speak = mock.Mock()
skill.get_response = mock.Mock()

skill.get_response.return_value = 'octopus'

options = ['a balloon', 'an octopus', 'a piano']
response = skill.ask_selection(options, 'which is better')
self.assertEqual(options[1], response)

# Assert that the spoken sentence contains all options.
spoken_sentence = skill.speak.call_args[0][0]
for opt in options:
self.assertTrue(opt in spoken_sentence)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
What do you want

0 comments on commit 3679eb1

Please sign in to comment.