Skip to content

Commit 09ee393

Browse files
fix the types thing
1 parent c3d5661 commit 09ee393

File tree

4 files changed

+249
-26
lines changed

4 files changed

+249
-26
lines changed

β€Žinternal/extgen/paramparser.goβ€Ž

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ func (pp *ParameterParser) generateSingleParamDeclaration(param phpParameter) []
6868
if param.IsNullable {
6969
decls = append(decls, fmt.Sprintf("zend_bool %s_is_null = 0;", param.Name))
7070
}
71-
case phpArray, phpMixed:
71+
case phpArray:
72+
decls = append(decls, fmt.Sprintf("zend_array *%s = NULL;", param.Name))
73+
case phpMixed:
7274
decls = append(decls, fmt.Sprintf("zval *%s = NULL;", param.Name))
7375
case "callable":
7476
decls = append(decls, fmt.Sprintf("zval *%s_callback;", param.Name))
@@ -120,7 +122,7 @@ func (pp *ParameterParser) generateParamParsingMacro(param phpParameter) string
120122
case phpBool:
121123
return fmt.Sprintf("\n Z_PARAM_BOOL_OR_NULL(%s, %s_is_null)", param.Name, param.Name)
122124
case phpArray:
123-
return fmt.Sprintf("\n Z_PARAM_ARRAY_OR_NULL(%s)", param.Name)
125+
return fmt.Sprintf("\n Z_PARAM_ARRAY_HT_OR_NULL(%s)", param.Name)
124126
case phpMixed:
125127
return fmt.Sprintf("\n Z_PARAM_ZVAL_OR_NULL(%s)", param.Name)
126128
case phpCallable:
@@ -139,7 +141,7 @@ func (pp *ParameterParser) generateParamParsingMacro(param phpParameter) string
139141
case phpBool:
140142
return fmt.Sprintf("\n Z_PARAM_BOOL(%s)", param.Name)
141143
case phpArray:
142-
return fmt.Sprintf("\n Z_PARAM_ARRAY(%s)", param.Name)
144+
return fmt.Sprintf("\n Z_PARAM_ARRAY_HT(%s)", param.Name)
143145
case phpMixed:
144146
return fmt.Sprintf("\n Z_PARAM_ZVAL(%s)", param.Name)
145147
case phpCallable:

β€Žinternal/extgen/templates/extension.c.tplβ€Ž

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ PHP_METHOD({{namespacedClassName $.Namespace .ClassName}}, {{.PhpName}}) {
9595
zend_bool {{$param.Name}} = {{if $param.HasDefault}}{{if eq $param.DefaultValue "true"}}1{{else}}0{{end}}{{else}}0{{end}};{{if $param.IsNullable}}
9696
zend_bool {{$param.Name}}_is_null = 0;{{end}}
9797
{{- else if eq $param.PhpType "array"}}
98-
zval *{{$param.Name}} = NULL;
98+
zend_array *{{$param.Name}} = NULL;
9999
{{- else if eq $param.PhpType "callable"}}
100100
zval *{{$param.Name}}_callback;
101101
{{- end}}
@@ -106,7 +106,7 @@ PHP_METHOD({{namespacedClassName $.Namespace .ClassName}}, {{.PhpName}}) {
106106
{{$optionalStarted := false}}{{range .Params}}{{if .HasDefault}}{{if not $optionalStarted -}}
107107
Z_PARAM_OPTIONAL
108108
{{$optionalStarted = true}}{{end}}{{end -}}
109-
{{if .IsNullable}}{{if eq .PhpType "string"}}Z_PARAM_STR_OR_NULL({{.Name}}, {{.Name}}_is_null){{else if eq .PhpType "int"}}Z_PARAM_LONG_OR_NULL({{.Name}}, {{.Name}}_is_null){{else if eq .PhpType "float"}}Z_PARAM_DOUBLE_OR_NULL({{.Name}}, {{.Name}}_is_null){{else if eq .PhpType "bool"}}Z_PARAM_BOOL_OR_NULL({{.Name}}, {{.Name}}_is_null){{else if eq .PhpType "array"}}Z_PARAM_ARRAY_OR_NULL({{.Name}}){{else if eq .PhpType "callable"}}Z_PARAM_ZVAL_OR_NULL({{.Name}}_callback){{end}}{{else}}{{if eq .PhpType "string"}}Z_PARAM_STR({{.Name}}){{else if eq .PhpType "int"}}Z_PARAM_LONG({{.Name}}){{else if eq .PhpType "float"}}Z_PARAM_DOUBLE({{.Name}}){{else if eq .PhpType "bool"}}Z_PARAM_BOOL({{.Name}}){{else if eq .PhpType "array"}}Z_PARAM_ARRAY({{.Name}}){{else if eq .PhpType "callable"}}Z_PARAM_ZVAL({{.Name}}_callback){{end}}{{end}}
109+
{{if .IsNullable}}{{if eq .PhpType "string"}}Z_PARAM_STR_OR_NULL({{.Name}}, {{.Name}}_is_null){{else if eq .PhpType "int"}}Z_PARAM_LONG_OR_NULL({{.Name}}, {{.Name}}_is_null){{else if eq .PhpType "float"}}Z_PARAM_DOUBLE_OR_NULL({{.Name}}, {{.Name}}_is_null){{else if eq .PhpType "bool"}}Z_PARAM_BOOL_OR_NULL({{.Name}}, {{.Name}}_is_null){{else if eq .PhpType "array"}}Z_PARAM_ARRAY_HT_OR_NULL({{.Name}}){{else if eq .PhpType "callable"}}Z_PARAM_ZVAL_OR_NULL({{.Name}}_callback){{end}}{{else}}{{if eq .PhpType "string"}}Z_PARAM_STR({{.Name}}){{else if eq .PhpType "int"}}Z_PARAM_LONG({{.Name}}){{else if eq .PhpType "float"}}Z_PARAM_DOUBLE({{.Name}}){{else if eq .PhpType "bool"}}Z_PARAM_BOOL({{.Name}}){{else if eq .PhpType "array"}}Z_PARAM_ARRAY_HT({{.Name}}){{else if eq .PhpType "callable"}}Z_PARAM_ZVAL({{.Name}}_callback){{end}}{{end}}
110110
{{end -}}
111111
ZEND_PARSE_PARAMETERS_END();
112112
{{else}}
@@ -115,22 +115,22 @@ PHP_METHOD({{namespacedClassName $.Namespace .ClassName}}, {{.PhpName}}) {
115115

116116
{{- if ne .ReturnType "void"}}
117117
{{- if eq .ReturnType "string"}}
118-
zend_string* result = {{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}}{{else if eq .PhpType "callable"}}{{.Name}}_callback{{end}}{{else}}{{if eq .PhpType "callable"}}{{.Name}}_callback{{else}}{{.Name}}{{end}}{{end}}{{end}}{{end}});
118+
zend_string* result = {{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}}{{else if eq .PhpType "callable"}}{{.Name}}_callback{{end}}{{else}}{{if eq .PhpType "array"}}{{.Name}}{{else if eq .PhpType "callable"}}{{.Name}}_callback{{else}}{{.Name}}{{end}}{{end}}{{end}}{{end}});
119119
if (result) {
120120
RETURN_STR(result);
121121
}
122122
RETURN_EMPTY_STRING();
123123
{{- else if eq .ReturnType "int"}}
124-
zend_long result = {{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}} ? Z_ARRVAL_P({{.Name}}) : NULL{{else if eq .PhpType "callable"}}{{.Name}}_callback{{end}}{{else}}{{if eq .PhpType "array"}}Z_ARRVAL_P({{.Name}}){{else if eq .PhpType "callable"}}{{.Name}}_callback{{else}}(long){{.Name}}{{end}}{{end}}{{end}}{{end}});
124+
zend_long result = {{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}}{{else if eq .PhpType "callable"}}{{.Name}}_callback{{end}}{{else}}{{if eq .PhpType "array"}}{{.Name}}{{else if eq .PhpType "callable"}}{{.Name}}_callback{{else}}(long){{.Name}}{{end}}{{end}}{{end}}{{end}});
125125
RETURN_LONG(result);
126126
{{- else if eq .ReturnType "float"}}
127-
double result = {{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}} ? Z_ARRVAL_P({{.Name}}) : NULL{{else if eq .PhpType "callable"}}{{.Name}}_callback{{end}}{{else}}{{if eq .PhpType "array"}}Z_ARRVAL_P({{.Name}}){{else if eq .PhpType "callable"}}{{.Name}}_callback{{else}}(double){{.Name}}{{end}}{{end}}{{end}}{{end}});
127+
double result = {{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}}{{else if eq .PhpType "callable"}}{{.Name}}_callback{{end}}{{else}}{{if eq .PhpType "array"}}{{.Name}}{{else if eq .PhpType "callable"}}{{.Name}}_callback{{else}}(double){{.Name}}{{end}}{{end}}{{end}}{{end}});
128128
RETURN_DOUBLE(result);
129129
{{- else if eq .ReturnType "bool"}}
130-
int result = {{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}} ? Z_ARRVAL_P({{.Name}}) : NULL{{else if eq .PhpType "callable"}}{{.Name}}_callback{{end}}{{else}}{{if eq .PhpType "array"}}Z_ARRVAL_P({{.Name}}){{else if eq .PhpType "callable"}}{{.Name}}_callback{{else}}(int){{.Name}}{{end}}{{end}}{{end}}{{end}});
130+
int result = {{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}}{{else if eq .PhpType "callable"}}{{.Name}}_callback{{end}}{{else}}{{if eq .PhpType "array"}}{{.Name}}{{else if eq .PhpType "callable"}}{{.Name}}_callback{{else}}(int){{.Name}}{{end}}{{end}}{{end}}{{end}});
131131
RETURN_BOOL(result);
132132
{{- else if eq .ReturnType "array"}}
133-
void* result = {{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}} ? Z_ARRVAL_P({{.Name}}) : NULL{{else if eq .PhpType "callable"}}{{.Name}}_callback{{end}}{{else}}{{if eq .PhpType "array"}}Z_ARRVAL_P({{.Name}}){{else}}{{if eq .PhpType "callable"}}{{.Name}}_callback{{else}}{{.Name}}{{end}}{{end}}{{end}}{{end}}{{end}});
133+
void* result = {{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}}{{else if eq .PhpType "callable"}}{{.Name}}_callback{{end}}{{else}}{{if eq .PhpType "array"}}{{.Name}}{{else if eq .PhpType "callable"}}{{.Name}}_callback{{else}}{{.Name}}{{end}}{{end}}{{end}}{{end}});
134134
if (result != NULL) {
135135
HashTable *ht = (HashTable*)result;
136136
RETURN_ARR(ht);
@@ -139,7 +139,7 @@ PHP_METHOD({{namespacedClassName $.Namespace .ClassName}}, {{.PhpName}}) {
139139
}
140140
{{- end}}
141141
{{- else}}
142-
{{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}} ? Z_ARRVAL_P({{.Name}}) : NULL{{else if eq .PhpType "callable"}}{{.Name}}_callback{{end}}{{else}}{{if eq .PhpType "string"}}{{.Name}}{{else if eq .PhpType "int"}}(long){{.Name}}{{else if eq .PhpType "float"}}(double){{.Name}}{{else if eq .PhpType "bool"}}(int){{.Name}}{{else if eq .PhpType "array"}}Z_ARRVAL_P({{.Name}}){{else if eq .PhpType "callable"}}{{.Name}}_callback{{end}}{{end}}{{end}}{{end}});
142+
{{.Name}}_wrapper(intern->go_handle{{if .Params}}{{range .Params}}, {{if .IsNullable}}{{if eq .PhpType "string"}}{{.Name}}_is_null ? NULL : {{.Name}}{{else if eq .PhpType "int"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "float"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "bool"}}{{.Name}}_is_null ? NULL : &{{.Name}}{{else if eq .PhpType "array"}}{{.Name}}{{else if eq .PhpType "callable"}}{{.Name}}_callback{{end}}{{else}}{{if eq .PhpType "string"}}{{.Name}}{{else if eq .PhpType "int"}}(long){{.Name}}{{else if eq .PhpType "float"}}(double){{.Name}}{{else if eq .PhpType "bool"}}(int){{.Name}}{{else if eq .PhpType "array"}}{{.Name}}{{else if eq .PhpType "callable"}}{{.Name}}_callback{{end}}{{end}}{{end}}{{end}});
143143
{{- end}}
144144
}
145145
{{end}}{{end}}
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
# Integration Test Fixtures
2+
3+
This directory contains Go source files used as test fixtures for the FrankenPHP extension-init integration tests.
4+
5+
## Overview
6+
7+
These fixtures test the full end-to-end workflow of the extension-init command:
8+
1. Generating extension files from Go source code
9+
2. Compiling FrankenPHP with the generated extension
10+
3. Executing PHP code that uses the extension
11+
4. Verifying the output
12+
13+
## Test Fixtures
14+
15+
### Happy Path Tests
16+
17+
#### `basic_function.go`
18+
Tests basic function generation with primitive types:
19+
- `test_uppercase(string): string` - String parameter and return
20+
- `test_add_numbers(int, int): int` - Integer parameters
21+
- `test_multiply(float, float): float` - Float parameters
22+
- `test_is_enabled(bool): bool` - Boolean parameter
23+
24+
**What it tests:**
25+
- Function parsing and generation
26+
- Type conversion for all primitive types
27+
- C/Go bridge code generation
28+
- PHP stub file generation
29+
30+
#### `class_methods.go`
31+
Tests opaque class generation with methods:
32+
- `Counter` class - Integer counter with increment/decrement operations
33+
- `StringHolder` class - String storage and manipulation
34+
35+
**What it tests:**
36+
- Class declaration with `//export_php:class`
37+
- Method declaration with `//export_php:method`
38+
- Object lifecycle (creation and destruction)
39+
- Method calls with various parameter and return types
40+
- Nullable parameters (`?int`)
41+
- Opaque object encapsulation (no direct property access)
42+
43+
#### `constants.go`
44+
Tests constant generation and usage:
45+
- Global constants (int, string, bool, float)
46+
- Iota sequences for enumerations
47+
- Class constants
48+
- Functions using constants
49+
50+
**What it tests:**
51+
- `//export_php:const` directive
52+
- `//export_php:classconstant` directive
53+
- Constant type detection and conversion
54+
- Iota sequence handling
55+
- Integration of constants with functions and classes
56+
57+
#### `namespace.go`
58+
Tests namespace support:
59+
- Functions in namespace `TestIntegration\Extension`
60+
- Classes in namespace
61+
- Constants in namespace
62+
63+
**What it tests:**
64+
- `//export_php:namespace` directive
65+
- Namespace declaration in stub files
66+
- C name mangling for namespaces
67+
- Proper scoping of functions, classes, and constants
68+
69+
### Error Case Tests
70+
71+
#### `invalid_signature.go`
72+
Tests error handling for invalid function signatures:
73+
- Function with unsupported return type
74+
75+
**What it tests:**
76+
- Validation of return types
77+
- Clear error messages for unsupported types
78+
- Graceful failure during generation
79+
80+
#### `type_mismatch.go`
81+
Tests error handling for type mismatches:
82+
- PHP signature declares `int` but Go function expects `string`
83+
- Method return type mismatch
84+
85+
**What it tests:**
86+
- Parameter type validation
87+
- Return type validation
88+
- Type compatibility checking between PHP and Go
89+
90+
## Running Integration Tests Locally
91+
92+
Integration tests are tagged with `//go:build integration` and are skipped by default because they require:
93+
1. PHP development headers (`php-config`)
94+
2. PHP sources (for `gen_stub.php` script)
95+
3. xcaddy (for building FrankenPHP)
96+
97+
### Prerequisites
98+
99+
1. **Install PHP development headers:**
100+
```bash
101+
# Ubuntu/Debian
102+
sudo apt-get install php-dev
103+
104+
# macOS
105+
brew install php
106+
```
107+
108+
2. **Download PHP sources:**
109+
```bash
110+
wget https://www.php.net/distributions/php-8.4.0.tar.gz
111+
tar xzf php-8.4.0.tar.gz
112+
export GEN_STUB_SCRIPT=$PWD/php-8.4.0/build/gen_stub.php
113+
```
114+
115+
3. **Install xcaddy:**
116+
```bash
117+
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
118+
```
119+
120+
### Running the Tests
121+
122+
```bash
123+
cd internal/extgen
124+
go test -tags integration -v -timeout 30m
125+
```
126+
127+
The timeout is set to 30 minutes because:
128+
- Each test compiles a full FrankenPHP binary with xcaddy
129+
- Multiple test scenarios are run sequentially
130+
- Compilation can be slow on CI runners
131+
132+
### Skipping Tests
133+
134+
If any of the prerequisites are not met, the tests will be skipped automatically with a clear message:
135+
- Missing `GEN_STUB_SCRIPT`: "Integration tests require PHP sources"
136+
- Missing `xcaddy`: "Integration tests require xcaddy to build FrankenPHP"
137+
- Missing `php-config`: "Integration tests require PHP development headers"
138+
139+
## CI Integration
140+
141+
Integration tests run automatically in CI on:
142+
- Pull requests to `main` branch
143+
- Pushes to `main` branch
144+
- PHP versions: 8.3, 8.4
145+
- Platform: Linux (Ubuntu)
146+
147+
The CI workflow (`.github/workflows/tests.yaml`) automatically:
148+
1. Sets up Go and PHP
149+
2. Installs xcaddy
150+
3. Downloads PHP sources
151+
4. Sets `GEN_STUB_SCRIPT` environment variable
152+
5. Runs integration tests with 30-minute timeout
153+
154+
## Adding New Test Fixtures
155+
156+
To add a new integration test fixture:
157+
158+
1. **Create a new Go file** in this directory with your test code
159+
2. **Use export_php directives** to declare functions, classes, or constants
160+
3. **Add a new test function** in `internal/extgen/integration_test.go`:
161+
```go
162+
func TestYourFeature(t *testing.T) {
163+
suite := setupTest(t)
164+
165+
sourceFile := filepath.Join("..", "..", "testdata", "integration", "your_file.go")
166+
sourceFile, err := filepath.Abs(sourceFile)
167+
require.NoError(t, err)
168+
169+
targetFile, err := suite.createGoModule(sourceFile)
170+
require.NoError(t, err)
171+
172+
err = suite.runExtensionInit(targetFile)
173+
require.NoError(t, err)
174+
175+
_, err = suite.compileFrankenPHP(filepath.Dir(targetFile))
176+
require.NoError(t, err)
177+
178+
phpCode := `<?php /* your test PHP code */ `
179+
180+
output, err := suite.runPHPCode(phpCode)
181+
require.NoError(t, err)
182+
183+
// Add assertions
184+
assert.Contains(t, output, "expected output")
185+
}
186+
```
187+
188+
4. **Document your fixture** in this README
189+
190+
## Test Coverage
191+
192+
Current integration test coverage:
193+
- βœ… Basic functions with primitive types
194+
- βœ… Classes with methods
195+
- βœ… Nullable parameters
196+
- βœ… Global and class constants
197+
- βœ… Iota sequences
198+
- βœ… Namespaces
199+
- βœ… Invalid signatures (error case)
200+
- βœ… Type mismatches (error case)
201+
- βœ… Missing gen_stub.php (error case)
202+
203+
Future coverage goals:
204+
- Array handling (packed, associative, maps)
205+
- Default parameter values
206+
- Multiple namespaces (error case)
207+
- Complex nested types
208+
- Performance benchmarks

0 commit comments

Comments
Β (0)