/** * Convert the object to an instance of ``IntString``. * * @param string|IntString $obj Object to convert to ``IntString``. * * @return IntString * @throws InvalidArgumentException if object is not a string or format is invalid. */ public static function parse($obj) { if ($obj instanceof IntString) { return $obj; } if (is_integer($obj)) { return new VersionComponent($obj); } try { $intValue = (int) String::ensureIsString($obj); } catch (InvalidArgumentException $e) { $args = ['position' => '1st', 'expected' => 'string" or "integer', 'actual' => typeof($obj)]; $msg = nml_msg('Invalid argument type.'); $msg .= nml_msg(' {position} parameter must to be an instance of "{expected}"; "{actual}" given.', $args); throw new InvalidArgumentException($msg, 1, $e); } $stringValue = ltrim($obj, "{$intValue}"); // Validate that 0 (zero) is not interpreted as '' (empty string) if ($stringValue === $obj) { $msg = nml_msg('Invalid argument value.'); $msg .= nml_msg(' "{0}" (string) must to start with an integer.', $obj); throw new InvalidArgumentException($msg); } return new IntString($intValue, $stringValue); }
/** * Busca un mensaje único, en singular y plural, traducido en el dominio 'nml'. * El mensaje puede contener cadenas de formato. * * @param string $singular Mensaje con formato que se va a buscar cuando $n * es uno (1). * @param string $plural Mensaje con formato que se va a buscar cuando $n * es distinto a (1). * @param integer $n Cantidad * @param array|mixed $args Un objeto, una lista de objetos o múltiples * argumentos que se van a incluir en las cadenas de formato del mensaje. * * @return string * @see dngettext * */ function nmsg($singular, $plural, $n, $args = null) { $translated = dngettext(GETTEXT_DOMAIN, $singular, $plural, $n); if (func_num_args() > 4) { $args = array_slice(func_get_args(), 3); } return String::format($translated, $args); }
/** * @testdox Can check if Version instance is valid * @coverage Version::isValid * @dataProvider isValidProvider */ public function testIsValid($expected, Version $version) { $actual = $version->isValid(); $message = String::format('$version->{method}(); // {actual}', ['method' => 'isValid', 'obj' => static::export($version), 'actual' => static::export($actual)]); $this->assertInternalType('boolean', $actual, $message . ' # Should return a boolean #'); if ($expected === true) { $this->assertTrue($actual, $message); } else { $this->assertFalse($actual, $message); } }
/** * Overrides default tests, due to this class constructor do not throws argument exceptions. * So, using any type should be pass. * * @testdox Do not throws error on creating new instances, due to all arguments passed are ignored * @group Criticals */ public function testConstructorWithBadArguments() { $actual = null; $message = String::format('$object = new {class}();', ['class' => Object::class]); try { $actual = new Object(); } catch (Exception $e) { $actual = $e; $message .= String::format(' // # Constructor should not throws exceptions. Error: {0}', $this->exporter->export($e->getMessage())); } $this->assertInstanceOf(Object::class, $actual, $message); }
/** * Overrides default tests, due to this class constructor do not throws argument exceptions. * So, using any type should be pass. * * @testdox Do not throws error on creating new instances * @dataProvider badConstructorArgumentsProvider * @group Criticals */ public function testConstructorWithBadArguments($obj) { $actual = null; $message = String::format('$type = new {class}({obj});', ['class' => Type::class, 'obj' => $this->exporter->shortenedExport($obj)]); try { $actual = new Type($obj); } catch (\Exception $e) { $actual = $e; $message .= String::format(' // # Constructor should not throws exceptions. Error: {0}', $this->exporter->export($e->getMessage())); } $this->assertInstanceOf(Type::class, $actual, $message); }
/** * Gets the property getter method name. * You can customize the getter prefix by implementing ``ICustomPrefixedPropertiesContainer`` interface. * * @param string $name Property name. * * @return string * @throws InvalidArgumentException If property is not valid or has not getter. * @throws BadMethodCallException If custom prefix is not an ``string`` instance. * @see ICustomPrefixedPropertiesContainer::getCustomGetterPrefix() */ protected static function getPropertyGetter($name) { $args = ['class' => get_called_class()]; $prefix = 'get'; $args['name'] = static::ensurePropertyExists($name, $args['class']); try { $getter = static::ensureMethodExists($prefix . $args['name']); } catch (InvalidArgumentException $error) { $msg = nml_msg('"{name}" property has not a getter method in "{class}".', $args); if (is_subclass_of($args['class'], ICustomPrefixedPropertiesContainer::class)) { // If not available standard getter, check if custom available try { $prefix = String::ensureIsString(static::getCustomGetterPrefix()); } catch (InvalidArgumentException $e) { $msg = nml_msg('"{class}::getCustomGetterPrefix" method must to return an string.', $args['class']); throw new BadMethodCallException($msg, 31, $e); } try { $getter = static::ensureMethodExists($prefix . $args['name']); } catch (InvalidArgumentException $e) { throw new InvalidArgumentException($msg, 32, $e); } } else { // Error for non custom prefixes throw new InvalidArgumentException($msg, 30, $error); } } return $getter; }
/** * Extract the string representation of specified object in one line. * * @param mixed $obj Object to export. * @param integer $depth How many levels of depth will export in arrays and objects. If $depth <= 0, * only '...' will be returned for content of object or array. Default: ``2``. * @param bool $short If class names are returned without namespace. Default: ``false``. * * @return string * @see Exporter::shortenedRecursiveExport() * @see Exporter::export() */ public static function export($obj, $depth = 2, $short = false) { if (static::$exporter === null) { static::$exporter = new Exporter(); } $depth = (int) $depth < 0 ? 0 : (int) $depth; $short = (bool) $short; $str = null; if (is_object($obj)) { $className = static::getClass($obj, $short); if ($depth <= 0) { // Do not show properties $content = '{...}'; } else { $arrayObject = static::$exporter->toArray($obj); // Initial content without deep $content = static::export($arrayObject, 1, $short); // Replace array braces and separator $content = str_replace([' => ', '[ ', ' ]'], [': ', '{ ', ' }'], $content); // var_dump($content, $depth); if ($depth > 1) { foreach ($arrayObject as $key => $value) { $format = '{0}: {1}'; if (is_object($value)) { $sclass = static::getClass($value, $short); $sVal = "{$sclass}({...})"; } elseif (is_array($value)) { $sVal = '[...]'; } else { continue; } $search = String::format($format, $key, $sVal); $replacement = String::format($format, $key, static::export($value, $depth - 1, $short)); $content = str_replace($search, $replacement, $content); } } } $str = String::format('{0}({1})', $className, $content); $str = str_replace(', }', ' }', $str); } elseif (is_array($obj)) { if ($depth <= 0) { $str = count($obj) > 0 ? '[...]' : ''; } else { $str = ''; foreach ($obj as $key => $value) { // Export all items recursively $str .= String::format('{0} => {1}, ', $key, static::export($value, $depth - 1, $short)); } $str = String::format('[ {0} ]', $str); $str = str_replace(', ]', ' ]', $str); } } else { $str = static::$exporter->export($obj); } return $str; }
/** * @testdox Is compliant with ``NelsonMartell\IComparer`` interface * @depends testCanUseCompareMethodInArraySorting */ public function testIsCompliantWithIComparerIterface() { $message = String::format('"{0}" do not implements "{1}" interface.', $this->getTargetClassName(), IComparer::class); $this->assertContains(IComparer::class, $this->getTargetClassReflection()->getInterfaceNames(), $message); }
/** * @coverage VersionComponent::isNull * @coverage VersionComponent::isNotNull * @coverage VersionComponent::isDefault * @coverage VersionComponent::isNotDefault * @dataProvider nullOrDefaultStatesProvider */ public function testCanCheckIfVersionComponentIsInDefaultOrNullState($expected, VersionComponent $versionComponent) { static $format = '$versionComponent->{method}(); // {actual}'; $actuals['isDefault'] = $versionComponent->isDefault(); $actuals['isNotDefault'] = $versionComponent->isNotDefault(); $actuals['isNull'] = $versionComponent->isNull(); $actuals['isNotNull'] = $versionComponent->isNotNull(); $messages = []; foreach ($actuals as $method => $actual) { $messages[$method] = String::format($format, ['method' => $method, 'actual' => static::export($actual)]); } foreach ($actuals as $method => $actual) { // Pre-tests for returning type $this->assertInternalType('boolean', $actual, $messages[$method] . ' # Should return a boolean #'); } // Pre-tests for different values $this->assertNotEquals($actuals['isDefault'], $actuals['isNotDefault'], $messages['isDefault'] . PHP_EOL . $messages['isNotDefault']); $this->assertNotEquals($actuals['isNull'], $actuals['isNotNull'], $messages['isNull'] . PHP_EOL . $messages['isNotNull']); // Test expected if ($expected === 'default') { $this->assertTrue($actuals['isDefault'], $messages['isDefault']); // Can't be null AND default $this->assertNotEquals($actuals['isNull'], $actuals['isDefault'], '#Can\'t be both, DEFAULT and NULL, at the same time' . PHP_EOL . $messages['isDefault'] . PHP_EOL . $messages['isNull']); } elseif ($expected === 'null') { $this->assertTrue($actuals['isNull'], $messages['isNull']); // Can't be null AND default $this->assertNotEquals($actuals['isNull'], $actuals['isDefault'], '#Can\'t be both, NULL and DEFAULT, at the same time' . PHP_EOL . $messages['isNull'] . PHP_EOL . $messages['isDefault']); } else { $this->assertTrue($actuals['isNotDefault'], $messages['isNotDefault']); $this->assertTrue($actuals['isNotNull'], $messages['isNotNull']); } }
/** * Gets the string representation of this object collection. * * You can format the output, by setting $format param to one of this * options: * - `R` or `r`: All items, separated by comma and space (`, `). * This is the default format. * - `L` or `l`: Same as `r` option, but enclosed in braces (`{`, `}`). * - `g`: A full string, containing class name, items count and items * list (this list, like `L` option). * - `G`: Same as `g`, but using a full class name (including namespace). * * You can also use a custom format instead, using this placeholders: * - `{class}`: Short class name (without namespace part); * - `{nsclass}`: Full class name (included namespace); * - `{count}`: Items count; and * - `{items}`: List of items, using comma and space (`, `) as separator. * * Example: For a instance with 10 elements (numbers: 1-10), using: * `Collection::ToString('My collection ({count} items): { {items} }');` * Result: 'My collection (10 items): { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }' * * @param string $format String format (optional). By default, `r`. * * @return string * @see String::format * */ public function toString($format = 'r') { static $defaultFormats = ['r' => '{items}', 'l' => '{ {items} }', 'g' => '{class} ({count} items): { {items} }', 'G' => '{nsclass} ({count} items): { {items} }']; if ($format == null or !is_string($format)) { $format = 'r'; //Override if is not an string } $str = ''; switch ($format) { case 'r': case 'l': case 'g': case 'G': $str = $defaultFormats[$format]; break; default: $str = $format; } $t = $this->GetType(); $items = implode(', ', $this->items); $placeHoldersValues = ['class' => $t->ShortName, 'nsclass' => $t->Name, 'count' => $this->Count, 'items' => $items]; $s = String::Format($str, $placeHoldersValues); return $s; }
/** * @dataProvider readwritePropertiesProvider */ public function testPropertiesWithFullAccessAreReadablesAndWritables(IStrictPropertiesContainer $obj = null, $property = null, $value = null, $expected = null) { if ($obj === null) { $this->markTestSkipped('Target class has not read-write properties to test.'); } $exporter = new Exporter(); $var = get_class($obj); $var = Inflector::variable(substr($var, strrpos($var, '\\') === false ? 0 : strrpos($var, '\\') + 1)); $obj->{$property} = $value; $actual = $obj->{$property}; $message = String::format('${var}->{property} = {value}; $actual = ${var}->{property}; // {actual}', ['var' => $var, 'property' => $property, 'actual' => $exporter->shortenedExport($actual), 'value' => $exporter->shortenedExport($value)]); $this->assertEquals($expected, $actual, $message); }
/** * @expectedException InvalidArgumentException * @dataProvider nonStringObjectsProvider */ public function testDoNotPerformsFormatWithPlaceholdersValuesNotConvertiblesToString($obj) { $format = PHP_EOL . 'This test should throws an "{0}" with data: {testErrorData}.' . PHP_EOL; $str = String::format($format, [InvalidArgumentException::class, 'testErrorData' => $obj]); }