| OLD | NEW |
| 1 // Copyright (c) 2014, the Fletch project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Fletch project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE.md file. | 3 // BSD-style license that can be found in the LICENSE.md file. |
| 4 | 4 |
| 5 import 'dart:ffi'; | 5 import 'dart:ffi'; |
| 6 import "package:expect/expect.dart"; | 6 import "package:expect/expect.dart"; |
| 7 | 7 |
| 8 bool isRangeError(e) => e is RangeError; | 8 bool isRangeError(e) => e is RangeError; |
| 9 bool isArgumentError(e) => e is ArgumentError; | 9 bool isArgumentError(e) => e is ArgumentError; |
| 10 | 10 |
| 11 main() { | 11 main() { |
| 12 testLookup(); | |
| 13 | |
| 14 testICall(); | |
| 15 testPCall(); | |
| 16 | |
| 17 testAllocate(false); | 12 testAllocate(false); |
| 18 testAllocate(true); | 13 testAllocate(true); |
| 19 } | 14 |
| 20 | 15 testVAndICall(); |
| 21 testLookup() { | 16 testFailingLibraryLookups(); |
| 22 Expect.isTrue(Foreign.lookup('qsort') is Foreign); | 17 testDefaultLibraryLookups(); |
| 23 Expect.isTrue(Foreign.lookup('qsort', library: null) is Foreign); | 18 testPCallAndMemory(); |
| 24 Expect.isTrue(Foreign.lookup('qsort', library: '') is Foreign); | 19 } |
| 25 | 20 |
| 21 checkOutOfBoundsThrows(function) { |
| 22 Expect.throws(function, (e) => e is RangeError); |
| 23 } |
| 24 |
| 25 testPCallAndMemory() { |
| 26 // Please see the expected values in the ffi_test_library.c file (obvious |
| 27 // from the code below, but that is where they are defined). |
| 28 // For all memory returning functions we expect there to be 4 values of the |
| 29 // type we are working on. |
| 30 var libPath = ForeignLibrary.bundleLibraryName('ffi_test_library'); |
| 31 ForeignLibrary fl = new ForeignLibrary.fromName(libPath); |
| 32 ForeignPointer p = new ForeignPointer(); |
| 33 var pcall0 = fl.lookup('pfun0'); |
| 34 var foreignPointer = pcall0.pcall$0(p); |
| 35 var memory = new ForeignMemory.fromForeignPointer(foreignPointer, 16); |
| 36 Expect.equals(memory.address, foreignPointer.address); |
| 37 Expect.equals(memory.getInt32(0), 1); |
| 38 Expect.equals(memory.getInt32(4), 2); |
| 39 Expect.equals(memory.getInt32(8), 3); |
| 40 Expect.equals(memory.getInt32(12), 4); |
| 41 checkOutOfBoundsThrows(() => memory.getInt32(16)); |
| 42 memory.free(); |
| 43 memory = new ForeignMemory.fromForeignPointer(foreignPointer, 16); |
| 44 |
| 45 var pcall1 = fl.lookup('pfun1'); |
| 46 foreignPointer = pcall1.pcall$1(p, 42); |
| 47 memory = new ForeignMemory.fromForeignPointer(foreignPointer, 16); |
| 48 Expect.equals(memory.address, foreignPointer.address); |
| 49 Expect.equals(memory.getInt32(0), 42); |
| 50 Expect.equals(memory.getInt32(4), 42); |
| 51 Expect.equals(memory.getInt32(8), 42); |
| 52 Expect.equals(memory.getInt32(12), 42); |
| 53 memory.setInt32(8, -1); |
| 54 Expect.equals(memory.getInt32(0), 42); |
| 55 Expect.equals(memory.getInt32(4), 42); |
| 56 Expect.equals(memory.getInt32(8), -1); |
| 57 Expect.equals(memory.getInt32(12), 42); |
| 58 memory.free(); |
| 59 |
| 60 var pcall2 = fl.lookup('pfun2'); |
| 61 foreignPointer = pcall2.pcall$2(p, 42, 43); |
| 62 memory = new ForeignMemory.fromForeignPointer(foreignPointer, 16); |
| 63 Expect.equals(memory.address, foreignPointer.address); |
| 64 Expect.equals(memory.getInt32(0), 42); |
| 65 Expect.equals(memory.getInt32(4), 43); |
| 66 Expect.equals(memory.getInt32(8), 42); |
| 67 Expect.equals(memory.getInt32(12), 43); |
| 68 memory.free(); |
| 69 |
| 70 // All tetsts below here is basically sanity checking that we correctly |
| 71 // convert the values to and from c, and that we can also set and read |
| 72 // back values correctly. |
| 73 |
| 74 var memint8 = fl.lookup('memint8'); |
| 75 foreignPointer = memint8.pcall$0(p); |
| 76 memory = new ForeignMemory.fromForeignPointer(foreignPointer, 4); |
| 77 Expect.equals(memory.address, foreignPointer.address); |
| 78 Expect.equals(memory.getInt8(0), -1); |
| 79 Expect.equals(memory.getInt8(1), -128); |
| 80 Expect.equals(memory.getInt8(2), 99); |
| 81 Expect.equals(memory.getInt8(3), 100); |
| 82 Expect.equals(memory.getUint8(0), 255); |
| 83 Expect.equals(memory.getUint8(1), 128); |
| 84 Expect.equals(memory.getUint8(2), 99); |
| 85 Expect.equals(memory.getUint8(3), 100); |
| 86 memory.setInt8(1, -1); |
| 87 memory.setUint8(2, 100); |
| 88 Expect.equals(memory.getInt8(0), -1); |
| 89 Expect.equals(memory.getInt8(1), -1); |
| 90 Expect.equals(memory.getInt8(2), 100); |
| 91 Expect.equals(memory.getInt8(3), 100); |
| 92 Expect.equals(memory.getUint8(0), 255); |
| 93 Expect.equals(memory.getUint8(1), 255); |
| 94 Expect.equals(memory.getUint8(2), 100); |
| 95 Expect.equals(memory.getUint8(3), 100); |
| 96 checkOutOfBoundsThrows(() => memory.getUint8(4)); |
| 97 memory.free(); |
| 98 |
| 99 var memint16 = fl.lookup('memint16'); |
| 100 foreignPointer = memint16.pcall$0(p); |
| 101 memory = new ForeignMemory.fromForeignPointer(foreignPointer, 8); |
| 102 Expect.equals(memory.address, foreignPointer.address); |
| 103 Expect.equals(memory.getInt16(0), 32767); |
| 104 Expect.equals(memory.getInt16(2), -32768); |
| 105 Expect.equals(memory.getInt16(4), 0); |
| 106 Expect.equals(memory.getInt16(6), -1); |
| 107 memory.setInt16(2, -1); |
| 108 Expect.equals(memory.getInt16(0), 32767); |
| 109 Expect.equals(memory.getInt16(2), -1); |
| 110 Expect.equals(memory.getInt16(4), 0); |
| 111 Expect.equals(memory.getInt16(6), -1); |
| 112 checkOutOfBoundsThrows(() => memory.getInt16(8)); |
| 113 memory.free(); |
| 114 |
| 115 var memuint16 = fl.lookup('memuint16'); |
| 116 foreignPointer = memuint16.pcall$0(p); |
| 117 memory = new ForeignMemory.fromForeignPointer(foreignPointer, 8); |
| 118 Expect.equals(memory.address, foreignPointer.address); |
| 119 Expect.equals(memory.getUint16(0), 0); |
| 120 Expect.equals(memory.getUint16(2), 32767); |
| 121 Expect.equals(memory.getUint16(4), 32768); |
| 122 Expect.equals(memory.getUint16(6), 65535); |
| 123 memory.setUint16(6, 1); |
| 124 Expect.equals(memory.getUint16(0), 0); |
| 125 Expect.equals(memory.getUint16(2), 32767); |
| 126 Expect.equals(memory.getUint16(4), 32768); |
| 127 Expect.equals(memory.getUint16(6), 1); |
| 128 checkOutOfBoundsThrows(() => memory.getUint16(8)); |
| 129 memory.free(); |
| 130 |
| 131 var memuint32 = fl.lookup('memuint32'); |
| 132 foreignPointer = memuint32.pcall$0(p); |
| 133 memory = new ForeignMemory.fromForeignPointer(foreignPointer, 16); |
| 134 Expect.equals(memory.address, foreignPointer.address); |
| 135 Expect.equals(memory.getUint32(0), 0); |
| 136 Expect.equals(memory.getUint32(4), 1); |
| 137 Expect.equals(memory.getUint32(8), 65536); |
| 138 Expect.equals(memory.getUint32(12), 4294967295); |
| 139 memory.setUint32(8, 1); |
| 140 Expect.equals(memory.getUint32(0), 0); |
| 141 Expect.equals(memory.getUint32(4), 1); |
| 142 Expect.equals(memory.getUint32(8), 1); |
| 143 Expect.equals(memory.getUint32(12), 4294967295); |
| 144 checkOutOfBoundsThrows(() => memory.getUint32(16)); |
| 145 memory.free(); |
| 146 |
| 147 var memint64 = fl.lookup('memint64'); |
| 148 foreignPointer = memint64.pcall$0(p); |
| 149 memory = new ForeignMemory.fromForeignPointer(foreignPointer, 32); |
| 150 Expect.equals(memory.address, foreignPointer.address); |
| 151 Expect.equals(memory.getInt64(0), 0); |
| 152 Expect.equals(memory.getInt64(8), -1); |
| 153 Expect.equals(memory.getInt64(16), 9223372036854775807); |
| 154 Expect.equals(memory.getInt64(24), -9223372036854775808); |
| 155 memory.setInt64(8, 9223372036854775806); |
| 156 Expect.equals(memory.getInt64(0), 0); |
| 157 // TODO(ricow): Failure, need to investigate |
| 158 Expect.equals(memory.getInt64(8), 9223372036854775806); |
| 159 Expect.equals(memory.getInt64(16), 9223372036854775807); |
| 160 Expect.equals(memory.getInt64(24), -9223372036854775808); |
| 161 checkOutOfBoundsThrows(() => memory.getInt64(25)); |
| 162 memory.free(); |
| 163 |
| 164 var memfloat32 = fl.lookup('memfloat32'); |
| 165 foreignPointer = memfloat32.pcall$0(p); |
| 166 memory = new ForeignMemory.fromForeignPointer(foreignPointer, 16); |
| 167 Expect.equals(memory.address, foreignPointer.address); |
| 168 Expect.approxEquals(memory.getFloat32(0), 0); |
| 169 Expect.approxEquals(memory.getFloat32(4), 1.175494e-38, 0.01); |
| 170 Expect.approxEquals(memory.getFloat32(8), 3.402823e+38); |
| 171 Expect.equals(memory.getFloat32(12), 4); |
| 172 memory.setFloat32(4, 2.1); |
| 173 Expect.equals(memory.getFloat32(0), 0); |
| 174 Expect.approxEquals(memory.getFloat32(4), 2.1); |
| 175 Expect.approxEquals(memory.getFloat32(8), 3.402823e+38); |
| 176 Expect.equals(memory.getFloat32(12), 4); |
| 177 checkOutOfBoundsThrows(() => memory.getFloat32(16)); |
| 178 memory.free(); |
| 179 |
| 180 var memfloat64 = fl.lookup('memfloat64'); |
| 181 foreignPointer = memfloat64.pcall$0(p); |
| 182 memory = new ForeignMemory.fromForeignPointer(foreignPointer, 32); |
| 183 Expect.equals(memory.address, foreignPointer.address); |
| 184 Expect.equals(memory.getFloat64(0), 0); |
| 185 Expect.approxEquals(memory.getFloat64(8), 1.79769e+308); |
| 186 Expect.approxEquals(memory.getFloat64(16), -1.79769e+308); |
| 187 Expect.equals(memory.getFloat64(24), 4); |
| 188 memory.setFloat64(24, 1.79769e+308); |
| 189 Expect.equals(memory.getFloat64(0), 0); |
| 190 Expect.approxEquals(memory.getFloat64(8), 1.79769e+308); |
| 191 Expect.approxEquals(memory.getFloat64(16), -1.79769e+308); |
| 192 Expect.approxEquals(memory.getFloat64(24), 1.79769e+308); |
| 193 checkOutOfBoundsThrows(() => memory.getFloat64(25)); |
| 194 memory.free(); |
| 195 |
| 196 fl.close(); |
| 197 } |
| 198 |
| 199 testVAndICall() { |
| 200 // We assume that there is a ffi_test_library library build. |
| 201 var libPath = ForeignLibrary.bundleLibraryName('ffi_test_library'); |
| 202 ForeignLibrary fl = new ForeignLibrary.fromName(libPath); |
| 203 |
| 204 // Test metods that use a static int. |
| 205 var setup = fl.lookup('setup'); |
| 206 var getcount = fl.lookup('getcount'); |
| 207 var inc = fl.lookup('inc'); |
| 208 var setcount = fl.lookup('setcount'); |
| 209 Expect.equals(null, setup.vcall$0()); |
| 210 Expect.equals(0, getcount.icall$0()); |
| 211 Expect.equals(null, inc.vcall$0()); |
| 212 Expect.equals(1, getcount.icall$0()); |
| 213 Expect.equals(42, setcount.icall$1(42)); |
| 214 |
| 215 // Test all the icall wrappers, all c functions returns the sum of the |
| 216 // arguments. |
| 217 var icall0 = fl.lookup('ifun0'); |
| 218 var icall1 = fl.lookup('ifun1'); |
| 219 var icall2 = fl.lookup('ifun2'); |
| 220 var icall3 = fl.lookup('ifun3'); |
| 221 var icall4 = fl.lookup('ifun4'); |
| 222 var icall5 = fl.lookup('ifun5'); |
| 223 var icall6 = fl.lookup('ifun6'); |
| 224 Expect.equals(0, icall0.icall$0()); |
| 225 Expect.equals(1, icall1.icall$1(1)); |
| 226 Expect.equals(2, icall2.icall$2(1, 1)); |
| 227 Expect.equals(3, icall3.icall$3(1, 1, 1)); |
| 228 Expect.equals(4, icall4.icall$4(1, 1, 1, 1)); |
| 229 Expect.equals(5, icall5.icall$5(1, 1, 1, 1, 1)); |
| 230 Expect.equals(6, icall6.icall$6(1, 1, 1, 1, 1, 1)); |
| 231 |
| 232 // Some limit tests, this is more of sanity checking of our conversions. |
| 233 Expect.equals(-1, icall1.icall$1(-1)); |
| 234 Expect.equals(-2, icall2.icall$2(-1, -1)); |
| 235 Expect.equals(2147483647, icall3.icall$3(2147483647, 0, 0)); |
| 236 Expect.equals(2147483646, icall3.icall$3(2147483647, -1, 0)); |
| 237 Expect.equals(-2147483647, icall3.icall$3(2147483647, 2, 0)); |
| 238 Expect.equals(0, icall1.icall$1(4294967296)); |
| 239 Expect.equals(1, icall1.icall$1(4294967297)); |
| 240 Expect.equals(-1, icall1.icall$1(4294967295)); |
| 241 Expect.equals(0, icall1.icall$1(1024 * 4294967296)); |
| 242 Expect.equals(1, icall1.icall$1(1024 * 4294967296 + 1)); |
| 243 |
| 244 // Test all the void wrappers. The vcall c functions will set the count to |
| 245 // the sum of the arguments, testable by running getcount. |
| 246 var vcall0 = fl.lookup('vfun0'); |
| 247 var vcall1 = fl.lookup('vfun1'); |
| 248 var vcall2 = fl.lookup('vfun2'); |
| 249 var vcall3 = fl.lookup('vfun3'); |
| 250 var vcall4 = fl.lookup('vfun4'); |
| 251 var vcall5 = fl.lookup('vfun5'); |
| 252 var vcall6 = fl.lookup('vfun6'); |
| 253 Expect.equals(null, vcall0.vcall$0()); |
| 254 Expect.equals(0, getcount.icall$0()); |
| 255 Expect.equals(null, vcall1.vcall$1(1)); |
| 256 Expect.equals(1, getcount.icall$0()); |
| 257 Expect.equals(null, vcall2.vcall$2(1, 1)); |
| 258 Expect.equals(2, getcount.icall$0()); |
| 259 Expect.equals(null, vcall3.vcall$3(1, 1, 1)); |
| 260 Expect.equals(3, getcount.icall$0()); |
| 261 Expect.equals(null, vcall4.vcall$4(1, 1, 1, 1)); |
| 262 Expect.equals(4, getcount.icall$0()); |
| 263 Expect.equals(null, vcall5.vcall$5(1, 1, 1, 1, 1)); |
| 264 Expect.equals(5, getcount.icall$0()); |
| 265 Expect.equals(null, vcall6.vcall$6(1, 1, 1, 1, 1, 1)); |
| 266 Expect.equals(6, getcount.icall$0()); |
| 267 fl.close(); |
| 268 } |
| 269 |
| 270 testFailingLibraryLookups() { |
| 271 var libPath = ForeignLibrary.bundleLibraryName('foobar'); |
| 26 Expect.throws( | 272 Expect.throws( |
| 27 () => Foreign.lookup('qsort', library: 'does-not-exist'), | 273 () => new ForeignLibrary.fromName(libPath), |
| 28 isArgumentError); | 274 isArgumentError); |
| 29 Expect.throws( | 275 Expect.throws( |
| 30 () => Foreign.lookup('does-not-exist'), | 276 () => new ForeignLibrary.fromName('random__for_not_hitting_foobar.so'), |
| 31 isArgumentError); | 277 isArgumentError); |
| 32 Expect.throws( | 278 } |
| 33 () => Foreign.lookup('does-not-exist', library: null), | 279 |
| 34 isArgumentError); | 280 testDefaultLibraryLookups() { |
| 35 } | 281 Expect.isTrue(ForeignLibrary.main.lookup('qsort') is ForeignFunction); |
| 36 | |
| 37 testICall() { | |
| 38 Foreign getpid = Foreign.lookup('getpid'); | |
| 39 int pid = getpid.icall$0(); | |
| 40 Expect.isTrue(pid > 0); | |
| 41 Expect.equals(pid, getpid.icall$0()); | |
| 42 } | |
| 43 | |
| 44 class ForeignPid extends Foreign { | |
| 45 static ForeignPid getpid() => _function.pcall$0(new ForeignPid()); | |
| 46 static Foreign _function = Foreign.lookup('getpid'); | |
| 47 } | |
| 48 | |
| 49 testPCall() { | |
| 50 ForeignPid pid = ForeignPid.getpid(); | |
| 51 Expect.isTrue(pid.value > 0); | |
| 52 Expect.equals(pid.value, ForeignPid.getpid().value); | |
| 53 } | 282 } |
| 54 | 283 |
| 55 testAllocate(bool finalized) { | 284 testAllocate(bool finalized) { |
| 56 int length = 10; | 285 int length = 10; |
| 57 Foreign memory = finalized | 286 ForeignMemory memory = finalized |
| 58 ? new Foreign.allocatedFinalize(length) | 287 ? new ForeignMemory.allocatedFinalize(length) |
| 59 : new Foreign.allocated(length); | 288 : new ForeignMemory.allocated(length); |
| 60 Expect.isTrue(memory.value != 0); | 289 Expect.isTrue(memory.address != 0); |
| 61 | |
| 62 Expect.throws(() => memory.getUint8(-100), isRangeError); | 290 Expect.throws(() => memory.getUint8(-100), isRangeError); |
| 63 Expect.throws(() => memory.getUint8(-1), isRangeError); | 291 Expect.throws(() => memory.getUint8(-1), isRangeError); |
| 64 Expect.throws(() => memory.getUint8(10), isRangeError); | 292 Expect.throws(() => memory.getUint8(10), isRangeError); |
| 65 Expect.throws(() => memory.getUint8(100), isRangeError); | 293 Expect.throws(() => memory.getUint8(100), isRangeError); |
| 66 | |
| 67 Expect.throws(() => memory.getUint32(7), isRangeError); | 294 Expect.throws(() => memory.getUint32(7), isRangeError); |
| 68 | 295 |
| 296 Expect.throws(() => memory.setUint8(length, 0), isRangeError); |
| 297 Expect.throws(() => memory.setUint16(length - 1, 0), isRangeError); |
| 298 Expect.throws(() => memory.setUint32(length - 3, 0), isRangeError); |
| 299 Expect.throws(() => memory.setUint64(length - 7, 0), isRangeError); |
| 300 Expect.throws(() => memory.setInt8(length, 0), isRangeError); |
| 301 Expect.throws(() => memory.setInt16(length - 1, 0), isRangeError); |
| 302 Expect.throws(() => memory.setInt32(length - 3, 0), isRangeError); |
| 303 Expect.throws(() => memory.setInt64(length - 7, 0), isRangeError); |
| 304 |
| 69 Expect.throws(() => memory.setUint32(0, 0.0), isArgumentError); | 305 Expect.throws(() => memory.setUint32(0, 0.0), isArgumentError); |
| 70 Expect.throws(() => memory.setUint32(0, new Object()), isArgumentError); | 306 Expect.throws(() => memory.setUint32(0, new Object()), isArgumentError); |
| 71 Expect.throws(() => memory.setFloat32(0, 0), isArgumentError); | 307 Expect.throws(() => memory.setFloat32(0, 0), isArgumentError); |
| 72 Expect.throws(() => memory.setFloat32(0, new Object()), isArgumentError); | 308 Expect.throws(() => memory.setFloat32(0, new Object()), isArgumentError); |
| 73 | 309 |
| 74 Expect.equals(0, memory.getUint32(6)); | 310 Expect.equals(0, memory.getUint32(6)); |
| 75 | 311 |
| 76 for (int i = 0; i < length; i++) { | 312 for (int i = 0; i < length; i++) { |
| 77 Expect.equals(0, memory.getUint8(i)); | 313 Expect.equals(0, memory.getUint8(i)); |
| 78 Expect.equals(i, memory.setUint8(i, i)); | 314 Expect.equals(i, memory.setUint8(i, i)); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 94 Expect.equals(1.0, memory.getFloat32(0)); | 330 Expect.equals(1.0, memory.getFloat32(0)); |
| 95 | 331 |
| 96 memory.setFloat64(0, 2.0); | 332 memory.setFloat64(0, 2.0); |
| 97 Expect.equals(2.0, memory.getFloat64(0)); | 333 Expect.equals(2.0, memory.getFloat64(0)); |
| 98 | 334 |
| 99 if (!finalized) { | 335 if (!finalized) { |
| 100 memory.free(); | 336 memory.free(); |
| 101 memory.free(); // Free'ing multiple times is okay. | 337 memory.free(); // Free'ing multiple times is okay. |
| 102 } | 338 } |
| 103 } | 339 } |
| OLD | NEW |