diff --git a/src/Fields/BaseField.php b/src/Fields/BaseField.php index 3be621e..d306033 100644 --- a/src/Fields/BaseField.php +++ b/src/Fields/BaseField.php @@ -292,30 +292,27 @@ protected function checkMaximumConstraint($val, $maxConstraint) return $val <= $maxConstraint; } - protected function checkMinLengthConstraint($val, $minLength) + protected function getLengthForConstraint($val) { if (is_string($val)) { - return strlen($val) >= $minLength; + return strlen($val); } elseif (is_array($val)) { - return count($val) >= $minLength; + return count($val); } elseif (is_object($val)) { - return count($val) >= $minLength; + return count((array)$val); } else { - throw $this->getValidationException('invalid value for minLength constraint', $val); + throw $this->getValidationException('invalid value for length constraint', $val); } } + protected function checkMinLengthConstraint($val, $minLength) + { + return $this->getLengthForConstraint($val) >= $minLength; + } + protected function checkMaxLengthConstraint($val, $maxLength) { - if (is_string($val)) { - return strlen($val) <= $maxLength; - } elseif (is_array($val)) { - return count($val) <= $maxLength; - } elseif (is_object($val)) { - return count($val) <= $maxLength; - } else { - throw $this->getValidationException('invalid value for maxLength constraint', $val); - } + return $this->getLengthForConstraint($val) <= $maxLength; } protected function getAllowedValues() diff --git a/tests/FieldTypesTest.php b/tests/FieldTypesTest.php index c163c70..fe342c4 100644 --- a/tests/FieldTypesTest.php +++ b/tests/FieldTypesTest.php @@ -19,23 +19,23 @@ public function testAny() ['default', '3.14', '3.14'], ['default', true, true], ['default', '', ''], - [(object) ['format' => 'default', 'constraints' => (object) ['required' => true]], + [['format' => 'default', 'constraints' => ['required' => true]], null, null, ], // any field has no empty value, so required without enum is meaningless - [(object) [ + [[ 'format' => 'default', - 'constraints' => (object) ['required' => true, 'enum' => ['test', 1, false]], + 'constraints' => ['required' => true, 'enum' => ['test', 1, false]], ], null, self::ERROR], - [(object) [ + [[ 'format' => 'default', - 'constraints' => (object) ['required' => true, 'enum' => ['test', 1, false]], + 'constraints' => ['required' => true, 'enum' => ['test', 1, false]], ], 'FOO', self::ERROR], - [(object) [ + [[ 'format' => 'default', - 'constraints' => (object) ['required' => true, 'enum' => ['test', 1, false]], + 'constraints' => ['required' => true, 'enum' => ['test', 1, false]], ], false, false], - [(object) [ + [[ 'format' => 'default', - 'constraints' => (object) ['required' => true, 'enum' => ['test', 1, null, false]], + 'constraints' => ['required' => true, 'enum' => ['test', 1, null, false]], ], null, null], ]); } @@ -47,42 +47,42 @@ public function testArray() ['default', '[]', []], ['default', ['key', 'value'], ['key', 'value']], ['default', '["key", "value"]', ['key', 'value']], - ['default', (object) ['key' => 'value'], self::ERROR], + ['default', (object)['key' => 'value'], self::ERROR], ['default', '{"key": "value"}', self::ERROR], ['default', 'string', self::ERROR], ['default', 1, self::ERROR], ['default', '3.14', self::ERROR], ['default', '', self::ERROR], // missingValues is handled at the schema level // required - [(object) ['format' => 'default', 'constraints' => (object) ['required' => true]], + [['format' => 'default', 'constraints' => ['required' => true]], null, self::ERROR, ], - [(object) ['format' => 'default', 'constraints' => (object) ['required' => true]], + [['format' => 'default', 'constraints' => ['required' => true]], [], [], ], // enum - [(object) [ - 'format' => 'default', 'constraints' => (object) ['enum' => [[1, 2], ['foo', 'bar']]], + [[ + 'format' => 'default', 'constraints' => ['enum' => [[1, 2], ['foo', 'bar']]], ], [], self::ERROR], - [(object) [ - 'format' => 'default', 'constraints' => (object) [ + [[ + 'format' => 'default', 'constraints' => [ 'required' => true, 'enum' => [[1, 2], ['foo', 'bar']], ], ], '[1,2]', [1, 2]], - [(object) [ - 'format' => 'default', 'constraints' => (object) ['enum' => [[1, 2], ['foo', 'bar']]], + [[ + 'format' => 'default', 'constraints' => ['enum' => [[1, 2], ['foo', 'bar']]], ], [1, 2], [1, 2]], // minLength / maxLength - [(object) ['format' => 'default', 'constraints' => (object) ['minLength' => 1]], [], self::ERROR], - [(object) ['format' => 'default', 'constraints' => (object) ['minLength' => 1]], [1], [1]], - [(object) ['format' => 'default', 'constraints' => (object) ['minLength' => 1]], [1, 2], [1, 2]], - [(object) ['format' => 'default', 'constraints' => (object) ['minLength' => 1]], 'invalid', self::ERROR], - [(object) ['format' => 'default', 'constraints' => (object) ['maxLength' => 1]], [], []], - [(object) ['format' => 'default', 'constraints' => (object) ['maxLength' => 1]], [1], [1]], - [(object) ['format' => 'default', 'constraints' => (object) ['maxLength' => 1]], [1, 2], self::ERROR], - [(object) ['format' => 'default', 'constraints' => (object) ['minLength' => 1, 'maxLength' => 1]], + [['format' => 'default', 'constraints' => ['minLength' => 1]], [], self::ERROR], + [['format' => 'default', 'constraints' => ['minLength' => 1]], [1], [1]], + [['format' => 'default', 'constraints' => ['minLength' => 1]], [1, 2], [1, 2]], + [['format' => 'default', 'constraints' => ['minLength' => 1]], 'invalid', self::ERROR], + [['format' => 'default', 'constraints' => ['maxLength' => 1]], [], []], + [['format' => 'default', 'constraints' => ['maxLength' => 1]], [1], [1]], + [['format' => 'default', 'constraints' => ['maxLength' => 1]], [1, 2], self::ERROR], + [['format' => 'default', 'constraints' => ['minLength' => 1, 'maxLength' => 1]], [1, 2], self::ERROR, ], - [(object) ['format' => 'default', 'constraints' => (object) ['minLength' => 1, 'maxLength' => 1]], + [['format' => 'default', 'constraints' => ['minLength' => 1, 'maxLength' => 1]], [1], [1], ], - [(object) ['format' => 'default', 'constraints' => (object) ['minLength' => 1, 'maxLength' => 1]], + [['format' => 'default', 'constraints' => ['minLength' => 1, 'maxLength' => 1]], [], self::ERROR, ], ]); } @@ -91,7 +91,7 @@ public function testBoolean() { $this->assertFieldTestData('boolean', [ ['default', true, true], - [(object) ['format' => 'default', 'trueValues' => ['yes']], 'yes', true], + [['format' => 'default', 'trueValues' => ['yes']], 'yes', true], ['default', 'y', self::ERROR], ['default', 'true', true], ['default', 't', self::ERROR], @@ -102,7 +102,7 @@ public function testBoolean() ['default', 'no', self::ERROR], ['default', 'n', self::ERROR], ['default', 'false', false], - [(object) ['format' => 'default', 'falseValues' => ['f']], 'f', false], + [['format' => 'default', 'falseValues' => ['f']], 'f', false], ['default', '0', false], ['default', 'NO', self::ERROR], ['default', 'No', self::ERROR], @@ -111,13 +111,13 @@ public function testBoolean() ['default', '3.14', self::ERROR], ['default', '', self::ERROR], // missingValues is handled at the schema level, // required - [(object) ['format' => 'default', 'constraints' => (object) ['required' => true]], null, self::ERROR], + [['format' => 'default', 'constraints' => ['required' => true]], null, self::ERROR], // enum - [(object) [ - 'format' => 'default', 'constraints' => (object) ['enum' => [false]], + [[ + 'format' => 'default', 'constraints' => ['enum' => [false]], ], true, self::ERROR], - [(object) [ - 'format' => 'default', 'constraints' => (object) ['enum' => [false]], + [[ + 'format' => 'default', 'constraints' => ['enum' => [false]], ], false, false], ]); } @@ -142,14 +142,19 @@ public function testDate() ['%d/%m/%y', '', self::ERROR], // missingValues is handled at the schema level, ['invalid', '21/11/06 16:30', self::ERROR], // required - [(object) ['format' => 'default', 'constraints' => (object) ['required' => true]], null, self::ERROR], + [['format' => 'default', 'constraints' => ['required' => true]], null, self::ERROR], // enum - [(object) [ - 'format' => 'default', 'constraints' => (object) ['enum' => ['2019-01-01']], + [[ + 'format' => 'default', 'constraints' => ['enum' => ['2019-01-01']], ], '2019-01-01', Carbon::create(2019, 1, 1, 0, 0, 0)], - [(object) [ - 'format' => 'default', 'constraints' => (object) ['enum' => ['2019-01-01']], + [[ + 'format' => 'default', 'constraints' => ['enum' => ['2019-01-01']], ], '2019-01-02', self::ERROR], + // minimum / maximum + [['format' => 'default', 'constraints' => ['minimum' => '2019-01-01']], '2018-12-28', self::ERROR], + [['format' => 'default', 'constraints' => ['maximum' => '2019-01-01']], '2019-01-02', self::ERROR], + [['format' => 'default', 'constraints' => ['minimum' => '2019-01-01', 'maximum' => '2019-01-01']], '2019-01-01', Carbon::create(2019, 1, 1, 0, 0, 0)], + [['format' => 'default', 'constraints' => ['minimum' => '2019-01-01', 'maximum' => '2019-01-04']], '2019-01-01', Carbon::create(2019, 1, 1, 0, 0, 0)], ]); } @@ -173,14 +178,19 @@ public function testDatetime() ['%d/%m/%y %H:%M', '', self::ERROR], // missingValues is handled at the schema level, ['invalid', '21/11/06 16:30', self::ERROR], // required - [(object) ['format' => 'default', 'constraints' => (object) ['required' => true]], null, self::ERROR], + [['format' => 'default', 'constraints' => ['required' => true]], null, self::ERROR], // enum - [(object) [ - 'format' => 'default', 'constraints' => (object) ['enum' => ['2014-01-01T06:00:00Z']], + [[ + 'format' => 'default', 'constraints' => ['enum' => ['2014-01-01T06:00:00Z']], ], '2014-01-01T06:00:00Z', Carbon::create(2014, 1, 1, 6, 0, 0, 'UTC')], - [(object) [ - 'format' => 'default', 'constraints' => (object) ['enum' => ['2014-01-01T06:00:00Z']], + [[ + 'format' => 'default', 'constraints' => ['enum' => ['2014-01-01T06:00:00Z']], ], '2014-01-01T06:01:00Z', self::ERROR], + // minimum / maximum + [['format' => 'default', 'constraints' => ['minimum' => '2014-01-01T06:35:21Z']], '2014-01-01T06:35:20Z', self::ERROR], + [['format' => 'default', 'constraints' => ['maximum' => '2014-01-01T06:35:21Z']], '2014-01-01T06:35:22Z', self::ERROR], + [['format' => 'default', 'constraints' => ['minimum' => '2014-01-01T06:35:21Z', 'maximum' => '2014-01-01T06:35:21Z']], '2014-01-01T06:35:21Z', Carbon::create(2014, 1, 1, 6, 35, 21, 'UTC')], + [['format' => 'default', 'constraints' => ['minimum' => '2014-01-01T06:35:21Z', 'maximum' => '2014-01-01T06:35:22Z']], '2014-01-01T06:35:21Z', Carbon::create(2014, 1, 1, 6, 35, 21, 'UTC')], ]); } @@ -198,15 +208,15 @@ public function testDuration() ['default', 1, self::ERROR], ['default', '', self::ERROR], // missingValues is handled at the schema level, ['default', [], self::ERROR], - ['default', (object) [], self::ERROR], + ['default', [], self::ERROR], // required - [(object) ['format' => 'default', 'constraints' => (object) ['required' => true]], null, self::ERROR], + [['format' => 'default', 'constraints' => ['required' => true]], null, self::ERROR], // enum - [(object) [ - 'format' => 'default', 'constraints' => (object) ['enum' => ['P1Y10M3DT5H11M7S']], + [[ + 'format' => 'default', 'constraints' => ['enum' => ['P1Y10M3DT5H11M7S']], ], 'P1Y10M3DT5H11M7S', new CarbonInterval(1, 10, 0, 3, 5, 11, 7)], - [(object) [ - 'format' => 'default', 'constraints' => (object) ['enum' => ['P1Y10M3DT5H11M7S']], + [[ + 'format' => 'default', 'constraints' => ['enum' => ['P1Y10M3DT5H11M7S']], ], 'P1Y10M3DT5H11M8S', self::ERROR], ]); } @@ -216,47 +226,47 @@ public function testGeojson() $this->assertFieldTestData('geojson', [ [ 'default', - (object) ['properties' => (object) ['Ã' => 'Ã'], 'type' => 'Feature', 'geometry' => null], - (object) ['properties' => (object) ['Ã' => 'Ã'], 'type' => 'Feature', 'geometry' => null], + ['properties' => ['Ã' => 'Ã'], 'type' => 'Feature', 'geometry' => null], + ['properties' => ['Ã' => 'Ã'], 'type' => 'Feature', 'geometry' => null], ], [ 'default', '{"geometry": null, "type": "Feature", "properties": {"\\u00c3": "\\u00c3"}}', - (object) ['properties' => (object) ['Ã' => 'Ã'], 'type' => 'Feature', 'geometry' => null], + ['properties' => ['Ã' => 'Ã'], 'type' => 'Feature', 'geometry' => null], ], [ 'default', - (object) ['coordinates' => [0, 0, 0], 'type' => 'Point'], - (object) ['coordinates' => [0, 0, 0], 'type' => 'Point'], + ['coordinates' => [0, 0, 0], 'type' => 'Point'], + ['coordinates' => [0, 0, 0], 'type' => 'Point'], ], ['default', 'string', self::ERROR], ['default', 1, self::ERROR], ['default', '3.14', self::ERROR], ['default', '', self::ERROR], // missingValues is handled at the schema level, - ['default', (object) [], self::ERROR], + ['default', [], self::ERROR], ['default', '{}', self::ERROR], [ 'topojson', - (object) ['type' => 'LineString', 'arcs' => [42]], - (object) ['type' => 'LineString', 'arcs' => [42]], + ['type' => 'LineString', 'arcs' => [42]], + ['type' => 'LineString', 'arcs' => [42]], ], [ 'topojson', '{"type": "LineString", "arcs": [42]}', - (object) ['type' => 'LineString', 'arcs' => [42]], + ['type' => 'LineString', 'arcs' => [42]], ], ['topojson', 'string', self::ERROR], ['topojson', 1, self::ERROR], ['topojson', '3.14', self::ERROR], ['topojson', '', self::ERROR], // required - [(object) ['format' => 'default', 'constraints' => (object) ['required' => true]], null, self::ERROR], + [['format' => 'default', 'constraints' => ['required' => true]], null, self::ERROR], // enum - [(object) [ - 'format' => 'default', 'constraints' => (object) ['enum' => ['{"geometry": null, "type": "Feature", "properties": {"\\u00c3": "\\u00c3"}}']], - ], '{"geometry": null, "type": "Feature", "properties": {"\\u00c3": "\\u00c3"}}', (object) ['properties' => (object) ['Ã' => 'Ã'], 'type' => 'Feature', 'geometry' => null]], - [(object) [ - 'format' => 'default', 'constraints' => (object) ['enum' => ['{"geometry": null, "type": "Feature", "properties": {"\\u00c3": "\\u00c3"}}']], + [[ + 'format' => 'default', 'constraints' => ['enum' => ['{"geometry": null, "type": "Feature", "properties": {"\\u00c3": "\\u00c3"}}']], + ], '{"geometry": null, "type": "Feature", "properties": {"\\u00c3": "\\u00c3"}}', ['properties' => ['Ã' => 'Ã'], 'type' => 'Feature', 'geometry' => null]], + [[ + 'format' => 'default', 'constraints' => ['enum' => ['{"geometry": null, "type": "Feature", "properties": {"\\u00c3": "\\u00c3"}}']], ], '{"geometry": null, "type": "Feature", "properties": {"\\u00c3": "\\u00c4"}}', self::ERROR], ]); } @@ -268,7 +278,7 @@ public function testGeopoint() ['default', [180, 90], self::ERROR], ['default', '180,90', [180, 90]], ['default', '180, -90', [180, -90]], - ['default', (object) ['lon' => 180, 'lat' => 90], self::ERROR], + ['default', ['lon' => 180, 'lat' => 90], self::ERROR], ['default', '181,90', self::ERROR], ['default', '0,91', self::ERROR], ['default', 'string', self::ERROR], @@ -278,7 +288,7 @@ public function testGeopoint() ['array', [180, 90], [180, 90]], ['array', [180, 90], [180, 90]], ['array', '[180, -90]', [180, -90]], - ['array', (object) ['lon' => 180, 'lat' => 90], self::ERROR], + ['array', ['lon' => 180, 'lat' => 90], self::ERROR], ['array', [181, 90], self::ERROR], ['array', [0, 91], self::ERROR], ['array', '180,90', self::ERROR], @@ -286,12 +296,12 @@ public function testGeopoint() ['array', 1, self::ERROR], ['array', '3.14', self::ERROR], ['array', '', self::ERROR], // missingValues is handled at the schema level, - ['object', (object) ['lon' => 180, 'lat' => 90], [180, 90]], + ['object', ['lon' => 180, 'lat' => 90], [180, 90]], ['object', '{"lon":180, "lat":90}', [180, 90]], ['object', '{"lat":90, "lon":180, "foo": "bar"}', [180, 90]], ['object', '[180, -90]', self::ERROR], - ['object', (object) ['lon' => 181, 'lat' => 90], self::ERROR], - ['object', (object) ['lon' => 180, 'lat' => -91], self::ERROR], + ['object', ['lon' => 181, 'lat' => 90], self::ERROR], + ['object', ['lon' => 180, 'lat' => -91], self::ERROR], ['object', [180, -90], self::ERROR], ['object', '180,90', self::ERROR], ['object', 'string', self::ERROR], @@ -299,10 +309,10 @@ public function testGeopoint() ['object', '3.14', self::ERROR], ['object', '', self::ERROR], // missingValues is handled at the schema level, // required - [(object) ['format' => 'default', 'constraints' => (object) ['required' => true]], null, self::ERROR], + [['format' => 'default', 'constraints' => ['required' => true]], null, self::ERROR], // enum - [(object) ['format' => 'array', 'constraints' => (object) ['enum' => ['[180, -90]']]], '[180, -90]', [180, -90]], - [(object) ['format' => 'array', 'constraints' => (object) ['enum' => ['[180, -90]']]], '[171, -90]', self::ERROR], + [['format' => 'array', 'constraints' => ['enum' => ['[180, -90]']]], '[180, -90]', [180, -90]], + [['format' => 'array', 'constraints' => ['enum' => ['[180, -90]']]], '[171, -90]', self::ERROR], ]); } @@ -314,74 +324,97 @@ public function testInteger() ['default', '3.14', self::ERROR], ['default', '', self::ERROR], // missingValues is handled at the schema level, // required - [(object) ['format' => 'default', 'constraints' => (object) ['required' => true]], null, self::ERROR], + [['format' => 'default', 'constraints' => ['required' => true]], null, self::ERROR], // enum - [(object) ['format' => 'default', 'constraints' => (object) ['enum' => [0, '1']]], '0', 0], - [(object) ['format' => 'default', 'constraints' => (object) ['enum' => [0, '1']]], '2', self::ERROR], + [['format' => 'default', 'constraints' => ['enum' => [0, '1']]], '0', 0], + [['format' => 'default', 'constraints' => ['enum' => [0, '1']]], '2', self::ERROR], + // minimum / maximum + [['format' => 'default', 'constraints' => ['minimum' => 2]], 1, self::ERROR], + [['format' => 'default', 'constraints' => ['maximum' => '0']], 1, self::ERROR], + [['format' => 'default', 'constraints' => ['maximum' => "1", 'minimum' => 1]], "1", 1], ]); } public function testNumber() { $this->assertFieldTestData('number', [ - [(object) ['format' => 'default'], 1, 1.0], - [(object) ['format' => 'default'], 1, 1.0], - [(object) ['format' => 'default'], 1.0, 1.0], - [(object) ['format' => 'default'], '1', 1.0], - [(object) ['format' => 'default'], '10.00', 10.0], - [(object) ['format' => 'default'], '10.50', 10.5], - [(object) ['format' => 'default'], '100%', 1.0], - [(object) ['format' => 'default'], '1000‰', self::ERROR], // spec only supports percent sign - [(object) ['format' => 'default'], '-1000', -1000.0], - [(object) ['format' => 'default', 'groupChar' => ','], '1,000', 1000.0], - [(object) ['format' => 'default', 'groupChar' => ','], '10,000.00', 10000.0], - [(object) ['format' => 'default', 'groupChar' => ','], '10,000,000.50', 10000000.5], - [(object) ['format' => 'default', 'groupChar' => '#'], '10#000.00', 10000.0], - [(object) ['format' => 'default', 'groupChar' => '#'], '10#000#000.50', 10000000.5], - [(object) ['format' => 'default', 'groupChar' => '#'], '10.50', 10.5], - [(object) ['format' => 'default', 'groupChar' => '#'], '1#000', 1000.0], - [(object) ['format' => 'default', 'groupChar' => '#', 'decimalChar' => '@'], '10#000@00', 10000.0], - [(object) ['format' => 'default', 'groupChar' => '#', 'decimalChar' => '@'], '10#000#000@50', 10000000.5], - [(object) ['format' => 'default', 'groupChar' => '#', 'decimalChar' => '@'], '10@50', 10.5], - [(object) ['format' => 'default', 'groupChar' => '#', 'decimalChar' => '@'], '1#000', 1000.0], - [(object) ['format' => 'default', 'groupChar' => ',', 'currency' => true], '10,000.00', 10000.0], - [(object) ['format' => 'default', 'groupChar' => ',', 'currency' => true], '10,000,000.00', 10000000.0], - [(object) ['format' => 'default', 'currency' => true], '$10000.00', 10000.0], - [(object) ['format' => 'default', 'groupChar' => ',', 'currency' => true], ' 10,000.00 €', 10000.0], - [(object) ['format' => 'default', 'groupChar' => ' ', 'decimalChar' => ','], '10 000,00', 10000.0], - [(object) ['format' => 'default', 'groupChar' => ' ', 'decimalChar' => ','], '10 000 000,00', 10000000.0], - [(object) ['format' => 'default', 'groupChar' => ' ', 'decimalChar' => ',', 'currency' => true], '10000,00 ₪', 10000.0], - [(object) ['format' => 'default', 'groupChar' => ' ', 'decimalChar' => ',', 'currency' => true], ' 10 000,00 £', 10000.0], - [(object) ['format' => 'default'], '10,000a.00', self::ERROR], - [(object) ['format' => 'default'], '10+000.00', self::ERROR], - [(object) ['format' => 'default'], '$10:000.00', self::ERROR], - [(object) ['format' => 'default'], 'string', self::ERROR], - [(object) ['format' => 'default'], '', self::ERROR], // missingValues is handled at the schema level, + [['format' => 'default'], 1, 1.0], + [['format' => 'default'], 1, 1.0], + [['format' => 'default'], 1.0, 1.0], + [['format' => 'default'], '1', 1.0], + [['format' => 'default'], '10.00', 10.0], + [['format' => 'default'], '10.50', 10.5], + [['format' => 'default'], '100%', 1.0], + [['format' => 'default'], '1000‰', self::ERROR], // spec only supports percent sign + [['format' => 'default'], '-1000', -1000.0], + [['format' => 'default', 'groupChar' => ','], '1,000', 1000.0], + [['format' => 'default', 'groupChar' => ','], '10,000.00', 10000.0], + [['format' => 'default', 'groupChar' => ','], '10,000,000.50', 10000000.5], + [['format' => 'default', 'groupChar' => '#'], '10#000.00', 10000.0], + [['format' => 'default', 'groupChar' => '#'], '10#000#000.50', 10000000.5], + [['format' => 'default', 'groupChar' => '#'], '10.50', 10.5], + [['format' => 'default', 'groupChar' => '#'], '1#000', 1000.0], + [['format' => 'default', 'groupChar' => '#', 'decimalChar' => '@'], '10#000@00', 10000.0], + [['format' => 'default', 'groupChar' => '#', 'decimalChar' => '@'], '10#000#000@50', 10000000.5], + [['format' => 'default', 'groupChar' => '#', 'decimalChar' => '@'], '10@50', 10.5], + [['format' => 'default', 'groupChar' => '#', 'decimalChar' => '@'], '1#000', 1000.0], + [['format' => 'default', 'groupChar' => ',', 'currency' => true], '10,000.00', 10000.0], + [['format' => 'default', 'groupChar' => ',', 'currency' => true], '10,000,000.00', 10000000.0], + [['format' => 'default', 'currency' => true], '$10000.00', 10000.0], + [['format' => 'default', 'groupChar' => ',', 'currency' => true], ' 10,000.00 €', 10000.0], + [['format' => 'default', 'groupChar' => ' ', 'decimalChar' => ','], '10 000,00', 10000.0], + [['format' => 'default', 'groupChar' => ' ', 'decimalChar' => ','], '10 000 000,00', 10000000.0], + [['format' => 'default', 'groupChar' => ' ', 'decimalChar' => ',', 'currency' => true], '10000,00 ₪', 10000.0], + [['format' => 'default', 'groupChar' => ' ', 'decimalChar' => ',', 'currency' => true], ' 10 000,00 £', 10000.0], + [['format' => 'default'], '10,000a.00', self::ERROR], + [['format' => 'default'], '10+000.00', self::ERROR], + [['format' => 'default'], '$10:000.00', self::ERROR], + [['format' => 'default'], 'string', self::ERROR], + [['format' => 'default'], '', self::ERROR], // missingValues is handled at the schema level, // required - [(object) ['format' => 'default', 'constraints' => (object) ['required' => true]], null, self::ERROR], + [['format' => 'default', 'constraints' => ['required' => true]], null, self::ERROR], // enum - [(object) ['format' => 'default', 'constraints' => (object) ['enum' => [0.5, '1.6']]], '1.6', 1.6], - [(object) ['format' => 'default', 'constraints' => (object) ['enum' => [0.5, '1.6']]], '0.55', self::ERROR], + [['format' => 'default', 'constraints' => ['enum' => [0.5, '1.6']]], '1.6', 1.6], + [['format' => 'default', 'constraints' => ['enum' => [0.5, '1.6']]], '0.55', self::ERROR], + // minimum / maximum + [['format' => 'default', 'constraints' => ['minimum' => 2]], 1.4, self::ERROR], + [['format' => 'default', 'constraints' => ['maximum' => '0']], 1.2, self::ERROR], + [['format' => 'default', 'constraints' => ['minimum' => 1.1, 'maximum' => "1.1"]], "1.1", 1.1], + [['format' => 'default', 'constraints' => ['minimum' => 1.2, 'maximum' => "1.4"]], "1.2", 1.2], ]); } public function testObject() { $this->assertFieldTestData('object', [ - ['default', (object) [], (object) []], - ['default', '{}', (object) []], - ['default', (object) ['key' => 'value'], (object) ['key' => 'value']], - ['default', '{"key": "value"}', (object) ['key' => 'value']], + ['default', [], []], + ['default', '{}', []], + ['default', ['key' => 'value'], ['key' => 'value']], + ['default', '{"key": "value"}', ['key' => 'value']], ['default', '["key", "value"]', self::ERROR], ['default', 'string', self::ERROR], ['default', 1, self::ERROR], ['default', '3.14', self::ERROR], ['default', '', self::ERROR], // missingValues is handled at the schema level, // required - [(object) ['format' => 'default', 'constraints' => (object) ['required' => true]], null, self::ERROR], + [['format' => 'default', 'constraints' => ['required' => true]], null, self::ERROR], // enum - [(object) ['format' => 'default', 'constraints' => (object) ['enum' => ['{"foo":"bar"}']]], '{"foo":"bar"}', (object) ['foo' => 'bar']], - [(object) ['format' => 'default', 'constraints' => (object) ['enum' => ['{"foo":"bar"}']]], '{"foox":"bar"}', self::ERROR], + [['format' => 'default', 'constraints' => ['enum' => ['{"foo":"bar"}']]], '{"foo":"bar"}', ['foo' => 'bar']], + [['format' => 'default', 'constraints' => ['enum' => ['{"foo":"bar"}']]], '{"foox":"bar"}', self::ERROR], + // minLength / maxLength + [['format' => 'default', 'constraints' => ['minLength' => 1]], '{}', self::ERROR], + [['format' => 'default', 'constraints' => ['minLength' => 1]], '{"a":1}', (object)["a"=>1]], + [['format' => 'default', 'constraints' => ['minLength' => 1]], '{"a":1, "b":2}', (object)["a"=>1,"b"=>2]], + [['format' => 'default', 'constraints' => ['minLength' => 1]], 'invalid', self::ERROR], + [['format' => 'default', 'constraints' => ['maxLength' => 1]], '{}', (object)[]], + [['format' => 'default', 'constraints' => ['maxLength' => 1]], '{"a":1}', (object)["a"=>1]], + [['format' => 'default', 'constraints' => ['maxLength' => 1]], '{"a":1, "b":2}', self::ERROR], + [['format' => 'default', 'constraints' => ['minLength' => 1, 'maxLength' => 1]], + '{"a":1, "b":2}', self::ERROR, ], + [['format' => 'default', 'constraints' => ['minLength' => 1, 'maxLength' => 1]], + '{"a":1}', (object)["a"=>1], ], + [['format' => 'default', 'constraints' => ['minLength' => 1, 'maxLength' => 1]], + '{}', self::ERROR, ], ]); } @@ -404,11 +437,27 @@ public function testString() ['binary', 'dGVzdA==', 'dGVzdA=='], ['binary', '', ''], // required - [(object) ['format' => 'default', 'constraints' => (object) ['required' => true]], '', ''], - [(object) ['format' => 'default', 'constraints' => (object) ['required' => true]], null, self::ERROR], + [['format' => 'default', 'constraints' => ['required' => true]], '', ''], + [['format' => 'default', 'constraints' => ['required' => true]], null, self::ERROR], // enum - [(object) ['format' => 'default', 'constraints' => (object) ['enum' => ['foobar']]], 'foobar', 'foobar'], - [(object) ['format' => 'default', 'constraints' => (object) ['enum' => ['foobar']]], 'foobarx', self::ERROR], + [['format' => 'default', 'constraints' => ['enum' => ['foobar']]], 'foobar', 'foobar'], + [['format' => 'default', 'constraints' => ['enum' => ['foobar']]], 'foobarx', self::ERROR], + // minLength / maxLength + [['format' => 'default', 'constraints' => ['minLength' => 1]], "", self::ERROR], + [['format' => 'default', 'constraints' => ['minLength' => 1]], "a", "a"], + [['format' => 'default', 'constraints' => ['minLength' => 1]], "ab", "ab"], + [['format' => 'default', 'constraints' => ['maxLength' => 1]], "", ""], + [['format' => 'default', 'constraints' => ['maxLength' => 1]], "a", "a"], + [['format' => 'default', 'constraints' => ['maxLength' => 1]], "ab", self::ERROR], + [['format' => 'default', 'constraints' => ['minLength' => 1, 'maxLength' => 1]], + "ab", self::ERROR, ], + [['format' => 'default', 'constraints' => ['minLength' => 1, 'maxLength' => 1]], + "a", "a", ], + [['format' => 'default', 'constraints' => ['minLength' => 1, 'maxLength' => 1]], + "", self::ERROR, ], + // pattern + [['format' => 'default', 'constraints' => ['pattern' => '^[a-z]*$']], 'AAA', self::ERROR], + [['format' => 'default', 'constraints' => ['pattern' => '^[a-z]*$']], 'aaa', 'aaa'] ]); } @@ -442,10 +491,15 @@ public function testTime() ['%H:%M:%S', '06:35:21', [6, 35, 21]], ['%H:%M', '06:35:21', self::ERROR], // required - [(object) ['format' => 'default', 'constraints' => (object) ['required' => true]], null, self::ERROR], + [['format' => 'default', 'constraints' => ['required' => true]], null, self::ERROR], // enum - [(object) ['format' => 'default', 'constraints' => (object) ['enum' => ['06:00:00']]], '06:00:00', [6, 0, 0]], - [(object) ['format' => 'default', 'constraints' => (object) ['enum' => ['06:00:00']]], '06:01:00', self::ERROR], + [['format' => 'default', 'constraints' => ['enum' => ['06:00:00']]], '06:00:00', [6, 0, 0]], + [['format' => 'default', 'constraints' => ['enum' => ['06:00:00']]], '06:01:00', self::ERROR], + // minimum / maximum + [['format' => 'default', 'constraints' => ['minimum' => '06:35:21']], '06:35:20', self::ERROR], + [['format' => 'default', 'constraints' => ['maximum' => '06:35:21']], '06:35:22', self::ERROR], + [['format' => 'default', 'constraints' => ['minimum' => '06:35:21', 'maximum' => '06:35:21']], '06:35:21', [6, 35, 21]], + [['format' => 'default', 'constraints' => ['minimum' => '06:35:21', 'maximum' => '06:35:22']], '06:35:21', [6, 35, 21]], ]); } @@ -458,10 +512,14 @@ public function testYear() ['default', 20000, 20000], ['default', '3.14', self::ERROR], // required - [(object) ['format' => 'default', 'constraints' => (object) ['required' => true]], null, self::ERROR], + [['format' => 'default', 'constraints' => ['required' => true]], null, self::ERROR], // enum - [(object) ['format' => 'default', 'constraints' => (object) ['enum' => [2000]]], '2000', 2000], - [(object) ['format' => 'default', 'constraints' => (object) ['enum' => [2000]]], '2001', self::ERROR], + [['format' => 'default', 'constraints' => ['enum' => [2000]]], '2000', 2000], + [['format' => 'default', 'constraints' => ['enum' => [2000]]], '2001', self::ERROR], + // minimum / maximum + [['format' => 'default', 'constraints' => ['minimum' => '2000']], '1999', self::ERROR], + [['format' => 'default', 'constraints' => ['maximum' => '2000']], '2001', self::ERROR], + [['format' => 'default', 'constraints' => ['minimum' => '2000', 'maximum' => '2000']], '2000', 2000], ]); } @@ -482,10 +540,15 @@ public function testYearMonth() ['default', '3.14', self::ERROR], ['default', '', self::ERROR], // required - [(object) ['format' => 'default', 'constraints' => (object) ['required' => true]], null, self::ERROR], + [['format' => 'default', 'constraints' => ['required' => true]], null, self::ERROR], // enum - [(object) ['format' => 'default', 'constraints' => (object) ['enum' => [[2000, 10]]]], '2000-10', [2000, 10]], - [(object) ['format' => 'default', 'constraints' => (object) ['enum' => [[2000, 10]]]], '2000-11', self::ERROR], + [['format' => 'default', 'constraints' => ['enum' => [[2000, 10]]]], '2000-10', [2000, 10]], + [['format' => 'default', 'constraints' => ['enum' => [[2000, 10]]]], '2000-10', [2000, 10]], + [['format' => 'default', 'constraints' => ['enum' => [[2000, 10]]]], '2000-11', self::ERROR], + // minimum / maximum + [['format' => 'default', 'constraints' => ['minimum' => '2000-10']], '1999-12', self::ERROR], + [['format' => 'default', 'constraints' => ['maximum' => '2000-10']], '2001-01', self::ERROR], + [['format' => 'default', 'constraints' => ['minimum' => '2000-10', 'maximum' => '2000-10']], '2000-10', [2000, 10]], ]); } @@ -496,15 +559,15 @@ protected function assertFieldTestData($fieldType, $testData) $testLine[3] = null; } list($format, $inputValue, $expectedCastValue, $expectedInferType) = $testLine; - if (is_object($format)) { + if (is_array($format)) { $descriptor = $format; - $descriptor->type = $fieldType; + $descriptor["type"] = $fieldType; } else { - $descriptor = (object) ['type' => $fieldType, 'format' => $format]; + $descriptor = ['type' => $fieldType, 'format' => $format]; } $assertMessage = 'descriptor='.json_encode($descriptor).", input='".json_encode($inputValue)."', expected='".json_encode($expectedCastValue)."'"; - if (!isset($descriptor->name)) { - $descriptor->name = 'unknown'; + if (!isset($descriptor["name"])) { + $descriptor["name"] = 'unknown'; } $field = FieldsFactory::field($descriptor); if ($expectedCastValue === self::ERROR) {