Skip to content

Commit a5fa9c9

Browse files
committed
improve jextract text checking tools
1 parent b99e2ab commit a5fa9c9

File tree

3 files changed

+149
-75
lines changed

3 files changed

+149
-75
lines changed

Sources/JExtractSwift/Swift2JavaTranslator+Printing.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ extension Swift2JavaTranslator {
3131
for (_, ty) in importedTypes.sorted(by: { (lhs, rhs) in lhs.key < rhs.key }) {
3232
let filename = "\(ty.javaClassName).java"
3333
log.info("Printing contents: \(filename)")
34-
printImportedClass(&printer, ty)
34+
printImportedNominalType(&printer, ty)
3535

3636
try writeContents(
3737
printer.finalize(),
@@ -110,7 +110,7 @@ extension Swift2JavaTranslator {
110110
}
111111
}
112112

113-
public func printImportedClass(_ printer: inout CodePrinter, _ decl: ImportedNominalType) {
113+
public func printImportedNominalType(_ printer: inout CodePrinter, _ decl: ImportedNominalType) {
114114
printHeader(&printer)
115115
printPackage(&printer)
116116
printImports(&printer)
@@ -152,7 +152,6 @@ extension Swift2JavaTranslator {
152152
}
153153

154154
public func printHeader(_ printer: inout CodePrinter) {
155-
assert(printer.isEmpty)
156155
printer.print(
157156
"""
158157
// Generated by jextract-swift

Tests/JExtractSwiftTests/Asserts/TextAssertions.swift

Lines changed: 98 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,102 @@ import JExtractSwift
1616
import Testing
1717
import struct Foundation.CharacterSet
1818

19+
func assertOutput(
20+
dump: Bool = false,
21+
_ translator: Swift2JavaTranslator,
22+
input: String,
23+
detectChunkByInitialLines: Int = 4,
24+
expectedChunks: [String],
25+
fileID: String = #fileID,
26+
filePath: String = #filePath,
27+
line: Int = #line,
28+
column: Int = #column
29+
) {
30+
try! translator.analyze(swiftInterfacePath: "/fake/Fake.swiftinterface", text: input)
31+
32+
let output = CodePrinter.toString { printer in
33+
for ty in translator.importedTypes.values {
34+
translator.printImportedNominalType(&printer, ty)
35+
printer.print("\n")
36+
printer.print("// ======================================================================")
37+
printer.print("// ======================================================================")
38+
printer.print("\n")
39+
}
40+
translator.printModule(&printer)
41+
}
42+
43+
let gotLines = output.split(separator: "\n")
44+
for expected in expectedChunks {
45+
let expectedLines = expected.split(separator: "\n")
46+
47+
var matchingOutputOffset = 0
48+
let expectedInitialMatchingLines = expectedLines[0..<detectChunkByInitialLines]
49+
.map({$0.trimmingCharacters(in: .whitespacesAndNewlines)})
50+
.joined(separator: "\n")
51+
for offset in 0..<gotLines.count where gotLines.count > (offset+detectChunkByInitialLines) {
52+
let textLinesAtOffset = gotLines[offset..<offset+detectChunkByInitialLines]
53+
.map({$0.trimmingCharacters(in: .whitespacesAndNewlines)})
54+
.joined(separator: "\n")
55+
56+
// print("CHECKING GOT@\(offset)->\(offset + detectChunkByInitialLines) ==========")
57+
// print(textLinesAtOffset)
58+
// print("AGAINST EXPECTED@\(0)->\(expectedInitialMatchingLines) ==========")
59+
// print(expectedInitialMatchingLines)
60+
// print("")
61+
// print("")
62+
63+
if textLinesAtOffset == expectedInitialMatchingLines {
64+
matchingOutputOffset = offset
65+
// print("MATCHED \(matchingOutputOffset)")
66+
break
67+
}
68+
}
69+
70+
var diffLineNumbers: [Int] = []
71+
72+
for (no, (g, e)) in zip(gotLines.dropFirst(matchingOutputOffset), expectedLines).enumerated() {
73+
if g.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).count == 0
74+
|| e.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).count == 0 {
75+
continue
76+
}
77+
78+
let ge = g.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
79+
let ee = e.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
80+
if ge.commonPrefix(with: ee) != ee {
81+
diffLineNumbers.append(no + matchingOutputOffset)
82+
83+
let sourceLocation = SourceLocation(
84+
fileID: fileID, filePath: filePath, line: line, column: column)
85+
#expect(ge == ee, sourceLocation: sourceLocation)
86+
}
87+
}
88+
89+
let hasDiff = diffLineNumbers.count > 0
90+
if hasDiff || dump {
91+
print("")
92+
if hasDiff {
93+
print("error: Number of not matching lines: \(diffLineNumbers.count)!".red)
94+
95+
print("==== ---------------------------------------------------------------")
96+
print("Expected output:")
97+
for (n, e) in expectedLines.enumerated() {
98+
print("\(n): \(e)".yellow(if: diffLineNumbers.map({$0 - matchingOutputOffset}).contains(n)))
99+
}
100+
}
101+
102+
print("==== ---------------------------------------------------------------")
103+
print("Got output:")
104+
let surroundingContext = 5
105+
let printFromLineNo = matchingOutputOffset
106+
let printToLineNo = matchingOutputOffset + expectedLines.count
107+
for (n, g) in gotLines.enumerated() where n >= printFromLineNo && n <= printToLineNo {
108+
print("\(n): \(g)".red(if: diffLineNumbers.contains(n)))
109+
}
110+
print("==== ---------------------------------------------------------------\n")
111+
}
112+
}
113+
}
114+
19115
func assertOutput(
20116
dump: Bool = false,
21117
_ got: String,
@@ -32,21 +128,13 @@ func assertOutput(
32128

33129
for (no, (g, e)) in zip(gotLines, expectedLines).enumerated() {
34130
if g.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).count == 0
35-
|| e.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).count == 0
36-
{
131+
|| e.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).count == 0 {
37132
continue
38133
}
39134

40135
let ge = g.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
41136
let ee = e.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
42137
if ge.commonPrefix(with: ee) != ee {
43-
// print("")
44-
// print("[\(file):\(line)] " + "Difference found on line: \(no + 1)!".red)
45-
// print("Expected @ \(file):\(Int(line) + no + 3 /*formatting*/ + 1):")
46-
// print(e.yellow)
47-
// print("Got instead:")
48-
// print(g.red)
49-
50138
diffLineNumbers.append(no)
51139

52140
let sourceLocation = SourceLocation(
@@ -57,7 +145,7 @@ func assertOutput(
57145
}
58146

59147
let hasDiff = diffLineNumbers.count > 0
60-
if hasDiff || dump{
148+
if hasDiff || dump {
61149
print("")
62150
if hasDiff {
63151
print("error: Number of not matching lines: \(diffLineNumbers.count)!".red)

Tests/JExtractSwiftTests/OptionalImportTests.swift

Lines changed: 49 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ final class OptionalImportTests {
3434
// MANGLED NAME: $fake
3535
public func globalGetIntOptional() -> Int?
3636
37+
// MANGLED NAME: $fake
38+
public func globalGetFloatOptional() -> Float?
39+
3740
// FIXME: Hack to allow us to translate "String", even though it's not
3841
// actually available
3942
// MANGLED NAME: $ss
@@ -49,38 +52,30 @@ final class OptionalImportTests {
4952
)
5053
st.log.logLevel = .warning
5154

52-
try st.analyze(swiftInterfacePath: "/fake/Fake.swiftinterface", text: class_interfaceFile)
53-
54-
let funcDecl = st.importedGlobalFuncs.first {
55-
$0.baseIdentifier == "globalGetIntOptional"
56-
}!
57-
58-
let output = CodePrinter.toString { printer in
59-
st.printFuncDowncallMethod(&printer, decl: funcDecl, selfVariant: nil)
60-
}
61-
6255
assertOutput(
63-
output,
64-
expected:
65-
"""
66-
/**
67-
* Downcall to Swift:
68-
* {@snippet lang=swift :
69-
* public func globalGetIntOptional() -> Int?
70-
* }
71-
*/
72-
public static java.util.OptionalLong globalGetIntOptional() {
73-
var mh$ = globalGetIntOptional.HANDLE;
74-
try {
75-
if (TRACE_DOWNCALLS) {
76-
traceDowncall();
77-
}
78-
return (java.util.OptionalLong) mh$.invokeExact();
79-
} catch (Throwable ex$) {
80-
throw new AssertionError("should not reach here", ex$);
81-
}
82-
}
83-
"""
56+
st,
57+
input: class_interfaceFile,
58+
expectedChunks: [
59+
"""
60+
/**
61+
* Downcall to Swift:
62+
* {@snippet lang=swift :
63+
* public func globalGetIntOptional() -> Int?
64+
* }
65+
*/
66+
public static java.util.OptionalLong globalGetIntOptional() {
67+
var mh$ = globalGetIntOptional.HANDLE;
68+
try {
69+
if (TRACE_DOWNCALLS) {
70+
traceDowncall();
71+
}
72+
return (java.util.OptionalLong) mh$.invokeExact();
73+
} catch (Throwable ex$) {
74+
throw new AssertionError("should not reach here", ex$);
75+
}
76+
}
77+
"""
78+
]
8479
)
8580
}
8681

@@ -92,38 +87,30 @@ final class OptionalImportTests {
9287
)
9388
st.log.logLevel = .warning
9489

95-
try st.analyze(swiftInterfacePath: "/fake/Fake.swiftinterface", text: class_interfaceFile)
96-
97-
let funcDecl = st.importedGlobalFuncs.first {
98-
$0.baseIdentifier == "globalGetStringOptional"
99-
}!
100-
101-
let output = CodePrinter.toString { printer in
102-
st.printFuncDowncallMethod(&printer, decl: funcDecl, selfVariant: nil)
103-
}
104-
10590
assertOutput(
106-
output,
107-
expected:
108-
"""
109-
/**
110-
* Downcall to Swift:
111-
* {@snippet lang=swift :
112-
* public func globalGetStringOptional() -> String?
113-
* }
114-
*/
115-
public static java.util.Optional<String> globalGetStringOptional() {
116-
var mh$ = globalGetStringOptional.HANDLE;
117-
try {
118-
if (TRACE_DOWNCALLS) {
119-
traceDowncall();
120-
}
121-
return (java.util.Optional<String>) mh$.invokeExact();
122-
} catch (Throwable ex$) {
123-
throw new AssertionError("should not reach here", ex$);
124-
}
125-
}
126-
"""
91+
st,
92+
input: class_interfaceFile,
93+
expectedChunks: [
94+
"""
95+
/**
96+
* Downcall to Swift:
97+
* {@snippet lang=swift :
98+
* public func globalGetStringOptional() -> String?
99+
* }
100+
*/
101+
public static java.util.Optional<String> globalGetStringOptional() {
102+
var mh$ = globalGetStringOptional.HANDLE;
103+
try {
104+
if (TRACE_DOWNCALLS) {
105+
traceDowncall();
106+
}
107+
return (java.util.Optional<String>) mh$.invokeExact();
108+
} catch (Throwable ex$) {
109+
throw new AssertionError("should not reach here", ex$);
110+
}
111+
}
112+
"""
113+
]
127114
)
128115
}
129116
}

0 commit comments

Comments
 (0)