Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot match buffer content for a pointer argument when a method is passed with a local array #342

Closed
rainbowkenny opened this issue Aug 4, 2024 · 1 comment

Comments

@rainbowkenny
Copy link

rainbowkenny commented Aug 4, 2024

See the two subcases starting with "Cannot ..." below - I expected invocations to happen with the buffer content matched by the what's pointed by the parameter. But they didn't match. My expectation is that Fakeit should match the argument at the exact time when the method is called, including a pointer to some local data, but this seem not to be the case. I had to make the local array static or global. Is this a limit of Fakeit?

#include <array>

#include "doctest.h"
#include "fakeit.hpp"
#include "stdio.h"

namespace {
using namespace fakeit;
auto matchArray = [](int a[]) { return a[0] == 1 && a[1] == 2 && a[2] == 3; };
auto matchStdArray = [](std::array<int, 3> a) {
  return a[0] == 1 && a[1] == 2 && a[2] == 3;
};
}  // namespace

class TestInterface {
 public:
  virtual void method1(int a) = 0;
  virtual void method2(int *a) = 0;
  virtual void method3(int a[]) = 0;
  virtual void method4(std::array<int, 3> a) = 0;
  virtual ~TestInterface() = default;
};

void func1(TestInterface *ti) {
  static int staticLocalArray[3] = {1, 2, 3};
  ti->method2(staticLocalArray);
}
int globalArray[3] = {1, 2, 3};
void func2(TestInterface *ti) { ti->method2(globalArray); }
void func3(TestInterface *ti) {
  int localArray[3] = {1, 2, 3};
  ti->method2(localArray);
}
void func4(TestInterface *ti) { ti->method1(1); }
void func5(TestInterface *ti) {
  int localArray[3] = {1, 2, 3};
  ti->method3(localArray);
  std::cout << "Dtor\n";
}
void func6(TestInterface *ti) {
  std::array<int, 3> localArray = {1, 2, 3};
  ti->method4(localArray);
}

TEST_CASE("Verify method invokation with matching arguments") {
  Mock<TestInterface> mti;
  Fake(Method(mti, method1), Method(mti, method2), Method(mti, method3),
       Method(mti, method4));
  auto &ti = mti.get();

  SUBCASE("Matching simple arguments") {
    ti.method1(5);
    Verify(Method(mti, method1).Using(5));
    ti.method1(5);
    Verify(Method(mti, method1).Matching([](int a) { return a == 5; }));
  }
  SUBCASE("Matching pointer arguments") {
    int num = 1;
    int *pNum = &num;
    ti.method2(pNum);
    Verify(Method(mti, method2).Matching([](int *a) { return *a == 1; }));
  }
  SUBCASE("Matching pointer arguments with different scope") {
    {
      int num = 1;
      int *pNum = &num;
      ti.method2(pNum);
    }
    Verify(Method(mti, method2).Matching([](int *a) { return *a == 1; }));
  }
  SUBCASE("Matching array arguments ") {
    int array[3] = {1, 2, 3};
    ti.method3(array);
    Verify(Method(mti, method3).Matching(matchArray));
  }
  SUBCASE("Matching pointer to array arguments ") {
    {  // add a scope to test lifetime
      {
        int array[3] = {1, 2, 3};
        ti.method2(array);
      }
    }
    Verify(Method(mti, method2).Matching(matchArray));
  }
  SUBCASE(
      "Matching pointer to static local array arguments with some "
      "redirection") {
    func1(&ti);
    Verify(Method(mti, method2).Matching(matchArray));
  }
  SUBCASE("Matching pointer to global array arguments with some redirection") {
    func2(&ti);
    Verify(Method(mti, method2).Matching(matchArray));
  }
  SUBCASE(
      "Cannot match pointer to local array arguments with some redirection") {
    func3(&ti);
    VerifyNoOtherInvocations(Method(mti, method2).Matching(matchArray));
  }
  SUBCASE("Can match simple local arguments with some redirection") {
    func4(&ti);
    Verify(Method(mti, method1).Matching([](int a) { return a == 1; }));
  }
  SUBCASE("Cannot match local array arguments with some redirection") {
    func5(&ti);
    VerifyNoOtherInvocations(Method(mti, method3).Matching(matchArray));
  }
  SUBCASE("Should match local std::array arguments with some redirection") {
    func6(&ti);
    Verify(Method(mti, method4).Matching(matchStdArray));
  }
}
@FranckRJ
Copy link
Collaborator

FranckRJ commented Oct 6, 2024

Yeah, it's a limitation on how we verify the calls. We do it after the call happen instead of when it happened, so we can't access objects that are behind pointers / references if these objects were destroyed between the call and the check.

I try to centralize all the discussions about this limitation in the issue #274, so I'll close yours, but if you think it's not 100% related to the issue I linked let me know and I'll reopen it.

@FranckRJ FranckRJ closed this as not planned Won't fix, can't repro, duplicate, stale Oct 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants