text: import pytest
  
  from fontbakery.utils import (
      bullet_list,
      can_shape,
      pretty_print_list,
      text_flow,
      unindent_and_unwrap_rationale,
  )
  from fontTools.ttLib import TTFont
  from fontbakery.codetesting import portable_path
  
  
  def test_text_flow():
      assert text_flow("") == ""
  
      assert text_flow("Testing") == "Testing"
  
      assert text_flow("One Two Three") == "One Two Three"
  
      assert text_flow("One Two Three",
                       width=5) == ("One\n"
                                    "Two\n"
                                    "Three")
  
      assert text_flow("One Two Three",
                       width=6,
                       space_padding=True) == ("One   \n"
                                               "Two   \n"
                                               "Three ")
  
      assert text_flow("One Two Three",
                       width=7,
                       space_padding=True) == ("One Two\n"
                                               "Three  ")
  
      assert text_flow("One Two Three",
                       width=9,
                       left_margin=2,
                       space_padding=True) == ("  One Two\n"
                                               "  Three  ")
  
      assert text_flow("One Two Three",
                       width=7,
                       left_margin=1,
                       space_padding=True) == (" One   \n"
                                               " Two   \n"
                                               " Three ")
  
      assert text_flow("One Two Three",
                       width=9,
                       left_margin=1,
                       right_margin=1,
                       space_padding=True) == (" One Two \n"
                                               " Three   ")
  
      assert text_flow("One Two Three",
                       width=8,
                       left_margin=1,
                       right_margin=1,
                       space_padding=True) == (" One    \n"
                                               " Two    \n"
                                               " Three  ")
  
      assert text_flow("One Two Three Four",
                       width=7,
                       left_margin=1,
                       right_margin=1,
                       space_padding=True) == (" One   \n"
                                               " Two   \n"
                                               " Three \n"
                                               " Four  ")
  
      assert text_flow("One Two Three Four",
                       width=6,
                       left_margin=1,
                       right_margin=1,
                       space_padding=True) == (" One  \n"
                                               " Two  \n"
                                               " Thre \n"
                                               " e    \n"
                                               " Four ")
  
  # FIXME!
  #    assert text_flow("One Two Three",
  #                     width=12,
  #                     left_margin=6,
  #                     first_line_indent=-5,
  #                     space_padding=True) == (     " One   \n"
  #                                             "      Two   \n"
  #                                             "      Three ")
  
  
  def test_can_shape():
      font = TTFont(portable_path(
          "data/test/source-sans-pro/OTF/SourceSansPro-Regular.otf"
      ))
      assert can_shape(font, "ABC")
      assert not can_shape(font, "こんにちは")
  
  
  def test_unindent_and_unwrap_rationale():
      rationale = """
          This is a line that is very long, so long in fact that it must be hard wrapped
          because it is longer than 88 lines, including the two 4-space indents.
  
          This is a new paragraph. This paragraph is also too long to fit within the
          maximum width, so it must be hard wrapped.
          This is a new line that was NOT soft-wrapped, so it will end up appendend to
          the previous line.⏎
          This is yet another line, but this one was soft-wrapped (Shift+Return), which
          means that it will not be appendend to the end of the previous line.
  
          This is the last paragraph.
      """
      expected_rationale = (
          "\n"
          "This is a line that is very long, so long in fact that it must be hard wrapped"
          " because it is longer than 88 lines, including the two 4-space indents.\n"
          "\n"
          "This is a new paragraph. This paragraph is also too long to fit within the"
          " maximum width, so it must be hard wrapped."
          " This is a new line that was NOT soft-wrapped, so it will end up appendend to"
          " the previous line.\n"
          "This is yet another line, but this one was soft-wrapped (Shift+Return), which"
          " means that it will not be appendend to the end of the previous line.\n"
          "\n"
          "This is the last paragraph."
          "\n"
      )
      assert unindent_and_unwrap_rationale(rationale) == expected_rationale
  
  
  def _make_values(count: int) -> list:
      """Helper method that returns a list with 'count' number of items"""
      return [f"item {i}" for i in range(1, count + 1)]
  
  
  @pytest.mark.parametrize('values, expected_str', [
      # (_make_values(0), ""),  # causes IndexError
      (_make_values(1), "item 1"),
      (_make_values(2), "item 1 and item 2"),
      (_make_values(3), "item 1, item 2 and item 3"),
      (_make_values(4), "item 1, item 2, item 3 and item 4"),
      (_make_values(12), ("item 1, item 2, item 3, item 4, item 5, item 6, item 7,"
                          " item 8, item 9, item 10, item 11 and item 12")),
  ])
  def test_pretty_print_list_full(values, expected_str):
      config = {'full_lists': True}
      assert pretty_print_list(config, values) == expected_str
      assert pretty_print_list(config, values, shorten=3) == expected_str
      assert pretty_print_list(
          config, values, sep=" + ") == expected_str.replace(", ", " + ")
      assert pretty_print_list(
          config, values, glue="&") == expected_str.replace("and", "&")
  
  
  MORE_MSG = "\n\nUse -F or --full-lists to disable shortening of long lists."
  
  
  @pytest.mark.parametrize('values, shorten, expected_str', [
      (_make_values(1), None, "item 1"),
      (_make_values(1), 0, "item 1"),
      (_make_values(1), 1, "item 1"),
      (_make_values(1), 2, "item 1"),
      (_make_values(2), None, "item 1 and item 2"),
      (_make_values(2), 0, "item 1 and item 2"),
      (_make_values(2), 1, "item 1 and item 2"),
      (_make_values(2), 2, "item 1 and item 2"),
      (_make_values(2), 3, "item 1 and item 2"),
      (_make_values(3), None, "item 1, item 2 and item 3"),
      (_make_values(3), 1, "item 1, item 2 and item 3"),
      (_make_values(3), 2, "item 1, item 2 and item 3"),
      (_make_values(3), 3, "item 1, item 2 and item 3"),
      (_make_values(3), 4, "item 1, item 2 and item 3"),
      (_make_values(4), None, "item 1, item 2, item 3 and item 4"),
      (_make_values(4), 0, "item 1, item 2, item 3 and item 4"),
      (_make_values(4), 1, f"item 1 and 3 more.{MORE_MSG}"),
      (_make_values(4), 2, "item 1, item 2, item 3 and item 4"),
      (_make_values(4), 3, "item 1, item 2, item 3 and item 4"),
      (_make_values(4), 4, "item 1, item 2, item 3 and item 4"),
      (_make_values(4), 5, "item 1, item 2, item 3 and item 4"),
      (_make_values(5), None, "item 1, item 2, item 3, item 4 and item 5"),
      (_make_values(5), 0, "item 1, item 2, item 3, item 4 and item 5"),
      (_make_values(5), 1, f"item 1 and 4 more.{MORE_MSG}"),
      (_make_values(5), 2, f"item 1, item 2 and 3 more.{MORE_MSG}"),
      (_make_values(5), 3, "item 1, item 2, item 3, item 4 and item 5"),
      (_make_values(5), 4, "item 1, item 2, item 3, item 4 and item 5"),
      (_make_values(5), 5, "item 1, item 2, item 3, item 4 and item 5"),
      (_make_values(5), 6, "item 1, item 2, item 3, item 4 and item 5"),
      (_make_values(12), None, ("item 1, item 2, item 3, item 4, item 5, item 6, item 7,"
                                " item 8, item 9, item 10, item 11 and item 12")),
      (_make_values(12), 0, ("item 1, item 2, item 3, item 4, item 5, item 6, item 7,"
                             " item 8, item 9, item 10, item 11 and item 12")),
      (_make_values(12), 1, f"item 1 and 11 more.{MORE_MSG}"),
      (_make_values(12), 6, ("item 1, item 2, item 3, item 4, item 5, item 6"
                             f" and 6 more.{MORE_MSG}")),
      (_make_values(13), None, ("item 1, item 2, item 3, item 4, item 5, item 6, item 7,"
                                f" item 8, item 9, item 10 and 3 more.{MORE_MSG}")),
      (_make_values(13), 0, ("item 1, item 2, item 3, item 4, item 5, item 6, item 7,"
                             " item 8, item 9, item 10, item 11, item 12 and item 13")),
      (_make_values(13), 1, f"item 1 and 12 more.{MORE_MSG}"),
      (_make_values(13), 6, ("item 1, item 2, item 3, item 4, item 5, item 6"
                             f" and 7 more.{MORE_MSG}")),
  ])
  def test_pretty_print_list_shorten(values, shorten, expected_str):
      config = {}
      if shorten is not None:
          assert pretty_print_list(config, values, shorten=shorten) == expected_str
      else:
          assert pretty_print_list(config, values) == expected_str
  
  
  @pytest.mark.parametrize('values, expected_str', [
      (_make_values(1), "\t- item 1"),
      (_make_values(2), "\t- item 1 \n\n\t- And item 2"),
      (_make_values(3), "\t- item 1\n\n\t- item 2 \n\n\t- And item 3"),
      (_make_values(4), "\t- item 1\n\n\t- item 2\n\n\t- item 3 \n\n\t- And item 4"),
  ])
  def test_bullet_list(values, expected_str):
      config = {'full_lists': True}
      assert bullet_list(config, values) == expected_str
      assert bullet_list(config, values, bullet="*") == expected_str.replace("-", "*")
      assert bullet_list(config, values, indentation="") == expected_str.replace("\t", "")
  