org.sonar.api.batch.fs.internal.TestInputFileBuilder Maven / Gradle / Ivy
Show all versions of sonar-plugin-api-impl Show documentation
/*
* SonarQube
* Copyright (C) 2009-2024 SonarSource SA
* mailto:info 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.fs.internal;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.utils.PathUtils;
/**
* Intended to be used in unit tests that need to create {@link InputFile}s.
* An InputFile is unambiguously identified by a module key and a relative path, so these parameters are mandatory.
*
* A module base directory is only needed to construct absolute paths.
*
* Examples of usage of the constructors:
*
*
* InputFile file1 = TestInputFileBuilder.create("module1", "myfile.java").build();
* InputFile file2 = TestInputFileBuilder.create("", fs.baseDir(), myfile).build();
*
*
* file1 will have the "module1" as both module key and module base directory.
* file2 has an empty string as module key, and a relative path which is the path from the filesystem base directory to myfile.
*
* @since 6.3
*/
public class TestInputFileBuilder {
private static int batchId = 1;
private final int id;
private final String relativePath;
private String oldRelativePath;
private final String projectKey;
@CheckForNull
private Path projectBaseDir;
private Path moduleBaseDir;
private String language;
private InputFile.Type type = InputFile.Type.MAIN;
private InputFile.Status status;
private int lines = -1;
private Charset charset;
private String hash;
private int nonBlankLines;
private int[] originalLineStartOffsets = new int[0];
private int[] originalLineEndOffsets = new int[0];
private int lastValidOffset = -1;
private boolean publish = true;
private String contents;
/**
* Create a InputFile identified by the given project key and relative path.
*/
public TestInputFileBuilder(String projectKey, String relativePath) {
this(projectKey, relativePath, batchId++);
}
/**
* Create a InputFile with a given module key and module base directory.
* The relative path is generated comparing the file path to the module base directory.
* filePath must point to a file that is within the module base directory.
*/
public TestInputFileBuilder(String projectKey, File moduleBaseDir, File filePath) {
String relativePathStr = moduleBaseDir.toPath().relativize(filePath.toPath()).toString();
this.projectKey = projectKey;
setModuleBaseDir(moduleBaseDir.toPath());
this.relativePath = PathUtils.sanitize(relativePathStr);
this.id = batchId++;
}
public TestInputFileBuilder(String projectKey, String relativePath, int id) {
this.projectKey = projectKey;
setModuleBaseDir(Paths.get(projectKey));
this.relativePath = PathUtils.sanitize(relativePath);
this.id = id;
}
public TestInputFileBuilder(String projectKey, String relativePath, String oldRelativePath, int id) {
this.projectKey = projectKey;
setModuleBaseDir(Paths.get(projectKey));
this.relativePath = PathUtils.sanitize(relativePath);
this.oldRelativePath = oldRelativePath;
this.id = id;
}
public static TestInputFileBuilder create(String moduleKey, File moduleBaseDir, File filePath) {
return new TestInputFileBuilder(moduleKey, moduleBaseDir, filePath);
}
public static TestInputFileBuilder create(String moduleKey, String relativePath) {
return new TestInputFileBuilder(moduleKey, relativePath);
}
public static int nextBatchId() {
return batchId++;
}
public TestInputFileBuilder setProjectBaseDir(Path projectBaseDir) {
this.projectBaseDir = normalize(projectBaseDir);
return this;
}
public TestInputFileBuilder setModuleBaseDir(Path moduleBaseDir) {
this.moduleBaseDir = normalize(moduleBaseDir);
return this;
}
private static Path normalize(Path path) {
try {
return path.normalize().toRealPath(LinkOption.NOFOLLOW_LINKS);
} catch (IOException e) {
return path.normalize();
}
}
public TestInputFileBuilder setLanguage(@Nullable String language) {
this.language = language;
return this;
}
public TestInputFileBuilder setType(InputFile.Type type) {
this.type = type;
return this;
}
public TestInputFileBuilder setStatus(InputFile.Status status) {
this.status = status;
return this;
}
public TestInputFileBuilder setLines(int lines) {
this.lines = lines;
return this;
}
public TestInputFileBuilder setCharset(Charset charset) {
this.charset = charset;
return this;
}
public TestInputFileBuilder setHash(String hash) {
this.hash = hash;
return this;
}
/**
* Set contents of the file and calculates metadata from it.
* The contents will be returned by {@link InputFile#contents()} and {@link InputFile#inputStream()} and can be
* inconsistent with the actual physical file pointed by {@link InputFile#path()}, {@link InputFile#absolutePath()}, etc.
*/
public TestInputFileBuilder setContents(String content) {
this.contents = content;
initMetadata(content);
return this;
}
public TestInputFileBuilder setNonBlankLines(int nonBlankLines) {
this.nonBlankLines = nonBlankLines;
return this;
}
public TestInputFileBuilder setLastValidOffset(int lastValidOffset) {
this.lastValidOffset = lastValidOffset;
return this;
}
public TestInputFileBuilder setOriginalLineStartOffsets(int[] originalLineStartOffsets) {
this.originalLineStartOffsets = originalLineStartOffsets;
return this;
}
public TestInputFileBuilder setOriginalLineEndOffsets(int[] originalLineEndOffsets) {
this.originalLineEndOffsets = originalLineEndOffsets;
return this;
}
public TestInputFileBuilder setPublish(boolean publish) {
this.publish = publish;
return this;
}
public TestInputFileBuilder setMetadata(Metadata metadata) {
this.setLines(metadata.lines());
this.setLastValidOffset(metadata.lastValidOffset());
this.setNonBlankLines(metadata.nonBlankLines());
this.setHash(metadata.hash());
this.setOriginalLineStartOffsets(metadata.originalLineStartOffsets());
this.setOriginalLineEndOffsets(metadata.originalLineEndOffsets());
return this;
}
public TestInputFileBuilder initMetadata(String content) {
AnalysisWarnings analysisWarnings = warning -> {};
return setMetadata(new FileMetadata(analysisWarnings).readMetadata(new StringReader(content)));
}
public DefaultInputFile build() {
Path absolutePath = moduleBaseDir.resolve(relativePath);
if (projectBaseDir == null) {
projectBaseDir = moduleBaseDir;
}
String projectRelativePath = projectBaseDir.relativize(absolutePath).toString();
DefaultIndexedFile indexedFile = new DefaultIndexedFile(absolutePath, projectKey, projectRelativePath, relativePath, type, language, id, new SensorStrategy(), oldRelativePath);
DefaultInputFile inputFile = new DefaultInputFile(indexedFile,
f -> f.setMetadata(new Metadata(lines, nonBlankLines, hash, originalLineStartOffsets, originalLineEndOffsets, lastValidOffset)),
contents, f -> {});
inputFile.setStatus(status);
inputFile.setCharset(charset);
inputFile.setPublished(publish);
return inputFile;
}
public static DefaultInputModule newDefaultInputModule(String moduleKey, File baseDir) {
ProjectDefinition definition = ProjectDefinition.create()
.setKey(moduleKey)
.setBaseDir(baseDir)
.setWorkDir(new File(baseDir, ".sonar"));
return newDefaultInputModule(definition);
}
public static DefaultInputModule newDefaultInputModule(ProjectDefinition projectDefinition) {
return new DefaultInputModule(projectDefinition, TestInputFileBuilder.nextBatchId());
}
public static DefaultInputModule newDefaultInputModule(AbstractProjectOrModule parent, String key) throws IOException {
Path basedir = parent.getBaseDir().resolve(key);
Files.createDirectory(basedir);
return newDefaultInputModule(key, basedir.toFile());
}
public static DefaultInputProject newDefaultInputProject(String projectKey, File baseDir) {
ProjectDefinition definition = ProjectDefinition.create()
.setKey(projectKey)
.setBaseDir(baseDir)
.setWorkDir(new File(baseDir, ".sonar"));
return newDefaultInputProject(definition);
}
public static DefaultInputProject newDefaultInputProject(ProjectDefinition projectDefinition) {
return new DefaultInputProject(projectDefinition, TestInputFileBuilder.nextBatchId());
}
public static DefaultInputProject newDefaultInputProject(String key, Path baseDir) throws IOException {
Files.createDirectory(baseDir);
return newDefaultInputProject(key, baseDir.toFile());
}
public static DefaultInputDir newDefaultInputDir(AbstractProjectOrModule module, String relativePath) throws IOException {
Path basedir = module.getBaseDir().resolve(relativePath);
Files.createDirectory(basedir);
return new DefaultInputDir(module.key(), relativePath)
.setModuleBaseDir(module.getBaseDir());
}
public static DefaultInputFile newDefaultInputFile(Path projectBaseDir, AbstractProjectOrModule module, String relativePath) {
return new TestInputFileBuilder(module.key(), relativePath)
.setStatus(InputFile.Status.SAME)
.setProjectBaseDir(projectBaseDir)
.setModuleBaseDir(module.getBaseDir())
.build();
}
}