From c1c32c9eed483bbd1293ef317686c642c8317c41 Mon Sep 17 00:00:00 2001 From: Ad Schellevis Date: Tue, 28 Jan 2020 15:41:29 +0100 Subject: [PATCH] Extend PortField to support multiple items, closes https://github.com/opnsense/core/issues/3895 - while here fix unit tests to support 8.5.x - add unit test for PortField --- .../mvc/app/library/OPNsense/Core/Config.php | 2 +- .../OPNsense/Base/FieldTypes/PortField.php | 64 +++----- .../app/compound/OPNsense/Monit/MonitTest.php | 4 +- .../models/OPNsense/Base/BaseModelTest.php | 24 +-- .../Base/FieldTypes/AuthGroupFieldTest.php | 8 +- .../AuthenticationServerFieldTest.php | 8 +- .../Base/FieldTypes/BooleanFieldTest.php | 12 +- .../Base/FieldTypes/CertificateFieldTest.php | 8 +- .../Base/FieldTypes/CountryFieldTest.php | 12 +- .../Base/FieldTypes/IntegerFieldTest.php | 12 +- .../Base/FieldTypes/InterfaceFieldTest.php | 12 +- .../FieldTypes/ModelRelationFieldTest.php | 2 +- .../Base/FieldTypes/OptionFieldTest.php | 4 +- .../Base/FieldTypes/PortFieldTest.php | 137 ++++++++++++++++++ 14 files changed, 212 insertions(+), 97 deletions(-) create mode 100644 src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/PortFieldTest.php diff --git a/src/opnsense/mvc/app/library/OPNsense/Core/Config.php b/src/opnsense/mvc/app/library/OPNsense/Core/Config.php index ece962207..1975d600a 100644 --- a/src/opnsense/mvc/app/library/OPNsense/Core/Config.php +++ b/src/opnsense/mvc/app/library/OPNsense/Core/Config.php @@ -300,7 +300,7 @@ class Config extends Singleton } // in case there are no backups, restore defaults. $logger->error(gettext('No valid config.xml found, attempting to restore factory config.')); - $this->restoreBackup('/usr/local/etc/config.xml'); + $this->restoreBackup('/usr/local/etc/config.xml.sample'); } } diff --git a/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/PortField.php b/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/PortField.php index 0ccfa4301..9abc1e2a6 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/PortField.php +++ b/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/PortField.php @@ -1,7 +1,7 @@ enableWellKown) { - self::$internalOptionList = array("any") + self::$wellknownservices; + if ($this->enableWellKown) { + foreach (array("any") + self::$wellknownservices as $wellknown) { + $this->internalOptionList[(string)$wellknown] = $wellknown; } + } - for ($port = 1; $port <= 65535; $port++) { - self::$internalOptionList[] = (string)$port; - } + for ($port = 1; $port <= 65535; $port++) { + $this->internalOptionList[(string)$port] = (string)$port; } } @@ -173,35 +162,24 @@ class PortField extends BaseField */ public function getValidators() { - $validators = parent::getValidators(); - if ( - ($this->internalIsRequired == true || $this->internalValue != null) && - count(self::$internalOptionList) > 0 - ) { - if (count(explode("-", $this->internalValue)) == 2 && $this->enableRanges) { - // range validation - $validators[] = new CallbackValidator(["callback" => function ($data) { - $messages = []; + if ($this->enableRanges) { + // add valid ranges to options + foreach (explode(",", $this->internalValue) as $data) { + if (strpos($data, "-") !== false) { $tmp = explode('-', $data); - foreach ($tmp as $port) { - if ( - filter_var( - $port, - FILTER_VALIDATE_INT, - array('options' => array('min_range' => 1, 'max_range' => 65535)) - ) === false + if (count($tmp) == 2) { + if (filter_var($tmp[0],FILTER_VALIDATE_INT, + array('options' => array('min_range' => 1, 'max_range' => 65535))) !== false && + filter_var($tmp[1],FILTER_VALIDATE_INT, + array('options' => array('min_range' => 1, 'max_range' => 65535))) !== false && + $tmp[0] < $tmp[1] ) { - $messages[] = $this->getValidationMessage(); - break; + $this->internalOptionList[$data] = $data; } } - return $messages; - }]); - } else { - $validators[] = new InclusionIn(array('message' => $this->getValidationMessage(), - 'domain' => self::$internalOptionList)); + } } } - return $validators; + return parent::getValidators(); } } diff --git a/src/opnsense/mvc/tests/app/compound/OPNsense/Monit/MonitTest.php b/src/opnsense/mvc/tests/app/compound/OPNsense/Monit/MonitTest.php index 6523b9b09..13a8fe6d4 100644 --- a/src/opnsense/mvc/tests/app/compound/OPNsense/Monit/MonitTest.php +++ b/src/opnsense/mvc/tests/app/compound/OPNsense/Monit/MonitTest.php @@ -40,13 +40,13 @@ class MonitTest extends \PHPUnit\Framework\TestCase // holds the SettingsController object protected static $setMonit; - protected function setUp() + protected function setUp(): void { // XXX: Unit test has dependencies, which are not handled within the same test suite. $this->markTestIncomplete(); } - public static function setUpBeforeClass() + public static function setUpBeforeClass(): void { self::$setMonit = new \OPNsense\Monit\Api\SettingsController(); } diff --git a/src/opnsense/mvc/tests/app/models/OPNsense/Base/BaseModelTest.php b/src/opnsense/mvc/tests/app/models/OPNsense/Base/BaseModelTest.php index e62592078..8af715676 100644 --- a/src/opnsense/mvc/tests/app/models/OPNsense/Base/BaseModelTest.php +++ b/src/opnsense/mvc/tests/app/models/OPNsense/Base/BaseModelTest.php @@ -88,12 +88,12 @@ class BaseModelTest extends \PHPUnit\Framework\TestCase } /** - * @expectedException InvalidArgumentException - * @expectedExceptionMessage FromEmailXXX not an attribute of general * @depends testRunMigrations */ public function testCannotSetNonExistingField() { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage("FromEmailXXX not an attribute of general"); BaseModelTest::$model->general->FromEmailXXX = "test@test.nl"; } @@ -167,11 +167,11 @@ class BaseModelTest extends \PHPUnit\Framework\TestCase /** * @depends testCanAssignArrayType - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage not a valid number */ public function testValidationNOK() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("not a valid number"); // replace all numbers foreach (BaseModelTest::$model->arraytypes->item->iterateItems() as $nodeid => $node) { $node->number = "XXX"; @@ -241,11 +241,11 @@ class BaseModelTest extends \PHPUnit\Framework\TestCase /** * @depends testGetNodes - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage number should be unique */ public function testConstraintsNok() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("number should be unique"); $count = 2; foreach (BaseModelTest::$model->arraytypes->item->iterateItems() as $nodeid => $node) { $count--; @@ -285,12 +285,12 @@ class BaseModelTest extends \PHPUnit\Framework\TestCase } /** - * @expectedException Exception - * @expectedExceptionMessage All fields should contain data or none of them * @depends testAllOrNoneInitial */ public function testAllOrNoneNok() { + $this->expectException(\Exception::class); + $this->expectExceptionMessage("All fields should contain data or none of them"); BaseModelTest::$model->AllOrNone->value1 = ""; BaseModelTest::$model->AllOrNone->value2 = "X"; BaseModelTest::$model->AllOrNone->value3 = ""; @@ -327,12 +327,12 @@ class BaseModelTest extends \PHPUnit\Framework\TestCase } /** - * @expectedException Exception - * @expectedExceptionMessage Only one option could be selected * @depends testSingleSelectInitial */ public function testSingleSelectNok() { + $this->expectException(\Exception::class); + $this->expectExceptionMessage("Only one option could be selected"); BaseModelTest::$model->SingleSelect->value1 = "x"; BaseModelTest::$model->SingleSelect->value2 = "x"; BaseModelTest::$model->SingleSelect->value3 = ""; @@ -371,11 +371,11 @@ class BaseModelTest extends \PHPUnit\Framework\TestCase /** * @depends testDependConstraintInitial - * @expectedException Exception - * @expectedExceptionMessage when value1 is enabled value2 is required */ public function testDependConstraintNok() { + $this->expectException(\Exception::class); + $this->expectExceptionMessage("when value1 is enabled value2 is required"); BaseModelTest::$model->DependConstraint->value1 = "1"; BaseModelTest::$model->DependConstraint->value2 = ""; BaseModelTest::$model->serializeToConfig(); diff --git a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/AuthGroupFieldTest.php b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/AuthGroupFieldTest.php index 69fd90bdc..e23981338 100644 --- a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/AuthGroupFieldTest.php +++ b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/AuthGroupFieldTest.php @@ -68,11 +68,11 @@ class AuthGroupFieldTest extends Field_Framework_TestCase /** * @depends testCanBeCreated - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage CsvListValidator */ public function testSelectSetWithUnknownValue() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("CsvListValidator"); // init field $field = new AuthGroupField(); $field->eventPostLoading(); @@ -97,11 +97,11 @@ class AuthGroupFieldTest extends Field_Framework_TestCase /** * @depends testCanBeCreated - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage InclusionIn */ public function testSelectSetOnSingleValue() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("InclusionIn"); // init field $field = new AuthGroupField(); $field->eventPostLoading(); diff --git a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/AuthenticationServerFieldTest.php b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/AuthenticationServerFieldTest.php index 999a86b5f..cc355d4b7 100644 --- a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/AuthenticationServerFieldTest.php +++ b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/AuthenticationServerFieldTest.php @@ -81,11 +81,11 @@ class AuthenticationServerFieldTest extends Field_Framework_TestCase /** * @depends testCanBeCreated - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage CsvListValidator */ public function testSelectSetWithUnknownValue() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("CsvListValidator"); // init field $field = new AuthenticationServerField(); $field->eventPostLoading(); @@ -110,11 +110,11 @@ class AuthenticationServerFieldTest extends Field_Framework_TestCase /** * @depends testCanBeCreated - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage InclusionIn */ public function testSelectSetOnSingleValue() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("InclusionIn"); // init field $field = new AuthenticationServerField(); $field->eventPostLoading(); diff --git a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/BooleanFieldTest.php b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/BooleanFieldTest.php index 45180bc2e..101c4aa5c 100644 --- a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/BooleanFieldTest.php +++ b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/BooleanFieldTest.php @@ -48,22 +48,22 @@ class BooleanFieldTest extends Field_Framework_TestCase } /** - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage Regex */ public function testShouldNotBeANumber() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("Regex"); $field = new BooleanField(); $field->setValue("90"); $this->validateThrow($field); } /** - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage Regex */ public function testShouldNotBeAString() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("Regex"); $field = new BooleanField(); $field->setValue("xx"); $this->validateThrow($field); @@ -71,11 +71,11 @@ class BooleanFieldTest extends Field_Framework_TestCase /** - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage PresenceOf */ public function testRequiredEmpty() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("PresenceOf"); $field = new BooleanField(); $field->setRequired("Y"); $field->setValue(""); diff --git a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/CertificateFieldTest.php b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/CertificateFieldTest.php index 53203e359..0b794d46a 100644 --- a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/CertificateFieldTest.php +++ b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/CertificateFieldTest.php @@ -81,11 +81,11 @@ class CertificateFieldTest extends Field_Framework_TestCase /** * @depends testCanBeCreated - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage CsvListValidator */ public function testSelectSetWithUnknownValue() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("CsvListValidator"); // init field $field = new CertificateField(); $field->eventPostLoading(); @@ -110,11 +110,11 @@ class CertificateFieldTest extends Field_Framework_TestCase /** * @depends testCanBeCreated - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage InclusionIn */ public function testSelectSetOnSingleValue() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("InclusionIn"); // init field $field = new CertificateField(); $field->eventPostLoading(); diff --git a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/CountryFieldTest.php b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/CountryFieldTest.php index be49ea1d7..c1af9fac0 100644 --- a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/CountryFieldTest.php +++ b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/CountryFieldTest.php @@ -48,11 +48,11 @@ class CountryFieldTest extends Field_Framework_TestCase } /** - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage PresenceOf */ public function testRequiredEmpty() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("PresenceOf"); $field = new CountryField(); $field->eventPostLoading(); $field->setRequired("Y"); @@ -99,11 +99,11 @@ class CountryFieldTest extends Field_Framework_TestCase } /** * @depends testCanBeCreated - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage CsvListValidator */ public function testSelectSetWithUnknownValue() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("CsvListValidator"); // init field $field = new CountryField(); $field->eventPostLoading(); @@ -128,11 +128,11 @@ class CountryFieldTest extends Field_Framework_TestCase /** * @depends testCanBeCreated - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage InclusionIn */ public function testSelectSetOnSingleValue() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("InclusionIn"); // init field $field = new CountryField(); $field->eventPostLoading(); diff --git a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/IntegerFieldTest.php b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/IntegerFieldTest.php index 378cd4e04..9fc36a77b 100644 --- a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/IntegerFieldTest.php +++ b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/IntegerFieldTest.php @@ -48,11 +48,11 @@ class IntegerFieldTest extends Field_Framework_TestCase } /** - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage MinMaxValidator */ public function testValueLargerThenMax() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("MinMaxValidator"); $field = new IntegerField(); $field->setMaximumValue(100); $field->setMinimumValue(10); @@ -62,11 +62,11 @@ class IntegerFieldTest extends Field_Framework_TestCase } /** - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage MinMaxValidator */ public function testValueSmallerThenMin() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("MinMaxValidator"); $field = new IntegerField(); $field->setMaximumValue(100); $field->setMinimumValue(10); @@ -102,11 +102,11 @@ class IntegerFieldTest extends Field_Framework_TestCase } /** - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage PresenceOf */ public function testRequiredEmpty() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("PresenceOf"); $field = new IntegerField(); $field->setRequired("Y"); $field->setValue(""); diff --git a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/InterfaceFieldTest.php b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/InterfaceFieldTest.php index e830c84bd..ff34fff5a 100644 --- a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/InterfaceFieldTest.php +++ b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/InterfaceFieldTest.php @@ -68,11 +68,11 @@ class InterfaceFieldTest extends Field_Framework_TestCase /** * @depends testCanBeCreated - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage InclusionIn */ public function testSelectHasNoParents() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("InclusionIn"); // init field $field = new InterfaceField(); $field->eventPostLoading(); @@ -109,11 +109,11 @@ class InterfaceFieldTest extends Field_Framework_TestCase /** * @depends testCanBeCreated - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage CsvListValidator */ public function testSelectSetWithUnknownValue() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("CsvListValidator"); // init field $field = new InterfaceField(); $field->eventPostLoading(); @@ -138,11 +138,11 @@ class InterfaceFieldTest extends Field_Framework_TestCase /** * @depends testCanBeCreated - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage InclusionIn */ public function testSelectSetOnSingleValue() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("InclusionIn"); // init field $field = new InterfaceField(); $field->eventPostLoading(); diff --git a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/ModelRelationFieldTest.php b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/ModelRelationFieldTest.php index 4b2ec0154..cb1455b78 100644 --- a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/ModelRelationFieldTest.php +++ b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/ModelRelationFieldTest.php @@ -39,7 +39,7 @@ use \OPNsense\Core\Config; class ModelRelationFieldTest extends Field_Framework_TestCase { - protected function setUp() + protected function setUp(): void { FactoryDefault::getDefault()->get('config')->globals->config_path = __DIR__ . '/ModelRelationFieldTest/'; Config::getInstance()->forceReload(); diff --git a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/OptionFieldTest.php b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/OptionFieldTest.php index 7d3f8edd1..bcb90e542 100644 --- a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/OptionFieldTest.php +++ b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/OptionFieldTest.php @@ -48,11 +48,11 @@ class OptionFieldTest extends Field_Framework_TestCase } /** - * @expectedException \Phalcon\Validation\Exception - * @expectedExceptionMessage PresenceOf */ public function testRequiredEmpty() { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("PresenceOf"); $field = new OptionField(); $field->setRequired("Y"); $field->setValue(""); diff --git a/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/PortFieldTest.php b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/PortFieldTest.php new file mode 100644 index 000000000..456e39334 --- /dev/null +++ b/src/opnsense/mvc/tests/app/models/OPNsense/Base/FieldTypes/PortFieldTest.php @@ -0,0 +1,137 @@ +assertInstanceOf('\OPNsense\Base\FieldTypes\PortField', new PortField()); + } + + /** + */ + public function testRequiredEmpty() + { + $this->expectException(\Phalcon\Validation\Exception::class); + $this->expectExceptionMessage("PresenceOf"); + $field = new PortField(); + $field->setRequired("Y"); + $field->setValue(""); + $field->eventPostLoading(); + $this->validateThrow($field); + } + + /** + * required not empty + */ + public function testRequiredNotEmpty() + { + $field = new PortField(); + $field->setRequired("Y"); + $field->setValue("80"); + $field->eventPostLoading(); + $this->assertEmpty($this->validate($field)); + } + + /** + * required not empty + */ + public function testValidValues() + { + $field = new PortField(); + $field->setEnableRanges("Y"); + $field->setEnableWellKnown("Y"); + $field->eventPostLoading(); + foreach (array("80", "443", "https", "80-100") as $value) { + $field->setValue($value); + $this->assertEmpty($this->validate($field)); + } + } + + /** + * all items valid + */ + public function testValidValueList() + { + $field = new PortField(); + $field->setEnableRanges("Y"); + $field->setEnableWellKnown("Y"); + $field->setMultiple("Y"); + $field->eventPostLoading(); + $field->setValue("80,443,https,80-100"); + $this->assertEmpty($this->validate($field)); + } + + /** + * range not expected + */ + public function testRangeNotExpected() + { + $field = new PortField(); + $field->setEnableWellKnown("Y"); + $field->setMultiple("Y"); + $field->eventPostLoading(); + $field->setValue("80;443;https;80-100"); + $this->assertNotEmpty($this->validate($field)); + } + + /** + * required not empty + */ + public function testInValidValues() + { + $field = new PortField(); + foreach (array("x1", "x2", "999999-88888888") as $value) { + $field->setValue($value); + $this->assertNotEmpty($this->validate($field)); + } + } + + /** + * type is not a container + */ + public function testIsContainer() + { + $field = new PortField(); + $this->assertFalse($field->isContainer()); + } +}