View Javadoc
1   /*******************************************************************************
2    * Copyright (c) 2017 CEA LIST, Zeligsoft
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Eclipse Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/epl-v10.html
7    *
8    * Contributors:
9    *     CEA LIST - initial API and implementation
10   *     Based on work from Zeligsoft (in context of C++ test suite)
11   *
12   *******************************************************************************/
13  
14  package org.eclipse.papyrus.designer.languages.common.testutils;
15  
16  import static org.hamcrest.MatcherAssert.assertThat;
17  import static org.junit.Assert.assertNotNull;
18  import static org.junit.Assert.assertTrue;
19  import static org.junit.Assert.fail;
20  
21  import java.io.InputStream;
22  import java.util.Scanner;
23  
24  import org.eclipse.core.resources.IFile;
25  import org.eclipse.core.resources.IFolder;
26  import org.eclipse.core.resources.IProject;
27  import org.eclipse.core.resources.IResource;
28  import org.eclipse.core.resources.ResourcesPlugin;
29  import org.eclipse.core.runtime.CoreException;
30  
31  @SuppressWarnings("nls")
32  public class FileComparison {
33  
34  	/**
35  	 * Compare the files in folder with what we expect to see. When comparing
36  	 * file content, filter out whitespace which will replace all whitespace
37  	 * with a single space in the actual file content and the expected file
38  	 * content in order to avoid problems with differences caused by code
39  	 * formatting options where the test suite is run. Then a simple string
40  	 * comparison is done.
41  	 * 
42  	 * @param generatedFolder
43  	 *            the generated folder
44  	 * @param modelProject
45  	 *            the project containing the model
46  	 * @param fileName
47  	 *            the filename to compare
48  	 * @param depthSegments
49  	 *            hierarchical folders, if any
50  	 * @throws Exception
51  	 */
52  	public static void assertGeneratedMatchesExpected(IFolder generatedFolder, IProject modelProject, String fileName, String... depthSegments) throws Exception {
53  		assertTrue("Default generated folder \"" + generatedFolder + "\" was not generated", generatedFolder.exists());
54  
55  		// test generated folder
56  		IFolder generatedPackageFolder = null;
57  		for (int i = 0; i < depthSegments.length; i++) {
58  			if (i == 0) {
59  				generatedPackageFolder = generatedFolder.getFolder(depthSegments[i]);
60  			} else {
61  				generatedPackageFolder = generatedPackageFolder.getFolder(depthSegments[i]);
62  			}
63  			assertTrue("Package folder \"" + depthSegments[i] + "\" was not generated.", generatedPackageFolder.exists());
64  		}
65  
66  		// test generated file
67  		IFile generatedFile = null;
68  		if (generatedPackageFolder != null) {
69  			generatedFile = generatedPackageFolder.getFile(fileName);
70  		} else {
71  			generatedFile = generatedFolder.getFile(fileName);
72  		}
73  		assertTrue("File " + fileName + " was not generated.", generatedFile.exists());
74  		String fileContent = getFileContents(generatedFile);
75  
76  
77  		// test expected folder
78  		IFolder expectedFolder = null;
79  		for (int i = 0; i < depthSegments.length; i++) {
80  			
81  			if (i == 0) {
82  				expectedFolder = modelProject.getFolder(depthSegments[i]);
83  			} else {
84  				expectedFolder = expectedFolder.getFolder(depthSegments[i]);
85  			}
86  			assertTrue("Expected folder \"" + depthSegments[i] + "\" does not exist.", expectedFolder.exists());
87  		}
88  
89  		// test expected file
90  		IFile expectedFile = null;
91  		if (expectedFolder != null) {
92  			expectedFile = expectedFolder.getFile(fileName);
93  		} else {
94  			expectedFile = modelProject.getFile(fileName);
95  		}
96  		assertTrue("Expected file " + fileName + " does not exist.", expectedFile.exists());
97  		String expectedFileContent = getFileContents(expectedFile);
98  
99  		assertContentMatches(fileName, fileContent, expectedFileContent);
100 	}
101 
102 	public static void assertGeneratedMatchesExpected(IFolder generatedFolder, IFolder expectedFolder) {
103 		try {
104 			for (IResource memberExp : expectedFolder.members()) {
105 				IResource memberGen = generatedFolder.findMember(memberExp.getName());
106 				assertThat(String.format("expected file or folder \"%s\" does not exist in generated code", memberExp.getName()), memberGen != null);
107 				if (memberGen instanceof IFile) {
108 					assertThat("expected resource exists, but is not a file in generated code", memberGen instanceof IFile);
109 					String generatedFileContent = getFileContents((IFile) memberGen);
110 					String expectedFileContent = getFileContents((IFile) memberExp);
111 
112 					assertContentMatches(memberGen.getName(), generatedFileContent, expectedFileContent);
113 				}
114 				else if (memberGen instanceof IFolder) {
115 					assertThat("expected resource exists, but is not a folder in generated code", memberGen instanceof IFolder);
116 					assertGeneratedMatchesExpected((IFolder) memberGen, (IFolder) memberExp);
117 				}
118 			}
119 		} catch (CoreException e) {
120 			fail(e.getMessage());
121 		}
122 	}
123 	
124 	public static IProject getGeneratedProject(String genProjectName) {
125 
126 		IProject genProject = ResourcesPlugin.getWorkspace().getRoot().getProject(genProjectName);
127 		if(genProject == null || !genProject.exists()) {
128 			throw new AssertionError("Generated project not found");
129 		}
130 
131 		return genProject;
132 	}
133 
134 	
135 	public static String getFileContents(IFile file) throws CoreException {
136 		InputStream inStream = file.getContents();
137 		assertNotNull("Contents of file \"" + file.getName() + "\" are empty.", inStream);
138 		String content = null;
139 		Scanner s = new Scanner(inStream);
140 
141 		s.useDelimiter("\\Z");
142 
143 		content = s.hasNext() ? s.next() : "";
144 		s.close();
145 
146 		return content;// == null ? null : content.replaceAll("\\s+", " ").trim();
147 	}
148 
149 	public static void assertContentMatches(String filename, String generated, String expected) {
150 		Scanner expectedScanner = new Scanner(expected);
151 		char[] strippedGen = generated.replaceAll("\\s+", "").trim().toCharArray();
152 		int genCharsTraversed = 0;
153 		boolean outofchars = false;
154 
155 		/*
156 		 * line by line in expected
157 		 * char by char in generated
158 		 * compare char by char expected to generated until no more chars in line
159 		 * if not matching then print line expected against line generated by
160 		 * keeping track of the amount of chars traversed, then traverse the
161 		 * generated with white characters
162 		 */
163 		try {
164 			int lineNumber = 1;
165 			int lineCharBegin = 0;
166 			for (; !outofchars && expectedScanner.hasNextLine(); ++lineNumber) {
167 				lineCharBegin = genCharsTraversed;
168 				String eLine = expectedScanner.nextLine();
169 				String strippedELine = eLine.replaceAll("\\s+", "").trim();
170 				char[] strippedExpected = strippedELine.toCharArray();
171 				for (int i = 0; i < strippedExpected.length; i++) {
172 					if (strippedExpected[i] != strippedGen[genCharsTraversed]) {
173 						fail(filename + ':' + lineNumber + "expected '" + eLine.trim() + "'but found '" + rebuildStringForLineError(generated.trim(), eLine.trim(), i, genCharsTraversed, lineCharBegin) + "'");
174 					}
175 					genCharsTraversed++;
176 					if (genCharsTraversed == strippedGen.length) {
177 						outofchars = true;
178 					}
179 				}
180 			}
181 			if (expectedScanner.hasNextLine()) {
182 				fail(filename + ':' + lineNumber + " expected '" + expectedScanner.nextLine() + "' but found end-of-file");
183 			} else if (!outofchars) {
184 				fail(filename + ':' + lineNumber + " expected end-of-file but found '" + rebuildStringForEndOfFileError(generated.trim(), genCharsTraversed) + '\'');
185 			}
186 		} finally {
187 			if (expectedScanner != null) {
188 				expectedScanner.close();
189 			}
190 		}
191 	}
192 
193 	private static String rebuildStringForLineError(String generatedString, String expectedLine, int beginInExpectedLine, int genCharsTraversed, int firstCharInExpLine) {
194 		String brokenLine = "";
195 
196 		int lengthFromFirstDiff = expectedLine.replaceAll("\\s+", "").length() - beginInExpectedLine;
197 		char[] generatedChars = generatedString.replaceAll("\\s+", " ").toCharArray();
198 		int nonwhitechars = 0;
199 		for (int i = 0; i < generatedChars.length; i++) {
200 			if (generatedChars[i] != ' ') {
201 				nonwhitechars++;
202 			}
203 			if (nonwhitechars >= firstCharInExpLine && nonwhitechars < genCharsTraversed + lengthFromFirstDiff) {
204 				// start copying
205 				brokenLine += generatedChars[i];
206 			} else if (nonwhitechars == genCharsTraversed + lengthFromFirstDiff) {
207 				// copy number of characters for the length of the expected line
208 				if (generatedChars[i + 1] != '\0') {
209 					brokenLine += "...";
210 				}
211 				break;
212 			}
213 		}
214 
215 		return brokenLine;
216 	}
217 
218 	private static String rebuildStringForEndOfFileError(String generatedString, int genCharsTraversed) {
219 		String brokenLine = "";
220 
221 		char[] generatedChars = generatedString.replaceAll("\\s+", " ").toCharArray();
222 		int nonwhitechars = 0;
223 		for (int i = 0; i < generatedChars.length; i++) {
224 			if (generatedChars[i] != ' ') {
225 				nonwhitechars++;
226 			}
227 			if (nonwhitechars > genCharsTraversed && generatedChars[i] != '\0') {
228 				// start copying
229 				brokenLine += generatedChars[i];
230 			} else if (nonwhitechars == genCharsTraversed + 15 || generatedChars[i] == '\0') {
231 				// copy only 15 chars
232 				if (generatedChars[i + 1] != '\0') {
233 					brokenLine += "...";
234 				}
235 				break;
236 			}
237 		}
238 		return brokenLine;
239 	}
240 }