diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /gfx/angle/src/tests/preprocessor_tests | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-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')
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, ¶m.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, ¶m.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)); |