package org.jmlspecs.openjmltest;
import java.net.URI;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import org.jmlspecs.openjml.Utils;
/** This class makes a mock JavaFileObject. It holds a String as its content
* and is given a pseudo-filename to use, but does not represent an actual file in
* the file system.
* <P>
* Note that we use Kind.OTHER to designate specification (non-.java) files.
*
* @author David Cok
*/
public class TestJavaFileObject extends SimpleJavaFileObject {
/** The content of the mock file */
//@ non_null
protected String content;
/** A fake file name, used when the user does not want to be bothered
* supplying one. We make and cache this because it is a pain to
* deal with exceptions in constructors.
*/
//@ non_null
static final protected URI uritest = makeURI();
/** A utility method to make the URI, so it can handle the exceptions.
* We don't try to recover gracefully if the exception occurs - this is
* just used in testing anyway. */
private static URI makeURI() {
try {
return new URI("file:///TEST.java");
} catch (Exception e) {
System.err.println("CATASTROPHIC EXIT - FAILED TO CONSTRUCT A MOCK URI");
System.exit(3);
return null;
}
}
// TODO - will it be a problem if someone makes two of these objects in
// the same test (since they will have the same name)?
/** A constructor of a JavaFileObject of kind SOURCE,
* with the given content and a made-up file name.
* @param s The content of the file
*/
public TestJavaFileObject(/*@ non_null */ String s) {
super(uritest,Kind.SOURCE);
content = s;
}
/** Constructs a new JavaFileObject of kind SOURCE or OTHER depending on the
* filename extension
* @param filename the filename to use (no leading slash) (null indicates to
* use the internal fabricated filename)
* @param content the content of the pseudo file
* @throws Exception if a URI cannot be created
*/
public TestJavaFileObject(/*@ nullable */String filename, /*@ non_null */String content) throws Exception {
// This takes three slashes because the filename is supposed to be absolute.
// In our case this is not a real file anyway, so we pretend it is absolute.
super(filename == null ? uritest : new URI("file:///" + filename),
filename == null || filename.endsWith(".java") ? Kind.SOURCE : Kind.OTHER);
this.content = content;
}
/** Constructs a new JavaFileObject
* @param uri the URI to use
* @param content the content of the pseudo file
*/
public TestJavaFileObject(/*@ non_null */URI uri, /*@ non_null */String content) {
super(uri,uri.getPath().endsWith(".java") ? Kind.SOURCE : Kind.OTHER);
this.content = content;
}
/** Overrides the parent to provide the content directly from the String
* supplied at construction, rather than reading the file. This is called
* by the system.
*/
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return content;
}
/** Overrides the parent method to allow name compatibility between
* pseudo files of different kinds. TODO _ better description of what the system uses this for
*/
// Don't worry about whether the kinds match, just the file prefix
@Override
public boolean isNameCompatible(String simpleName, Kind kind) {
String s = uri.getPath();
if (kind == Kind.OTHER) {
int i = s.lastIndexOf('/');
s = s.substring(i+1);
return s.startsWith(simpleName);
} else {
String baseName = simpleName + kind.extension;
return s.endsWith("/" + baseName);
}
}
/** Returns true if the receiver and argument represent the same file */
public boolean equals(Object o) {
if (!(o instanceof JavaFileObject)) return false;
return Utils.ifSourcesEqual(this, (JavaFileObject)o);
}
/** A definition of hashCode, since we have a definition of equals */
public int hashCode() {
// Two things are equal if they have the same string, so we'll
// use that for the hashCode
return uri.normalize().getPath().hashCode();
// FIXME -0 this is not right, since if one is a suffix of the other they are equal and should have the same hashCode
}
public String toString() {
//String s = super.toString(); // Something like file:///tt/TestJava.java from TestJavaFileObject
String s = getName(); // Something like tt/TestJava.java
// Note: in stack traces it appears that everything gets dropped up to and including
// the last /
return s;
}
}