/*
[The "BSD license"]
Copyright (c) 2009 Terence Parr
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.stringtemplate.v4.test;
import org.junit.Test;
import org.stringtemplate.v4.*;
import org.stringtemplate.v4.misc.ErrorBuffer;
import static org.junit.Assert.*;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
public class TestImports extends BaseTest {
@Test public void testImportDir() throws Exception {
/*
dir1
g.stg has a() that imports dir2 with absolute path
dir2
a.st
b.st
*/
String dir1 = getRandomDir()+"/dir1";
String dir2 = getRandomDir()+"/dir2";
String gstr =
"import \""+dir2+"\"\n" +
"a() ::= <<dir1 a>>\n";
writeFile(dir1, "g.stg", gstr);
String a = "a() ::= <<dir2 a>>\n";
String b = "b() ::= <<dir2 b>>\n";
writeFile(dir2, "a.st", a);
writeFile(dir2, "b.st", b);
STGroup group = new STGroupFile(dir1+"/g.stg");
ST st = group.getInstanceOf("b"); // visible only if import worked
String expected = "dir2 b";
String result = st.render();
assertEquals(expected, result);
}
@Test public void testImportDirInJarViaCLASSPATH() throws Exception {
/*
sub
g.stg has a() and imports base via classpath
base
a.st
b.st
*/
String root = getRandomDir();
String sub = root +"/sub";
String base = root +"/base";
String gstr =
"import \"base\"\n" +
"a() ::= <<sub a>>\n";
writeFile(sub, "g.stg", gstr);
writeFile(base, "a.st", "a() ::= <<base a>>\n");
writeFile(base, "b.st", "b() ::= <<base b>>\n");
writeTestFile(
"STGroup group = new STGroupFile(\"sub/g.stg\");\n" +
"ST st = group.getInstanceOf(\"b\");\n"+ // visible only if import worked
"String result = st.render();\n",
root);
compile("Test.java", root);
// jar has sub, base as dirs in CLASSPATH
jar("test.jar", new String[]{"sub", "base", "Test.class"}, root);
deleteFile(root+"/sub");
deleteFile(root+"/base");
String result = java("Test", "test.jar", root);
String expected = "base b\n";
assertEquals(expected, result);
}
@Test public void testImportGroupAtSameLevelInJar() throws Exception {
/*
org/foo/templates
main.stg imports lib.stg
lib.stg
*/
String root = getRandomDir();
System.out.println(root);
String dir = root+"/org/foo/templates";
String main =
"import \"lib.stg\"\n" + // should see in same dir as main.stg
"a() ::= <<main a calls <bold()>!>>\n"+
"b() ::= <<main b>>\n";
writeFile(dir, "main.stg", main);
String lib =
"bold() ::= <<lib bold>>\n";
writeFile(dir, "lib.stg", lib);
writeTestFile(
"STGroup group = new STGroupFile(\"org/foo/templates/main.stg\");\n" +
"ST st = group.getInstanceOf(\"a\");\n"+
"String result = st.render();\n",
root);
compile("Test.java", root);
jar("test.jar", new String[] {"org", "Test.class"}, root);
deleteFile(root+"/org");
String result = java("Test", "test.jar", root);
String expected = "main a calls lib bold!\n";
assertEquals(expected, result);
}
@Test public void testImportGroupAtSameLevelInJar2() throws Exception {
/*
org/foo/templates
main.stg imports lib.stg
lib.stg
*/
String root = getRandomDir();
System.out.println(root);
String dir = root+"/org/foo/templates";
String main =
"import \"lib.stg\"\n" + // should see in same dir as main.stg
"a() ::= <<main a calls <bold()>!>>\n"+
"b() ::= <<main b>>\n";
writeFile(dir, "main.stg", main);
String lib =
"bold() ::= <<lib bold>>\n";
writeFile(dir, "lib.stg", lib);
writeTestFile(
"URL url = new STGroup().getURL(\"org/foo/templates/main.stg\");\n" +
"STGroup group = new STGroupFile(url,\"UTF-8\",'<','>');\n" +
"ST st = group.getInstanceOf(\"a\");\n"+
"String result = st.render();\n",
root);
compile("Test.java", root);
jar("test.jar", new String[] {"org", "Test.class"}, root);
deleteFile(root+"/org");
String result = java("Test", "test.jar", root);
String expected = "main a calls lib bold!\n";
assertEquals(expected, result);
}
@Test public void testImportGroupInJarViaCLASSPATH() throws Exception {
/*
org/foo/templates
main.stg imports org/foo/lib/lib.stg
org/foo/lib
lib.stg
*/
String root = getRandomDir();
System.out.println(root);
String dir = root+"/org/foo/templates";
String main =
"import \"org/foo/lib/lib.stg\"\n" +
"a() ::= <<main a calls <bold()>!>>\n"+
"b() ::= <<main b>>\n";
writeFile(dir, "main.stg", main);
String lib =
"bold() ::= <<lib bold>>\n";
dir = root+"/org/foo/lib";
writeFile(dir, "lib.stg", lib);
writeTestFile(
"STGroup group = new STGroupFile(\"org/foo/templates/main.stg\");\n" +
"ST st = group.getInstanceOf(\"a\");\n"+
"String result = st.render();\n",
root);
compile("Test.java", root);
jar("test.jar", new String[] {"org", "Test.class"}, root);
deleteFile(root+"/org");
String result = java("Test", "test.jar", root);
String expected = "main a calls lib bold!\n";
assertEquals(expected, result);
}
@Test public void testImportTemplateFileInJarViaCLASSPATH() throws Exception {
/*
org/foo/templates
main.stg imports foo.st
foo.st
*/
String root = getRandomDir();
System.out.println(root);
String dir = root+"/org/foo/templates";
String main =
"import \"foo.st\"\n" + // should see in same dir as main.stg
"a() ::= <<main a calls <foo()>!>>\n"+
"b() ::= <<main b>>\n";
writeFile(dir, "main.stg", main);
String foo =
"foo() ::= <<foo>>\n";
writeFile(root, "foo.st", foo);
writeTestFile(
"STGroup group = new STGroupFile(\"org/foo/templates/main.stg\");\n" +
"ST st = group.getInstanceOf(\"a\");\n"+
"String result = st.render();\n",
root);
compile("Test.java", root);
jar("test.jar", new String[] {"org", "Test.class"}, root);
deleteFile(root+"/org");
String result = java("Test", "test.jar", root);
String expected = "main a calls foo!\n";
assertEquals(expected, result);
}
@Test public void testImportRelativeDir() throws Exception {
/*
dir
g.stg has a() that imports subdir with relative path
subdir
a.st
b.st
c.st
*/
String dir = getRandomDir();
String gstr =
"import \"subdir\"\n" + // finds subdir in dir
"a() ::= <<dir1 a>>\n";
writeFile(dir, "g.stg", gstr);
String a = "a() ::= <<subdir a>>\n";
String b = "b() ::= <<subdir b>>\n";
String c = "c() ::= <<subdir c>>\n";
writeFile(dir, "subdir/a.st", a);
writeFile(dir, "subdir/b.st", b);
writeFile(dir, "subdir/c.st", c);
STGroup group = new STGroupFile(dir +"/g.stg");
ST st = group.getInstanceOf("b"); // visible only if import worked
String expected = "subdir b";
String result = st.render();
assertEquals(expected, result);
st = group.getInstanceOf("c");
result = st.render();
expected = "subdir c";
assertEquals(expected, result);
}
@Test public void testImportRelativeDirInJarViaCLASSPATH() throws Exception {
/*
org/foo/templates
g.stg has a() that imports subdir with relative path
subdir
a.st
b.st
c.st
*/
String root = getRandomDir();
System.out.println(root);
String dir = root+"/org/foo/templates";
String gstr =
"import \"subdir\"\n" + // finds subdir in dir
"a() ::= <<dir1 a>>\n";
writeFile(dir, "g.stg", gstr);
String a = "a() ::= <<subdir a>>\n";
String b = "b() ::= <<subdir b>>\n";
String c = "c() ::= <<subdir b>>\n";
writeFile(dir, "subdir/a.st", a);
writeFile(dir, "subdir/b.st", b);
writeFile(dir, "subdir/c.st", c);
jar("test.jar", new String[] {"org"}, root);
deleteFile(root + "/org");
File path = new File(root + File.separatorChar + "test.jar");
assertTrue(path.isFile());
URLClassLoader loader = new URLClassLoader(new URL[] { path.toURI().toURL() });
STGroup group = new STGroupFile(loader.getResource("org/foo/templates/g.stg"), "UTF-8", '<', '>');
ST st = group.getInstanceOf("b");
String result = st.render();
String expected = "subdir b";
assertEquals(expected, result);
}
@Test public void testEmptyGroupImportGroupFileSameDir() throws Exception {
/*
dir
group1.stg that imports group2.stg in same dir with just filename
group2.stg has c()
*/
String dir = getRandomDir();
String groupFile =
"import \"group2.stg\"\n";
writeFile(dir, "group1.stg", groupFile);
groupFile =
"c() ::= \"g2 c\"\n";
writeFile(dir, "group2.stg", groupFile);
STGroup group1 = new STGroupFile(dir+"/group1.stg");
ST st = group1.getInstanceOf("c"); // should see c()
String expected = "g2 c";
String result = st.render();
assertEquals(expected, result);
}
@Test public void testImportGroupFileSameDir() throws Exception {
/*
dir
group1.stg that imports group2.stg in same dir with just filename
group2.stg has c()
*/
String dir = getRandomDir();
String groupFile =
"import \"group2.stg\"\n" +
"a() ::= \"g1 a\"\n"+
"b() ::= \"<c()>\"\n";
writeFile(dir, "group1.stg", groupFile);
groupFile =
"c() ::= \"g2 c\"\n";
writeFile(dir, "group2.stg", groupFile);
STGroup group1 = new STGroupFile(dir+"/group1.stg");
ST st = group1.getInstanceOf("c"); // should see c()
String expected = "g2 c";
String result = st.render();
assertEquals(expected, result);
}
@Test public void testImportRelativeGroupFile() throws Exception {
/*
dir
group1.stg that imports group2.stg in same dir with just filename
subdir
group2.stg has c()
*/
String dir = getRandomDir();
String groupFile =
"import \"subdir/group2.stg\"\n" +
"a() ::= \"g1 a\"\n"+
"b() ::= \"<c()>\"\n";
writeFile(dir, "group1.stg", groupFile);
groupFile =
"c() ::= \"g2 c\"\n";
writeFile(dir, "subdir/group2.stg", groupFile);
STGroup group1 = new STGroupFile(dir+"/group1.stg");
ST st = group1.getInstanceOf("c"); // should see c()
String expected = "g2 c";
String result = st.render();
assertEquals(expected, result);
}
@Test public void testImportTemplateFileSameDir() throws Exception {
/*
dir
group1.stg (that imports c.st)
c.st
*/
String dir = getRandomDir();
String groupFile =
"import \"c.st\"\n" +
"a() ::= \"g1 a\"\n"+
"b() ::= \"<c()>\"\n";
writeFile(dir, "group1.stg", groupFile);
writeFile(dir, "c.st", "c() ::= \"c\"\n");
STGroup group1 = new STGroupFile(dir+"/group1.stg");
ST st = group1.getInstanceOf("c"); // should see c()
String expected = "c";
String result = st.render();
assertEquals(expected, result);
}
@Test public void testImportRelativeTemplateFile() throws Exception {
/*
dir
group1.stg that imports c.st
subdir
c.st
*/
String dir = getRandomDir();
String groupFile =
"import \"subdir/c.st\"\n" +
"a() ::= \"g1 a\"\n"+
"b() ::= \"<c()>\"\n";
writeFile(dir, "group1.stg", groupFile);
String stFile =
"c() ::= \"c\"\n";
writeFile(dir, "subdir/c.st", stFile);
STGroup group1 = new STGroupFile(dir+"/group1.stg");
ST st = group1.getInstanceOf("c"); // should see c()
String expected = "c";
String result = st.render();
assertEquals(expected, result);
}
@Test public void testImportTemplateFromAnotherGroupObject() throws Exception {
/*
dir1
a.st
b.st
dir2
a.st
*/
String dir1 = getRandomDir();
String a = "a() ::= <<dir1 a>>\n";
String b = "b() ::= <<dir1 b>>\n";
writeFile(dir1, "a.st", a);
writeFile(dir1, "b.st", b);
String dir2 = getRandomDir();
a = "a() ::= << <b()> >>\n";
writeFile(dir2, "a.st", a);
STGroup group1 = new STGroupDir(dir1);
STGroup group2 = new STGroupDir(dir2);
group2.importTemplates(group1);
ST st = group2.getInstanceOf("b");
String expected = "dir1 b";
String result = st.render();
assertEquals(expected, result);
// do it again, but make a template ref imported template
st = group2.getInstanceOf("a");
expected = " dir1 b ";
result = st.render();
assertEquals(expected, result);
}
@Test public void testImportTemplateInGroupFileFromDir() throws Exception {
/*
dir
x
a.st
y
group.stg has b, c
*/
String dir = getRandomDir();
writeFile(dir, "x/a.st", "a() ::= << <b()> >>");
String groupFile =
"b() ::= \"group file b\"\n"+
"c() ::= \"group file c\"\n";
writeFile(dir, "y/group.stg", groupFile);
STGroup group1 = new STGroupDir(dir+"/x");
STGroup group2 = new STGroupFile(dir+"/y/group.stg");
group1.importTemplates(group2);
ST st = group1.getInstanceOf("a");
String expected = " group file b ";
String result = st.render();
assertEquals(expected, result);
}
@Test public void testImportTemplateInGroupFileFromGroupFile() throws Exception {
String dir = getRandomDir();
String groupFile =
"a() ::= \"g1 a\"\n"+
"b() ::= \"<c()>\"\n";
writeFile(dir, "x/group.stg", groupFile);
groupFile =
"b() ::= \"g2 b\"\n"+
"c() ::= \"g2 c\"\n";
writeFile(dir, "y/group.stg", groupFile);
STGroup group1 = new STGroupFile(dir+"/x/group.stg");
STGroup group2 = new STGroupFile(dir+"/y/group.stg");
group1.importTemplates(group2);
ST st = group1.getInstanceOf("b");
String expected = "g2 c";
String result = st.render();
assertEquals(expected, result);
}
@Test public void testImportTemplateFromSubdir() throws Exception {
// /randomdir/x/subdir/a and /randomdir/y/subdir/b
String dir = getRandomDir();
writeFile(dir, "x/subdir/a.st", "a() ::= << </subdir/b()> >>");
writeFile(dir, "y/subdir/b.st", "b() ::= <<x's subdir/b>>");
STGroup group1 = new STGroupDir(dir+"/x");
STGroup group2 = new STGroupDir(dir+"/y");
group1.importTemplates(group2);
ST st = group1.getInstanceOf("/subdir/a");
String expected = " x's subdir/b ";
String result = st.render();
assertEquals(expected, result);
}
@Test public void testImportTemplateFromGroupFile() throws Exception {
// /randomdir/x/subdir/a and /randomdir/y/subdir.stg which has a and b
String dir = getRandomDir();
writeFile(dir, "x/subdir/a.st", "a() ::= << </subdir/b()> >>");
String groupFile =
"a() ::= \"group file: a\"\n"+
"b() ::= \"group file: b\"\n";
writeFile(dir, "y/subdir.stg", groupFile);
STGroup group1 = new STGroupDir(dir+"/x");
STGroup group2 = new STGroupDir(dir+"/y");
group1.importTemplates(group2);
ST st = group1.getInstanceOf("subdir/a");
String expected = " group file: b ";
String result = st.render();
assertEquals(expected, result);
}
@Test public void testPolymorphicTemplateReference() throws Exception {
String dir1 = getRandomDir();
String b = "b() ::= <<dir1 b>>\n";
writeFile(dir1, "b.st", b);
String dir2 = getRandomDir();
String a = "a() ::= << <b()> >>\n";
b = "b() ::= <<dir2 b>>\n";
writeFile(dir2, "a.st", a);
writeFile(dir2, "b.st", b);
STGroup group1 = new STGroupDir(dir1);
STGroup group2 = new STGroupDir(dir2);
group1.importTemplates(group2);
// normal lookup; a created from dir2 calls dir2.b
ST st = group2.getInstanceOf("a");
String expected = " dir2 b ";
String result = st.render();
assertEquals(expected, result);
// polymorphic lookup; a created from dir1 calls dir2.a which calls dir1.b
st = group1.getInstanceOf("a");
expected = " dir1 b ";
result = st.render();
assertEquals(expected, result);
}
@Test public void testSuper() throws Exception {
String dir1 = getRandomDir();
String a = "a() ::= <<dir1 a>>\n";
String b = "b() ::= <<dir1 b>>\n";
writeFile(dir1, "a.st", a);
writeFile(dir1, "b.st", b);
String dir2 = getRandomDir();
a = "a() ::= << [<super.a()>] >>\n";
writeFile(dir2, "a.st", a);
STGroup group1 = new STGroupDir(dir1);
STGroup group2 = new STGroupDir(dir2);
group2.importTemplates(group1);
ST st = group2.getInstanceOf("a");
String expected = " [dir1 a] ";
String result = st.render();
assertEquals(expected, result);
}
@Test public void testUnloadImportedTemplate() throws Exception {
String dir1 = getRandomDir();
String a = "a() ::= <<dir1 a>>\n";
String b = "b() ::= <<dir1 b>>\n";
writeFile(dir1, "a.st", a);
writeFile(dir1, "b.st", b);
String dir2 = getRandomDir();
a = "a() ::= << <b()> >>\n";
writeFile(dir2, "a.st", a);
STGroup group1 = new STGroupDir(dir1);
STGroup group2 = new STGroupDir(dir2);
group2.importTemplates(group1);
ST st = group2.getInstanceOf("a");
ST st2 = group2.getInstanceOf("b");
int originalHashCode = System.identityHashCode(st);
int originalHashCode2 = System.identityHashCode(st2);
group1.unload(); // blast cache
st = group2.getInstanceOf("a");
int newHashCode = System.identityHashCode(st);
assertEquals(originalHashCode==newHashCode, false); // diff objects
String expected = " dir1 b ";
String result = st.render();
assertEquals(expected, result);
st = group2.getInstanceOf("b");
int newHashCode2 = System.identityHashCode(st);
assertEquals(originalHashCode2==newHashCode2, false); // diff objects
result = st.render();
expected = "dir1 b";
assertEquals(expected, result);
}
@Test
public void testUnloadImportedTemplatedSpecifiedInGroupFile() throws Exception {
writeFile(tmpdir, "t.stg",
"import \"g1.stg\"\n\nmain() ::= <<\nv1-<f()>\n>>");
writeFile(tmpdir, "g1.stg", "f() ::= \"g1\"");
writeFile(tmpdir, "g2.stg", "f() ::= \"g2\"\nf2() ::= \"f2\"\n");
STGroup group = new org.stringtemplate.v4.STGroupFile(tmpdir + "/t.stg");
ST st = group.getInstanceOf("main");
assertEquals("v1-g1", st.render());
// Change the imports of group t.
writeFile(tmpdir, "t.stg",
"import \"g2.stg\"\n\nmain() ::= <<\nv2-<f()>;<f2()>\n>>");
group.unload(); // will also unload already imported groups
st = group.getInstanceOf("main");
assertEquals("v2-g2;f2", st.render());
}
/** Cannot import from a group file unless it's the root.
*/
@Test public void testGroupFileInDirImportsAnotherGroupFile() throws Exception {
// /randomdir/group.stg with a() imports /randomdir/imported.stg with b()
// can't have groupdir then groupfile inside that imports
String dir = getRandomDir();
String groupFile =
"import \"imported.stg\"\n" +
"a() ::= \"a: <b()>\"\n";
writeFile(dir, "group.stg", groupFile);
String importedFile =
"b() ::= \"b\"\n";
writeFile(dir, "imported.stg", importedFile);
STErrorListener errors = new ErrorBuffer();
STGroup group = new STGroupDir(dir);
group.setListener(errors);
group.getInstanceOf("/group/a");
String result = errors.toString();
String expecting =
"import illegal in group files embedded in STGroupDirs; import \"imported.stg\" in STGroupDir";
assertTrue(result.contains(expecting));
}
@Test public void testGroupFileInDirImportsAGroupDir() throws Exception {
/*
dir
g.stg has a() that imports subdir with relative path
subdir
b.st
c.st
*/
String dir = getRandomDir();
String gstr =
"import \"subdir\"\n" + // finds subdir in dir
"a() ::= \"a: <b()>\"\n";
writeFile(dir, "g.stg", gstr);
writeFile(dir, "subdir/b.st", "b() ::= \"b: <c()>\"\n");
writeFile(dir, "subdir/c.st", "c() ::= <<subdir c>>\n");
STGroup group = new STGroupFile(dir +"/g.stg");
ST st = group.getInstanceOf("a");
String expected = "a: b: subdir c";
String result = st.render();
assertEquals(expected, result);
}
}