package com.github.jknack.antlr4ide.parsetree;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.abego.treelayout.NodeExtentProvider;
import org.abego.treelayout.TreeForTreeLayout;
import org.abego.treelayout.TreeLayout;
import org.abego.treelayout.TreeLayout.DumpConfiguration;
import org.abego.treelayout.util.DefaultConfiguration;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.github.jknack.antlr4ide.generator.ToolOptions;
import com.github.jknack.antlr4ide.generator.ToolOptionsProvider;
import com.github.jknack.antlr4ide.lang.Grammar;
import com.github.jknack.antlr4ide.lang.Import;
import com.github.jknack.antlr4ide.lang.LangFactory;
import com.github.jknack.antlr4ide.lang.LexerRule;
import com.github.jknack.antlr4ide.lang.ParserRule;
import com.github.jknack.antlr4ide.lang.PrequelConstruct;
import com.github.jknack.antlr4ide.lang.Rule;
import com.github.jknack.antlr4ide.lang.Terminal;
import com.github.jknack.antlr4ide.services.ModelExtensions;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@RunWith(PowerMockRunner.class)
public class ParseTreeGeneratorTest {
@Test
@PrepareForTest({ParseTreeGenerator.class, ProcessBuilder.class, ModelExtensions.class,
Socket.class, ServerSocket.class, PrintWriter.class, BufferedReader.class,
InputStreamReader.class })
public void build() throws Exception {
String ruleName = "rule";
String input = "3+4*5";
String sexpression = "( expression ( sum ( number 3 ) '+' ( expression ( prod ( number 2 ) '*' ( number 4 ) ) ) ) ) ";
int freePort = 41900;
ToolOptionsProvider optionsProvider = createMock(ToolOptionsProvider.class);
String toolPath = "/tmp/antlr4-x-complete.jar";
String[] vmArgs = {};
ToolOptions options = createMock(ToolOptions.class);
expect(options.getAntlrTool()).andReturn(toolPath);
expect(options.getOutputDirectory()).andReturn("target/antlr4/generated-sources");
expect(options.vmArguments()).andReturn(vmArgs);
IPath location = Path.fromPortableString("/home/edgar/ws space/project/G4.g4");
IPath prolocation = location.removeLastSegments(1);
IProject project = createMock(IProject.class);
expect(project.getLocation()).andReturn(prolocation);
IWorkspaceRoot workspaceRoot = createMock(IWorkspaceRoot.class);
IFile file = createMock(IFile.class);
expect(file.getLocation()).andReturn(location);
expect(file.getProject()).andReturn(project);
LexerRule plusRule = createMock(LexerRule.class);
expect(plusRule.getName()).andReturn("+");
plusRule.setName("+");
LexerRule starRule = createMock(LexerRule.class);
expect(starRule.getName()).andReturn("*");
starRule.setName("*");
LangFactory langFactory = createMock(LangFactory.class);
expect(langFactory.createLexerRule()).andReturn(plusRule);
expect(langFactory.createLexerRule()).andReturn(starRule);
URI resourceURI = URI.createURI("platform:/resource/project/G.g4");
Resource resource = createMock(Resource.class);
expect(resource.getURI()).andReturn(resourceURI);
EList<PrequelConstruct> prequels = new BasicEList<PrequelConstruct>();
Grammar grammar = createMock(Grammar.class);
expect(grammar.eResource()).andReturn(resource);
expect(grammar.getPrequels()).andReturn(prequels);
Rule rule = createMock(Rule.class);
expect(rule.getName()).andReturn(ruleName);
expect(rule.eContainer()).andReturn(grammar);
expect(workspaceRoot.getFile(Path.fromOSString("/project/G.g4"))).andReturn(file);
expect(optionsProvider.options(file)).andReturn(options);
List<String> command = Lists.newArrayList("java", "-cp",
toolPath + File.pathSeparator + ToolOptionsProvider.RUNTIME_JAR, ParseTreeGenerator.MAIN,
freePort + "");
Process process = createMock(Process.class);
ProcessBuilder pb = PowerMock.createMockAndExpectNew(ProcessBuilder.class, command);
expect(pb.directory(prolocation.toFile())).andReturn(pb);
expect(pb.start()).andReturn(process);
OutputStream out = createMock(OutputStream.class);
PrintWriter writer = PowerMock.createMockAndExpectNew(PrintWriter.class, out, true);
writer.println("parsetree");
writer.println(location.toOSString());
writer.println("null");
writer.println("target/antlr4/generated-sources");
writer.println("0");
writer.println("rule");
writer.println("3+4*5");
writer.close();
InputStream in = createMock(InputStream.class);
InputStreamReader streamReader = PowerMock.createMockAndExpectNew(InputStreamReader.class, in);
BufferedReader reader = PowerMock.createMockAndExpectNew(BufferedReader.class, streamReader);
expect(reader.readLine()).andReturn(sexpression);
expect(reader.readLine()).andReturn(null);
reader.close();
ServerSocket serverSocket = PowerMock.createMockAndExpectNew(ServerSocket.class, 0);
expect(serverSocket.getLocalPort()).andReturn(freePort);
serverSocket.close();
Socket socket = PowerMock.createMockAndExpectNew(Socket.class, "localhost", freePort);
expect(socket.getOutputStream()).andReturn(out);
expect(socket.getInputStream()).andReturn(in);
socket.close();
Rule parserRule = createMock(ParserRule.class);
Rule lexerRule = createMock(LexerRule.class);
Terminal three = createMock(Terminal.class);
PowerMock.mockStatic(ModelExtensions.class);
Map<String, EObject> ruleMap = new HashMap<String, EObject>();
ruleMap.put("parserRule", parserRule);
ruleMap.put("lexerRule", lexerRule);
expect(ModelExtensions.ruleMap(grammar, true)).andReturn(ruleMap);
expect(ModelExtensions.imports(grammar)).andReturn(Sets.<Import> newHashSet());
Object[] mocks = {rule, grammar, resource, workspaceRoot, optionsProvider, project, file,
options, process, parserRule, lexerRule, three, langFactory,
plusRule, starRule, serverSocket, socket, out, in, writer, reader, streamReader };
PowerMock.replay(ProcessBuilder.class, pb, ModelExtensions.class, Socket.class,
ServerSocket.class, PrintWriter.class, BufferedReader.class, InputStreamReader.class);
replay(mocks);
ParseTreeGenerator generator = new ParseTreeGenerator();
generator.setWorkspaceRoot(workspaceRoot);
generator.setOptionsProvider(optionsProvider);
generator.setLangFactory(langFactory);
TreeForTreeLayout<ParseTreeNode> tree = generator.build(rule, input);
assertNotNull(tree);
assertEquals(
"\"expression\"\n" +
" \"sum\"\n" +
" \"number\"\n" +
" \"3\"\n" +
" \"+\"\n" +
" \"expression\"\n" +
" \"prod\"\n" +
" \"number\"\n" +
" \"2\"\n" +
" \"*\"\n" +
" \"number\"\n" +
" \"4\"\n",
dump(tree).replace("\r", ""));
verify(mocks);
PowerMock.verify(ProcessBuilder.class, pb, ModelExtensions.class, Socket.class,
ServerSocket.class, PrintWriter.class, BufferedReader.class, InputStreamReader.class);
}
private String dump(final TreeForTreeLayout<ParseTreeNode> tree) {
DumpConfiguration conf = new DumpConfiguration(" ", false, false);
OutputStream stream = new ByteArrayOutputStream();
new TreeLayout<ParseTreeNode>(tree, new NodeExtentProvider<ParseTreeNode>() {
@Override
public double getHeight(final ParseTreeNode node) {
return 0;
}
@Override
public double getWidth(final ParseTreeNode node) {
return 0;
}
}, new DefaultConfiguration<ParseTreeNode>(10, 10)).dumpTree(new PrintStream(stream), conf);
return stream.toString();
}
}