[squeak-dev] The Inbox: FFI-Tests-mt.66.mcz

commits at source.squeak.org commits at source.squeak.org
Thu Jul 14 14:11:45 UTC 2022


A new version of FFI-Tests was added to project The Inbox:
http://source.squeak.org/inbox/FFI-Tests-mt.66.mcz

==================== Summary ====================

Name: FFI-Tests-mt.66
Author: mt
Time: 14 December 2021, 11:16:18.08291 am
UUID: 9ea84003-a3cf-cd49-bb99-a01aec974a56
Ancestors: FFI-Tests-mt.65

Clarify tests with alias-to-atomic types. We should start on working on the coercion logic in the FFI plugin rather sooner than later. :-)

==================== Snapshot ====================

SystemOrganization addCategory: #'FFI-Tests'!
SystemOrganization addCategory: #'FFI-Tests-Fixtures'!

ExternalUnion subclass: #FFITestUdSi2
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestUdSi2 class>>fields (in category 'field definition') -----
fields
	"FFITestUdSi2 defineFields"
	^#(
		(d1 	'double')
		(sii1	'FFITestSi2')
	)!

ExternalUnion subclass: #FFITestUdi
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestUdi class>>fields (in category 'field definition') -----
fields
	"
	self defineFields
	"
	^#(
		(d1	'double')
		(i1	'int64_t')
	)!

ExternalUnion subclass: #FFITestUfd
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestUfd class>>fields (in category 'field definition') -----
fields
	"FFITestUfd defineFields"
	^#(
		(f1	'float')
		(d1	'double')
	)!

ExternalUnion subclass: #FFITestUfi
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestUfi class>>fields (in category 'field definition') -----
fields
	"FFITestUfi defineFields"
	^#(
		(f1	'float')
		(i1	'int32_t')
	)!

ExternalTypeAlias subclass: #FFITestAliasForChar
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestAliasForChar class>>originalTypeName (in category 'type alias') -----
originalTypeName

	^ 'char'!

ExternalTypeAlias subclass: #FFITestAliasForCharPointer
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestAliasForCharPointer class>>originalTypeName (in category 'as yet unclassified') -----
originalTypeName
	"
	self defineFields
	"
	^ 'char*'!

ExternalTypeAlias subclass: #FFITestAliasForInt32
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestAliasForInt32 class>>originalTypeName (in category 'type alias') -----
originalTypeName
	"
	self defineFields
	"
	^ 'int32_t'!

ExternalTypeAlias subclass: #FFITestAliasForInt32Array
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestAliasForInt32Array class>>originalTypeName (in category 'type alias') -----
originalTypeName
	"
	self defineFields.
	"
	^ 'int32_t[5]'!

ExternalTypeAlias subclass: #FFITestAliasForInt32ArrayPointer
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestAliasForInt32ArrayPointer class>>originalTypeName (in category 'type alias') -----
originalTypeName
	"
	self defineFields
	"
	"^ 'int32_t[5]*' -- Not supported"
	"^ 'void**' -- Not supported"
	^ 'void*' "Workaround."!

ExternalTypeAlias subclass: #FFITestAliasForInt32Pointer
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestAliasForInt32Pointer class>>originalTypeName (in category 'type alias') -----
originalTypeName
	"
	self defineFields
	"
	^ 'int32_t*'!

ExternalTypeAlias subclass: #FFITestAliasForPoint4Pointer
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestAliasForPoint4Pointer class>>originalTypeName (in category 'type alias') -----
originalTypeName

	^ 'FFITestPoint4*'!

ExternalTypeAlias subclass: #FFITestAliasForSdi
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestAliasForSdi class>>originalTypeName (in category 'as yet unclassified') -----
originalTypeName
	"
	self defineFields
	"
	^ 'FFITestSdi'!

ExternalTypeAlias subclass: #FFITestAliasForSdiPointer
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestAliasForSdiPointer class>>originalTypeName (in category 'type alias') -----
originalTypeName
	"
	self defineFields
	"
	^ 'FFITestSdi*'!

ExternalTypeAlias subclass: #FFITestAliasForUfi
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestAliasForUfi class>>originalTypeName (in category 'type alias') -----
originalTypeName
	"
	self defineFields.
	"
	^ 'FFITestUfi'!

ExternalTypeAlias subclass: #FFITestAliasForVoidPointer
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestAliasForVoidPointer class>>originalTypeName (in category 'type alias') -----
originalTypeName
	"
	self defineFields
	"
	^ 'void*'!

ExternalStructure subclass: #FFISmallStruct1
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFISmallStruct1 class>>fields (in category 'field definition') -----
fields
	"FFISmallStruct1 defineFields"
	^#(
		(x	'byte')
		(y	'byte')
	)!

ExternalStructure subclass: #FFITestBiggerStruct
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestBiggerStruct class>>fields (in category 'field definition') -----
fields
	"FFITestBiggerStruct defineFields"
	^#(
		(x	'int64_t')
		(y	'int64_t')
		(z	'int64_t')
		(w	'int64_t')
		(r	'int64_t')
		(s	'int64_t')
		(t	'int64_t')
		(u	'int64_t'))!

ExternalStructure subclass: #FFITestCompoundStruct
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestCompoundStruct class>>fields (in category 'field definition') -----
fields
	"FFITestCompoundStruct defineFields"
	^#(
		(s1	#FFISmallStruct1)
		(p1	'FFISmallStruct1 *')
		(s2	#FFITestPoint2)
		(p2	'FFITestPoint2 *')
		(s4	#FFITestPoint4)
		(p4	'FFITestPoint4 *')
	)!

ExternalStructure subclass: #FFITestEmptyStruct
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

ExternalStructure subclass: #FFITestLink
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestLink class>>fields (in category 'field definition') -----
fields
	"
	self defineFields.
	"
	^ #(
		(prev 'FFITestLink*')
		(next 'FFITestLink*')
	)!

ExternalStructure subclass: #FFITestMisalignedCompoundStruct
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestMisalignedCompoundStruct class>>fields (in category 'field definition') -----
fields
	"FFITestMisalignedCompoundStruct defineFields"
	^#(
		(s1	'int16_t') "short"
		(s2	'FFITestMisalignedStruct')
	)!

ExternalStructure subclass: #FFITestMisalignedStruct
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestMisalignedStruct class>>fields (in category 'field definition') -----
fields
	"FFITestMisalignedStruct defineFields"
	^#(
		(s1	'int16_t') "short"
		(i1	'int32_t')
	)!

ExternalStructure subclass: #FFITestPoint2
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

!FFITestPoint2 commentStamp: 'ar 8/14/2006 23:06' prior: 0!
A class used for testing structures as arguments for the FFI.!

----- Method: FFITestPoint2 class>>fields (in category 'field definition') -----
fields
	"FFITestPoint2 defineFields"
	^#(
		(x	'int32_t')
		(y	'int32_t')
	)!

----- Method: FFITestPoint2 class>>fromPoint: (in category 'instance creation') -----
fromPoint: aPoint

	^ self new
		setX: aPoint x setY: aPoint y;
		yourself!

----- Method: FFITestPoint2>>asPoint (in category 'converting') -----
asPoint

	^ self x @ self y!

----- Method: FFITestPoint2>>setX:setY: (in category 'initialization') -----
setX: xValue setY: yValue.

	self x: xValue.
	self y: yValue.!

ExternalStructure subclass: #FFITestPoint4
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

!FFITestPoint4 commentStamp: 'ar 8/14/2006 23:06' prior: 0!
A class used for testing structures as arguments for the FFI.!

----- Method: FFITestPoint4 class>>fields (in category 'field definition') -----
fields
	"FFITestPoint4 defineFields"
	^#(
		(x	'int32_t')
		(y	'int32_t')
		(z	'int32_t')
		(w	'int32_t')
	)!

ExternalStructure subclass: #FFITestSSdi5
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSSdi5 class>>fields (in category 'field definition') -----
fields
	"FFITestSSdi5 defineFields"
	^#(
		(sdi1	'FFITestSdi')
		(sdi2	'FFITestSdi')
		(sdi3	'FFITestSdi')
		(sdi4	'FFITestSdi')
		(sdi5	'FFITestSdi')
	)!

ExternalStructure subclass: #FFITestSUfdUdSi2
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSUfdUdSi2 class>>fields (in category 'field definition') -----
fields
	"FFITestSUfdUdSi2 defineFields"
	^#(
		(ufd1	'FFITestUfd')
		(udSii2	'FFITestUdSi2')
	)!

ExternalStructure subclass: #FFITestSUfdUfi
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSUfdUfi class>>fields (in category 'field definition') -----
fields
	"FFITestSUfdUfi defineFields"
	^#(
		(ufd1	'FFITestUfd')
		(ufi2	'FFITestUfi')
	)!

ExternalStructure subclass: #FFITestSd2
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSd2 class>>fields (in category 'field definition') -----
fields
	"FFITestSd2 defineFields"
	^#(
		(d1	'double')
		(d2	'double')
	)!

ExternalStructure subclass: #FFITestSdA5i
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSdA5i class>>fields (in category 'as yet unclassified') -----
fields
	"
	FFITestSdA5i defineFields
	"
	^ #(
	(d1 'double')
	(a5i2 'int32_t[5]')
	)!

ExternalStructure subclass: #FFITestSdi
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSdi class>>fields (in category 'field definition') -----
fields
	"FFITestSdi defineFields"
	^#(
		(d1	'double')
		(i2	'int32_t')
	)!

ExternalStructure subclass: #FFITestSf2
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSf2 class>>fields (in category 'field definition') -----
fields
	"FFITestSf2 defineFields"
	^#(
		(f1	'float')
		(f2	'float')
	)!

ExternalStructure subclass: #FFITestSf2d
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSf2d class>>fields (in category 'field definition') -----
fields
	"FFITestSf2d defineFields"
	^#(
		(f1	'float')
		(f2	'float')
		(d3	'double')
	)!

ExternalStructure subclass: #FFITestSf4
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSf4 class>>fields (in category 'field definition') -----
fields
	"FFITestSf4 defineFields"
	^#(
		(f1	'float')
		(f2	'float')
		(f3	'float')
		(f4	'float')
	)!

ExternalStructure subclass: #FFITestSfd
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSfd class>>fields (in category 'field definition') -----
fields
	"FFITestSfd defineFields"
	^#(
		(f1	'float')
		(d2	'double')
	)!

ExternalStructure subclass: #FFITestSfdf
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSfdf class>>fields (in category 'field definition') -----
fields
	"FFITestSfdf defineFields"
	^#(
		(f1	'float')
		(d2	'double')
		(f3	'float')
	)!

ExternalStructure subclass: #FFITestSfi
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSfi class>>fields (in category 'field definition') -----
fields
	"FFITestSfi defineFields"
	^#(
		(f1	'float')
		(i2	'int32_t')
	)!

ExternalStructure subclass: #FFITestSi2
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSi2 class>>fields (in category 'field definition') -----
fields
	"FFITestSi2 defineFields"
	^#(
		(i1	'int32_t')
		(i2	'int32_t')
	)!

ExternalStructure subclass: #FFITestSl2
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSl2 class>>fields (in category 'field definition') -----
fields
	"FFITestSl2 defineFields"
	^#(
		(l1	'int64_t') "longlong"
		(l2	'int64_t') "longlong"
	)!

ExternalStructure subclass: #FFITestSs2
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSs2 class>>fields (in category 'field definition') -----
fields
	"FFITestSs2 defineFields"
	^#(
		(s1	'int16_t') "short"
		(s2	'int16_t') "short"
	)!

ExternalStructure subclass: #FFITestSs2i
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSs2i class>>fields (in category 'field definition') -----
fields
	"FFITestSs2i defineFields"
	^#(
		(s1	'int16_t') "short"
		(s2	'int16_t') "short"
		(i3	'int32_t')
	)!

ExternalStructure subclass: #FFITestSs4
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSs4 class>>fields (in category 'field definition') -----
fields
	"FFITestSs4 defineFields"
	^#(
		(s1	'int16_t') "short"
		(s2	'int16_t') "short"
		(s3	'int16_t') "short"
		(s4	'int16_t') "short"
	)!

ExternalStructure subclass: #FFITestSsSsf
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSsSsf class>>fields (in category 'field definition') -----
fields
	"FFITestSsSsf defineFields"
	^#(
		(s1	'int16_t') "short"
		(ssf2	'FFITestSsf')
	)!

ExternalStructure subclass: #FFITestSsSsi
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSsSsi class>>fields (in category 'field definition') -----
fields
	"FFITestSsSsi defineFields"
	^#(
		(s1	'int16_t') "short"
		(ssi2	FFITestSsi)
	)!

ExternalStructure subclass: #FFITestSsf
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSsf class>>fields (in category 'field definition') -----
fields
	"FFITestSsf defineFields"
	^#(
		(s1	'int16_t') "short"
		(f2	'float')
	)!

ExternalStructure subclass: #FFITestSsi
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSsi class>>fields (in category 'field definition') -----
fields
	"FFITestSsi defineFields"
	^#(
		(s1	'int16_t') "short"
		(i2	'int32_t')
	)!

ExternalStructure subclass: #FFITestSsis
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSsis class>>fields (in category 'field definition') -----
fields
	"FFITestSsis defineFields"
	^#(
		(s1	'int16_t') "short"
		(i2	'int32_t')
		(s3	'int16_t') "short"
	)!

ExternalStructure subclass: #FFITestSslf
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSslf class>>fields (in category 'field definition') -----
fields
	"FFITestSslf defineFields"
	^#(
		(s1	'int16_t') "short"
		(l2	'int64_t') "longlong"
		(f3	'float')
	)!

ExternalStructure subclass: #FFITestSsls
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: FFITestSsls class>>fields (in category 'field definition') -----
fields
	"FFITestSsls defineFields"
	^#(
		(s1	'int16_t') "short"
		(l2	'int64_t') "longlong"
		(s3	'int16_t') "short"
	)!

ExternalStructure subclass: #X64TestStruct
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: X64TestStruct class>>fields (in category 'field definition') -----
fields
	"X64TestStruct defineFields"
	^#(
		(one 'longlong')
		(two 'double')
		(three 'longlong')
		(four 'double')
		(five 'longlong')
		(six 'double')
		(seven 'longlong')
		(eight 'double')
		(nine 'longlong')
		(ten 'double')
		(eleven 'longlong')
		(twelve 'double')
		(thirteen 'longlong')
		(fourteen 'double')
		(fifteen 'longlong')
		(sixteen 'double')
	)!

ExternalStructure subclass: #X64TestStruct2
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: X64TestStruct2 class>>fields (in category 'field definition') -----
fields
	"X64TestStruct2 defineFields"
	^#(
		(one #X64TestStruct)
		(two #X64TestStruct)
	)!

ExternalStructure subclass: #X64TestStruct3
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

----- Method: X64TestStruct3 class>>fields (in category 'field definition') -----
fields
	"X64TestStruct3 defineFields"
	^#(
		(one 'longlong')
		(two 'double')
		(three 'longlong')
		(four 'double')
		(five 'longlong')
		(six 'double')
		(seven 'longlong')
		(eight 'double')
		(nine 'longlong')
		(ten 'double')
		(eleven 'longlong')
		(twelve 'double')
		(thirteen 'longlong')
		(fourteen 'double')
		(fifteen 'longlong')
		(sixteen 'double')
		(seventeen #X64TestStruct)
		(eighteen #X64TestStruct2)
		(nineteen 'X64TestStruct*')
		(twenty 'X64TestStruct2*')
	)!

ExternalLibrary subclass: #FFITestLibrary
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests-Fixtures'!

!FFITestLibrary commentStamp: 'ar 8/14/2006 23:06' prior: 0!
ExternalLibrarty used in FFI tests!

----- Method: FFITestLibrary class>>ffiPrintString: (in category 'other') -----
ffiPrintString: aString
	"
	FFITestLibrary ffiPrintString: 'Hello'
	"
	<cdecl: char* 'ffiPrintString' (char *) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiPrintWideString: (in category 'other') -----
ffiPrintWideString: aString
	"
	FFITestLibrary ffiPrintString: 'Hello'
	"
	<cdecl: uchar32_t* 'ffiPrintString' (uchar32_t *) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTest4IntSum:with:with:with: (in category 'atomic - int32_t') -----
ffiTest4IntSum: c1 with: c2 with: c3 with: c4
	"FFITestLibrary ffiTest4IntSum: 1 with: 2 with: 3 with: 4"
	<cdecl: int32_t 'ffiTest4IntSum' (int32_t int32_t int32_t int32_t) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTest8IntSum:with:with:with:with:with:with:with: (in category 'atomic - int32_t') -----
ffiTest8IntSum: c1 with: c2 with: c3 with: c4 with: c5 with: c6 with: c7 with: c8
	"FFITestLibrary ffiTest8IntSum: 1 with: 2 with: 3 with: 4 with: 5 with: 6 with: 7 with: 8"
	<cdecl: int32_t 'ffiTest8IntSum' (int32_t int32_t int32_t int32_t int32_t int32_t int32_t int32_t) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTest8LongLongSum:with:with:with:with:with:with:with: (in category 'atomic - int64_t') -----
ffiTest8LongLongSum: long1 with: long2 with: long3 with: long4 with: long5 with: long6 with: long7 with: long8

	<cdecl: longlong 'ffiTest8LongLongSum' (longlong longlong longlong longlong longlong longlong longlong longlong) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTest8longSum:with:with:with:with:with:with:with: (in category 'atomic - c_long') -----
ffiTest8longSum: c1 with: c2 with: c3 with: c4 with: c5 with: c6 with: c7 with: c8
	"FFITestLibrary ffiTest8LongSum: 1 with: 2 with: 3 with: 4 with: 5 with: 6 with: 7 with: 8"
	<cdecl: c_long 'ffiTest8longSum' (c_long c_long c_long c_long c_long c_long c_long c_long) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestAliasForPointerResult:with: (in category 'experiments') -----
ffiTestAliasForPointerResult: pt1 with: pt2
	"Allocates the result. Needs to be free'd after calling."
	<cdecl: FFITestAliasForPoint4Pointer 'ffiTestPointers' (FFITestPoint4* FFITestPoint4*) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestArrayResultWith:with: (in category 'experiments') -----
ffiTestArrayResultWith: pt1 with: pt2
	"Allocates the result. Needs to be free'd after calling."
	<cdecl: FFITestPoint4[] 'ffiTestPointers' (FFITestPoint4* FFITestPoint4*) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestArrayResultWithString: (in category 'experiments') -----
ffiTestArrayResultWithString: aString
	"
	FFITestLibrary ffiTestArrayResultWithString: 'Hello Squeak'.
	"
	<cdecl: char[] 'ffiPrintString' (char *) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestArrayType (in category 'experiments') -----
ffiTestArrayType
	"Just a mock. Not sure whether there will ever be call signatures using array types ... isn't this pass-by-pointer anyway?"
	
	<cdecl: char[5] 'ffiTestArrayType' (float[5] FFITestPoint2[10] int[1]) module: 'SqueakFFIPrims'>
	^ self externalCallFailed !

----- Method: FFITestLibrary class>>ffiTestBool:with:with:with: (in category 'atomic - bool') -----
ffiTestBool: b1 with: b2 with: b3 with: b4
	"FFITestLibrary ffiTestBool: true with: false with: true with: false"
	<cdecl: bool 'ffiTestInts' (bool bool bool bool) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestChars:with:with:with: (in category 'atomic - char') -----
ffiTestChars: c1 with: c2 with: c3 with: c4
	"Answers c1 + c2 as Character.
	FFITestLibrary ffiTestChars: $A with: 32 with: 0 with: 0
	"
	<cdecl: char 'ffiTestChars' (char char char char) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestDecoration (in category 'experiments') -----
ffiTestDecoration
	"Just a mock. Commas and 'const' should be ignored while parsing the signature."
	
	<cdecl: threaded const void* 'ffiTestDecoration' (void*, const int*, double, const int[], char*) module: 'SqueakFFIPrims'>
	^ self externalCallFailed !

----- Method: FFITestLibrary class>>ffiTestDoubles14:with:with:with:with:with:with:with:with:with:with:with:with:with: (in category 'atomic - floats') -----
ffiTestDoubles14: f1 with: f2 with: f3 with: f4 with: f5 with: f6 with: f7 with: f8 with: f9 with: f10 with: f11 with: f12 with: f13 with: f14

	<cdecl: double 'ffiTestDoubles14' (double double double double double double double double double double double double double double) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestDoubles9:with:with:with:with:with:with:with:with: (in category 'atomic - floats') -----
ffiTestDoubles9: f1 with: f2 with: f3 with: f4 with: f5 with: f6 with: f7 with: f8 with: f9
	"FFITestLibrary ffiTestDoubles9: 1.0 with: 2.0 with: 3.0 with: 4.0 with: 5.0 with: 6.0 with: 7.0 with: 8.0 with: 9.0"
	<cdecl: double 'ffiTestDoubles9' (double double double double double double double double double) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestDoubles:with: (in category 'atomic - floats') -----
ffiTestDoubles: f1 with: f2
	"FFITestLibrary ffiTestDoubles: $A with: 65.0"
	<cdecl: double 'ffiTestDoubles' (double double) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestFloats13:with:with:with:with:with:with:with:with:with:with:with:with: (in category 'atomic - floats') -----
ffiTestFloats13: f1 with: f2 with: f3 with: f4 with: f5 with: f6 with: f7 with: f8 with: f9 with: f10 with: f11 with: f12 with: f13

	<cdecl: float 'ffiTestFloats13' (float float float float float float float float float float float float float) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestFloats14:with:with:with:with:with:with:with:with:with:with:with:with:with: (in category 'atomic - floats') -----
ffiTestFloats14: f1 with: f2 with: f3 with: f4 with: f5 with: f6 with: f7 with: f8 with: f9 with: f10 with: f11 with: f12 with: f13 with: f14

	<cdecl: float 'ffiTestFloats14' (float float float float float float float float float float float float float float) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestFloats7:with:with:with:with:with:with: (in category 'atomic - floats') -----
ffiTestFloats7: f1 with: f2 with: f3 with: f4 with: f5 with: f6 with: f7

	<cdecl: float 'ffiTestFloats7' (float float float float float float float) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestFloats:with: (in category 'atomic - floats') -----
ffiTestFloats: f1 with: f2
	"FFITestLibrary ffiTestFloats: $A with: 65.0"
	<cdecl: float 'ffiTestFloats' (float float) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestFunctionByIndex (in category 'experiments') -----
ffiTestFunctionByIndex
	"Just a mock. Functions can be specified by index."
	
	<cdecl: void 42 (void)>
	^ self externalCallFailed !

----- Method: FFITestLibrary class>>ffiTestFunctionByString (in category 'experiments') -----
ffiTestFunctionByString
	"Just a mock. Functions can be specified by string."
	
	<cdecl: void 'ffiTestFunctionByString' (void)>
	^ self externalCallFailed !

----- Method: FFITestLibrary class>>ffiTestFunctionByToken (in category 'experiments') -----
ffiTestFunctionByToken
	"Just a mock. Functions can be specified by token."
	
	<cdecl: void ffiTestFunctionByToken (void)>
	^ self externalCallFailed !

----- Method: FFITestLibrary class>>ffiTestInitSUfdUdSi2:with: (in category 'structure - init') -----
ffiTestInitSUfdUdSi2: ufd with: udSi2
	"FFITestLibrary ffiTestInitSUfdUdSi2: ... with: .."
	<cdecl: FFITestSUfdUdSi2 'ffiTestInitSUfdUdSi2' (FFITestUfd FFITestUdSi2) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestInitSUfdUfi:with: (in category 'structure - init') -----
ffiTestInitSUfdUfi: ufd with: ufi
	"FFITestLibrary ffiTestInitSUfdUfi: ... with: .."
	<cdecl: FFITestSUfdUfi 'ffiTestInitSUfdUfi' (FFITestUfd FFITestUfi) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestInitUdSi2_d: (in category 'structure - init') -----
ffiTestInitUdSi2_d: d
	"FFITestLibrary ffiTestInitUdSi2_d: 1.0"
	<cdecl: FFITestUdSi2 'ffiTestInitUdSi2_d' (double) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestInitUdSi2_ii:with: (in category 'structure - init') -----
ffiTestInitUdSi2_ii: i1 with: i2
	"FFITestLibrary ffiTestInitUdSi2_ii: 1 with: 2"
	<cdecl: FFITestUdSi2 'ffiTestInitUdSi2_ii' (int32_t int32_t) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestInitUfd_d: (in category 'structure - init') -----
ffiTestInitUfd_d: d
	"FFITestLibrary ffiTestInitUfd_d: 1.0"
	<cdecl: FFITestUfd 'ffiTestInitUfd_d' (double) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestInitUfd_f: (in category 'structure - init') -----
ffiTestInitUfd_f: f
	"FFITestLibrary ffiTestInitUfd_f: 1.0"
	<cdecl: FFITestUfd 'ffiTestInitUfd_f' (float) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestInitUfi_f: (in category 'structure - init') -----
ffiTestInitUfi_f: f
	"FFITestLibrary ffiTestInitUfi_f: 1.0"
	<cdecl: FFITestUfi 'ffiTestInitUfi_f' (float) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestInitUfi_i: (in category 'structure - init') -----
ffiTestInitUfi_i: i
	"FFITestLibrary ffiTestInitUfi_i: 2"
	<cdecl: FFITestUfi 'ffiTestInitUfi_i' (long) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestInt4IntAliasSum:with:with:with: (in category 'type alias') -----
ffiTestInt4IntAliasSum: c1 with: c2 with: c3 with: c4
	"FFITestLibrary ffiTest4IntSum: 1 with: 2 with: 3 with: 4"
	<cdecl: int 'ffiTest4IntSum' (FFITestAliasForInt32 FFITestAliasForInt32 FFITestAliasForInt32 FFITestAliasForInt32) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestIntAlias4IntAliasSum:with:with:with: (in category 'type alias') -----
ffiTestIntAlias4IntAliasSum: c1 with: c2 with: c3 with: c4
	"FFITestLibrary ffiTest4IntSum: 1 with: 2 with: 3 with: 4"
	<cdecl: FFITestAliasForInt32 'ffiTest4IntSum' (FFITestAliasForInt32 FFITestAliasForInt32 FFITestAliasForInt32 FFITestAliasForInt32) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestIntAlias4IntSum:with:with:with: (in category 'type alias') -----
ffiTestIntAlias4IntSum: c1 with: c2 with: c3 with: c4
	"FFITestLibrary ffiTest4IntSum: 1 with: 2 with: 3 with: 4"
	<cdecl: FFITestAliasForInt32 'ffiTest4IntSum' (int32_t int32_t int32_t int32_t) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestInts8:with:with:with:with:with:with:with: (in category 'atomic - int32_t') -----
ffiTestInts8: c1 with: c2 with: c3 with: c4 with: c5 with: c6 with: c7 with: c8
	"Always answers 42."
	<cdecl: int32_t 'ffiTestInts8' (int32_t int32_t int32_t int32_t int32_t int32_t int32_t int32_t) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestInts:with:with:with: (in category 'atomic - int32_t') -----
ffiTestInts: c1 with: c2 with: c3 with: c4
	"Adds c1 + c2"
	<cdecl: int32_t 'ffiTestInts' (int32_t int32_t int32_t int32_t) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestLongLong8:with:with:with:with:with:with:with:with:with: (in category 'atomic - int64_t') -----
ffiTestLongLong8: char1 with: char2 with: char3 with: char4 with: char5 with: char6 with: char7 with: char8 with: long1 with: long2

	<cdecl: longlong 'ffiTestLongLong8' (char char char char char char char char longlong longlong) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestLongLong8a1:with:with:with:with:with:with:with:with:with:with: (in category 'atomic - int64_t') -----
ffiTestLongLong8a1: char1 with: char2 with: char3 with: char4 with: char5 with: char6 with: char7 with: char8 with: char9 with: long1 with: long2

	<cdecl: longlong 'ffiTestLongLong8a1' (char char char char char char char char char longlong longlong) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestLongLong8a2:with:with:with:with:with:with:with:with:with:with:with: (in category 'atomic - int64_t') -----
ffiTestLongLong8a2: char1 with: char2 with: char3 with: char4 with: char5 with: char6 with: char7 with: char8 with: char9 with: char10 with: long1 with: long2

	<cdecl: longlong 'ffiTestLongLong8a2' (char char char char char char char char char char longlong longlong) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestLongLong:with: (in category 'atomic - int64_t') -----
ffiTestLongLong: long1 with: long2
	"FFITestLibrary ffiTestLongLong: 3 with: 4"
	<cdecl: longlong 'ffiTestLongLong' (longlong longlong) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestLongLonga1:with:with: (in category 'atomic - int64_t') -----
ffiTestLongLonga1: byte with: long1 with: long2
	"FFITestLibrary ffiTestLongLongA1: 3 with: 4 with: 5"
	<cdecl: longlong 'ffiTestLongLonga1' (char longlong longlong) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestLongLonga2:with:with:with: (in category 'atomic - int64_t') -----
ffiTestLongLonga2: byte1 with: byte2 with: long1 with: long2

	<cdecl: longlong 'ffiTestLongLonga2' (char char longlong longlong) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestLongLonga3:with:with: (in category 'atomic - int64_t') -----
ffiTestLongLonga3: byte1 with: long1 with: byte2
	"FFITestLibrary ffiTestLongLonga3: 3 with: 4 with: 5"
	<cdecl: longlong 'ffiTestLongLonga3' (char longlong char) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestLongLongs8:with:with:with:with:with:with:with: (in category 'atomic - int64_t') -----
ffiTestLongLongs8: long1 with: long2 with: long3 with: long4 with: long5 with: long6 with: long7 with: long8
	"Always answers 42."
	<cdecl: longlong 'ffiTestLongLongs8' (longlong longlong longlong longlong longlong longlong longlong longlong) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestMixedDoublesAndLongs:with:with:with:with:with:with:with:with:with:with:with:with:with:with: (in category 'atomic') -----
ffiTestMixedDoublesAndLongs: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 with: arg14 with: arg15 "with: arg16 with: arg17 with: arg18 with: arg19 with: arg20"
 
	<cdecl: double 'ffiTestMixedDoublesAndLongs' (double c_long double c_long double c_long double c_long double c_long double c_long double c_long double c_long double c_long double c_long) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestMixedDoublesIntAndStruct:with:with:with:with:with:with:with:with:with:with: (in category 'structure') -----
ffiTestMixedDoublesIntAndStruct: f1 with: f2 with: f3 with: f4 with: f5 with: f6 with: f7 with: f8 with: f9 with: i1 with: s1
	"
	FFITestLibrary ffiTestMixedDoublesIntAndStruct: 1.0
		with: 2.0 with: 3.0 with: 4.0 with: 5.0
		with: 6.0 with: 7.0 with: 8.0 with: 9.0 with: 42
		with: (FFITestPoint4 new x: 3; y: 4; z: 5; w:6)
	"
	<cdecl: double 'ffiTestMixedDoublesIntAndStruct' (double double double double double double double double double long FFITestPoint4) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestMixedFloatsAndDouble:with:with:with: (in category 'atomic') -----
ffiTestMixedFloatsAndDouble: f1 with: d1 with: f2 with: f3
	"FFITestLibrary ffiTestMixedFloatsAndDouble: 1.2 with: 3.4 with: 5.6 with: 7.8"
	<cdecl: double 'ffiTestMixedFloatsAndDouble' (float double float float) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestMixedIntAndStruct2:with: (in category 'structure') -----
ffiTestMixedIntAndStruct2: i with: pt4
	"FFITestLibrary ffiTestMixedIntAndStruct2: 2 with: (FFITestPoint4 new x: 3; y: 4; z: 5; w:6)"
	<cdecl: int32_t 'ffiTestMixedIntAndStruct2' (int32_t FFITestPoint4) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestMixedIntAndStruct3:with: (in category 'structure') -----
ffiTestMixedIntAndStruct3: i with: anFFISmallStruct1
	"FFITestLibrary ffiTestMixedIntAndStruct3: 2 with: (FFISmallStruct1 new x: 3; y: 4)"
	<cdecl: int32_t 'ffiTestMixedIntAndStruct3' (int32_t FFISmallStruct1) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestMixedIntAndStruct:with:with: (in category 'structure') -----
ffiTestMixedIntAndStruct: i with: pt1 with: pt2
	"FFITestLibrary ffiTestMixedIntAndStruct: 2 with: (FFITestPoint2 new x: 3; y: 4) with: (FFITestPoint2 new x: 5; y: 6)"
	<cdecl: int32_t 'ffiTestMixedIntAndStruct' (int32_t FFITestPoint2 FFITestPoint2) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestPointers:with: (in category 'structure - points') -----
ffiTestPointers: pt1 with: pt2
	"Allocates the result. Needs to be free'd after calling."
	<cdecl: FFITestPoint4* 'ffiTestPointers' (FFITestPoint4* FFITestPoint4*) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSSdi5 (in category 'structure - return') -----
ffiTestReturnSSdi5
	"FFITestLibrary ffiTestReturnSSdi5"
	<cdecl: FFITestSSdi5 'ffiTestReturnSSdi5' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSd2 (in category 'structure - return') -----
ffiTestReturnSd2
	"FFITestLibrary ffiTestReturnSd2"
	<cdecl: FFITestSd2 'ffiTestReturnSd2' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSdi (in category 'structure - return') -----
ffiTestReturnSdi
	"FFITestLibrary ffiTestReturnSdi"
	<cdecl: FFITestSdi 'ffiTestReturnSdi' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSf2 (in category 'structure - return') -----
ffiTestReturnSf2
	"FFITestLibrary ffiTestReturnSf2"
	<cdecl: FFITestSf2 'ffiTestReturnSf2' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSf2d (in category 'structure - return') -----
ffiTestReturnSf2d
	"FFITestLibrary ffiTestReturnSf2d"
	<cdecl: FFITestSf2d 'ffiTestReturnSf2d' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSf4 (in category 'structure - return') -----
ffiTestReturnSf4
	"FFITestLibrary ffiTestReturnSf4"
	<cdecl: FFITestSf4 'ffiTestReturnSf4' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSfd (in category 'structure - return') -----
ffiTestReturnSfd
	"FFITestLibrary ffiTestReturnSfd"
	<cdecl: FFITestSfd 'ffiTestReturnSfd' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSfdf (in category 'structure - return') -----
ffiTestReturnSfdf
	"FFITestLibrary ffiTestReturnSfdf"
	<cdecl: FFITestSfdf 'ffiTestReturnSfdf' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSfi (in category 'structure - return') -----
ffiTestReturnSfi
	"FFITestLibrary ffiTestReturnSfi"
	<cdecl: FFITestSfi 'ffiTestReturnSfi' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSi2 (in category 'structure - return') -----
ffiTestReturnSi2
	"FFITestLibrary ffiTestReturnSi2"
	<cdecl: FFITestSi2 'ffiTestReturnSi2' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSl2 (in category 'structure - return') -----
ffiTestReturnSl2
	"FFITestLibrary ffiTestReturnSl2"
	<cdecl: FFITestSl2 'ffiTestReturnSl2' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSs2 (in category 'structure - return') -----
ffiTestReturnSs2
	"FFITestLibrary ffiTestReturnSs2"
	<cdecl: FFITestSs2 'ffiTestReturnSs2' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSs2i (in category 'structure - return') -----
ffiTestReturnSs2i
	"FFITestLibrary ffiTestReturnSs2i"
	<cdecl: FFITestSs2i 'ffiTestReturnSs2i' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSs4 (in category 'structure - return') -----
ffiTestReturnSs4
	"FFITestLibrary ffiTestReturnSs4"
	<cdecl: FFITestSs4 'ffiTestReturnSs4' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSsSsf (in category 'structure - return') -----
ffiTestReturnSsSsf
	"FFITestLibrary ffiTestReturnSsSsf"
	<cdecl: FFITestSsSsf 'ffiTestReturnSsSsf' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSsSsi (in category 'structure - return') -----
ffiTestReturnSsSsi
	"FFITestLibrary ffiTestReturnSsSsi"
	<cdecl: FFITestSsSsi 'ffiTestReturnSsSsi' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSsf (in category 'structure - return') -----
ffiTestReturnSsf
	"FFITestLibrary ffiTestReturnSsf"
	<cdecl: FFITestSsf 'ffiTestReturnSsf' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSsi (in category 'structure - return') -----
ffiTestReturnSsi
	"FFITestLibrary ffiTestReturnSsi"
	<cdecl: FFITestSsi 'ffiTestReturnSsi' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSsis (in category 'structure - return') -----
ffiTestReturnSsis
	"FFITestLibrary ffiTestReturnSsis"
	<cdecl: FFITestSsis 'ffiTestReturnSsis' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSslf (in category 'structure - return') -----
ffiTestReturnSslf
	"FFITestLibrary ffiTestReturnSslf"
	<cdecl: FFITestSslf 'ffiTestReturnSslf' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestReturnSsls (in category 'structure - return') -----
ffiTestReturnSsls
	"FFITestLibrary ffiTestReturnSsls"
	<cdecl: FFITestSsls 'ffiTestReturnSsls' () module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestShorts:with:with:with: (in category 'atomic - int16_t') -----
ffiTestShorts: c1 with: c2 with: c3 with: c4
	"Answers c1 + c2.
	FFITestLibrary ffiTestShorts: 1 with: 2 with: 3 with: 4"
	<cdecl: short 'ffiTestShorts' (short short short short) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestSmallStructReturn (in category 'structure - return') -----
ffiTestSmallStructReturn
	"FFITestLibrary ffiTestSmallStructReturn"
	<cdecl: FFISmallStruct1 'ffiTestSmallStructReturn' (void) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestStruct64:with: (in category 'structure - points') -----
ffiTestStruct64: pt1 with: pt2
	"pt1 + pt2"
	<cdecl: FFITestPoint2 'ffiTestStruct64' (FFITestPoint2 FFITestPoint2) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestStructBig:with: (in category 'structure - points') -----
ffiTestStructBig: pt1 with: pt2
	"pt1 + pt2"
	<cdecl: FFITestPoint4 'ffiTestStructBig' (FFITestPoint4 FFITestPoint4) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestStructBigger:with: (in category 'structure - points') -----
ffiTestStructBigger: pt1 with: pt2
	"Copies the values of pt1 to x, y, z, w and pt2 to r, s, t, u in the resulting struct."
	<cdecl: FFITestBiggerStruct 'ffiTestStructBigger' (FFITestPoint4 FFITestPoint4) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestSumSSdi5: (in category 'structure - sums') -----
ffiTestSumSSdi5: structSdi5
	"
	FFITestLibrary ffiTestSumSSdi5: FFITestLibrary ffiTestReturnSSdi5
	"
	<cdecl: double 'ffiTestSumSSdi5' (FFITestSSdi5) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestSumSUfdUdSi2_d: (in category 'structure - sums') -----
ffiTestSumSUfdUdSi2_d: sUfdUfi
	"
	FFITestLibrary ffiTestSumOfFloatFromSUfdUdSi2: (FFITestLibrary ...)
	"
	<cdecl: double 'ffiTestSumSUfdUdSi2_d' (FFITestSUfdUdSi2) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestSumSUfdUfi_f: (in category 'structure - sums') -----
ffiTestSumSUfdUfi_f: sUfdUfi
	"
	FFITestLibrary ffiTestSumSUfdUfi_f: (FFITestLibrary ...)
	"
	<cdecl: double 'ffiTestSumSUfdUfi_f' (FFITestSUfdUfi) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestSumSdi: (in category 'structure - sums') -----
ffiTestSumSdi: sdi
	"
	FFITestLibrary ffiTestSumSdi: FFITestLibrary ffiTestReturnSdi
	"
	<cdecl: double 'ffiTestSumSdi' (FFITestSdi) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestSumSdi_2:with: (in category 'structure - sums') -----
ffiTestSumSdi_2: sdi1 with: sdi2
	"
	FFITestLibrary
		ffiTestSumSdi_2: FFITestLibrary ffiTestReturnSdi
		with: FFITestLibrary ffiTestReturnSdi
	"
	<cdecl: double 'ffiTestSumSdi_2' (FFITestSdi FFITestSdi) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestSumSdi_4:with:with:with: (in category 'structure - sums') -----
ffiTestSumSdi_4: sdi1 with: sdi2 with: sdi3 with: sdi4
	"
	FFITestLibrary
		ffiTestSumSdi_4: FFITestLibrary ffiTestReturnSdi
		with: FFITestLibrary ffiTestReturnSdi
		with: FFITestLibrary ffiTestReturnSdi
		with: FFITestLibrary ffiTestReturnSdi
	"
	<cdecl: double 'ffiTestSumSdi_4' (FFITestSdi FFITestSdi FFITestSdi FFITestSdi) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestSumSfd: (in category 'structure - sums') -----
ffiTestSumSfd: sfd
	"
	FFITestLibrary ffiTestSumSfd: FFITestLibrary ffiTestReturnSfd
	"
	<cdecl: double 'ffiTestSumSfd' (FFITestSfd) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestSumSfd_2:with: (in category 'structure - sums') -----
ffiTestSumSfd_2: sfd1 with: sfd2
	"
	FFITestLibrary
		ffiTestSumSfd_2: FFITestLibrary ffiTestReturnSfd
		with: FFITestLibrary ffiTestReturnSfd
	"
	<cdecl: double 'ffiTestSumSfd_2' (FFITestSfd FFITestSfd) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestSumSfd_4:with:with:with: (in category 'structure - sums') -----
ffiTestSumSfd_4: sfd1 with: sfd2 with: sfd3 with: sfd4
	"
	FFITestLibrary
		ffiTestSumSfd_4: FFITestLibrary ffiTestReturnSfd
		with: FFITestLibrary ffiTestReturnSfd
		with: FFITestLibrary ffiTestReturnSfd
		with: FFITestLibrary ffiTestReturnSfd				
	"
	<cdecl: double 'ffiTestSumSfd_4' (FFITestSfd FFITestSfd FFITestSfd FFITestSfd) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestSumSslf: (in category 'structure - sums') -----
ffiTestSumSslf: sslf
	"
	FFITestLibrary ffiTestSumSslf: FFITestLibrary ffiTestReturnSslf
	"
	<cdecl: double 'ffiTestSumSslf' (FFITestSslf) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestSumSslf_2:with: (in category 'structure - sums') -----
ffiTestSumSslf_2: sslf1 with: sslf2
	"
	FFITestLibrary
		ffiTestSumSslf_2: FFITestLibrary ffiTestReturnSslf
		with: FFITestLibrary ffiTestReturnSslf		
	"
	<cdecl: double 'ffiTestSumSslf_2' (FFITestSslf FFITestSslf) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestSumSslf_4:with:with:with: (in category 'structure - sums') -----
ffiTestSumSslf_4: sslf1 with: sslf2 with: sslf3 with: sslf4
	"
	FFITestLibrary
		ffiTestSumSslf_4: FFITestLibrary ffiTestReturnSslf
		with: FFITestLibrary ffiTestReturnSslf
		with: FFITestLibrary ffiTestReturnSslf	
		with: FFITestLibrary ffiTestReturnSslf	
	"
	<cdecl: double 'ffiTestSumSslf_4' (FFITestSslf FFITestSslf FFITestSslf FFITestSslf) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestSumdWithSdi_4:with:with:with:with: (in category 'structure - sums') -----
ffiTestSumdWithSdi_4: aDouble with: sdi1 with: sdi2 with: sdi3 with: sdi4
	"
	FFITestLibrary
		ffiTestSumdWithSdi_4: 4.0
		with: FFITestLibrary ffiTestReturnSdi
		with: FFITestLibrary ffiTestReturnSdi
		with: FFITestLibrary ffiTestReturnSdi
		with: FFITestLibrary ffiTestReturnSdi
	"
	<cdecl: double 'ffiTestSumdWithSdi_4' (double FFITestSdi FFITestSdi FFITestSdi FFITestSdi) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestSumdiWithSdi_4:with:with:with:with:with: (in category 'structure - sums') -----
ffiTestSumdiWithSdi_4: aDouble with: anInt with: sdi1 with: sdi2 with: sdi3 with: sdi4
	"
	FFITestLibrary
		ffiTestSumdiWithSdi_4: 4.0
		with: 3
		with: FFITestLibrary ffiTestReturnSdi
		with: FFITestLibrary ffiTestReturnSdi
		with: FFITestLibrary ffiTestReturnSdi
		with: FFITestLibrary ffiTestReturnSdi
	"
	<cdecl: double 'ffiTestSumdiWithSdi_4' (double long FFITestSdi FFITestSdi FFITestSdi FFITestSdi) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestSumfWithSfd_4:with:with:with:with: (in category 'structure - sums') -----
ffiTestSumfWithSfd_4: aFloat with: sfd1 with: sfd2 with: sfd3 with: sfd4
	"
	FFITestLibrary
		ffiTestSumf: 0.5
		with: FFITestLibrary ffiTestReturnSfd
		with: FFITestLibrary ffiTestReturnSfd
		with: FFITestLibrary ffiTestReturnSfd
		with: FFITestLibrary ffiTestReturnSfd
	"
	<cdecl: double 'ffiTestSumfWithSfd_4' (float FFITestSfd FFITestSfd FFITestSfd FFITestSfd) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestSumiWithSdi_4:with:with:with:with: (in category 'structure - sums') -----
ffiTestSumiWithSdi_4: anInt with: sdi1 with: sdi2 with: sdi3 with: sdi4
	"
	FFITestLibrary
		ffiTestSumiWithSdi_4: 3
		with: FFITestLibrary ffiTestReturnSdi
		with: FFITestLibrary ffiTestReturnSdi
		with: FFITestLibrary ffiTestReturnSdi
		with: FFITestLibrary ffiTestReturnSdi
	"
	<cdecl: double 'ffiTestSumiWithSdi_4' (int32_t FFITestSdi FFITestSdi FFITestSdi FFITestSdi) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestUint:with:with:with: (in category 'atomic - uint32_t') -----
ffiTestUint: c1 with: c2 with: c3 with: c4
	"Answers c1 + c2. Repurpose ffiTestInts to check uint32_t range."
	<cdecl: int32_t 'ffiTestInts' (uint32_t uint32_t uint32_t uint32_t) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestVoid (in category 'experiments') -----
ffiTestVoid
	"Note that ffiTestVoid does exist in the module."
	<cdecl: void 'ffiTestVoid' (void) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>ffiTestVoidPointer (in category 'experiments') -----
ffiTestVoidPointer
	"Note that ffiTestVoidPointer does exist in the module."
	<cdecl: void* 'ffiTestVoidPointer' (void*) module:'SqueakFFIPrims'>
	^self externalCallFailed!

----- Method: FFITestLibrary class>>moduleName (in category 'accessing') -----
moduleName
	"Use the fully qualified VM name so we ensure testing loading a library"
	^'SqueakFFIPrims'!

TestCase subclass: #ExternalTypeTests
	instanceVariableNames: 'heapObject'
	classVariableNames: ''
	poolDictionaries: 'FFIConstants'
	category: 'FFI-Tests'!

----- Method: ExternalTypeTests>>classesForStructures (in category 'running') -----
classesForStructures
	"Answer a list of struct classes to be used when testing struct types."
	
	^ {
		FFITestPoint2.
		FFITestSdi.
		FFITestUfd.
		FFITestCompoundStruct.
	}!

----- Method: ExternalTypeTests>>classesForTypeAliases (in category 'running') -----
classesForTypeAliases
	"Answer a list of type-alias classes to be used when testing types for type aliases."
	
	^ {
		FFITestAliasForChar. "alias to atomic"
		FFITestAliasForInt32. "alias to atomic"
		FFITestAliasForSdi. "alias to struct"
	}!

----- Method: ExternalTypeTests>>expectedFailures (in category 'failures') -----
expectedFailures

	^ #(
	testBasicTypeForArrayType "Fails because compiledSpec does not yet encode that information"
	)!

----- Method: ExternalTypeTests>>specsForTypeAliasForPointer (in category 'running') -----
specsForTypeAliasForPointer
	"Answer a list of type-alias classes to be used when testing types for type aliases."
	
	^ {
		FFITestAliasForInt32Pointer . ExternalType int32_t asPointerType .
		FFITestAliasForVoidPointer . ExternalType void asPointerType .
		FFITestAliasForSdiPointer . FFITestSdi externalType asPointerType
	}!

----- Method: ExternalTypeTests>>tearDown (in category 'running') -----
tearDown

	heapObject ifNotNil: [heapObject free].!

----- Method: ExternalTypeTests>>testAliasForArray (in category 'tests - type aliases') -----
testAliasForArray

	| type originalType |
	type := FFITestAliasForInt32Array externalType.
	originalType := ExternalType int32_t asArrayType: 5.
	
	self
		assert: type isArrayType;
		assert: type isTypeAlias;

		deny: type isAtomic;
		deny: type isPointerType;
		deny: type isStructureType.

	self
		assert: originalType
		identical: type originalType;

		assert: originalType byteSize
		equals: type byteSize;
		assert: originalType byteAlignment
		equals: type byteAlignment.
		
	self
		"The alias has its own referentClass."
		assert: FFITestAliasForInt32Array identical: type referentClass;
		assert: nil "array of atomics" identical: originalType referentClass.!

----- Method: ExternalTypeTests>>testAliasForArrayByName (in category 'tests - type aliases') -----
testAliasForArrayByName

	| type |
	type := FFITestAliasForInt32Array externalType.
	self
		assert: type
		identical: (ExternalType typeNamed: type typeName);
		assert: type asPointerType
		identical: (ExternalType typeNamed: type asPointerType typeName).!

----- Method: ExternalTypeTests>>testAliasForArrayPointer (in category 'tests - type aliases') -----
testAliasForArrayPointer
	"Not supported. User void* for n-dimensional arrays."
	
	| type originalType |
	type := FFITestAliasForInt32ArrayPointer externalType.
	originalType := ExternalType void asPointerType.
	
	self
		assert: type isTypeAlias;
		assert: type isPointerType.

	self
		assert: originalType
		identical: type originalType.!

----- Method: ExternalTypeTests>>testAliasForArrayPointerByName (in category 'tests - type aliases') -----
testAliasForArrayPointerByName
	
	| type |
	type := FFITestAliasForInt32ArrayPointer externalType.
	self
		assert: type
		identical: (ExternalType typeNamed: type typeName);
		assert: type asPointerType
		identical: (ExternalType typeNamed: type asPointerType typeName).!

----- Method: ExternalTypeTests>>testAliasForAtomic (in category 'tests - type aliases') -----
testAliasForAtomic

	| type originalType |
	type := FFITestAliasForInt32 externalType.
	originalType := ExternalType int32_t.
	
	self
		assert: type isAtomic; "alias means alias =)"
		assert: type isTypeAlias;

		deny: type isPointerType;
		deny: type isStructureType;
		deny: type isArrayType.

	self
		assert: originalType
		identical: type originalType;

		assert: originalType byteSize
		equals: type byteSize;
		assert: originalType byteAlignment
		equals: type byteAlignment.
		
	self
		"The alias has its own referentClass."
		assert: FFITestAliasForInt32 identical: type referentClass;
		assert: nil identical: originalType referentClass.!

----- Method: ExternalTypeTests>>testAliasForAtomicByName (in category 'tests - type aliases') -----
testAliasForAtomicByName

	| type |
	type := FFITestAliasForInt32 externalType.
	self
		assert: type
		identical: (ExternalType typeNamed: type typeName);
		assert: type asPointerType
		identical: (ExternalType typeNamed: type asPointerType typeName).!

----- Method: ExternalTypeTests>>testAliasForPointer (in category 'tests - type aliases') -----
testAliasForPointer

	self specsForTypeAliasForPointer groupsDo: [:aliasClass :originalPointerType | 
		| pointerType type originalType |
		pointerType := aliasClass externalType.
	
		self
			assert: pointerType isTypeAlias;
			assert: pointerType isPointerType;

			deny: pointerType isAtomic;			
			deny: pointerType isStructureType;
			deny: pointerType isArrayType.
		
		"Note that it should be possible to access the original type."
		self
			assert: originalPointerType
			identical: pointerType originalType.
		
		"Check whether specs are equal to the original type's specs."
		self
			assert: originalPointerType byteSize
			equals: pointerType byteSize;
			assert: originalPointerType byteAlignment
			equals: pointerType byteAlignment.

		"Note that the non-pointer type of the alias is virtually a copy."
		type := pointerType "e.g. IntPr" asNonPointerType. "e.g. int ... but w/ different referentClass and referencedType"

		self
			deny: type isTypeAlias;
			assert: type isTypeAliasReferenced;
			deny: type isPointerType;
			assert: [type isAtomic "... but for something non-pointer-ish"
				or: [type isStructureType
				or: [type isArrayType]]].
			
		originalType := originalPointerType "e.g. int*" asNonPointerType. "e.g. int"
		self deny: originalType equals: type.
		self deny: originalPointerType equals: pointerType.
			
		"Check whether specs of non-pointer type are equal
		to the original type's non-pointer type specs."
		self
			assert: originalType headerWord
			equals: type headerWord;
			assert: originalType byteSize
			equals: type byteSize;
			assert: originalType byteAlignment
			equals: type byteAlignment.

		self
			"The alias has its own referentClass."
			assert: aliasClass equals: pointerType referentClass;
			assert: aliasClass equals: type referentClass;
			deny: aliasClass equals: originalPointerType referentClass;
			deny: aliasClass equals: originalType referentClass;
			
			"You can go back and forth in the type alias"
			assert: pointerType identical: type asPointerType;
			assert: type identical: pointerType asNonPointerType].!

----- Method: ExternalTypeTests>>testAliasForPointerByName (in category 'tests - type aliases') -----
testAliasForPointerByName

	self specsForTypeAliasForPointer groupsDo: [:aliasClass :originalPointerType | 
		| pointerType type |
		pointerType := aliasClass externalType asPointerType.
		type := pointerType asNonPointerType. 
		self
			assert: pointerType
			identical: (ExternalType typeNamed: pointerType typeName);
			assert: type
			identical: (ExternalType typeNamed: type typeName)].!

----- Method: ExternalTypeTests>>testAliasForStruct (in category 'tests - type aliases') -----
testAliasForStruct

	| type originalType |
	type := FFITestAliasForSdi externalType.
	originalType := FFITestSdi externalType.
	
	self
		assert: type isStructureType;
		assert: type isTypeAlias;

		deny: type isAtomic;
		deny: type isPointerType;		
		deny: type isArrayType.

	self
		assert: originalType
		identical: type originalType;

		assert: originalType byteSize
		equals: type byteSize;
		assert: originalType byteAlignment
		equals: type byteAlignment.
		
	self
		"The alias has its own referentClass."
		assert: FFITestAliasForSdi identical: type referentClass;
		assert: FFITestSdi identical: originalType referentClass.!

----- Method: ExternalTypeTests>>testAliasForStructByName (in category 'tests - type aliases') -----
testAliasForStructByName

	| type |
	type := FFITestAliasForSdi externalType.
	self
		assert: type
		identical: (ExternalType typeNamed: type typeName);
		assert: type asPointerType
		identical: (ExternalType typeNamed: type asPointerType typeName).!

----- Method: ExternalTypeTests>>testArrayOfAliases (in category 'tests - array types') -----
testArrayOfAliases

	self classesForTypeAliases do: [:aliasClass |
		| contentType arrayType |
		contentType := aliasClass externalType.
		arrayType := contentType asArrayType: 5.
			
		self assert: arrayType isArrayType.
		self assert: contentType identical: arrayType contentType.
		self assert: 5 equals: arrayType size.
		self assert: 5 * contentType byteSize equals: arrayType byteSize.

		self
			assert: contentType
			identical: arrayType contentType;
			assert: contentType byteAlignment
			equals: arrayType byteAlignment.
	
		self
			assert: contentType isTypeAlias;
			assert: (contentType isAtomic or: [contentType isStructureType]);
			deny: contentType isPointerType;
			deny: contentType isArrayType.
				
		self
			deny: arrayType isAtomic;
			deny: arrayType isStructureType;
			deny: arrayType isPointerType;
			deny: arrayType isTypeAlias.
	
		self
			deny: contentType referentClass isNil;
			assert: arrayType referentClass isNil].!

----- Method: ExternalTypeTests>>testArrayOfAliasesByName (in category 'tests - array types') -----
testArrayOfAliasesByName

	self classesForTypeAliases do: [:aliasClass |
		| contentType arrayType |
		contentType := aliasClass externalType.
		arrayType := contentType asArrayType: 5.
		self
			assert: arrayType
			identical: (ExternalType typeNamed: arrayType typeName);
			assert: arrayType asPointerType
			identical: (ExternalType typeNamed: arrayType asPointerType typeName)].!

----- Method: ExternalTypeTests>>testArrayOfAliasesForArrays (in category 'tests - array types') -----
testArrayOfAliasesForArrays
	"This is the only way to construct n-dimensional arrays for now."

	| contentType arrayType |
	contentType := FFITestAliasForInt32Array externalType.
	arrayType := contentType asArrayType: 5.
		
	self assert: arrayType isArrayType.
	self assert: contentType identical: arrayType contentType.
	self assert: 5 equals: arrayType size.
	self assert: 5 * contentType byteSize equals: arrayType byteSize.

	self
		assert: contentType
		identical: arrayType contentType;
		assert: contentType byteAlignment
		equals: arrayType byteAlignment.

	self
		assert: contentType isTypeAlias;
		assert: contentType isArrayType;
		deny: contentType isAtomic;
		deny: contentType isStructureType;
		deny: contentType isPointerType.
			
	self
		deny: arrayType isAtomic;
		deny: arrayType isStructureType;
		deny: arrayType isPointerType;
		deny: arrayType isTypeAlias.

	self
		deny: contentType referentClass isNil;
		assert: arrayType referentClass isNil.!

----- Method: ExternalTypeTests>>testArrayOfAliasesForPointers (in category 'tests - array types') -----
testArrayOfAliasesForPointers

	self specsForTypeAliasForPointer groupsDo: [:aliasClass :originalType |
		| contentType arrayType |
		contentType := aliasClass externalType.
		arrayType := contentType asArrayType: 5.
			
		self assert: arrayType isArrayType.
		self assert: contentType identical: arrayType contentType.
		self assert: 5 equals: arrayType size.
		self assert: 5 * contentType byteSize equals: arrayType byteSize.

		self
			assert: contentType
			identical: arrayType contentType;
			assert: contentType byteAlignment
			equals: arrayType byteAlignment.
		
		self
			assert: contentType isTypeAlias;
			assert: contentType isPointerType;
			deny: contentType isAtomic;
			deny: contentType isStructureType;
			deny: contentType isArrayType.
		
		self
			deny: arrayType isAtomic;
			deny: arrayType isStructureType;
			deny: arrayType isPointerType;
			deny: arrayType isTypeAlias.
	
		self
			deny: contentType referentClass isNil;
			assert: arrayType referentClass isNil].!

----- Method: ExternalTypeTests>>testArrayOfAliasesForPointersByName (in category 'tests - array types') -----
testArrayOfAliasesForPointersByName

	self specsForTypeAliasForPointer groupsDo: [:aliasClass :originalType |
		| contentType arrayType |
		contentType := aliasClass externalType.
		arrayType := contentType asArrayType: 5.
		self
			assert: arrayType asNonPointerType
			identical: (ExternalType typeNamed: arrayType asNonPointerType typeName);
			assert: arrayType asPointerType
			identical: (ExternalType typeNamed: arrayType asPointerType typeName)].!

----- Method: ExternalTypeTests>>testArrayOfAliasesForPointersDereferenced (in category 'tests - array types') -----
testArrayOfAliasesForPointersDereferenced
	"It should be possible to use the non-pointer type of an alias-to-pointer type as contentType in an array/container."

	self specsForTypeAliasForPointer groupsDo: [:aliasClass :originalType |
		| contentType arrayType |
		contentType := aliasClass externalType asNonPointerType.
		contentType byteSize = 0 ifTrue: [^ self "Ignore void"].
		arrayType := contentType asArrayType: 5.
			
		self assert: arrayType isArrayType.
		self assert: contentType identical: arrayType contentType.
		self assert: 5 equals: arrayType size.
		self assert: 5 * contentType byteSize equals: arrayType byteSize.

		self
			assert: contentType
			identical: arrayType contentType;
			assert: contentType byteAlignment
			equals: arrayType byteAlignment.
		
		self
			deny: contentType isTypeAlias;
			deny: contentType isPointerType;
			assert: [contentType isAtomic
				or: [contentType isStructureType
				or: [contentType isArrayType]]].
		
		self
			deny: arrayType isAtomic;
			deny: arrayType isStructureType;
			deny: arrayType isPointerType;
			deny: arrayType isTypeAlias.
	
		self
			deny: contentType referentClass isNil;
			assert: arrayType referentClass isNil].!

----- Method: ExternalTypeTests>>testArrayOfArrays (in category 'tests - array types') -----
testArrayOfArrays
	"Not directly supported."
	
	self
		assert: (ExternalType typeNamed: 'char[5]')
		identical: (ExternalType typeNamed: 'char[5][5]').
		
	self
		should: [(ExternalType char asArrayType: 5) asArrayType: 5]
		raise: Error.

	self
		assert: (ExternalType typeNamed: 'FFITestPoint2[5]')
		identical: (ExternalType typeNamed: 'FFITestPoint2[5][5]').
		
	self
		should: [(FFITestPoint2 externalType asArrayType: 5) asArrayType: 5]
		raise: Error.
!

----- Method: ExternalTypeTests>>testArrayOfAtomics (in category 'tests - array types') -----
testArrayOfAtomics

	ExternalType atomicTypes allButFirst "void" do: [:contentType |
		| arrayType |
		arrayType := contentType asArrayType: 5.
		
		self assert: arrayType isArrayType.
		self assert: contentType identical: arrayType contentType.
		self assert: 5 equals: arrayType size.
		self assert: 5 * contentType byteSize equals: arrayType byteSize.
		
		self deny: arrayType isAtomic.
		self deny: arrayType isStructureType.
		self deny: arrayType isPointerType.
		self deny: arrayType isTypeAlias.
		
		self assert: arrayType referentClass isNil].!

----- Method: ExternalTypeTests>>testArrayOfAtomicsByName (in category 'tests - array types') -----
testArrayOfAtomicsByName

	ExternalType atomicTypes allButFirst "void" do: [:contentType |
		| arrayType |
		arrayType := contentType asArrayType: 5.
		self
			assert: arrayType
			identical: (ExternalType typeNamed: arrayType typeName);
			assert: arrayType asPointerType
			identical: (ExternalType typeNamed: arrayType asPointerType typeName)].!

----- Method: ExternalTypeTests>>testArrayOfAtomicsWithSpecialSize (in category 'tests - array types') -----
testArrayOfAtomicsWithSpecialSize
	"Test char[] and char[0]."

	| contentType containerType |
	contentType := ExternalType char.
	
	containerType := contentType asArrayType: 0.
	self assert: containerType identical: (ExternalType typeNamed: 'char[0]').
	self assert: 0 equals: containerType byteSize.
	self assert: 0 equals: containerType size.
	self assert: contentType identical: containerType contentType.
	self assert: contentType byteAlignment equals: containerType byteAlignment.

	containerType := contentType asArrayType: nil.
	self assert: containerType identical: (ExternalType typeNamed: 'char[]').
	self assert: nil equals: containerType byteSize.
	self assert: nil equals: containerType size.
	self assert: contentType identical: containerType contentType.
	self assert: contentType byteAlignment equals: containerType byteAlignment.!

----- Method: ExternalTypeTests>>testArrayOfPointersToAtomics (in category 'tests - array types') -----
testArrayOfPointersToAtomics

	ExternalType atomicTypes "including void" do: [:atomicType |
		| arrayType contentType |
		contentType := atomicType asPointerType.
		arrayType := contentType asArrayType: 5.
		
		self assert: arrayType isArrayType.
		self assert: contentType identical: arrayType contentType.
		self assert: 5 equals: arrayType size.
		self assert: 5 * contentType byteSize equals: arrayType byteSize.
		
		self deny: arrayType isAtomic.
		self deny: arrayType isStructureType.
		self deny: arrayType isPointerType.
		self deny: arrayType isTypeAlias.
		
		self assert: arrayType referentClass isNil].!

----- Method: ExternalTypeTests>>testArrayOfPointersToAtomicsByName (in category 'tests - array types') -----
testArrayOfPointersToAtomicsByName

	ExternalType atomicTypes "including void" do: [:atomicType |
		| arrayType contentType |
		contentType := atomicType asPointerType.
		arrayType := contentType asArrayType: 5.
		self
			assert: arrayType
			identical: (ExternalType typeNamed: arrayType typeName);
			assert: arrayType asPointerType
			identical: (ExternalType typeNamed: arrayType asPointerType typeName)].!

----- Method: ExternalTypeTests>>testArrayOfPointersToAtomicsWithSpecialSize (in category 'tests - array types') -----
testArrayOfPointersToAtomicsWithSpecialSize
	"Test char*[] and char*[0]."
	
	| contentType containerType |
	contentType := ExternalType char asPointerType. "char*"

	containerType := contentType asArrayType: 0.
	self assert: containerType identical: (ExternalType typeNamed: 'char*[0]').
	self assert: 0 equals: containerType byteSize.
	self assert: 0 equals: containerType size.
	self assert: contentType identical: containerType contentType.
	self assert: contentType byteAlignment equals: containerType byteAlignment.

	containerType := contentType asArrayType: nil.
	self assert: containerType identical: (ExternalType typeNamed: 'char*[]').
	self assert: nil equals: containerType byteSize.
	self assert: nil equals: containerType size.
	self assert: contentType identical: containerType contentType.
	self assert: contentType byteAlignment equals: containerType byteAlignment.

!

----- Method: ExternalTypeTests>>testArrayOfPointersToStructs (in category 'tests - array types') -----
testArrayOfPointersToStructs

	self classesForStructures do: [:structClass |
		| arrayType contentType |
		contentType := structClass externalType asPointerType.
		arrayType := contentType asArrayType: 5.
		
		self assert: arrayType isArrayType.
		self assert: contentType identical: arrayType contentType.
		self assert: 5 equals: arrayType size.
		self assert: 5 * contentType byteSize equals: arrayType byteSize.
		
		self deny: arrayType isAtomic.
		self deny: arrayType isStructureType.
		self deny: arrayType isPointerType.
		self deny: arrayType isTypeAlias.
		
		self assert: arrayType referentClass isNil].!

----- Method: ExternalTypeTests>>testArrayOfPointersToStructsByName (in category 'tests - array types') -----
testArrayOfPointersToStructsByName

	self classesForStructures do: [:structClass |
		| arrayType contentType |
		contentType := structClass externalType asPointerType.
		arrayType := contentType asArrayType: 5.
		self
			assert: arrayType
			identical: (ExternalType typeNamed: arrayType typeName);
			assert: arrayType asPointerType
			identical: (ExternalType typeNamed: arrayType asPointerType typeName)].!

----- Method: ExternalTypeTests>>testArrayOfPointersToStructsWithSpecialSize (in category 'tests - array types') -----
testArrayOfPointersToStructsWithSpecialSize
	
	| contentType containerType |
	contentType := FFITestPoint2 externalType asPointerType. "FFITestPoint2*"

	containerType := contentType asArrayType: 0.
	self assert: containerType identical: (ExternalType typeNamed: 'FFITestPoint2*[0]').
	self assert: 0 equals: containerType byteSize.
	self assert: 0 equals: containerType size.
	self assert: contentType identical: containerType contentType.
	self assert: contentType byteAlignment equals: containerType byteAlignment.

	containerType := contentType asArrayType: nil.
	self assert: containerType identical: (ExternalType typeNamed: 'FFITestPoint2*[]').
	self assert: nil equals: containerType byteSize.
	self assert: nil equals: containerType size.
	self assert: contentType identical: containerType contentType.
	self assert: contentType byteAlignment equals: containerType byteAlignment.
!

----- Method: ExternalTypeTests>>testArrayOfStructs (in category 'tests - array types') -----
testArrayOfStructs

	self classesForStructures do: [:structClass |
		| arrayType contentType |
		contentType := structClass externalType.
		arrayType := structClass externalType asArrayType: 5.
		
		self assert: arrayType isArrayType.
		self assert: contentType identical: arrayType contentType.
		self assert: 5 equals: arrayType size.
		self assert: 5 * contentType byteSize equals: arrayType byteSize.	
		
		self deny: arrayType isAtomic.
		self deny: arrayType isStructureType.
		self deny: arrayType isPointerType.
		self deny: arrayType isTypeAlias.
		
		self assert: arrayType referentClass isNil].!

----- Method: ExternalTypeTests>>testArrayOfStructsByName (in category 'tests - array types') -----
testArrayOfStructsByName

	self classesForStructures do: [:structClass |
		| arrayType contentType |
		contentType := structClass externalType.
		arrayType := structClass externalType asArrayType: 5.
		self
			assert: arrayType
			identical: (ExternalType typeNamed: arrayType typeName);
			assert: arrayType asPointerType
			identical: (ExternalType typeNamed: arrayType asPointerType typeName)].!

----- Method: ExternalTypeTests>>testArrayOfStructsEmpty (in category 'tests - array types') -----
testArrayOfStructsEmpty

	| structClass arrayType contentType |
	structClass := FFITestEmptyStruct.
	contentType := structClass externalType.
	arrayType := structClass externalType asArrayType: 5.

	self assert: contentType isEmpty.
	self assert: 0 equals: contentType byteSize.
	self assert: 0 equals: arrayType byteSize.	
			
	self assert: arrayType isArrayType.
	self assert: contentType identical: arrayType contentType.
	self assert: 5 equals: arrayType size.
	
	self deny: arrayType isAtomic.
	self deny: arrayType isStructureType.
	self deny: arrayType isPointerType.
	self deny: arrayType isTypeAlias.
	
	self assert: arrayType referentClass isNil.!

----- Method: ExternalTypeTests>>testArrayOfStructsWithSpecialSize (in category 'tests - array types') -----
testArrayOfStructsWithSpecialSize

	| contentType containerType |
	contentType := FFITestPoint2 externalType.
	
	containerType := contentType asArrayType: 0.
	self assert: containerType identical: (ExternalType typeNamed: 'FFITestPoint2[0]').
	self assert: 0 equals: containerType byteSize.
	self assert: 0 equals: containerType size.
	self assert: contentType identical: containerType contentType.
	self assert: contentType byteAlignment equals: containerType byteAlignment.

	containerType := contentType asArrayType: nil.
	self assert: containerType identical: (ExternalType typeNamed: 'FFITestPoint2[]').
	self assert: nil equals: containerType byteSize.
	self assert: nil equals: containerType size.
	self assert: contentType identical: containerType contentType.
	self assert: contentType byteAlignment equals: containerType byteAlignment.!

----- Method: ExternalTypeTests>>testArrayOfUnknown (in category 'tests - unkown types') -----
testArrayOfUnknown
	"For missing a referentClass, an unknown type will be constructed."
	
	| type |
	Smalltalk garbageCollect.
	ExternalType cleanupUnusedTypes.
	
	self assert: nil equals: (ExternalType typeNamed: 'UnknownStruct[]').
	self assert: nil equals: (ExternalType typeNamed: 'UnknownStruct[5]').	
	
	type := ExternalType newTypeNamed: 'UnknownStruct[5]'.
	self assert: type isArrayType.
	self assert: type isUnknownType.

	type := ExternalType newTypeNamed: 'UnknownStruct[]'.
	self assert: type isArrayType.
	self assert: type isUnknownType.
	
	"Already there."
	self should: [ExternalType newTypeNamed: 'UnknownStruct[]'] raise: Error.
	self should: [ExternalType newTypeNamed: 'UnknownStruct[5]'] raise: Error.	
!

----- Method: ExternalTypeTests>>testArrayOfVoid (in category 'tests - array types') -----
testArrayOfVoid

	self
		should: [ExternalType void asArrayType: 5]
		raise: Error.!

----- Method: ExternalTypeTests>>testArrayVsPointer (in category 'tests - array types') -----
testArrayVsPointer

	| arrayType pointerType |
	arrayType := ExternalType typeNamed: 'char[]'.
	pointerType := ExternalType typeNamed: 'char*'.
	self
		assert: arrayType isArrayType;
		deny: arrayType isPointerType;
		assert: pointerType isPointerType;
		deny: pointerType isArrayType.
	
	self deny: arrayType typeName = pointerType typeName.
	self deny: arrayType asPointerType typeName = pointerType typeName.!

----- Method: ExternalTypeTests>>testArrayWithLargeByteSize (in category 'tests - array types') -----
testArrayWithLargeByteSize

	| arrayType byteSize contentType arraySize |
	byteSize := FFIStructSizeMask + 1.
	contentType := ExternalType uint64_t.
	arraySize := (byteSize / contentType byteSize) rounded.
	arrayType := contentType asArrayType: arraySize.
	self assert: arrayType byteSize > FFIStructSizeMask.!

----- Method: ExternalTypeTests>>testAtomicType (in category 'tests - atomic types') -----
testAtomicType
	"Check the basic integrity of atomic types."

	ExternalType atomicTypes do: [:type |
		self
			assert: type isAtomic;
			assert: type typeName equals: type atomicTypeName;
			
			deny: type isPointerType;
			deny: type isStructureType;
			deny: type isArrayType;
			deny: type isTypeAlias;
			
			assert: type referentClass isNil].!

----- Method: ExternalTypeTests>>testAtomicTypeByName (in category 'tests - atomic types') -----
testAtomicTypeByName
	"Check whether the lookup of atomic types will yield the singleton instances of those types."

	ExternalType atomicTypeNames do: [:typeName |
		self
			assert: (ExternalType typeNamed: typeName)
			identical: (ExternalType typeNamed: typeName)].!

----- Method: ExternalTypeTests>>testAtomicTypeBySelector (in category 'tests - atomic types') -----
testAtomicTypeBySelector
	"Check whether all atomic type names are available as message on the class ExternalType such as 'ExternalType char'."
	
	ExternalType atomicTypeNames do: [:typeName |
		self assert: (ExternalType perform: typeName asSymbol) isAtomic].!

----- Method: ExternalTypeTests>>testAtomicTypeBySpec (in category 'tests - atomic types') -----
testAtomicTypeBySpec
	"Check whether the lookup of atomic types will yield the singleton instances of those types."

	ExternalType atomicTypes do: [:type |
		self
			assert: type
			identical: (ExternalType lookupType: type typeName);
			assert: type
			identical: (ExternalType lookupType: type)].!

----- Method: ExternalTypeTests>>testAtomicTypeNameByType (in category 'tests - atomic types') -----
testAtomicTypeNameByType
	"Check whether #typeName answers a name that can be used for looking up atomic types."
	
	ExternalType atomicTypes do: [:type |
		self
			assert: type
			identical: (ExternalType typeNamed: type typeName).
		self
			assert: type asPointerType
			identical: (ExternalType typeNamed: type asPointerType typeName)].!

----- Method: ExternalTypeTests>>testAtomicTypeRange (in category 'tests - atomic types') -----
testAtomicTypeRange
	"Tests the range of non-integer and non-float types. Includes char types because those look different in Smalltalk."
	
	self should: [ExternalType void minVal] raise: Error.
	self should: [ExternalType void maxVal] raise: Error.

	self should: [ExternalType bool minVal] raise: Error.
	self should: [ExternalType bool maxVal] raise: Error.	

	self should: [ExternalType char8_t minVal] raise: Error.
	self should: [ExternalType char8_t maxVal] raise: Error.	

	self should: [ExternalType uchar8_t minVal] raise: Error.
	self should: [ExternalType uchar8_t maxVal] raise: Error.	
!

----- Method: ExternalTypeTests>>testBasicType (in category 'tests - compiled spec') -----
testBasicType

	| type baseType |
	type := ExternalType int32_t.
	baseType := type asBasicType.
	self assert: ExternalType identical: baseType asNonPointerType class.	
	self assert: ExternalType identical: baseType asPointerType class.!

----- Method: ExternalTypeTests>>testBasicTypeForArrayType (in category 'tests - compiled spec') -----
testBasicTypeForArrayType

	| type baseType |
	type := ExternalType typeNamed: 'char[5]'.
	baseType := type asBasicType.
	self assert: type isArrayType equals: baseType isArrayType.
	self assert: type byteSize equals: baseType byteSize.
	self assert: type size equals: baseType size.		!

----- Method: ExternalTypeTests>>testBasicTypeForAtomicType (in category 'tests - compiled spec') -----
testBasicTypeForAtomicType
	"Check all information about atomics compiled in the compiledSpec's headerWord. While there might be polymorphic optimizations for in-image type checking, the basic type MUST contain all that information, too. Some checks will signal errors, which is okay as long as there are errors for the basic type, too."
	
	ExternalType atomicTypes do: [:type |
		| baseType |
		baseType := type asBasicType.
		#(isAtomic atomicType byteSize size
		isIntegerType isFloatType isCharType isBoolType isVoid
		isEmpty)
			do: [:selector |
				self
					assert: (type perform: selector)
					equals: (baseType perform: selector)].
		#(isSigned isUnsigned isSinglePrecision isDoublePrecision)
			do: [:selector |
				self
					assert: ([type perform: selector] on: Error do: [#error])
					equals: ([baseType perform: selector] on: Error do: [#error])]].!

----- Method: ExternalTypeTests>>testBasicTypeForPointerType (in category 'tests - compiled spec') -----
testBasicTypeForPointerType

	| type baseType |
	type := ExternalType int32_t asPointerType.
	baseType := type asBasicType.
	self assert: type isPointerType equals: baseType isPointerType.
	self assert: type byteSize equals: baseType byteSize.
	self assert: type size equals: baseType size.!

----- Method: ExternalTypeTests>>testBasicTypeForStructureType (in category 'tests - compiled spec') -----
testBasicTypeForStructureType

	| type baseType |
	type := ExternalType typeNamed: 'FFITestSdi'.
	baseType := type asBasicType.
	self assert: type isStructureType equals: baseType isStructureType.
	self assert: type byteSize equals: baseType byteSize.
	self assert: type size equals: baseType size.		!

----- Method: ExternalTypeTests>>testCompilationOrder (in category 'tests - compiled spec') -----
testCompilationOrder

	| order target requirements |
	order := ExternalStructure allStructuresInCompilationOrder readStream.
	target := #FFITestCompoundStruct.
	requirements := #( FFISmallStruct1 FFITestPoint2 FFITestPoint4 ).
	requirements, {target} do: [:nextClassName |
		[order peek name ~= nextClassName] whileTrue: [
			self
				assert: order next name ~= target
				description: 'Could not find expected compilation order for ', target;
				deny: order atEnd
				description: 'Compilation units missing!!'].
		order reset].!

----- Method: ExternalTypeTests>>testCompilationOrderParseBasicType (in category 'tests - compiled spec') -----
testCompilationOrderParseBasicType
	"Compilation order is computed by checking the basic types as prerequisites. So, any elaborate typeName must be parsed into its basic form."

	#(
	'int32_t' 'int32_t'
	'int32_t*' 'int32_t'
	'MyStruct' 'MyStruct'
	'MyStruct*' 'MyStruct'

	'int32_t[]' 'int32_t'
	'int32_t[5]' 'int32_t'
	'int32_t*[]' 'int32_t'
	'int32_t*[5]' 'int32_t'

	'(int32_t[])*' 'int32_t'
	'(int32_t[5])*' 'int32_t'	
	'(int32_t*[])*' 'int32_t'
	'(int32_t*[5])*' 'int32_t'

	'MyStructPtr' 'MyStructPtr'
	'MyStructPtr[5]' 'MyStructPtr'
	'(MyStructPtr[5])*' 'MyStructPtr'
	'*MyStructPtr' 'MyStructPtr'	
	'(*MyStructPtr)[5]' 'MyStructPtr'
	'((*MyStructPtr)[5])*' 'MyStructPtr'
	
	) groupsDo: [:typeName :basicTypeName |
		self
			assert: basicTypeName
			equals: (ExternalType parseBasicTypeName: typeName)]!

----- Method: ExternalTypeTests>>testFloatPrecision (in category 'tests - atomic float types') -----
testFloatPrecision

	self
		assert: ExternalType float isSinglePrecision;
		assert: ExternalType double
		equals: ExternalType float asDoublePrecision;
		assert: ExternalType double isDoublePrecision;
		assert: ExternalType float
		equals: ExternalType float asSinglePrecision.!

----- Method: ExternalTypeTests>>testFloatSign (in category 'tests - atomic float types') -----
testFloatSign
	"Float and double types are always signed. Thus, the check is not defined but only for integer types."

	self
		should: [ExternalType float isSigned] raise: Error;
		should: [ExternalType float isUnsigned] raise: Error;
		should: [ExternalType float asSigned] raise: Error;
		should: [ExternalType float asUnsigned] raise: Error;
		should: [ExternalType double isSigned] raise: Error;
		should: [ExternalType double isUnsigned] raise: Error;
		should: [ExternalType double asSigned] raise: Error;
		should: [ExternalType double asUnsigned] raise: Error.!

----- Method: ExternalTypeTests>>testFloatTypeRange (in category 'tests - atomic float types') -----
testFloatTypeRange

	self assert: -3.4028234663852886e38 equals: ExternalType float minVal.
	self assert: 3.4028234663852886e38 equals: ExternalType float maxVal.	 
	self assert: -1.7976931348623157e308 equals: ExternalType double minVal. 
	self assert: 1.7976931348623157e308 equals: ExternalType double maxVal.	 !

----- Method: ExternalTypeTests>>testFloatTypes (in category 'tests - atomic float types') -----
testFloatTypes

	#(
		float 4
		double 8
	) pairsDo: [:typeName :byteSize |
		| type |
		type := ExternalType typeNamed: typeName.
		self
			assert: type isFloatType;
			assert: byteSize equals: type byteSize;
			assert: type companionType notNil;
			assert: type companionType isFloatType].!

----- Method: ExternalTypeTests>>testIntegerNotCharType (in category 'tests - atomic integer types') -----
testIntegerNotCharType

	#( signedChar unsignedChar ) do: [:typeName |
		| type |
		type := ExternalType typeNamed: typeName.
		self deny: type isIntegerType].!

----- Method: ExternalTypeTests>>testIntegerPointerTypes (in category 'tests - atomic integer types') -----
testIntegerPointerTypes

	| wordSize |
	wordSize := FFIPlatformDescription current wordSize.
	
	#(size_t ptrdiff_t uintptr_t intptr_t) do: [:typeName |
		| type |
		type := ExternalType typeNamed: typeName.
		self
			assert: type isIntegerType;
			assert: wordSize equals: type byteSize].!

----- Method: ExternalTypeTests>>testIntegerPrecision (in category 'tests - atomic integer types') -----
testIntegerPrecision
	"Precision is not defined on integer types."
	
	ExternalType atomicTypes do: [:type |
		type isIntegerType ifTrue: [
			self
				should: [type isSinglePrecision]
				raise: Error;
				should: [type isDoublePrecision]
				raise: Error]].!

----- Method: ExternalTypeTests>>testIntegerSign (in category 'tests - atomic integer types') -----
testIntegerSign

	ExternalType atomicTypes do: [:type |
		self
			assert: type isIntegerType ==> [
				(type isSigned and: [type asUnsigned isUnsigned])
					or: [type isUnsigned and: [type asSigned isSigned]]]].!

----- Method: ExternalTypeTests>>testIntegerTypeRange (in category 'tests - atomic integer types') -----
testIntegerTypeRange

	self assert: 0 equals: ExternalType uint8_t "byte" minVal.
	self assert: 255 equals: ExternalType uint8_t "byte" maxVal.	
	self assert: -128 equals: ExternalType int8_t "sbyte" minVal.
	self assert: 127 equals: ExternalType int8_t "sbyte" maxVal.

	self assert: 0 equals: ExternalType uint16_t "ushort" minVal.
	self assert: 65535 equals: ExternalType uint16_t "ushort" maxVal.	
	self assert: -32768 equals: ExternalType int16_t "short" minVal.
	self assert: 32767 equals: ExternalType int16_t "short" maxVal.	

	self assert: 0 equals: ExternalType uint32_t "ulong" minVal.
	self assert: 4294967295 equals: ExternalType uint32_t "ulong" maxVal.	
	self assert: -2147483648 equals: ExternalType int32_t "long" minVal.
	self assert: 2147483647 equals: ExternalType int32_t "long" maxVal.	

	self assert: 0 equals: ExternalType uint64_t "ulonglong" minVal.
	self assert: 18446744073709551615 equals: ExternalType uint64_t "ulonglong" maxVal.	
	self assert: -9223372036854775808 equals: ExternalType int64_t "longlong" minVal.
	self assert: 9223372036854775807 equals: ExternalType int64_t "longlong" maxVal.	
!

----- Method: ExternalTypeTests>>testIntegerTypes (in category 'tests - atomic integer types') -----
testIntegerTypes

	#(
		uint8_t 1 int8_t 1
		uint16_t 2 int16_t 2
		uint32_t 4 int32_t 4
		uint64_t 8 int64_t 8
	) pairsDo: [:typeName :byteSize |
		| type |
		type := ExternalType typeNamed: typeName.
		self
			assert: type isIntegerType;
			assert: byteSize equals: type byteSize;
			assert: type companionType notNil;
			assert: type companionType isIntegerType].!

----- Method: ExternalTypeTests>>testIntegerTypesAsCharTypes (in category 'tests - atomic integer types') -----
testIntegerTypesAsCharTypes

	#( int8_t int16_t int32_t ) do: [:typeName |
		| integerType |
		integerType := ExternalType typeNamed: typeName.
		self
			deny: integerType isCharType;
			assert: integerType asCharType isCharType;
			assert: integerType byteSize equals: integerType asCharType byteSize;
			
			deny: integerType asUnsigned isCharType;
			assert: integerType asUnsigned asCharType isCharType;
			assert: integerType asUnsigned byteSize equals: integerType asUnsigned asCharType byteSize].!

----- Method: ExternalTypeTests>>testPointerByShortcut (in category 'tests - pointer types') -----
testPointerByShortcut

	| pointer |
	pointer := ExternalType void asPointerType.
	self
		assert: pointer
		identical: ExternalType pointer;
		assert: pointer
		identical: (ExternalType typeNamed: 'pointer');
		assert: pointer
		identical: (ExternalType lookupType: pointer);
		assert: pointer
		identical: (ExternalType lookupType: #pointer).!

----- Method: ExternalTypeTests>>testPointerToAlias (in category 'tests - pointer types') -----
testPointerToAlias
	"Test pointer types for type aliases for atomic types or struct types. Do not test pointer types to type aliases for array types."

	self classesForTypeAliases do: [:aliasClass | | type pointerType |
		type := aliasClass externalType.
		pointerType := type asPointerType.

		self
			assert: type isTypeAlias;
			assert: (type isAtomic or: [type isStructureType]);
			deny: type isPointerType;
			deny: type isArrayType.
		
		self
			assert: pointerType isPointerType;
			deny: pointerType isAtomic;
			deny: pointerType isStructureType;
			deny: pointerType isArrayType;
			deny: pointerType isTypeAlias.
		
		self
			"referentClass is retained to instantiate the correct classes for return values (i.e. ExternalStructure or ExternalData)"
			assert: type referentClass
			identical: pointerType referentClass].!

----- Method: ExternalTypeTests>>testPointerToAliasForArray (in category 'tests - pointer types') -----
testPointerToAliasForArray

	| type pointerType |
	type := FFITestAliasForInt32Array externalType.
	pointerType := type asPointerType.

	self
		assert: type isArrayType;
		assert: type isTypeAlias.
			
	self
		assert: pointerType isPointerType;
		deny: pointerType isAtomic;
		deny: pointerType isStructureType;
		deny: pointerType isArrayType;
		deny: pointerType isTypeAlias.
	
	self assert: pointerType referentClass notNil.!

----- Method: ExternalTypeTests>>testPointerToAliasForPointer (in category 'tests - pointer types') -----
testPointerToAliasForPointer
	"Alias-for-pointer types are actual pointer types. Their non-pointer type points to the original non-pointer type. See #testAliasForPointer."
	
	self specsForTypeAliasForPointer groupsDo: [:aliasClass :originalType | | type |
		type := aliasClass externalType.

		self
			assert: type
			identical: type asPointerType].!

----- Method: ExternalTypeTests>>testPointerToArray (in category 'tests - pointer types') -----
testPointerToArray
	"The pointer type of an array type should look like a pointer to its content type except that we omit the referentClass so that we will always get ExternalData from an FFI call. From there, #contentType is very easy to access. Note that MyStruct* and MyStruct[] are different. See #testArrayVsPointer."
	
	| arrayTypes |
	arrayTypes := #(
		char 'char*' int32_t 'int32_t*' double 'double*'
		FFITestSdi 'FFITestSdi*' FFITestUfd 'FFITestUfd*')
			collect: [:typeName | (ExternalType typeNamed: typeName) asArrayType: 5].

	arrayTypes do: [:arrayType | | pointerType |
		pointerType := arrayType asPointerType.
		
		self
			deny: pointerType isAtomic;
			assert: pointerType isPointerType;
			deny: pointerType isStructureType;
			deny: pointerType isArrayType;
			deny: pointerType isTypeAlias;
			
			"Important!! We really want to get ExternalData for such return types. We MUST NOT instantiate the content type because we would loose the array type and thus the size information."
			assert: pointerType referentClass isNil].!

----- Method: ExternalTypeTests>>testPointerToAtomic (in category 'tests - pointer types') -----
testPointerToAtomic

	ExternalType atomicTypes do: [:type | | pointerType |
		pointerType := type asPointerType.
		
		self
			deny: pointerType isAtomic;
			assert: pointerType isPointerType;
			deny: pointerType isStructureType;
			deny: pointerType isArrayType;
			deny: pointerType isTypeAlias;
			
			assert: pointerType referentClass isNil].!

----- Method: ExternalTypeTests>>testPointerToPointer (in category 'tests - pointer types') -----
testPointerToPointer
	"A double pointer could either mean array-of-pointers or address of a pointer to be initialized such as in a domain-specific allocate(void**). Since we do not support by-address invocation in FFI calls yet and we do have array types, such a type is not supported. See ExternalFunction >> #flags."

	self
		assert: nil
		equals: (ExternalType typeNamed: 'char**'). "Use 'char*[]' if possible."

	self
		should: [ExternalType newTypeNamed: 'char**']
		raise: Error.!

----- Method: ExternalTypeTests>>testPointerToPointerVsArrayOfPointers (in category 'tests - pointer types') -----
testPointerToPointerVsArrayOfPointers
	"For visual clarity, the pointer type of an array-of-pointers type will look different from the pointer type of an array-of-atomics/structs. Also see #testPointerToPointer."

	| arrayType |
	arrayType := ExternalType typeNamed: 'int32_t[]'.
	
	self
		assert: '(int32_t[])*'
		equals: arrayType asPointerType typeName.
		
	arrayType := ExternalType typeNamed: 'int32_t*[]'.
	
	self
		assert: '(int32_t*[])*'
		equals: arrayType asPointerType typeName.!

----- Method: ExternalTypeTests>>testPointerToStruct (in category 'tests - pointer types') -----
testPointerToStruct

	self classesForStructures do: [:structClass | | type pointerType |
		type := structClass externalType.
		pointerType := type asPointerType.
		
		self
			deny: pointerType isAtomic;
			assert: pointerType isPointerType;
			deny: pointerType isStructureType;
			deny: pointerType isArrayType;
			deny: pointerType isTypeAlias;
			
			assert: structClass
			identical: pointerType referentClass].!

----- Method: ExternalTypeTests>>testStructType (in category 'tests - struct types') -----
testStructType
	"Check the basic integrity of struct types."

	self classesForStructures do: [:structClass | | type |
		type := structClass externalType.
		self
			deny: type isAtomic;
			deny: type isPointerType;
			assert: type isStructureType;
			deny: type isArrayType;
			deny: type isTypeAlias;
			
			assert: structClass
			identical: type referentClass].!

----- Method: ExternalTypeTests>>testStructTypeByName (in category 'tests - struct types') -----
testStructTypeByName

	self classesForStructures do: [:structClass | | type pointerType |
		type := structClass externalType asNonPointerType.
		pointerType := type asPointerType.
		self
			assert: type
			identical: (ExternalType typeNamed: type typeName);
			assert: pointerType
			identical: (ExternalType typeNamed: pointerType typeName)]!

----- Method: ExternalTypeTests>>testStructTypeBySpec (in category 'tests - struct types') -----
testStructTypeBySpec

	self classesForStructures do: [:structClass | | type |
		type := structClass externalType.
		self
			assert: type
			identical: (ExternalType lookupType: structClass)]!

----- Method: ExternalTypeTests>>testUnknownReferentClass (in category 'tests - unkown types') -----
testUnknownReferentClass

	| type |
	Smalltalk garbageCollect.
	ExternalType cleanupUnusedTypes.
	type := ExternalType typeNamed: 'UnknownStructForTest'.
	self assert: type isNil.
	type := ExternalType newTypeNamed: 'UnknownStructForTest'.
	self assert: type isUnknownType.
	self
		should: [ExternalType newTypeNamed: 'UnknownStructForTest']
		raise: Error. "Already existing"
!

TestCase subclass: #FFIAllocateTests
	instanceVariableNames: 'externalObjects'
	classVariableNames: ''
	poolDictionaries: 'FFIConstants'
	category: 'FFI-Tests'!

!FFIAllocateTests commentStamp: 'mt 5/10/2021 10:18' prior: 0!
A collection of tests around the allocation of structs, unions, and arrays of atomics/structs/unions. Includes tests about accessing (field read/write) those after allocation.!

FFIAllocateTests subclass: #FFIAllocateExternalTests
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests'!

----- Method: FFIAllocateExternalTests class>>shouldInheritSelectors (in category 'testing') -----
shouldInheritSelectors

	^ true!

----- Method: FFIAllocateExternalTests>>allocate: (in category 'running') -----
allocate: spec

	| result |
	result := externalObjects add: (self lookupType: spec) allocateExternal.
	self checkAllocate: result.
	^ result!

----- Method: FFIAllocateExternalTests>>allocate:size: (in category 'running') -----
allocate: spec size: size

	| result |
	result := externalObjects add: ((self lookupType: spec) allocateExternal: size).
	self checkAllocate: result.
	^ result!

----- Method: FFIAllocateExternalTests>>checkAllocate: (in category 'running') -----
checkAllocate: externalObject

	| type handle |
	self assert: externalObject notNil.

	type := externalObject externalType.
	handle := externalObject getHandle.
	
	self deny: externalObject isNull.
	self deny: handle isNull.
	self deny: handle isNil.
	
	self assert: type isPointerType.
	self assert: handle isExternalAddress.!

----- Method: FFIAllocateExternalTests>>checkFree: (in category 'running') -----
checkFree: externalObject

	| type handle |
	type := externalObject externalType.
	handle := externalObject getHandle.

	self assert: externalObject isNull.
	
	(type isTypeAlias and: [type isAtomic]) ifTrue: [
		self assert: handle isNil.
		^ self].
	
	self assert: type isPointerType.	
	self assert: handle isExternalAddress.
	self assert: handle isNull.!

----- Method: FFIAllocateExternalTests>>checkType: (in category 'running') -----
checkType: externalObject

	self assert: externalObject externalType isPointerType.!

----- Method: FFIAllocateExternalTests>>expectedFailures (in category 'failures') -----
expectedFailures

	^ super expectedFailures
	
	copyWithoutAll: #(
		test04LinkedList "Storing pointers works fine."
	)!

----- Method: FFIAllocateExternalTests>>test00ReaderWriter (in category 'tests') -----
test00ReaderWriter
	"Overwritten to show that #reader and #writer is virtually a #yourself on external objects that point to external memory."

	| si2 |
	si2 := self allocate: FFITestSi2.
	
	self assert: si2 == si2 reader.
	self assert: si2 == si2 writer.
	self assert: si2 reader == si2.
	self assert: si2 writer == si2.!

----- Method: FFIAllocateExternalTests>>test01ArrayFromTo (in category 'tests - array') -----
test01ArrayFromTo
	"Overwritten because missing #writer as no effect. See #test00ReaderWriter."
	
	| points portion |
	points := FFITestPoint2 allocateExternal: 5.
	
	portion := points from: 2 to: 3.
	
	portion withIndexDo: [:point :index | point setX: index+1 setY: index+1].
	self
		assert: { 0 at 0 . 2 at 2 . 3 at 3 . 0 at 0 . 0 at 0 }
		equals: (points collect: [:each | each asPoint]).!

----- Method: FFIAllocateExternalTests>>test02ArrayCopyFromTo (in category 'tests - array') -----
test02ArrayCopyFromTo
	"Overwritten to emphasize that the copy is in internal memory. Implementation is the same, see #allocate:size:."

	super test02ArrayCopyFromTo.!

----- Method: FFIAllocateExternalTests>>test02StructureCompositeAccess (in category 'tests - structure') -----
test02StructureCompositeAccess
	"Overwritten because #writer is not necessary for external memory."
	
	| composite |
	composite := self allocate: FFITestSsSsf.
	
	self assert: 0 equals: composite s1.
	self assert: 0 equals: composite ssf2 s1.
	self assert: 0.0 equals: composite ssf2 f2.
	
	composite s1: 1.
	self assert: 1 equals: composite s1.
	
	composite ssf2 s1: 2.
	self assert: 2 equals: composite ssf2 s1.
	
	composite ssf2 f2: 3.0.
	self assert: 3.0 equals: composite ssf2 f2.!

----- Method: FFIAllocateExternalTests>>test04UnionCompositeAccess (in category 'tests - union') -----
test04UnionCompositeAccess
	"Overwritten because #writer is not necessary."
	
	| composite |
	composite := self allocate: FFITestUdSi2.
	
	self assert: 0.0 equals: composite d1.
	self assert: 0 equals: composite sii1 i1.
	self assert: 0 equals: composite sii1 i2.
	
	composite d1: 1.0.
	self assert: 1.0 equals: composite d1.
	composite d1: 0.0. "Clear to clear shared sub-structure."
	
	composite sii1 i1: 2.
	self assert: 2 equals: composite sii1 i1.
	
	composite sii1 i2: 3.
	self assert: 3 equals: composite sii1 i2.!

----- Method: FFIAllocateExternalTests>>test05UnionCompositeAccessTwo (in category 'tests - union') -----
test05UnionCompositeAccessTwo
	"Overwritten because #writer is not necessary for external memory."
	
	| composite |
	composite := self allocate: FFITestSUfdUdSi2.

	self assert: 0.0 equals: composite ufd1 f1.
	composite ufd1 f1: 3.5.
	self assert: 3.5 equals: composite ufd1 f1.

	self assert: 0 equals: composite udSii2 sii1 i1.
	composite udSii2 sii1 i1: 42.
	self assert: 42 equals: composite udSii2 sii1 i1.!

----- Method: FFIAllocateExternalTests>>test06ArrayOfPointers (in category 'tests - array') -----
test06ArrayOfPointers
	"Overwritten because in external memory, we can manage pointer indirections. Be sure to not log the inner allocation because the array's #free will recursively free the memory."

	| array type string|
	type := self lookupType: 'char*'.
	array := self allocate: type size: 5.
	self assert: 5 * type byteSize equals: array byteSize.
		
	string := array contentType asNonPointerType allocateExternal: 7.
	string setSize: nil. "Not needed due to null-termination."
	
	string at: 1 put: $S.
	string at: 2 put: $Q.
	string at: 3 put: $U.
	string at: 4 put: $E.
	string at: 5 put: $A.				
	string at: 6 put: $K.
	string at: 7 put: Character null. "Not needed here because memory was zero from the beginning."
	self assert: 'SQUEAK' equals: string fromCString.

	array at: 1 put: string.
	self assert: 'SQUEAK' equals: array first fromCString.!

----- Method: FFIAllocateExternalTests>>test10ArrayClasses (in category 'tests - array') -----
test10ArrayClasses
	"Array classes do not apply to external allocation."!

----- Method: FFIAllocateExternalTests>>test17ArrayFromUnkownSize (in category 'tests - array') -----
test17ArrayFromUnkownSize
	"Overwritten because there is no out-of-bounds check for external memory."
	
	| array portion |
	array := self allocate: 'int32_t' size: 5.
	1 to: array size do: [:index | array at: index put: index].

	array setSize: nil. "Possible but limited for byte-array handles."
	portion := array reader from: 3.
	self assert: 3 equals: (portion at: 1).
	self assert: 4 equals: (portion at: 2).!

----- Method: FFIAllocateExternalTests>>test21ArrayAssureLocal (in category 'tests - array') -----
test21ArrayAssureLocal
	"Copy the array into local (object) memory."

	| original copy |
	original := self allocate: ExternalType int32_t size: 5.
	copy := original assureLocal.
	self deny: original == copy.
	self assert: copy assureLocal identical: copy.!

----- Method: FFIAllocateTests>>allocate: (in category 'running') -----
allocate: spec

	| result |
	result := externalObjects add: (self lookupType: spec) allocate.
	self checkAllocate: result.
	^ result!

----- Method: FFIAllocateTests>>allocate:size: (in category 'running') -----
allocate: spec size: size

	| result |
	result := externalObjects add: ((self lookupType: spec) allocate: size).
	self checkAllocate: result.
	^ result!

----- Method: FFIAllocateTests>>checkAllocate: (in category 'running') -----
checkAllocate: externalObject

	| type handle |
	self assert: externalObject notNil.

	type := externalObject externalType.
	handle := externalObject getHandle.
	
	self deny: externalObject isNull.
	self deny: handle isNull.
	self deny: handle isNil.
	
	self deny: type isPointerType.
	self deny: handle isExternalAddress.!

----- Method: FFIAllocateTests>>checkFree: (in category 'running') -----
checkFree: externalObject

	| type handle |
	type := externalObject externalType.
	handle := externalObject getHandle.

	self assert: externalObject isNull.
	
	(type isTypeAlias and: [type isAtomic]) ifTrue: [
		self assert: handle isNil.
		^ self].

	(type isTypeAlias and: [type isPointerType]) ifTrue: [
		self assert: handle isExternalAddress.
		self assert: handle isNull.
		^ self].

	self assert: handle isNil.!

----- Method: FFIAllocateTests>>checkType: (in category 'running') -----
checkType: externalObject

	self assert: externalObject externalType isPointerType not.!

----- Method: FFIAllocateTests>>expectedFailures (in category 'failures') -----
expectedFailures

	^ #(
	test04LinkedList "We don't have pointers to internal memory, yet."
	)!

----- Method: FFIAllocateTests>>lookupType: (in category 'running') -----
lookupType: structClassOrTypeNameOrType

	^ ExternalType lookupType: structClassOrTypeNameOrType!

----- Method: FFIAllocateTests>>performTest (in category 'running') -----
performTest
	"Tests should opt-in to have more control."
	
	| prior1 prior2 |
	prior1 := ExternalType useArrayClasses.
	prior2 := ExternalData extraSizeChecks.
	[ExternalType useArrayClasses: false.
	ExternalData extraSizeChecks: true.
	super performTest]
		ensure: [
			ExternalType useArrayClasses: prior1.
			ExternalData extraSizeChecks: prior2].!

----- Method: FFIAllocateTests>>setUp (in category 'running') -----
setUp

	super setUp.
	externalObjects := OrderedCollection new.!

----- Method: FFIAllocateTests>>tearDown (in category 'running') -----
tearDown

	externalObjects do: [:externalObject |
		externalObjects isExternalObject "i.e. not a RawBitsArray"
			ifTrue: [
				externalObject free.
				self checkFree: externalObject]].
	super tearDown.!

----- Method: FFIAllocateTests>>test00ReaderWriter (in category 'tests') -----
test00ReaderWriter

	| si2 |
	si2 := self allocate: FFITestSi2.
	
	self deny: si2 == si2 reader.
	self deny: si2 reader == si2 reader.
	
	self assert: (si2 ffiEqual: si2 reader).
	self assert: (si2 reader ffiEqual: si2).

	self deny: si2 == si2 writer.
	self deny: si2 writer == si2 writer.
	
	self assert: (si2 ffiEqual: si2 writer).
	self assert: (si2 writer ffiEqual: si2).
!

----- Method: FFIAllocateTests>>test01AliasForAtomicAccess (in category 'tests - type alias') -----
test01AliasForAtomicAccess

	| char |
	char := self allocate: FFITestAliasForChar.
	self assert: Character null equals: char value.
	char value: $A.	
	self assert: $A equals: char value.!

----- Method: FFIAllocateTests>>test01ArrayFromTo (in category 'tests - array') -----
test01ArrayFromTo
	"Access a sub-range in the external data. Internal memory will be copied if not accessed through a read-writer."
	
	| points portion |
	points := self allocate: FFITestPoint2 size: 5.
	portion := points from: 2 to: 3.
	
	portion withIndexDo: [:point :index | point setX: index+1 setY: index+1].
	self "Forgot to use a read-writer..."
		assert: { 0 at 0 . 0 at 0 . 0 at 0 . 0 at 0 . 0 at 0 }
		equals: (points collect: [:each | each asPoint]).

	portion withIndexDo: [:point :index | point setX: index+1 setY: index+1].
	self "Forgot to use a read-writer early enough..."
		assert: { 0 at 0 . 0 at 0 . 0 at 0 . 0 at 0 . 0 at 0 }
		equals: (points collect: [:each | each asPoint]).

	portion := points writer from: 2 to: 3.
	portion withIndexDo: [:point :index | point setX: index+1 setY: index+1].
	self
		assert: { 0 at 0 . 2 at 2 . 3 at 3 . 0 at 0 . 0 at 0 }
		equals: (points collect: [:each | each asPoint]).
	
	points zeroMemory.
	portion := points reader from: 2 to: 3.
	portion writer withIndexDo: [:point :index | point setX: index+1 setY: index+1].
	self "Both #reader and #writer used. No worries."
		assert: { 0 at 0 . 2 at 2 . 3 at 3 . 0 at 0 . 0 at 0 }
		equals: (points collect: [:each | each asPoint]).!

----- Method: FFIAllocateTests>>test01AtomicsAllocated (in category 'tests - atomics') -----
test01AtomicsAllocated
	
	self should: [(self allocate: ExternalType void)] raise: Error.
	self assert: false equals: (self allocate: ExternalType bool) value.

	self assert: 0 equals: (self allocate: ExternalType int8_t "sbyte") value.
	self assert: 0 equals: (self allocate: ExternalType uint8_t "byte") value.

	self assert: 0 equals: (self allocate: ExternalType uint16_t "ushort") value.
	self assert: 0 equals: (self allocate: ExternalType int16_t "short") value.

	self assert: 0 equals: (self allocate: ExternalType uint32_t "ulong") value.
	self assert: 0 equals: (self allocate: ExternalType int32_t "long") value.

	self assert: 0 equals: (self allocate: ExternalType uint64_t "ulonglong") value.
	self assert: 0 equals: (self allocate: ExternalType int64_t "longlong") value.

	self assert: Character null equals: (self allocate: ExternalType schar) value.
	self assert: Character null equals: (self allocate: ExternalType char) value.

	self assert: 0.0 equals: (self allocate: ExternalType float) value.
	self assert: 0.0 equals: (self allocate: ExternalType double) value.!

----- Method: FFIAllocateTests>>test01ByHandleInt32Access (in category 'tests - array by handle') -----
test01ByHandleInt32Access

	| type handle |
	type := ExternalType int32_t.
	handle := (self allocate: type size: 5) getHandle.
	self assert: 0 equals: (type handle: handle atIndex: 2).
	type handle: handle atIndex: 2 put: 42.
	type handle: handle atIndex: 1 put: 0.	
	self assert: 42 equals: (type handle: handle atIndex: 2).!

----- Method: FFIAllocateTests>>test01Identity (in category 'tests') -----
test01Identity

	| a b c |
	a := self allocate: FFITestPoint2.
	b := self allocate: FFITestPoint2.
	c := FFITestPoint2 fromHandle: a getHandle.
	
	self assert: (a ffiIdentical: a).
	self deny: (a ffiIdentical: b).
	self assert: (a ffiIdentical: c). "!!!! unlike #=="
	
	self assert: a == a.
	self deny: a == b.
	self deny: a == c. "!!!! unlike #ffiIdentical:"	

!

----- Method: FFIAllocateTests>>test01StructureAccess (in category 'tests - structure') -----
test01StructureAccess

	| sfi |
	sfi := self allocate: FFITestSfi.
	
	"1) Test initial values."
	self assert: 0.0 equals: sfi f1.
	self assert: 0 equals: sfi i2.
	
	"2) Test basic read/write of fields"
	sfi i2: 2.
	self assert: 2 equals: sfi i2.
	self assert: 0.0 equals: sfi f1. "not touched"
	sfi f1: 2.0.
	self assert: 2.0 equals: sfi f1.
	self assert: 2 equals: sfi i2. "not touched"!

----- Method: FFIAllocateTests>>test01UnionAccess (in category 'tests - union') -----
test01UnionAccess

	| ufi |
	ufi := self allocate: FFITestUfi.
	
	"1) Test initial values."
	self assert: 0.0 equals: ufi f1.
	self assert: 0 equals: ufi i1.
	
	"2) Test basic read/write of fields"
	ufi i1: 2.
	self assert: 2 equals: ufi i1.
	self deny: 0.0 equals: ufi f1. "overwritten"
	ufi f1: 2.0.
	self assert: 2.0 equals: ufi f1.
	self deny: 2 equals: ufi i1. "overwritten"!

----- Method: FFIAllocateTests>>test02AliasForAtomicZeroMemory (in category 'tests - type alias') -----
test02AliasForAtomicZeroMemory

	| char |
	char := self allocate: FFITestAliasForChar.
	char value: $A.	
	char zeroMemory.
	self assert: Character null equals: char value.!

----- Method: FFIAllocateTests>>test02ArrayCopyFromTo (in category 'tests - array') -----
test02ArrayCopyFromTo
	"Copy a portion of an array into a new array."

	| points copy |
	points := self allocate: FFITestPoint2 size: 5.
	
	copy := points copyFrom: 2 to: 3.
	self deny: copy getHandle isExternalAddress.
	
	"We need a writer to modify internal memory."
	copy withIndexDo: [:point :index | point setX: index+1 setY: index+1].
	self deny: { 2 at 2 . 3 at 3 } equals: (copy collect: [:each | each asPoint]).
	copy writer withIndexDo: [:point :index | point setX: index+1 setY: index+1].
	self assert: { 2 at 2 . 3 at 3 } equals: (copy collect: [:each | each asPoint]).

	"Check that we did not touch the original."
	self
		assert: { 0 at 0 . 0 at 0 . 0 at 0 . 0 at 0 . 0 at 0 }
		equals: (points collect: [:each | each asPoint]).!

----- Method: FFIAllocateTests>>test02AtomicsReinterpreted (in category 'tests - atomics') -----
test02AtomicsReinterpreted
	
	#(
	int8_t int16_t minVal 
	int8_t int16_t maxVal 
	int16_t int32_t minVal 
	int16_t int32_t maxVal 
	int32_t int64_t minVal 
	int32_t int64_t maxVal 	
	) groupsDo: [:smallIntegerTypeName :bigIntegerTypeName :valueSelector |
		| smallIntegerType bigIntegerType value data |
		smallIntegerType := ExternalType typeNamed: smallIntegerTypeName.
		bigIntegerType := ExternalType typeNamed: bigIntegerTypeName.
		value := smallIntegerType perform: valueSelector.
		data := self allocate: bigIntegerType.
		data value: value.
		data setContentType: smallIntegerType.
		self assert: value equals: data value]!

----- Method: FFIAllocateTests>>test02ByHandleFloatAccess (in category 'tests - array by handle') -----
test02ByHandleFloatAccess

	| type handle |
	type := ExternalType float.
	handle := (self allocate: type size: 5) getHandle.
	self assert: 0.0 equals: (type handle: handle atIndex: 2).
	type handle: handle atIndex: 2 put: 1.23.
	type handle: handle atIndex: 1 put: 0.0.
	self assert: ((type handle: handle atIndex: 2)
		between: 1.23 - 0.0005 and: 1.23 + 0.0005).!

----- Method: FFIAllocateTests>>test02Equality (in category 'tests') -----
test02Equality

	| a b c |
	a := self allocate: FFITestPoint2.
	b := self allocate: FFITestPoint2.
	c := FFITestPoint2 fromHandle: a getHandle.
	
	self assert: (a ffiEqual: a).
	self assert: (a ffiEqual: b).
	self assert: (a ffiEqual: c).
	
	self assert: a = a.
	self deny: a = b.
	self assert: a = c. "bc. #ffiIdentical: by default"
!

----- Method: FFIAllocateTests>>test02StructureCompositeAccess (in category 'tests - structure') -----
test02StructureCompositeAccess
	"Tests the access to composite structures. Uses #writer to avoid copy-on-access for sub-structs."
	
	| composite |
	composite := self allocate: FFITestSsSsf.
	
	self assert: 0 equals: composite s1.
	self assert: 0 equals: composite ssf2 s1.
	self assert: 0.0 equals: composite ssf2 f2.
	
	composite s1: 1.
	self assert: 1 equals: composite s1.
	
	composite ssf2 s1: 2.
	self assert: 0 equals: composite ssf2 s1.
	composite writer ssf2 s1: 2.
	self assert: 2 equals: composite ssf2 s1.
	
	composite ssf2 f2: 3.0.
	self assert: 0.0 equals: composite ssf2 f2.
	composite writer ssf2 f2: 3.0.
	self assert: 3.0 equals: composite ssf2 f2.!

----- Method: FFIAllocateTests>>test02Union_IEEE32BitWord (in category 'tests - union') -----
test02Union_IEEE32BitWord
	"Test union-specific field overlay, directly and indirectly."

	| ufi |
	ufi := self allocate: FFITestUfi.
	
	ufi f1: 3.0. "Direct write"
	self assert: 3.0 asIEEE32BitWord equals: ufi i1.
	self assert: 3.0 equals: (Float fromIEEE32Bit: ufi i1).
	
	ufi i1: 4.0 asIEEE32BitWord.
	self assert: 4.0 equals: (Float fromIEEE32Bit: ufi i1).
	self assert: 4.0 equals: ufi f1. "Direct read"!

----- Method: FFIAllocateTests>>test03AliasForStructureAccess (in category 'tests - type alias') -----
test03AliasForStructureAccess

	| sdi |
	sdi := self allocate: FFITestAliasForSdi.
	
	self assert: 0.0 equals: sdi d1.
	self assert: 0 equals: sdi i2.

	sdi d1: 1.0.
	sdi i2: 2.
		
	self assert: 1.0 equals: sdi d1.
	self assert: 2 equals: sdi i2.!

----- Method: FFIAllocateTests>>test03ArrayAccess (in category 'tests - array') -----
test03ArrayAccess

	| somePoints firstPoint |
	somePoints := self allocate: FFITestPoint2 size: 5.
	self assert: 5 equals: somePoints size.
	firstPoint := somePoints at: 1.
	self assert: 0 at 0 equals: firstPoint asPoint.
	firstPoint setX: 2 setY: 3.
	self assert: 2 at 3 equals: firstPoint asPoint.!

----- Method: FFIAllocateTests>>test03ByHandleDoubleAccess (in category 'tests - array by handle') -----
test03ByHandleDoubleAccess

	| type handle |
	type := ExternalType double.
	handle := (self allocate: type size: 5) getHandle.
	self assert: 0.0 equals: (type handle: handle atIndex: 2).
	type handle: handle atIndex: 2 put: 1.23456.
	type handle: handle atIndex: 1 put: 0.0.
	self assert: 1.23456 equals: (type handle: handle atIndex: 2).!

----- Method: FFIAllocateTests>>test03GlobalVariable (in category 'tests') -----
test03GlobalVariable
	"If you happen to have to address to a global variable you can use a type alias or just external data for it. See ExternalObject class >> #fromHandle:."

	| global alias |
	global := self allocate: FFITestAliasForInt32.
	self deny: global isFFIArray.
	self assert: 0 equals: global value.
	
	alias := global class fromHandle: global getHandle.
	self assert: 0 equals: alias value.
	
	alias value: 42.
	self assert: 42 equals: alias value.
	self assert: 42 equals: global value.!

----- Method: FFIAllocateTests>>test03StructureCopy (in category 'tests - structure') -----
test03StructureCopy

	| original copy |
	original := self allocate: FFITestPoint2.
	original setX: 1 setY: 2.
		
	copy := original copy.
	self assert: (original ffiEqual: copy).
	self deny: (original ffiIdentical: copy).
	
	copy setX: 3 setY: 4.
	self assert: 1 at 2 equals: original asPoint.
	self assert: 3 at 4 equals: copy asPoint.!

----- Method: FFIAllocateTests>>test03Union_IEEE64BitWord (in category 'tests - union') -----
test03Union_IEEE64BitWord
	"Test union-specific field overlay, directly and indirectly."

	| udi |
	udi := self allocate: FFITestUdi.
	
	udi d1: 3.0. "Direct write"
	self assert: 3.0 asIEEE64BitWord equals: udi i1.
	self assert: 3.0 equals: (Float fromIEEE64Bit: udi i1).
	
	udi i1: 4.0 asIEEE64BitWord.
	self assert: 4.0 equals: (Float fromIEEE64Bit: udi i1).
	self assert: 4.0 equals: udi d1. "Direct read"!

----- Method: FFIAllocateTests>>test04AliasForUnionAccess (in category 'tests - type alias') -----
test04AliasForUnionAccess

	| ufi |
	ufi := self allocate: FFITestAliasForUfi.
	
	self assert: 0.0 equals: ufi f1.
	self assert: 0 equals: ufi i1.

	ufi i1: 2.
	self assert: 2 equals: ufi i1.
	self deny: 0.0 equals: ufi f1. "overwritten"
	ufi f1: 2.0.
	self assert: 2.0 equals: ufi f1.
	self deny: 2 equals: ufi i1. "overwritten"!

----- Method: FFIAllocateTests>>test04ArrayCompositeAccess (in category 'tests - array') -----
test04ArrayCompositeAccess

	| data |
	data := FFITestSdA5i allocate.
	self assert: 0 equals: data a5i2 first.
	data writer a5i2 at: 1 put: 42.
	self assert: 42 equals: data a5i2 first.!

----- Method: FFIAllocateTests>>test04ByHandleCharAccess (in category 'tests - array by handle') -----
test04ByHandleCharAccess

	| type handle |
	type := ExternalType char.
	handle := (self allocate: type size: 5) getHandle.
	self assert: Character null equals: (type handle: handle atIndex: 2).
	type handle: handle atIndex: 2 put: $A.
	type handle: handle atIndex: 1 put: Character null.	
	self assert: $A equals: (type handle: handle atIndex: 2).!

----- Method: FFIAllocateTests>>test04GlobalVariableInArray (in category 'tests') -----
test04GlobalVariableInArray
	"If you happen to have to address to a global variable you can use a type alias or just external data for it. See ExternalObject class >> #fromHandle:."

	| global alias |
	global := self allocate: ExternalType int32_t.
	self assert: global isFFIArray.
	self assert: 0 equals: global value.

	alias := global class fromHandle: global getHandle.
	alias setContentType: global contentType.
	self assert: 0 equals: alias value.
	
	alias value: 42.
	self assert: 42 equals: alias value.
	self assert: 42 equals: global value.!

----- Method: FFIAllocateTests>>test04LinkedList (in category 'tests - structure') -----
test04LinkedList

	| link1 link2 link3 |
	link1 := self allocate: FFITestLink.
	link2 := self allocate: FFITestLink.
	link3 := self allocate: FFITestLink.
	
	link1 next: link2. link2 prev: link1.
	link2 next: link3. link3 prev: link2.
	link3 next: link1. link1 prev: link3.
	
	self assert: link1 next = link2.
	self assert: link2 next = link3.
	self assert: link3 next = link1.

	self assert: link3 prev = link2.
	self assert: link2 prev = link1.
	self assert: link1 prev = link3.	!

----- Method: FFIAllocateTests>>test04UnionCompositeAccess (in category 'tests - union') -----
test04UnionCompositeAccess
	"Tests the access to composite union. Uses #writer to avoid copy-on-access for sub-structs."
	
	| composite |
	composite := self allocate: FFITestUdSi2.
	
	self assert: 0.0 equals: composite d1.
	self assert: 0 equals: composite sii1 i1.
	self assert: 0 equals: composite sii1 i2.
	
	composite d1: 1.0.
	self assert: 1.0 equals: composite d1.
	composite d1: 0.0. "Clear to clear shared sub-structure."
	
	composite sii1 i1: 2.
	self assert: 0 equals: composite sii1 i1.
	composite writer sii1 i1: 2.
	self assert: 2 equals: composite sii1 i1.
	
	composite sii1 i2: 3.
	self assert: 0 equals: composite sii1 i2.
	composite writer sii1 i2: 3.
	self assert: 3 equals: composite sii1 i2.!

----- Method: FFIAllocateTests>>test05AliasForPointerToStructureAccess (in category 'tests - type alias') -----
test05AliasForPointerToStructureAccess

	| sdi |
	sdi := self allocate: FFITestAliasForSdiPointer.
	
	self assert: 0.0 equals: sdi d1.
	self assert: 0 equals: sdi i2.

	sdi d1: 1.0.
	sdi i2: 2.
		
	self assert: 1.0 equals: sdi d1.
	self assert: 2 equals: sdi i2.!

----- Method: FFIAllocateTests>>test05ArrayReadWriteCString (in category 'tests - array') -----
test05ArrayReadWriteCString

	| array string |
	string := 'Hello Squeak!!'.
	self assert: string isByteString.	

	ExternalData allowDetectForUnknownSizeDuring: [
		array := self allocate: ExternalType byte size: 0.
		self should: [array toCString: string] raise: Error. "Wrong type"
		array := self allocate: ExternalType char size: string size.
		self should: [array toCString: string] raise: Error. "Wrong size"
		
		array := self allocate: ExternalType char size: string size + 1.	
		array toCString: string.
		self assert: array size isNil. "It's NUL-terminated now."
		self assert: string equals: array fromCString.		
		
		array := self allocate: ExternalType string size: string size + 1.	
		self should: [array toCString: string] raise: Error. "Use 'char' for allocation."].!

----- Method: FFIAllocateTests>>test05ByHandleBoolAccess (in category 'tests - array by handle') -----
test05ByHandleBoolAccess

	| type handle |
	type := ExternalType bool.
	handle := (self allocate: type size: 5) getHandle.
	self assert: false equals: (type handle: handle atIndex: 2).
	type handle: handle atIndex: 2 put: true.
	type handle: handle atIndex: 1 put: false.	
	self assert: true equals: (type handle: handle atIndex: 2).!

----- Method: FFIAllocateTests>>test05StructureZeroMemory (in category 'tests - structure') -----
test05StructureZeroMemory

	| sfi |
	sfi := self allocate: FFITestSfi.	
	sfi i2: 2.
	sfi f1: 2.0.
	
	sfi zeroMemory.
	self assert: 0.0 equals: sfi f1.
	self assert: 0 equals: sfi i2.!

----- Method: FFIAllocateTests>>test05UnionCompositeAccessTwo (in category 'tests - union') -----
test05UnionCompositeAccessTwo
	
	| composite |
	composite := self allocate: FFITestSUfdUdSi2.

	self assert: 0.0 equals: composite ufd1 f1.
	composite ufd1 f1: 3.5.
	self deny: 3.5 equals: composite ufd1 f1.
	composite writer ufd1 f1: 3.5.
	self assert: 3.5 equals: composite ufd1 f1.

	self assert: 0 equals: composite udSii2 sii1 i1.
	composite udSii2 sii1 i1: 42.
	self deny: 42 equals: composite udSii2 sii1 i1.
	composite writer udSii2 sii1 i1: 42.
	self assert: 42 equals: composite udSii2 sii1 i1.!

----- Method: FFIAllocateTests>>test05ZeroMemory (in category 'tests') -----
test05ZeroMemory

	1 to: 32 do: [:numBytes |
		| array |
		array := self allocate: ExternalType byte size: numBytes.
		array atAllPut: 1.
		self deny: (array allSatisfy: [:byte | byte = 0]).
		array zeroMemory.
		self assert: (array allSatisfy: [:byte | byte = 0])].!

----- Method: FFIAllocateTests>>test06AliasForArrayAccess (in category 'tests - type alias') -----
test06AliasForArrayAccess

	| array |
	array := self allocate: FFITestAliasForInt32Array.
	self assert: FFITestAliasForInt32Array identical: array class.
	
	self assert: 0 equals: (array at: 5).
	array at: 5 put: 42.
	self assert: 42 equals: (array at: 5).!

----- Method: FFIAllocateTests>>test06ArrayOfPointers (in category 'tests - array') -----
test06ArrayOfPointers
	"In internal memory, byte-array pointers do not count. We cannot really do anything here with an array of null-pointers."
	
	| array type |
	type := self lookupType: 'char*'.
	array := self allocate: type size: 6.
	self assert: 0 equals: array byteSize.

	self deny: array isNull.
	array do: [:each |
		self assert: each isNull.
		self assert: 0 equals: each byteSize].!

----- Method: FFIAllocateTests>>test06ByArrayHandleInt32Access (in category 'tests - array by handle') -----
test06ByArrayHandleInt32Access

	| type handle |
	type := ExternalType int32_t.
	ExternalType useArrayClassesDuring: [
		handle := (self allocate: type size: 5) getHandle].
	self assert: 0 equals: (type handle: handle atIndex: 2).
	type handle: handle atIndex: 2 put: 42.
	type handle: handle atIndex: 1 put: 0.	
	self assert: 42 equals: (type handle: handle atIndex: 2).!

----- Method: FFIAllocateTests>>test06MemoryAtPut (in category 'tests') -----
test06MemoryAtPut

	1 to: 32 do: [:numBytes |
		| source target |
		source := self allocate: ExternalType byte size: numBytes.
		source atAllPut: 1.
		target := self allocate: source contentType size: source size.
		self assert: (target allSatisfy: [:byte | byte = 0]).
		target getHandle
			memoryAt: 1
			put: source getHandle
			length: source byteSize.
		self assert: (target allSatisfy: [:byte | byte = 1])].!

----- Method: FFIAllocateTests>>test06StructureAsArray (in category 'tests - structure') -----
test06StructureAsArray

	| sfi array element |
	sfi := self allocate: FFITestSfi.
	sfi f1: 2.5.		
	sfi i2: 10.

	array := ExternalData with: sfi reader.
	element := array first.

	self assert: (sfi ffiIdentical: element).
	self assert: (sfi ffiEqual: element).

	self assert: 2.5 equals: element f1.
	self assert: 10 equals: element i2.!

----- Method: FFIAllocateTests>>test06UnionCopy (in category 'tests - union') -----
test06UnionCopy

	| original copy |
	original := self allocate: FFITestUdi.
	original d1: 1.0.
		
	copy := original copy.
	self assert: (original ffiEqual: copy).
	self deny: (original ffiIdentical: copy).
	
	copy i1: 2.
	self assert: 1.0 equals: original d1.
	self assert: 2 equals: copy i1.!

----- Method: FFIAllocateTests>>test07ArraySetSize (in category 'tests - array') -----
test07ArraySetSize

	| data |
	data := self allocate: ExternalType byte size: 10.
	
	data setSize: 2. "limit access"
	self assert: ExternalType byte identical: data contentType.
	self assert: 2 equals: data size.
	self shouldnt: [data at: 2] raise: Error.
	self should: [data at: 3] raise: Error.
	
	data setSize: 5. "move limit"
	self assert: ExternalType byte identical: data contentType.
	self assert: 5 equals: data size.
	self shouldnt: [data at: 5] raise: Error.
	self should: [data at: 6] raise: Error.

	data setSize: nil. "ignore size"
	self assert: ExternalType byte identical: data contentType.
	self shouldnt: [data at: 3] raise: Error.
	self shouldnt: [data at: 6] raise: Error.
	self shouldnt: [data at: 10] raise: Error.!

----- Method: FFIAllocateTests>>test07ByArrayHandleFloatAccess (in category 'tests - array by handle') -----
test07ByArrayHandleFloatAccess

	| type handle |
	type := ExternalType float.
	ExternalType useArrayClassesDuring: [
		handle := (self allocate: type size: 5) getHandle].
	self assert: 0.0 equals: (type handle: handle atIndex: 2).
	type handle: handle atIndex: 2 put: 1.23.
	type handle: handle atIndex: 1 put: 0.0.
	self assert: ((type handle: handle atIndex: 2)
		between: 1.23 - 0.0005 and: 1.23 + 0.0005).!

----- Method: FFIAllocateTests>>test07UnionZeroMemory (in category 'tests - union') -----
test07UnionZeroMemory

	| ufi |
	ufi := self allocate: FFITestUfi.
	ufi f1: 2.0.
	ufi i1: 2.

	ufi zeroMemory.
	self assert: 0.0 equals: ufi f1.
	self assert: 0 equals: ufi i1.!

----- Method: FFIAllocateTests>>test08ArraySetContentType (in category 'tests - array') -----
test08ArraySetContentType

	| data |
	data := self allocate: ExternalType byte size: 1.
	data at: 1 put: 65.
	
	self assert: 65 equals: data first.
	data setContentType: ExternalType char.
	self assert: $A equals: data first.!

----- Method: FFIAllocateTests>>test08ByArrayHandleDoubleAccess (in category 'tests - array by handle') -----
test08ByArrayHandleDoubleAccess

	| type handle |
	type := ExternalType double.
	ExternalType useArrayClassesDuring: [
		handle := (self allocate: type size: 5) getHandle].
	self assert: 0.0 equals: (type handle: handle atIndex: 2).
	type handle: handle atIndex: 2 put: 1.23456.
	type handle: handle atIndex: 1 put: 0.0.
	self assert: 1.23456 equals: (type handle: handle atIndex: 2).!

----- Method: FFIAllocateTests>>test09ArrayReadCStringList (in category 'tests - array') -----
test09ArrayReadCStringList

	| data |	
	ExternalData allowDetectForUnknownSizeDuring: [
		data := self allocate: ExternalType char size: 9.
		data setType: ExternalType byte.
		self assert: data size isNil.
		
		#[65 66 67 0 68 69 70 0 0] withIndexDo: [:byte :index | data at: index put: byte].
		data setType: ExternalType char.
		self assert:#('ABC' 'DEF') equals: data fromCStrings].!

----- Method: FFIAllocateTests>>test09ByArrayHandleCharAccess (in category 'tests - array by handle') -----
test09ByArrayHandleCharAccess

	| type handle |
	type := ExternalType char.
	ExternalType useArrayClassesDuring: [
		handle := (self allocate: type size: 5) getHandle].
	self assert: Character null equals: (type handle: handle atIndex: 2).
	type handle: handle atIndex: 2 put: $A.
	type handle: handle atIndex: 1 put: Character null.	
	self assert: $A equals: (type handle: handle atIndex: 2).!

----- Method: FFIAllocateTests>>test10ArrayClasses (in category 'tests - array') -----
test10ArrayClasses
	"For integer and float types, allocate arrays and check for specific array classes. Then construct a conventional byte array for an external data structure. A copy should also convert into a specific array class with the same contents."
	
	ExternalType useArrayClassesDuring: [
		
	ExternalType atomicTypes do: [:contentType |
		(contentType isIntegerType
			or: [contentType isFloatType]
			or: [contentType isCharType and: [contentType byteSize ~= 2 "No array class for 16-bit characters yet"]]) ifTrue: [
				| array arrayType data copy |
				array := self allocate: contentType size: 5.
				arrayType := array externalType.

				self assert: array isFFIArray.
				self assert: 5 equals: array size.
				self assert: array byteSize equals: arrayType byteSize.
				
				contentType isCharType ifFalse: [
					self flag: #discuss. "mt: What is signedChar even for?"
					self assert: contentType equals: array contentType].

				self deny: array isNull.
				self deny: (array isKindOf: ExternalData).
				self assert: array equals: array getHandle.
				
				self shouldnt: [array at: 1 put: contentType allocate first] raise: Error.
				self shouldnt: [array zeroMemory] raise: Error.
				self should: [array setContentType: ExternalType byte] raise: Error.
				self should: [array setSize: 42] raise: Error.

				data := ExternalData
					fromHandle: (ByteArray new: arrayType byteSize)
					type: arrayType.
				copy := data copy. "From external data into raw-bits array."
				self deny: array equals: data.			
				self assert: array equals: copy. ]]].!

----- Method: FFIAllocateTests>>test10ByArrayHandleBoolAccess (in category 'tests - array by handle') -----
test10ByArrayHandleBoolAccess

	| type handle |
	type := ExternalType bool.
	ExternalType useArrayClassesDuring: [
		handle := (self allocate: type size: 5) getHandle].
	self assert: false equals: (type handle: handle atIndex: 2).
	type handle: handle atIndex: 2 put: true.
	type handle: handle atIndex: 1 put: false.	
	self assert: true equals: (type handle: handle atIndex: 2).!

----- Method: FFIAllocateTests>>test11ArrayAsVoidPointer (in category 'tests - array') -----
test11ArrayAsVoidPointer
	"Check whether the undefined content type -- void -- works. Type casting via #setContentType: is necessary in such cases."
	
	| type void array |
	type := ExternalType int32_t.
	void := ExternalType void.
	array := self allocate: type size: 5.
	self assert: type equals: array contentType.
	array setContentType: void.
	self checkAllocate: array. "Checks container type."
	self assert: void equals: array contentType.
	self assert: array size isNil.
	self should: [array at: 1] raise: Error.
	self should: [array at: 1 put: 42] raise: Error.	
	array setContentType: type.
	self checkAllocate: array.
	self assert: type equals: array contentType.
	self assert: array size isNil.
	self shouldnt: [array at: 1] raise: Error.
	self shouldnt: [array at: 1 put: 42] raise: Error.	!

----- Method: FFIAllocateTests>>test12ArrayWithLargeSize (in category 'tests - array') -----
test12ArrayWithLargeSize

	| array byteSize contentType arraySize |
	byteSize := FFIStructSizeMask + 1.
	contentType := ExternalType uint64_t.
	arraySize := (byteSize / contentType byteSize) rounded.
	array := self allocate:  contentType size: arraySize.
	self assert: array byteSize > FFIStructSizeMask.!

----- Method: FFIAllocateTests>>test13ArrayFirst (in category 'tests - array') -----
test13ArrayFirst
	"Access a sub-range in the external data."
	
	| array portion |
	array := self allocate: 'int32_t' size: 5.
	1 to: array size do: [:index | array at: index put: index].

	array setSize: nil. "Not needed for #first:."
	portion := array reader first: 2.
	self assert: #(1 2) equals: (portion collect: #yourself).

	portion at: 2 put: 42.
	self assert: 42 equals: (array at: 2).!

----- Method: FFIAllocateTests>>test14ArrayLast (in category 'tests - array') -----
test14ArrayLast
	"Access a sub-range in the external data."
	
	| array portion |
	array := self allocate: 'int32_t' size: 5.
	1 to: array size do: [:index | array at: index put: index].
	
	portion := array reader last: 2.
	self assert: #(4 5) equals: (portion collect: #yourself).

	portion at: 2 put: 42.
	self assert: 42 equals: (array at: 5).!

----- Method: FFIAllocateTests>>test15ArrayLastError (in category 'tests - array') -----
test15ArrayLastError
	"Access a sub-range in the external data. Error for unknown size because #last: needs to access the end of the array."
	
	| array |
	array := self allocate: 'int32_t' size: 5.
	array setSize: nil.
	self should: [array last: 2] raise: Error.!

----- Method: FFIAllocateTests>>test16ArrayFrom (in category 'tests - array') -----
test16ArrayFrom
	"Access a sub-range in the external data by moving the start of the array."
	
	| array portion |
	array := self allocate: 'int32_t' size: 5.
	1 to: array size do: [:index | array at: index put: index].

	portion := array reader from: 3.
	self assert: #(3 4 5) equals: (portion collect: #yourself).!

----- Method: FFIAllocateTests>>test17ArrayFromUnkownSize (in category 'tests - array') -----
test17ArrayFromUnkownSize
	"Access a sub-range in the external data by moving the start of the array."
	
	| array portion |
	array := self allocate: 'int32_t' size: 5.
	1 to: array size do: [:index | array at: index put: index].

	array setSize: nil. "Possible but limited for byte-array handles."
	portion := array reader from: 3.
	self assert: 3 equals: (portion at: 1).
	self should: [portion at: 2] raise: Error.!

----- Method: FFIAllocateTests>>test18ArrayMoveBackAndForth (in category 'tests - array') -----
test18ArrayMoveBackAndForth
	"Check whether it is possible to move back-and-forth in memory without keeping track of the original array."
	
	| array portion |
	array := self allocate: 'int32_t' size: 5.
	1 to: array size do: [:index | array at: index put: index].

	portion := array reader from: 3.
	self assert: 3 equals: (portion at: 1).
	portion := portion from: 0.
	self assert: 2 equals: (portion at: 1).

	portion := array reader from: 3.
	self assert: 3 equals: (portion at: 1).
	portion := portion from: -1.
	self assert: 1 equals: (portion at: 1).

	portion := portion from: 4.
	self assert: 4 equals: (portion at: 1).!

----- Method: FFIAllocateTests>>test19ArrayFromVoidPointer (in category 'tests - array') -----
test19ArrayFromVoidPointer
	"Check whether the construction of external data with void or void* will always set void* as containerType and void as contentType. Whether or not the #externalType will be a pointer type still corresponds to the kind of handle, that is, byte array (void) or external address (void*)."
		
	| type void array |
	type := ExternalType int32_t.
	void := ExternalType void.
	array := self allocate: type size: 5.

	array := ExternalData
		fromHandle: array getHandle
		type: void asPointerType.
	self assert: void asPointerType equals: array containerType.	
	self assert: void equals: array contentType.
	self checkAllocate: array.

	array := ExternalData
		fromHandle: array getHandle
		type: void. "Should still become void*"
	self assert: void asPointerType equals: array containerType.	
	self assert: void equals: array contentType.
	self checkAllocate: array.

	array := ExternalData fromHandle: array getHandle.
	self assert: void asPointerType equals: array containerType.	
	self assert: void equals: array contentType.
	self checkAllocate: array.!

----- Method: FFIAllocateTests>>test20ArrayCopy (in category 'tests - array') -----
test20ArrayCopy
	"Copy the array into a new array."

	| original firstCopy secondCopy |
	original := self allocate: ExternalType int32_t size: 5.
	firstCopy := original copy.
	secondCopy := firstCopy copy.
	
	firstCopy withIndexDo: [:num :index | firstCopy at: index put: index].
	self assert: #(0 0 0 0 0) equals: (original collect: #yourself).
	self assert: #(1 2 3 4 5) equals: (firstCopy collect: #yourself).
	self assert: #(0 0 0 0 0) equals: (secondCopy collect: #yourself).	

	secondCopy withIndexDo: [:num :index | secondCopy at: index put: index+1].
	self assert: #(0 0 0 0 0) equals: (original collect: #yourself).
	self assert: #(1 2 3 4 5) equals: (firstCopy collect: #yourself).
	self assert: #(2 3 4 5 6) equals: (secondCopy collect: #yourself).	
!

----- Method: FFIAllocateTests>>test21ArrayAssureLocal (in category 'tests - array') -----
test21ArrayAssureLocal
	"Copy the array into local (object) memory."

	| original copy |
	original := self allocate: ExternalType int32_t size: 5.
	copy := original assureLocal.
	self assert: original identical: copy.!

----- Method: FFIAllocateTests>>test22ArrayForVoidPointers (in category 'tests - array') -----
test22ArrayForVoidPointers
	"Use a single external object to avoid #isNull check."
	
	| type array object |
	type := ExternalType void asPointerType.
	array := self allocate: type size: 1.

	object := (externalObjects add: FFITestPoint2 allocateExternal).
	array at: 1 put: object getHandle. "Write address, discard type."

	self deny: array isNull.
	self deny: array first isNull.
	
	self assert: array byteSize isNil. "Unknown because of void* content"
	self assert: array first byteSize isNil. "Unknown because of void content"!

TestCase subclass: #FFIImageTests
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests'!

----- Method: FFIImageTests class>>checkPlatformChange (in category 'manual checks') -----
checkPlatformChange
	"
	self checkPlatformChange.
	"
	| old new bench |
	old := FFIPlatformDescription newCurrent name: 'TEST'.
	new := FFIPlatformDescription newCurrent.

	self assert: [old ~= new].
	bench := [ExternalType platformChangedFrom: old to: new] bench.
	Transcript showln: bench.
	self debug: #test05TypeIntegrity.
	!

----- Method: FFIImageTests class>>checkTypeIntegrity (in category 'manual checks') -----
checkTypeIntegrity
	"
	self checkTypeIntegrity.
	"
	ExternalType initializeFast.
	self debug: #test05TypeIntegrity.

	ExternalType initialize.
	self debug: #test05TypeIntegrity.
	
	ExternalType resetAllTypes.
	self debug: #test05TypeIntegrity.!

----- Method: FFIImageTests>>test01AllAtomicTypes (in category 'tests') -----
test01AllAtomicTypes

	ExternalType allAtomicTypes do: [:type |
		self
			assert: type isAtomic;
			deny: type isPointerType;
			deny: type isStructureType;
			deny: type isArrayType].!

----- Method: FFIImageTests>>test02AllStructureTypes (in category 'tests') -----
test02AllStructureTypes

	ExternalType allStructTypes do: [:type |
		self
			deny: type isAtomic;
			deny: type isPointerType;
			assert: type isStructureType;
			deny: type isArrayType].!

----- Method: FFIImageTests>>test03AllPointerTypes (in category 'tests') -----
test03AllPointerTypes

	ExternalType allPointerTypes do: [:type |
		self
			deny: type isAtomic;
			assert: type isPointerType;
			deny: type isStructureType;
			deny: type isArrayType].!

----- Method: FFIImageTests>>test04AllArrayTypes (in category 'tests') -----
test04AllArrayTypes

	ExternalType allArrayTypes do: [:type |
		self
			deny: type isAtomic;
			deny: type isPointerType;
			deny: type isStructureType;
			assert: type isArrayType].!

----- Method: FFIImageTests>>test05TypeIntegrity (in category 'tests') -----
test05TypeIntegrity

	"ExternalType initialize."

	#(atomicTypesDo: structTypesDo: pointerTypesDo: arrayTypesDo: typeAliasTypesDo:)
		do: [:enumerator |
			ExternalType perform: enumerator with: [:type |
				self assert: type compiledSpec notNil.
				self assert: type byteAlignment notNil.
				self assert: type asPointerType notNil.
				self assert: type asNonPointerType notNil.]].!

----- Method: FFIImageTests>>test06AllTypes (in category 'tests') -----
test06AllTypes
	"Check uniqueness of all known types."
	
	| set |
	set := Set new.
	ExternalType allTypesDo: [:type |
		self assert: (set ifAbsentAdd: type)].!

----- Method: FFIImageTests>>test07AllTypeNames (in category 'tests') -----
test07AllTypeNames
	"Check uniqueness of all known type names."

	| set |
	set := Set new.
	ExternalType allTypesDo: [:type |
		self assert: (set ifAbsentAdd: type typeName)].!

TestCase subclass: #FFIPluginTests
	instanceVariableNames: 'heapObject'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests'!

!FFIPluginTests commentStamp: '<historical>' prior: 0!
SUnitized tests for the FFI (mostly the plugin side)!

FFIPluginTests subclass: #FFIPluginConstructedTests
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests'!

----- Method: FFIPluginConstructedTests class>>shouldInheritSelectors (in category 'testing') -----
shouldInheritSelectors
	^ true!

----- Method: FFIPluginConstructedTests>>expectedFailures (in category 'failures') -----
expectedFailures
	"We can actually call that one function with 20 arguments. :-)"
	
	^ super expectedFailures copyWithout: #testMixedDoublesAndLongsSum!

----- Method: FFIPluginConstructedTests>>invoke:withArguments: (in category 'support') -----
invoke: functionName withArguments: someObjects
	"Use primitive 117 to invoke the call, not 120."
	
	| prototype externalFunction |
	prototype := (FFITestLibrary class >> (self lookupSelector: functionName numArgs: someObjects size)) externalLibraryFunction.
	externalFunction := ExternalLibraryFunction
		name: functionName module: prototype module
		callType: prototype flags returnType: prototype argTypes first
		argumentTypes: prototype argTypes allButFirst.
	^ externalFunction invokeWithArguments: someObjects!

FFIPluginTests subclass: #FFIPluginLibraryTests
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests'!

----- Method: FFIPluginLibraryTests class>>shouldInheritSelectors (in category 'testing') -----
shouldInheritSelectors
	^ true!

----- Method: FFIPluginLibraryTests>>invoke:withArguments: (in category 'support') -----
invoke: functionName withArguments: someObjects
	"Use an instance of the library. Compile class-side methods to instance-side methods as needed."

	| selector library |
	selector := self lookupSelector: functionName numArgs: someObjects size.
	library := FFITestLibrary new.

	(library respondsTo: selector) ifFalse: [ | signature source prototype method |
		"1) Build method signature."
		signature := String streamContents: [:s | | index |
			index := 0. selector do: [:char | s nextPut: char.
				char = $: ifTrue: [ index := index + 1.
					s space; nextPutAll: 'arg'; nextPutAll: index asString; space]]].
		"2) Construct method source."
		prototype := library class class compiledMethodAt: selector.
		source := '{1}\	{2}\	<generated>\	{3}\	^ self externalCallFailed' withCRs
			format: {
				signature.
				'"This method was automatically generated. See {1}>>{2}"'
					format: {prototype methodClass. prototype selector}.
				 prototype externalLibraryFunction copy
					setModule: nil; printString }.
		"3) Compile instance-side FFI call in library."
		library class compileSilently: source classified: '*autogenerated - primitives'.
		method := library class compiledMethodAt: selector.
		method becomeForward: (method copyWithSourceCode: source)].

	^ library perform: selector withArguments: someObjects!

----- Method: FFIPluginTests>>expectedFailures (in category 'failures') -----
expectedFailures

	^ #(
		testIntAliasCall "argument-type coercing failed - handle must not be atomic but ByteArray or ExternalAddress"
		testIntAliasCallReturnIntAlias "return-type coercing failed - check referentClass notNil missing?"
		testIntCallReturnIntAlias "return-type coercing failed - check referentClass notNil missing?"
		testMixedDoublesAndLongsSum "more than 15 method args needed"
		testSumStructSslf4 "some overflow issue, maybe expected"
		testPrintWideString "no support for WideString arguments yet")!

----- Method: FFIPluginTests>>invoke: (in category 'support') -----
invoke: selector

	^ self invoke: selector withArguments: #()!

----- Method: FFIPluginTests>>invoke:with: (in category 'support') -----
invoke: selector with: arg1

	^ self invoke: selector withArguments: {arg1}!

----- Method: FFIPluginTests>>invoke:with:with: (in category 'support') -----
invoke: selector with: arg1 with: arg2

	^ self invoke: selector withArguments: {arg1. arg2}!

----- Method: FFIPluginTests>>invoke:with:with:with: (in category 'support') -----
invoke: selector with: arg1 with: arg2 with: arg3

	^ self invoke: selector withArguments: {arg1. arg2. arg3}!

----- Method: FFIPluginTests>>invoke:with:with:with:with: (in category 'support') -----
invoke: selector with: arg1 with: arg2 with: arg3 with: arg4

	^ self invoke: selector withArguments: {arg1. arg2. arg3. arg4}!

----- Method: FFIPluginTests>>invoke:with:with:with:with:with: (in category 'support') -----
invoke: selector with: arg1 with: arg2 with: arg3 with: arg4 with: arg5

	^ self invoke: selector withArguments: {arg1. arg2. arg3. arg4. arg5}!

----- Method: FFIPluginTests>>invoke:withArguments: (in category 'support') -----
invoke: functionName withArguments: someObjects
 
	^ FFITestLibrary
		perform: (self lookupSelector: functionName numArgs: someObjects size)
		withArguments: someObjects!

----- Method: FFIPluginTests>>lookupSelector:numArgs: (in category 'support') -----
lookupSelector: functionName numArgs: numArgs

	^ Symbol lookup: (
		numArgs > 0
			ifFalse: [functionName]
			ifTrue: [
				functionName, ':'
					, (Array new: (numArgs min: 15) - 1 withAll: 'with:') join])!

----- Method: FFIPluginTests>>tearDown (in category 'running') -----
tearDown

	heapObject ifNotNil: [heapObject free].!

----- Method: FFIPluginTests>>test4IntSum (in category 'tests - atomics') -----
test4IntSum

	| result n interval |
	n := 4.
	interval := 1 - n * n to: n * n by: 2 * n + 1.
	result := self invoke: 'ffiTest4IntSum' withArguments: interval asArray.
	self assert: interval sum equals: result!

----- Method: FFIPluginTests>>test8IntSum (in category 'tests - atomics') -----
test8IntSum

	| result n interval |
	n := 8.
	interval := 1 - n * n to: n * n by: 2 * n + 1.
	result := self invoke: 'ffiTest8IntSum' withArguments: interval asArray.
	self assert: interval sum equals: result!

----- Method: FFIPluginTests>>test8LongLongSum (in category 'tests - atomics') -----
test8LongLongSum

	| result n interval |
	n := 8.
	interval := 1 - n * n << 32 + (1 - n * n) to: n * n - n << 32 + (3 * n * n) by: 2 * n << 32 + (3 * n).
	result := self invoke: 'ffiTest8LongLongSum' withArguments: interval asArray.
	self assert: interval sum equals: result!

----- Method: FFIPluginTests>>test8LongSum (in category 'tests - atomics') -----
test8LongSum

	| result n interval |
	n := 8.
	interval := 1 - n * n to: n * n by: 2 * n + 1.
	result := self invoke: 'ffiTest8longSum' withArguments: interval asArray.
	self assert: interval sum equals: result!

----- Method: FFIPluginTests>>testArrayResultWithPoint (in category 'tests - arrays') -----
testArrayResultWithPoint
	"Test returning of pointers to arrays"
	| pt1 pt2 pt3 |
	pt1 := FFITestPoint4 new.
	pt1 x: 1. pt1 y: 2. pt1 z: 3. pt1 w: 4.
	pt2 := FFITestPoint4 new.
	pt2 x: 5. pt2 y: 6. pt2 z: 7. pt2 w: 8.
	pt3 := heapObject := FFITestLibrary ffiTestArrayResultWith: pt1 with: pt2.
	
	self assert: pt3 isFFIArray.
	pt3 := pt3 value.
	
	self assert: pt3 x = 6.
	self assert: pt3 y = 8.
	self assert: pt3 z = 10.
	self assert: pt3 w = 12.!

----- Method: FFIPluginTests>>testArrayResultWithString (in category 'tests - arrays') -----
testArrayResultWithString
	"Note that the result does not have to be free'd because the FFITestLibrary is just passing along a Smalltalkg string. I think."

	| string result |
	string := 'Hello Squeak!!'.
	result := FFITestLibrary ffiTestArrayResultWithString: string.
	self assert: result isFFIArray.
	ExternalData allowDetectForUnknownSizeDuring: [
		self assert: string equals: result fromCString].!

----- Method: FFIPluginTests>>testBoolsToInts (in category 'tests - other') -----
testBoolsToInts

	| result |
	result := FFITestLibrary ffiTestBool: true with: false with: true with: false.
	self assert: result.
	result := FFITestLibrary ffiTestBool: -1 with: 1 with: 0 with: 0.
	self deny: result.
	result := FFITestLibrary ffiTestBool: false with: false with: true with: true.
	self deny: result.!

----- Method: FFIPluginTests>>testChars (in category 'tests - atomics') -----
testChars

	| result |
	result := self invoke: 'ffiTestChars' with: $A with: 65 with: 65.0 with: true.
	self assert: result isCharacter.
	self assert: 130 equals: result asciiValue.!

----- Method: FFIPluginTests>>testDoubles (in category 'tests - atomics') -----
testDoubles
	
	| result |
	result := self invoke: 'ffiTestDoubles' with: $A with: 65.0.
	self assert: 130.0 equals: result.
	result := self invoke: 'ffiTestDoubles' with: 41 with: true.
	self assert: 42.0 equals: result.!

----- Method: FFIPluginTests>>testDoubles14 (in category 'tests - atomics') -----
testDoubles14

	| result n args |
	n := 14.
	args := (123.456789 to: 3.210987 * 13 + 123.456789 by: 3.210987) asArray first: n.
	result := self invoke: 'ffiTestDoubles14' withArguments: args.
	self assert: args sum equals: result!

----- Method: FFIPluginTests>>testDoubles9 (in category 'tests - atomics') -----
testDoubles9

	| result |
	result := self invoke: 'ffiTestDoubles9' withArguments: #(1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0).
	self assert: 45.0 equals: result!

----- Method: FFIPluginTests>>testFloats (in category 'tests - atomics') -----
testFloats

	| result |
	result :=self invoke: 'ffiTestFloats' with: $A with: 65.0.
	self assert: 130.0 equals: result.!

----- Method: FFIPluginTests>>testFloats13 (in category 'tests - atomics') -----
testFloats13

	| result n args |
	n := 13.
	args := (123.456 to: 3.21 * 13 + 123.456 by: 3.21) asArray first: n.
	result := self invoke: 'ffiTestFloats13' withArguments: args.
	self assert: (result between: args sum - 0.0005 and: args sum + 0.0005)!

----- Method: FFIPluginTests>>testFloats14 (in category 'tests - atomics') -----
testFloats14

	| result n args |
	n := 14.
	args := (123.456 to: 3.21 * 13 + 123.456 by: 3.21) asArray first: n.
	result := self invoke: 'ffiTestFloats14' withArguments: args.
	self assert: (result between: args sum - 0.0005 and: args sum + 0.0005)!

----- Method: FFIPluginTests>>testFloats7 (in category 'tests - atomics') -----
testFloats7

	| result n args |
	n := 7.
	args := (123.456 to: 3.21 * 13 + 123.456 by: 3.21) asArray first: n.
	result := self invoke: 'ffiTestFloats7' withArguments: args.
	self assert: (result between: args sum - 0.0005 and: args sum + 0.0005)!

----- Method: FFIPluginTests>>testIntAliasCall (in category 'tests - type alias') -----
testIntAliasCall

	| result |
	self flag: #workaround. "mt: You can use #fromHandle: on atomics directly to make coercion work for now. However, #on: and #value(:) is the correct interface."
	result := FFITestLibrary
		ffiTestIntAlias4IntSum: (FFITestAliasForInt32 on: 1)
		with: (FFITestAliasForInt32 on: 2)
		with: (FFITestAliasForInt32 on: 3)
		with: (FFITestAliasForInt32 on: 4).
	self assert: 10 equals: result.!

----- Method: FFIPluginTests>>testIntAliasCallReturnIntAlias (in category 'tests - type alias') -----
testIntAliasCallReturnIntAlias

	| result |
	result := FFITestLibrary
		ffiTestIntAlias4IntAliasSum: (FFITestAliasForInt32 on: 1)
		with: (FFITestAliasForInt32 on: 2)
		with: (FFITestAliasForInt32 on: 3)
		with: (FFITestAliasForInt32 on: 4).
	self
		assert: (result isKindOf: FFITestAliasForInt32);
		assert: 10 equals: result value.!

----- Method: FFIPluginTests>>testIntCallReturnIntAlias (in category 'tests - type alias') -----
testIntCallReturnIntAlias

	| result |
	result := FFITestLibrary ffiTestIntAlias4IntSum: 1 with: 2 with: 3 with: 4.
	self
		assert: (result isKindOf: FFITestAliasForInt32);
		assert: 10 equals: result value.!

----- Method: FFIPluginTests>>testInts (in category 'tests - atomics') -----
testInts

	| result |
	result := self invoke: 'ffiTestInts' with: $A with: 65 with: 65.0 with: true.
	self assert: 	$A asInteger + 65 equals: result.
!

----- Method: FFIPluginTests>>testInts8 (in category 'tests - other') -----
testInts8

	| result n interval |
	n := 8.
	interval := 1 - n * n to: n * n by: 2 * n + 1.
	result := self invoke: 'ffiTestInts8' withArguments: interval asArray.
	self assert: 42 equals: result!

----- Method: FFIPluginTests>>testLoadSymbolFromModule (in category 'tests - other') -----
testLoadSymbolFromModule
	| address |
	
	"Ok"
	address := ExternalAddress loadSymbol: 'ffiTestFloats' module: FFITestLibrary moduleName.
	self deny: address isNil.
	self deny: address isNull.
	"Symbol does not exists"
	self 
		should: [ ExternalAddress loadSymbol: 'ffi_does_not_exist' module: FFITestLibrary moduleName ]
		raise: Error.
	"Module does not exists"
	self 
		should: [ ExternalAddress loadSymbol: 'ffiTestFloats' module: 'NonExistingModule' ]
		raise: Error.		!

----- Method: FFIPluginTests>>testLongLong (in category 'tests - atomics') -----
testLongLong
	"Test passing and returning longlongs"
	| long1 long2 long3 |
	long1 := 16r123456789012.
	long2 := (-1 << 31).
	long3 := self invoke: 'ffiTestLongLong' with: long1 with: long2.
	self assert: (long1 + long2) equals: long3.!

----- Method: FFIPluginTests>>testLongLong8 (in category 'tests - atomics') -----
testLongLong8

	| long1 long2 bytes result |
	bytes := (1 to: 8) asArray.
	long1 := 16r123456789012.
	long2 := (-1 << 31).
	result := self invoke: 'ffiTestLongLong8' withArguments: bytes, { long1 . long2 }.
	self assert: (bytes sum + long1 + long2) equals: result.!

----- Method: FFIPluginTests>>testLongLong8a1 (in category 'tests - atomics') -----
testLongLong8a1

	| long1 long2 bytes result |
	bytes := (1 to: 9) asArray.
	long1 := 16r123456789012.
	long2 := (-1 << 31).
	result := self invoke: 'ffiTestLongLong8a1' withArguments: bytes, { long1 . long2 }.
	self assert: (bytes sum + long1 + long2) equals: result.!

----- Method: FFIPluginTests>>testLongLong8a2 (in category 'tests - atomics') -----
testLongLong8a2

	| long1 long2 bytes result |
	bytes := (1 to: 10) asArray.
	long1 := 16r123456789012.
	long2 := (-1 << 31).
	result := self invoke: 'ffiTestLongLong8a2' withArguments: bytes, { long1 . long2 }.
	self assert: (bytes sum + long1 + long2) equals: result.!

----- Method: FFIPluginTests>>testLongLongA1 (in category 'tests - atomics') -----
testLongLongA1
	"Test passing a char and two longlongs."
	
	| byte long1 long2 result |
	byte := 42.
	long1 := 16r123456789012.
	long2 := (-1 << 31).
	result := self invoke: 'ffiTestLongLonga1' with: byte with: long1 with: long2.
	self assert: (byte + long1 + long2) equals: result.!

----- Method: FFIPluginTests>>testLongLongA2 (in category 'tests - atomics') -----
testLongLongA2

	| byte1 byte2 long1 long2 result |
	byte1 := 3.
	byte2 := 4.
	long1 := 16r123456789012.
	long2 := (-1 << 31).
	result := self invoke: 'ffiTestLongLonga2' with: byte1 with: byte2 with: long1 with: long2.
	self assert: (byte1 + byte2 + long1 + long2) equals: result.!

----- Method: FFIPluginTests>>testLongLongA3 (in category 'tests - atomics') -----
testLongLongA3
	"Test passing a char, a longlong, and another char."
	| byte1 long1 byte2 result |
	byte1 := 3.
	long1 := 16r123456789012.
	byte2 := 4.
	result := self invoke: 'ffiTestLongLonga3' with: byte1 with: long1 with: byte2.
	self assert: (byte1 + long1 + byte2) equals: result.!

----- Method: FFIPluginTests>>testLongLongs8 (in category 'tests - other') -----
testLongLongs8

	| result n interval |
	n := 8.
	interval := 1 - n * n << 32 + (1 - n * n) to: n * n - n << 32 + (3 * n * n) by: 2 * n << 32 + (3 * n).
	result := self invoke: 'ffiTestLongLongs8' withArguments: interval asArray.
	self assert: 42 equals: result!

----- Method: FFIPluginTests>>testMixedDoublesAndLongsSum (in category 'tests - atomics') -----
testMixedDoublesAndLongsSum

	| result n args |
	n := 20.
	args := (1 to: n) collect: [:i| i odd ifTrue: [(i // 2) odd ifTrue: [123.456 * (10 raisedTo: i)] ifFalse: [-654.321 * (10 raisedTo: i)]] ifFalse: [(i // 2) odd ifTrue: [54321 * i] ifFalse: [-54321 * i]]].
	result := self invoke: 'ffiTestMixedDoublesAndLongs' withArguments: args asArray.
	self assert: args sum equals: result!

----- Method: FFIPluginTests>>testMixedDoublesIntAndStruct (in category 'tests - atomics') -----
testMixedDoublesIntAndStruct

	| result i struct |
	i := 42.
	struct := FFITestPoint4 new.
	struct x: 1. struct y: 2. struct z: 3. struct w: 4.
	result := self
		invoke: 'ffiTestMixedDoublesIntAndStruct'
		withArguments: { 1.0 . 2.0 . 3.0 . 4.0 . 5.0 . 6.0 . 7.0 . 8.0 . 9.0 . 42 . struct }.
	self assert: (result closeTo: 45.0 + 42 + 10).!

----- Method: FFIPluginTests>>testMixedFloatsAndDouble (in category 'tests - atomics') -----
testMixedFloatsAndDouble

	| result |
	result := self invoke: 'ffiTestMixedFloatsAndDouble' with: 1.2 with: 3.4 with: 5.6 with: 7.8.
	self assert: (result closeTo: 1.2 + 3.4 + 5.6 + 7.8) !

----- Method: FFIPluginTests>>testMixedIntAndStruct (in category 'tests - structure') -----
testMixedIntAndStruct
	"Test passing an integer and two structures."
	| i1 pt1 pt2 result |
	i1 := 42.
	pt1 := FFITestPoint2 new.
	pt1 x: 3. pt1 y: 4.
	pt2 := FFITestPoint2 new.
	pt2 x: 5. pt2 y: 6.
	result := self invoke: 'ffiTestMixedIntAndStruct' with: i1 with: pt1 with: pt2.
	self assert: 60 equals: result.!

----- Method: FFIPluginTests>>testMixedIntAndStruct2 (in category 'tests - structure') -----
testMixedIntAndStruct2
	"Test passing an integer and two structures."
	| i1 pt1 result |
	i1 := 42.
	pt1 := FFITestPoint4 new.
	pt1 x: 3. pt1 y: 4. pt1 z: 5. pt1 w: 6.
	result := self invoke: 'ffiTestMixedIntAndStruct2' with: i1 with: pt1.
	self assert: 60 equals: result.!

----- Method: FFIPluginTests>>testMixedIntAndStruct3 (in category 'tests - structure') -----
testMixedIntAndStruct3
	"Test passing an integer and a small structure."
	| i1 pt1 result |
	i1 := 42.
	pt1 := FFISmallStruct1 new.
	pt1 x: 3. pt1 y: 4.
	result := self invoke: 'ffiTestMixedIntAndStruct3' with: i1 with: pt1.
	self assert: 49 equals: result.!

----- Method: FFIPluginTests>>testPoint2 (in category 'tests - structure') -----
testPoint2
	"Test passing and returning up of structures >32bit and <= 64 bit"
	| pt1 pt2 pt3 |
	pt1 := FFITestPoint2 new.
	pt1 x: 1. pt1 y: 2.
	pt2 := FFITestPoint2 new.
	pt2 x: 3. pt2 y: 4.
	pt3 := self invoke: 'ffiTestStruct64' with: pt1 with: pt2.
	self assert: pt3 x = 4.
	self assert: pt3 y = 6.!

----- Method: FFIPluginTests>>testPoint4 (in category 'tests - structure') -----
testPoint4
	"Test passing and returning up of structures > 64 bit"
	| pt1 pt2 pt3 |
	pt1 := FFITestPoint4 new.
	pt1 x: 1. pt1 y: 2. pt1 z: 3. pt1 w: 4.
	pt2 := FFITestPoint4 new.
	pt2 x: 5. pt2 y: 6. pt2 z: 7. pt2 w: 8.
	pt3 := self invoke: 'ffiTestStructBig' with: pt1 with: pt2.
	self assert: pt3 x = 6.
	self assert: pt3 y = 8.
	self assert: pt3 z = 10.
	self assert: pt3 w = 12.!

----- Method: FFIPluginTests>>testPoint4Bigger (in category 'tests - structure') -----
testPoint4Bigger
	"Test passing and returning up of structures > 64 bit"
	| pt1 pt2 pt3 |
	pt1 := FFITestPoint4 new.
	pt1 x: 1. pt1 y: 2. pt1 z: 3. pt1 w: 4.
	pt2 := FFITestPoint4 new.
	pt2 x: 5. pt2 y: 6. pt2 z: 7. pt2 w: 8.
	pt3 := self invoke: 'ffiTestStructBigger' with: pt1 with: pt2.
	self assert: pt3 x equals: pt1 x.
	self assert: pt3 y equals: pt1 y.
	self assert: pt3 z equals: pt1 z.
	self assert: pt3 w equals: pt1 w.
	self assert: pt3 r equals: pt2 x.
	self assert: pt3 s equals: pt2 y.
	self assert: pt3 t equals: pt2 z.
	self assert: pt3 u equals: pt2 w.
!

----- Method: FFIPluginTests>>testPointers (in category 'tests - structure') -----
testPointers
	"Test passing and returning of pointers to structs"
	| pt1 pt2 pt3 |
	pt1 := FFITestPoint4 new.
	pt1 x: 1. pt1 y: 2. pt1 z: 3. pt1 w: 4.
	pt2 := FFITestPoint4 new.
	pt2 x: 5. pt2 y: 6. pt2 z: 7. pt2 w: 8.
	pt3 := heapObject := self invoke: 'ffiTestPointers' with: pt1 with: pt2.
	self assert: pt3 x = 6.
	self assert: pt3 y = 8.
	self assert: pt3 z = 10.
	self assert: pt3 w = 12.!

----- Method: FFIPluginTests>>testPrintString (in category 'tests - other') -----
testPrintString

	| result |
	result := self invoke: 'ffiPrintString' with: 'Hello World!!'.
	self assert: result = 'Hello World!!'.!

----- Method: FFIPluginTests>>testPrintWideString (in category 'tests - other') -----
testPrintWideString

	| string result |
	string := 'Hello World!!', (Character value: 1024).
	result := self invoke: 'ffiPrintWideString' with: string.
	self assert: result = string.!

----- Method: FFIPluginTests>>testReturnPointerAlias (in category 'tests - type alias') -----
testReturnPointerAlias
	"Check the handle of a returned alias-to-pointer type. Should be an external address."
	
	| pt1 pt2 pt3 |
	pt1 := FFITestPoint4 new.
	pt1 x: 1. pt1 y: 2. pt1 z: 3. pt1 w: 4.
	pt2 := FFITestPoint4 new.
	pt2 x: 5. pt2 y: 6. pt2 z: 7. pt2 w: 8.
	pt3 := heapObject := FFITestLibrary ffiTestAliasForPointerResult: pt1 with: pt2.
	
	self assert: pt3 getHandle isExternalAddress.
	self assert: pt3 externalType isPointerType.
	
	self assert: pt3 x = 6.
	self assert: pt3 y = 8.
	self assert: pt3 z = 10.
	self assert: pt3 w = 12.!

----- Method: FFIPluginTests>>testReturnStructPassingUnionUfdUdSi2 (in category 'tests - union') -----
testReturnStructPassingUnionUfdUdSi2
	"Test returning struct made from 2 unions"
	| ufd udSi2 sUfdUdSi2 |
	ufd := self invoke: 'ffiTestInitUfd_d' with: Float pi.
	udSi2 := self invoke: 'ffiTestInitUdSi2_ii' with: 1 with: 2.
	sUfdUdSi2 := self invoke: 'ffiTestInitSUfdUdSi2' with: ufd with: udSi2.
	self assert: Float pi equals: sUfdUdSi2 ufd1 d1.
	self assert: 1 equals: sUfdUdSi2 udSii2 sii1 i1.
	self assert: 2 equals: sUfdUdSi2 udSii2 sii1 i2.!

----- Method: FFIPluginTests>>testReturnStructPassingUnionUfdUfi (in category 'tests - union') -----
testReturnStructPassingUnionUfdUfi
	"Test returning struct made from 2 unions"
	| ufd ufi sUfdUfi |
	ufd := self invoke: 'ffiTestInitUfd_d' with: Float pi.
	ufi := self invoke: 'ffiTestInitUfi_i' with: 1.
	sUfdUfi := self invoke: 'ffiTestInitSUfdUfi' with: ufd with: ufi.
	self assert: Float pi equals: sUfdUfi ufd1 d1.
	self assert: 1 equals: sUfdUfi ufi2 i1.!

----- Method: FFIPluginTests>>testReturnStructSSdi5 (in category 'tests - structure') -----
testReturnStructSSdi5
	"Test returning struct with five struct double int (64 + 32 bits)"
	| ssdi5 |
	ssdi5 := self invoke: 'ffiTestReturnSSdi5'.
	self assert: ssdi5 sdi1 d1 = 1.0.
	self assert: ssdi5 sdi2 d1 = 2.0.
	self assert: ssdi5 sdi3 d1 = 3.0.
	self assert: ssdi5 sdi4 d1 = 4.0.
	self assert: ssdi5 sdi5 d1 = 5.0.
	self assert: ssdi5 sdi1 i2 = 1.
	self assert: ssdi5 sdi2 i2 = 2.
	self assert: ssdi5 sdi3 i2 = 3.
	self assert: ssdi5 sdi4 i2 = 4.
	self assert: ssdi5 sdi5 i2 = 5.!

----- Method: FFIPluginTests>>testReturnStructSd2 (in category 'tests - structure') -----
testReturnStructSd2
	"Test returning struct with two double"
	| sd2 |
	sd2 := self invoke: 'ffiTestReturnSd2'.
	self assert: sd2 d1 = 1.0.
	self assert: sd2 d2 = 2.0.!

----- Method: FFIPluginTests>>testReturnStructSdi (in category 'tests - structure') -----
testReturnStructSdi
	"Test returning struct double int (64 + 32 bits)"
	| sdi |
	sdi := self invoke: 'ffiTestReturnSdi'.
	self assert: sdi d1 = 1.0.
	self assert: sdi i2 = 2.!

----- Method: FFIPluginTests>>testReturnStructSf2 (in category 'tests - structure') -----
testReturnStructSf2
	"Test returning struct with two float"
	| sf2 |
	sf2 := self invoke: 'ffiTestReturnSf2'.
	self assert: sf2 f1 = 1.0.
	self assert: sf2 f2 = 2.0.!

----- Method: FFIPluginTests>>testReturnStructSf2d (in category 'tests - structure') -----
testReturnStructSf2d
	"Test returning struct with two float one double"
	| sf2d |
	sf2d := self invoke: 'ffiTestReturnSf2d'.
	self assert: sf2d f1 = 1.0.
	self assert: sf2d f2 = 2.0.
	self assert: sf2d d3 = 3.0.!

----- Method: FFIPluginTests>>testReturnStructSf4 (in category 'tests - structure') -----
testReturnStructSf4
	"Test returning struct with four float"
	| sf4 |
	sf4 := self invoke: 'ffiTestReturnSf4'.
	self assert: sf4 f1 = 1.0.
	self assert: sf4 f2 = 2.0.
	self assert: sf4 f3 = 3.0.
	self assert: sf4 f4 = 4.0.!

----- Method: FFIPluginTests>>testReturnStructSfdf (in category 'tests - structure') -----
testReturnStructSfdf
	"Test returning struct with float double float"
	| sfdf |
	sfdf := self invoke: 'ffiTestReturnSfdf'.
	self assert: sfdf f1 = 1.0.
	self assert: sfdf d2 = 2.0.
	self assert: sfdf f3 = 3.0.!

----- Method: FFIPluginTests>>testReturnStructSfi (in category 'tests - structure') -----
testReturnStructSfi
	"Test returning struct with float int (32 + 32 bits)"
	| sfi |
	sfi := self invoke: 'ffiTestReturnSfi'.
	self assert: sfi f1 = 1.0.
	self assert: sfi i2 = 2.!

----- Method: FFIPluginTests>>testReturnStructSi2 (in category 'tests - structure') -----
testReturnStructSi2
	"Test returning struct with two int (32 bits)"
	| si2 |
	si2 := self invoke: 'ffiTestReturnSi2'.
	self assert: si2 i1 = 1.
	self assert: si2 i2 = 2.!

----- Method: FFIPluginTests>>testReturnStructSl2 (in category 'tests - structure') -----
testReturnStructSl2
	"Test returning struct with two long long int (64 bits)"
	| sl2 |
	sl2 := self invoke: 'ffiTestReturnSl2'.
	self assert: sl2 l1 = 1.
	self assert: sl2 l2 = 2.!

----- Method: FFIPluginTests>>testReturnStructSs2 (in category 'tests - structure') -----
testReturnStructSs2
	"Test returning struct with two short int (16 bits)"
	| ss2 |
	ss2 := self invoke: 'ffiTestReturnSs2'.
	self assert: ss2 s1 = 1.
	self assert: ss2 s2 = 2.!

----- Method: FFIPluginTests>>testReturnStructSs2i (in category 'tests - structure') -----
testReturnStructSs2i
	"Test returning struct with two short int (16 bits) one int (32 bits)"
	| ss2i |
	ss2i := self invoke: 'ffiTestReturnSs2i'.
	self assert: ss2i s1 = 1.
	self assert: ss2i s2 = 2.
	self assert: ss2i i3 = 3.!

----- Method: FFIPluginTests>>testReturnStructSs4 (in category 'tests - structure') -----
testReturnStructSs4
	"Test returning struct with four short int (16 bits)"
	| ss4 |
	ss4 := self invoke: 'ffiTestReturnSs4'.
	self assert: ss4 s1 = 1.
	self assert: ss4 s2 = 2.
	self assert: ss4 s3 = 3.
	self assert: ss4 s4 = 4.!

----- Method: FFIPluginTests>>testReturnStructSsSsf (in category 'tests - structure') -----
testReturnStructSsSsf
	"Test returning struct with short and sub structure short-float"
	| ssSsf |
	ssSsf := self invoke: 'ffiTestReturnSsSsf'.
	self assert: ssSsf s1 = 1.
	self assert: ssSsf ssf2 s1 = 2.
	self assert: ssSsf ssf2 f2 = 3.0.!

----- Method: FFIPluginTests>>testReturnStructSsSsi (in category 'tests - structure') -----
testReturnStructSsSsi
	"Test returning struct with short and sub structure short-int"
	| ssSsi |
	ssSsi := self invoke: 'ffiTestReturnSsSsi'.
	self assert: ssSsi s1 = 1.
	self assert: ssSsi ssi2 s1 = 2.
	self assert: ssSsi ssi2 i2 = 3.!

----- Method: FFIPluginTests>>testReturnStructSsf (in category 'tests - structure') -----
testReturnStructSsf
	"Test returning struct with short float (16 + 32 bits)"
	| ssf |
	ssf := self invoke: 'ffiTestReturnSsf'.
	self assert: ssf s1 = 1.
	self assert: ssf f2 = 2.0.!

----- Method: FFIPluginTests>>testReturnStructSsi (in category 'tests - structure') -----
testReturnStructSsi
	"Test returning struct with short int (16 + 32 bits)"
	| ssi |
	ssi := self invoke: 'ffiTestReturnSsi'.
	self assert: ssi s1 = 1.
	self assert: ssi i2 = 2.!

----- Method: FFIPluginTests>>testReturnStructSsis (in category 'tests - structure') -----
testReturnStructSsis
	"Test returning struct with short int short (16 + 32 + 16 bits)"
	| ssis |
	ssis := self invoke: 'ffiTestReturnSsis'.
	self assert: ssis s1 = 1.
	self assert: ssis i2 = 2.
	self assert: ssis s3 = 3.!

----- Method: FFIPluginTests>>testReturnStructSslf (in category 'tests - structure') -----
testReturnStructSslf
	"Test returning struct with short longlong float (16 + 64 + 32 bits)"
	| sslf |
	sslf := self invoke: 'ffiTestReturnSslf'.
	self assert: sslf s1 = 1.
	self assert: sslf l2 = 2.
	self assert: sslf f3 = 3.0.!

----- Method: FFIPluginTests>>testReturnStructSsls (in category 'tests - structure') -----
testReturnStructSsls
	"Test returning struct with short longlong short (16 + 64 + 16 bits)"
	| ssls |
	ssls := self invoke: 'ffiTestReturnSsls'.
	self assert: ssls s1 = 1.
	self assert: ssls l2 = 2.
	self assert: ssls s3 = 3.!

----- Method: FFIPluginTests>>testReturnUnionUdSi2 (in category 'tests - union') -----
testReturnUnionUdSi2
	"Test returning union with double or 2 int (64 or 64 bits)"
	| udSi2 |
	udSi2 := self invoke: 'ffiTestInitUdSi2_d' with: Float pi.
	self assert: Float pi equals: udSi2 d1.
	self assert: (Float pi basicAt: 1) equals: udSi2 sii1 i2. "Assume Little Endianness"
	self assert: (Float pi basicAt: 2) equals: udSi2 sii1 i1.
	udSi2 := self invoke: 'ffiTestInitUdSi2_ii' with: 1 with: 2.
	self assert: 1 equals: udSi2 sii1 i1.
	self assert: 2 equals: udSi2 sii1 i2.!

----- Method: FFIPluginTests>>testReturnUnionUfd (in category 'tests - union') -----
testReturnUnionUfd
	"Test returning union with float or double (32 or 64 bits)"
	| ufd |
	ufd := self invoke: 'ffiTestInitUfd_f' with: 1.0.
	self assert: 1.0 equals: ufd f1.
	ufd := self invoke: 'ffiTestInitUfd_d' with: 2.0.
	self assert: 2 equals: ufd d1.!

----- Method: FFIPluginTests>>testReturnUnionUfi (in category 'tests - union') -----
testReturnUnionUfi
	"Test returning union with float or int (32 or 32 bits)"
	| ufi |
	ufi := self invoke: 'ffiTestInitUfi_f' with: 1.0.
	self assert: 1.0 equals: ufi f1.
	self assert: 1.0 asIEEE32BitWord equals: ufi i1.
	ufi := self invoke: 'ffiTestInitUfi_i' with: 2.
	self assert: 2 equals: ufi i1.!

----- Method: FFIPluginTests>>testShorts (in category 'tests - atomics') -----
testShorts
	
	| result |
	result := self invoke: 'ffiTestShorts' with: $A with: 65 with: 65.0 with: true.
	self assert: 130 equals: result.!

----- Method: FFIPluginTests>>testSmallStructureReturn (in category 'tests - structure') -----
testSmallStructureReturn
	"Test returning small structures (<4 bytes) which are returned in a register on some platforms."
	| pt1 |

	pt1 := self invoke: 'ffiTestSmallStructReturn'.
	self assert: pt1 x = 3.
	self assert: pt1 y = 4.!

----- Method: FFIPluginTests>>testSumStructSSdi5 (in category 'tests - structure') -----
testSumStructSSdi5
	"Test passing a structure larger than 8 eighbytes"
	| sdi1 sdi2 sdi3 sdi4 sdi5 ssdi5 sum |
	sdi1 := FFITestSdi new.
	sdi1 d1: 0.5; i2: 16r12345678.
	sdi2 := FFITestSdi new.
	sdi2 d1: 0.25; i2: 16r01234567.
	sdi3 := FFITestSdi new.
	sdi3 d1: 0.125; i2: 3.
	sdi4 := FFITestSdi new.
	sdi4 d1: 2.0; i2: 1.
	sdi5 := FFITestSdi new.
	sdi5 d1: 4.0; i2: 2.
	ssdi5 := FFITestSSdi5 new.
	ssdi5 sdi1: sdi1; sdi2: sdi2; sdi3: sdi3; sdi4: sdi4; sdi5: sdi5.
	sum := self invoke: 'ffiTestSumSSdi5' with: ssdi5.
	self assert: 0.5 + 16r12345678 + 0.25 + 16r01234567 + 0.125 + 3 + 2.0 + 1 + 4.0 + 2 equals: sum!

----- Method: FFIPluginTests>>testSumStructSUfdUdsi2 (in category 'tests - structure') -----
testSumStructSUfdUdsi2
	"Sum up the double parts of two unions in a struct."
	
	| sUfdUdsi2 sum |
	sUfdUdsi2 := heapObject := FFITestSUfdUdSi2 allocateExternal.
	sUfdUdsi2 ufd1 d1: 123.456.
	sUfdUdsi2 udSii2 d1: 456.123.
	sum := self invoke: 'ffiTestSumSUfdUdSi2_d' with: sUfdUdsi2.
	self assert: 123.456 + 456.123 equals: sum.!

----- Method: FFIPluginTests>>testSumStructSUfdUfi (in category 'tests - structure') -----
testSumStructSUfdUfi
	"Sum up the float parts of two unions in a struct."

	| sUfdUdsi2 result expected |
	sUfdUdsi2 := heapObject := FFITestSUfdUfi allocateExternal.
	sUfdUdsi2 ufd1 f1: 123.456.
	sUfdUdsi2 ufi2 f1: 456.123.
	result := self invoke: 'ffiTestSumSUfdUfi_f' with: sUfdUdsi2.
	expected := 123.456 + 456.123.
	self assert: (result between: expected - 0.0005 and: expected + 0.0005).!

----- Method: FFIPluginTests>>testSumStructSdi (in category 'tests - structure') -----
testSumStructSdi
	"Test passing structure double int"
	| sdi sum |
	sdi := FFITestSdi new.
	sdi d1: 0.5; i2: 16r12345678.
	sum := self invoke: 'ffiTestSumSdi' with: sdi.
	self assert: 0.5 + 16r12345678 equals: sum!

----- Method: FFIPluginTests>>testSumStructSdi2 (in category 'tests - structure') -----
testSumStructSdi2
	"Test passing 2 structure double int"
	| sdi1 sdi2 sum |
	sdi1 := FFITestSdi new.
	sdi1 d1: 0.5; i2: 16r12345678.
	sdi2 := FFITestSdi new.
	sdi2 d1: 0.25; i2: 16r01234567.
	sum := self invoke: 'ffiTestSumSdi_2' with: sdi1 with: sdi2.
	self assert: 0.5 + 16r12345678 + 0.25 + 16r01234567 equals: sum!

----- Method: FFIPluginTests>>testSumStructSdi4 (in category 'tests - structure') -----
testSumStructSdi4
	"Test passing 4 structure double int"
	| sdi1 sdi2 sdi3 sdi4 sum |
	sdi1 := FFITestSdi new.
	sdi1 d1: 0.5; i2: 16r12345678.
	sdi2 := FFITestSdi new.
	sdi2 d1: 0.25; i2: 16r01234567.
	sdi3 := FFITestSdi new.
	sdi3 d1: 0.125; i2: 3.
	sdi4 := FFITestSdi new.
	sdi4 d1: 2.0; i2: 1.
	sum := self invoke: 'ffiTestSumSdi_4' with: sdi1 with: sdi2 with: sdi3 with: sdi4.
	self assert: 0.5 + 16r12345678 + 0.25 + 16r01234567 + 0.125 + 3 + 2.0 + 1 equals: sum!

----- Method: FFIPluginTests>>testSumStructSfd (in category 'tests - structure') -----
testSumStructSfd
	"Test passing structure float double"
	| sfd sum |
	sfd := FFITestSfd new.
	sfd f1: 0.5; d2: 305419896.0.
	sum := self invoke: 'ffiTestSumSfd' with: sfd.
	self assert: 0.5 + 305419896.0 equals: sum!

----- Method: FFIPluginTests>>testSumStructSfd2 (in category 'tests - structure') -----
testSumStructSfd2
	"Test passing 2 structure float double "
	| sfd1 sfd2 sum |
	sfd1 := FFITestSfd new.
	sfd1 f1: 0.5; d2: 305419896.0.
	sfd2 := FFITestSfd new.
	sfd2 f1: 0.25; d2: 19088743.0.
	sum := self invoke: 'ffiTestSumSfd_2' with: sfd1 with: sfd2.
	self assert: 0.5 + 305419896.0 + 0.25 + 19088743.0 equals: sum!

----- Method: FFIPluginTests>>testSumStructSfd4 (in category 'tests - structure') -----
testSumStructSfd4
	"Test passing 4 structure float double"
	| sfd1 sfd2 sfd3 sfd4 sum |
	sfd1 := FFITestSfd new.
	sfd1 f1: 0.5; d2: 305419896.0.
	sfd2 := FFITestSfd new.
	sfd2 f1: 0.25; d2: 19088743.0.
	sfd3 := FFITestSfd new.
	sfd3 f1: 0.125; d2: 3.
	sfd4 := FFITestSfd new.
	sfd4 f1: 2.0; d2: 1.
	sum := self invoke: 'ffiTestSumSfd_4' with: sfd1 with: sfd2 with: sfd3 with: sfd4.
	self assert: 0.5 + 305419896.0 + 0.25 + 19088743.0 + 0.125 + 3.0 + 2.0 + 1.0 equals: sum!

----- Method: FFIPluginTests>>testSumStructSslf (in category 'tests - structure') -----
testSumStructSslf
	"Test passing structure short long float"
	| sslf sum |
	sslf := FFITestSslf new.
	sslf s1: -32768; l2: 16r1234560000; f3: 65536.0.
	sum := self invoke: 'ffiTestSumSslf' with: sslf.
	self assert: -32768 + 16r1234560000 + 65536.0 equals: sum!

----- Method: FFIPluginTests>>testSumStructSslf2 (in category 'tests - structure') -----
testSumStructSslf2
	"Test passing structure short long float"
	| sslf1 sslf2 sum |
	sslf1 := FFITestSslf new.
	sslf1 s1: -32768; l2: 16r123456789012; f3: 65536.0.
	sslf2 := FFITestSslf new.
	sslf2 s1: 32767; l2: (-1 << 31); f3: -65536.0.	
	sum := self invoke: 'ffiTestSumSslf_2' with: sslf1 with: sslf2.
	self
		assert: sslf1 s1 + sslf1 l2 + sslf1 f3 + sslf2 s1 + sslf2 l2 + sslf2 f3
		equals: sum!

----- Method: FFIPluginTests>>testSumStructSslf4 (in category 'tests - structure') -----
testSumStructSslf4
	"Test passing structure short long float"
	| sslf1 sslf2 sslf3 sslf4 sum |
	sslf1 := FFITestSslf new.
	sslf1 s1: -32768; l2: 16r123456789012; f3: 65536.0.
	sslf2 := FFITestSslf new.
	sslf2 s1: 32767; l2: (-1 << 31); f3: -65536.0.
	sslf3 := FFITestSslf new.
	sslf3 s1: 1; l2: 16r123456789012; f3: 123.456.	
	sslf4 := FFITestSslf new.
	sslf4 s1: 2; l2: (-1 << 31); f3: 456.123.	
	sum := self invoke: 'ffiTestSumSslf_2' with: sslf1 with: sslf2.
	self
		assert: sslf1 s1 + sslf1 l2 + sslf1 f3 + sslf2 s1 + sslf2 l2 + sslf2 f3
			+ sslf3 s1 + sslf3 l2 + sslf3 f3 + sslf4 s1 + sslf4 l2 + sslf4 f3
		equals: sum!

----- Method: FFIPluginTests>>testSumdWithStructSdi4 (in category 'tests - structure') -----
testSumdWithStructSdi4
	"Test passing 4 structure double int"
	| sdi1 sdi2 sdi3 sdi4 sum |
	sdi1 := FFITestSdi new.
	sdi1 d1: 0.5; i2: 16r12345678.
	sdi2 := FFITestSdi new.
	sdi2 d1: 0.25; i2: 16r01234567.
	sdi3 := FFITestSdi new.
	sdi3 d1: 0.125; i2: 3.
	sdi4 := FFITestSdi new.
	sdi4 d1: 2.0; i2: 1.
	sum := self invoke: 'ffiTestSumdWithSdi_4' with: 5.0 with: sdi1 with: sdi2 with: sdi3 with: sdi4.
	self assert: 5.0 + 0.5 + 16r12345678 + 0.25 + 16r01234567 + 0.125 + 3 + 2.0 + 1 equals: sum!

----- Method: FFIPluginTests>>testSumdiWithStructSdi4 (in category 'tests - structure') -----
testSumdiWithStructSdi4
	"Test passing 4 structure double int"
	| sdi1 sdi2 sdi3 sdi4 sum |
	sdi1 := FFITestSdi new.
	sdi1 d1: 0.5; i2: 16r12345678.
	sdi2 := FFITestSdi new.
	sdi2 d1: 0.25; i2: 16r01234567.
	sdi3 := FFITestSdi new.
	sdi3 d1: 0.125; i2: 3.
	sdi4 := FFITestSdi new.
	sdi4 d1: 2.0; i2: 1.
	sum := self invoke: 'ffiTestSumdiWithSdi_4' withArguments: { 5.0 . 6 . sdi1 . sdi2 . sdi3 . sdi4 }.
	self assert: 5.0 + 6 + 0.5 + 16r12345678 + 0.25 + 16r01234567 + 0.125 + 3 + 2.0 + 1 equals: sum!

----- Method: FFIPluginTests>>testSumfWithStructSfd4 (in category 'tests - structure') -----
testSumfWithStructSfd4
	"Test passing 4 structure float double"
	| sfd1 sfd2 sfd3 sfd4 sum |
	sfd1 := FFITestSfd new.
	sfd1 f1: 0.5; d2: 305419896.0.
	sfd2 := FFITestSfd new.
	sfd2 f1: 0.25; d2: 19088743.0.
	sfd3 := FFITestSfd new.
	sfd3 f1: 0.125; d2: 3.
	sfd4 := FFITestSfd new.
	sfd4 f1: 2.0; d2: 1.
	sum := self invoke: 'ffiTestSumfWithSfd_4' with: 5.0 with: sfd1 with: sfd2 with: sfd3 with: sfd4.
	self assert: 5.0 + 0.5 + 305419896.0 + 0.25 + 19088743.0 + 0.125 + 3.0 + 2.0 + 1.0 equals: sum!

----- Method: FFIPluginTests>>testSumiWithStructSdi4 (in category 'tests - structure') -----
testSumiWithStructSdi4
	"Test passing 4 structure double int"
	| sdi1 sdi2 sdi3 sdi4 sum |
	sdi1 := FFITestSdi new.
	sdi1 d1: 0.5; i2: 16r12345678.
	sdi2 := FFITestSdi new.
	sdi2 d1: 0.25; i2: 16r01234567.
	sdi3 := FFITestSdi new.
	sdi3 d1: 0.125; i2: 3.
	sdi4 := FFITestSdi new.
	sdi4 d1: 2.0; i2: 1.
	sum := self invoke: 'ffiTestSumiWithSdi_4' with: 5 with: sdi1 with: sdi2 with: sdi3 with: sdi4.
	self assert: 5 + 0.5 + 16r12345678 + 0.25 + 16r01234567 + 0.125 + 3 + 2.0 + 1 equals: sum!

----- Method: FFIPluginTests>>testUnsignedIntegerRange (in category 'tests - other') -----
testUnsignedIntegerRange
	"Simple test for making sure the FFI can call certain numbers in the uint range. Note that only the first two parameters are summed up."

	| result arg1 arg2 arg3 arg4 |
	arg1 := arg2 := 3894967296 "1<<32-4e8".
	arg3 := arg4 := 3103854339.
	result := FFITestLibrary ffiTestUint: arg1 with: arg2 with: arg3 with: arg4.
	self assert: -8e8 "due to overflow" equals: result.!

TestCase subclass: #FFIPluginTypeTests
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'FFI-Tests'!

!FFIPluginTypeTests commentStamp: 'mt 5/10/2021 09:48' prior: 0!
A collection of tests around the type signatures for the FFITestLibrary.!

----- Method: FFIPluginTypeTests>>argTypesAt: (in category 'support') -----
argTypesAt: selector

	^ (FFITestLibrary class >> selector) externalLibraryFunction argTypes!

----- Method: FFIPluginTypeTests>>testArray (in category 'tests') -----
testArray

	(self argTypesAt: #ffiTestArrayType)	do: [:type |
		self
			assert: type isPointerType;
			deny: type isArrayType;
			assert: type asNonPointerType isArrayType;
			assert: type asNonPointerType size > 0]!

----- Method: FFIPluginTypeTests>>testAtomicBool (in category 'tests') -----
testAtomicBool

	self
		flag: #ffiLongVsInt;
		assert: (self argTypesAt: #ffiTestBool:with:with:with:)
		equals: (Array new: 5 withAll: ExternalType bool).!

----- Method: FFIPluginTypeTests>>testAtomicChar (in category 'tests') -----
testAtomicChar

	self
		flag: #ffiLongVsInt;
		assert: (self argTypesAt: #ffiTestChars:with:with:with:)
		equals: (Array new: 5 withAll: ExternalType char).!

----- Method: FFIPluginTypeTests>>testAtomicCharPointer (in category 'tests') -----
testAtomicCharPointer

	self
		assert: (self argTypesAt: #ffiPrintString:)
		equals: (Array new: 2 withAll: ExternalType char asPointerType).!

----- Method: FFIPluginTypeTests>>testAtomicDouble (in category 'tests') -----
testAtomicDouble

	self
		assert: (self argTypesAt: #ffiTestDoubles:with:)
		equals: (Array new: 3 withAll: ExternalType double).!

----- Method: FFIPluginTypeTests>>testAtomicFloat (in category 'tests') -----
testAtomicFloat

	self
		assert: (self argTypesAt: #ffiTestFloats:with:)
		equals: (Array new: 3 withAll: ExternalType float).!

----- Method: FFIPluginTypeTests>>testAtomicInt (in category 'tests') -----
testAtomicInt

	self
		flag: #ffiLongVsInt;
		assert: (self argTypesAt: #ffiTestInts:with:with:with:)
		equals: (Array new: 5 withAll: ExternalType int).!

----- Method: FFIPluginTypeTests>>testAtomicLong (in category 'tests') -----
testAtomicLong

	self
		flag: #ffiLongVsInt;
		assert: (self argTypesAt: #ffiTestInts:with:with:with:)
		equals: (Array new: 5 withAll: ExternalType long).!

----- Method: FFIPluginTypeTests>>testAtomicLongLong (in category 'tests') -----
testAtomicLongLong

	self
		assert: (self argTypesAt: #ffiTestLongLong:with:)
		equals: (Array new: 3 withAll: ExternalType longlong).!

----- Method: FFIPluginTypeTests>>testAtomicString (in category 'tests') -----
testAtomicString

	self
		assert: (self argTypesAt: #ffiPrintString:)
		equals: (Array new: 2 withAll: ExternalType string).!

----- Method: FFIPluginTypeTests>>testAtomicUint (in category 'tests') -----
testAtomicUint

	self
		flag: #ffiLongVsInt;
		assert: (self argTypesAt: #ffiTestUint:with:with:with:) allButFirst
		equals: (Array new: 4 withAll: ExternalType uint).!

----- Method: FFIPluginTypeTests>>testAtomicUlong (in category 'tests') -----
testAtomicUlong

	self
		flag: #ffiLongVsInt;
		assert: (self argTypesAt: #ffiTestUint:with:with:with:) allButFirst
		equals: (Array new: 4 withAll: ExternalType ulong).!

----- Method: FFIPluginTypeTests>>testAtomicVoid (in category 'tests') -----
testAtomicVoid
	"Only test for return type since argument 'void' means 'no argument' in C."
	
	self
		assert: (self argTypesAt: #ffiTestVoid)
		equals: {ExternalType void}.!

----- Method: FFIPluginTypeTests>>testAtomicVoidPointer (in category 'tests') -----
testAtomicVoidPointer

	self
		assert: (self argTypesAt: #ffiTestVoidPointer)
		equals: (Array new: 2 withAll: ExternalType void asPointerType).!

----- Method: FFIPluginTypeTests>>testStruct (in category 'tests') -----
testStruct

	self
		assert: (self argTypesAt: #ffiTestStruct64:with:)
		equals: (Array new: 3 withAll: FFITestPoint2 externalType).!

----- Method: FFIPluginTypeTests>>testStructPointer (in category 'tests') -----
testStructPointer

	self
		assert: (self argTypesAt: #ffiTestPointers:with:)
		equals: (Array new: 3 withAll: FFITestPoint4 externalType asPointerType).!



More information about the Squeak-dev mailing list