@@ -20,22 +20,18 @@ | |||
<dependency> | |||
<groupId>com.google.guava</groupId> | |||
<artifactId>guava</artifactId> | |||
<version>18.0</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>commons-io</groupId> | |||
<artifactId>commons-io</artifactId> | |||
<version>2.4</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.apache.commons</groupId> | |||
<artifactId>commons-lang3</artifactId> | |||
<version>3.3.2</version> | |||
<groupId>commons-lang</groupId> | |||
<artifactId>commons-lang</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.google.code.findbugs</groupId> | |||
<artifactId>jsr305</artifactId> | |||
<version>3.0.0</version> | |||
<scope>provided</scope> | |||
</dependency> | |||
<dependency> |
@@ -20,8 +20,12 @@ | |||
package org.sonar.xoo.coverage; | |||
import com.google.common.base.Splitter; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.lang3.StringUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.sensor.Sensor; | |||
import org.sonar.api.batch.sensor.SensorContext; | |||
@@ -32,11 +36,6 @@ import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.xoo.Xoo; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
public abstract class AbstractCoverageSensor implements Sensor { | |||
private static final Logger LOG = Loggers.get(AbstractCoverageSensor.class); | |||
@@ -24,7 +24,7 @@ import java.io.IOException; | |||
import java.io.Serializable; | |||
import java.util.List; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.lang3.StringUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.measure.MetricFinder; | |||
import org.sonar.api.batch.sensor.Sensor; |
@@ -25,7 +25,7 @@ import java.io.IOException; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.lang3.StringUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.sensor.Sensor; | |||
import org.sonar.api.batch.sensor.SensorContext; |
@@ -25,7 +25,7 @@ import java.io.IOException; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.lang3.StringUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.sensor.Sensor; | |||
import org.sonar.api.batch.sensor.SensorContext; |
@@ -20,18 +20,17 @@ | |||
package org.sonar.xoo.scm; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.lang3.StringUtils; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.scm.BlameCommand; | |||
import org.sonar.api.batch.scm.BlameLine; | |||
import org.sonar.api.utils.DateUtils; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.nio.charset.StandardCharsets; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.scm.BlameCommand; | |||
import org.sonar.api.batch.scm.BlameLine; | |||
import org.sonar.api.utils.DateUtils; | |||
public class XooBlameCommand extends BlameCommand { | |||
@@ -20,8 +20,13 @@ | |||
package org.sonar.xoo.test; | |||
import com.google.common.base.Splitter; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.lang3.StringUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.batch.DependsUpon; | |||
import org.sonar.api.batch.fs.FilePredicates; | |||
import org.sonar.api.batch.fs.FileSystem; | |||
@@ -38,12 +43,6 @@ import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.xoo.Xoo; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
/** | |||
* Parse files *.xoo.testcoverage | |||
*/ |
@@ -20,8 +20,12 @@ | |||
package org.sonar.xoo.test; | |||
import com.google.common.base.Splitter; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.lang3.StringUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.batch.DependedUpon; | |||
import org.sonar.api.batch.fs.FilePredicates; | |||
import org.sonar.api.batch.fs.FileSystem; | |||
@@ -38,11 +42,6 @@ import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.xoo.Xoo; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
/** | |||
* Parse files *.xoo.test | |||
*/ |
@@ -93,8 +93,7 @@ public class ProjectDataLoader { | |||
} | |||
private List<FilePathWithHashDto> searchFilesWithHashAndRevision(DbSession session, ComponentDto module) { | |||
return module.isRootProject() ? | |||
dbClient.componentDao().selectEnabledFilesFromProject(session, module.uuid()) | |||
return module.isRootProject() ? dbClient.componentDao().selectEnabledFilesFromProject(session, module.uuid()) | |||
: dbClient.componentDao().selectEnabledDescendantFiles(session, module.uuid()); | |||
} | |||
@@ -129,7 +128,7 @@ public class ProjectDataLoader { | |||
} | |||
} | |||
private void addSettingsToChildrenModules(ProjectRepositories ref, String moduleKey, Map<String, String> parentProperties, TreeModuleSettings treeModuleSettings, | |||
private static void addSettingsToChildrenModules(ProjectRepositories ref, String moduleKey, Map<String, String> parentProperties, TreeModuleSettings treeModuleSettings, | |||
boolean hasScanPerm) { | |||
Map<String, String> currentParentProperties = newHashMap(); | |||
currentParentProperties.putAll(parentProperties); |
@@ -202,7 +202,7 @@ public class BatchExtensionDictionnary { | |||
return results; | |||
} | |||
private void evaluateClass(Class extensionClass, Class annotationClass, List<Object> results) { | |||
private static void evaluateClass(Class extensionClass, Class annotationClass, List<Object> results) { | |||
Annotation annotation = extensionClass.getAnnotation(annotationClass); | |||
if (annotation != null) { | |||
if (annotation.annotationType().isAssignableFrom(DependsUpon.class)) { |
@@ -87,7 +87,7 @@ public class PhaseProfiling extends AbstractTimeProfiling { | |||
* @param o | |||
* @return | |||
*/ | |||
private String toStringOrSimpleName(Object o) { | |||
private static String toStringOrSimpleName(Object o) { | |||
String toString = o.toString(); | |||
if (toString == null || toString.startsWith(o.getClass().getName())) { | |||
return o.getClass().getSimpleName(); |
@@ -19,8 +19,6 @@ | |||
*/ | |||
package org.sonar.batch.scan.report; | |||
import org.sonar.batch.issue.tracking.TrackedIssue; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.Properties; | |||
@@ -31,11 +29,12 @@ import org.sonar.api.rule.Severity; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.batch.issue.IssueCache; | |||
import org.sonar.batch.issue.tracking.TrackedIssue; | |||
import org.sonar.batch.scan.filesystem.InputPathCache; | |||
@Properties({ | |||
@Property(key = ConsoleReport.CONSOLE_REPORT_ENABLED_KEY, name = "Enable console report", description = "Set this to true to generate a report in console output", | |||
type = PropertyType.BOOLEAN, defaultValue = "false")}) | |||
@Property(key = ConsoleReport.CONSOLE_REPORT_ENABLED_KEY, defaultValue = "false", name = "Enable console report", | |||
description = "Set this to true to generate a report in console output", type = PropertyType.BOOLEAN)}) | |||
public class ConsoleReport implements Reporter { | |||
@VisibleForTesting | |||
@@ -122,7 +121,7 @@ public class ConsoleReport implements Reporter { | |||
LOG.info(sb.toString()); | |||
} | |||
private void printNewIssues(Report r, StringBuilder sb) { | |||
private static void printNewIssues(Report r, StringBuilder sb) { | |||
int newIssues = r.totalNewIssues; | |||
if (newIssues > 0) { | |||
sb.append(StringUtils.leftPad("+" + newIssues, LEFT_PAD)).append(" issue" + (newIssues > 1 ? "s" : "")).append("\n\n"); |
@@ -21,16 +21,6 @@ package org.sonar.batch.scan.report; | |||
import com.google.common.collect.Maps; | |||
import freemarker.template.Template; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.io.IOUtils; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.Properties; | |||
import org.sonar.api.Property; | |||
import org.sonar.api.PropertyType; | |||
import org.sonar.api.batch.fs.FileSystem; | |||
import org.sonar.api.config.Settings; | |||
import java.io.File; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
@@ -40,19 +30,26 @@ import java.io.OutputStreamWriter; | |||
import java.io.Writer; | |||
import java.net.URISyntaxException; | |||
import java.util.Map; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.Properties; | |||
import org.sonar.api.Property; | |||
import org.sonar.api.PropertyType; | |||
import org.sonar.api.batch.fs.FileSystem; | |||
import org.sonar.api.config.Settings; | |||
@Properties({ | |||
@Property(key = HtmlReport.HTML_REPORT_ENABLED_KEY, name = "Enable HTML report", description = "Set this to true to generate an HTML report", | |||
type = PropertyType.BOOLEAN, defaultValue = "false"), | |||
@Property(key = HtmlReport.HTML_REPORT_LOCATION_KEY, name = "HTML Report location", | |||
description = "Location of the generated report. Can be absolute or relative to working directory", | |||
type = PropertyType.STRING, defaultValue = HtmlReport.HTML_REPORT_LOCATION_DEFAULT, global = false, project = false), | |||
@Property(key = HtmlReport.HTML_REPORT_NAME_KEY, name = "HTML Report name", | |||
description = "Name of the generated report. Will be suffixed by .html or -light.html", | |||
type = PropertyType.STRING, defaultValue = HtmlReport.HTML_REPORT_NAME_DEFAULT, global = false, project = false), | |||
@Property(key = HtmlReport.HTML_REPORT_LIGHTMODE_ONLY, name = "Html report in light mode only", project = true, | |||
description = "Set this to true to only generate the new issues report (light report)", | |||
type = PropertyType.BOOLEAN, defaultValue = "false")}) | |||
@Property(key = HtmlReport.HTML_REPORT_ENABLED_KEY, defaultValue = "false", name = "Enable HTML report", description = "Set this to true to generate an HTML report", | |||
type = PropertyType.BOOLEAN), | |||
@Property(key = HtmlReport.HTML_REPORT_LOCATION_KEY, defaultValue = HtmlReport.HTML_REPORT_LOCATION_DEFAULT, name = "HTML Report location", | |||
description = "Location of the generated report. Can be absolute or relative to working directory", project = false, global = false, type = PropertyType.STRING), | |||
@Property(key = HtmlReport.HTML_REPORT_NAME_KEY, defaultValue = HtmlReport.HTML_REPORT_NAME_DEFAULT, name = "HTML Report name", | |||
description = "Name of the generated report. Will be suffixed by .html or -light.html", project = false, global = false, type = PropertyType.STRING), | |||
@Property(key = HtmlReport.HTML_REPORT_LIGHTMODE_ONLY, defaultValue = "false", name = "Html report in light mode only", | |||
description = "Set this to true to only generate the new issues report (light report)", project = true, type = PropertyType.BOOLEAN)}) | |||
public class HtmlReport implements Reporter { | |||
private static final Logger LOG = LoggerFactory.getLogger(HtmlReport.class); | |||
@@ -111,7 +108,7 @@ public class HtmlReport implements Reporter { | |||
if (!reportFileDir.isAbsolute()) { | |||
reportFileDir = new File(fs.workDir(), reportFileDirStr); | |||
} | |||
if (reportFileDirStr.endsWith(".html")) { | |||
if (StringUtils.endsWith(reportFileDirStr, ".html")) { | |||
LOG.warn(HTML_REPORT_LOCATION_KEY + " should indicate a directory. Using parent folder."); | |||
reportFileDir = reportFileDir.getParentFile(); | |||
} |
@@ -22,6 +22,7 @@ package org.sonar.batch.scm; | |||
import com.google.common.base.Joiner; | |||
import java.util.LinkedHashMap; | |||
import java.util.Map; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.picocontainer.Startable; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.Properties; | |||
@@ -40,13 +41,13 @@ import org.sonar.batch.scan.ImmutableProjectReactor; | |||
@Property( | |||
key = ScmConfiguration.FORCE_RELOAD_KEY, | |||
defaultValue = "false", | |||
type = PropertyType.BOOLEAN, | |||
name = "Force reloading of SCM information for all files", | |||
description = "By default only files modified since previous analysis are inspected. Set this parameter to true to force the reloading.", | |||
module = false, | |||
category = CoreProperties.CATEGORY_SCM, | |||
project = false, | |||
module = false, | |||
global = false, | |||
category = CoreProperties.CATEGORY_SCM) | |||
type = PropertyType.BOOLEAN) | |||
}) | |||
@InstantiationStrategy(InstantiationStrategy.PER_BATCH) | |||
@BatchSide | |||
@@ -103,7 +104,7 @@ public final class ScmConfiguration implements Startable { | |||
if (providerPerKey.containsKey(forcedProviderKey)) { | |||
this.provider = providerPerKey.get(forcedProviderKey); | |||
} else { | |||
String supportedProviders = providerPerKey.isEmpty() ? "No SCM provider installed" : "Supported SCM providers are " + Joiner.on(",").join(providerPerKey.keySet()); | |||
String supportedProviders = providerPerKey.isEmpty() ? "No SCM provider installed" : ("Supported SCM providers are " + Joiner.on(",").join(providerPerKey.keySet())); | |||
throw new IllegalArgumentException("SCM provider was set to \"" + forcedProviderKey + "\" but no SCM provider found for this key. " + supportedProviders); | |||
} | |||
} | |||
@@ -111,7 +112,7 @@ public final class ScmConfiguration implements Startable { | |||
private void considerOldScmUrl() { | |||
if (settings.hasKey(CoreProperties.LINKS_SOURCES_DEV)) { | |||
String url = settings.getString(CoreProperties.LINKS_SOURCES_DEV); | |||
if (url.startsWith("scm:")) { | |||
if (StringUtils.startsWith(url, "scm:")) { | |||
String[] split = url.split(":"); | |||
if (split.length > 1) { | |||
setProviderIfSupported(split[1]); |
@@ -69,7 +69,7 @@ public class ProgressReport implements Runnable { | |||
} | |||
} | |||
private void log(String message) { | |||
private static void log(String message) { | |||
synchronized (LOG) { | |||
LOG.info(message); | |||
LOG.notifyAll(); |
@@ -244,7 +244,7 @@ public class ComponentContainer implements ContainerPopulator.Container { | |||
return this; | |||
} | |||
private String getName(Object extension) { | |||
private static String getName(Object extension) { | |||
if (extension instanceof Class) { | |||
return ((Class<?>) extension).getName(); | |||
} |
@@ -139,7 +139,7 @@ class FileSourceDto { | |||
return result; | |||
} | |||
private void addBlock(int blockId, Block block, Map<Integer, StringBuilder> dupPerLine) { | |||
private static void addBlock(int blockId, Block block, Map<Integer, StringBuilder> dupPerLine) { | |||
int currentLine = block.start; | |||
for (int i = 0; i < block.length; i++) { | |||
if (dupPerLine.get(currentLine) == null) { |
@@ -56,11 +56,12 @@ public class DefaultCpdTokens extends DefaultStorable implements NewCpdTokens { | |||
} | |||
@Override | |||
public NewCpdTokens addToken(TextRange range, String image) { | |||
public DefaultCpdTokens addToken(TextRange range, String image) { | |||
Preconditions.checkNotNull(range, "Range should not be null"); | |||
Preconditions.checkNotNull(image, "Image should not be null"); | |||
Preconditions.checkState(inputFile != null, "Call onFile() first"); | |||
Preconditions.checkState(lastRange == null || lastRange.end().compareTo(range.start()) >= 0, | |||
"Tokens of file %s should be provided in order. \nPrevious token: %s\nLast token: %s", inputFile, lastRange, range); | |||
Preconditions.checkState(lastRange == null || lastRange.end().compareTo(range.start()) <= 0, | |||
"Tokens of file %s should be provided in order.\nPrevious token: %s\nLast token: %s", inputFile, lastRange, range); | |||
String value = image; | |||
@@ -72,6 +73,7 @@ public class DefaultCpdTokens extends DefaultStorable implements NewCpdTokens { | |||
} | |||
currentIndex++; | |||
sb.append(value); | |||
lastRange = range; | |||
return this; | |||
} |
@@ -0,0 +1,134 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.sensor.cpd.internal; | |||
import org.junit.Test; | |||
import org.sonar.api.batch.fs.internal.DefaultInputFile; | |||
import org.sonar.api.batch.sensor.internal.SensorStorage; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.fail; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
public class DefaultCpdTokensTest { | |||
private static final DefaultInputFile INPUT_FILE = new DefaultInputFile("foo", "src/Foo.java") | |||
.setLines(2) | |||
.setOriginalLineOffsets(new int[] {0, 50}) | |||
.setLastValidOffset(100); | |||
@Test | |||
public void save_no_tokens() { | |||
SensorStorage sensorStorage = mock(SensorStorage.class); | |||
DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage) | |||
.onFile(INPUT_FILE); | |||
tokens.save(); | |||
verify(sensorStorage).store(tokens); | |||
assertThat(tokens.inputFile()).isEqualTo(INPUT_FILE); | |||
} | |||
@Test | |||
public void save_one_token() { | |||
SensorStorage sensorStorage = mock(SensorStorage.class); | |||
DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage) | |||
.onFile(INPUT_FILE) | |||
.addToken(INPUT_FILE.newRange(1, 2, 1, 5), "foo"); | |||
tokens.save(); | |||
verify(sensorStorage).store(tokens); | |||
assertThat(tokens.getTokenLines()).extracting("value", "startLine", "hashCode", "startUnit", "endUnit").containsExactly(tuple("foo", 1, "foo".hashCode(), 1, 1)); | |||
} | |||
@Test | |||
public void save_many_tokens() { | |||
SensorStorage sensorStorage = mock(SensorStorage.class); | |||
DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage) | |||
.onFile(INPUT_FILE) | |||
.addToken(INPUT_FILE.newRange(1, 2, 1, 5), "foo") | |||
.addToken(INPUT_FILE.newRange(1, 6, 1, 10), "bar") | |||
.addToken(INPUT_FILE.newRange(1, 20, 1, 25), "biz") | |||
.addToken(INPUT_FILE.newRange(2, 1, 2, 10), "next"); | |||
tokens.save(); | |||
verify(sensorStorage).store(tokens); | |||
assertThat(tokens.getTokenLines()) | |||
.extracting("value", "startLine", "hashCode", "startUnit", "endUnit") | |||
.containsExactly( | |||
tuple("foobarbiz", 1, "foobarbiz".hashCode(), 1, 3), | |||
tuple("next", 2, "next".hashCode(), 4, 4)); | |||
} | |||
@Test | |||
public void basic_validation() { | |||
SensorStorage sensorStorage = mock(SensorStorage.class); | |||
DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage); | |||
try { | |||
tokens.save(); | |||
fail("Expected exception"); | |||
} catch (Exception e) { | |||
assertThat(e).hasMessage("Call onFile() first"); | |||
} | |||
try { | |||
tokens.addToken(INPUT_FILE.newRange(1, 2, 1, 5), "foo"); | |||
fail("Expected exception"); | |||
} catch (Exception e) { | |||
assertThat(e).hasMessage("Call onFile() first"); | |||
} | |||
try { | |||
tokens.addToken(null, "foo"); | |||
fail("Expected exception"); | |||
} catch (Exception e) { | |||
assertThat(e).hasMessage("Range should not be null"); | |||
} | |||
try { | |||
tokens.addToken(INPUT_FILE.newRange(1, 2, 1, 5), null); | |||
fail("Expected exception"); | |||
} catch (Exception e) { | |||
assertThat(e).hasMessage("Image should not be null"); | |||
} | |||
} | |||
@Test | |||
public void validate_tokens_order() { | |||
SensorStorage sensorStorage = mock(SensorStorage.class); | |||
DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage) | |||
.onFile(INPUT_FILE) | |||
.addToken(INPUT_FILE.newRange(1, 6, 1, 10), "bar"); | |||
try { | |||
tokens.addToken(INPUT_FILE.newRange(1, 2, 1, 5), "foo"); | |||
fail("Expected exception"); | |||
} catch (Exception e) { | |||
assertThat(e).hasMessage("Tokens of file [moduleKey=foo, relative=src/Foo.java, basedir=null] should be provided in order.\n" + | |||
"Previous token: Range[from [line=1, lineOffset=6] to [line=1, lineOffset=10]]\n" + | |||
"Last token: Range[from [line=1, lineOffset=2] to [line=1, lineOffset=5]]"); | |||
} | |||
} | |||
} |