diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cc851c5..891adc8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,29 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Added +- Methods `getLineNumber` and `getColumnNumber` which return a nullable `int` + for the following classes: + `Comment`, `CSSList`, `SourceException`, `Charset`, `CSSNamespace`, `Import`, + `Rule`, `DeclarationBlock`, `RuleSet`, `CSSFunction`, `Value` (#1225) +- `Positionable` interface for CSS items that may have a position + (line and perhaps column number) in the parsed CSS (#1221) + ### Changed +- Implement `Positionable` in the following CSS item classes: + `Comment`, `CSSList`, `SourceException`, `Charset`, `CSSNamespace`, `Import`, + `Rule`, `DeclarationBlock`, `RuleSet`, `CSSFunction`, `Value` (#1225) + ### Deprecated +- `getLineNo()` is deprecated in these classes (use `getLineNumber()` instead): + `Comment`, `CSSList`, `SourceException`, `Charset`, `CSSNamespace`, `Import`, + `Rule`, `DeclarationBlock`, `RuleSet`, `CSSFunction`, `Value` (#1225, #1233) +- `Rule::getColNo()` is deprecated (use `getColumnNumber()` instead) + (#1225, #1233) +- Providing zero as the line number argument to `Rule::setPosition()` is + deprecated (pass `null` instead if there is no line number) (#1225, #1233) + ### Removed ### Fixed diff --git a/composer.json b/composer.json index acf650a2..e3caf0cc 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,8 @@ "ext-iconv": "*" }, "require-dev": { - "phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.41" + "phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.41", + "rawr/cross-data-providers": "^2.0.0" }, "suggest": { "ext-mbstring": "for parsing UTF-8 CSS" diff --git a/src/CSSList/CSSList.php b/src/CSSList/CSSList.php index 0f40d40a..2156aa11 100644 --- a/src/CSSList/CSSList.php +++ b/src/CSSList/CSSList.php @@ -9,6 +9,8 @@ use Sabberworm\CSS\Parsing\SourceException; use Sabberworm\CSS\Parsing\UnexpectedEOFException; use Sabberworm\CSS\Parsing\UnexpectedTokenException; +use Sabberworm\CSS\Position\Position; +use Sabberworm\CSS\Position\Positionable; use Sabberworm\CSS\Property\AtRule; use Sabberworm\CSS\Property\Charset; use Sabberworm\CSS\Property\CSSNamespace; @@ -29,8 +31,10 @@ * * It can also contain `Import` and `Charset` objects stemming from at-rules. */ -abstract class CSSList implements Renderable, Commentable +abstract class CSSList implements Commentable, Positionable, Renderable { + use Position; + /** * @var array * @@ -45,13 +49,6 @@ abstract class CSSList implements Renderable, Commentable */ protected $aContents; - /** - * @var int - * - * @internal since 8.8.0 - */ - protected $iLineNo; - /** * @param int $iLineNo */ @@ -59,7 +56,7 @@ public function __construct($iLineNo = 0) { $this->aComments = []; $this->aContents = []; - $this->iLineNo = $iLineNo; + $this->setPosition($iLineNo); } /** @@ -258,14 +255,6 @@ private static function identifierIs($sIdentifier, $sMatch) ?: preg_match("/^(-\\w+-)?$sMatch$/i", $sIdentifier) === 1; } - /** - * @return int - */ - public function getLineNo() - { - return $this->iLineNo; - } - /** * Prepends an item to the list of contents. * diff --git a/src/Comment/Comment.php b/src/Comment/Comment.php index 1d8810ec..fb571b40 100644 --- a/src/Comment/Comment.php +++ b/src/Comment/Comment.php @@ -4,15 +4,12 @@ use Sabberworm\CSS\OutputFormat; use Sabberworm\CSS\Renderable; +use Sabberworm\CSS\Position\Position; +use Sabberworm\CSS\Position\Positionable; -class Comment implements Renderable +class Comment implements Positionable, Renderable { - /** - * @var int - * - * @internal since 8.8.0 - */ - protected $iLineNo; + use Position; /** * @var string @@ -28,7 +25,7 @@ class Comment implements Renderable public function __construct($sComment = '', $iLineNo = 0) { $this->sComment = $sComment; - $this->iLineNo = $iLineNo; + $this->setPosition($iLineNo); } /** @@ -39,14 +36,6 @@ public function getComment() return $this->sComment; } - /** - * @return int - */ - public function getLineNo() - { - return $this->iLineNo; - } - /** * @param string $sComment * diff --git a/src/Parsing/SourceException.php b/src/Parsing/SourceException.php index 1ca668a9..1aa27b43 100644 --- a/src/Parsing/SourceException.php +++ b/src/Parsing/SourceException.php @@ -2,12 +2,12 @@ namespace Sabberworm\CSS\Parsing; -class SourceException extends \Exception +use Sabberworm\CSS\Position\Position; +use Sabberworm\CSS\Position\Positionable; + +class SourceException extends \Exception implements Positionable { - /** - * @var int - */ - private $iLineNo; + use Position; /** * @param string $sMessage @@ -15,18 +15,10 @@ class SourceException extends \Exception */ public function __construct($sMessage, $iLineNo = 0) { - $this->iLineNo = $iLineNo; + $this->setPosition($iLineNo); if (!empty($iLineNo)) { $sMessage .= " [line no: $iLineNo]"; } parent::__construct($sMessage); } - - /** - * @return int - */ - public function getLineNo() - { - return $this->iLineNo; - } } diff --git a/src/Position/Position.php b/src/Position/Position.php new file mode 100644 index 00000000..1c4d0df0 --- /dev/null +++ b/src/Position/Position.php @@ -0,0 +1,72 @@ +|null + */ + protected $lineNumber; + + /** + * @var int<0, max>|null + */ + protected $columnNumber; + + /** + * @return int<1, max>|null + */ + public function getLineNumber() + { + return $this->lineNumber; + } + + /** + * @return int<0, max> + */ + public function getLineNo() + { + $lineNumber = $this->getLineNumber(); + + return $lineNumber !== null ? $lineNumber : 0; + } + + /** + * @return int<0, max>|null + */ + public function getColumnNumber() + { + return $this->columnNumber; + } + + /** + * @return int<0, max> + */ + public function getColNo() + { + $columnNumber = $this->getColumnNumber(); + + return $columnNumber !== null ? $columnNumber : 0; + } + + /** + * @param int<0, max>|null $lineNumber + * @param int<0, max>|null $columnNumber + */ + public function setPosition($lineNumber, $columnNumber = null) + { + // The conditional is for backwards compatibility (backcompat); `0` will not be allowed in future. + $this->lineNumber = $lineNumber !== 0 ? $lineNumber : null; + $this->columnNumber = $columnNumber; + } +} diff --git a/src/Position/Positionable.php b/src/Position/Positionable.php new file mode 100644 index 00000000..4539c425 --- /dev/null +++ b/src/Position/Positionable.php @@ -0,0 +1,45 @@ +|null + */ + public function getLineNumber(); + + /** + * @return int<0, max> + * + * @deprecated in version 8.9.0, will be removed in v9.0. Use `getLineNumber()` instead. + */ + public function getLineNo(); + + /** + * @return int<0, max>|null + */ + public function getColumnNumber(); + + /** + * @return int<0, max> + * + * @deprecated in version 8.9.0, will be removed in v9.0. Use `getColumnNumber()` instead. + */ + public function getColNo(); + + /** + * @param int<0, max>|null $lineNumber + * Providing zero for this parameter is deprecated in version 8.9.0, and will not be supported from v9.0. + * Use `null` instead when no line number is available. + * @param int<0, max>|null $columnNumber + */ + public function setPosition($lineNumber, $columnNumber = null); +} diff --git a/src/Property/CSSNamespace.php b/src/Property/CSSNamespace.php index 0d90cc3b..188d3581 100644 --- a/src/Property/CSSNamespace.php +++ b/src/Property/CSSNamespace.php @@ -4,12 +4,16 @@ use Sabberworm\CSS\Comment\Comment; use Sabberworm\CSS\OutputFormat; +use Sabberworm\CSS\Position\Position; +use Sabberworm\CSS\Position\Positionable; /** * `CSSNamespace` represents an `@namespace` rule. */ -class CSSNamespace implements AtRule +class CSSNamespace implements AtRule, Positionable { + use Position; + /** * @var string */ @@ -41,18 +45,10 @@ public function __construct($mUrl, $sPrefix = null, $iLineNo = 0) { $this->mUrl = $mUrl; $this->sPrefix = $sPrefix; - $this->iLineNo = $iLineNo; + $this->setPosition($iLineNo); $this->aComments = []; } - /** - * @return int - */ - public function getLineNo() - { - return $this->iLineNo; - } - /** * @return string * diff --git a/src/Property/Charset.php b/src/Property/Charset.php index de9016ad..1ebff3f3 100644 --- a/src/Property/Charset.php +++ b/src/Property/Charset.php @@ -4,6 +4,8 @@ use Sabberworm\CSS\Comment\Comment; use Sabberworm\CSS\OutputFormat; +use Sabberworm\CSS\Position\Position; +use Sabberworm\CSS\Position\Positionable; use Sabberworm\CSS\Value\CSSString; /** @@ -14,8 +16,10 @@ * - May only appear at the very top of a Document’s contents. * - Must not appear more than once. */ -class Charset implements AtRule +class Charset implements AtRule, Positionable { + use Position; + /** * @var CSSString */ @@ -42,18 +46,10 @@ class Charset implements AtRule public function __construct(CSSString $oCharset, $iLineNo = 0) { $this->oCharset = $oCharset; - $this->iLineNo = $iLineNo; + $this->setPosition($iLineNo); $this->aComments = []; } - /** - * @return int - */ - public function getLineNo() - { - return $this->iLineNo; - } - /** * @param string|CSSString $oCharset * diff --git a/src/Property/Import.php b/src/Property/Import.php index e3f10474..5b474493 100644 --- a/src/Property/Import.php +++ b/src/Property/Import.php @@ -4,13 +4,17 @@ use Sabberworm\CSS\Comment\Comment; use Sabberworm\CSS\OutputFormat; +use Sabberworm\CSS\Position\Position; +use Sabberworm\CSS\Position\Positionable; use Sabberworm\CSS\Value\URL; /** * Class representing an `@import` rule. */ -class Import implements AtRule +class Import implements AtRule, Positionable { + use Position; + /** * @var URL */ @@ -21,13 +25,6 @@ class Import implements AtRule */ private $sMediaQuery; - /** - * @var int - * - * @internal since 8.8.0 - */ - protected $iLineNo; - /** * @var array * @@ -44,18 +41,10 @@ public function __construct(URL $oLocation, $sMediaQuery, $iLineNo = 0) { $this->oLocation = $oLocation; $this->sMediaQuery = $sMediaQuery; - $this->iLineNo = $iLineNo; + $this->setPosition($iLineNo); $this->aComments = []; } - /** - * @return int - */ - public function getLineNo() - { - return $this->iLineNo; - } - /** * @param URL $oLocation * diff --git a/src/Rule/Rule.php b/src/Rule/Rule.php index 037132e3..e358d93f 100644 --- a/src/Rule/Rule.php +++ b/src/Rule/Rule.php @@ -8,6 +8,8 @@ use Sabberworm\CSS\Parsing\ParserState; use Sabberworm\CSS\Parsing\UnexpectedEOFException; use Sabberworm\CSS\Parsing\UnexpectedTokenException; +use Sabberworm\CSS\Position\Position; +use Sabberworm\CSS\Position\Positionable; use Sabberworm\CSS\Renderable; use Sabberworm\CSS\Value\RuleValueList; use Sabberworm\CSS\Value\Value; @@ -17,8 +19,10 @@ * * In CSS, `Rule`s are expressed as follows: “key: value[0][0] value[0][1], value[1][0] value[1][1];” */ -class Rule implements Renderable, Commentable +class Rule implements Commentable, Positionable, Renderable { + use Position; + /** * @var string */ @@ -39,18 +43,6 @@ class Rule implements Renderable, Commentable */ private $aIeHack; - /** - * @var int - */ - protected $iLineNo; - - /** - * @var int - * - * @internal since 8.8.0 - */ - protected $iColNo; - /** * @var array * @@ -69,8 +61,7 @@ public function __construct($sRule, $iLineNo = 0, $iColNo = 0) $this->mValue = null; $this->bIsImportant = false; $this->aIeHack = []; - $this->iLineNo = $iLineNo; - $this->iColNo = $iColNo; + $this->setPosition($iLineNo, $iColNo); $this->aComments = []; } @@ -142,34 +133,6 @@ private static function listDelimiterForRule($sRule) } } - /** - * @return int - */ - public function getLineNo() - { - return $this->iLineNo; - } - - /** - * @return int - */ - public function getColNo() - { - return $this->iColNo; - } - - /** - * @param int $iLine - * @param int $iColumn - * - * @return void - */ - public function setPosition($iLine, $iColumn) - { - $this->iColNo = $iColumn; - $this->iLineNo = $iLine; - } - /** * @param string $sRule * @@ -295,7 +258,7 @@ public function addValue($mValue, $sType = ' ') } if (!$this->mValue instanceof RuleValueList || $this->mValue->getListSeparator() !== $sType) { $mCurrentValue = $this->mValue; - $this->mValue = new RuleValueList($sType, $this->iLineNo); + $this->mValue = new RuleValueList($sType, $this->getLineNumber()); if ($mCurrentValue) { $this->mValue->addListComponent($mCurrentValue); } diff --git a/src/RuleSet/DeclarationBlock.php b/src/RuleSet/DeclarationBlock.php index 3b6c8775..9cc14ebf 100644 --- a/src/RuleSet/DeclarationBlock.php +++ b/src/RuleSet/DeclarationBlock.php @@ -434,8 +434,8 @@ public function expandBackgroundShorthand() 'background-repeat' => ['repeat'], 'background-attachment' => ['scroll'], 'background-position' => [ - new Size(0, '%', false, $this->iLineNo), - new Size(0, '%', false, $this->iLineNo), + new Size(0, '%', false, $this->getLineNo()), + new Size(0, '%', false, $this->getLineNo()), ], ]; $mRuleValue = $oRule->getValue(); @@ -801,7 +801,7 @@ public function createFontShorthand() $aLHValues = $mRuleValue->getListComponents(); } if ($aLHValues[0] !== 'normal') { - $val = new RuleValueList('/', $this->iLineNo); + $val = new RuleValueList('/', $this->getLineNo()); $val->addListComponent($aFSValues[0]); $val->addListComponent($aLHValues[0]); $oNewRule->addValue($val); @@ -817,7 +817,7 @@ public function createFontShorthand() } else { $aFFValues = $mRuleValue->getListComponents(); } - $oFFValue = new RuleValueList(',', $this->iLineNo); + $oFFValue = new RuleValueList(',', $this->getLineNo()); $oFFValue->setListComponents($aFFValues); $oNewRule->addValue($oFFValue); @@ -851,7 +851,10 @@ public function render($oOutputFormat) $sResult = $oOutputFormat->comments($this); if (count($this->aSelectors) === 0) { // If all the selectors have been removed, this declaration block becomes invalid - throw new OutputException("Attempt to print declaration block with missing selector", $this->iLineNo); + throw new OutputException( + 'Attempt to print declaration block with missing selector', + $this->getLineNumber() + ); } $sResult .= $oOutputFormat->sBeforeDeclarationBlock; $sResult .= $oOutputFormat->implode( diff --git a/src/RuleSet/RuleSet.php b/src/RuleSet/RuleSet.php index c0843389..85b94f26 100644 --- a/src/RuleSet/RuleSet.php +++ b/src/RuleSet/RuleSet.php @@ -8,6 +8,8 @@ use Sabberworm\CSS\Parsing\ParserState; use Sabberworm\CSS\Parsing\UnexpectedEOFException; use Sabberworm\CSS\Parsing\UnexpectedTokenException; +use Sabberworm\CSS\Position\Position; +use Sabberworm\CSS\Position\Positionable; use Sabberworm\CSS\Renderable; use Sabberworm\CSS\Rule\Rule; @@ -20,8 +22,10 @@ * If you want to manipulate a `RuleSet`, use the methods `addRule(Rule $rule)`, `getRules()` and `removeRule($rule)` * (which accepts either a `Rule` or a rule name; optionally suffixed by a dash to remove all related rules). */ -abstract class RuleSet implements Renderable, Commentable +abstract class RuleSet implements Commentable, Positionable, Renderable { + use Position; + /** * the rules in this rule set, using the property name as the key, * with potentially multiple rules per property name. @@ -30,13 +34,6 @@ abstract class RuleSet implements Renderable, Commentable */ private $aRules; - /** - * @var int - * - * @internal since 8.8.0 - */ - protected $iLineNo; - /** * @var array * @@ -50,7 +47,7 @@ abstract class RuleSet implements Renderable, Commentable public function __construct($iLineNo = 0) { $this->aRules = []; - $this->iLineNo = $iLineNo; + $this->setPosition($iLineNo); $this->aComments = []; } @@ -102,14 +99,6 @@ public static function parseRuleSet(ParserState $oParserState, RuleSet $oRuleSet $oParserState->consume('}'); } - /** - * @return int - */ - public function getLineNo() - { - return $this->iLineNo; - } - /** * @param Rule|null $oSibling * diff --git a/src/Value/CSSFunction.php b/src/Value/CSSFunction.php index fcf641d5..703f6658 100644 --- a/src/Value/CSSFunction.php +++ b/src/Value/CSSFunction.php @@ -34,7 +34,7 @@ public function __construct($sName, $aArguments, $sSeparator = ',', $iLineNo = 0 $aArguments = $aArguments->getListComponents(); } $this->sName = $sName; - $this->iLineNo = $iLineNo; + $this->setPosition($iLineNo); // TODO: redundant? parent::__construct($aArguments, $sSeparator, $iLineNo); } diff --git a/src/Value/Value.php b/src/Value/Value.php index 3816289d..beb74464 100644 --- a/src/Value/Value.php +++ b/src/Value/Value.php @@ -6,27 +6,24 @@ use Sabberworm\CSS\Parsing\SourceException; use Sabberworm\CSS\Parsing\UnexpectedEOFException; use Sabberworm\CSS\Parsing\UnexpectedTokenException; +use Sabberworm\CSS\Position\Position; +use Sabberworm\CSS\Position\Positionable; use Sabberworm\CSS\Renderable; /** * Abstract base class for specific classes of CSS values: `Size`, `Color`, `CSSString` and `URL`, and another * abstract subclass `ValueList`. */ -abstract class Value implements Renderable +abstract class Value implements Positionable, Renderable { - /** - * @var int - * - * @internal since 8.8.0 - */ - protected $iLineNo; + use Position; /** * @param int $iLineNo */ public function __construct($iLineNo = 0) { - $this->iLineNo = $iLineNo; + $this->setPosition($iLineNo); } /** @@ -218,12 +215,4 @@ private static function parseUnicodeRangeValue(ParserState $oParserState) } while (strlen($sRange) < $iCodepointMaxLength && preg_match("/[A-Fa-f0-9\?-]/", $oParserState->peek())); return "U+{$sRange}"; } - - /** - * @return int - */ - public function getLineNo() - { - return $this->iLineNo; - } } diff --git a/tests/Unit/Position/Fixtures/ConcretePosition.php b/tests/Unit/Position/Fixtures/ConcretePosition.php new file mode 100644 index 00000000..0db38706 --- /dev/null +++ b/tests/Unit/Position/Fixtures/ConcretePosition.php @@ -0,0 +1,13 @@ +subject = new ConcretePosition(); + } + + /** + * @test + */ + public function getLineNumberInitiallyReturnsNull() + { + $this->doSetUp(); + + self::assertNull($this->subject->getLineNumber()); + } + + /** + * @test + */ + public function getColumnNumberInitiallyReturnsNull() + { + $this->doSetUp(); + + self::assertNull($this->subject->getColumnNumber()); + } + + /** + * @return array}> + */ + public function provideLineNumber() + { + return [ + 'line 1' => [1], + 'line 42' => [42], + ]; + } + + /** + * @test + * + * @param int<1, max> $lineNumber + * + * @dataProvider provideLineNumber + */ + public function setPositionOnVirginSetsLineNumber($lineNumber) + { + $this->doSetUp(); + + $this->subject->setPosition($lineNumber); + + self::assertSame($lineNumber, $this->subject->getLineNumber()); + } + + /** + * @test + * + * @param int<1, max> $lineNumber + * + * @dataProvider provideLineNumber + */ + public function setPositionSetsNewLineNumber($lineNumber) + { + $this->doSetUp(); + + $this->subject->setPosition(99); + + $this->subject->setPosition($lineNumber); + + self::assertSame($lineNumber, $this->subject->getLineNumber()); + } + + /** + * @test + */ + public function setPositionWithNullClearsLineNumber() + { + $this->doSetUp(); + + $this->subject->setPosition(99); + + $this->subject->setPosition(null); + + self::assertNull($this->subject->getLineNumber()); + } + + /** + * @return array}> + */ + public function provideColumnNumber() + { + return [ + 'column 0' => [0], + 'column 14' => [14], + 'column 39' => [39], + ]; + } + + /** + * @test + * + * @param int<0, max> $columnNumber + * + * @dataProvider provideColumnNumber + */ + public function setPositionOnVirginSetsColumnNumber($columnNumber) + { + $this->doSetUp(); + + $this->subject->setPosition(1, $columnNumber); + + self::assertSame($columnNumber, $this->subject->getColumnNumber()); + } + + /** + * @test + * + * @param int $columnNumber + * + * @dataProvider provideColumnNumber + */ + public function setPositionSetsNewColumnNumber($columnNumber) + { + $this->doSetUp(); + + $this->subject->setPosition(1, 99); + + $this->subject->setPosition(2, $columnNumber); + + self::assertSame($columnNumber, $this->subject->getColumnNumber()); + } + + /** + * @test + */ + public function setPositionWithoutColumnNumberClearsColumnNumber() + { + $this->doSetUp(); + + $this->subject->setPosition(1, 99); + + $this->subject->setPosition(2); + + self::assertNull($this->subject->getColumnNumber()); + } + + /** + * @test + */ + public function setPositionWithNullForColumnNumberClearsColumnNumber() + { + $this->doSetUp(); + + $this->subject->setPosition(1, 99); + + $this->subject->setPosition(2, null); + + self::assertNull($this->subject->getColumnNumber()); + } + + /** + * @return array, 1: int<0, max>}> + */ + public function provideLineAndColumnNumber() + { + if (!\class_exists(DataProviders::class)) { + self::markTestSkipped('`DataProviders` class is not available'); + return []; + } + + return DataProviders::cross($this->provideLineNumber(), $this->provideColumnNumber()); + } + + /** + * @test + * + * @param int $lineNumber + * @param int $columnNumber + * + * @dataProvider provideLineAndColumnNumber + */ + public function setPositionOnVirginSetsLineAndColumnNumber($lineNumber, $columnNumber) + { + $this->doSetUp(); + + $this->subject->setPosition($lineNumber, $columnNumber); + + self::assertSame($lineNumber, $this->subject->getLineNumber()); + self::assertSame($columnNumber, $this->subject->getColumnNumber()); + } + + /** + * @test + * + * @param int $lineNumber + * @param int $columnNumber + * + * @dataProvider provideLineAndColumnNumber + */ + public function setPositionSetsNewLineAndColumnNumber($lineNumber, $columnNumber) + { + $this->doSetUp(); + + $this->subject->setPosition(98, 99); + + $this->subject->setPosition($lineNumber, $columnNumber); + + self::assertSame($lineNumber, $this->subject->getLineNumber()); + self::assertSame($columnNumber, $this->subject->getColumnNumber()); + } +} diff --git a/tests/UnitDeprecated/Position/PositionTest.php b/tests/UnitDeprecated/Position/PositionTest.php new file mode 100644 index 00000000..f7378e04 --- /dev/null +++ b/tests/UnitDeprecated/Position/PositionTest.php @@ -0,0 +1,158 @@ +subject = new ConcretePosition(); + } + + /** + * @return array}> + */ + public function provideLineNumber() + { + return [ + 'line 1' => [1], + 'line 42' => [42], + ]; + } + + /** + * @return array}> + */ + public function provideColumnNumber() + { + return [ + 'column 0' => [0], + 'column 14' => [14], + 'column 39' => [39], + ]; + } + + /** + * @test + */ + public function getLineNoInitiallyReturnsZero() + { + $this->doSetUp(); + + self::assertSame(0, $this->subject->getLineNo()); + } + + /** + * @test + * + * @paarm int $lineNumber + * + * @dataProvider provideLineNumber + */ + public function getLineNoReturnsLineNumberSet($lineNumber) + { + $this->doSetUp(); + + $this->subject->setPosition($lineNumber); + + self::assertSame($lineNumber, $this->subject->getLineNo()); + } + + /** + * @test + */ + public function getLineNoReturnsZeroAfterLineNumberCleared() + { + $this->doSetUp(); + + $this->subject->setPosition(99); + + $this->subject->setPosition(null); + + self::assertSame(0, $this->subject->getLineNo()); + } + + /** + * @test + */ + public function getColNoInitiallyReturnsZero() + { + $this->doSetUp(); + + self::assertSame(0, $this->subject->getColNo()); + } + + /** + * @test + * + * @param int $columnNumber + * + * @dataProvider provideColumnNumber + */ + public function getColNoReturnsColumnNumberSet($columnNumber) + { + $this->doSetUp(); + + $this->subject->setPosition(1, $columnNumber); + + self::assertSame($columnNumber, $this->subject->getColNo()); + } + + /** + * @test + */ + public function getColNoReturnsZeroAfterColumnNumberCleared() + { + $this->doSetUp(); + + $this->subject->setPosition(1, 99); + + $this->subject->setPosition(2); + + self::assertSame(0, $this->subject->getColNo()); + } + + /** + * @test + */ + public function setPositionWithZeroClearsLineNumber() + { + $this->doSetUp(); + + $this->subject->setPosition(99); + + $this->subject->setPosition(0); + + self::assertNull($this->subject->getLineNumber()); + } + + /** + * @test + */ + public function getLineNoAfterSetPositionWithZeroReturnsZero() + { + $this->doSetUp(); + + $this->subject->setPosition(99); + + $this->subject->setPosition(0); + + self::assertSame(0, $this->subject->getLineNo()); + } +}