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()); } } }