Skip to content

Commit 3043372

Browse files
authored
chore(cargo-php): add tests and generate deterministic output (#677)
1 parent 08e3a47 commit 3043372

File tree

7 files changed

+166
-7
lines changed

7 files changed

+166
-7
lines changed

allowed_bindings.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,5 +373,10 @@ bind! {
373373
zend_observer_error_register,
374374
zend_function,
375375
zend_op_array,
376-
zend_throw_exception_hook
376+
zend_throw_exception_hook,
377+
zend_compile_string,
378+
zend_execute,
379+
zend_get_executed_scope,
380+
zend_destroy_static_vars,
381+
destroy_op_array
377382
}

crates/cli/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@ default = ["enum"]
3333
enum = ["ext-php-rs/enum"]
3434
runtime = ["ext-php-rs/runtime"]
3535
static = ["ext-php-rs/static"]
36+
37+
[dev-dependencies]
38+
insta = "1"
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
source: crates/cli/tests/stubs_snapshot.rs
3+
assertion_line: 69
4+
expression: stubs
5+
---
6+
<?php
7+
8+
// Stubs for ext-php-rs
9+
10+
namespace {
11+
class TestClass {
12+
const NEW_CONSTANT_NAME = 5;
13+
14+
const SOME_OTHER_STR = 'Hello, world!';
15+
16+
public $a;
17+
18+
public $b;
19+
20+
public function __construct(int $a, int $b) {}
21+
22+
public function builderPattern(): \TestClass {}
23+
24+
public function testCamelCase(int $a = 5, int $test = 100): void {}
25+
26+
public static function x(): int {}
27+
}
28+
29+
const CONST_NAME = 100;
30+
31+
const HELLO_WORLD = 100;
32+
33+
function get_zval_convert(object $z): int {}
34+
35+
function hello_world(): string {}
36+
37+
function new_class(): \TestClass {}
38+
}

crates/cli/tests/stubs_snapshot.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#![cfg(not(windows))]
2+
#![allow(missing_docs)]
3+
4+
use std::io::BufReader;
5+
use std::path::PathBuf;
6+
use std::process::{Command, Stdio};
7+
8+
use cargo_metadata::Message;
9+
10+
#[test]
11+
fn hello_world_stubs() {
12+
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
13+
let workspace_root = manifest_dir
14+
.parent()
15+
.and_then(|p| p.parent())
16+
.expect("Failed to find workspace root");
17+
18+
// Use a separate target directory to avoid polluting the main target/
19+
// with artifacts built under different feature sets (which causes
20+
// "multiple candidates for rmeta dependency" errors in other tests).
21+
let target_dir = workspace_root.join("target").join("tests");
22+
23+
// Build the hello_world example as cdylib
24+
let build_output = Command::new("cargo")
25+
.current_dir(workspace_root)
26+
.env("CARGO_TARGET_DIR", &target_dir)
27+
.args([
28+
"build",
29+
"--example",
30+
"hello_world",
31+
"--message-format=json-render-diagnostics",
32+
])
33+
.stdout(Stdio::piped())
34+
.stderr(Stdio::inherit())
35+
.output()
36+
.expect("Failed to run cargo build");
37+
38+
assert!(
39+
build_output.status.success(),
40+
"Failed to build hello_world example: {}",
41+
String::from_utf8_lossy(&build_output.stdout)
42+
);
43+
44+
let reader = BufReader::new(build_output.stdout.as_slice());
45+
let lib_path = Message::parse_stream(reader)
46+
.filter_map(Result::ok)
47+
.find_map(|msg| match msg {
48+
Message::CompilerArtifact(artifact) if artifact.target.name == "hello_world" => {
49+
artifact
50+
.filenames
51+
.into_iter()
52+
.find(|f| f.extension() == Some(std::env::consts::DLL_EXTENSION))
53+
}
54+
_ => None,
55+
})
56+
.expect("Failed to find hello_world cdylib artifact in cargo output");
57+
58+
// Run cargo-php stubs --stdout against the built cdylib
59+
let stubs_output = Command::new("cargo")
60+
.current_dir(workspace_root)
61+
.env("CARGO_TARGET_DIR", &target_dir)
62+
.args(["run", "-p", "cargo-php", "--", "stubs", "--stdout"])
63+
.arg(lib_path.as_str())
64+
.output()
65+
.expect("Failed to run cargo-php stubs");
66+
67+
assert!(
68+
stubs_output.status.success(),
69+
"cargo-php stubs failed: {}",
70+
String::from_utf8_lossy(&stubs_output.stderr)
71+
);
72+
73+
let stubs = String::from_utf8(stubs_output.stdout).expect("Invalid UTF-8 in stubs output");
74+
insta::assert_snapshot!(stubs);
75+
}

docsrs_bindings.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2273,6 +2273,26 @@ pub struct _zend_executor_globals {
22732273
pub strtod_state: zend_strtod_state,
22742274
pub reserved: [*mut ::std::os::raw::c_void; 6usize],
22752275
}
2276+
pub const _zend_compile_position_ZEND_COMPILE_POSITION_AT_SHEBANG: _zend_compile_position = 0;
2277+
pub const _zend_compile_position_ZEND_COMPILE_POSITION_AT_OPEN_TAG: _zend_compile_position = 1;
2278+
pub const _zend_compile_position_ZEND_COMPILE_POSITION_AFTER_OPEN_TAG: _zend_compile_position = 2;
2279+
pub type _zend_compile_position = ::std::os::raw::c_uint;
2280+
pub use self::_zend_compile_position as zend_compile_position;
2281+
unsafe extern "C" {
2282+
pub static mut zend_compile_string: ::std::option::Option<
2283+
unsafe extern "C" fn(
2284+
source_string: *mut zend_string,
2285+
filename: *const ::std::os::raw::c_char,
2286+
position: zend_compile_position,
2287+
) -> *mut zend_op_array,
2288+
>;
2289+
}
2290+
unsafe extern "C" {
2291+
pub fn destroy_op_array(op_array: *mut zend_op_array);
2292+
}
2293+
unsafe extern "C" {
2294+
pub fn zend_destroy_static_vars(op_array: *mut zend_op_array);
2295+
}
22762296
unsafe extern "C" {
22772297
pub fn zend_is_auto_global(name: *mut zend_string) -> bool;
22782298
}
@@ -2379,6 +2399,9 @@ unsafe extern "C" {
23792399
module_number: ::std::os::raw::c_int,
23802400
) -> *mut zend_constant;
23812401
}
2402+
unsafe extern "C" {
2403+
pub fn zend_execute(op_array: *mut zend_op_array, return_value: *mut zval);
2404+
}
23822405
unsafe extern "C" {
23832406
pub fn zend_lookup_class_ex(
23842407
name: *mut zend_string,
@@ -2400,6 +2423,9 @@ pub struct _zend_vm_stack {
24002423
pub end: *mut zval,
24012424
pub prev: zend_vm_stack,
24022425
}
2426+
unsafe extern "C" {
2427+
pub fn zend_get_executed_scope() -> *mut zend_class_entry;
2428+
}
24032429
unsafe extern "C" {
24042430
pub fn zend_fetch_function_str(
24052431
name: *const ::std::os::raw::c_char,

src/describe/stub.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ impl ToStub for Module {
9191
insert(ns, r#enum.to_stub()?);
9292
}
9393

94+
for bucket in entries.values_mut() {
95+
bucket.sort();
96+
}
97+
9498
let mut entries: StdVec<_> = entries.iter().collect();
9599
entries.sort_by(|(l, _), (r, _)| match (l, r) {
96100
(None, _) => Ordering::Greater,
@@ -282,11 +286,19 @@ impl ToStub for Class {
282286

283287
writeln!(buf, "{{")?;
284288

289+
let mut constants: StdVec<_> = stub(&self.constants).collect::<Result<_, FmtError>>()?;
290+
let mut properties: StdVec<_> = stub(&self.properties).collect::<Result<_, FmtError>>()?;
291+
let mut methods: StdVec<_> = stub(&self.methods).collect::<Result<_, FmtError>>()?;
292+
constants.sort();
293+
properties.sort();
294+
methods.sort();
295+
285296
buf.push_str(
286-
&stub(&self.constants)
287-
.chain(stub(&self.properties))
288-
.chain(stub(&self.methods))
289-
.collect::<Result<StdVec<_>, FmtError>>()?
297+
&constants
298+
.into_iter()
299+
.chain(properties)
300+
.chain(methods)
301+
.collect::<StdVec<_>>()
290302
.join(NEW_LINE_SEPARATOR),
291303
);
292304

src/wrapper.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,12 @@ void ext_php_rs_zend_execute(zend_op_array *op_array) {
130130
zend_execute(op_array, &local_retval);
131131
} zend_catch {
132132
destroy_op_array(op_array);
133-
efree_size(op_array, sizeof(zend_op_array));
133+
efree(op_array);
134134
zend_bailout();
135135
} zend_end_try();
136136

137137
zval_ptr_dtor(&local_retval);
138138
zend_destroy_static_vars(op_array);
139139
destroy_op_array(op_array);
140-
efree_size(op_array, sizeof(zend_op_array));
140+
efree(op_array);
141141
}

0 commit comments

Comments
 (0)