Tests for readonlyness

This commit is contained in:
Clément Fournier committed 2022-04-24 17:11:33 +02:00
1 parent 6cf5e09088
commit dae31bf308
4 files changed
+139 -46

No files matched your search

@@ -48,6 +48,7 @@ import net.sourceforge.pmd.util.log.MessageReporter;
*/
@SuppressWarnings("PMD.CloseResource")
public final class FileCollector implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(FileCollector.class);
private final List<TextFile> allFilesToProcess = new ArrayList<>();
@@ -167,8 +168,11 @@ public final class FileCollector implements AutoCloseable {
reporter.error("Not a regular file {}", file);
return false;
}
NioTextFile nioTextFile = new NioTextFile(file, charset, discoverer.getDefaultLanguageVersion(language), getDisplayName(file));
addFileImpl(nioTextFile);
LanguageVersion lv = discoverer.getDefaultLanguageVersion(language);
Objects.requireNonNull(lv);
addFileImpl(TextFile.builderForPath(file, charset, lv)
.withDisplayName(getDisplayName(file))
.build());
return true;
}
@@ -371,7 +375,7 @@ public final class FileCollector implements AutoCloseable {
*/
public void exclude(FileCollector excludeCollector) {
Set<TextFile> toExclude = new HashSet<>(excludeCollector.allFilesToProcess);
for (Iterator<TextFile> iterator = allFilesToProcess.iterator(); iterator.hasNext();) {
for (Iterator<TextFile> iterator = allFilesToProcess.iterator(); iterator.hasNext(); ) {
TextFile file = iterator.next();
if (toExclude.contains(file)) {
LOG.trace("Excluding file {}", file.getPathId());
@@ -385,7 +389,7 @@ public final class FileCollector implements AutoCloseable {
* collection.
*/
public void filterLanguages(Set<Language> languages) {
for (Iterator<TextFile> iterator = allFilesToProcess.iterator(); iterator.hasNext();) {
for (Iterator<TextFile> iterator = allFilesToProcess.iterator(); iterator.hasNext(); ) {
TextFile file = iterator.next();
Language lang = file.getLanguageVersion().getLanguage();
if (!languages.contains(lang)) {
@@ -27,13 +27,19 @@ class NioTextFile extends BaseCloseable implements TextFile {
private final Charset charset;
private final LanguageVersion languageVersion;
private final @Nullable String displayName;
private boolean readOnly;
NioTextFile(Path path, Charset charset, LanguageVersion languageVersion, @Nullable String displayName) {
NioTextFile(Path path,
Charset charset,
LanguageVersion languageVersion,
@Nullable String displayName,
boolean readOnly) {
AssertionUtil.requireParamNotNull("path", path);
AssertionUtil.requireParamNotNull("charset", charset);
AssertionUtil.requireParamNotNull("language version", languageVersion);
this.displayName = displayName;
this.readOnly = readOnly;
this.path = path;
this.charset = charset;
this.languageVersion = languageVersion;
@@ -56,12 +62,15 @@ class NioTextFile extends BaseCloseable implements TextFile {
@Override
public boolean isReadOnly() {
return !Files.isWritable(path);
return readOnly || !Files.isWritable(path);
}
@Override
public void writeContents(TextFileContent content) throws IOException {
ensureOpen();
if (isReadOnly()) {
throw new ReadOnlyFileException();
}
try (BufferedWriter bw = Files.newBufferedWriter(path, charset)) {
if (content.getLineTerminator().equals(TextFileContent.NORMALIZED_LINE_TERM)) {
content.getNormalizedText().writeFully(bw);
@@ -26,10 +26,41 @@ public abstract class TextFileBuilder {
this.languageVersion = AssertionUtil.requireParamNotNull("language version", languageVersion);
}
/**
* Specify that the built file is read only. Some text files are
* always read-only.
*
* @return This builder
*/
public TextFileBuilder asReadOnly() {
// default is appropriate if the file type is always read-only
return this;
}
/**
* Sets a custom display name for the new file. If null, or this is
* never called, the display name defaults to the path ID.
*
* @param displayName A display name
*
* @return This builder
*/
public TextFileBuilder withDisplayName(@Nullable String displayName) {
this.displayName = displayName;
return this;
}
/**
* Creates and returns the new text file.
*/
public abstract TextFile build();
static class ForNio extends TextFileBuilder {
private final Path path;
private final Charset charset;
private boolean readOnly = false;
ForNio(LanguageVersion languageVersion, Path path, Charset charset) {
super(languageVersion);
@@ -37,9 +68,15 @@ public abstract class TextFileBuilder {
this.charset = AssertionUtil.requireParamNotNull("charset", charset);
}
@Override
public TextFileBuilder asReadOnly() {
readOnly = true;
return this;
}
@Override
public TextFile build() {
return new NioTextFile(path, charset, languageVersion, displayName);
return new NioTextFile(path, charset, languageVersion, displayName, readOnly);
}
}
@@ -77,22 +114,4 @@ public abstract class TextFileBuilder {
}
}
/**
* Sets a custom display name for the new file. If null, or this is
* never called, the display name defaults to the path ID.
*
* @param displayName A display name
*
* @return This builder
*/
public TextFileBuilder withDisplayName(@Nullable String displayName) {
this.displayName = displayName;
return this;
}
/**
* Creates and returns the new text file.
*/
public abstract TextFile build();
}
@@ -4,6 +4,11 @@
package net.sourceforge.pmd.lang.document;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.Charset;
@@ -13,7 +18,6 @@ import java.nio.file.Path;
import org.apache.commons.io.IOUtils;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
@@ -32,10 +36,47 @@ public class TextFilesTest {
public void testNioFile() throws IOException {
Path file = makeTmpFile(StandardCharsets.UTF_8, "some content");
try (TextFile tf = TextFile.forPath(file, StandardCharsets.UTF_8, dummyVersion)) {
Assert.assertEquals(file.toAbsolutePath().toString(), tf.getPathId());
Assert.assertEquals(file.toString(), tf.getDisplayName());
Assert.assertEquals(dummyVersion, tf.getLanguageVersion());
Assert.assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText());
assertEquals(file.toAbsolutePath().toString(), tf.getPathId());
assertEquals(file.toString(), tf.getDisplayName());
assertEquals(dummyVersion, tf.getLanguageVersion());
assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText());
}
}
@Test
public void testNioFileWrite() throws IOException {
Path file = makeTmpFile(StandardCharsets.UTF_8, "some content");
try (TextFile tf = TextFile.forPath(file, StandardCharsets.UTF_8, dummyVersion)) {
assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText());
assertFalse("readonly", tf.isReadOnly());
tf.writeContents(
TextFileContent.fromCharSeq("new content")
);
assertEquals(Chars.wrap("new content"), tf.readContents().getNormalizedText());
}
}
@Test
public void testNioFileExplicitReadOnly() throws IOException {
Path file = makeTmpFile(StandardCharsets.UTF_8, "some content");
try (TextFile tf = TextFile.builderForPath(file, StandardCharsets.UTF_8, dummyVersion)
.asReadOnly().build()) {
assertTrue("readonly", tf.isReadOnly());
assertThrows(ReadOnlyFileException.class, () -> tf.writeContents(
TextFileContent.fromCharSeq("new content")
));
}
}
@Test
public void testNioFileCanBeReadMultipleTimes() throws IOException {
Path file = makeTmpFile(StandardCharsets.UTF_8, "some content");
try (TextFile tf = TextFile.forPath(file, StandardCharsets.UTF_8, dummyVersion)) {
assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText());
assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText());
}
}
@@ -45,10 +86,10 @@ public class TextFilesTest {
try (TextFile tf = TextFile.builderForPath(file, StandardCharsets.UTF_8, dummyVersion)
.withDisplayName("aname")
.build()) {
Assert.assertEquals(file.toAbsolutePath().toString(), tf.getPathId());
Assert.assertEquals("aname", tf.getDisplayName());
Assert.assertEquals(dummyVersion, tf.getLanguageVersion());
Assert.assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText());
assertEquals(file.toAbsolutePath().toString(), tf.getPathId());
assertEquals("aname", tf.getDisplayName());
assertEquals(dummyVersion, tf.getLanguageVersion());
assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText());
}
}
@@ -56,7 +97,7 @@ public class TextFilesTest {
public void testNioFileEscape() throws IOException {
Path file = makeTmpFile(StandardCharsets.UTF_8, "some\r\ncontent");
try (TextFile tf = TextFile.forPath(file, StandardCharsets.UTF_8, dummyVersion)) {
Assert.assertEquals(Chars.wrap("some\ncontent"), tf.readContents().getNormalizedText());
assertEquals(Chars.wrap("some\ncontent"), tf.readContents().getNormalizedText());
}
}
@@ -64,22 +105,42 @@ public class TextFilesTest {
public void testReaderFileEscape() throws IOException {
Path file = makeTmpFile(StandardCharsets.UTF_8, "some\r\ncontent");
try (TextFile tf = TextFile.forReader(Files.newBufferedReader(file, StandardCharsets.UTF_8), "filename", dummyVersion)) {
Assert.assertEquals("filename", tf.getPathId());
Assert.assertEquals("filename", tf.getDisplayName());
Assert.assertEquals(dummyVersion, tf.getLanguageVersion());
Assert.assertEquals(Chars.wrap("some\ncontent"), tf.readContents().getNormalizedText());
Assert.assertThrows(ReadOnlyFileException.class, () -> tf.writeContents(
assertEquals("filename", tf.getPathId());
assertEquals("filename", tf.getDisplayName());
assertEquals(dummyVersion, tf.getLanguageVersion());
assertEquals(Chars.wrap("some\ncontent"), tf.readContents().getNormalizedText());
assertThrows(ReadOnlyFileException.class, () -> tf.writeContents(
TextFileContent.fromCharSeq("new content")
));
}
}@Test
}
@Test
public void testStringFileEscape() throws IOException {
try (TextFile tf = TextFile.forCharSeq("cont\r\nents", "filename", dummyVersion)) {
Assert.assertEquals("filename", tf.getPathId());
Assert.assertEquals("filename", tf.getDisplayName());
Assert.assertEquals(dummyVersion, tf.getLanguageVersion());
Assert.assertEquals(Chars.wrap("cont\r\nent"), tf.readContents().getNormalizedText());
Assert.assertThrows(ReadOnlyFileException.class, () -> tf.writeContents(
assertEquals("filename", tf.getPathId());
assertEquals("filename", tf.getDisplayName());
assertEquals(dummyVersion, tf.getLanguageVersion());
assertEquals(Chars.wrap("cont\nents"), tf.readContents().getNormalizedText());
assertThrows(ReadOnlyFileException.class, () -> tf.writeContents(
TextFileContent.fromCharSeq("new content")
));
}
}
@Test
public void testStringFileCanBeReadMultipleTimes() throws IOException {
try (TextFile tf = TextFile.forCharSeq("contents", "filename", dummyVersion)) {
assertEquals(Chars.wrap("contents"), tf.readContents().getNormalizedText());
assertEquals(Chars.wrap("contents"), tf.readContents().getNormalizedText());
assertEquals(Chars.wrap("contents"), tf.readContents().getNormalizedText());
}
}
@Test
public void testStringFileIsReadonly() throws IOException {
try (TextFile tf = TextFile.forCharSeq("contents", "filename", dummyVersion)) {
assertThrows(ReadOnlyFileException.class, () -> tf.writeContents(
TextFileContent.fromCharSeq("new content")
));
}