From: Erlend Kristiansen Date: Mon, 2 Sep 2013 13:44:46 +0000 (+0200) Subject: Adding tests for LongestCommonPrefixExtractor. X-Git-Url: http://git.uio.no/git/?a=commitdiff_plain;h=b9afe13c620f24679b7647932ebb645ffd09374d;p=ifi-stolz-refaktor.git Adding tests for LongestCommonPrefixExtractor. At the same time removing PropertyExtractorExecutor. LongestCommonPrefixExtractor now works on ExpressionStatements only, and when the expression is a MethodInvocation. --- diff --git a/software/no.uio.ifi.refaktor.tests/src/no/uio/ifi/refaktor/tests/LongestCommonPrefixExtractorTest.java b/software/no.uio.ifi.refaktor.tests/src/no/uio/ifi/refaktor/tests/LongestCommonPrefixExtractorTest.java new file mode 100644 index 00000000..94eaf371 --- /dev/null +++ b/software/no.uio.ifi.refaktor.tests/src/no/uio/ifi/refaktor/tests/LongestCommonPrefixExtractorTest.java @@ -0,0 +1,126 @@ +package no.uio.ifi.refaktor.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import no.uio.ifi.refaktor.extractors.LongestCommonPrefixExtractor; +import no.uio.ifi.refaktor.utils.SmartTextSelection; + +import org.eclipse.jface.text.Document; +import org.junit.Before; +import org.junit.Test; + +public class LongestCommonPrefixExtractorTest { + + private String classStart; + private String methodText; + private String endStartFoo; + private String startFoo; + private String testCode; + private String singleStatement; + private String testExpression; + private String blockText; + + @Before + public void setUp() throws Exception { + classStart = "class TestClass {"; + endStartFoo = "b.c.d();a.b.c.f();"; + startFoo = "a." + endStartFoo; + singleStatement = "a.b.c.g(a.c);"; + testExpression = "a.b.d.f()"; + blockText = "{" + startFoo + "if(" + testExpression + "){" + singleStatement + "return a.b.d();}}"; + methodText = "public void foo() " + blockText; + testCode = classStart + methodText + "}"; + } + + @Test + public void testSelectionIsValidStartFoo() { + makeStartFooExtractor(); + } + + @Test + public void testExtractPropertyStartFoo() { + LongestCommonPrefixExtractor extractor = makeStartFooExtractor(); + extractor.extractProperty(); + assertEquals("a.b.c", extractor.stringProperty()); + } + + private LongestCommonPrefixExtractor makeStartFooExtractor() { + SmartTextSelection selection = new SmartTextSelection(new Document(testCode), testCode.indexOf(startFoo), startFoo.length()); + LongestCommonPrefixExtractor extractor = new LongestCommonPrefixExtractor(selection); + assertTrue(extractor.selectionIsValid()); + return extractor; + } + + @Test + public void testSelectionIsValidEndStartFoo() { + SmartTextSelection selection = new SmartTextSelection(new Document(testCode), testCode.indexOf(endStartFoo), endStartFoo.length()); + LongestCommonPrefixExtractor extractor = new LongestCommonPrefixExtractor(selection); + assertFalse("Partial selection of statements shall not be allowed", extractor.selectionIsValid()); + } + + @Test + public void testSelectionIsValidSingleStatement() { + makeSingleStatementExtractor(); + } + + @Test + public void testExtractPropertySingleStatement() { + LongestCommonPrefixExtractor extractor = makeSingleStatementExtractor(); + extractor.extractProperty(); + assertEquals("a.b.c", extractor.stringProperty()); + } + + private LongestCommonPrefixExtractor makeSingleStatementExtractor() { + SmartTextSelection selection = new SmartTextSelection(new Document(testCode), testCode.indexOf(singleStatement), singleStatement.length()); + LongestCommonPrefixExtractor extractor = new LongestCommonPrefixExtractor(selection); + assertTrue("Single statements shall be allowed", extractor.selectionIsValid()); + return extractor; + } + + @Test + public void testSelectionIsValidTestExpression() { + SmartTextSelection selection = new SmartTextSelection(new Document(testCode), testCode.indexOf(testExpression), testExpression.length()); + LongestCommonPrefixExtractor extractor = new LongestCommonPrefixExtractor(selection); + assertFalse("Expressions shall not be allowed", extractor.selectionIsValid()); + } + + @Test + public void testSelectionIsValidMethodText() { + makeMethodTextExtractor(); + } + + @Test + public void testExtractPropertyMethodText() { + LongestCommonPrefixExtractor extractor = makeMethodTextExtractor(); + extractor.extractProperty(); + assertEquals("a.b.c", extractor.stringProperty()); + } + + private LongestCommonPrefixExtractor makeMethodTextExtractor() { + SmartTextSelection selection = new SmartTextSelection(new Document(testCode), testCode.indexOf(methodText), methodText.length()); + LongestCommonPrefixExtractor extractor = new LongestCommonPrefixExtractor(selection); + assertTrue("Selecting whole methods should be allowed", extractor.selectionIsValid()); + return extractor; + } + + @Test + public void testSelectionIsValidBlockText() { + makeBlockTextExtractor(); + } + + @Test + public void textExtractPropertyBlockText() { + LongestCommonPrefixExtractor extractor = makeBlockTextExtractor(); + extractor.extractProperty(); + assertEquals("a.b.c", extractor.stringProperty()); + } + + private LongestCommonPrefixExtractor makeBlockTextExtractor() { + SmartTextSelection selection = new SmartTextSelection(new Document(testCode), testCode.indexOf(blockText), blockText.length()); + LongestCommonPrefixExtractor extractor = new LongestCommonPrefixExtractor(selection); + assertTrue("Selecting blocks should be allowed", extractor.selectionIsValid()); + return extractor; + } + +} diff --git a/software/no.uio.ifi.refaktor.tests/src/no/uio/ifi/refaktor/tests/PropertyExtractorExecutorTest.java b/software/no.uio.ifi.refaktor.tests/src/no/uio/ifi/refaktor/tests/PropertyExtractorExecutorTest.java deleted file mode 100644 index 37b10451..00000000 --- a/software/no.uio.ifi.refaktor.tests/src/no/uio/ifi/refaktor/tests/PropertyExtractorExecutorTest.java +++ /dev/null @@ -1,67 +0,0 @@ -package no.uio.ifi.refaktor.tests; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import no.uio.ifi.refaktor.extractors.PropertyExtractor; -import no.uio.ifi.refaktor.extractors.PropertyExtractorExecutor; -import no.uio.ifi.refaktor.utils.ParseUtils; -import no.uio.ifi.refaktor.utils.SmartTextSelection; - -import org.eclipse.jdt.core.dom.MethodDeclaration; -import org.eclipse.jface.text.Document; -import org.junit.Before; -import org.junit.Test; - -public class PropertyExtractorExecutorTest { - - private String methodText; - private SmartTextSelection selection; - private SimplePropertyExtractor extractor; - private PropertyExtractorExecutor executor; - - class SimplePropertyExtractor extends PropertyExtractor { - - private String property; - - public SimplePropertyExtractor(SmartTextSelection selection) { - super(selection); - } - - @Override - public boolean selectionIsValid() { - return getSelection() != null && getSelection().getText().equals(methodText); - } - - public String property() { - return property; - } - - public boolean visit(MethodDeclaration node) { - property = ParseUtils.getNodeText(node, getDocument()); - return false; - } - } - - @Before - public void setUp() throws Exception { - methodText = "public void foo() { System.out.println(\"bar\"); }"; - String classStart = "class TestCode { "; - String testCode = classStart + methodText + "}"; - selection = new SmartTextSelection(new Document(testCode), classStart.length(), methodText.length()); - extractor = new SimplePropertyExtractor(selection); - executor = new PropertyExtractorExecutor(extractor); - } - - @Test - public void testExtractProperty() { - assertEquals("The selection range may have been poorly defined.", methodText, selection.getText()); - executor.extractProperty(); - assertEquals(selection.getText(), extractor.property()); - } - - @Test - public void testSelectionIsValid() { - assertTrue(executor.selectionIsValid()); - } - -} diff --git a/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/extractors/LongestCommonPrefixExtractor.java b/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/extractors/LongestCommonPrefixExtractor.java index 7df3089c..aff74eac 100644 --- a/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/extractors/LongestCommonPrefixExtractor.java +++ b/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/extractors/LongestCommonPrefixExtractor.java @@ -1,35 +1,134 @@ package no.uio.ifi.refaktor.extractors; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedList; + import no.uio.ifi.refaktor.utils.ParseUtils; import no.uio.ifi.refaktor.utils.SmartTextSelection; -import org.eclipse.jdt.core.dom.QualifiedName; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.ExpressionStatement; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.NodeFinder; +import org.eclipse.jdt.core.dom.Statement; public class LongestCommonPrefixExtractor extends PropertyExtractor { - + + protected class SelectionAttributesCollector extends ASTVisitor { + + private SmartTextSelection selection; + private LinkedList selectedStatements; + private NodeFinder nodeFinder; + + public SelectionAttributesCollector(SmartTextSelection selection) { + this.selection = selection; + this.selectedStatements = new LinkedList(); + nodeFinder = ParseUtils.getNodeFinder(selection); + findSelectedStatements(getCoveringNode()); + } + + private ASTNode getCoveringNode() { + return nodeFinder.getCoveringNode(); + } + + private ASTNode getCoveredNode() { + return nodeFinder.getCoveredNode(); + } + + public boolean isSingleNodeSelection() { + return getCoveringNode() == getCoveredNode(); + } + + public ASTNode getSelectedNode() { + if (!isSingleNodeSelection()) + return null; + return getCoveredNode(); + } + + public void findSelectedStatements(ASTNode node) { + node.accept(this); + Collections.sort(selectedStatements, new Comparator(){ + @Override + public int compare(ASTNode node1, ASTNode node2) { + if (node1.equals(node2)) + return 0; + else if (node1.getStartPosition() < node2.getStartPosition()) + return -1; + else if (node1.getStartPosition() > node2.getStartPosition()) + return 1; + else + return 0; + }}); + } + + @Override + public boolean preVisit2(ASTNode node) { + if (node instanceof Statement && nodeInSelection(node, selection)) { + selectedStatements.add(node); + // Only visit top-level statements + return false; + } + + if (node instanceof MethodDeclaration || node instanceof Block ) + return true; + + return false; + } + + public boolean selectedNodeHasBlockStructure() { + return isSingleNodeSelection() && + (getSelectedNode() instanceof MethodDeclaration || getSelectedNode() instanceof Block); + } + + public boolean noStatementsSelected() { + return selectedStatements.isEmpty(); + } + + private boolean selectionMatchesStatementsStartAndEnd() { + return selectedStatements.getFirst().getStartPosition() == selection.getOffset() + && nodeEnd(selectedStatements.getLast()) == selection.getEnd(); + } + + private int nodeEnd(ASTNode astNode) { + return astNode.getStartPosition() + astNode.getLength(); + } + } + protected String property; + private SelectionAttributesCollector selectionAttributesCollector; public LongestCommonPrefixExtractor(SmartTextSelection selection) { super(selection); + selectionAttributesCollector = new SelectionAttributesCollector(selection); } - - //TODO: what about simple names? @Override - public boolean visit(QualifiedName node) { + public boolean visit(ExpressionStatement node) { if (!nodeInSelection(node)) return false; - - String nodeText = ParseUtils.getNodeText(node, getSelection().getDocument()).trim(); - + + String prefix = getPrefix(node); + if (property == null) { - property = nodeText; + property = prefix; } else { - property = longestCommonPrefix(property, nodeText); + property = longestCommonPrefix(property, prefix); } return false; } + public String getPrefix(ExpressionStatement node) { + Expression expression = node.getExpression(); + if (expression instanceof MethodInvocation) + return ParseUtils.getNodeText(((MethodInvocation) expression).getExpression(), getDocument()).trim(); + return ParseUtils.getNodeText(node, getDocument()).trim(); + } + private String longestCommonPrefix(String attribute, String nodeText) { String commonPrefix = attribute.substring(0, numberOfCommonCharacters(attribute, nodeText)); if (commonPrefix.endsWith(".")) { @@ -52,7 +151,7 @@ public class LongestCommonPrefixExtractor extends PropertyExtractor { private boolean belowStringLengths(int index, String attribute, String nodeText) { return index < attribute.length() && index < nodeText.length(); } - + private boolean charsMatchingAt(String attribute, String nodeText, int index) { return attribute.charAt(index) == nodeText.charAt(index); } @@ -60,4 +159,23 @@ public class LongestCommonPrefixExtractor extends PropertyExtractor { public String stringProperty() { return property; } + + @Override + public boolean selectionIsValid() { + if (!super.selectionIsValid()) + return false; + + if (selectionAttributesCollector.noStatementsSelected()) + return false; + + if (selectionAttributesCollector.selectedNodeHasBlockStructure()) + return true; + + return selectionAttributesCollector.selectionMatchesStatementsStartAndEnd(); + } + + @Override + protected ASTNode getStartNode() { + return selectionAttributesCollector.getCoveringNode(); + } } \ No newline at end of file diff --git a/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/extractors/PropertyExtractor.java b/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/extractors/PropertyExtractor.java index 00c18933..b4571740 100644 --- a/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/extractors/PropertyExtractor.java +++ b/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/extractors/PropertyExtractor.java @@ -1,10 +1,12 @@ package no.uio.ifi.refaktor.extractors; +import no.uio.ifi.refaktor.utils.ParseUtils; import no.uio.ifi.refaktor.utils.SmartTextSelection; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.ITextSelection; public abstract class PropertyExtractor extends ASTVisitor { @@ -22,8 +24,11 @@ public abstract class PropertyExtractor extends ASTVisitor { public IDocument getDocument() { return selection.getDocument(); } - protected boolean nodeInSelection(ASTNode node) { + return nodeInSelection(node, getSelection()); + } + + protected boolean nodeInSelection(ASTNode node, ITextSelection selection) { return selection.getOffset() <= node.getStartPosition() && (node.getStartPosition() + node.getLength()) <= (selection.getOffset() + selection.getLength()); } @@ -32,10 +37,14 @@ public abstract class PropertyExtractor extends ASTVisitor { return selection != null; } - public void extractProperty(ASTNode startNode) { + public void extractProperty() { if (!selectionIsValid()) throw new RuntimeException(this.getClass().getCanonicalName() + ": Trying to extract property from invalid selection!"); - startNode.accept(this); + getStartNode().accept(this); + } + + protected ASTNode getStartNode() { + return ParseUtils.getNodeFinder(selection).getCoveringNode(); } } diff --git a/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/extractors/PropertyExtractorExecutor.java b/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/extractors/PropertyExtractorExecutor.java deleted file mode 100644 index a5c6c741..00000000 --- a/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/extractors/PropertyExtractorExecutor.java +++ /dev/null @@ -1,28 +0,0 @@ -package no.uio.ifi.refaktor.extractors; - -import no.uio.ifi.refaktor.utils.ParseUtils; - -import org.eclipse.jdt.core.dom.ASTNode; - -public class PropertyExtractorExecutor { - - private PropertyExtractor extractor; - - public PropertyExtractorExecutor(PropertyExtractor extractor) { - this.extractor = extractor; - } - - public void extractProperty() { - extractor.extractProperty(getCoveringNode()); - } - - private ASTNode getCoveringNode() { - return ParseUtils.getNodeFinder(extractor.getDocument(), extractor.getSelection()).getCoveringNode(); - } - - public boolean selectionIsValid() { - return extractor.selectionIsValid(); - } - -} - diff --git a/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/extractors/SelectedNodeTextExtractor.java b/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/extractors/SelectedNodeTextExtractor.java index f8c3b777..25d0801a 100644 --- a/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/extractors/SelectedNodeTextExtractor.java +++ b/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/extractors/SelectedNodeTextExtractor.java @@ -22,5 +22,4 @@ public class SelectedNodeTextExtractor extends PropertyExtractor { public String stringProperty() { return property; } - } diff --git a/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/handlers/TestPropertyExtractorHandler.java b/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/handlers/TestPropertyExtractorHandler.java index 7f4bbf57..1e733b57 100644 --- a/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/handlers/TestPropertyExtractorHandler.java +++ b/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/handlers/TestPropertyExtractorHandler.java @@ -1,7 +1,6 @@ package no.uio.ifi.refaktor.handlers; import no.uio.ifi.refaktor.extractors.LongestCommonPrefixExtractor; -import no.uio.ifi.refaktor.extractors.PropertyExtractorExecutor; import no.uio.ifi.refaktor.utils.ParseUtils; import no.uio.ifi.refaktor.utils.SmartTextSelection; @@ -27,10 +26,9 @@ public class TestPropertyExtractorHandler extends SelectionAbstractHandler { editor.getSite().getSelectionProvider().setSelection(smartTextSelection); LongestCommonPrefixExtractor extractor = new LongestCommonPrefixExtractor(smartTextSelection); - PropertyExtractorExecutor executor = new PropertyExtractorExecutor(extractor); String dialogText; - if (executor.selectionIsValid()) { - executor.extractProperty(); + if (extractor.selectionIsValid()) { + extractor.extractProperty(); dialogText = extractor.stringProperty(); } else { dialogText = "Selection is invalid"; diff --git a/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/utils/ParseUtils.java b/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/utils/ParseUtils.java index 3ea11cec..065254c2 100644 --- a/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/utils/ParseUtils.java +++ b/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/utils/ParseUtils.java @@ -85,5 +85,9 @@ public class ParseUtils { return new NodeFinder(cu.getRoot(), selection.getOffset(), selection.getLength()); } + public static NodeFinder getNodeFinder(SmartTextSelection selection) { + return getNodeFinder(selection.getDocument(), selection); + } + } diff --git a/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/utils/SmartTextSelection.java b/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/utils/SmartTextSelection.java index 4019f384..db2e53c4 100644 --- a/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/utils/SmartTextSelection.java +++ b/software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/utils/SmartTextSelection.java @@ -23,4 +23,8 @@ public class SmartTextSelection extends TextSelection implements ITextSelection return document; } + public int getEnd() { + return getOffset() + getLength(); + } + }