Merge pull request #2459 from forslund/test/common-play-skills
Common play skill testspull/2470/head
commit
74c6a483fd
|
@ -12,21 +12,19 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
import time
|
||||
from os.path import abspath
|
||||
|
||||
from mycroft.messagebus.message import Message
|
||||
|
||||
|
||||
def ensure_uri(s):
|
||||
"""
|
||||
Interprete paths as file:// uri's
|
||||
"""Interprete paths as file:// uri's.
|
||||
|
||||
Args:
|
||||
s: string to be checked
|
||||
Arguments:
|
||||
s: string to be checked
|
||||
|
||||
Returns:
|
||||
if s is uri, s is returned otherwise file:// is prepended
|
||||
Returns:
|
||||
if s is uri, s is returned otherwise file:// is prepended
|
||||
"""
|
||||
if isinstance(s, str):
|
||||
if '://' not in s:
|
||||
|
@ -43,33 +41,25 @@ def ensure_uri(s):
|
|||
|
||||
|
||||
class AudioService:
|
||||
"""
|
||||
AudioService class for interacting with the audio subsystem
|
||||
"""AudioService class for interacting with the audio subsystem
|
||||
|
||||
Arguments:
|
||||
bus: Mycroft messagebus connection
|
||||
Arguments:
|
||||
bus: Mycroft messagebus connection
|
||||
"""
|
||||
|
||||
def __init__(self, bus):
|
||||
self.bus = bus
|
||||
self.bus.on('mycroft.audio.service.track_info_reply',
|
||||
self._track_info)
|
||||
self.info = None
|
||||
|
||||
def _track_info(self, message=None):
|
||||
"""
|
||||
Handler for catching returning track info
|
||||
"""
|
||||
self.info = message.data
|
||||
|
||||
def queue(self, tracks=None):
|
||||
""" Queue up a track to playing playlist.
|
||||
"""Queue up a track to playing playlist.
|
||||
|
||||
Args:
|
||||
tracks: track uri or list of track uri's
|
||||
Arguments:
|
||||
tracks: track uri or list of track uri's
|
||||
Each track can be added as a tuple with (uri, mime)
|
||||
to give a hint of the mime type to the system
|
||||
"""
|
||||
tracks = tracks or []
|
||||
if isinstance(tracks, str):
|
||||
if isinstance(tracks, (str, tuple)):
|
||||
tracks = [tracks]
|
||||
elif not isinstance(tracks, list):
|
||||
raise ValueError
|
||||
|
@ -78,15 +68,15 @@ class AudioService:
|
|||
data={'tracks': tracks}))
|
||||
|
||||
def play(self, tracks=None, utterance=None, repeat=None):
|
||||
""" Start playback.
|
||||
"""Start playback.
|
||||
|
||||
Args:
|
||||
tracks: track uri or list of track uri's
|
||||
Each track can be added as a tuple with (uri, mime)
|
||||
to give a hint of the mime type to the system
|
||||
utterance: forward utterance for further processing by the
|
||||
audio service.
|
||||
repeat: if the playback should be looped
|
||||
Arguments:
|
||||
tracks: track uri or list of track uri's
|
||||
Each track can be added as a tuple with (uri, mime)
|
||||
to give a hint of the mime type to the system
|
||||
utterance: forward utterance for further processing by the
|
||||
audio service.
|
||||
repeat: if the playback should be looped
|
||||
"""
|
||||
repeat = repeat or False
|
||||
tracks = tracks or []
|
||||
|
@ -102,31 +92,30 @@ class AudioService:
|
|||
'repeat': repeat}))
|
||||
|
||||
def stop(self):
|
||||
""" Stop the track. """
|
||||
"""Stop the track."""
|
||||
self.bus.emit(Message('mycroft.audio.service.stop'))
|
||||
|
||||
def next(self):
|
||||
""" Change to next track. """
|
||||
"""Change to next track."""
|
||||
self.bus.emit(Message('mycroft.audio.service.next'))
|
||||
|
||||
def prev(self):
|
||||
""" Change to previous track. """
|
||||
"""Change to previous track."""
|
||||
self.bus.emit(Message('mycroft.audio.service.prev'))
|
||||
|
||||
def pause(self):
|
||||
""" Pause playback. """
|
||||
"""Pause playback."""
|
||||
self.bus.emit(Message('mycroft.audio.service.pause'))
|
||||
|
||||
def resume(self):
|
||||
""" Resume paused playback. """
|
||||
"""Resume paused playback."""
|
||||
self.bus.emit(Message('mycroft.audio.service.resume'))
|
||||
|
||||
def seek(self, seconds=1):
|
||||
"""
|
||||
seek X seconds
|
||||
"""Seek X seconds.
|
||||
|
||||
Args:
|
||||
seconds (int): number of seconds to seek, if negative rewind
|
||||
Arguments:
|
||||
seconds (int): number of seconds to seek, if negative rewind
|
||||
"""
|
||||
if seconds < 0:
|
||||
self.seek_backward(abs(seconds))
|
||||
|
@ -134,42 +123,37 @@ class AudioService:
|
|||
self.seek_forward(seconds)
|
||||
|
||||
def seek_forward(self, seconds=1):
|
||||
"""
|
||||
skip ahead X seconds
|
||||
"""Skip ahead X seconds.
|
||||
|
||||
Args:
|
||||
seconds (int): number of seconds to skip
|
||||
Arguments:
|
||||
seconds (int): number of seconds to skip
|
||||
"""
|
||||
self.bus.emit(Message('mycroft.audio.service.seek_forward',
|
||||
{"seconds": seconds}))
|
||||
|
||||
def seek_backward(self, seconds=1):
|
||||
"""
|
||||
rewind X seconds
|
||||
"""Rewind X seconds
|
||||
|
||||
Args:
|
||||
seconds (int): number of seconds to rewind
|
||||
Arguments:
|
||||
seconds (int): number of seconds to rewind
|
||||
"""
|
||||
self.bus.emit(Message('mycroft.audio.service.seek_backward',
|
||||
{"seconds": seconds}))
|
||||
|
||||
def track_info(self):
|
||||
""" Request information of current playing track.
|
||||
"""Request information of current playing track.
|
||||
|
||||
Returns:
|
||||
Dict with track info.
|
||||
Returns:
|
||||
Dict with track info.
|
||||
"""
|
||||
self.info = None
|
||||
self.bus.emit(Message('mycroft.audio.service.track_info'))
|
||||
wait = 5.0
|
||||
while self.info is None and wait >= 0:
|
||||
time.sleep(0.1)
|
||||
wait -= 0.1
|
||||
|
||||
return self.info or {}
|
||||
info = self.bus.wait_for_response(
|
||||
Message('mycroft.audio.service.track_info'),
|
||||
reply_type='mycroft.audio.service.track_info_reply',
|
||||
timeout=5)
|
||||
return info.data if info else {}
|
||||
|
||||
def available_backends(self):
|
||||
""" Return available audio backends.
|
||||
"""Return available audio backends.
|
||||
|
||||
Returns:
|
||||
dict with backend names as keys
|
||||
|
@ -180,4 +164,5 @@ class AudioService:
|
|||
|
||||
@property
|
||||
def is_playing(self):
|
||||
"""True if the audioservice is playing, else False."""
|
||||
return self.track_info() != {}
|
||||
|
|
|
@ -52,7 +52,8 @@ class CommonPlaySkill(MycroftSkill, ABC):
|
|||
# with a translatable name in their initialize() method.
|
||||
|
||||
def bind(self, bus):
|
||||
""" Overrides the normal bind method.
|
||||
"""Overrides the normal bind method.
|
||||
|
||||
Adds handlers for play:query and play:start messages allowing
|
||||
interaction with the playback control skill.
|
||||
|
||||
|
@ -66,6 +67,7 @@ class CommonPlaySkill(MycroftSkill, ABC):
|
|||
self.add_event('play:start', self.__handle_play_start)
|
||||
|
||||
def __handle_play_query(self, message):
|
||||
"""Query skill if it can start playback from given phrase."""
|
||||
search_phrase = message.data["phrase"]
|
||||
|
||||
# First, notify the requestor that we are attempting to handle
|
||||
|
@ -94,11 +96,19 @@ class CommonPlaySkill(MycroftSkill, ABC):
|
|||
"searching": False}))
|
||||
|
||||
def __calc_confidence(self, match, phrase, level):
|
||||
# "play pandora"
|
||||
# "play pandora is my girlfriend"
|
||||
# "play tom waits on pandora"
|
||||
"""Translate confidence level and match to a 0-1 value.
|
||||
|
||||
# Assume the more of the words that get consumed, the better the match
|
||||
"play pandora"
|
||||
"play pandora is my girlfriend"
|
||||
"play tom waits on pandora"
|
||||
|
||||
Assume the more of the words that get consumed, the better the match
|
||||
|
||||
Arguments:
|
||||
match (str): Matching string
|
||||
phrase (str): original input phrase
|
||||
level (CPSMatchLevel): match level
|
||||
"""
|
||||
consumed_pct = len(match.split()) / len(phrase.split())
|
||||
if consumed_pct > 1.0:
|
||||
consumed_pct = 1.0 / consumed_pct # deal with over/under-matching
|
||||
|
@ -123,6 +133,7 @@ class CommonPlaySkill(MycroftSkill, ABC):
|
|||
return 0.0 # should never happen
|
||||
|
||||
def __handle_play_start(self, message):
|
||||
"""Bus handler for starting playback using the skill."""
|
||||
if message.data["skill_id"] != self.skill_id:
|
||||
# Not for this skill!
|
||||
return
|
||||
|
@ -142,8 +153,7 @@ class CommonPlaySkill(MycroftSkill, ABC):
|
|||
self.CPS_start(phrase, data)
|
||||
|
||||
def CPS_play(self, *args, **kwargs):
|
||||
"""
|
||||
Begin playback of a media file or stream
|
||||
"""Begin playback of a media file or stream
|
||||
|
||||
Normally this method will be invoked with somthing like:
|
||||
self.CPS_play(url)
|
||||
|
@ -160,6 +170,7 @@ class CommonPlaySkill(MycroftSkill, ABC):
|
|||
self.audioservice.play(*args, **kwargs)
|
||||
|
||||
def stop(self):
|
||||
"""Stop anything playing on the audioservice."""
|
||||
if self.audioservice.is_playing:
|
||||
self.audioservice.stop()
|
||||
return True
|
||||
|
@ -172,11 +183,9 @@ class CommonPlaySkill(MycroftSkill, ABC):
|
|||
# act as a CommonPlay Skill
|
||||
@abstractmethod
|
||||
def CPS_match_query_phrase(self, phrase):
|
||||
"""
|
||||
Analyze phrase to see if it is a play-able phrase with this
|
||||
skill.
|
||||
"""Analyze phrase to see if it is a play-able phrase with this skill.
|
||||
|
||||
Args:
|
||||
Arguments:
|
||||
phrase (str): User phrase uttered after "Play", e.g. "some music"
|
||||
|
||||
Returns:
|
||||
|
@ -204,10 +213,9 @@ class CommonPlaySkill(MycroftSkill, ABC):
|
|||
|
||||
@abstractmethod
|
||||
def CPS_start(self, phrase, data):
|
||||
"""
|
||||
Begin playing whatever is specified in 'phrase'
|
||||
"""Begin playing whatever is specified in 'phrase'
|
||||
|
||||
Args:
|
||||
Arguments:
|
||||
phrase (str): User phrase uttered after "Play", e.g. "some music"
|
||||
data (dict): Callback data specified in match_query_phrase()
|
||||
"""
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
from unittest import TestCase, mock
|
||||
|
||||
from mycroft.messagebus import Message
|
||||
from mycroft.skills.audioservice import AudioService
|
||||
|
||||
|
||||
class TestAudioServiceControls(TestCase):
|
||||
def assertLastMessageTypeEqual(self, bus, msg_type):
|
||||
message = bus.emit.call_args_list[-1][0][0]
|
||||
self.assertEqual(message.msg_type, msg_type)
|
||||
|
||||
def setUp(self):
|
||||
self.bus = mock.Mock(name='bus')
|
||||
self.audioservice = AudioService(self.bus)
|
||||
|
||||
def test_pause(self):
|
||||
self.audioservice.pause()
|
||||
self.assertLastMessageTypeEqual(self.bus,
|
||||
'mycroft.audio.service.pause')
|
||||
|
||||
def test_resume(self):
|
||||
self.audioservice.resume()
|
||||
self.assertLastMessageTypeEqual(self.bus,
|
||||
'mycroft.audio.service.resume')
|
||||
|
||||
def test_next(self):
|
||||
self.audioservice.next()
|
||||
self.assertLastMessageTypeEqual(self.bus, 'mycroft.audio.service.next')
|
||||
|
||||
def test_prev(self):
|
||||
self.audioservice.prev()
|
||||
self.assertLastMessageTypeEqual(self.bus, 'mycroft.audio.service.prev')
|
||||
|
||||
def test_stop(self):
|
||||
self.audioservice.stop()
|
||||
self.assertLastMessageTypeEqual(self.bus, 'mycroft.audio.service.stop')
|
||||
|
||||
def test_seek(self):
|
||||
self.audioservice.seek()
|
||||
message = self.bus.emit.call_args_list[-1][0][0]
|
||||
self.assertEqual(message.msg_type,
|
||||
'mycroft.audio.service.seek_forward')
|
||||
self.assertEqual(message.data['seconds'], 1)
|
||||
self.audioservice.seek(5)
|
||||
message = self.bus.emit.call_args_list[-1][0][0]
|
||||
self.assertEqual(message.msg_type,
|
||||
'mycroft.audio.service.seek_forward')
|
||||
self.assertEqual(message.data['seconds'], 5)
|
||||
self.audioservice.seek(-5)
|
||||
message = self.bus.emit.call_args_list[-1][0][0]
|
||||
self.assertEqual(message.msg_type,
|
||||
'mycroft.audio.service.seek_backward')
|
||||
self.assertEqual(message.data['seconds'], 5)
|
||||
|
||||
|
||||
class TestAudioServicePlay(TestCase):
|
||||
def setUp(self):
|
||||
self.bus = mock.Mock(name='bus')
|
||||
self.audioservice = AudioService(self.bus)
|
||||
|
||||
def test_proper_uri(self):
|
||||
self.audioservice.play('file:///hello_nasty.mp3')
|
||||
message = self.bus.emit.call_args_list[-1][0][0]
|
||||
self.assertEqual(message.msg_type, 'mycroft.audio.service.play')
|
||||
self.assertEqual(message.data['tracks'], ['file:///hello_nasty.mp3'])
|
||||
self.assertEqual(message.data['repeat'], False)
|
||||
|
||||
def test_path(self):
|
||||
self.audioservice.play('/hello_nasty.mp3')
|
||||
message = self.bus.emit.call_args_list[-1][0][0]
|
||||
self.assertEqual(message.msg_type, 'mycroft.audio.service.play')
|
||||
self.assertEqual(message.data['tracks'], ['file:///hello_nasty.mp3'])
|
||||
self.assertEqual(message.data['repeat'], False)
|
||||
|
||||
def test_tuple(self):
|
||||
"""Test path together with mimetype."""
|
||||
self.audioservice.play(('/hello_nasty.mp3', 'audio/mp3'))
|
||||
message = self.bus.emit.call_args_list[-1][0][0]
|
||||
self.assertEqual(message.msg_type, 'mycroft.audio.service.play')
|
||||
self.assertEqual(message.data['tracks'],
|
||||
[('file:///hello_nasty.mp3', 'audio/mp3')])
|
||||
self.assertEqual(message.data['repeat'], False)
|
||||
|
||||
def test_invalid(self):
|
||||
"""Test play request with invalid type."""
|
||||
with self.assertRaises(ValueError):
|
||||
self.audioservice.play(12)
|
||||
|
||||
def test_extra_arguments(self):
|
||||
"""Test sending along utterance and setting repeat."""
|
||||
self.audioservice.play('/hello_nasty.mp3', 'on vlc', True)
|
||||
message = self.bus.emit.call_args_list[-1][0][0]
|
||||
self.assertEqual(message.msg_type, 'mycroft.audio.service.play')
|
||||
self.assertEqual(message.data['tracks'], ['file:///hello_nasty.mp3'])
|
||||
self.assertEqual(message.data['repeat'], True)
|
||||
self.assertEqual(message.data['utterance'], 'on vlc')
|
||||
|
||||
|
||||
class TestAudioServiceQueue(TestCase):
|
||||
def setUp(self):
|
||||
self.bus = mock.Mock(name='bus')
|
||||
self.audioservice = AudioService(self.bus)
|
||||
|
||||
def test_uri(self):
|
||||
self.audioservice.queue('file:///hello_nasty.mp3')
|
||||
message = self.bus.emit.call_args_list[-1][0][0]
|
||||
self.assertEqual(message.msg_type, 'mycroft.audio.service.queue')
|
||||
self.assertEqual(message.data['tracks'], ['file:///hello_nasty.mp3'])
|
||||
|
||||
def test_path(self):
|
||||
self.audioservice.queue('/hello_nasty.mp3')
|
||||
message = self.bus.emit.call_args_list[-1][0][0]
|
||||
self.assertEqual(message.msg_type, 'mycroft.audio.service.queue')
|
||||
self.assertEqual(message.data['tracks'], ['file:///hello_nasty.mp3'])
|
||||
|
||||
def test_tuple(self):
|
||||
self.audioservice.queue(('/hello_nasty.mp3', 'audio/mp3'))
|
||||
message = self.bus.emit.call_args_list[-1][0][0]
|
||||
self.assertEqual(message.msg_type, 'mycroft.audio.service.queue')
|
||||
self.assertEqual(message.data['tracks'],
|
||||
[('file:///hello_nasty.mp3', 'audio/mp3')])
|
||||
|
||||
def test_invalid(self):
|
||||
with self.assertRaises(ValueError):
|
||||
self.audioservice.queue(12)
|
||||
|
||||
|
||||
class TestAudioServiceMisc(TestCase):
|
||||
def test_lifecycle(self):
|
||||
bus = mock.Mock(name='bus')
|
||||
audioservice = AudioService(bus)
|
||||
self.assertEqual(audioservice.bus, bus)
|
||||
|
||||
def test_available_backends(self):
|
||||
bus = mock.Mock(name='bus')
|
||||
audioservice = AudioService(bus)
|
||||
|
||||
available_backends = {
|
||||
'simple': {
|
||||
'suported_uris': ['http', 'file'],
|
||||
'default': True,
|
||||
'remote': False
|
||||
}
|
||||
}
|
||||
bus.wait_for_response.return_value = Message('test_msg',
|
||||
available_backends)
|
||||
response = audioservice.available_backends()
|
||||
self.assertEqual(available_backends, response)
|
||||
# Check no response behaviour
|
||||
bus.wait_for_response.return_value = None
|
||||
response = audioservice.available_backends()
|
||||
self.assertEqual({}, response)
|
||||
|
||||
def test_track_info(self):
|
||||
"""Test is_playing property."""
|
||||
bus = mock.Mock(name='bus')
|
||||
audioservice = AudioService(bus)
|
||||
info = {'album': 'Hello Nasty',
|
||||
'artist': 'Beastie Boys',
|
||||
'name': 'Intergalactic'
|
||||
}
|
||||
bus.wait_for_response.return_value = Message('test_msg', info)
|
||||
self.assertEqual(audioservice.track_info(), info)
|
||||
bus.wait_for_response.return_value = None
|
||||
self.assertEqual(audioservice.track_info(), {})
|
||||
|
||||
def test_is_playing(self):
|
||||
"""Test is_playing property."""
|
||||
bus = mock.Mock(name='bus')
|
||||
audioservice = AudioService(bus)
|
||||
audioservice.track_info = mock.Mock()
|
||||
|
||||
audioservice.track_info.return_value = {'track': 'one cool song'}
|
||||
self.assertTrue(audioservice.is_playing)
|
||||
audioservice.track_info.return_value = {}
|
||||
self.assertFalse(audioservice.is_playing)
|
|
@ -0,0 +1,140 @@
|
|||
from unittest import TestCase, mock
|
||||
|
||||
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)
|
||||
|
||||
|
||||
class TestCommonPlay(TestCase):
|
||||
def setUp(self):
|
||||
self.skill = CPSTest()
|
||||
self.bus = mock.Mock(name='bus')
|
||||
self.skill.bind(self.bus)
|
||||
self.audioservice = mock.Mock(name='audioservice')
|
||||
self.skill.audioservice = self.audioservice
|
||||
|
||||
def test_lifecycle(self):
|
||||
skill = CPSTest()
|
||||
bus = mock.Mock(name='bus')
|
||||
skill.bind(bus)
|
||||
self.assertTrue(isinstance(skill.audioservice, AudioService))
|
||||
bus.on.assert_any_call('play:query', AnyCallable())
|
||||
bus.on.assert_any_call('play:start', AnyCallable())
|
||||
skill.shutdown()
|
||||
|
||||
def test_handle_start_playback(self):
|
||||
"""Test common play start method."""
|
||||
self.skill.audioservice.is_playing = True
|
||||
start_playback = self.bus.on.call_args_list[-1][0][1]
|
||||
|
||||
phrase = 'Don\'t open until doomsday'
|
||||
start_playback(Message('play:start', data={'phrase': phrase,
|
||||
'skill_id': 'asdf'}))
|
||||
self.skill.CPS_start.assert_not_called()
|
||||
|
||||
self.bus.emit.reset_mock()
|
||||
start_playback(Message('play:start',
|
||||
data={'phrase': phrase,
|
||||
'skill_id': self.skill.skill_id}))
|
||||
self.audioservice.stop.assert_called_once_with()
|
||||
self.skill.CPS_start.assert_called_once_with(phrase, None)
|
||||
|
||||
def test_cps_play(self):
|
||||
"""Test audioservice play helper."""
|
||||
self.skill.play_service_string = 'play on godzilla'
|
||||
self.skill.CPS_play(['looking_for_freedom.mp3'],
|
||||
utterance='play on mothra')
|
||||
self.audioservice.play.assert_called_once_with(
|
||||
['looking_for_freedom.mp3'], utterance='play on mothra')
|
||||
|
||||
self.audioservice.play.reset_mock()
|
||||
# Assert that the utterance is injected
|
||||
self.skill.CPS_play(['looking_for_freedom.mp3'])
|
||||
self.audioservice.play.assert_called_once_with(
|
||||
['looking_for_freedom.mp3'], utterance='play on godzilla')
|
||||
|
||||
def test_stop(self):
|
||||
"""Test default reaction to stop command."""
|
||||
self.audioservice.is_playing = False
|
||||
self.assertFalse(self.skill.stop())
|
||||
|
||||
self.audioservice.is_playing = True
|
||||
self.assertTrue(self.skill.stop())
|
||||
|
||||
|
||||
class TestCPSQuery(TestCase):
|
||||
def setUp(self):
|
||||
self.skill = CPSTest()
|
||||
self.bus = mock.Mock(name='bus')
|
||||
self.skill.bind(self.bus)
|
||||
self.audioservice = mock.Mock(name='audioservice')
|
||||
self.skill.audioservice = self.audioservice
|
||||
self.query_phrase = self.bus.on.call_args_list[-2][0][1]
|
||||
|
||||
def test_handle_play_query_no_match(self):
|
||||
"""Test common play match when no match is found."""
|
||||
|
||||
# Check Not matching queries
|
||||
self.skill.CPS_match_query_phrase.return_value = None
|
||||
self.query_phrase(Message('play:query',
|
||||
data={'phrase': 'Monster mash'}))
|
||||
|
||||
# Check that the skill replied that it was searching
|
||||
extension = self.bus.emit.call_args_list[-2][0][0]
|
||||
self.assertEqual(extension.data['phrase'], 'Monster mash')
|
||||
self.assertEqual(extension.data['skill_id'], self.skill.skill_id)
|
||||
self.assertEqual(extension.data['searching'], True)
|
||||
|
||||
# Assert that the skill reported that it couldn't find the phrase
|
||||
response = self.bus.emit.call_args_list[-1][0][0]
|
||||
self.assertEqual(response.data['phrase'], 'Monster mash')
|
||||
self.assertEqual(response.data['skill_id'], self.skill.skill_id)
|
||||
self.assertEqual(response.data['searching'], False)
|
||||
|
||||
def test_play_query_match(self):
|
||||
"""Test common play match when a match is found."""
|
||||
phrase = 'Don\'t open until doomsday'
|
||||
self.skill.CPS_match_query_phrase.return_value = (phrase,
|
||||
CPSMatchLevel.TITLE)
|
||||
self.query_phrase(Message('play:query',
|
||||
data={'phrase': phrase}))
|
||||
# Assert that the skill reported the correct confidence
|
||||
response = self.bus.emit.call_args_list[-1][0][0]
|
||||
self.assertEqual(response.data['phrase'], phrase)
|
||||
self.assertEqual(response.data['skill_id'], self.skill.skill_id)
|
||||
self.assertAlmostEqual(response.data['conf'], 0.85)
|
||||
|
||||
# Partial phrase match
|
||||
self.skill.CPS_match_query_phrase.return_value = ('until doomsday',
|
||||
CPSMatchLevel.TITLE)
|
||||
self. query_phrase(Message('play:query',
|
||||
data={'phrase': phrase}))
|
||||
# Assert that the skill reported the correct confidence
|
||||
response = self.bus.emit.call_args_list[-1][0][0]
|
||||
self.assertEqual(response.data['phrase'], phrase)
|
||||
self.assertEqual(response.data['skill_id'], self.skill.skill_id)
|
||||
self.assertAlmostEqual(response.data['conf'], 0.825)
|
||||
|
||||
|
||||
class CPSTest(CommonPlaySkill):
|
||||
"""Simple skill for testing the CommonPlaySkill"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.CPS_match_query_phrase = mock.Mock(name='match_phrase')
|
||||
self.CPS_start = mock.Mock(name='start_playback')
|
||||
self.skill_id = 'CPSTest'
|
||||
|
||||
def CPS_match_query_phrase(self, phrase):
|
||||
pass
|
||||
|
||||
def CPS_start(self, data):
|
||||
pass
|
Loading…
Reference in New Issue