package org.anarres.cpp;
import java.io.*;
import junit.framework.Test;
import static org.anarres.cpp.Token.*;
public class PreprocessorTestCase extends BaseTestCase {
private OutputStreamWriter writer;
private Preprocessor p;
public void setUp() throws Exception {
final PipedOutputStream po = new PipedOutputStream();
writer = new OutputStreamWriter(po);
p = new Preprocessor();
p.addInput(
new LexerSource(
new InputStreamReader(
new PipedInputStream(po)
),
true
)
);
}
private static class I {
private String t;
public I(String t) {
this.t = t;
}
public String getText() {
return t;
}
public String toString() {
return getText();
}
}
private static I I(String t) {
return new I(t);
}
/*
* When writing tests in this file, remember the preprocessor
* stashes NLs, so you won't see an immediate NL at the end of any
* input line. You will see it right before the next nonblank on
* the following input line.
*/
public void testPreprocessor() throws Exception {
/* Magic macros */
testInput("line = __LINE__\n",
I("line"), WHITESPACE, '=', WHITESPACE, INTEGER
/*, NL - all nls deferred so as not to block the reader */
);
testInput("file = __FILE__\n", NL, /* from before, etc */
I("file"), WHITESPACE, '=', WHITESPACE, STRING
);
/* Simple definitions */
testInput("#define A a /* a defined */\n", NL);
testInput("#define B b /* b defined */\n", NL);
testInput("#define C c /* c defined */\n", NL);
/* Expansion of arguments */
testInput("#define EXPAND(x) x\n", NL);
testInput("EXPAND(a)\n", NL, I("a"));
testInput("EXPAND(A)\n", NL, I("a"));
/* Stringification */
testInput("#define _STRINGIFY(x) #x\n", NL);
testInput("_STRINGIFY(A)\n", NL, "A");
testInput("#define STRINGIFY(x) _STRINGIFY(x)\n", NL);
testInput("STRINGIFY(b)\n", NL, "b");
testInput("STRINGIFY(A)\n", NL, "a");
/* Concatenation */
testInput("#define _CONCAT(x, y) x ## y\n", NL);
testInput("_CONCAT(A, B)\n", NL, I("AB"));
testInput("#define A_CONCAT done_a_concat\n", NL);
testInput("_CONCAT(A, _CONCAT(B, C))\n", NL,
I("done_a_concat"), '(', I("b"), ',', WHITESPACE, I("c"), ')'
);
testInput("#define CONCAT(x, y) _CONCAT(x, y)\n", NL);
testInput("CONCAT(A, CONCAT(B, C))\n", NL, I("abc"));
testInput("#define _CONCAT3(x, y, z) x ## y ## z\n", NL);
testInput("_CONCAT3(a, b, c)\n", NL, I("abc"));
testInput("_CONCAT3(A, B, C)\n", NL, I("ABC"));
/* Redefinitions, undefinitions. */
testInput("#define two three\n", NL);
testInput("one /* one */\n", NL, I("one"), WHITESPACE, CCOMMENT);
testInput("#define one two\n", NL);
testInput("one /* three */\n", NL, I("three"), WHITESPACE, CCOMMENT);
testInput("#undef two\n", NL);
testInput("#define two five\n", NL);
testInput("one /* five */\n", NL, I("five"), WHITESPACE, CCOMMENT);
testInput("#undef two\n", NL);
testInput("one /* two */\n", NL, I("two"), WHITESPACE, CCOMMENT);
testInput("#undef one\n", NL);
testInput("#define one four\n", NL);
testInput("one /* four */\n", NL, I("four"), WHITESPACE, CCOMMENT);
testInput("#undef one\n", NL);
testInput("#define one one\n", NL);
testInput("one /* one */\n", NL, I("one"), WHITESPACE, CCOMMENT);
/* Variadic macros. */
testInput("#define var(x...) a x b\n", NL);
testInput("#define var(...) a __VA_ARGS__ b\n", NL);
testInput("var(e, f, g)\n", NL,
I("a"), WHITESPACE,
I("e"), ',', WHITESPACE,
I("f"), ',', WHITESPACE,
I("g"), WHITESPACE,
I("b")
);
testInput("#define _Widen(x) L ## x\n", NL);
testInput("#define Widen(x) _Widen(x)\n", NL);
testInput("#define LStr(x) _Widen(#x)\n", NL);
testInput("LStr(x);\n", NL, I("L"), "x");
writer.close();
Token t;
do {
t = p.token();
System.out.println("Remaining token " + t);
} while(t.getType() != EOF);
}
private void testInput(String in, Object... out)
throws Exception {
System.out.print("Input: " + in);
writer.write(in);
writer.flush();
for (int i = 0; i < out.length; i++) {
Token t = p.token();
System.out.println(t);
Object v = out[i];
if (v instanceof String) {
if (t.getType() != STRING)
fail("Expected STRING, but got " + t);
assertEquals((String)v, (String)t.getValue());
}
else if (v instanceof I) {
if (t.getType() != IDENTIFIER)
fail("Expected IDENTIFIER " + v + ", but got " + t);
assertEquals( ((I)v).getText(), (String)t.getText());
}
else if (v instanceof Character)
assertEquals( (int)((Character)v).charValue(), t.getType());
else if (v instanceof Integer)
assertEquals( ((Integer)v).intValue(), t.getType());
else
fail("Bad object " + v.getClass());
}
}
}