Merge pull request #1358 from rablewis/1262

[#1262] Prevent infinite loop with NodeIterator.
This commit is contained in:
Sebastian Zarnekow 2020-02-03 09:35:28 +01:00 committed by GitHub
commit 04aedc416e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 440 additions and 0 deletions

View file

@ -0,0 +1,21 @@
/*******************************************************************************
* Copyright (c) 2020 Robert Lewis 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
*******************************************************************************/
package org.eclipse.xtext.nodemodel;
import org.eclipse.xtext.nodemodel.impl.AbstractNode;
/**
* @author Robert Lewis - Initial contribution and API
*/
public class BasicNodeIterable extends org.eclipse.xtext.nodemodel.impl.BasicNodeIterable {
protected BasicNodeIterable(AbstractNode startWith) {
super(startWith);
}
}

View file

@ -0,0 +1,56 @@
/*******************************************************************************
* Copyright (c) 2020 Robert Lewis 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
*******************************************************************************/
package org.eclipse.xtext.nodemodel;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.xtext.nodemodel.impl.AbstractNode;
import org.junit.Assert;
import org.junit.Test;
/**
* @author Robert Lewis - Initial contribution and API
*/
public class BasicNodeIterableTest {
@Test
public void forEachTest() {
AbstractNode alpha = BasicNodeIteratorTest.nodeWithTwoSiblings();
BasicNodeIterable iterable = new BasicNodeIterable(alpha);
List<String> tokens = new ArrayList<String>();
for (INode node : iterable) {
tokens.add(node.getText());
}
Assert.assertEquals("alpha", tokens.get(0));
Assert.assertEquals("beta", tokens.get(1));
Assert.assertEquals("gamma", tokens.get(2));
}
@Test
public void forEachReverseTest() {
AbstractNode alpha = BasicNodeIteratorTest.nodeWithTwoSiblings();
BasicNodeIterable iterable = new BasicNodeIterable(alpha);
List<String> tokens = new ArrayList<String>();
for (INode node : iterable.reverse()) {
tokens.add(node.getText());
}
Assert.assertEquals("gamma", tokens.get(0));
Assert.assertEquals("beta", tokens.get(1));
Assert.assertEquals("alpha", tokens.get(2));
}
@Test(expected=NullPointerException.class)
public void testStartWithNullThrowsNPE() {
new BasicNodeIterable(null);
}
}

View file

@ -0,0 +1,20 @@
/*******************************************************************************
* Copyright (c) 2020 Robert Lewis 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
*******************************************************************************/
package org.eclipse.xtext.nodemodel;
import org.eclipse.xtext.nodemodel.impl.AbstractNode;
/**
* @author Robert Lewis - Initial contribution and API
*/
public class BasicNodeIterator extends org.eclipse.xtext.nodemodel.impl.BasicNodeIterator {
public BasicNodeIterator(AbstractNode startWith) {
super(startWith);
}
}

View file

@ -0,0 +1,138 @@
/*******************************************************************************
* Copyright (c) 2020 Robert Lewis 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
*******************************************************************************/
package org.eclipse.xtext.nodemodel;
import java.util.NoSuchElementException;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.impl.EObjectImpl;
import org.eclipse.xtext.nodemodel.impl.AbstractNode;
import org.eclipse.xtext.nodemodel.impl.NodeModelBuilder;
import org.junit.Assert;
import org.junit.Test;
/**
* @author Robert Lewis - Initial contribution and API
*/
public class BasicNodeIteratorTest {
private static AbstractNode getSingleNode() {
return new RootNode();
}
public static AbstractNode nodeWithTwoSiblings() {
NodeModelBuilder builder = new NodeModelBuilder();
String text = "alpha beta gamma";
RootNode root = new RootNode();
root.basicSetCompleteContent(text);
EObject alpha = new EObjectImpl() {};
builder.newLeafNode(text.indexOf("alpha"), "alpha".length(), alpha, false, null, root);
EObject beta = new EObjectImpl() {};
builder.newLeafNode(text.indexOf("beta"), "beta".length(), beta, false, null, root);
EObject gamma = new EObjectImpl() {};
builder.newLeafNode(text.indexOf("gamma"), "gamma".length(), gamma, false, null, root);
return root.basicGetFirstChild();
}
@Test(expected=NullPointerException.class)
public void testStartWithNullThrowsNPE() {
new BasicNodeIterator(null);
}
@Test
public void testSingleNodeHasNext() {
AbstractNode single = getSingleNode();
BasicNodeIterator it = new BasicNodeIterator(single);
Assert.assertTrue(it.hasNext());
it.next();
Assert.assertFalse(it.hasNext());
}
@Test(expected=NoSuchElementException.class)
public void testNextTooFarThrowsException() {
AbstractNode single = getSingleNode();
BasicNodeIterator it = new BasicNodeIterator(single);
it.next();
it.next();
}
@Test
public void testIterateThreeNodes() {
AbstractNode alpha = nodeWithTwoSiblings();
BasicNodeIterator it = new BasicNodeIterator(alpha);
Assert.assertTrue(it.hasNext());
it.next();
Assert.assertTrue(it.hasNext());
it.next();
Assert.assertTrue(it.hasNext());
it.next();
Assert.assertFalse(it.hasNext());
}
@Test
public void testSingleNodeHasPrevious() {
AbstractNode single = getSingleNode();
BasicNodeIterator it = new BasicNodeIterator(single);
Assert.assertTrue(it.hasPrevious());
it.previous();
Assert.assertFalse(it.hasPrevious());
}
@Test
public void testIteratePreviousStartsWithLastNode() {
AbstractNode alpha = nodeWithTwoSiblings();
BasicNodeIterator it = new BasicNodeIterator(alpha);
INode result = it.previous();
Assert.assertEquals("gamma", result.getText());
}
@Test(expected=NoSuchElementException.class)
public void testPreviousTooFarThrowsException() {
AbstractNode single = getSingleNode();
BasicNodeIterator it = new BasicNodeIterator(single);
it.previous();
it.previous();
}
@Test
public void testIterateThreeNodesInReverse() {
AbstractNode alpha = nodeWithTwoSiblings();
BasicNodeIterator it = new BasicNodeIterator(alpha);
Assert.assertTrue(it.hasPrevious());
it.previous();
Assert.assertTrue(it.hasPrevious());
it.previous();
Assert.assertTrue(it.hasPrevious());
it.previous();
Assert.assertFalse(it.hasPrevious());
}
}

View file

@ -0,0 +1,56 @@
/*******************************************************************************
* Copyright (c) 2020 Robert Lewis 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
*******************************************************************************/
package org.eclipse.xtext.nodemodel.util;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.xtext.nodemodel.INode;
import org.junit.Assert;
import org.junit.Test;
/**
* @author Robert Lewis - Initial contribution and API
*/
public class NodeIterableTest {
@Test
public void forEachTest() {
INode alpha = NodeIteratorTest.nodeWithTwoSiblings();
NodeIterable iterable = new NodeIterable(alpha);
List<String> tokens = new ArrayList<String>();
for (INode node : iterable) {
tokens.add(node.getText());
}
Assert.assertEquals("alpha", tokens.get(0));
Assert.assertEquals("beta", tokens.get(1));
Assert.assertEquals("gamma", tokens.get(2));
}
@Test
public void forEachReverseTest() {
INode alpha = NodeIteratorTest.nodeWithTwoSiblings();
NodeIterable iterable = new NodeIterable(alpha);
List<String> tokens = new ArrayList<String>();
for (INode node : iterable.reverse()) {
tokens.add(node.getText());
}
Assert.assertEquals("gamma", tokens.get(0));
Assert.assertEquals("beta", tokens.get(1));
Assert.assertEquals("alpha", tokens.get(2));
}
@Test(expected=NullPointerException.class)
public void testStartWithNullThrowsNPE() {
new NodeIterable(null);
}
}

View file

@ -0,0 +1,139 @@
/*******************************************************************************
* Copyright (c) 2020 Robert Lewis 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
*******************************************************************************/
package org.eclipse.xtext.nodemodel.util;
import java.util.NoSuchElementException;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.impl.EObjectImpl;
import org.eclipse.xtext.nodemodel.ICompositeNode;
import org.eclipse.xtext.nodemodel.ILeafNode;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.impl.NodeModelBuilder;
import org.eclipse.xtext.nodemodel.impl.RootNode;
import org.junit.Assert;
import org.junit.Test;
/**
* @author Robert Lewis - Initial contribution and API
*/
public class NodeIteratorTest {
private static INode getSingleNode() {
return new RootNode();
}
public static INode nodeWithTwoSiblings() {
NodeModelBuilder builder = new NodeModelBuilder();
String text = "alpha beta gamma";
ICompositeNode root = builder.newRootNode(text);
EObject alpha = new EObjectImpl() {};
ILeafNode alphaNode = builder.newLeafNode(text.indexOf("alpha"), "alpha".length(), alpha, false, null, root);
EObject beta = new EObjectImpl() {};
builder.newLeafNode(text.indexOf("beta"), "beta".length(), beta, false, null, root);
EObject gamma = new EObjectImpl() {};
builder.newLeafNode(text.indexOf("gamma"), "gamma".length(), gamma, false, null, root);
return alphaNode;
}
@Test(expected=NullPointerException.class)
public void testStartWithNullThrowsNPE() {
new NodeIterator(null);
}
@Test
public void testSingleNodeHasNext() {
INode single = getSingleNode();
NodeIterator it = new NodeIterator(single);
Assert.assertTrue(it.hasNext());
it.next();
Assert.assertFalse(it.hasNext());
}
@Test(expected=NoSuchElementException.class)
public void testNextTooFarThrowsException() {
INode single = getSingleNode();
NodeIterator it = new NodeIterator(single);
it.next();
it.next();
}
@Test
public void testIterateThreeNodes() {
INode alpha = nodeWithTwoSiblings();
NodeIterator it = new NodeIterator(alpha);
Assert.assertTrue(it.hasNext());
it.next();
Assert.assertTrue(it.hasNext());
it.next();
Assert.assertTrue(it.hasNext());
it.next();
Assert.assertFalse(it.hasNext());
}
@Test
public void testSingleNodeHasPrevious() {
INode single = getSingleNode();
NodeIterator it = new NodeIterator(single);
Assert.assertTrue(it.hasPrevious());
it.previous();
Assert.assertFalse(it.hasPrevious());
}
@Test
public void testIteratePreviousStartsWithLastNode() {
INode alpha = nodeWithTwoSiblings();
NodeIterator it = new NodeIterator(alpha);
INode result = it.previous();
Assert.assertEquals("gamma", result.getText());
}
@Test(expected=NoSuchElementException.class)
public void testPreviousTooFarThrowsException() {
INode single = getSingleNode();
NodeIterator it = new NodeIterator(single);
it.previous();
it.previous();
}
@Test
public void testIterateThreeNodesInReverse() {
INode alpha = nodeWithTwoSiblings();
NodeIterator it = new NodeIterator(alpha);
Assert.assertTrue(it.hasPrevious());
it.previous();
Assert.assertTrue(it.hasPrevious());
it.previous();
Assert.assertTrue(it.hasPrevious());
it.previous();
Assert.assertFalse(it.hasPrevious());
}
}

View file

@ -1,5 +1,7 @@
package org.eclipse.xtext.nodemodel.impl;
import java.util.Objects;
import org.eclipse.xtext.nodemodel.BidiIterable;
import org.eclipse.xtext.nodemodel.BidiIterator;
import org.eclipse.xtext.nodemodel.util.ReversedBidiIterator;
@ -12,6 +14,7 @@ public class BasicNodeIterable implements BidiIterable<AbstractNode> {
private final AbstractNode startWith;
protected BasicNodeIterable(AbstractNode startWith) {
Objects.requireNonNull(startWith);
this.startWith = startWith;
}

View file

@ -8,6 +8,7 @@
package org.eclipse.xtext.nodemodel.impl;
import java.util.NoSuchElementException;
import java.util.Objects;
import org.eclipse.xtext.nodemodel.BidiIterator;
@ -23,6 +24,7 @@ public class BasicNodeIterator extends UnmodifiableIterator<AbstractNode> implem
private AbstractNode lastReturned;
protected BasicNodeIterator(AbstractNode startWith) {
Objects.requireNonNull(startWith);
this.startWith = startWith;
}

View file

@ -1,5 +1,7 @@
package org.eclipse.xtext.nodemodel.util;
import java.util.Objects;
import org.eclipse.xtext.nodemodel.BidiIterable;
import org.eclipse.xtext.nodemodel.BidiIterator;
import org.eclipse.xtext.nodemodel.INode;
@ -12,6 +14,7 @@ public class NodeIterable implements BidiIterable<INode> {
private final INode startWith;
public NodeIterable(INode startWith) {
Objects.requireNonNull(startWith);
this.startWith = startWith;
}

View file

@ -8,6 +8,7 @@
package org.eclipse.xtext.nodemodel.util;
import java.util.NoSuchElementException;
import java.util.Objects;
import org.eclipse.xtext.nodemodel.BidiIterator;
import org.eclipse.xtext.nodemodel.INode;
@ -23,6 +24,7 @@ public class NodeIterator extends UnmodifiableIterator<INode> implements BidiIte
private INode lastReturned;
public NodeIterator(INode startWith) {
Objects.requireNonNull(startWith);
this.startWith = startWith;
}