package org.erlide.engine.util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.erlide.engine.ErlangEngine;
import org.erlide.engine.internal.model.root.ErlProject;
import org.erlide.engine.model.ErlElementKind;
import org.erlide.engine.model.IErlElement;
import org.erlide.engine.model.erlang.ErlangFunction;
import org.erlide.engine.model.erlang.IErlFunction;
import org.erlide.engine.model.erlang.IErlImport;
import org.erlide.engine.model.erlang.IErlPreprocessorDef;
import org.erlide.engine.model.erlang.IErlRecordDef;
import org.erlide.engine.model.erlang.IErlTypespec;
import org.erlide.engine.model.root.IErlElementLocator;
import org.erlide.engine.model.root.IErlModel;
import org.erlide.engine.model.root.IErlModule;
import org.erlide.engine.model.root.IErlProject;
import org.erlide.engine.services.parsing.ScannerService;
import org.erlide.engine.services.search.ModelFindService;
import org.erlide.engine.services.search.ModelUtilService;
import org.erlide.util.ErlLogger;
import org.erlide.util.SystemConfiguration;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.ericsson.otp.erlang.OtpErlangAtom;
import com.ericsson.otp.erlang.OtpErlangList;
import com.ericsson.otp.erlang.OtpErlangLong;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangTuple;
import com.google.common.collect.Lists;
public class ModelUtilsTest {
private static IErlProject projects[] = null;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
ErlideTestUtils.initProjects();
// We set up projects here, it's quite costly
final String name1 = "testproject1";
final IErlProject erlProject1 = ErlideTestUtils
.createProject(ErlideTestUtils.getTmpPath(name1), name1);
final String name2 = "testproject2";
final IErlProject erlProject2 = ErlideTestUtils
.createProject(ErlideTestUtils.getTmpPath(name2), name2);
projects = new IErlProject[] { erlProject1, erlProject2 };
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
ErlideTestUtils.deleteProjects();
}
private ModelUtilService modelUtilService;
private ModelFindService modelFindService;
@Before
public void setUp() throws Exception {
modelUtilService = ErlangEngine.getInstance().getModelUtilService();
modelFindService = ErlangEngine.getInstance().getModelFindService();
ErlideTestUtils.initModulesAndIncludes();
}
@After
public void tearDown() throws Exception {
ErlideTestUtils.deleteModules();
}
@Test
public void getImportsAsListTest() throws Exception {
// given
// an Erlang module with imports
final IErlModule moduleA = ErlideTestUtils.createModule(projects[0], "ax.erl",
"-module(ax).\n-import(lists, [reverse/1, foldl/3].\n");
moduleA.open(null);
// when
// fetching imports as list of OtpErlangTuple
final Collection<IErlElement> children = moduleA.getChildren();
final Collection<IErlImport> imports2 = moduleA.getImports();
final List<OtpErlangObject> imports = modelUtilService.getImportsAsList(moduleA);
// then
// they should be returned
assertEquals(2, children.size());
assertEquals(1, imports2.size());
assertEquals(1, imports.size());
final OtpErlangAtom listAtom = new OtpErlangAtom("lists");
assertEquals(
new OtpErlangTuple(new OtpErlangObject[] { listAtom,
new OtpErlangList(new OtpErlangObject[] {
makeTuple2("reverse", 1), makeTuple2("foldl", 3) }) }),
imports.get(0));
}
@Test
public void findExternalTypeTest() throws Exception {
// given
// an Erlang module with typedef
final IErlModule moduleB = ErlideTestUtils.createModule(projects[0], "bx.erl",
"-module(bx).\n-type concat_thing() :: atom() | integer() | float() | string().\n");
// final IErlModule moduleC =
// ErlideTestUtils.createErlModule(projects[1],
// "c.erl", "-module(c).\n-type cc() :: b:concat_thing().\n");
final ScannerService scanner = moduleB.getScanner();
try {
moduleB.open(null);
projects[0].open(null);
// moduleC.open(null);
// when
// looking for it
// within project
final IErlElementLocator model = ErlangEngine.getInstance().getModel();
final IErlElement element1 = modelFindService.findTypeDef(model, projects[0],
moduleB, "bx", "concat_thing",
moduleB.getResource().getLocation().toPortableString(),
IErlElementLocator.Scope.PROJECT_ONLY);
// in other project but path given
final IErlElement element2 = modelFindService.findTypeDef(model, projects[1],
moduleB, "bx", "concat_thing",
moduleB.getResource().getLocation().toPortableString(),
IErlElementLocator.Scope.PROJECT_ONLY);
// in other project no path given, search all projects true
final IErlElement element3 = modelFindService.findTypeDef(model, projects[1],
moduleB, "bx", "concat_thing", null,
IErlElementLocator.Scope.ALL_PROJECTS);
// in other project no path given, search all projects false, ->
// null
final IErlElement element4 = modelFindService.findTypeDef(model, projects[1],
moduleB, "bx", "concat_thing", null,
IErlElementLocator.Scope.PROJECT_ONLY);
// then
// it should be returned if found
assertTrue(element1 instanceof IErlTypespec);
assertNull(element2);
assertTrue(element3 instanceof IErlTypespec);
assertNull(element4);
} finally {
scanner.dispose();
}
}
@Test
public void findExternalFunctionModuleTest() throws Exception {
// given
// a module with functions and functions
final IErlModule moduleD = ErlideTestUtils.createModule(projects[0], "d.erl",
"-module(d).\n-export([f/0]).\nf() ->\n ok.\ng() ->\n ?MODULE:f().\n");
moduleD.open(null);
// when
// looking for it with ?MODULE
final IErlElementLocator model = ErlangEngine.getInstance().getModel();
final IErlElement element1 = modelFindService.findFunction(model, projects[0],
moduleD, "?MODULE", null, new ErlangFunction("f", 0),
IErlElementLocator.Scope.PROJECT_ONLY);
// then
// it should be found
assertTrue(element1 instanceof IErlFunction);
}
@Test
public void findPreprocessorDefTest() throws Exception {
// given
// a module with includes and record
final IErlProject project = projects[0];
final IErlModule include = ErlideTestUtils.createInclude(project, "a.hrl",
"-record(rec1, {field, another=def}).\n-define(MACRO(A), lists:reverse(A)).\n");
final IErlModule module = ErlideTestUtils.createModule(project, "f.erl",
"-module(f).\n-include(\"a.hrl\").\n-export([f/0]).\n-record(rec2, {a, b}).\n"
+ "f() ->\n lists:reverse([1, 0]),\n lists:reverse([1, 0], [2]).\n");
module.open(null);
project.open(null);
final IErlPreprocessorDef preprocessorDef1 = modelFindService
.findPreprocessorDef(module, "rec1", ErlElementKind.RECORD_DEF);
final IErlPreprocessorDef preprocessorDef2 = modelFindService
.findPreprocessorDef(include, "rec1", ErlElementKind.RECORD_DEF);
final IErlPreprocessorDef preprocessorDef3 = modelFindService.findPreprocessorDef(
Arrays.asList(projects), "f.erl", "rec2", ErlElementKind.RECORD_DEF);
// then
// the record should be returned
assertNotNull(module);
assertNotNull(preprocessorDef1);
assertTrue(preprocessorDef1 instanceof IErlRecordDef);
assertEquals(preprocessorDef1, preprocessorDef2);
assertEquals(preprocessorDef1.getParent(), include);
assertNotNull(preprocessorDef3);
assertEquals(preprocessorDef3.getParent(), module);
}
@Test
public void findPreprocessorDefOtpIncludeTest() throws Exception {
// given
// a module with includes and record
final IErlProject project = projects[0];
final IErlModule module = ErlideTestUtils.createModule(project, "g.erl",
"-module(g).\n-include_lib(\"kernel/include/file.hrl\").\n-export([f/0]).\n-record(rec2, {a, b}).\n"
+ "f() ->\n lists:reverse([1, 0]),\n lists:reverse([1, 0], [2]).\n");
module.open(null);
// when
// looking for the record
final IErlPreprocessorDef preprocessorDef = modelFindService
.findPreprocessorDef(module, "file_info", ErlElementKind.RECORD_DEF);
// then
// the record should be returned
assertNotNull(module);
assertNotNull(preprocessorDef);
assertTrue(preprocessorDef instanceof IErlRecordDef);
assertEquals(ErlangEngine.getInstance().getModelUtilService()
.getProject(preprocessorDef), project);
}
private OtpErlangTuple makeTuple2(final String functionName, final int arity) {
return new OtpErlangTuple(new OtpErlangObject[] { new OtpErlangAtom(functionName),
new OtpErlangLong(arity) });
}
@Test
public void getPreprocessorDefs() throws Exception {
final IErlProject project = projects[0];
final IErlModule module = ErlideTestUtils.createModule(project, "a.erl",
"-module(g).\n" + "-include_lib(\"kernel/include/file.hrl\").\n"
+ "-export([f/0]).\n" + "-define(A(B), '++B++').\n"
+ "-record(rec2, {a, b}).\n" + "f() ->\n"
+ " lists:reverse([1, 0]),\n"
+ " lists:reverse([1, 0], [2]).\n");
module.open(null);
final List<IErlPreprocessorDef> macroDefs = modelUtilService
.getAllPreprocessorDefs(module, ErlElementKind.MACRO_DEF);
final List<IErlPreprocessorDef> recordDefs = modelUtilService
.getAllPreprocessorDefs(module, ErlElementKind.RECORD_DEF);
assertEquals(2, macroDefs.size());
assertEquals(3, recordDefs.size());
}
@Test
public void getExternalModuleWithPrefix() throws Exception {
File externalFile = null;
IErlProject project = null;
try {
// given
// an erlang project and an external file not in any project
final String projectName = "testproject";
project = ErlideTestUtils.createTmpErlProject(projectName);
final String externalFileName = "external.erl";
externalFile = ErlideTestUtils.createTmpFile(externalFileName,
"-module(external).\nf([_ | _]=L ->\n atom_to_list(L).\n");
final String absolutePath = externalFile.getAbsolutePath();
final String externalsFileName = "x.erlidex";
final File externalsFile = ErlideTestUtils.createTmpFile(externalsFileName,
absolutePath);
((ErlProject) project)
.setExternalModulesFile(externalsFile.getAbsolutePath());
project.open(null);
// when
// looking via prefix
final List<String> moduleNames0 = modelUtilService.findUnitsWithPrefix("ex",
project, false, false);
final List<String> modules1 = modelUtilService.findUnitsWithPrefix("ex",
project, true, false);
final List<String> listModules = modelUtilService.findUnitsWithPrefix("list",
project, true, false);
// then
// we should find it iff we check externals
assertEquals(0, moduleNames0.size());
assertEquals(1, modules1.size());
assertEquals(SystemConfiguration.withoutExtension(externalFileName),
modules1.get(0));
assertEquals(1, listModules.size());
assertEquals("lists", listModules.get(0));
} finally {
if (externalFile != null && externalFile.exists()) {
externalFile.delete();
}
if (project != null) {
ErlideTestUtils.deleteProject(project);
}
}
}
@Test
public void findExternalModuleFromPath() throws Exception {
File externalFile = null;
IErlProject project = null;
try {
// given
// an erlang project and an external file not in any project
final String projectName = "testproject";
project = ErlideTestUtils.createTmpErlProject(projectName);
final String externalFileName = "external.erl";
externalFile = ErlideTestUtils.createTmpFile(externalFileName,
"-module(external).\nf([_ | _]=L ->\n atom_to_list(L).\n");
final String absolutePath = externalFile.getAbsolutePath();
final String externalsFileName = "x.erlidex";
final File externalsFile = ErlideTestUtils.createTmpFile(externalsFileName,
absolutePath);
((ErlProject) project)
.setExternalModulesFile(externalsFile.getAbsolutePath());
project.open(null);
// when
// looking for it
final IErlElementLocator model = ErlangEngine.getInstance().getModel();
final IErlModule module = modelFindService.findModule(model, null, null,
absolutePath, IErlElementLocator.Scope.ALL_PROJECTS);
// then
// we should find it
assertNotNull(module);
assertEquals(externalFileName, module.getName());
} finally {
if (externalFile != null && externalFile.exists()) {
externalFile.delete();
}
if (project != null) {
ErlideTestUtils.deleteProject(project);
}
}
}
@Test
public void findExternalIncludeFromPath() throws Exception {
File externalFile = null;
IErlProject project = null;
try {
// given
// an erlang project and an external file not in any project
final String projectName = "testproject";
project = ErlideTestUtils.createTmpErlProject(projectName);
final String externalFileName = "external.hrl";
externalFile = ErlideTestUtils.createTmpFile(externalFileName,
"-module(external).\nf([_ | _]=L ->\n atom_to_list(L).\n");
final String absolutePath = externalFile.getAbsolutePath();
final String externalsFileName = "x.erlidex";
final File externalsFile = ErlideTestUtils.createTmpFile(externalsFileName,
absolutePath);
((ErlProject) project)
.setExternalIncludesFile(externalsFile.getAbsolutePath());
project.open(null);
// when
// looking for it
final IErlElementLocator model = ErlangEngine.getInstance().getModel();
final IErlModule module = modelFindService.findInclude(model, project, null,
externalFileName, absolutePath);
// then
// we should find it
assertNotNull(module);
assertEquals(externalFileName, module.getName());
} finally {
if (externalFile != null && externalFile.exists()) {
externalFile.delete();
}
if (project != null) {
ErlideTestUtils.deleteProject(project);
}
}
}
@Test
public void getModulesWithReferencedProjectsWithPrefix() throws Exception {
// given
// two erlang projects, the first references the second, second has
// an erlang module
final IProject project = projects[0].getWorkspaceProject();
final IProjectDescription description = project.getDescription();
final IProject[] refs = new IProject[] { projects[1].getWorkspaceProject() };
description.setReferencedProjects(refs);
project.setDescription(description, null);
final IErlModule module = ErlideTestUtils.createModule(projects[1], "abc.erl",
"-module(abc).\n-export(f/0)\nf() ->\n {abc, ok}.\n");
ErlideTestUtils.createModule(projects[0], "bbc.erl",
"-module(bbc).\n-export(f/0)\nf() ->\n {abc, ok}.\n");
// when
// looking for module with prefix, it should be found
final List<String> moduleNames = modelUtilService.findUnitsWithPrefix("a",
projects[0], false, false);
// then
// we should find it
assertNotNull(moduleNames);
assertEquals(1, moduleNames.size());
assertEquals(module.getModuleName(), moduleNames.get(0));
}
@Test
public void getModuleFromExternalModulePath() throws Exception {
File externalFile = null;
IErlProject project = null;
try {
// given
// an erlang project and an external file not in any project
final String projectName = "testproject";
project = ErlideTestUtils.createTmpErlProject(projectName);
final String externalFileName = "external.erl";
externalFile = ErlideTestUtils.createTmpFile(externalFileName,
"-module(external).\nf([_ | _]=L ->\n atom_to_list(L).\n");
final String absolutePath = externalFile.getAbsolutePath();
final String externalsFileName = "x.erlidex";
final File externalsFile = ErlideTestUtils.createTmpFile(externalsFileName,
absolutePath);
((ErlProject) project)
.setExternalModulesFile(externalsFile.getAbsolutePath());
project.open(null);
// when
// looking for it with its external module path
final IErlModel model = ErlangEngine.getInstance().getModel();
final IErlModule module = modelFindService.findModule(model, null, null,
absolutePath, IErlElementLocator.Scope.ALL_PROJECTS);
assertNotNull(module);
final String externalModulePath = ErlangEngine.getInstance()
.getModelUtilService().getExternalModulePath(model, module);
ErlLogger.debug(" >> %s", externalModulePath);
final IErlModule module2 = modelUtilService
.getModuleFromExternalModulePath(model, externalModulePath);
// then
// we should find it
assertNotNull(module2);
assertEquals(externalFileName, module.getName());
assertEquals(module, module2);
} finally {
if (externalFile != null && externalFile.exists()) {
externalFile.delete();
}
if (project != null) {
ErlideTestUtils.deleteProject(project);
}
}
}
@Test
public void findTypespec() throws Exception {
// given
// a project with a module and an include with a typespec
final IErlProject project = projects[0];
final String includeName = "a.hrl";
final IErlModule include = ErlideTestUtils.createModule(project, includeName,
"-type date() :: {pos_integer(), pos_integer(), pos_integer()}.\n");
include.open(null);
final IErlModule module = ErlideTestUtils.createModule(project, "f.erl",
"-module(f).\n-include(\"a.hrl\").\n-export([f/0]).\n-record(rec2, {a, b}).\n"
+ "f() ->\n lists:reverse([1, 0]),\n lists:reverse([1, 0], [2]).\n");
module.open(null);
// when
// looking for the typespec
final IErlTypespec typespec = modelFindService.findTypespec(module, "date");
// then
// it should be found
assertNotNull(typespec);
assertEquals(typespec.getParent(), include);
}
@Test
public void findPreprocessorDefExternalIncludeOnIncludePathTest() throws Exception {
File externalInclude = null;
IErlProject project = null;
// given
// a project with an include dir outside the model, the include file
// contains a record def
try {
// ErlModelCache.getDefault().setNoModelCache(true);
// ErlModelCache.getDefault().clearModelCache();
final String projectName = "testprojectx";
project = ErlideTestUtils
.createProject(ErlideTestUtils.getTmpPath(projectName), projectName);
final IErlModule module = ErlideTestUtils.createModule(project, "a.erl",
"-include(\"x.hrl\").\n");
final String includeName = "x.hrl";
externalInclude = ErlideTestUtils.createTmpFile(includeName,
"-record(rec2, {field, another=def}.");
final String includePath = externalInclude.getAbsolutePath();
final IPath p = new Path(includePath).removeLastSegments(1);
((ErlProject) project).setIncludeDirs(Lists.newArrayList(p));
project.open(null);
// when
// looking for the record def
final IErlPreprocessorDef preprocessorDef = modelFindService
.findPreprocessorDef(module, "rec2", ErlElementKind.RECORD_DEF);
final Collection<IErlProject> myprojects = Lists.newArrayList(project);
ErlangEngine.getInstance().getModelFindService().findPreprocessorDef(
myprojects, "a.erl", "rec2", ErlElementKind.RECORD_DEF);
// then
// it should be found
assertNotNull(preprocessorDef);
} finally {
if (project != null) {
ErlideTestUtils.deleteProject(project);
}
if (externalInclude != null && externalInclude.exists()) {
externalInclude.delete();
}
// ErlModelCache.getDefault().setNoModelCache(false);
}
}
@Test
public void findPreprocessorDefExternalIncludePathTest() throws Exception {
File externalInclude = null;
IErlProject project = null;
// given
// a project with an include dir outside the model, the include file
// contains a record def
try {
final String projectName = "testprojectx";
project = ErlideTestUtils
.createProject(ErlideTestUtils.getTmpPath(projectName), projectName);
final IErlModule module = ErlideTestUtils.createModule(project, "a.erl",
"-include(\"x.hrl\").\n");
final String includeName = "x.hrl";
externalInclude = ErlideTestUtils.createTmpFile(includeName,
"-record(rec2, {field, another=def}.");
final String includePath = externalInclude.getAbsolutePath();
final String externalsFileName = "x.erlidex";
final File externalsFile = ErlideTestUtils.createTmpFile(externalsFileName,
includePath);
((ErlProject) project)
.setExternalIncludesFile(externalsFile.getAbsolutePath());
project.open(null);
// when
// looking for the record def
final IErlPreprocessorDef preprocessorDef = modelFindService
.findPreprocessorDef(module, "rec2", ErlElementKind.RECORD_DEF);
final Collection<IErlProject> myprojects = Lists.newArrayList(project);
modelFindService.findPreprocessorDef(myprojects, "a.erl", "rec2",
ErlElementKind.RECORD_DEF);
// then
// it should be found
assertNotNull(preprocessorDef);
} finally {
if (project != null) {
ErlideTestUtils.deleteProject(project);
}
if (externalInclude != null && externalInclude.exists()) {
externalInclude.delete();
}
}
}
}