Skip to content

Commit fc1c147

Browse files
refactor: Migrate PythonGeneratorTestUtils from Xtend to Java
1 parent e9fd478 commit fc1c147

File tree

4 files changed

+253
-233
lines changed

4 files changed

+253
-233
lines changed
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
package com.regnosys.rosetta.generator.python;
2+
3+
import com.google.inject.Provider;
4+
import com.regnosys.rosetta.rosetta.RosettaModel;
5+
import com.regnosys.rosetta.tests.util.ModelHelper;
6+
import jakarta.inject.Inject;
7+
import org.apache.commons.io.FileUtils;
8+
import org.apache.maven.model.Model;
9+
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
10+
import org.eclipse.emf.common.util.URI;
11+
import org.eclipse.emf.ecore.resource.Resource;
12+
import org.eclipse.emf.ecore.resource.ResourceSet;
13+
import org.eclipse.xtext.resource.XtextResourceSet;
14+
import org.eclipse.xtext.testing.util.ParseHelper;
15+
import org.slf4j.Logger;
16+
import org.slf4j.LoggerFactory;
17+
18+
import java.io.File;
19+
import java.io.FileReader;
20+
import java.io.IOException;
21+
import java.nio.charset.StandardCharsets;
22+
import java.nio.file.FileVisitOption;
23+
import java.nio.file.Files;
24+
import java.nio.file.Path;
25+
import java.nio.file.Paths;
26+
import java.util.*;
27+
import java.util.stream.Collectors;
28+
import java.util.stream.Stream;
29+
30+
import static org.junit.jupiter.api.Assertions.assertTrue;
31+
32+
public class PythonGeneratorTestUtils {
33+
34+
private static final Logger LOGGER = LoggerFactory.getLogger(PythonGeneratorTestUtils.class);
35+
36+
@Inject
37+
private ModelHelper modelHelper;
38+
@Inject
39+
private Provider<XtextResourceSet> resourceSetProvider;
40+
@Inject
41+
private ParseHelper<RosettaModel> parseHelper;
42+
@Inject
43+
private PythonCodeGenerator generator;
44+
45+
public Properties getProperties() throws Exception {
46+
MavenXpp3Reader reader = new MavenXpp3Reader();
47+
Model model = reader.read(new FileReader("pom.xml"));
48+
return model.getProperties();
49+
}
50+
51+
public String getProperty(String property) throws Exception {
52+
MavenXpp3Reader reader = new MavenXpp3Reader();
53+
Model model = reader.read(new FileReader("pom.xml"));
54+
return model.getProperties().getProperty(property);
55+
}
56+
57+
public String getPropertyOrMessage(String propertyName) {
58+
// Check if property exists
59+
String property = null;
60+
try {
61+
property = getProperty(propertyName);
62+
if (property == null || property.isEmpty()) {
63+
LOGGER.error("Property:{} does not exist or is empty", propertyName);
64+
}
65+
} catch (Exception e) {
66+
LOGGER.error("Exception when getting property:{} exception:{}", propertyName, e.getMessage());
67+
}
68+
return property;
69+
}
70+
71+
public void cleanFolder(String folderPath) {
72+
File folder = new File(folderPath + File.separator + "src");
73+
if (folder.exists() && folder.isDirectory()) {
74+
try {
75+
FileUtils.cleanDirectory(folder);
76+
} catch (IOException e) {
77+
LOGGER.error("Failed to delete folder content: " + e.getMessage());
78+
}
79+
} else {
80+
LOGGER.info("{} does not exist or is not a directory", folderPath);
81+
}
82+
}
83+
84+
public void writeFiles(String pythonTgtPath, Map<String, ? extends CharSequence> generatedFiles)
85+
throws IOException {
86+
for (Map.Entry<String, ? extends CharSequence> entry : generatedFiles.entrySet()) {
87+
String filePath = entry.getKey();
88+
String fileContents = entry.getValue().toString();
89+
Path outputPath = Path.of(pythonTgtPath + File.separator + filePath);
90+
Files.createDirectories(outputPath.getParent());
91+
Files.write(outputPath, fileContents.getBytes(StandardCharsets.UTF_8));
92+
}
93+
LOGGER.info("Write Files ... wrote: {}", generatedFiles.size());
94+
}
95+
96+
public Map<String, CharSequence> generatePythonFromRosettaModel(RosettaModel m, ResourceSet resourceSet) {
97+
String version = m.getVersion();
98+
Map<String, CharSequence> result = new HashMap<>();
99+
result.putAll(generator.beforeGenerate(m.eResource(), m, version));
100+
result.putAll(generator.generate(m.eResource(), m, version));
101+
result.putAll(generator.afterGenerate(m.eResource(), m, version));
102+
return result;
103+
}
104+
105+
public List<Path> getFileList(String dslSourceDir, String suffix) throws Exception {
106+
LOGGER.info("getFileList ... looking for files with suffix {} in {}", suffix, dslSourceDir);
107+
108+
if (dslSourceDir == null) {
109+
throw new Exception("Initialization failure: source dsl path not specified");
110+
}
111+
112+
if (suffix == null) {
113+
throw new Exception("Initialization failure: extension not specified");
114+
}
115+
116+
Path sourcePath = Paths.get(dslSourceDir);
117+
if (!Files.exists(sourcePath)) {
118+
throw new Exception("Unable to generate Python from non-existent source directory: " + dslSourceDir);
119+
}
120+
121+
List<Path> result = new ArrayList<>();
122+
File directory = new File(dslSourceDir);
123+
if (directory.isDirectory()) {
124+
File[] files = directory.listFiles(file -> file.isFile() && file.getName().endsWith(suffix));
125+
if (files != null) {
126+
for (File file : files) {
127+
result.add(file.toPath());
128+
}
129+
}
130+
}
131+
LOGGER.info("getFileList ... found {} files in {}", result.size(), dslSourceDir);
132+
return result;
133+
}
134+
135+
public List<Path> getFileListWithRecursion(String dslSourceDir, String suffix) throws Exception {
136+
LOGGER.info("getFileListWithRecursion ... looking for files with suffix {} in {}", suffix, dslSourceDir);
137+
138+
if (dslSourceDir == null) {
139+
throw new Exception("Initialization failure: source dsl path not specified");
140+
}
141+
142+
if (suffix == null) {
143+
throw new Exception("Initialization failure: extension not specified");
144+
}
145+
146+
Path sourcePath = Paths.get(dslSourceDir);
147+
if (!Files.exists(sourcePath)) {
148+
throw new Exception("Unable to generate Python from non-existent source directory: " + dslSourceDir);
149+
}
150+
151+
List<Path> result = new ArrayList<>();
152+
153+
try (Stream<Path> stream = Files.walk(sourcePath, FileVisitOption.FOLLOW_LINKS)) {
154+
result.addAll(
155+
stream
156+
.filter(path -> Files.isRegularFile(path) && path.toString().endsWith(suffix))
157+
.collect(Collectors.toList()));
158+
} catch (IOException e) {
159+
throw e;
160+
}
161+
LOGGER.info("getFileListWithRecursion ... found {} files in {}", result.size(), dslSourceDir);
162+
return result;
163+
}
164+
165+
public void generatePythonFromDSLFiles(List<Path> dslFilePathList, String outputPath) throws Exception {
166+
LOGGER.info("generatePythonFromDSLFiles ... generating Python from {} rosetta files", dslFilePathList.size());
167+
XtextResourceSet resourceSet = resourceSetProvider.get();
168+
// Assuming parseHelper.parse is what is meant by 'parse' in the Xtend file,
169+
// but Xtend had 'extension ParseHelper', so 'parse' calls ParseHelper.parse.
170+
parseHelper.parse(ModelHelper.commonTestTypes, resourceSet);
171+
172+
resourceSet.getResource(URI.createURI("classpath:/model/basictypes.rosetta"), true);
173+
resourceSet.getResource(URI.createURI("classpath:/model/annotations.rosetta"), true);
174+
175+
List<Resource> resources = dslFilePathList.stream()
176+
.map(it -> resourceSet.getResource(URI.createURI(it.toString()), true))
177+
.collect(Collectors.toList());
178+
179+
LOGGER.info("generatePythonFromDSLFiles ... converted to resources");
180+
181+
List<RosettaModel> rosettaModels = resources.stream()
182+
.flatMap(r -> r.getContents().stream())
183+
.filter(RosettaModel.class::isInstance)
184+
.map(RosettaModel.class::cast)
185+
.collect(Collectors.toList());
186+
187+
LOGGER.info("generatePythonFromDSLFiles ... created {} rosetta models", rosettaModels.size());
188+
189+
if (rosettaModels.isEmpty()) {
190+
return;
191+
}
192+
193+
RosettaModel m = rosettaModels.get(0);
194+
String version = m.getVersion();
195+
Map<String, CharSequence> generatedFiles = new HashMap<>();
196+
197+
generator.beforeAllGenerate(resourceSet, rosettaModels, version);
198+
for (RosettaModel model : rosettaModels) {
199+
LOGGER.info("generatePythonFromDSLFiles ... processing model: {}", model.getName());
200+
Map<String, CharSequence> python = generatePythonFromRosettaModel(model, resourceSet);
201+
generatedFiles.putAll(python);
202+
}
203+
generatedFiles.putAll(generator.afterAllGenerate(resourceSet, rosettaModels, version));
204+
205+
cleanFolder(outputPath);
206+
writeFiles(outputPath, generatedFiles);
207+
LOGGER.info("generatePythonFromDSLFiles ... done");
208+
}
209+
210+
public Map<String, CharSequence> generatePythonFromString(String modelContent) throws Exception {
211+
// model.parseRosettaWithNoErrors in Xtend ->
212+
// modelHelper.parseRosettaWithNoErrors(modelContent)
213+
RosettaModel m = modelHelper.parseRosettaWithNoErrors(modelContent);
214+
ResourceSet resourceSet = m.eResource().getResourceSet();
215+
String version = m.getVersion();
216+
217+
Map<String, CharSequence> result = new HashMap<>();
218+
result.putAll(generator.beforeAllGenerate(resourceSet, Collections.singletonList(m), version));
219+
result.putAll(generator.beforeGenerate(m.eResource(), m, version));
220+
result.putAll(generator.generate(m.eResource(), m, version));
221+
result.putAll(generator.afterGenerate(m.eResource(), m, version));
222+
result.putAll(generator.afterAllGenerate(resourceSet, Collections.singletonList(m), version));
223+
return result;
224+
}
225+
226+
public String generatePythonAndExtractBundle(String model) throws Exception {
227+
Map<String, CharSequence> python = generatePythonFromString(model);
228+
return python.get("src/com/_bundle.py").toString();
229+
}
230+
231+
public void assertGeneratedContainsExpectedString(String generated, String expectedString) {
232+
String msg = String.format("""
233+
generated Python does not match expected
234+
Expected:
235+
%s
236+
Generated:
237+
%s""", expectedString, generated);
238+
239+
assertTrue(generated.contains(expectedString), msg);
240+
}
241+
242+
public void assertBundleContainsExpectedString(String model, String expectedString) throws Exception {
243+
// Generate the bundle using the existing function
244+
String generatedBundle = generatePythonAndExtractBundle(model);
245+
assertGeneratedContainsExpectedString(generatedBundle, expectedString);
246+
}
247+
}

0 commit comments

Comments
 (0)