Files
carbon-lang/toolchain/lex/tokenized_buffer_test_helpers.h
T
Chandler Carruth 4148161e24 Refactor value store code to use separate files. (#4477)
This is in anticipation of making the integer value store be customized
heavily. I'd like to extract it from the common code when doing that, so
first disentangling them here without any intended change in
functionality or behavior to enable that.

I've tried to update `#include`s to be as minimal as I can and added a
few missing includes spotted in the process.

I've split the test for value store to include what was easy focused on
just the value store templates rather than the unified shared value
stores.

This might surface some opportunities for adding more tests, but for
this PR, just doing the minimal restructuring.
2024-11-04 04:00:17 +00:00

150 lines
5.3 KiB
C++

// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef CARBON_TOOLCHAIN_LEX_TOKENIZED_BUFFER_TEST_HELPERS_H_
#define CARBON_TOOLCHAIN_LEX_TOKENIZED_BUFFER_TEST_HELPERS_H_
#include <gmock/gmock.h>
#include "common/check.h"
#include "toolchain/base/shared_value_stores.h"
#include "toolchain/lex/tokenized_buffer.h"
namespace Carbon::Testing {
struct ExpectedToken {
friend auto operator<<(std::ostream& output, const ExpectedToken& expected)
-> std::ostream& {
output << "\ntoken: { kind: '" << expected.kind << "'";
if (expected.line != -1) {
output << ", line: " << expected.line;
}
if (expected.column != -1) {
output << ", column " << expected.column;
}
if (expected.indent_column != -1) {
output << ", indent: " << expected.indent_column;
}
if (!expected.text.empty()) {
output << ", spelling: '" << expected.text.str() << "'";
}
if (expected.string_contents) {
output << ", string contents: '" << expected.string_contents->str()
<< "'";
}
if (expected.recovery) {
output << ", recovery: true";
}
output << " }";
return output;
}
Lex::TokenKind kind;
int line = -1;
int column = -1;
int indent_column = -1;
bool recovery = false;
llvm::StringRef text = "";
SharedValueStores* value_stores = nullptr;
std::optional<llvm::StringRef> string_contents = std::nullopt;
};
// TODO: Consider rewriting this into a `TokenEq` matcher which is used inside
// `ElementsAre`. If that isn't easily done, potentially worth checking for size
// mismatches first.
// NOLINTNEXTLINE: Expands from GoogleTest.
MATCHER_P(HasTokens, raw_all_expected, "") {
const Lex::TokenizedBuffer& buffer = arg;
llvm::ArrayRef<ExpectedToken> all_expected = raw_all_expected;
bool matches = true;
auto buffer_it = buffer.tokens().begin();
for (const ExpectedToken& expected : all_expected) {
if (buffer_it == buffer.tokens().end()) {
// The size check outside the loop will fail and print useful info.
break;
}
int index = buffer_it - buffer.tokens().begin();
auto token = *buffer_it++;
Lex::TokenKind actual_kind = buffer.GetKind(token);
if (actual_kind != expected.kind) {
*result_listener << "\nToken " << index << " is a " << actual_kind
<< ", expected a " << expected.kind << ".";
matches = false;
}
int actual_line = buffer.GetLineNumber(token);
if (expected.line != -1 && actual_line != expected.line) {
*result_listener << "\nToken " << index << " is at line " << actual_line
<< ", expected " << expected.line << ".";
matches = false;
}
int actual_column = buffer.GetColumnNumber(token);
if (expected.column != -1 && actual_column != expected.column) {
*result_listener << "\nToken " << index << " is at column "
<< actual_column << ", expected " << expected.column
<< ".";
matches = false;
}
int actual_indent_column =
buffer.GetIndentColumnNumber(buffer.GetLine(token));
if (expected.indent_column != -1 &&
actual_indent_column != expected.indent_column) {
*result_listener << "\nToken " << index << " has column indent "
<< actual_indent_column << ", expected "
<< expected.indent_column << ".";
matches = false;
}
int actual_recovery = buffer.IsRecoveryToken(token);
if (expected.recovery != actual_recovery) {
*result_listener << "\nToken " << index << " is "
<< (actual_recovery ? "recovery" : "non-recovery")
<< ", expected "
<< (expected.recovery ? "recovery" : "non-recovery")
<< ".";
matches = false;
}
llvm::StringRef actual_text = buffer.GetTokenText(token);
if (!expected.text.empty() && actual_text != expected.text) {
*result_listener << "\nToken " << index << " has spelling `"
<< actual_text.str() << "`, expected `"
<< expected.text.str() << "`.";
matches = false;
}
CARBON_CHECK(!expected.string_contents ||
expected.kind == Lex::TokenKind::StringLiteral);
if (expected.string_contents &&
actual_kind == Lex::TokenKind::StringLiteral) {
llvm::StringRef actual_contents =
expected.value_stores->string_literal_values().Get(
buffer.GetStringLiteralValue(token));
if (actual_contents != *expected.string_contents) {
*result_listener << "\nToken " << index << " has contents `"
<< actual_contents.str() << "`, expected `"
<< expected.string_contents->str() << "`.";
matches = false;
}
}
}
int actual_size = buffer.tokens().end() - buffer.tokens().begin();
if (static_cast<int>(all_expected.size()) != actual_size) {
*result_listener << "\nExpected " << all_expected.size()
<< " tokens but found " << actual_size << ".";
matches = false;
}
return matches;
}
} // namespace Carbon::Testing
#endif // CARBON_TOOLCHAIN_LEX_TOKENIZED_BUFFER_TEST_HELPERS_H_