package com.sleekbyte.tailor.functional.yaml; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertTrue; import com.sleekbyte.tailor.Tailor; import com.sleekbyte.tailor.common.ExitCode; import com.sleekbyte.tailor.common.Messages; import com.sleekbyte.tailor.common.Rules; import com.sleekbyte.tailor.common.Severity; import com.sleekbyte.tailor.output.Printer; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.ExpectedSystemExit; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.mockito.runners.MockitoJUnitRunner; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintStream; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Tests for {@link Tailor} configuration file flow. * Test config file functionality. */ @RunWith(MockitoJUnitRunner.class) public final class YamlConfigurationTest { @Rule public TemporaryFolder folder = new TemporaryFolder(); @Rule public final ExpectedSystemExit exit = ExpectedSystemExit.none(); protected static final String TEST_INPUT_DIR = "src/test/swift/com/sleekbyte/tailor/functional/yaml"; protected static final String NEWLINE_REGEX = "\\r?\\n"; private static final String YAML_TEST_1 = "YamlTest1.swift"; private static final String YAML_TEST_2 = "YamlTest2.swift"; protected ByteArrayOutputStream outContent; protected ByteArrayOutputStream errContent; protected File inputFile; protected List<String> expectedMessages; @Before public void setUp() throws IOException { inputFile = new File(TEST_INPUT_DIR); expectedMessages = new ArrayList<>(); outContent = new ByteArrayOutputStream(); errContent = new ByteArrayOutputStream(); System.setOut(new PrintStream(outContent, false, Charset.defaultCharset().name())); System.setErr(new PrintStream(errContent, false, Charset.defaultCharset().name())); } @After public void tearDown() { System.setOut(null); System.setErr(null); } @Test public void testIncludeOption() throws IOException { // Add expected output addExpectedMsg(3, 7, Rules.UPPER_CAMEL_CASE, Messages.CLASS + Messages.NAMES + Messages.UPPER_CAMEL_CASE, YAML_TEST_1); addExpectedMsg(7, 7, Rules.UPPER_CAMEL_CASE, Messages.CLASS + Messages.NAMES + Messages.UPPER_CAMEL_CASE, YAML_TEST_1); addExpectedMsg(12, 15, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(13, 18, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(17, 15, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(18, 18, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(20, 26, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(21, 16, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(25, 63, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(27, 71, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(29, 57, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(31, 4, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); // Create config file that wants to only analyze YAML_TEST_1.swift File configurationFile = includeOptionConfig(".tailor.yml"); String[] command = new String[] { "--config", configurationFile.getAbsolutePath(), "--no-color" }; runTest(command); } @Test public void testExceptOption() throws IOException { // Add expected output addExpectedMsg(8, 33, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_2); addExpectedMsg(9, 16, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_2); addExpectedMsg(10, 23, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_2); addExpectedMsg(11, 39, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_2); addExpectedMsg(12, 2, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_2); addExpectedMsg(14, 23, Rules.TRAILING_CLOSURE, Messages.CLOSURE + Messages.TRAILING_CLOSURE, YAML_TEST_2); addExpectedMsg(18, 2, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_2); // Create config file that will only analyze YAML_TEST_2.swift for violations other than upper-camel-case File configurationFile = exceptOptionConfig(".tailor.yml"); String[] command = new String[] { "--config", configurationFile.getAbsolutePath() }; runTest(command); } @Test public void testOnlyExceptOptionPrecedence() throws IOException { // Add expected output addExpectedMsg(3, 7, Rules.UPPER_CAMEL_CASE, Messages.CLASS + Messages.NAMES + Messages.UPPER_CAMEL_CASE, YAML_TEST_1); addExpectedMsg(7, 7, Rules.UPPER_CAMEL_CASE, Messages.CLASS + Messages.NAMES + Messages.UPPER_CAMEL_CASE, YAML_TEST_1); // Create config file that wants to only analyze YAML_TEST_1.swift for upper-camel-case violations // Test for precedence of `only` over `except` File configurationFile = onlyAndExceptPrecedenceConfig(".tailor.yml"); String[] command = new String[] { "--config", configurationFile.getAbsolutePath(), "--no-color" }; runTest(command); } @Test public void testNoColorOption() throws IOException { // Add expected output addExpectedMsg(3, 7, Rules.UPPER_CAMEL_CASE, Messages.CLASS + Messages.NAMES + Messages.UPPER_CAMEL_CASE, YAML_TEST_1); addExpectedMsg(7, 7, Rules.UPPER_CAMEL_CASE, Messages.CLASS + Messages.NAMES + Messages.UPPER_CAMEL_CASE, YAML_TEST_1); File configurationFile = noColorConfig(".tailor.yml"); String[] command = new String[] { "--config", configurationFile.getAbsolutePath(), }; runTest(command); } @Test public void testCliAndConfigFilePrecedence() throws IOException { addExpectedMsg(12, 15, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(13, 18, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(17, 15, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(18, 18, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(20, 26, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(21, 16, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(25, 63, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(27, 71, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(29, 57, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(31, 4, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); File configurationFile = onlyAndExceptPrecedenceConfig(".tailor.yml"); String[] command = new String[] { "--only", "terminating-semicolon", "--config", configurationFile.getAbsolutePath(), "--no-color" }; runTest(command); } private void runTest(String[] command) throws UnsupportedEncodingException { Tailor.main(command); List<String> actualOutput = new ArrayList<>(); String[] msgs = outContent.toString(Charset.defaultCharset().name()).split(NEWLINE_REGEX); // Skip first five lines for config info, progress, and file header, last two lines for summary msgs = Arrays.copyOfRange(msgs, 5, msgs.length - 2); for (String msg : msgs) { String truncatedMsg = msg.substring(msg.indexOf(inputFile.getName())); actualOutput.add(truncatedMsg); } assertArrayEquals(outContent.toString(Charset.defaultCharset().name()), this.expectedMessages.toArray(), actualOutput.toArray()); } @Test public void testPurge() throws IOException { addExpectedMsg(12, 15, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(13, 18, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(17, 15, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(18, 18, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(20, 26, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(21, 16, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(25, 63, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(27, 71, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(29, 57, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); addExpectedMsg(31, 4, Rules.TERMINATING_SEMICOLON, Messages.STATEMENTS + Messages.SEMICOLON, YAML_TEST_1); File configurationFile = purgeConfig(".tailor.yml"); String[] command = new String[] { "--only", "terminating-semicolon", "--config", configurationFile.getAbsolutePath(), "--no-color" }; runTest(command); } @Test public void testInvalidPurge() throws IOException { exit.expectSystemExitWithStatus(ExitCode.failure()); exit.checkAssertionAfterwards(() -> assertTrue("STDERR should contain error message", errContent.toString().contains("Invalid number of files specified for purge in config file"))); File configurationFile = invalidPurgeConfig(".tailor.yml"); String[] command = new String[] { "--only", "terminating-semicolon", "--config", configurationFile.getAbsolutePath(), "--no-color" }; Tailor.main(command); } private void addExpectedMsg(int line, int column, Rules rule, String msg, String fileName) { expectedMessages.add( Printer.genOutputStringForTest(rule, inputFile.getName() + "/" + fileName, line, column, Severity.WARNING, msg)); } private File includeOptionConfig(String fileName) throws IOException { File configFile = folder.newFile(fileName); Writer streamWriter = new OutputStreamWriter(new FileOutputStream(configFile), Charset.forName("UTF-8")); PrintWriter printWriter = new PrintWriter(streamWriter); printWriter.println("include:"); printWriter.println(" - '**/" + YAML_TEST_1 + "'"); streamWriter.close(); printWriter.close(); return configFile; } private File onlyAndExceptPrecedenceConfig(String fileName) throws IOException { File configFile = folder.newFile(fileName); Writer streamWriter = new OutputStreamWriter(new FileOutputStream(configFile), Charset.forName("UTF-8")); PrintWriter printWriter = new PrintWriter(streamWriter); printWriter.println("include:"); printWriter.println(" - '**/" + YAML_TEST_1 + "'"); printWriter.println("only:"); printWriter.println(" - upper-camel-case"); printWriter.println("except:"); printWriter.println(" - terminating-semicolon"); streamWriter.close(); printWriter.close(); return configFile; } private File noColorConfig(String fileName) throws IOException { File configFile = folder.newFile(fileName); Writer streamWriter = new OutputStreamWriter(new FileOutputStream(configFile), Charset.forName("UTF-8")); PrintWriter printWriter = new PrintWriter(streamWriter); printWriter.println("include:"); printWriter.println(" - '**/" + YAML_TEST_1 + "'"); printWriter.println("only:"); printWriter.println(" - upper-camel-case"); printWriter.println("except:"); printWriter.println(" - terminating-semicolon"); printWriter.println("color: disable"); streamWriter.close(); printWriter.close(); return configFile; } private File exceptOptionConfig(String fileName) throws IOException { File configFile = folder.newFile(fileName); Writer streamWriter = new OutputStreamWriter(new FileOutputStream(configFile), Charset.forName("UTF-8")); PrintWriter printWriter = new PrintWriter(streamWriter); printWriter.println("color: disable"); printWriter.println("include:"); printWriter.println(" - '**/" + YAML_TEST_2 + "'"); printWriter.println("except:"); printWriter.println(" - upper-camel-case"); streamWriter.close(); printWriter.close(); return configFile; } private File purgeConfig(String fileName) throws IOException { File configFile = folder.newFile(fileName); Writer streamWriter = new OutputStreamWriter(new FileOutputStream(configFile), Charset.forName("UTF-8")); PrintWriter printWriter = new PrintWriter(streamWriter); printWriter.println("purge: 1"); printWriter.println("include:"); printWriter.println(" - '**/" + YAML_TEST_1 + "'"); streamWriter.close(); printWriter.close(); return configFile; } private File invalidPurgeConfig(String fileName) throws IOException { File configFile = folder.newFile(fileName); Writer streamWriter = new OutputStreamWriter(new FileOutputStream(configFile), Charset.forName("UTF-8")); PrintWriter printWriter = new PrintWriter(streamWriter); printWriter.println("purge: -1"); printWriter.println("include:"); printWriter.println(" - '**/" + YAML_TEST_1 + "'"); streamWriter.close(); printWriter.close(); return configFile; } }