- Added Sudzy composer dependency for model validation

- All models now extend a generic Model class that extends Sudzy
- Wrote tests for Subscriber and Setting model validation
- Rewrote model tests to make sure they look the same
- Updated both tests with cleanup logic in the beginning
- Added test:unit-single method to Robo for selective unit testing

Closes #54
This commit is contained in:
Vlad
2015-08-11 23:48:21 +00:00
parent 0df8973b7e
commit 12bead358c
10 changed files with 361 additions and 118 deletions

2
.gitignore vendored
View File

@@ -10,3 +10,5 @@ node_modules
npm-debug.log npm-debug.log
!tasks/** !tasks/**
/views/cache/** /views/cache/**
temp
.idea

View File

@@ -14,34 +14,20 @@ class RoboFile extends \Robo\Tasks {
} }
function watch() { function watch() {
$files = array( $files = array(// global admin styles
// global admin styles 'assets/css/src/admin.styl', // rtl specific styles
'assets/css/src/admin.styl', 'assets/css/src/rtl.styl');
// rtl specific styles
'assets/css/src/rtl.styl'
);
$command = array( $command = array('./node_modules/stylus/bin/stylus -u', ' nib -w' . join(' ', $files) . ' -o assets/css/');
'./node_modules/stylus/bin/stylus -u',
' nib -w'.
join(' ', $files).
' -o assets/css/'
);
$this->_exec(join(' ', $command)); $this->_exec(join(' ', $command));
} }
function makepot() { function makepot() {
$this->_exec('grunt makepot'. $this->_exec('grunt makepot' . ' --gruntfile ' . __DIR__ . '/tasks/makepot/makepot.js' . ' --base_path ' . __DIR__);
' --gruntfile '.__DIR__.'/tasks/makepot/makepot.js'.
' --base_path '.__DIR__
);
} }
function pushpot() { function pushpot() {
$this->_exec('grunt pushpot'. $this->_exec('grunt pushpot' . ' --gruntfile ' . __DIR__ . '/tasks/makepot/makepot.js' . ' --base_path ' . __DIR__);
' --gruntfile '.__DIR__.'/tasks/makepot/makepot.js'.
' --base_path '.__DIR__
);
} }
function testUnit() { function testUnit() {
@@ -50,13 +36,19 @@ class RoboFile extends \Robo\Tasks {
$this->_exec('vendor/bin/codecept run unit'); $this->_exec('vendor/bin/codecept run unit');
} }
function testUnitSingle($unit = null) {
if (!$unit) {
throw new Exception("Your need to specify what you want to test (e.g.: test:unit-single models/SubscriberCest)");
}
$this->_exec('vendor/bin/codecept build');
$this->loadEnv();
$this->_exec('vendor/bin/codecept run unit ' . $unit);
}
function testAcceptance() { function testAcceptance() {
$this->_exec('vendor/bin/codecept build'); $this->_exec('vendor/bin/codecept build');
$this->loadEnv(); $this->loadEnv();
$this $this->taskExec('phantomjs --webdriver=4444')->background()->run();
->taskExec('phantomjs --webdriver=4444')
->background()
->run();
sleep(2); sleep(2);
$this->_exec('vendor/bin/codecept run acceptance'); $this->_exec('vendor/bin/codecept run acceptance');
} }
@@ -64,10 +56,7 @@ class RoboFile extends \Robo\Tasks {
function testAll() { function testAll() {
$this->_exec('vendor/bin/codecept build'); $this->_exec('vendor/bin/codecept build');
$this->loadEnv(); $this->loadEnv();
$this $this->taskexec('phantomjs --webdriver=4444')->background()->run();
->taskexec('phantomjs --webdriver=4444')
->background()
->run();
sleep(2); sleep(2);
$this->_exec('vendor/bin/codecept run'); $this->_exec('vendor/bin/codecept run');
} }
@@ -82,15 +71,8 @@ class RoboFile extends \Robo\Tasks {
$dotenv = new Dotenv\Dotenv(__DIR__); $dotenv = new Dotenv\Dotenv(__DIR__);
$dotenv->load(); $dotenv->load();
$this $this->taskWriteToFile('tests/acceptance.suite.yml')->textFromFile('tests/acceptance.suite.src')->run();
->taskWriteToFile('tests/acceptance.suite.yml')
->textFromFile('tests/acceptance.suite.src')
->run();
$this $this->taskReplaceInFile('tests/acceptance.suite.yml')->regex("/url.*/")->to('url: ' . "'" . getenv('WP_TEST_URL') . "'")->run();
->taskReplaceInFile('tests/acceptance.suite.yml')
->regex("/url.*/")
->to('url: ' . "'" . getenv('WP_TEST_URL'). "'")
->run();
} }
} }

View File

@@ -1,4 +1,10 @@
{ {
"repositories": [
{
"type": "vcs",
"url": "https://github.com/mailpoet/sudzy"
}
],
"require": { "require": {
"php": ">=5.3.3", "php": ">=5.3.3",
"twig/twig": "1.*", "twig/twig": "1.*",
@@ -6,7 +12,8 @@
"cerdic/css-tidy": "*", "cerdic/css-tidy": "*",
"sunra/php-simple-html-dom-parser": "*", "sunra/php-simple-html-dom-parser": "*",
"tburry/pquery": "*", "tburry/pquery": "*",
"j4mie/paris": "1.5.4" "j4mie/paris": "1.5.4 as 1.4",
"tag/sudzy" : "dev-master"
}, },
"require-dev": { "require-dev": {
@@ -14,7 +21,8 @@
"codeception/verify": "*", "codeception/verify": "*",
"codegyre/robo": "*", "codegyre/robo": "*",
"vlucas/phpdotenv": "*", "vlucas/phpdotenv": "*",
"umpirsky/twig-gettext-extractor": "1.1.*" "umpirsky/twig-gettext-extractor": "1.1.*",
"raveren/kint": "^1.0"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {

115
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"hash": "4b157c8484b1247df06b05f728db16bc", "hash": "99a6abaeb9ef73071b63a330b58242cc",
"packages": [ "packages": [
{ {
"name": "cerdic/css-tidy", "name": "cerdic/css-tidy",
@@ -255,6 +255,55 @@
], ],
"time": "2013-05-04 14:32:03" "time": "2013-05-04 14:32:03"
}, },
{
"name": "tag/sudzy",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/mailpoet/sudzy.git",
"reference": "329e1b339baa1e662cb263e5bc30930456ab5227"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mailpoet/sudzy/zipball/329e1b339baa1e662cb263e5bc30930456ab5227",
"reference": "329e1b339baa1e662cb263e5bc30930456ab5227",
"shasum": ""
},
"require": {
"j4mie/paris": ">=1.4",
"php": ">=5.3.0"
},
"type": "library",
"autoload": {
"psr-0": {
"Sudzy": ".",
"ValidationException": "Sudzy"
}
},
"license": [
"BSD"
],
"authors": [
{
"name": "Tom Gregory",
"email": "tom@alt-tag.com",
"homepage": "http://alt-tag.com/",
"role": "Developer"
}
],
"description": "Model validator for use with Paris (and Idiorm).",
"homepage": "https://github.com/tag/sudzy",
"keywords": [
"idiorm",
"model",
"paris",
"validator"
],
"support": {
"source": "https://github.com/mailpoet/sudzy/tree/master"
},
"time": "2015-08-11 20:30:34"
},
{ {
"name": "tburry/pquery", "name": "tburry/pquery",
"version": "v1.1.0", "version": "v1.1.0",
@@ -1386,6 +1435,57 @@
], ],
"time": "2015-05-04 20:22:00" "time": "2015-05-04 20:22:00"
}, },
{
"name": "raveren/kint",
"version": "1.0.6",
"source": {
"type": "git",
"url": "https://github.com/raveren/kint.git",
"reference": "0cb1329798c85df500e4dfac607c5d6834c18431"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/raveren/kint/zipball/0cb1329798c85df500e4dfac607c5d6834c18431",
"reference": "0cb1329798c85df500e4dfac607c5d6834c18431",
"shasum": ""
},
"require": {
"php": ">=5.1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"files": [
"Kint.class.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Rokas Šleinius",
"homepage": "https://github.com/raveren"
},
{
"name": "Contributors",
"homepage": "https://github.com/raveren/kint/contributors"
}
],
"description": "Kint - debugging helper for PHP developers",
"homepage": "https://github.com/raveren/kint",
"keywords": [
"debug",
"kint",
"php"
],
"time": "2015-07-02 11:06:58"
},
{ {
"name": "sebastian/comparator", "name": "sebastian/comparator",
"version": "1.2.0", "version": "1.2.0",
@@ -2896,9 +2996,18 @@
"time": "2015-05-30 16:15:01" "time": "2015-05-30 16:15:01"
} }
], ],
"aliases": [], "aliases": [
{
"alias": "1.4",
"alias_normalized": "1.4.0.0",
"version": "1.5.4.0",
"package": "j4mie/paris"
}
],
"minimum-stability": "stable", "minimum-stability": "stable",
"stability-flags": [], "stability-flags": {
"tag/sudzy": 20
},
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {

View File

@@ -0,0 +1,19 @@
<?php namespace MailPoet\Models;
class CustomValidator {
function __construct() {
$this->validator = new \Sudzy\Engine();
}
function init() {
$this->validator->addValidator(
'isString',
function ($val) {
return is_string($val);
}
);
return $this->validator;
}
}

13
lib/Models/Model.php Normal file
View File

@@ -0,0 +1,13 @@
<?php
namespace MailPoet\Models;
if (!defined('ABSPATH')) {
exit;
}
class Model extends \Sudzy\ValidModel {
function __construct() {
$customValidator = new CustomValidator();
parent::__construct($customValidator->init());
}
}

View File

@@ -1,8 +1,31 @@
<?php <?php
namespace MailPoet\Models; namespace MailPoet\Models;
if (!defined('ABSPATH')) exit; if (!defined('ABSPATH')) {
exit;
class Setting extends \Model { }
public static $_table = MP_SETTINGS_TABLE;
class Setting extends Model {
public static $_table = MP_SETTINGS_TABLE;
function __construct() {
parent::__construct();
$this->addValidations(
"name",
array("required" => "validation_option_name_blank",
"isString" => "validation_option_name_string",
"minLength|2" => "validation_option_name_length"
)
);
$this->addValidations(
"value",
array("required" => "validation_option_value_blank",
"isString" => "validation_option_value_string",
"minLength|2" => "validation_option_value_length"
)
);
}
} }

View File

@@ -1,8 +1,32 @@
<?php <?php
namespace MailPoet\Models; namespace MailPoet\Models;
if (!defined('ABSPATH')) exit; if (!defined('ABSPATH')) {
exit;
class Subscriber extends \Model { }
public static $_table = MP_SUBSCRIBERS_TABLE;
class Subscriber extends Model {
public static $_table = MP_SUBSCRIBERS_TABLE;
function __construct() {
$this->addValidations(
'email',
array('required' => "validation_email_blank",
'isEmail' => "validation_email_invalid"
)
);
$this->addValidations(
'first_name',
array('required' => "validation_first_name_blank",
'minLength|2' => "validation_first_name_length"
)
);
$this->addValidations(
'last_name',
array('required' => "validation_last_name_blank",
'minLength|2' => "validation_last_name_length"
)
);
}
} }

View File

@@ -1,22 +1,58 @@
<?php <?php
use \MailPoet\Models\Setting; use MailPoet\Models\Setting;
class SettingCest { class SettingCest {
function _before() { function _before() {
$this->data = array('name' => 'sending_method', 'value' => 'smtp');
// clean up after previously failed test
$setting = Setting::where('name', $this->data['name'])->findOne();
if ($setting !== false) {
$setting->delete();
}
$setting = Setting::create(); $setting = Setting::create();
$setting->name = 'sending_method'; $setting->name = $this->data['name'];
$setting->value = 'smtp'; $setting->value = $this->data['value'];
$setting->save(); $setting->save();
} }
function itCanBeCreated() { function itCanBeCreated() {
$setting = Setting::where('name', 'sending_method')->findOne(); $setting = Setting::where('name', $this->data['name'])->findOne();
expect($setting->id)->notNull(); expect($setting->id)->notNull();
} }
function nameShouldValidate() {
$conflict_setting = Setting::create();
$conflict_setting->validateField('name', '');
expect($conflict_setting->getValidationErrors()[0])->equals('validation_option_name_blank');
$conflict_setting = Setting::create();
$conflict_setting->validateField('name', 31337);
expect($conflict_setting->getValidationErrors()[0])->equals('validation_option_name_string');
$conflict_setting = Setting::create();
$conflict_setting->validateField('name', 'a');
expect($conflict_setting->getValidationErrors()[0])->equals('validation_option_name_length');
}
function valueShouldValidate() {
$conflict_setting = Setting::create();
$conflict_setting->validateField('value', '');
expect($conflict_setting->getValidationErrors()[0])->equals('validation_option_value_blank');
$conflict_setting = Setting::create();
$conflict_setting->validateField('value', 31337);
expect($conflict_setting->getValidationErrors()[0])->equals('validation_option_value_string');
$conflict_setting = Setting::create();
$conflict_setting->validateField('value', 'a');
expect($conflict_setting->getValidationErrors()[0])->equals('validation_option_value_length');
}
function _after() { function _after() {
$setting = Setting::where('name', 'sending_method')->findOne()->delete(); $setting = Setting::where('name', $this->data['name'])->findOne()->delete();
} }
} }

View File

@@ -1,24 +1,22 @@
<?php <?php
use \MailPoet\Models\Subscriber; use MailPoet\Models\Subscriber;
class SubscriberCest { class SubscriberCest {
function _before() { function _before() {
$this->data = array( $this->data = array('first_name' => 'John', 'last_name' => 'Mailer', 'email' => 'john@mailpoet.com');
'first_name' => 'John',
'last_name' => 'Mailer', // clean up after previously failed test
'email' => 'john@mailpoet.com' $subscriber = Subscriber::where('email', $this->data['email'])->findOne();
); if ($subscriber !== false) {
$subscriber->delete();
}
$this->subscriber = Subscriber::create(); $this->subscriber = Subscriber::create();
$this $this->subscriber->first_name = $this->data['first_name'];
->subscriber
->first_name = $this->data['first_name'];
$this $this->subscriber->last_name = $this->data['last_name'];
->subscriber
->last_name = $this->data['last_name'];
$this->subscriber->email = $this->data['email']; $this->subscriber->email = $this->data['email'];
@@ -32,20 +30,17 @@ class SubscriberCest {
function itHasAFirstName() { function itHasAFirstName() {
$subscriber = Subscriber::where('email', $this->data['email'])->findOne(); $subscriber = Subscriber::where('email', $this->data['email'])->findOne();
expect($subscriber->first_name) expect($subscriber->first_name)->equals($this->data['first_name']);
->equals($this->data['first_name']);
} }
function itHasALastName() { function itHasALastName() {
$subscriber = Subscriber::where('email', $this->data['email'])->findOne(); $subscriber = Subscriber::where('email', $this->data['email'])->findOne();
expect($subscriber->last_name) expect($subscriber->last_name)->equals($this->data['last_name']);
->equals($this->data['last_name']);
} }
function itHasAnEmail() { function itHasAnEmail() {
$subscriber = Subscriber::where('email', $this->data['email'])->findOne(); $subscriber = Subscriber::where('email', $this->data['email'])->findOne();
expect($subscriber->email) expect($subscriber->email)->equals($this->data['email']);
->equals($this->data['email']);
} }
function emailMustBeUnique() { function emailMustBeUnique() {
@@ -62,7 +57,39 @@ class SubscriberCest {
expect($conflicted)->equals(true); expect($conflicted)->equals(true);
} }
function emailShouldValidate() {
$conflict_subscriber = Subscriber::create();
$conflict_subscriber->validateField('email', '');
expect($conflict_subscriber->getValidationErrors()[0])->equals('validation_email_blank');
$conflict_subscriber = Subscriber::create();
$conflict_subscriber->validateField('email', 'some @ email . com');
expect($conflict_subscriber->getValidationErrors()[0])->equals('validation_email_invalid');
}
function firstNameShouldValidate() {
$conflict_subscriber = Subscriber::create();
$conflict_subscriber->validateField('first_name', '');
expect($conflict_subscriber->getValidationErrors()[0])->equals('validation_first_name_blank');
$conflict_subscriber = Subscriber::create();
$conflict_subscriber->validateField('first_name', 'a');
expect($conflict_subscriber->getValidationErrors()[0])->equals('validation_first_name_length');
}
function lastNameShouldValidate() {
$conflict_subscriber = Subscriber::create();
$conflict_subscriber->validateField('last_name', '');
expect($conflict_subscriber->getValidationErrors()[0])->equals('validation_last_name_blank');
$conflict_subscriber = Subscriber::create();
$conflict_subscriber->validateField('last_name', 'a');
expect($conflict_subscriber->getValidationErrors()[0])->equals('validation_last_name_length');
}
function _after() { function _after() {
$subscriber = Subscriber::where('email', $this->data['email'])->findOne()->delete(); $subscriber = Subscriber::where('email', $this->data['email'])->findOne()->delete();
} }
} }