blob: 3becb3f4fa845d186560f1a4ff43df416f90683b [file] [log] [blame]
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// This program and the accompanying materials are made available
// under the terms of the Eclipse Public License v2.0 which accompanies
// this distribution, and is available at
// https://www.eclipse.org/legal/epl-2.0/
package org.eclipse.wst.jsdt.chromium.debug.core.sourcemap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import junit.framework.Assert;
import org.eclipse.wst.jsdt.chromium.debug.core.model.StringMappingData;
import org.eclipse.wst.jsdt.chromium.debug.core.model.VmResourceId;
import org.eclipse.wst.jsdt.chromium.debug.core.sourcemap.SourcePositionMap.TranslateDirection;
import org.eclipse.wst.jsdt.chromium.debug.core.sourcemap.SourcePositionMapBuilder.CannotAddException;
import org.eclipse.wst.jsdt.chromium.debug.core.sourcemap.SourcePositionMapBuilder.MappingHandle;
import org.eclipse.wst.jsdt.chromium.debug.core.sourcemap.SourcePositionMapBuilder.ResourceSection;
import org.junit.Test;
public class PositionMapBuilderImplTest {
/**
* Creates a sample position map and checks several points.
*/
@Test
public void basicTest() throws CannotAddException {
SourcePositionMapBuilder builder = new PositionMapBuilderImpl();
builder.addMapping(new ResourceSection(new VmResourceId("source1.js", null), 0, 0, 5, 0),
new ResourceSection(new VmResourceId("compiled.js", null), 0, 0, 1, 0),
new TextSectionMappingImpl(
new StringMappingData(new int [] { 0,0, 1,0, 2,0, 3,0, 4,0 } , 5, 0),
new StringMappingData(new int [] { 0,0, 0,10, 0,20, 0,30, 0,40 }, 0, 50)));
builder.addMapping(new ResourceSection(new VmResourceId("source2.js", null), 0, 0, 5, 0),
new ResourceSection(new VmResourceId("compiled.js", null), 1, 0, 2, 0),
new TextSectionMappingImpl(
new StringMappingData(new int [] { 0,0, 1,0, 2,0, 3,0, 4,0}, 5, 0),
new StringMappingData(new int [] { 1,0, 1,10, 1,20, 1,30, 1,40}, 1, 50)));
builder.addMapping(new ResourceSection(new VmResourceId("source3.js", null), 0, 0, 5, 0),
new ResourceSection(new VmResourceId("compiled.js", null), 2, 0, 3, 0),
new TextSectionMappingImpl(
new StringMappingData(new int [] {0,0, 1,0, 2,0, 3,0, 4,0}, 5, 0),
new StringMappingData(new int [] {2,0, 2,10, 2,20, 2,30, 2,40}, 2, 50)));
SourcePositionMap map = builder.getSourcePositionMap();
checkTwoWay(map, "other.js", 17, 4, "other.js", 17, 4, TranslateDirection.VM_TO_USER);
checkTwoWay(map, "compiled.js", 2, 11, "source3.js", 1, 1, TranslateDirection.VM_TO_USER);
checkTwoWay(map, "compiled.js", 0, 0, "source1.js", 0, 0, TranslateDirection.VM_TO_USER);
checkTwoWay(map, "compiled.js", 0, 1, "source1.js", 0, 1, TranslateDirection.VM_TO_USER);
checkTwoWay(map, "compiled.js", 1, 0, "source2.js", 0, 0, TranslateDirection.VM_TO_USER);
checkTwoWay(map, "compiled.js", 1, 3, "source2.js", 0, 3, TranslateDirection.VM_TO_USER);
checkTwoWay(map, "compiled.js", 2, 0, "source3.js", 0, 0, TranslateDirection.VM_TO_USER);
checkTwoWay(map, "compiled.js", 2, 3, "source3.js", 0, 3, TranslateDirection.VM_TO_USER);
checkTwoWay(map, "compiled.js", 3, 0, "compiled.js", 3, 0, TranslateDirection.VM_TO_USER);
checkTwoWay(map, "compiled.js", 3, 3, "compiled.js", 3, 3, TranslateDirection.VM_TO_USER);
}
private static SourcePosition checkOneWay(SourcePositionMap map,
String fromFile, int fromLine, int fromColumn,
String toFile, int toLine, int toColumn, TranslateDirection direction) {
SourcePosition result = map.translatePosition(new VmResourceId(fromFile, null),
fromLine, fromColumn, direction);
Assert.assertEquals(new SourcePosition(new VmResourceId(toFile, null), toLine, toColumn),
result);
return result;
}
private static void checkTwoWay(SourcePositionMap map,
String fromFile, int fromLine, int fromColumn,
String toFile, int toLine, int toColumn, TranslateDirection direction) {
checkOneWay(map, fromFile, fromLine, fromColumn, toFile, toLine, toColumn, direction);
SourcePosition result = map.translatePosition(new VmResourceId(toFile, null), toLine, toColumn,
direction.opposite());
Assert.assertEquals(new SourcePosition(new VmResourceId(fromFile, null), fromLine, fromColumn),
result);
}
/**
* Checks that {@link SourcePositionMapBuilder#addMapping} correctly handles overlapping regions.
*/
@Test
public void testAddMappingOverlaps() throws CannotAddException {
new OverlappingMapTestFramework().run();
}
private static abstract class MultiRangeMapTestFrameworkBase {
static final VmResourceId COMPILED_JS_ID = new VmResourceId("compiled.js", null);
static ResourceSection[] GOOD_SECTIONS = {
new ResourceSection(COMPILED_JS_ID, 1, 0, 2, 0),
new ResourceSection(COMPILED_JS_ID, 3, 0, 3, 0),
new ResourceSection(COMPILED_JS_ID, 5, 0, 5, 0),
new ResourceSection(COMPILED_JS_ID, 5, 0, 5, 0),
new ResourceSection(COMPILED_JS_ID, 5, 0, 8, 0),
new ResourceSection(COMPILED_JS_ID, 8, 0, 8, 0),
};
private static final int SHUFFLE_TRIES = 10;
void run() throws CannotAddException {
// We get all good sections and add them in a random order. Then we check
// that each of conflict section will not add.
Random random = new Random(0);
for (int i = 0; i < SHUFFLE_TRIES; i++) {
runOneShuffle(random);
}
}
protected abstract void runOneShuffle(Random random) throws CannotAddException;
protected ArrayList<MappingHandle> addGoodRanges(SourcePositionMapBuilder builder,
Random random) throws CannotAddException {
List<ResourceSection> vmSections =
new ArrayList<SourcePositionMapBuilder.ResourceSection>(Arrays.asList(GOOD_SECTIONS));
Collections.shuffle(vmSections, random);
ArrayList<MappingHandle> result =
new ArrayList<SourcePositionMapBuilder.MappingHandle>(vmSections.size());
// Add all good sections.
int index = 0;
for (ResourceSection section : vmSections) {
addSection(builder, section, index);
index++;
}
return result;
}
protected static MappingHandle addSection(SourcePositionMapBuilder builder,
ResourceSection vmSection, int index) throws CannotAddException {
ResourceSection originalSection =
new ResourceSection(new VmResourceId(("source" + index + ".js"), null), 0, 0, 5, 0);
TextSectionMappingImpl textMapping = new TextSectionMappingImpl(
new StringMappingData(
new int [] { vmSection.getStart().getLine(), vmSection.getStart().getColumn() },
vmSection.getEnd().getLine(), vmSection.getEnd().getColumn()),
new StringMappingData((new int [] { 0, 0 }), 5, 0));
return builder.addMapping(originalSection, vmSection, textMapping);
}
}
private static class OverlappingMapTestFramework extends MultiRangeMapTestFrameworkBase {
private static ResourceSection[] CONFLICT_SECTIONS = {
new ResourceSection(COMPILED_JS_ID, 1, 0, 2, 0),
new ResourceSection(COMPILED_JS_ID, 0, 1, 1, 1),
new ResourceSection(COMPILED_JS_ID, 1, 1, 2, 1),
new ResourceSection(COMPILED_JS_ID, 1, 1, 1, 2),
new ResourceSection(COMPILED_JS_ID, 2, 0, 4, 0),
new ResourceSection(COMPILED_JS_ID, 4, 0, 6, 0),
new ResourceSection(COMPILED_JS_ID, 6, 0, 7, 0),
new ResourceSection(COMPILED_JS_ID, 7, 0, 9, 0),
};
protected void runOneShuffle(Random random) throws CannotAddException {
final SourcePositionMapBuilder builder = new PositionMapBuilderImpl();
List<MappingHandle> goodRangeHandles = addGoodRanges(builder, random);
final int conflict_section_index = goodRangeHandles.size();
// Now try to add conflict sections.
for (final ResourceSection section : CONFLICT_SECTIONS) {
assertThrowsAddException(new RunnableWithCannotAddException() {
public void run() throws CannotAddException {
addSection(builder, section, conflict_section_index);
}
});
}
}
}
/**
* Checks that {@link SourcePositionMapBuilder} can add mappings and delete them
* in different order.
*/
@Test
public void testAddAndDeleteMapping() throws CannotAddException {
new AddAndDeleteMapTestFramework().run();
}
private static class AddAndDeleteMapTestFramework extends MultiRangeMapTestFrameworkBase {
protected void runOneShuffle(Random random) throws CannotAddException {
final SourcePositionMapBuilder builder = new PositionMapBuilderImpl();
ArrayList<MappingHandle> goodRangeHandles = addGoodRanges(builder, random);
// Delete ranges in other order.
Collections.shuffle(goodRangeHandles, random);
for (MappingHandle handle : goodRangeHandles) {
handle.delete();
}
}
}
private interface RunnableWithCannotAddException {
void run() throws CannotAddException;
}
private static void assertThrowsAddException(RunnableWithCannotAddException runnable) {
try {
runnable.run();
Assert.fail("Exception expected");
} catch (CannotAddException e) {
// Expected exception.
}
}
}