This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
lnkohana/system/tests/kohana/ValidationTest.php
2013-04-22 14:09:50 +10:00

677 lines
17 KiB
PHP

<?php defined('SYSPATH') OR die('Kohana bootstrap needs to be included before tests run');
/**
* Tests the Validation lib that's shipped with Kohana
*
* @group kohana
* @group kohana.core
* @group kohana.core.validation
*
* @package Kohana
* @category Tests
* @author Kohana Team
* @author BRMatt <matthew@sigswitch.com>
* @copyright (c) 2008-2012 Kohana Team
* @license http://kohanaframework.org/license
*/
class Kohana_ValidationTest extends Unittest_TestCase
{
/**
* Tests Validation::factory()
*
* Makes sure that the factory method returns an instance of Validation lib
* and that it uses the variables passed
*
* @test
*/
public function test_factory_method_returns_instance_with_values()
{
$values = array(
'this' => 'something else',
'writing tests' => 'sucks',
'why the hell' => 'amIDoingThis',
);
$instance = Validation::factory($values);
$this->assertTrue($instance instanceof Validation);
$this->assertSame(
$values,
$instance->data()
);
}
/**
* When we copy() a validation object, we should have a new validation object
* with the exact same attributes, apart from the data, which should be the
* same as the array we pass to copy()
*
* @test
* @covers Validation::copy
*/
public function test_copy_copies_all_attributes_except_data()
{
$validation = new Validation(array('foo' => 'bar', 'fud' => 'fear, uncertainty, doubt', 'num' => 9));
$validation->rule('num', 'is_int')->rule('foo', 'is_string');
$copy_data = array('foo' => 'no', 'fud' => 'maybe', 'num' => 42);
$copy = $validation->copy($copy_data);
$this->assertNotSame($validation, $copy);
foreach (array('_rules', '_bound', '_labels', '_empty_rules', '_errors') as $attribute)
{
// This is just an easy way to check that the attributes are identical
// Without hardcoding the expected values
$this->assertAttributeSame(
self::readAttribute($validation, $attribute),
$attribute,
$copy
);
}
$this->assertSame($copy_data, $copy->data());
}
/**
* When the validation object is initially created there should be no labels
* specified
*
* @test
*/
public function test_initially_there_are_no_labels()
{
$validation = new Validation(array());
$this->assertAttributeSame(array(), '_labels', $validation);
}
/**
* Adding a label to a field should set it in the labels array
* If the label already exists it should overwrite it
*
* In both cases thefunction should return a reference to $this
*
* @test
* @covers Validation::label
*/
public function test_label_adds_and_overwrites_label_and_returns_this()
{
$validation = new Validation(array());
$this->assertSame($validation, $validation->label('email', 'Email Address'));
$this->assertAttributeSame(array('email' => 'Email Address'), '_labels', $validation);
$this->assertSame($validation, $validation->label('email', 'Your Email'));
$validation->label('name', 'Your Name');
$this->assertAttributeSame(
array('email' => 'Your Email', 'name' => 'Your Name'),
'_labels',
$validation
);
}
/**
* Using labels() we should be able to add / overwrite multiple labels
*
* The function should also return $this for chaining purposes
*
* @test
* @covers Validation::labels
*/
public function test_labels_adds_and_overwrites_multiple_labels_and_returns_this()
{
$validation = new Validation(array());
$initial_data = array('kung fu' => 'fighting', 'fast' => 'cheetah');
$this->assertSame($validation, $validation->labels($initial_data));
$this->assertAttributeSame($initial_data, '_labels', $validation);
$this->assertSame($validation, $validation->labels(array('fast' => 'lightning')));
$this->assertAttributeSame(
array('fast' => 'lightning', 'kung fu' => 'fighting'),
'_labels',
$validation
);
}
/**
* Using bind() we should be able to add / overwrite multiple bound variables
*
* The function should also return $this for chaining purposes
*
* @test
* @covers Validation::bind
*/
public function test_bind_adds_and_overwrites_multiple_variables_and_returns_this()
{
$validation = new Validation(array());
$data = array('kung fu' => 'fighting', 'fast' => 'cheetah');
$bound = array(':foo' => 'some value');
// Test binding an array of values
$this->assertSame($validation, $validation->bind($bound));
$this->assertAttributeSame($bound, '_bound', $validation);
// Test binding one value
$this->assertSame($validation, $validation->bind(':foo', 'some other value'));
$this->assertAttributeSame(array(':foo' => 'some other value'), '_bound', $validation);
}
/**
* We should be able to used bound variables in callbacks
*
* @test
* @covers Validation::check
*/
public function test_bound_callback()
{
$data = array(
'kung fu' => 'fighting',
'fast' => 'cheetah',
);
$validation = new Validation($data);
$validation->bind(':class', 'Valid')
// Use the bound value in a callback
->rule('fast', array(':class', 'max_length'), array(':value', 2));
// The rule should have run and check() should fail
$this->assertSame($validation->check(), FALSE);
}
/**
* Provides test data for test_check
*
* @return array
*/
public function provider_check()
{
// $data_array, $rules, $labels, $first_expected, $expected_error
return array(
array(
array('foo' => 'bar'),
array('foo' => array(array('not_empty', NULL))),
array(),
TRUE,
array(),
),
array(
array('unit' => 'test'),
array(
'foo' => array(array('not_empty', NULL)),
'unit' => array(array('min_length', array(':value', 6))
),
),
array(),
FALSE,
array(
'foo' => 'foo must not be empty',
'unit' => 'unit must be at least 6 characters long'
),
),
array(
array('foo' => 'bar'),
array(
// Tests wildcard rules
TRUE => array(array('min_length', array(':value', 4))),
'foo' => array(
array('not_empty', NULL),
// Tests the array syntax for callbacks
array(array('Valid', 'exact_length'), array(':value', 3)),
// Tests the Class::method syntax for callbacks
array('Valid::exact_length', array(':value', 3)),
// Tests the lambda function syntax for callbacks
// Commented out for PHP 5.2 support
// array(function($value){return TRUE;}, array(':value')),
// Tests using a function as a rule
array('is_string', array(':value')),
),
// Tests that rules do not run on empty fields unless they are in _empty_rules
'unit' => array(array('exact_length', array(':value', 4))),
),
array(),
FALSE,
array('foo' => 'foo must be at least 4 characters long'),
),
// Switch things around and make :value an array
array(
array('foo' => array('test', 'data')),
array('foo' => array(array('in_array', array('kohana', ':value')))),
array(),
FALSE,
array('foo' => 'foo must be one of the available options'),
),
// Test wildcard rules with no other rules
array(
array('foo' => array('test')),
array(TRUE => array(array('is_string', array(':value')))),
array('foo' => 'foo'),
FALSE,
array('foo' => '1.foo.is_string'),
),
// Test array rules use method as error name
array(
array('foo' => 'test'),
array('foo' => array(array(array('Valid', 'min_length'), array(':value', 10)))),
array(),
FALSE,
array('foo' => 'foo must be at least 10 characters long'),
),
);
}
/**
* Tests Validation::check()
*
* @test
* @covers Validation::check
* @covers Validation::rule
* @covers Validation::rules
* @covers Validation::errors
* @covers Validation::error
* @dataProvider provider_check
* @param array $array The array of data
* @param array $rules The array of rules
* @param array $labels The array of labels
* @param boolean $expected Is it valid?
* @param boolean $expected_errors Array of expected errors
*/
public function test_check($array, $rules, $labels, $expected, $expected_errors)
{
$validation = new Validation($array);
foreach ($labels as $field => $label)
{
$validation->label($field, $label);
}
foreach ($rules as $field => $field_rules)
{
foreach ($field_rules as $rule)
$validation->rule($field, $rule[0], $rule[1]);
}
$status = $validation->check();
$errors = $validation->errors(TRUE);
$this->assertSame($expected, $status);
$this->assertSame($expected_errors, $errors);
$validation = new validation($array);
foreach ($rules as $field => $rules)
{
$validation->rules($field, $rules);
}
$validation->labels($labels);
$this->assertSame($expected, $validation->check());
}
/**
* Tests Validation::check()
*
* @test
* @covers Validation::check
*/
public function test_check_stops_when_error_added_by_callback()
{
$validation = new Validation(array(
'foo' => 'foo',
));
$validation
->rule('foo', array($this, '_validation_callback'), array(':validation'))
// This rule should never run
->rule('foo', 'min_length', array(':value', 20));
$validation->check();
$errors = $validation->errors();
$expected = array(
'foo' => array(
0 => '_validation_callback',
1 => NULL,
),
);
$this->assertSame($errors, $expected);
}
public function _validation_callback(Validation $object)
{
// Simply add the error
$object->error('foo', '_validation_callback');
}
/**
* Provides test data for test_errors()
*
* @return array
*/
public function provider_errors()
{
// [data, rules, expected], ...
return array(
// No Error
array(
array('username' => 'frank'),
array('username' => array(array('not_empty', NULL))),
array(),
),
// Error from message file
array(
array('username' => ''),
array('username' => array(array('not_empty', NULL))),
array('username' => 'username must not be empty'),
),
// No error message exists, display the path expected
array(
array('username' => 'John'),
array('username' => array(array('strpos', array(':value', 'Kohana')))),
array('username' => 'Validation.username.strpos'),
),
);
}
/**
* Tests Validation::errors()
*
* @test
* @covers Validation::errors
* @dataProvider provider_errors
* @param array $array The array of data
* @param array $rules The array of rules
* @param array $expected Array of expected errors
*/
public function test_errors($array, $rules, $expected)
{
$validation = Validation::factory($array);
foreach ($rules as $field => $field_rules)
{
$validation->rules($field, $field_rules);
}
$validation->check();
$this->assertSame($expected, $validation->errors('Validation', FALSE));
// Should be able to get raw errors array
$this->assertAttributeSame($validation->errors(NULL), '_errors', $validation);
}
/**
* Provides test data for test_translated_errors()
*
* @return array
*/
public function provider_translated_errors()
{
// [data, rules, expected], ...
return array(
array(
array('Spanish' => ''),
array('Spanish' => array(array('not_empty', NULL))),
// Errors are not translated yet so only the label will translate
array('Spanish' => 'Español must not be empty'),
array('Spanish' => 'Spanish must not be empty'),
),
);
}
/**
* Tests Validation::errors()
*
* @test
* @covers Validation::errors
* @dataProvider provider_translated_errors
* @param array $data The array of data to test
* @param array $rules The array of rules to add
* @param array $translated_expected The array of expected errors when translated
* @param array $untranslated_expected The array of expected errors when not translated
*/
public function test_translated_errors($data, $rules, $translated_expected, $untranslated_expected)
{
$validation = Validation::factory($data);
$current = i18n::lang();
i18n::lang('es');
foreach ($rules as $field => $field_rules)
{
$validation->rules($field, $field_rules);
}
$validation->check();
$result_1 = $validation->errors('Validation', TRUE);
$result_2 = $validation->errors('Validation', 'en');
$result_3 = $validation->errors('Validation', FALSE);
// Restore the current language
i18n::lang($current);
$this->assertSame($translated_expected, $result_1);
$this->assertSame($translated_expected, $result_2);
$this->assertSame($untranslated_expected, $result_3);
}
/**
* Tests Validation::errors()
*
* @test
* @covers Validation::errors
*/
public function test_parameter_labels()
{
$validation = Validation::factory(array('foo' => 'bar'))
->rule('foo', 'equals', array(':value', 'something'))
->label('something', 'Spanish');
$current = i18n::lang();
i18n::lang('es');
$validation->check();
$translated_expected = array('foo' => 'foo must equal Español');
$untranslated_expected = array('foo' => 'foo must equal Spanish');
$result_1 = $validation->errors('Validation', TRUE);
$result_2 = $validation->errors('Validation', 'en');
$result_3 = $validation->errors('Validation', FALSE);
// Restore the current language
i18n::lang($current);
$this->assertSame($translated_expected, $result_1);
$this->assertSame($translated_expected, $result_2);
$this->assertSame($untranslated_expected, $result_3);
}
/**
* Tests Validation::errors()
*
* @test
* @covers Validation::errors
*/
public function test_arrays_in_parameters()
{
$validation = Validation::factory(array('foo' => 'bar'))
->rule('foo', 'equals', array(':value', array('one', 'two')));
$validation->check();
$expected = array('foo' => 'foo must equal one, two');
$this->assertSame($expected, $validation->errors('Validation', FALSE));
}
/**
* Tests Validation::check()
*
* @test
* @covers Validation::check
*/
public function test_data_stays_unaltered()
{
$validation = Validation::factory(array('foo' => 'bar'))
->rule('something', 'not_empty');
$before = $validation->data();
$validation->check();
$after = $validation->data();
$expected = array('foo' => 'bar');
$this->assertSame($expected, $before);
$this->assertSame($expected, $after);
}
/**
* Tests Validation::errors()
*
* @test
* @covers Validation::errors
*/
public function test_object_parameters_not_in_messages()
{
$validation = Validation::factory(array('foo' => 'foo'))
->rule('bar', 'matches', array(':validation', ':field', 'foo'));
$validation->check();
$errors = $validation->errors('validation');
$expected = array('bar' => 'bar must be the same as foo');
$this->assertSame($expected, $errors);
}
/**
* Tests Validation::as_array()
*
* @test
* @covers Validation::as_array
*/
public function test_as_array_returns_original_array()
{
$data = array(
'one' => 'hello',
'two' => 'world',
'ten' => '',
);
$validation = Validation::factory($data);
$this->assertSame($data, $validation->as_array());
}
/**
* Tests Validation::data()
*
* @test
* @covers Validation::data
*/
public function test_data_returns_original_array()
{
$data = array(
'one' => 'hello',
'two' => 'world',
'ten' => '',
);
$validation = Validation::factory($data);
$this->assertSame($data, $validation->data());
}
// @codingStandardsIgnoreStart
public function test_offsetExists()
// @codingStandardsIgnoreEnd
{
$array = array(
'one' => 'Hello',
'two' => 'World',
'ten' => NULL,
);
$validation = Validation::factory($array);
$this->assertTrue(isset($validation['one']));
$this->assertFalse(isset($validation['ten']));
$this->assertFalse(isset($validation['five']));
}
// @codingStandardsIgnoreStart
public function test_offsetSet_throws_exception()
// @codingStandardsIgnoreEnd
{
$this->setExpectedException('Kohana_Exception');
$validation = Validation::factory(array());
// Validation is read-only
$validation['field'] = 'something';
}
// @codingStandardsIgnoreStart
public function test_offsetGet()
// @codingStandardsIgnoreEnd
{
$array = array(
'one' => 'Hello',
'two' => 'World',
'ten' => NULL,
);
$validation = Validation::factory($array);
$this->assertSame($array['one'], $validation['one']);
$this->assertSame($array['two'], $validation['two']);
$this->assertSame($array['ten'], $validation['ten']);
}
// @codingStandardsIgnoreStart
public function test_offsetUnset()
// @codingStandardsIgnoreEnd
{
$this->setExpectedException('Kohana_Exception');
$validation = Validation::factory(array(
'one' => 'Hello, World!',
));
// Validation is read-only
unset($validation['one']);
}
/**
* http://dev.kohanaframework.org/issues/4365
*
* @test
* @covers Validation::errors
*/
public function test_error_type_check()
{
$array = array(
'email' => 'not an email address',
);
$validation = Validation::factory($array)
->rule('email', 'not_empty')
->rule('email', 'email')
;
$validation->check();
$errors = $validation->errors('tests/validation/error_type_check');
$this->assertSame($errors, $validation->errors('validation'));
}
}