"""
Tests format_string util

@Created on March 18, 2021
@janamian
"""

import unittest
from fprime_gds.common.utils.string_util import format_string_template


class TestFormatString(unittest.TestCase):
    def test_format_with_no_issue(self):
        template = "Opcode 0x%04X dispatched to port %d and value %f"
        values = (181, 8, 1.234)
        expected = "Opcode 0x00B5 dispatched to port 8 and value 1.234000"
        actual = format_string_template(template, values)
        self.assertEqual(expected, actual)

    def test_format_value_with_string_input_as_other_types(self):
        template = "Opcode 0x%04X dispatched to port %u and value %.2f"
        values = (181, "8", 1.234)
        expected = "Opcode 0x00B5 dispatched to port 8 and value 1.23"
        actual = format_string_template(template, values)
        self.assertEqual(expected, actual)

    def test_format_with_format_spec(self):
        template = "Opcode 0x%04X dispatched to port %04d and value %0.02f"
        values = (181, 8, 1.234)
        expected = "Opcode 0x00B5 dispatched to port 0008 and value 1.23"
        actual = format_string_template(template, values)
        self.assertEqual(expected, actual)

    def test_format_bad_case(self):
        template = "Opcode 0x%04X dispatched to port %04d and value %0.02f"
        values = ("181", "8", "0.123")
        with self.assertRaises(ValueError):
            self.assertEqual(format_string_template(template, values))

    def test_format_decimal_with_width_flag(self):
        template = "Decimals: %d %ld"
        values = (1977, 650000)
        expected = "Decimals: 1977 650000"
        actual = format_string_template(template, values)
        self.assertEqual(expected, actual)

    def test_format_preceding_with_blanks(self):
        template = "Preceding with blanks: %10d"
        values = (1977,)
        expected = "Preceding with blanks:       1977"
        actual = format_string_template(template, values)
        self.assertEqual(expected, actual)

    def test_format_preceding_with_zeros(self):
        template = "Preceding with zeros: %010d"
        values = (1977,)
        expected = "Preceding with zeros: 0000001977"
        actual = format_string_template(template, values)
        self.assertEqual(expected, actual)

    def test_format_some_different_radices(self):
        template = "Some different radices: %d %x %o %#x %#o"
        values = (100, 100, 100, 100, 100)
        # The alternate form causes a leading octal specifier ('0o') to be inserted before the first digit. This is different than C behavior
        # `See https://docs.python.org/3/library/stdtypes.html#printf-style-bytes-formatting`
        expected = "Some different radices: 100 64 144 0x64 0o144"
        actual = format_string_template(template, values)
        self.assertEqual(expected, actual)

    def test_format_floats(self):
        template = "floats: %4.2f %+.0e %E"
        values = (3.1416, 3.1416, 3.1416)
        expected = "floats: 3.14 +3e+00 3.141600E+00"
        actual = format_string_template(template, values)
        self.assertEqual(expected, actual)

    def test_format_asterisk_width(self):
        # asterisk `*` is not supported by python string-format
        template = "Width trick: %*d"
        values = (5, 10)
        with self.assertRaises(ValueError):
            actual = format_string_template(template, values)

    def test_format_regular_string(self):
        template = "%s"
        values = ("A string",)
        expected = "A string"
        actual = format_string_template(template, values)
        self.assertEqual(expected, actual)

    def test_format_percent_sign(self):
        template = "%.2f%%"
        values = (1.23456,)
        expected = "1.23%"
        actual = format_string_template(template, values)
        self.assertEqual(expected, actual)

    def test_format_single_value(self):
        template = "%.2f%%"
        values = 1.23456
        expected = "1.23%"
        actual = format_string_template(template, values)
        self.assertEqual(expected, actual)

    def test_format_list_value(self):
        template = "%.2f%%, %.2f%%"
        values = [1.23456, 1.23456]
        expected = "1.23%, 1.23%"
        actual = format_string_template(template, values)
        self.assertEqual(expected, actual)

    def test_format_tuple_value(self):
        template = "%.2f%%, %.2f%%"
        values = (1.23456, 1.23456)
        expected = "1.23%, 1.23%"
        actual = format_string_template(template, values)
        self.assertEqual(expected, actual)

    def test_format_unsigned_flag_with_length_flag(self):
        template = "Something %lu something %llu something else %lu"
        values = (123456, 123457, 123458)
        expected = "Something 123456 something 123457 something else 123458"
        actual = format_string_template(template, values)
        self.assertEqual(expected, actual)


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