- 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
!tasks/**
/views/cache/**
temp
.idea

View File

@@ -14,34 +14,20 @@ class RoboFile extends \Robo\Tasks {
}
function watch() {
$files = array(
// global admin styles
'assets/css/src/admin.styl',
// rtl specific styles
'assets/css/src/rtl.styl'
);
$files = array(// global admin styles
'assets/css/src/admin.styl', // rtl specific styles
'assets/css/src/rtl.styl');
$command = array(
'./node_modules/stylus/bin/stylus -u',
' nib -w'.
join(' ', $files).
' -o assets/css/'
);
$command = array('./node_modules/stylus/bin/stylus -u', ' nib -w' . join(' ', $files) . ' -o assets/css/');
$this->_exec(join(' ', $command));
}
function makepot() {
$this->_exec('grunt makepot'.
' --gruntfile '.__DIR__.'/tasks/makepot/makepot.js'.
' --base_path '.__DIR__
);
$this->_exec('grunt makepot' . ' --gruntfile ' . __DIR__ . '/tasks/makepot/makepot.js' . ' --base_path ' . __DIR__);
}
function pushpot() {
$this->_exec('grunt pushpot'.
' --gruntfile '.__DIR__.'/tasks/makepot/makepot.js'.
' --base_path '.__DIR__
);
$this->_exec('grunt pushpot' . ' --gruntfile ' . __DIR__ . '/tasks/makepot/makepot.js' . ' --base_path ' . __DIR__);
}
function testUnit() {
@@ -50,13 +36,19 @@ class RoboFile extends \Robo\Tasks {
$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() {
$this->_exec('vendor/bin/codecept build');
$this->loadEnv();
$this
->taskExec('phantomjs --webdriver=4444')
->background()
->run();
$this->taskExec('phantomjs --webdriver=4444')->background()->run();
sleep(2);
$this->_exec('vendor/bin/codecept run acceptance');
}
@@ -64,10 +56,7 @@ class RoboFile extends \Robo\Tasks {
function testAll() {
$this->_exec('vendor/bin/codecept build');
$this->loadEnv();
$this
->taskexec('phantomjs --webdriver=4444')
->background()
->run();
$this->taskexec('phantomjs --webdriver=4444')->background()->run();
sleep(2);
$this->_exec('vendor/bin/codecept run');
}
@@ -82,15 +71,8 @@ class RoboFile extends \Robo\Tasks {
$dotenv = new Dotenv\Dotenv(__DIR__);
$dotenv->load();
$this
->taskWriteToFile('tests/acceptance.suite.yml')
->textFromFile('tests/acceptance.suite.src')
->run();
$this->taskWriteToFile('tests/acceptance.suite.yml')->textFromFile('tests/acceptance.suite.src')->run();
$this
->taskReplaceInFile('tests/acceptance.suite.yml')
->regex("/url.*/")
->to('url: ' . "'" . getenv('WP_TEST_URL'). "'")
->run();
$this->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": {
"php": ">=5.3.3",
"twig/twig": "1.*",
@@ -6,7 +12,8 @@
"cerdic/css-tidy": "*",
"sunra/php-simple-html-dom-parser": "*",
"tburry/pquery": "*",
"j4mie/paris": "1.5.4"
"j4mie/paris": "1.5.4 as 1.4",
"tag/sudzy" : "dev-master"
},
"require-dev": {
@@ -14,7 +21,8 @@
"codeception/verify": "*",
"codegyre/robo": "*",
"vlucas/phpdotenv": "*",
"umpirsky/twig-gettext-extractor": "1.1.*"
"umpirsky/twig-gettext-extractor": "1.1.*",
"raveren/kint": "^1.0"
},
"autoload": {
"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",
"This file is @generated automatically"
],
"hash": "4b157c8484b1247df06b05f728db16bc",
"hash": "99a6abaeb9ef73071b63a330b58242cc",
"packages": [
{
"name": "cerdic/css-tidy",
@@ -255,6 +255,55 @@
],
"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",
"version": "v1.1.0",
@@ -1386,6 +1435,57 @@
],
"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",
"version": "1.2.0",
@@ -2896,9 +2996,18 @@
"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",
"stability-flags": [],
"stability-flags": {
"tag/sudzy": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"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
namespace MailPoet\Models;
if (!defined('ABSPATH')) exit;
class Setting extends \Model {
public static $_table = MP_SETTINGS_TABLE;
if (!defined('ABSPATH')) {
exit;
}
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
namespace MailPoet\Models;
if (!defined('ABSPATH')) exit;
class Subscriber extends \Model {
public static $_table = MP_SUBSCRIBERS_TABLE;
if (!defined('ABSPATH')) {
exit;
}
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
use \MailPoet\Models\Setting;
use MailPoet\Models\Setting;
class SettingCest {
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->name = 'sending_method';
$setting->value = 'smtp';
$setting->name = $this->data['name'];
$setting->value = $this->data['value'];
$setting->save();
}
function itCanBeCreated() {
$setting = Setting::where('name', 'sending_method')->findOne();
$setting = Setting::where('name', $this->data['name'])->findOne();
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() {
$setting = Setting::where('name', 'sending_method')->findOne()->delete();
$setting = Setting::where('name', $this->data['name'])->findOne()->delete();
}
}

View File

@@ -1,24 +1,22 @@
<?php
use \MailPoet\Models\Subscriber;
use MailPoet\Models\Subscriber;
class SubscriberCest {
function _before() {
$this->data = array(
'first_name' => 'John',
'last_name' => 'Mailer',
'email' => 'john@mailpoet.com'
);
$this->data = array('first_name' => 'John', 'last_name' => 'Mailer', 'email' => 'john@mailpoet.com');
// clean up after previously failed test
$subscriber = Subscriber::where('email', $this->data['email'])->findOne();
if ($subscriber !== false) {
$subscriber->delete();
}
$this->subscriber = Subscriber::create();
$this
->subscriber
->first_name = $this->data['first_name'];
$this->subscriber->first_name = $this->data['first_name'];
$this
->subscriber
->last_name = $this->data['last_name'];
$this->subscriber->last_name = $this->data['last_name'];
$this->subscriber->email = $this->data['email'];
@@ -32,20 +30,17 @@ class SubscriberCest {
function itHasAFirstName() {
$subscriber = Subscriber::where('email', $this->data['email'])->findOne();
expect($subscriber->first_name)
->equals($this->data['first_name']);
expect($subscriber->first_name)->equals($this->data['first_name']);
}
function itHasALastName() {
$subscriber = Subscriber::where('email', $this->data['email'])->findOne();
expect($subscriber->last_name)
->equals($this->data['last_name']);
expect($subscriber->last_name)->equals($this->data['last_name']);
}
function itHasAnEmail() {
$subscriber = Subscriber::where('email', $this->data['email'])->findOne();
expect($subscriber->email)
->equals($this->data['email']);
expect($subscriber->email)->equals($this->data['email']);
}
function emailMustBeUnique() {
@@ -62,7 +57,39 @@ class SubscriberCest {
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() {
$subscriber = Subscriber::where('email', $this->data['email'])->findOne()->delete();
}
}