├── test_helper.php ├── tests ├── fast_assert_036.phpt ├── fast_assert_003.phpt ├── fast_assert_001.phpt ├── fast_assert_031.phpt ├── fast_assert_002.phpt ├── fast_assert_037.phpt ├── fast_assert_035.phpt ├── fast_assert_034.phpt ├── fast_assert_008.phpt ├── fast_assert_015.phpt ├── fast_assert_010.phpt ├── fast_assert_033.phpt ├── fast_assert_011.phpt ├── fast_assert_009.phpt ├── fast_assert_013.phpt ├── fast_assert_014.phpt ├── fast_assert_032.phpt ├── fast_assert_004.phpt ├── fast_assert_012.phpt ├── fast_assert_017.phpt ├── fast_assert_020.phpt ├── fast_assert_027.phpt ├── fast_assert_018.phpt ├── fast_assert_026.phpt ├── fast_assert_025.phpt ├── fast_assert_028.phpt ├── fast_assert_016.phpt ├── fast_assert_021.phpt ├── fast_assert_023.phpt ├── fast_assert_022.phpt ├── fast_assert_024.phpt ├── fast_assert_007.phpt ├── fast_assert_019.phpt ├── fast_assert_005.phpt ├── fast_assert_030.phpt ├── fast_assert_006.phpt └── fast_assert_029.phpt ├── .gitignore ├── config.m4 ├── php_fast_assert.h ├── README.md ├── CONTRIBUTING.md ├── docs └── stubs │ └── Assert.php ├── LICENSE └── fast_assert.cc /test_helper.php: -------------------------------------------------------------------------------- 1 | getMessage()."\n"; } 8 | ?> 9 | --EXPECT-- 10 | It is forbidden to call Asserts constructor 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile* 2 | ac* 3 | autom4te.cache 4 | build 5 | config.guess 6 | config.h* 7 | config.log 8 | config.nice 9 | config.status 10 | config.sub 11 | configure* 12 | include 13 | install-sh 14 | libtool 15 | ltmain.sh 16 | missing 17 | mkinstalldirs 18 | modules 19 | run-tests.php 20 | safe_array_lookup.l* 21 | vg* 22 | .idea 23 | .libs 24 | .deps 25 | sal_intellij_module 26 | *.iml 27 | *.la 28 | *.lo 29 | TODO 30 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | PHP_ARG_ENABLE(fast_assert, whether to enable fast_assert support, 2 | [ --enable-fast_assert Enable fast_assert support]) 3 | 4 | if test "$PHP_FAST_ASSERT" != "no"; then 5 | PHP_REQUIRE_CXX() 6 | PHP_SUBST(FAST_ASSERT_SHARED_LIBADD) 7 | PHP_ADD_LIBRARY(stdc++, 1, FAST_ASSERT_SHARED_LIBADD) 8 | AC_DEFINE(HAVE_FAST_ASSERT, 1, [Whether you have Fast Assert]) 9 | PHP_NEW_EXTENSION(fast_assert, fast_assert.cc, $ext_shared) 10 | fi -------------------------------------------------------------------------------- /tests/fast_assert_003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert::logic() function - basic test to ensure that Assert::logic works as expected 3 | --FILE-- 4 | is_true(true)->is_true(2==2))); 7 | try { 8 | Assert::logic()->is_true(false); 9 | } 10 | catch (LogicException $e) 11 | { 12 | var_dump($e->getCode()); 13 | echo $e->getMessage()."\n"; 14 | } 15 | ?> 16 | --EXPECT-- 17 | bool(true) 18 | bool(true) 19 | int(0) 20 | The statement (bool) false was not true 21 | -------------------------------------------------------------------------------- /tests/fast_assert_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert::argument() function - basic test to ensure that Assert::argument works as expected 3 | --FILE-- 4 | is_true(true)->is_true(2==2))); 7 | try { 8 | Assert::argument()->is_true(false); 9 | } 10 | catch (InvalidArgumentException $e) 11 | { 12 | var_dump($e->getCode()); 13 | echo $e->getMessage()."\n"; 14 | } 15 | ?> 16 | --EXPECT-- 17 | bool(true) 18 | bool(true) 19 | int(0) 20 | The statement (bool) false was not true 21 | -------------------------------------------------------------------------------- /tests/fast_assert_031.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert with test - assure that Assert::with() works properly 3 | --FILE-- 4 | is_true(false); } 9 | catch (Exception $e) { echo $e->getMessage()."\n"; } 10 | 11 | try { Assert::with('MyNewAwesomeException')->is_true(false); } 12 | catch (MyNewAwesomeException $e) { echo $e->getMessage()."\n"; } 13 | 14 | ?> 15 | --EXPECT-- 16 | The statement (bool) false was not true 17 | The statement (bool) false was not true 18 | -------------------------------------------------------------------------------- /tests/fast_assert_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert::received_value() function - basic test to ensure that Assert::received_value works as expected 3 | --FILE-- 4 | is_true(true)->is_true(2==2))); 7 | try { 8 | Assert::received_value()->is_true(false); 9 | } 10 | catch (UnexpectedValueException $e) 11 | { 12 | var_dump($e->getCode()); 13 | echo $e->getMessage()."\n"; 14 | } 15 | ?> 16 | --EXPECT-- 17 | bool(true) 18 | bool(true) 19 | int(0) 20 | The statement (bool) false was not true 21 | -------------------------------------------------------------------------------- /tests/fast_assert_037.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Basic test of error handling when passing in 0 and 1 args to an Assert method that 3 | takes two 4 | --FILE-- 5 | are_same(1); } 7 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 8 | try { Assert::argument()->are_same(); } 9 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 10 | ?> 11 | --EXPECTREGEX-- 12 | Warning: Assert::are_same\(\) expects at least 2 parameters, 1 given(.*) 13 | The values \(no statement was passed in!\) and \(no statement was passed in!\) are not identical 14 | 15 | Warning: Assert::are_same\(\) expects at least 2 parameters, 0 given(.*) 16 | The values \(no statement was passed in!\) and \(no statement was passed in!\) are not identical 17 | -------------------------------------------------------------------------------- /tests/fast_assert_035.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_empty() function - basic test to ensure that is_empty works as expected 3 | --FILE-- 4 | is_empty($a); } 11 | catch (InvalidArgumentException $e) { echo "Right Value\n"; } 12 | } 13 | else { 14 | Assert::argument()->is_empty($a); 15 | echo "Right Value\n"; 16 | } 17 | } 18 | 19 | test_is_empty(false); 20 | test_is_empty(true); 21 | test_is_empty(0.0); 22 | test_is_empty(0); 23 | test_is_empty(1.1); 24 | test_is_empty(11); 25 | test_is_empty([]); 26 | test_is_empty(['abc']); 27 | test_is_empty(new stdClass()); 28 | test_is_empty(null); 29 | test_is_empty('0.0'); 30 | test_is_empty('0'); 31 | ?> 32 | --EXPECT-- 33 | Right Value 34 | Right Value 35 | Right Value 36 | Right Value 37 | Right Value 38 | Right Value 39 | Right Value 40 | Right Value 41 | Right Value 42 | Right Value 43 | Right Value 44 | Right Value 45 | -------------------------------------------------------------------------------- /php_fast_assert.h: -------------------------------------------------------------------------------- 1 | #ifndef PHP_FAST_ASSERT_H 2 | #define PHP_FAST_ASSERT_H 3 | 4 | #define PHP_FAST_ASSERT_VERSION "0.1.1" 5 | #define PHP_FAST_ASSERT_EXTNAME "fast_assert" 6 | 7 | #ifdef HAVE_CONFIG_H 8 | #include "config.h" 9 | #endif 10 | 11 | extern "C" { 12 | #include "php.h" 13 | } 14 | 15 | typedef struct _fast_assert_globals { 16 | // global object handles pointing to the 3 commonly used assert objects 17 | zend_object_handle invalid_arg_assert_handle; 18 | zend_object_handle unexpected_val_assert_handle; 19 | zend_object_handle logic_exception_assert_handle; 20 | } fast_assert_globals; 21 | 22 | #ifdef ZTS 23 | #define AssertGlobals(v) TSRMG(fa_globals_id, fast_assert_globals *, v) 24 | extern int fa_globals_id; 25 | #else 26 | #define AssertGlobals(v) (fa_globals.v) 27 | extern fast_assert_globals fa_globals; 28 | #endif /* ZTS */ 29 | 30 | extern zend_module_entry fast_assert_module_entry; 31 | #define phpext_fast_assert_ptr &fast_assert_module_entry; 32 | 33 | #endif /* PHP_FAST_ASSERT_H */ 34 | -------------------------------------------------------------------------------- /tests/fast_assert_034.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_not_empty() function - basic test to ensure that is_not_empty works as expected 3 | --FILE-- 4 | is_not_empty($a); } 11 | catch (InvalidArgumentException $e) { echo "Right Value\n"; } 12 | } 13 | else { 14 | Assert::argument()->is_not_empty($a); 15 | echo "Right Value\n"; 16 | } 17 | } 18 | 19 | test_is_not_empty(false); 20 | test_is_not_empty(true); 21 | test_is_not_empty(0.0); 22 | test_is_not_empty(0); 23 | test_is_not_empty(1.1); 24 | test_is_not_empty(11); 25 | test_is_not_empty([]); 26 | test_is_not_empty(['abc']); 27 | test_is_not_empty(new stdClass()); 28 | test_is_not_empty(null); 29 | test_is_not_empty('0.0'); 30 | test_is_not_empty('0'); 31 | ?> 32 | --EXPECT-- 33 | Right Value 34 | Right Value 35 | Right Value 36 | Right Value 37 | Right Value 38 | Right Value 39 | Right Value 40 | Right Value 41 | Right Value 42 | Right Value 43 | Right Value 44 | Right Value 45 | -------------------------------------------------------------------------------- /tests/fast_assert_008.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_false() function - basic test to ensure that is_false works as expected 3 | --FILE-- 4 | is_false(false); }); 7 | will_not_throw(function () { Assert::argument()->is_false(1 == 2); }); 8 | will_not_throw(function () { Assert::argument()->is_false(1 == 2)->is_false(false); }); 9 | 10 | will_throw(function () { Assert::argument()->is_false(0); }); 11 | will_throw(function () { Assert::argument()->is_false(new stdClass()); }); 12 | will_throw(function () { Assert::argument()->is_false(0.0); }); 13 | will_throw(function () { Assert::argument()->is_false(['hello' => 'world']); }); 14 | will_throw(function () { Assert::argument()->is_false(['hello']); }); 15 | will_throw(function () { Assert::argument()->is_false('o'); }); 16 | ?> 17 | --EXPECT-- 18 | No exception thrown 19 | No exception thrown 20 | No exception thrown 21 | Exception thrown 22 | Exception thrown 23 | Exception thrown 24 | Exception thrown 25 | Exception thrown 26 | Exception thrown 27 | -------------------------------------------------------------------------------- /tests/fast_assert_015.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_not_null() function - basic test to ensure that is_not_null works as expected 3 | --FILE-- 4 | is_not_null(false); }); 7 | will_not_throw(function () { Assert::argument()->is_not_null(123456); }); 8 | will_not_throw(function () { Assert::argument()->is_not_null(new stdClass()); }); 9 | will_not_throw(function () { Assert::argument()->is_not_null(0.0); }); 10 | will_not_throw(function () { Assert::argument()->is_not_null(['hello' => 'world']); }); 11 | will_not_throw(function () { Assert::argument()->is_not_null(['hello']); }); 12 | will_not_throw(function () { Assert::argument()->is_not_null('o'); }); 13 | will_not_throw(function () { Assert::argument()->is_not_null(2)->is_not_null('woohoo'); }); 14 | 15 | will_throw(function () { Assert::argument()->is_not_null(null); }); 16 | ?> 17 | --EXPECT-- 18 | No exception thrown 19 | No exception thrown 20 | No exception thrown 21 | No exception thrown 22 | No exception thrown 23 | No exception thrown 24 | No exception thrown 25 | No exception thrown 26 | Exception thrown 27 | -------------------------------------------------------------------------------- /tests/fast_assert_010.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_float() function - basic test to ensure that is_float works as expected 3 | --FILE-- 4 | is_float(0.0); }); 7 | will_not_throw(function () { Assert::argument()->is_float(-1.23); }); 8 | will_not_throw(function () { Assert::argument()->is_float(2.1)->is_float(0.0); }); 9 | 10 | will_throw(function () { Assert::argument()->is_float(false); }); 11 | will_throw(function () { Assert::argument()->is_float(null); }); 12 | will_throw(function () { Assert::argument()->is_float(new stdClass()); }); 13 | will_throw(function () { Assert::argument()->is_float(0); }); 14 | will_throw(function () { Assert::argument()->is_float(['hello' => 'world']); }); 15 | will_throw(function () { Assert::argument()->is_float(['hello']); }); 16 | will_throw(function () { Assert::argument()->is_float('o'); }); 17 | ?> 18 | --EXPECT-- 19 | No exception thrown 20 | No exception thrown 21 | No exception thrown 22 | Exception thrown 23 | Exception thrown 24 | Exception thrown 25 | Exception thrown 26 | Exception thrown 27 | Exception thrown 28 | Exception thrown 29 | -------------------------------------------------------------------------------- /tests/fast_assert_033.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_in_array() function - basic test to ensure that is_in_array works as expected 3 | --FILE-- 4 | is_in_array(['a','b','c'], 'd'); }); 8 | will_throw(function () { Assert::argument()->is_in_array([0 => 'a',1 => 'b', 2 =>'c'], []); }); 9 | will_throw(function () { Assert::argument()->is_in_array('notanarraylol', 'a'); }); 10 | will_throw(function () { Assert::argument()->is_in_array([], 'b'); }); 11 | 12 | will_not_throw(function () { Assert::argument()->is_in_array([0 => 'a',1 => 'b', 3 =>'c'], 'a'); }); 13 | will_not_throw(function () { Assert::argument()->is_in_array(['a','b','c'], 'a'); }); 14 | will_not_throw(function () { Assert::argument()->is_in_array([0 => 'a', 'b' => ['c']], ['c']); }); 15 | will_not_throw(function () { Assert::argument()->is_in_array([0 => 'a'], 'a')->is_in_array(['hello' => 'world'], 'world'); }); 16 | ?> 17 | --EXPECT-- 18 | Exception thrown 19 | Exception thrown 20 | Exception thrown 21 | Exception thrown 22 | No exception thrown 23 | No exception thrown 24 | No exception thrown 25 | No exception thrown 26 | -------------------------------------------------------------------------------- /tests/fast_assert_011.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_array() function - basic test to ensure that is_array works as expected 3 | --FILE-- 4 | is_array(['hello' => 'world']); }); 7 | will_not_throw(function () { Assert::argument()->is_array(['hello']); }); 8 | will_not_throw(function () { Assert::argument()->is_array([])->is_array(['asdf', 'fdsa']); }); 9 | 10 | will_throw(function () { Assert::argument()->is_array(false); }); 11 | will_throw(function () { Assert::argument()->is_array(null); }); 12 | will_throw(function () { Assert::argument()->is_array(new stdClass()); }); 13 | will_throw(function () { Assert::argument()->is_array(0.0); }); 14 | will_throw(function () { Assert::argument()->is_array(123); }); 15 | will_throw(function () { Assert::argument()->is_array(true); }); 16 | will_throw(function () { Assert::argument()->is_array('o'); }); 17 | ?> 18 | --EXPECT-- 19 | No exception thrown 20 | No exception thrown 21 | No exception thrown 22 | Exception thrown 23 | Exception thrown 24 | Exception thrown 25 | Exception thrown 26 | Exception thrown 27 | Exception thrown 28 | Exception thrown 29 | -------------------------------------------------------------------------------- /tests/fast_assert_009.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_integer() function - basic test to ensure that is_integer works as expected 3 | --FILE-- 4 | is_integer(0); }); 7 | will_not_throw(function () { Assert::argument()->is_integer(1); }); 8 | will_not_throw(function () { Assert::argument()->is_integer(2)->is_integer(0); }); 9 | 10 | will_throw(function () { Assert::argument()->is_integer(false); }); 11 | will_throw(function () { Assert::argument()->is_integer(null); }); 12 | will_throw(function () { Assert::argument()->is_integer(new stdClass()); }); 13 | will_throw(function () { Assert::argument()->is_integer(0.0); }); 14 | will_throw(function () { Assert::argument()->is_integer(['hello' => 'world']); }); 15 | will_throw(function () { Assert::argument()->is_integer(['hello']); }); 16 | will_throw(function () { Assert::argument()->is_integer('o'); }); 17 | ?> 18 | --EXPECT-- 19 | No exception thrown 20 | No exception thrown 21 | No exception thrown 22 | Exception thrown 23 | Exception thrown 24 | Exception thrown 25 | Exception thrown 26 | Exception thrown 27 | Exception thrown 28 | Exception thrown 29 | -------------------------------------------------------------------------------- /tests/fast_assert_013.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_string() function - basic test to ensure that is_string works as expected 3 | --FILE-- 4 | is_string('abc'); }); 7 | will_not_throw(function () { Assert::argument()->is_string("123"); }); 8 | will_not_throw(function () { Assert::argument()->is_string('baby')->is_string("you and me!"); }); 9 | 10 | will_throw(function () { Assert::argument()->is_string(false); }); 11 | will_throw(function () { Assert::argument()->is_string(null); }); 12 | will_throw(function () { Assert::argument()->is_string(new stdClass()); }); 13 | will_throw(function () { Assert::argument()->is_string(0.0); }); 14 | will_throw(function () { Assert::argument()->is_string(['hello' => 'world']); }); 15 | will_throw(function () { Assert::argument()->is_string(['hello']); }); 16 | will_throw(function () { Assert::argument()->is_string(42); }); 17 | ?> 18 | --EXPECT-- 19 | No exception thrown 20 | No exception thrown 21 | No exception thrown 22 | Exception thrown 23 | Exception thrown 24 | Exception thrown 25 | Exception thrown 26 | Exception thrown 27 | Exception thrown 28 | Exception thrown 29 | -------------------------------------------------------------------------------- /tests/fast_assert_014.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_boolean() function - basic test to ensure that is_boolean works as expected 3 | --FILE-- 4 | is_boolean(true); }); 7 | will_not_throw(function () { Assert::argument()->is_boolean(false); }); 8 | will_not_throw(function () { Assert::argument()->is_boolean(true)->is_boolean(false); }); 9 | 10 | will_throw(function () { Assert::argument()->is_boolean(42); }); 11 | will_throw(function () { Assert::argument()->is_boolean(null); }); 12 | will_throw(function () { Assert::argument()->is_boolean(new stdClass()); }); 13 | will_throw(function () { Assert::argument()->is_boolean(0.0); }); 14 | will_throw(function () { Assert::argument()->is_boolean(['hello' => 'world']); }); 15 | will_throw(function () { Assert::argument()->is_boolean(['hello']); }); 16 | will_throw(function () { Assert::argument()->is_boolean('o'); }); 17 | ?> 18 | --EXPECT-- 19 | No exception thrown 20 | No exception thrown 21 | No exception thrown 22 | Exception thrown 23 | Exception thrown 24 | Exception thrown 25 | Exception thrown 26 | Exception thrown 27 | Exception thrown 28 | Exception thrown 29 | -------------------------------------------------------------------------------- /tests/fast_assert_032.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_associative_array() function - basic test to ensure that is_associative_array works as expected 3 | --FILE-- 4 | is_associative_array(['a','b','c']); }); 8 | will_throw(function () { Assert::argument()->is_associative_array([0 => 'a',1 => 'b', 2 =>'c']); }); 9 | will_throw(function () { Assert::argument()->is_associative_array('notanarraylol'); }); 10 | will_throw(function () { Assert::argument()->is_associative_array([]); }); 11 | 12 | will_not_throw(function () { Assert::argument()->is_associative_array([0 => 'a',1 => 'b', 3 =>'c']); }); 13 | will_not_throw(function () { Assert::argument()->is_associative_array([1 => 'a',2 => 'b', 0 =>'c']); }); 14 | will_not_throw(function () { Assert::argument()->is_associative_array([0 => 'a', 'b' => 'c']); }); 15 | will_not_throw(function () { Assert::argument()->is_associative_array([0 => 'a', 'b' => 'c'])->is_associative_array(['hello' => 'world']); }); 16 | ?> 17 | --EXPECT-- 18 | Exception thrown 19 | Exception thrown 20 | Exception thrown 21 | Exception thrown 22 | No exception thrown 23 | No exception thrown 24 | No exception thrown 25 | No exception thrown 26 | -------------------------------------------------------------------------------- /tests/fast_assert_004.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_true() function - basic test to ensure that is_true works as expected 3 | --FILE-- 4 | is_true(true); }); 7 | will_not_throw(function () { Assert::argument()->is_true(1 == 1); }); 8 | will_not_throw(function () { Assert::argument()->is_true(1 == 1)->is_true(true); }); 9 | will_throw(function () { Assert::argument()->is_true(false); }); 10 | will_throw(function () { Assert::argument()->is_true(false)->is_true(true); }); 11 | will_throw(function () { Assert::argument()->is_true(1); }); 12 | will_throw(function () { Assert::argument()->is_true(new stdClass()); }); 13 | will_throw(function () { Assert::argument()->is_true(3.14159); }); 14 | will_throw(function () { Assert::argument()->is_true(['hello' => 'world']); }); 15 | will_throw(function () { Assert::argument()->is_true(['hello', 'world']); }); 16 | will_throw(function () { Assert::argument()->is_true(null); }); 17 | ?> 18 | --EXPECT-- 19 | No exception thrown 20 | No exception thrown 21 | No exception thrown 22 | Exception thrown 23 | Exception thrown 24 | Exception thrown 25 | Exception thrown 26 | Exception thrown 27 | Exception thrown 28 | Exception thrown 29 | Exception thrown 30 | -------------------------------------------------------------------------------- /tests/fast_assert_012.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_object() function - basic test to ensure that is_object works as expected 3 | --FILE-- 4 | is_object(new stdClass()); }); 10 | will_not_throw(function () { Assert::argument()->is_object(new FakeClass()); }); 11 | will_not_throw(function () { Assert::argument()->is_object(new stdClass())->is_object(new FakeClass()); }); 12 | 13 | will_throw(function () { Assert::argument()->is_object(false); }); 14 | will_throw(function () { Assert::argument()->is_object(null); }); 15 | will_throw(function () { Assert::argument()->is_object(42); }); 16 | will_throw(function () { Assert::argument()->is_object(0.0); }); 17 | will_throw(function () { Assert::argument()->is_object(['hello' => 'world']); }); 18 | will_throw(function () { Assert::argument()->is_object(['hello']); }); 19 | will_throw(function () { Assert::argument()->is_object('o'); }); 20 | ?> 21 | --EXPECT-- 22 | No exception thrown 23 | No exception thrown 24 | No exception thrown 25 | Exception thrown 26 | Exception thrown 27 | Exception thrown 28 | Exception thrown 29 | Exception thrown 30 | Exception thrown 31 | Exception thrown 32 | -------------------------------------------------------------------------------- /tests/fast_assert_017.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_numeric() function - basic test to ensure that is_numeric works as expected 3 | --FILE-- 4 | is_numeric(123456); }); 7 | will_not_throw(function () { Assert::argument()->is_numeric(0.0); }); 8 | will_not_throw(function () { Assert::argument()->is_numeric("3.14159"); }); 9 | will_not_throw(function () { Assert::argument()->is_numeric('-14159'); }); 10 | will_not_throw(function () { Assert::argument()->is_numeric(2)->is_numeric('123'); }); 11 | 12 | will_throw(function () { Assert::argument()->is_numeric(null); }); 13 | will_throw(function () { Assert::argument()->is_numeric(false); }); 14 | will_throw(function () { Assert::argument()->is_numeric(new stdClass()); }); 15 | will_throw(function () { Assert::argument()->is_numeric(['hello' => 'world']); }); 16 | will_throw(function () { Assert::argument()->is_numeric(['hello']); }); 17 | will_throw(function () { Assert::argument()->is_numeric('o'); }); 18 | ?> 19 | --EXPECT-- 20 | No exception thrown 21 | No exception thrown 22 | No exception thrown 23 | No exception thrown 24 | No exception thrown 25 | Exception thrown 26 | Exception thrown 27 | Exception thrown 28 | Exception thrown 29 | Exception thrown 30 | Exception thrown 31 | -------------------------------------------------------------------------------- /tests/fast_assert_020.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_scalar() function - basic test to ensure that is_scalar works as expected 3 | --FILE-- 4 | is_scalar(123456); }); 7 | will_not_throw(function () { Assert::argument()->is_scalar(0.0); }); 8 | will_not_throw(function () { Assert::argument()->is_scalar("3.14159"); }); 9 | will_not_throw(function () { Assert::argument()->is_scalar('-14159'); }); 10 | will_not_throw(function () { Assert::argument()->is_scalar(2)->is_scalar('123'); }); 11 | will_not_throw(function () { Assert::argument()->is_scalar(false); }); 12 | will_not_throw(function () { Assert::argument()->is_scalar('o'); }); 13 | 14 | will_throw(function () { Assert::argument()->is_scalar(new stdClass()); }); 15 | will_throw(function () { Assert::argument()->is_scalar(['hello' => 'world']); }); 16 | will_throw(function () { Assert::argument()->is_scalar(['hello']); }); 17 | will_throw(function () { Assert::argument()->is_scalar(null); }); 18 | ?> 19 | --EXPECT-- 20 | No exception thrown 21 | No exception thrown 22 | No exception thrown 23 | No exception thrown 24 | No exception thrown 25 | No exception thrown 26 | No exception thrown 27 | Exception thrown 28 | Exception thrown 29 | Exception thrown 30 | Exception thrown 31 | -------------------------------------------------------------------------------- /tests/fast_assert_027.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_classname() function - basic test to ensure that is_classname works as expected 3 | --FILE-- 4 | is_classname('A'); }); 30 | will_not_throw(function () { Assert::argument()->is_classname('B'); }); 31 | will_not_throw(function () { Assert::argument()->is_classname('I'); }); 32 | will_not_throw(function () { Assert::argument()->is_classname('D'); }); 33 | will_not_throw(function () { Assert::argument()->is_classname('Z'); }); 34 | 35 | will_throw(function () { Assert::argument()->is_classname(null); }); 36 | will_throw(function () { Assert::argument()->is_classname('fake123'); }); 37 | will_throw(function () { Assert::argument()->is_classname('T'); }); 38 | ?> 39 | --EXPECT-- 40 | No exception thrown 41 | No exception thrown 42 | No exception thrown 43 | No exception thrown 44 | No exception thrown 45 | Exception thrown 46 | Exception thrown 47 | Exception thrown 48 | -------------------------------------------------------------------------------- /tests/fast_assert_018.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_not_numeric() function - basic test to ensure that is_not_numeric works as expected 3 | --FILE-- 4 | is_not_numeric(123456); }); 7 | will_throw(function () { Assert::argument()->is_not_numeric(0.0); }); 8 | will_throw(function () { Assert::argument()->is_not_numeric("3.14159"); }); 9 | will_throw(function () { Assert::argument()->is_not_numeric('-14159'); }); 10 | will_throw(function () { Assert::argument()->is_not_numeric(2)->is_not_numeric('123'); }); 11 | 12 | will_not_throw(function () { Assert::argument()->is_not_numeric(null); }); 13 | will_not_throw(function () { Assert::argument()->is_not_numeric(false); }); 14 | will_not_throw(function () { Assert::argument()->is_not_numeric(new stdClass()); }); 15 | will_not_throw(function () { Assert::argument()->is_not_numeric(['hello' => 'world']); }); 16 | will_not_throw(function () { Assert::argument()->is_not_numeric(['hello']); }); 17 | will_not_throw(function () { Assert::argument()->is_not_numeric('o'); }); 18 | will_not_throw(function () { Assert::argument()->is_not_numeric(null)->is_not_numeric(false); }); 19 | ?> 20 | --EXPECT-- 21 | Exception thrown 22 | Exception thrown 23 | Exception thrown 24 | Exception thrown 25 | Exception thrown 26 | No exception thrown 27 | No exception thrown 28 | No exception thrown 29 | No exception thrown 30 | No exception thrown 31 | No exception thrown 32 | No exception thrown 33 | -------------------------------------------------------------------------------- /tests/fast_assert_026.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_instance_of() function - basic test to ensure that is_instance_of works as expected 3 | --FILE-- 4 | is_instance_of($a, 'A'); }); 24 | will_not_throw(function () use ($b) { Assert::argument()->is_instance_of($b, 'B'); }); 25 | will_not_throw(function () use ($b) { Assert::argument()->is_instance_of($b, 'I'); }); 26 | will_not_throw(function () use ($c) { Assert::argument()->is_instance_of($c, 'I'); }); 27 | will_not_throw(function () use ($c) { Assert::argument()->is_instance_of($c, 'B'); }); 28 | 29 | will_throw(function () { Assert::argument()->is_instance_of(null, null); }); 30 | will_throw(function () use ($a) { Assert::argument()->is_instance_of($a, 'fake123'); }); 31 | will_throw(function () use ($a) { Assert::argument()->is_instance_of($a, 'B'); }); 32 | will_throw(function () use ($a) { Assert::argument()->is_instance_of($a, 'I'); }); 33 | ?> 34 | --EXPECT-- 35 | No exception thrown 36 | No exception thrown 37 | No exception thrown 38 | No exception thrown 39 | No exception thrown 40 | Exception thrown 41 | Exception thrown 42 | Exception thrown 43 | Exception thrown 44 | -------------------------------------------------------------------------------- /tests/fast_assert_025.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_callable() function - basic test to ensure that is_callable works as expected 3 | --FILE-- 4 | is_callable(123456); }); 7 | will_throw(function () { Assert::argument()->is_callable(0.0); }); 8 | will_throw(function () { Assert::argument()->is_callable("3.14159"); }); 9 | will_throw(function () { Assert::argument()->is_callable('-14159'); }); 10 | will_throw(function () { Assert::argument()->is_callable(null); }); 11 | will_throw(function () { Assert::argument()->is_callable(false); }); 12 | will_throw(function () { Assert::argument()->is_callable(new stdClass()); }); 13 | will_throw(function () { Assert::argument()->is_callable(['hello' => 'world']); }); 14 | will_throw(function () { Assert::argument()->is_callable(['hello']); }); 15 | will_throw(function () { Assert::argument()->is_callable('o'); }); 16 | 17 | $a = function () { $b = 1; }; 18 | will_not_throw(function () { Assert::argument()->is_callable(function () {}); }); 19 | will_not_throw(function () use ($a) { Assert::argument()->is_callable($a); }); 20 | will_not_throw(function () use ($a) { Assert::argument()->is_callable($a)->is_callable(function () {}); }); 21 | ?> 22 | --EXPECT-- 23 | Exception thrown 24 | Exception thrown 25 | Exception thrown 26 | Exception thrown 27 | Exception thrown 28 | Exception thrown 29 | Exception thrown 30 | Exception thrown 31 | Exception thrown 32 | Exception thrown 33 | No exception thrown 34 | No exception thrown 35 | No exception thrown 36 | -------------------------------------------------------------------------------- /tests/fast_assert_028.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->uses_trait() function - basic test to ensure that uses_trait works as expected 3 | --FILE-- 4 | uses_trait($a, 'T'); }); 33 | will_not_throw(function () use ($b) { Assert::argument()->uses_trait($b, 'T'); }); 34 | //will_not_throw(function () use ($c) { Assert::argument()->uses_trait($c, 'T'); }); 35 | will_not_throw(function () use ($c) { Assert::argument()->uses_trait($c, 'S')->uses_trait($c, 'S'); }); 36 | 37 | will_throw(function () { Assert::argument()->uses_trait(null, null); }); 38 | will_throw(function () use ($a) { Assert::argument()->uses_trait($a, 'fake123'); }); 39 | will_throw(function () use ($a) { Assert::argument()->uses_trait($a, 'S'); }); 40 | will_throw(function () use ($b) { Assert::argument()->uses_trait($b, 'S'); }); 41 | will_throw(function () use ($c) { Assert::argument()->uses_trait($c, 'T'); }); 42 | ?> 43 | --EXPECT-- 44 | No exception thrown 45 | No exception thrown 46 | No exception thrown 47 | Exception thrown 48 | Exception thrown 49 | Exception thrown 50 | Exception thrown 51 | Exception thrown 52 | -------------------------------------------------------------------------------- /tests/fast_assert_016.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_key_in_array() function - basic test to ensure that is_key_in_array works as expected 3 | --FILE-- 4 | 'world', 'goodnight' => 'moon', 1234 => 321]; 9 | public $test_arr = [1, 2, 3, 4, 5]; 10 | public function runtests() { 11 | will_not_throw(function () { Assert::argument()->is_key_in_array('hello', $this->test_aarr); }); 12 | will_not_throw(function () { Assert::argument()->is_key_in_array("goodnight", $this->test_aarr); }); 13 | will_not_throw(function () { Assert::argument()->is_key_in_array(1234, $this->test_aarr); }); 14 | will_not_throw(function () { Assert::argument()->is_key_in_array(0, $this->test_arr); }); 15 | will_not_throw(function () { Assert::argument()->is_key_in_array(4, $this->test_arr); }); 16 | 17 | will_throw(function () { Assert::argument()->is_key_in_array(5, $this->test_arr); }); 18 | will_throw(function () { Assert::argument()->is_key_in_array(2.4, $this->test_aarr); }); 19 | will_throw(function () { Assert::argument()->is_key_in_array(null, $this->test_aarr); }); 20 | will_throw(function () { Assert::argument()->is_key_in_array('asdf', $this->test_aarr); }); 21 | will_throw(function () { Assert::argument()->is_key_in_array('asdf', 'notanarray'); }); 22 | } 23 | } 24 | $tester = new TC(); 25 | $tester->runtests(); 26 | ?> 27 | --EXPECT-- 28 | No exception thrown 29 | No exception thrown 30 | No exception thrown 31 | No exception thrown 32 | No exception thrown 33 | Exception thrown 34 | Exception thrown 35 | Exception thrown 36 | Exception thrown 37 | Exception thrown 38 | -------------------------------------------------------------------------------- /tests/fast_assert_021.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->are_same() function - basic test to ensure that are_same works as expected 3 | --FILE-- 4 | are_same(123456, 123456); }); 7 | will_not_throw(function () { Assert::argument()->are_same(0.0, 0.0); }); 8 | will_not_throw(function () { Assert::argument()->are_same("3.14159", "3.14159"); }); 9 | will_not_throw(function () { Assert::argument()->are_same(2, 2)->are_same('123', '123'); }); 10 | will_not_throw(function () { Assert::argument()->are_same(false, false); }); 11 | will_not_throw(function () { Assert::argument()->are_same(['hello' => 123], ['hello' => 123]); }); 12 | $a = new stdClass(); 13 | will_not_throw(function () use ($a) { Assert::argument()->are_same($a, $a); }); 14 | will_not_throw(function () { Assert::argument()->are_same(null, null); }); 15 | 16 | will_throw(function () use ($a) { Assert::argument()->are_same(new stdClass(), $a); }); 17 | will_throw(function () { Assert::argument()->are_same(['hello' => 'world'], ['hello' => 123]); }); 18 | will_throw(function () { Assert::argument()->are_same(['hello'], 'hello'); }); 19 | will_throw(function () { Assert::argument()->are_same(123456, '123456'); }); 20 | will_throw(function () { Assert::argument()->are_same(0.0, 0.1); }); 21 | will_throw(function () { Assert::argument()->are_same(3.14159, "3.14159"); }); 22 | ?> 23 | --EXPECT-- 24 | No exception thrown 25 | No exception thrown 26 | No exception thrown 27 | No exception thrown 28 | No exception thrown 29 | No exception thrown 30 | No exception thrown 31 | No exception thrown 32 | Exception thrown 33 | Exception thrown 34 | Exception thrown 35 | Exception thrown 36 | Exception thrown 37 | Exception thrown 38 | -------------------------------------------------------------------------------- /tests/fast_assert_023.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->are_equal() function - basic test to ensure that are_equal works as expected 3 | --FILE-- 4 | are_equal(123456, '123456'); }); 7 | will_not_throw(function () { Assert::argument()->are_equal(0.0, "0.0"); }); 8 | will_not_throw(function () { Assert::argument()->are_equal("3.14159", "3.14159"); }); 9 | will_not_throw(function () { Assert::argument()->are_equal(2, '2')->are_equal('123', '123'); }); 10 | will_not_throw(function () { Assert::argument()->are_equal(false, false); }); 11 | will_not_throw(function () { Assert::argument()->are_equal(['hello' => 123], ['hello' => 123]); }); 12 | $a = new stdClass(); 13 | will_not_throw(function () use ($a) { Assert::argument()->are_equal($a, $a); }); 14 | will_not_throw(function () { Assert::argument()->are_equal(null, null); }); 15 | will_not_throw(function () use ($a) { Assert::argument()->are_equal(new stdClass(), $a); }); 16 | 17 | will_throw(function () { Assert::argument()->are_equal(['hello' => 'world'], ['hello' => 123]); }); 18 | will_throw(function () { Assert::argument()->are_equal(['hello'], 'hello'); }); 19 | will_throw(function () { Assert::argument()->are_equal(123456, 1234567); }); 20 | will_throw(function () { Assert::argument()->are_equal(0.0, 0.1); }); 21 | will_throw(function () { Assert::argument()->are_equal(3.14159, "3.1124"); }); 22 | ?> 23 | --EXPECT-- 24 | No exception thrown 25 | No exception thrown 26 | No exception thrown 27 | No exception thrown 28 | No exception thrown 29 | No exception thrown 30 | No exception thrown 31 | No exception thrown 32 | No exception thrown 33 | Exception thrown 34 | Exception thrown 35 | Exception thrown 36 | Exception thrown 37 | Exception thrown 38 | -------------------------------------------------------------------------------- /tests/fast_assert_022.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->are_not_same() function - basic test to ensure that are_not_same works as expected 3 | --FILE-- 4 | are_not_same(123456, 123456); }); 7 | will_throw(function () { Assert::argument()->are_not_same(0.0, 0.0); }); 8 | will_throw(function () { Assert::argument()->are_not_same("3.14159", "3.14159"); }); 9 | will_throw(function () { Assert::argument()->are_not_same(2, 2)->are_not_same('123', '123'); }); 10 | will_throw(function () { Assert::argument()->are_not_same(false, false); }); 11 | will_throw(function () { Assert::argument()->are_not_same(['hello' => 123], ['hello' => 123]); }); 12 | $a = new stdClass(); 13 | will_throw(function () use ($a) { Assert::argument()->are_not_same($a, $a); }); 14 | will_throw(function () { Assert::argument()->are_not_same(null, null); }); 15 | 16 | will_not_throw(function () use ($a) { Assert::argument()->are_not_same(new stdClass(), $a); }); 17 | will_not_throw(function () { Assert::argument()->are_not_same(['hello' => 'world'], ['hello' => 123]); }); 18 | will_not_throw(function () { Assert::argument()->are_not_same(['hello'], 'hello'); }); 19 | will_not_throw(function () { Assert::argument()->are_not_same(123456, '123456'); }); 20 | will_not_throw(function () { Assert::argument()->are_not_same(0.0, 0.1); }); 21 | will_not_throw(function () { Assert::argument()->are_not_same(3.14159, "3.14159"); }); 22 | ?> 23 | --EXPECT-- 24 | Exception thrown 25 | Exception thrown 26 | Exception thrown 27 | Exception thrown 28 | Exception thrown 29 | Exception thrown 30 | Exception thrown 31 | Exception thrown 32 | No exception thrown 33 | No exception thrown 34 | No exception thrown 35 | No exception thrown 36 | No exception thrown 37 | No exception thrown 38 | -------------------------------------------------------------------------------- /tests/fast_assert_024.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->are_not_equal() function - basic test to ensure that are_not_equal works as expected 3 | --FILE-- 4 | are_not_equal(123456, '123456'); }); 7 | will_throw(function () { Assert::argument()->are_not_equal(0.0, "0.0"); }); 8 | will_throw(function () { Assert::argument()->are_not_equal("3.14159", "3.14159"); }); 9 | will_throw(function () { Assert::argument()->are_not_equal(2, '2')->are_not_equal('123', '123'); }); 10 | will_throw(function () { Assert::argument()->are_not_equal(false, false); }); 11 | will_throw(function () { Assert::argument()->are_not_equal(['hello' => 123], ['hello' => 123]); }); 12 | $a = new stdClass(); 13 | will_throw(function () use ($a) { Assert::argument()->are_not_equal($a, $a); }); 14 | will_throw(function () { Assert::argument()->are_not_equal(null, null); }); 15 | will_throw(function () use ($a) { Assert::argument()->are_not_equal(new stdClass(), $a); }); 16 | 17 | will_not_throw(function () { Assert::argument()->are_not_equal(['hello' => 'world'], ['hello' => 123]); }); 18 | will_not_throw(function () { Assert::argument()->are_not_equal(['hello'], 'hello'); }); 19 | will_not_throw(function () { Assert::argument()->are_not_equal(123456, 1234567); }); 20 | will_not_throw(function () { Assert::argument()->are_not_equal(0.0, 0.1); }); 21 | will_not_throw(function () { Assert::argument()->are_not_equal(3.14159, "3.1124"); }); 22 | ?> 23 | --EXPECT-- 24 | Exception thrown 25 | Exception thrown 26 | Exception thrown 27 | Exception thrown 28 | Exception thrown 29 | Exception thrown 30 | Exception thrown 31 | Exception thrown 32 | Exception thrown 33 | No exception thrown 34 | No exception thrown 35 | No exception thrown 36 | No exception thrown 37 | No exception thrown 38 | -------------------------------------------------------------------------------- /tests/fast_assert_007.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert error message test - assure that different objects generate appropriate error messages 3 | --FILE-- 4 | is_true(false); } 6 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 7 | 8 | try { Assert::argument()->is_true(null); } 9 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 10 | 11 | try { Assert::argument()->is_true(1234); } 12 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 13 | 14 | try { Assert::argument()->is_true(3.141592); } 15 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 16 | 17 | try { Assert::argument()->is_true("hello world"); } 18 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 19 | 20 | try { Assert::argument()->is_true(['hello']); } 21 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 22 | 23 | try { Assert::argument()->is_true(['hello' => 'world']); } 24 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 25 | 26 | try { Assert::argument()->is_true(new stdClass()); } 27 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 28 | 29 | try { Assert::argument()->is_true(); } 30 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 31 | 32 | ?> 33 | --EXPECTREGEX-- 34 | The statement \(bool\) false was not true 35 | The statement null was not true 36 | The statement \(int\) 1234 was not true 37 | The statement \(float\) 3.141592 was not true 38 | The statement \(string\) hello world was not true 39 | The statement Array was not true 40 | The statement Array was not true 41 | The statement Object was not true 42 | 43 | Warning: Assert::is_true\(\) expects at least 1 parameter, 0 given(.*) 44 | The statement \(no statement was passed in!\) was not true 45 | -------------------------------------------------------------------------------- /tests/fast_assert_019.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_integery() function - basic test to ensure that is_integery works as expected 3 | --FILE-- 4 | is_integery(123456); }); 7 | will_not_throw(function () { Assert::argument()->is_integery(0.0); }); 8 | will_not_throw(function () { Assert::argument()->is_integery(123532.0); }); 9 | will_not_throw(function () { Assert::argument()->is_integery('-14159'); }); 10 | will_not_throw(function () { Assert::argument()->is_integery(2)->is_integery('123'); }); 11 | will_not_throw(function () { Assert::argument()->is_integery('-14.0'); }); 12 | 13 | will_throw(function () { Assert::argument()->is_integery("3.14159"); }); 14 | will_throw(function () { Assert::argument()->is_integery(3.14159); }); 15 | will_throw(function () { Assert::argument()->is_integery('-14.1'); }); 16 | will_throw(function () { Assert::argument()->is_integery(null); }); 17 | will_throw(function () { Assert::argument()->is_integery(false); }); 18 | will_throw(function () { Assert::argument()->is_integery(new stdClass()); }); 19 | will_throw(function () { Assert::argument()->is_integery(['hello' => 'world']); }); 20 | will_throw(function () { Assert::argument()->is_integery(['hello']); }); 21 | will_throw(function () { Assert::argument()->is_integery('o'); }); 22 | will_throw(function () { Assert::argument()->is_integery('1e6'); }); 23 | will_throw(function () { Assert::argument()->is_integery('1e0'); }); 24 | ?> 25 | --EXPECT-- 26 | No exception thrown 27 | No exception thrown 28 | No exception thrown 29 | No exception thrown 30 | No exception thrown 31 | No exception thrown 32 | Exception thrown 33 | Exception thrown 34 | Exception thrown 35 | Exception thrown 36 | Exception thrown 37 | Exception thrown 38 | Exception thrown 39 | Exception thrown 40 | Exception thrown 41 | Exception thrown 42 | Exception thrown 43 | -------------------------------------------------------------------------------- /tests/fast_assert_005.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert->is_truthy() function - basic test to ensure that is_truthy works as expected 3 | --FILE-- 4 | is_truthy(true); }); 7 | will_not_throw(function () { Assert::argument()->is_truthy(1 == 1); }); 8 | will_not_throw(function () { Assert::argument()->is_truthy(1 == 1)->is_truthy(true); }); 9 | will_not_throw(function () { Assert::argument()->is_truthy(1); }); 10 | will_not_throw(function () { Assert::argument()->is_truthy(new stdClass()); }); 11 | will_not_throw(function () { Assert::argument()->is_truthy(3.14159); }); 12 | will_not_throw(function () { Assert::argument()->is_truthy(['hello' => 'world']); }); 13 | will_not_throw(function () { Assert::argument()->is_truthy(['hello']); }); 14 | will_not_throw(function () { Assert::argument()->is_truthy('o'); }); 15 | will_not_throw(function () { Assert::argument()->is_truthy('0.0'); }); 16 | will_throw(function () { Assert::argument()->is_truthy(false); }); 17 | will_throw(function () { Assert::argument()->is_truthy(0); }); 18 | will_throw(function () { Assert::argument()->is_truthy(0.0); }); 19 | will_throw(function () { Assert::argument()->is_truthy([]); }); 20 | will_throw(function () { Assert::argument()->is_truthy(false)->is_truthy(true); }); 21 | will_throw(function () { Assert::argument()->is_truthy(null); }); 22 | will_throw(function () { Assert::argument()->is_truthy(''); }); 23 | will_throw(function () { Assert::argument()->is_truthy('0'); }); 24 | ?> 25 | --EXPECT-- 26 | No exception thrown 27 | No exception thrown 28 | No exception thrown 29 | No exception thrown 30 | No exception thrown 31 | No exception thrown 32 | No exception thrown 33 | No exception thrown 34 | No exception thrown 35 | No exception thrown 36 | Exception thrown 37 | Exception thrown 38 | Exception thrown 39 | Exception thrown 40 | Exception thrown 41 | Exception thrown 42 | Exception thrown 43 | Exception thrown 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Fast assert is a php extension that provides a nice way of making Assertions in php. 2 | It provides facilities for making various assertions using clean function-chaining syntax without 3 | having to pay any performance costs. For comparison, a functionally-equivalent version 4 | of Assert implemented in PHP is 150 times slower. 5 | 6 | Examples 7 | -------- 8 | 9 | To assert that a value $a is an integer that is greater than 0: 10 | 11 | ``` 12 | Assert::argument()->is_integer($a)->is_true($a > 0); 13 | ``` 14 | 15 | If either assertion fails, this will throw an InvalidArgumentException. 16 | 17 | To assert that an object is of a particular type: 18 | 19 | ``` 20 | Assert::received_value()->is_instance_of($obj, "MyDesiredClass"); 21 | ``` 22 | 23 | If this assertion fails, this will throw an UnexpectedValueException. 24 | 25 | See the documentation at docs/stubs/Assert.php for a full listing of 26 | Assert's methods. 27 | 28 | Installation 29 | ------------ 30 | 31 | First, you must build the extension with the following commands: 32 | 33 | - `phpize` 34 | - `./configure --enable-fast_assert` 35 | - `make` 36 | - `make test` 37 | 38 | Then, you can install it with: 39 | - `sudo make install` 40 | - Add the line `extension=fast_assert.so` to your php configuration file of choice. Your php.ini file should work, 41 | or you can try something like `echo "extension=fast_assert.so" > /etc/php.d/fast_assert.ini` 42 | 43 | ## Copyright and License 44 | 45 | Copyright 2014 Box, Inc. All rights reserved. 46 | 47 | Licensed under the Apache License, Version 2.0 (the "License"); 48 | you may not use this file except in compliance with the License. 49 | You may obtain a copy of the License at 50 | 51 | http://www.apache.org/licenses/LICENSE-2.0 52 | 53 | Unless required by applicable law or agreed to in writing, software 54 | distributed under the License is distributed on an "AS IS" BASIS, 55 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 56 | See the License for the specific language governing permissions and 57 | limitations under the License. 58 | -------------------------------------------------------------------------------- /tests/fast_assert_030.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert error message test - assure that a long error message (over 512 chars) gets truncated 3 | --FILE-- 4 | is_true(false, $err_msg); } 8 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 9 | 10 | // now do it with a 1200 char long message! this should be truncated at 1023 chars 11 | try { Assert::argument()->is_true(false, $err_msg.$err_msg); } 12 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 13 | 14 | ?> 15 | --EXPECT-- 16 | The statement (bool) false was not true, 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 17 | The statement (bool) false was not true, 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901 18 | 19 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | All contributions are welcome to this project. 4 | 5 | ## Contributor License Agreement 6 | 7 | Before a contribution can be merged into this project, please fill out the Contributor License Agreement (CLA) located at: 8 | 9 | http://box.github.io/cla 10 | 11 | To learn more about CLAs and why they are important to open source projects, please see the [Wikipedia entry](http://en.wikipedia.org/wiki/Contributor_License_Agreement). 12 | 13 | ## How to contribute 14 | 15 | * **File an issue** - if you found a bug, want to request an enhancement, or want to implement something (bug fix or feature). 16 | * **Send a pull request** - if you want to contribute code. Please be sure to file an issue first. 17 | 18 | ## Pull request best practices 19 | 20 | We want to accept your pull requests. Please follow these steps: 21 | 22 | ### Step 1: File an issue 23 | 24 | Before writing any code, please file an issue stating the problem you want to solve or the feature you want to implement. This allows us to give you feedback before you spend any time writing code. There may be a known limitation that can't be addressed, or a bug that has already been fixed in a different way. The issue allows us to communicate and figure out if it's worth your time to write a bunch of code for the project. 25 | 26 | ### Step 2: Fork this repository in GitHub 27 | 28 | This will create your own copy of our repository. 29 | 30 | ### Step 3: Add the upstream source 31 | 32 | The upstream source is the project under the Box organization on GitHub. To add an upstream source for this project, type: 33 | 34 | ``` 35 | git remote add upstream git@github.com:Box/fast_assert.git 36 | ``` 37 | 38 | This will come in useful later. 39 | 40 | ### Step 4: Create a feature branch 41 | 42 | Create a branch with a descriptive name, such as `add-search`. 43 | 44 | ### Step 5: Push your feature branch to your fork 45 | 46 | As you develop code, continue to push code to your remote feature branch. Please make sure to include the issue number you're addressing in your commit message, such as: 47 | 48 | ``` 49 | git commit -m "Adding search (fixes #123)" 50 | ``` 51 | 52 | This helps us out by allowing us to track which issue your commit relates to. 53 | 54 | Keep a separate feature branch for each issue you want to address. 55 | 56 | ### Step 6: Rebase 57 | 58 | Before sending a pull request, rebase against upstream, such as: 59 | 60 | ``` 61 | git fetch upstream 62 | git rebase upstream/master 63 | ``` 64 | 65 | This will add your changes on top of what's already in upstream, minimizing merge issues. 66 | 67 | ### Step 7: Run the tests 68 | 69 | Make sure that all tests are passing before submitting a pull request. 70 | 71 | ### Step 8: Send the pull request 72 | 73 | Send the pull request from your feature branch to us. Be sure to include a description that lets us know what work you did. 74 | 75 | Keep in mind that we like to see one issue addressed per pull request, as this helps keep our git history clean and we can more easily track down issues. 76 | -------------------------------------------------------------------------------- /tests/fast_assert_006.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Assert instance method error messages - ensure each method throws proper string 3 | --FILE-- 4 | is_true(false); } 6 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 7 | 8 | try { Assert::argument()->is_truthy(false); } 9 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 10 | 11 | try { Assert::argument()->is_false(true); } 12 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 13 | 14 | try { Assert::argument()->is_integer(true); } 15 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 16 | 17 | try { Assert::argument()->is_float(true); } 18 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 19 | 20 | try { Assert::argument()->is_array(true); } 21 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 22 | 23 | try { Assert::argument()->is_object(true); } 24 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 25 | 26 | try { Assert::argument()->is_string(true); } 27 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 28 | 29 | try { Assert::argument()->is_boolean(42); } 30 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 31 | 32 | try { Assert::argument()->is_not_null(null); } 33 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 34 | 35 | try { Assert::argument()->is_key_in_array('asdf', ['asdf']); } 36 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 37 | 38 | try { Assert::argument()->is_key_in_array('asdf', 'not-an-array'); } 39 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 40 | 41 | try { Assert::argument()->is_numeric('abc'); } 42 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 43 | 44 | try { Assert::argument()->is_not_numeric('123'); } 45 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 46 | 47 | try { Assert::argument()->is_integery('123.234'); } 48 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 49 | 50 | try { Assert::argument()->is_scalar(null); } 51 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 52 | 53 | try { Assert::argument()->are_same(123, "123"); } 54 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 55 | 56 | try { Assert::argument()->are_not_same(123, 123); } 57 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 58 | 59 | try { Assert::argument()->are_equal(123, "1234"); } 60 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 61 | 62 | try { Assert::argument()->are_not_equal(123, '123'); } 63 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 64 | 65 | try { Assert::argument()->is_callable(123); } 66 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 67 | 68 | try { Assert::argument()->is_instance_of(new stdClass(), 123); } 69 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 70 | 71 | try { Assert::argument()->is_classname('fakeclass'); } 72 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 73 | 74 | try { Assert::argument()->uses_trait(new stdClass(), 123); } 75 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 76 | 77 | try { Assert::argument()->is_associative_array([1,2,3]); } 78 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 79 | 80 | try { Assert::argument()->is_in_array([1,2,3], 4); } 81 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 82 | 83 | try { Assert::argument()->is_empty([1,2,3]); } 84 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 85 | 86 | try { Assert::argument()->is_not_empty(null); } 87 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 88 | ?> 89 | --EXPECT-- 90 | The statement (bool) false was not true 91 | The statement (bool) false was not truthy 92 | The statement (bool) true was not false 93 | The value (bool) true is not an integer 94 | The value (bool) true is not a float 95 | The value (bool) true is not an array 96 | The value (bool) true is not an object 97 | The value (bool) true is not a string 98 | The value (int) 42 is not a boolean 99 | The given value should not have been null 100 | The key (string) asdf was not in Array 101 | Argument 2 passed to is_key_in_array is (string) not-an-array, not an array 102 | The value (string) abc is not numeric 103 | The value (string) 123 is numeric 104 | The value (string) 123.234 does not represent an integer 105 | The value null is not a scalar 106 | The values (int) 123 and (string) 123 are not identical 107 | The values (int) 123 and (int) 123 are identical 108 | The values (int) 123 and (string) 1234 are not equal 109 | The values (int) 123 and (string) 123 are equal 110 | The value (int) 123 is not callable 111 | The value Object is not an instance of (int) 123 112 | The value (string) fakeclass is not a class name 113 | The value Object does not use the trait (int) 123 114 | The value Array is not an associative array 115 | The value (int) 4 is not in the array Array 116 | The value Array is not empty 117 | The value null is empty 118 | -------------------------------------------------------------------------------- /tests/fast_assert_029.phpt: -------------------------------------------------------------------------------- 1 | --TEST--, error message horray!@# 2 | Assert error message test - assure that assert properly appends optional error messages to exception messages 3 | --FILE-- 4 | is_true(false, "error message horray!@#"); } 6 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 7 | 8 | try { Assert::argument()->is_truthy(false, "error message horray!@#"); } 9 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 10 | 11 | try { Assert::argument()->is_false(true, "error message horray!@#"); } 12 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 13 | 14 | try { Assert::argument()->is_integer(true, "error message horray!@#"); } 15 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 16 | 17 | try { Assert::argument()->is_float(true, "error message horray!@#"); } 18 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 19 | 20 | try { Assert::argument()->is_array(true, "error message horray!@#"); } 21 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 22 | 23 | try { Assert::argument()->is_object(true, "error message horray!@#"); } 24 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 25 | 26 | try { Assert::argument()->is_string(true, "error message horray!@#"); } 27 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 28 | 29 | try { Assert::argument()->is_boolean(42, "error message horray!@#"); } 30 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 31 | 32 | try { Assert::argument()->is_not_null(null, "error message horray!@#"); } 33 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 34 | 35 | try { Assert::argument()->is_key_in_array('asdf', ['asdf'], "error message horray!@#"); } 36 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 37 | 38 | try { Assert::argument()->is_key_in_array('asdf', 'not-an-array', "error message horray!@#"); } 39 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 40 | 41 | try { Assert::argument()->is_numeric('abc', "error message horray!@#"); } 42 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 43 | 44 | try { Assert::argument()->is_not_numeric('123', "error message horray!@#"); } 45 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 46 | 47 | try { Assert::argument()->is_integery('123.234', "error message horray!@#"); } 48 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 49 | 50 | try { Assert::argument()->is_scalar(null, "error message horray!@#"); } 51 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 52 | 53 | try { Assert::argument()->are_same(123, "123", "error message horray!@#"); } 54 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 55 | 56 | try { Assert::argument()->are_not_same(123, 123, "error message horray!@#"); } 57 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 58 | 59 | try { Assert::argument()->are_equal(123, "1234", "error message horray!@#"); } 60 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 61 | 62 | try { Assert::argument()->are_not_equal(123, '123', "error message horray!@#"); } 63 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 64 | 65 | try { Assert::argument()->is_callable(123, "error message horray!@#"); } 66 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 67 | 68 | try { Assert::argument()->is_instance_of(new stdClass(), 123, "error message horray!@#"); } 69 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 70 | 71 | try { Assert::argument()->is_classname('fakeclass', "error message horray!@#"); } 72 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 73 | 74 | try { Assert::argument()->uses_trait(new stdClass(), 123, "error message horray!@#"); } 75 | catch (InvalidArgumentException $e) { echo $e->getMessage()."\n"; } 76 | ?> 77 | --EXPECT-- 78 | The statement (bool) false was not true, error message horray!@# 79 | The statement (bool) false was not truthy, error message horray!@# 80 | The statement (bool) true was not false, error message horray!@# 81 | The value (bool) true is not an integer, error message horray!@# 82 | The value (bool) true is not a float, error message horray!@# 83 | The value (bool) true is not an array, error message horray!@# 84 | The value (bool) true is not an object, error message horray!@# 85 | The value (bool) true is not a string, error message horray!@# 86 | The value (int) 42 is not a boolean, error message horray!@# 87 | The given value should not have been null, error message horray!@# 88 | The key (string) asdf was not in Array, error message horray!@# 89 | Argument 2 passed to is_key_in_array is (string) not-an-array, not an array, error message horray!@# 90 | The value (string) abc is not numeric, error message horray!@# 91 | The value (string) 123 is numeric, error message horray!@# 92 | The value (string) 123.234 does not represent an integer, error message horray!@# 93 | The value null is not a scalar, error message horray!@# 94 | The values (int) 123 and (string) 123 are not identical, error message horray!@# 95 | The values (int) 123 and (int) 123 are identical, error message horray!@# 96 | The values (int) 123 and (string) 1234 are not equal, error message horray!@# 97 | The values (int) 123 and (string) 123 are equal, error message horray!@# 98 | The value (int) 123 is not callable, error message horray!@# 99 | The value Object is not an instance of (int) 123, error message horray!@# 100 | The value (string) fakeclass is not a class name, error message horray!@# 101 | The value Object does not use the trait (int) 123, error message horray!@# 102 | 103 | -------------------------------------------------------------------------------- /docs/stubs/Assert.php: -------------------------------------------------------------------------------- 1 | 6 | * Copyright (c) Box, Inc. 2013 7 | */ 8 | 9 | #include "php_fast_assert.h" 10 | #include "zend_exceptions.h" 11 | #include "zend_operators.h" 12 | #include "ext/spl/spl_exceptions.h" 13 | 14 | #define likely(x) __builtin_expect((x),1) 15 | #define unlikely(x) __builtin_expect((x),0) 16 | 17 | const char *IS_TRUE_ERR = "The statement %s was not true"; 18 | const char *IS_TRUTHY_ERR = "The statement %s was not truthy"; 19 | const char *IS_EMPTY_ERR = "The value %s is not empty"; 20 | const char *IS_NOT_EMPTY_ERR = "The value %s is empty"; 21 | const char *IS_FALSE_ERR = "The statement %s was not false"; 22 | const char *IS_INTEGER_ERR = "The value %s is not an integer"; 23 | const char *IS_FLOAT_ERR = "The value %s is not a float"; 24 | const char *IS_ARRAY_ERR = "The value %s is not an array"; 25 | const char *IS_OBJECT_ERR = "The value %s is not an object"; 26 | const char *IS_STRING_ERR = "The value %s is not a string"; 27 | const char *IS_BOOLEAN_ERR = "The value %s is not a boolean"; 28 | const char *IS_NOT_NULL_ERR = "The given value should not have been %s"; 29 | const char *IS_KEY_IN_ARRAY_ERR = "The key %s was not in %s"; 30 | const char *IS_KEY_IN_ARRAY_INVALID_ARR_ERR = "Argument 2 passed to is_key_in_array is %s, not an array"; 31 | const char *IS_NUMERIC_ERR = "The value %s is not numeric"; 32 | const char *IS_NOT_NUMERIC_ERR = "The value %s is numeric"; 33 | const char *IS_INTEGERY_ERR = "The value %s does not represent an integer"; 34 | const char *IS_SCALAR_ERR = "The value %s is not a scalar"; 35 | const char *ARE_SAME_ERR = "The values %s and %s are not identical"; 36 | const char *ARE_NOT_SAME_ERR = "The values %s and %s are identical"; 37 | const char *ARE_EQUAL_ERR = "The values %s and %s are not equal"; 38 | const char *ARE_NOT_EQUAL_ERR = "The values %s and %s are equal"; 39 | const char *IS_CALLABLE_ERR = "The value %s is not callable"; 40 | const char *IS_INSTANCE_OF_ERR = "The value %s is not an instance of %s"; 41 | const char *IS_CLASSNAME_ERR = "The value %s is not a class name"; 42 | const char *USES_TRAIT_ERR = "The value %s does not use the trait %s"; 43 | const char *IS_ASSOC_ARR_ERR = "The value %s is not an associative array"; 44 | const char *IS_IN_ARRAY_ERR = "The value %s is not in the array %s"; 45 | const char *WITH_NO_ARG_ERR = "You must pass an argument to Assert::with!"; 46 | const char *WITH_NO_STRING_ERR = "You must pass a string to Assert::with!"; 47 | const char *WITH_INVALID_CLASSNAME_ERR = "You must pass a valid classname to Assert::with!"; 48 | const char *WITH_NOT_EXCEPTION_SUBCLASS_ERR = "The classname passed to Assert::with is not a subclass of Exception!"; 49 | 50 | zend_class_entry *fast_assert_ce; 51 | zend_object_handlers fake_assert_obj_handlers; 52 | 53 | /* Global storage */ 54 | #ifdef ZTS 55 | int fa_globals_id; 56 | #else 57 | fast_assert_globals fa_globals; 58 | #endif /* ZTS */ 59 | 60 | /** 61 | * Helper macros to extract params from assert's instance method calls 62 | */ 63 | #define ASSERT_EXTRACT_ONE_PARAM(errstring, arg, err_msg) do { \ 64 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z", &arg, &err_msg) == FAILURE) { \ 65 | assert_throw_exception_on_unary_assertion(getThis(), errstring, NULL, err_msg TSRMLS_CC); \ 66 | return; \ 67 | } \ 68 | } while(0) 69 | 70 | #define ASSERT_EXTRACT_TWO_PARAMS(errstring, arg, arg2, err_msg) do { \ 71 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|z", &arg, &arg2, &err_msg) == FAILURE) { \ 72 | assert_throw_exception_on_binary_assertion(getThis(), errstring, NULL, NULL, err_msg TSRMLS_CC); \ 73 | return; \ 74 | } \ 75 | } while (0) 76 | 77 | /* 78 | * Helper function to print an appropriate error string to strbuf using the fmt string passed in and 79 | * the value of err_val 80 | * NOTE: this unfortunately duplicates lots of logic from 'zend_make_printable_zval', due to the requirement 81 | * that this function not malloc any memory and not raise spurious E_NOTICE warnings 82 | */ 83 | static void debug_print_zval(char *strbuf, const char* err_fmt_string, zval *err_val, size_t maxlen) 84 | { 85 | // buffer to store any intermediate representations of values 86 | char intstrbuf[512]; 87 | 88 | // short circuit if err_val is NULL (happens when no arg is passed in) 89 | if (!err_val) { 90 | snprintf(strbuf, maxlen, err_fmt_string, "(no statement was passed in!)"); 91 | return; 92 | } 93 | 94 | switch (Z_TYPE_P(err_val)) { 95 | case IS_NULL: 96 | snprintf(strbuf, maxlen, err_fmt_string, "null"); 97 | return; 98 | case IS_BOOL: 99 | if (Z_LVAL_P(err_val)) { 100 | snprintf(strbuf, maxlen, err_fmt_string, "(bool) true"); 101 | } else { 102 | snprintf(strbuf, maxlen, err_fmt_string, "(bool) false"); 103 | } 104 | return; 105 | case IS_STRING: 106 | snprintf(intstrbuf, 512, "(string) %s", Z_STRVAL_P(err_val)); 107 | snprintf(strbuf, maxlen, err_fmt_string, intstrbuf); 108 | return; 109 | case IS_LONG: 110 | snprintf(intstrbuf, 512, "(int) %d", Z_LVAL_P(err_val)); 111 | snprintf(strbuf, maxlen, err_fmt_string, intstrbuf); 112 | return; 113 | case IS_DOUBLE: 114 | snprintf(intstrbuf, 512, "(float) %f", Z_DVAL_P(err_val)); 115 | snprintf(strbuf, maxlen, err_fmt_string, intstrbuf); 116 | return; 117 | case IS_ARRAY: 118 | snprintf(strbuf, maxlen, err_fmt_string, "Array"); 119 | return; 120 | case IS_OBJECT: 121 | snprintf(strbuf, maxlen, err_fmt_string, "Object"); 122 | return; 123 | case IS_RESOURCE: 124 | snprintf(strbuf, maxlen, err_fmt_string, "Resource"); 125 | return; 126 | default: 127 | snprintf(strbuf, maxlen, err_fmt_string, "Unknown"); 128 | } 129 | } 130 | 131 | /** 132 | * Helper method to dump a nice error string into strbuf. This bacially does 133 | * (err_fmt_string % (pretty_print(err_val))) + ", " + err_msg 134 | */ 135 | static void get_good_error_string(char *strbuf, const char* err_fmt_string, zval *err_val, zval *err_msg, size_t maxlen) 136 | { 137 | int str_len; 138 | memset((void *)strbuf, 0, maxlen); 139 | debug_print_zval(strbuf, err_fmt_string, err_val, maxlen); 140 | if (err_msg && Z_TYPE_P(err_msg) == IS_STRING) { 141 | str_len = strlen(strbuf); // NOTE: str_len does not include the null terminating char 142 | strncat(strbuf, ", ", maxlen - str_len - 1); 143 | strncat(strbuf, Z_STRVAL_P(err_msg), maxlen - str_len - 3); 144 | } 145 | } 146 | 147 | /** 148 | * Helper method to throw an exception on a 'generic' assert object - i.e. one made with a custom 149 | * exception type 150 | */ 151 | static void throw_exception_using_generic_assert_obj(zval* assert_obj, char *message TSRMLS_DC) 152 | { 153 | zval *classname; 154 | zend_class_entry **ce; 155 | classname = zend_read_property(fast_assert_ce, assert_obj, "exception_type", sizeof("exception_type") - 1, 1 TSRMLS_CC); 156 | zend_lookup_class(Z_STRVAL_P(classname), Z_STRLEN_P(classname), &ce TSRMLS_CC); 157 | zend_throw_exception(*ce, message, 0 TSRMLS_CC); 158 | } 159 | 160 | /** 161 | * Helper method to throw an exception. Uses the assert_obj zval to decide which type of exception to throw, and 162 | * populates the message of the exception by doing (err_fmt_string % (pretty_print(err_val))) + ", " + err_msg 163 | */ 164 | static void assert_throw_exception_on_unary_assertion(zval *assert_obj, const char *err_fmt_string, zval *err_val, zval* err_msg TSRMLS_DC) 165 | { 166 | // string buffer for storing the exception string 167 | // NOTE: zend_throw_exception copies the string a few function calls down, so we can use stack memory here 168 | char strbuf[1024]; 169 | get_good_error_string(strbuf, err_fmt_string, err_val, err_msg, 1024); 170 | 171 | // switch on the handle of the object passed in 172 | zend_object_handle obj_handle = Z_OBJ_HANDLE_P(assert_obj); 173 | 174 | if (obj_handle == AssertGlobals(invalid_arg_assert_handle)) { 175 | zend_throw_exception(spl_ce_InvalidArgumentException, strbuf, 0 TSRMLS_CC); 176 | return; 177 | } else if (obj_handle == AssertGlobals(unexpected_val_assert_handle)) { 178 | zend_throw_exception(spl_ce_UnexpectedValueException, strbuf, 0 TSRMLS_CC); 179 | return; 180 | } else if (obj_handle == AssertGlobals(logic_exception_assert_handle)) { 181 | zend_throw_exception(spl_ce_LogicException, strbuf, 0 TSRMLS_CC); 182 | return; 183 | } 184 | 185 | // if this wasn't a special object corresponding to an exception type, 186 | // throw the type of exception that the object contains 187 | throw_exception_using_generic_assert_obj(assert_obj, strbuf TSRMLS_CC); 188 | return; 189 | } 190 | 191 | /** 192 | * Helper method to throw an exception using 2 arguments, val1 and val2, in the error string. 193 | * NOTE: err_fmt_string must have two string format specifiers (i.e., two %s's) 194 | * PS: This method is a little bit of a hack in that it just makes a new format string with one %s 195 | * and passes it down to assert_throw_exception_on_unary_assertion. Yay code reuse! 196 | */ 197 | static void assert_throw_exception_on_binary_assertion(zval *assert_obj, const char *err_fmt_string, zval *val1, zval* val2, zval* err_msg TSRMLS_DC) 198 | { 199 | char val1_print_buffer[512]; 200 | char new_format_string[512]; 201 | debug_print_zval(val1_print_buffer, "%s", val1, 512); 202 | snprintf(new_format_string, 512, err_fmt_string, val1_print_buffer, "%s"); 203 | assert_throw_exception_on_unary_assertion(assert_obj, new_format_string, val2, err_msg TSRMLS_CC); 204 | } 205 | 206 | PHP_METHOD(Assert, __construct) 207 | { 208 | char errbuf[128]; 209 | strncpy(errbuf, "It is forbidden to call Asserts constructor", 128); 210 | zend_throw_exception(spl_ce_BadMethodCallException, errbuf, 0 TSRMLS_CC); 211 | } 212 | 213 | PHP_METHOD(Assert, is_true) 214 | { 215 | zval* arg; 216 | zval* err_msg = NULL; 217 | ASSERT_EXTRACT_ONE_PARAM(IS_TRUE_ERR, arg, err_msg); 218 | 219 | if (unlikely(Z_TYPE_P(arg) != IS_BOOL)) { 220 | assert_throw_exception_on_unary_assertion(getThis(), IS_TRUE_ERR, arg, err_msg TSRMLS_CC); 221 | return; 222 | } 223 | if (unlikely(!(Z_LVAL_P(arg)))) { 224 | assert_throw_exception_on_unary_assertion(getThis(), IS_TRUE_ERR, arg, err_msg TSRMLS_CC); 225 | return; 226 | } 227 | RETURN_ZVAL(getThis(), 1, 0); 228 | } 229 | 230 | PHP_METHOD(Assert, is_truthy) 231 | { 232 | zval *arg; 233 | zval* err_msg = NULL; 234 | ASSERT_EXTRACT_ONE_PARAM(IS_TRUTHY_ERR, arg, err_msg); 235 | 236 | if (unlikely(!i_zend_is_true(arg))) { 237 | assert_throw_exception_on_unary_assertion(getThis(), IS_TRUTHY_ERR, arg, err_msg TSRMLS_CC); 238 | return; 239 | } 240 | RETURN_ZVAL(getThis(), 1, 0); 241 | } 242 | 243 | PHP_METHOD(Assert, is_empty) 244 | { 245 | zval *arg; 246 | zval* err_msg = NULL; 247 | ASSERT_EXTRACT_ONE_PARAM(IS_EMPTY_ERR, arg, err_msg); 248 | 249 | if (unlikely(i_zend_is_true(arg))) { 250 | assert_throw_exception_on_unary_assertion(getThis(), IS_EMPTY_ERR, arg, err_msg TSRMLS_CC); 251 | return; 252 | } 253 | RETURN_ZVAL(getThis(), 1, 0); 254 | } 255 | 256 | PHP_METHOD(Assert, is_not_empty) 257 | { 258 | zval *arg; 259 | zval* err_msg = NULL; 260 | ASSERT_EXTRACT_ONE_PARAM(IS_NOT_EMPTY_ERR, arg, err_msg); 261 | 262 | if (unlikely(!i_zend_is_true(arg))) { 263 | assert_throw_exception_on_unary_assertion(getThis(), IS_NOT_EMPTY_ERR, arg, err_msg TSRMLS_CC); 264 | } 265 | RETURN_ZVAL(getThis(), 1, 0); 266 | } 267 | 268 | PHP_METHOD(Assert, is_false) 269 | { 270 | zval* arg; 271 | zval* err_msg = NULL; 272 | ASSERT_EXTRACT_ONE_PARAM(IS_FALSE_ERR, arg, err_msg); 273 | 274 | if (unlikely(Z_TYPE_P(arg) != IS_BOOL)) { 275 | assert_throw_exception_on_unary_assertion(getThis(), IS_FALSE_ERR, arg, err_msg TSRMLS_CC); 276 | return; 277 | } 278 | if (unlikely(Z_LVAL_P(arg))) { 279 | assert_throw_exception_on_unary_assertion(getThis(), IS_FALSE_ERR, arg, err_msg TSRMLS_CC); 280 | return; 281 | } 282 | RETURN_ZVAL(getThis(), 1, 0); 283 | } 284 | 285 | PHP_METHOD(Assert, is_integer) 286 | { 287 | zval* arg; 288 | zval* err_msg = NULL; 289 | ASSERT_EXTRACT_ONE_PARAM(IS_INTEGER_ERR, arg, err_msg); 290 | 291 | if (unlikely(Z_TYPE_P(arg) != IS_LONG)) { 292 | assert_throw_exception_on_unary_assertion(getThis(), IS_INTEGER_ERR, arg, err_msg TSRMLS_CC); 293 | return; 294 | } 295 | RETURN_ZVAL(getThis(), 1, 0); 296 | } 297 | 298 | PHP_METHOD(Assert, is_float) 299 | { 300 | zval* arg; 301 | zval* err_msg = NULL; 302 | ASSERT_EXTRACT_ONE_PARAM(IS_FLOAT_ERR, arg, err_msg); 303 | 304 | if (unlikely(Z_TYPE_P(arg) != IS_DOUBLE)) { 305 | assert_throw_exception_on_unary_assertion(getThis(), IS_FLOAT_ERR, arg, err_msg TSRMLS_CC); 306 | return; 307 | } 308 | RETURN_ZVAL(getThis(), 1, 0); 309 | } 310 | 311 | PHP_METHOD(Assert, is_array) 312 | { 313 | zval* arg; 314 | zval* err_msg = NULL; 315 | ASSERT_EXTRACT_ONE_PARAM(IS_ARRAY_ERR, arg, err_msg); 316 | 317 | if (unlikely(Z_TYPE_P(arg) != IS_ARRAY)) { 318 | assert_throw_exception_on_unary_assertion(getThis(), IS_ARRAY_ERR, arg, err_msg TSRMLS_CC); 319 | return; 320 | } 321 | RETURN_ZVAL(getThis(), 1, 0); 322 | } 323 | 324 | PHP_METHOD(Assert, is_object) 325 | { 326 | zval* arg; 327 | zval* err_msg = NULL; 328 | ASSERT_EXTRACT_ONE_PARAM(IS_OBJECT_ERR, arg, err_msg); 329 | 330 | if (unlikely(Z_TYPE_P(arg) != IS_OBJECT)) { 331 | assert_throw_exception_on_unary_assertion(getThis(), IS_OBJECT_ERR, arg, err_msg TSRMLS_CC); 332 | return; 333 | } 334 | RETURN_ZVAL(getThis(), 1, 0); 335 | } 336 | 337 | PHP_METHOD(Assert, is_string) 338 | { 339 | zval* arg; 340 | zval* err_msg = NULL; 341 | ASSERT_EXTRACT_ONE_PARAM(IS_STRING_ERR, arg, err_msg); 342 | 343 | if (unlikely(Z_TYPE_P(arg) != IS_STRING)) { 344 | assert_throw_exception_on_unary_assertion(getThis(), IS_STRING_ERR, arg, err_msg TSRMLS_CC); 345 | return; 346 | } 347 | RETURN_ZVAL(getThis(), 1, 0); 348 | } 349 | 350 | PHP_METHOD(Assert, is_boolean) 351 | { 352 | zval* arg; 353 | zval* err_msg = NULL; 354 | ASSERT_EXTRACT_ONE_PARAM(IS_BOOLEAN_ERR, arg, err_msg); 355 | 356 | if (unlikely(Z_TYPE_P(arg) != IS_BOOL)) { 357 | assert_throw_exception_on_unary_assertion(getThis(), IS_BOOLEAN_ERR, arg, err_msg TSRMLS_CC); 358 | return; 359 | } 360 | RETURN_ZVAL(getThis(), 1, 0); 361 | } 362 | 363 | PHP_METHOD(Assert, is_not_null) 364 | { 365 | zval* arg; 366 | zval* err_msg = NULL; 367 | ASSERT_EXTRACT_ONE_PARAM(IS_NOT_NULL_ERR, arg, err_msg); 368 | 369 | if (unlikely(Z_TYPE_P(arg) == IS_NULL)) { 370 | assert_throw_exception_on_unary_assertion(getThis(), IS_NOT_NULL_ERR, arg, err_msg TSRMLS_CC); 371 | return; 372 | } 373 | RETURN_ZVAL(getThis(), 1, 0); 374 | } 375 | 376 | PHP_METHOD(Assert, is_key_in_array) 377 | { 378 | zval *zarray = NULL; 379 | HashTable *array = NULL; 380 | zval* err_msg = NULL; 381 | zval *key = NULL; 382 | int key_exists = 0; 383 | ASSERT_EXTRACT_TWO_PARAMS(IS_KEY_IN_ARRAY_ERR, key, zarray, err_msg); 384 | 385 | // make sure the 2nd arg is an array 386 | if (Z_TYPE_P(zarray) != IS_ARRAY) { 387 | assert_throw_exception_on_unary_assertion(getThis(), IS_KEY_IN_ARRAY_INVALID_ARR_ERR, zarray, err_msg TSRMLS_CC); 388 | return; 389 | } 390 | array = Z_ARRVAL_P(zarray); 391 | 392 | switch (Z_TYPE_P(key)) { 393 | case IS_STRING: 394 | if (zend_symtable_exists(array, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1)) { 395 | key_exists = 1; 396 | } 397 | break; 398 | case IS_LONG: 399 | if (zend_hash_index_exists(array, Z_LVAL_P(key))) { 400 | key_exists = 1; 401 | } 402 | break; 403 | case IS_NULL: 404 | // this makes me sad, but this case is included to maintain completely parity with array_key_exists 405 | if (zend_hash_exists(array, "", 1)) { 406 | key_exists = 1; 407 | } 408 | break; 409 | } 410 | 411 | if (unlikely(!key_exists)) { 412 | assert_throw_exception_on_binary_assertion(getThis(), IS_KEY_IN_ARRAY_ERR, key, zarray, err_msg TSRMLS_CC); 413 | } 414 | RETURN_ZVAL(getThis(), 1, 0); 415 | } 416 | 417 | static int is_numeric_helper(zval *val) 418 | { 419 | switch (Z_TYPE_P(val)) { 420 | case IS_DOUBLE: 421 | case IS_LONG: 422 | return 1; 423 | case IS_STRING: 424 | return (is_numeric_string(Z_STRVAL_P(val), Z_STRLEN_P(val), NULL, NULL, 0)) ? 1 : 0; 425 | default: 426 | return 0; 427 | } 428 | } 429 | 430 | PHP_METHOD(Assert, is_numeric) 431 | { 432 | zval* val; 433 | zval* err_msg = NULL; 434 | ASSERT_EXTRACT_ONE_PARAM(IS_NUMERIC_ERR, val, err_msg); 435 | 436 | if (unlikely(!is_numeric_helper(val))) { 437 | assert_throw_exception_on_unary_assertion(getThis(), IS_NUMERIC_ERR, val, err_msg TSRMLS_CC); 438 | return; 439 | } 440 | RETURN_ZVAL(getThis(), 1, 0); 441 | } 442 | 443 | PHP_METHOD(Assert, is_not_numeric) 444 | { 445 | zval* val; 446 | zval* err_msg = NULL; 447 | ASSERT_EXTRACT_ONE_PARAM(IS_NOT_NUMERIC_ERR, val, err_msg); 448 | 449 | if (unlikely(is_numeric_helper(val))) { 450 | assert_throw_exception_on_unary_assertion(getThis(), IS_NOT_NUMERIC_ERR, val, err_msg TSRMLS_CC); 451 | return; 452 | } 453 | RETURN_ZVAL(getThis(), 1, 0); 454 | } 455 | 456 | /** 457 | * Helper method that returns 1 if a string of length len has a character other than 458 | * '-', '.', or '0' to '9' 459 | */ 460 | static int string_contains_nonnumber_char(char *str, int len) 461 | { 462 | int i; 463 | for (i = 0; i < len; i++) { 464 | if (str[i] < 45 || str[i] > 57 ) { 465 | return 1; 466 | } 467 | } 468 | return 0; 469 | } 470 | 471 | PHP_METHOD(Assert, is_integery) 472 | { 473 | zval* val; 474 | long lval; 475 | double dval; 476 | zend_uchar retval; 477 | zval* err_msg = NULL; 478 | ASSERT_EXTRACT_ONE_PARAM(IS_INTEGERY_ERR, val, err_msg); 479 | 480 | switch (Z_TYPE_P(val)) { 481 | case IS_LONG: 482 | break; 483 | case IS_DOUBLE: 484 | if (unlikely((Z_DVAL_P(val) - (long)Z_DVAL_P(val)) != 0)) { 485 | assert_throw_exception_on_unary_assertion(getThis(), IS_INTEGERY_ERR, val, err_msg TSRMLS_CC); 486 | return; 487 | } 488 | break; 489 | case IS_STRING: 490 | retval = is_numeric_string(Z_STRVAL_P(val), Z_STRLEN_P(val), &lval, &dval, 0); 491 | if (retval == IS_LONG) { 492 | break; 493 | } 494 | // NOTE: we explicity disallow exponential strings, because PHP handles them in a braindead, 495 | // idiotic manner. in php, (int) '1e6' == 1 and '1e6' + 0 == 1000000. 496 | if (retval == IS_DOUBLE && 497 | dval - (long)dval == 0 && 498 | !string_contains_nonnumber_char(Z_STRVAL_P(val), Z_STRLEN_P(val))) 499 | { 500 | break; 501 | } 502 | assert_throw_exception_on_unary_assertion(getThis(), IS_INTEGERY_ERR, val, err_msg TSRMLS_CC); 503 | return; 504 | default: 505 | assert_throw_exception_on_unary_assertion(getThis(), IS_INTEGERY_ERR, val, err_msg TSRMLS_CC); 506 | return; 507 | } 508 | RETURN_ZVAL(getThis(), 1, 0); 509 | } 510 | 511 | PHP_METHOD(Assert, is_scalar) 512 | { 513 | zval* val; 514 | zval* err_msg = NULL; 515 | ASSERT_EXTRACT_ONE_PARAM(IS_SCALAR_ERR, val, err_msg); 516 | 517 | switch (Z_TYPE_P(val)) { 518 | case IS_BOOL: 519 | case IS_DOUBLE: 520 | case IS_LONG: 521 | case IS_STRING: 522 | break; 523 | default: 524 | assert_throw_exception_on_unary_assertion(getThis(), IS_SCALAR_ERR, val, err_msg TSRMLS_CC); 525 | return; 526 | } 527 | RETURN_ZVAL(getThis(), 1, 0); 528 | } 529 | 530 | /* 531 | * Helper function that simply returns 1 if the two zvals are identical 532 | * is_identical_function has a weird interface where it returns the result sometimes in the retval 533 | * or sometimes in a zval 534 | */ 535 | static int is_identical_helper(zval* arg1, zval* arg2 TSRMLS_DC) 536 | { 537 | zval res; 538 | if (is_identical_function(&res, arg1, arg2 TSRMLS_CC) == FAILURE) { 539 | return 0; 540 | } 541 | return (int)Z_LVAL(res); 542 | } 543 | 544 | PHP_METHOD(Assert, are_same) 545 | { 546 | zval* val1 = NULL; 547 | zval* val2 = NULL; 548 | zval* err_msg = NULL; 549 | ASSERT_EXTRACT_TWO_PARAMS(ARE_SAME_ERR, val1, val2, err_msg); 550 | 551 | if (unlikely(!is_identical_helper(val1, val2 TSRMLS_CC))) { 552 | assert_throw_exception_on_binary_assertion(getThis(), ARE_SAME_ERR, val1, val2, err_msg TSRMLS_CC); 553 | return; 554 | } 555 | RETURN_ZVAL(getThis(), 1, 0); 556 | } 557 | 558 | PHP_METHOD(Assert, are_not_same) 559 | { 560 | zval* val1; 561 | zval* val2; 562 | zval* err_msg = NULL; 563 | ASSERT_EXTRACT_TWO_PARAMS(ARE_NOT_SAME_ERR, val1, val2, err_msg); 564 | 565 | if (unlikely(is_identical_helper(val1, val2 TSRMLS_CC))) { 566 | assert_throw_exception_on_binary_assertion(getThis(), ARE_NOT_SAME_ERR, val1, val2, err_msg TSRMLS_CC); 567 | return; 568 | } 569 | RETURN_ZVAL(getThis(), 1, 0); 570 | } 571 | 572 | PHP_METHOD(Assert, are_equal) 573 | { 574 | zval* val1; 575 | zval* val2; 576 | zval* err_msg = NULL; 577 | zval res; 578 | ASSERT_EXTRACT_TWO_PARAMS(ARE_EQUAL_ERR, val1, val2, err_msg); 579 | 580 | if (unlikely(!fast_equal_function(&res, val1, val2 TSRMLS_CC))) { 581 | assert_throw_exception_on_binary_assertion(getThis(), ARE_EQUAL_ERR, val1, val2, err_msg TSRMLS_CC); 582 | return; 583 | } 584 | RETURN_ZVAL(getThis(), 1, 0); 585 | } 586 | 587 | PHP_METHOD(Assert, are_not_equal) 588 | { 589 | zval* val1; 590 | zval* val2; 591 | zval* err_msg = NULL; 592 | zval res; 593 | ASSERT_EXTRACT_TWO_PARAMS(ARE_NOT_EQUAL_ERR, val1, val2, err_msg); 594 | 595 | if (unlikely(fast_equal_function(&res, val1, val2 TSRMLS_CC))) { 596 | assert_throw_exception_on_binary_assertion(getThis(), ARE_NOT_EQUAL_ERR, val1, val2, err_msg TSRMLS_CC); 597 | return; 598 | } 599 | RETURN_ZVAL(getThis(), 1, 0); 600 | } 601 | 602 | PHP_METHOD(Assert, is_callable) 603 | { 604 | zval* val; 605 | zval* err_msg = NULL; 606 | ASSERT_EXTRACT_ONE_PARAM(IS_CALLABLE_ERR, val, err_msg); 607 | if (unlikely(!zend_is_callable_ex(val, NULL, 0, NULL, NULL, NULL, NULL TSRMLS_CC))) { 608 | assert_throw_exception_on_unary_assertion(getThis(), IS_CALLABLE_ERR, val, err_msg TSRMLS_CC); 609 | return; 610 | } 611 | RETURN_ZVAL(getThis(), 1, 0); 612 | } 613 | 614 | PHP_METHOD(Assert, is_instance_of) 615 | { 616 | zval* obj; 617 | zval* classname; 618 | zval* err_msg = NULL; 619 | zend_class_entry **ce; 620 | zend_class_entry *instance_ce; 621 | ASSERT_EXTRACT_TWO_PARAMS(IS_INSTANCE_OF_ERR, obj, classname, err_msg); 622 | 623 | // if the correct args were passed in, the classname exists, and the object is an instance of classname, return successfully! 624 | if (likely(Z_TYPE_P(obj) == IS_OBJECT && Z_TYPE_P(classname) == IS_STRING)) { 625 | if (likely(zend_lookup_class(Z_STRVAL_P(classname), Z_STRLEN_P(classname), &ce TSRMLS_CC) == SUCCESS)) { 626 | if (likely(HAS_CLASS_ENTRY(*obj) && instanceof_function(Z_OBJCE_P(obj), *ce TSRMLS_CC))) { 627 | RETURN_ZVAL(getThis(), 1, 0); 628 | } 629 | } 630 | } 631 | 632 | assert_throw_exception_on_binary_assertion(getThis(), IS_INSTANCE_OF_ERR, obj, classname, err_msg TSRMLS_CC); 633 | return; 634 | } 635 | 636 | PHP_METHOD(Assert, is_classname) 637 | { 638 | zval *val; 639 | zval* err_msg = NULL; 640 | zend_class_entry **ce; 641 | zend_bool class_exists_retval; 642 | zend_bool iface_exists_retval; 643 | ASSERT_EXTRACT_ONE_PARAM(IS_CLASSNAME_ERR, val, err_msg); 644 | 645 | if (likely(Z_TYPE_P(val) == IS_STRING)) { 646 | if (likely(zend_lookup_class(Z_STRVAL_P(val), Z_STRLEN_P(val), &ce TSRMLS_CC) == SUCCESS)) { 647 | // the class_exists_retval is true when the class isn't an interface 648 | // (not sure what exactly the second part of the bitwise flag logic ensures, the - operation obfuscates the flags) 649 | // this maintains exact parity with the default behavior of class_exists() and iface_exists() 650 | class_exists_retval = (((*ce)->ce_flags & (ZEND_ACC_INTERFACE | (ZEND_ACC_TRAIT - ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))) == 0); 651 | iface_exists_retval = (((*ce)->ce_flags & ZEND_ACC_INTERFACE) > 0); 652 | 653 | if (likely(class_exists_retval || iface_exists_retval)) { 654 | RETURN_ZVAL(getThis(), 1, 0); 655 | } 656 | } 657 | } 658 | assert_throw_exception_on_unary_assertion(getThis(), IS_CLASSNAME_ERR, val, err_msg TSRMLS_CC); 659 | return; 660 | } 661 | 662 | PHP_METHOD(Assert, uses_trait) 663 | { 664 | zval* obj; 665 | zval* trait_name; 666 | zval* err_msg = NULL; 667 | zend_class_entry **trait_ce_p; 668 | zend_class_entry *trait_ce; 669 | zend_class_entry *obj_ce; 670 | zend_class_entry *obj_trait_ce; 671 | zend_uint num_traits; 672 | ASSERT_EXTRACT_TWO_PARAMS(USES_TRAIT_ERR, obj, trait_name, err_msg); 673 | 674 | // BIG IMPORTANT NOTE: this function actually doesn't accurately judge whether a trait is used in a class because 675 | // this doesn't look at traits used by parent classes. This is equivalent to doing 676 | // array_key_exists($trait_name, class_uses($obj)); 677 | if (likely(Z_TYPE_P(obj) == IS_OBJECT && Z_TYPE_P(trait_name) == IS_STRING)) { // verify types, then lookup trait 678 | if (likely(zend_lookup_class(Z_STRVAL_P(trait_name), Z_STRLEN_P(trait_name), &trait_ce_p TSRMLS_CC) == SUCCESS)) { 679 | 680 | trait_ce = *trait_ce_p; 681 | obj_ce = Z_OBJCE_P(obj); 682 | 683 | for (num_traits = 0; num_traits < obj_ce->num_traits; num_traits++) { 684 | obj_trait_ce = obj_ce->traits[num_traits]; 685 | 686 | if (obj_trait_ce->name_length == trait_ce->name_length && 687 | !strncmp(obj_trait_ce->name, trait_ce->name, trait_ce->name_length)) { 688 | RETURN_ZVAL(getThis(), 1, 0); 689 | } 690 | } 691 | } 692 | } 693 | 694 | assert_throw_exception_on_binary_assertion(getThis(), USES_TRAIT_ERR, obj, trait_name, err_msg TSRMLS_CC); 695 | return; 696 | 697 | } 698 | 699 | /** 700 | * A quick note on the behavior of this function: This operates by ensuring that all of the keys 701 | * in the array are ascending, in order integers starting from 0. The function in php user-land 702 | * operates like this: if (array_keys($arr) !== array_keys(array_keys($arr)) throw exception; 703 | * These in fact do the same exact thing! Applying array_keys twice to $arr produces an array 704 | * where both the keys and values are increasing integers starting from 0. Applying array keys 705 | * to $arr once produces an array where the keys are in order ascending integers and the values 706 | * are the array keys. You can see how this works: the only way the two things are equal is if 707 | * the keys of $arr are in-order ascending integers as well! 708 | */ 709 | static int is_assoc_array_helper(zval* arr) 710 | { 711 | ulong i = 0; 712 | ulong idx; 713 | int type; 714 | char *key; 715 | uint keylen; 716 | HashTable *array = Z_ARRVAL_P(arr); 717 | 718 | for (zend_hash_internal_pointer_reset(array); 719 | zend_hash_has_more_elements(array) == SUCCESS; 720 | zend_hash_move_forward(array)) { 721 | 722 | type = zend_hash_get_current_key_ex(array, &key, &keylen, &idx, 0, NULL); 723 | if (type == HASH_KEY_IS_STRING) { 724 | return 1; 725 | } 726 | if (idx != i) { 727 | return 1; 728 | } 729 | i++; 730 | } 731 | 732 | return 0; 733 | } 734 | 735 | PHP_METHOD(Assert, is_associative_array) 736 | { 737 | zval *arr; 738 | zval *err_msg = NULL; 739 | ASSERT_EXTRACT_ONE_PARAM(IS_ASSOC_ARR_ERR, arr, err_msg); 740 | 741 | if (unlikely(Z_TYPE_P(arr) != IS_ARRAY)) { 742 | assert_throw_exception_on_unary_assertion(getThis(), IS_ASSOC_ARR_ERR, arr, err_msg TSRMLS_CC); 743 | return; 744 | } 745 | if (unlikely(!is_assoc_array_helper(arr))) { 746 | assert_throw_exception_on_unary_assertion(getThis(), IS_ASSOC_ARR_ERR, arr, err_msg TSRMLS_CC); 747 | return; 748 | } 749 | RETURN_ZVAL(getThis(), 1, 0); 750 | } 751 | 752 | PHP_METHOD(Assert, is_in_array) 753 | { 754 | zval *value, /* value to check for */ 755 | *array, /* array to check in */ 756 | **entry, /* pointer to array entry */ 757 | res; /* comparison result */ 758 | HashPosition pos; /* hash iterator */ 759 | zval *err_msg = NULL; 760 | ASSERT_EXTRACT_TWO_PARAMS(IS_IN_ARRAY_ERR, array, value, err_msg); 761 | 762 | if (unlikely(Z_TYPE_P(array) != IS_ARRAY)) { 763 | assert_throw_exception_on_binary_assertion(getThis(), IS_IN_ARRAY_ERR, value, array, err_msg TSRMLS_CC); 764 | return; 765 | } 766 | 767 | zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos); 768 | while (zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **)&entry, &pos) == SUCCESS) { 769 | is_identical_function(&res, value, *entry TSRMLS_CC); 770 | 771 | // if a match was found, return! 772 | if (Z_LVAL(res)) { 773 | RETURN_ZVAL(getThis(), 1, 0); 774 | } 775 | // otherwise, advance the iterator 776 | zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos); 777 | } 778 | 779 | assert_throw_exception_on_binary_assertion(getThis(), IS_IN_ARRAY_ERR, value, array, err_msg TSRMLS_CC); 780 | return; 781 | } 782 | 783 | static void copy_global_assert_obj_to_return_value(zval *retval, zend_object_handle handle) 784 | { 785 | // init the proper object value 786 | zend_object_value oval; 787 | oval.handlers = &fake_assert_obj_handlers; 788 | oval.handle = handle; 789 | 790 | // copy everything needed into return_value (a zval*) 791 | Z_TYPE_P(retval) = IS_OBJECT; 792 | Z_OBJVAL_P(retval) = oval; 793 | zval_copy_ctor(retval); 794 | } 795 | 796 | PHP_METHOD(Assert, argument) 797 | { 798 | copy_global_assert_obj_to_return_value(return_value, AssertGlobals(invalid_arg_assert_handle)); 799 | return; 800 | } 801 | 802 | PHP_METHOD(Assert, received_value) 803 | { 804 | copy_global_assert_obj_to_return_value(return_value, AssertGlobals(unexpected_val_assert_handle)); 805 | return; 806 | } 807 | 808 | PHP_METHOD(Assert, logic) 809 | { 810 | copy_global_assert_obj_to_return_value(return_value, AssertGlobals(logic_exception_assert_handle)); 811 | return; 812 | } 813 | 814 | PHP_METHOD(Assert, with) 815 | { 816 | zval* classname; 817 | zend_class_entry **ce; 818 | char errbuf[128]; 819 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &classname) == FAILURE) { 820 | strncpy(errbuf, WITH_NO_ARG_ERR, 128); 821 | zend_throw_exception(spl_ce_InvalidArgumentException, errbuf, 0 TSRMLS_CC); 822 | return; 823 | } 824 | 825 | // make sure the classname is a valid classname! 826 | if (Z_TYPE_P(classname) != IS_STRING) { 827 | strncpy(errbuf, WITH_NO_STRING_ERR, 128); 828 | zend_throw_exception(spl_ce_InvalidArgumentException, errbuf, 0 TSRMLS_CC); 829 | return; 830 | } 831 | 832 | // classname has to be a subclass of Exception, otherwise throw exception! 833 | if (zend_lookup_class(Z_STRVAL_P(classname), Z_STRLEN_P(classname), &ce TSRMLS_CC) == FAILURE) { 834 | strncpy(errbuf, WITH_INVALID_CLASSNAME_ERR, 128); 835 | zend_throw_exception(spl_ce_InvalidArgumentException, errbuf, 0 TSRMLS_CC); 836 | return; 837 | } 838 | if (!instanceof_function(*ce, zend_exception_get_default(TSRMLS_C) TSRMLS_CC)) { 839 | strncpy(errbuf, WITH_NOT_EXCEPTION_SUBCLASS_ERR, 128); 840 | zend_throw_exception(spl_ce_InvalidArgumentException, errbuf, 0 TSRMLS_CC); 841 | return; 842 | } 843 | 844 | // we can now rest assured this assert object can be created - now make it! 845 | object_init_ex(return_value, fast_assert_ce); 846 | 847 | // now, finally, set the "exception_type" property on the new exception object 848 | zend_update_property(fast_assert_ce, return_value, "exception_type", sizeof("exception_type") - 1, classname TSRMLS_CC); 849 | 850 | return; 851 | } 852 | 853 | static zend_function_entry fast_assert_methods[] = { 854 | PHP_ME(Assert, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) 855 | PHP_ME(Assert, is_true, NULL, ZEND_ACC_PUBLIC) 856 | PHP_ME(Assert, is_truthy, NULL, ZEND_ACC_PUBLIC) 857 | PHP_ME(Assert, is_empty, NULL, ZEND_ACC_PUBLIC) 858 | PHP_ME(Assert, is_not_empty, NULL, ZEND_ACC_PUBLIC) 859 | PHP_ME(Assert, is_false, NULL, ZEND_ACC_PUBLIC) 860 | PHP_ME(Assert, is_integer, NULL, ZEND_ACC_PUBLIC) 861 | PHP_ME(Assert, is_float, NULL, ZEND_ACC_PUBLIC) 862 | PHP_ME(Assert, is_array, NULL, ZEND_ACC_PUBLIC) 863 | PHP_ME(Assert, is_object, NULL, ZEND_ACC_PUBLIC) 864 | PHP_ME(Assert, is_string, NULL, ZEND_ACC_PUBLIC) 865 | PHP_ME(Assert, is_boolean, NULL, ZEND_ACC_PUBLIC) 866 | PHP_ME(Assert, is_not_null, NULL, ZEND_ACC_PUBLIC) 867 | PHP_ME(Assert, is_key_in_array, NULL, ZEND_ACC_PUBLIC) 868 | PHP_ME(Assert, is_numeric, NULL, ZEND_ACC_PUBLIC) 869 | PHP_ME(Assert, is_not_numeric, NULL, ZEND_ACC_PUBLIC) 870 | PHP_ME(Assert, is_integery, NULL, ZEND_ACC_PUBLIC) 871 | PHP_ME(Assert, is_scalar, NULL, ZEND_ACC_PUBLIC) 872 | PHP_ME(Assert, are_same, NULL, ZEND_ACC_PUBLIC) 873 | PHP_ME(Assert, are_not_same, NULL, ZEND_ACC_PUBLIC) 874 | PHP_ME(Assert, are_equal, NULL, ZEND_ACC_PUBLIC) 875 | PHP_ME(Assert, are_not_equal, NULL, ZEND_ACC_PUBLIC) 876 | PHP_ME(Assert, is_callable, NULL, ZEND_ACC_PUBLIC) 877 | PHP_ME(Assert, is_instance_of, NULL, ZEND_ACC_PUBLIC) 878 | PHP_ME(Assert, is_classname, NULL, ZEND_ACC_PUBLIC) 879 | PHP_ME(Assert, uses_trait, NULL, ZEND_ACC_PUBLIC) 880 | PHP_ME(Assert, is_associative_array, NULL, ZEND_ACC_PUBLIC) 881 | PHP_ME(Assert, is_in_array, NULL, ZEND_ACC_PUBLIC) 882 | PHP_ME(Assert, argument, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) 883 | PHP_ME(Assert, received_value, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) 884 | PHP_ME(Assert, logic, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) 885 | PHP_ME(Assert, with, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) { 886 | NULL, NULL, NULL 887 | } 888 | }; 889 | 890 | /** 891 | * Stubs for all unneccesary methods for reserved Assert objects 892 | * (i.e. those returned by ::argument and ::logic, etc) in the object handler methods 893 | */ 894 | void stub_add_ref(zval *object TSRMLS_DC) {} 895 | void stub_del_ref(zval *object TSRMLS_DC) {} 896 | zend_object_value stub_clone_obj(zval *object TSRMLS_DC) {} 897 | 898 | /* 899 | * Helper function to register a new assert object using a temporary zval 900 | * Returns the object handle (i.e. unsigned int) of the new object 901 | */ 902 | static zend_object_handle create_new_assert_object(TSRMLS_D) 903 | { 904 | zval obj; 905 | Z_SET_ISREF_TO(obj, 0); 906 | Z_SET_REFCOUNT(obj, 0); 907 | object_init_ex(&obj, fast_assert_ce); 908 | return Z_OBJ_HANDLE(obj); 909 | } 910 | 911 | PHP_MINIT_FUNCTION(fast_assert) 912 | { 913 | // register the fast assert class 914 | zend_class_entry ce; 915 | INIT_CLASS_ENTRY(ce, "Assert", fast_assert_methods); 916 | fast_assert_ce = zend_register_internal_class(&ce TSRMLS_CC); 917 | 918 | fake_assert_obj_handlers = *zend_get_std_object_handlers(); 919 | fake_assert_obj_handlers.add_ref = stub_add_ref; 920 | fake_assert_obj_handlers.del_ref = stub_del_ref; 921 | fake_assert_obj_handlers.clone_obj = stub_clone_obj; 922 | 923 | /* init thread-safe fast assert global struct */ 924 | #ifdef ZTS 925 | ts_allocate_id(&fa_globals_id, sizeof(fast_assert_globals), NULL, NULL); 926 | #endif 927 | 928 | return SUCCESS; 929 | } 930 | 931 | PHP_RINIT_FUNCTION(fast_assert) 932 | { 933 | // register the 3 important assert objects! 934 | AssertGlobals(invalid_arg_assert_handle) = create_new_assert_object(TSRMLS_C); 935 | AssertGlobals(unexpected_val_assert_handle) = create_new_assert_object(TSRMLS_C); 936 | AssertGlobals(logic_exception_assert_handle) = create_new_assert_object(TSRMLS_C); 937 | return SUCCESS; 938 | } 939 | 940 | //// BEGIN BOILERPLATE ////// 941 | 942 | zend_module_entry fast_assert_module_entry = { 943 | #if ZEND_MODULE_API_NO >= 20010901 944 | STANDARD_MODULE_HEADER, 945 | #endif 946 | PHP_FAST_ASSERT_EXTNAME, 947 | NULL, /* functions */ 948 | PHP_MINIT(fast_assert), /* minit */ 949 | NULL, /* MSHUTDOWN */ 950 | //NULL, /* RINIT */ 951 | PHP_RINIT(fast_assert), /* RINIT */ 952 | NULL, /* RSHUTDOWN */ 953 | NULL, /* MINFO */ 954 | #if ZEND_MODULE_API_NO >= 20010901 955 | PHP_FAST_ASSERT_VERSION, 956 | #endif 957 | STANDARD_MODULE_PROPERTIES 958 | }; 959 | 960 | #ifdef COMPILE_DL_FAST_ASSERT 961 | extern "C" { 962 | ZEND_GET_MODULE(fast_assert) 963 | } 964 | #endif 965 | 966 | //// END BOILERPLATE ////// 967 | --------------------------------------------------------------------------------