Skip to content

Commit df418b0

Browse files
committed
add codegen tests
1 parent e087327 commit df418b0

File tree

2 files changed

+254
-1
lines changed

2 files changed

+254
-1
lines changed

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ extension JNISwift2JavaGenerator {
378378
guard let genericArgs = nominalType.genericArguments, genericArgs.count == 1 else {
379379
throw JavaTranslationError.unsupportedSwiftType(swiftResult.type)
380380
}
381-
return try translateOptionalResult(wrappedType: swiftResult.type)
381+
return try translateOptionalResult(wrappedType: genericArgs[0])
382382

383383
default:
384384
guard let javaType = JNIJavaTypeTranslator.translate(knownType: knownType, config: self.config), javaType.implementsJavaValue else {
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import JExtractSwiftLib
16+
import Testing
17+
18+
@Suite
19+
struct JNIOptionalTests {
20+
let source =
21+
"""
22+
class MyClass { }
23+
24+
public func optionalSugar(_ arg: Int64?) -> Int32?
25+
public func optionalExplicit(_ arg: Optional<String>) -> Optional<String>
26+
public func optionalClass(_ arg: MyClass?) -> MyClass?
27+
public func optionalJavaKitClass(_ arg: JavaLong?)
28+
"""
29+
30+
let classLookupTable = [
31+
"JavaLong": "java.lang.Long",
32+
]
33+
34+
@Test
35+
func optionalSugar_javaBindings() throws {
36+
try assertOutput(
37+
input: source,
38+
.jni,
39+
.java,
40+
javaClassLookupTable: classLookupTable,
41+
expectedChunks: [
42+
"""
43+
/**
44+
* Downcall to Swift:
45+
* {@snippet lang=swift :
46+
* public func optionalSugar(_ arg: Int64?) -> Int32?
47+
* }
48+
*/
49+
public static OptionalInt optionalSugar(OptionalLong arg) {
50+
long combined$ = SwiftModule.$optionalSugar((byte) (arg.isPresent() ? 1 : 0), arg.orElse(0L));
51+
byte discriminator$ = (byte) (combined$ & 0xFF);
52+
int value$ = (int) (combined$ >> 32);
53+
return discriminator$ == 1 ? OptionalInt.of(value$) : OptionalInt.empty();
54+
}
55+
""",
56+
"""
57+
private static native long $optionalSugar(byte arg_discriminator, long arg_value);
58+
"""
59+
]
60+
)
61+
}
62+
63+
@Test
64+
func optionalSugar_swiftThunks() throws {
65+
try assertOutput(
66+
input: source,
67+
.jni,
68+
.swift,
69+
detectChunkByInitialLines: 1,
70+
javaClassLookupTable: classLookupTable,
71+
expectedChunks: [
72+
"""
73+
@_cdecl("Java_com_example_swift_SwiftModule__00024optionalSugar__BJ")
74+
func Java_com_example_swift_SwiftModule__00024optionalSugar__BJ(environment: UnsafeMutablePointer<JNIEnv?>!, thisClass: jclass, arg_discriminator: jbyte, arg_value: jlong) -> jlong {
75+
let value$ = SwiftModule.optionalSugar(arg_discriminator == 1 ? Int64(fromJNI: arg_value, in: environment!) : nil).map {
76+
Int64($0) << 32 | Int64(1)
77+
} ?? 0
78+
return value$.getJNIValue(in: environment!)
79+
}
80+
"""
81+
]
82+
)
83+
}
84+
85+
@Test
86+
func optionalExplicit_javaBindings() throws {
87+
try assertOutput(
88+
input: source,
89+
.jni,
90+
.java,
91+
javaClassLookupTable: classLookupTable,
92+
expectedChunks: [
93+
"""
94+
/**
95+
* Downcall to Swift:
96+
* {@snippet lang=swift :
97+
* public func optionalExplicit(_ arg: Optional<String>) -> Optional<String>
98+
* }
99+
*/
100+
public static Optional<String> optionalExplicit(Optional<String> arg) {
101+
byte[] result_discriminator$ = new byte[1];
102+
java.lang.String result$ = SwiftModule.$optionalExplicit((byte) (arg.isPresent() ? 1 : 0), arg.orElse(null), result_discriminator$);
103+
return (result_discriminator$[0] == 1) ? Optional.of(result$) : Optional.empty();
104+
}
105+
""",
106+
"""
107+
private static native java.lang.String $optionalExplicit(byte arg_discriminator, java.lang.String arg_value, byte[] result_discriminator$);
108+
"""
109+
]
110+
)
111+
}
112+
113+
@Test
114+
func optionalExplicit_swiftThunks() throws {
115+
try assertOutput(
116+
input: source,
117+
.jni,
118+
.swift,
119+
detectChunkByInitialLines: 1,
120+
javaClassLookupTable: classLookupTable,
121+
expectedChunks: [
122+
"""
123+
@_cdecl("Java_com_example_swift_SwiftModule__00024optionalExplicit__BLjava_lang_String_2_3B")
124+
func Java_com_example_swift_SwiftModule__00024optionalExplicit__BLjava_lang_String_2_3B(environment: UnsafeMutablePointer<JNIEnv?>!, thisClass: jclass, arg_discriminator: jbyte, arg_value: jstring?, result_discriminator$: jbyteArray?) -> jstring? {
125+
let result$: jstring?
126+
if let innerResult$ = SwiftModule.optionalExplicit(arg_discriminator == 1 ? String(fromJNI: arg_value, in: environment!) : nil) {
127+
result$ = innerResult$.getJNIValue(in: environment!)
128+
var flag$ = Int8(1)
129+
environment.interface.SetByteArrayRegion(environment, result_discriminator$, 0, 1, &flag$)
130+
} // render(_:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+NativeTranslation.swift:624
131+
else {
132+
result$ = String.jniPlaceholderValue
133+
var flag$ = Int8(0)
134+
environment.interface.SetByteArrayRegion(environment, result_discriminator$, 0, 1, &flag$)
135+
} // render(_:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+NativeTranslation.swift:634
136+
return result$
137+
}
138+
"""
139+
]
140+
)
141+
}
142+
143+
@Test
144+
func optionalClass_javaBindings() throws {
145+
try assertOutput(
146+
input: source,
147+
.jni,
148+
.java,
149+
javaClassLookupTable: classLookupTable,
150+
expectedChunks: [
151+
"""
152+
/**
153+
* Downcall to Swift:
154+
* {@snippet lang=swift :
155+
* public func optionalClass(_ arg: MyClass?) -> MyClass?
156+
* }
157+
*/
158+
public static Optional<MyClass> optionalClass(Optional<MyClass> arg, SwiftArena swiftArena$) {
159+
byte[] result_discriminator$ = new byte[1];
160+
long result$ = SwiftModule.$optionalClass(arg.map(MyClass::$memoryAddress).orElse(0L), result_discriminator$);
161+
return (result_discriminator$[0] == 1) ? Optional.of(new MyClass(result$, swiftArena$)) : Optional.empty();
162+
}
163+
""",
164+
"""
165+
private static native long $optionalClass(long arg, byte[] result_discriminator$);
166+
"""
167+
]
168+
)
169+
}
170+
171+
@Test
172+
func optionalClass_swiftThunks() throws {
173+
try assertOutput(
174+
input: source,
175+
.jni,
176+
.swift,
177+
detectChunkByInitialLines: 1,
178+
javaClassLookupTable: classLookupTable,
179+
expectedChunks: [
180+
"""
181+
@_cdecl("Java_com_example_swift_SwiftModule__00024optionalClass__J_3B")
182+
func Java_com_example_swift_SwiftModule__00024optionalClass__J_3B(environment: UnsafeMutablePointer<JNIEnv?>!, thisClass: jclass, arg: jlong, result_discriminator$: jbyteArray?) -> jlong {
183+
let argBits$ = Int(Int64(fromJNI: arg, in: environment!))
184+
let arg$ = UnsafeMutablePointer<MyClass>(bitPattern: argBits$)
185+
let result$: jlong
186+
if let innerResult$ = SwiftModule.optionalClass(arg$?.pointee) {
187+
let _result$ = UnsafeMutablePointer<MyClass>.allocate(capacity: 1)
188+
_result$.initialize(to: innerResult$)
189+
let _resultBits$ = Int64(Int(bitPattern: _result$))
190+
result$ = _resultBits$.getJNIValue(in: environment!)
191+
var flag$ = Int8(1)
192+
environment.interface.SetByteArrayRegion(environment, result_discriminator$, 0, 1, &flag$)
193+
} // render(_:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+NativeTranslation.swift:624
194+
else {
195+
result$ = 0
196+
var flag$ = Int8(0)
197+
environment.interface.SetByteArrayRegion(environment, result_discriminator$, 0, 1, &flag$)
198+
} // render(_:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+NativeTranslation.swift:634
199+
return result$
200+
}
201+
"""
202+
]
203+
)
204+
}
205+
206+
@Test
207+
func optionalJavaKitClass_javaBindings() throws {
208+
try assertOutput(
209+
input: source,
210+
.jni,
211+
.java,
212+
javaClassLookupTable: classLookupTable,
213+
expectedChunks: [
214+
"""
215+
/**
216+
* Downcall to Swift:
217+
* {@snippet lang=swift :
218+
* public func optionalJavaKitClass(_ arg: JavaLong?)
219+
* }
220+
*/
221+
public static void optionalJavaKitClass(Optional<java.lang.Long> arg) {
222+
SwiftModule.$optionalJavaKitClass(arg.orElse(null));
223+
}
224+
""",
225+
"""
226+
private static native void $optionalJavaKitClass(java.lang.Long arg);
227+
"""
228+
]
229+
)
230+
}
231+
232+
@Test
233+
func optionalJavaKitClass_swiftThunks() throws {
234+
try assertOutput(
235+
input: source,
236+
.jni,
237+
.swift,
238+
detectChunkByInitialLines: 1,
239+
javaClassLookupTable: classLookupTable,
240+
expectedChunks: [
241+
"""
242+
@_cdecl("Java_com_example_swift_SwiftModule__00024optionalJavaKitClass__Ljava_lang_Long_2")
243+
func Java_com_example_swift_SwiftModule__00024optionalJavaKitClass__Ljava_lang_Long_2(environment: UnsafeMutablePointer<JNIEnv?>!, thisClass: jclass, arg: jobject?) {
244+
SwiftModule.optionalJavaKitClass(arg.map {
245+
return JavaLong(javaThis: $0, environment: environment!)
246+
} // render(_:_:) @ JExtractSwiftLib/JNISwift2JavaGenerator+NativeTranslation.swift:666
247+
)
248+
}
249+
"""
250+
]
251+
)
252+
}
253+
}

0 commit comments

Comments
 (0)