/**
     * Tests {@link Convert::html2raw()}
     */
    public function testHtml2raw()
    {
        $val1 = 'This has a <strong>strong tag</strong>.';
        $this->assertEquals('This has a *strong tag*.', Convert::html2raw($val1), 'Strong tags are replaced with asterisks');
        $val1 = 'This has a <b class="test" style="font-weight: bold">b tag with attributes</b>.';
        $this->assertEquals('This has a *b tag with attributes*.', Convert::html2raw($val1), 'B tags with attributes are replaced with asterisks');
        $val2 = 'This has a <strong class="test" style="font-weight: bold">strong tag with attributes</STRONG>.';
        $this->assertEquals('This has a *strong tag with attributes*.', Convert::html2raw($val2), 'Strong tags with attributes are replaced with asterisks');
        $val3 = '<script type="application/javascript">Some really nasty javascript here</script>';
        $this->assertEquals('', Convert::html2raw($val3), 'Script tags are completely removed');
        $val4 = '<style type="text/css">Some really nasty CSS here</style>';
        $this->assertEquals('', Convert::html2raw($val4), 'Style tags are completely removed');
        $val5 = '<script type="application/javascript">Some really nasty
		multiline javascript here</script>';
        $this->assertEquals('', Convert::html2raw($val5), 'Multiline script tags are completely removed');
        $val6 = '<style type="text/css">Some really nasty
		multiline CSS here</style>';
        $this->assertEquals('', Convert::html2raw($val6), 'Multiline style tags are completely removed');
        $val7 = '<p>That&#39;s absolutely correct</p>';
        $this->assertEquals("That's absolutely correct", Convert::html2raw($val7), "Single quotes are decoded correctly");
        $val8 = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor ' . 'incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud ' . 'exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute ' . 'irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla ' . 'pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia ' . 'deserunt mollit anim id est laborum.';
        $this->assertEquals($val8, Convert::html2raw($val8), 'Test long text is unwrapped');
        $this->assertEquals(<<<PHP
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum.
PHP
, Convert::html2raw($val8, false, 60), 'Test long text is wrapped');
    }
 /**
  * Simple conversion of HTML to plaintext.
  *
  * @param string $data Input data
  * @param bool $preserveLinks
  * @param int $wordWrap
  * @param array $config
  * @return string
  */
 public static function html2raw($data, $preserveLinks = false, $wordWrap = 0, $config = null)
 {
     $defaultConfig = array('PreserveLinks' => false, 'ReplaceBoldAsterisk' => true, 'CompressWhitespace' => true, 'ReplaceImagesWithAlt' => true);
     if (isset($config)) {
         $config = array_merge($defaultConfig, $config);
     } else {
         $config = $defaultConfig;
     }
     $data = preg_replace("/<style([^A-Za-z0-9>][^>]*)?>.*?<\\/style[^>]*>/is", "", $data);
     $data = preg_replace("/<script([^A-Za-z0-9>][^>]*)?>.*?<\\/script[^>]*>/is", "", $data);
     if ($config['ReplaceBoldAsterisk']) {
         $data = preg_replace('%<(strong|b)( [^>]*)?>|</(strong|b)>%i', '*', $data);
     }
     // Expand hyperlinks
     if (!$preserveLinks && !$config['PreserveLinks']) {
         $data = preg_replace_callback('/<a[^>]*href\\s*=\\s*"([^"]*)">(.*?)<\\/a>/i', function ($matches) {
             return Convert::html2raw($matches[2]) . "[{$matches['1']}]";
         }, $data);
         $data = preg_replace_callback('/<a[^>]*href\\s*=\\s*([^ ]*)>(.*?)<\\/a>/i', function ($matches) {
             return Convert::html2raw($matches[2]) . "[{$matches['1']}]";
         }, $data);
     }
     // Replace images with their alt tags
     if ($config['ReplaceImagesWithAlt']) {
         $data = preg_replace('/<img[^>]*alt *= *"([^"]*)"[^>]*>/i', ' \\1 ', $data);
         $data = preg_replace('/<img[^>]*alt *= *([^ ]*)[^>]*>/i', ' \\1 ', $data);
     }
     // Compress whitespace
     if ($config['CompressWhitespace']) {
         $data = preg_replace("/\\s+/", " ", $data);
     }
     // Parse newline tags
     $data = preg_replace("/\\s*<[Hh][1-6]([^A-Za-z0-9>][^>]*)?> */", "\n\n", $data);
     $data = preg_replace("/\\s*<[Pp]([^A-Za-z0-9>][^>]*)?> */", "\n\n", $data);
     $data = preg_replace("/\\s*<[Dd][Ii][Vv]([^A-Za-z0-9>][^>]*)?> */", "\n\n", $data);
     $data = preg_replace("/\n\n\n+/", "\n\n", $data);
     $data = preg_replace("/<[Bb][Rr]([^A-Za-z0-9>][^>]*)?> */", "\n", $data);
     $data = preg_replace("/<[Tt][Rr]([^A-Za-z0-9>][^>]*)?> */", "\n", $data);
     $data = preg_replace("/<\\/[Tt][Dd]([^A-Za-z0-9>][^>]*)?> */", "    ", $data);
     $data = preg_replace('/<\\/p>/i', "\n\n", $data);
     // Replace HTML entities
     $data = html_entity_decode($data, ENT_QUOTES, 'UTF-8');
     // Remove all tags (but optionally keep links)
     // strip_tags seemed to be restricting the length of the output
     // arbitrarily. This essentially does the same thing.
     if (!$preserveLinks && !$config['PreserveLinks']) {
         $data = preg_replace('/<\\/?[^>]*>/', '', $data);
     } else {
         $data = strip_tags($data, '<a>');
     }
     // Wrap
     if ($wordWrap) {
         $data = wordwrap(trim($data), $wordWrap);
     }
     return trim($data);
 }
 /**
  * @return array Array of associative arrays for each task (Keys: 'class', 'title', 'description')
  */
 protected function getTasks()
 {
     $availableTasks = array();
     $taskClasses = ClassInfo::subclassesFor('SilverStripe\\Dev\\BuildTask');
     // remove the base class
     array_shift($taskClasses);
     foreach ($taskClasses as $class) {
         if (!$this->taskEnabled($class)) {
             continue;
         }
         $singleton = BuildTask::singleton($class);
         $desc = Director::is_cli() ? Convert::html2raw($singleton->getDescription()) : $singleton->getDescription();
         $availableTasks[] = array('class' => $class, 'title' => $singleton->getTitle(), 'segment' => $singleton->config()->segment ?: str_replace('\\', '-', $class), 'description' => $desc);
     }
     return $availableTasks;
 }