Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15383378
D21762.id51874.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
D21762.id51874.diff
View Options
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1014,6 +1014,9 @@
'phutil_load_library' => 'init/lib/moduleutils.php',
'phutil_loggable_string' => 'utils/utils.php',
'phutil_microseconds_since' => 'utils/utils.php',
+ 'phutil_nonempty_scalar' => 'utils/utils.php',
+ 'phutil_nonempty_string' => 'utils/utils.php',
+ 'phutil_nonempty_stringlike' => 'utils/utils.php',
'phutil_parse_bytes' => 'utils/viewutils.php',
'phutil_partition' => 'utils/utils.php',
'phutil_passthru' => 'future/exec/execx.php',
diff --git a/src/unit/engine/phutil/PhutilTestCase.php b/src/unit/engine/phutil/PhutilTestCase.php
--- a/src/unit/engine/phutil/PhutilTestCase.php
+++ b/src/unit/engine/phutil/PhutilTestCase.php
@@ -154,6 +154,147 @@
throw new PhutilTestSkippedException($message);
}
+ final protected function assertCaught(
+ $expect,
+ $actual,
+ $message = null) {
+
+ if ($message !== null) {
+ $message = phutil_string_cast($message);
+ }
+
+ if ($actual === null) {
+ // This is okay: no exception.
+ } else if ($actual instanceof Exception) {
+ // This is also okay.
+ } else if ($actual instanceof Throwable) {
+ // And this is okay too.
+ } else {
+ // Anything else is no good.
+
+ if ($message !== null) {
+ $output = pht(
+ 'Call to "assertCaught(..., <junk>, ...)" for test case "%s" '.
+ 'passed bad value for test result. Expected null, Exception, '.
+ 'or Throwable; got: %s.',
+ $message,
+ phutil_describe_type($actual));
+ } else {
+ $output = pht(
+ 'Call to "assertCaught(..., <junk>, ...)" passed bad value for '.
+ 'test result. Expected null, Exception, or Throwable; got: %s.',
+ phutil_describe_type($actual));
+ }
+
+ $this->failTest($output);
+
+ throw new PhutilTestTerminatedException($output);
+ }
+
+ $expect_list = null;
+
+ if ($expect === false) {
+ $expect_list = array();
+ } else if ($expect === true) {
+ $expect_list = array(
+ 'Exception',
+ 'Throwable',
+ );
+ } else if (is_string($expect) || is_array($expect)) {
+ $list = (array)$expect;
+
+ $items_ok = true;
+ foreach ($list as $key => $item) {
+ if (!phutil_nonempty_stringlike($item)) {
+ $items_ok = false;
+ break;
+ }
+
+ $list[$key] = phutil_string_cast($item);
+ }
+
+ if ($items_ok) {
+ $expect_list = $list;
+ }
+ }
+
+ if ($expect_list === null) {
+ if ($message !== null) {
+ $output = pht(
+ 'Call to "assertCaught(<junk>, ...)" for test case "%s" '.
+ 'passed bad expected value. Expected bool, class name as a string, '.
+ 'or a list of class names. Got: %s.',
+ $message,
+ phutil_describe_type($expect));
+ } else {
+ $output = pht(
+ 'Call to "assertCaught(<junk>, ...)" passed bad expected value. '.
+ 'expected result. Expected null, Exception, or Throwable; got: %s.',
+ phutil_describe_type($expect));
+ }
+
+ $this->failTest($output);
+
+ throw new PhutilTestTerminatedException($output);
+ }
+
+ if ($actual === null) {
+ $is_match = !$expect_list;
+ } else {
+ $is_match = false;
+ foreach ($expect_list as $exception_class) {
+ if ($actual instanceof $exception_class) {
+ $is_match = true;
+ break;
+ }
+ }
+ }
+
+ if ($is_match) {
+ $this->assertions++;
+ return;
+ }
+
+ $caller = self::getCallerInfo();
+ $file = $caller['file'];
+ $line = $caller['line'];
+
+ $output = array();
+
+ if ($message !== null) {
+ $output[] = pht(
+ 'Assertion of caught exception failed (at %s:%d in test case "%s").',
+ $file,
+ $line,
+ $message);
+ } else {
+ $output[] = pht(
+ 'Assertion of caught exception failed (at %s:%d).',
+ $file,
+ $line);
+ }
+
+ if ($actual === null) {
+ $output[] = pht('Expected any exception, got no exception.');
+ } else if (!$expect_list) {
+ $output[] = pht(
+ 'Expected no exception, got exception of class "%s".',
+ get_class($actual));
+ } else {
+ $expected_classes = implode(', ', $expect_list);
+ $output[] = pht(
+ 'Expected exception (in class(es): %s), got exception of class "%s".',
+ $expected_classes,
+ get_class($actual));
+ }
+
+ $output = implode("\n\n", $output);
+
+ $this->failTest($output);
+
+ throw new PhutilTestTerminatedException($output);
+ }
+
/* -( Exception Handling )------------------------------------------------- */
diff --git a/src/utils/__tests__/PhutilUtilsTestCase.php b/src/utils/__tests__/PhutilUtilsTestCase.php
--- a/src/utils/__tests__/PhutilUtilsTestCase.php
+++ b/src/utils/__tests__/PhutilUtilsTestCase.php
@@ -1000,4 +1000,74 @@
}
}
+ public function testEmptyStringMethods() {
+
+ $uri = new PhutilURI('http://example.org/');
+
+ $map = array(
+ array(null, false, false, false, 'literal null'),
+ array('', false, false, false, 'empty string'),
+ array('x', true, true, true, 'nonempty string'),
+ array(false, null, null, null, 'bool'),
+ array(1, null, null, true, 'integer'),
+ array($uri, null, true, true, 'uri object'),
+ array(2.5, null, null, true, 'float'),
+ array(array(), null, null, null, 'array'),
+ array((object)array(), null, null, null, 'object'),
+ );
+
+ foreach ($map as $test_case) {
+ $input = $test_case[0];
+
+ $expect_string = $test_case[1];
+ $expect_stringlike = $test_case[2];
+ $expect_scalar = $test_case[3];
+
+ $test_name = $test_case[4];
+
+ $this->executeEmptyStringTest(
+ $input,
+ $expect_string,
+ 'phutil_nonempty_string',
+ $test_name);
+
+ $this->executeEmptyStringTest(
+ $input,
+ $expect_stringlike,
+ 'phutil_nonempty_stringlike',
+ $test_name);
+
+ $this->executeEmptyStringTest(
+ $input,
+ $expect_scalar,
+ 'phutil_nonempty_scalar',
+ $test_name);
+ }
+
+ }
+
+ private function executeEmptyStringTest($input, $expect, $call, $name) {
+ $name = sprintf('%s(<%s>)', $call, $name);
+
+ $caught = null;
+ try {
+ $actual = call_user_func($call, $input);
+ } catch (Exception $ex) {
+ $caught = $ex;
+ } catch (Throwable $ex) {
+ $caught = $ex;
+ }
+
+ if ($expect === null) {
+ $expect_exceptions = array('InvalidArgumentException');
+ } else {
+ $expect_exceptions = false;
+ }
+
+ $this->assertCaught($expect_exceptions, $caught, $name);
+ if (!$caught) {
+ $this->assertEqual($expect, $actual, $name);
+ }
+ }
+
}
diff --git a/src/utils/utils.php b/src/utils/utils.php
--- a/src/utils/utils.php
+++ b/src/utils/utils.php
@@ -2094,3 +2094,128 @@
throw new PhutilRegexException($message);
}
+
+
+/**
+ * Test if a value is a nonempty string.
+ *
+ * The value "null" and the empty string are considered empty; all other
+ * strings are considered nonempty.
+ *
+ * This method raises an exception if passed a value which is neither null
+ * nor a string.
+ *
+ * @param Value to test.
+ * @return bool True if the parameter is a nonempty string.
+ */
+function phutil_nonempty_string($value) {
+ if ($value === null) {
+ return false;
+ }
+
+ if ($value === '') {
+ return false;
+ }
+
+ if (is_string($value)) {
+ return true;
+ }
+
+ throw new InvalidArgumentException(
+ pht(
+ 'Call to phutil_nonempty_string() expected null or a string, got: %s.',
+ phutil_describe_type($value)));
+}
+
+
+/**
+ * Test if a value is a nonempty, stringlike value.
+ *
+ * The value "null", the empty string, and objects which have a "__toString()"
+ * method which returns the empty string are empty.
+ *
+ * Other strings, and objects with a "__toString()" method that returns a
+ * string other than the empty string are considered nonempty.
+ *
+ * This method raises an exception if passed any other value.
+ *
+ * @param Value to test.
+ * @return bool True if the parameter is a nonempty, stringlike value.
+ */
+function phutil_nonempty_stringlike($value) {
+ if ($value === null) {
+ return false;
+ }
+
+ if ($value === '') {
+ return false;
+ }
+
+ if (is_string($value)) {
+ return true;
+ }
+
+ if (is_object($value)) {
+ try {
+ $string = phutil_string_cast($value);
+ return phutil_nonempty_string($string);
+ } catch (Exception $ex) {
+ // Continue below.
+ } catch (Throwable $ex) {
+ // Continue below.
+ }
+ }
+
+ throw new InvalidArgumentException(
+ pht(
+ 'Call to phutil_nonempty_stringlike() expected a string or stringlike '.
+ 'object, got: %s.',
+ phutil_describe_type($value)));
+}
+
+
+/**
+ * Test if a value is a nonempty, scalar value.
+ *
+ * The value "null", the empty string, and objects which have a "__toString()"
+ * method which returns the empty string are empty.
+ *
+ * Other strings, objects with a "__toString()" method which returns a
+ * string other than the empty string, integers, and floats are considered
+ * scalar.
+ *
+ * This method raises an exception if passed any other value.
+ *
+ * @param Value to test.
+ * @return bool True if the parameter is a nonempty, scalar value.
+ */
+function phutil_nonempty_scalar($value) {
+ if ($value === null) {
+ return false;
+ }
+
+ if ($value === '') {
+ return false;
+ }
+
+ if (is_string($value) || is_int($value) || is_float($value)) {
+ return true;
+ }
+
+ if (is_object($value)) {
+ try {
+ $string = phutil_string_cast($value);
+ return phutil_nonempty_string($string);
+ } catch (Exception $ex) {
+ // Continue below.
+ } catch (Throwable $ex) {
+ // Continue below.
+ }
+ }
+
+ throw new InvalidArgumentException(
+ pht(
+ 'Call to phutil_nonempty_scalar() expected: a string; or stringlike '.
+ 'object; or int; or float. Got: %s.',
+ phutil_describe_type($value)));
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Mar 15, 4:27 PM (4 w, 1 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7223517
Default Alt Text
D21762.id51874.diff (10 KB)
Attached To
Mode
D21762: Introduce PHP8.1 replacement functions for string tests which may take multiple types
Attached
Detach File
Event Timeline
Log In to Comment