Skip to content

Commit 5eeca1b

Browse files
LarsEckartJayBazuziisidore
committed
@ F implement InlineKotlinReporter
Co-authored-by: Jay Bazuzi <[email protected]> Co-authored-by: Llewellyn Falco <[email protected]>
1 parent f95a31b commit 5eeca1b

File tree

1 file changed

+129
-0
lines changed

1 file changed

+129
-0
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package org.approvaltests.inline;
2+
3+
import com.spun.util.StringUtils;
4+
import com.spun.util.io.FileUtils;
5+
import org.approvaltests.core.ApprovalFailureReporter;
6+
import org.approvaltests.core.ApprovalReporterWithCleanUp;
7+
import org.approvaltests.namer.StackTraceNamer;
8+
import org.lambda.functions.Function2;
9+
import org.lambda.functions.Function3;
10+
import java.io.File;
11+
12+
public class InlineKotlinReporter implements ApprovalFailureReporter, ApprovalReporterWithCleanUp {
13+
private final String sourceFilePath;
14+
private final StackTraceNamer stackTraceNamer;
15+
private final Function2<String, String, String> footerCreator;
16+
private final ApprovalFailureReporter reporter;
17+
private String additionalLines = null;
18+
private Function3<String, String, String, String> createNewReceivedFileText;
19+
20+
public InlineKotlinReporter(ApprovalFailureReporter reporter, Function2<String, String, String> footerCreator) {
21+
this.reporter = reporter;
22+
this.stackTraceNamer = new StackTraceNamer();
23+
this.sourceFilePath = stackTraceNamer.getSourceFilePath();
24+
this.createNewReceivedFileText = (kotlinSourceCode, actual, methodName) ->
25+
createNewReceivedFileText(kotlinSourceCode, actual, methodName);
26+
this.footerCreator = footerCreator != null ? footerCreator : (source, actual) -> "";
27+
}
28+
29+
public InlineKotlinReporter(ApprovalFailureReporter reporter) {
30+
this(reporter, null);
31+
}
32+
33+
@Override
34+
public boolean report(String received, String approved) {
35+
additionalLines = footerCreator.call(received, approved);
36+
String sourceFile = sourceFilePath + stackTraceNamer.getInfo().getClassName() + ".kt";
37+
String newSource = createReceived(FileUtils.readFile(received));
38+
return reporter.report(newSource, sourceFile);
39+
}
40+
41+
public String createReceived(String actual) {
42+
String file = sourceFilePath + stackTraceNamer.getInfo().getClassName() + ".kt";
43+
String received = getReceivedFileName();
44+
String text = FileUtils.readFile(file);
45+
String fullText = this.createNewReceivedFileText.call(
46+
text, actual + additionalLines,
47+
this.stackTraceNamer.getInfo().getMethodName()
48+
);
49+
FileUtils.writeFile(new File(received), fullText);
50+
return received;
51+
}
52+
53+
private String getReceivedFileName() {
54+
return sourceFilePath + stackTraceNamer.getInfo().getClassName() + ".received.txt";
55+
}
56+
57+
@Override
58+
public void cleanUp(String received, String approved) {
59+
FileUtils.delete(getReceivedFileName());
60+
}
61+
62+
public static String createNewReceivedFileText(String kotlinSourceCode, String actual, String methodName) {
63+
String normalizedSourceCode = kotlinSourceCode.replaceAll("\\r\\n", "\n");
64+
CodeParts codeParts = CodeParts.splitCode(normalizedSourceCode, methodName);
65+
if (codeParts.method != null && codeParts.method.contains("expected = \"\"\"")) {
66+
replaceExpected(codeParts, actual);
67+
} else {
68+
addExpected(codeParts, actual);
69+
}
70+
return codeParts.getFullCode();
71+
}
72+
73+
private static void addExpected(CodeParts codeParts, String actual) {
74+
int start = codeParts.method.indexOf("{") + 2;
75+
String before = codeParts.method.substring(0, start);
76+
String after = codeParts.method.substring(start);
77+
codeParts.method = before + getExpected(actual, codeParts.tab) + after;
78+
}
79+
80+
private static String getExpected(String actual, String tab) {
81+
return String.format(
82+
"%s%sval expected = \"\"\"\n%s%s%s%s\"\"\".trimIndent()\n", tab, tab, indent(actual, tab), tab, tab,
83+
tab
84+
);
85+
}
86+
87+
private static void replaceExpected(CodeParts codeParts, String actual) {
88+
int start = codeParts.method.indexOf("expected = \"\"\"");
89+
start = codeParts.method.substring(0, start).lastIndexOf("\n") + 1;
90+
// Find the closing """ by looking for it at the start of a line (after whitespace)
91+
int searchPos = start + "expected = \"\"\"".length();
92+
int end = -1;
93+
while (searchPos < codeParts.method.length()) {
94+
int nextTripleQuote = codeParts.method.indexOf("\"\"\"", searchPos);
95+
if (nextTripleQuote == -1) break;
96+
// Check if this """ is at the start of a line (preceded only by whitespace)
97+
int lineStart = codeParts.method.lastIndexOf("\n", nextTripleQuote - 1) + 1;
98+
String textBeforeQuote = codeParts.method.substring(lineStart, nextTripleQuote);
99+
if (textBeforeQuote.trim().isEmpty()) {
100+
end = nextTripleQuote;
101+
break;
102+
}
103+
searchPos = nextTripleQuote + 1;
104+
}
105+
if (end == -1) {
106+
// Fallback to old behavior if we can't find it
107+
end = codeParts.method.indexOf("\"\"\"", start + "expected = \"\"\"".length());
108+
}
109+
end += 3; // Move past the closing """
110+
// Check if there's a .trimIndent() after the closing """
111+
String afterTripleQuote = codeParts.method.substring(end);
112+
if (afterTripleQuote.startsWith(".trimIndent()")) {
113+
end += ".trimIndent()".length();
114+
}
115+
end = codeParts.method.indexOf("\n", end) + 1;
116+
String before = codeParts.method.substring(0, start);
117+
String after = codeParts.method.substring(end);
118+
codeParts.method = before + getExpected(actual, codeParts.tab) + after;
119+
}
120+
121+
public static String indent(String actual, String tab) {
122+
String[] split = StringUtils.split(actual, "\n");
123+
String output = "";
124+
for (String line : split) {
125+
output += tab + tab + tab + line + "\n";
126+
}
127+
return output;
128+
}
129+
}

0 commit comments

Comments
 (0)