winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

ReportingHandlerTests.cpp (5360B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 
      4 #include "ReportingHandler.h"
      5 
      6 #include <catch2/catch_test_macros.hpp>
      7 
      8 #include <chrono>
      9 #include <mutex>
     10 #include <optional>
     11 #include <thread>
     12 
     13 #define TEST(...) TEST_CASE("[ReportingHandlerTests] " __VA_ARGS__)
     14 
     15 using namespace SFS;
     16 using namespace SFS::details;
     17 
     18 TEST("Testing SetLoggingCallback()")
     19 {
     20     ReportingHandler handler;
     21 
     22     bool called = false;
     23     auto handling = [&](const LogData&) { called = true; };
     24 
     25     handler.SetLoggingCallback(handling);
     26     REQUIRE_FALSE(called);
     27 
     28     LOG_INFO(handler, "Test");
     29 
     30     called = false;
     31     handler.SetLoggingCallback(nullptr);
     32 
     33     LOG_INFO(handler, "Test");
     34     REQUIRE_FALSE(called);
     35 }
     36 
     37 TEST("Testing Severities")
     38 {
     39     ReportingHandler handler;
     40 
     41     std::optional<LogSeverity> severity;
     42     auto handling = [&](const LogData& data) { severity = data.severity; };
     43 
     44     handler.SetLoggingCallback(handling);
     45 
     46     REQUIRE(!severity.has_value());
     47 
     48     LOG_INFO(handler, "Test");
     49     REQUIRE(severity.has_value());
     50     REQUIRE(*severity == LogSeverity::Info);
     51     severity.reset();
     52 
     53     LOG_WARNING(handler, "Test");
     54     REQUIRE(severity.has_value());
     55     REQUIRE(*severity == LogSeverity::Warning);
     56     severity.reset();
     57 
     58     LOG_ERROR(handler, "Test");
     59     REQUIRE(severity.has_value());
     60     REQUIRE(*severity == LogSeverity::Error);
     61     severity.reset();
     62 
     63     LOG_VERBOSE(handler, "Test");
     64     REQUIRE(severity.has_value());
     65     REQUIRE(*severity == LogSeverity::Verbose);
     66 
     67     handler.SetLoggingCallback(nullptr);
     68 }
     69 
     70 TEST("Testing file/line/function")
     71 {
     72     ReportingHandler handler;
     73 
     74     std::string file;
     75     int line = 0;
     76     std::string function;
     77     auto handling = [&](const LogData& data) {
     78         file = std::string(data.file);
     79         line = data.line;
     80         function = std::string(data.function);
     81     };
     82 
     83     handler.SetLoggingCallback(handling);
     84 
     85     LOG_INFO(handler, "Test");
     86     CHECK(file.find("ReportingHandlerTests.cpp") != std::string::npos);
     87     CHECK(line == (__LINE__ - 2));
     88     CHECK(function == "CATCH2_INTERNAL_TEST_4");
     89 
     90     LOG_WARNING(handler, "Test");
     91     CHECK(file.find("ReportingHandlerTests.cpp") != std::string::npos);
     92     CHECK(line == (__LINE__ - 2));
     93     CHECK(function == "CATCH2_INTERNAL_TEST_4");
     94 }
     95 
     96 TEST("Testing LogFormatting")
     97 {
     98     ReportingHandler handler;
     99 
    100     std::string message;
    101     auto handling = [&](const LogData& data) { message = data.message; };
    102 
    103     handler.SetLoggingCallback(handling);
    104 
    105     REQUIRE(message.empty());
    106 
    107     LOG_INFO(handler, "Test %s", "Test");
    108     REQUIRE(message == "Test Test");
    109 
    110     LOG_WARNING(handler, "Test %s %s", "Test1", "Test2");
    111     REQUIRE(message == "Test Test1 Test2");
    112 
    113     LOG_ERROR(handler, "Test %s %s %s", "Test1", "Test2", "Test3");
    114     REQUIRE(message == "Test Test1 Test2 Test3");
    115 
    116     LOG_INFO(handler, "Test %d %d", 1, true);
    117     REQUIRE(message == "Test 1 1");
    118 
    119     LOG_INFO(handler, "Test %d %s", 2, false ? "true" : "false");
    120     REQUIRE(message == "Test 2 false");
    121 
    122     handler.SetLoggingCallback(nullptr);
    123 }
    124 
    125 TEST("Testing setting another logging callback waits for an existing call to finish")
    126 {
    127     ReportingHandler handler;
    128 
    129     // Set a callback that will be blocked by a mutex
    130     std::mutex mutex;
    131     bool called = false;
    132     std::chrono::time_point<std::chrono::system_clock> time1;
    133     bool startedCall = false;
    134     auto handling = [&](const LogData& logData) {
    135         startedCall = true;
    136         std::lock_guard guard(mutex);
    137         called = true;
    138         time1 = logData.time;
    139     };
    140 
    141     handler.SetLoggingCallback(handling);
    142 
    143     // Make sure the callback is blocked
    144     std::unique_lock lock(mutex);
    145 
    146     // Spawn a thread that will be blocked by the callback
    147     std::thread t([&]() { LOG_INFO(handler, "Test"); });
    148 
    149     LoggingCallbackFn anotherHandling;
    150     SECTION("Setting another callback")
    151     {
    152         anotherHandling = [&](const LogData&) {};
    153     }
    154     SECTION("Setting a nullptr callback")
    155     {
    156         anotherHandling = nullptr;
    157     }
    158 
    159     // Spawn a second thread that tries to set another callback
    160     std::chrono::time_point<std::chrono::system_clock> time2;
    161     std::thread t2([&]() {
    162         // Make sure the callback has started and is now blocked
    163         while (!startedCall)
    164         {
    165             std::this_thread::sleep_for(std::chrono::milliseconds(1));
    166         }
    167 
    168         // Now setting another callback should be blocked until we unlock the mutex
    169         handler.SetLoggingCallback(std::move(anotherHandling));
    170         INFO("The first callback should have been called at this point");
    171         REQUIRE(called);
    172         time2 = std::chrono::system_clock::now();
    173     });
    174 
    175     // Unlocking the mutex will allow the threads to continue
    176     lock.unlock();
    177     t.join();
    178     t2.join();
    179 
    180     INFO("The first callback should have been called before the second callback was set");
    181     REQUIRE(time1 < time2);
    182 }
    183 
    184 TEST("Testing ToString(LogSeverity)")
    185 {
    186     REQUIRE(SFS::ToString(LogSeverity::Info) == "Info");
    187     REQUIRE(SFS::ToString(LogSeverity::Warning) == "Warning");
    188     REQUIRE(SFS::ToString(LogSeverity::Error) == "Error");
    189     REQUIRE(SFS::ToString(LogSeverity::Verbose) == "Verbose");
    190 }