lombok.LombokTestSource Maven / Gradle / Ivy
/*
* Copyright (C) 2014-2019 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package lombok;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.junit.Assert;
import lombok.core.LombokImmutableList;
import lombok.core.configuration.BubblingConfigurationResolver;
import lombok.core.configuration.ConfigurationFile;
import lombok.core.configuration.ConfigurationFileToSource;
import lombok.core.configuration.ConfigurationParser;
import lombok.core.configuration.ConfigurationProblemReporter;
import lombok.core.configuration.ConfigurationResolver;
import lombok.core.configuration.ConfigurationSource;
import lombok.core.configuration.SingleConfigurationSource;
public class LombokTestSource {
private final File file;
private final String content;
private final LombokImmutableList messages;
private final Map formatPreferences;
private final boolean ignore;
private final boolean skipCompareContent;
private final boolean skipIdempotent;
private final boolean unchanged;
private final int versionLowerLimit, versionUpperLimit;
private final ConfigurationResolver configuration;
private final String specifiedEncoding;
private final List platforms;
public boolean runOnPlatform(String platform) {
if (platforms == null || platforms.isEmpty()) return true;
int inclusiveCount = 0;
for (String pl : platforms) {
if (pl.startsWith("!")) continue;
inclusiveCount++;
if (pl.equalsIgnoreCase(platform)) return true;
}
if (inclusiveCount == platforms.size()) {
return false;
}
for (String pl : platforms) {
if (!pl.startsWith("!")) continue;
if (pl.regionMatches(true, 1, platform, 0, platform.length())) return false;
}
return true;
}
public boolean versionWithinLimit(int version) {
return version >= versionLowerLimit && version <= versionUpperLimit;
}
public File getFile() {
return file;
}
public String getContent() {
return content;
}
public LombokImmutableList getMessages() {
return messages;
}
public boolean isIgnore() {
return ignore;
}
public boolean forceUnchanged() {
return unchanged;
}
public boolean isSkipCompareContent() {
return skipCompareContent;
}
public boolean isSkipIdempotent() {
return skipIdempotent;
}
public String getSpecifiedEncoding() {
return specifiedEncoding;
}
public ConfigurationResolver getConfiguration() {
return configuration;
}
public Map getFormatPreferences() {
return formatPreferences;
}
private static final Pattern VERSION_STYLE_1 = Pattern.compile("^(\\d+)(?:\\s+.*)?$");
private static final Pattern VERSION_STYLE_2 = Pattern.compile("^\\:(\\d+)(?:\\s+.*)?$");
private static final Pattern VERSION_STYLE_3 = Pattern.compile("^(\\d+):(?:\\s+.*)?$");
private static final Pattern VERSION_STYLE_4 = Pattern.compile("^(\\d+):(\\d+)(?:\\s+.*)?$");
private int[] parseVersionLimit(String spec) {
/* Single version: '5' */ {
Matcher m = VERSION_STYLE_1.matcher(spec);
if (m.matches()) {
int v = Integer.parseInt(m.group(1));
return new int[] {v, v};
}
}
/* Upper bound: ':5' (inclusive) */ {
Matcher m = VERSION_STYLE_2.matcher(spec);
if (m.matches()) return new int[] {0, Integer.parseInt(m.group(1))};
}
/* Lower bound '5:' (inclusive) */ {
Matcher m = VERSION_STYLE_3.matcher(spec);
if (m.matches()) return new int[] {Integer.parseInt(m.group(1)), Integer.MAX_VALUE};
}
/* Range '7:8' (inclusive) */ {
Matcher m = VERSION_STYLE_4.matcher(spec);
if (m.matches()) return new int[] {Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2))};
}
return null;
}
private static final Pattern IGNORE_PATTERN = Pattern.compile("^\\s*ignore\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE);
private static final Pattern UNCHANGED_PATTERN = Pattern.compile("^\\s*unchanged\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE);
private static final Pattern SKIP_COMPARE_CONTENT_PATTERN = Pattern.compile("^\\s*skip[- ]?compare[- ]?contents?\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE);
private static final Pattern SKIP_IDEMPOTENT_PATTERN = Pattern.compile("^\\s*skip[- ]?idempotent\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE);
private LombokTestSource(File file, String content, List messages, List directives) {
this.file = file;
this.content = content;
this.messages = messages == null ? LombokImmutableList.of() : LombokImmutableList.copyOf(messages);
StringBuilder conf = new StringBuilder();
int versionLower = 0;
int versionUpper = Integer.MAX_VALUE;
boolean ignore = false;
boolean skipCompareContent = false;
boolean skipIdempotent = false;
boolean unchanged = false;
String encoding = null;
Map formats = new HashMap();
String[] platformLimit = null;
for (String directive : directives) {
directive = directive.trim();
String lc = directive.toLowerCase();
if (IGNORE_PATTERN.matcher(directive).matches()) {
ignore = true;
continue;
}
if (UNCHANGED_PATTERN.matcher(directive).matches()) {
unchanged = true;
continue;
}
if (SKIP_COMPARE_CONTENT_PATTERN.matcher(directive).matches()) {
skipCompareContent = true;
continue;
}
if (SKIP_IDEMPOTENT_PATTERN.matcher(directive).matches()) {
skipIdempotent = true;
continue;
}
if (lc.startsWith("platform ")) {
String platformDesc = lc.substring("platform ".length());
int idx = platformDesc.indexOf(':');
if (idx != -1) platformDesc = platformDesc.substring(0, idx).trim();
platformLimit = platformDesc.split("\\s*,\\s*");
continue;
}
if (lc.startsWith("version ")) {
int[] limits = parseVersionLimit(lc.substring(7).trim());
if (limits == null) {
Assert.fail("Directive line \"" + directive + "\" in '" + file.getAbsolutePath() + "' invalid: version must be followed by a single integer.");
throw new RuntimeException();
}
versionLower = limits[0];
versionUpper = limits[1];
continue;
}
if (lc.startsWith("conf:")) {
String confLine = directive.substring(5).trim();
conf.append(confLine).append("\n");
continue;
}
if (lc.startsWith("encoding:")) {
encoding = directive.substring(9).trim();
continue;
}
if (lc.startsWith("format:")) {
String formatLine = directive.substring(7).trim();
int idx = formatLine.indexOf('=');
if (idx == -1) throw new IllegalArgumentException("To add a format directive, use: \"//FORMAT: javaLangAsFQN = skip\"");
String key = formatLine.substring(0, idx).trim();
String value = formatLine.substring(idx + 1).trim();
formats.put(key.toLowerCase(), value);
continue;
}
if (lc.startsWith("issue ")) continue;
Assert.fail("Directive line \"" + directive + "\" in '" + file.getAbsolutePath() + "' invalid: unrecognized directive.");
throw new RuntimeException();
}
this.specifiedEncoding = encoding;
this.versionLowerLimit = versionLower;
this.versionUpperLimit = versionUpper;
this.ignore = ignore;
this.skipCompareContent = skipCompareContent;
this.skipIdempotent = skipIdempotent;
this.unchanged = unchanged;
this.platforms = platformLimit == null ? null : Arrays.asList(platformLimit);
ConfigurationProblemReporter reporter = new ConfigurationProblemReporter() {
@Override public void report(String sourceDescription, String problem, int lineNumber, CharSequence line) {
Assert.fail("Problem on directive line: " + problem + " at conf line #" + lineNumber + " (" + line + ")");
}
};
final ConfigurationFile configurationFile = ConfigurationFile.fromCharSequence(file.getAbsoluteFile().getPath(), conf, ConfigurationFile.getLastModifiedOrMissing(file));
final ConfigurationSource source = SingleConfigurationSource.parse(configurationFile, new ConfigurationParser(reporter));
ConfigurationFileToSource sourceFinder = new ConfigurationFileToSource() {
@Override public ConfigurationSource parsed(ConfigurationFile fileLocation) {
return fileLocation.equals(configurationFile) ? source : null;
}
};
this.configuration = new BubblingConfigurationResolver(configurationFile, sourceFinder);
this.formatPreferences = Collections.unmodifiableMap(formats);
}
public static LombokTestSource readDirectives(File file) throws IOException {
List directives = new ArrayList();
{
InputStream rawIn = new FileInputStream(file);
try {
BufferedReader in = new BufferedReader(new InputStreamReader(rawIn, "UTF-8"));
try {
for (String i = in.readLine(); i != null; i = in.readLine()) {
if (i.isEmpty()) continue;
if (i.startsWith("//")) {
directives.add(i.substring(2));
} else {
break;
}
}
}
finally {
in.close();
}
}
finally {
rawIn.close();
}
}
return new LombokTestSource(file, "", null, directives);
}
public static LombokTestSource read(File sourceFolder, File messagesFolder, String fileName) throws IOException {
return read0(sourceFolder, messagesFolder, fileName, "UTF-8");
}
private static LombokTestSource read0(File sourceFolder, File messagesFolder, String fileName, String encoding) throws IOException {
StringBuilder content = null;
List directives = new ArrayList();
File sourceFile = new File(sourceFolder, fileName);
if (sourceFile.exists()) {
InputStream rawIn = new FileInputStream(sourceFile);
try {
BufferedReader in = new BufferedReader(new InputStreamReader(rawIn, encoding));
try {
for (String i = in.readLine(); i != null; i = in.readLine()) {
if (content != null) {
content.append(i).append("\n");
continue;
}
if (i.isEmpty()) continue;
if (i.startsWith("//")) {
directives.add(i.substring(2));
} else {
content = new StringBuilder();
content.append(i).append("\n");
}
}
}
finally {
in.close();
}
}
finally {
rawIn.close();
}
}
if (content == null) content = new StringBuilder();
List messages = null;
if (messagesFolder != null) {
File messagesFile = new File(messagesFolder, fileName + ".messages");
try {
InputStream rawIn = new FileInputStream(messagesFile);
try {
messages = CompilerMessageMatcher.readAll(rawIn);
}
finally {
rawIn.close();
}
} catch (FileNotFoundException e) {
messages = null;
}
}
LombokTestSource source = new LombokTestSource(sourceFile, content.toString(), messages, directives);
String specifiedEncoding = source.getSpecifiedEncoding();
// The source file has an 'encoding' header to test encoding issues. Of course, reading the encoding header
// requires knowing the encoding of the file first. In practice we get away with it, because UTF-8 and US-ASCII are compatible enough.
// The fix is therefore to read in as UTF-8 initially, and if the file requests that it should be read as another encoding, toss it all
// and reread that way.
if (specifiedEncoding == null || specifiedEncoding.equalsIgnoreCase(encoding)) return source;
return read0(sourceFolder, messagesFolder, fileName, specifiedEncoding);
}
public int minVersion() {
return Math.max(6, versionLowerLimit);
}
public int maxVersion() {
return versionUpperLimit;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy