blob: 38cdfacfaff17a3123578e44480426c1cae2425b [file] [log] [blame] [edit]
#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();
}