From 31b7a9c3127560ea0c488b88e93077e08600652f Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 14 Feb 2020 12:21:16 +0100 Subject: [PATCH] Add expect option to logger command --- kernel/driver.cc | 4 ++- kernel/log.cc | 59 ++++++++++++++++++++++++++++++++++++++++++- kernel/log.h | 17 +++++++++++++ passes/cmds/logger.cc | 36 +++++++++++++++++++++++++- 4 files changed, 113 insertions(+), 3 deletions(-) diff --git a/kernel/driver.cc b/kernel/driver.cc index 9040408bc..1802e8aac 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -664,13 +664,15 @@ int main(int argc, char **argv) } #endif + log_check_expected(); + yosys_atexit(); memhasher_off(); if (call_abort) abort(); - log_flush(); + log_flush(); #if defined(_MSC_VER) _exit(0); #elif defined(_WIN32) diff --git a/kernel/log.cc b/kernel/log.cc index f5d6c488e..997c39c64 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -42,6 +42,7 @@ std::vector log_files; std::vector log_streams; std::map> log_hdump; std::vector log_warn_regexes, log_nowarn_regexes, log_werror_regexes; +std::vector> log_expect_log, log_expect_warning, log_expect_error; std::set log_warnings, log_experimentals, log_experimentals_ignored; int log_warnings_count = 0; bool log_hdump_all = false; @@ -68,6 +69,7 @@ int string_buf_index = -1; static struct timeval initial_tv = { 0, 0 }; static bool next_print_log = false; static int log_newline_count = 0; +static bool check_expected_logs = true; static void log_id_cache_clear() { @@ -162,7 +164,7 @@ void logv(const char *format, va_list ap) { log_warn_regex_recusion_guard = true; - if (log_warn_regexes.empty()) + if (log_warn_regexes.empty() && log_expect_log.empty()) { linebuffer.clear(); } @@ -174,6 +176,11 @@ void logv(const char *format, va_list ap) for (auto &re : log_warn_regexes) if (std::regex_search(linebuffer, re)) log_warning("Found log message matching -W regex:\n%s", str.c_str()); + + for (auto &item : log_expect_log) + if (std::regex_search(linebuffer, item.first)) + item.second.current_count++; + linebuffer.clear(); } } @@ -244,6 +251,10 @@ static void logv_warning_with_prefix(const char *prefix, if (std::regex_search(message, re)) log_error("%s", message.c_str()); + for (auto &item : log_expect_warning) + if (std::regex_search(message, item.first)) + item.second.current_count++; + if (log_warnings.count(message)) { log("%s%s", prefix, message.c_str()); @@ -328,6 +339,12 @@ static void logv_error_with_prefix(const char *prefix, if (log_error_atexit) log_error_atexit(); + for (auto &item : log_expect_error) + if (std::regex_search(log_last_error, item.first)) + item.second.current_count++; + + if (check_expected_logs) + log_check_expected(); #ifdef EMSCRIPTEN log_files = backup_log_files; throw 0; @@ -636,6 +653,46 @@ void log_wire(RTLIL::Wire *wire, std::string indent) log("%s", buf.str().c_str()); } +void log_check_expected() +{ + check_expected_logs = false; + + for (auto &item : log_expect_warning) { + if (item.second.current_count != item.second.expected_count) { + log_error("Expected warning pattern '%s' not found !\n", item.second.pattern.c_str()); + } + if (item.second.current_count != item.second.expected_count) { + log_error("Expected warning pattern '%s' found %d time(s), instead of %d time(s) !\n", + item.second.pattern.c_str(), item.second.current_count, item.second.expected_count); + } + } + + for (auto &item : log_expect_log) { + if (item.second.current_count == 0) { + log_error("Expected log pattern '%s' not found !\n", item.second.pattern.c_str()); + } + if (item.second.current_count != item.second.expected_count) { + log_error("Expected log pattern '%s' found %d time(s), instead of %d time(s) !\n", + item.second.pattern.c_str(), item.second.current_count, item.second.expected_count); + } + } + + for (auto &item : log_expect_error) + if (item.second.current_count == item.second.expected_count) { + log("Expected error pattern '%s' found !!!\n", item.second.pattern.c_str()); + #ifdef EMSCRIPTEN + log_files = backup_log_files; + throw 0; + #elif defined(_MSC_VER) + _exit(0); + #else + _Exit(0); + #endif + } else { + log_error("Expected error pattern '%s' not found !\n", item.second.pattern.c_str()); + } +} + // --------------------------------------------------- // This is the magic behind the code coverage counters // --------------------------------------------------- diff --git a/kernel/log.h b/kernel/log.h index 9db8efaa5..0f912fccb 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -135,6 +135,23 @@ void log_backtrace(const char *prefix, int levels); void log_reset_stack(); void log_flush(); +struct LogExpectedItem +{ + LogExpectedItem(std::string pattern, int expected) : + expected_count(expected), + current_count(0), + pattern(pattern) + { + } + + int expected_count; + int current_count; + std::string pattern; +}; + +extern std::vector> log_expect_log, log_expect_warning, log_expect_error; +void log_check_expected(); + const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true); const char *log_const(const RTLIL::Const &value, bool autoint = true); const char *log_id(RTLIL::IdString id); diff --git a/passes/cmds/logger.cc b/passes/cmds/logger.cc index 3feef7dc5..30768980e 100644 --- a/passes/cmds/logger.cc +++ b/passes/cmds/logger.cc @@ -57,6 +57,9 @@ struct LoggerPass : public Pass { log(" -experimental \n"); log(" do not print warnings for the specified experimental feature\n"); log("\n"); + log(" -expect \n"); + log(" expect log,warning or error to appear. In case of error return code is 0.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design * design) YS_OVERRIDE @@ -125,13 +128,44 @@ struct LoggerPass : public Pass { log("Disabled debug log messages."); continue; } - break; if (args[argidx] == "-experimental" && argidx+1 < args.size()) { std::string value = args[++argidx]; log("Added '%s' experimental ignore list.", value.c_str()); log_experimentals_ignored.insert(value); continue; } + if (args[argidx] == "-expect" && argidx+3 < args.size()) { + std::string type = args[++argidx]; + if (type!="error" && type!="warning" && type!="log") + log_cmd_error("Expect command require type to be 'log', 'warning' or 'error' !\n"); + if (type=="error" && log_expect_error.size()>0) + log_cmd_error("Only single error message can be expected !\n"); + std::string pattern = args[++argidx]; + if (pattern.front() == '\"' && pattern.back() == '\"') pattern = pattern.substr(1, pattern.size() - 2); + int count = atoi(args[++argidx].c_str()); + if (count<=0) + log_cmd_error("Number of expected messages must be higher then 0 !\n"); + if (type=="error" && count!=1) + log_cmd_error("Expected error message occurrences must be 1 !\n"); + log("Added regex '%s' for warnings to expected %s list.\n", pattern.c_str(), type.c_str()); + if (type=="error") + log_expect_error.push_back(std::make_pair(std::regex(pattern, + std::regex_constants::nosubs | + std::regex_constants::optimize | + std::regex_constants::egrep), LogExpectedItem(pattern, count))); + else if (type=="warning") + log_expect_warning.push_back(std::make_pair(std::regex(pattern, + std::regex_constants::nosubs | + std::regex_constants::optimize | + std::regex_constants::egrep), LogExpectedItem(pattern, count))); + else + log_expect_log.push_back(std::make_pair(std::regex(pattern, + std::regex_constants::nosubs | + std::regex_constants::optimize | + std::regex_constants::egrep), LogExpectedItem(pattern, count))); + + continue; + } break; } extra_args(args, argidx, design, false); -- 2.30.2