| // Copyright 2019 The Fuchsia 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 "src/developer/debug/zxdb/expr/parse_string.h" |
| |
| #include <gtest/gtest.h> |
| |
| namespace zxdb { |
| |
| namespace { |
| |
| ErrOr<std::string> Parse(ExprLanguage lang, std::string_view input, size_t* in_out_cur, |
| size_t* error_location) { |
| std::optional<StringLiteralBegin> info = DoesBeginStringLiteral(lang, input, *in_out_cur); |
| if (!info) |
| return Err("Test harness says this does not begin a string."); |
| |
| return ParseStringLiteral(input, *info, in_out_cur, error_location); |
| } |
| |
| } // namespace |
| |
| TEST(ParseString, DoesBeginStringLiteral_C) { |
| std::optional<StringLiteralBegin> info = DoesBeginStringLiteral(ExprLanguage::kC, "", 0); |
| EXPECT_FALSE(info); |
| |
| info = DoesBeginStringLiteral(ExprLanguage::kC, "hello", 0); |
| EXPECT_FALSE(info); |
| |
| info = DoesBeginStringLiteral(ExprLanguage::kC, "\"", 0); |
| ASSERT_TRUE(info); |
| EXPECT_FALSE(info->is_raw); |
| EXPECT_EQ(0u, info->string_begin); |
| EXPECT_EQ(1u, info->contents_begin); |
| |
| info = DoesBeginStringLiteral(ExprLanguage::kC, " \"string", 2); |
| ASSERT_TRUE(info); |
| EXPECT_FALSE(info->is_raw); |
| EXPECT_EQ(3u, info->contents_begin); |
| |
| // Incomplete raw prefix. |
| info = DoesBeginStringLiteral(ExprLanguage::kC, "R\"", 0); |
| EXPECT_FALSE(info); |
| info = DoesBeginStringLiteral(ExprLanguage::kC, "R\"foo \"", 0); |
| EXPECT_FALSE(info); |
| |
| // Delimiters can not include some characters. |
| info = DoesBeginStringLiteral(ExprLanguage::kC, "R\" () \"", 0); |
| EXPECT_FALSE(info); |
| info = DoesBeginStringLiteral(ExprLanguage::kC, "R\"\\a()\\a\"", 0); |
| EXPECT_FALSE(info); |
| |
| // Valid raw prefix. |
| info = DoesBeginStringLiteral(ExprLanguage::kC, "R\"(", 0); |
| ASSERT_TRUE(info); |
| EXPECT_TRUE(info->is_raw); |
| EXPECT_EQ("", info->raw_marker); |
| EXPECT_EQ(0u, info->string_begin); |
| EXPECT_EQ(3u, info->contents_begin); |
| |
| info = DoesBeginStringLiteral(ExprLanguage::kC, " R\"delimiter( ", 2); |
| ASSERT_TRUE(info); |
| EXPECT_TRUE(info->is_raw); |
| EXPECT_EQ("delimiter", info->raw_marker); |
| EXPECT_EQ(2u, info->string_begin); |
| EXPECT_EQ(14u, info->contents_begin); |
| } |
| |
| TEST(ParseString, DoesBeginStringLiteral_Rust) { |
| std::optional<StringLiteralBegin> info = DoesBeginStringLiteral(ExprLanguage::kRust, "", 0); |
| EXPECT_FALSE(info); |
| |
| info = DoesBeginStringLiteral(ExprLanguage::kRust, "hello", 0); |
| EXPECT_FALSE(info); |
| |
| info = DoesBeginStringLiteral(ExprLanguage::kRust, "\"", 0); |
| ASSERT_TRUE(info); |
| EXPECT_FALSE(info->is_raw); |
| EXPECT_EQ(1u, info->contents_begin); |
| |
| info = DoesBeginStringLiteral(ExprLanguage::kRust, " \"string", 2); |
| ASSERT_TRUE(info); |
| EXPECT_FALSE(info->is_raw); |
| EXPECT_EQ(3u, info->contents_begin); |
| |
| // Incomplete raw prefix. |
| info = DoesBeginStringLiteral(ExprLanguage::kRust, "r#", 0); |
| EXPECT_FALSE(info); |
| info = DoesBeginStringLiteral(ExprLanguage::kRust, "r#### ", 0); |
| EXPECT_FALSE(info); |
| |
| // Valid raw prefix. |
| info = DoesBeginStringLiteral(ExprLanguage::kRust, "r#\"", 0); |
| ASSERT_TRUE(info); |
| EXPECT_TRUE(info->is_raw); |
| EXPECT_EQ("#", info->raw_marker); |
| EXPECT_EQ(0u, info->string_begin); |
| EXPECT_EQ(3u, info->contents_begin); |
| |
| info = DoesBeginStringLiteral(ExprLanguage::kRust, " r####\" hello", 2); |
| ASSERT_TRUE(info); |
| EXPECT_TRUE(info->is_raw); |
| EXPECT_EQ("####", info->raw_marker); |
| EXPECT_EQ(2u, info->string_begin); |
| EXPECT_EQ(8u, info->contents_begin); |
| } |
| |
| TEST(ParseString, EscapedC) { |
| size_t cur = 0; |
| size_t error_location = 1234; |
| ErrOr<std::string> result = |
| Parse(ExprLanguage::kC, R"("some\rescaped\n")", &cur, &error_location); |
| ASSERT_TRUE(result.ok()) << result.err().msg(); |
| EXPECT_EQ("some\rescaped\n", result.value()); |
| |
| // Unterminated string. |
| cur = 0; |
| result = Parse(ExprLanguage::kC, "\"something", &cur, &error_location); |
| ASSERT_TRUE(result.has_error()); |
| EXPECT_EQ(0u, error_location); |
| EXPECT_EQ("Hit end of input before the end of the string.", result.err().msg()); |
| |
| // C-specific silliness. |
| cur = 0; |
| result = Parse(ExprLanguage::kC, R"("a\f\b\v ")", &cur, &error_location); |
| ASSERT_TRUE(result.ok()); |
| EXPECT_EQ("a\f\b\v ", result.value()); |
| |
| // Hex sequences. We truncate overlong hex sequences ("\x1234" here) to the low 8 bits. |
| cur = 0; |
| result = Parse(ExprLanguage::kC, R"("\x01zed \x0x1 \x1234 \x1")", &cur, &error_location); |
| ASSERT_TRUE(result.ok()) << result.err().msg(); |
| // The output contains a null so we have to construct manually. |
| std::string expected("\x01zed "); |
| expected.push_back(0); |
| expected += "x1 \x34 \x01"; |
| EXPECT_EQ(expected, result.value()); |
| |
| // Octal sequences. |
| cur = 0; |
| result = Parse(ExprLanguage::kC, R"("\019 \0\1 \1234 \1")", &cur, &error_location); |
| ASSERT_TRUE(result.ok()) << result.err().msg(); |
| expected = "\x01"; |
| expected.append("9 "); |
| expected.push_back(0); |
| expected.push_back(1); |
| expected += " \x9c \x01"; // 0x1234 = 0x29c, we truncate to the low bits to get 0x9c. |
| EXPECT_EQ(expected, result.value()); |
| |
| // Unicode escape sequences are unimplemented. |
| cur = 0; |
| result = Parse(ExprLanguage::kC, R"("\u1234")", &cur, &error_location); |
| ASSERT_TRUE(result.has_error()); |
| EXPECT_EQ("Unicode escape sequences are not supported.", result.err().msg()); |
| } |
| |
| TEST(ParseString, EscapedRust) { |
| size_t cur = 0; |
| size_t error_location = 1234; |
| ErrOr<std::string> result = |
| Parse(ExprLanguage::kRust, R"("some\rescaped\n")", &cur, &error_location); |
| ASSERT_TRUE(result.ok()) << result.err().msg(); |
| EXPECT_EQ("some\rescaped\n", result.value()); |
| |
| // Unterminated string. |
| cur = 0; |
| result = Parse(ExprLanguage::kRust, R"("\x1)", &cur, &error_location); |
| ASSERT_TRUE(result.has_error()); |
| EXPECT_EQ(3u, error_location); |
| EXPECT_EQ("Expecting two hex digits.", result.err().msg()); |
| |
| // Rust-specific escapes (\0 is a null). |
| cur = 0; |
| result = Parse(ExprLanguage::kRust, R"("foo\01bar")", &cur, &error_location); |
| ASSERT_TRUE(result.ok()) << result.err().msg(); |
| std::string expected("foo"); |
| expected.push_back(0); |
| expected += "1bar"; |
| EXPECT_EQ(expected, result.value()); |
| |
| // Hex sequence that's not two digits. |
| cur = 0; |
| result = Parse(ExprLanguage::kRust, R"("\x1z)", &cur, &error_location); |
| ASSERT_TRUE(result.has_error()); |
| EXPECT_EQ(3u, error_location); |
| EXPECT_EQ("Expecting two hex digits.", result.err().msg()); |
| |
| // Hex sequences. All Rust hex sequences are two digits so "\x1234" -> "\x12" + "34" |
| cur = 0; |
| result = Parse(ExprLanguage::kRust, R"("\x01zed \x00x1 \x1234 \x01")", &cur, &error_location); |
| ASSERT_TRUE(result.ok()) << result.err().msg(); |
| // The output contains a null so we have to construct manually. |
| expected = "\x01zed "; |
| expected.push_back(0); |
| expected += "x1 \x12"; |
| expected += "34 \x01"; |
| EXPECT_EQ(expected, result.value()); |
| |
| // Unicode escape sequences are unimplemented. |
| cur = 0; |
| result = Parse(ExprLanguage::kRust, R"("\u{1234}")", &cur, &error_location); |
| ASSERT_TRUE(result.has_error()); |
| EXPECT_EQ("Unicode escape sequences are not supported.", result.err().msg()); |
| } |
| |
| TEST(ParseString, RawC) { |
| // Unterminated. |
| size_t cur = 0; |
| size_t error_location = 1234; |
| ErrOr<std::string> result = Parse(ExprLanguage::kC, "R\"(", &cur, &error_location); |
| ASSERT_TRUE(result.has_error()); |
| EXPECT_EQ("Hit end of input before the end of the string.", result.err().msg()); |
| EXPECT_EQ(0u, error_location); |
| |
| // Empty. |
| cur = 0; |
| result = Parse(ExprLanguage::kC, "R\"()\"", &cur, &error_location); |
| ASSERT_TRUE(result.ok()); |
| EXPECT_EQ(5u, cur); |
| EXPECT_EQ("", result.value()); |
| |
| // Raw string with good ending and various escaped and weird characters. |
| cur = 2; |
| result = Parse(ExprLanguage::kC, " R\"(hello\" world \\x10 \n)\" ", &cur, &error_location); |
| ASSERT_TRUE(result.ok()); |
| EXPECT_EQ(26u, cur); |
| EXPECT_EQ("hello\" world \\x10 \n", result.value()); |
| |
| // Raw string with delimiter. |
| cur = 0; |
| result = Parse(ExprLanguage::kC, "R\"foo(foo)\"foo)foo\" ", &cur, &error_location); |
| ASSERT_TRUE(result.ok()); |
| EXPECT_EQ(19u, cur); |
| EXPECT_EQ("foo)\"foo", result.value()); |
| } |
| |
| TEST(ParseString, RawRust) { |
| // Unterminated. |
| size_t cur = 0; |
| size_t error_location = 1234; |
| ErrOr<std::string> result = Parse(ExprLanguage::kRust, "r#\"", &cur, &error_location); |
| ASSERT_TRUE(result.has_error()); |
| EXPECT_EQ("Hit end of input before the end of the string.", result.err().msg()); |
| EXPECT_EQ(0u, error_location); |
| |
| // Empty. |
| cur = 0; |
| result = Parse(ExprLanguage::kRust, "r#\"\"#", &cur, &error_location); |
| ASSERT_TRUE(result.ok()); |
| EXPECT_EQ(5u, cur); |
| EXPECT_EQ("", result.value()); |
| |
| // Raw string with good ending and various escaped and weird characters. |
| cur = 2; |
| result = Parse(ExprLanguage::kRust, " r#\"hello\" world \\x10 \n\"# ", &cur, &error_location); |
| ASSERT_TRUE(result.ok()); |
| EXPECT_EQ(26u, cur); |
| EXPECT_EQ("hello\" world \\x10 \n", result.value()); |
| |
| // Raw string with delimiter. |
| cur = 0; |
| result = Parse(ExprLanguage::kRust, "r##\"#\"#\"## ", &cur, &error_location); |
| ASSERT_TRUE(result.ok()); |
| EXPECT_EQ(10u, cur); |
| EXPECT_EQ("#\"#", result.value()); |
| } |
| |
| } // namespace zxdb |