File: test_c_preprocessor.c

package info (click to toggle)
emscripten 3.1.6~dfsg-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 114,112 kB
  • sloc: ansic: 583,052; cpp: 391,943; javascript: 79,361; python: 54,180; sh: 49,997; pascal: 4,658; makefile: 3,426; asm: 2,191; lisp: 1,869; ruby: 488; cs: 142
file content (186 lines) | stat: -rw-r--r-- 12,653 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#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

	test('#define SAMPLE_TEXTURE_2D texture \nvec4 c = SAMPLE_TEXTURE_2D(tex, texCoord);\n', 'vec4 c = texture(tex, texCoord);\n'); // Test expanding a non-macro to a macro-like call site

	test('#extension GL_EXT_shader_texture_lod : enable\n', '#extension GL_EXT_shader_texture_lod : enable\n'); // Test that GLSL preprocessor macros are preserved
	test('#version 300 es\n', '#version 300 es\n'); // Test that GLSL preprocessor macros are preserved
	test('#pragma foo\n', '#pragma foo\n'); // Test that GLSL preprocessor macros are preserved

	test('#define FOO() bar\nFOO()\n', 'bar\n'); // Test preprocessor macros that do not take in any parameters

	test('#define FOO 1\n#if FOO\n#define BAR this_is_right\n#else\n#define BAR this_is_wrong\n#endif\nBAR', 'this_is_right\n'); // Test nested #defines in both sides of an #if-#else block.

	test('\n#define FOO 1\nFOO\n', '\n1\n'); // Test that preprocessor is not confused by an input that starts with a \n

	if (numFailed) throw numFailed + ' tests failed!';
});

int main()
{
  test_remove_cpp_comments_in_shaders();

  test_c_preprocessor();
}