|
| 1 | +--TEST-- |
| 2 | +Feature GH-11934 (Allow to pass CData into struct and/or union fields) |
| 3 | +--EXTENSIONS-- |
| 4 | +ffi |
| 5 | +--INI-- |
| 6 | +ffi.enable=1 |
| 7 | +--FILE-- |
| 8 | +<?php |
| 9 | + |
| 10 | +$cdef = FFI::cdef(); |
| 11 | + |
| 12 | +echo "--- Primitive types ---\n"; |
| 13 | + |
| 14 | +// Choose integer numbers off the maximum to test copy |
| 15 | +$types = [ |
| 16 | + 'uint8_t' => 200, |
| 17 | + 'uint16_t' => 16000, |
| 18 | + 'uint32_t' => 1000_000, |
| 19 | + 'uint64_t' => PHP_INT_MAX - 100, |
| 20 | + 'int8_t' => -100, |
| 21 | + 'int16_t' => -16000, |
| 22 | + 'int32_t' => -1000_000, |
| 23 | + 'int64_t' => PHP_INT_MIN + 100, |
| 24 | + 'char' => 'F', |
| 25 | + 'bool' => false, |
| 26 | + 'float' => 1.00, |
| 27 | + 'double' => -1.00, |
| 28 | +]; |
| 29 | + |
| 30 | +// Positive test |
| 31 | +foreach ($types as $type => $value) { |
| 32 | + $source = $cdef->new($type); |
| 33 | + $source->cdata = $value; |
| 34 | + $struct = $cdef->new("struct { $type field; }"); |
| 35 | + $struct->field = $source; |
| 36 | + echo "Positive test $type: "; |
| 37 | + var_dump($struct->field === $value); |
| 38 | +} |
| 39 | + |
| 40 | +// Negative test |
| 41 | +$dummy = $cdef->new("int[2]"); |
| 42 | +foreach ($types as $type => $value) { |
| 43 | + $struct = $cdef->new("struct { int field; }"); |
| 44 | + $struct->field = $dummy; |
| 45 | +} |
| 46 | + |
| 47 | +// Enum test |
| 48 | +$enum_definition = "enum { A, B, C, D }"; |
| 49 | +$source = $cdef->new($enum_definition); |
| 50 | +$source->cdata = 2; |
| 51 | +$struct = $cdef->new("struct { $enum_definition field; }"); |
| 52 | +$struct->field = $source; |
| 53 | +echo "Positive test enum: "; |
| 54 | +var_dump($struct->field === $source->cdata); |
| 55 | +$struct->field = $dummy; |
| 56 | + |
| 57 | +echo "--- Struct ---\n"; |
| 58 | + |
| 59 | +// Nested structs |
| 60 | +$cdef = FFI::cdef(" |
| 61 | + struct inner_struct { |
| 62 | + int data[1]; |
| 63 | + }; |
| 64 | + struct my_struct { |
| 65 | + int foo; |
| 66 | + int bar; |
| 67 | + struct inner_struct inner; |
| 68 | + }; |
| 69 | + struct my_nesting_struct { |
| 70 | + struct my_struct field; |
| 71 | + };"); |
| 72 | +$source = $cdef->new("struct my_struct"); |
| 73 | +$source->foo = 123; |
| 74 | +$source->bar = 456; |
| 75 | +$source->inner->data[0] = 789; |
| 76 | +$struct = $cdef->new("struct my_nesting_struct"); |
| 77 | +$struct->field = $source; |
| 78 | +var_dump($struct->field->foo === 123 && $struct->field->bar === 456 && $struct->field->inner->data[0] === 789); |
| 79 | + |
| 80 | +echo "--- Callback return type ---\n"; |
| 81 | + |
| 82 | +$ffi = FFI::cdef(' |
| 83 | +typedef uint32_t (*test_callback)(); |
| 84 | +typedef struct { |
| 85 | + test_callback call_me; |
| 86 | +} my_struct; |
| 87 | +'); |
| 88 | + |
| 89 | +$struct = $ffi->new('my_struct'); |
| 90 | +$struct->call_me = function () use ($ffi) { |
| 91 | + $int = $ffi->new('uint32_t'); |
| 92 | + $int->cdata = 42; |
| 93 | + return $int; |
| 94 | +}; |
| 95 | + |
| 96 | +var_dump(($struct->call_me)()); |
| 97 | + |
| 98 | +echo "--- Other FFI\CData assignment ---\n"; |
| 99 | + |
| 100 | +$ffi = FFI::cdef(''); |
| 101 | + |
| 102 | +$source = $ffi->new('uint32_t'); |
| 103 | +$source->cdata = 123; |
| 104 | +$target = $ffi->new('uint32_t'); |
| 105 | +$target->cdata = $source; |
| 106 | + |
| 107 | +var_dump($target->cdata); |
| 108 | + |
| 109 | +echo "--- Array element ---\n"; |
| 110 | + |
| 111 | +$ffi = FFI::cdef(''); |
| 112 | + |
| 113 | +$source = $ffi->new('uint32_t'); |
| 114 | +$source->cdata = 123; |
| 115 | +$target = $ffi->new('uint32_t[1]'); |
| 116 | +$target[0] = $source; |
| 117 | + |
| 118 | +var_dump($target[0]); |
| 119 | + |
| 120 | +?> |
| 121 | +--EXPECTF-- |
| 122 | +--- Primitive types --- |
| 123 | +Positive test uint8_t: bool(true) |
| 124 | +Positive test uint16_t: bool(true) |
| 125 | +Positive test uint32_t: bool(true) |
| 126 | +Positive test uint64_t: bool(true) |
| 127 | +Positive test int8_t: bool(true) |
| 128 | +Positive test int16_t: bool(true) |
| 129 | +Positive test int32_t: bool(true) |
| 130 | +Positive test int64_t: bool(true) |
| 131 | +Positive test char: bool(true) |
| 132 | +Positive test bool: bool(true) |
| 133 | +Positive test float: bool(true) |
| 134 | +Positive test double: bool(true) |
| 135 | + |
| 136 | +Warning: Object of class FFI\CData could not be converted to int in %s on line %d |
| 137 | + |
| 138 | +Warning: Object of class FFI\CData could not be converted to int in %s on line %d |
| 139 | + |
| 140 | +Warning: Object of class FFI\CData could not be converted to int in %s on line %d |
| 141 | + |
| 142 | +Warning: Object of class FFI\CData could not be converted to int in %s on line %d |
| 143 | + |
| 144 | +Warning: Object of class FFI\CData could not be converted to int in %s on line %d |
| 145 | + |
| 146 | +Warning: Object of class FFI\CData could not be converted to int in %s on line %d |
| 147 | + |
| 148 | +Warning: Object of class FFI\CData could not be converted to int in %s on line %d |
| 149 | + |
| 150 | +Warning: Object of class FFI\CData could not be converted to int in %s on line %d |
| 151 | + |
| 152 | +Warning: Object of class FFI\CData could not be converted to int in %s on line %d |
| 153 | + |
| 154 | +Warning: Object of class FFI\CData could not be converted to int in %s on line %d |
| 155 | + |
| 156 | +Warning: Object of class FFI\CData could not be converted to int in %s on line %d |
| 157 | + |
| 158 | +Warning: Object of class FFI\CData could not be converted to int in %s on line %d |
| 159 | +Positive test enum: bool(true) |
| 160 | + |
| 161 | +Warning: Object of class FFI\CData could not be converted to int in %s on line %d |
| 162 | +--- Struct --- |
| 163 | +bool(true) |
| 164 | +--- Callback return type --- |
| 165 | +int(42) |
| 166 | +--- Other FFI\CData assignment --- |
| 167 | +int(123) |
| 168 | +--- Array element --- |
| 169 | +int(123) |
0 commit comments