Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: b3fafa92fbe37a4112ab6c47089bf29e685a93e4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/*******************************************************************************
 * Copyright (c) 2008, 2016 Institute for Software, HSR Hochschule fuer Technik 
 * Rapperswil, University of applied sciences and others
 *
 * This program and the accompanying materials 
 * are made available under the terms of the Eclipse Public License 2.0 
 * which accompanies this distribution, and is available at 
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0  
 * 
 * Contributors: 
 *     Institute for Software - initial API and implementation 
 ******************************************************************************/
package org.eclipse.cdt.core.parser.tests.rewrite.comenthandler;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.IASTComment;
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.parser.tests.rewrite.RewriteBaseTest;
import org.eclipse.cdt.core.parser.tests.rewrite.TestSourceFile;
import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.ASTCommenter;
import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.NodeCommentMap;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;

/**
 * This test tests the behavior of the class ASTCommenter. It checks if the ASTCommenter assigns
 * the comments contained in an AST to the right ASTNodes.<br>
 * The source for the CommentHandling tests is located at
 * /resources/rewrite/CommentHandlingTestSource.rts.<br>
 * This file contains the source code and the expected output for all the tests.
 * Following a little example how such a test looks like:<br><br>
 * 
 * <code><pre>
 * //!NameOfTheTest - will be used as JUnit test name
 * //#org.eclipse.cdt.core.parser.tests.rewrite.comenthandler.CommentHandlingTest
 * //@NameOfASourceFile.h
 * class myTestClass
 * {
 *  //myLeadingComment
 *  void aMethod(); //myTrailingComment
 *  //myFreestandingComment
 *  //myFreestandingComment2
 * };
 * 
 * //=
 * =>leading
 * void aMethod(); = //myLeadingComment
 * 
 * =>trailing
 * void aMethod(); = //myTrailingComment
 * 
 * =>freestanding
 * void aMethod(); = //myFreestandingComment , //myFreestandingComment2
 * </pre></code>
 * 
 * The second line (//#org.eclipse.cdt...) indicates the test class (in this case this class).<br>
 * The "//=" indicates the beginning of the expected test result.<br>
 * The test result contains three sections (separated by "=>leading", "=>trailing" and
 * "=>freestanding").<br>
 * Each section contains the raw signature of the node to which a comment is assigned plus " = "
 * and the comment. If there are several comments assigned to the same node they are concatenated
 * with a " , ".
 * 
 * @author Guido Zgraggen IFS, Lukas Felber IFS
 */
public class CommentHandlingTest extends RewriteBaseTest {
	private static final String ANY_CHAR_REGEXP = "(.*)"; //$NON-NLS-1$
	private static final String SEPARATOR = System.getProperty("line.separator"); //$NON-NLS-1$

	private static final String LEADING_COMMENT_SEPARATOR = "=>leading"; //$NON-NLS-1$
	private static final String TRAILING_COMMENT_SEPARATOR = "=>trailing"; //$NON-NLS-1$
	private static final String FREESTANDING_COMMENT_SEPARATOR = "=>freestanding"; //$NON-NLS-1$

	private static final String LEADING_COMMENT_TITLE = "<<<=== Leading Comment Test Section ===>>>"; //$NON-NLS-1$
	private static final String TRAILING_COMMENT_TITLE = "<<<=== Trailing Comment Test Section ===>>>"; //$NON-NLS-1$
	private static final String FREESTANDING_COMMENT_TITLE = "<<<=== Freestanding Comment Test Section ===>>>"; //$NON-NLS-1$
	
	public CommentHandlingTest(String name, List<TestSourceFile> files) {
		super(name, files);
	}

	@Override
	protected void runTest() throws Throwable {
		if (fileMap.isEmpty()) {
			fail("No file for testing"); //$NON-NLS-1$
		}
		
		for (String fileName : fileMap.keySet()) {
			TestSourceFile file = fileMap.get(fileName);
			NodeCommentMap nodeMap = getNodeMapForFile(fileName);
			assertEquals(buildExpectedResult(file).toString(), buildActualResult(nodeMap).toString());
		}
	}

	protected NodeCommentMap getNodeMapForFile(String fileName) throws Exception {
		return ASTCommenter.getCommentedNodeMap(getUnit(fileName));
	}

	private StringBuilder buildExpectedResult(TestSourceFile file) {
		Matcher matcher = Pattern.compile(CommentHandlingTest.getSeparatingRegexp(),
				Pattern.MULTILINE | Pattern.DOTALL).matcher(file.getExpectedSource());
		if (!matcher.find()) {
			fail("Missing expected section. Expected result code must be of the following format:\n\"=>leading\n...\n=>trailing\n...\n=>freestanding\""); //$NON-NLS-1$
		}
		StringBuilder expectedResultBuilder = new StringBuilder();
		
		String leadingResult = matcher.group(1);
		String trailingResult = matcher.group(2);
		String freestandingResult = matcher.group(3);
		
		appendLineTrimmed(expectedResultBuilder, LEADING_COMMENT_TITLE);
		appendLineTrimmed(expectedResultBuilder, leadingResult);
		appendLineTrimmed(expectedResultBuilder, TRAILING_COMMENT_TITLE);
		appendLineTrimmed(expectedResultBuilder, trailingResult);
		appendLineTrimmed(expectedResultBuilder, FREESTANDING_COMMENT_TITLE);
		appendLineTrimmed(expectedResultBuilder, freestandingResult);

		return expectedResultBuilder;
	}

	private StringBuilder buildActualResult(NodeCommentMap nodeMap) {
		StringBuilder actualResultBuilder = new StringBuilder();
		appendLineTrimmed(actualResultBuilder, LEADING_COMMENT_TITLE);
		appendLineTrimmed(actualResultBuilder, getCommentMapResult(nodeMap.getLeadingMap()));
		appendLineTrimmed(actualResultBuilder, TRAILING_COMMENT_TITLE);
		appendLineTrimmed(actualResultBuilder, getCommentMapResult(nodeMap.getTrailingMap()));
		appendLineTrimmed(actualResultBuilder, FREESTANDING_COMMENT_TITLE);
		appendLineTrimmed(actualResultBuilder, getCommentMapResult(nodeMap.getFreestandingMap()));
		return actualResultBuilder;
	}

	private String getCommentMapResult(Map<IASTNode, List<IASTComment>> map) {
		TreeSet<IASTNode> keyTree = new TreeSet<IASTNode>(new NodeOffsetComparator());
		keyTree.addAll(map.keySet());
		StringBuilder output = new StringBuilder();
		for (IASTNode actNode : keyTree) {
			List<IASTComment> comments = map.get(actNode);
			output.append(getSignature(actNode)).append(" = "); //$NON-NLS-1$
			boolean first = true;
			for (IASTComment actComment : comments) {
				if (!first) {
					output.append(" , "); //$NON-NLS-1$
				}
				output.append(actComment.getRawSignature());
				first = false;
			}
			output.append(SEPARATOR);
		}
		return output.toString().trim();
	}

	private String getSignature(IASTNode node) {
		if (node instanceof IASTCompositeTypeSpecifier) {
			IASTCompositeTypeSpecifier comp = (IASTCompositeTypeSpecifier) node;
			return comp.getName().toString();
		} else if (node instanceof IASTEnumerationSpecifier) {
			IASTEnumerationSpecifier comp = (IASTEnumerationSpecifier) node;
			return comp.getName().toString();
		} else if (node instanceof IASTTranslationUnit) {
			return Path.fromOSString(node.getFileLocation().getFileName()).lastSegment();
		}
		return node.getRawSignature();
	}

	private static String getSeparatingRegexp() {
		return LEADING_COMMENT_SEPARATOR + ANY_CHAR_REGEXP + TRAILING_COMMENT_SEPARATOR +
				ANY_CHAR_REGEXP + FREESTANDING_COMMENT_SEPARATOR + ANY_CHAR_REGEXP;
	}
	
	protected IASTTranslationUnit getUnit(String fileName) throws CoreException {
		ITranslationUnit tu = (ITranslationUnit) CCorePlugin.getDefault().getCoreModel().create(
				project.getFile(fileName));
		return tu.getAST();
	}
	
	private final class NodeOffsetComparator implements Comparator<IASTNode> {
		@Override
		public int compare(IASTNode o1, IASTNode o2) {
			int offDif = o1.getFileLocation().getNodeOffset() - o2.getFileLocation().getNodeOffset();
			if (offDif == 0) {
				return o1.getFileLocation().getNodeLength() - o2.getFileLocation().getNodeLength();
			}
			return offDif;
		}
	}
	
	private void appendLineTrimmed(StringBuilder builderToAppendTo, String line) {
		builderToAppendTo.append(line.trim());
		builderToAppendTo.append(SEPARATOR);
	}
}

Back to the top