package org.erlide.core.services.builder; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.File; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.erlide.dialyzer.builder.DialyzerMarkerUtils; import org.erlide.dialyzer.builder.DialyzerUtils; import org.erlide.engine.ErlangEngine; import org.erlide.engine.model.root.IErlElementLocator; import org.erlide.engine.model.root.IErlModule; import org.erlide.engine.model.root.IErlProject; import org.erlide.engine.util.ErlideTestUtils; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import com.google.common.collect.Sets; public class DialyzerUtilsTest { enum SEL { MODULE, SRC, PROJECT } @BeforeClass public static void setUpBeforeClass() throws Exception { ErlideTestUtils.initProjects(); } @AfterClass public static void tearDownAfterClass() throws Exception { ErlideTestUtils.deleteProjects(); } @Before public void setUp() throws Exception { ErlideTestUtils.initModulesAndIncludes(); } @After public void tearDown() throws Exception { ErlideTestUtils.deleteModules(); } @Test public void dialyzePrepareSelectionModuleBeamsTest() throws Exception { dialyzePrepareFromSelection(false, SEL.MODULE); } @Test public void dialyzePrepareSelectionModuleSourcesTest() throws Exception { dialyzePrepareFromSelection(true, SEL.MODULE); } @Test public void dialyzePrepareSelectionSrcFolderBeamsTest() throws Exception { dialyzePrepareFromSelection(false, SEL.SRC); } @Test public void dialyzePrepareSelectionSrcFolderSourcesTest() throws Exception { dialyzePrepareFromSelection(true, SEL.SRC); } @Test public void dialyzePrepareSelectionProjectBeamsTest() throws Exception { dialyzePrepareFromSelection(false, SEL.PROJECT); } @Test public void dialyzePrepareSelectionProjectSourcesTest() throws Exception { dialyzePrepareFromSelection(true, SEL.PROJECT); } @Test public void dialyzeMarkerOnFile() throws Exception { IErlProject erlProject = null; try { // given // an erlang module in an erlang project final String projectName = "testproject"; erlProject = ErlideTestUtils.createTmpErlProject(projectName); final String moduleName = "test.erl"; final IErlModule erlModule = ErlideTestUtils.createModule(erlProject, moduleName, "-module(test).\n-export([f/0]).\n-f() ->\n atom_to_list(\"hej\").\n"); IMarker[] markers = erlProject.getWorkspaceProject().findMarkers( DialyzerMarkerUtils.DIALYZE_WARNING_MARKER, true, IResource.DEPTH_INFINITE); assertEquals(0, markers.length); // when // putting a dialyzer warning on it final int lineNumber = 3; final String message = "test message"; final IErlElementLocator model = ErlangEngine.getInstance().getModel(); DialyzerMarkerUtils.addDialyzerWarningMarker(model, erlModule.getResource().getLocation().toPortableString(), lineNumber, message); // then // there should be a marker with proper file name and the proper // line number markers = erlProject.getWorkspaceProject().findMarkers( DialyzerMarkerUtils.DIALYZE_WARNING_MARKER, true, IResource.DEPTH_INFINITE); assertEquals(1, markers.length); final IMarker marker = markers[0]; assertEquals(moduleName, marker.getResource().getName()); assertEquals(lineNumber, marker.getAttribute(IMarker.LINE_NUMBER)); assertEquals(message, marker.getAttribute(IMarker.MESSAGE)); } finally { if (erlProject != null) { ErlideTestUtils.deleteProject(erlProject); } } } @Test public void dialyzeWithExternalInclude() throws Exception { // http://www.assembla.com/spaces/erlide/tickets/608-dialyzer---navigate-to-external-includes-from-markers File externalFile = null; IErlProject erlProject = null; File externalIncludesFile = null; final IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); try { // given // an erlang project and an external file not in any project final String projectName = "testproject"; erlProject = ErlideTestUtils.createTmpErlProject(projectName); final String externalFileName = "external.hrl"; externalFile = ErlideTestUtils.createTmpFile(externalFileName, "f([_ | _]=L) ->\n atom_to_list(L).\n"); externalIncludesFile = ErlideTestUtils.createTmpFile("external_includes", externalFile.getAbsolutePath()); DialyzerMarkerUtils.removeDialyzerMarkersFor(root); // when // putting dialyzer warning markers on the external file final String message = "test message"; final int lineNumber = 2; final IErlElementLocator model = ErlangEngine.getInstance().getModel(); DialyzerMarkerUtils.addDialyzerWarningMarker(model, externalFile.getAbsolutePath(), lineNumber, message); // then // the marker should have the proper file name and the include file // should appear in External Files final IMarker[] markers = root.findMarkers( DialyzerMarkerUtils.DIALYZE_WARNING_MARKER, true, IResource.DEPTH_INFINITE); assertThat(markers.length, is(greaterThan(0))); for (final IMarker marker : markers) { // for some reason, when running on Hudson, we get two identical // markers... final String path = (String) marker .getAttribute(DialyzerMarkerUtils.PATH_ATTRIBUTE); final IPath p = new Path(path); assertEquals(externalFileName, p.lastSegment()); assertEquals(lineNumber, marker.getAttribute(IMarker.LINE_NUMBER)); assertEquals(message, marker.getAttribute(IMarker.MESSAGE)); } } finally { DialyzerMarkerUtils.removeDialyzerMarkersFor(root); if (externalIncludesFile != null && externalIncludesFile.exists()) { externalIncludesFile.delete(); } if (externalFile != null && externalFile.exists()) { externalFile.delete(); } if (erlProject != null) { ErlideTestUtils.deleteProject(erlProject); } } } public void dialyzePrepareFromSelection(final boolean sources, final SEL select) throws Exception { // http://www.assembla.com/spaces/erlide/tickets/607-dialyzer---only-dialyze-on-selection IErlProject erlProject = null; try { // given // a project with two erlang modules, one of them selected final String projectName = "testproject"; erlProject = ErlideTestUtils.createTmpErlProject(projectName); assertNotNull(erlProject); final IErlModule a = ErlideTestUtils.createModule(erlProject, "a.erl", "-module(a).\n-export([t/0]).\nt() ->\n p(a).\np(L) ->\n lists:reverse(L).\n"); assertNotNull(a); final IErlModule b = ErlideTestUtils.createModule(erlProject, "b.erl", "-module(b).\n-export([t/0]).\nt() ->\n p(a).\np(L) ->\n lists:reverse(L).\n"); assertNotNull(b); ErlideTestUtils.invokeBuilderOn(erlProject); // when // collecting files to dialyze final IResource selectedResource = selectResource(select, erlProject, a); final Set<IErlModule> modules = DialyzerUtils.collectModulesFromResource( ErlangEngine.getInstance().getModel(), selectedResource); final Set<IErlProject> projects = Sets.newHashSet(); projects.add(erlProject); final List<String> names = new ArrayList<>(); final List<IPath> includeDirs = new ArrayList<>(); final List<String> files = new ArrayList<>(); DialyzerUtils.collectFilesAndIncludeDirs(modules, projects, files, names, includeDirs, sources); // then // only selected files (or corresponding beam) should be collected if (select == SEL.MODULE) { assertEquals(1, files.size()); final IPath p = new Path(files.get(0)); final String f = p.lastSegment(); if (sources) { assertEquals("a.erl", f); } else { assertEquals("a.beam", f); } } else { assertEquals(2, files.size()); final Set<String> fSet = new HashSet<>(2); for (final String i : files) { fSet.add(new Path(i).lastSegment()); } if (sources) { assertTrue(fSet.contains("a.erl")); assertTrue(fSet.contains("b.erl")); } else { assertTrue(fSet.contains("a.beam")); assertTrue(fSet.contains("b.beam")); } } } finally { if (erlProject != null) { ErlideTestUtils.deleteProject(erlProject); } } } private IResource selectResource(final SEL select, final IErlProject erlProject, final IErlModule a) { switch (select) { case MODULE: return a.getResource(); case PROJECT: return erlProject.getResource(); default: case SRC: return erlProject.getWorkspaceProject().getFolder("src"); } } // @Test // public void dialyzeModuleWithExternalInclude() throws Exception { // IErlProject erlProject = null; // try { // // given // // a project with an erlang module, inluding an external file // final String projectName = "testproject"; // erlProject = createTmpErlProject(projectName); // ErlideTestUtils.getTmpPath("testexternals"); // assertNotNull(erlProject); // final IErlModule include = ErlideTestUtils.createErlModule( // erlProject, "i.hrl", "-record(a, {b, c}).\n"); // final IErlModule f = ErlideTestUtils // .createErlModule( // erlProject, // "f.erl", // "-module(a).\n-export([t/0]).\n-include(\"i.hrl\").\nt() ->\n p(#a{b=b, c=c}).\n"); // assertNotNull(f); // ErlideTestUtils.invokeBuilderOn(erlProject); // // when // // dialyzing it // final Map<IErlProject, Set<IErlModule>> modules = new // HashMap<IErlProject, Set<IErlModule>>(); // DialyzerUtils.addModulesFromResource(ErlangCore.getModel(), // erlProject.getResource(), modules); // final List<String> names = new ArrayList<String>(); // final List<IPath> includeDirs = new ArrayList<IPath>(); // final List<String> files = new ArrayList<String>(); // DialyzerUtils.collectFilesAndIncludeDirs(erlProject, modules, // erlProject.getProject(), files, names, includeDirs, false); // // then // // it should find the include file // assertEquals(1, files.size()); // assertEquals("a.beam", new Path(files.get(0)).lastSegment()); // // } finally { // if (erlProject != null) { // ErlideTestUtils.deleteErlProject(erlProject); // } // } @Test public void dialyzeBinaryOnProjectWithErrorFile() throws Exception { // http://www.assembla.com/spaces/erlide/tickets/616-dialyzer-�-crash-on-binary-analysis-and-files-with-errors IErlProject erlProject = null; try { // given // a project with two erlang modules, one of them with an erlang // error, preventing it from generating a beam-file final String projectName = "testproject"; erlProject = ErlideTestUtils.createTmpErlProject(projectName); assertNotNull(erlProject); final IErlModule a = ErlideTestUtils.createModule(erlProject, "a.erl", "-module(a).\n-export([t/0]).\nt() ->\n p(a).\np(L) ->\n lists:reverse(L).\n"); assertNotNull(a); final IErlModule b = ErlideTestUtils.createModule(erlProject, "b.erl", "-module(b).\n-export([t/0]).\nt() ->\n p(a).\np(L) ->\n fel som tusan.\n"); assertNotNull(b); ErlideTestUtils.invokeBuilderOn(erlProject); // when // collecting files to dialyze final Set<IErlModule> modules = DialyzerUtils.collectModulesFromResource( ErlangEngine.getInstance().getModel(), erlProject.getResource()); final Set<IErlProject> projects = Sets.newHashSet(); projects.add(erlProject); final List<String> names = new ArrayList<>(); final List<IPath> includeDirs = new ArrayList<>(); final List<String> files = new ArrayList<>(); DialyzerUtils.collectFilesAndIncludeDirs(modules, projects, files, names, includeDirs, false); // then // it should only take the existing beam files assertEquals(1, files.size()); final IPath p = new Path(files.get(0)); final String f = p.lastSegment(); assertEquals("a.beam", f); } finally { if (erlProject != null) { ErlideTestUtils.deleteProject(erlProject); } } } }