123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413 |
- // Copyright (c) 2015-2016 The Khronos Group Inc.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #include <string>
- #include <utility>
- #include <vector>
- #include "gmock/gmock.h"
- #include "test/test_fixture.h"
- #include "test/unit_spirv.h"
- namespace spvtools {
- namespace {
- using ::testing::Eq;
- TEST(TextLiteral, GoodI32) {
- spv_literal_t l;
- ASSERT_EQ(SPV_SUCCESS, spvTextToLiteral("-0", &l));
- EXPECT_EQ(SPV_LITERAL_TYPE_INT_32, l.type);
- EXPECT_EQ(0, l.value.i32);
- ASSERT_EQ(SPV_SUCCESS, spvTextToLiteral("-2147483648", &l));
- EXPECT_EQ(SPV_LITERAL_TYPE_INT_32, l.type);
- EXPECT_EQ((-2147483647L - 1), l.value.i32);
- }
- TEST(TextLiteral, GoodU32) {
- spv_literal_t l;
- ASSERT_EQ(SPV_SUCCESS, spvTextToLiteral("0", &l));
- EXPECT_EQ(SPV_LITERAL_TYPE_UINT_32, l.type);
- EXPECT_EQ(0, l.value.i32);
- ASSERT_EQ(SPV_SUCCESS, spvTextToLiteral("4294967295", &l));
- EXPECT_EQ(SPV_LITERAL_TYPE_UINT_32, l.type);
- EXPECT_EQ(4294967295, l.value.u32);
- }
- TEST(TextLiteral, GoodI64) {
- spv_literal_t l;
- ASSERT_EQ(SPV_SUCCESS, spvTextToLiteral("-2147483649", &l));
- EXPECT_EQ(SPV_LITERAL_TYPE_INT_64, l.type);
- EXPECT_EQ(-2147483649LL, l.value.i64);
- }
- TEST(TextLiteral, GoodU64) {
- spv_literal_t l;
- ASSERT_EQ(SPV_SUCCESS, spvTextToLiteral("4294967296", &l));
- EXPECT_EQ(SPV_LITERAL_TYPE_UINT_64, l.type);
- EXPECT_EQ(4294967296u, l.value.u64);
- }
- TEST(TextLiteral, GoodFloat) {
- spv_literal_t l;
- ASSERT_EQ(SPV_SUCCESS, spvTextToLiteral("1.0", &l));
- EXPECT_EQ(SPV_LITERAL_TYPE_FLOAT_32, l.type);
- EXPECT_EQ(1.0, l.value.f);
- ASSERT_EQ(SPV_SUCCESS, spvTextToLiteral("1.5", &l));
- EXPECT_EQ(SPV_LITERAL_TYPE_FLOAT_32, l.type);
- EXPECT_EQ(1.5, l.value.f);
- ASSERT_EQ(SPV_SUCCESS, spvTextToLiteral("-.25", &l));
- EXPECT_EQ(SPV_LITERAL_TYPE_FLOAT_32, l.type);
- EXPECT_EQ(-.25, l.value.f);
- }
- TEST(TextLiteral, BadString) {
- spv_literal_t l;
- EXPECT_EQ(SPV_FAILED_MATCH, spvTextToLiteral("", &l));
- EXPECT_EQ(SPV_FAILED_MATCH, spvTextToLiteral("-", &l));
- EXPECT_EQ(SPV_FAILED_MATCH, spvTextToLiteral("--", &l));
- EXPECT_EQ(SPV_FAILED_MATCH, spvTextToLiteral("1-2", &l));
- EXPECT_EQ(SPV_FAILED_MATCH, spvTextToLiteral("123a", &l));
- EXPECT_EQ(SPV_FAILED_MATCH, spvTextToLiteral("12.2.3", &l));
- EXPECT_EQ(SPV_FAILED_MATCH, spvTextToLiteral("\"", &l));
- EXPECT_EQ(SPV_FAILED_MATCH, spvTextToLiteral("\"z", &l));
- EXPECT_EQ(SPV_FAILED_MATCH, spvTextToLiteral("a\"", &l));
- }
- class GoodStringTest
- : public ::testing::TestWithParam<std::pair<const char*, const char*>> {};
- TEST_P(GoodStringTest, GoodStrings) {
- spv_literal_t l;
- ASSERT_EQ(SPV_SUCCESS, spvTextToLiteral(std::get<0>(GetParam()), &l));
- EXPECT_EQ(SPV_LITERAL_TYPE_STRING, l.type);
- EXPECT_EQ(std::get<1>(GetParam()), l.str);
- }
- INSTANTIATE_TEST_SUITE_P(
- TextLiteral, GoodStringTest,
- ::testing::ValuesIn(std::vector<std::pair<const char*, const char*>>{
- {R"("-")", "-"},
- {R"("--")", "--"},
- {R"("1-2")", "1-2"},
- {R"("123a")", "123a"},
- {R"("12.2.3")", "12.2.3"},
- {R"("\"")", "\""},
- {R"("\\")", "\\"},
- {"\"\\foo\nbar\"", "foo\nbar"},
- {"\"\\foo\\\nbar\"", "foo\nbar"},
- {"\"\xE4\xBA\xB2\"", "\xE4\xBA\xB2"},
- {"\"\\\xE4\xBA\xB2\"", "\xE4\xBA\xB2"},
- {"\"this \\\" and this \\\\ and \\\xE4\xBA\xB2\"",
- "this \" and this \\ and \xE4\xBA\xB2"}}));
- TEST(TextLiteral, StringTooLong) {
- spv_literal_t l;
- std::string too_long =
- std::string("\"") +
- std::string(SPV_LIMIT_LITERAL_STRING_BYTES_MAX + 1, 'a') + "\"";
- EXPECT_EQ(SPV_ERROR_OUT_OF_MEMORY, spvTextToLiteral(too_long.data(), &l));
- }
- TEST(TextLiteral, GoodLongString) {
- spv_literal_t l;
- // The universal limit of 65535 Unicode characters might make this
- // fail validation, since SPV_LIMIT_LITERAL_STRING_BYTES_MAX is 4*65535.
- // However, as an implementation detail, we'll allow the assembler
- // to parse it. Otherwise we'd have to scan the string for valid UTF-8
- // characters.
- std::string unquoted(SPV_LIMIT_LITERAL_STRING_BYTES_MAX, 'a');
- std::string good_long = std::string("\"") + unquoted + "\"";
- EXPECT_EQ(SPV_SUCCESS, spvTextToLiteral(good_long.data(), &l));
- EXPECT_EQ(SPV_LITERAL_TYPE_STRING, l.type);
- EXPECT_EQ(unquoted.data(), l.str);
- }
- TEST(TextLiteral, GoodUTF8String) {
- const std::string unquoted =
- spvtest::MakeLongUTF8String(SPV_LIMIT_LITERAL_STRING_UTF8_CHARS_MAX);
- const std::string good_long = std::string("\"") + unquoted + "\"";
- spv_literal_t l;
- EXPECT_EQ(SPV_SUCCESS, spvTextToLiteral(good_long.data(), &l));
- EXPECT_EQ(SPV_LITERAL_TYPE_STRING, l.type);
- EXPECT_EQ(unquoted.data(), l.str);
- }
- // A test case for parsing literal numbers.
- struct TextLiteralCase {
- uint32_t bitwidth;
- const char* text;
- bool is_signed;
- bool success;
- std::vector<uint32_t> expected_values;
- };
- using IntegerTest =
- spvtest::TextToBinaryTestBase<::testing::TestWithParam<TextLiteralCase>>;
- std::vector<uint32_t> successfulEncode(const TextLiteralCase& test,
- IdTypeClass type) {
- spv_instruction_t inst;
- std::string message;
- auto capture_message = [&message](spv_message_level_t, const char*,
- const spv_position_t&,
- const char* m) { message = m; };
- IdType expected_type{test.bitwidth, test.is_signed, type};
- EXPECT_EQ(SPV_SUCCESS,
- AssemblyContext(nullptr, capture_message)
- .binaryEncodeNumericLiteral(test.text, SPV_ERROR_INVALID_TEXT,
- expected_type, &inst))
- << message;
- return inst.words;
- }
- std::string failedEncode(const TextLiteralCase& test, IdTypeClass type) {
- spv_instruction_t inst;
- std::string message;
- auto capture_message = [&message](spv_message_level_t, const char*,
- const spv_position_t&,
- const char* m) { message = m; };
- IdType expected_type{test.bitwidth, test.is_signed, type};
- EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
- AssemblyContext(nullptr, capture_message)
- .binaryEncodeNumericLiteral(test.text, SPV_ERROR_INVALID_TEXT,
- expected_type, &inst));
- return message;
- }
- TEST_P(IntegerTest, IntegerBounds) {
- if (GetParam().success) {
- EXPECT_THAT(successfulEncode(GetParam(), IdTypeClass::kScalarIntegerType),
- Eq(GetParam().expected_values));
- } else {
- std::stringstream ss;
- ss << "Integer " << GetParam().text << " does not fit in a "
- << GetParam().bitwidth << "-bit "
- << (GetParam().is_signed ? "signed" : "unsigned") << " integer";
- EXPECT_THAT(failedEncode(GetParam(), IdTypeClass::kScalarIntegerType),
- Eq(ss.str()));
- }
- }
- // Four nicely named methods for making TextLiteralCase values.
- // Their names have underscores in some places to make it easier
- // to read the table that follows.
- TextLiteralCase Make_Ok__Signed(uint32_t bitwidth, const char* text,
- std::vector<uint32_t> encoding) {
- return TextLiteralCase{bitwidth, text, true, true, encoding};
- }
- TextLiteralCase Make_Ok__Unsigned(uint32_t bitwidth, const char* text,
- std::vector<uint32_t> encoding) {
- return TextLiteralCase{bitwidth, text, false, true, encoding};
- }
- TextLiteralCase Make_Bad_Signed(uint32_t bitwidth, const char* text) {
- return TextLiteralCase{bitwidth, text, true, false, {}};
- }
- TextLiteralCase Make_Bad_Unsigned(uint32_t bitwidth, const char* text) {
- return TextLiteralCase{bitwidth, text, false, false, {}};
- }
- // clang-format off
- INSTANTIATE_TEST_SUITE_P(
- DecimalIntegers, IntegerTest,
- ::testing::ValuesIn(std::vector<TextLiteralCase>{
- // Check max value and overflow value for 1-bit numbers.
- Make_Ok__Signed(1, "0", {0}),
- Make_Ok__Unsigned(1, "1", {1}),
- Make_Bad_Signed(1, "1"),
- Make_Bad_Unsigned(1, "2"),
- // Check max value and overflow value for 2-bit numbers.
- Make_Ok__Signed(2, "1", {1}),
- Make_Ok__Unsigned(2, "3", {3}),
- Make_Bad_Signed(2, "2"),
- Make_Bad_Unsigned(2, "4"),
- // Check max negative value and overflow value for signed
- // 1- and 2-bit numbers. Signed negative numbers are sign-extended.
- Make_Ok__Signed(1, "-0", {uint32_t(0)}),
- Make_Ok__Signed(1, "-1", {uint32_t(-1)}),
- Make_Ok__Signed(2, "-0", {0}),
- Make_Ok__Signed(2, "-1", {uint32_t(-1)}),
- Make_Ok__Signed(2, "-2", {uint32_t(-2)}),
- Make_Bad_Signed(2, "-3"),
- Make_Bad_Unsigned(2, "2224323424242424"),
- Make_Ok__Unsigned(16, "65535", {0xFFFF}),
- Make_Bad_Unsigned(16, "65536"),
- Make_Bad_Signed(16, "65535"),
- Make_Ok__Signed(16, "32767", {0x7FFF}),
- Make_Ok__Signed(16, "-32768", {0xFFFF8000}),
- // Check values around 32-bits in magnitude.
- Make_Ok__Unsigned(33, "4294967296", {0, 1}),
- Make_Ok__Unsigned(33, "4294967297", {1, 1}),
- Make_Bad_Unsigned(33, "8589934592"),
- Make_Bad_Signed(33, "4294967296"),
- Make_Ok__Signed(33, "-4294967296", {0x0, 0xFFFFFFFF}),
- Make_Ok__Unsigned(64, "4294967296", {0, 1}),
- Make_Ok__Unsigned(64, "4294967297", {1, 1}),
- // Check max value and overflow value for 64-bit numbers.
- Make_Ok__Signed(64, "9223372036854775807", {0xffffffff, 0x7fffffff}),
- Make_Bad_Signed(64, "9223372036854775808"),
- Make_Ok__Unsigned(64, "9223372036854775808", {0x00000000, 0x80000000}),
- Make_Ok__Unsigned(64, "18446744073709551615", {0xffffffff, 0xffffffff}),
- Make_Ok__Signed(64, "-9223372036854775808", {0x00000000, 0x80000000}),
- }));
- // clang-format on
- using IntegerLeadingMinusTest =
- spvtest::TextToBinaryTestBase<::testing::TestWithParam<TextLiteralCase>>;
- TEST_P(IntegerLeadingMinusTest, CantHaveLeadingMinusOnUnsigned) {
- EXPECT_FALSE(GetParam().success);
- EXPECT_THAT(failedEncode(GetParam(), IdTypeClass::kScalarIntegerType),
- Eq("Cannot put a negative number in an unsigned literal"));
- }
- // clang-format off
- INSTANTIATE_TEST_SUITE_P(
- DecimalAndHexIntegers, IntegerLeadingMinusTest,
- ::testing::ValuesIn(std::vector<TextLiteralCase>{
- // Unsigned numbers never allow a leading minus sign.
- Make_Bad_Unsigned(16, "-0"),
- Make_Bad_Unsigned(16, "-0x0"),
- Make_Bad_Unsigned(16, "-0x1"),
- Make_Bad_Unsigned(32, "-0"),
- Make_Bad_Unsigned(32, "-0x0"),
- Make_Bad_Unsigned(32, "-0x1"),
- Make_Bad_Unsigned(64, "-0"),
- Make_Bad_Unsigned(64, "-0x0"),
- Make_Bad_Unsigned(64, "-0x1"),
- }));
- // clang-format off
- INSTANTIATE_TEST_SUITE_P(
- HexIntegers, IntegerTest,
- ::testing::ValuesIn(std::vector<TextLiteralCase>{
- // Check 0x and 0X prefices.
- Make_Ok__Signed(16, "0x1234", {0x1234}),
- Make_Ok__Signed(16, "0X1234", {0x1234}),
- // Check 1-bit numbers
- Make_Ok__Signed(1, "0x0", {0}),
- Make_Ok__Signed(1, "0x1", {uint32_t(-1)}),
- Make_Ok__Unsigned(1, "0x0", {0}),
- Make_Ok__Unsigned(1, "0x1", {1}),
- Make_Bad_Signed(1, "0x2"),
- Make_Bad_Unsigned(1, "0x2"),
- // Check 2-bit numbers
- Make_Ok__Signed(2, "0x0", {0}),
- Make_Ok__Signed(2, "0x1", {1}),
- Make_Ok__Signed(2, "0x2", {uint32_t(-2)}),
- Make_Ok__Signed(2, "0x3", {uint32_t(-1)}),
- Make_Ok__Unsigned(2, "0x0", {0}),
- Make_Ok__Unsigned(2, "0x1", {1}),
- Make_Ok__Unsigned(2, "0x2", {2}),
- Make_Ok__Unsigned(2, "0x3", {3}),
- Make_Bad_Signed(2, "0x4"),
- Make_Bad_Unsigned(2, "0x4"),
- // Check 8-bit numbers
- Make_Ok__Signed(8, "0x7f", {0x7f}),
- Make_Ok__Signed(8, "0x80", {0xffffff80}),
- Make_Ok__Unsigned(8, "0x80", {0x80}),
- Make_Ok__Unsigned(8, "0xff", {0xff}),
- Make_Bad_Signed(8, "0x100"),
- Make_Bad_Unsigned(8, "0x100"),
- // Check 16-bit numbers
- Make_Ok__Signed(16, "0x7fff", {0x7fff}),
- Make_Ok__Signed(16, "0x8000", {0xffff8000}),
- Make_Ok__Unsigned(16, "0x8000", {0x8000}),
- Make_Ok__Unsigned(16, "0xffff", {0xffff}),
- Make_Bad_Signed(16, "0x10000"),
- Make_Bad_Unsigned(16, "0x10000"),
- // Check 32-bit numbers
- Make_Ok__Signed(32, "0x7fffffff", {0x7fffffff}),
- Make_Ok__Signed(32, "0x80000000", {0x80000000}),
- Make_Ok__Unsigned(32, "0x80000000", {0x80000000}),
- Make_Ok__Unsigned(32, "0xffffffff", {0xffffffff}),
- Make_Bad_Signed(32, "0x100000000"),
- Make_Bad_Unsigned(32, "0x100000000"),
- // Check 48-bit numbers
- Make_Ok__Unsigned(48, "0x7ffffffff", {0xffffffff, 7}),
- Make_Ok__Unsigned(48, "0x800000000", {0, 8}),
- Make_Ok__Signed(48, "0x7fffffffffff", {0xffffffff, 0x7fff}),
- Make_Ok__Signed(48, "0x800000000000", {0, 0xffff8000}),
- Make_Bad_Signed(48, "0x1000000000000"),
- Make_Bad_Unsigned(48, "0x1000000000000"),
- // Check 64-bit numbers
- Make_Ok__Signed(64, "0x7fffffffffffffff", {0xffffffff, 0x7fffffff}),
- Make_Ok__Signed(64, "0x8000000000000000", {0x00000000, 0x80000000}),
- Make_Ok__Unsigned(64, "0x7fffffffffffffff", {0xffffffff, 0x7fffffff}),
- Make_Ok__Unsigned(64, "0x8000000000000000", {0x00000000, 0x80000000}),
- }));
- // clang-format on
- TEST(OverflowIntegerParse, Decimal) {
- std::string signed_input = "-18446744073709551616";
- std::string expected_message0 =
- "Invalid signed integer literal: " + signed_input;
- EXPECT_THAT(failedEncode(Make_Bad_Signed(64, signed_input.c_str()),
- IdTypeClass::kScalarIntegerType),
- Eq(expected_message0));
- std::string unsigned_input = "18446744073709551616";
- std::string expected_message1 =
- "Invalid unsigned integer literal: " + unsigned_input;
- EXPECT_THAT(failedEncode(Make_Bad_Unsigned(64, unsigned_input.c_str()),
- IdTypeClass::kScalarIntegerType),
- Eq(expected_message1));
- // TODO(dneto): When the given number doesn't have a leading sign,
- // we say we're trying to parse an unsigned number, even when the caller
- // asked for a signed number. This is kind of weird, but it's an
- // artefact of how we do the parsing.
- EXPECT_THAT(failedEncode(Make_Bad_Signed(64, unsigned_input.c_str()),
- IdTypeClass::kScalarIntegerType),
- Eq(expected_message1));
- }
- TEST(OverflowIntegerParse, Hex) {
- std::string input = "0x10000000000000000";
- std::string expected_message = "Invalid unsigned integer literal: " + input;
- EXPECT_THAT(failedEncode(Make_Bad_Signed(64, input.c_str()),
- IdTypeClass::kScalarIntegerType),
- Eq(expected_message));
- EXPECT_THAT(failedEncode(Make_Bad_Unsigned(64, input.c_str()),
- IdTypeClass::kScalarIntegerType),
- Eq(expected_message));
- }
- } // namespace
- } // namespace spvtools
|