/******************************************************************************* * Copyright (c) 2008, 2016 xored software, Inc. and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * xored software, Inc. - initial API and Implementation (Alex Panchenko) *******************************************************************************/ package org.eclipse.dltk.ruby.formatter.tests; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import org.eclipse.dltk.compiler.util.Util; import org.eclipse.dltk.formatter.FormatterDocument; import org.eclipse.dltk.formatter.IFormatterContainerNode; import org.eclipse.dltk.formatter.IFormatterDocument; import org.eclipse.dltk.formatter.IFormatterNode; import org.eclipse.dltk.ruby.formatter.internal.RubyFormatterNodeBuilder; import org.eclipse.dltk.ruby.formatter.internal.RubyParser; import org.eclipse.dltk.ruby.formatter.internal.nodes.FormatterBlockWithBeginEndNode; import org.eclipse.dltk.ui.formatter.FormatterException; import org.jruby.ast.ArgumentNode; import org.jruby.ast.ArrayNode; import org.jruby.ast.ListNode; import org.jruby.ast.Node; import org.jruby.ast.ext.HeredocNode; import org.jruby.ast.visitor.AbstractVisitor; import org.jruby.evaluator.Instruction; import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.parser.RubyParserResult; public class ParserTest extends AbstractRubyFormatterTest { public void testEndKeyword() throws FormatterException { final String input = "class Test" + Util.LINE_SEPARATOR + "end" + Util.LINE_SEPARATOR; final RubyParserResult result = RubyParser.parse(input); assertNotNull(result); final RubyFormatterNodeBuilder builder = new RubyFormatterNodeBuilder(); final IFormatterDocument document = new FormatterDocument(input); final IFormatterContainerNode root = builder.build(result, document); assertNotNull(root); List<IFormatterNode> children = root.getChildren(); assertEquals(2, children.size()); final FormatterBlockWithBeginEndNode classNode = (FormatterBlockWithBeginEndNode) children .get(0); IFormatterNode endNode = classNode.getEnd(); assertEquals(3, endNode.getEndOffset() - endNode.getStartOffset()); assertEquals(input.indexOf("end"), endNode.getStartOffset()); } public void testEmptyHereDoc() throws FormatterException { final String input = "a = <<THIS" + Util.LINE_SEPARATOR + "THIS" + Util.LINE_SEPARATOR; RubyParserResult result = RubyParser.parse(input); assertNotNull(result); } public void testHereDocParser() throws FormatterException { final String id1 = "THIS"; final String[] hereDoc1 = new String[] { "Line 1=a", "Line 2" }; final String id2 = "THAT"; final String[] hereDoc2 = new String[] { "Line 3=b", "Line 4" }; String input = createInput(id1, hereDoc1, id2, hereDoc2); RubyParserResult result = RubyParser.parse(input); assertNotNull(result); final List<HeredocNode> heredocNodes = selectHeredocNodes(result); assertEquals(2, heredocNodes.size()); final HeredocNode doc1 = heredocNodes.get(0); assertTrue(substring(input, doc1.getEndMarkerPosition()) .indexOf(id1) >= 0); final String content1 = substring(input, doc1.getContentPosition()); assertTrue(content1.indexOf(id1) < 0); assertTrue(content1.indexOf(hereDoc1[0]) >= 0); assertTrue(content1.indexOf(hereDoc1[1]) >= 0); final HeredocNode doc2 = heredocNodes.get(1); assertTrue(substring(input, doc2.getEndMarkerPosition()) .indexOf(id2) >= 0); final String content2 = substring(input, doc2.getContentPosition()); assertTrue(content2.indexOf(id2) < 0); assertTrue(content2.indexOf(hereDoc2[0]) >= 0); assertTrue(content2.indexOf(hereDoc2[1]) >= 0); } /** * @param input * @param position */ private String substring(String input, ISourcePosition position) { return input.substring(position.getStartOffset(), position.getEndOffset()); } private String createInput(final String id1, final String[] hereDoc1, final String id2, final String[] hereDoc2) { List<String> lines = new ArrayList<>(); lines.add("def myfunc"); lines.add("print <<\"" + id1 + "\", <<\"" + id2 + "\",1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19"); lines.addAll(Arrays.asList(hereDoc1)); lines.add(id1); lines.addAll(Arrays.asList(hereDoc2)); lines.add(id2); lines.add("end"); String input = joinLines(lines); return input; } private List<HeredocNode> selectHeredocNodes(RubyParserResult result) { final List<HeredocNode> heredocNodes = new ArrayList<>(); result.getAST().accept(new AbstractVisitor() { @Override protected Instruction visitNode(Node visited) { if (visited instanceof HeredocNode) { heredocNodes.add((HeredocNode) visited); } visitChildren(visited); return null; } private void visitChildren(Node visited) { List<Node> children = visited.childNodes(); for (Iterator<Node> i = children.iterator(); i.hasNext();) { final Node child = i.next(); visitChild(child); } } private void visitChild(final Node child) { if (child != null && isVisitable(child)) { child.accept(this); } } private boolean isVisitable(Node node) { return !(node instanceof ArgumentNode) && node.getClass() != ListNode.class; } }); return heredocNodes; } public void testRuby19hash() throws FormatterException { final String input = "hash = { one: 1, two: 2 }"; RubyParserResult result = RubyParser.parse(input); assertNotNull(result); final List<Node> arrays = new ArrayList<>(); result.getAST().accept(new AbstractVisitor() { @Override protected Instruction visitNode(Node visited) { if (visited instanceof ArrayNode) { arrays.add(visited); } visitChildren(visited); return null; } private void visitChildren(Node visited) { List<Node> children = visited.childNodes(); for (Iterator<Node> i = children.iterator(); i.hasNext();) { final Node child = i.next(); visitChild(child); } } private void visitChild(final Node child) { if (child != null) { child.accept(this); } } }); assertEquals(1, arrays.size()); final ArrayNode node = (ArrayNode) arrays.get(0); assertEquals(4, node.size()); } }