package org.infernus.idea.checkstyle.service.cmd; import com.google.common.collect.ImmutableMap; import com.intellij.notification.Notification; import com.intellij.notification.NotificationType; import com.intellij.notification.Notifications; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.messages.MessageBus; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.Configuration; import org.hamcrest.Matchers; import org.infernus.idea.checkstyle.CheckStyleBundle; import org.infernus.idea.checkstyle.csapi.CheckstyleInternalObject; import org.infernus.idea.checkstyle.model.ConfigurationLocation; import org.infernus.idea.checkstyle.service.CheckstyleActionsImpl; import org.infernus.idea.checkstyle.service.ConfigurationBuilder; import org.infernus.idea.checkstyle.service.ConfigurationMatcher; import org.infernus.idea.checkstyle.service.FileUtil; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import java.io.IOException; import java.io.InputStream; import java.net.URISyntaxException; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import static org.mockito.Mockito.*; public class OpLoadConfigurationTest { private final ConfigurationLocation configurationLocation = mock(ConfigurationLocation.class); private final Project project = mock(Project.class); private final Module module = mock(Module.class); private final Notifications notifications = mock(Notifications.class); private OpLoadConfiguration underTest; @Before public void setUp() throws IOException { interceptApplicationNotifications(); when(configurationLocation.resolveAssociatedFile("aFileToResolve", project, module)).thenReturn("aResolvedFile"); when(configurationLocation.resolveAssociatedFile("triggersAnIoException", project, module)).thenThrow(new IOException ("aTriggeredIoException")); underTest = new OpLoadConfiguration(configurationLocation, null, project, module); } private void interceptApplicationNotifications() { final MessageBus messageBus = mock(MessageBus.class); when(project.getMessageBus()).thenReturn(messageBus); when(messageBus.syncPublisher(Notifications.TOPIC)).thenReturn(notifications); final Application application = mock(Application.class); when(application.isUnitTestMode()).thenReturn(true); when(application.getMessageBus()).thenReturn(messageBus); ApplicationManager.setApplication(application, mock(Disposable.class)); } @Test public void filePathsAreNotResolvedOnANonDefaultImplementationOfConfiguration() throws CheckstyleException { final Configuration config = mock(Configuration.class); verifyZeroInteractions(config); } @Test public void childrenOfUpdatedElementsArePreserved() throws CheckstyleException { Configuration config = ConfigurationBuilder.checker() .withChild(ConfigurationBuilder.config("SuppressionFilter").withAttribute("file", "aFileToResolve") .withChild(ConfigurationBuilder.config("aChildModule"))).build(); underTest.resolveFilePaths(config); assertThat(config, Matchers.is(ConfigurationMatcher.configEqualTo(ConfigurationBuilder.checker() .withChild(ConfigurationBuilder.config("SuppressionFilter").withAttribute("file", "aResolvedFile") .withChild(ConfigurationBuilder.config("aChildModule"))).build()))); } @Test public void attributesOfUpdatedElementsArePreserved() throws CheckstyleException { Configuration config = ConfigurationBuilder.checker() .withChild(ConfigurationBuilder.config("TreeWalker") .withChild(ConfigurationBuilder.config("ImportControl") .withAttribute("file", "aFileToResolve") .withAttribute("anotherAttribute", "anotherValue"))).build(); underTest.resolveFilePaths(config); assertThat(config, Matchers.is(ConfigurationMatcher.configEqualTo(ConfigurationBuilder.checker().withChild (ConfigurationBuilder.config("TreeWalker").withChild(ConfigurationBuilder.config("ImportControl") .withAttribute("file", "aResolvedFile").withAttribute("anotherAttribute", "anotherValue"))) .build()))); } @Test public void messagesOfUpdatedElementsArePreserved() throws CheckstyleException { Configuration config = ConfigurationBuilder.checker().withChild(ConfigurationBuilder.config ("SuppressionFilter").withAttribute("file", "aFileToResolve").withMessage("messageKey", "messageValue").withMessage("anotherMessageKey", "anotherMessageValue")).build(); underTest.resolveFilePaths(config); assertThat(config, Matchers.is(ConfigurationMatcher.configEqualTo(ConfigurationBuilder.checker().withChild (ConfigurationBuilder.config("SuppressionFilter").withAttribute("file", "aResolvedFile").withMessage ("messageKey", "messageValue").withMessage("anotherMessageKey", "anotherMessageValue")).build ()))); } @Test public void multipleElementsAreUpdated() throws CheckstyleException { Configuration config = ConfigurationBuilder.checker().withChild(ConfigurationBuilder.config ("SuppressionFilter").withAttribute("file", "aFileToResolve")).withChild(ConfigurationBuilder.config ("TreeWalker").withChild(ConfigurationBuilder.config("ImportControl").withAttribute("file", "anUnresolvableFile")).withChild(ConfigurationBuilder.config("RegexpHeader").withAttribute ("headerFile", "aFileToResolve"))).build(); underTest.resolveFilePaths(config); assertThat(config, Matchers.is(ConfigurationMatcher.configEqualTo(ConfigurationBuilder.checker().withChild (ConfigurationBuilder.config("SuppressionFilter").withAttribute("file", "aResolvedFile")).withChild (ConfigurationBuilder.config("TreeWalker").withChild(ConfigurationBuilder.config("RegexpHeader") .withAttribute("headerFile", "aResolvedFile"))).build()))); } @Test public void removalOfElementsDoesNotEffectOtherElements() throws CheckstyleException { Configuration config = ConfigurationBuilder.checker().withChild(ConfigurationBuilder.config ("SuppressionFilter").withAttribute("file", "anUnresolvableFile")).withChild(ConfigurationBuilder .config("TreeWalker").withChild(ConfigurationBuilder.config("RegexpHeader").withAttribute ("headerFile", "anUnresolvableFile")).withChild(ConfigurationBuilder.config("ConstantName"))) .build(); underTest.resolveFilePaths(config); assertThat(config, Matchers.is(ConfigurationMatcher.configEqualTo(ConfigurationBuilder.checker().withChild (ConfigurationBuilder.config("TreeWalker").withChild(ConfigurationBuilder.config("ConstantName"))) .build()))); } @Test public void aModuleWithAFilenameThatRaisesAnIOExceptionOnResolutionDoesNotModifyTheConfiguration() throws CheckstyleException { Configuration config = ConfigurationBuilder.checker().withChild(ConfigurationBuilder.config ("SuppressionFilter").withAttribute("file", "triggersAnIoException")).build(); underTest.resolveFilePaths(config); assertThat(config, Matchers.is(ConfigurationMatcher.configEqualTo(ConfigurationBuilder.checker().withChild (ConfigurationBuilder.config("SuppressionFilter").withAttribute("file", "triggersAnIoException")) .build()))); } @Test public void aModuleWithAFilenameThatRaisesAnIOExceptionOnResolutionTriggersAnErrorNotification() throws CheckstyleException { underTest.resolveFilePaths(ConfigurationBuilder.checker().withChild(ConfigurationBuilder.config ("SuppressionFilter").withAttribute("file", "triggersAnIoException")).build()); final Notification notification = sentNotification(); assertThat(notification, is(not(nullValue()))); assertThat(notification.getType(), is(equalTo(NotificationType.ERROR))); assertThat(notification.getContent(), is(equalTo(CheckStyleBundle.message("checkstyle.checker-failed", "aTriggeredIoException")))); } @Test public void aModuleWithAFilenameThatIsNotResolvesTriggersAWarningNotification() throws CheckstyleException { underTest.resolveFilePaths(ConfigurationBuilder.checker().withChild(ConfigurationBuilder.config("TreeWalker") .withChild(ConfigurationBuilder.config("RegexpHeader").withAttribute("headerFile", "anUnresolvableFile"))).build()); final Notification notification = sentNotification(); assertThat(notification, is(not(nullValue()))); assertThat(notification.getType(), is(equalTo(NotificationType.WARNING))); assertThat(notification.getContent(), is(equalTo(CheckStyleBundle.message("checkstyle.not-found" + "" + "" + ".RegexpHeader")))); } @Test public void aModuleWithAFilenameThatIsBlankDoesNotHaveResolutionAttempted() throws CheckstyleException { underTest.resolveFilePaths(ConfigurationBuilder.checker().withChild(ConfigurationBuilder.config("TreeWalker") .withChild(ConfigurationBuilder.config("ImportControl").withAttribute("file", ""))).build()); //verifyZeroInteractions(configurationLocation); } private Notification sentNotification() { final ArgumentCaptor<Notification> notificationCaptor = ArgumentCaptor.forClass(Notification.class); verify(notifications).notify(notificationCaptor.capture()); return notificationCaptor.getValue(); } @Test public void aSuppressionFilterWithAResolvableFilenameHasTheModuleUpdated() throws CheckstyleException { Configuration config = ConfigurationBuilder.checker().withChild(ConfigurationBuilder.config ("SuppressionFilter").withAttribute("file", "aFileToResolve")).build(); underTest.resolveFilePaths(config); assertThat(config, Matchers.is(ConfigurationMatcher.configEqualTo(ConfigurationBuilder.checker().withChild (ConfigurationBuilder.config("SuppressionFilter").withAttribute("file", "aResolvedFile")).build()))); } @Test public void aSuppressionFilterWithAnUnresolvableFilenameHasTheModuleRemoved() throws CheckstyleException { Configuration config = ConfigurationBuilder.checker().withChild(ConfigurationBuilder.config ("SuppressionFilter").withAttribute("file", "anUnresolvableFile")).build(); underTest.resolveFilePaths(config); assertThat(config, Matchers.is(ConfigurationMatcher.configEqualTo(ConfigurationBuilder.checker().build()))); } @Test public void aRegexpHeaderWithAResolvableFilenameHasTheModuleUpdated() throws CheckstyleException { Configuration config = ConfigurationBuilder.checker().withChild(ConfigurationBuilder.config("TreeWalker") .withChild(ConfigurationBuilder.config("RegexpHeader").withAttribute("headerFile", "aFileToResolve")) ).build(); underTest.resolveFilePaths(config); assertThat(config, Matchers.is(ConfigurationMatcher.configEqualTo(ConfigurationBuilder.checker().withChild (ConfigurationBuilder.config("TreeWalker").withChild(ConfigurationBuilder.config("RegexpHeader") .withAttribute("headerFile", "aResolvedFile"))).build()))); } @Test public void aRegexpHeaderWithAnUnresolvableFilenameHasTheModuleReferenceRemoved() throws CheckstyleException { Configuration config = ConfigurationBuilder.checker().withChild(ConfigurationBuilder.config("TreeWalker") .withChild(ConfigurationBuilder.config("RegexpHeader").withAttribute("headerFile", "anUnresolvableFile"))).build(); underTest.resolveFilePaths(config); assertThat(config, Matchers.is(ConfigurationMatcher.configEqualTo(ConfigurationBuilder.checker().withChild (ConfigurationBuilder.config("TreeWalker")).build()))); } @Test public void aImportControlWithAResolvableFilenameHasTheModuleUpdated() throws CheckstyleException { Configuration config = ConfigurationBuilder.checker().withChild(ConfigurationBuilder.config("TreeWalker") .withChild(ConfigurationBuilder.config("ImportControl").withAttribute("file", "aFileToResolve"))) .build(); underTest.resolveFilePaths(config); assertThat(config, Matchers.is(ConfigurationMatcher.configEqualTo(ConfigurationBuilder.checker().withChild (ConfigurationBuilder.config("TreeWalker").withChild(ConfigurationBuilder.config("ImportControl") .withAttribute("file", "aResolvedFile"))).build()))); } @Test public void anImportControlWithAnUnresolvableFilenameHasTheModuleReferenceRemoved() throws CheckstyleException { Configuration config = ConfigurationBuilder.checker().withChild(ConfigurationBuilder.config("TreeWalker") .withChild(ConfigurationBuilder.config("ImportControl").withAttribute("file", "anUnresolvableFile"))) .build(); underTest.resolveFilePaths(config); assertThat(config, Matchers.is(ConfigurationMatcher.configEqualTo(ConfigurationBuilder.checker().withChild (ConfigurationBuilder.config("TreeWalker")).build()))); } @Test public void testNoConfiguration() throws CheckstyleException { OpLoadConfiguration testee = new OpLoadConfiguration(configurationLocation, null, project, module) { @Override Configuration callLoadConfiguration(final InputStream inputStream) { return null; } }; try { testee.execute(project); } catch (CheckstyleException e) { // expected Assert.assertTrue(e.getMessage().contains("Couldn't find root module")); } } @Test public void testWrongConfigurationClass() throws CheckstyleException { Configuration config = new Configuration() { @Override public String[] getAttributeNames() { throw new UnsupportedOperationException(); } @Override public String getAttribute(final String name) throws CheckstyleException { throw new UnsupportedOperationException(); } @Override public Configuration[] getChildren() { throw new UnsupportedOperationException(); } @Override public String getName() { throw new UnsupportedOperationException(); } @Override public ImmutableMap<String, String> getMessages() { throw new UnsupportedOperationException(); } }; underTest.resolveFilePaths(config); // just log a warning and do nothing ... well ... } @Test public void testConstructors() { new OpLoadConfiguration(configurationLocation, project); new OpLoadConfiguration(configurationLocation, null, project); new OpLoadConfiguration(configurationLocation, null, project, module); VirtualFile virtualFile = mock(VirtualFile.class); new OpLoadConfiguration((VirtualFile) virtualFile, project); new OpLoadConfiguration((VirtualFile) virtualFile, null, project); new OpLoadConfiguration("doesn't matter", project); } @Test public void testLoadFromString() throws IOException, URISyntaxException { final String configXml = FileUtil.readFile("cmd/config-ok.xml"); CheckstyleInternalObject csConfig = new CheckstyleActionsImpl(project).loadConfiguration(configXml); Assert.assertNotNull(csConfig); } }