/*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.truffle.api.test.source;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.net.URL;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
import org.junit.Assert;
import org.junit.Test;
import com.oracle.truffle.api.source.MissingMIMETypeException;
import com.oracle.truffle.api.source.MissingNameException;
import com.oracle.truffle.api.source.Source;
public class SourceBuilderTest {
@Test
public void assignMimeTypeAndIdentity() {
Source.Builder<RuntimeException, MissingMIMETypeException, RuntimeException> builder = Source.newBuilder("// a comment\n").name("Empty comment");
Source s1 = builder.mimeType("content/unknown").build();
assertEquals("No mime type assigned", "content/unknown", s1.getMimeType());
Source s2 = builder.mimeType("text/x-c").build();
assertEquals("They have the same content", s1.getCode(), s2.getCode());
assertNotEquals("But different type", s1.getMimeType(), s2.getMimeType());
assertNotEquals("So they are different", s1, s2);
assertNotNull("Every source must have URI", s1.getURI());
assertEquals("Source with different MIME type has the same URI", s1.getURI(), s2.getURI());
}
@Test
public void assignMimeTypeAndIdentityForReader() throws IOException {
String text = "// Hello";
Source.Builder<IOException, MissingMIMETypeException, RuntimeException> builder = Source.newBuilder(new StringReader(text)).name("test.txt");
Source s1 = builder.name("Hello").mimeType("text/plain").build();
assertEquals("Base type assigned", "text/plain", s1.getMimeType());
Source s2 = builder.mimeType("text/x-c").build();
assertEquals("They have the same content", s1.getCode(), s2.getCode());
assertEquals("// Hello", s1.getCode());
assertNotEquals("But different type", s1.getMimeType(), s2.getMimeType());
assertNotEquals("So they are different", s1, s2);
assertNotNull("Every source must have URI", s1.getURI());
assertEquals("Source with different MIME type has the same URI", s1.getURI(), s2.getURI());
}
@Test
public void assignMimeTypeAndIdentityForFile() throws IOException {
File file = File.createTempFile("Hello", ".java").getCanonicalFile();
file.deleteOnExit();
String text;
try (FileWriter w = new FileWriter(file)) {
text = "// Hello";
w.write(text);
}
// JDK8 default fails on OS X: https://bugs.openjdk.java.net/browse/JDK-8129632
String nonCannonical = file.getParent() + File.separatorChar + ".." + File.separatorChar + file.getParentFile().getName() + File.separatorChar + file.getName();
final File nonCannonicalFile = new File(nonCannonical);
assertTrue("Exists, as it is the same file", nonCannonicalFile.exists());
Source.Builder<IOException, RuntimeException, RuntimeException> builder = Source.newBuilder(nonCannonicalFile);
Source s1 = builder.build();
assertEquals("Path is cannonicalized", file.getPath(), s1.getPath());
assertEquals("Name is short", file.getName(), s1.getName());
assertEquals("Recognized as Java", "text/x-java", s1.getMimeType());
Source s2 = builder.mimeType("text/x-c").build();
assertEquals("They have the same content", s1.getCode(), s2.getCode());
assertEquals("// Hello", s1.getCode());
assertNotEquals("But different type", s1.getMimeType(), s2.getMimeType());
assertNotEquals("So they are different", s1, s2);
assertEquals("File URI is used from cannonicalized form", file.toURI(), s1.getURI());
assertEquals("Sources with different MIME type has the same URI", s1.getURI(), s2.getURI());
}
@Test
public void mimeTypeIsDetectedRandomBytes() throws IOException {
File file = File.createTempFile("Hello", ".bin").getCanonicalFile();
file.deleteOnExit();
try (FileOutputStream w = new FileOutputStream(file)) {
w.write(0x04);
w.write(0x05);
}
Source source = Source.newBuilder(file).build();
assertEither(source.getMimeType(), "content/unknown", "application/octet-stream", "text/plain", "application/macbinary");
}
@Test
public void mimeTypeIsDetectedRandomBytesForURI() throws IOException {
File file = File.createTempFile("Hello", ".bin").getCanonicalFile();
file.deleteOnExit();
try (FileOutputStream w = new FileOutputStream(file)) {
w.write(0x04);
w.write(0x05);
}
Source source = Source.newBuilder(file.toURI().toURL()).build();
assertEither(source.getMimeType(), "content/unknown", "application/octet-stream", "text/plain", "application/macbinary");
}
@Test
public void ioExceptionWhenFileDoesntExist() throws Exception {
File file = File.createTempFile("Hello", ".java").getCanonicalFile();
file.delete();
assertFalse("Doesn't exist", file.exists());
Source.Builder<IOException, RuntimeException, RuntimeException> builder = Source.newBuilder(file);
Source s1 = null;
try {
s1 = builder.build();
} catch (IOException e) {
// OK, file doesn't exist
return;
}
fail("No source should be created: " + s1);
}
@Test
public void ioExceptionWhenReaderThrowsIt() throws Exception {
final IOException ioEx = new IOException();
Reader reader = new Reader() {
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
throw ioEx;
}
@Override
public void close() throws IOException {
}
};
Source.Builder<IOException, RuntimeException, RuntimeException> builder = Source.newBuilder(reader).name("unloadable.txt").mimeType("text/plain");
Source s1 = null;
try {
s1 = builder.build();
} catch (IOException e) {
Assert.assertSame(ioEx, e);
return;
}
fail("No source should be created: " + s1);
}
@Test
public void assignMimeTypeAndIdentityForVirtualFile() throws Exception {
File file = File.createTempFile("Hello", ".java").getCanonicalFile();
file.deleteOnExit();
String text = "// Hello";
Source.Builder<RuntimeException, RuntimeException, RuntimeException> builder = Source.newBuilder(file).content(text).mimeType("text/x-java");
// JDK8 default fails on OS X: https://bugs.openjdk.java.net/browse/JDK-8129632
Source s1 = builder.build();
assertEquals("Recognized as Java", "text/x-java", s1.getMimeType());
Source s2 = builder.mimeType("text/x-c").build();
assertEquals("They have the same content", s1.getCode(), s2.getCode());
assertEquals("// Hello", s1.getCode());
assertNotEquals("But different type", s1.getMimeType(), s2.getMimeType());
assertNotEquals("So they are different", s1, s2);
assertEquals("File URI", file.toURI(), s1.getURI());
assertEquals("Source with different MIME type has the same URI", s1.getURI(), s2.getURI());
}
@Test
public void noIOWhenContentSpecified() {
File file = new File("some.js");
String text = "// Hello";
Source source = Source.newBuilder(file).content(text).build();
assertEquals("The content has been changed", text, source.getCode());
assertNotNull("Mime type specified", source.getMimeType());
assertTrue("Recognized as JavaScript", source.getMimeType().endsWith("/javascript"));
assertEquals("some.js", source.getName());
}
@Test
public void fromTextWithFileURI() {
File file = new File("some.js");
String text = "// Hello";
Source source = Source.newBuilder(text).uri(file.toURI()).mimeType("plain/text").name("another.js").build();
assertEquals("The content has been changed", text, source.getCode());
assertNotNull("Mime type specified", source.getMimeType());
assertEquals("Assigned MIME type", "plain/text", source.getMimeType());
assertEquals("another.js", source.getName());
assertEquals("Using the specified URI", file.toURI(), source.getURI());
}
@Test
public void assignMimeTypeAndIdentityForURL() throws IOException {
File file = File.createTempFile("Hello", ".java");
file.deleteOnExit();
String text;
try (FileWriter w = new FileWriter(file)) {
text = "// Hello";
w.write(text);
}
Source.Builder<IOException, RuntimeException, RuntimeException> builder = Source.newBuilder(file.toURI().toURL()).name("Hello.java");
Source s1 = builder.build();
assertEquals("Recognized as Java", "text/x-java", s1.getMimeType());
Source s2 = builder.mimeType("text/x-c").build();
assertEquals("They have the same content", s1.getCode(), s2.getCode());
assertEquals("// Hello", s1.getCode());
assertNotEquals("But different type", s1.getMimeType(), s2.getMimeType());
assertNotEquals("So they are different", s1, s2);
assertEquals("File URI", file.toURI(), s1.getURI());
assertEquals("Source with different MIME type has the same URI", s1.getURI(), s2.getURI());
}
@Test
public void literalSources() throws IOException {
final String code = "test code";
final String description = "test description";
final Source literal = Source.newBuilder(code).name(description).mimeType("content/unknown").build();
assertEquals(literal.getName(), description);
assertEquals(literal.getCode(), code);
assertNull(literal.getURL());
assertNotNull("Every source must have URI", literal.getURI());
final char[] buffer = new char[code.length()];
assertEquals(literal.getReader().read(buffer), code.length());
assertEquals(new String(buffer), code);
}
@Test
public void clientManagedSourceChange() {
final String path = "test.input";
final String code1 = "test\ntest";
final String code2 = "test\ntest\nlonger\ntest";
final Source source1 = Source.newBuilder(new File(path)).content(code1).mimeType("content/unknown").build();
assertEquals(source1.getCode(), code1);
assertEquals(source1.getLineNumber(code1.length() - 1), 2);
final Source source2 = Source.newBuilder(new File(path)).content(code2).mimeType("content/unknown").build();
assertEquals(source2.getCode(), code2);
assertEquals(source2.getLineNumber(code2.length() - 1), 4);
assertEquals("File URI", new File(path).toURI(), source1.getURI());
assertEquals("File sources with different content have the same URI", source1.getURI(), source2.getURI());
}
@Test
public void clientManagedSourceChangeAbsolute() {
final String path = new File("test.input").getAbsolutePath();
final String code1 = "test\ntest";
final String code2 = "test\ntest\nlonger\ntest";
final Source source1 = Source.newBuilder(new File(path)).content(code1).mimeType("x-application/input").build();
assertEquals(source1.getCode(), code1);
assertEquals(source1.getLineNumber(code1.length() - 1), 2);
final Source source2 = Source.newBuilder(new File(path)).content(code2).mimeType("x-application/input").build();
assertEquals(source2.getCode(), code2);
assertEquals(source2.getLineNumber(code2.length() - 1), 4);
assertEquals("File URI", new File("test.input").getAbsoluteFile().toURI(), source1.getURI());
assertEquals("File sources with different content have the same URI", source1.getURI(), source2.getURI());
}
@Test
public void jarURLGetsAName() throws IOException {
File sample = File.createTempFile("sample", ".jar");
sample.deleteOnExit();
JarOutputStream os = new JarOutputStream(new FileOutputStream(sample));
os.putNextEntry(new ZipEntry("x.js"));
os.write("Hi!".getBytes("UTF-8"));
os.closeEntry();
os.close();
URL resource = new URL("jar:" + sample.toURI() + "!/x.js");
assertNotNull("Resource found", resource);
assertEquals("JAR protocol", "jar", resource.getProtocol());
Source s = Source.newBuilder(resource).build();
assertEquals("Hi!", s.getCode());
assertEquals("x.js", s.getName());
sample.delete();
}
@Test
public void whatAreTheDefaultValuesOfNewFromReader() throws Exception {
StringReader r = new StringReader("Hi!");
Source source = Source.newBuilder(r).name("almostEmpty").mimeType("text/plain").build();
assertEquals("Hi!", source.getCode());
assertEquals("almostEmpty", source.getName());
assertNull(source.getPath());
assertNotNull(source.getURI());
assertEquals("truffle", source.getURI().getScheme());
assertNull(source.getURL());
assertEquals("text/plain", source.getMimeType());
}
@Test
public void fileWithReload() throws Exception {
File file = File.createTempFile("ChangeMe", ".java");
file.deleteOnExit();
String text;
try (FileWriter w = new FileWriter(file)) {
text = "// Hello";
w.write(text);
}
Source original = Source.newBuilder(file).build();
assertEquals(text, original.getCode());
String newText;
try (FileWriter w = new FileWriter(file)) {
newText = "// Hello World!";
w.write(newText);
}
Source reloaded = Source.newBuilder(file).build();
assertNotEquals(original, reloaded);
assertEquals("New source has the new text", newText, reloaded.getCode());
assertEquals("Old source1 remains unchanged", text, original.getCode());
}
@Test
public void normalSourceIsNotInter() {
Source source = Source.newBuilder("anything").mimeType("text/plain").name("anyname").build();
assertFalse("Not internal", source.isInternal());
assertFalse("Not interactive", source.isInteractive());
}
@Test
public void markSourceAsInternal() {
Source source = Source.newBuilder("anything internal").mimeType("text/plain").name("internalsrc").internal().build();
assertTrue("This source is internal", source.isInternal());
}
@Test
public void markSourceAsInteractive() {
Source source = Source.newBuilder("anything interactive").mimeType("text/plain").name("interactivesrc").interactive().build();
assertTrue("This source is interactive", source.isInteractive());
}
public void subSourceHashAndEquals() {
Source src = Source.newBuilder("One Two Three").name("counting.en").mimeType("content/unknown").build();
Source one = src.subSource(0, 3);
Source two = src.subSource(4, 3);
Source three = src.subSource(8, src.getLength() - 8);
Source oneSnd = src.subSource(0, 3);
Source twoSnd = src.subSource(4, 3);
Source threeSnd = src.subSource(8, src.getLength() - 8);
assertNotEquals("One: " + one.getCode() + " two: " + two.getCode(), one, two);
assertNotEquals(three, two);
assertNotEquals(one, three);
assertNotEquals(oneSnd, twoSnd);
assertEquals(one, oneSnd);
assertEquals(two, twoSnd);
assertEquals(three, threeSnd);
assertEquals(one.hashCode(), oneSnd.hashCode());
assertEquals(two.hashCode(), twoSnd.hashCode());
assertEquals(three.hashCode(), threeSnd.hashCode());
assertEquals(src.getURI(), one.getURI());
assertEquals(src.getURI(), two.getURI());
assertEquals(src.getURI(), three.getURI());
}
@Test
public void subSourceFromTwoFiles() throws Exception {
File f1 = File.createTempFile("subSource", ".js").getCanonicalFile();
File f2 = File.createTempFile("subSource", ".js").getCanonicalFile();
try (FileWriter w = new FileWriter(f1)) {
w.write("function test() {\n" + " return 1;\n" + "}\n");
}
try (FileWriter w = new FileWriter(f2)) {
w.write("function test() {\n" + " return 1;\n" + "}\n");
}
Source s1 = Source.newBuilder(f1).build();
Source s2 = Source.newBuilder(f2).build();
assertNotEquals("Different sources", s1, s2);
assertEquals("But same content", s1.getCode(), s2.getCode());
Source sub1 = s1.subSource(0, 8);
Source sub2 = s2.subSource(0, 8);
assertNotEquals("Different sub sources", sub1, sub2);
assertEquals("with the same content", sub1.getCode(), sub2.getCode());
assertNotEquals("and different hash", sub1.hashCode(), sub2.hashCode());
assertEquals(f1.toURI(), s1.getURI());
assertEquals(s1.getURI(), sub1.getURI());
assertEquals(f2.toURI(), s2.getURI());
assertEquals(s2.getURI(), sub2.getURI());
}
@Test
public void throwsErrorNameCannotBeNull() {
try {
Source.newBuilder("Hi").name(null);
} catch (NullPointerException ex) {
return;
}
fail("Expecting NullPointerException");
}
@Test
public void throwsErrorIfNameIsNull() {
try {
Source.newBuilder("Hi").mimeType("content/unknown").build();
} catch (MissingNameException ex) {
// OK
return;
}
fail("Expecting MissingNameException");
}
@Test
public void throwsErrorIfMIMETypeIsNull() {
try {
Source.newBuilder("Hi").name("unknown.txt").build();
} catch (MissingMIMETypeException ex) {
// OK
return;
}
fail("Expecting MissingNameException");
}
@Test
public void succeedsWithBothNameAndMIME() {
Source src = Source.newBuilder("Hi").mimeType("content/unknown").name("unknown.txt").build();
assertNotNull(src);
}
private static void assertEither(String mimeType, String... expected) {
for (String e : expected) {
if (mimeType.equals(e)) {
return;
}
}
fail("Unexpected MIME type: " + mimeType);
}
}