blob: c10d80e5f5f2602966605e14bcb85c8b84285992 [file] [log] [blame]
// 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