summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/tests/preprocessor_tests
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /gfx/angle/src/tests/preprocessor_tests
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'gfx/angle/src/tests/preprocessor_tests')
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/MockDiagnostics.h20
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/MockDirectiveHandler.h34
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/PreprocessorTest.cpp29
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/PreprocessorTest.h30
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/char_test.cpp98
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/comment_test.cpp69
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/define_test.cpp988
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/error_test.cpp92
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/extension_test.cpp136
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/identifier_test.cpp162
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/if_test.cpp1048
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/input_test.cpp178
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/location_test.cpp351
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/number_test.cpp170
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/operator_test.cpp80
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/pragma_test.cpp154
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/space_test.cpp106
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/token_test.cpp90
-rwxr-xr-xgfx/angle/src/tests/preprocessor_tests/version_test.cpp229
19 files changed, 4064 insertions, 0 deletions
diff --git a/gfx/angle/src/tests/preprocessor_tests/MockDiagnostics.h b/gfx/angle/src/tests/preprocessor_tests/MockDiagnostics.h
new file mode 100755
index 000000000..397617869
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/MockDiagnostics.h
@@ -0,0 +1,20 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef PREPROCESSOR_TESTS_MOCK_DIAGNOSTICS_H_
+#define PREPROCESSOR_TESTS_MOCK_DIAGNOSTICS_H_
+
+#include "gmock/gmock.h"
+#include "compiler/preprocessor/DiagnosticsBase.h"
+
+class MockDiagnostics : public pp::Diagnostics
+{
+ public:
+ MOCK_METHOD3(print,
+ void(ID id, const pp::SourceLocation& loc, const std::string& text));
+};
+
+#endif // PREPROCESSOR_TESTS_MOCK_DIAGNOSTICS_H_
diff --git a/gfx/angle/src/tests/preprocessor_tests/MockDirectiveHandler.h b/gfx/angle/src/tests/preprocessor_tests/MockDirectiveHandler.h
new file mode 100755
index 000000000..7560adde4
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/MockDirectiveHandler.h
@@ -0,0 +1,34 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef PREPROCESSOR_TESTS_MOCK_DIRECTIVE_HANDLER_H_
+#define PREPROCESSOR_TESTS_MOCK_DIRECTIVE_HANDLER_H_
+
+#include "gmock/gmock.h"
+#include "compiler/preprocessor/DirectiveHandlerBase.h"
+
+class MockDirectiveHandler : public pp::DirectiveHandler
+{
+ public:
+ MOCK_METHOD2(handleError,
+ void(const pp::SourceLocation& loc, const std::string& msg));
+
+ MOCK_METHOD4(handlePragma,
+ void(const pp::SourceLocation& loc,
+ const std::string& name,
+ const std::string& value,
+ bool stdgl));
+
+ MOCK_METHOD3(handleExtension,
+ void(const pp::SourceLocation& loc,
+ const std::string& name,
+ const std::string& behavior));
+
+ MOCK_METHOD2(handleVersion,
+ void(const pp::SourceLocation& loc, int version));
+};
+
+#endif // PREPROCESSOR_TESTS_MOCK_DIRECTIVE_HANDLER_H_
diff --git a/gfx/angle/src/tests/preprocessor_tests/PreprocessorTest.cpp b/gfx/angle/src/tests/preprocessor_tests/PreprocessorTest.cpp
new file mode 100755
index 000000000..b4acd28df
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/PreprocessorTest.cpp
@@ -0,0 +1,29 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "compiler/preprocessor/Token.h"
+
+void PreprocessorTest::preprocess(const char* input, const char* expected)
+{
+ ASSERT_TRUE(mPreprocessor.init(1, &input, NULL));
+
+ int line = 1;
+ pp::Token token;
+ std::stringstream stream;
+ do
+ {
+ mPreprocessor.lex(&token);
+ for (; line < token.location.line; ++line)
+ {
+ stream << "\n";
+ }
+ stream << token;
+ } while (token.type != pp::Token::LAST);
+
+ std::string actual = stream.str();
+ EXPECT_STREQ(expected, actual.c_str());
+}
diff --git a/gfx/angle/src/tests/preprocessor_tests/PreprocessorTest.h b/gfx/angle/src/tests/preprocessor_tests/PreprocessorTest.h
new file mode 100755
index 000000000..e270f1285
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/PreprocessorTest.h
@@ -0,0 +1,30 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "gtest/gtest.h"
+
+#include "MockDiagnostics.h"
+#include "MockDirectiveHandler.h"
+#include "compiler/preprocessor/Preprocessor.h"
+
+#ifndef PREPROCESSOR_TESTS_PREPROCESSOR_TEST_H_
+#define PREPROCESSOR_TESTS_PREPROCESSOR_TEST_H_
+
+class PreprocessorTest : public testing::Test
+{
+ protected:
+ PreprocessorTest() : mPreprocessor(&mDiagnostics, &mDirectiveHandler) { }
+
+ // Preprocesses the input string and verifies that it matches
+ // expected output.
+ void preprocess(const char* input, const char* expected);
+
+ MockDiagnostics mDiagnostics;
+ MockDirectiveHandler mDirectiveHandler;
+ pp::Preprocessor mPreprocessor;
+};
+
+#endif // PREPROCESSOR_TESTS_PREPROCESSOR_TEST_H_
diff --git a/gfx/angle/src/tests/preprocessor_tests/char_test.cpp b/gfx/angle/src/tests/preprocessor_tests/char_test.cpp
new file mode 100755
index 000000000..641ef2cf8
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/char_test.cpp
@@ -0,0 +1,98 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include <algorithm>
+#include <climits>
+
+#include "PreprocessorTest.h"
+#include "compiler/preprocessor/Token.h"
+
+class CharTest : public PreprocessorTest,
+ public testing::WithParamInterface<int>
+{
+};
+
+static const char kPunctuators[] = {
+ '.', '+', '-', '/', '*', '%', '<', '>', '[', ']', '(', ')', '{', '}',
+ '^', '|', '&', '~', '=', '!', ':', ';', ',', '?'};
+static const int kNumPunctuators =
+ sizeof(kPunctuators) / sizeof(kPunctuators[0]);
+
+bool isPunctuator(char c)
+{
+ static const char* kPunctuatorBeg = kPunctuators;
+ static const char* kPunctuatorEnd = kPunctuators + kNumPunctuators;
+ return std::find(kPunctuatorBeg, kPunctuatorEnd, c) != kPunctuatorEnd;
+}
+
+static const char kWhitespaces[] = {' ', '\t', '\v', '\f', '\n', '\r'};
+static const int kNumWhitespaces =
+ sizeof(kWhitespaces) / sizeof(kWhitespaces[0]);
+
+bool isWhitespace(char c)
+{
+ static const char* kWhitespaceBeg = kWhitespaces;
+ static const char* kWhitespaceEnd = kWhitespaces + kNumWhitespaces;
+ return std::find(kWhitespaceBeg, kWhitespaceEnd, c) != kWhitespaceEnd;
+}
+
+TEST_P(CharTest, Identified)
+{
+ std::string str(1, static_cast<char>(GetParam()));
+ const char* cstr = str.c_str();
+ int length = 1;
+
+ // Note that we pass the length param as well because the invalid
+ // string may contain the null character.
+ ASSERT_TRUE(mPreprocessor.init(1, &cstr, &length));
+
+ int expectedType = pp::Token::LAST;
+ std::string expectedValue;
+
+ if (str[0] == '#')
+ {
+ // Lone '#' is ignored.
+ }
+ else if ((str[0] == '_') ||
+ ((str[0] >= 'a') && (str[0] <= 'z')) ||
+ ((str[0] >= 'A') && (str[0] <= 'Z')))
+ {
+ expectedType = pp::Token::IDENTIFIER;
+ expectedValue = str;
+ }
+ else if (str[0] >= '0' && str[0] <= '9')
+ {
+ expectedType = pp::Token::CONST_INT;
+ expectedValue = str;
+ }
+ else if (isPunctuator(str[0]))
+ {
+ expectedType = str[0];
+ expectedValue = str;
+ }
+ else if (isWhitespace(str[0]))
+ {
+ // Whitespace is ignored.
+ }
+ else
+ {
+ // Everything else is invalid.
+ using testing::_;
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_INVALID_CHARACTER, _, str));
+ }
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(expectedType, token.type);
+ EXPECT_EQ(expectedValue, token.text);
+};
+
+// Note +1 for the max-value in range. It is there because the max-value
+// not included in the range.
+INSTANTIATE_TEST_CASE_P(All, CharTest,
+ testing::Range(CHAR_MIN, CHAR_MAX + 1));
+
diff --git a/gfx/angle/src/tests/preprocessor_tests/comment_test.cpp b/gfx/angle/src/tests/preprocessor_tests/comment_test.cpp
new file mode 100755
index 000000000..d3712ea64
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/comment_test.cpp
@@ -0,0 +1,69 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "compiler/preprocessor/Token.h"
+
+class CommentTest : public PreprocessorTest,
+ public testing::WithParamInterface<const char*>
+{
+};
+
+TEST_P(CommentTest, CommentIgnored)
+{
+ const char* str = GetParam();
+
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::LAST, token.type);
+}
+
+INSTANTIATE_TEST_CASE_P(LineComment, CommentTest,
+ testing::Values("//foo\n", // With newline.
+ "//foo", // Without newline.
+ "//**/", // Nested block comment.
+ "////", // Nested line comment.
+ "//\"")); // Invalid character.
+
+INSTANTIATE_TEST_CASE_P(BlockComment, CommentTest,
+ testing::Values("/*foo*/",
+ "/*foo\n*/", // With newline.
+ "/*//*/", // Nested line comment.
+ "/*/**/", // Nested block comment.
+ "/***/", // With lone '*'.
+ "/*\"*/")); // Invalid character.
+
+class BlockCommentTest : public PreprocessorTest
+{
+};
+
+TEST_F(BlockCommentTest, CommentReplacedWithSpace)
+{
+ const char* str = "/*foo*/bar";
+
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
+ EXPECT_EQ("bar", token.text);
+ EXPECT_TRUE(token.hasLeadingSpace());
+}
+
+TEST_F(BlockCommentTest, UnterminatedComment)
+{
+ const char* str = "/*foo";
+
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ using testing::_;
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_EOF_IN_COMMENT, _, _));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
diff --git a/gfx/angle/src/tests/preprocessor_tests/define_test.cpp b/gfx/angle/src/tests/preprocessor_tests/define_test.cpp
new file mode 100755
index 000000000..e074d1982
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/define_test.cpp
@@ -0,0 +1,988 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "compiler/preprocessor/Token.h"
+
+using testing::_;
+
+class DefineTest : public PreprocessorTest
+{
+};
+
+TEST_F(DefineTest, NonIdentifier)
+{
+ const char* input = "#define 2 foo\n"
+ "2\n";
+ const char* expected = "\n"
+ "2\n";
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_UNEXPECTED_TOKEN,
+ pp::SourceLocation(0, 1),
+ "2"));
+
+ preprocess(input, expected);
+};
+
+TEST_F(DefineTest, RedefinePredefined)
+{
+ const char* input = "#define __LINE__ 10\n"
+ "__LINE__\n"
+ "#define __FILE__ 20\n"
+ "__FILE__\n"
+ "#define __VERSION__ 200\n"
+ "__VERSION__\n"
+ "#define GL_ES 0\n"
+ "GL_ES\n";
+ const char* expected = "\n"
+ "2\n"
+ "\n"
+ "0\n"
+ "\n"
+ "100\n"
+ "\n"
+ "1\n";
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
+ pp::SourceLocation(0, 1),
+ "__LINE__"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
+ pp::SourceLocation(0, 3),
+ "__FILE__"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
+ pp::SourceLocation(0, 5),
+ "__VERSION__"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
+ pp::SourceLocation(0, 7),
+ "GL_ES"));
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ReservedUnderScore1)
+{
+ const char* input = "#define __foo bar\n"
+ "__foo\n";
+ const char* expected = "\n"
+ "bar\n";
+
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_WARNING_MACRO_NAME_RESERVED,
+ pp::SourceLocation(0, 1), "__foo"));
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ReservedUnderScore2)
+{
+ const char* input = "#define foo__bar baz\n"
+ "foo__bar\n";
+ const char* expected = "\n"
+ "baz\n";
+
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_WARNING_MACRO_NAME_RESERVED,
+ pp::SourceLocation(0, 1), "foo__bar"));
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ReservedGL)
+{
+ const char* input = "#define GL_foo bar\n"
+ "GL_foo\n";
+ const char* expected = "\n"
+ "GL_foo\n";
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_MACRO_NAME_RESERVED,
+ pp::SourceLocation(0, 1),
+ "GL_foo"));
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjRedefineValid)
+{
+ const char* input = "#define foo (1-1)\n"
+ "#define foo /* whitespace */ (1-1) /* other */ \n"
+ "foo\n";
+ const char* expected = "\n"
+ "\n"
+ "(1-1)\n";
+ // No error or warning.
+ using testing::_;
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjRedefineInvalid)
+{
+ const char* input = "#define foo (0)\n"
+ "#define foo (1-1)\n"
+ "foo\n";
+ const char* expected = "\n"
+ "\n"
+ "(0)\n";
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_MACRO_REDEFINED,
+ pp::SourceLocation(0, 2),
+ "foo"));
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncRedefineValid)
+{
+ const char* input = "#define foo(a) ( a )\n"
+ "#define foo( a )( /* whitespace */ a /* other */ )\n"
+ "foo(b)\n";
+ const char* expected = "\n"
+ "\n"
+ "( b )\n";
+ // No error or warning.
+ using testing::_;
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncRedefineInvalid)
+{
+ const char* input = "#define foo(b) ( a )\n"
+ "#define foo(b) ( b )\n"
+ "foo(1)\n";
+ const char* expected = "\n"
+ "\n"
+ "( a )\n";
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_MACRO_REDEFINED,
+ pp::SourceLocation(0, 2),
+ "foo"));
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjBasic)
+{
+ const char* input = "#define foo 1\n"
+ "foo\n";
+ const char* expected = "\n"
+ "1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjEmpty)
+{
+ const char* input = "#define foo\n"
+ "foo\n";
+ const char* expected = "\n"
+ "\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjChain)
+{
+ const char* input = "#define foo 1\n"
+ "#define bar foo\n"
+ "bar\n";
+ const char* expected = "\n"
+ "\n"
+ "1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjChainReverse)
+{
+ const char* input = "#define bar foo\n"
+ "#define foo 1\n"
+ "bar\n";
+ const char* expected = "\n"
+ "\n"
+ "1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjRecursive)
+{
+ const char* input = "#define foo bar\n"
+ "#define bar baz\n"
+ "#define baz foo\n"
+ "foo\n"
+ "bar\n"
+ "baz\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "foo\n"
+ "bar\n"
+ "baz\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjCompositeChain)
+{
+ const char* input = "#define foo 1\n"
+ "#define bar a foo\n"
+ "bar\n";
+ const char* expected = "\n"
+ "\n"
+ "a 1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjCompositeChainReverse)
+{
+ const char* input = "#define bar a foo\n"
+ "#define foo 1\n"
+ "bar\n";
+ const char* expected = "\n"
+ "\n"
+ "a 1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjCompositeRecursive)
+{
+ const char* input = "#define foo a bar\n"
+ "#define bar b baz\n"
+ "#define baz c foo\n"
+ "foo\n"
+ "bar\n"
+ "baz\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "a b c foo\n"
+ "b c a bar\n"
+ "c a b baz\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjChainSelfRecursive)
+{
+ const char* input = "#define foo foo\n"
+ "#define bar foo\n"
+ "bar\n";
+ const char* expected = "\n"
+ "\n"
+ "foo\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjectLikeWithParens)
+{
+ const char* input = "#define foo ()1\n"
+ "foo()\n"
+ "#define bar ()2\n"
+ "bar()\n";
+ const char* expected = "\n"
+ "()1()\n"
+ "\n"
+ "()2()\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncEmpty)
+{
+ const char* input = "#define foo()\n"
+ "foo()\n";
+ const char* expected = "\n"
+ "\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncNoArgs)
+{
+ const char* input = "#define foo() bar\n"
+ "foo()\n";
+ const char* expected = "\n"
+ "bar\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncOneArgUnused)
+{
+ const char* input = "#define foo(x) 1\n"
+ "foo(bar)\n";
+ const char* expected = "\n"
+ "1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncTwoArgsUnused)
+{
+ const char* input = "#define foo(x,y) 1\n"
+ "foo(bar,baz)\n";
+ const char* expected = "\n"
+ "1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncOneArg)
+{
+ const char* input = "#define foo(x) ((x)+1)\n"
+ "foo(bar)\n";
+ const char* expected = "\n"
+ "((bar)+1)\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncTwoArgs)
+{
+ const char* input = "#define foo(x,y) ((x)*(y))\n"
+ "foo(bar,baz)\n";
+ const char* expected = "\n"
+ "((bar)*(baz))\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncEmptyArgs)
+{
+ const char* input = "#define zero() pass\n"
+ "#define one(x) pass\n"
+ "#define two(x,y) pass\n"
+ "zero()\n"
+ "one()\n"
+ "two(,)\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "pass\n"
+ "pass\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncMacroAsParam)
+{
+ const char* input = "#define x 0\n"
+ "#define foo(x) x\n"
+ "foo(1)\n";
+ const char* expected = "\n"
+ "\n"
+ "1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncOneArgMulti)
+{
+ const char* input = "#define foo(x) (x)\n"
+ "foo(this is a multi-word argument)\n";
+ const char* expected = "\n"
+ "(this is a multi-word argument)\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncTwoArgsMulti)
+{
+ const char* input = "#define foo(x,y) x,two fish,red fish,y\n"
+ "foo(one fish, blue fish)\n";
+ const char* expected = "\n"
+ "one fish,two fish,red fish,blue fish\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncCompose)
+{
+ const char* input = "#define bar(x) (1+(x))\n"
+ "#define foo(y) (2*(y))\n"
+ "foo(bar(3))\n";
+ const char* expected = "\n"
+ "\n"
+ "(2*((1+(3))))\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncArgWithParens)
+{
+ const char* input = "#define foo(x) (x)\n"
+ "foo(argument(with parens) FTW)\n";
+ const char* expected = "\n"
+ "(argument(with parens) FTW)\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncMacroAsNonMacro)
+{
+ const char* input = "#define foo(bar) bar\n"
+ "foo bar\n";
+ const char* expected = "\n"
+ "foo bar\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncExtraNewlines)
+{
+ const char* input = "#define foo(a) (a)\n"
+ "foo\n"
+ "(\n"
+ "1\n"
+ ")\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "\n"
+ "(1)\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ChainObjToFunc)
+{
+ const char* input = "#define foo() pass\n"
+ "#define bar foo()\n"
+ "bar\n";
+ const char* expected = "\n"
+ "\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ChainObjToNonFunc)
+{
+ const char* input = "#define pass() fail\n"
+ "#define bar pass\n"
+ "bar\n";
+ const char* expected = "\n"
+ "\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ChainObjToFuncWithArgs)
+{
+ const char* input = "#define foo(fail) fail\n"
+ "#define bar foo(pass)\n"
+ "bar\n";
+ const char* expected = "\n"
+ "\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ChainObjToFuncCompose)
+{
+ const char* input = "#define baz(fail) fail\n"
+ "#define bar(fail) fail\n"
+ "#define foo bar(baz(pass))\n"
+ "foo\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ChainObjToFuncParensInText1)
+{
+ const char* input = "#define fail() pass\n"
+ "#define foo fail\n"
+ "foo()\n";
+ const char* expected = "\n"
+ "\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ChainObjToFuncParensInText2)
+{
+ const char* input = "#define bar with,embedded,commas\n"
+ "#define func(x) pass\n"
+ "#define foo func\n"
+ "foo(bar)\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ChainObjToFuncMultiLevel)
+{
+ const char* input = "#define foo(x) pass\n"
+ "#define bar foo\n"
+ "#define baz bar\n"
+ "#define joe baz\n"
+ "joe (fail)\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjToFuncRecursive)
+{
+ const char* input = "#define A(a,b) B(a,b)\n"
+ "#define C A(0,C)\n"
+ "C\n";
+ const char* expected = "\n"
+ "\n"
+ "B(0,C)\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ChainFuncToFuncCompose)
+{
+ const char* input = "#define baz(fail) fail\n"
+ "#define bar(fail) fail\n"
+ "#define foo() bar(baz(pass))\n"
+ "foo()\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncSelfRecursive)
+{
+ const char* input = "#define foo(a) foo(2*(a))\n"
+ "foo(3)\n";
+ const char* expected = "\n"
+ "foo(2*(3))\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncSelfCompose)
+{
+ const char* input = "#define foo(a) foo(2*(a))\n"
+ "foo(foo(3))\n";
+ const char* expected = "\n"
+ "foo(2*(foo(2*(3))))\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncSelfComposeNonFunc)
+{
+ const char* input = "#define foo(bar) bar\n"
+ "foo(foo)\n";
+ const char* expected = "\n"
+ "foo\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncSelfComposeNonFuncMultiTokenArg)
+{
+ const char* input = "#define foo(bar) bar\n"
+ "foo(1+foo)\n";
+ const char* expected = "\n"
+ "1+foo\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FinalizeUnexpandedMacro)
+{
+ const char* input = "#define expand(x) expand(x once)\n"
+ "#define foo(x) x\n"
+ "foo(expand(just))\n";
+ const char* expected = "\n"
+ "\n"
+ "expand(just once)\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncArgWithCommas)
+{
+ const char* input = "#define foo(x) pass\n"
+ "foo(argument (with,embedded, commas) -- baz)\n";
+ const char* expected = "\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncArgObjMaroWithComma)
+{
+ const char* input = "#define foo(a) (a)\n"
+ "#define bar two,words\n"
+ "foo(bar)\n";
+ const char* expected = "\n"
+ "\n"
+ "(two,words)\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncLeftParenInMacroRightParenInText)
+{
+ const char* input = "#define bar(a) a*2\n"
+ "#define foo bar(\n"
+ "foo b)\n";
+ const char* expected = "\n"
+ "\n"
+ "b*2\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, RepeatedArg)
+{
+ const char* input = "#define double(x) x x\n"
+ "double(1)\n";
+ const char* expected = "\n"
+ "1 1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncMissingRightParen)
+{
+ const char* input = "#define foo(x) (2*(x))\n"
+ "foo(3\n";
+ const char* expected = "\n"
+ "\n";
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_MACRO_UNTERMINATED_INVOCATION,
+ pp::SourceLocation(0, 2),
+ "foo"));
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncIncorrectArgCount)
+{
+ const char* input = "#define foo(x,y) ((x)+(y))\n"
+ "foo()\n"
+ "foo(1)\n"
+ "foo(1,2,3)\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "\n";
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_MACRO_TOO_FEW_ARGS,
+ pp::SourceLocation(0, 2),
+ "foo"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_MACRO_TOO_FEW_ARGS,
+ pp::SourceLocation(0, 3),
+ "foo"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_MACRO_TOO_MANY_ARGS,
+ pp::SourceLocation(0, 4),
+ "foo"));
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, Undef)
+{
+ const char* input = "#define foo 1\n"
+ "foo\n"
+ "#undef foo\n"
+ "foo\n";
+ const char* expected = "\n"
+ "1\n"
+ "\n"
+ "foo\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, UndefPredefined)
+{
+ const char* input = "#undef __LINE__\n"
+ "__LINE__\n"
+ "#undef __FILE__\n"
+ "__FILE__\n"
+ "#undef __VERSION__\n"
+ "__VERSION__\n"
+ "#undef GL_ES\n"
+ "GL_ES\n";
+ const char* expected = "\n"
+ "2\n"
+ "\n"
+ "0\n"
+ "\n"
+ "100\n"
+ "\n"
+ "1\n";
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
+ pp::SourceLocation(0, 1),
+ "__LINE__"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
+ pp::SourceLocation(0, 3),
+ "__FILE__"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
+ pp::SourceLocation(0, 5),
+ "__VERSION__"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
+ pp::SourceLocation(0, 7),
+ "GL_ES"));
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, UndefRedefine)
+{
+ const char* input = "#define foo 1\n"
+ "foo\n"
+ "#undef foo\n"
+ "foo\n"
+ "#define foo 2\n"
+ "foo\n";
+ const char* expected = "\n"
+ "1\n"
+ "\n"
+ "foo\n"
+ "\n"
+ "2\n";
+
+ preprocess(input, expected);
+}
+
+// Example from C99 standard section 6.10.3.5 Scope of macro definitions
+TEST_F(DefineTest, C99Example)
+{
+ const char* input =
+ "#define x 3 \n"
+ "#define f(a) f(x * (a)) \n"
+ "#undef x \n"
+ "#define x 2 \n"
+ "#define g f \n"
+ "#define z z[0] \n"
+ "#define h g(~ \n"
+ "#define m(a) a(w) \n"
+ "#define w 0,1 \n"
+ "#define t(a) a \n"
+ "#define p() int \n"
+ "#define q(x) x \n"
+ " \n"
+ "f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);\n"
+ "g(x+(3,4)-w) | h 5) & m\n"
+ " (f)^m(m);\n"
+ "p() i[q()] = { q(1), 23, 4, 5, };\n";
+ const char* expected =
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);\n"
+ "f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) &\n"
+ " f(2 * (0,1))^m(0,1);\n"
+ "int i[] = { 1, 23, 4, 5, };\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, Predefined_GL_ES)
+{
+ const char* input = "GL_ES\n";
+ const char* expected = "1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, Predefined_VERSION)
+{
+ const char* input = "__VERSION__\n";
+ const char* expected = "100\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, Predefined_LINE1)
+{
+ const char* str = "\n\n__LINE__";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::CONST_INT, token.type);
+ EXPECT_EQ("3", token.text);
+}
+
+TEST_F(DefineTest, Predefined_LINE2)
+{
+ const char* str = "#line 10\n"
+ "__LINE__\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::CONST_INT, token.type);
+ EXPECT_EQ("10", token.text);
+}
+
+TEST_F(DefineTest, Predefined_FILE1)
+{
+ const char* const str[] = {"", "", "__FILE__"};
+ ASSERT_TRUE(mPreprocessor.init(3, str, NULL));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::CONST_INT, token.type);
+ EXPECT_EQ("2", token.text);
+}
+
+TEST_F(DefineTest, Predefined_FILE2)
+{
+ const char* const str[] = {"#line 10 20\n", "__FILE__"};
+ ASSERT_TRUE(mPreprocessor.init(2, str, NULL));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::CONST_INT, token.type);
+ EXPECT_EQ("21", token.text);
+}
+
+// Defined operator produced by macro expansion should be parsed inside #if directives
+TEST_F(DefineTest, ExpandedDefinedParsedInsideIf)
+{
+ const char *input =
+ "#define bar 1\n"
+ "#define foo defined(bar)\n"
+ "#if foo\n"
+ "bar\n"
+ "#endif\n";
+ const char *expected =
+ "\n"
+ "\n"
+ "\n"
+ "1\n"
+ "\n";
+ preprocess(input, expected);
+}
+
+// Defined operator produced by macro expansion should not be parsed outside #if directives
+TEST_F(DefineTest, ExpandedDefinedNotParsedOutsideIf)
+{
+ const char *input =
+ "#define foo defined(bar)\n"
+ "foo\n";
+ const char *expected =
+ "\n"
+ "defined(bar)\n";
+ preprocess(input, expected);
+}
+
+// Test that line directive expressions give errors on negative or undefined shifts.
+TEST_F(DefineTest, NegativeShiftInLineDirective)
+{
+ const char *input =
+ "#line 1 << -1\n"
+ "#line 1 >> -1\n"
+ "#line 1 << x\n"
+ "#line 1 >> x\n";
+ const char *expected =
+ "\n"
+ "\n"
+ "\n"
+ "\n";
+
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_UNDEFINED_SHIFT, _, _)).Times(4);
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_INVALID_LINE_NUMBER, _, _)).Times(2);
+ preprocess(input, expected);
+}
+
+// Undefining a macro in its invocation parameters produces and error
+TEST_F(DefineTest, UndefineInInvocation)
+{
+ const char *input =
+ "#define G(a, b) a b\n"
+ "G(\n"
+ "#undef G\n"
+ "1, 2)\n";
+ const char *expected = "\n\n\n1 2\n";
+
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED,
+ pp::SourceLocation(0, 3), _));
+
+ preprocess(input, expected);
+}
+
+// Undefining a macro before its invocation parameters produces and error
+TEST_F(DefineTest, UndefineInInvocationPreLParen)
+{
+ const char *input =
+ "#define G(a, b) a b\n"
+ "G\n"
+ "#undef G\n"
+ "(1, 2)\n";
+ const char *expected = "\n\n\n1 2\n";
+
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED,
+ pp::SourceLocation(0, 3), _));
+
+ preprocess(input, expected);
+}
+
+// The name of the macro "a" is inside an incomplete macro invocation of macro "m()" in its own
+// expansion. This should not result in infinite recursion.
+TEST_F(DefineTest, RecursiveMacroNameInsideIncompleteMacroInvocationInMacroExpansion)
+{
+ const char *input =
+ "#define m(a)\n"
+ "#define a m((a)\n"
+ "a)\n";
+ const char *expected =
+ "\n"
+ "\n"
+ "\n";
+ preprocess(input, expected);
+}
diff --git a/gfx/angle/src/tests/preprocessor_tests/error_test.cpp b/gfx/angle/src/tests/preprocessor_tests/error_test.cpp
new file mode 100755
index 000000000..f0cf8af65
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/error_test.cpp
@@ -0,0 +1,92 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "compiler/preprocessor/Token.h"
+
+class ErrorTest : public PreprocessorTest
+{
+};
+
+TEST_F(ErrorTest, Empty)
+{
+ const char* str = "#error\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler, handleError(pp::SourceLocation(0, 1), ""));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(ErrorTest, OneTokenMessage)
+{
+ const char* str = "#error foo\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handleError(pp::SourceLocation(0, 1), " foo"));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(ErrorTest, TwoTokenMessage)
+{
+ const char* str = "#error foo bar\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handleError(pp::SourceLocation(0, 1), " foo bar"));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(ErrorTest, Comments)
+{
+ const char* str = "/*foo*/"
+ "#"
+ "/*foo*/"
+ "error"
+ "/*foo*/"
+ "foo"
+ "/*foo*/"
+ "bar"
+ "/*foo*/"
+ "//foo"
+ "\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handleError(pp::SourceLocation(0, 1), " foo bar"));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(ErrorTest, MissingNewline)
+{
+ const char* str = "#error foo";
+ const char* expected = "";
+
+ using testing::_;
+ // Directive successfully parsed.
+ EXPECT_CALL(mDirectiveHandler,
+ handleError(pp::SourceLocation(0, 1), " foo"));
+ // Error reported about EOF.
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_EOF_IN_DIRECTIVE, _, _));
+
+ preprocess(str, expected);
+}
diff --git a/gfx/angle/src/tests/preprocessor_tests/extension_test.cpp b/gfx/angle/src/tests/preprocessor_tests/extension_test.cpp
new file mode 100755
index 000000000..468ca4982
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/extension_test.cpp
@@ -0,0 +1,136 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "compiler/preprocessor/Token.h"
+
+class ExtensionTest : public PreprocessorTest
+{
+};
+
+TEST_F(ExtensionTest, Valid)
+{
+ const char* str = "#extension foo : bar\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handleExtension(pp::SourceLocation(0, 1), "foo", "bar"));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(ExtensionTest, Comments)
+{
+ const char* str = "/*foo*/"
+ "#"
+ "/*foo*/"
+ "extension"
+ "/*foo*/"
+ "foo"
+ "/*foo*/"
+ ":"
+ "/*foo*/"
+ "bar"
+ "/*foo*/"
+ "//foo"
+ "\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handleExtension(pp::SourceLocation(0, 1), "foo", "bar"));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(ExtensionTest, MissingNewline)
+{
+ const char* str = "#extension foo : bar";
+ const char* expected = "";
+
+ using testing::_;
+ // Directive successfully parsed.
+ EXPECT_CALL(mDirectiveHandler,
+ handleExtension(pp::SourceLocation(0, 1), "foo", "bar"));
+ // Error reported about EOF.
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_EOF_IN_DIRECTIVE, _, _));
+
+ preprocess(str, expected);
+}
+
+TEST_F(ExtensionTest, ExtensionAfterNonPreProcessorTokenESSL1)
+{
+ const char *str = "int baz = 1;\n"
+ "#extension foo : bar\n";
+ const char *expected = "int baz = 1;\n\n";
+
+ using testing::_;
+ // Directive successfully parsed.
+ EXPECT_CALL(mDirectiveHandler,
+ handleExtension(pp::SourceLocation(0, 2), "foo", "bar"));
+ // Expect a warning about extension pragmas after non-preprocessor tokens.
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1, _, _));
+
+ preprocess(str, expected);
+}
+
+TEST_F(ExtensionTest, ExtensionAfterNonPreProcessorTokenESSL3)
+{
+ const char *str = "#version 300 es\n"
+ "int baz = 1;\n"
+ "#extension foo : bar\n";
+ const char *expected = "\nint baz = 1;\n\n";
+
+ using testing::_;
+ // Directive successfully parsed.
+ EXPECT_CALL(mDirectiveHandler,
+ handleVersion(pp::SourceLocation(0, 1), 300));
+ // Expect a error about extension pragmas after non-preprocessor tokens.
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3, _, _));
+
+ preprocess(str, expected);
+}
+
+struct ExtensionTestParam
+{
+ const char* str;
+ pp::Diagnostics::ID id;
+};
+
+using testing::WithParamInterface;
+class InvalidExtensionTest : public ExtensionTest,
+ public WithParamInterface<ExtensionTestParam>
+{
+};
+
+TEST_P(InvalidExtensionTest, Identified)
+{
+ ExtensionTestParam param = GetParam();
+ const char* expected = "\n";
+
+ using testing::_;
+ // No handleExtension call.
+ EXPECT_CALL(mDirectiveHandler, handleExtension(_, _, _)).Times(0);
+ // Invalid extension directive call.
+ EXPECT_CALL(mDiagnostics, print(param.id, pp::SourceLocation(0, 1), _));
+
+ preprocess(param.str, expected);
+}
+
+static const ExtensionTestParam kParams[] = {
+ {"#extension\n", pp::Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE},
+ {"#extension 1\n", pp::Diagnostics::PP_INVALID_EXTENSION_NAME},
+ {"#extension foo bar\n", pp::Diagnostics::PP_UNEXPECTED_TOKEN},
+ {"#extension foo : \n", pp::Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE},
+ {"#extension foo : 1\n", pp::Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR},
+ {"#extension foo : bar baz\n", pp::Diagnostics::PP_UNEXPECTED_TOKEN}
+};
+INSTANTIATE_TEST_CASE_P(All, InvalidExtensionTest, testing::ValuesIn(kParams));
diff --git a/gfx/angle/src/tests/preprocessor_tests/identifier_test.cpp b/gfx/angle/src/tests/preprocessor_tests/identifier_test.cpp
new file mode 100755
index 000000000..4712b38cb
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/identifier_test.cpp
@@ -0,0 +1,162 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "compiler/preprocessor/Token.h"
+
+#define CLOSED_RANGE(x, y) testing::Range(x, static_cast<char>((y) + 1))
+
+class IdentifierTest : public PreprocessorTest
+{
+protected:
+ void expectIdentifier(const std::string& str)
+ {
+ const char* cstr = str.c_str();
+ ASSERT_TRUE(mPreprocessor.init(1, &cstr, 0));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
+ EXPECT_EQ(str, token.text);
+ }
+};
+
+class SingleLetterIdentifierTest : public IdentifierTest,
+ public testing::WithParamInterface<char>
+{
+};
+
+// This test covers identifier names of form [_a-zA-Z].
+TEST_P(SingleLetterIdentifierTest, Identified)
+{
+ std::string str(1, GetParam());
+ expectIdentifier(str);
+}
+
+// Test string: '_'
+INSTANTIATE_TEST_CASE_P(Underscore,
+ SingleLetterIdentifierTest,
+ testing::Values('_'));
+
+// Test string: [a-z]
+INSTANTIATE_TEST_CASE_P(a_z,
+ SingleLetterIdentifierTest,
+ CLOSED_RANGE('a', 'z'));
+
+// Test string: [A-Z]
+INSTANTIATE_TEST_CASE_P(A_Z,
+ SingleLetterIdentifierTest,
+ CLOSED_RANGE('A', 'Z'));
+
+typedef std::tr1::tuple<char, char> IdentifierParams;
+class DoubleLetterIdentifierTest :
+ public IdentifierTest,
+ public testing::WithParamInterface<IdentifierParams>
+{
+};
+
+// This test covers identifier names of form [_a-zA-Z][_a-zA-Z0-9].
+TEST_P(DoubleLetterIdentifierTest, Identified)
+{
+ std::string str;
+ str.push_back(std::tr1::get<0>(GetParam()));
+ str.push_back(std::tr1::get<1>(GetParam()));
+
+ expectIdentifier(str);
+}
+
+// Test string: "__"
+INSTANTIATE_TEST_CASE_P(Underscore_Underscore,
+ DoubleLetterIdentifierTest,
+ testing::Combine(testing::Values('_'),
+ testing::Values('_')));
+
+// Test string: "_"[a-z]
+INSTANTIATE_TEST_CASE_P(Underscore_a_z,
+ DoubleLetterIdentifierTest,
+ testing::Combine(testing::Values('_'),
+ CLOSED_RANGE('a', 'z')));
+
+// Test string: "_"[A-Z]
+INSTANTIATE_TEST_CASE_P(Underscore_A_Z,
+ DoubleLetterIdentifierTest,
+ testing::Combine(testing::Values('_'),
+ CLOSED_RANGE('A', 'Z')));
+
+// Test string: "_"[0-9]
+INSTANTIATE_TEST_CASE_P(Underscore_0_9,
+ DoubleLetterIdentifierTest,
+ testing::Combine(testing::Values('_'),
+ CLOSED_RANGE('0', '9')));
+
+// Test string: [a-z]"_"
+INSTANTIATE_TEST_CASE_P(a_z_Underscore,
+ DoubleLetterIdentifierTest,
+ testing::Combine(CLOSED_RANGE('a', 'z'),
+ testing::Values('_')));
+
+// Test string: [a-z][a-z]
+INSTANTIATE_TEST_CASE_P(a_z_a_z,
+ DoubleLetterIdentifierTest,
+ testing::Combine(CLOSED_RANGE('a', 'z'),
+ CLOSED_RANGE('a', 'z')));
+
+// Test string: [a-z][A-Z]
+INSTANTIATE_TEST_CASE_P(a_z_A_Z,
+ DoubleLetterIdentifierTest,
+ testing::Combine(CLOSED_RANGE('a', 'z'),
+ CLOSED_RANGE('A', 'Z')));
+
+// Test string: [a-z][0-9]
+INSTANTIATE_TEST_CASE_P(a_z_0_9,
+ DoubleLetterIdentifierTest,
+ testing::Combine(CLOSED_RANGE('a', 'z'),
+ CLOSED_RANGE('0', '9')));
+
+// Test string: [A-Z]"_"
+INSTANTIATE_TEST_CASE_P(A_Z_Underscore,
+ DoubleLetterIdentifierTest,
+ testing::Combine(CLOSED_RANGE('A', 'Z'),
+ testing::Values('_')));
+
+// Test string: [A-Z][a-z]
+INSTANTIATE_TEST_CASE_P(A_Z_a_z,
+ DoubleLetterIdentifierTest,
+ testing::Combine(CLOSED_RANGE('A', 'Z'),
+ CLOSED_RANGE('a', 'z')));
+
+// Test string: [A-Z][A-Z]
+INSTANTIATE_TEST_CASE_P(A_Z_A_Z,
+ DoubleLetterIdentifierTest,
+ testing::Combine(CLOSED_RANGE('A', 'Z'),
+ CLOSED_RANGE('A', 'Z')));
+
+// Test string: [A-Z][0-9]
+INSTANTIATE_TEST_CASE_P(A_Z_0_9,
+ DoubleLetterIdentifierTest,
+ testing::Combine(CLOSED_RANGE('A', 'Z'),
+ CLOSED_RANGE('0', '9')));
+
+// The tests above cover one-letter and various combinations of two-letter
+// identifier names. This test covers all characters in a single string.
+TEST_F(IdentifierTest, AllLetters)
+{
+ std::string str;
+ for (char c = 'a'; c <= 'z'; ++c)
+ str.push_back(c);
+
+ str.push_back('_');
+
+ for (char c = 'A'; c <= 'Z'; ++c)
+ str.push_back(c);
+
+ str.push_back('_');
+
+ for (char c = '0'; c <= '9'; ++c)
+ str.push_back(c);
+
+ expectIdentifier(str);
+}
diff --git a/gfx/angle/src/tests/preprocessor_tests/if_test.cpp b/gfx/angle/src/tests/preprocessor_tests/if_test.cpp
new file mode 100755
index 000000000..7940b564a
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/if_test.cpp
@@ -0,0 +1,1048 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "compiler/preprocessor/Token.h"
+
+class IfTest : public PreprocessorTest
+{
+};
+
+TEST_F(IfTest, If_0)
+{
+ const char* str = "pass_1\n"
+ "#if 0\n"
+ "fail\n"
+ "#endif\n"
+ "pass_2\n";
+ const char* expected = "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, If_1)
+{
+ const char* str = "pass_1\n"
+ "#if 1\n"
+ "pass_2\n"
+ "#endif\n"
+ "pass_3\n";
+ const char* expected = "pass_1\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "pass_3\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, If_0_Else)
+{
+ const char* str = "pass_1\n"
+ "#if 0\n"
+ "fail\n"
+ "#else\n"
+ "pass_2\n"
+ "#endif\n"
+ "pass_3\n";
+ const char* expected = "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "pass_3\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, If_1_Else)
+{
+ const char* str = "pass_1\n"
+ "#if 1\n"
+ "pass_2\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n"
+ "pass_3\n";
+ const char* expected = "pass_1\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_3\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, If_0_Elif)
+{
+ const char* str = "pass_1\n"
+ "#if 0\n"
+ "fail_1\n"
+ "#elif 0\n"
+ "fail_2\n"
+ "#elif 1\n"
+ "pass_2\n"
+ "#elif 1\n"
+ "fail_3\n"
+ "#else\n"
+ "fail_4\n"
+ "#endif\n"
+ "pass_3\n";
+ const char* expected = "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_3\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, If_1_Elif)
+{
+ const char* str = "pass_1\n"
+ "#if 1\n"
+ "pass_2\n"
+ "#elif 0\n"
+ "fail_1\n"
+ "#elif 1\n"
+ "fail_2\n"
+ "#else\n"
+ "fail_4\n"
+ "#endif\n"
+ "pass_3\n";
+ const char* expected = "pass_1\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_3\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, If_Elif_Else)
+{
+ const char* str = "pass_1\n"
+ "#if 0\n"
+ "fail_1\n"
+ "#elif 0\n"
+ "fail_2\n"
+ "#elif 0\n"
+ "fail_3\n"
+ "#else\n"
+ "pass_2\n"
+ "#endif\n"
+ "pass_3\n";
+ const char* expected = "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "pass_3\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, If_0_Nested)
+{
+ const char* str = "pass_1\n"
+ "#if 0\n"
+ "fail_1\n"
+ "#if 1\n"
+ "fail_2\n"
+ "#else\n"
+ "fail_3\n"
+ "#endif\n"
+ "#else\n"
+ "pass_2\n"
+ "#endif\n"
+ "pass_3\n";
+ const char* expected = "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "pass_3\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, If_1_Nested)
+{
+ const char* str = "pass_1\n"
+ "#if 1\n"
+ "pass_2\n"
+ "#if 1\n"
+ "pass_3\n"
+ "#else\n"
+ "fail_1\n"
+ "#endif\n"
+ "#else\n"
+ "fail_2\n"
+ "#endif\n"
+ "pass_4\n";
+ const char* expected = "pass_1\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "pass_3\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_4\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorPrecedence)
+{
+ const char* str = "#if 1 + 2 * 3 + - (26 % 17 - + 4 / 2)\n"
+ "fail_1\n"
+ "#else\n"
+ "pass_1\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "pass_1\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorDefined)
+{
+ const char* str = "#if defined foo\n"
+ "fail_1\n"
+ "#else\n"
+ "pass_1\n"
+ "#endif\n"
+ "#define foo\n"
+ "#if defined(foo)\n"
+ "pass_2\n"
+ "#else\n"
+ "fail_2\n"
+ "#endif\n"
+ "#undef foo\n"
+ "#if defined ( foo ) \n"
+ "fail_3\n"
+ "#else\n"
+ "pass_3\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_3\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorEQ)
+{
+ const char* str = "#if 4 - 1 == 2 + 1\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorNE)
+{
+ const char* str = "#if 1 != 2\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorLess)
+{
+ const char* str = "#if 1 < 2\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorGreater)
+{
+ const char* str = "#if 2 > 1\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorLE)
+{
+ const char* str = "#if 1 <= 2\n"
+ "pass_1\n"
+ "#else\n"
+ "fail_1\n"
+ "#endif\n"
+ "#if 2 <= 2\n"
+ "pass_2\n"
+ "#else\n"
+ "fail_2\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorGE)
+{
+ const char* str = "#if 2 >= 1\n"
+ "pass_1\n"
+ "#else\n"
+ "fail_1\n"
+ "#endif\n"
+ "#if 2 >= 2\n"
+ "pass_2\n"
+ "#else\n"
+ "fail_2\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorBitwiseOR)
+{
+ const char* str = "#if (0xaaaaaaaa | 0x55555555) == 0xffffffff\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorBitwiseAND)
+{
+ const char* str = "#if (0xaaaaaaa & 0x5555555) == 0\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorBitwiseXOR)
+{
+ const char* str = "#if (0xaaaaaaa ^ 0x5555555) == 0xfffffff\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorBitwiseComplement)
+{
+ const char* str = "#if (~ 0xdeadbeef) == -3735928560\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorLeft)
+{
+ const char* str = "#if (1 << 12) == 4096\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorRight)
+{
+ const char* str = "#if (31762 >> 8) == 124\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, ExpressionWithMacros)
+{
+ const char* str = "#define one 1\n"
+ "#define two 2\n"
+ "#define three 3\n"
+ "#if one + two == three\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, JunkInsideExcludedBlockIgnored)
+{
+ const char* str = "#if 0\n"
+ "foo !@#$%^&* .1bar\n"
+ "#foo\n"
+ "#if bar\n"
+ "fail\n"
+ "#endif\n"
+ "#else\n"
+ "pass\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, Ifdef)
+{
+ const char* str = "#define foo\n"
+ "#ifdef foo\n"
+ "pass_1\n"
+ "#else\n"
+ "fail_1\n"
+ "#endif\n"
+ "#undef foo\n"
+ "#ifdef foo\n"
+ "fail_2\n"
+ "#else\n"
+ "pass_2\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "\n"
+ "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, Ifndef)
+{
+ const char* str = "#define foo\n"
+ "#ifndef foo\n"
+ "fail_1\n"
+ "#else\n"
+ "pass_1\n"
+ "#endif\n"
+ "#undef foo\n"
+ "#ifndef foo\n"
+ "pass_2\n"
+ "#else\n"
+ "fail_2\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, MissingExpression)
+{
+ const char* str = "#if\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_INVALID_EXPRESSION,
+ pp::SourceLocation(0, 1),
+ "syntax error"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, DivisionByZero)
+{
+ const char* str = "#if 1 / (3 - (1 + 2))\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_DIVISION_BY_ZERO,
+ pp::SourceLocation(0, 1), "1 / 0"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, ModuloByZero)
+{
+ const char* str = "#if 1 % (3 - (1 + 2))\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_DIVISION_BY_ZERO,
+ pp::SourceLocation(0, 1), "1 % 0"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, DecIntegerOverflow)
+{
+ const char* str = "#if 4294967296\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_INTEGER_OVERFLOW,
+ pp::SourceLocation(0, 1), "4294967296"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, OctIntegerOverflow)
+{
+ const char* str = "#if 077777777777\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_INTEGER_OVERFLOW,
+ pp::SourceLocation(0, 1), "077777777777"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, HexIntegerOverflow)
+{
+ const char* str = "#if 0xfffffffff\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_INTEGER_OVERFLOW,
+ pp::SourceLocation(0, 1), "0xfffffffff"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, UndefinedMacro)
+{
+ const char* str = "#if UNDEFINED\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
+ pp::SourceLocation(0, 1),
+ "UNDEFINED"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, InvalidExpressionIgnoredForExcludedElif)
+{
+ const char* str = "#if 1\n"
+ "pass\n"
+ "#elif UNDEFINED\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ // No error or warning.
+ using testing::_;
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, ElseWithoutIf)
+{
+ const char* str = "#else\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
+ pp::SourceLocation(0, 1),
+ "else"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, ElifWithoutIf)
+{
+ const char* str = "#elif 1\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
+ pp::SourceLocation(0, 1),
+ "elif"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, EndifWithoutIf)
+{
+ const char* str = "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
+ pp::SourceLocation(0, 1),
+ "endif"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, ElseAfterElse)
+{
+ const char* str = "#if 1\n"
+ "#else\n"
+ "#else\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
+ pp::SourceLocation(0, 3),
+ "else"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, ElifAfterElse)
+{
+ const char* str = "#if 1\n"
+ "#else\n"
+ "#elif 0\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
+ pp::SourceLocation(0, 3),
+ "elif"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, UnterminatedIf)
+{
+ const char* str = "#if 1\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_CONDITIONAL_UNTERMINATED,
+ pp::SourceLocation(0, 1),
+ "if"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, UnterminatedIfdef)
+{
+ const char* str = "#ifdef foo\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_CONDITIONAL_UNTERMINATED,
+ pp::SourceLocation(0, 1),
+ "ifdef"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+// The preprocessor only allows one expression to follow an #if directive.
+// Supplying two integer expressions should be an error.
+TEST_F(IfTest, ExtraIntExpression)
+{
+ const char *str =
+ "#if 1 1\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
+ pp::SourceLocation(0, 1), "1"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+// The preprocessor only allows one expression to follow an #if directive.
+// Supplying two expressions where one uses a preprocessor define should be an error.
+TEST_F(IfTest, ExtraIdentifierExpression)
+{
+ const char *str =
+ "#define one 1\n"
+ "#if 1 one\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
+ pp::SourceLocation(0, 2), "1"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+// Divide by zero that's not evaluated because of short-circuiting should not cause an error.
+TEST_F(IfTest, ShortCircuitedDivideByZero)
+{
+ const char *str =
+ "#if 1 || (2 / 0)\n"
+ "pass\n"
+ "#endif\n";
+ const char *expected =
+ "\n"
+ "pass\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+// Undefined identifier that's not evaluated because of short-circuiting should not cause an error.
+TEST_F(IfTest, ShortCircuitedUndefined)
+{
+ const char *str =
+ "#if 1 || UNDEFINED\n"
+ "pass\n"
+ "#endif\n";
+ const char *expected =
+ "\n"
+ "pass\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+// Defined operator produced by macro expansion has undefined behavior according to C++ spec,
+// which the GLSL spec references (see C++14 draft spec section 16.1.4), but this behavior is
+// needed for passing dEQP tests, which enforce stricter compatibility between implementations.
+TEST_F(IfTest, DefinedOperatorValidAfterMacroExpansion)
+{
+ const char *str =
+ "#define foo defined\n"
+ "#if !foo bar\n"
+ "pass\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
+ pp::SourceLocation(0, 2), "defined"));
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
+ pp::SourceLocation(0, 2), "bar"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+// Defined operator produced by macro expansion has undefined behavior according to C++ spec,
+// which the GLSL spec references (see C++14 draft spec section 16.1.4), but this behavior is
+// needed for passing dEQP tests, which enforce stricter compatibility between implementations.
+TEST_F(IfTest, UnterminatedDefinedInMacro)
+{
+ const char *str =
+ "#define foo defined(\n"
+ "#if foo\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
+ pp::SourceLocation(0, 2), "defined"));
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
+ pp::SourceLocation(0, 2), "("));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+// Defined operator produced by macro expansion has undefined behavior according to C++ spec,
+// which the GLSL spec references (see C++14 draft spec section 16.1.4), but this behavior is
+// needed for passing dEQP tests, which enforce stricter compatibility between implementations.
+TEST_F(IfTest, UnterminatedDefinedInMacro2)
+{
+ const char *str =
+ "#define foo defined(bar\n"
+ "#if foo\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
+ pp::SourceLocation(0, 2), "defined"));
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
+ pp::SourceLocation(0, 2), "("));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+// Undefined shift: negative shift offset.
+TEST_F(IfTest, BitShiftLeftOperatorNegativeOffset)
+{
+ const char *str =
+ "#if 2 << -1 == 1\n"
+ "foo\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_UNDEFINED_SHIFT, pp::SourceLocation(0, 1), "2 << -1"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+// Undefined shift: shift offset is out of range.
+TEST_F(IfTest, BitShiftLeftOperatorOffset32)
+{
+ const char *str =
+ "#if 2 << 32 == 1\n"
+ "foo\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_UNDEFINED_SHIFT, pp::SourceLocation(0, 1), "2 << 32"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+// Left hand side of shift is negative.
+TEST_F(IfTest, BitShiftLeftOperatorNegativeLHS)
+{
+ const char *str =
+ "#if (-2) << 1 == -4\n"
+ "pass\n"
+ "#endif\n";
+ const char *expected =
+ "\n"
+ "pass\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+// Undefined shift: shift offset is out of range.
+TEST_F(IfTest, BitShiftRightOperatorNegativeOffset)
+{
+ const char *str =
+ "#if 2 >> -1 == 4\n"
+ "foo\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_UNDEFINED_SHIFT, pp::SourceLocation(0, 1), "2 >> -1"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+// Undefined shift: shift offset is out of range.
+TEST_F(IfTest, BitShiftRightOperatorOffset32)
+{
+ const char *str =
+ "#if 2 >> 32 == 0\n"
+ "foo\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_UNDEFINED_SHIFT, pp::SourceLocation(0, 1), "2 >> 32"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+// Left hand side of shift is negative.
+TEST_F(IfTest, BitShiftRightOperatorNegativeLHS)
+{
+ const char *str =
+ "#if (-2) >> 1 == 0x7fffffff\n"
+ "pass\n"
+ "#endif\n";
+ const char *expected =
+ "\n"
+ "pass\n"
+ "\n";
+
+ preprocess(str, expected);
+}
diff --git a/gfx/angle/src/tests/preprocessor_tests/input_test.cpp b/gfx/angle/src/tests/preprocessor_tests/input_test.cpp
new file mode 100755
index 000000000..ca1878c5f
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/input_test.cpp
@@ -0,0 +1,178 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "compiler/preprocessor/Input.h"
+#include "compiler/preprocessor/Token.h"
+
+class InitTest : public PreprocessorTest
+{
+};
+
+TEST_F(InitTest, ZeroCount)
+{
+ EXPECT_TRUE(mPreprocessor.init(0, NULL, NULL));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::LAST, token.type);
+}
+
+TEST_F(InitTest, NullString)
+{
+ EXPECT_FALSE(mPreprocessor.init(1, NULL, NULL));
+}
+
+TEST(InputTest, DefaultConstructor)
+{
+ pp::Input input;
+ EXPECT_EQ(0u, input.count());
+ int lineNo = 0;
+ EXPECT_EQ(0u, input.read(NULL, 1, &lineNo));
+}
+
+TEST(InputTest, NullLength)
+{
+ const char* str[] = {"foo"};
+ pp::Input input(1, str, NULL);
+ EXPECT_EQ(3u, input.length(0));
+}
+
+TEST(InputTest, NegativeLength)
+{
+ const char* str[] = {"foo"};
+ int length[] = {-1};
+ pp::Input input(1, str, length);
+ EXPECT_EQ(3u, input.length(0));
+}
+
+TEST(InputTest, ActualLength)
+{
+ const char* str[] = {"foobar"};
+ int length[] = {3};
+ pp::Input input(1, str, length);
+ // Note that strlen(str[0]) != length[0].
+ // Even then Input should just accept any non-negative number.
+ EXPECT_EQ(static_cast<size_t>(length[0]), input.length(0));
+}
+
+TEST(InputTest, String)
+{
+ const char* str[] = {"foo"};
+ pp::Input input(1, str, NULL);
+ EXPECT_STREQ(str[0], input.string(0));
+}
+
+TEST(InputTest, ReadSingleString)
+{
+ int count = 1;
+ const char* str[] = {"foo"};
+ char buf[4] = {'\0', '\0', '\0', '\0'};
+
+ int maxSize = 1;
+ int lineNo = 0;
+ pp::Input input1(count, str, NULL);
+ EXPECT_EQ(1u, input1.read(buf, maxSize, &lineNo));
+ EXPECT_EQ('f', buf[0]);
+ EXPECT_EQ(1u, input1.read(buf, maxSize, &lineNo));
+ EXPECT_EQ('o', buf[0]);
+ EXPECT_EQ(1u, input1.read(buf, maxSize, &lineNo));
+ EXPECT_EQ('o', buf[0]);
+ EXPECT_EQ(0u, input1.read(buf, maxSize, &lineNo));
+
+ maxSize = 2;
+ pp::Input input2(count, str, NULL);
+ EXPECT_EQ(2u, input2.read(buf, maxSize, &lineNo));
+ EXPECT_STREQ("fo", buf);
+ EXPECT_EQ(1u, input2.read(buf, maxSize, &lineNo));
+ EXPECT_EQ('o', buf[0]);
+ EXPECT_EQ(0u, input2.read(buf, maxSize, &lineNo));
+
+ maxSize = 3;
+ pp::Input input3(count, str, NULL);
+ EXPECT_EQ(3u, input3.read(buf, maxSize, &lineNo));
+ EXPECT_STREQ("foo", buf);
+ EXPECT_EQ(0u, input3.read(buf, maxSize, &lineNo));
+
+ maxSize = 4;
+ pp::Input input4(count, str, NULL);
+ EXPECT_EQ(3u, input4.read(buf, maxSize, &lineNo));
+ EXPECT_STREQ("foo", buf);
+ EXPECT_EQ(0u, input4.read(buf, maxSize, &lineNo));
+}
+
+TEST(InputTest, ReadMultipleStrings)
+{
+ int count = 3;
+ const char* str[] = {"f", "o", "o"};
+ char buf[4] = {'\0', '\0', '\0', '\0'};
+
+ int maxSize = 1;
+ int lineNo = 0;
+ pp::Input input1(count, str, NULL);
+ EXPECT_EQ(1u, input1.read(buf, maxSize, &lineNo));
+ EXPECT_EQ('f', buf[0]);
+ EXPECT_EQ(1u, input1.read(buf, maxSize, &lineNo));
+ EXPECT_EQ('o', buf[0]);
+ EXPECT_EQ(1u, input1.read(buf, maxSize, &lineNo));
+ EXPECT_EQ('o', buf[0]);
+ EXPECT_EQ(0u, input1.read(buf, maxSize, &lineNo));
+
+ maxSize = 2;
+ pp::Input input2(count, str, NULL);
+ EXPECT_EQ(2u, input2.read(buf, maxSize, &lineNo));
+ EXPECT_STREQ("fo", buf);
+ EXPECT_EQ(1u, input2.read(buf, maxSize, &lineNo));
+ EXPECT_EQ('o', buf[0]);
+ EXPECT_EQ(0u, input2.read(buf, maxSize, &lineNo));
+
+ maxSize = 3;
+ pp::Input input3(count, str, NULL);
+ EXPECT_EQ(3u, input3.read(buf, maxSize, &lineNo));
+ EXPECT_STREQ("foo", buf);
+ EXPECT_EQ(0u, input3.read(buf, maxSize, &lineNo));
+
+ maxSize = 4;
+ pp::Input input4(count, str, NULL);
+ EXPECT_EQ(3u, input4.read(buf, maxSize, &lineNo));
+ EXPECT_STREQ("foo", buf);
+ EXPECT_EQ(0u, input4.read(buf, maxSize, &lineNo));
+}
+
+TEST(InputTest, ReadStringsWithLength)
+{
+ int count = 2;
+ const char* str[] = {"foo", "bar"};
+ // Note that the length for the first string is 2 which is less than
+ // strlen(str[0]. We want to make sure that the last character is ignored.
+ int length[] = {2, 3};
+ char buf[6] = {'\0', '\0', '\0', '\0', '\0', '\0'};
+ size_t maxSize = 5;
+ int lineNo = 0;
+
+ pp::Input input(count, str, length);
+ EXPECT_EQ(maxSize, input.read(buf, maxSize, &lineNo));
+ EXPECT_STREQ("fobar", buf);
+}
+
+TEST(InputTest, ReadStringsWithLineContinuation)
+{
+ int count = 2;
+ const char* str[] = {"foo\\", "\nba\\\r\nr"};
+ int length[] = {4, 7};
+ char buf[11] = {'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'};
+ size_t maxSize = 11;
+ int lineNo = 0;
+
+ pp::Input input(count, str, length);
+ EXPECT_EQ(3u, input.read(buf, maxSize, &lineNo));
+ EXPECT_EQ(0, lineNo);
+ EXPECT_EQ(2u, input.read(buf + 3, maxSize - 3, &lineNo));
+ EXPECT_EQ(1, lineNo);
+ EXPECT_EQ(1u, input.read(buf + 5, maxSize - 5, &lineNo));
+ EXPECT_EQ(2, lineNo);
+ EXPECT_STREQ("foobar", buf);
+}
diff --git a/gfx/angle/src/tests/preprocessor_tests/location_test.cpp b/gfx/angle/src/tests/preprocessor_tests/location_test.cpp
new file mode 100755
index 000000000..ebaf68a83
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/location_test.cpp
@@ -0,0 +1,351 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "compiler/preprocessor/Token.h"
+
+class LocationTest : public PreprocessorTest
+{
+protected:
+ void expectLocation(int count,
+ const char* const string[],
+ const int length[],
+ const pp::SourceLocation& location)
+ {
+ ASSERT_TRUE(mPreprocessor.init(count, string, length));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
+ EXPECT_EQ("foo", token.text);
+
+ EXPECT_EQ(location.file, token.location.file);
+ EXPECT_EQ(location.line, token.location.line);
+ }
+};
+
+TEST_F(LocationTest, String0_Line1)
+{
+ const char* str = "foo";
+ pp::SourceLocation loc(0, 1);
+
+ SCOPED_TRACE("String0_Line1");
+ expectLocation(1, &str, NULL, loc);
+}
+
+TEST_F(LocationTest, String0_Line2)
+{
+ const char* str = "\nfoo";
+ pp::SourceLocation loc(0, 2);
+
+ SCOPED_TRACE("String0_Line2");
+ expectLocation(1, &str, NULL, loc);
+}
+
+TEST_F(LocationTest, String1_Line1)
+{
+ const char* const str[] = {"\n\n", "foo"};
+ pp::SourceLocation loc(1, 1);
+
+ SCOPED_TRACE("String1_Line1");
+ expectLocation(2, str, NULL, loc);
+}
+
+TEST_F(LocationTest, String1_Line2)
+{
+ const char* const str[] = {"\n\n", "\nfoo"};
+ pp::SourceLocation loc(1, 2);
+
+ SCOPED_TRACE("String1_Line2");
+ expectLocation(2, str, NULL, loc);
+}
+
+TEST_F(LocationTest, NewlineInsideCommentCounted)
+{
+ const char* str = "/*\n\n*/foo";
+ pp::SourceLocation loc(0, 3);
+
+ SCOPED_TRACE("NewlineInsideCommentCounted");
+ expectLocation(1, &str, NULL, loc);
+}
+
+TEST_F(LocationTest, ErrorLocationAfterComment)
+{
+ const char* str = "/*\n\n*/@";
+
+ ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_INVALID_CHARACTER,
+ pp::SourceLocation(0, 3),
+ "@"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+// The location of a token straddling two or more strings is that of the
+// first character of the token.
+
+TEST_F(LocationTest, TokenStraddlingTwoStrings)
+{
+ const char* const str[] = {"f", "oo"};
+ pp::SourceLocation loc(0, 1);
+
+ SCOPED_TRACE("TokenStraddlingTwoStrings");
+ expectLocation(2, str, NULL, loc);
+}
+
+TEST_F(LocationTest, TokenStraddlingThreeStrings)
+{
+ const char* const str[] = {"f", "o", "o"};
+ pp::SourceLocation loc(0, 1);
+
+ SCOPED_TRACE("TokenStraddlingThreeStrings");
+ expectLocation(3, str, NULL, loc);
+}
+
+TEST_F(LocationTest, EndOfFileWithoutNewline)
+{
+ const char* const str[] = {"foo"};
+ ASSERT_TRUE(mPreprocessor.init(1, str, NULL));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
+ EXPECT_EQ("foo", token.text);
+ EXPECT_EQ(0, token.location.file);
+ EXPECT_EQ(1, token.location.line);
+
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::LAST, token.type);
+ EXPECT_EQ(0, token.location.file);
+ EXPECT_EQ(1, token.location.line);
+}
+
+TEST_F(LocationTest, EndOfFileAfterNewline)
+{
+ const char* const str[] = {"foo\n"};
+ ASSERT_TRUE(mPreprocessor.init(1, str, NULL));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
+ EXPECT_EQ("foo", token.text);
+ EXPECT_EQ(0, token.location.file);
+ EXPECT_EQ(1, token.location.line);
+
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::LAST, token.type);
+ EXPECT_EQ(0, token.location.file);
+ EXPECT_EQ(2, token.location.line);
+}
+
+TEST_F(LocationTest, EndOfFileAfterEmptyString)
+{
+ const char* const str[] = {"foo\n", "\n", ""};
+ ASSERT_TRUE(mPreprocessor.init(3, str, NULL));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
+ EXPECT_EQ("foo", token.text);
+ EXPECT_EQ(0, token.location.file);
+ EXPECT_EQ(1, token.location.line);
+
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::LAST, token.type);
+ EXPECT_EQ(2, token.location.file);
+ EXPECT_EQ(1, token.location.line);
+}
+
+TEST_F(LocationTest, ValidLineDirective1)
+{
+ const char* str = "#line 10\n"
+ "foo";
+ pp::SourceLocation loc(0, 10);
+
+ SCOPED_TRACE("ValidLineDirective1");
+ expectLocation(1, &str, NULL, loc);
+}
+
+TEST_F(LocationTest, ValidLineDirective2)
+{
+ const char* str = "#line 10 20\n"
+ "foo";
+ pp::SourceLocation loc(20, 10);
+
+ SCOPED_TRACE("ValidLineDirective2");
+ expectLocation(1, &str, NULL, loc);
+}
+
+TEST_F(LocationTest, LineDirectiveCommentsIgnored)
+{
+ const char* str = "/* bar */"
+ "#"
+ "/* bar */"
+ "line"
+ "/* bar */"
+ "10"
+ "/* bar */"
+ "20"
+ "/* bar */"
+ "// bar "
+ "\n"
+ "foo";
+ pp::SourceLocation loc(20, 10);
+
+ SCOPED_TRACE("LineDirectiveCommentsIgnored");
+ expectLocation(1, &str, NULL, loc);
+}
+
+TEST_F(LocationTest, LineDirectiveWithMacro1)
+{
+ const char* str = "#define L 10\n"
+ "#define F(x) x\n"
+ "#line L F(20)\n"
+ "foo";
+ pp::SourceLocation loc(20, 10);
+
+ SCOPED_TRACE("LineDirectiveWithMacro1");
+ expectLocation(1, &str, NULL, loc);
+}
+
+TEST_F(LocationTest, LineDirectiveWithMacro2)
+{
+ const char* str = "#define LOC 10 20\n"
+ "#line LOC\n"
+ "foo";
+ pp::SourceLocation loc(20, 10);
+
+ SCOPED_TRACE("LineDirectiveWithMacro2");
+ expectLocation(1, &str, NULL, loc);
+}
+
+TEST_F(LocationTest, LineDirectiveWithPredefinedMacro)
+{
+ const char* str = "#line __LINE__ __FILE__\n"
+ "foo";
+ pp::SourceLocation loc(0, 1);
+
+ SCOPED_TRACE("LineDirectiveWithMacro");
+ expectLocation(1, &str, NULL, loc);
+}
+
+TEST_F(LocationTest, LineDirectiveNewlineBeforeStringBreak)
+{
+ const char* const str[] = {"#line 10 20\n", "foo"};
+ // String number is incremented after it is set by the line directive.
+ // Also notice that line number is reset after the string break.
+ pp::SourceLocation loc(21, 1);
+
+ SCOPED_TRACE("LineDirectiveNewlineBeforeStringBreak");
+ expectLocation(2, str, NULL, loc);
+}
+
+TEST_F(LocationTest, LineDirectiveNewlineAfterStringBreak)
+{
+ const char* const str[] = {"#line 10 20", "\nfoo"};
+ // String number is incremented before it is set by the line directive.
+ pp::SourceLocation loc(20, 10);
+
+ SCOPED_TRACE("LineDirectiveNewlineAfterStringBreak");
+ expectLocation(2, str, NULL, loc);
+}
+
+TEST_F(LocationTest, LineDirectiveMissingNewline)
+{
+ const char* str = "#line 10";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
+
+ using testing::_;
+ // Error reported about EOF.
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_EOF_IN_DIRECTIVE, _, _));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+struct LineTestParam
+{
+ const char* str;
+ pp::Diagnostics::ID id;
+};
+
+class InvalidLineTest : public LocationTest,
+ public testing::WithParamInterface<LineTestParam>
+{
+};
+
+TEST_P(InvalidLineTest, Identified)
+{
+ LineTestParam param = GetParam();
+ ASSERT_TRUE(mPreprocessor.init(1, &param.str, NULL));
+
+ using testing::_;
+ // Invalid line directive call.
+ EXPECT_CALL(mDiagnostics, print(param.id, pp::SourceLocation(0, 1), _));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+static const LineTestParam kParams[] = {
+ {"#line\n", pp::Diagnostics::PP_INVALID_LINE_DIRECTIVE},
+ {"#line foo\n", pp::Diagnostics::PP_INVALID_LINE_NUMBER},
+ {"#line defined(foo)\n", pp::Diagnostics::PP_INVALID_LINE_NUMBER},
+ {"#line 10 foo\n", pp::Diagnostics::PP_INVALID_FILE_NUMBER},
+ {"#line 10 20 foo\n", pp::Diagnostics::PP_UNEXPECTED_TOKEN},
+ {"#line 0xffffffff\n", pp::Diagnostics::PP_INTEGER_OVERFLOW},
+ {"#line 10 0xffffffff\n", pp::Diagnostics::PP_INTEGER_OVERFLOW}};
+
+INSTANTIATE_TEST_CASE_P(All, InvalidLineTest, testing::ValuesIn(kParams));
+
+struct LineExpressionTestParam
+{
+ const char *expression;
+ int expectedLine;
+};
+
+class LineExpressionTest : public LocationTest,
+ public testing::WithParamInterface<LineExpressionTestParam>
+{
+};
+
+TEST_P(LineExpressionTest, ExpressionEvaluation)
+{
+ LineExpressionTestParam param = GetParam();
+ const char *strs[3] = {"#line ", param.expression, "\nfoo"};
+
+ pp::SourceLocation loc(2, param.expectedLine);
+
+ expectLocation(3, strs, NULL, loc);
+}
+
+static const LineExpressionTestParam kParamsLineExpressionTest[] = {
+ {"1 + 2", 3},
+ {"5 - 3", 2},
+ {"7 * 11", 77},
+ {"20 / 10", 2},
+ {"10 % 5", 0},
+ {"7 && 3", 1},
+ {"7 || 0", 1},
+ {"11 == 11", 1},
+ {"11 != 11", 0},
+ {"11 > 7", 1},
+ {"11 < 7", 0},
+ {"11 >= 7", 1},
+ {"11 <= 7", 0},
+ {"!11", 0},
+ {"-1", -1},
+ {"+9", 9},
+ {"(1 + 2) * 4", 12},
+ {"3 | 5", 7},
+ {"3 ^ 5", 6},
+ {"3 & 5", 1},
+ {"~5", ~5},
+ {"2 << 3", 16},
+ {"16 >> 2", 4}};
+
+INSTANTIATE_TEST_CASE_P(All, LineExpressionTest, testing::ValuesIn(kParamsLineExpressionTest));
diff --git a/gfx/angle/src/tests/preprocessor_tests/number_test.cpp b/gfx/angle/src/tests/preprocessor_tests/number_test.cpp
new file mode 100755
index 000000000..4e295d307
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/number_test.cpp
@@ -0,0 +1,170 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "compiler/preprocessor/Token.h"
+
+#define CLOSED_RANGE(x, y) testing::Range(x, static_cast<char>((y) + 1))
+
+class InvalidNumberTest : public PreprocessorTest,
+ public testing::WithParamInterface<const char*>
+{
+};
+
+TEST_P(InvalidNumberTest, InvalidNumberIdentified)
+{
+ const char* str = GetParam();
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ using testing::_;
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_INVALID_NUMBER, _, str));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+INSTANTIATE_TEST_CASE_P(InvalidIntegers, InvalidNumberTest,
+ testing::Values("1a", "08", "0xG"));
+
+
+INSTANTIATE_TEST_CASE_P(InvalidFloats, InvalidNumberTest,
+ testing::Values("1eg", "0.a", "0.1.2", ".0a", ".0.1"));
+
+typedef std::tr1::tuple<const char*, char> IntegerParams;
+class IntegerTest : public PreprocessorTest,
+ public testing::WithParamInterface<IntegerParams>
+{
+};
+
+TEST_P(IntegerTest, Identified)
+{
+ std::string str(std::tr1::get<0>(GetParam())); // prefix.
+ str.push_back(std::tr1::get<1>(GetParam())); // digit.
+ const char* cstr = str.c_str();
+
+ ASSERT_TRUE(mPreprocessor.init(1, &cstr, 0));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::CONST_INT, token.type);
+ EXPECT_EQ(str, token.text);
+}
+
+INSTANTIATE_TEST_CASE_P(DecimalInteger,
+ IntegerTest,
+ testing::Combine(testing::Values(""),
+ CLOSED_RANGE('0', '9')));
+
+INSTANTIATE_TEST_CASE_P(OctalInteger,
+ IntegerTest,
+ testing::Combine(testing::Values("0"),
+ CLOSED_RANGE('0', '7')));
+
+INSTANTIATE_TEST_CASE_P(HexadecimalInteger_0_9,
+ IntegerTest,
+ testing::Combine(testing::Values("0x", "0X"),
+ CLOSED_RANGE('0', '9')));
+
+INSTANTIATE_TEST_CASE_P(HexadecimalInteger_a_f,
+ IntegerTest,
+ testing::Combine(testing::Values("0x", "0X"),
+ CLOSED_RANGE('a', 'f')));
+
+INSTANTIATE_TEST_CASE_P(HexadecimalInteger_A_F,
+ IntegerTest,
+ testing::Combine(testing::Values("0x", "0X"),
+ CLOSED_RANGE('A', 'F')));
+
+class FloatTest : public PreprocessorTest
+{
+ protected:
+ void expectFloat(const std::string& str)
+ {
+ const char* cstr = str.c_str();
+ ASSERT_TRUE(mPreprocessor.init(1, &cstr, 0));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::CONST_FLOAT, token.type);
+ EXPECT_EQ(str, token.text);
+ }
+};
+
+typedef std::tr1::tuple<char, char, const char*, char> FloatScientificParams;
+class FloatScientificTest :
+ public FloatTest,
+ public testing::WithParamInterface<FloatScientificParams>
+{
+};
+
+// This test covers floating point numbers of form [0-9][eE][+-]?[0-9].
+TEST_P(FloatScientificTest, FloatIdentified)
+{
+ std::string str;
+ str.push_back(std::tr1::get<0>(GetParam())); // significand [0-9].
+ str.push_back(std::tr1::get<1>(GetParam())); // separator [eE].
+ str.append(std::tr1::get<2>(GetParam())); // sign [" " "+" "-"].
+ str.push_back(std::tr1::get<3>(GetParam())); // exponent [0-9].
+
+ SCOPED_TRACE("FloatScientificTest");
+ expectFloat(str);
+}
+
+INSTANTIATE_TEST_CASE_P(FloatScientific,
+ FloatScientificTest,
+ testing::Combine(CLOSED_RANGE('0', '9'),
+ testing::Values('e', 'E'),
+ testing::Values("", "+", "-"),
+ CLOSED_RANGE('0', '9')));
+
+typedef std::tr1::tuple<char, char> FloatFractionParams;
+class FloatFractionTest :
+ public FloatTest,
+ public testing::WithParamInterface<FloatFractionParams>
+{
+};
+
+// This test covers floating point numbers of form [0-9]"." and [0-9]?"."[0-9].
+TEST_P(FloatFractionTest, FloatIdentified)
+{
+ std::string str;
+
+ char significand = std::tr1::get<0>(GetParam());
+ if (significand != '\0')
+ str.push_back(significand);
+
+ str.push_back('.');
+
+ char fraction = std::tr1::get<1>(GetParam());
+ if (fraction != '\0')
+ str.push_back(fraction);
+
+ SCOPED_TRACE("FloatFractionTest");
+ expectFloat(str);
+}
+
+INSTANTIATE_TEST_CASE_P(FloatFraction_X_X,
+ FloatFractionTest,
+ testing::Combine(CLOSED_RANGE('0', '9'),
+ CLOSED_RANGE('0', '9')));
+
+INSTANTIATE_TEST_CASE_P(FloatFraction_0_X,
+ FloatFractionTest,
+ testing::Combine(testing::Values('\0'),
+ CLOSED_RANGE('0', '9')));
+
+INSTANTIATE_TEST_CASE_P(FloatFraction_X_0,
+ FloatFractionTest,
+ testing::Combine(CLOSED_RANGE('0', '9'),
+ testing::Values('\0')));
+
+// In the tests above we have tested individual parts of a float separately.
+// This test has all parts of a float.
+TEST_F(FloatTest, FractionScientific)
+{
+ SCOPED_TRACE("FractionScientific");
+ expectFloat("0.1e+2");
+}
diff --git a/gfx/angle/src/tests/preprocessor_tests/operator_test.cpp b/gfx/angle/src/tests/preprocessor_tests/operator_test.cpp
new file mode 100755
index 000000000..505cbe3fc
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/operator_test.cpp
@@ -0,0 +1,80 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "compiler/preprocessor/Token.h"
+
+struct OperatorTestParam
+{
+ const char* str;
+ int op;
+};
+
+class OperatorTest : public PreprocessorTest,
+ public testing::WithParamInterface<OperatorTestParam>
+{
+};
+
+TEST_P(OperatorTest, Identified)
+{
+ OperatorTestParam param = GetParam();
+
+ ASSERT_TRUE(mPreprocessor.init(1, &param.str, 0));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(param.op, token.type);
+ EXPECT_EQ(param.str, token.text);
+}
+
+static const OperatorTestParam kOperators[] = {
+ {"(", '('},
+ {")", ')'},
+ {"[", '['},
+ {"]", ']'},
+ {".", '.'},
+ {"+", '+'},
+ {"-", '-'},
+ {"~", '~'},
+ {"!", '!'},
+ {"*", '*'},
+ {"/", '/'},
+ {"%", '%'},
+ {"<", '<'},
+ {">", '>'},
+ {"&", '&'},
+ {"^", '^'},
+ {"|", '|'},
+ {"?", '?'},
+ {":", ':'},
+ {"=", '='},
+ {",", ','},
+ {"++", pp::Token::OP_INC},
+ {"--", pp::Token::OP_DEC},
+ {"<<", pp::Token::OP_LEFT},
+ {">>", pp::Token::OP_RIGHT},
+ {"<=", pp::Token::OP_LE},
+ {">=", pp::Token::OP_GE},
+ {"==", pp::Token::OP_EQ},
+ {"!=", pp::Token::OP_NE},
+ {"&&", pp::Token::OP_AND},
+ {"^^", pp::Token::OP_XOR},
+ {"||", pp::Token::OP_OR},
+ {"+=", pp::Token::OP_ADD_ASSIGN},
+ {"-=", pp::Token::OP_SUB_ASSIGN},
+ {"*=", pp::Token::OP_MUL_ASSIGN},
+ {"/=", pp::Token::OP_DIV_ASSIGN},
+ {"%=", pp::Token::OP_MOD_ASSIGN},
+ {"<<=", pp::Token::OP_LEFT_ASSIGN},
+ {">>=", pp::Token::OP_RIGHT_ASSIGN},
+ {"&=", pp::Token::OP_AND_ASSIGN},
+ {"^=", pp::Token::OP_XOR_ASSIGN},
+ {"|=", pp::Token::OP_OR_ASSIGN}
+};
+
+INSTANTIATE_TEST_CASE_P(All, OperatorTest,
+ testing::ValuesIn(kOperators));
+
diff --git a/gfx/angle/src/tests/preprocessor_tests/pragma_test.cpp b/gfx/angle/src/tests/preprocessor_tests/pragma_test.cpp
new file mode 100755
index 000000000..92992aced
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/pragma_test.cpp
@@ -0,0 +1,154 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "compiler/preprocessor/Token.h"
+
+class PragmaTest : public PreprocessorTest
+{
+};
+
+TEST_F(PragmaTest, EmptyName)
+{
+ const char* str = "#pragma\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ // No handlePragma calls.
+ EXPECT_CALL(mDirectiveHandler, handlePragma(_, _, _, false)).Times(0);
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(PragmaTest, EmptyValue)
+{
+ const char* str = "#pragma foo\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handlePragma(pp::SourceLocation(0, 1), "foo", "", false));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(PragmaTest, NameValue)
+{
+ const char* str = "#pragma foo(bar)\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handlePragma(pp::SourceLocation(0, 1), "foo", "bar", false));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(PragmaTest, STDGL)
+{
+ const char* str = "#pragma STDGL\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handlePragma(_, _, _, _)).Times(0);
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(PragmaTest, STDGLInvariantAll)
+{
+ const char* str = "#pragma STDGL invariant(all)\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handlePragma(pp::SourceLocation(0, 1), "invariant", "all", true));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(PragmaTest, Comments)
+{
+ const char* str = "/*foo*/"
+ "#"
+ "/*foo*/"
+ "pragma"
+ "/*foo*/"
+ "foo"
+ "/*foo*/"
+ "("
+ "/*foo*/"
+ "bar"
+ "/*foo*/"
+ ")"
+ "/*foo*/"
+ "//foo"
+ "\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handlePragma(pp::SourceLocation(0, 1), "foo", "bar", false));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(PragmaTest, MissingNewline)
+{
+ const char* str = "#pragma foo(bar)";
+ const char* expected = "";
+
+ using testing::_;
+ // Pragma successfully parsed.
+ EXPECT_CALL(mDirectiveHandler,
+ handlePragma(pp::SourceLocation(0, 1), "foo", "bar", false));
+ // Error reported about EOF.
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_EOF_IN_DIRECTIVE, _, _));
+
+ preprocess(str, expected);
+}
+
+class InvalidPragmaTest : public PragmaTest,
+ public testing::WithParamInterface<const char*>
+{
+};
+
+TEST_P(InvalidPragmaTest, Identified)
+{
+ const char* str = GetParam();
+ const char* expected = "\n";
+
+ using testing::_;
+ // No handlePragma calls.
+ EXPECT_CALL(mDirectiveHandler, handlePragma(_, _, _, false)).Times(0);
+ // Unrecognized pragma warning.
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA,
+ pp::SourceLocation(0, 1), _));
+
+ preprocess(str, expected);
+}
+
+INSTANTIATE_TEST_CASE_P(All, InvalidPragmaTest, testing::Values(
+ "#pragma 1\n", // Invalid name.
+ "#pragma foo()\n", // Missing value.
+ "#pragma foo bar)\n", // Missing left paren,
+ "#pragma foo(bar\n", // Missing right paren.
+ "#pragma foo bar\n", // Missing parens.
+ "#pragma foo(bar) baz\n")); // Extra tokens.
diff --git a/gfx/angle/src/tests/preprocessor_tests/space_test.cpp b/gfx/angle/src/tests/preprocessor_tests/space_test.cpp
new file mode 100755
index 000000000..0c3494be5
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/space_test.cpp
@@ -0,0 +1,106 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "compiler/preprocessor/Token.h"
+
+class SpaceTest : public PreprocessorTest
+{
+ protected:
+ void expectSpace(const std::string& str)
+ {
+ const char* cstr = str.c_str();
+ ASSERT_TRUE(mPreprocessor.init(1, &cstr, 0));
+
+ pp::Token token;
+ // "foo" is returned after ignoring the whitespace characters.
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
+ EXPECT_EQ("foo", token.text);
+ // The whitespace character is however recorded with the next token.
+ EXPECT_TRUE(token.hasLeadingSpace());
+ }
+};
+
+// Whitespace characters allowed in GLSL.
+// Note that newline characters (\n) will be tested separately.
+static const char kSpaceChars[] = {' ', '\t', '\v', '\f'};
+
+// This test fixture tests the processing of a single whitespace character.
+// All tests in this fixture are ran with all possible whitespace character
+// allowed in GLSL.
+class SpaceCharTest : public SpaceTest,
+ public testing::WithParamInterface<char>
+{
+};
+
+TEST_P(SpaceCharTest, SpaceIgnored)
+{
+ // Construct test string with the whitespace char before "foo".
+ std::string str(1, GetParam());
+ str.append("foo");
+
+ expectSpace(str);
+}
+
+INSTANTIATE_TEST_CASE_P(SingleSpaceChar,
+ SpaceCharTest,
+ testing::ValuesIn(kSpaceChars));
+
+// This test fixture tests the processing of a string containing consecutive
+// whitespace characters. All tests in this fixture are ran with all possible
+// combinations of whitespace characters allowed in GLSL.
+typedef std::tr1::tuple<char, char, char> SpaceStringParams;
+class SpaceStringTest : public SpaceTest,
+ public testing::WithParamInterface<SpaceStringParams>
+{
+};
+
+TEST_P(SpaceStringTest, SpaceIgnored)
+{
+ // Construct test string with the whitespace char before "foo".
+ std::string str;
+ str.push_back(std::tr1::get<0>(GetParam()));
+ str.push_back(std::tr1::get<1>(GetParam()));
+ str.push_back(std::tr1::get<2>(GetParam()));
+ str.append("foo");
+
+ expectSpace(str);
+}
+
+INSTANTIATE_TEST_CASE_P(SpaceCharCombination,
+ SpaceStringTest,
+ testing::Combine(testing::ValuesIn(kSpaceChars),
+ testing::ValuesIn(kSpaceChars),
+ testing::ValuesIn(kSpaceChars)));
+
+// The tests above make sure that the space char is recorded in the
+// next token. This test makes sure that a token is not incorrectly marked
+// to have leading space.
+TEST_F(SpaceTest, LeadingSpace)
+{
+ const char* str = " foo+ -bar";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
+ EXPECT_EQ("foo", token.text);
+ EXPECT_TRUE(token.hasLeadingSpace());
+
+ mPreprocessor.lex(&token);
+ EXPECT_EQ('+', token.type);
+ EXPECT_FALSE(token.hasLeadingSpace());
+
+ mPreprocessor.lex(&token);
+ EXPECT_EQ('-', token.type);
+ EXPECT_TRUE(token.hasLeadingSpace());
+
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
+ EXPECT_EQ("bar", token.text);
+ EXPECT_FALSE(token.hasLeadingSpace());
+}
diff --git a/gfx/angle/src/tests/preprocessor_tests/token_test.cpp b/gfx/angle/src/tests/preprocessor_tests/token_test.cpp
new file mode 100755
index 000000000..106647c8e
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/token_test.cpp
@@ -0,0 +1,90 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "gtest/gtest.h"
+
+#include "compiler/preprocessor/Token.h"
+
+TEST(TokenTest, DefaultConstructor)
+{
+ pp::Token token;
+ EXPECT_EQ(0, token.type);
+ EXPECT_EQ(0u, token.flags);
+ EXPECT_EQ(0, token.location.line);
+ EXPECT_EQ(0, token.location.file);
+ EXPECT_EQ("", token.text);
+}
+
+TEST(TokenTest, Assignment)
+{
+ pp::Token token;
+ token.type = 1;
+ token.flags = 1;
+ token.location.line = 1;
+ token.location.file = 1;
+ token.text.assign("foo");
+
+ token = pp::Token();
+ EXPECT_EQ(0, token.type);
+ EXPECT_EQ(0u, token.flags);
+ EXPECT_EQ(0, token.location.line);
+ EXPECT_EQ(0, token.location.file);
+ EXPECT_EQ("", token.text);
+}
+
+TEST(TokenTest, Equals)
+{
+ pp::Token token;
+ EXPECT_TRUE(token.equals(pp::Token()));
+
+ token.type = 1;
+ EXPECT_FALSE(token.equals(pp::Token()));
+ token.type = 0;
+
+ token.flags = 1;
+ EXPECT_FALSE(token.equals(pp::Token()));
+ token.flags = 0;
+
+ token.location.line = 1;
+ EXPECT_FALSE(token.equals(pp::Token()));
+ token.location.line = 0;
+
+ token.location.file = 1;
+ EXPECT_FALSE(token.equals(pp::Token()));
+ token.location.file = 0;
+
+ token.text.assign("foo");
+ EXPECT_FALSE(token.equals(pp::Token()));
+ token.text.clear();
+
+ EXPECT_TRUE(token.equals(pp::Token()));
+}
+
+TEST(TokenTest, HasLeadingSpace)
+{
+ pp::Token token;
+ EXPECT_FALSE(token.hasLeadingSpace());
+ token.setHasLeadingSpace(true);
+ EXPECT_TRUE(token.hasLeadingSpace());
+ token.setHasLeadingSpace(false);
+ EXPECT_FALSE(token.hasLeadingSpace());
+}
+
+TEST(TokenTest, Write)
+{
+ pp::Token token;
+ token.text.assign("foo");
+ std::stringstream out1;
+ out1 << token;
+ EXPECT_TRUE(out1.good());
+ EXPECT_EQ("foo", out1.str());
+
+ token.setHasLeadingSpace(true);
+ std::stringstream out2;
+ out2 << token;
+ EXPECT_TRUE(out2.good());
+ EXPECT_EQ(" foo", out2.str());
+}
diff --git a/gfx/angle/src/tests/preprocessor_tests/version_test.cpp b/gfx/angle/src/tests/preprocessor_tests/version_test.cpp
new file mode 100755
index 000000000..a38542db1
--- /dev/null
+++ b/gfx/angle/src/tests/preprocessor_tests/version_test.cpp
@@ -0,0 +1,229 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "compiler/preprocessor/Token.h"
+
+class VersionTest : public PreprocessorTest
+{
+};
+
+TEST_F(VersionTest, Valid)
+{
+ const char* str = "#version 200\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handleVersion(pp::SourceLocation(0, 1), 200));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(VersionTest, CommentsIgnored)
+{
+ const char* str = "/*foo*/"
+ "#"
+ "/*foo*/"
+ "version"
+ "/*foo*/"
+ "200"
+ "/*foo*/"
+ "//foo"
+ "\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handleVersion(pp::SourceLocation(0, 1), 200));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(VersionTest, MissingNewline)
+{
+ const char* str = "#version 200";
+ const char* expected = "";
+
+ using testing::_;
+ // Directive successfully parsed.
+ EXPECT_CALL(mDirectiveHandler,
+ handleVersion(pp::SourceLocation(0, 1), 200));
+ // Error reported about EOF.
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_EOF_IN_DIRECTIVE, _, _));
+
+ preprocess(str, expected);
+}
+
+TEST_F(VersionTest, AfterComments)
+{
+ const char* str = "/* block comment acceptable */\n"
+ "// line comment acceptable\n"
+ "#version 200\n";
+ const char* expected = "\n\n\n";
+
+ using testing::_;
+ // Directive successfully parsed.
+ EXPECT_CALL(mDirectiveHandler,
+ handleVersion(pp::SourceLocation(0, 3), 200));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(VersionTest, AfterWhitespace)
+{
+ const char* str = "\n"
+ "\n"
+ "#version 200\n";
+ const char* expected = "\n\n\n";
+
+ using testing::_;
+ // Directive successfully parsed.
+ EXPECT_CALL(mDirectiveHandler,
+ handleVersion(pp::SourceLocation(0, 3), 200));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(VersionTest, AfterValidToken)
+{
+ const char* str = "foo\n"
+ "#version 200\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
+
+ using testing::_;
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
+ pp::SourceLocation(0, 2), _));
+
+ pp::Token token;
+ do
+ {
+ mPreprocessor.lex(&token);
+ } while (token.type != pp::Token::LAST);
+}
+
+TEST_F(VersionTest, AfterInvalidToken)
+{
+ const char* str = "$\n"
+ "#version 200\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
+
+ using testing::_;
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_INVALID_CHARACTER,
+ pp::SourceLocation(0, 1), "$"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
+ pp::SourceLocation(0, 2), _));
+
+ pp::Token token;
+ do
+ {
+ mPreprocessor.lex(&token);
+ } while (token.type != pp::Token::LAST);
+}
+
+TEST_F(VersionTest, AfterValidDirective)
+{
+ const char* str = "#\n"
+ "#version 200\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
+
+ using testing::_;
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
+ pp::SourceLocation(0, 2), _));
+
+ pp::Token token;
+ do
+ {
+ mPreprocessor.lex(&token);
+ } while (token.type != pp::Token::LAST);
+}
+
+TEST_F(VersionTest, AfterInvalidDirective)
+{
+ const char* str = "#foo\n"
+ "#version 200\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
+
+ using testing::_;
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_DIRECTIVE_INVALID_NAME,
+ pp::SourceLocation(0, 1), "foo"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
+ pp::SourceLocation(0, 2), _));
+
+ pp::Token token;
+ do
+ {
+ mPreprocessor.lex(&token);
+ } while (token.type != pp::Token::LAST);
+}
+
+TEST_F(VersionTest, AfterExcludedBlock)
+{
+ const char* str = "#if 0\n"
+ "foo\n"
+ "#endif\n"
+ "#version 200\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
+
+ using testing::_;
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
+ pp::SourceLocation(0, 4), _));
+
+ pp::Token token;
+ do
+ {
+ mPreprocessor.lex(&token);
+ } while (token.type != pp::Token::LAST);
+}
+
+struct VersionTestParam
+{
+ const char* str;
+ pp::Diagnostics::ID id;
+};
+
+class InvalidVersionTest : public VersionTest,
+ public testing::WithParamInterface<VersionTestParam>
+{
+};
+
+TEST_P(InvalidVersionTest, Identified)
+{
+ VersionTestParam param = GetParam();
+ const char* expected = "\n";
+
+ using testing::_;
+ // No handleVersion call.
+ EXPECT_CALL(mDirectiveHandler, handleVersion(_, _)).Times(0);
+ // Invalid version directive call.
+ EXPECT_CALL(mDiagnostics, print(param.id, pp::SourceLocation(0, 1), _));
+
+ preprocess(param.str, expected);
+}
+
+static const VersionTestParam kParams[] = {
+ {"#version\n", pp::Diagnostics::PP_INVALID_VERSION_DIRECTIVE},
+ {"#version foo\n", pp::Diagnostics::PP_INVALID_VERSION_NUMBER},
+ {"#version 100 foo\n", pp::Diagnostics::PP_UNEXPECTED_TOKEN},
+ {"#version 0xffffffff\n", pp::Diagnostics::PP_INTEGER_OVERFLOW}
+};
+
+INSTANTIATE_TEST_CASE_P(All, InvalidVersionTest, testing::ValuesIn(kParams));