[test] Add --check-baseline to generate-bytecode-expectations
Add a new mode to generate-bytecode-expectations to be used in a coming test that tests that the bytecode expectations generated by --rebaseline match the current state. Change-Id: Ic03787cd853f9bf7d9b4412f96a767036c848c61 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1708477 Auto-Submit: Dan Elphick <delphick@chromium.org> Commit-Queue: Dan Elphick <delphick@chromium.org> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Cr-Commit-Position: refs/heads/master@{#62825}
This commit is contained in:
parent
aa478cac4f
commit
d251ec411c
@ -2,9 +2,11 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include "test/cctest/interpreter/bytecode-expectations-printer.h"
|
||||
@ -37,6 +39,7 @@ class ProgramOptions final {
|
||||
read_raw_js_snippet_(false),
|
||||
read_from_stdin_(false),
|
||||
rebaseline_(false),
|
||||
check_baseline_(false),
|
||||
wrap_(true),
|
||||
module_(false),
|
||||
top_level_(false),
|
||||
@ -58,6 +61,8 @@ class ProgramOptions final {
|
||||
return output_filename_.empty() && !rebaseline_;
|
||||
}
|
||||
bool rebaseline() const { return rebaseline_; }
|
||||
bool check_baseline() const { return check_baseline_; }
|
||||
bool baseline() const { return rebaseline_ || check_baseline_; }
|
||||
bool wrap() const { return wrap_; }
|
||||
bool module() const { return module_; }
|
||||
bool top_level() const { return top_level_; }
|
||||
@ -66,7 +71,7 @@ class ProgramOptions final {
|
||||
bool async_iteration() const { return async_iteration_; }
|
||||
bool private_methods() const { return private_methods_; }
|
||||
bool verbose() const { return verbose_; }
|
||||
bool suppress_runtime_errors() const { return rebaseline_ && !verbose_; }
|
||||
bool suppress_runtime_errors() const { return baseline() && !verbose_; }
|
||||
std::vector<std::string> input_filenames() const { return input_filenames_; }
|
||||
std::string output_filename() const { return output_filename_; }
|
||||
std::string test_function_name() const { return test_function_name_; }
|
||||
@ -77,6 +82,7 @@ class ProgramOptions final {
|
||||
bool read_raw_js_snippet_;
|
||||
bool read_from_stdin_;
|
||||
bool rebaseline_;
|
||||
bool check_baseline_;
|
||||
bool wrap_;
|
||||
bool module_;
|
||||
bool top_level_;
|
||||
@ -174,6 +180,8 @@ ProgramOptions ProgramOptions::FromCommandLine(int argc, char** argv) {
|
||||
options.read_from_stdin_ = true;
|
||||
} else if (strcmp(argv[i], "--rebaseline") == 0) {
|
||||
options.rebaseline_ = true;
|
||||
} else if (strcmp(argv[i], "--check-baseline") == 0) {
|
||||
options.check_baseline_ = true;
|
||||
} else if (strcmp(argv[i], "--no-wrap") == 0) {
|
||||
options.wrap_ = false;
|
||||
} else if (strcmp(argv[i], "--module") == 0) {
|
||||
@ -203,7 +211,13 @@ ProgramOptions ProgramOptions::FromCommandLine(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
if (options.rebaseline_ && options.input_filenames_.empty()) {
|
||||
if (options.rebaseline() && options.check_baseline()) {
|
||||
REPORT_ERROR("Can't check baseline and rebaseline at the same time.");
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
if ((options.check_baseline_ || options.rebaseline_) &&
|
||||
options.input_filenames_.empty()) {
|
||||
#if defined(V8_OS_POSIX) || defined(V8_OS_WIN)
|
||||
if (options.verbose_) {
|
||||
std::cout << "Looking for golden files in " << kGoldenFilesPath << '\n';
|
||||
@ -236,24 +250,29 @@ bool ProgramOptions::Validate() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rebaseline_ && read_raw_js_snippet_) {
|
||||
REPORT_ERROR("Cannot use --rebaseline on a raw JS snippet.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rebaseline_ && !output_filename_.empty()) {
|
||||
REPORT_ERROR("Output file cannot be specified together with --rebaseline.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rebaseline_ && read_from_stdin_) {
|
||||
REPORT_ERROR("Cannot --rebaseline when input is --stdin.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (input_filenames_.size() > 1 && !rebaseline_ && !read_raw_js_snippet()) {
|
||||
if (baseline() && read_raw_js_snippet_) {
|
||||
REPORT_ERROR(
|
||||
"Multiple input files, but no --rebaseline or --raw-js specified.");
|
||||
"Cannot use --rebaseline or --check-baseline on a raw JS snippet.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (baseline() && !output_filename_.empty()) {
|
||||
REPORT_ERROR(
|
||||
"Output file cannot be specified together with --rebaseline or "
|
||||
"--check-baseline.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (baseline() && read_from_stdin_) {
|
||||
REPORT_ERROR(
|
||||
"Cannot --rebaseline or --check-baseline when input is --stdin.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (input_filenames_.size() > 1 && !baseline() && !read_raw_js_snippet()) {
|
||||
REPORT_ERROR(
|
||||
"Multiple input files, but no --rebaseline, --check-baseline or "
|
||||
"--raw-js specified.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -331,6 +350,7 @@ V8InitializationScope::V8InitializationScope(const char* exec_path)
|
||||
: platform_(v8::platform::NewDefaultPlatform()) {
|
||||
i::FLAG_always_opt = false;
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
i::FLAG_enable_lazy_source_positions = false;
|
||||
|
||||
v8::V8::InitializeICUDefaultLocation(exec_path);
|
||||
v8::V8::InitializeExternalStartupData(exec_path);
|
||||
@ -462,6 +482,16 @@ bool WriteExpectationsFile(const std::vector<std::string>& snippet_list,
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string WriteExpectationsToString(
|
||||
const std::vector<std::string>& snippet_list,
|
||||
const V8InitializationScope& platform, const ProgramOptions& options) {
|
||||
std::stringstream output_string;
|
||||
|
||||
GenerateExpectationsFile(output_string, snippet_list, platform, options);
|
||||
|
||||
return output_string.str();
|
||||
}
|
||||
|
||||
void PrintMessage(v8::Local<v8::Message> message, v8::Local<v8::Value>) {
|
||||
std::cerr << "INFO: "
|
||||
<< *v8::String::Utf8Value(message->GetIsolate(), message->Get())
|
||||
@ -475,11 +505,12 @@ void PrintUsage(const char* exec_path) {
|
||||
<< "\nUsage: " << exec_path
|
||||
<< " [OPTIONS]... [INPUT FILES]...\n\n"
|
||||
"Options:\n"
|
||||
" --help Print this help message.\n"
|
||||
" --verbose Emit messages about the progress of the tool.\n"
|
||||
" --raw-js Read raw JavaScript, instead of the output format.\n"
|
||||
" --stdin Read from standard input instead of file.\n"
|
||||
" --help Print this help message.\n"
|
||||
" --verbose Emit messages about the progress of the tool.\n"
|
||||
" --raw-js Read raw JavaScript, instead of the output format.\n"
|
||||
" --stdin Read from standard input instead of file.\n"
|
||||
" --rebaseline Rebaseline input snippet file.\n"
|
||||
" --check-baseline Checks the current baseline is valid.\n"
|
||||
" --no-wrap Do not wrap the snippet in a function.\n"
|
||||
" --disable-oneshot-opt Disable Oneshot Optimization.\n"
|
||||
" --print-callee Print bytecode of callee, function should "
|
||||
@ -496,9 +527,9 @@ void PrintUsage(const char* exec_path) {
|
||||
" Specify the type of the entries in the constant pool "
|
||||
"(default: mixed).\n"
|
||||
"\n"
|
||||
"When using --rebaseline, flags --no-wrap, --test-function-name \n"
|
||||
"and --pool-type will be overridden by the options specified in \n"
|
||||
"the input file header.\n\n"
|
||||
"When using --rebaseline or --check-baseline, flags --no-wrap,\n"
|
||||
"--test-function-name and --pool-type will be overridden by the\n"
|
||||
"options specified in the input file header.\n\n"
|
||||
"Each raw JavaScript file is interpreted as a single snippet.\n\n"
|
||||
"This tool is intended as a help in writing tests.\n"
|
||||
"Please, DO NOT blindly copy and paste the output "
|
||||
@ -507,6 +538,62 @@ void PrintUsage(const char* exec_path) {
|
||||
|
||||
} // namespace
|
||||
|
||||
bool CheckBaselineExpectations(const std::string& input_filename,
|
||||
const std::vector<std::string>& snippet_list,
|
||||
const V8InitializationScope& platform,
|
||||
const ProgramOptions& options) {
|
||||
std::string actual =
|
||||
WriteExpectationsToString(snippet_list, platform, options);
|
||||
|
||||
std::ifstream input_stream(input_filename);
|
||||
if (!input_stream.is_open()) {
|
||||
REPORT_ERROR("Could not open " << input_filename << " for reading.");
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool check_failed = false;
|
||||
std::string expected((std::istreambuf_iterator<char>(input_stream)),
|
||||
std::istreambuf_iterator<char>());
|
||||
if (expected != actual) {
|
||||
REPORT_ERROR("Mismatch: " << input_filename);
|
||||
check_failed = true;
|
||||
if (expected.size() != actual.size()) {
|
||||
REPORT_ERROR(" Expected size (" << expected.size()
|
||||
<< ") != actual size (" << actual.size()
|
||||
<< ")");
|
||||
}
|
||||
|
||||
int line = 1;
|
||||
for (size_t i = 0; i < std::min(expected.size(), actual.size()); ++i) {
|
||||
if (expected[i] != actual[i]) {
|
||||
// Find the start of the line that has the mismatch carefully
|
||||
// handling the case where it's the first line that mismatches.
|
||||
size_t start = expected[i] != '\n' ? expected.rfind("\n", i)
|
||||
: actual.rfind("\n", i);
|
||||
if (start == std::string::npos) {
|
||||
start = 0;
|
||||
} else {
|
||||
++start;
|
||||
}
|
||||
|
||||
// If there is no new line, then these two lines will consume the
|
||||
// remaining characters in the string, because npos - start will
|
||||
// always be longer than the string itself.
|
||||
std::string expected_line =
|
||||
expected.substr(start, expected.find("\n", i) - start);
|
||||
std::string actual_line =
|
||||
actual.substr(start, actual.find("\n", i) - start);
|
||||
REPORT_ERROR(" First mismatch on line " << line << ")");
|
||||
REPORT_ERROR(" Expected : '" << expected_line << "'");
|
||||
REPORT_ERROR(" Actual : '" << actual_line << "'");
|
||||
break;
|
||||
}
|
||||
if (expected[i] == '\n') line++;
|
||||
}
|
||||
}
|
||||
return check_failed;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ProgramOptions options = ProgramOptions::FromCommandLine(argc, argv);
|
||||
|
||||
@ -524,9 +611,10 @@ int main(int argc, char** argv) {
|
||||
if (options.read_from_stdin()) {
|
||||
// Rebaseline will never get here, so we will always take the
|
||||
// GenerateExpectationsFile at the end of this function.
|
||||
DCHECK(!options.rebaseline());
|
||||
DCHECK(!options.rebaseline() && !options.check_baseline());
|
||||
ExtractSnippets(&snippet_list, std::cin, options.read_raw_js_snippet());
|
||||
} else {
|
||||
bool check_failed = false;
|
||||
for (const std::string& input_filename : options.input_filenames()) {
|
||||
if (options.verbose()) {
|
||||
std::cerr << "Processing " << input_filename << '\n';
|
||||
@ -539,25 +627,35 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
ProgramOptions updated_options = options;
|
||||
if (options.rebaseline()) {
|
||||
if (options.baseline()) {
|
||||
updated_options.UpdateFromHeader(input_stream);
|
||||
CHECK(updated_options.Validate());
|
||||
}
|
||||
|
||||
ExtractSnippets(&snippet_list, input_stream,
|
||||
options.read_raw_js_snippet());
|
||||
input_stream.close();
|
||||
|
||||
if (options.rebaseline()) {
|
||||
if (!WriteExpectationsFile(snippet_list, platform, updated_options,
|
||||
input_filename)) {
|
||||
return 3;
|
||||
}
|
||||
} else if (options.check_baseline()) {
|
||||
check_failed |= CheckBaselineExpectations(input_filename, snippet_list,
|
||||
platform, updated_options);
|
||||
}
|
||||
|
||||
if (options.baseline()) {
|
||||
snippet_list.clear();
|
||||
}
|
||||
}
|
||||
if (check_failed) {
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.rebaseline()) {
|
||||
if (!options.baseline()) {
|
||||
if (!WriteExpectationsFile(snippet_list, platform, options,
|
||||
options.output_filename())) {
|
||||
return 3;
|
||||
|
Loading…
Reference in New Issue
Block a user