commit e8fdb5109de5506bb2d4a0fc52a73f5613af6b68 Author: Ismo Vuorinen Date: Fri Jun 8 13:02:36 2018 +0300 Initial commit with tests, and stuff. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dfd6caa --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/vendor +composer.lock \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..eec0e5a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,22 @@ +language: php +php: + - 5.6 + - 7.0 + - 7.1 + - 7.2 + - nightly +matrix: + allow_failures: + - php: nightly + fast_finish: true +cache: + directories: + - $HOME/.composer/cache/files +before_script: + - phpenv global "$TRAVIS_PHP_VERSION" + - composer config extra.platform.php $TRAVIS_PHP_VERSION +install: + - flags="--ansi --prefer-dist --no-interaction --optimize-autoloader --no-suggest --no-progress" + - travis_wait 30 composer install $flags +script: +- ./vendor/bin/phpunit -c phpunit.xml diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..527a59a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,87 @@ +# Changelog + +All Notable changes to `ivuorinen\BBCodeParser` will be documented in this file. + +## v3.0.0 - 2018-06-08 + +- Project now in new hands +- Tests + +# Changelog of `Golonka\BBCodeParser` + +## v2.2.0 - 2015-09-07 + +### Added +- You can now strip all BBCode tags by using the ``stripBBCodeTags`` function. + +## v2.1.0 - 2015-06-20 + +### Added +- Made ``parseCaseSensitive`` and ``parseCaseInsensitive`` functions to make parsing more readable. + +## v2.0.0 - 2015-06-02 + +### Added +- Using PSR-4 instead of PSR-0 +- Moved the ``arrayOnly`` and ``arrayExcept`` functions into a trait +- Minimum supported PHP version bumped to 5.4 + +### Fixed +- Renamed some tag names, mostly making them all lowercase + - `` underLine -> underline `` + - `` lineThrough -> linethrough `` + - `` fontSize -> size `` + - `` fontColor -> color `` + - `` namedQuote -> namedquote `` + - `` namedQuote -> namedquote `` + - `` namedLink -> namedlink `` + - `` orderedListNumerical -> orderedlistnumerical `` + - `` orderedListAlpha -> orderedlistalpha `` + - `` unorderedList -> unorderedlist `` + - `` listItem -> listitem `` + +### Removed +- The ``iterate`` property is removed. Unneeded after improvements in parsing method. +- Removed deprecated tags ``[ul]`` and ``[ol]`` + +## v1.4 - 2015-05-05 + +### Added +- Optional parameter enables or disables case insensitivity. Disabled by default. + +## v1.3.0 - 2014-06-30 + +### Fixed +- The only/except functionally have been broken since like 1.1, but now it´s working. Better late then never! + +## v1.2.7 - 2014-05-19 + +### Added +- A new iterate key is added to tags that typically could contain more tags of the same kind, like quotes. + +### Fixed +- Problem where tags of the same kind would just parse the top level. + +## v1.2.6 - 2014-05-17 + +### Fixed +- Fixed a problem where if a tag had a line break in them they wouldn't parse. + +## v1.2.5 - 2014-05-15 + +### Fixed +- Improved most regex matches by removing unnecessary greediness. + +## v1.2.0 - 2014-03-25 + +### Fixed +- Better syntax for lists. + +## v1.1.0 - 2014-01-27 + +### Added +- Support for custom bbcode tags. + +## v1.0.0 - 2013-11-07 + +Released the package. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..f564977 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,32 @@ +# Contributing + +Contributions are **welcome** and will be fully **credited**. + +We accept contributions via Pull Requests on [Github](https://github.com/ivuorinen/bbcodeparser). + + +## Pull Requests + +- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). + +- **Add tests!** - Your patch won't be accepted if it doesn't have tests. + +- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. + +- **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. + +- **Create feature branches** - Don't ask us to pull from your master branch. + +- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. + +- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. + + +## Running Tests + +``` bash +$ vendor/bin/phpunit +``` + + +**Happy coding**! \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..da008a4 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,22 @@ +# The MIT License (MIT) + +Copyright (c) 2018 Ismo Vuorinen +Copyright (c) 2013-2015 Joseph Landberg + +> Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in +> all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +> THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..499feb3 --- /dev/null +++ b/README.md @@ -0,0 +1,120 @@ +[![Latest Version](https://img.shields.io/github/release/ivuorinen/bbcodeparser.svg?style=flat-square)](https://github.com/ivuorinen/bbcodeparser/releases) +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) +[![Build Status](https://img.shields.io/travis/ivuorinen/BBCodeParser/master.svg?style=flat-square)](https://travis-ci.org/ivuorinen/BBCodeParser) +[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/ivuorinen/bbcodeparser/master.svg?style=flat-square)](https://scrutinizer-ci.com/g/ivuorinen/bbcodeparser/code-structure) +[![Quality Score](https://img.shields.io/scrutinizer/g/ivuorinen/bbcodeparser/master.svg?style=flat-square)](https://scrutinizer-ci.com/g/ivuorinen/bbcodeparser) +[![Total Downloads](https://img.shields.io/packagist/dt/ivuorinen/bbcodeparser.svg?style=flat-square)](https://packagist.org/packages/ivuorinen/bbcodeparser) + +The ``ivuorinen\BBCodeParser`` package will help you with parsing BBCode. +This package is build on work by [Joseph Landberg](https://github.com/golonka). + +## Install + +Via Composer + +``` bash +$ composer require ivuorinen/bbcodeparser +``` + +## Usage +To parse some text it's as easy as this! +``` php +$bbcode = new ivuorinen\BBCode\BBCodeParser; + +echo $bbcode->parse('[b]Bold Text![/b]'); +// Bold Text! +``` +Would like the parser to not use all bbcodes? Just do like this. +``` php +$bbcode = new ivuorinen\BBCode\BBCodeParser; + +echo $bbcode->only('bold', 'italic') + ->parse('[b][u]Bold[/u] [i]Italic[/i]![/b]'); + // [u]Bold[/u] Italic! + +echo $bbcode->except('bold') + ->parse('[b]Bold[/b] [i]Italic[/i]'); + // [b]Bold[/b] Italic +``` + +By default the parser is case sensitive. But if you would like the parser to accept tags like `` [B]Bold Text[/B] `` it's really easy. +``` php +$bbcode = new ivuorinen\BBCode\BBCodeParser; + +// Case insensitive +echo $bbcode->parse('[b]Bold[/b] [I]Italic![/I]', true); + // Bold Italic! + +// Or like this + +echo $bbcode->parseCaseInsensitive('[b]Bold[/b] [i]Italic[/i]'); + // Bold Italic! +``` +You could also make it more explicit that the parser is case sensitive by using another helper function. +``` php + $bbcode = new ivuorinen\BBCode\BBCodeParser; + + echo $bbcode->parseCaseSensitive('[b]Bold[/b] [I]Italic![/I]'); + // Bold [I]Italic![/I] +``` + +If you would like to completely remove all BBCode it's just one function call away. +``` php + $bbcode = new ivuorinen\BBCode\BBCodeParser; + + echo $bbcode->stripBBCodeTags('[b]Bold[/b] [i]Italic![/i]'); + // Bold Italic! +``` + +## Laravel integration +The integration into Laravel is really easy, and the method is the same for both Laravel 4 and Laravel 5. +This package supports Laravel Package Auto-Discovery, so it should be picked up automatically. + +If you don't want auto-discovery, or because of old habits, just open your ``app.php`` config file. + +In there you just add this to your providers array +``` php +'ivuorinen\BBCode\BBCodeParserServiceProvider' +``` + +And this to your facades array +``` php +'BBCode' => 'ivuorinen\BBCode\Facades\BBCodeParser' +``` + +The syntax is the same as if you would use it in vanilla PHP but with the ``BBCode::`` before the methods. +Here are some examples. +``` php +// Simple parsing +echo BBCode::parse('[b]Bold Text![/b]'); + +// Limiting the parsers with the only method +echo BBCode::only('bold', 'italic') + ->parse('[b][u]Bold[/u] [i]Italic[/i]![/b]'); + // [u]Bold[/u] Italic! + +// Or the except method +echo BBCode::except('bold') + ->parse('[b]Bold[/b] [i]Italic[/i]'); + // [b]Bold[/b] Italic +``` + +## Testing + +``` bash +$ phpunit +``` + +## Contributing + +Please see [CONTRIBUTING](CONTRIBUTING.md) for details. + +## Credits + +- [Ismo Vuorinen](https://github.com/ivuorinen) +- [Joseph Landberg](https://github.com/golonka) +- [All Contributors](../../contributors) + +## License + +The MIT License (MIT). Please see [License File](LICENSE.md) for more information. diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..15c4bdb --- /dev/null +++ b/composer.json @@ -0,0 +1,50 @@ +{ + "name": "ivuorinen/bbcodeparser", + "description": "Parse your BBCode easy with this library.", + "keywords": ["bbcode", "parser", "laravel", "psr-1", "psr-2", "psr-4"], + "homepage": "https://github.com/ivuorinen/bbcodeparser", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Ismo Vuorinen", + "email": "ismo@ivuorinen.net", + "homepage": "https://github.com/ivuorinen" + }, + { + "name": "Joseph Landberg", + "email": "joseph.landberg@gmail.com", + "homepage": "https://github.com/golonka/" + } + ], + "require": { + "php": ">=7" + }, + "require-dev": { + "phpunit/phpunit": "~5", + "squizlabs/php_codesniffer": "~2", + "orchestra/testbench": "~3.0" + }, + "autoload": { + "psr-4": { + "ivuorinen\\BBCode\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { "ivuorinen\\BBCode\\Tests\\": "tests/" }, + "classmap": [ + "tests/" + ] + }, + "minimum-stability": "stable", + "extra": { + "laravel": { + "providers": [ + "ivuorinen\\BBCode\\BBCodeParserServiceProvider" + ], + "aliases": { + "BBCode": "ivuorinen\\BBCode\\Facades\\BBCodeParser" + } + } + } +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..b08155f --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,21 @@ + + + + + ./tests + + + + + ./src + + + \ No newline at end of file diff --git a/src/BBCodeParser.php b/src/BBCodeParser.php new file mode 100644 index 0000000..60f405d --- /dev/null +++ b/src/BBCodeParser.php @@ -0,0 +1,245 @@ + [ + 'pattern' => '/\[b\](.*?)\[\/b\]/s', + 'replace' => '$1', + 'content' => '$1' + ], + 'italic' => [ + 'pattern' => '/\[i\](.*?)\[\/i\]/s', + 'replace' => '$1', + 'content' => '$1' + ], + 'underline' => [ + 'pattern' => '/\[u\](.*?)\[\/u\]/s', + 'replace' => '$1', + 'content' => '$1' + ], + 'linethrough' => [ + 'pattern' => '/\[s\](.*?)\[\/s\]/s', + 'replace' => '$1', + 'content' => '$1' + ], + 'size' => [ + 'pattern' => '/\[size\=([1-7])\](.*?)\[\/size\]/s', + 'replace' => '$2', + 'content' => '$2' + ], + 'color' => [ + 'pattern' => '/\[color\=(#[A-f0-9]{6}|#[A-f0-9]{3})\](.*?)\[\/color\]/s', + 'replace' => '$2', + 'content' => '$2' + ], + 'center' => [ + 'pattern' => '/\[center\](.*?)\[\/center\]/s', + 'replace' => '
$1
', + 'content' => '$1' + ], + 'left' => [ + 'pattern' => '/\[left\](.*?)\[\/left\]/s', + 'replace' => '
$1
', + 'content' => '$1' + ], + 'right' => [ + 'pattern' => '/\[right\](.*?)\[\/right\]/s', + 'replace' => '
$1
', + 'content' => '$1' + ], + 'quote' => [ + 'pattern' => '/\[quote\](.*?)\[\/quote\]/s', + 'replace' => '
$1
', + 'content' => '$1' + ], + 'namedquote' => [ + 'pattern' => '/\[quote\=(.*?)\](.*)\[\/quote\]/s', + 'replace' => '
$1$2
', + 'content' => '$2' + ], + 'link' => [ + 'pattern' => '/\[url\](.*?)\[\/url\]/s', + 'replace' => '$1', + 'content' => '$1' + ], + 'namedlink' => [ + 'pattern' => '/\[url\=(.*?)\](.*?)\[\/url\]/s', + 'replace' => '$2', + 'content' => '$2' + ], + 'image' => [ + 'pattern' => '/\[img\](.*?)\[\/img\]/s', + 'replace' => '', + 'content' => '$1' + ], + 'orderedlistnumerical' => [ + 'pattern' => '/\[list=1\](.*?)\[\/list\]/s', + 'replace' => '
    $1
', + 'content' => '$1' + ], + 'orderedlistalpha' => [ + 'pattern' => '/\[list=a\](.*?)\[\/list\]/s', + 'replace' => '
    $1
', + 'content' => '$1' + ], + 'unorderedlist' => [ + 'pattern' => '/\[list\](.*?)\[\/list\]/s', + 'replace' => '
    $1
', + 'content' => '$1' + ], + 'listitem' => [ + 'pattern' => '/\[\*\](.*)/', + 'replace' => '
  • $1
  • ', + 'content' => '$1' + ], + 'code' => [ + 'pattern' => '/\[code\](.*?)\[\/code\]/s', + 'replace' => '$1', + 'content' => '$1' + ], + 'youtube' => [ + 'pattern' => '/\[youtube\](.*?)\[\/youtube\]/s', + 'replace' => '', + 'content' => '$1' + ], + 'linebreak' => [ + 'pattern' => '/\r\n/', + 'replace' => '
    ', + 'content' => '' + ] + ]; + + private $enabledParsers; + + public function __construct() + { + $this->enabledParsers = $this->parsers; + } + + /** + * Parses the BBCode string + * @param string $source String containing the BBCode + * @param bool $caseInsensitive + * @return string Parsed string + */ + public function parse($source, $caseInsensitive = false) + { + foreach ($this->enabledParsers as $name => $parser) { + $pattern = ($caseInsensitive) ? $parser['pattern'] . 'i' : $parser['pattern']; + + $source = $this->searchAndReplace($pattern, $parser['replace'], $source); + } + return $source; + } + + /** + * Remove all BBCode + * @param string $source + * @return string Parsed text + */ + public function stripBBCodeTags($source) + { + foreach ($this->parsers as $name => $parser) { + $source = $this->searchAndReplace($parser['pattern'] . 'i', $parser['content'], $source); + } + return $source; + } + + /** + * Searches after a specified pattern and replaces it with provided structure + * @param string $pattern Search pattern + * @param string $replace Replacement structure + * @param string $source Text to search in + * @return string Parsed text + */ + protected function searchAndReplace($pattern, $replace, $source) + { + while (preg_match($pattern, $source)) { + $source = preg_replace($pattern, $replace, $source); + } + + return $source; + } + + /** + * Helper function to parse case sensitive + * @param string $source String containing the BBCode + * @return string Parsed text + */ + public function parseCaseSensitive($source) + { + return $this->parse($source, false); + } + + /** + * Helper function to parse case insensitive + * @param string $source String containing the BBCode + * @return string Parsed text + */ + public function parseCaseInsensitive($source) + { + return $this->parse($source, true); + } + + /** + * Limits the parsers to only those you specify + * @param mixed $only parsers + * @return object BBCodeParser object + */ + public function only($only = null) + { + $only = (is_array($only)) ? $only : func_get_args(); + $this->enabledParsers = $this->arrayOnly($this->parsers, $only); + return $this; + } + + /** + * Removes the parsers you want to exclude + * @param mixed $except parsers + * @return BBCodeParser + */ + public function except($except = null) + { + $except = (is_array($except)) ? $except : func_get_args(); + $this->enabledParsers = $this->arrayExcept($this->parsers, $except); + return $this; + } + + /** + * List of chosen parsers + * @return array array of parsers + */ + public function getParsers() + { + return $this->enabledParsers; + } + + /** + * Sets the parser pattern and replace. + * This can be used for new parsers or overwriting existing ones. + * @param string $name Parser name + * @param string $pattern Pattern + * @param string $replace Replace pattern + * @param string $content Parsed text pattern + * @return void + */ + public function setParser($name, $pattern, $replace, $content) + { + $this->parsers[$name] = array( + 'pattern' => $pattern, + 'replace' => $replace, + 'content' => $content + ); + + $this->enabledParsers[$name] = array( + 'pattern' => $pattern, + 'replace' => $replace, + 'content' => $content + ); + } +} diff --git a/src/BBCodeParserServiceProvider.php b/src/BBCodeParserServiceProvider.php new file mode 100644 index 0000000..040027f --- /dev/null +++ b/src/BBCodeParserServiceProvider.php @@ -0,0 +1,36 @@ +app->bind('bbcode', function () { + return new BBCodeParser; + }); + } + + /** + * Get the services provided by the provider. + * + * @return array + */ + public function provides() + { + return ['bbcode']; + } +} diff --git a/src/Facades/BBCodeParser.php b/src/Facades/BBCodeParser.php new file mode 100644 index 0000000..d7a9ab9 --- /dev/null +++ b/src/Facades/BBCodeParser.php @@ -0,0 +1,11 @@ +arrayOnly($parsers, $only); + } + + /** + * @param array $parsers + * @param $except + * @see \ivuorinen\BBCode\Traits\ArrayTrait::arrayExcept + * @return array + */ + public function publicArrayExcept(array $parsers, $except) + { + return $this->arrayExcept($parsers, $except); + } +} diff --git a/tests/ArrayTraitTest.php b/tests/ArrayTraitTest.php new file mode 100644 index 0000000..f1885dd --- /dev/null +++ b/tests/ArrayTraitTest.php @@ -0,0 +1,26 @@ +class = new ArrayTraitHelper(); + } + + public function test_array_only() + { + $this->assertTrue(\method_exists($this->class, 'arrayOnly')); + } + + public function test_array_except() + { + $this->assertTrue(\method_exists($this->class, 'arrayExcept')); + } +} diff --git a/tests/BBCodeParserFacadeTest.php b/tests/BBCodeParserFacadeTest.php new file mode 100644 index 0000000..60f9e6c --- /dev/null +++ b/tests/BBCodeParserFacadeTest.php @@ -0,0 +1,34 @@ +callMethod( + new \ivuorinen\BBCode\Facades\BBCodeParser, + 'getFacadeAccessor', + [] + ); + $this->assertEquals('bbcode', $method); + } catch (ReflectionException $e) { + $this->throwException($e); + } + } + + /** + * @param $obj + * @param $name + * @param array $args + * @return mixed + * @throws ReflectionException + */ + public static function callMethod($obj, $name, array $args) + { + $class = new \ReflectionClass($obj); + $method = $class->getMethod($name); + $method->setAccessible(true); + return $method->invokeArgs($obj, $args); + } + +} diff --git a/tests/BBCodeParserServiceProviderTest.php b/tests/BBCodeParserServiceProviderTest.php new file mode 100644 index 0000000..cfec3e7 --- /dev/null +++ b/tests/BBCodeParserServiceProviderTest.php @@ -0,0 +1,20 @@ +app); + $this->assertEquals(['bbcode'], $provider->provides()); + } + + public function testRegister() + { + $this->assertInstanceOf( + \ivuorinen\BBCode\BBCodeParser::class, + $this->app['bbcode'] + ); + } +} diff --git a/tests/BBCodeParserTest.php b/tests/BBCodeParserTest.php new file mode 100644 index 0000000..590c861 --- /dev/null +++ b/tests/BBCodeParserTest.php @@ -0,0 +1,376 @@ + array( + 'bbcode' => 'b', + 'expected' => 'strong', + ), + 'italic' => array( + 'bbcode' => 'i', + 'expected' => 'em', + ), + 'underline' => array( + 'bbcode' => 'u' + ), + 'linethrough' => array( + 'bbcode' => 'u' + ), + 'size' => array( + 'bbcode_test' => '[size=%s]%s[/size]', + 'expected_test' => '%s', + 'values' => ['1', 'text'] + ), + 'color' => array( + 'bbcode_test' => '[color=%s]%s[/color]', + 'expected_test' => '%s', + 'values' => ['#123456', 'color'] + ), + 'center' => array( + 'bbcode' => 'center', + 'expected_test' => '
    %s
    ', + 'values' => ['center aligned'] + ), + 'left' => array( + 'bbcode' => 'left', + 'expected_test' => '
    %s
    ', + 'values' => ['left aligned'] + ), + 'right' => array( + 'bbcode' => 'right', + 'expected_test' => '
    %s
    ', + 'values' => ['right aligned'] + ), + 'quote' => array( + 'bbcode' => 'quote', + 'expected_test' => '
    %s
    ', + 'values' => ['quotable text'] + ), + 'namedquote' => array( + 'bbcode_test' => '[quote=%s]%s[/quote]', + 'expected_test' => '
    %s%s
    ', + 'values' => ['name', 'quotable text'] + ), + 'link' => array( + 'bbcode' => 'url', + 'bbcode_test' => '[url]%s[/url]', + 'expected_test' => '%1$s', + 'values' => ['value'] + ), + 'namedlink' => array( + 'bbcode' => 'url', + 'bbcode_test' => '[url=%s]%s[/url]', + 'expected_test' => '%s', + 'values' => ['link', 'value'] + ), + 'image' => array( + 'bbcode' => 'img', + 'expected_test' => '', + 'values' => ['link'] + ), + 'linebreak' => array( + 'bbcode_test' => "\r\n", + 'expected_test' => '
    ' + ), + 'code' => array( + 'bbcode' => 'code', + 'values' => ['link'] + ), + 'youtube' => array( + 'bbcode' => 'youtube', + 'expected_test' => '', + 'values' => ['dQw4w9WgXcQ'] + ), + 'listitem' => array( + 'bbcode_test' => "[*] List item", + 'expected_test' => '
  • List item
  • ' + ), + 'orderedlistnumerical' => array( + 'bbcode' => 'list', + 'bbcode_test' => '[list=1]%s[/list]', + 'expected_test' => '
      %s
    ', + 'values' => ['X'] + ), + 'orderedlistalpha' => array( + 'bbcode' => 'list', + 'bbcode_test' => '[list=a]%s[/list]', + 'expected_test' => '
      %s
    ', + 'values' => ['X'] + ), + 'unorderedlist' => array( + 'bbcode' => 'list', + 'bbcode_test' => '[list]%s[/list]', + 'expected_test' => '
      %s
    ', + 'values' => ['X'] + ), + ); + + public $lowerCaseTests = array( + ['bbcode' => '[code]Result[/code]', 'expected' => 'Result'], + ['bbcode' => '[i]Result[/i]', 'expected' => 'Result'], + ); + + public $upperCaseTests = array( + ['bbcode' => '[CODE]Result[/CODE]', 'expected' => 'Result'], + ['bbcode' => '[I]Result[/I]', 'expected' => 'Result'], + ); + + public $mixedCaseTests = array( + ['bbcode' => '[Code]Result[/Code]', 'expected' => 'Result'], + ['bbcode' => '[I]Result[/i]', 'expected' => 'Result'], + ); + + protected function setUp() + { + parent::setUp(); + + $this->parser = new BBCodeParser(); + } + + public function test_it_has_known_parsers() + { + $this->assertEquals( + $this->parser->parsers, + $this->parser->getParsers() + ); + } + + public function test_parsers_have_required_keys() + { + $keys = array('pattern', 'replace', 'content'); + $parsers = $this->parser->getParsers(); + + foreach ($parsers as $parserName => $parser) { + foreach ($keys as $key) { + $this->assertArrayHasKey( + $key, + $parser, + sprintf('Parser: %s, Key: %s', $parserName, $key) + ); + } + } + } + + public function test_parser_regexp_is_valid() + { + $parsers = $this->parser->getParsers(); + foreach ($parsers as $parserName => $parser) { + $pattern = $parser['pattern']; + + $this->assertTrue( + $this->assertRegexpIsValid($pattern), + sprintf('Key: %s, Regexp %s', $parserName, $pattern) + ); + } + } + + public function test_parser_default() + { + foreach ($this->testedParsers as $name => $options) { + $test = $this->createTest($options, $name); + + $result = $this->parser->parse($test['bbcode_test']); + $this->assertEquals($test['expected_test'], $result, $name); + } + } + + public function test_parser_sensitive() + { + $testTemp = 'Test: %s / bbcode: %s / Actual: %s / Expected: %s'; + + /** + * We expect these to pass + * Using: assertEquals + */ + foreach ($this->lowerCaseTests as $case) { + $bbcode = $case['bbcode']; + $expected = $case['expected']; + + $result = $this->parser->parseCaseSensitive($bbcode); + $this->assertEquals($expected, $result, sprintf( + $testTemp, 'lowercase, sensitive', $bbcode, $result, $expected + )); + } + + /** + * We expect these to fail + * Using: assertNotEquals + */ + foreach ($this->upperCaseTests as $case) { + $bbcode = $case['bbcode']; + $expected = $case['expected']; + + $result = $this->parser->parseCaseSensitive($bbcode); + $this->assertNotEquals($expected, $result, sprintf( + $testTemp, 'uppercase, sensitive', $bbcode, $result, $expected + )); + } + + /** + * We expect these to fail + * Using: assertNotEquals + */ + foreach ($this->mixedCaseTests as $case) { + $bbcode = $case['bbcode']; + $expected = $case['expected']; + + $result = $this->parser->parseCaseSensitive($bbcode); + $this->assertNotEquals($expected, $result, sprintf( + $testTemp, 'mixed case, sensitive', $bbcode, $result, $expected + )); + } + } + + public function test_parser_insensitive() + { + /** + * Now we run with insensitive case turned on, so everything + * should pass -- why this is not the default in original + * package baffles me. + */ + $cases = array_merge( + $this->lowerCaseTests, + $this->upperCaseTests, + $this->mixedCaseTests + ); + + foreach ($cases as $case) { + $bbcode = $case['bbcode']; + $expected = $case['expected']; + $this->assertEquals( + $expected, $this->parser->parse($bbcode, true) + ); + + $this->assertEquals( + $expected, + $this->parser->parseCaseInsensitive($bbcode) + ); + } + } + + public function test_stripBBCodeTags() + { + foreach ($this->mixedCaseTests as $test) { + $this->assertEquals( + \strip_tags($test['expected']), + $this->parser->stripBBCodeTags($test['bbcode']) + ); + } + } + + public function test_only() + { + $keys = array('bold', 'underline'); + + $parsers = $this->parser->getParsers(); + $onlyFew = $this->parser->only($keys)->getParsers(); + + $this->assertEquals($keys, array_keys($onlyFew)); + $this->assertNotEquals(array_keys($parsers), array_keys($onlyFew)); + } + + public function test_except() + { + $keys = array('bold', 'underline'); + + $parsers = $this->parser->getParsers(); + $exceptFew = $this->parser->except($keys)->getParsers(); + + $this->assertNotEquals($keys, array_keys($exceptFew)); + $this->assertNotEquals(array_keys($parsers), array_keys($exceptFew)); + } + + public function test_adding_a_new_parser() + { + $this->parser->setParser('test', 'x', 'y', 'z'); + $expected = array('pattern' => 'x', 'replace' => 'y', 'content' => 'z'); + $parsers = $this->parser->getParsers(); + + $this->assertArrayHasKey('test', $parsers); + $this->assertArraySubset($expected, $parsers['test']); + } + + public function test_we_have_all_parsers_tested() + { + $parsers = array_keys($this->parser->except($this->skipParsers)->getParsers()); + $missing = array(); + + foreach ($parsers as $parser) { + $result = isset($this->testedParsers[$parser]); + + if ($result) { + $this->assertTrue($result, sprintf('Parser missing: %s', $parser)); + } + + if (!$result) { + $missing[$parser] = $parser; + } + } + + if (!empty($missing)) { + $missing = sprintf( + 'Missing tests: %s', + implode(", ", $missing) + ); + $this->markTestIncomplete($missing); + } + } + + /** + * This is a helper to use our self::testedParsers + * rules for automated test generation. Automation ftw. + * + * @param array $options + * @param $name + * @return array + */ + public function createTest($options = [], $name) + { + if (!isset($options['bbcode'])) { + $options['bbcode'] = $name; + } + + if (!isset($options['values']) || empty($options['values'])) { + $options['values'] = ['Testing']; + } + + if (!isset($options['bbcode_test'])) { + $bbcodeValues = $options['values']; + array_unshift($bbcodeValues, $options['bbcode']); + array_push($bbcodeValues, $options['bbcode']); + $options['bbcode_test'] = vsprintf('[%s]%s[/%s]', $bbcodeValues); + } else { + $options['bbcode_test'] = vsprintf($options['bbcode_test'], $options['values']); + } + + if (!isset($options['expected'])) { + $options['expected'] = $options['bbcode']; + } + + if (!isset($options['expected_test'])) { + $expectedValues = $options['values']; + array_unshift($expectedValues, $options['expected']); + array_push($expectedValues, $options['expected']); + $options['expected_test'] = vsprintf('<%s>%s', $expectedValues); + } else { + $options['expected_test'] = vsprintf($options['expected_test'], $options['values']); + } + + return $options; + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..06b69fc --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,21 @@ +