[K/N] Treat DEF files as regular test source, compiled with cinterop

^KT-61259
This commit is contained in:
Vladimir Sukharev
2023-12-05 00:36:00 +01:00
committed by Space Team
parent 2530cba82a
commit 0b0ba3160f
57 changed files with 988 additions and 934 deletions
@@ -1,8 +0,0 @@
---
int (*arrayPointer)[1];
int globalArray[3] = {1, 2, 3};
struct StructWithArrayPtr {
int (*arrayPointer)[1];
};
@@ -1,9 +0,0 @@
#ifdef __cplusplus
extern "C" {
#endif
const char* name();
#ifdef __cplusplus
}
#endif
@@ -1,8 +0,0 @@
#include <string>
#include "auxiliarySources.aux.h"
static std::string _name = "Hello from C++";
const char* name() {
return _name.c_str();
}
@@ -1,2 +0,0 @@
# The def file is empty intentianally
# `auxiliarySources.aux.h` is meant to be included via `-header` option of cinterop tool
@@ -1,9 +0,0 @@
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
import auxiliarySources.*
import kotlin.test.*
import kotlinx.cinterop.*
fun main() {
assertEquals(name()!!.toKString(), "Hello from C++")
}
@@ -1,30 +0,0 @@
---
enum B2 {
ZERO, ONE, TWO, THREE
};
enum E : short {
A, B
};
struct __attribute__((packed)) S {
long long x1 : 1;
enum B2 x2 : 2;
unsigned short x3 : 3;
unsigned int x4 : 4;
int x5 : 5;
long long x6 : 63;
enum E x7: 2;
_Bool x8 : 1;
struct { int x9:4; };
};
static long long getX1(struct S* s) { return s->x1; }
static enum B2 getX2(struct S* s) { return s->x2; }
static unsigned short getX3(struct S* s) { return s->x3; }
static unsigned int getX4(struct S* s) { return s->x4; }
static int getX5(struct S* s) { return s->x5; }
static long long getX6(struct S* s) { return s->x6; }
static enum E getX7(struct S* s) { return s->x7; }
static _Bool getX8(struct S* s) { return s->x8; }
static int getX9(struct S* s) { return s->x9; }
@@ -1,78 +0,0 @@
---
#include <stdarg.h>
struct S {
int x;
};
static int getX(struct S (*callback)(void)) {
return callback().x;
}
static void applyCallback(struct S s, void (*callback)(struct S)) {
callback(s);
}
static struct S makeS(int x, ...) {
return (struct S){ x };
}
enum E {
ZERO, ONE, TWO
};
static enum E makeE(int ordinal, ...) {
return ordinal;
}
struct Args {
char a1;
char a2;
short a3;
int a4;
long long a5;
float a6;
double a7;
void* a8;
unsigned char a9;
unsigned short a10;
unsigned int a11;
unsigned long long a12;
enum E a13;
struct S a14;
void* a15;
};
static struct Args getVarargs(int ignore, ...) {
va_list args;
va_start(args, ignore);
struct Args result = {
va_arg(args, char),
va_arg(args, char),
va_arg(args, short),
va_arg(args, int),
va_arg(args, long long),
va_arg(args, double),
va_arg(args, double),
va_arg(args, void*),
va_arg(args, unsigned char),
va_arg(args, unsigned short),
va_arg(args, unsigned int),
va_arg(args, unsigned long long),
va_arg(args, enum E),
va_arg(args, struct S),
va_arg(args, void*)
};
va_end(args);
return result;
}
static int sum(int first, int second) {
return first + second;
}
@@ -1,4 +0,0 @@
---
enum E {
A, B, C
};
@@ -1,11 +0,0 @@
---
struct StructDeclared;
struct StructDefined { int x; };
int useStructDeclared(struct StructDeclared* declared) {
return -1;
}
int useStructDefined(struct StructDefined* defined) {
return -2;
}
@@ -1,94 +0,0 @@
headerFilter = NOTHING
---
#include <stdio.h>
#include <stdlib.h>
typedef int (*atoiPtrType)(const char*);
static atoiPtrType getAtoiPtr() {
return &atoi;
}
static void __printInt(int x) {
printf("%d\n", x);
}
static void* __getPrintIntPtr() {
return &__printInt;
}
typedef void* (*getPrintIntPtrPtrType)(void);
static getPrintIntPtrPtrType getGetPrintIntPtrPtr() {
return &__getPrintIntPtr;
}
static double __add(double x, double y) {
return x + y;
}
typedef double (*addPtrType)(double, double);
static addPtrType getAddPtr() {
return &__add;
}
static int __doubleToInt(double x) {
return (int) x;
}
typedef int (*doubleToIntPtrType)(double);
static doubleToIntPtrType getDoubleToIntPtr() {
return &__doubleToInt;
}
static _Bool __isIntPositive(int x) {
return x > 0;
}
typedef _Bool (*isIntPositivePtrType)(int);
static isIntPositivePtrType getIsIntPositivePtr() {
return &__isIntPositive;
}
static unsigned int getMaxUInt(void) {
return 0xffffffff;
}
static typeof(&getMaxUInt) getMaxUIntGetter() {
return &getMaxUInt;
}
typedef int (*longSignatureFunctionPtrType)(
int, int, int, int, int, int, int, int, int, int, int, int,
int, int, int, int, int, int, int, int, int, int, int
);
typedef int (*notSoLongSignatureFunctionPtrType)(
int, int, int, int, int, int, int, int, int, int, int,
int, int, int, int, int, int, int, int, int, int, int
);
static int longSignatureFunction(
int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10, int p11, int p12,
int p13, int p14, int p15, int p16, int p17, int p18, int p19, int p20, int p21, int p22, int p23
) {
return 42;
}
static int notSoLongSignatureFunction(
int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10, int p11, int p12,
int p13, int p14, int p15, int p16, int p17, int p18, int p19, int p20, int p21, int p22
) {
return 42;
}
static longSignatureFunctionPtrType getLongSignatureFunctionPtr() {
return &longSignatureFunction;
}
static notSoLongSignatureFunctionPtrType getNotSoLongSignatureFunctionPtr() {
return &notSoLongSignatureFunction;
}
@@ -1,48 +0,0 @@
// OUT_DATA_FILE: funptr.out
/*
* Copyright 2010-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
import kotlinx.cinterop.*
import funptr.*
import kotlin.test.*
typealias NotSoLongSignatureFunction = (
Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int,
Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int
) -> Int
fun main(args: Array<String>) {
val atoiPtr = getAtoiPtr()!!
val getPrintIntPtrPtr = getGetPrintIntPtrPtr()!!
val printIntPtr = getPrintIntPtrPtr()!!.reinterpret<CFunction<(Int) -> Unit>>()
val fortyTwo = memScoped {
atoiPtr("42".cstr.getPointer(memScope))
}
printIntPtr(fortyTwo)
printIntPtr(
getDoubleToIntPtr()!!(
getAddPtr()!!(5.1, 12.2)
)
)
val isIntPositivePtr = getIsIntPositivePtr()!!
printIntPtr(isIntPositivePtr(42).ifThenOneElseZero())
printIntPtr(isIntPositivePtr(-42).ifThenOneElseZero())
assertEquals(getMaxUIntGetter()!!(), UInt.MAX_VALUE)
val longSignaturePtr: COpaquePointer? = getLongSignatureFunctionPtr()
val notSoLongSignaturePtr: CPointer<CFunction<NotSoLongSignatureFunction>>? = getNotSoLongSignatureFunctionPtr()
printIntPtr(notSoLongSignaturePtr!!.invoke(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
printIntPtr(notSoLongSignatureFunction(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
}
fun Boolean.ifThenOneElseZero() = if (this) 1 else 0
@@ -1,33 +0,0 @@
---
const int g1 = 42;
int g2 = 17;
struct S {
int x;
} g3 = { 128 };
int g4[2] = { 13, 14 };
int g5[2][2] = { 15, 16, 17, 18 };
struct S* const g6 = &g3;
void foo() {
// Test that local vars are not treated as global ones.
float g1;
}
// Test non-compilable variable:
typedef int MyInt;
MyInt g7;
#define g7 bad macro
// Test property name mangling:
struct g1 {};
struct g1_ {};
typedef void* voidptr;
_Pragma("clang assume_nonnull begin")
const voidptr g8 = 0x1, g9 = 0x2;
_Pragma("clang assume_nonnull end")
@@ -1,27 +0,0 @@
#ifdef __cplusplus
extern "C" {
#endif
// Forward declaration.
struct S;
extern struct S s;
const char* getContent(struct S* s);
void setContent(struct S* s, const char* name);
union U;
extern union U u;
double getDouble(union U* u);
void setDouble(union U* u, double value);
// Global array of unknown size.
extern char array[];
int arrayLength();
void setArrayValue(char* array, char value);
#ifdef __cplusplus
}
#endif
@@ -1,53 +0,0 @@
#include <string>
#include "incompleteTypes.aux.h"
extern "C" {
struct S {
std::string name;
};
S s = {
.name = "initial"
};
void setContent(struct S* s, const char* name) {
// Note that copy here is intentional: we use it as a workaround
// for short lifetime of copy of the passed Kotlin string.
s->name = name;
}
const char* getContent(struct S* s) {
return s->name.c_str();
}
union U {
float f;
double d;
};
void setDouble(union U* u, double value) {
u->d = value;
}
double getDouble(union U* u) {
return u->d;
}
union U u = {
.d = 0.0
};
char array[5] = { 0, 0, 0, 0, 0 };
void setArrayValue(char* array, char value) {
for (int i = 0; i < 5; ++i) {
array[i] = value;
}
}
int arrayLength() {
return sizeof(array) / sizeof(char);
}
}
@@ -1,2 +0,0 @@
# The def file is empty intentianally
# `incompleteTypes.aux.h` is meant to be included via `-header` option of cinterop tool
@@ -1,28 +0,0 @@
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
import incompleteTypes.*
import kotlinx.cinterop.*
import kotlin.test.*
fun main() {
assertNotNull(s.ptr)
assertNotNull(u.ptr)
assertNotNull(array)
assertEquals("initial", getContent(s.ptr)?.toKString())
setContent(s.ptr, "yo")
val ptr = getContent(s.ptr)
assertEquals("yo", ptr?.toKString())
assertEquals(0.0, getDouble(u.ptr))
setDouble(u.ptr, Double.MIN_VALUE)
assertEquals(Double.MIN_VALUE, getDouble(u.ptr))
for (i in 0 until arrayLength()) {
assertEquals(0x0, array[i])
}
setArrayValue(array, 0x1)
for (i in 0 until arrayLength()) {
assertEquals(0x1, array[i])
}
}
@@ -1,7 +0,0 @@
strictEnums = bcm2835FunctionSelect
---
enum bcm2835FunctionSelect {
BCM2835_GPIO_FSEL_INPT = 0x00, BCM2835_GPIO_FSEL_OUTP = 0x01, BCM2835_GPIO_FSEL_ALT0 = 0x04, BCM2835_GPIO_FSEL_ALT1 = 0x05,
BCM2835_GPIO_FSEL_ALT2 = 0x06, BCM2835_GPIO_FSEL_ALT3 = 0x07, BCM2835_GPIO_FSEL_ALT4 = 0x03, BCM2835_GPIO_FSEL_ALT5 = 0x02,
BCM2835_GPIO_FSEL_MASK = 0x07
};
@@ -1,7 +0,0 @@
import kt43265.*
import kotlin.test.*
@kotlinx.cinterop.ExperimentalForeignApi
fun main() {
assertEquals(bcm2835FunctionSelect.BCM2835_GPIO_FSEL_ALT3, bcm2835FunctionSelect.BCM2835_GPIO_FSEL_MASK)
}
@@ -1,25 +0,0 @@
---
#include <stdlib.h>
#include <pthread.h>
typedef struct {
int d;
} TestStruct;
typedef struct {
void (*f)(TestStruct data);
} ThreadData;
void *dispatch(void *rawArg) {
ThreadData *arg = rawArg;
arg->f((TestStruct) {.d = 1});
return NULL;
}
void invokeFromThread(void (*f)(TestStruct data)) {
pthread_t thread_id;
ThreadData *threadData = malloc(sizeof(ThreadData));
threadData->f = f;
pthread_create(&thread_id, NULL, dispatch, (void *) threadData);
pthread_join(thread_id, NULL);
}
@@ -1,7 +0,0 @@
---
#define KFILE "FILE:" __FILE__
#define KLINE "LINE:" __LINE__
#define KTIME "TIME:" __TIME__
#define KDATE "DATE:" __DATE__
#define KFILENAME "NAME:" __FILE_NAME__
#define KBASEFILE "BASE:" __BASE_FILE__
@@ -1,8 +0,0 @@
compilerOpts = -fmodules
---
#define KFILE "FILE:" __FILE__
#define KLINE "LINE:" __LINE__
#define KTIME "TIME:" __TIME__
#define KDATE "DATE:" __DATE__
#define KFILENAME "NAME:" __FILE_NAME__
#define KBASEFILE "BASE:" __BASE_FILE__
@@ -1,2 +0,0 @@
language = Objective-C
headers = kt63048.h
@@ -1,7 +0,0 @@
#import "Foundation/NSString.h"
#import "Foundation/NSObject.h"
@interface WithClassProperty : NSObject
-(instancetype) init;
@property (class, readonly, copy) NSString * stringProperty;
@end
@@ -1,6 +0,0 @@
#import "kt63048.h"
@implementation WithClassProperty : NSObject
-(instancetype) init {}
+ (NSString *) stringProperty { return @"153"; }
@end
@@ -1,15 +0,0 @@
#include "leakMemoryWithRunningThreadUnchecked.h"
#include <atomic>
#include <thread>
extern "C" void test_RunInNewThread(void (*f)()) {
std::atomic<bool> haveRun(false);
std::thread t([f, &haveRun]() {
f();
haveRun = true;
while (true) {}
});
t.detach();
while (!haveRun) {}
}
@@ -1,5 +0,0 @@
package leakMemoryWithRunningThreadUnchecked
---
void test_RunInNewThread(void (*)());
@@ -1,9 +0,0 @@
#ifdef __cplusplus
extern "C" {
#endif
void test_RunInNewThread(void (*)());
#ifdef __cplusplus
}
#endif
@@ -1,6 +0,0 @@
---
const char* empty() { return ""; }
const char* foo() { return "foo"; }
const char* kuku() { return "куку"; }
const char* invalid_utf8() { return "\x85\xAF"; }
const char* zero_in_the_middle() { return "before zero\0after zero"; }
@@ -1,6 +1,20 @@
// MODULE: cinterop
// FILE: carrayPointers.def
---
int (*arrayPointer)[1];
int globalArray[3] = {1, 2, 3};
struct StructWithArrayPtr {
int (*arrayPointer)[1];
};
// MODULE: main(cinterop)
// FILE: main.kt
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
import arrayPointers.*
import carrayPointers.*
import kotlin.test.*
import kotlinx.cinterop.*
@@ -0,0 +1,40 @@
// FREE_CINTEROP_ARGS: -header auxiliaryCppSources.h
// MODULE: cinterop
// FILE: auxiliaryCppSources.def
# The def file is intentionally empty
# `auxiliaryCppSources.h` is meant to be included via `-header` free arg of cinterop tool
// FILE: auxiliaryCppSources.h
#ifdef __cplusplus
extern "C" {
#endif
const char* name();
#ifdef __cplusplus
}
#endif
// FILE: auxiliaryCppSources.cpp
#include <string>
#include "auxiliaryCppSources.h"
static std::string _name = "Hello from C++";
const char* name() {
return _name.c_str();
}
// MODULE: main(cinterop)
// FILE: main.kt
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
import auxiliaryCppSources.*
import kotlin.test.*
import kotlinx.cinterop.*
fun main() {
assertEquals(name()!!.toKString(), "Hello from C++")
}
@@ -4,6 +4,42 @@
*/
// May need disabling when gcSchedulerType=aggressive . since it may be too slow
// MODULE: cinterop
// FILE: bitfields.def
---
enum B2 {
ZERO, ONE, TWO, THREE
};
enum E : short {
A, B
};
struct __attribute__((packed)) S {
long long x1 : 1;
enum B2 x2 : 2;
unsigned short x3 : 3;
unsigned int x4 : 4;
int x5 : 5;
long long x6 : 63;
enum E x7: 2;
_Bool x8 : 1;
struct { int x9:4; };
};
static long long getX1(struct S* s) { return s->x1; }
static enum B2 getX2(struct S* s) { return s->x2; }
static unsigned short getX3(struct S* s) { return s->x3; }
static unsigned int getX4(struct S* s) { return s->x4; }
static int getX5(struct S* s) { return s->x5; }
static long long getX6(struct S* s) { return s->x6; }
static enum E getX7(struct S* s) { return s->x7; }
static _Bool getX8(struct S* s) { return s->x8; }
static int getX9(struct S* s) { return s->x9; }
// MODULE: main(cinterop)
// FILE: main.kt
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
import bitfields.*
@@ -2,11 +2,92 @@
* Copyright 2010-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
// MODULE: cinterop
// FILE: ccallbacksAndVarargs.def
---
#include <stdarg.h>
struct S {
int x;
};
static int getX(struct S (*callback)(void)) {
return callback().x;
}
static void applyCallback(struct S s, void (*callback)(struct S)) {
callback(s);
}
static struct S makeS(int x, ...) {
return (struct S){ x };
}
enum E {
ZERO, ONE, TWO
};
static enum E makeE(int ordinal, ...) {
return ordinal;
}
struct Args {
char a1;
char a2;
short a3;
int a4;
long long a5;
float a6;
double a7;
void* a8;
unsigned char a9;
unsigned short a10;
unsigned int a11;
unsigned long long a12;
enum E a13;
struct S a14;
void* a15;
};
static struct Args getVarargs(int ignore, ...) {
va_list args;
va_start(args, ignore);
struct Args result = {
va_arg(args, char),
va_arg(args, char),
va_arg(args, short),
va_arg(args, int),
va_arg(args, long long),
va_arg(args, double),
va_arg(args, double),
va_arg(args, void*),
va_arg(args, unsigned char),
va_arg(args, unsigned short),
va_arg(args, unsigned int),
va_arg(args, unsigned long long),
va_arg(args, enum E),
va_arg(args, struct S),
va_arg(args, void*)
};
va_end(args);
return result;
}
static int sum(int first, int second) {
return first + second;
}
// MODULE: main(cinterop)
// FILE: main.kt
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
import kotlin.test.*
import kotlinx.cinterop.*
import callbacksAndVarargs.*
import ccallbacksAndVarargs.*
fun main() {
testStructCallbacks()
@@ -2,10 +2,20 @@
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
// MODULE: cinterop
// FILE: cenums.def
---
enum E {
A, B, C
};
// MODULE: main(cinterop)
// FILE: main.kt
// !LANGUAGE: +EnumEntries
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
import enums.*
import cenums.*
import kotlinx.cinterop.*
import kotlin.test.*
@@ -1,7 +1,26 @@
// This test mostly checks frontend behaviour.
// MODULE: cinterop
// FILE: cForwardDeclarations.def
---
struct StructDeclared;
struct StructDefined { int x; };
int useStructDeclared(struct StructDeclared* declared) {
return -1;
}
int useStructDefined(struct StructDefined* defined) {
return -2;
}
// MODULE: main(cinterop)
// FILE: main.kt
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
import forwardDeclarations.*
import cForwardDeclarations.*
import cnames.structs.StructDeclared
import kotlin.test.assertEquals
@@ -0,0 +1,149 @@
// OUTPUT_DATA_FILE: funptr.out
/*
* Copyright 2010-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
// MODULE: cinterop
// FILE: cfunptr.def
headerFilter = NOTHING
---
#include <stdio.h>
#include <stdlib.h>
typedef int (*atoiPtrType)(const char*);
static atoiPtrType getAtoiPtr() {
return &atoi;
}
static void __printInt(int x) {
printf("%d\n", x);
}
static void* __getPrintIntPtr() {
return &__printInt;
}
typedef void* (*getPrintIntPtrPtrType)(void);
static getPrintIntPtrPtrType getGetPrintIntPtrPtr() {
return &__getPrintIntPtr;
}
static double __add(double x, double y) {
return x + y;
}
typedef double (*addPtrType)(double, double);
static addPtrType getAddPtr() {
return &__add;
}
static int __doubleToInt(double x) {
return (int) x;
}
typedef int (*doubleToIntPtrType)(double);
static doubleToIntPtrType getDoubleToIntPtr() {
return &__doubleToInt;
}
static _Bool __isIntPositive(int x) {
return x > 0;
}
typedef _Bool (*isIntPositivePtrType)(int);
static isIntPositivePtrType getIsIntPositivePtr() {
return &__isIntPositive;
}
static unsigned int getMaxUInt(void) {
return 0xffffffff;
}
static typeof(&getMaxUInt) getMaxUIntGetter() {
return &getMaxUInt;
}
typedef int (*longSignatureFunctionPtrType)(
int, int, int, int, int, int, int, int, int, int, int, int,
int, int, int, int, int, int, int, int, int, int, int
);
typedef int (*notSoLongSignatureFunctionPtrType)(
int, int, int, int, int, int, int, int, int, int, int,
int, int, int, int, int, int, int, int, int, int, int
);
static int longSignatureFunction(
int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10, int p11, int p12,
int p13, int p14, int p15, int p16, int p17, int p18, int p19, int p20, int p21, int p22, int p23
) {
return 42;
}
static int notSoLongSignatureFunction(
int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10, int p11, int p12,
int p13, int p14, int p15, int p16, int p17, int p18, int p19, int p20, int p21, int p22
) {
return 42;
}
static longSignatureFunctionPtrType getLongSignatureFunctionPtr() {
return &longSignatureFunction;
}
static notSoLongSignatureFunctionPtrType getNotSoLongSignatureFunctionPtr() {
return &notSoLongSignatureFunction;
}
// MODULE: main(cinterop)
// FILE: main.kt
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
import kotlinx.cinterop.*
import cfunptr.*
import kotlin.test.*
typealias NotSoLongSignatureFunction = (
Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int,
Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int
) -> Int
fun main(args: Array<String>) {
val atoiPtr = getAtoiPtr()!!
val getPrintIntPtrPtr = getGetPrintIntPtrPtr()!!
val printIntPtr = getPrintIntPtrPtr()!!.reinterpret<CFunction<(Int) -> Unit>>()
val fortyTwo = memScoped {
atoiPtr("42".cstr.getPointer(memScope))
}
printIntPtr(fortyTwo)
printIntPtr(
getDoubleToIntPtr()!!(
getAddPtr()!!(5.1, 12.2)
)
)
val isIntPositivePtr = getIsIntPositivePtr()!!
printIntPtr(isIntPositivePtr(42).ifThenOneElseZero())
printIntPtr(isIntPositivePtr(-42).ifThenOneElseZero())
assertEquals(getMaxUIntGetter()!!(), UInt.MAX_VALUE)
val longSignaturePtr: COpaquePointer? = getLongSignatureFunctionPtr()
val notSoLongSignaturePtr: CPointer<CFunction<NotSoLongSignatureFunction>>? = getNotSoLongSignatureFunctionPtr()
printIntPtr(notSoLongSignaturePtr!!.invoke(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
printIntPtr(notSoLongSignatureFunction(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
}
fun Boolean.ifThenOneElseZero() = if (this) 1 else 0
@@ -2,10 +2,50 @@
* Copyright 2010-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
// MODULE: cinterop
// FILE: cglobals.def
---
const int g1 = 42;
int g2 = 17;
struct S {
int x;
} g3 = { 128 };
int g4[2] = { 13, 14 };
int g5[2][2] = { 15, 16, 17, 18 };
struct S* const g6 = &g3;
void foo() {
// Test that local vars are not treated as global ones.
float g1;
}
// Test non-compilable variable:
typedef int MyInt;
MyInt g7;
#define g7 bad macro
// Test property name mangling:
struct g1 {};
struct g1_ {};
typedef void* voidptr;
_Pragma("clang assume_nonnull begin")
const voidptr g8 = 0x1, g9 = 0x2;
_Pragma("clang assume_nonnull end")
// MODULE: main(cinterop)
// FILE: main.kt
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class, kotlin.experimental.ExperimentalNativeApi::class)
import kotlinx.cinterop.*
import globals.*
import cglobals.*
fun main(args: Array<String>) {
assert(g1__ == 42)
@@ -0,0 +1,122 @@
// FREE_CINTEROP_ARGS: -header library.h
// MODULE: cinterop
// FILE: library.def
# The def file is intentionally empty
# `library.h` is meant to be included via `-header` option of cinterop tool
// FILE: library.h
#ifdef __cplusplus
extern "C" {
#endif
// Forward declaration.
struct S;
extern struct S s;
const char* getContent(struct S* s);
void setContent(struct S* s, const char* name);
union U;
extern union U u;
double getDouble(union U* u);
void setDouble(union U* u, double value);
// Global array of unknown size.
extern char array[];
int arrayLength();
void setArrayValue(char* array, char value);
#ifdef __cplusplus
}
#endif
// FILE: library.cpp
#include <string>
#include "library.h"
extern "C" {
struct S {
std::string name;
};
S s = {
.name = "initial"
};
void setContent(struct S* s, const char* name) {
// Note that copy here is intentional: we use it as a workaround
// for short lifetime of copy of the passed Kotlin string.
s->name = name;
}
const char* getContent(struct S* s) {
return s->name.c_str();
}
union U {
float f;
double d;
};
void setDouble(union U* u, double value) {
u->d = value;
}
double getDouble(union U* u) {
return u->d;
}
union U u = {
.d = 0.0
};
char array[5] = { 0, 0, 0, 0, 0 };
void setArrayValue(char* array, char value) {
for (int i = 0; i < 5; ++i) {
array[i] = value;
}
}
int arrayLength() {
return sizeof(array) / sizeof(char);
}
}
// MODULE: main(cinterop)
// FILE: main.kt
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
import library.*
import kotlinx.cinterop.*
import kotlin.test.*
fun main() {
assertNotNull(s.ptr)
assertNotNull(u.ptr)
assertNotNull(array)
assertEquals("initial", getContent(s.ptr)?.toKString())
setContent(s.ptr, "yo")
val ptr = getContent(s.ptr)
assertEquals("yo", ptr?.toKString())
assertEquals(0.0, getDouble(u.ptr))
setDouble(u.ptr, Double.MIN_VALUE)
assertEquals(Double.MIN_VALUE, getDouble(u.ptr))
for (i in 0 until arrayLength()) {
assertEquals(0x0, array[i])
}
setArrayValue(array, 0x1)
for (i in 0 until arrayLength()) {
assertEquals(0x1, array[i])
}
}
@@ -0,0 +1,20 @@
// MODULE: cinterop
// FILE: kt43265.def
strictEnums = bcm2835FunctionSelect
---
enum bcm2835FunctionSelect {
BCM2835_GPIO_FSEL_INPT = 0x00, BCM2835_GPIO_FSEL_OUTP = 0x01, BCM2835_GPIO_FSEL_ALT0 = 0x04, BCM2835_GPIO_FSEL_ALT1 = 0x05,
BCM2835_GPIO_FSEL_ALT2 = 0x06, BCM2835_GPIO_FSEL_ALT3 = 0x07, BCM2835_GPIO_FSEL_ALT4 = 0x03, BCM2835_GPIO_FSEL_ALT5 = 0x02,
BCM2835_GPIO_FSEL_MASK = 0x07
};
// MODULE: main(cinterop)
// FILE: main.kt
import kt43265.*
import kotlin.test.*
@kotlinx.cinterop.ExperimentalForeignApi
fun main() {
assertEquals(bcm2835FunctionSelect.BCM2835_GPIO_FSEL_ALT3, bcm2835FunctionSelect.BCM2835_GPIO_FSEL_MASK)
}
@@ -1,3 +1,34 @@
// MODULE: cinterop
// FILE: kt44283.def
---
#include <stdlib.h>
#include <pthread.h>
typedef struct {
int d;
} TestStruct;
typedef struct {
void (*f)(TestStruct data);
} ThreadData;
void *dispatch(void *rawArg) {
ThreadData *arg = rawArg;
arg->f((TestStruct) {.d = 1});
return NULL;
}
void invokeFromThread(void (*f)(TestStruct data)) {
pthread_t thread_id;
ThreadData *threadData = malloc(sizeof(ThreadData));
threadData->f = f;
pthread_create(&thread_id, NULL, dispatch, (void *) threadData);
pthread_join(thread_id, NULL);
}
// MODULE: main(cinterop)
// FILE: main.kt
@file:OptIn(kotlin.native.runtime.NativeRuntimeApi::class)
import kotlinx.cinterop.*
@@ -1,3 +1,17 @@
// MODULE: cinterop
// FILE: kt54284.def
---
#define KFILE "FILE:" __FILE__
#define KLINE "LINE:" __LINE__
#define KTIME "TIME:" __TIME__
#define KDATE "DATE:" __DATE__
#define KFILENAME "NAME:" __FILE_NAME__
#define KBASEFILE "BASE:" __BASE_FILE__
// MODULE: main(cinterop)
// FILE: main.kt
import kotlinx.cinterop.*
import kt54284.*
import kotlin.test.*
@@ -1,3 +1,17 @@
// MODULE: cinterop
// FILE: kt54284_fmodules.def
compilerOpts = -fmodules
---
#define KFILE "FILE:" __FILE__
#define KLINE "LINE:" __LINE__
#define KTIME "TIME:" __TIME__
#define KDATE "DATE:" __DATE__
#define KFILENAME "NAME:" __FILE_NAME__
#define KBASEFILE "BASE:" __BASE_FILE__
// MODULE: main(cinterop)
// FILE: main.kt
import kotlinx.cinterop.*
import kt54284_fmodules.*
import kotlin.test.*
@@ -1,3 +1,29 @@
// MODULE: cinterop
// FILE: kt63048.def
language = Objective-C
headers = kt63048.h
// FILE: kt63048.h
#import "Foundation/NSString.h"
#import "Foundation/NSObject.h"
@interface WithClassProperty : NSObject
-(instancetype) init;
@property (class, readonly, copy) NSString * stringProperty;
@end
// FILE: kt63048.m
#import "kt63048.h"
@implementation WithClassProperty : NSObject
-(instancetype) init {}
+ (NSString *) stringProperty { return @"153"; }
@end
// MODULE: main(cinterop)
// FILE: main.kt
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class, kotlin.experimental.ExperimentalObjCName::class)
import kt63048.*
@@ -1,3 +1,40 @@
// MODULE: cinterop
// FILE: leakMemoryWithRunningThreadUnchecked.def
package leakMemoryWithRunningThreadUnchecked
---
void test_RunInNewThread(void (*)());
// FILE: leakMemoryWithRunningThreadUnchecked.h
#ifdef __cplusplus
extern "C" {
#endif
void test_RunInNewThread(void (*)());
#ifdef __cplusplus
}
#endif
// FILE: leakMemoryWithRunningThreadUnchecked.cpp
#include "leakMemoryWithRunningThreadUnchecked.h"
#include <atomic>
#include <thread>
extern "C" void test_RunInNewThread(void (*f)()) {
std::atomic<bool> haveRun(false);
std::thread t([f, &haveRun]() {
f();
haveRun = true;
while (true) {}
});
t.detach();
while (!haveRun) {}
}
// MODULE: main(cinterop)
// FILE: main.kt
@file:OptIn(
kotlin.experimental.ExperimentalNativeApi::class,
kotlin.native.runtime.NativeRuntimeApi::class,
@@ -1,3 +1,15 @@
// MODULE: cinterop
// FILE: toKString.def
---
const char* empty() { return ""; }
const char* foo() { return "foo"; }
const char* kuku() { return "куку"; }
const char* invalid_utf8() { return "\x85\xAF"; }
const char* zero_in_the_middle() { return "before zero\0after zero"; }
// MODULE: main(cinterop)
// FILE: main.kt
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
import toKString.*
@@ -1,128 +0,0 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.test.blackbox;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateNativeTestsKt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("native/native.tests/testData/CInterop/executable")
@TestDataPath("$PROJECT_ROOT")
public class ClassicNativeCInteropExecutableTest extends AbstractNativeCInteropExecutableTest {
@Test
public void testAllFilesPresentInExecutable() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/CInterop/executable"), Pattern.compile("^([^_](.+))$"), null, false);
}
@Test
@TestMetadata("arrayPointers")
public void testArrayPointers() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/arrayPointers/");
}
@Test
@TestMetadata("auxiliarySources")
public void testAuxiliarySources() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/auxiliarySources/");
}
@Test
@TestMetadata("bitfields")
public void testBitfields() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/bitfields/");
}
@Test
@TestMetadata("callbacksAndVarargs")
public void testCallbacksAndVarargs() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/callbacksAndVarargs/");
}
@Test
@TestMetadata("enums")
public void testEnums() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/enums/");
}
@Test
@TestMetadata("forwardDeclarations")
public void testForwardDeclarations() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/forwardDeclarations/");
}
@Test
@TestMetadata("funptr")
public void testFunptr() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/funptr/");
}
@Test
@TestMetadata("globals")
public void testGlobals() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/globals/");
}
@Test
@TestMetadata("incompleteTypes")
public void testIncompleteTypes() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/incompleteTypes/");
}
@Test
@TestMetadata("kt43265")
public void testKt43265() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/kt43265/");
}
@Test
@TestMetadata("kt44283")
public void testKt44283() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/kt44283/");
}
@Test
@TestMetadata("kt54284")
public void testKt54284() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/kt54284/");
}
@Test
@TestMetadata("kt54284_fmodules")
public void testKt54284_fmodules() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/kt54284_fmodules/");
}
@Test
@TestMetadata("kt63048")
public void testKt63048() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/kt63048/");
}
@Test
@TestMetadata("leakMemoryWithRunningThreadUnchecked")
public void testLeakMemoryWithRunningThreadUnchecked() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/leakMemoryWithRunningThreadUnchecked/");
}
@Test
@TestMetadata("objcInstancetype")
public void testObjcInstancetype() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/objcInstancetype/");
}
@Test
@TestMetadata("toKString")
public void testToKString() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/toKString/");
}
}
@@ -1,132 +0,0 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.test.blackbox;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.junit.jupiter.api.Tag;
import org.jetbrains.kotlin.konan.test.blackbox.support.group.FirPipeline;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateNativeTestsKt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("native/native.tests/testData/CInterop/executable")
@TestDataPath("$PROJECT_ROOT")
@Tag("frontend-fir")
@FirPipeline()
public class FirNativeCInteropExecutableTest extends AbstractNativeCInteropExecutableTest {
@Test
public void testAllFilesPresentInExecutable() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/CInterop/executable"), Pattern.compile("^([^_](.+))$"), null, false);
}
@Test
@TestMetadata("arrayPointers")
public void testArrayPointers() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/arrayPointers/");
}
@Test
@TestMetadata("auxiliarySources")
public void testAuxiliarySources() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/auxiliarySources/");
}
@Test
@TestMetadata("bitfields")
public void testBitfields() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/bitfields/");
}
@Test
@TestMetadata("callbacksAndVarargs")
public void testCallbacksAndVarargs() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/callbacksAndVarargs/");
}
@Test
@TestMetadata("enums")
public void testEnums() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/enums/");
}
@Test
@TestMetadata("forwardDeclarations")
public void testForwardDeclarations() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/forwardDeclarations/");
}
@Test
@TestMetadata("funptr")
public void testFunptr() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/funptr/");
}
@Test
@TestMetadata("globals")
public void testGlobals() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/globals/");
}
@Test
@TestMetadata("incompleteTypes")
public void testIncompleteTypes() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/incompleteTypes/");
}
@Test
@TestMetadata("kt43265")
public void testKt43265() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/kt43265/");
}
@Test
@TestMetadata("kt44283")
public void testKt44283() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/kt44283/");
}
@Test
@TestMetadata("kt54284")
public void testKt54284() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/kt54284/");
}
@Test
@TestMetadata("kt54284_fmodules")
public void testKt54284_fmodules() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/kt54284_fmodules/");
}
@Test
@TestMetadata("kt63048")
public void testKt63048() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/kt63048/");
}
@Test
@TestMetadata("leakMemoryWithRunningThreadUnchecked")
public void testLeakMemoryWithRunningThreadUnchecked() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/leakMemoryWithRunningThreadUnchecked/");
}
@Test
@TestMetadata("objcInstancetype")
public void testObjcInstancetype() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/objcInstancetype/");
}
@Test
@TestMetadata("toKString")
public void testToKString() throws Exception {
runTest("native/native.tests/testData/CInterop/executable/toKString/");
}
}
@@ -34,6 +34,117 @@ public class FirNativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/standalone"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Nested
@TestMetadata("native/native.tests/testData/standalone/cinterop")
@TestDataPath("$PROJECT_ROOT")
@Tag("standalone")
@EnforcedProperty(property = ClassLevelProperty.TEST_KIND, propertyValue = "STANDALONE_NO_TR")
@UseStandardTestCaseGroupProvider()
@Tag("frontend-fir")
@FirPipeline()
public class Cinterop {
@Test
public void testAllFilesPresentInCinterop() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/standalone/cinterop"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("arrayPointers.kt")
public void testArrayPointers() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/arrayPointers.kt");
}
@Test
@TestMetadata("auxiliarySources.kt")
public void testAuxiliarySources() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/auxiliarySources.kt");
}
@Test
@TestMetadata("bitfields.kt")
public void testBitfields() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/bitfields.kt");
}
@Test
@TestMetadata("callbacksAndVarargs.kt")
public void testCallbacksAndVarargs() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/callbacksAndVarargs.kt");
}
@Test
@TestMetadata("enums.kt")
public void testEnums() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/enums.kt");
}
@Test
@TestMetadata("forwardDeclarations.kt")
public void testForwardDeclarations() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/forwardDeclarations.kt");
}
@Test
@TestMetadata("funptr.kt")
public void testFunptr() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/funptr.kt");
}
@Test
@TestMetadata("globals.kt")
public void testGlobals() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/globals.kt");
}
@Test
@TestMetadata("incompleteTypes.kt")
public void testIncompleteTypes() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/incompleteTypes.kt");
}
@Test
@TestMetadata("kt43265.kt")
public void testKt43265() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/kt43265.kt");
}
@Test
@TestMetadata("kt44283.kt")
public void testKt44283() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/kt44283.kt");
}
@Test
@TestMetadata("kt54284.kt")
public void testKt54284() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/kt54284.kt");
}
@Test
@TestMetadata("kt54284_fmodules.kt")
public void testKt54284_fmodules() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/kt54284_fmodules.kt");
}
@Test
@TestMetadata("kt63048.kt")
public void testKt63048() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/kt63048.kt");
}
@Test
@TestMetadata("leakMemoryWithRunningThreadUnchecked.kt")
public void testLeakMemoryWithRunningThreadUnchecked() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/leakMemoryWithRunningThreadUnchecked.kt");
}
@Test
@TestMetadata("toKString.kt")
public void testToKString() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/toKString.kt");
}
}
@Nested
@TestMetadata("native/native.tests/testData/standalone/console")
@TestDataPath("$PROJECT_ROOT")
@@ -31,6 +31,115 @@ public class NativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/standalone"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Nested
@TestMetadata("native/native.tests/testData/standalone/cinterop")
@TestDataPath("$PROJECT_ROOT")
@Tag("standalone")
@EnforcedProperty(property = ClassLevelProperty.TEST_KIND, propertyValue = "STANDALONE_NO_TR")
@UseStandardTestCaseGroupProvider()
public class Cinterop {
@Test
public void testAllFilesPresentInCinterop() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/standalone/cinterop"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("arrayPointers.kt")
public void testArrayPointers() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/arrayPointers.kt");
}
@Test
@TestMetadata("auxiliarySources.kt")
public void testAuxiliarySources() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/auxiliarySources.kt");
}
@Test
@TestMetadata("bitfields.kt")
public void testBitfields() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/bitfields.kt");
}
@Test
@TestMetadata("callbacksAndVarargs.kt")
public void testCallbacksAndVarargs() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/callbacksAndVarargs.kt");
}
@Test
@TestMetadata("enums.kt")
public void testEnums() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/enums.kt");
}
@Test
@TestMetadata("forwardDeclarations.kt")
public void testForwardDeclarations() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/forwardDeclarations.kt");
}
@Test
@TestMetadata("funptr.kt")
public void testFunptr() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/funptr.kt");
}
@Test
@TestMetadata("globals.kt")
public void testGlobals() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/globals.kt");
}
@Test
@TestMetadata("incompleteTypes.kt")
public void testIncompleteTypes() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/incompleteTypes.kt");
}
@Test
@TestMetadata("kt43265.kt")
public void testKt43265() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/kt43265.kt");
}
@Test
@TestMetadata("kt44283.kt")
public void testKt44283() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/kt44283.kt");
}
@Test
@TestMetadata("kt54284.kt")
public void testKt54284() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/kt54284.kt");
}
@Test
@TestMetadata("kt54284_fmodules.kt")
public void testKt54284_fmodules() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/kt54284_fmodules.kt");
}
@Test
@TestMetadata("kt63048.kt")
public void testKt63048() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/kt63048.kt");
}
@Test
@TestMetadata("leakMemoryWithRunningThreadUnchecked.kt")
public void testLeakMemoryWithRunningThreadUnchecked() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/leakMemoryWithRunningThreadUnchecked.kt");
}
@Test
@TestMetadata("toKString.kt")
public void testToKString() throws Exception {
runTest("native/native.tests/testData/standalone/cinterop/toKString.kt");
}
}
@Nested
@TestMetadata("native/native.tests/testData/standalone/console")
@TestDataPath("$PROJECT_ROOT")
@@ -208,20 +208,6 @@ fun main() {
) {
model("CInterop/experimental/cases", pattern = "^([^_](.+))$", recursive = false)
}
testClass<AbstractNativeCInteropExecutableTest>(
suiteTestClassName = "ClassicNativeCInteropExecutableTest",
) {
model("CInterop/executable", pattern = "^([^_](.+))$", recursive = false)
}
testClass<AbstractNativeCInteropExecutableTest>(
suiteTestClassName = "FirNativeCInteropExecutableTest",
annotations = listOf(
*frontendFir()
),
) {
model("CInterop/executable", pattern = "^([^_](.+))$", recursive = false)
}
}
// ObjCExport tests.
@@ -1,70 +0,0 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.konan.test.blackbox
import com.intellij.testFramework.TestDataFile
import org.jetbrains.kotlin.konan.test.blackbox.support.ClassLevelProperty
import org.jetbrains.kotlin.konan.test.blackbox.support.EnforcedProperty
import org.jetbrains.kotlin.konan.test.blackbox.support.TestCase
import org.jetbrains.kotlin.konan.test.blackbox.support.TestCompilerArgs
import org.jetbrains.kotlin.konan.test.blackbox.support.TestKind
import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.TestCompilationResult.Companion.assertSuccess
import org.jetbrains.kotlin.konan.test.blackbox.support.runner.TestExecutable
import org.jetbrains.kotlin.konan.test.blackbox.support.settings.PipelineType
import java.io.File
@EnforcedProperty(ClassLevelProperty.COMPILER_OUTPUT_INTERCEPTOR, "NONE")
abstract class AbstractNativeCInteropExecutableTest : AbstractNativeSimpleTest() {
protected fun runTest(@TestDataFile testDataDir: String) {
val testName = File(testDataDir).name
val defFile = File(testDataDir, "$testName.def")
muteCInteropTestIfNecessary(defFile, targets.testTarget)
val interopSourceFileM = File(testDataDir, "$testName.m")
val interopSourceFileCPP = File(testDataDir, "$testName.cpp")
val interopSourceFile = when {
interopSourceFileM.exists() -> interopSourceFileM
interopSourceFileCPP.exists() -> interopSourceFileCPP
else -> null
}
val ktFile = File(testDataDir, "$testName.kt")
val compilerArgs = buildList {
add("-compiler-option")
add("-I$testDataDir")
val auxHeader = File(testDataDir, "$testName.aux.h")
if (auxHeader.exists()) {
add("-header")
add(auxHeader.absolutePath)
}
interopSourceFile?.let {
add("-Xcompile-source")
add(it.absolutePath)
add("-Xsource-compiler-option")
add("-fobjc-arc")
add("-Xsource-compiler-option")
add("-DNS_FORMAT_ARGUMENT(A)=")
}
}
val library = cinteropToLibrary(
targets = targets,
defFile = defFile,
outputDir = buildDir,
freeCompilerArgs = TestCompilerArgs(compilerArgs)
).assertSuccess().resultingArtifact
val testCase = generateTestCaseWithSingleFile(
sourceFile = ktFile,
freeCompilerArgs = TestCompilerArgs(testRunSettings.get<PipelineType>().compilerFlags),
testKind = TestKind.STANDALONE_NO_TR,
extras = TestCase.NoTestRunnerExtras("main")
)
val compilationResult = compileToExecutable(testCase, library.asLibraryDependency()).assertSuccess()
val testExecutable = TestExecutable.fromCompilationResult(testCase, compilationResult)
runExecutableAndVerify(testCase, testExecutable)
}
}
@@ -37,7 +37,7 @@ abstract class AbstractNativeCInteropKT39120Test : AbstractNativeCInteropBaseTes
val golden1File = testPathFull.resolve("pod1.contents.gold.txt")
val golden2File = testPathFull.resolve("pod2.contents.gold.txt")
val includeFrameworkArgs = TestCompilerArgs("-compiler-option", "-F${testDataDir.canonicalPath}")
val includeFrameworkArgs = TestCInteropArgs("-compiler-option", "-F${testDataDir.canonicalPath}")
val klib1: KLIB = cinteropToLibrary(targets, def1File, buildDir, includeFrameworkArgs).assertSuccess().resultingArtifact
val metadata1 = klib1.dumpMetadata(kotlinNativeClassLoader.classLoader, false, null)
@@ -45,7 +45,7 @@ abstract class AbstractNativeCInteropKT39120Test : AbstractNativeCInteropBaseTes
val actualFiltered1Output = filterContentsOutput(metadata1, " pod.Version|POD|class Pod")
assertEquals(StringUtilRt.convertLineSeparators(expectedFiltered1Output), StringUtilRt.convertLineSeparators(actualFiltered1Output))
val cinterop2ExtraArgs = TestCompilerArgs("-l", klib1.klibFile.canonicalPath, "-compiler-option", "-fmodules")
val cinterop2ExtraArgs = TestCInteropArgs("-l", klib1.klibFile.canonicalPath, "-compiler-option", "-fmodules")
val klib2: KLIB = cinteropToLibrary(targets, def2File, buildDir, includeFrameworkArgs + cinterop2ExtraArgs).assertSuccess().resultingArtifact
val metadata2 = klib2.dumpMetadata(kotlinNativeClassLoader.classLoader, false, null)
@@ -60,7 +60,7 @@ abstract class AbstractNativeCInteropKT39120Test : AbstractNativeCInteropBaseTes
files += TestFile.createCommitted(ktFile, this)
}
val compilationResult = compileToExecutable(
createTestCaseNoTestRun(module, TestCompilerArgs(listOf())),
createTestCaseNoTestRun(module, TestCompilerArgs.EMPTY),
klib1.asLibraryDependency(),
klib2.asLibraryDependency()
)
@@ -9,6 +9,7 @@ import com.intellij.openapi.util.text.StringUtilRt
import com.intellij.testFramework.TestDataFile
import org.jetbrains.kotlin.konan.target.Family
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.test.blackbox.support.TestCInteropArgs
import org.jetbrains.kotlin.konan.test.blackbox.support.TestCompilerArgs
import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.TestCompilationResult
import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.TestCompilationResult.Companion.assertSuccess
@@ -88,11 +89,11 @@ abstract class AbstractNativeCInteropTest : AbstractNativeCInteropBaseTest() {
getBuiltinsGoldenFile(testPathFull)
else
getGoldenFile(testPathFull)
val fmodulesArgs = if (fmodules) TestCompilerArgs("-compiler-option", "-fmodules") else TestCompilerArgs.EMPTY
val fmodulesArgs = if (fmodules) TestCInteropArgs("-compiler-option", "-fmodules") else TestCompilerArgs.EMPTY
val includeArgs = if (testDataDir.name.startsWith("framework"))
TestCompilerArgs("-compiler-option", "-F${testDataDir.canonicalPath}")
TestCInteropArgs("-compiler-option", "-F${testDataDir.canonicalPath}")
else
TestCompilerArgs("-compiler-option", "-I${includeFolder.canonicalPath}")
TestCInteropArgs("-compiler-option", "-I${includeFolder.canonicalPath}")
val testCompilationResult = cinteropToLibrary(targets, defFile, buildDir, includeArgs + fmodulesArgs)
// If we are running fmodules-specific test without -fmodules then we want to be sure that cinterop fails the way we want it to.
@@ -177,7 +177,7 @@ class LinkerOutputTestKT55578 : AbstractNativeLinkerOutputTest() {
private fun compileKlib(defFile: File, sourceFile: File? = null, extraArgs: List<String> = emptyList()): KLIB {
val sourceArguments = sourceFile?.let { listOf("-Xcompile-source", sourceFile.absolutePath) } ?: emptyList()
return cinteropToLibrary(targets, defFile, buildDir, TestCompilerArgs(extraArgs + sourceArguments))
return cinteropToLibrary(targets, defFile, buildDir, TestCInteropArgs(extraArgs + sourceArguments))
.assertSuccess().resultingArtifact
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.konan.test.blackbox.support
import org.jetbrains.kotlin.konan.test.blackbox.support.TestDirectives.ENTRY_POINT
import org.jetbrains.kotlin.konan.test.blackbox.support.TestDirectives.EXIT_CODE
import org.jetbrains.kotlin.konan.test.blackbox.support.TestDirectives.EXPECTED_TIMEOUT_FAILURE
import org.jetbrains.kotlin.konan.test.blackbox.support.TestDirectives.FREE_CINTEROP_ARGS
import org.jetbrains.kotlin.konan.test.blackbox.support.TestDirectives.FREE_COMPILER_ARGS
import org.jetbrains.kotlin.konan.test.blackbox.support.TestDirectives.INPUT_DATA_FILE
import org.jetbrains.kotlin.konan.test.blackbox.support.TestDirectives.KIND
@@ -129,6 +130,10 @@ internal object TestDirectives : SimpleDirectivesContainer() {
description = "Specify free compiler arguments for Kotlin/Native compiler"
)
val FREE_CINTEROP_ARGS by stringDirective(
description = "Specify free CInterop tool arguments"
)
val LLDB_TRACE by stringDirective(
description = """
Specify a filename containing the LLDB commands and the patterns that
@@ -210,15 +215,23 @@ internal enum class MutedOption {
K2
}
internal class TestCompilerArgs(val compilerArgs: List<String>) {
internal class TestCInteropArgs(cinteropArgs: List<String>) : TestCompilerArgs(emptyList(), cinteropArgs) {
constructor(vararg cinteropArgs: String) : this(cinteropArgs.asList())
}
internal open class TestCompilerArgs(val compilerArgs: List<String>, val cinteropArgs: List<String> = emptyList()) {
constructor(vararg compilerArgs: String) : this(compilerArgs.asList())
private val uniqueCompilerArgs = compilerArgs.toSet()
override fun hashCode() = uniqueCompilerArgs.hashCode()
override fun equals(other: Any?) = (other as? TestCompilerArgs)?.uniqueCompilerArgs == uniqueCompilerArgs
private val uniqueCinteropArgs = cinteropArgs.toSet()
override fun hashCode() = (uniqueCompilerArgs + uniqueCinteropArgs).hashCode()
override fun equals(other: Any?) = (other as? TestCompilerArgs)?.uniqueCompilerArgs == uniqueCompilerArgs &&
other.uniqueCinteropArgs == uniqueCinteropArgs
operator fun plus(otherCompilerArgs: TestCompilerArgs): TestCompilerArgs = this + otherCompilerArgs.compilerArgs
operator fun plus(otherCompilerArgs: List<String>): TestCompilerArgs = TestCompilerArgs(compilerArgs + otherCompilerArgs)
operator fun plus(otherCompilerArgs: TestCompilerArgs): TestCompilerArgs = TestCompilerArgs(
this.compilerArgs + otherCompilerArgs.compilerArgs,
this.cinteropArgs + otherCompilerArgs.cinteropArgs
)
companion object {
val EMPTY = TestCompilerArgs(emptyList())
@@ -330,9 +343,15 @@ internal fun parseFileName(parsedDirective: RegisteredDirectivesParser.ParsedDir
""".trimIndent()
}
assertTrue(fileName.endsWith(".kt") && fileName.length > 3 && '/' !in fileName && '\\' !in fileName) {
"$location: Invalid file name in ${parsedDirective.directive} directive: $fileName"
}
val fileExtension = fileName.split(".").last()
if (fileExtension in setOf("kt", "def", "h", "c", "cpp", "m"))
assertTrue(fileName.length > 3 && '/' !in fileName && '\\' !in fileName) {
"$location: Invalid file name with extension $fileExtension in ${parsedDirective.directive} directive: $fileName"
}
else
assertTrue(false) {
"$location: Invalid file extension .$fileExtension in ${parsedDirective.directive} directive: $fileName"
}
return fileName
}
@@ -356,19 +375,18 @@ internal fun parseExpectedExitCode(registeredDirectives: RegisteredDirectives, l
}
internal fun parseFreeCompilerArgs(registeredDirectives: RegisteredDirectives, location: Location): TestCompilerArgs {
if (FREE_COMPILER_ARGS !in registeredDirectives)
return TestCompilerArgs.EMPTY
val freeCInteropArgs = registeredDirectives[FREE_CINTEROP_ARGS]
val freeCompilerArgs = registeredDirectives[FREE_COMPILER_ARGS]
val forbiddenCompilerArgs = TestCompilerArgs.findForbiddenArgs(freeCompilerArgs)
assertTrue(forbiddenCompilerArgs.isEmpty()) {
"""
if (freeCompilerArgs.isNotEmpty()) {
val forbiddenCompilerArgs = TestCompilerArgs.findForbiddenArgs(freeCompilerArgs)
assertTrue(forbiddenCompilerArgs.isEmpty()) {
"""
$location: Forbidden compiler arguments found in $FREE_COMPILER_ARGS directive: $forbiddenCompilerArgs
All arguments: $freeCompilerArgs
""".trimIndent()
}
}
return TestCompilerArgs(freeCompilerArgs)
return TestCompilerArgs(freeCompilerArgs, freeCInteropArgs)
}
internal fun parseOutputDataFile(baseDir: File, registeredDirectives: RegisteredDirectives, location: Location): OutputDataFile? =
@@ -273,11 +273,25 @@ internal class CInteropCompilation(
classLoader: KotlinNativeClassLoader,
freeCompilerArgs: TestCompilerArgs,
defFile: File,
sources: List<File> = emptyList(),
expectedArtifact: KLIB
) : TestCompilation<KLIB>() {
override val result: TestCompilationResult<out KLIB> by lazy {
val extraArgsArray = freeCompilerArgs.compilerArgs.toTypedArray()
val extraArgsArray = buildList {
addAll(freeCompilerArgs.cinteropArgs)
sources.forEach {
add("-Xcompile-source")
add(it.absolutePath)
}
add("-Xsource-compiler-option")
add("-fobjc-arc")
add("-Xsource-compiler-option")
add("-DNS_FORMAT_ARGUMENT(A)=")
add("-compiler-option")
add("-I${defFile.parentFile}")
}.toTypedArray()
val loggedCInteropParameters = LoggedData.CInteropParameters(extraArgs = extraArgsArray, defFile = defFile)
val (loggedCall: LoggedData, immediateResult: TestCompilationResult.ImmediateResult<out KLIB>) = try {
val (exitCode, cinteropOutput, cinteropOutputHasErrors, duration) = invokeCInterop(
@@ -429,7 +443,8 @@ internal class StaticCacheCompilation(
private val options: Options,
private val pipelineType: PipelineType,
dependencies: Iterable<TestCompilationDependency<*>>,
expectedArtifact: KLIBStaticCache
expectedArtifact: KLIBStaticCache,
makePerFileCacheOverride: Boolean? = null,
) : BasicCompilation<KLIBStaticCache>(
targets = settings.get(),
home = settings.get(),
@@ -454,7 +469,7 @@ internal class StaticCacheCompilation(
cacheMode.staticCacheForDistributionLibrariesRootDir ?: fail { "No cache root directory found for cache mode $cacheMode" }
}
private val makePerFileCache: Boolean = settings.get<CacheMode>().makePerFileCaches
private val makePerFileCache: Boolean = makePerFileCacheOverride ?: settings.get<CacheMode>().makePerFileCaches
private val partialLinkageConfig: UsedPartialLinkageConfig = settings.get()
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.konan.test.blackbox.support.compilation
import org.jetbrains.kotlin.container.topologicalSort
import org.jetbrains.kotlin.konan.test.blackbox.muteCInteropTestIfNecessary
import org.jetbrains.kotlin.konan.test.blackbox.support.PackageName
import org.jetbrains.kotlin.konan.test.blackbox.support.TestCase
import org.jetbrains.kotlin.konan.test.blackbox.support.TestCase.*
@@ -196,16 +197,41 @@ internal class TestCompilationFactory {
}
return cachedKlibCompilations.computeIfAbsent(cacheKey) {
val klibCompilation = if (isGivenKlibArtifact)
GivenLibraryCompilation(klibArtifact)
else
LibraryCompilation(
settings = settings,
freeCompilerArgs = freeCompilerArgs,
sourceModules = sourceModules.flatMapToSet { sortDependsOnTopologically(it) },
dependencies = dependencies.forKlib(),
expectedArtifact = klibArtifact
)
val (klibCompilation, makePerFileCacheOverride) = if (isGivenKlibArtifact)
GivenLibraryCompilation(klibArtifact) to null
else {
val filesByExtension = sourceModules.first().files
.map { it.location }
.groupBy { it.name.split(".").last() }
when {
filesByExtension.contains("kt") -> LibraryCompilation(
settings = settings,
freeCompilerArgs = freeCompilerArgs,
sourceModules = sourceModules.flatMapToSet { sortDependsOnTopologically(it) },
dependencies = dependencies.forKlib(),
expectedArtifact = klibArtifact
) to null
filesByExtension.contains("def") -> {
val defFile = filesByExtension["def"]!!.single()
muteCInteropTestIfNecessary(defFile, settings.get<KotlinNativeTargets>().testTarget)
val cSourceFiles = buildList {
for (ext in listOf("cpp", "c", "m")) {
filesByExtension[ext]?.let { addAll(it) }
}
}
CInteropCompilation(
classLoader = settings.get(),
targets = settings.get(),
freeCompilerArgs = freeCompilerArgs,
defFile = defFile,
sources = cSourceFiles,
expectedArtifact = klibArtifact
) to false // CInterop klib cannot be compiled into per-file cache
}
else -> error("Test module must contain either KT or DEF file")
}
}
val staticCacheCompilation: StaticCacheCompilation? =
staticCacheArtifactAndOptions?.let { (staticCacheArtifact, staticCacheOptions) ->
@@ -215,7 +241,8 @@ internal class TestCompilationFactory {
options = staticCacheOptions,
pipelineType = settings.get(),
dependencies = dependencies.forStaticCache(klibCompilation.asKlibDependency(type = /* does not matter in fact*/ Library)),
expectedArtifact = staticCacheArtifact
expectedArtifact = staticCacheArtifact,
makePerFileCacheOverride = makePerFileCacheOverride,
)
}