Compare commits

..

No commits in common. "master" and "master" have entirely different histories.

14 changed files with 131 additions and 293 deletions

2
.gitignore vendored
View file

@ -1 +1,3 @@
*.swp
tags
vendor

View file

@ -1,14 +0,0 @@
build_settings:
verbose: false
prefer_symlink: false
setup:
composer:
action: "install"
test:
php_unit:
directory: "tests/"
args: "--configuration 'phpunit.xml'"
complete:

25
Jenkinsfile vendored
View file

@ -1,25 +0,0 @@
pipeline {
agent any
stages {
stage('PHP 7.1') {
steps {
sh '/usr/local/bin/composer-php7.1 install'
sh 'php7.1 /usr/local/bin/phpunit-7'
}
}
stage('PHP 7.3') {
steps {
sh '/usr/local/bin/composer-php7.3 update'
sh 'php7.3 /usr/local/bin/phpunit-9'
}
}
stage('PHP 7.4') {
steps {
sh '/usr/local/bin/composer-php7.4 update'
sh 'php7.4 /usr/local/bin/phpunit-9'
}
}
}
}

View file

@ -20,5 +20,4 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,4 +0,0 @@
.PHONY: tests
tests:
phpunit

View file

@ -1,22 +1,16 @@
csv-validator
=============
[![Build Status](https://ci.gitnet.fr/buildStatus/icon?job=Gitnet%2Fcsv-validator%2F3)](https://ci.gitnet.fr/job/Gitnet/job/csv-validator/job/3/)
CSV validator library
That uses the constraints of Symfony framework: [http://symfony.com/doc/current/reference/constraints.html](http://symfony.com/doc/current/reference/constraints.html).
* [Installation](#installation)
* [Example](#example)
* [Contributors](#contributors)
Installation
------------
You need [composer](https://getcomposer.org/):
composer require deblan/csv-validator
composer require deblan/csv-validator dev-master
Example
@ -45,7 +39,7 @@ $validator->addFieldConstraint(0, new Email());
$validator->addFieldConstraint(1, new Date());
// Validate the legend
$validator->setExpectedHeaders(['foo', 'bar', 'bim']);
$validator->setExpectedLegend(array('foo', 'bar', 'bim'));
// An line must contain 3 columns
$validator->addDataConstraint(new Callback(function($data, ExecutionContextInterface $context) {
@ -55,17 +49,17 @@ $validator->addDataConstraint(new Callback(function($data, ExecutionContextInter
}));
// Initialisation of the parser
$parser = new CsvParser();
$parser->setHasHeaders(true);
$parser = new CsvParser(__DIR__.'/tests/fixtures/example.csv');
$parser->setHasLegend(true);
$validator->validate($parser->parseFile(__DIR__.'/tests/fixtures/example.csv'));
$validator->validate($parser);
if ($validator->isValid() === false) {
foreach ($validator->getErrors() as $error) {
$line = $error->getLine();
$line = $error->getLine();
$column = $error->getColumn();
$message = $error->getViolation()->getMessage();
echo <<<EOF
<ul>
<li>Line: $line</li>
@ -79,42 +73,3 @@ EOF;
}
}
```
Run `example.php` and see results:
```
<ul>
<li>Line: 1</li>
<li>Column: </li>
<li>
<p>Invalid legend.</p>
</li>
</ul>
<ul>
<li>Line: 4</li>
<li>Column: </li>
<li>
<p>The line must contain 3 columns</p>
</li>
</ul>
<ul>
<li>Line: 2</li>
<li>Column: 1</li>
<li>
<p>This value is not a valid email address.</p>
</li>
</ul>
<ul>
<li>Line: 3</li>
<li>Column: 2</li>
<li>
<p>This value is not a valid date.</p>
</li>
</ul>
```
Contributors
------------
* Simon Vieille
* Gautier Deruette

View file

@ -15,8 +15,8 @@
},
"minimum-stability": "dev",
"require": {
"php": "^7.1.3",
"symfony/validator": "^4",
"deblan/csv": "v2.0.*|v3.*"
"php": ">=5.6.0",
"symfony/validator": "2.*",
"deblan/csv": "v1.1"
}
}

View file

@ -2,6 +2,7 @@
use Deblan\Csv\CsvParser;
use Deblan\CsvValidator\Validator;
use Symfony\Component\Validator\Validation;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\Date;
use Symfony\Component\Validator\Constraints\Callback;
@ -19,27 +20,27 @@ $validator->addFieldConstraint(0, new Email());
$validator->addFieldConstraint(1, new Date());
// Validate the legend
$validator->setExpectedHeaders(['foo', 'bar', 'bim']);
$validator->setExpectedLegend(array('foo', 'bar', 'bim'));
// An line must contain 3 columns
$validator->addDataConstraint(new Callback(function ($data, ExecutionContextInterface $context) {
$validator->addDataConstraint(new Callback(function($data, ExecutionContextInterface $context) {
if (count($data) !== 6) { // 6 because of the legend (3 fields * 2)
$context->addViolation('The line must contain 3 columns');
}
}));
// Initialisation of the parser
$parser = new CsvParser();
$parser->setHasHeaders(true);
$parser = new CsvParser(__DIR__.'/tests/fixtures/example.csv');
$parser->setHasLegend(true);
$validator->validate($parser->parseFile(__DIR__.'/tests/fixtures/example.csv'));
$validator->validate($parser);
if ($validator->isValid() === false) {
foreach ($validator->getErrors() as $error) {
$line = $error->getLine();
$line = $error->getLine();
$column = $error->getColumn();
$message = $error->getViolation()->getMessage();
echo <<<EOF
<ul>
<li>Line: $line</li>

View file

@ -7,6 +7,7 @@
convertWarningsToExceptions = "true"
processIsolation = "false"
stopOnFailure = "false"
syntaxCheck = "false"
bootstrap = "vendor/autoload.php" >
<testsuites>

View file

@ -10,8 +10,7 @@ use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\Validation;
/**
* Class Validator.
*
* Class Validator
* @author Simon Vieille <simon@deblan.fr>
*/
class Validator
@ -37,7 +36,7 @@ class Validator
protected $dataConstraints = [];
/**
* @var bool
* @var boolean
*/
protected $hasValidate = false;
@ -45,14 +44,14 @@ class Validator
* @var array
*/
protected $errors = [];
/**
* @var array
*/
protected $expectedHeaders = [];
protected $expectedLegend = [];
/**
* Constructor.
* Constructor
*
* @param RecursiveValidator $validator
*/
@ -60,17 +59,16 @@ class Validator
{
if ($validator === null) {
$validator = Validation::createValidator();
}
}
$this->validator = $validator;
}
/**
* Append a constraint to a specific column.
* Append a constraint to a specific column
*
* @param int $key The column number
* @param integer $key The column number
* @param Constraint $constraint The constraint
*
* @return Validator
*/
public function addFieldConstraint($key, Constraint $constraint)
@ -85,10 +83,9 @@ class Validator
}
/**
* Append a constraint to a specific line.
* Append a constraint to a specific line
*
* @param Constraint $constraint The constraint
*
* @return Validator
*/
public function addDataConstraint(Constraint $constraint)
@ -99,63 +96,63 @@ class Validator
}
/**
* Set the expected legend.
* Set the expected legend
*
* @param array $legend Expected legend
*
* @return Validator
*/
public function setExpectedHeaders(array $legend)
public function setExpectedLegend(array $legend)
{
$this->expectedHeaders = $legend;
$this->expectedLegend = $legend;
return $this;
}
/**
* Run the validation.
*
* Run the validation
* @param CsvParser $parser
*/
public function validate(CsvParser $parser)
{
if ($this->parser !== $parser) {
$this->parser = $parser;
$this->parser->parse();
$this->errors = [];
$this->hasValidate = false;
} elseif ($this->hasValidate) {
}
elseif ($this->hasValidate) {
return;
}
$this->validateHeaders();
$this->validateLegend();
$this->validateDatas();
$this->validateFields();
$this->hasValidate = true;
}
/**
* Validates the legend.
* Validates the legend
*/
protected function validateHeaders()
protected function validateLegend()
{
if (!$this->parser->getHasHeaders()) {
if (!$this->parser->getHasLegend()) {
return;
}
if (empty($this->expectedHeaders)) {
if (empty($this->expectedLegend)) {
return;
}
if ($this->parser->getHeaders() !== $this->expectedHeaders) {
if ($this->parser->getLegend() !== $this->expectedLegend) {
$this->mergeErrorMessage('Invalid legend.', 1);
}
}
/**
* Validates datas.
* Validates datas
*/
protected function validateDatas()
protected function validateDatas()
{
if (empty($this->dataConstraints)) {
return;
@ -171,21 +168,21 @@ class Validator
}
/**
* Validates fields.
* Validates fields
*/
protected function validateFields()
protected function validateFields()
{
if (empty($this->fieldConstraints)) {
return;
}
foreach ($this->parser->getDatas() as $line => $data) {
foreach ($this->fieldConstraints as $key => $constraints) {
if (!isset($data[$key])) {
$column = $this->getTrueColunm($key);
$this->mergeErrorMessage(
sprintf('Field "%s" does not exist.', $column),
$this->getTrueLine($line),
sprintf('Field "%s" does not exist.', $column),
$this->getTrueLine($line),
$column
);
} else {
@ -193,8 +190,8 @@ class Validator
$violations = $this->validator->validate($data[$key], $constraint);
$this->mergeViolationsMessages(
$violations,
$this->getTrueLine($line),
$violations,
$this->getTrueLine($line),
$this->getTrueColunm($key)
);
}
@ -204,11 +201,11 @@ class Validator
}
/**
* Add violations.
* Add violations
*
* @param ConstraintViolationList $violations
* @param int $line The line of the violations
* @param int|null $key The column of the violations
* @param integer $line The line of the violations
* @param integer|null $key The column of the violations
*/
protected function mergeViolationsMessages(ConstraintViolationList $violations, $line, $key = null)
{
@ -222,11 +219,11 @@ class Validator
}
/**
* Create and append a violation from a string error.
* Create and append a violation from a string error
*
* @param string $message The error message
* @param int $line The line of the violations
* @param int|null $key The column of the violations
* @param string $message The error message
* @param integer $line The line of the violations
* @param integer|null $key The column of the violations
*/
protected function mergeErrorMessage($message, $line, $key = null)
{
@ -235,9 +232,9 @@ class Validator
}
/**
* Returns the validation status.
* Returns the validation status
*
* @return bool
* @return boolean
* @throw RuntimeException No validation yet
*/
public function isValid()
@ -250,7 +247,7 @@ class Validator
}
/**
* Returns the errors.
* Returns the errors
*
* @return array
*/
@ -260,55 +257,51 @@ class Validator
}
/**
* Generate a ConstraintViolation.
* Generate a ConstraintViolation
*
* @param string $message The error message
*
* @return ConstraintViolation
*/
protected function generateConstraintViolation($message)
protected function generateConstraintViolation($message)
{
return new ConstraintViolation($message, $message, [], null, '', null);
}
/**
* Generate a Violation.
*
* @param string $message The error message
* @param int $line The line of the violations
* @param int|null $key The column of the violations
* Generate a Violation
*
* @param string $message The error message
* @param integer $line The line of the violations
* @param integer|null $key The column of the violations
* @return Violation
*/
protected function generateViolation($line, $key, ConstraintViolation $violation)
protected function generateViolation($line, $key, ConstraintViolation $violation)
{
return new Violation($line, $key, $violation);
}
/**
* Get the true line number of an error.
* Get the true line number of an error
*
* @param int $line
*
* @return int
* @param integer $line
* @return integer
*/
protected function getTrueLine($line)
protected function getTrueLine($line)
{
if ($this->parser->getHasHeaders()) {
++$line;
if ($this->parser->getHasLegend()) {
$line++;
}
return ++$line;
}
/**
* Get the true culumn number of an error.
* Get the true culumn number of an error
*
* @param int $key
*
* @return int
* @param integer $key
* @return integer
*/
protected function getTrueColunm($key)
protected function getTrueColunm($key)
{
return ++$key;
}

View file

@ -5,32 +5,31 @@ namespace Deblan\CsvValidator;
use Symfony\Component\Validator\ConstraintViolation;
/**
* Class Violation.
*
* Class Violation
* @author Simon Vieille <simon@deblan.fr>
*/
class Violation
{
/**
* @var int
* @var integer
*/
protected $line;
/**
* @var int
* @var integer
*/
protected $column;
/**
* @var ConstraintViolation
*/
protected $violation;
/**
* Constructor.
* Constructor
*
* @param int $line The line of the violation
* @param int $column The column of the violation
* @param integer $line The line of the violation
* @param integer $column The column of the violation
* @param ConstraintViolation $violation The violation
*/
public function __construct($line, $column, ConstraintViolation $violation)
@ -42,7 +41,6 @@ class Violation
/**
* @param int $line
*
* @return Violation
*/
public function setLine($line)
@ -62,7 +60,6 @@ class Violation
/**
* @param int $column
*
* @return Violation
*/
public function setColumn($column)
@ -86,7 +83,6 @@ class Violation
/**
* @param ConstraintViolation $violation
*
* @return Violation
*/
public function setViolation(ConstraintViolation $violation)

View file

@ -1,46 +0,0 @@
<?php
use PHPUnit\Framework\TestCase;
/**
* class ExampleTest.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class ExampleTest extends TestCase
{
public function testExemple()
{
$content = shell_exec('php -f '.__DIR__.'/../example.php');
$this->assertEquals('<ul>
<li>Line: 1</li>
<li>Column: </li>
<li>
<p>Invalid legend.</p>
</li>
</ul>
<ul>
<li>Line: 4</li>
<li>Column: </li>
<li>
<p>The line must contain 3 columns</p>
</li>
</ul>
<ul>
<li>Line: 2</li>
<li>Column: 1</li>
<li>
<p>This value is not a valid email address.</p>
</li>
</ul>
<ul>
<li>Line: 3</li>
<li>Column: 2</li>
<li>
<p>This value is not a valid date.</p>
</li>
</ul>
', $content);
}
}

View file

@ -1,105 +1,86 @@
<?php
use PHPUnit\Framework\TestCase;
use Deblan\Csv\CsvParser;
use Deblan\CsvValidator\Validator;
use Symfony\Component\Validator\Validation;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Email;
class ValidatorTest extends TestCase
class ValidatorTest extends \PHPUnit_Framework_TestCase
{
public function testViolation()
{
$parser = $this->generateParser('example.csv');
$validator = $this->generateValidator($parser);
$this->expectException('\RuntimeException');
$this->setExpectedException('\RuntimeException');
$validator->isValid();
}
public function testExpectedHeaders()
{
$parser = $this->generateParser('example.csv');
$parser->setHasHeaders(true);
$validator = $this->generateValidator();
$validator->setExpectedHeaders(['foo', 'bar', 'boo']);
$validator->validate($parser->parseFile(__DIR__.'/fixtures/example.csv'));
$this->assertEquals(true, $validator->isValid());
$this->assertEquals(0, count($validator->getErrors()));
$validator = $this->generateValidator();
$validator->setExpectedHeaders(['bad', 'legend']);
$validator->validate($parser->parseFile(__DIR__.'/fixtures/example.csv'));
$this->assertEquals(false, $validator->isValid());
$this->assertEquals(1, count($validator->getErrors()));
}
public function testNoConstraint()
{
$parser = $this->generateParser('example.csv');
$validator = $this->generateValidator();
$validator->validate($parser->parseFile(__DIR__.'/fixtures/example.csv'));
$validator = $this->generateValidator($parser);
$validator->validate();
$this->assertEquals(true, $validator->isValid());
}
public function testFieldContraintsOk()
{
$parser = $this->generateParser('example.csv');
$validator = $this->generateValidator();
$validator = $this->generateValidator($parser);
$validator->addFieldConstraint(0, new NotBlank());
$validator->validate($parser->parseFile(__DIR__.'/fixtures/example.csv'));
$validator->validate();
$this->assertEquals(true, $validator->isValid());
$this->assertEquals(0, count($validator->getErrors()));
$parser = $this->generateParser('example.csv');
$validator = $this->generateValidator();
$validator = $this->generateValidator($parser);
$validator->addFieldConstraint(1, new NotBlank());
$validator->validate($parser->parseFile(__DIR__.'/fixtures/example.csv'));
$validator->validate();
$this->assertEquals(true, $validator->isValid());
$this->assertEquals(0, count($validator->getErrors()));
$parser = $this->generateParser('example.csv');
$validator = $this->generateValidator();
$validator = $this->generateValidator($parser);
$validator->addFieldConstraint(0, new NotBlank());
$validator->addFieldConstraint(1, new NotBlank());
$validator->validate($parser->parseFile(__DIR__.'/fixtures/example.csv'));
$validator->validate();
$this->assertEquals(true, $validator->isValid());
$this->assertEquals(0, count($validator->getErrors()));
}
public function testFieldContraintsKo()
{
$parser = $this->generateParser();
$validator = $this->generateValidator();
$validator->addFieldConstraint(0, new Email());
$validator->validate($parser->parseFile(__DIR__.'/fixtures/example.csv'));
$this->assertEquals(false, $validator->isValid());
$this->assertEquals(2, count($validator->getErrors()));
$parser = $this->generateParser();
$validator = $this->generateValidator();
$validator->addFieldConstraint(1, new Email());
$validator->validate($parser->parseFile(__DIR__.'/fixtures/example.csv'));
$this->assertEquals(false, $validator->isValid());
$this->assertEquals(5, count($validator->getErrors()));
$parser = $this->generateParser('example.csv');
$validator = $this->generateValidator();
$validator = $this->generateValidator($parser);
$validator->addFieldConstraint(0, new Email());
$validator->validate();
$this->assertEquals(false, $validator->isValid());
$this->assertEquals(4, count($validator->getErrors()));
$parser = $this->generateParser('example.csv');
$validator = $this->generateValidator($parser);
$validator->addFieldConstraint(1, new Email());
$validator->validate();
$this->assertEquals(false, $validator->isValid());
$this->assertEquals(4, count($validator->getErrors()));
$parser = $this->generateParser('example.csv');
$validator = $this->generateValidator($parser);
$validator->addFieldConstraint(0, new Email());
$validator->addFieldConstraint(1, new Email());
$validator->validate($parser->parseFile(__DIR__.'/fixtures/example.csv'));
$validator->validate();
$this->assertEquals(false, $validator->isValid());
$this->assertEquals(7, count($validator->getErrors()));
$this->assertEquals(8, count($validator->getErrors()));
}
protected function generateParser()
protected function generateParser($file)
{
return new CsvParser();
return new CsvParser(__DIR__.'/fixtures/'.$file);
}
protected function generateValidator()
protected function generateValidator(CsvParser $parser)
{
return new Validator(Validation::createValidator());
return new Validator($parser, Validation::createValidator());
}
}

View file

@ -1,10 +1,9 @@
<?php
use PHPUnit\Framework\TestCase;
use Symfony\Component\Validator\ConstraintViolation;
use Deblan\CsvValidator\Violation;
class ViolationTest extends TestCase
class ViolationTest extends \PHPUnit_Framework_TestCase
{
public function testViolation()
{