/******************************************************************************* * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com> * Copyright (C) 2010, Jens Baumgart <jens.baumgart@sap.com> * Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com> * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package org.jboss.tools.openshift.egit.internal.test.util; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.egit.core.project.RepositoryMapping; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FileUtils; public class TestUtils { public final static String AUTHOR = "The Author <The.author@some.com>"; public final static String COMMITTER = "The Commiter <The.committer@some.com>"; /** * Create a "temporary" directory * * @param name * the name of the directory * @return a directory as child of a "temporary" folder in the user home * directory; may or may not exist * @throws IOException */ public File createTempDir(String name) throws IOException { File userHome = FS.DETECTED.userHome(); File rootDir = new File(userHome, "EGitCoreTestTempDir"); File result = new File(rootDir, name); if (result.exists()) FileUtils.delete(result, FileUtils.RECURSIVE | FileUtils.RETRY); return result; } public static File createGitDir(TestProject testProject) throws IOException { return new File(testProject.getProject().getLocation().toFile(), Constants.DOT_GIT); } /** * Cleanup: delete the "temporary" folder and all children * * @throws IOException */ public void deleteTempDirs() throws IOException { File userHome = FS.DETECTED.userHome(); File rootDir = new File(userHome, "EGitCoreTestTempDir"); if (rootDir.exists()) FileUtils.delete(rootDir, FileUtils.RECURSIVE | FileUtils.RETRY); } /** * Read the stream into a String * * @param inputStream * @return the contents of the stream * @throws IOException */ public String slurpAndClose(InputStream inputStream) throws IOException { StringBuilder stringBuilder = new StringBuilder(); try { int ch; while ((ch = inputStream.read()) != -1) { stringBuilder.append((char) ch); } } finally { inputStream.close(); } return stringBuilder.toString(); } /** * Add a file to an existing project * * @param project * the project * @param path * e.g. "folder1/folder2/test.txt" * @param content * the contents * @return the file * @throws Exception * if the file can not be created */ public IFile addFileToProject(IProject project, String path, String content) throws Exception { IPath filePath = new Path(path); IFolder folder = null; for (int i = 0; i < filePath.segmentCount() - 1; i++) { if (folder == null) { folder = project.getFolder(filePath.segment(i)); } else { folder = folder.getFolder(filePath.segment(i)); } if (!folder.exists()) folder.create(false, true, null); } IFile file = project.getFile(filePath); file.create(new ByteArrayInputStream(content.getBytes(project .getDefaultCharset())), true, null); return file; } /** * Change the content of a file * * @param project * @param file * @param newContent * @return the file * @throws Exception */ public IFile changeContentOfFile(IProject project, IFile file, String newContent) throws Exception { file.setContents(new ByteArrayInputStream(newContent.getBytes(project .getDefaultCharset())), 0, null); return file; } /** * Create a project in the local file system * * @param parentFile * the parent * @param projectName * project name * @return the project with a location pointing to the local file system * @throws Exception */ public IProject createProjectInLocalFileSystem(File parentFile, String projectName) throws Exception { IProject project = ResourcesPlugin.getWorkspace().getRoot() .getProject(projectName); if (project.exists()) { project.delete(true, null); } File testFile = new File(parentFile, projectName); if (testFile.exists()) FileUtils.delete(testFile, FileUtils.RECURSIVE | FileUtils.RETRY); IProjectDescription desc = ResourcesPlugin.getWorkspace() .newProjectDescription(projectName); desc.setLocation(new Path(new File(parentFile, projectName).getPath())); project.create(desc, null); project.open(null); return project; } /** * verifies that repository contains exactly the given files. * * @param repository * @param paths * @throws Exception */ public void assertRepositoryExactlyContains(Repository repository, String... paths) throws Exception { RepoDiff repoDiff = createRepoDiff(repository, paths); if (repoDiff.hasUnexpected()) { fail(repoDiff.getUnexpectedFiles()); } if (repoDiff.hasMissing()) { fail(repoDiff.getUnexpectedFiles()); } } public void assertRepositoryMisses(Repository repository, String... paths) throws Exception { RepoDiff repoDiff = createRepoDiff(repository, paths); for (String missingPath : paths) { assertTrue(repoDiff.getMissing().contains(missingPath)); } } /** * verifies that repository contains exactly the given files. * * @param repository * @param paths * @throws Exception */ private RepoDiff createRepoDiff(Repository repository, String... expectedPaths) throws Exception { RepoDiff repoDiff = new RepoDiff(); Set<String> expectedFiles = new HashSet<>(Arrays.asList(expectedPaths)); TreeWalk treeWalk = new TreeWalk(repository); treeWalk.addTree(repository.resolve("HEAD^{tree}")); treeWalk.setRecursive(true); while (treeWalk.next()) { String path = treeWalk.getPathString(); if (!expectedFiles.contains(path)) { repoDiff.addUnexpected(path); } expectedFiles.remove(path); } repoDiff.addAllMissing(expectedFiles); return repoDiff; } public class RepoDiff { private List<String> unexpected = new ArrayList<>(); private List<String> missing = new ArrayList<>(); public void addMissing(String path) { missing.add(path); } public void addAllMissing(Collection<String> paths) { missing.addAll(paths); } public List<String> getMissing() { return missing; } public boolean hasMissing() { return !missing.isEmpty(); } public String getMissingFiles() { StringBuilder builder = new StringBuilder("Repository is nissing files: "); for (String missingPath : getMissing()) { builder.append(missingPath).append(','); } return builder.toString(); } public void addUnexpected(String path) { unexpected.add(path); } public List<String> getUnexpected() { return unexpected; } public boolean hasUnexpected() { return !unexpected.isEmpty(); } public String getUnexpectedFiles() { StringBuilder builder = new StringBuilder("Repository contains unexpected expected files: "); for (String unexpectedPath : getUnexpected()) { builder.append(unexpectedPath).append(','); } return builder.toString(); } } /** * verifies that repository contains the given files (and eventually others) * with the given content. Usage example:<br> * * <code> * assertRepositoryContainsFiles(repository, "foo/a.txt", "content of A", * "foo/b.txt", "content of B") * </code> * * @param repository * @param fileContentToubles * @throws Exception * * @see #assertRepositoryContainsExactlyFilesWithContent */ public void assertRepositoryContainsFilesWithContent(Repository repository, String... fileContentToubles) throws Exception { HashMap<String, String> expectedfiles = mkmap(fileContentToubles); visitRepository(new Expectation(expectedfiles), repository); } private static class ExactExpectation implements GitRepoVisitor { private Map<String, String> expectedFiles; ExactExpectation(Map<String, String> expectedFiles) { this.expectedFiles = expectedFiles; } @Override public void visit(TreeWalk treeWalk) throws Exception { String path = treeWalk.getPathString(); assertTrue(expectedFiles.containsKey(path)); ObjectId objectId = treeWalk.getObjectId(0); byte[] expectedContent = expectedFiles.get(path).getBytes(); byte[] repoContent = treeWalk.getObjectReader().open(objectId) .getBytes(); if (!Arrays.equals(repoContent, expectedContent)) { fail("File " + path + " has repository content " + new String(repoContent) + " instead of expected content " + new String(expectedContent)); } expectedFiles.remove(path); } } private static class Expectation implements GitRepoVisitor { private Map<String, String> expectedFiles; Expectation(Map<String, String> expectedFiles) { this.expectedFiles = expectedFiles; } @Override public void visit(TreeWalk treeWalk) throws Exception { String path = treeWalk.getPathString(); if (!expectedFiles.containsKey(path)) { return; } byte[] expectedContent = expectedFiles.get(path).getBytes(); ObjectId objectId = treeWalk.getObjectId(0); byte[] repoContent = treeWalk.getObjectReader().open(objectId).getBytes(); if (!Arrays.equals(repoContent, expectedContent)) { fail("File " + path + " has repository content " + new String(repoContent) + " instead of expected content " + new String(expectedContent)); } expectedFiles.remove(path); } } private static interface GitRepoVisitor { public void visit(TreeWalk treeWalk) throws Exception; } private void visitRepository(GitRepoVisitor visitor, Repository repository) throws Exception { TreeWalk treeWalk = new TreeWalk(repository); treeWalk.addTree(repository.resolve("HEAD^{tree}")); treeWalk.setRecursive(true); while (treeWalk.next()) { visitor.visit(treeWalk); } } private static HashMap<String, String> mkmap(String... args) { if ((args.length % 2) > 0) throw new IllegalArgumentException("needs to be filepath/content pairs"); HashMap<String, String> map = new HashMap<>(); for (int i = 0; i < args.length; i += 2) { map.put(args[i], args[i + 1]); } return map; } public String getPathInRepository(IResource resource) { RepositoryMapping mapping = RepositoryMapping.getMapping(resource); if (mapping == null) { throw new IllegalArgumentException(resource + " is not in any repository"); } return mapping.getRepoRelativePath(resource); } }