package org.teiid.designer.core.workspace; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNull.nullValue; import static org.hamcrest.core.IsNull.notNullValue; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.stubVoid; import static org.mockito.Mockito.when; import java.io.File; import java.util.ArrayList; import java.util.List; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.Matchers; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.teiid.core.designer.EclipseMock; import org.teiid.core.designer.util.FileUtils; import org.teiid.designer.core.ModelWorkspaceMock; import org.teiid.designer.core.ModelerCore; public final class WorkspaceResourceFinderUtilTest { private static final String NAME = "MyModel"; private IResource model; private IProject modelProject; private ModelWorkspaceMock modelWorkspaceMock; private List<IResource> resources = new ArrayList<IResource>(); @After public void afterEach() throws Exception { this.modelWorkspaceMock.dispose(); this.resources.clear(); } @SuppressWarnings( "deprecation" ) @Before public void beforeEach() throws Exception { final EclipseMock eclipseMock = new EclipseMock(); this.modelWorkspaceMock = new ModelWorkspaceMock(eclipseMock); this.modelProject = mock(IProject.class); eclipseMock.addProject(this.modelProject); when(this.modelProject.isOpen()).thenReturn(true); when(this.modelProject.getProject()).thenReturn(this.modelProject); when(this.modelProject.hasNature(ModelerCore.NATURE_ID)).thenReturn(true); when(this.modelProject.members()).thenReturn(new IResource[0]); // add the workspace resources to the visitor stubVoid(this.modelProject).toAnswer(new Answer<Void>() { @Override public Void answer(final InvocationOnMock invocation) throws Throwable { final Object[] args = invocation.getArguments(); final IResourceVisitor visitor = (IResourceVisitor)args[0]; // add each resource to the visitor for (final IResource resource : getResources()) { visitor.visit(resource); } return null; } }).on().accept(Matchers.<IResourceVisitor>anyVararg()); { // .project file final File dotFile = File.createTempFile("dotFile", ".project"); dotFile.deleteOnExit(); final IPath path = new Path(dotFile.getAbsolutePath()); final IFile dotIfile = mock(IFile.class); when(dotIfile.getName()).thenReturn(".project"); when(dotIfile.getType()).thenReturn(IResource.FILE); when(dotIfile.isAccessible()).thenReturn(true); when(dotIfile.getLocation()).thenReturn(path); when(dotIfile.getProject()).thenReturn(this.modelProject); when(this.modelProject.getFile(DotProjectUtils.DOT_PROJECT)).thenReturn(dotIfile); } this.model = createFile(NAME); } List<IResource> getResources() { return this.resources; } IWorkspaceRoot getWorkspaceRoot() { return this.modelWorkspaceMock.getEclipseMock().workspaceRoot(); } @Test public void shouldNotHaveCircularDependenciesWhenNoDependents() { assertThat(WorkspaceResourceFinderUtil.getFirstResourceHavingCircularDependency(this.model), is(nullValue())); } @Test public void shouldHaveCircularDependencies() throws Exception { // this.model depends on aaa, aaa depends on bbb, bbb depends on this.model final IFile aaa = createFile("aaa"); final IFile bbb = createFile("bbb"); final String modelHeader = createXmiHeader(aaa.getName()); writeFile(this.model.getRawLocation().toFile(), modelHeader); final String aaaHeader = createXmiHeader(bbb.getName()); writeFile(aaa.getRawLocation().toFile(), aaaHeader); final String bbbHeader = createXmiHeader(this.model.getName()); writeFile(bbb.getRawLocation().toFile(), bbbHeader); assertThat(WorkspaceResourceFinderUtil.getFirstResourceHavingCircularDependency(this.model), is(notNullValue())); } @Test public void shouldNotHaveCircularDependencies() throws Exception { // this.model depends on aaa final IFile aaa = createFile("aaa"); final String modelHeader = createXmiHeader(aaa.getName()); writeFile(this.model.getRawLocation().toFile(), modelHeader); assertThat(WorkspaceResourceFinderUtil.getFirstResourceHavingCircularDependency(this.model), is(nullValue())); } private static void writeFile(final File file, final String content) throws Exception { FileUtils.write(content.getBytes(), file); } private IFile createFile(final String name) throws Exception { final File file = File.createTempFile(name, ".xmi"); file.deleteOnExit(); final IPath path = new Path(file.getAbsolutePath()); final IFile iFile = mock(IFile.class); when(iFile.getName()).thenReturn(file.getName()); when(iFile.getLocation()).thenReturn(path); when(iFile.getRawLocation()).thenReturn(path); when(iFile.getFullPath()).thenReturn(path); when(iFile.exists()).thenReturn(true); when(iFile.getType()).thenReturn(IResource.FILE); when(iFile.getProject()).thenReturn(this.modelProject); this.resources.add(iFile); when(this.modelProject.members()).thenReturn(this.resources.toArray(new IResource[this.resources.size()])); when(this.modelProject.findMember(path)).thenReturn(iFile); when(this.modelProject.findMember(path.toString())).thenReturn(iFile); return iFile; } private String createXmiHeader(final String... modelsToImport) { final StringBuilder builder = new StringBuilder(); builder.append("<?xml version=\"1.0\" encoding=\"ASCII\"?> <xmi:XMI xmi:version=\"2.0\" xmlns:xmi=\"http://www.omg.org/XMI\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:diagram=\"http://www.metamatrix.com/metamodels/Diagram\" xmlns:mmcore=\"http://www.metamatrix.com/metamodels/Core\" xmlns:mmws=\"http://www.metamatrix.com/metamodels/WebService\" xmlns:transformation=\"http://www.metamatrix.com/metamodels/Transformation\">"); builder.append("<mmcore:ModelAnnotation xmi:uuid=\"mmuuid:ae435d62-1cff-4038-ae14-4a5fdf5fd417\" primaryMetamodelUri=\"http://www.metamatrix.com/metamodels/WebService\" modelType=\"VIRTUAL\" ProducerName=\"Teiid Designer\" ProducerVersion=\"9.2.0\">"); int i = 0; if ((modelsToImport != null) && (modelsToImport.length != 0)) { for (final String model : modelsToImport) { final String modelName = model.substring(0, model.indexOf(".xmi")); builder.append("<modelImports xmi:uuid=\"mmuuid:96eda359-0832-46e7-9e33-c878a3603dc").append(i).append("\" "); builder.append("name=\"").append(modelName).append("\" modelLocation=\"").append(model).append("\" uuid=\"mmuuid:88b08082-c021-4c3a-a4a3-148f5e58dc3").append(i).append("\" "); builder.append("modelType=\"VIRTUAL\" primaryMetamodelUri=\"http://www.metamatrix.com/metamodels/XmlDocument\"/>"); ++i; } } builder.append("</mmcore:ModelAnnotation>"); builder.append("</xmi:XMI>"); return builder.toString(); } }