package com.pablissimo.sonar;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.TempFolder;
import org.sonar.api.utils.command.Command;
import org.sonar.api.utils.command.CommandExecutor;
import org.sonar.api.utils.command.StreamConsumer;
import edu.emory.mathcs.backport.java.util.Arrays;
public class TsLintExecutorImplTest {
TsLintExecutorImpl executorImpl;
CommandExecutor commandExecutor;
TempFolder tempFolder;
File tempOutputFile;
System2 system;
TsLintExecutorConfig config;
@Before
public void setUp() throws Exception {
this.system = mock(System2.class);
this.tempFolder = mock(TempFolder.class);
this.tempOutputFile = mock(File.class);
when(this.tempOutputFile.getAbsolutePath()).thenReturn("path/to/temp");
when(this.tempFolder.newFile()).thenReturn(this.tempOutputFile);
this.commandExecutor = mock(CommandExecutor.class);
this.executorImpl = spy(new TsLintExecutorImpl(this.system, this.tempFolder));
when(this.executorImpl.createExecutor()).thenReturn(this.commandExecutor);
doReturn(mock(BufferedReader.class)).when(this.executorImpl).getBufferedReaderForFile(any(File.class));
// Setup a default config, which each method will mutate as required
this.config = new TsLintExecutorConfig();
this.config.setPathToTsLint("path/to/tslint");
this.config.setConfigFile("path/to/config");
this.config.setRulesDir("path/to/rules");
this.config.setTimeoutMs(40000);
}
@Test
public void executesCommandWithCorrectArgumentsAndTimeouts() {
final ArrayList<Command> capturedCommands = new ArrayList<Command>();
final ArrayList<Long> capturedTimeouts = new ArrayList<Long>();
Answer<Integer> captureCommand = new Answer<Integer>() {
@Override
public Integer answer(InvocationOnMock invocation) throws Throwable {
capturedCommands.add((Command) invocation.getArguments()[0]);
capturedTimeouts.add((long) invocation.getArguments()[3]);
return 0;
}
};
when(this.commandExecutor.execute(any(Command.class), any(StreamConsumer.class), any(StreamConsumer.class), any(long.class))).then(captureCommand);
this.executorImpl.execute(this.config, Arrays.asList(new String[] { "path/to/file", "path/to/another" }));
assertEquals(1, capturedCommands.size());
Command theCommand = capturedCommands.get(0);
long theTimeout = capturedTimeouts.get(0);
assertEquals("node path/to/tslint --format json --rules-dir path/to/rules --out path/to/temp --config path/to/config path/to/file path/to/another", theCommand.toCommandLine());
// Expect one timeout period per file processed
assertEquals(2 * 40000, theTimeout);
}
@Test
public void doesNotSendFileListToTsLint_ifConfigSaysToUseProjectFile() {
final ArrayList<Command> capturedCommands = new ArrayList<Command>();
final ArrayList<Long> capturedTimeouts = new ArrayList<Long>();
Answer<Integer> captureCommand = new Answer<Integer>() {
@Override
public Integer answer(InvocationOnMock invocation) throws Throwable {
capturedCommands.add((Command) invocation.getArguments()[0]);
capturedTimeouts.add((long) invocation.getArguments()[3]);
return 0;
}
};
this.config.setPathToTsConfig("path/to/tsconfig.json");
when(this.commandExecutor.execute(any(Command.class), any(StreamConsumer.class), any(StreamConsumer.class), any(long.class))).then(captureCommand);
this.executorImpl.execute(this.config, Arrays.asList(new String[] { "path/to/file", "path/to/another" }));
assertEquals(1, capturedCommands.size());
Command theCommand = capturedCommands.get(0);
long theTimeout = capturedTimeouts.get(0);
assertEquals("node path/to/tslint --format json --rules-dir path/to/rules --out path/to/temp --config path/to/config --project path/to/tsconfig.json", theCommand.toCommandLine());
// Timeout should be just what we specified since we're not batching
assertEquals(40000, theTimeout);
}
@Test
public void usesTypeCheckParameter_ifConfigSaysToUseTypeCheck() {
final ArrayList<Command> capturedCommands = new ArrayList<Command>();
Answer<Integer> captureCommand = new Answer<Integer>() {
@Override
public Integer answer(InvocationOnMock invocation) throws Throwable {
capturedCommands.add((Command) invocation.getArguments()[0]);
return 0;
}
};
this.config.setPathToTsConfig("path/to/tsconfig.json");
this.config.setShouldPerformTypeCheck(true);
when(this.commandExecutor.execute(any(Command.class), any(StreamConsumer.class), any(StreamConsumer.class), any(long.class))).then(captureCommand);
this.executorImpl.execute(this.config, Arrays.asList(new String[] { "path/to/file", "path/to/another" }));
assertEquals(1, capturedCommands.size());
Command theCommand = capturedCommands.get(0);
assertEquals("node path/to/tslint --format json --rules-dir path/to/rules --out path/to/temp --config path/to/config --project path/to/tsconfig.json --type-check", theCommand.toCommandLine());
}
@Test
public void DoesNotAddRulesDirParameter_IfNull() {
final ArrayList<Command> capturedCommands = new ArrayList<Command>();
final ArrayList<Long> capturedTimeouts = new ArrayList<Long>();
Answer<Integer> captureCommand = new Answer<Integer>() {
@Override
public Integer answer(InvocationOnMock invocation) throws Throwable {
capturedCommands.add((Command) invocation.getArguments()[0]);
capturedTimeouts.add((long) invocation.getArguments()[3]);
return 0;
}
};
when(this.commandExecutor.execute(any(Command.class), any(StreamConsumer.class), any(StreamConsumer.class), any(long.class))).then(captureCommand);
this.config.setRulesDir(null);
this.executorImpl.execute(this.config, Arrays.asList(new String[] { "path/to/file" }));
Command theCommand = capturedCommands.get(0);
assertFalse(theCommand.toCommandLine().contains("--rules-dir"));
}
@Test
public void DoesNotAddRulesDirParameter_IfEmptyString() {
final ArrayList<Command> capturedCommands = new ArrayList<Command>();
final ArrayList<Long> capturedTimeouts = new ArrayList<Long>();
Answer<Integer> captureCommand = new Answer<Integer>() {
@Override
public Integer answer(InvocationOnMock invocation) throws Throwable {
capturedCommands.add((Command) invocation.getArguments()[0]);
capturedTimeouts.add((long) invocation.getArguments()[3]);
return 0;
}
};
when(this.commandExecutor.execute(any(Command.class), any(StreamConsumer.class), any(StreamConsumer.class), any(long.class))).then(captureCommand);
this.config.setRulesDir("");
this.executorImpl.execute(this.config, Arrays.asList(new String[] { "path/to/file" }));
Command theCommand = capturedCommands.get(0);
assertFalse(theCommand.toCommandLine().contains("--rules-dir"));
}
@Test
public void BatchesExecutions_IfTooManyFilesForCommandLine() {
List<String> filenames = new ArrayList<String>();
int currentLength = 0;
int standardCmdLength = "node path/to/tslint --format json --rules-dir path/to/rules --out path/to/temp --config path/to/config".length();
String firstBatch = "first batch";
while (currentLength + 12 < TsLintExecutorImpl.MAX_COMMAND_LENGTH - standardCmdLength) {
filenames.add(firstBatch);
currentLength += firstBatch.length() + 1; // 1 for the space
}
filenames.add("second batch");
final ArrayList<Command> capturedCommands = new ArrayList<Command>();
final ArrayList<Long> capturedTimeouts = new ArrayList<Long>();
Answer<Integer> captureCommand = new Answer<Integer>() {
@Override
public Integer answer(InvocationOnMock invocation) throws Throwable {
capturedCommands.add((Command) invocation.getArguments()[0]);
capturedTimeouts.add((long) invocation.getArguments()[3]);
return 0;
}
};
when(this.commandExecutor.execute(any(Command.class), any(StreamConsumer.class), any(StreamConsumer.class), any(long.class))).then(captureCommand);
this.executorImpl.execute(this.config, filenames);
assertEquals(2, capturedCommands.size());
Command theSecondCommand = capturedCommands.get(1);
assertFalse(theSecondCommand.toCommandLine().contains("first batch"));
assertTrue(theSecondCommand.toCommandLine().contains("second batch"));
}
@Test(expected=IllegalArgumentException.class)
public void execute_throws_ifNullConfigSupplied() {
this.executorImpl.execute(null, new ArrayList<String>());
}
@Test(expected=IllegalArgumentException.class)
public void execute_throws_ifNullFileListSupplied() {
this.executorImpl.execute(this.config, null);
}
@Test
public void useAlreadyExistsTsLintOutput_ifConfigSaysToUseTsLintOutput() throws IOException {
this.config.setPathToTsLintOutput("path/to/output.json");
doReturn(mock(BufferedReader.class)).when(this.executorImpl).getBufferedReaderForFile(any(File.class));
List<String> result = this.executorImpl.execute(this.config, Arrays.asList(new String[]{}));
assertEquals(1, result.size());
}
}