# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Unit tests for the app_ui module."""

import unittest
from xml.etree import ElementTree as element_tree

from devil import devil_env
from devil.android import app_ui
from devil.android import device_errors
from devil.utils import geometry

with devil_env.SysPath(devil_env.PYMOCK_PATH):
  import mock  # pylint: disable=import-error

MOCK_XML_LOADING = '''
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<hierarchy rotation="0">
  <node bounds="[0,50][1536,178]" content-desc="Loading"
      resource-id="com.example.app:id/spinner"/>
</hierarchy>
'''.strip()

MOCK_XML_LOADED = '''
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<hierarchy rotation="0">
  <node bounds="[0,50][1536,178]" content-desc=""
      resource-id="com.example.app:id/toolbar">
    <node bounds="[0,58][112,170]" content-desc="Open navigation drawer"/>
    <node bounds="[121,50][1536,178]"
        resource-id="com.example.app:id/actionbar_custom_view">
      <node bounds="[121,50][1424,178]"
          resource-id="com.example.app:id/actionbar_title" text="Primary"/>
      <node bounds="[1424,50][1536,178]" content-desc="Search"
          resource-id="com.example.app:id/actionbar_search_button"/>
    </node>
  </node>
  <node bounds="[0,178][576,1952]" resource-id="com.example.app:id/drawer">
    <node bounds="[0,178][144,1952]"
        resource-id="com.example.app:id/mini_drawer">
      <node bounds="[40,254][104,318]" resource-id="com.example.app:id/avatar"/>
      <node bounds="[16,354][128,466]" content-desc="Primary"
          resource-id="com.example.app:id/image_view"/>
      <node bounds="[16,466][128,578]" content-desc="Social"
          resource-id="com.example.app:id/image_view"/>
      <node bounds="[16,578][128,690]" content-desc="Promotions"
          resource-id="com.example.app:id/image_view"/>
    </node>
  </node>
</hierarchy>
'''.strip()


class UiAppTest(unittest.TestCase):
  def setUp(self):
    self.device = mock.Mock()
    self.device.pixel_density = 320  # Each dp pixel is 2 real pixels.
    self.app = app_ui.AppUi(self.device, package='com.example.app')
    self._setMockXmlScreenshots([MOCK_XML_LOADED])

  def _setMockXmlScreenshots(self, xml_docs):
    """Mock self.app._GetRootUiNode to load nodes from some test xml_docs.

    Each time the method is called it will return a UI node for each string
    given in |xml_docs|, or rise a time out error when the list is exhausted.
    """

    # pylint: disable=protected-access
    def get_mock_root_ui_node(value):
      if isinstance(value, Exception):
        raise value
      return app_ui._UiNode(self.device, element_tree.fromstring(value),
                            self.app.package)

    xml_docs.append(device_errors.CommandTimeoutError('Timed out!'))

    self.app._GetRootUiNode = mock.Mock(
        side_effect=(get_mock_root_ui_node(doc) for doc in xml_docs))

  def assertNodeHasAttribs(self, node, attr):
    # pylint: disable=protected-access
    for key, value in attr.items():
      self.assertEqual(node._GetAttribute(key), value)

  def assertTappedOnceAt(self, x, y):
    self.device.RunShellCommand.assert_called_once_with(
        ['input', 'tap', str(x), str(y)], check_return=True)

  def testFind_byText(self):
    node = self.app.GetUiNode(text='Primary')
    self.assertNodeHasAttribs(
        node, {
            'text': 'Primary',
            'content-desc': None,
            'resource-id': 'com.example.app:id/actionbar_title',
        })
    self.assertEqual(node.bounds, geometry.Rectangle([121, 50], [1424, 178]))

  def testFind_byContentDesc(self):
    node = self.app.GetUiNode(content_desc='Social')
    self.assertNodeHasAttribs(
        node, {
            'text': None,
            'content-desc': 'Social',
            'resource-id': 'com.example.app:id/image_view',
        })
    self.assertEqual(node.bounds, geometry.Rectangle([16, 466], [128, 578]))

  def testFind_byResourceId_autocompleted(self):
    node = self.app.GetUiNode(resource_id='image_view')
    self.assertNodeHasAttribs(node, {
        'content-desc': 'Primary',
        'resource-id': 'com.example.app:id/image_view',
    })

  def testFind_byResourceId_absolute(self):
    node = self.app.GetUiNode(resource_id='com.example.app:id/image_view')
    self.assertNodeHasAttribs(node, {
        'content-desc': 'Primary',
        'resource-id': 'com.example.app:id/image_view',
    })

  def testFind_byMultiple(self):
    node = self.app.GetUiNode(
        resource_id='image_view', content_desc='Promotions')
    self.assertNodeHasAttribs(
        node, {
            'content-desc': 'Promotions',
            'resource-id': 'com.example.app:id/image_view',
        })
    self.assertEqual(node.bounds, geometry.Rectangle([16, 578], [128, 690]))

  def testFind_notFound(self):
    node = self.app.GetUiNode(resource_id='does_not_exist')
    self.assertIsNone(node)

  def testFind_noArgsGiven(self):
    # Same exception given by Python for a function call with not enough args.
    with self.assertRaises(TypeError):
      self.app.GetUiNode()

  def testGetChildren(self):
    node = self.app.GetUiNode(resource_id='mini_drawer')
    self.assertNodeHasAttribs(node[0],
                              {'resource-id': 'com.example.app:id/avatar'})
    self.assertNodeHasAttribs(node[1], {'content-desc': 'Primary'})
    self.assertNodeHasAttribs(node[2], {'content-desc': 'Social'})
    self.assertNodeHasAttribs(node[3], {'content-desc': 'Promotions'})
    with self.assertRaises(IndexError):
      # pylint: disable=pointless-statement
      node[4]

  def testTap_center(self):
    node = self.app.GetUiNode(content_desc='Open navigation drawer')
    node.Tap()
    self.assertTappedOnceAt(56, 114)

  def testTap_topleft(self):
    node = self.app.GetUiNode(content_desc='Open navigation drawer')
    node.Tap(geometry.Point(0, 0))
    self.assertTappedOnceAt(0, 58)

  def testTap_withOffset(self):
    node = self.app.GetUiNode(content_desc='Open navigation drawer')
    node.Tap(geometry.Point(10, 20))
    self.assertTappedOnceAt(10, 78)

  def testTap_withOffsetInDp(self):
    node = self.app.GetUiNode(content_desc='Open navigation drawer')
    node.Tap(geometry.Point(10, 20), dp_units=True)
    self.assertTappedOnceAt(20, 98)

  def testTap_dpUnitsIgnored(self):
    node = self.app.GetUiNode(content_desc='Open navigation drawer')
    node.Tap(dp_units=True)
    self.assertTappedOnceAt(56, 114)  # Still taps at center.

  @mock.patch('time.sleep', mock.Mock())
  def testWaitForUiNode_found(self):
    self._setMockXmlScreenshots(
        [MOCK_XML_LOADING, MOCK_XML_LOADING, MOCK_XML_LOADED])
    node = self.app.WaitForUiNode(resource_id='actionbar_title')
    self.assertNodeHasAttribs(node, {'text': 'Primary'})

  @mock.patch('time.sleep', mock.Mock())
  def testWaitForUiNode_notFound(self):
    self._setMockXmlScreenshots(
        [MOCK_XML_LOADING, MOCK_XML_LOADING, MOCK_XML_LOADING])
    with self.assertRaises(device_errors.CommandTimeoutError):
      self.app.WaitForUiNode(resource_id='actionbar_title')
