# Path: ledgerbil/colorable.py
# class Colorable:
# 
#     START_CODE = "\033"
#     END_CODE = f"{START_CODE}[0m"
# 
#     BRIGHT_OFFSET = 60
# 
#     COLORS = {
#         "black": 30,
#         "gray": 30,
#         "grey": 30,
#         "red": 31,
#         "green": 32,
#         "yellow": 33,
#         "blue": 34,
#         "magenta": 35,
#         "purple": 35,
#         "cyan": 36,
#         "white": 37,
#     }
# 
#     ansi_escape = re.compile(r"\x1B\[[0-?]*[ -/]*[@-~]")
# 
#     def __init__(self, color, value, fmt="", bright=False):
# 
#         if color not in self.COLORS:
#             raise UnsupportedColorError(
#                 f"I don't know what to do with this color: {color}"
#             )
# 
#         self.my_color = color
#         self.value = value
#         self.bright = bright
#         self.format_string = fmt
# 
#     def __repr__(self):
#         return (
#             f"Colorable('{self.my_color}', '{self.value}', "
#             f"fmt='{self.format_string}', bright={self.bright})"
#         )
# 
#     def __str__(self):
#         start = self.ansi_sequence(self.COLORS[self.my_color], bright=self.bright)
#         ansi_str = f"{start}{self.value:{self.format_string}}{self.END_CODE}"
#         return ansi_str
# 
#     def __len__(self):
#         return len(self.value)
# 
#     def __eq__(self, other):
#         return str(self) == str(other)
# 
#     def ansi_sequence(self, code, bright=False):
#         offset = 60 if bright else 0
#         color = code + offset
#         return f"{self.START_CODE}[0;{color}m"
# 
#     def plain(self):
#         return self.value
# 
#     @staticmethod
#     def get_plain_string(ansi_string):
#         return Colorable.ansi_escape.sub("", ansi_string)
# 
# class UnsupportedColorError(Exception):
#     pass


import pytest
from ..colorable import Colorable, UnsupportedColorError


def test_color_with_commas():
    """Colorable should add commas for thousands if specified in format"""
    for key, value in Colorable.COLORS.items():
        c = Colorable(key, 5000, fmt=",")
        assert str(c) == f"\x1b[0;{value}m5,000\x1b[0m"


def test_color_with_floats():
    """Colorable should apply float formatting if specified"""
    for key, value in Colorable.COLORS.items():
        c = Colorable(key, 5000.127, fmt="9.2f")
        assert str(c) == f"\x1b[0;{value}m  5000.13\x1b[0m"


def test_plain():
    """Plain should return string without ansi escape sequences"""
    c = Colorable("red", "blah")
    assert str(c) == "\x1b[0;31mblah\x1b[0m"
    assert c.plain() == "blah"


def test_get_plain_string():
    """get_plain_string should return string without ansi sequences"""
    assert Colorable.get_plain_string("\x1b[0;31mblah\x1b[0m") == "blah"


def test_unsupported_color_error():
    """A color string that doesn't exist in COLORS dict should error"""

# Path: ledgerbil/colorable.py
# class Colorable:
# 
#     START_CODE = "\033"
#     END_CODE = f"{START_CODE}[0m"
# 
#     BRIGHT_OFFSET = 60
# 
#     COLORS = {
#         "black": 30,
#         "gray": 30,
#         "grey": 30,
#         "red": 31,
#         "green": 32,
#         "yellow": 33,
#         "blue": 34,
#         "magenta": 35,
#         "purple": 35,
#         "cyan": 36,
#         "white": 37,
#     }
# 
#     ansi_escape = re.compile(r"\x1B\[[0-?]*[ -/]*[@-~]")
# 
#     def __init__(self, color, value, fmt="", bright=False):
# 
#         if color not in self.COLORS:
#             raise UnsupportedColorError(
#                 f"I don't know what to do with this color: {color}"
#             )
# 
#         self.my_color = color
#         self.value = value
#         self.bright = bright
#         self.format_string = fmt
# 
#     def __repr__(self):
#         return (
#             f"Colorable('{self.my_color}', '{self.value}', "
#             f"fmt='{self.format_string}', bright={self.bright})"
#         )
# 
#     def __str__(self):
#         start = self.ansi_sequence(self.COLORS[self.my_color], bright=self.bright)
#         ansi_str = f"{start}{self.value:{self.format_string}}{self.END_CODE}"
#         return ansi_str
# 
#     def __len__(self):
#         return len(self.value)
# 
#     def __eq__(self, other):
#         return str(self) == str(other)
# 
#     def ansi_sequence(self, code, bright=False):
#         offset = 60 if bright else 0
#         color = code + offset
#         return f"{self.START_CODE}[0;{color}m"
# 
#     def plain(self):
#         return self.value
# 
#     @staticmethod
#     def get_plain_string(ansi_string):
#         return Colorable.ansi_escape.sub("", ansi_string)
# 
# class UnsupportedColorError(Exception):
#     pass


# Path: ledgerbil/tests/test_colorable.py
import pytest
from ..colorable import Colorable, UnsupportedColorError



def test_color_with_commas():
    """Colorable should add commas for thousands if specified in format"""
    for key, value in Colorable.COLORS.items():
        c = Colorable(key, 5000, fmt=",")
        assert str(c) == f"\x1b[0;{value}m5,000\x1b[0m"


def test_color_with_floats():
    """Colorable should apply float formatting if specified"""
    for key, value in Colorable.COLORS.items():
        c = Colorable(key, 5000.127, fmt="9.2f")
        assert str(c) == f"\x1b[0;{value}m  5000.13\x1b[0m"


def test_plain():
    """Plain should return string without ansi escape sequences"""
    c = Colorable("red", "blah")
    assert str(c) == "\x1b[0;31mblah\x1b[0m"
    assert c.plain() == "blah"


def test_get_plain_string():
    """get_plain_string should return string without ansi sequences"""
    assert Colorable.get_plain_string("\x1b[0;31mblah\x1b[0m") == "blah"


def test_unsupported_color_error():
    """A color string that doesn't exist in COLORS dict should error"""

    with pytest.raises(UnsupportedColorError) as excinfo: