/*******************************************************************************
* Copyright (c) 2008, 2015 Wind River Systems, Inc. and others.
* 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
*
* Contributors:
* Markus Schorn - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.scanner;
import org.eclipse.cdt.core.dom.parser.c.GCCScannerExtensionConfiguration;
import org.eclipse.cdt.core.parser.FileContent;
import org.eclipse.cdt.core.parser.IToken;
import org.eclipse.cdt.core.parser.IncludeFileContentProvider;
import org.eclipse.cdt.core.parser.NullLogService;
import org.eclipse.cdt.core.parser.OffsetLimitReachedException;
import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.ScannerInfo;
import org.eclipse.cdt.core.testplugin.CTestPlugin;
import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
import org.eclipse.cdt.internal.core.parser.scanner.CPreprocessor;
import org.eclipse.cdt.internal.core.parser.scanner.MacroExpander;
import org.eclipse.cdt.internal.core.parser.scanner.MacroExpansionTracker;
import org.eclipse.text.edits.ReplaceEdit;
import junit.framework.TestSuite;
public class ExpansionExplorerTests extends BaseTestCase {
public static TestSuite suite() {
return suite(ExpansionExplorerTests.class);
}
private void performTest(int steps) throws Exception {
CharSequence[] bufs= TestSourceReader.getContentsForTest(
CTestPlugin.getDefault().getBundle(), "parser", getClass(), getName(), steps+2);
String[] input= new String[steps+2];
int i= -1;
for (CharSequence buf : bufs) {
input[++i]= buf.toString().trim();
}
final MacroExpander expander= createExpander(input[0]);
final String original= input[1];
verifyStepCount(expander, original, steps);
verifyStep(expander, original, Integer.MAX_VALUE, original, input[steps+1]);
for (i= 0; i < steps; i++) {
verifyStep(expander, original, i, input[i+1], input[i+2]);
}
}
private void verifyStepCount(MacroExpander expander, String original, int steps) {
MacroExpansionTracker tracker= new MacroExpansionTracker(Integer.MAX_VALUE);
expander.expand(original, tracker, "", 1, false);
assertEquals(steps, tracker.getStepCount());
}
private void verifyStep(MacroExpander expander, String original, int step, String expectedPre,
String expectedPost) {
MacroExpansionTracker tracker= new MacroExpansionTracker(step);
expander.expand(original, tracker, "", 1, false);
String pre = tracker.getCodeBeforeStep();
ReplaceEdit replacement = tracker.getReplacement();
assertNotNull(pre);
assertNotNull(replacement);
String post= apply(pre, replacement);
assertEquals("incorrect value pre " + step, expectedPre, pre);
assertEquals("incorrect value post " + step, expectedPost, post);
}
private String apply(String pre, ReplaceEdit replacement) {
StringBuilder buf= new StringBuilder();
buf.append(pre, 0, replacement.getOffset());
buf.append(replacement.getText());
buf.append(pre, replacement.getExclusiveEnd(), pre.length());
return buf.toString();
}
private MacroExpander createExpander(final String macrodefs) throws OffsetLimitReachedException {
CPreprocessor cpp= new CPreprocessor(FileContent.create("<macro-expander>", macrodefs.toCharArray()),
new ScannerInfo(), ParserLanguage.C, new NullLogService(),
GCCScannerExtensionConfiguration.getInstance(), IncludeFileContentProvider.getEmptyFilesProvider());
int type;
do {
type= cpp.nextTokenRaw().getType();
} while (type != IToken.tEND_OF_INPUT);
return cpp.getAdapter(MacroExpander.class);
}
// #define A
// B
// B
public void testNoOp() throws Exception {
performTest(0);
}
// #define A B
// A
// B
public void testObject() throws Exception {
performTest(1);
}
// #define A A1
// #define A1 A2
// #define A2 A
// A
// A1
// A2
// A
public void testObjectChain() throws Exception {
performTest(3);
}
// #define A(x) B+x
// A(c)
// B+c
public void testFunction() throws Exception {
performTest(1);
}
// #define A(x) x+x
// #define _t t
// A(_t)
// A(t)
// t+t
public void testFunctionParam() throws Exception {
performTest(2);
}
// #define A(x,y) x+y
// #define _t t
// A(_t, _t)
// A(t, _t)
// A(t, t)
// t+t
public void test2Params() throws Exception {
performTest(3);
}
// #define A(x,y,z) x + y + z
// #define _t t
// A ( _t , , _t )
// A ( t , , _t )
// A ( t , , t )
// t + + t
public void test3Params() throws Exception {
performTest(3);
}
// #define m !(m)+n
// #define n(n) n(m)
// m(m)
// !(m)+n(m)
// !(m)+n(!(m)+n)
// !(m)+!(m)+n(m)
// !(m)+!(m)+n(!(m)+n)
public void testRecursiveExpansion() throws Exception {
performTest(4);
}
// #define f(x,y) (x + y)
// #define g(x,y) (x*y)
// #define _a a
// #define _b b
// f( g(_a,_b), g(_b,_a) )
// f( g(a,_b), g(_b,_a) )
// f( g(a,b), g(_b,_a) )
// f( (a*b), g(_b,_a) )
// f( (a*b), g(b,_a) )
// f( (a*b), g(b,a) )
// f( (a*b), (b*a) )
// ((a*b) + (b*a))
public void testNestedFunctions() throws Exception {
performTest(7);
}
// #define id(x) x
// id(
// id(a))
// id(
// a)
// a
public void testNewline() throws Exception {
performTest(2);
}
// #define f x _a _b x
// #define _a a
// #define _b b
// f
// x _a _b x
// x a _b x
// x a b x
public void testSpace() throws Exception {
performTest(3);
}
// #define L __LINE__
// #define x(a) a
// x(L)
// x(__LINE__)
// x(1)
// 1
public void testLineNumber() throws Exception {
performTest(3);
}
// #define L __LINE__
// #define x(a,b) a,b
// x(L,
// L)
// x(__LINE__,
// L)
// x(2,
// L)
// x(2,
// __LINE__)
// x(2,
// 2)
// 2,2
public void testLineNumber2() throws Exception {
performTest(5);
}
// #define str(x) #x
// #define xstr(x) str(x)
// xstr(__LINE__)
// xstr(1)
// str(1)
// "1"
public void testStringify() throws Exception {
performTest(3);
}
// #define vararg(x, y...) bla(x, y)
// #define _p p
// vararg( _p );
// vararg( p );
// bla(p, );
public void testVararg1() throws Exception {
performTest(2);
}
// #define vararg(x, y...) bla(x, ##y)
// #define _p p
// vararg( _p );
// vararg( p );
// bla(p);
public void testVararg1x() throws Exception {
performTest(2);
}
// #define vararg(x, y...) bla(x, y)
// #define _p p
// vararg( _p , _p );
// vararg( p , _p );
// vararg( p , p );
// bla(p, p);
public void testVararg2() throws Exception {
performTest(3);
}
// #define vararg(x, y...) bla(x, ## y)
// #define _p p
// vararg( _p , _p );
// vararg( p , _p );
// vararg( p , p );
// bla(p, p);
public void testVararg2x() throws Exception {
performTest(3);
}
// #define func2(x,y) (x,y)
// #define _p p
// func2(_p);
// func2(p);
// (p,);
public void testTooFewArgs() throws Exception {
performTest(2);
}
}