GoogleTest/Mock rapidjson::Value& 的 SaveArg

GoogleTest/Mock SaveArg of a rapidjson::Value&

我正在尝试使用 GoogleTest 取回传递给函数的参数。该函数的声明是这样的

void foo(rapidjson::Value &element, int number) {}

我会像这样创建一个 ON_CALL

rapidjson::Value elementVal;
ON_CALL(SomeClassNameWhereFooIsAMember, foo).WillByDefault(SaveArg<0>(&elementVal));

我连编译都不会。

error C2248: 'rapidjson::GenericValue<rapidjson::UTF8<char>,rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>>::GenericValue': cannot access private member declared in class 'rapidjson::GenericValue<rapidjson::UTF8<char>,rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>>'

有什么想法吗?

更新 1:

我根据 Chris Olsen 的回复尝试了以下方法

#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "rapidjson/document.h"

using namespace ::testing;

class FooClass
{
public:
    virtual void foo(rapidjson::Value& element, int number) {}
};

class MockFoo : public FooClass
{
public:
    MOCK_METHOD(void, foo, (rapidjson::Value& element, int number));
};

ACTION_P(SaveRapidJsonValueArg, p)
{
    rapidjson::Document d;  // Needed only to get the required allocator param
    p->CopyFrom(arg0, d.GetAllocator());
}

TEST(RapidJsonTests, SaveArgTest)
{
    MockFoo mock;

    rapidjson::Document document;
    rapidjson::Document::AllocatorType& allocator = document.GetAllocator();

    rapidjson::Value object(rapidjson::kObjectType);
    object.AddMember("Math", "50", allocator);
    object.AddMember("Science", "70", allocator);
    object.AddMember("English", "50", allocator);
    object.AddMember("Social Science", "70", allocator);

    rapidjson::Value saveVal;

    ON_CALL(mock, foo).WillByDefault(SaveRapidJsonValueArg(&saveVal));

    mock.foo(object, 1);

    if (saveVal.HasMember("Math"))
        std::cout << saveVal["Math"].GetString() << "\n";
}

执行在 HasMember() 调用时崩溃。

更新 2:

再次感谢克里斯·奥尔森!这是我最后做的。

ACTION_P2(SaveRapidJsonValueArg, valuePtr, doc)
{
    valuePtr->CopyFrom(arg1, doc->GetAllocator());
}

TEST(RapidJsonTests, SaveArgTest)
{
    ...
    ...

    ON_CALL(mock, foo).WillByDefault(SaveRapidJsonValueArg(&saveVal, &document));

    ...
    ...
}

再次感谢克里斯!

很难从显示的代码中判断问题出在哪里。您应该尽可能提供 minimal reproducible example

您可能 运行 遇到的一个问题是 RapidJSON 不允许 Value 对象的正常复制。它改用移动语义。来自 RapidJSON Tutorial:

A very special decision during design of RapidJSON is that, assignment of value does not copy the source value to destination value. Instead, the value from source is moved to the destination. For example,

Value a(123);
Value b(456);
b = a;         // a becomes a Null value, b becomes number 123.

要实际复制 Value 对象,您可以使用 Value::CopyFrom 方法。 custom action 可用于在 gMock 中执行此操作:

#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "rapidjson/document.h"

using namespace ::testing;

class FooClass
{
public:
    virtual void foo(rapidjson::Value& element, int number) {}
};

class MockFoo : public FooClass
{
public:
    MOCK_METHOD(void, foo, (rapidjson::Value& element, int number));
};

struct CaptureFooValue
{
    void operator()(const rapidjson::Value &element, int) const
    {
        v.CopyFrom(element, d.GetAllocator(), true);
    }
    rapidjson::Value &v;
    rapidjson::Document &d;
};

TEST(RapidJsonTests, SaveArgTest)
{
    MockFoo mock;
    rapidjson::Document document;
    rapidjson::Document::AllocatorType& allocator = document.GetAllocator();

    rapidjson::Value object(rapidjson::kObjectType);
    object.AddMember("Math", "50", allocator);
    object.AddMember("Science", "70", allocator);
    object.AddMember("English", "50", allocator);
    object.AddMember("Social Science", "70", allocator);

    rapidjson::Value saveVal;

    ON_CALL(mock, foo).WillByDefault(CaptureFooValue{saveVal, document});

    mock.foo(object, 1);

    if (saveVal.HasMember("Math"))
        std::cout << saveVal["Math"].GetString() << "\n";
}