package com.googlecode.jslint4java.maven;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Arrays;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import junit.framework.AssertionFailedError;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.testing.AbstractMojoTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Files;
import com.google.common.io.Resources;
import com.googlecode.jslint4java.Option;
// NB: Even though this is being run with JUnit 4, the asserts are still largely JUnit 3. Yay inheritance!
@RunWith(JUnit4.class)
public class JSLintMojoTest extends AbstractMojoTestCase {
private static final String GOAL = "lint";
/** A directory containing a file with an error in. */
private static final String BAD_JS = "bad-js";
/** A directory containing javascript with no lint errors. */
private static final String GOOD_JS = "good-js";
private static final String POM_XML = "pom.xml";
@Rule
public TemporaryFolder temp = new TemporaryFolder();
private File baseDir;
private JSLintMojo mojo;
private final FakeLog logger = new FakeLog();
private void assertLogContains(String expected) {
for (FakeLog.LogItem item : logger.loggedItems) {
if (item.msg.toString().contains(expected)) {
return;
}
}
StringBuilder sb = new StringBuilder();
sb.append("Didn't find error text in logs: \"");
sb.append(expected);
sb.append("\"; log was:\n");
sb.append(Joiner.on("\n").join(logger.loggedItems));
fail(sb.toString());
}
/**
* Check the file exists and is not empty.
*
* @return the expected file, for further inspection.
*/
private File assertFileExists(String filename) {
File expectedFile = new File(temp.getRoot(), filename);
assertTrue(expectedFile + " exists", expectedFile.exists());
assertTrue("file has non-zero length", expectedFile.length() > 0);
return expectedFile;
}
private File baseRelative(String child) {
return new File(baseDir, child);
}
public MojoFailureException executeMojoExpectingFailure() throws MojoExecutionException {
try {
mojo.execute();
throw new AssertionFailedError("expected failure but saw none");
} catch (MojoFailureException e) {
return e;
}
}
private File getResourceFile(String filename) throws URISyntaxException {
URL resource = Resources.getResource(JSLintMojoTest.class, filename);
File file = new File(resource.toURI());
assertTrue(file + " doesn't exist?", file.exists());
return file;
}
private String readFile(File reportFile) throws FileNotFoundException, IOException {
return Files.toString(reportFile, Charsets.UTF_8);
}
@Before
@Override
public void setUp() throws Exception {
super.setUp();
File pom = getResourceFile(POM_XML);
baseDir = pom.getParentFile();
mojo = (JSLintMojo) lookupMojo(GOAL, pom);
mojo.setLog(logger);
// We don't care about "use strict" for these tests.
mojo.addOption(Option.SLOPPY, "true");
mojo.setOutputFolder(temp.getRoot());
}
@After
@Override
public void tearDown() throws Exception {
super.tearDown();
}
// Given the rate that JSLint changes at this is no bad thing.
@Test
public void testAlternateJSLint() throws Exception {
// This always returns "OK"
mojo.setJslint(getResourceFile("dummy-jslint.js"));
useBadSource();
mojo.execute();
// Should be no exception raised.
}
@Test
public void testBasics() throws Exception {
useGoodSource();
mojo.execute();
}
@Test
public void testDefaultEncoding() {
assertEquals("UTF-8", mojo.getEncoding());
}
@Test
public void testFailOnError() throws Exception {
useBadSource();
mojo.setFailOnError(false);
mojo.execute();
assertLogContains("JSLint found 1 problems in 1 files");
}
@Test
public void testFailure() throws Exception {
useBadSource();
MojoFailureException e = executeMojoExpectingFailure();
assertEquals("JSLint found 1 problems in 1 files", e.getMessage());
}
@Test
public void testLogToConsole() throws Exception {
useBadSource();
executeMojoExpectingFailure();
assertTrue("we logged something", !logger.loggedItems.isEmpty());
assertLogContains("bad.js:1:26: Expected ';' and instead saw '(end)'.");
}
@Test
public void testLogToFile() throws Exception {
useBadSource();
executeMojoExpectingFailure();
assertFileExists("jslint.xml");
// Additional reports we should always generate.
assertFileExists("checkstyle.xml");
assertFileExists("junit.xml");
assertFileExists("report.html");
assertFileExists("report.txt");
}
@Test
public void testLogToFileContents() throws Exception {
useGoodSource();
mojo.execute();
File report = assertFileExists("jslint.xml");
Matcher m = Pattern.compile("<file\\s").matcher(readFile(report));
assertTrue("found first <file", m.find());
assertTrue("found second <file", m.find());
assertFalse("no more <file", m.find());
}
@Test
public void testLogToFileMakesDirectory() throws Exception {
assertTrue(temp.getRoot().delete());
testLogToFile();
}
@Test
public void testLogToFileOnSuccess() throws Exception {
useGoodSource();
mojo.execute();
assertFileExists("jslint.xml");
}
@Test
public void testOptions() throws Exception {
useGoodSource();
mojo.setOptions(ImmutableMap.of("sloppy", "false"));
executeMojoExpectingFailure();
assertTrue(true);
}
// Check the stuff we specified is actually there.
@Test
public void testOptionsFromPom() {
Map<String, String> options = mojo.getOptions();
assertThat(options.size(), is(2));
assertThat(options, hasEntry("es5", "true"));
// This actually comes from our setUp() call…
assertThat(options, hasEntry("sloppy", "true"));
}
@Test
public void testSkip() throws Exception {
mojo.setSkip(true);
mojo.execute();
assertLogContains("skipping");
}
private void useBadSource() {
mojo.setSourceFolders(Arrays.asList(baseRelative(BAD_JS)));
}
private void useGoodSource() {
mojo.setSourceFolders(Arrays.asList(baseRelative(GOOD_JS)));
}
}