Repository: bitcoin/bitcoin
File: src/test/util/logging.h (C/C++)

Code before:
// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_TEST_UTIL_LOGGING_H
#define BITCOIN_TEST_UTIL_LOGGING_H

#include <util/macros.h>

#include <functional>
#include <list>
#include <string>

class DebugLogHelper
{
    const std::string m_message;
    bool m_found{false};
    std::list<std::function<void(const std::string&)>>::iterator m_print_connection;

    //! Custom match checking function.
    //!
    //! Invoked with pointers to lines containing matching strings, and with
    //! null if check_found() is called without any successful match.
    //!
    //! Can return true to enable default DebugLogHelper behavior of:
    //! (1) ending search after first successful match, and
    //! (2) raising an error in check_found if no match was found
    //! Can return false to do the opposite in either case.
    using MatchFn = std::function<bool(const std::string* line)>;
    MatchFn m_match;

    void check_found();

public:
    explicit DebugLogHelper(std::string message, MatchFn match = [](const std::string*){ return true; });
    ~DebugLogHelper() noexcept(false) { check_found(); }
};

#define ASSERT_DEBUG_LOG(message) DebugLogHelper UNIQUE_NAME(debugloghelper)(message)

#endif // BITCOIN_TEST_UTIL_LOGGING_H


Review comment (bug):
I'm very much against these long and scary comments - seems like a strong code smell. The comment will quickly reflect an old version of the code since it's not high-level enough and we simply won't update it when the code changes. And honestly reading the whole thing didn't help me with understanding the gist of it.

If we feel the code isn't self-explanatory we should adjust the code instead of writing long documentation for it. If you still feel docs are needed, let's do it more high-level without all the details that the code can already tell us, maybe something like:

```suggestion
    /**
     * RAII test helper that asserts a log line containing `message` is emitted during its lifetime.
     * The optional `match` predicate is called for each such line, and once at destruction with `nullptr`, if none.
     * If that final call returns true, an error is printed and the process aborts (default).
     */
```

Code after:
    //! Invoked with pointers to lines containing matching strings, and with
    //! null if check_found() is called without any successful match.
    //!
    //! Can return true to enable default DebugLogHelper behavior of:
    //! (1) ending search after first successful match, and
    //! (2) raising an error in check_found if no match was found
    //! Can return false to do the opposite in either case.
    using MatchFn = std::function<bool(const std::string* line)>;

    explicit DebugLogHelper(std::string message, MatchFn match = [](const std::string*){ return true; });

    DebugLogHelper(const DebugLogHelper&) = delete;
    DebugLogHelper& operator=(const DebugLogHelper&) = delete;

    ~DebugLogHelper();

private:
    const std::string m_message;
    bool m_found{false};
    std::list<std::function<void(const std::string&)>>::iterator m_print_connection;
    MatchFn m_match;
};

#define ASSERT_DEBUG_LOG(message) DebugLogHelper UNIQUE_NAME(debugloghelper)(message)

#endif // BITCOIN_TEST_UTIL_LOGGING_H