Skip to content

Commit 3b9bb41

Browse files
committed
BridgeJS: Tests for generic exports
1 parent fb1f1ce commit 3b9bb41

12 files changed

Lines changed: 4809 additions & 108 deletions

File tree

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import Foundation
2+
import SwiftParser
3+
import SwiftSyntax
4+
import Testing
5+
6+
@testable import BridgeJSCore
7+
@testable import BridgeJSSkeleton
8+
9+
@Suite struct CrossModuleGenericExportTests {
10+
@Test
11+
func registersDependencyStructAndConformsRetroactivelyWhenDepLacksGenerics() throws {
12+
let core = try buildSkeleton(
13+
moduleName: "Core",
14+
source: """
15+
@JS public struct Vector3D {
16+
public let x: Double
17+
@JS public init(x: Double) { self.x = x }
18+
}
19+
"""
20+
)
21+
let dependencyStructs = DependencyGenericStruct.collect(
22+
from: [(moduleName: "Core", skeleton: core)]
23+
)
24+
#expect(dependencyStructs.count == 1)
25+
#expect(dependencyStructs.first?.definingModuleHasGenerics == false)
26+
27+
let output = try renderExportGlue(
28+
source: """
29+
import Core
30+
@JS public func use<T: _BridgedSwiftGenericBridgeable>(_ value: T) -> T {
31+
return value
32+
}
33+
""",
34+
dependencies: [(moduleName: "Core", skeleton: core)],
35+
dependencyStructs: dependencyStructs
36+
)
37+
38+
#expect(output.contains("_bjs_registerGenericExportType(Core.Vector3D.self)"))
39+
#expect(output.contains("extension Core.Vector3D: @retroactive _BridgedSwiftGenericBridgeable {"))
40+
#expect(
41+
output.contains(
42+
"@_spi(BridgeJS) public static var bridgeJSTypeName: StaticString { \"Vector3D\" }"
43+
)
44+
)
45+
#expect(
46+
output.contains(
47+
"@_spi(BridgeJS) public static let bridgeJSTypeID: Int32 = _swift_js_resolve_type_id(Core.Vector3D.bridgeJSTypeName)"
48+
)
49+
)
50+
}
51+
52+
@Test
53+
func registersDependencyStructWithoutConformanceWhenDepHasGenerics() throws {
54+
let core = try buildSkeleton(
55+
moduleName: "Core",
56+
source: """
57+
@JS public struct Vector3D {
58+
public let x: Double
59+
@JS public init(x: Double) { self.x = x }
60+
}
61+
@JS public func coreUse<T: _BridgedSwiftGenericBridgeable>(_ value: T) -> T {
62+
return value
63+
}
64+
"""
65+
)
66+
let dependencyStructs = DependencyGenericStruct.collect(
67+
from: [(moduleName: "Core", skeleton: core)]
68+
)
69+
#expect(dependencyStructs.first?.definingModuleHasGenerics == true)
70+
71+
let output = try renderExportGlue(
72+
source: """
73+
import Core
74+
@JS public func use<T: _BridgedSwiftGenericBridgeable>(_ value: T) -> T {
75+
return value
76+
}
77+
""",
78+
dependencies: [(moduleName: "Core", skeleton: core)],
79+
dependencyStructs: dependencyStructs
80+
)
81+
82+
#expect(output.contains("_bjs_registerGenericExportType(Core.Vector3D.self)"))
83+
#expect(!output.contains("@retroactive _BridgedSwiftGenericBridgeable"))
84+
}
85+
86+
private func renderExportGlue(
87+
source: String,
88+
dependencies: [(moduleName: String, skeleton: BridgeJSSkeleton)],
89+
dependencyStructs: [DependencyGenericStruct]
90+
) throws -> String {
91+
let swiftAPI = SwiftToSkeleton(
92+
progress: .silent,
93+
moduleName: "App",
94+
exposeToGlobal: false,
95+
externalModuleIndex: ExternalModuleIndex(dependencies: dependencies)
96+
)
97+
swiftAPI.addSourceFile(Parser.parse(source: source), inputFilePath: "App.swift")
98+
let skeleton = try swiftAPI.finalize()
99+
let exported = try #require(skeleton.exported)
100+
let exportSwift = ExportSwift(
101+
progress: .silent,
102+
moduleName: skeleton.moduleName,
103+
skeleton: exported,
104+
hasGenerics: true,
105+
dependencyStructs: dependencyStructs
106+
)
107+
return try #require(try exportSwift.finalize())
108+
}
109+
110+
private func buildSkeleton(
111+
moduleName: String,
112+
source: String,
113+
dependencies: [(moduleName: String, skeleton: BridgeJSSkeleton)] = []
114+
) throws -> BridgeJSSkeleton {
115+
let swiftAPI = SwiftToSkeleton(
116+
progress: .silent,
117+
moduleName: moduleName,
118+
exposeToGlobal: false,
119+
externalModuleIndex: ExternalModuleIndex(dependencies: dependencies)
120+
)
121+
swiftAPI.addSourceFile(Parser.parse(source: source), inputFilePath: "\(moduleName).swift")
122+
return try swiftAPI.finalize()
123+
}
124+
}

0 commit comments

Comments
 (0)