code: def test_truncate_html_words(self):
      # Plain text.
      self.assertEqual(
          utils.truncate_html_words("short string", 20), "short string"
      )
      self.assertEqual(
          utils.truncate_html_words("word " * 100, 20),
          "word " * 20 + "…",
      )
  
      # Plain text with Unicode content.
      self.assertEqual(
          utils.truncate_html_words(
              "我愿意这样，朋友——我独自远行，不但没有你，\
                   并且再没有别的影在黑暗里。",
              12,
          ),
          "我愿意这样，朋友——我独自远行" + " …",
      )
      self.assertEqual(
          utils.truncate_html_words(
              "Ты мелькнула, ты предстала, Снова сердце задрожало,", 3
          ),
          "Ты мелькнула, ты" + " …",
      )
      self.assertEqual(
          utils.truncate_html_words("Trong đầm gì đẹp bằng sen", 4),
          "Trong đầm gì đẹp" + " …",
      )
  
      # Words enclosed or intervaled by HTML tags.
      self.assertEqual(
          utils.truncate_html_words("<p>" + "word " * 100 + "</p>", 20),
          "<p>" + "word " * 20 + "…</p>",
      )
      self.assertEqual(
          utils.truncate_html_words(
              '<span\nstyle="\n…\n">' + "word " * 100 + "</span>", 20
          ),
          '<span\nstyle="\n…\n">' + "word " * 20 + "…</span>",
      )
      self.assertEqual(
          utils.truncate_html_words("<br>" + "word " * 100, 20),
          "<br>" + "word " * 20 + "…",
      )
      self.assertEqual(
          utils.truncate_html_words(
              "<!-- comment -->" + "word " * 100, 20
          ),
          "<!-- comment -->" + "word " * 20 + "…",
      )
  
      # Words enclosed or intervaled by HTML tags with a custom end
      # marker containing HTML tags.
      self.assertEqual(
          utils.truncate_html_words(
              "<p>" + "word " * 100 + "</p>", 20, "<span>marker</span>"
          ),
          "<p>" + "word " * 20 + "<span>marker</span></p>",
      )
      self.assertEqual(
          utils.truncate_html_words(
              '<span\nstyle="\n…\n">' + "word " * 100 + "</span>",
              20,
              "<span>marker</span>",
          ),
          '<span\nstyle="\n…\n">'
          + "word " * 20
          + "<span>marker</span></span>",
      )
      self.assertEqual(
          utils.truncate_html_words(
              "<br>" + "word " * 100, 20, "<span>marker</span>"
          ),
          "<br>" + "word " * 20 + "<span>marker</span>",
      )
      self.assertEqual(
          utils.truncate_html_words(
              "<!-- comment -->" + "word " * 100,
              20,
              "<span>marker</span>",
          ),
          "<!-- comment -->" + "word " * 20 + "<span>marker</span>",
      )
  
      # Words with hypens and apostrophes.
      self.assertEqual(
          utils.truncate_html_words("a-b " * 100, 20), "a-b " * 20 + "…"
      )
      self.assertEqual(
          utils.truncate_html_words("it's " * 100, 20),
          "it's " * 20 + "…",
      )
  
      # Words with HTML entity references.
      self.assertEqual(
          utils.truncate_html_words("&eacute; " * 100, 20),
          "&eacute; " * 20 + "…",
      )
      self.assertEqual(
          utils.truncate_html_words("caf&eacute; " * 100, 20),
          "caf&eacute; " * 20 + "…",
      )
      self.assertEqual(
          utils.truncate_html_words("&egrave;lite " * 100, 20),
          "&egrave;lite " * 20 + "…",
      )
      self.assertEqual(
          utils.truncate_html_words("cafeti&eacute;re " * 100, 20),
          "cafeti&eacute;re " * 20 + "…",
      )
      self.assertEqual(
          utils.truncate_html_words("&int;dx " * 100, 20),
          "&int;dx " * 20 + "…",
      )
  
      # Words with HTML character references inside and outside
      # the ASCII range.
      self.assertEqual(
          utils.truncate_html_words("&#xe9; " * 100, 20),
          "&#xe9; " * 20 + "…",
      )
      self.assertEqual(
          utils.truncate_html_words("&#x222b;dx " * 100, 20),
          "&#x222b;dx " * 20 + "…",
      )
  
      # Words with invalid or broken HTML references.
      self.assertEqual(
          utils.truncate_html_words("&invalid;", 20), "&invalid;"
      )
      self.assertEqual(
          utils.truncate_html_words("&#9999999999;", 20),
          "&#9999999999;",
      )
      self.assertEqual(
          utils.truncate_html_words("&#xfffffffff;", 20),
          "&#xfffffffff;",
      )
      self.assertEqual(
          utils.truncate_html_words("&mdash text", 20), "&mdash text"
      )
      self.assertEqual(
          utils.truncate_html_words("&#1234 text", 20), "&#1234 text"
      )
      self.assertEqual(
          utils.truncate_html_words("&#xabc text", 20), "&#xabc text"
      )
  
imports: import locale
  import logging
  import os
  import shutil
  from datetime import timezone
  from sys import platform
  from tempfile import mkdtemp
  from pelican import utils
  from pelican.generators import TemplatePagesGenerator
  from pelican.settings import read_settings
  from pelican.tests.support import LoggedTestCase, get_article, locale_available, unittest
  from pelican.writers import Writer
label_desc: Use image node_id 11 for calling the TestUtils obj's underlying member method code with example usage: obj.test_truncate_html_words() without return types