[trace] First shot at AbstractTraceRegion#invertFor(..), more consistent naming, trace regions are trimmed automatically by the tree appendable

This commit is contained in:
Sebastian Zarnekow 2012-02-23 00:47:47 +01:00
parent 1f4595b25a
commit bda495a6d0
7 changed files with 379 additions and 30 deletions

View file

@ -14,6 +14,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.xtext.util.ITextRegionWithLineInformation;
import com.google.common.collect.Lists;
/**
* @author Sebastian Zarnekow - Initial contribution and API
*/
@ -24,7 +26,7 @@ public abstract class AbstractStatefulTraceRegion extends AbstractTraceRegion {
private final List<ILocationData> associatedLocations;
protected AbstractStatefulTraceRegion(ITextRegionWithLineInformation myRegion, ILocationData associatedLocation, @Nullable AbstractTraceRegion parent) {
this(myRegion, Collections.singletonList(associatedLocation), parent);
this(myRegion, Lists.newArrayList(associatedLocation), parent);
}
protected AbstractStatefulTraceRegion(ITextRegionWithLineInformation myRegion, List<ILocationData> associatedLocations, @Nullable AbstractTraceRegion parent) {
@ -65,4 +67,8 @@ public abstract class AbstractStatefulTraceRegion extends AbstractTraceRegion {
return Collections.unmodifiableList(associatedLocations);
}
protected List<ILocationData> getWritableAssociatedLocations() {
return associatedLocations;
}
}

View file

@ -8,16 +8,25 @@
package org.eclipse.xtext.generator.trace;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.util.AbstractTreeIterator;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.xtext.util.ITextRegionWithLineInformation;
import org.eclipse.xtext.util.Pair;
import org.eclipse.xtext.util.TextRegionWithLineInformation;
import org.eclipse.xtext.util.Tuples;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.primitives.Ints;
/**
* Abstract base class for trace regions. Implements the {@link #equals(Object)}
@ -93,6 +102,174 @@ public abstract class AbstractTraceRegion {
return nestedRegions;
}
public List<AbstractTraceRegion> invertFor(URI expectedAssociatedPath, URI myPath, String myProjectName) {
Map<URI, List<Pair<ILocationData, AbstractTraceRegion>>> matchingLocations = collectMatchingLocations(expectedAssociatedPath);
List<Pair<ILocationData, AbstractTraceRegion>> expectedMatchingLocations = matchingLocations.get(expectedAssociatedPath);
if (expectedMatchingLocations == null)
return Collections.emptyList();
inplaceSortByOffset(expectedMatchingLocations);
List<AbstractTraceRegion> result = toInvertedTraceRegions(expectedMatchingLocations, myPath, myProjectName);
return result;
}
public Map<URI, List<AbstractTraceRegion>> invertAll(URI myPath, String myProjectName) {
Map<URI, List<Pair<ILocationData, AbstractTraceRegion>>> matchingLocations = collectMatchingLocations(null);
Map<URI, List<AbstractTraceRegion>> result = Maps.newHashMapWithExpectedSize(matchingLocations.size());
for(URI uri: matchingLocations.keySet()) {
List<Pair<ILocationData, AbstractTraceRegion>> expectedMatchingLocations = matchingLocations.get(uri);
if (expectedMatchingLocations != null) {
inplaceSortByOffset(expectedMatchingLocations);
List<AbstractTraceRegion> resultPerURI = toInvertedTraceRegions(expectedMatchingLocations, myPath, myProjectName);
result.put(uri, resultPerURI);
}
}
return result;
}
protected Map<URI, List<Pair<ILocationData, AbstractTraceRegion>>> collectMatchingLocations(@Nullable URI expectedAssociatedPath) {
Map<URI, List<Pair<ILocationData, AbstractTraceRegion>>> result = Maps.newHashMapWithExpectedSize(2);
Iterator<AbstractTraceRegion> treeIterator = treeIterator();
while(treeIterator.hasNext()) {
AbstractTraceRegion next = treeIterator.next();
URI associatedPath = next.getAssociatedPath();
List<Pair<ILocationData, AbstractTraceRegion>> matchingLocations = getCollectingList(associatedPath,
expectedAssociatedPath, result);
for(ILocationData locationData: next.getAssociatedLocations()) {
if (associatedPath == null) {
matchingLocations = getCollectingList(locationData.getPath(), expectedAssociatedPath, result);
}
if (matchingLocations != null) {
matchingLocations.add(Tuples.create(locationData, next));
}
}
}
return result;
}
@Nullable
protected List<Pair<ILocationData, AbstractTraceRegion>> getCollectingList(@Nullable URI associatedPath,
@Nullable URI expectedAssociatedPath, Map<URI, List<Pair<ILocationData, AbstractTraceRegion>>> listsPerURI) {
List<Pair<ILocationData, AbstractTraceRegion>> result = null;
if (associatedPath != null && (expectedAssociatedPath == null || associatedPath.equals(expectedAssociatedPath))) {
result = listsPerURI.get(associatedPath);
if (result == null) {
result = Lists.newArrayList();
listsPerURI.put(associatedPath, result);
}
}
return result;
}
public TreeIterator<AbstractTraceRegion> treeIterator() {
TreeIterator<AbstractTraceRegion> treeIterator = new AbstractTreeIterator<AbstractTraceRegion>(this) {
private static final long serialVersionUID = 1L;
@Override
protected Iterator<? extends AbstractTraceRegion> getChildren(@Nullable Object object) {
if (object == null)
return Iterators.emptyIterator();
AbstractTraceRegion casted = (AbstractTraceRegion) object;
return casted.getNestedRegions().iterator();
}
/**
* @throws UnsupportedOperationException always
*/
@Override
public void remove() {
throw new UnsupportedOperationException("remove is not supported");
}
};
return treeIterator;
}
protected void inplaceSortByOffset(List<Pair<ILocationData, AbstractTraceRegion>> locations) {
Collections.sort(locations, new Comparator<Pair<ILocationData, AbstractTraceRegion>>() {
public int compare(@Nullable Pair<ILocationData, AbstractTraceRegion> o1, @Nullable Pair<ILocationData, AbstractTraceRegion> o2) {
if (o1 == null || o2 == null)
throw new IllegalArgumentException("o1 == null || o2 == null");
ILocationData loc1 = o1.getFirst();
ILocationData loc2 = o2.getFirst();
int result = Ints.compare(loc1.getOffset(), loc2.getOffset());
if (result == 0) {
result = Ints.compare(loc2.getLength(), loc1.getLength());
}
return result;
}
});
}
/**
* Produces trees from a sorted list of locations. If the locations overlap, they'll be splitted
* automatically to fulfil the contract of invariant of trace regions.
*/
protected List<AbstractTraceRegion> toInvertedTraceRegions(
List<Pair<ILocationData, AbstractTraceRegion>> locations, URI myPath, String myProjectName) {
List<AbstractTraceRegion> result = Lists.newArrayListWithCapacity(2);
TraceRegion current = null;
int currentEndOffset = 0;
for(int i = 0; i < locations.size(); i++) { // avoid concurrent modification exceptions
Pair<ILocationData, AbstractTraceRegion> nextPair = locations.get(i);
ILocationData nextLocation = nextPair.getFirst();
AbstractTraceRegion nextRegion = nextPair.getSecond();
if (current != null) {
// equal region - add mapped location
if (current.getMyOffset() == nextLocation.getOffset() && current.getMyLength() == nextLocation.getLength()) {
current.getWritableAssociatedLocations().add(createLocationData(nextRegion, myPath, myProjectName));
} else {
// walk upwards if necessary
while(current != null && currentEndOffset <= nextLocation.getOffset()) {
current = (TraceRegion) current.getParent();
if (current != null)
currentEndOffset = current.getMyOffset() + current.getMyLength();
else
currentEndOffset = 0;
}
}
}
if (current != null) {
int nextOffset = nextLocation.getOffset();
if (nextOffset + nextLocation.getLength() <= currentEndOffset) {
current = new TraceRegion(nextOffset, nextLocation.getLength(), nextLocation.getLineNumber(), nextLocation.getEndLineNumber(),
createLocationData(nextRegion, myPath, myProjectName), current);
currentEndOffset = nextLocation.getOffset() + nextLocation.getLength();
} else {
int nextLength = currentEndOffset - nextOffset;
int nextEndLine = current.getMyEndLineNumber();
int splittedLength = nextLocation.getLength() - nextLength;
int splittedBeginLine = nextEndLine;
ILocationData splitted = new LocationData(currentEndOffset, splittedLength, splittedBeginLine, nextLocation.getEndLineNumber(), nextLocation.getPath(), nextLocation.getProjectName());
for(int j = i + 1; j < locations.size() && splitted != null; j++) {
ILocationData shiftMe = locations.get(j).getFirst();
if (splitted.getOffset() == shiftMe.getOffset()) {
if (splitted.getLength() > shiftMe.getLength()) {
locations.add(j, Tuples.create(splitted, nextRegion));
splitted = null;
}
} else if (splitted.getOffset() < shiftMe.getOffset()) {
locations.add(j, Tuples.create(splitted, nextRegion));
splitted = null;
}
}
if (splitted != null) {
locations.add(Tuples.create(splitted, nextRegion));
}
current = new TraceRegion(nextOffset, nextLength, nextLocation.getLineNumber(), splittedBeginLine,
createLocationData(nextRegion, myPath, myProjectName), current);
currentEndOffset = nextOffset + nextLength;
}
} else {
current = new TraceRegion(nextLocation.getOffset(), nextLocation.getLength(), nextLocation.getLineNumber(), nextLocation.getEndLineNumber(),
createLocationData(nextRegion, myPath, myProjectName), null);
currentEndOffset = nextLocation.getOffset() + nextLocation.getLength();
result.add(current);
}
}
return result;
}
public LocationData createLocationData(AbstractTraceRegion nextRegion, URI myPath, String myProjectName) {
return new LocationData(nextRegion.getMyOffset(), nextRegion.getMyLength(), nextRegion.getMyLineNumber(), nextRegion.getMyEndLineNumber(), myPath, myProjectName);
}
/**
* Returns an iterator that will only offer leaf trace regions.
* If the nested regions have gaps, these will be filled with parent data.
@ -120,7 +297,7 @@ public abstract class AbstractTraceRegion {
* they belong to the same resource. Otherwise <code>null</code> is returned.
*/
@Nullable
public ILocationData getMergedLocationData() {
public ILocationData getMergedAssociatedLocation() {
List<ILocationData> allData = getAssociatedLocations();
if (allData.size() == 1) {
return allData.get(0);
@ -131,16 +308,16 @@ public abstract class AbstractTraceRegion {
ITextRegionWithLineInformation region = ITextRegionWithLineInformation.EMPTY_REGION;
for(ILocationData data: allData) {
if (path != null) {
if (!path.equals(data.getLocation())) {
if (!path.equals(data.getPath())) {
return null;
}
} else {
if (data.getLocation() == null) {
if (data.getPath() == null) {
if (!allNull)
throw new IllegalStateException("Iff multiple associated locations are present, the path has to be set");
} else {
allNull = false;
path = data.getLocation();
path = data.getPath();
projectName = data.getProjectName();
}
}
@ -151,9 +328,9 @@ public abstract class AbstractTraceRegion {
@Nullable
public URI getAssociatedPath() {
ILocationData data = getMergedLocationData();
ILocationData data = getMergedAssociatedLocation();
if (data != null) {
URI result = data.getLocation();
URI result = data.getPath();
if (result != null) {
return result;
}
@ -166,7 +343,7 @@ public abstract class AbstractTraceRegion {
@Nullable
public String getAssociatedProjectName() {
ILocationData data = getMergedLocationData();
ILocationData data = getMergedAssociatedLocation();
if (data != null) {
String result = data.getProjectName();
if (result != null) {

View file

@ -16,7 +16,7 @@ import org.eclipse.xtext.util.ITextRegionWithLineInformation;
*/
public interface ILocationData extends ITextRegionWithLineInformation {
@Nullable URI getLocation();
@Nullable URI getPath();
@Nullable String getProjectName();
}

View file

@ -18,22 +18,22 @@ import org.eclipse.xtext.util.TextRegionWithLineInformation;
*/
public class LocationData extends TextRegionWithLineInformation implements ILocationData {
private final URI location;
private final URI path;
private final String projectName;
public LocationData(int offset, int length, int lineNumber, int endLineNumber, @Nullable URI location, @Nullable String projectName) {
public LocationData(int offset, int length, int lineNumber, int endLineNumber, @Nullable URI path, @Nullable String projectName) {
super(offset, length, lineNumber, endLineNumber);
this.location = location;
this.path = path;
this.projectName = projectName;
}
public LocationData(@NonNull ITextRegionWithLineInformation region, @Nullable URI location, @Nullable String projectName) {
this(region.getOffset(), region.getLength(), region.getLineNumber(), region.getEndLineNumber(), location, projectName);
public LocationData(@NonNull ITextRegionWithLineInformation region, @Nullable URI path, @Nullable String projectName) {
this(region.getOffset(), region.getLength(), region.getLineNumber(), region.getEndLineNumber(), path, projectName);
}
@Nullable
public URI getLocation() {
return location;
public URI getPath() {
return path;
}
@Nullable
@ -45,7 +45,7 @@ public class LocationData extends TextRegionWithLineInformation implements ILoca
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((location == null) ? 0 : location.hashCode());
result = prime * result + ((path == null) ? 0 : path.hashCode());
result = prime * result + ((projectName == null) ? 0 : projectName.hashCode());
return result;
}
@ -59,10 +59,10 @@ public class LocationData extends TextRegionWithLineInformation implements ILoca
if (getClass() != obj.getClass())
return false;
LocationData other = (LocationData) obj;
if (location == null) {
if (other.location != null)
if (path == null) {
if (other.path != null)
return false;
} else if (!location.equals(other.location))
} else if (!path.equals(other.path))
return false;
if (projectName == null) {
if (other.projectName != null)
@ -75,7 +75,7 @@ public class LocationData extends TextRegionWithLineInformation implements ILoca
@Override
@NonNull
public String toString() {
return "LocationData [location=" + location + ", projectName=" + projectName + "]";
return "LocationData [" + super.toString() + "][path=" + path + ", projectName=" + projectName + "]";
}
}

View file

@ -14,7 +14,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.xtext.util.TextRegionWithLineInformation;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
/**
* @author Sebastian Zarnekow - Initial contribution and API
@ -34,14 +34,14 @@ public class TraceRegion extends AbstractStatefulTraceRegion {
public TraceRegion(int myOffset, int myLength, int myLineNumber, int myEndLineNumber, ILocationData locationData, @Nullable AbstractTraceRegion parent) {
super(new TextRegionWithLineInformation(myOffset, myLength, myLineNumber, myEndLineNumber), locationData, parent);
if (parent == null) {
if (locationData.getLocation() == null) {
if (locationData.getPath() == null) {
throw new IllegalArgumentException("associatedPath may not be null");
}
if (locationData.getProjectName() == null) {
throw new IllegalArgumentException("associatedProjectName may not be null");
}
} else {
if (parent.getAssociatedPath() == null && locationData.getLocation() == null) {
if (parent.getAssociatedPath() == null && locationData.getPath() == null) {
throw new IllegalArgumentException("associatedPath may not be null");
}
if (parent.getAssociatedProjectName() == null && locationData.getProjectName() == null) {
@ -51,10 +51,10 @@ public class TraceRegion extends AbstractStatefulTraceRegion {
}
public TraceRegion(int myOffset, int myLength, int myLineNumber, int myEndLineNumber, List<ILocationData> allLocationData, @Nullable AbstractTraceRegion parent) {
super(new TextRegionWithLineInformation(myOffset, myLength, myLineNumber, myEndLineNumber), ImmutableList.copyOf(allLocationData), parent);
super(new TextRegionWithLineInformation(myOffset, myLength, myLineNumber, myEndLineNumber), Lists.newArrayList(allLocationData), parent);
if (parent == null) {
for(ILocationData locationData: allLocationData) {
if (locationData.getLocation() == null) {
if (locationData.getPath() == null) {
throw new IllegalArgumentException("associatedPath may not be null");
}
if (locationData.getProjectName() == null) {
@ -65,7 +65,7 @@ public class TraceRegion extends AbstractStatefulTraceRegion {
boolean nullSeen = false;
boolean notNullSeen = false;
for(ILocationData locationData: allLocationData) {
if (locationData.getLocation() == null) {
if (locationData.getPath() == null) {
nullSeen = true;
} else {
notNullSeen = true;

View file

@ -63,7 +63,7 @@ public class TraceRegionSerializer {
}
public void writeLocation(ILocationData location, Callback<AbstractTraceRegion, ILocationData> callback) throws IOException {
callback.doWriteLocation(location.getOffset(), location.getLength(), location.getLineNumber(), location.getEndLineNumber(), location.getLocation(), location.getProjectName());
callback.doWriteLocation(location.getOffset(), location.getLength(), location.getLineNumber(), location.getEndLineNumber(), location.getPath(), location.getProjectName());
}
}

View file

@ -10,6 +10,7 @@ package org.eclipse.xtext.generator.trace;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.common.util.URI;
import org.eclipse.xtext.generator.trace.AbstractStatefulTraceRegion;
@ -34,8 +35,8 @@ public class TraceRegionTest extends Assert {
TraceRegion region = new TraceRegion(0, 1, 0, 0, 2, 3, 0, 0, null, URI.createURI("uri"), "project");
assertEquals(0, region.getMyOffset());
assertEquals(1, region.getMyLength());
assertEquals(2, region.getMergedLocationData().getOffset());
assertEquals(3, region.getMergedLocationData().getLength());
assertEquals(2, region.getMergedAssociatedLocation().getOffset());
assertEquals(3, region.getMergedAssociatedLocation().getLength());
assertEquals(URI.createURI("uri"), region.getAssociatedPath());
assertEquals("project", region.getAssociatedProjectName());
assertNull(region.getParent());
@ -223,4 +224,169 @@ public class TraceRegionTest extends Assert {
new TraceRegion(2, 1, 0, 0, 5, 6, 0, 0, parent, null, null);
assertEquals("<1:2[a<3:4[b<5:6[c]]d]e", root.getAnnotatedString("abcde"));
}
@Test
public void testInvertFor_01() {
URI path = URI.createURI("a");
TraceRegion root = new TraceRegion(1, 2, 3, 4, 5, 6, 7, 8, null, path, "projectA");
List<AbstractTraceRegion> invertedList = root.invertFor(path, URI.createURI("b"), "projectB");
assertEquals(1, invertedList.size());
AbstractTraceRegion inverted = invertedList.get(0);
assertEquals(5, inverted.getMyOffset());
assertEquals(6, inverted.getMyLength());
assertEquals(7, inverted.getMyLineNumber());
assertEquals(8, inverted.getMyEndLineNumber());
ILocationData associatedLocation = inverted.getMergedAssociatedLocation();
assertEquals(1, associatedLocation.getOffset());
assertEquals(2, associatedLocation.getLength());
assertEquals(3, associatedLocation.getLineNumber());
assertEquals(4, associatedLocation.getEndLineNumber());
}
@Test
public void testInvertFor_02() {
URI path = URI.createURI("a");
TraceRegion root = new TraceRegion(0, 2, 0, 2, 4, 2, 4, 6, null, path, "projectA");
TraceRegion first = new TraceRegion(0, 1, 0, 1, 4, 1, 4, 5, root, null, null);
TraceRegion second = new TraceRegion(1, 1, 1, 2, 5, 1, 5, 6, root, null, null);
List<AbstractTraceRegion> invertedList = root.invertFor(path, URI.createURI("b"), "projectB");
assertEquals(1, invertedList.size());
AbstractTraceRegion inverted = invertedList.get(0);
assertEquals(2, inverted.getNestedRegions().size());
assertEquals(4, inverted.getMyOffset());
assertEquals(2, inverted.getMyLength());
assertEquals(4, inverted.getMyLineNumber());
assertEquals(6, inverted.getMyEndLineNumber());
ILocationData associatedLocation = inverted.getMergedAssociatedLocation();
assertEquals(0, associatedLocation.getOffset());
assertEquals(2, associatedLocation.getLength());
assertEquals(0, associatedLocation.getLineNumber());
assertEquals(2, associatedLocation.getEndLineNumber());
AbstractTraceRegion firstChild = inverted.getNestedRegions().get(0);
assertEquals(0, firstChild.getNestedRegions().size());
assertEquals(4, firstChild.getMyOffset());
assertEquals(1, firstChild.getMyLength());
assertEquals(4, firstChild.getMyLineNumber());
assertEquals(5, firstChild.getMyEndLineNumber());
associatedLocation = firstChild.getMergedAssociatedLocation();
assertEquals(0, associatedLocation.getOffset());
assertEquals(1, associatedLocation.getLength());
assertEquals(0, associatedLocation.getLineNumber());
assertEquals(1, associatedLocation.getEndLineNumber());
AbstractTraceRegion secondChild = inverted.getNestedRegions().get(1);
assertEquals(0, secondChild.getNestedRegions().size());
assertEquals(5, secondChild.getMyOffset());
assertEquals(1, secondChild.getMyLength());
assertEquals(5, secondChild.getMyLineNumber());
assertEquals(6, secondChild.getMyEndLineNumber());
associatedLocation = secondChild.getMergedAssociatedLocation();
assertEquals(1, associatedLocation.getOffset());
assertEquals(1, associatedLocation.getLength());
assertEquals(1, associatedLocation.getLineNumber());
assertEquals(2, associatedLocation.getEndLineNumber());
}
@Test
public void testInvertFor_03() {
URI path = URI.createURI("a");
TraceRegion root = new TraceRegion(0, 2, 0, 2, 4, 3, 4, 6, null, path, "projectA");
TraceRegion first = new TraceRegion(0, 1, 0, 1, 4, 1, 4, 5, root, null, null);
TraceRegion second = new TraceRegion(1, 1, 1, 2, 6, 1, 5, 6, root, null, null);
List<AbstractTraceRegion> invertedList = root.invertFor(path, URI.createURI("b"), "projectB");
assertEquals(1, invertedList.size());
AbstractTraceRegion inverted = invertedList.get(0);
assertEquals(2, inverted.getNestedRegions().size());
assertEquals(4, inverted.getMyOffset());
assertEquals(3, inverted.getMyLength());
assertEquals(4, inverted.getMyLineNumber());
assertEquals(6, inverted.getMyEndLineNumber());
ILocationData associatedLocation = inverted.getMergedAssociatedLocation();
assertEquals(0, associatedLocation.getOffset());
assertEquals(2, associatedLocation.getLength());
assertEquals(0, associatedLocation.getLineNumber());
assertEquals(2, associatedLocation.getEndLineNumber());
AbstractTraceRegion firstChild = inverted.getNestedRegions().get(0);
assertEquals(0, firstChild.getNestedRegions().size());
assertEquals(4, firstChild.getMyOffset());
assertEquals(1, firstChild.getMyLength());
assertEquals(4, firstChild.getMyLineNumber());
assertEquals(5, firstChild.getMyEndLineNumber());
associatedLocation = firstChild.getMergedAssociatedLocation();
assertEquals(0, associatedLocation.getOffset());
assertEquals(1, associatedLocation.getLength());
assertEquals(0, associatedLocation.getLineNumber());
assertEquals(1, associatedLocation.getEndLineNumber());
AbstractTraceRegion secondChild = inverted.getNestedRegions().get(1);
assertEquals(0, secondChild.getNestedRegions().size());
assertEquals(6, secondChild.getMyOffset());
assertEquals(1, secondChild.getMyLength());
assertEquals(5, secondChild.getMyLineNumber());
assertEquals(6, secondChild.getMyEndLineNumber());
associatedLocation = secondChild.getMergedAssociatedLocation();
assertEquals(1, associatedLocation.getOffset());
assertEquals(1, associatedLocation.getLength());
assertEquals(1, associatedLocation.getLineNumber());
assertEquals(2, associatedLocation.getEndLineNumber());
}
@Test
public void testInvertFor_04() {
URI path = URI.createURI("a");
TraceRegion root = new TraceRegion(0, 2, 0, 2, 4, 3, 4, 6, null, path, "projectA");
TraceRegion first = new TraceRegion(0, 1, 0, 1, 4, 2, 4, 5, root, null, null);
TraceRegion second = new TraceRegion(1, 1, 1, 2, 5, 2, 5, 6, root, null, null);
List<AbstractTraceRegion> invertedList = root.invertFor(path, URI.createURI("b"), "projectB");
assertEquals(1, invertedList.size());
AbstractTraceRegion inverted = invertedList.get(0);
assertEquals(2, inverted.getNestedRegions().size());
assertEquals(4, inverted.getMyOffset());
assertEquals(3, inverted.getMyLength());
assertEquals(4, inverted.getMyLineNumber());
assertEquals(6, inverted.getMyEndLineNumber());
ILocationData associatedLocation = inverted.getMergedAssociatedLocation();
assertEquals(0, associatedLocation.getOffset());
assertEquals(2, associatedLocation.getLength());
assertEquals(0, associatedLocation.getLineNumber());
assertEquals(2, associatedLocation.getEndLineNumber());
AbstractTraceRegion firstChild = inverted.getNestedRegions().get(0);
assertEquals(1, firstChild.getNestedRegions().size());
assertEquals(4, firstChild.getMyOffset());
assertEquals(2, firstChild.getMyLength());
assertEquals(4, firstChild.getMyLineNumber());
assertEquals(5, firstChild.getMyEndLineNumber());
associatedLocation = firstChild.getMergedAssociatedLocation();
assertEquals(0, associatedLocation.getOffset());
assertEquals(1, associatedLocation.getLength());
assertEquals(0, associatedLocation.getLineNumber());
assertEquals(1, associatedLocation.getEndLineNumber());
AbstractTraceRegion grandChild = firstChild.getNestedRegions().get(0);
assertEquals(0, grandChild.getNestedRegions().size());
assertEquals(5, grandChild.getMyOffset());
assertEquals(1, grandChild.getMyLength());
assertEquals(5, grandChild.getMyLineNumber());
assertEquals(5, grandChild.getMyEndLineNumber());
associatedLocation = grandChild.getMergedAssociatedLocation();
assertEquals(1, associatedLocation.getOffset());
assertEquals(1, associatedLocation.getLength());
assertEquals(1, associatedLocation.getLineNumber());
assertEquals(2, associatedLocation.getEndLineNumber());
AbstractTraceRegion secondChild = inverted.getNestedRegions().get(1);
assertEquals(0, secondChild.getNestedRegions().size());
assertEquals(6, secondChild.getMyOffset());
assertEquals(1, secondChild.getMyLength());
assertEquals(5, secondChild.getMyLineNumber());
assertEquals(6, secondChild.getMyEndLineNumber());
associatedLocation = secondChild.getMergedAssociatedLocation();
assertEquals(1, associatedLocation.getOffset());
assertEquals(1, associatedLocation.getLength());
assertEquals(1, associatedLocation.getLineNumber());
assertEquals(2, associatedLocation.getEndLineNumber());
}
}