From 2d6256e4191697fdc4d033e93d53a59308a516fe Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Sun, 18 Sep 2016 19:47:16 +0200 Subject: [PATCH] Refactor project validation, add test --- .../jsite/application/ProjectInserter.java | 229 --------------------- .../jsite/application/validation/CheckReport.java | 37 ++++ .../jsite/application/validation/Issue.java | 64 ++++++ .../application/validation/ProjectValidator.java | 107 ++++++++++ src/main/java/de/todesbaum/jsite/main/Main.java | 9 +- .../validation/ProjectValidatorTest.java | 172 ++++++++++++++++ 6 files changed, 385 insertions(+), 233 deletions(-) create mode 100644 src/main/java/de/todesbaum/jsite/application/validation/CheckReport.java create mode 100644 src/main/java/de/todesbaum/jsite/application/validation/Issue.java create mode 100644 src/main/java/de/todesbaum/jsite/application/validation/ProjectValidator.java create mode 100644 src/test/java/de/todesbaum/jsite/application/validation/ProjectValidatorTest.java diff --git a/src/main/java/de/todesbaum/jsite/application/ProjectInserter.java b/src/main/java/de/todesbaum/jsite/application/ProjectInserter.java index c7dad3b..e43c8b1 100644 --- a/src/main/java/de/todesbaum/jsite/application/ProjectInserter.java +++ b/src/main/java/de/todesbaum/jsite/application/ProjectInserter.java @@ -23,17 +23,9 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; import java.util.List; -import java.util.Map; -import java.util.Map.Entry; import java.util.Optional; -import java.util.Set; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; @@ -227,92 +219,6 @@ public class ProjectInserter implements FileScannerListener, Runnable { } /** - * Validates the given project. The project will be checked for any invalid - * conditions, such as invalid insert or request keys, missing path names, - * missing default file, and so on. - * - * @param project - * The project to check - * @return The encountered warnings and errors - */ - public static CheckReport validateProject(Project project) { - CheckReport checkReport = new CheckReport(); - if ((project.getLocalPath() == null) || (project.getLocalPath().trim().length() == 0)) { - checkReport.addIssue("error.no-local-path", true); - } - if ((project.getPath() == null) || (project.getPath().trim().length() == 0)) { - checkReport.addIssue("error.no-path", true); - } - if ((project.getIndexFile() == null) || (project.getIndexFile().length() == 0)) { - checkReport.addIssue("warning.empty-index", false); - } else { - File indexFile = new File(project.getLocalPath(), project.getIndexFile()); - if (!indexFile.exists()) { - checkReport.addIssue("error.index-missing", true); - } - } - String indexFile = project.getIndexFile(); - boolean hasIndexFile = (indexFile != null) && (indexFile.length() > 0); - List allowedIndexContentTypes = Arrays.asList("text/html", "application/xhtml+xml"); - if (hasIndexFile && !allowedIndexContentTypes.contains(project.getFileOption(indexFile).getMimeType())) { - checkReport.addIssue("warning.index-not-html", false); - } - Map fileOptions = project.getFileOptions(); - Set> fileOptionEntries = fileOptions.entrySet(); - boolean insert = fileOptionEntries.isEmpty(); - for (Entry fileOptionEntry : fileOptionEntries) { - String fileName = fileOptionEntry.getKey(); - FileOption fileOption = fileOptionEntry.getValue(); - insert |= fileOption.isInsert() || fileOption.isInsertRedirect(); - if (fileName.equals(project.getIndexFile()) && !fileOption.isInsert() && !fileOption.isInsertRedirect()) { - checkReport.addIssue("error.index-not-inserted", true); - } - if (!fileOption.isInsert() && fileOption.isInsertRedirect() && ((fileOption.getCustomKey().length() == 0) || "CHK@".equals(fileOption.getCustomKey()))) { - checkReport.addIssue("error.no-custom-key", true, fileName); - } - } - if (!insert) { - checkReport.addIssue("error.no-files-to-insert", true); - } - Set fileNames = new HashSet(); - for (Entry fileOptionEntry : fileOptionEntries) { - FileOption fileOption = fileOptionEntry.getValue(); - if (!fileOption.isInsert() && !fileOption.isInsertRedirect()) { - logger.log(Level.FINEST, "Ignoring {0}.", fileOptionEntry.getKey()); - continue; - } - String fileName = fileOption.getChangedName().orElse(fileOptionEntry.getKey()); - logger.log(Level.FINEST, "Adding “{0}” for {1}.", new Object[] { fileName, fileOptionEntry.getKey() }); - if (!fileNames.add(fileName)) { - checkReport.addIssue("error.duplicate-file", true, fileName); - } - } - long totalSize = 0; - final CountDownLatch completionLatch = new CountDownLatch(1); - FileScanner fileScanner = new FileScanner(project, (error, files) -> completionLatch.countDown()); - fileScanner.startInBackground(); - while (completionLatch.getCount() > 0) { - try { - completionLatch.await(); - } catch (InterruptedException ie1) { - /* TODO: logging */ - } - } - for (ScannedFile scannedFile : fileScanner.getFiles()) { - String fileName = scannedFile.getFilename(); - FileOption fileOption = project.getFileOption(fileName); - if ((fileOption != null) && !fileOption.isInsert()) { - continue; - } - totalSize += new File(project.getLocalPath(), fileName).length(); - } - if (totalSize > 2 * 1024 * 1024) { - checkReport.addIssue("warning.site-larger-than-2-mib", false); - } - return checkReport; - } - - /** * {@inheritDoc} */ @Override @@ -435,139 +341,4 @@ public class ProjectInserter implements FileScannerListener, Runnable { } } - /** - * Container class that collects all warnings and errors that occured during - * {@link ProjectInserter#validateProject(Project) project validation}. - * - * @author David ‘Bombe’ Roden - */ - public static class CheckReport implements Iterable { - - /** The issures that occured. */ - private final List issues = new ArrayList(); - - /** - * Adds an issue. - * - * @param issue - * The issue to add - */ - public void addIssue(Issue issue) { - issues.add(issue); - } - - /** - * Creates an {@link Issue} from the given error key and fatality flag - * and {@link #addIssue(Issue) adds} it. - * - * @param errorKey - * The error key - * @param fatal - * {@code true} if the error is fatal, {@code false} if only - * a warning should be generated - * @param parameters - * Any additional parameters - */ - public void addIssue(String errorKey, boolean fatal, String... parameters) { - addIssue(new Issue(errorKey, fatal, parameters)); - } - - /** - * {@inheritDoc} - */ - @Override - public Iterator iterator() { - return issues.iterator(); - } - - /** - * Returns whether this check report does not contain any errors. - * - * @return {@code true} if this check report does not contain any - * errors, {@code false} if this check report does contain - * errors - */ - public boolean isEmpty() { - return issues.isEmpty(); - } - - /** - * Returns the number of issues in this check report. - * - * @return The number of issues - */ - public int size() { - return issues.size(); - } - - } - - /** - * Container class for a single issue. An issue contains an error key - * that describes the error, and a fatality flag that determines whether - * the insert has to be aborted (if the flag is {@code true}) or if it - * can still be performed and only a warning should be generated (if the - * flag is {@code false}). - * - * @author David ‘Bombe’ - * Roden - */ - public static class Issue { - - /** The error key. */ - private final String errorKey; - - /** The fatality flag. */ - private final boolean fatal; - - /** Additional parameters. */ - private String[] parameters; - - /** - * Creates a new issue. - * - * @param errorKey - * The error key - * @param fatal - * The fatality flag - * @param parameters - * Any additional parameters - */ - protected Issue(String errorKey, boolean fatal, String... parameters) { - this.errorKey = errorKey; - this.fatal = fatal; - this.parameters = parameters; - } - - /** - * Returns the key of the encountered error. - * - * @return The error key - */ - public String getErrorKey() { - return errorKey; - } - - /** - * Returns whether the issue is fatal and the insert has to be - * aborted. Otherwise only a warning should be shown. - * - * @return {@code true} if the insert needs to be aborted, {@code - * false} otherwise - */ - public boolean isFatal() { - return fatal; - } - - /** - * Returns any additional parameters. - * - * @return The additional parameters - */ - public String[] getParameters() { - return parameters; - } - - } - } diff --git a/src/main/java/de/todesbaum/jsite/application/validation/CheckReport.java b/src/main/java/de/todesbaum/jsite/application/validation/CheckReport.java new file mode 100644 index 0000000..7a10c36 --- /dev/null +++ b/src/main/java/de/todesbaum/jsite/application/validation/CheckReport.java @@ -0,0 +1,37 @@ +package de.todesbaum.jsite.application.validation; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import de.todesbaum.jsite.application.Project; + +/** + * Container class that collects all warnings and errors that occured during + * {@link ProjectValidator#validateProject(Project) project validation}. + * + * @author David ‘Bombe’ Roden + */ +public class CheckReport implements Iterable { + + private final List issues = new ArrayList<>(); + + void addIssue(String errorKey, boolean fatal, String... parameters) { + issues.add(new Issue(errorKey, fatal, parameters)); + } + + public Collection getIssues() { + return issues; + } + + @Override + public Iterator iterator() { + return issues.iterator(); + } + + public boolean isEmpty() { + return issues.isEmpty(); + } + +} diff --git a/src/main/java/de/todesbaum/jsite/application/validation/Issue.java b/src/main/java/de/todesbaum/jsite/application/validation/Issue.java new file mode 100644 index 0000000..451aabc --- /dev/null +++ b/src/main/java/de/todesbaum/jsite/application/validation/Issue.java @@ -0,0 +1,64 @@ +package de.todesbaum.jsite.application.validation; + +import static java.lang.String.format; + +import java.util.Arrays; +import java.util.Objects; + +/** + * Container class for a single issue. An issue contains an error key that describes the error, + * and a fatality flag that determines whether the insert has to be aborted (if the flag is + * {@code true}) or if it can still be performed and only a warning should be generated (if the + * flag is {@code false}). + * + * @author David ‘Bombe’ Roden + */ +public class Issue { + + private final String errorKey; + private final boolean fatal; + private final String[] parameters; + + Issue(String errorKey, boolean fatal, String... parameters) { + this.errorKey = errorKey; + this.fatal = fatal; + this.parameters = parameters; + } + + public String getErrorKey() { + return errorKey; + } + + public boolean isFatal() { + return fatal; + } + + public String[] getParameters() { + return parameters; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Issue issue = (Issue) o; + return fatal == issue.fatal && + Objects.equals(errorKey, issue.errorKey) && + Arrays.equals(parameters, issue.parameters); + } + + @Override + public int hashCode() { + return Objects.hash(errorKey, fatal, parameters); + } + + @Override + public String toString() { + return format("Issue{errorKey=\"%s\", fatal=%s, parameters=%s}", errorKey, fatal, Arrays.toString(parameters)); + } + +} diff --git a/src/main/java/de/todesbaum/jsite/application/validation/ProjectValidator.java b/src/main/java/de/todesbaum/jsite/application/validation/ProjectValidator.java new file mode 100644 index 0000000..2e03e6c --- /dev/null +++ b/src/main/java/de/todesbaum/jsite/application/validation/ProjectValidator.java @@ -0,0 +1,107 @@ +package de.todesbaum.jsite.application.validation; + +import java.io.File; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.logging.Level; +import java.util.logging.Logger; + +import de.todesbaum.jsite.application.FileOption; +import de.todesbaum.jsite.application.Project; +import de.todesbaum.jsite.gui.FileScanner; +import de.todesbaum.jsite.gui.ScannedFile; + +/** + * Validates a project and returns a number of {@link Issue}s in a {@link CheckReport}. + * + * @author David ‘Bombe’ Roden + */ +public class ProjectValidator { + + private static final Logger logger = Logger.getLogger(ProjectValidator.class.getName()); + + public static CheckReport validateProject(Project project) { + CheckReport checkReport = new CheckReport(); + if ((project.getLocalPath() == null) || (project.getLocalPath().trim().length() == 0)) { + checkReport.addIssue("error.no-local-path", true); + return checkReport; + } + if ((project.getPath() == null) || (project.getPath().trim().length() == 0)) { + checkReport.addIssue("error.no-path", true); + } + if ((project.getIndexFile() == null) || (project.getIndexFile().length() == 0)) { + checkReport.addIssue("warning.empty-index", false); + } else { + File indexFile = new File(project.getLocalPath(), project.getIndexFile()); + if (!indexFile.exists()) { + checkReport.addIssue("error.index-missing", true); + } + } + String indexFile = project.getIndexFile(); + boolean hasIndexFile = (indexFile != null) && (indexFile.length() > 0); + List allowedIndexContentTypes = Arrays.asList("text/html", "application/xhtml+xml"); + if (hasIndexFile && !allowedIndexContentTypes.contains(project.getFileOption(indexFile).getMimeType())) { + checkReport.addIssue("warning.index-not-html", false); + } + Map fileOptions = project.getFileOptions(); + Set> fileOptionEntries = fileOptions.entrySet(); + boolean insert = fileOptionEntries.isEmpty(); + for (Entry fileOptionEntry : fileOptionEntries) { + String fileName = fileOptionEntry.getKey(); + FileOption fileOption = fileOptionEntry.getValue(); + insert |= fileOption.isInsert() || fileOption.isInsertRedirect(); + if (fileName.equals(project.getIndexFile()) && !fileOption.isInsert() && !fileOption.isInsertRedirect()) { + checkReport.addIssue("error.index-not-inserted", true); + } + if (!fileOption.isInsert() && fileOption.isInsertRedirect() && ((fileOption.getCustomKey().length() == 0) || "CHK@".equals( + fileOption.getCustomKey()))) { + checkReport.addIssue("error.no-custom-key", true, fileName); + } + } + if (!insert) { + checkReport.addIssue("error.no-files-to-insert", true); + } + Set fileNames = new HashSet<>(); + for (Entry fileOptionEntry : fileOptionEntries) { + FileOption fileOption = fileOptionEntry.getValue(); + if (!fileOption.isInsert() && !fileOption.isInsertRedirect()) { + logger.log(Level.FINEST, "Ignoring {0}.", fileOptionEntry.getKey()); + continue; + } + String fileName = fileOption.getChangedName().orElse(fileOptionEntry.getKey()); + logger.log(Level.FINEST, "Adding “{0}” for {1}.", new Object[] { fileName, fileOptionEntry.getKey() }); + if (!fileNames.add(fileName)) { + checkReport.addIssue("error.duplicate-file", true, fileName); + } + } + long totalSize = 0; + final CountDownLatch completionLatch = new CountDownLatch(1); + FileScanner fileScanner = new FileScanner(project, (error, files) -> completionLatch.countDown()); + fileScanner.startInBackground(); + while (completionLatch.getCount() > 0) { + try { + completionLatch.await(); + } catch (InterruptedException ie1) { + /* TODO: logging */ + } + } + for (ScannedFile scannedFile : fileScanner.getFiles()) { + String fileName = scannedFile.getFilename(); + FileOption fileOption = project.getFileOption(fileName); + if ((fileOption != null) && !fileOption.isInsert()) { + continue; + } + totalSize += new File(project.getLocalPath(), fileName).length(); + } + if (totalSize > 2 * 1024 * 1024) { + checkReport.addIssue("warning.site-larger-than-2-mib", false); + } + return checkReport; + } + +} diff --git a/src/main/java/de/todesbaum/jsite/main/Main.java b/src/main/java/de/todesbaum/jsite/main/Main.java index 8a0b898..a8d70e7 100644 --- a/src/main/java/de/todesbaum/jsite/main/Main.java +++ b/src/main/java/de/todesbaum/jsite/main/Main.java @@ -47,15 +47,16 @@ import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import net.pterodactylus.util.image.IconLoader; + import de.todesbaum.jsite.application.Freenet7Interface; import de.todesbaum.jsite.application.Node; import de.todesbaum.jsite.application.Project; -import de.todesbaum.jsite.application.ProjectInserter; -import de.todesbaum.jsite.application.ProjectInserter.CheckReport; -import de.todesbaum.jsite.application.ProjectInserter.Issue; import de.todesbaum.jsite.application.UpdateChecker; import de.todesbaum.jsite.application.UpdateListener; import de.todesbaum.jsite.application.WebOfTrustInterface; +import de.todesbaum.jsite.application.validation.CheckReport; +import de.todesbaum.jsite.application.validation.Issue; +import de.todesbaum.jsite.application.validation.ProjectValidator; import de.todesbaum.jsite.gui.NodeManagerListener; import de.todesbaum.jsite.gui.NodeManagerPage; import de.todesbaum.jsite.gui.PreferencesPage; @@ -561,7 +562,7 @@ public class Main implements ActionListener, ListSelectionListener, WizardListen JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.error.no-node-selected"), null, JOptionPane.ERROR_MESSAGE); return; } - CheckReport checkReport = ProjectInserter.validateProject(project); + CheckReport checkReport = ProjectValidator.validateProject(project); for (Issue issue : checkReport) { if (issue.isFatal()) { JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite." + issue.getErrorKey()), (Object[]) issue.getParameters()), null, JOptionPane.ERROR_MESSAGE); diff --git a/src/test/java/de/todesbaum/jsite/application/validation/ProjectValidatorTest.java b/src/test/java/de/todesbaum/jsite/application/validation/ProjectValidatorTest.java new file mode 100644 index 0000000..545ab45 --- /dev/null +++ b/src/test/java/de/todesbaum/jsite/application/validation/ProjectValidatorTest.java @@ -0,0 +1,172 @@ +package de.todesbaum.jsite.application.validation; + +import static de.todesbaum.jsite.application.validation.ProjectValidator.validateProject; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.not; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; + +import de.todesbaum.jsite.application.Project; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +/** + * Unit test for {@link ProjectValidator}. + * + * @author David ‘Bombe’ Roden + */ +public class ProjectValidatorTest { + + @Rule + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); + + private Project project = new Project(); + + @Before + public void setupProject() throws Exception { + project.setLocalPath(temporaryFolder.getRoot().getPath()); + project.setPath("temp"); + project.setIndexFile("index.html"); + temporaryFolder.newFile("index.html").createNewFile(); + } + + @Test + public void completelyValidProjectDoesNotGenerateAnyIssues() { + CheckReport checkReport = validateProject(project); + assertThat(checkReport.getIssues(), empty()); + } + + @Test + public void missingLocalPathResultsInError() { + project.setLocalPath(null); + CheckReport checkReport = validateProject(project); + assertThat(checkReport.getIssues(), hasItem(new Issue("error.no-local-path", true))); + } + + @Test + public void emptyLocalPathResultsInError() { + project.setLocalPath(" "); + CheckReport checkReport = validateProject(project); + assertThat(checkReport.getIssues(), hasItem(new Issue("error.no-local-path", true))); + } + + @Test + public void missingPathResultsInError() { + project.setPath(null); + CheckReport checkReport = validateProject(project); + assertThat(checkReport.getIssues(), hasItem(new Issue("error.no-path", true))); + } + + @Test + public void emptyPathResultsInError() { + project.setPath(" "); + CheckReport checkReport = validateProject(project); + assertThat(checkReport.getIssues(), hasItem(new Issue("error.no-path", true))); + } + + @Test + public void missingIndexFileResultsInWarning() { + project.setIndexFile(null); + CheckReport checkReport = validateProject(project); + assertThat(checkReport.getIssues(), hasItem(new Issue("warning.empty-index", false))); + } + + @Test + public void emptyIndexFileResultsInWarning() { + project.setIndexFile(""); + CheckReport checkReport = validateProject(project); + assertThat(checkReport.getIssues(), hasItem(new Issue("warning.empty-index", false))); + } + + @Test + public void settingIndexFileWithoutExistingFileResultsInWarning() { + project.setIndexFile("test.html"); + CheckReport checkReport = validateProject(project); + assertThat(checkReport.getIssues(), hasItem(new Issue("error.index-missing", true))); + } + + @Test + public void usingNonHtmlMimeTypeForIndexFileResultsInWarning() { + project.getFileOption("index.html").setMimeType("text/plain"); + CheckReport checkReport = validateProject(project); + assertThat(checkReport.getIssues(), hasItem(new Issue("warning.index-not-html", false))); + } + + @Test + public void notInsertingTheIndexFileAnyFileResultsInError() { + project.getFileOption("index.html").setInsert(false); + project.getFileOption("index.html").setInsertRedirect(false); + CheckReport checkReport = validateProject(project); + assertThat(checkReport.getIssues(), hasItem(new Issue("error.index-not-inserted", true))); + } + + @Test + public void insertingARedirectWithRedirectUrlResultsInError() { + project.getFileOption("index.html").setInsert(false); + CheckReport checkReport = validateProject(project); + assertThat(checkReport.getIssues(), hasItem(new Issue("error.no-custom-key", true, "index.html"))); + } + + @Test + public void insertingARedirectEmptyKeyUrlResultsInError() { + project.getFileOption("index.html").setInsert(false); + project.getFileOption("index.html").setCustomKey(null); + CheckReport checkReport = validateProject(project); + assertThat(checkReport.getIssues(), hasItem(new Issue("error.no-custom-key", true, "index.html"))); + } + + @Test + public void insertingARedirectToCHKUrlResultsInError() { + project.getFileOption("index.html").setInsert(false); + project.getFileOption("index.html").setCustomKey("CHK@"); + CheckReport checkReport = validateProject(project); + assertThat(checkReport.getIssues(), hasItem(new Issue("error.no-custom-key", true, "index.html"))); + } + + @Test + public void notInsertingAnyFileResultsInError() { + project.getFileOption("index.html").setInsert(false); + project.getFileOption("index.html").setInsertRedirect(false); + CheckReport checkReport = validateProject(project); + assertThat(checkReport.getIssues(), hasItem(new Issue("error.no-files-to-insert", true))); + } + + @Test + public void filesWithDuplicateTargetNamesResultInAnError() { + project.getFileOption("second.html").setChangedName("index.html"); + CheckReport checkReport = validateProject(project); + assertThat(checkReport.getIssues(), hasItem(new Issue("error.duplicate-file", true, "index.html"))); + } + + @Test + public void filesWithLessThenOrEqualTo2MegabytesDoNotResultInWarning() throws Exception { + File largeFile = new File(temporaryFolder.getRoot(), "large.html"); + Files.write(largeFile.toPath(), new byte[2 * 1048576], StandardOpenOption.CREATE_NEW); + CheckReport checkReport = validateProject(project); + assertThat(checkReport.getIssues(), not(hasItem(new Issue("warning.site-larger-than-2-mib", false)))); + } + + @Test + public void filesWithSizeOfMoreThan2MegabytesDoNotResultInWarning() throws Exception { + File largeFile = new File(temporaryFolder.getRoot(), "large.html"); + Files.write(largeFile.toPath(), new byte[2 * 1048576 + 1], StandardOpenOption.CREATE_NEW); + CheckReport checkReport = validateProject(project); + assertThat(checkReport.getIssues(), hasItem(new Issue("warning.site-larger-than-2-mib", false))); + } + + @Test + public void filesAreCorrectlyIgnoreForSizeCheckIfNotInserted() throws Exception { + File largeFile = new File(temporaryFolder.getRoot(), "large.html"); + Files.write(largeFile.toPath(), new byte[2 * 1048576 + 1], StandardOpenOption.CREATE_NEW); + project.getFileOption("large.html").setInsert(false); + CheckReport checkReport = validateProject(project); + assertThat(checkReport.getIssues(), not(hasItem(new Issue("warning.site-larger-than-2-mib", false)))); + } + +} -- 2.7.4