1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
|
/*
* SonarQube
* Copyright (C) 2009-2025 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 <b>module key</b> and a <b>relative path</b>, so these parameters are mandatory.
* <p>
* A module base directory is only needed to construct absolute paths.
* <p>
* Examples of usage of the constructors:
*
* <pre>
* InputFile file1 = TestInputFileBuilder.create("module1", "myfile.java").build();
* InputFile file2 = TestInputFileBuilder.create("", fs.baseDir(), myfile).build();
* </pre>
* <p>
* 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;
private boolean hidden = false;
/**
* 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 setHidden(boolean isHiddenFile) {
this.hidden = isHiddenFile;
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,
hidden);
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();
}
}
|