1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.xsdc.tests;
18 
19 import com.android.xsdc.FileSystem;
20 import com.android.xsdc.XmlSchema;
21 import com.android.xsdc.XsdHandler;
22 import com.android.xsdc.java.JavaCodeGenerator;
23 
24 import javax.tools.*;
25 import javax.xml.parsers.SAXParser;
26 import javax.xml.parsers.SAXParserFactory;
27 
28 import java.io.*;
29 import java.net.URI;
30 import java.util.ArrayList;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Locale;
34 import java.util.Map;
35 
36 import static org.junit.Assert.fail;
37 
38 class TestHelper {
39     static class InMemoryJavaFileObject extends SimpleJavaFileObject {
40         private final String contents;
41 
InMemoryJavaFileObject(String className, String contents)42         InMemoryJavaFileObject(String className, String contents) {
43             super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension),
44                     Kind.SOURCE);
45             this.contents = contents;
46         }
47 
48         @Override
getCharContent(boolean ignoreEncodingErrors)49         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
50             return contents;
51         }
52     }
53 
54     static class InMemoryJavaClassObject extends SimpleJavaFileObject {
55         private ByteArrayOutputStream baos;
56         private String name;
57 
InMemoryJavaClassObject(String name, Kind kind)58         InMemoryJavaClassObject(String name, Kind kind) {
59             super(URI.create("string:///" + name.replace('.', '/') + kind.extension), kind);
60             baos = new ByteArrayOutputStream();
61             this.name = name;
62         }
63 
getBytes()64         byte[] getBytes() {
65             return baos.toByteArray();
66         }
67 
68         @Override
openOutputStream()69         public OutputStream openOutputStream() {
70             return baos;
71         }
72 
getClassName()73         String getClassName() {
74             return name;
75         }
76     }
77 
78     static class InMemoryClassManager extends ForwardingJavaFileManager<JavaFileManager> {
79         private List<InMemoryJavaClassObject> classObjects;
80 
InMemoryClassManager(JavaFileManager fileManager)81         InMemoryClassManager(JavaFileManager fileManager) {
82             super(fileManager);
83             classObjects = new ArrayList<>();
84         }
85 
86         @Override
getJavaFileForOutput(Location location, String name, JavaFileObject.Kind kind, FileObject sibling)87         public JavaFileObject getJavaFileForOutput(Location location, String name,
88                 JavaFileObject.Kind kind, FileObject sibling) {
89             InMemoryJavaClassObject object = new InMemoryJavaClassObject(name, kind);
90             classObjects.add(object);
91             return object;
92         }
93 
getAllClasses()94         List<InMemoryJavaClassObject> getAllClasses() {
95             return classObjects;
96         }
97     }
98 
99     final static String packageName = "test";
100 
parseXsdAndCompile(InputStream in)101     static TestCompilationResult parseXsdAndCompile(InputStream in) throws Exception {
102         SAXParserFactory factory = SAXParserFactory.newInstance();
103         factory.setNamespaceAware(true);
104         SAXParser parser = factory.newSAXParser();
105         XsdHandler xsdHandler = new XsdHandler();
106         parser.parse(in, xsdHandler);
107         XmlSchema xmlSchema = xsdHandler.getSchema();
108         Map<String, StringBuffer> fileOutputMap = new HashMap<>();
109         FileSystem fs = new FileSystem(fileOutputMap);
110         JavaCodeGenerator javaCodeGenerator = new JavaCodeGenerator(xmlSchema, packageName, false);
111         javaCodeGenerator.print(fs);
112         List<JavaFileObject> javaFileObjects = new ArrayList<>();
113         for (Map.Entry<String, StringBuffer> entry : fileOutputMap.entrySet()) {
114             String className = entry.getKey().split("\\.")[0];
115             javaFileObjects.add(
116                     new InMemoryJavaFileObject(className, entry.getValue().toString()));
117         }
118         return new TestCompilationResult(compile(javaFileObjects));
119     }
120 
compile(List<JavaFileObject> javaFileObjects)121     private static List<InMemoryJavaClassObject> compile(List<JavaFileObject> javaFileObjects)
122             throws IOException {
123         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
124         DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
125         List<InMemoryJavaClassObject> ret = null;
126 
127         try (InMemoryClassManager fileManager = new InMemoryClassManager(
128                 compiler.getStandardFileManager(diagnostics, null, null))) {
129             JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics,
130                     null, null, javaFileObjects);
131             boolean success = task.call();
132 
133             if (!success) {
134                 StringBuilder log = new StringBuilder();
135                 log.append("Compilation failed!\n\n");
136                 for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
137                     log.append("Code: ").append(diagnostic.getCode()).append("\n");
138                     log.append("Kind: " + diagnostic.getKind() + "\n");
139                     log.append("Line: " + diagnostic.getLineNumber() + "\n");
140                     log.append("Column: " + diagnostic.getColumnNumber() + "\n");
141                     log.append("Source: " + diagnostic.getSource() + "\n");
142                     log.append("Message: " + diagnostic.getMessage(Locale.getDefault()) + "\n");
143                 }
144                 fail(log.toString());
145             }
146             ret = fileManager.getAllClasses();
147         }
148         return ret;
149     }
150 }
151