Skip to content

Commit 0edc00b

Browse files
committed
Introduce a new SPM-based test harness
Using the Swift Package Manager instead of xcode allows for developing on Linux and Windows, and could potentially make life easier. Ref. chinedufn#306
1 parent 5c3d672 commit 0edc00b

28 files changed

+619
-39
lines changed

SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunner/Result.swift

+3-7
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,23 @@
66
//
77

88
func swift_func_takes_callback_with_result_arg(
9-
arg: (RustResult<CallbackTestOpaqueRustType, String>) -> Void
9+
arg: (RustResult<CallbackTestOpaqueRustType, String>) -> ()
1010
) {
1111
arg(.Ok(CallbackTestOpaqueRustType(555)))
1212
}
1313

1414
public class ResultTestOpaqueSwiftType {
1515
var num: UInt32
16-
16+
1717
init(val: UInt32) {
1818
self.num = val
1919
}
20-
20+
2121
func val() -> UInt32 {
2222
self.num
2323
}
2424
}
2525

26-
extension AsyncRustFnReturnStruct: @unchecked Sendable {}
27-
2826
extension ResultTestOpaqueRustType: @unchecked Sendable {}
2927
extension ResultTestOpaqueRustType: Error {}
3028

@@ -43,7 +41,5 @@ extension ResultTransparentStruct: Error {}
4341
extension SameEnum: @unchecked Sendable {}
4442
extension SameEnum: Error {}
4543

46-
extension AsyncResultOkEnum: @unchecked Sendable {}
47-
4844
extension AsyncResultErrEnum: @unchecked Sendable {}
4945
extension AsyncResultErrEnum: Error {}

SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunnerTests/ResultTests.swift

+28-12
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,30 @@ class ResultTests: XCTestCase {
1313
rust_func_takes_result_string(.Ok("Success Message"))
1414
rust_func_takes_result_string(.Err("Error Message"))
1515
}
16-
16+
17+
/// Verify that we can return a Result<String, String> from Rust -> Swift.
18+
///
19+
/// The Err case evidences Swift’s `Error` protocol is implemented correctly
20+
/// for `RustStringRef`, i.e. `extension RustStringRef: Error {}`
21+
func testSwiftCallRustReturnsResultString() throws {
22+
let resultOk = try! rust_func_returns_result_string(true)
23+
XCTAssertEqual(resultOk.toString(), "Success Message")
24+
25+
do {
26+
let _ = try rust_func_returns_result_string(false)
27+
XCTFail("The function should have returned an error.")
28+
} catch let error as RustString {
29+
XCTAssertEqual(error.toString(), "Error Message")
30+
}
31+
}
32+
1733
/// Verify that we can pass a Result<OpaqueRust, OpaqueRust> from Swift -> Rust
1834
func testSwiftCallRustResultOpaqueRust() throws {
1935
let reflectedOk = try! rust_func_reflect_result_opaque_rust(
2036
.Ok(ResultTestOpaqueRustType(111))
2137
)
2238
XCTAssertEqual(reflectedOk.val(), 111)
23-
39+
2440
do {
2541
let _ = try rust_func_reflect_result_opaque_rust(
2642
.Err(ResultTestOpaqueRustType(222))
@@ -30,7 +46,7 @@ class ResultTests: XCTestCase {
3046
XCTAssertEqual(error.val(), 222)
3147
}
3248
}
33-
49+
3450
/// Verify that we can pass a Result<OpaqueSwift, OpaqueSwift> from Swift -> Rust
3551
func testSwiftCallRustResultOpaqueSwift() throws {
3652
rust_func_takes_result_opaque_swift(
@@ -64,7 +80,7 @@ class ResultTests: XCTestCase {
6480
XCTAssertEqual(error.val(), 222)
6581
}
6682
}
67-
83+
6884
/// Verify that we can receive a Result<OpaqueRust, TransparentEnum> from Rust
6985
func testResultOpaqueRustTransparentEnum() throws {
7086
XCTContext.runActivity(named: "Should return a ResultTestOpaqueRustType") {
@@ -75,7 +91,7 @@ class ResultTests: XCTestCase {
7591
XCTFail()
7692
}
7793
}
78-
94+
7995
XCTContext.runActivity(named: "Should throw an error") {
8096
_ in
8197
do {
@@ -95,7 +111,7 @@ class ResultTests: XCTestCase {
95111
}
96112
}
97113
}
98-
114+
99115
/// Verify that we can receive a Result<TransparentEnum, OpaqueRust> from Rust
100116
func testResultTransparentEnumOpaqueRust() throws {
101117
XCTContext.runActivity(named: "Should return a ResultTestOpaqueRustType") {
@@ -114,7 +130,7 @@ class ResultTests: XCTestCase {
114130
XCTFail()
115131
}
116132
}
117-
133+
118134
XCTContext.runActivity(named: "Should throw an error") {
119135
_ in
120136
do {
@@ -127,7 +143,7 @@ class ResultTests: XCTestCase {
127143
}
128144
}
129145
}
130-
146+
131147
/// Verify that we can receive a Result<(), TransparentEnum> from Rust
132148
func testResultUnitTypeTransparentEnum() throws {
133149
XCTContext.runActivity(named: "Should return a Unit type") {
@@ -138,7 +154,7 @@ class ResultTests: XCTestCase {
138154
XCTFail()
139155
}
140156
}
141-
157+
142158
XCTContext.runActivity(named: "Should throw an error") {
143159
_ in
144160
do {
@@ -158,7 +174,7 @@ class ResultTests: XCTestCase {
158174
}
159175
}
160176
}
161-
177+
162178
/// Verify that we can receive a Result<(primitive type, OpaqueRustType, String), TransparentEnum> from Rust
163179
func testResultTupleTransparentEnum() throws {
164180
XCTContext.runActivity(named: "Should return a tuple type") {
@@ -172,7 +188,7 @@ class ResultTests: XCTestCase {
172188
XCTFail()
173189
}
174190
}
175-
191+
176192
XCTContext.runActivity(named: "Should throw an error") {
177193
_ in
178194
do {
@@ -249,7 +265,7 @@ class ResultTests: XCTestCase {
249265
XCTAssertEqual(UInt32(i), value.val())
250266
}
251267
}
252-
268+
253269
/// Verify that we can use throwing initializers defined on the Rust side.
254270
func testThrowingInitializers() throws {
255271
XCTContext.runActivity(named: "Should fail") {

crates/swift-integration-tests/build.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use std::path::PathBuf;
22

33
fn main() {
4-
let out_dir = "../../SwiftRustIntegrationTestRunner/Generated";
5-
let out_dir = PathBuf::from(out_dir);
4+
// TODO: we can use --artifact-dir with OUT_DIR when that stabilizes.
5+
let out_dir = PathBuf::from("../../integration-tests/Sources/Generated");
66

77
let mut bridges = vec![];
88
read_files_recursive(PathBuf::from("src"), &mut bridges);

integration-tests/.gitignore

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
xcuserdata/
5+
DerivedData/
6+
.swiftpm/configuration/registries.json
7+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8+
.netrc

integration-tests/.swift-format

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"version": 1,
3+
"lineLength": 100,
4+
"indentation": {
5+
"spaces": 4
6+
},
7+
"maximumBlankLines": 1,
8+
"respectsExistingLineBreaks": true,
9+
"lineBreakBeforeControlFlowKeywords": false,
10+
}

integration-tests/Package.swift

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// swift-tools-version: 6.0
2+
3+
import PackageDescription
4+
5+
let linkerSettings: [LinkerSetting] = [
6+
.linkedLibrary("swift_integration_tests"),
7+
.unsafeFlags(["-L../target/debug/"])
8+
]
9+
10+
let package = Package(
11+
name: "IntegrationTests",
12+
targets: [
13+
// The compiled static rust library.
14+
.systemLibrary(
15+
name: "RustLib"),
16+
// The generated Swift wrapper code for the Rust library, plus some
17+
// Swift code used by the Rust library.
18+
.target(
19+
name: "SharedLib",
20+
dependencies: ["RustLib"],
21+
linkerSettings: linkerSettings),
22+
.testTarget(
23+
name: "IntegrationTests",
24+
dependencies: ["SharedLib", "RustLib"]),
25+
]
26+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*
2+
!.gitignore
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#include "../Generated/SwiftBridgeCore.h"
2+
#include "../Generated/swift-integration-tests/swift-integration-tests.h"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module RustLib [system] {
2+
header "bridge.h"
3+
link "swift_integration_tests"
4+
export *
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// RustTests.swift
3+
// SwiftRustIntegrationTestRunner
4+
//
5+
// Created by Frankie Nwafili on 11/14/21.
6+
//
7+
8+
import Foundation
9+
10+
public class ASwiftStack {
11+
private var stack: [UInt8] = []
12+
13+
func push (val: UInt8) {
14+
stack.append(val)
15+
}
16+
17+
func pop () {
18+
let _ = stack.popLast();
19+
}
20+
21+
func as_ptr() -> UnsafePointer<UInt8> {
22+
UnsafePointer(self.stack)
23+
}
24+
25+
func len () -> UInt {
26+
UInt(stack.count)
27+
}
28+
29+
func as_slice () -> UnsafeBufferPointer<UInt8> {
30+
UnsafeBufferPointer(start: self.as_ptr(), count: Int(self.len()))
31+
}
32+
}
33+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//
2+
// Callbacks.swift
3+
// SwiftRustIntegrationTestRunner
4+
//
5+
// Created by Frankie Nwafili on 9/11/22.
6+
//
7+
8+
import Foundation
9+
10+
func swift_takes_fnonce_callback_no_args_no_return(arg: () -> ()) {
11+
arg()
12+
}
13+
14+
func swift_takes_fnonce_callback_primitive(
15+
arg: (UInt8) -> UInt8
16+
) -> UInt8 {
17+
arg(4)
18+
}
19+
20+
func swift_takes_fnonce_callback_opaque_rust(
21+
arg: (CallbackTestOpaqueRustType) -> CallbackTestOpaqueRustType
22+
) {
23+
let doubled = arg(CallbackTestOpaqueRustType(10))
24+
if doubled.val() != 20 {
25+
fatalError("Callback not called")
26+
}
27+
}
28+
29+
func swift_takes_two_fnonce_callbacks(
30+
arg1: () -> (),
31+
arg2: (UInt8) -> UInt16
32+
) -> UInt16 {
33+
arg1()
34+
return arg2(3)
35+
}
36+
37+
func swift_takes_fnonce_callback_with_two_params(
38+
arg: (UInt8, UInt16) -> UInt16
39+
) -> UInt16 {
40+
arg(1, 2)
41+
}
42+
43+
/// When given an FnOnce callback this should panic.
44+
func swift_calls_rust_fnonce_callback_twice(arg: () -> ()) {
45+
arg()
46+
arg()
47+
}
48+
49+
class SwiftMethodCallbackTester {
50+
func method_with_fnonce_callback(callback: () -> ()) {
51+
callback()
52+
}
53+
54+
func method_with_fnonce_callback_primitive(callback: (UInt16) -> UInt16) -> UInt16 {
55+
callback(5)
56+
}
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//
2+
// FunctionAttributes.swift
3+
// SwiftRustIntegrationTestRunner
4+
//
5+
// Created by Erik Živković on 2022-12-17.
6+
//
7+
8+
import Foundation
9+
10+
func testCallSwiftFromRustByNameAttribute() -> RustString {
11+
return "StringFromSwift".intoRustString()
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*
2+
!.gitignore

0 commit comments

Comments
 (0)