From a4c61df6ec742c87196a0c732485095b3415103f Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 13 Jan 2022 23:36:58 +0100 Subject: [PATCH 01/29] feat: integration tests --- Cargo.toml | 3 +- guide/src/types/binary.md | 4 +- tests/Cargo.toml | 12 ++ tests/integration/array.php | 3 + tests/integration/array_assoc.php | 13 ++ tests/integration/binary.php | 6 + tests/integration/bool.php | 9 + tests/integration/callable.php | 3 + tests/integration/class.php | 5 + tests/integration/closure.php | 3 + tests/integration/closure_once.php | 11 ++ tests/integration/nullable.php | 5 + tests/integration/number_float.php | 7 + tests/integration/number_signed.php | 7 + tests/integration/number_unsigned.php | 12 ++ tests/integration/object.php | 14 ++ tests/integration/str.php | 3 + tests/integration/string.php | 3 + tests/src/lib.rs | 226 ++++++++++++++++++++++++++ 19 files changed, 346 insertions(+), 3 deletions(-) create mode 100644 tests/Cargo.toml create mode 100644 tests/integration/array.php create mode 100644 tests/integration/array_assoc.php create mode 100644 tests/integration/binary.php create mode 100644 tests/integration/bool.php create mode 100644 tests/integration/callable.php create mode 100644 tests/integration/class.php create mode 100644 tests/integration/closure.php create mode 100644 tests/integration/closure_once.php create mode 100644 tests/integration/nullable.php create mode 100644 tests/integration/number_float.php create mode 100644 tests/integration/number_signed.php create mode 100644 tests/integration/number_unsigned.php create mode 100644 tests/integration/object.php create mode 100644 tests/integration/str.php create mode 100644 tests/integration/string.php create mode 100644 tests/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 0c80d8bb8e..c117f3a969 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,8 @@ closure = [] [workspace] members = [ "crates/macros", - "crates/cli" + "crates/cli", + "tests" ] [package.metadata.docs.rs] diff --git a/guide/src/types/binary.md b/guide/src/types/binary.md index ea6d72548f..c1c6ef1507 100644 --- a/guide/src/types/binary.md +++ b/guide/src/types/binary.md @@ -43,7 +43,7 @@ pub fn test_binary(input: Binary) -> Binary { ```php 5, [1] => 4, [2] => 3, [3] => 2, [4] => 1 } ``` diff --git a/tests/Cargo.toml b/tests/Cargo.toml new file mode 100644 index 0000000000..55aef21025 --- /dev/null +++ b/tests/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "tests" +version = "0.0.0" +edition = "2021" +publish = false +license = "MIT OR Apache-2.0" + +[dependencies] +ext-php-rs = { path = "../", features = ["closure"] } + +[lib] +crate-type = ["cdylib"] \ No newline at end of file diff --git a/tests/integration/array.php b/tests/integration/array.php new file mode 100644 index 0000000000..4f77eaf5b0 --- /dev/null +++ b/tests/integration/array.php @@ -0,0 +1,3 @@ + '1', + 'second' => '2', + 'third' => '3' +]) as $key => $value) { + $output .= "{$key}={$value} "; +} + +echo trim($output); diff --git a/tests/integration/binary.php b/tests/integration/binary.php new file mode 100644 index 0000000000..210fbdc74a --- /dev/null +++ b/tests/integration/binary.php @@ -0,0 +1,6 @@ + $a, 'callable works'); diff --git a/tests/integration/class.php b/tests/integration/class.php new file mode 100644 index 0000000000..ac2270e6b9 --- /dev/null +++ b/tests/integration/class.php @@ -0,0 +1,5 @@ +test(); diff --git a/tests/integration/closure.php b/tests/integration/closure.php new file mode 100644 index 0000000000..3f1274e17a --- /dev/null +++ b/tests/integration/closure.php @@ -0,0 +1,3 @@ +first = 1; +$obj->second = 2; +$obj->third = 3; + +$output = ''; + +foreach (test_object($obj) as $key => $value) { + $output .= "{$key}={$value} "; +} + +echo trim($output); diff --git a/tests/integration/str.php b/tests/integration/str.php new file mode 100644 index 0000000000..bec4aa656d --- /dev/null +++ b/tests/integration/str.php @@ -0,0 +1,3 @@ + &str { + a +} + +#[php_function] +pub fn test_string(a: String) -> String { + a +} + +#[php_function] +pub fn test_bool(a: bool) -> bool { + a +} + +#[php_function] +pub fn test_number_signed(a: i32) -> i32 { + a +} + +#[php_function] +pub fn test_number_unsigned(a: u32) -> u32 { + a +} + +#[php_function] +pub fn test_number_float(a: f32) -> f32 { + a +} + +#[php_function] +pub fn test_array(a: Vec) -> Vec { + a +} + +#[php_function] +pub fn test_array_assoc(a: HashMap) -> HashMap { + a +} + +#[php_function] +pub fn test_binary(a: Binary) -> Binary { + a +} + +#[php_function] +pub fn test_nullable(a: Option) -> Option { + a +} + +#[php_function] +pub fn test_object(a: &mut ZendObject) -> &mut ZendObject { + a +} + +// TODO: not returning a closure +#[php_function] +pub fn test_closure() -> Closure { + Closure::wrap(Box::new(|a| a) as Box String>) +} + +// TODO: not returning a closure +#[php_function] +pub fn test_closure_once(a: String) -> Closure { + let example = a.clone(); + Closure::wrap_once(Box::new(move || example) as Box String>) +} + +#[php_function] +pub fn test_callable(call: ZendCallable, a: String) -> Zval { + call.try_call(vec![&a]).expect("Failed to call function") +} + +#[php_class] +pub struct TestClass { + foo: String, + bar: String, +} + +#[php_impl] +impl TestClass { + pub fn test(&self) -> String { + format!("{} {}", self.foo, self.bar) + } +} + +#[php_function] +pub fn test_class(foo: String, bar: String) -> TestClass { + TestClass { foo, bar } +} + +#[php_module] +pub fn get_module(module: ModuleBuilder) -> ModuleBuilder { + module +} + +#[cfg(test)] +mod tests { + use std::process::Command; + use std::sync::Once; + + static BUILD: Once = Once::new(); + + #[cfg(target_os = "linux")] + const EXTENSION: &str = "so"; + #[cfg(target_os = "macos")] + const EXTENSION: &str = "dylib"; + #[cfg(target_os = "windows")] + const EXTENSION: &str = "dll"; + + fn setup() { + BUILD.call_once(|| { + Command::new("cargo") + .arg("build") + .output() + .expect("failed to execute process") + .status + .success(); + }); + } + + fn run_php(file: &str) -> String { + setup(); + String::from_utf8( + Command::new("php") + .arg(format!( + "-dextension=../target/debug/libtests.{}", + EXTENSION + )) + .arg(format!("integration/{}", file)) + .output() + .expect("failed to run php file") + .stdout, + ) + .unwrap() + } + + #[test] + fn str_works() { + assert_eq!(run_php("str.php"), "str works"); + } + + #[test] + fn string_works() { + assert_eq!(run_php("string.php"), "string works"); + } + + #[test] + fn bool_works() { + assert_eq!(run_php("bool.php"), "true false"); + } + + #[test] + fn number_signed_works() { + assert_eq!(run_php("number_signed.php"), "-12 0 12"); + } + + #[test] + fn number_unsigned_works() { + assert_eq!(run_php("number_unsigned.php"), "thrown 0 12"); + } + + #[test] + fn number_float_works() { + let output = run_php("number_float.php"); + let floats: Vec = output + .split_whitespace() + .map(|a| a.parse::().unwrap()) + .collect(); + assert_eq!(floats, vec![-1.2, 0.0, 1.2]); + } + + #[test] + fn array_works() { + assert_eq!(run_php("array.php"), "a b c"); + } + + #[test] + fn array_assoc_works() { + let output = run_php("array_assoc.php"); + assert_eq!(output.contains("first=1"), true); + assert_eq!(output.contains("second=2"), true); + assert_eq!(output.contains("third=3"), true); + } + + #[test] + fn binary_works() { + assert_eq!(run_php("binary.php"), "1 2 3 4 5"); + } + + #[test] + fn nullable_works() { + assert_eq!(run_php("nullable.php"), "null not_null"); + } + + #[test] + fn object_works() { + let output = run_php("object.php"); + assert_eq!(output.contains("first=1"), true); + assert_eq!(output.contains("second=2"), true); + assert_eq!(output.contains("third=3"), true); + } + + #[test] + fn closure_works() { + assert_eq!(run_php("closure.php"), "closure works"); + } + + #[test] + fn closure_once_works() { + assert_eq!(run_php("closure_once.php"), "closure works once"); + } + + #[test] + fn callable_works() { + assert_eq!(run_php("callable.php"), "callable works"); + } + + #[test] + fn class_works() { + assert_eq!(run_php("class.php"), "class works"); + } +} From 216918a1a36621baf2c83ed45dfad9300269fc50 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 13 Jan 2022 23:39:05 +0100 Subject: [PATCH 02/29] fix: some leftovers in tests --- tests/integration/class.php | 2 +- tests/integration/number_unsigned.php | 13 ++++++------- tests/src/lib.rs | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/tests/integration/class.php b/tests/integration/class.php index ac2270e6b9..4634139225 100644 --- a/tests/integration/class.php +++ b/tests/integration/class.php @@ -1,5 +1,5 @@ test(); diff --git a/tests/integration/number_unsigned.php b/tests/integration/number_unsigned.php index 8ade7dfee5..f34226055b 100644 --- a/tests/integration/number_unsigned.php +++ b/tests/integration/number_unsigned.php @@ -1,12 +1,11 @@ Date: Thu, 13 Jan 2022 23:40:04 +0100 Subject: [PATCH 03/29] chore: remove todos --- tests/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 8572edde78..5e867344f0 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -56,13 +56,11 @@ pub fn test_object(a: &mut ZendObject) -> &mut ZendObject { a } -// TODO: not returning a closure #[php_function] pub fn test_closure() -> Closure { Closure::wrap(Box::new(|a| a) as Box String>) } -// TODO: not returning a closure #[php_function] pub fn test_closure_once(a: String) -> Closure { let example = a.clone(); From 09bf50d3bd2cf1cb47071153820abb52b02bb6ab Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 13 Jan 2022 23:45:22 +0100 Subject: [PATCH 04/29] fix: remove unnecessary lines --- tests/integration/array_assoc.php | 2 -- tests/integration/object.php | 2 -- 2 files changed, 4 deletions(-) diff --git a/tests/integration/array_assoc.php b/tests/integration/array_assoc.php index af62f27eaf..84af0fce61 100644 --- a/tests/integration/array_assoc.php +++ b/tests/integration/array_assoc.php @@ -1,7 +1,5 @@ '1', 'second' => '2', diff --git a/tests/integration/object.php b/tests/integration/object.php index baec4a3d9d..140fd99427 100644 --- a/tests/integration/object.php +++ b/tests/integration/object.php @@ -5,8 +5,6 @@ $obj->second = 2; $obj->third = 3; -$output = ''; - foreach (test_object($obj) as $key => $value) { $output .= "{$key}={$value} "; } From 2b9ca2a6e2eb05d2d7cbffa7e1caa606f13b235c Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 14 Jan 2022 13:21:48 +0100 Subject: [PATCH 05/29] chore: fix some styling --- tests/integration/closure_once.php | 3 +-- tests/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/integration/closure_once.php b/tests/integration/closure_once.php index 9f20accc6c..9e029e292f 100644 --- a/tests/integration/closure_once.php +++ b/tests/integration/closure_once.php @@ -1,7 +1,6 @@ Date: Fri, 14 Jan 2022 13:29:23 +0100 Subject: [PATCH 06/29] test: assert build status code --- tests/src/lib.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/src/lib.rs b/tests/src/lib.rs index beb3c8c4c8..d94d69d7d1 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -111,12 +111,15 @@ mod tests { fn setup() { BUILD.call_once(|| { - Command::new("cargo") - .arg("build") - .output() - .expect("failed to build extension") - .status - .success(); + assert_eq!( + Command::new("cargo") + .arg("build") + .output() + .expect("failed to build extension") + .status + .success(), + true + ); }); } From 04d81a78cff713b5e09d3973d4c2ad7734e3bd30 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 14 Jan 2022 13:35:48 +0100 Subject: [PATCH 07/29] test: remove unnecessary assignment --- tests/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/src/lib.rs b/tests/src/lib.rs index d94d69d7d1..524a6d2981 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -63,8 +63,7 @@ pub fn test_closure() -> Closure { #[php_function] pub fn test_closure_once(a: String) -> Closure { - let example = a.clone(); - Closure::wrap_once(Box::new(move || example) as Box String>) + Closure::wrap_once(Box::new(move || a) as Box String>) } #[php_function] From b363c1a79f5199550bd790e76f0a08daaef72d67 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 14 Jan 2022 13:38:45 +0100 Subject: [PATCH 08/29] lint: replace assert_eq with assert --- tests/src/lib.rs | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 524a6d2981..98f6fb4fe7 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -140,27 +140,27 @@ mod tests { #[test] fn str_works() { - assert_eq!(run_php("str.php"), "str works"); + assert!(run_php("str.php") == "str works"); } #[test] fn string_works() { - assert_eq!(run_php("string.php"), "string works"); + assert!(run_php("string.php") == "string works"); } #[test] fn bool_works() { - assert_eq!(run_php("bool.php"), "true false"); + assert!(run_php("bool.php") == "true false"); } #[test] fn number_signed_works() { - assert_eq!(run_php("number_signed.php"), "-12 0 12"); + assert!(run_php("number_signed.php") == "-12 0 12"); } #[test] fn number_unsigned_works() { - assert_eq!(run_php("number_unsigned.php"), "0 12 invalid"); + assert!(run_php("number_unsigned.php") == "0 12 invalid"); } #[test] @@ -170,57 +170,57 @@ mod tests { .split_whitespace() .map(|a| a.parse::().unwrap()) .collect(); - assert_eq!(floats, vec![-1.2, 0.0, 1.2]); + assert!(floats == vec![-1.2, 0.0, 1.2]); } #[test] fn array_works() { - assert_eq!(run_php("array.php"), "a b c"); + assert!(run_php("array.php") == "a b c"); } #[test] fn array_assoc_works() { let output = run_php("array_assoc.php"); - assert_eq!(output.contains("first=1"), true); - assert_eq!(output.contains("second=2"), true); - assert_eq!(output.contains("third=3"), true); + assert!(output.contains("first=1")); + assert!(output.contains("second=2")); + assert!(output.contains("third=3")); } #[test] fn binary_works() { - assert_eq!(run_php("binary.php"), "1 2 3 4 5"); + assert!(run_php("binary.php") = "1 2 3 4 5"); } #[test] fn nullable_works() { - assert_eq!(run_php("nullable.php"), "null not_null"); + assert!(run_php("nullable.php") == "null not_null"); } #[test] fn object_works() { let output = run_php("object.php"); - assert_eq!(output.contains("first=1"), true); - assert_eq!(output.contains("second=2"), true); - assert_eq!(output.contains("third=3"), true); + assert!(output.contains("first=1")); + assert!(output.contains("second=2")); + assert!(output.contains("third=3")); } #[test] fn closure_works() { - assert_eq!(run_php("closure.php"), "closure works"); + assert!(run_php("closure.php") == "closure works"); } #[test] fn closure_once_works() { - assert_eq!(run_php("closure_once.php"), "closure works once"); + assert!(run_php("closure_once.php") == "closure works once"); } #[test] fn callable_works() { - assert_eq!(run_php("callable.php"), "callable works"); + assert!(run_php("callable.php") == "callable works"); } #[test] fn class_works() { - assert_eq!(run_php("class.php"), "class works"); + assert!(run_php("class.php") == "class works"); } } From ff14190266724deec55199901597132c5b455123 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 14 Jan 2022 15:02:12 +0100 Subject: [PATCH 09/29] tests: fix condition --- tests/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 98f6fb4fe7..03f1b87f43 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -188,7 +188,7 @@ mod tests { #[test] fn binary_works() { - assert!(run_php("binary.php") = "1 2 3 4 5"); + assert!(run_php("binary.php") == "1 2 3 4 5"); } #[test] From df838e947c933ae253b139cccf9c163e91e2ce52 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sat, 15 Jan 2022 22:46:29 +0100 Subject: [PATCH 10/29] ci: use os from matrix --- .github/workflows/build.yml | 2 +- tests/src/lib.rs | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e09858bac8..a7996d88cf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,7 +8,7 @@ on: jobs: build: name: Build and Test - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: matrix: os: diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 03f1b87f43..2639e6e39b 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -101,13 +101,6 @@ mod tests { static BUILD: Once = Once::new(); - #[cfg(target_os = "linux")] - const EXTENSION: &str = "so"; - #[cfg(target_os = "macos")] - const EXTENSION: &str = "dylib"; - #[cfg(target_os = "windows")] - const EXTENSION: &str = "dll"; - fn setup() { BUILD.call_once(|| { assert_eq!( @@ -128,7 +121,7 @@ mod tests { Command::new("php") .arg(format!( "-dextension=../target/debug/libtests.{}", - EXTENSION + std::env::consts::DLL_EXTENSION )) .arg(format!("integration/{}", file)) .output() From 6d80fb7f258147b6ee0e70ab3a4112a99dc86249 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 16 Jan 2022 15:18:39 +0100 Subject: [PATCH 11/29] tests: restructure --- tests/integration/array.php | 3 - tests/integration/array_assoc.php | 11 -- tests/integration/binary.php | 6 - tests/integration/bool.php | 9 -- tests/integration/callable.php | 3 - tests/integration/class.php | 5 - tests/integration/closure.php | 3 - tests/integration/closure_once.php | 10 -- tests/integration/nullable.php | 5 - tests/integration/number_float.php | 7 -- tests/integration/number_signed.php | 7 -- tests/integration/number_unsigned.php | 11 -- tests/integration/object.php | 12 -- tests/integration/str.php | 3 - tests/integration/string.php | 3 - tests/src/integration/_utils.php | 15 +++ tests/src/integration/array.php | 26 ++++ tests/src/integration/array.rs | 4 + tests/src/integration/binary.php | 13 ++ tests/src/integration/binary.rs | 4 + tests/src/integration/bool.php | 6 + tests/src/integration/bool.rs | 4 + tests/src/integration/callable.php | 5 + tests/src/integration/callable.rs | 4 + tests/src/integration/class.php | 21 ++++ tests/src/integration/class.rs | 4 + tests/src/integration/closure.php | 13 ++ tests/src/integration/closure.rs | 4 + tests/src/integration/nullable.php | 6 + tests/src/integration/nullable.rs | 4 + tests/src/integration/number.php | 18 +++ tests/src/integration/number.rs | 4 + tests/src/integration/object.php | 16 +++ tests/src/integration/object.rs | 4 + tests/src/integration/string.php | 6 + tests/src/integration/string.rs | 4 + tests/src/lib.rs | 173 +++++++++----------------- 37 files changed, 242 insertions(+), 214 deletions(-) delete mode 100644 tests/integration/array.php delete mode 100644 tests/integration/array_assoc.php delete mode 100644 tests/integration/binary.php delete mode 100644 tests/integration/bool.php delete mode 100644 tests/integration/callable.php delete mode 100644 tests/integration/class.php delete mode 100644 tests/integration/closure.php delete mode 100644 tests/integration/closure_once.php delete mode 100644 tests/integration/nullable.php delete mode 100644 tests/integration/number_float.php delete mode 100644 tests/integration/number_signed.php delete mode 100644 tests/integration/number_unsigned.php delete mode 100644 tests/integration/object.php delete mode 100644 tests/integration/str.php delete mode 100644 tests/integration/string.php create mode 100644 tests/src/integration/_utils.php create mode 100644 tests/src/integration/array.php create mode 100644 tests/src/integration/array.rs create mode 100644 tests/src/integration/binary.php create mode 100644 tests/src/integration/binary.rs create mode 100644 tests/src/integration/bool.php create mode 100644 tests/src/integration/bool.rs create mode 100644 tests/src/integration/callable.php create mode 100644 tests/src/integration/callable.rs create mode 100644 tests/src/integration/class.php create mode 100644 tests/src/integration/class.rs create mode 100644 tests/src/integration/closure.php create mode 100644 tests/src/integration/closure.rs create mode 100644 tests/src/integration/nullable.php create mode 100644 tests/src/integration/nullable.rs create mode 100644 tests/src/integration/number.php create mode 100644 tests/src/integration/number.rs create mode 100644 tests/src/integration/object.php create mode 100644 tests/src/integration/object.rs create mode 100644 tests/src/integration/string.php create mode 100644 tests/src/integration/string.rs diff --git a/tests/integration/array.php b/tests/integration/array.php deleted file mode 100644 index 4f77eaf5b0..0000000000 --- a/tests/integration/array.php +++ /dev/null @@ -1,3 +0,0 @@ - '1', - 'second' => '2', - 'third' => '3' -]) as $key => $value) { - $output .= "{$key}={$value} "; -} - -echo trim($output); diff --git a/tests/integration/binary.php b/tests/integration/binary.php deleted file mode 100644 index 210fbdc74a..0000000000 --- a/tests/integration/binary.php +++ /dev/null @@ -1,6 +0,0 @@ - $a, 'callable works'); diff --git a/tests/integration/class.php b/tests/integration/class.php deleted file mode 100644 index 4634139225..0000000000 --- a/tests/integration/class.php +++ /dev/null @@ -1,5 +0,0 @@ -test(); diff --git a/tests/integration/closure.php b/tests/integration/closure.php deleted file mode 100644 index 3f1274e17a..0000000000 --- a/tests/integration/closure.php +++ /dev/null @@ -1,3 +0,0 @@ -first = 1; -$obj->second = 2; -$obj->third = 3; - -foreach (test_object($obj) as $key => $value) { - $output .= "{$key}={$value} "; -} - -echo trim($output); diff --git a/tests/integration/str.php b/tests/integration/str.php deleted file mode 100644 index bec4aa656d..0000000000 --- a/tests/integration/str.php +++ /dev/null @@ -1,3 +0,0 @@ - exit(1)); + +function assert_exception_thrown(callable $callback): void +{ + try { + call_user_func($callback); + exit(1); + } catch (\Throwable $th) { + } +} diff --git a/tests/src/integration/array.php b/tests/src/integration/array.php new file mode 100644 index 0000000000..b17a99eca5 --- /dev/null +++ b/tests/src/integration/array.php @@ -0,0 +1,26 @@ + '1', + 'b' => '2', + 'c' => '3' +]); + +assert(array_key_exists('a', $assoc)); +assert(array_key_exists('b', $assoc)); +assert(array_key_exists('c', $assoc)); +assert(in_array('1', $assoc)); +assert(in_array('2', $assoc)); +assert(in_array('3', $assoc)); diff --git a/tests/src/integration/array.rs b/tests/src/integration/array.rs new file mode 100644 index 0000000000..aeb26dbb56 --- /dev/null +++ b/tests/src/integration/array.rs @@ -0,0 +1,4 @@ +#[test] +fn binary_works() { + assert!(crate::integration::run_php("array.php")); +} \ No newline at end of file diff --git a/tests/src/integration/binary.php b/tests/src/integration/binary.php new file mode 100644 index 0000000000..30cbd429f7 --- /dev/null +++ b/tests/src/integration/binary.php @@ -0,0 +1,13 @@ + $a, 'test') === 'test'); diff --git a/tests/src/integration/callable.rs b/tests/src/integration/callable.rs new file mode 100644 index 0000000000..aad05c71d8 --- /dev/null +++ b/tests/src/integration/callable.rs @@ -0,0 +1,4 @@ +#[test] +fn callable_works() { + assert!(crate::integration::run_php("callable.php")); +} \ No newline at end of file diff --git a/tests/src/integration/class.php b/tests/src/integration/class.php new file mode 100644 index 0000000000..568cafbb17 --- /dev/null +++ b/tests/src/integration/class.php @@ -0,0 +1,21 @@ +getString() === 'lorem ipsum'); +$class->setString('dolor et'); +assert($class->getString() === 'dolor et'); + +assert($class->getNumber() === 2022); +$class->setNumber(2023); +assert($class->getNumber() === 2023); + +// Tests #prop decorator +assert($class->boolean); +$class->boolean = false; +assert($class->boolean === false); diff --git a/tests/src/integration/class.rs b/tests/src/integration/class.rs new file mode 100644 index 0000000000..0c97ff86b6 --- /dev/null +++ b/tests/src/integration/class.rs @@ -0,0 +1,4 @@ +#[test] +fn class_works() { + assert!(crate::integration::run_php("class.php")); +} \ No newline at end of file diff --git a/tests/src/integration/closure.php b/tests/src/integration/closure.php new file mode 100644 index 0000000000..8f202fc175 --- /dev/null +++ b/tests/src/integration/closure.php @@ -0,0 +1,13 @@ + $closure()); diff --git a/tests/src/integration/closure.rs b/tests/src/integration/closure.rs new file mode 100644 index 0000000000..58b44ad1b3 --- /dev/null +++ b/tests/src/integration/closure.rs @@ -0,0 +1,4 @@ +#[test] +fn closure_works() { + assert!(crate::integration::run_php("closure.php")); +} \ No newline at end of file diff --git a/tests/src/integration/nullable.php b/tests/src/integration/nullable.php new file mode 100644 index 0000000000..f3ba326818 --- /dev/null +++ b/tests/src/integration/nullable.php @@ -0,0 +1,6 @@ + test_number_unsigned(-12)); + +// Float +assert(round(test_number_float(-1.2), 2) === round(-1.2, 2)); +assert(round(test_number_float(0.0), 2) === round(0.0, 2)); +assert(round(test_number_float(1.2), 2) === round(1.2, 2)); diff --git a/tests/src/integration/number.rs b/tests/src/integration/number.rs new file mode 100644 index 0000000000..eb56e12531 --- /dev/null +++ b/tests/src/integration/number.rs @@ -0,0 +1,4 @@ +#[test] +fn number_works() { + assert!(crate::integration::run_php("number.php")); +} \ No newline at end of file diff --git a/tests/src/integration/object.php b/tests/src/integration/object.php new file mode 100644 index 0000000000..c0b4c3fac5 --- /dev/null +++ b/tests/src/integration/object.php @@ -0,0 +1,16 @@ +string = 'string'; +$obj->bool = true; +$obj->number = 2022; +$obj->array = [ + 1, 2, 3 +]; + +$test = test_object($obj); + +assert($test->string === 'string'); +assert($test->bool === true); +assert($test->number === 2022); +assert($test->array === [1, 2, 3]); diff --git a/tests/src/integration/object.rs b/tests/src/integration/object.rs new file mode 100644 index 0000000000..3c8f7c446b --- /dev/null +++ b/tests/src/integration/object.rs @@ -0,0 +1,4 @@ +#[test] +fn object_works() { + assert!(crate::integration::run_php("object.php")); +} \ No newline at end of file diff --git a/tests/src/integration/string.php b/tests/src/integration/string.php new file mode 100644 index 0000000000..63e111f56d --- /dev/null +++ b/tests/src/integration/string.php @@ -0,0 +1,6 @@ + Zval { #[php_class] pub struct TestClass { - foo: String, - bar: String, + string: String, + number: i32, + #[prop] + boolean: bool, } #[php_impl] impl TestClass { - pub fn test(&self) -> String { - format!("{} {}", self.foo, self.bar) + #[getter] + pub fn get_string(&self) -> String { + self.string.to_string() + } + + #[setter] + pub fn set_string(&mut self, string: String) { + self.string = string; + } + + #[getter] + pub fn get_number(&self) -> i32 { + self.number + } + + #[setter] + pub fn set_number(&mut self, number: i32) { + self.number = number; } } #[php_function] -pub fn test_class(foo: String, bar: String) -> TestClass { - TestClass { foo, bar } +pub fn test_class(string: String, number: i32) -> TestClass { + TestClass { + string, + number, + boolean: true, + } } #[php_module] @@ -95,7 +117,7 @@ pub fn get_module(module: ModuleBuilder) -> ModuleBuilder { } #[cfg(test)] -mod tests { +mod integration { use std::process::Command; use std::sync::Once; @@ -103,117 +125,36 @@ mod tests { fn setup() { BUILD.call_once(|| { - assert_eq!( - Command::new("cargo") - .arg("build") - .output() - .expect("failed to build extension") - .status - .success(), - true - ); + assert!(Command::new("cargo") + .arg("build") + .output() + .expect("failed to build extension") + .status + .success()); }); } - fn run_php(file: &str) -> String { + pub fn run_php(file: &str) -> bool { setup(); - String::from_utf8( - Command::new("php") - .arg(format!( - "-dextension=../target/debug/libtests.{}", - std::env::consts::DLL_EXTENSION - )) - .arg(format!("integration/{}", file)) - .output() - .expect("failed to run php file") - .stdout, - ) - .unwrap() - } - - #[test] - fn str_works() { - assert!(run_php("str.php") == "str works"); - } - - #[test] - fn string_works() { - assert!(run_php("string.php") == "string works"); - } - - #[test] - fn bool_works() { - assert!(run_php("bool.php") == "true false"); - } - - #[test] - fn number_signed_works() { - assert!(run_php("number_signed.php") == "-12 0 12"); - } - - #[test] - fn number_unsigned_works() { - assert!(run_php("number_unsigned.php") == "0 12 invalid"); - } - - #[test] - fn number_float_works() { - let output = run_php("number_float.php"); - let floats: Vec = output - .split_whitespace() - .map(|a| a.parse::().unwrap()) - .collect(); - assert!(floats == vec![-1.2, 0.0, 1.2]); - } - - #[test] - fn array_works() { - assert!(run_php("array.php") == "a b c"); - } - - #[test] - fn array_assoc_works() { - let output = run_php("array_assoc.php"); - assert!(output.contains("first=1")); - assert!(output.contains("second=2")); - assert!(output.contains("third=3")); - } - - #[test] - fn binary_works() { - assert!(run_php("binary.php") == "1 2 3 4 5"); - } - - #[test] - fn nullable_works() { - assert!(run_php("nullable.php") == "null not_null"); - } - - #[test] - fn object_works() { - let output = run_php("object.php"); - assert!(output.contains("first=1")); - assert!(output.contains("second=2")); - assert!(output.contains("third=3")); - } - - #[test] - fn closure_works() { - assert!(run_php("closure.php") == "closure works"); - } - - #[test] - fn closure_once_works() { - assert!(run_php("closure_once.php") == "closure works once"); - } - - #[test] - fn callable_works() { - assert!(run_php("callable.php") == "callable works"); - } - - #[test] - fn class_works() { - assert!(run_php("class.php") == "class works"); - } + Command::new("php") + .arg(format!( + "-dextension=../target/debug/libtests.{}", + std::env::consts::DLL_EXTENSION + )) + .arg(format!("src/integration/{}", file)) + .status() + .expect("failed to run php file") + .success() + } + + mod array; + mod binary; + mod bool; + mod callable; + mod class; + mod closure; + mod nullable; + mod number; + mod object; + mod string; } From b283f03c95b2494a29a3947b79648d5c52a458dd Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 16 Jan 2022 15:18:56 +0100 Subject: [PATCH 12/29] chore: run cargo fmt --- tests/src/integration/array.rs | 2 +- tests/src/integration/binary.rs | 2 +- tests/src/integration/bool.rs | 2 +- tests/src/integration/callable.rs | 2 +- tests/src/integration/class.rs | 2 +- tests/src/integration/closure.rs | 2 +- tests/src/integration/nullable.rs | 2 +- tests/src/integration/number.rs | 2 +- tests/src/integration/object.rs | 2 +- tests/src/integration/string.rs | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/src/integration/array.rs b/tests/src/integration/array.rs index aeb26dbb56..447ece1bde 100644 --- a/tests/src/integration/array.rs +++ b/tests/src/integration/array.rs @@ -1,4 +1,4 @@ #[test] fn binary_works() { assert!(crate::integration::run_php("array.php")); -} \ No newline at end of file +} diff --git a/tests/src/integration/binary.rs b/tests/src/integration/binary.rs index 2d5e9343fe..b47abc3886 100644 --- a/tests/src/integration/binary.rs +++ b/tests/src/integration/binary.rs @@ -1,4 +1,4 @@ #[test] fn binary_works() { assert!(crate::integration::run_php("binary.php")); -} \ No newline at end of file +} diff --git a/tests/src/integration/bool.rs b/tests/src/integration/bool.rs index a7ccaa8c37..aadf22aa97 100644 --- a/tests/src/integration/bool.rs +++ b/tests/src/integration/bool.rs @@ -1,4 +1,4 @@ #[test] fn bool_works() { assert!(crate::integration::run_php("bool.php")); -} \ No newline at end of file +} diff --git a/tests/src/integration/callable.rs b/tests/src/integration/callable.rs index aad05c71d8..1d4ac2d512 100644 --- a/tests/src/integration/callable.rs +++ b/tests/src/integration/callable.rs @@ -1,4 +1,4 @@ #[test] fn callable_works() { assert!(crate::integration::run_php("callable.php")); -} \ No newline at end of file +} diff --git a/tests/src/integration/class.rs b/tests/src/integration/class.rs index 0c97ff86b6..525220e859 100644 --- a/tests/src/integration/class.rs +++ b/tests/src/integration/class.rs @@ -1,4 +1,4 @@ #[test] fn class_works() { assert!(crate::integration::run_php("class.php")); -} \ No newline at end of file +} diff --git a/tests/src/integration/closure.rs b/tests/src/integration/closure.rs index 58b44ad1b3..fad7e3c255 100644 --- a/tests/src/integration/closure.rs +++ b/tests/src/integration/closure.rs @@ -1,4 +1,4 @@ #[test] fn closure_works() { assert!(crate::integration::run_php("closure.php")); -} \ No newline at end of file +} diff --git a/tests/src/integration/nullable.rs b/tests/src/integration/nullable.rs index 197b786845..5fc911722b 100644 --- a/tests/src/integration/nullable.rs +++ b/tests/src/integration/nullable.rs @@ -1,4 +1,4 @@ #[test] fn nullable_works() { assert!(crate::integration::run_php("nullable.php")); -} \ No newline at end of file +} diff --git a/tests/src/integration/number.rs b/tests/src/integration/number.rs index eb56e12531..94a518c4c8 100644 --- a/tests/src/integration/number.rs +++ b/tests/src/integration/number.rs @@ -1,4 +1,4 @@ #[test] fn number_works() { assert!(crate::integration::run_php("number.php")); -} \ No newline at end of file +} diff --git a/tests/src/integration/object.rs b/tests/src/integration/object.rs index 3c8f7c446b..11f70dbb7d 100644 --- a/tests/src/integration/object.rs +++ b/tests/src/integration/object.rs @@ -1,4 +1,4 @@ #[test] fn object_works() { assert!(crate::integration::run_php("object.php")); -} \ No newline at end of file +} diff --git a/tests/src/integration/string.rs b/tests/src/integration/string.rs index 0328f4b550..8f95dd5df4 100644 --- a/tests/src/integration/string.rs +++ b/tests/src/integration/string.rs @@ -1,4 +1,4 @@ #[test] fn string_works() { assert!(crate::integration::run_php("string.php")); -} \ No newline at end of file +} From aefed6efc78d8b6e5a7d97b8eea5745f35662b16 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 16 Jan 2022 15:44:40 +0100 Subject: [PATCH 13/29] cI: revert change for now --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a7996d88cf..e09858bac8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,7 +8,7 @@ on: jobs: build: name: Build and Test - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest strategy: matrix: os: From 854f1d66cb6d5d0ffda5d820585ace47d3b064b8 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 16 Jan 2022 18:09:53 +0100 Subject: [PATCH 14/29] tests: show more informations --- tests/src/integration/_utils.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/src/integration/_utils.php b/tests/src/integration/_utils.php index 8daca465be..1c7139127d 100644 --- a/tests/src/integration/_utils.php +++ b/tests/src/integration/_utils.php @@ -2,8 +2,6 @@ // Active assert and make it quiet assert_options(ASSERT_ACTIVE, 1); assert_options(ASSERT_WARNING, 0); -// Set up the callback -assert_options(ASSERT_CALLBACK, fn () => exit(1)); function assert_exception_thrown(callable $callback): void { From eb5a768c462ee0a01389b200caa689b4556b64d6 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 16 Jan 2022 18:25:35 +0100 Subject: [PATCH 15/29] tests: show stdout on error --- tests/src/lib.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 20cf2a22d9..202a468db2 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -127,6 +127,7 @@ mod integration { BUILD.call_once(|| { assert!(Command::new("cargo") .arg("build") + .arg("--release") .output() .expect("failed to build extension") .status @@ -136,15 +137,19 @@ mod integration { pub fn run_php(file: &str) -> bool { setup(); - Command::new("php") + let output = Command::new("php") .arg(format!( - "-dextension=../target/debug/libtests.{}", + "-dextension=../target/release/libtests.{}", std::env::consts::DLL_EXTENSION )) .arg(format!("src/integration/{}", file)) - .status() - .expect("failed to run php file") - .success() + .output() + .expect("failed to run php file"); + if output.status.success() { + true + } else { + panic!("{}", String::from_utf8(output.stdout).unwrap()); + } } mod array; From da50c8212ea870fa119bd51b461a3d37ffc07453 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 16 Jan 2022 18:33:39 +0100 Subject: [PATCH 16/29] tests: even more verbose informations --- tests/src/lib.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 202a468db2..2cd1bbd82e 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -148,7 +148,16 @@ mod integration { if output.status.success() { true } else { - panic!("{}", String::from_utf8(output.stdout).unwrap()); + panic!( + " + status: {} + stdout: {} + stderr: {} + ", + output.status, + String::from_utf8(output.stdout).unwrap(), + String::from_utf8(output.stderr).unwrap() + ); } } From 23a8df0dcc72ab7153f49591b69a670f5c8b2154 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 16 Jan 2022 21:49:09 +0100 Subject: [PATCH 17/29] tests: revert to non-release extension for tests --- tests/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 2cd1bbd82e..7d41f172c2 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -127,7 +127,6 @@ mod integration { BUILD.call_once(|| { assert!(Command::new("cargo") .arg("build") - .arg("--release") .output() .expect("failed to build extension") .status @@ -139,7 +138,7 @@ mod integration { setup(); let output = Command::new("php") .arg(format!( - "-dextension=../target/release/libtests.{}", + "-dextension=../target/debug/libtests.{}", std::env::consts::DLL_EXTENSION )) .arg(format!("src/integration/{}", file)) From 73c00bf1c41479dd670f0960a548f990fb07af91 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 16 Jan 2022 21:58:53 +0100 Subject: [PATCH 18/29] tests: test closure --- tests/src/integration/closure.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/src/integration/closure.php b/tests/src/integration/closure.php index 8f202fc175..7ce25c7f27 100644 --- a/tests/src/integration/closure.php +++ b/tests/src/integration/closure.php @@ -3,11 +3,10 @@ require('_utils.php'); // Closure -assert(test_closure()('once') === 'once'); -assert(test_closure()('twice') === 'twice'); +assert(test_closure()('works') === 'works'); // Closure once -$closure = test_closure_once('test'); +// $closure = test_closure_once('test'); -assert($closure() === 'test'); -assert_exception_thrown(fn () => $closure()); +// assert($closure() === 'test'); +// assert_exception_thrown(fn () => $closure()); From 053e2961b157f8ed8b18f2af3e2af4336cc69a47 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 16 Jan 2022 22:07:00 +0100 Subject: [PATCH 19/29] tests: enable closures again --- tests/src/integration/_utils.php | 3 ++- tests/src/integration/closure.php | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/src/integration/_utils.php b/tests/src/integration/_utils.php index 1c7139127d..e1940441dc 100644 --- a/tests/src/integration/_utils.php +++ b/tests/src/integration/_utils.php @@ -7,7 +7,8 @@ function assert_exception_thrown(callable $callback): void { try { call_user_func($callback); - exit(1); } catch (\Throwable $th) { + return; } + throw new Exception("Excption was not thrown", 255); } diff --git a/tests/src/integration/closure.php b/tests/src/integration/closure.php index 7ce25c7f27..7d4c0d21c0 100644 --- a/tests/src/integration/closure.php +++ b/tests/src/integration/closure.php @@ -6,7 +6,7 @@ assert(test_closure()('works') === 'works'); // Closure once -// $closure = test_closure_once('test'); +$closure = test_closure_once('test'); -// assert($closure() === 'test'); -// assert_exception_thrown(fn () => $closure()); +assert(call_user_func($closure) === 'test'); +assert_exception_thrown($closure); From eb4c9dd9f50d7e71623532ce945f5983de880999 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 16 Jan 2022 22:14:18 +0100 Subject: [PATCH 20/29] tests: disable closure once test --- tests/src/integration/closure.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/src/integration/closure.php b/tests/src/integration/closure.php index 7d4c0d21c0..70f4647105 100644 --- a/tests/src/integration/closure.php +++ b/tests/src/integration/closure.php @@ -6,7 +6,7 @@ assert(test_closure()('works') === 'works'); // Closure once -$closure = test_closure_once('test'); +// $closure = test_closure_once('test'); -assert(call_user_func($closure) === 'test'); -assert_exception_thrown($closure); +// assert(call_user_func($closure) === 'test'); +// assert_exception_thrown($closure); From 411e9a0a78bd14b274bac0f4f0770cc846cf0f24 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 3 Apr 2022 17:00:53 +0200 Subject: [PATCH 21/29] fix: enable closure once test again --- tests/src/integration/closure.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/src/integration/closure.php b/tests/src/integration/closure.php index 70f4647105..7d4c0d21c0 100644 --- a/tests/src/integration/closure.php +++ b/tests/src/integration/closure.php @@ -6,7 +6,7 @@ assert(test_closure()('works') === 'works'); // Closure once -// $closure = test_closure_once('test'); +$closure = test_closure_once('test'); -// assert(call_user_func($closure) === 'test'); -// assert_exception_thrown($closure); +assert(call_user_func($closure) === 'test'); +assert_exception_thrown($closure); From b8348fc956488beac33bf7a0a923f397c3dee8a1 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Fri, 24 Nov 2023 19:01:15 +0100 Subject: [PATCH 22/29] Fixup --- tests/src/integration/_utils.php | 3 --- tests/src/lib.rs | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/src/integration/_utils.php b/tests/src/integration/_utils.php index e1940441dc..2201e1f4f0 100644 --- a/tests/src/integration/_utils.php +++ b/tests/src/integration/_utils.php @@ -1,7 +1,4 @@ Date: Fri, 24 Nov 2023 19:53:15 +0100 Subject: [PATCH 23/29] Fixup --- src/args.rs | 4 ++-- src/types/zval.rs | 20 ++++++++++++++++++++ tests/src/integration/closure.php | 8 +++++++- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/args.rs b/src/args.rs index 7cd3f62d4a..cf5f4f745d 100644 --- a/src/args.rs +++ b/src/args.rs @@ -87,7 +87,7 @@ impl<'a> Arg<'a> { { self.zval .as_mut() - .and_then(|zv| T::from_zval_mut(zv)) + .and_then(|zv| T::from_zval_mut(zv.dereference_mut())) .ok_or(self) } @@ -98,7 +98,7 @@ impl<'a> Arg<'a> { where T: FromZvalMut<'a>, { - self.zval.as_mut().and_then(|zv| T::from_zval_mut(zv)) + self.zval.as_mut().and_then(|zv| T::from_zval_mut(zv.dereference_mut())) } /// Attempts to return a reference to the arguments internal Zval. diff --git a/src/types/zval.rs b/src/types/zval.rs index f031214f32..763d11a19b 100644 --- a/src/types/zval.rs +++ b/src/types/zval.rs @@ -51,6 +51,26 @@ impl Zval { } } + /// Dereference the zval, if it is a reference. + pub fn dereference(&self) -> &Self { + return self + .reference() + .or_else(|| self.indirect()) + .or(Some(self)) + .unwrap(); + } + + /// Dereference the zval mutable, if it is a reference. + pub fn dereference_mut(&mut self) -> &mut Self { + if self.is_reference() { + return self.reference_mut().unwrap(); + } + if self.is_indirect() { + return self.indirect_mut().unwrap(); + } + return self; + } + /// Returns the value of the zval if it is a long. pub fn long(&self) -> Option { if self.is_long() { diff --git a/tests/src/integration/closure.php b/tests/src/integration/closure.php index 7d4c0d21c0..803e4bf28f 100644 --- a/tests/src/integration/closure.php +++ b/tests/src/integration/closure.php @@ -1,12 +1,18 @@ Date: Fri, 24 Nov 2023 19:56:47 +0100 Subject: [PATCH 24/29] Fixup --- tests/src/integration/closure.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/src/integration/closure.php b/tests/src/integration/closure.php index 803e4bf28f..cc5cee6b89 100644 --- a/tests/src/integration/closure.php +++ b/tests/src/integration/closure.php @@ -1,8 +1,5 @@ Date: Fri, 24 Nov 2023 20:52:11 +0100 Subject: [PATCH 25/29] Fix argument type allocation --- src/types/zval.rs | 7 ++++--- src/zend/_type.rs | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/types/zval.rs b/src/types/zval.rs index 763d11a19b..b9adc7d119 100644 --- a/src/types/zval.rs +++ b/src/types/zval.rs @@ -56,19 +56,20 @@ impl Zval { return self .reference() .or_else(|| self.indirect()) - .or(Some(self)) - .unwrap(); + .unwrap_or(self) } /// Dereference the zval mutable, if it is a reference. pub fn dereference_mut(&mut self) -> &mut Self { if self.is_reference() { + #[allow(clippy::unwrap_used)] return self.reference_mut().unwrap(); } if self.is_indirect() { + #[allow(clippy::unwrap_used)] return self.indirect_mut().unwrap(); } - return self; + self } /// Returns the value of the zval if it is a long. diff --git a/src/zend/_type.rs b/src/zend/_type.rs index 4342e3fcf4..44432e0a1b 100644 --- a/src/zend/_type.rs +++ b/src/zend/_type.rs @@ -1,5 +1,5 @@ use std::{ - ffi::{c_void, CString}, + ffi::c_void, ptr, }; @@ -8,7 +8,7 @@ use crate::{ zend_type, IS_MIXED, MAY_BE_ANY, MAY_BE_BOOL, _IS_BOOL, _ZEND_IS_VARIADIC_BIT, _ZEND_SEND_MODE_SHIFT, _ZEND_TYPE_NAME_BIT, _ZEND_TYPE_NULLABLE_BIT, }, - flags::DataType, + flags::DataType, types::ZendStr, }; /// Internal Zend type. @@ -82,7 +82,7 @@ impl ZendType { allow_null: bool, ) -> Option { Some(Self { - ptr: CString::new(class_name).ok()?.into_raw() as *mut c_void, + ptr: ZendStr::new(class_name, true).as_ptr() as *mut c_void, type_mask: _ZEND_TYPE_NAME_BIT | (if allow_null { _ZEND_TYPE_NULLABLE_BIT From 9547daf7046fb89c87b0117087e5e2e5acd5e0a7 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Fri, 24 Nov 2023 21:43:42 +0100 Subject: [PATCH 26/29] Fix use after free --- src/args.rs | 4 +++- src/types/zval.rs | 6 ++---- src/zend/_type.rs | 10 ++++------ src/zend/try_catch.rs | 7 ++++--- tests/src/integration/closure.php | 2 +- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/args.rs b/src/args.rs index cf5f4f745d..4bc928f1f0 100644 --- a/src/args.rs +++ b/src/args.rs @@ -98,7 +98,9 @@ impl<'a> Arg<'a> { where T: FromZvalMut<'a>, { - self.zval.as_mut().and_then(|zv| T::from_zval_mut(zv.dereference_mut())) + self.zval + .as_mut() + .and_then(|zv| T::from_zval_mut(zv.dereference_mut())) } /// Attempts to return a reference to the arguments internal Zval. diff --git a/src/types/zval.rs b/src/types/zval.rs index b9adc7d119..d997d53d1f 100644 --- a/src/types/zval.rs +++ b/src/types/zval.rs @@ -53,14 +53,12 @@ impl Zval { /// Dereference the zval, if it is a reference. pub fn dereference(&self) -> &Self { - return self - .reference() - .or_else(|| self.indirect()) - .unwrap_or(self) + return self.reference().or_else(|| self.indirect()).unwrap_or(self); } /// Dereference the zval mutable, if it is a reference. pub fn dereference_mut(&mut self) -> &mut Self { + // TODO: probably more ZTS work is needed here if self.is_reference() { #[allow(clippy::unwrap_used)] return self.reference_mut().unwrap(); diff --git a/src/zend/_type.rs b/src/zend/_type.rs index 44432e0a1b..dc2ba47830 100644 --- a/src/zend/_type.rs +++ b/src/zend/_type.rs @@ -1,14 +1,12 @@ -use std::{ - ffi::c_void, - ptr, -}; +use std::{ffi::c_void, ptr}; use crate::{ ffi::{ zend_type, IS_MIXED, MAY_BE_ANY, MAY_BE_BOOL, _IS_BOOL, _ZEND_IS_VARIADIC_BIT, _ZEND_SEND_MODE_SHIFT, _ZEND_TYPE_NAME_BIT, _ZEND_TYPE_NULLABLE_BIT, }, - flags::DataType, types::ZendStr, + flags::DataType, + types::ZendStr, }; /// Internal Zend type. @@ -82,7 +80,7 @@ impl ZendType { allow_null: bool, ) -> Option { Some(Self { - ptr: ZendStr::new(class_name, true).as_ptr() as *mut c_void, + ptr: ZendStr::new(class_name, true).into_raw().as_ptr() as *mut c_void, type_mask: _ZEND_TYPE_NAME_BIT | (if allow_null { _ZEND_TYPE_NULLABLE_BIT diff --git a/src/zend/try_catch.rs b/src/zend/try_catch.rs index 2f0696ce72..5d3f56889b 100644 --- a/src/zend/try_catch.rs +++ b/src/zend/try_catch.rs @@ -35,12 +35,13 @@ pub fn try_catch R + RefUnwindSafe>(func: F) -> Result Date: Fri, 24 Nov 2023 21:46:48 +0100 Subject: [PATCH 27/29] Fixup --- tests/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 72f32f9aca..b5142ae846 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -1,3 +1,4 @@ +#![cfg_attr(windows, feature(abi_vectorcall))] use ext_php_rs::{binary::Binary, prelude::*, types::ZendObject, types::Zval}; use std::collections::HashMap; From 332b5a93e5ccaf5c59ccd85b448d405a8017f6fb Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Fri, 24 Nov 2023 22:19:44 +0100 Subject: [PATCH 28/29] Fix tests --- tests/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/src/lib.rs b/tests/src/lib.rs index b5142ae846..88a6b19b4c 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -144,6 +144,7 @@ mod integration { )) .arg("-dassert.active=1") .arg("-dassert.exception=1") + .arg("-dzend.assertions=1") .arg(format!("src/integration/{}", file)) .output() .expect("failed to run php file"); From 6ae0ac4b474aa20c2f4794422a4eed8e9f7cfec7 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Fri, 24 Nov 2023 22:27:40 +0100 Subject: [PATCH 29/29] Postpone for later --- src/closure.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/closure.rs b/src/closure.rs index 03e02653c7..d9884d133b 100644 --- a/src/closure.rs +++ b/src/closure.rs @@ -171,6 +171,7 @@ class_derives!(Closure); /// /// This trait is automatically implemented on functions with up to 8 /// parameters. +#[allow(clippy::missing_safety_doc)] pub unsafe trait PhpClosure { /// Invokes the closure. fn invoke<'a>(&'a mut self, parser: ArgParser<'a, '_>, ret: &mut Zval);