| #include <emscripten.h> |
| |
| EM_JS(void, test_remove_cpp_comments_in_shaders, (void), { |
| var numFailed = 0; |
| function test(input, expected) { |
| var obtained = remove_cpp_comments_in_shaders(input); |
| function remove_nl(t) { return t.replace(/\\n/g, "\\\\\\n")} |
| |
| if (obtained == expected) { |
| out(`OK: '${remove_nl(input)}' -> '${remove_nl(expected)}'`); |
| } else { |
| err(`\\nFailed! \\nInput: '${remove_nl(input)}'\\nObtained: '${remove_nl(obtained)}'\\nExpected: '${remove_nl(expected)}'\\n`); |
| ++numFailed; |
| } |
| } |
| test('foo(); // test // test2 // test3', 'foo(); '); // Test that C++ comments '//' are removed |
| test('foo(); / /// test', 'foo(); / '); // Test that no confusion with slightly similar looking inputs |
| test('foo(); // /*', 'foo(); '); // Test that // takes away /* |
| test('foo(); //\nbar();', 'foo(); \nbar();'); // Test that // ends at the next newline |
| test('foo(); //*\nbar(); */', 'foo(); \nbar(); */'); // Test that //* is interpreted as // |
| test('foo(); /* aaa', 'foo(); '); // Test that on malformed /* without ending */, we remove all content up to end of string |
| test('foo(); /*\neee\n*/bar();', 'foo(); bar();'); // Test that /* */ works over multiple lines |
| test('foo(); /* // */bar();', 'foo(); bar();'); // Test that // comments inside /* */ comments are not processed |
| test('foo(); /*eee*//bar();', 'foo(); /bar();'); // Test that // comment as part of /* */ is not processed |
| test('foo(); /* a /* b */ c */', 'foo(); c */'); // Test that /* */ should not nest |
| |
| // Verify known gotchas/quirks due to partial support: these are broken by design, as shaders do not support strings. |
| test('" // comment inside a string "', '" '); // Test that (unfortunately) comments will be removed even if they exist inside "" strings |
| test("' // comment inside a string '", "' "); // Test that (unfortunately) comments will be removed even if they exist inside '' strings |
| test('" // comment inside a multi\nline string "', '" \nline string "'); // Test that (unfortunately) newline inside string breaks a comment |
| test('" /* C comment inside a string */ "', '" "'); // Test that (unfortunately) C comments will also be removed inside strings |
| |
| if (numFailed) throw numFailed + ' tests failed!'; |
| }); |
| |
| EM_JS(void, test_c_preprocessor, (void), { |
| var numFailed = 0; |
| function test(input, expected) { |
| var obtained = preprocess_c_code(input); |
| function remove_nl(t) { return t.replace(/\\n/g, String.fromCharCode(92) + 'n'); } |
| |
| if (obtained == expected) { |
| out(`OK: '${remove_nl(input)}' -> '${remove_nl(expected)}'`); |
| } else { |
| err(`\\nFailed! \\nInput: '${remove_nl(input)}'\\nObtained: '${remove_nl(obtained)}'\\nExpected: '${remove_nl(expected)}'\\n`); |
| ++numFailed; |
| } |
| } |
| |
| test('A\n #ifdef FOO\n B\n #endif', 'A\n'); // Test #ifdef not taken (also test whitespace at the beginning of a line) |
| |
| test(' #define FOO 1\nA\n#ifdef FOO\n B\n #endif', 'A\n B\n'); // Test #ifdef taken |
| |
| test(' #define FOO 0\nA\n#ifdef FOO\n B\n #endif', 'A\n B\n'); // Test #ifdef should be taken when var #defined to 0. |
| |
| test('A\n#ifndef FOO\nB\n#endif', 'A\nB\n'); // Test #ifndef taken |
| test('#define FOO 1\nA\n#ifndef FOO\nB\n#endif', 'A\n'); // Test #ifndef not taken |
| test('#define FOO 0\nA\n#ifndef FOO\nB\n#endif', 'A\n'); // Test #ifndef not taken when #defined to 0. |
| |
| test('#define FOO 1\nA\n#ifdef FOO\nB\n#endif\n#undef FOO\n#ifdef FOO\nC\n#endif\n', 'A\nB\n'); // Test #undef |
| test('#define FOO 1\nA\n#ifdef FOO\nB\n#endif\n#undef FOO\n#ifndef FOO\nC\n#endif\n', 'A\nB\nC\n'); // Test #undef |
| |
| test('A\n#ifdef FOO\nB\n#else\nC\n#endif', 'A\nC\n'); // Test #ifdef-#else-#endif not taken |
| test('A\n#define FOO 0\n#ifdef FOO\nB\n#else\nC\n#endif', 'A\nB\n'); // Test #ifdef-#else-#endif taken |
| |
| test(' #define FOO 0\nA\n#if FOO\n B\n#else \n C\n #endif', 'A\n C\n'); // Test #if-#else-#endif not taken |
| test(' #define FOO 10\nA\n#if FOO\n B\n#else \n C\n #endif', 'A\n B\n'); // Test #if-#else-#endif taken |
| |
| test('#define FOO 1\n#define BAR 0\n#if FOO && BAR\nB\n#endif', ""); // Test && operator yielding negative |
| test('#define FOO 1\n#define BAR 1\n#if FOO && BAR\nB\n#endif', 'B\n'); // Test && operator yielding positive |
| test('#define FOO\t1\n#define BAR\t \t1\n#if FOO \t \t &&BAR\t\nB\n#endif', 'B\n'); // Test more complex whitespace around && |
| |
| test('#define FOO 1\n#define BAR 1\n#if (FOO && BAR)\nB\n#endif', 'B\n'); // Test parentheses around && |
| test('#define FOO 1\n#define BAR 1\n#if (((FOO && BAR)))\nB\n#endif', 'B\n'); // Test nested parenthesess around && |
| test('#define FOO 0\n#define BAR 1\n#define BAZ 1\n#if FOO&&BAR||BAZ\nB\n#endif', 'B\n'); // Test precedence of && and || |
| test('#define FOO 0\n#define BAR 1\n#define BAZ 1\n#if (FOO&&BAR)||BAZ\nB\n#endif', 'B\n'); // Test parentheses with && and || |
| test('#define FOO 0\n#define BAR 1\n#define BAZ 1\n#if FOO&&(BAR||BAZ)\nB\n#endif', ""); // Test parentheses with && and || |
| test('#define FOO 1\n#define BAR 1\n#define BAZ 0\n#if FOO||BAR&&BAZ\nB\n#endif', 'B\n'); // Test parentheses with && and || |
| test('#define FOO 1\n#define BAR 1\n#define BAZ 0\n#if (FOO||BAR)&&BAZ\nB\n#endif', ""); // Test parentheses with && and || |
| test('#define FOO 1\n#define BAR 1\n#define BAZ 0\n#if FOO||(BAR&&BAZ)\nB\n#endif', 'B\n'); // Test parentheses with && and || |
| |
| test('#define FOO 1\n#define BAR 1\n#define BAZ 0\n#if FOO&&BAR&&BAZ\nB\n#endif', ""); // Test two &&s |
| test('#define FOO 0\n#define BAR 1\n#define BAZ 1\n#if FOO&&BAR&&BAZ\nB\n#endif', ""); // Test two &&s |
| test('#define FOO 1\n#define BAR 0\n#define BAZ 1\n#if FOO&&BAR&&BAZ\nB\n#endif', ""); // Test two &&s |
| test('#define FOO 1\n#define BAR 1\n#define BAZ 1\n#if FOO&&BAR&&BAZ\nB\n#endif', 'B\n'); // Test two &&s |
| |
| test('#define FOO 1\n#define BAR 0\n#define BAZ 0\n#if FOO||BAR||BAZ\nB\n#endif', 'B\n'); // Test two ||s |
| test('#define FOO 0\n#define BAR 1\n#define BAZ 0\n#if FOO||BAR||BAZ\nB\n#endif', 'B\n'); // Test two ||s |
| test('#define FOO 0\n#define BAR 0\n#define BAZ 1\n#if FOO||BAR||BAZ\nB\n#endif', 'B\n'); // Test two ||s |
| test('#define FOO 0\n#define BAR 0\n#define BAZ 0\n#if FOO||BAR||BAZ\nB\n#endif', ""); // Test two ||s |
| |
| test('#define FOO 1\n#if FOO < 3\nB\n#endif', 'B\n'); // Test < |
| test('#define FOO 1\n#if FOO < 1\nB\n#endif', ""); // Test < |
| test('#define FOO 1\n#if FOO > 0\nB\n#endif', 'B\n'); // Test > |
| test('#define FOO 1\n#if FOO > 1\nB\n#endif', ""); // Test > |
| test('#define FOO 1\n#if FOO <= 1\nB\n#endif', 'B\n'); // Test <= |
| test('#define FOO 1\n#if FOO <= 0\nB\n#endif', ""); // Test <= |
| test('#define FOO 1\n#if FOO >= 1\nB\n#endif', 'B\n'); // Test >= |
| test('#define FOO 1\n#if FOO >= 2\nB\n#endif', ""); // Test >= |
| |
| test('#define FOO 1\n#define BAR 2\n#if FOO < 3 && BAR < 4\nB\n#endif', 'B\n'); // Test evaluation of && and < |
| test('#define FOO 1\n#define BAR 2\n#if FOO < 3 && BAR < 2\nB\n#endif', ""); // Test evaluation of && and < |
| |
| test('#define FOO 1\n#define BAR 2\n#if FOO == 1 && BAR == 2\nB\n#endif', 'B\n'); // Test evaluation of && and == |
| test('#define FOO 1\n#define BAR 2\n#if FOO == 1 && BAR != 2\nB\n#endif', ""); // Test evaluation of && and != |
| |
| test('#define FOO 1\n#define BAR 2\n#if FOO < 3 || BAR < 0\nB\n#endif', 'B\n'); // Test evaluation of || and < |
| test('#define FOO 1\n#define BAR 2\n#if FOO < 1 || BAR < 2\nB\n#endif', ""); // Test evaluation of || and < |
| |
| test('#define FOO 1\n#define BAR 2\n#if FOO == 1 || BAR == 3\nB\n#endif', 'B\n'); // Test evaluation of || and == |
| test('#define FOO 1\n#define BAR 2\n#if FOO != 1 || BAR != 2\nB\n#endif', ""); // Test evaluation of || and != |
| |
| test('#define FOO 1\n#define BAR 2\n#if FOO < 2 && BAR > 1 && FOO <= 1 && BAR >= 2 && FOO == 1 && BAR != 1\nB\n#endif', 'B\n'); // Test complex comparisons |
| test('#define FOO 1\n#define BAR 2\n#if FOO < 2 && BAR > 1 && FOO <= 1 && BAR >= 2 && FOO == 1 && BAR != 2\nB\n#endif', ""); // Test complex comparisons |
| |
| test('#define FOO 1\n#define BAR 1\n#if FOO == BAR\nB\n#endif', 'B\n'); // Test comparison of two vars against each other |
| test('#define FOO 1\n#define BAR 1\n#if FOO != BAR\nB\n#endif', ""); // Test comparison of two vars against each other |
| test('#define FOO 1\n#define BAR 2\n#if FOO == BAR\nB\n#endif', ""); // Test comparison of two vars against each other |
| test('#define FOO 1\n#define BAR 2\n#if FOO != BAR\nB\n#endif', 'B\n'); // Test comparison of two vars against each other |
| |
| test('#define FOO 0\n#if !FOO\nB\n#endif', 'B\n'); // Test unary ! |
| test('#define FOO 1\n#if !FOO\nB\n#endif', ""); // Test unary ! |
| |
| test('#define FOO 1\n#define BAR 0\n#if !FOO && BAR\nB\n#endif', ""); // Test unary ! and && precedence |
| test('#define FOO 1\n#define BAR 0\n#if FOO && !BAR\nB\n#endif', 'B\n'); // Test unary ! and && precedence |
| test('#define FOO 0\n#define BAR 1\n#if !(FOO && BAR)\nB\n#endif', 'B\n'); // Test unary ! and && precedence with parentheses |
| test('#define FOO 1\n#define BAR 1\n#if !(FOO && BAR)\nB\n#endif', ""); // Test unary ! and && precedence with parentheses |
| |
| test('#define FOO 1\n#if !!FOO\nB\n#endif', 'B\n'); // Test double !! |
| test('#define FOO 1\n#if !!(FOO)\nB\n#endif', 'B\n'); // Test double !! |
| test('#define FOO 1\n#if !(!FOO)\nB\n#endif', 'B\n'); // Test double !! |
| test('#define FOO 1\n#if ((!((!((!!!FOO))))))\nB\n#endif', ""); // Test complex ! and () |
| |
| test('#define M12 1\n#define M22 0\n#if M12 == 1 && M22 == 0\nB\n#endif', 'B\n'); // Test including a number in a variable name |
| test('#define M12 1\n#define M22 0\n#if M22 == 1 && M12 == 0\nB\n#endif', ""); // Test including a number in a variable name |
| |
| test('#define FOO 42\nFOO\n', '42\n'); // Test expanding a preprocessor symbol |
| |
| test('#define FOO 42\n#define BAR FOO\nBAR\n', '42\n'); // Test chained expanding a preprocessor symbol |
| test('#define MACRO(x) x\nMACRO(42)\n', '42\n'); // Test simple preprocessor macro |
| test('#define MACRO(x,y) x\nMACRO(42, 53)\n', '42\n'); // Test simple preprocessor macro |
| test('#define MACRO( \t x , y ) \t x \t\nMACRO(42, 53)\n', '42\n'); // Test simple preprocessor macro |
| |
| test('#define MACRO(x,y,z) x+y<=z\nMACRO(42,15,30)\n', '42+15<=30\n'); // Test three-arg macro |
| |
| test('#define FOO 1\n#define BAR 2\n#define BAZ 1\n#define MACRO(x,y,z) x<y&&z\n#if MACRO(FOO,BAR,BAZ)\nA\n#endif', 'A\n'); // Test three-arg macro in an #if comparison |
| test('#define FOO 1\n#define BAR 2\n#define BAZ 0\n#define MACRO(x,y,z) x<y&&z\n#if MACRO(FOO,BAR,BAZ)\nA\n#endif', ""); // Test three-arg macro in an #if comparison |
| |
| test('#if 1>2&&0\nA\n#endif', ""); // Test precedence between > and && |
| test('#if 0&&1>2\nA\n#endif', ""); // Test precedence between > and && |
| test('#if 2<3&&1\nA\n#endif', "A\n"); // Test precedence between > and && |
| test('#if 1&&2<3\nA\n#endif', "A\n"); // Test precedence between > and && |
| |
| test('#if 1+2<=3\nA\n#endif', 'A\n'); // Test arithmetic + and comparison op precedence |
| test('#if 1+2 <3\nA\n#endif', ""); // Test arithmetic + and comparison op precedence |
| |
| test('#if 1+2*0\nA\n#endif', "A\n"); // Test arithmetic + and * precedence |
| test('#if 1+1*2==4\nA\n#endif', ""); // Test arithmetic + and * precedence |
| |
| test('#if 5/2==2\nA\n#endif', "A\n"); // Test arithmetic integer divide / |
| |
| test('#if defined(FOO)\nA\n#endif', ""); // Test defined() macro |
| test('#define FOO 0\n#if defined(FOO)\nA\n#endif', "A\n"); // Test defined() macro |
| test('#define FOO 0\n#undef FOO\n#if defined(FOO)\nA\n#endif', ""); // Test defined() macro after #undef |
| |
| if (numFailed) throw numFailed + ' tests failed!'; |
| }); |
| |
| int main() |
| { |
| test_remove_cpp_comments_in_shaders(); |
| |
| test_c_preprocessor(); |
| } |