class TestFireTVSyncPython(unittest.TestCase):
    ADB_ATTR = "_adb"
    PATCH_KEY = "python"

    def setUp(self):
        with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
                self.PATCH_KEY], patchers.patch_shell("")[self.PATCH_KEY]:
            self.ftv = FireTVSync("HOST", 5555)
            self.ftv.adb_connect()

    def test_turn_on_off(self):
        """Test that the ``FireTVSync.turn_on`` and ``FireTVSync.turn_off`` methods work correctly."""
        with patchers.patch_connect(True)[
                self.PATCH_KEY], patchers.patch_shell("")[self.PATCH_KEY]:
            self.ftv.turn_on()
            self.assertEqual(
                getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd,
                constants.CMD_SCREEN_ON +
                " || (input keyevent {0} && input keyevent {1})".format(
                    constants.KEY_POWER, constants.KEY_HOME),
            )

            self.ftv.turn_off()
            self.assertEqual(
                getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd,
                constants.CMD_SCREEN_ON +
                " && input keyevent {0}".format(constants.KEY_SLEEP),
            )

    def test_send_intent(self):
        """Test that the ``_send_intent`` method works correctly."""
        with patchers.patch_connect(True)[
                self.PATCH_KEY], patchers.patch_shell("output\r\nretcode")[
                    self.PATCH_KEY]:
            result = self.ftv._send_intent("TEST",
                                           constants.INTENT_LAUNCH_FIRETV)
            self.assertEqual(
                getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd,
                "monkey -p TEST -c android.intent.category.LAUNCHER 1; echo $?",
            )
            self.assertDictEqual(result, {
                "output": "output",
                "retcode": "retcode"
            })

        with patchers.patch_connect(True)[
                self.PATCH_KEY], patchers.patch_shell(None)[self.PATCH_KEY]:
            result = self.ftv._send_intent("TEST",
                                           constants.INTENT_LAUNCH_FIRETV)
            self.assertEqual(
                getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd,
                "monkey -p TEST -c android.intent.category.LAUNCHER 1; echo $?",
            )
            self.assertDictEqual(result, {})

    def test_launch_app_stop_app(self):
        """Test that the ``FireTVSync.launch_app`` and ``FireTVSync.stop_app`` methods work correctly."""
        with patchers.patch_connect(True)[
                self.PATCH_KEY], patchers.patch_shell(None)[self.PATCH_KEY]:
            self.ftv.launch_app("TEST")
            self.assertEqual(
                getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd,
                constants.CMD_LAUNCH_APP_FIRETV.format("TEST"))

            self.ftv.stop_app("TEST")
            self.assertEqual(
                getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd,
                "am force-stop TEST")

    def test_running_apps(self):
        """Check that the ``running_apps`` property works correctly."""
        with patchers.patch_shell(None)[self.PATCH_KEY]:
            running_apps = self.ftv.running_apps()
            self.assertIsNone(running_apps, None)

        with patchers.patch_shell("")[self.PATCH_KEY]:
            running_apps = self.ftv.running_apps()
            self.assertIsNone(running_apps, None)

        with patchers.patch_shell(RUNNING_APPS_OUTPUT)[self.PATCH_KEY]:
            running_apps = self.ftv.running_apps()
            self.assertListEqual(running_apps, RUNNING_APPS_LIST)

    def test_get_properties(self):
        """Check that ``get_properties()`` works correctly."""
        with patchers.patch_shell(None)[self.PATCH_KEY]:
            with patchers.patch_calls(
                    self.ftv, self.ftv.screen_on_awake_wake_lock_size
            ) as screen_on_awake_wake_lock_size, patchers.patch_calls(
                    self.ftv, self.ftv.current_app_media_session_state
            ) as current_app_media_session_state, patchers.patch_calls(
                    self.ftv, self.ftv.
                    running_apps) as running_apps, patchers.patch_calls(
                        self.ftv, self.ftv.get_hdmi_input) as get_hdmi_input:
                self.ftv.get_properties(lazy=True)
                assert screen_on_awake_wake_lock_size.called
                assert not current_app_media_session_state.called
                assert not running_apps.called
                assert not get_hdmi_input.called

            with patchers.patch_calls(
                    self.ftv, self.ftv.screen_on_awake_wake_lock_size
            ) as screen_on_awake_wake_lock_size, patchers.patch_calls(
                    self.ftv, self.ftv.current_app_media_session_state
            ) as current_app_media_session_state, patchers.patch_calls(
                    self.ftv, self.ftv.
                    running_apps) as running_apps, patchers.patch_calls(
                        self.ftv, self.ftv.get_hdmi_input) as get_hdmi_input:
                self.ftv.get_properties(lazy=False, get_running_apps=True)
                assert screen_on_awake_wake_lock_size.called
                assert current_app_media_session_state.called
                assert running_apps.called
                assert get_hdmi_input.called

            with patchers.patch_calls(
                    self.ftv, self.ftv.screen_on_awake_wake_lock_size
            ) as screen_on_awake_wake_lock_size, patchers.patch_calls(
                    self.ftv, self.ftv.current_app_media_session_state
            ) as current_app_media_session_state, patchers.patch_calls(
                    self.ftv, self.ftv.
                    running_apps) as running_apps, patchers.patch_calls(
                        self.ftv, self.ftv.get_hdmi_input) as get_hdmi_input:
                self.ftv.get_properties(lazy=False, get_running_apps=False)
                assert screen_on_awake_wake_lock_size.called
                assert current_app_media_session_state.called
                assert not running_apps.called
                assert get_hdmi_input.called

    def test_get_properties_dict(self):
        """Check that ``get_properties_dict()`` works correctly."""
        with patchers.patch_shell(None)[self.PATCH_KEY]:
            with patchers.patch_calls(
                    self.ftv, self.ftv.get_properties) as get_properties:
                self.ftv.get_properties_dict()
                assert get_properties.called

    def test_update(self):
        """Check that the ``update`` method works correctly."""
        with patchers.patch_connect(False)[self.PATCH_KEY]:
            self.ftv.adb_connect()

        self.assertTupleEqual(self.ftv.update(), STATE_NONE)

    def assertUpdate(self, get_properties, update):
        """Check that the results of the `update` method are as expected."""
        with patch("androidtv.firetv.firetv_sync.FireTVSync.get_properties",
                   return_value=get_properties):
            self.assertTupleEqual(self.ftv.update(), update)

    def test_state_detection(self):
        """Check that the state detection works as expected."""
        self.assertUpdate([False, None, -1, None, None, None, None],
                          (constants.STATE_OFF, None, None, None))

        self.assertUpdate([True, False, -1, None, None, None, None],
                          (constants.STATE_STANDBY, None, None, None))

        self.assertUpdate(
            [True, True, 1, "com.amazon.tv.launcher", None, None, None],
            (constants.STATE_IDLE, "com.amazon.tv.launcher",
             ["com.amazon.tv.launcher"], None),
        )

        # Amazon Video
        self.assertUpdate(
            [
                True, True, 1, constants.APP_AMAZON_VIDEO, 3,
                [constants.APP_AMAZON_VIDEO], None
            ],
            (constants.STATE_PLAYING, constants.APP_AMAZON_VIDEO,
             [constants.APP_AMAZON_VIDEO], None),
        )

        self.assertUpdate(
            [
                True, True, 1, constants.APP_AMAZON_VIDEO, 2,
                [constants.APP_AMAZON_VIDEO], None
            ],
            (constants.STATE_PAUSED, constants.APP_AMAZON_VIDEO,
             [constants.APP_AMAZON_VIDEO], None),
        )

        self.assertUpdate(
            [
                True, True, 1, constants.APP_AMAZON_VIDEO, 1,
                [constants.APP_AMAZON_VIDEO], None
            ],
            (constants.STATE_IDLE, constants.APP_AMAZON_VIDEO,
             [constants.APP_AMAZON_VIDEO], None),
        )

        # Amazon Video with custom state detection rules
        self.ftv._state_detection_rules = {
            constants.APP_AMAZON_VIDEO: ["media_session_state"]
        }

        self.assertUpdate(
            [
                True, True, 2, constants.APP_AMAZON_VIDEO, 2,
                [constants.APP_AMAZON_VIDEO], None
            ],
            (constants.STATE_PAUSED, constants.APP_AMAZON_VIDEO,
             [constants.APP_AMAZON_VIDEO], None),
        )

        self.assertUpdate(
            [
                True, True, 5, constants.APP_AMAZON_VIDEO, 3,
                [constants.APP_AMAZON_VIDEO], None
            ],
            (constants.STATE_PLAYING, constants.APP_AMAZON_VIDEO,
             [constants.APP_AMAZON_VIDEO], None),
        )

        self.assertUpdate(
            [
                True, True, 5, constants.APP_AMAZON_VIDEO, 1,
                [constants.APP_AMAZON_VIDEO], None
            ],
            (constants.STATE_IDLE, constants.APP_AMAZON_VIDEO,
             [constants.APP_AMAZON_VIDEO], None),
        )

        self.ftv._state_detection_rules = {
            constants.APP_AMAZON_VIDEO: [{
                "standby": {
                    "media_session_state": 2
                }
            }]
        }
        self.assertUpdate(
            [
                True, True, 2, constants.APP_AMAZON_VIDEO, None,
                [constants.APP_AMAZON_VIDEO], None
            ],
            (constants.STATE_IDLE, constants.APP_AMAZON_VIDEO,
             [constants.APP_AMAZON_VIDEO], None),
        )

        # Firefox
        self.assertUpdate(
            [
                True, True, 3, constants.APP_FIREFOX, 3,
                [constants.APP_FIREFOX], None
            ],
            (constants.STATE_PLAYING, constants.APP_FIREFOX,
             [constants.APP_FIREFOX], None),
        )

        self.assertUpdate(
            [
                True, True, 1, constants.APP_FIREFOX, 3,
                [constants.APP_FIREFOX], None
            ],
            (constants.STATE_IDLE, constants.APP_FIREFOX,
             [constants.APP_FIREFOX], None),
        )

        # Hulu
        self.assertUpdate(
            [True, True, 4, constants.APP_HULU, 3, [constants.APP_HULU], None],
            (constants.STATE_PLAYING, constants.APP_HULU, [constants.APP_HULU
                                                           ], None),
        )

        self.assertUpdate(
            [True, True, 2, constants.APP_HULU, 3, [constants.APP_HULU], None],
            (constants.STATE_PAUSED, constants.APP_HULU, [constants.APP_HULU
                                                          ], None),
        )

        self.assertUpdate(
            [True, True, 1, constants.APP_HULU, 3, [constants.APP_HULU], None],
            (constants.STATE_IDLE, constants.APP_HULU, [constants.APP_HULU
                                                        ], None),
        )

        # Jellyfin
        self.assertUpdate(
            [
                True, True, 2, constants.APP_JELLYFIN_TV, 3,
                [constants.APP_JELLYFIN_TV], None
            ],
            (constants.STATE_PLAYING, constants.APP_JELLYFIN_TV,
             [constants.APP_JELLYFIN_TV], None),
        )

        self.assertUpdate(
            [
                True, True, 4, constants.APP_JELLYFIN_TV, 3,
                [constants.APP_JELLYFIN_TV], None
            ],
            (constants.STATE_PAUSED, constants.APP_JELLYFIN_TV,
             [constants.APP_JELLYFIN_TV], None),
        )

        # Netfilx
        self.assertUpdate(
            [
                True, True, 1, constants.APP_NETFLIX, 3,
                [constants.APP_NETFLIX], None
            ],
            (constants.STATE_PLAYING, constants.APP_NETFLIX,
             [constants.APP_NETFLIX], None),
        )

        self.assertUpdate(
            [
                True, True, 1, constants.APP_NETFLIX, 2,
                [constants.APP_NETFLIX], None
            ],
            (constants.STATE_PAUSED, constants.APP_NETFLIX,
             [constants.APP_NETFLIX], None),
        )

        self.assertUpdate(
            [
                True, True, 1, constants.APP_NETFLIX, 1,
                [constants.APP_NETFLIX], None
            ],
            (constants.STATE_IDLE, constants.APP_NETFLIX,
             [constants.APP_NETFLIX], None),
        )

        # Plex
        self.assertUpdate(
            [True, True, 1, constants.APP_PLEX, 3, [constants.APP_PLEX], None],
            (constants.STATE_PLAYING, constants.APP_PLEX, [constants.APP_PLEX
                                                           ], None),
        )

        self.assertUpdate(
            [True, True, 2, constants.APP_PLEX, 3, [constants.APP_PLEX], None],
            (constants.STATE_PAUSED, constants.APP_PLEX, [constants.APP_PLEX
                                                          ], None),
        )

        self.assertUpdate(
            [True, True, 1, constants.APP_PLEX, 1, [constants.APP_PLEX], None],
            (constants.STATE_IDLE, constants.APP_PLEX, [constants.APP_PLEX
                                                        ], None),
        )

        # Sport 1
        self.assertUpdate(
            [
                True, True, 3, constants.APP_SPORT1, 3, [constants.APP_SPORT1],
                None
            ],
            (constants.STATE_PLAYING, constants.APP_SPORT1,
             [constants.APP_SPORT1], None),
        )

        self.assertUpdate(
            [
                True, True, 2, constants.APP_SPORT1, 3, [constants.APP_SPORT1],
                None
            ],
            (constants.STATE_PAUSED, constants.APP_SPORT1,
             [constants.APP_SPORT1], None),
        )

        self.assertUpdate(
            [
                True, True, 1, constants.APP_SPORT1, 3, [constants.APP_SPORT1],
                None
            ],
            (constants.STATE_IDLE, constants.APP_SPORT1,
             [constants.APP_SPORT1], None),
        )

        # Spotify
        self.assertUpdate(
            [
                True, True, 1, constants.APP_SPOTIFY, 3,
                [constants.APP_SPOTIFY], None
            ],
            (constants.STATE_PLAYING, constants.APP_SPOTIFY,
             [constants.APP_SPOTIFY], None),
        )

        self.assertUpdate(
            [
                True, True, 1, constants.APP_SPOTIFY, 2,
                [constants.APP_SPOTIFY], None
            ],
            (constants.STATE_PAUSED, constants.APP_SPOTIFY,
             [constants.APP_SPOTIFY], None),
        )

        self.assertUpdate(
            [
                True, True, 1, constants.APP_SPOTIFY, 1,
                [constants.APP_SPOTIFY], None
            ],
            (constants.STATE_IDLE, constants.APP_SPOTIFY,
             [constants.APP_SPOTIFY], None),
        )

        # Twitch
        self.assertUpdate(
            [
                True, True, 2, constants.APP_TWITCH_FIRETV, 3,
                [constants.APP_TWITCH_FIRETV], None
            ],
            (constants.STATE_PAUSED, constants.APP_TWITCH_FIRETV,
             [constants.APP_TWITCH_FIRETV], None),
        )

        self.assertUpdate(
            [
                True, True, 1, constants.APP_TWITCH_FIRETV, 3,
                [constants.APP_TWITCH_FIRETV], None
            ],
            (constants.STATE_PLAYING, constants.APP_TWITCH_FIRETV,
             [constants.APP_TWITCH_FIRETV], None),
        )

        self.assertUpdate(
            [
                True, True, 1, constants.APP_TWITCH_FIRETV, 4,
                [constants.APP_TWITCH_FIRETV], None
            ],
            (constants.STATE_PLAYING, constants.APP_TWITCH_FIRETV,
             [constants.APP_TWITCH_FIRETV], None),
        )

        self.assertUpdate(
            [
                True, True, 1, constants.APP_TWITCH_FIRETV, 1,
                [constants.APP_TWITCH_FIRETV], None
            ],
            (constants.STATE_IDLE, constants.APP_TWITCH_FIRETV,
             [constants.APP_TWITCH_FIRETV], None),
        )

        # Waipu TV
        self.assertUpdate(
            [
                True, True, 3, constants.APP_WAIPU_TV, 1,
                [constants.APP_WAIPU_TV], None
            ],
            (constants.STATE_PLAYING, constants.APP_WAIPU_TV,
             [constants.APP_WAIPU_TV], None),
        )

        self.assertUpdate(
            [
                True, True, 2, constants.APP_WAIPU_TV, 1,
                [constants.APP_WAIPU_TV], None
            ],
            (constants.STATE_PAUSED, constants.APP_WAIPU_TV,
             [constants.APP_WAIPU_TV], None),
        )

        self.assertUpdate(
            [
                True, True, 1, constants.APP_WAIPU_TV, 1,
                [constants.APP_WAIPU_TV], None
            ],
            (constants.STATE_IDLE, constants.APP_WAIPU_TV,
             [constants.APP_WAIPU_TV], None),
        )

        # Unknown app
        self.assertUpdate(
            [True, True, 1, UNKNOWN_APP, 3, [UNKNOWN_APP], None],
            (constants.STATE_PLAYING, UNKNOWN_APP, [UNKNOWN_APP], None),
        )

        self.assertUpdate(
            [True, True, 1, UNKNOWN_APP, 2, [UNKNOWN_APP], None],
            (constants.STATE_PAUSED, UNKNOWN_APP, [UNKNOWN_APP], None),
        )

        self.assertUpdate(
            [True, True, 1, UNKNOWN_APP, 1, [UNKNOWN_APP], None],
            (constants.STATE_IDLE, UNKNOWN_APP, [UNKNOWN_APP], None),
        )

        self.assertUpdate(
            [True, True, 1, UNKNOWN_APP, None, [UNKNOWN_APP], None],
            (constants.STATE_PLAYING, UNKNOWN_APP, [UNKNOWN_APP], None),
        )

        self.assertUpdate(
            [True, True, 2, UNKNOWN_APP, None, [UNKNOWN_APP], None],
            (constants.STATE_PAUSED, UNKNOWN_APP, [UNKNOWN_APP], None),
        )
Пример #2
0
class TestFireTVSyncPython(unittest.TestCase):
    ADB_ATTR = '_adb'
    PATCH_KEY = 'python'

    def setUp(self):
        with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
                self.PATCH_KEY], patchers.patch_shell('')[self.PATCH_KEY]:
            self.ftv = FireTVSync('HOST', 5555)
            self.ftv.adb_connect()

    def test_turn_on_off(self):
        """Test that the ``FireTVSync.turn_on`` and ``FireTVSync.turn_off`` methods work correctly.

        """
        with patchers.patch_connect(True)[
                self.PATCH_KEY], patchers.patch_shell('')[self.PATCH_KEY]:
            self.ftv.turn_on()
            self.assertEqual(
                getattr(self.ftv._adb,
                        self.ADB_ATTR).shell_cmd, constants.CMD_SCREEN_ON +
                " || (input keyevent {0} && input keyevent {1})".format(
                    constants.KEY_POWER, constants.KEY_HOME))

            self.ftv.turn_off()
            self.assertEqual(
                getattr(self.ftv._adb,
                        self.ADB_ATTR).shell_cmd, constants.CMD_SCREEN_ON +
                " && input keyevent {0}".format(constants.KEY_SLEEP))

    def test_send_intent(self):
        """Test that the ``_send_intent`` method works correctly.

        """
        with patchers.patch_connect(True)[
                self.PATCH_KEY], patchers.patch_shell('output\r\nretcode')[
                    self.PATCH_KEY]:
            result = self.ftv._send_intent("TEST", constants.INTENT_LAUNCH)
            self.assertEqual(
                getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd,
                "monkey -p TEST -c android.intent.category.LAUNCHER 1; echo $?"
            )
            self.assertDictEqual(result, {
                'output': 'output',
                'retcode': 'retcode'
            })

        with patchers.patch_connect(True)[
                self.PATCH_KEY], patchers.patch_shell(None)[self.PATCH_KEY]:
            result = self.ftv._send_intent("TEST", constants.INTENT_LAUNCH)
            self.assertEqual(
                getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd,
                "monkey -p TEST -c android.intent.category.LAUNCHER 1; echo $?"
            )
            self.assertDictEqual(result, {})

    def test_launch_app_stop_app(self):
        """Test that the ``FireTVSync.launch_app`` and ``FireTVSync.stop_app`` methods work correctly.

        """
        with patchers.patch_connect(True)[
                self.PATCH_KEY], patchers.patch_shell(None)[self.PATCH_KEY]:
            self.ftv.launch_app("TEST")
            self.assertEqual(
                getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd,
                constants.CMD_LAUNCH_APP.format("TEST"))

            self.ftv.stop_app("TEST")
            self.assertEqual(
                getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd,
                "am force-stop TEST")

    def test_running_apps(self):
        """Check that the ``running_apps`` property works correctly.

        """
        with patchers.patch_shell(None)[self.PATCH_KEY]:
            running_apps = self.ftv.running_apps()
            self.assertIsNone(running_apps, None)

        with patchers.patch_shell('')[self.PATCH_KEY]:
            running_apps = self.ftv.running_apps()
            self.assertIsNone(running_apps, None)

        with patchers.patch_shell(RUNNING_APPS_OUTPUT)[self.PATCH_KEY]:
            running_apps = self.ftv.running_apps()
            self.assertListEqual(running_apps, RUNNING_APPS_LIST)

    def test_get_properties(self):
        """Check that ``get_properties()`` works correctly.

        """
        with patchers.patch_shell(None)[self.PATCH_KEY]:
            properties = self.ftv.get_properties_dict(lazy=True)
            self.assertDictEqual(properties, GET_PROPERTIES_DICT_NONE)

        with patchers.patch_shell(GET_PROPERTIES_OUTPUT1)[self.PATCH_KEY]:
            properties = self.ftv.get_properties_dict(lazy=True)
            self.assertDictEqual(properties, GET_PROPERTIES_DICT1)

        with patchers.patch_shell(GET_PROPERTIES_OUTPUT2)[self.PATCH_KEY]:
            properties = self.ftv.get_properties_dict(lazy=True)
            self.assertDictEqual(properties, GET_PROPERTIES_DICT2)

        with patchers.patch_shell(GET_PROPERTIES_OUTPUT3)[self.PATCH_KEY]:
            properties = self.ftv.get_properties_dict(lazy=True)
            self.assertDictEqual(properties, GET_PROPERTIES_DICT3)

        with patchers.patch_shell(GET_PROPERTIES_OUTPUT3A)[self.PATCH_KEY]:
            properties = self.ftv.get_properties_dict(lazy=True)
            self.assertDictEqual(properties, GET_PROPERTIES_DICT3A)

        with patchers.patch_shell(GET_PROPERTIES_OUTPUT3B)[self.PATCH_KEY]:
            properties = self.ftv.get_properties_dict(lazy=True)
            self.assertDictEqual(properties, GET_PROPERTIES_DICT3B)

        with patchers.patch_shell(GET_PROPERTIES_OUTPUT3C)[self.PATCH_KEY]:
            properties = self.ftv.get_properties_dict(lazy=True)
            self.assertDictEqual(properties, GET_PROPERTIES_DICT3C)

        with patchers.patch_shell(GET_PROPERTIES_OUTPUT3D)[self.PATCH_KEY]:
            properties = self.ftv.get_properties_dict(lazy=True)
            self.assertDictEqual(properties, GET_PROPERTIES_DICT3D)

        with patchers.patch_shell(GET_PROPERTIES_OUTPUT3E)[self.PATCH_KEY]:
            properties = self.ftv.get_properties_dict(lazy=True)
            self.assertDictEqual(properties, GET_PROPERTIES_DICT3E)

        with patchers.patch_shell(GET_PROPERTIES_OUTPUT3E)[self.PATCH_KEY]:
            properties = self.ftv.get_properties_dict(lazy=True,
                                                      get_running_apps=False)
            self.assertDictEqual(properties, GET_PROPERTIES_DICT3E)

        with patchers.patch_shell(GET_PROPERTIES_OUTPUT3E)[self.PATCH_KEY]:
            properties = self.ftv.get_properties_dict(lazy=False,
                                                      get_running_apps=False)
            self.assertDictEqual(properties, GET_PROPERTIES_DICT3E)

        with patchers.patch_shell(GET_PROPERTIES_OUTPUT3F)[self.PATCH_KEY]:
            properties = self.ftv.get_properties_dict(lazy=True)
            self.assertDictEqual(properties, GET_PROPERTIES_DICT3F)

        with patchers.patch_shell(GET_PROPERTIES_OUTPUT4)[self.PATCH_KEY]:
            properties = self.ftv.get_properties_dict(lazy=True)
            self.assertDictEqual(properties, GET_PROPERTIES_DICT4)

        with patchers.patch_shell(GET_PROPERTIES_OUTPUT4)[self.PATCH_KEY]:
            properties = self.ftv.get_properties_dict(lazy=True,
                                                      get_running_apps=False)
            self.assertDictEqual(properties, GET_PROPERTIES_DICT4)

        with patchers.patch_shell(GET_PROPERTIES_OUTPUT5)[self.PATCH_KEY]:
            properties = self.ftv.get_properties_dict(lazy=True)
            self.assertDictEqual(properties, GET_PROPERTIES_DICT5)

        with patchers.patch_shell(GET_PROPERTIES_OUTPUT5)[self.PATCH_KEY]:
            properties = self.ftv.get_properties_dict(lazy=False)
            self.assertDictEqual(properties, GET_PROPERTIES_DICT5)

    def test_update(self):
        """Check that the ``update`` method works correctly.

        """
        with patchers.patch_connect(False)[self.PATCH_KEY]:
            self.ftv.adb_connect()
        state = self.ftv.update()
        self.assertTupleEqual(state, STATE_NONE)

        with patchers.patch_connect(True)[self.PATCH_KEY]:
            self.assertTrue(self.ftv.adb_connect())

        with patchers.patch_shell(None)[self.PATCH_KEY]:
            state = self.ftv.update()
            self.assertTupleEqual(state, STATE_NONE)

        with patchers.patch_shell(GET_PROPERTIES_OUTPUT1)[self.PATCH_KEY]:
            state = self.ftv.update()
            self.assertTupleEqual(state, STATE1)

        with patchers.patch_shell(GET_PROPERTIES_OUTPUT2)[self.PATCH_KEY]:
            state = self.ftv.update()
            self.assertTupleEqual(state, STATE2)

        with patchers.patch_shell(GET_PROPERTIES_OUTPUT3)[self.PATCH_KEY]:
            state = self.ftv.update()
            self.assertTupleEqual(state, STATE3)

            self.ftv._state_detection_rules = STATE_DETECTION_RULES1
            state = self.ftv.update()
            self.assertEqual(state[0], constants.STATE_OFF)

            self.ftv._state_detection_rules = STATE_DETECTION_RULES2
            state = self.ftv.update()
            self.assertEqual(state[0], constants.STATE_OFF)

            self.ftv._state_detection_rules = STATE_DETECTION_RULES3
            state = self.ftv.update()
            self.assertEqual(state[0], constants.STATE_STANDBY)

            self.ftv._state_detection_rules = STATE_DETECTION_RULES4
            state = self.ftv.update()
            self.assertEqual(state[0], constants.STATE_PAUSED)

            self.ftv._state_detection_rules = STATE_DETECTION_RULES5
            state = self.ftv.update()
            self.assertEqual(state[0], constants.STATE_IDLE)

    def assertUpdate(self, get_properties, update):
        """Check that the results of the `update` method are as expected.

        """
        with patch('androidtv.firetv.firetv_sync.FireTVSync.get_properties',
                   return_value=get_properties):
            self.assertTupleEqual(self.ftv.update(), update)

    def test_state_detection(self):
        """Check that the state detection works as expected.

        """
        self.assertUpdate([False, None, -1, None, None, None, None],
                          (constants.STATE_OFF, None, None, None))

        self.assertUpdate([True, False, -1, None, None, None, None],
                          (constants.STATE_STANDBY, None, None, None))

        self.assertUpdate(
            [True, True, 1, "com.amazon.tv.launcher", None, None, None],
            (constants.STATE_IDLE, "com.amazon.tv.launcher",
             ["com.amazon.tv.launcher"], None))

        # Amazon Video
        self.assertUpdate([
            True, True, 1, constants.APP_AMAZON_VIDEO, 3,
            [constants.APP_AMAZON_VIDEO], None
        ], (constants.STATE_PLAYING, constants.APP_AMAZON_VIDEO,
            [constants.APP_AMAZON_VIDEO], None))

        self.assertUpdate([
            True, True, 1, constants.APP_AMAZON_VIDEO, 2,
            [constants.APP_AMAZON_VIDEO], None
        ], (constants.STATE_PAUSED, constants.APP_AMAZON_VIDEO,
            [constants.APP_AMAZON_VIDEO], None))

        self.assertUpdate([
            True, True, 1, constants.APP_AMAZON_VIDEO, 1,
            [constants.APP_AMAZON_VIDEO], None
        ], (constants.STATE_IDLE, constants.APP_AMAZON_VIDEO,
            [constants.APP_AMAZON_VIDEO], None))

        # Amazon Video with custom state detection rules
        self.ftv._state_detection_rules = {
            constants.APP_AMAZON_VIDEO: ['media_session_state']
        }

        self.assertUpdate([
            True, True, 2, constants.APP_AMAZON_VIDEO, 2,
            [constants.APP_AMAZON_VIDEO], None
        ], (constants.STATE_PAUSED, constants.APP_AMAZON_VIDEO,
            [constants.APP_AMAZON_VIDEO], None))

        self.assertUpdate([
            True, True, 5, constants.APP_AMAZON_VIDEO, 3,
            [constants.APP_AMAZON_VIDEO], None
        ], (constants.STATE_PLAYING, constants.APP_AMAZON_VIDEO,
            [constants.APP_AMAZON_VIDEO], None))

        self.assertUpdate([
            True, True, 5, constants.APP_AMAZON_VIDEO, 1,
            [constants.APP_AMAZON_VIDEO], None
        ], (constants.STATE_IDLE, constants.APP_AMAZON_VIDEO,
            [constants.APP_AMAZON_VIDEO], None))

        self.ftv._state_detection_rules = {
            constants.APP_AMAZON_VIDEO: [{
                'standby': {
                    'media_session_state': 2
                }
            }]
        }
        self.assertUpdate([
            True, True, 2, constants.APP_AMAZON_VIDEO, None,
            [constants.APP_AMAZON_VIDEO], None
        ], (constants.STATE_IDLE, constants.APP_AMAZON_VIDEO,
            [constants.APP_AMAZON_VIDEO], None))

        # Firefox
        self.assertUpdate([
            True, True, 3, constants.APP_FIREFOX, 3, [constants.APP_FIREFOX],
            None
        ], (constants.STATE_PLAYING, constants.APP_FIREFOX,
            [constants.APP_FIREFOX], None))

        self.assertUpdate([
            True, True, 1, constants.APP_FIREFOX, 3, [constants.APP_FIREFOX],
            None
        ], (constants.STATE_IDLE, constants.APP_FIREFOX,
            [constants.APP_FIREFOX], None))

        # Hulu
        self.assertUpdate(
            [True, True, 4, constants.APP_HULU, 3, [constants.APP_HULU], None],
            (constants.STATE_PLAYING, constants.APP_HULU, [constants.APP_HULU
                                                           ], None))

        self.assertUpdate(
            [True, True, 2, constants.APP_HULU, 3, [constants.APP_HULU], None],
            (constants.STATE_PAUSED, constants.APP_HULU, [constants.APP_HULU
                                                          ], None))

        self.assertUpdate(
            [True, True, 1, constants.APP_HULU, 3, [constants.APP_HULU], None],
            (constants.STATE_IDLE, constants.APP_HULU, [constants.APP_HULU
                                                        ], None))

        # Jellyfin
        self.assertUpdate([
            True, True, 2, constants.APP_JELLYFIN_TV, 3,
            [constants.APP_JELLYFIN_TV], None
        ], (constants.STATE_PLAYING, constants.APP_JELLYFIN_TV,
            [constants.APP_JELLYFIN_TV], None))

        self.assertUpdate([
            True, True, 4, constants.APP_JELLYFIN_TV, 3,
            [constants.APP_JELLYFIN_TV], None
        ], (constants.STATE_PAUSED, constants.APP_JELLYFIN_TV,
            [constants.APP_JELLYFIN_TV], None))

        # Netfilx
        self.assertUpdate([
            True, True, 1, constants.APP_NETFLIX, 3, [constants.APP_NETFLIX],
            None
        ], (constants.STATE_PLAYING, constants.APP_NETFLIX,
            [constants.APP_NETFLIX], None))

        self.assertUpdate([
            True, True, 1, constants.APP_NETFLIX, 2, [constants.APP_NETFLIX],
            None
        ], (constants.STATE_PAUSED, constants.APP_NETFLIX,
            [constants.APP_NETFLIX], None))

        self.assertUpdate([
            True, True, 1, constants.APP_NETFLIX, 1, [constants.APP_NETFLIX],
            None
        ], (constants.STATE_IDLE, constants.APP_NETFLIX,
            [constants.APP_NETFLIX], None))

        # Plex
        self.assertUpdate(
            [True, True, 1, constants.APP_PLEX, 3, [constants.APP_PLEX], None],
            (constants.STATE_PLAYING, constants.APP_PLEX, [constants.APP_PLEX
                                                           ], None))

        self.assertUpdate(
            [True, True, 2, constants.APP_PLEX, 3, [constants.APP_PLEX], None],
            (constants.STATE_PAUSED, constants.APP_PLEX, [constants.APP_PLEX
                                                          ], None))

        self.assertUpdate(
            [True, True, 1, constants.APP_PLEX, 1, [constants.APP_PLEX], None],
            (constants.STATE_IDLE, constants.APP_PLEX, [constants.APP_PLEX
                                                        ], None))

        # Sport 1
        self.assertUpdate([
            True, True, 3, constants.APP_SPORT1, 3, [constants.APP_SPORT1],
            None
        ], (constants.STATE_PLAYING, constants.APP_SPORT1,
            [constants.APP_SPORT1], None))

        self.assertUpdate([
            True, True, 2, constants.APP_SPORT1, 3, [constants.APP_SPORT1],
            None
        ], (constants.STATE_PAUSED, constants.APP_SPORT1,
            [constants.APP_SPORT1], None))

        self.assertUpdate([
            True, True, 1, constants.APP_SPORT1, 3, [constants.APP_SPORT1],
            None
        ], (constants.STATE_IDLE, constants.APP_SPORT1, [constants.APP_SPORT1
                                                         ], None))

        # Spotify
        self.assertUpdate([
            True, True, 1, constants.APP_SPOTIFY, 3, [constants.APP_SPOTIFY],
            None
        ], (constants.STATE_PLAYING, constants.APP_SPOTIFY,
            [constants.APP_SPOTIFY], None))

        self.assertUpdate([
            True, True, 1, constants.APP_SPOTIFY, 2, [constants.APP_SPOTIFY],
            None
        ], (constants.STATE_PAUSED, constants.APP_SPOTIFY,
            [constants.APP_SPOTIFY], None))

        self.assertUpdate([
            True, True, 1, constants.APP_SPOTIFY, 1, [constants.APP_SPOTIFY],
            None
        ], (constants.STATE_IDLE, constants.APP_SPOTIFY,
            [constants.APP_SPOTIFY], None))

        # Twitch
        self.assertUpdate([
            True, True, 2, constants.APP_TWITCH, 3, [constants.APP_TWITCH],
            None
        ], (constants.STATE_PAUSED, constants.APP_TWITCH,
            [constants.APP_TWITCH], None))

        self.assertUpdate([
            True, True, 1, constants.APP_TWITCH, 3, [constants.APP_TWITCH],
            None
        ], (constants.STATE_PLAYING, constants.APP_TWITCH,
            [constants.APP_TWITCH], None))

        self.assertUpdate([
            True, True, 1, constants.APP_TWITCH, 4, [constants.APP_TWITCH],
            None
        ], (constants.STATE_PLAYING, constants.APP_TWITCH,
            [constants.APP_TWITCH], None))

        self.assertUpdate([
            True, True, 1, constants.APP_TWITCH, 1, [constants.APP_TWITCH],
            None
        ], (constants.STATE_IDLE, constants.APP_TWITCH, [constants.APP_TWITCH
                                                         ], None))

        # Waipu TV
        self.assertUpdate([
            True, True, 3, constants.APP_WAIPU_TV, 1, [constants.APP_WAIPU_TV],
            None
        ], (constants.STATE_PLAYING, constants.APP_WAIPU_TV,
            [constants.APP_WAIPU_TV], None))

        self.assertUpdate([
            True, True, 2, constants.APP_WAIPU_TV, 1, [constants.APP_WAIPU_TV],
            None
        ], (constants.STATE_PAUSED, constants.APP_WAIPU_TV,
            [constants.APP_WAIPU_TV], None))

        self.assertUpdate([
            True, True, 1, constants.APP_WAIPU_TV, 1, [constants.APP_WAIPU_TV],
            None
        ], (constants.STATE_IDLE, constants.APP_WAIPU_TV,
            [constants.APP_WAIPU_TV], None))

        # Unknown app
        self.assertUpdate(
            [True, True, 1, 'unknown', 3, ['unknown'], None],
            (constants.STATE_PLAYING, 'unknown', ['unknown'], None))

        self.assertUpdate(
            [True, True, 1, 'unknown', 2, ['unknown'], None],
            (constants.STATE_PAUSED, 'unknown', ['unknown'], None))

        self.assertUpdate([True, True, 1, 'unknown', 1, ['unknown'], None],
                          (constants.STATE_IDLE, 'unknown', ['unknown'], None))

        self.assertUpdate(
            [True, True, 1, 'unknown', None, ['unknown'], None],
            (constants.STATE_PLAYING, 'unknown', ['unknown'], None))

        self.assertUpdate(
            [True, True, 2, 'unknown', None, ['unknown'], None],
            (constants.STATE_PAUSED, 'unknown', ['unknown'], None))