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(); } }