import unittest
import itertools
from unittest import TestCase
from metadata_model import *
from metadata_helpers import *
from metadata_parser_xml import *

# Simple test metadata block used by the tests below
test_metadata_xml = \
'''
<?xml version="1.0" encoding="utf-8"?>
<metadata xmlns="http://schemas.android.com/service/camera/metadata/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata_definitions.xsd">

<namespace name="testOuter1">
  <section name="testSection1">
    <controls>
      <entry name="control1" type="byte" visibility="public">
      </entry>
      <entry name="control2" type="byte" visibility="public">
      </entry>
    </controls>
    <dynamic>
      <entry name="dynamic1" type="byte" visibility="public">
      </entry>
      <entry name="dynamic2" type="byte" visibility="public">
      </entry>
      <clone entry="testOuter1.testSection1.control1" kind="controls">
      </clone>
    </dynamic>
    <static>
      <entry name="static1" type="byte" visibility="public">
      </entry>
      <entry name="static2" type="byte" visibility="public">
      </entry>
    </static>
  </section>
</namespace>
<namespace name="testOuter2">
  <section name="testSection2">
    <controls>
      <entry name="control1" type="byte" visibility="public">
      </entry>
      <entry name="control2" type="byte" visibility="public">
      </entry>
    </controls>
    <dynamic>
      <entry name="dynamic1" type="byte" visibility="public">
      </entry>
      <entry name="dynamic2" type="byte" visibility="public">
      </entry>
      <clone entry="testOuter2.testSection2.control1" kind="controls">
      </clone>
    </dynamic>
    <static>
      <namespace name="testInner2">
        <entry name="static1" type="byte" visibility="public">
        </entry>
        <entry name="static2" type="byte" visibility="public">
        </entry>
      </namespace>
    </static>
  </section>
</namespace>
</metadata>
'''

class TestHelpers(TestCase):

  def test_enum_calculate_value_string(self):
    def compare_values_against_list(expected_list, enum):
      for (idx, val) in enumerate(expected_list):
        self.assertEqual(val,
                         enum_calculate_value_string(list(enum.values)[idx]))

    plain_enum = Enum(parent=None, values=['ON', 'OFF'])

    compare_values_against_list(['0', '1'],
                                plain_enum)

    ###
    labeled_enum = Enum(parent=None, values=['A', 'B', 'C'], ids={
      'A': '12345',
      'B': '0xC0FFEE',
      'C': '0xDEADF00D'
    })

    compare_values_against_list(['12345', '0xC0FFEE', '0xDEADF00D'],
                                labeled_enum)

    ###
    mixed_enum = Enum(parent=None,
                      values=['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'],
                      ids={
                        'C': '0xC0FFEE',
                        'E': '123',
                        'G': '0xDEADF00D'
                      })

    expected_values = ['0', '1', '0xC0FFEE', '0xC0FFEF', '123', '124',
                       '0xDEADF00D',
                       '0xDEADF00E']

    compare_values_against_list(expected_values, mixed_enum)

  def test_enumerate_with_last(self):
    empty_list = []

    for (x, y) in enumerate_with_last(empty_list):
      self.fail("Should not return anything for empty list")

    single_value = [1]
    for (x, last) in enumerate_with_last(single_value):
      self.assertEqual(1, x)
      self.assertEqual(True, last)

    multiple_values = [4, 5, 6]
    lst = list(enumerate_with_last(multiple_values))
    self.assertListEqual([(4, False), (5, False), (6, True)], lst)

  def test_filter_tags(self):
    metadata = MetadataParserXml(test_metadata_xml, 'metadata_helpers_test.py').metadata

    test_text = \
'''
In the unlikely event of a
water landing, testOuter1.testSection1.control1 will deploy.
If testOuter2.testSection2.testInner2.static1,
then testOuter1.testSection1.
dynamic1 will ensue. That should be avoided if testOuter2.testSection2.
Barring issues, testOuter1.testSection1.dynamic1, and testOuter2.testSection2.control1.
In the third instance of testOuter1.testSection1.control1
we will take the other option.
If the path foo/android.testOuter1.testSection1.control1/bar.txt exists, then oh well.
'''
    def filter_test(node):
      return '*'

    def summary_test(node_set):
      text = "*" * len(node_set) + "\n"
      return text

    expected_text = \
'''
In the unlikely event of a
water landing, * will deploy.
If *,
then * will ensue. That should be avoided if testOuter2.testSection2.
Barring issues, *, and *.
In the third instance of *
we will take the other option.
If the path foo/android.testOuter1.testSection1.control1/bar.txt exists, then oh well.
****
'''
    result_text = filter_tags(test_text, metadata, filter_test, summary_test)

    self.assertEqual(result_text, expected_text)

  def test_wbr(self):
    wbr_string = "<wbr/>"
    wbr_gen = itertools.repeat(wbr_string)

    # No special characters, do nothing
    self.assertEqual("no-op", wbr("no-op"))
    # Insert WBR after characters in [ '.', '/', '_' ]
    self.assertEqual("word.{0}".format(wbr_string), wbr("word."))
    self.assertEqual("word/{0}".format(wbr_string), wbr("word/"))
    self.assertEqual("word_{0}".format(wbr_string), wbr("word_"))

    self.assertEqual("word.{0}break".format(wbr_string), wbr("word.break"))
    self.assertEqual("word/{0}break".format(wbr_string), wbr("word/break"))
    self.assertEqual("word_{0}break".format(wbr_string), wbr("word_break"))

    # Test words with more components
    self.assertEqual("word_{0}break_{0}again".format(wbr_string),
                      wbr("word_break_again"))
    self.assertEqual("word_{0}break_{0}again_{0}emphasis".format(wbr_string),
                      wbr("word_break_again_emphasis"))

    # Words with 2 or less subcomponents are ignored for the capital letters
    self.assertEqual("word_{0}breakIgnored".format(wbr_string),
                      wbr("word_breakIgnored"))
    self.assertEqual("wordIgnored".format(wbr_string),
                      wbr("wordIgnored"))

    # Words with at least 3 sub components get word breaks before caps
    self.assertEqual("word_{0}break_{0}again{0}Capitalized".format(wbr_string),
                      wbr("word_break_againCapitalized"))
    self.assertEqual("word.{0}break.{0}again{0}Capitalized".format(wbr_string),
                      wbr("word.break.againCapitalized"))
    self.assertEqual("a.{0}b{0}C.{0}d{0}E.{0}f{0}G".format(wbr_string),
                      wbr("a.bC.dE.fG"))

    # Don't be overly aggressive with all caps
    self.assertEqual("TRANSFORM_{0}MATRIX".format(wbr_string),
                      wbr("TRANSFORM_MATRIX"))

    self.assertEqual("SCENE_{0}MODE_{0}FACE_{0}PRIORITY".format(wbr_string),
                      wbr("SCENE_MODE_FACE_PRIORITY"))

    self.assertEqual("android.{0}color{0}Correction.{0}mode is TRANSFORM_{0}MATRIX.{0}".format(wbr_string),
                      wbr("android.colorCorrection.mode is TRANSFORM_MATRIX."))

    self.assertEqual("The overrides listed for SCENE_{0}MODE_{0}FACE_{0}PRIORITY are ignored".format(wbr_string),
                      wbr("The overrides listed for SCENE_MODE_FACE_PRIORITY are ignored"));

  def test_dedent(self):
    # Remove whitespace from 2nd and 3rd line (equal ws)
    self.assertEqual("bar\nline1\nline2", dedent("bar\n  line1\n  line2"))
    # Remove whitespace from all lines (1st line ws < 2/3 line ws)
    self.assertEqual("bar\nline1\nline2", dedent(" bar\n  line1\n  line2"))
    # Remove some whitespace from 2nd line, all whitespace from other lines
    self.assertEqual("bar\n  line1\nline2", dedent(" bar\n    line1\n  line2"))

if __name__ == '__main__':
    unittest.main()
