448 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			448 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
//===------ ResourceTrackerTest.cpp - Unit tests ResourceTracker API ------===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "OrcTestCommon.h"
 | 
						|
#include "llvm/ADT/FunctionExtras.h"
 | 
						|
#include "llvm/Config/llvm-config.h"
 | 
						|
#include "llvm/ExecutionEngine/Orc/Core.h"
 | 
						|
#include "llvm/ExecutionEngine/Orc/Shared/OrcError.h"
 | 
						|
#include "llvm/Testing/Support/Error.h"
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
using namespace llvm::orc;
 | 
						|
 | 
						|
class ResourceTrackerStandardTest : public CoreAPIsBasedStandardTest {};
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
template <typename ResourceT = unsigned>
 | 
						|
class SimpleResourceManager : public ResourceManager {
 | 
						|
public:
 | 
						|
  using HandleRemoveFunction = unique_function<Error(ResourceKey)>;
 | 
						|
 | 
						|
  using HandleTransferFunction =
 | 
						|
      unique_function<void(ResourceKey, ResourceKey)>;
 | 
						|
 | 
						|
  using RecordedResourcesMap = DenseMap<ResourceKey, ResourceT>;
 | 
						|
 | 
						|
  SimpleResourceManager(ExecutionSession &ES) : ES(ES) {
 | 
						|
    HandleRemove = [&](ResourceKey K) -> Error {
 | 
						|
      ES.runSessionLocked([&] { removeResource(K); });
 | 
						|
      return Error::success();
 | 
						|
    };
 | 
						|
 | 
						|
    HandleTransfer = [this](ResourceKey DstKey, ResourceKey SrcKey) {
 | 
						|
      transferResources(DstKey, SrcKey);
 | 
						|
    };
 | 
						|
 | 
						|
    ES.registerResourceManager(*this);
 | 
						|
  }
 | 
						|
 | 
						|
  SimpleResourceManager(const SimpleResourceManager &) = delete;
 | 
						|
  SimpleResourceManager &operator=(const SimpleResourceManager &) = delete;
 | 
						|
  SimpleResourceManager(SimpleResourceManager &&) = delete;
 | 
						|
  SimpleResourceManager &operator=(SimpleResourceManager &&) = delete;
 | 
						|
 | 
						|
  ~SimpleResourceManager() { ES.deregisterResourceManager(*this); }
 | 
						|
 | 
						|
  /// Set the HandleRemove function object.
 | 
						|
  void setHandleRemove(HandleRemoveFunction HandleRemove) {
 | 
						|
    this->HandleRemove = std::move(HandleRemove);
 | 
						|
  }
 | 
						|
 | 
						|
  /// Set the HandleTransfer function object.
 | 
						|
  void setHandleTransfer(HandleTransferFunction HandleTransfer) {
 | 
						|
    this->HandleTransfer = std::move(HandleTransfer);
 | 
						|
  }
 | 
						|
 | 
						|
  /// Create an association between the given key and resource.
 | 
						|
  template <typename MergeOp = std::plus<ResourceT>>
 | 
						|
  void recordResource(ResourceKey K, ResourceT Val = ResourceT(),
 | 
						|
                      MergeOp Merge = MergeOp()) {
 | 
						|
    auto Tmp = std::move(Resources[K]);
 | 
						|
    Resources[K] = Merge(std::move(Tmp), std::move(Val));
 | 
						|
  }
 | 
						|
 | 
						|
  /// Remove the resource associated with K from the map if present.
 | 
						|
  void removeResource(ResourceKey K) { Resources.erase(K); }
 | 
						|
 | 
						|
  /// Transfer resources from DstKey to SrcKey.
 | 
						|
  template <typename MergeOp = std::plus<ResourceT>>
 | 
						|
  void transferResources(ResourceKey DstKey, ResourceKey SrcKey,
 | 
						|
                         MergeOp Merge = MergeOp()) {
 | 
						|
    auto &DstResourceRef = Resources[DstKey];
 | 
						|
    ResourceT DstResources;
 | 
						|
    std::swap(DstResourceRef, DstResources);
 | 
						|
 | 
						|
    auto SI = Resources.find(SrcKey);
 | 
						|
    assert(SI != Resources.end() && "No resource associated with SrcKey");
 | 
						|
 | 
						|
    DstResourceRef = Merge(std::move(DstResources), std::move(SI->second));
 | 
						|
    Resources.erase(SI);
 | 
						|
  }
 | 
						|
 | 
						|
  /// Return a reference to the Resources map.
 | 
						|
  RecordedResourcesMap &getRecordedResources() { return Resources; }
 | 
						|
  const RecordedResourcesMap &getRecordedResources() const { return Resources; }
 | 
						|
 | 
						|
  Error handleRemoveResources(ResourceKey K) override {
 | 
						|
    return HandleRemove(K);
 | 
						|
  }
 | 
						|
 | 
						|
  void handleTransferResources(ResourceKey DstKey,
 | 
						|
                               ResourceKey SrcKey) override {
 | 
						|
    HandleTransfer(DstKey, SrcKey);
 | 
						|
  }
 | 
						|
 | 
						|
  static void transferNotAllowed(ResourceKey DstKey, ResourceKey SrcKey) {
 | 
						|
    llvm_unreachable("Resource transfer not allowed");
 | 
						|
  }
 | 
						|
 | 
						|
private:
 | 
						|
  ExecutionSession &ES;
 | 
						|
  HandleRemoveFunction HandleRemove;
 | 
						|
  HandleTransferFunction HandleTransfer;
 | 
						|
  RecordedResourcesMap Resources;
 | 
						|
};
 | 
						|
 | 
						|
TEST_F(ResourceTrackerStandardTest,
 | 
						|
       BasicDefineAndRemoveAllBeforeMaterializing) {
 | 
						|
 | 
						|
  bool ResourceManagerGotRemove = false;
 | 
						|
  SimpleResourceManager<> SRM(ES);
 | 
						|
  SRM.setHandleRemove([&](ResourceKey K) -> Error {
 | 
						|
    ResourceManagerGotRemove = true;
 | 
						|
    EXPECT_EQ(SRM.getRecordedResources().size(), 0U)
 | 
						|
        << "Unexpected resources recorded";
 | 
						|
    SRM.removeResource(K);
 | 
						|
    return Error::success();
 | 
						|
  });
 | 
						|
 | 
						|
  bool MaterializationUnitDestroyed = false;
 | 
						|
  auto MU = std::make_unique<SimpleMaterializationUnit>(
 | 
						|
      SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
 | 
						|
      [&](std::unique_ptr<MaterializationResponsibility> R) {
 | 
						|
        llvm_unreachable("Never called");
 | 
						|
      },
 | 
						|
      nullptr, SimpleMaterializationUnit::DiscardFunction(),
 | 
						|
      [&]() { MaterializationUnitDestroyed = true; });
 | 
						|
 | 
						|
  auto RT = JD.createResourceTracker();
 | 
						|
  cantFail(JD.define(std::move(MU), RT));
 | 
						|
  cantFail(RT->remove());
 | 
						|
  auto SymFlags = cantFail(ES.lookupFlags(
 | 
						|
      LookupKind::Static,
 | 
						|
      {{&JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
 | 
						|
      SymbolLookupSet(Foo, SymbolLookupFlags::WeaklyReferencedSymbol)));
 | 
						|
 | 
						|
  EXPECT_EQ(SymFlags.size(), 0U)
 | 
						|
      << "Symbols should have been removed from the symbol table";
 | 
						|
  EXPECT_TRUE(ResourceManagerGotRemove)
 | 
						|
      << "ResourceManager did not receive handleRemoveResources";
 | 
						|
  EXPECT_TRUE(MaterializationUnitDestroyed)
 | 
						|
      << "MaterializationUnit not destroyed in response to removal";
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ResourceTrackerStandardTest, BasicDefineAndRemoveAllAfterMaterializing) {
 | 
						|
 | 
						|
  bool ResourceManagerGotRemove = false;
 | 
						|
  SimpleResourceManager<> SRM(ES);
 | 
						|
  SRM.setHandleRemove([&](ResourceKey K) -> Error {
 | 
						|
    ResourceManagerGotRemove = true;
 | 
						|
    EXPECT_EQ(SRM.getRecordedResources().size(), 1U)
 | 
						|
        << "Unexpected number of resources recorded";
 | 
						|
    EXPECT_EQ(SRM.getRecordedResources().count(K), 1U)
 | 
						|
        << "Unexpected recorded resource";
 | 
						|
    SRM.removeResource(K);
 | 
						|
    return Error::success();
 | 
						|
  });
 | 
						|
 | 
						|
  auto MU = std::make_unique<SimpleMaterializationUnit>(
 | 
						|
      SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
 | 
						|
      [&](std::unique_ptr<MaterializationResponsibility> R) {
 | 
						|
        cantFail(R->withResourceKeyDo(
 | 
						|
            [&](ResourceKey K) { SRM.recordResource(K); }));
 | 
						|
        cantFail(R->notifyResolved({{Foo, FooSym}}));
 | 
						|
        cantFail(R->notifyEmitted());
 | 
						|
      });
 | 
						|
 | 
						|
  auto RT = JD.createResourceTracker();
 | 
						|
  cantFail(JD.define(std::move(MU), RT));
 | 
						|
  cantFail(ES.lookup({&JD}, Foo));
 | 
						|
  cantFail(RT->remove());
 | 
						|
  auto SymFlags = cantFail(ES.lookupFlags(
 | 
						|
      LookupKind::Static,
 | 
						|
      {{&JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
 | 
						|
      SymbolLookupSet(Foo, SymbolLookupFlags::WeaklyReferencedSymbol)));
 | 
						|
 | 
						|
  EXPECT_EQ(SymFlags.size(), 0U)
 | 
						|
      << "Symbols should have been removed from the symbol table";
 | 
						|
  EXPECT_TRUE(ResourceManagerGotRemove)
 | 
						|
      << "ResourceManager did not receive handleRemoveResources";
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ResourceTrackerStandardTest, BasicDefineAndRemoveAllWhileMaterializing) {
 | 
						|
 | 
						|
  bool ResourceManagerGotRemove = false;
 | 
						|
  SimpleResourceManager<> SRM(ES);
 | 
						|
  SRM.setHandleRemove([&](ResourceKey K) -> Error {
 | 
						|
    ResourceManagerGotRemove = true;
 | 
						|
    EXPECT_EQ(SRM.getRecordedResources().size(), 0U)
 | 
						|
        << "Unexpected resources recorded";
 | 
						|
    SRM.removeResource(K);
 | 
						|
    return Error::success();
 | 
						|
  });
 | 
						|
 | 
						|
  std::unique_ptr<MaterializationResponsibility> MR;
 | 
						|
  auto MU = std::make_unique<SimpleMaterializationUnit>(
 | 
						|
      SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
 | 
						|
      [&](std::unique_ptr<MaterializationResponsibility> R) {
 | 
						|
        MR = std::move(R);
 | 
						|
      });
 | 
						|
 | 
						|
  auto RT = JD.createResourceTracker();
 | 
						|
  cantFail(JD.define(std::move(MU), RT));
 | 
						|
 | 
						|
  ES.lookup(
 | 
						|
      LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo),
 | 
						|
      SymbolState::Ready,
 | 
						|
      [](Expected<SymbolMap> Result) {
 | 
						|
        EXPECT_THAT_EXPECTED(Result, Failed<FailedToMaterialize>())
 | 
						|
            << "Lookup failed unexpectedly";
 | 
						|
      },
 | 
						|
      NoDependenciesToRegister);
 | 
						|
 | 
						|
  cantFail(RT->remove());
 | 
						|
  auto SymFlags = cantFail(ES.lookupFlags(
 | 
						|
      LookupKind::Static,
 | 
						|
      {{&JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
 | 
						|
      SymbolLookupSet(Foo, SymbolLookupFlags::WeaklyReferencedSymbol)));
 | 
						|
 | 
						|
  EXPECT_EQ(SymFlags.size(), 0U)
 | 
						|
      << "Symbols should have been removed from the symbol table";
 | 
						|
  EXPECT_TRUE(ResourceManagerGotRemove)
 | 
						|
      << "ResourceManager did not receive handleRemoveResources";
 | 
						|
 | 
						|
  EXPECT_THAT_ERROR(MR->withResourceKeyDo([](ResourceKey K) {
 | 
						|
    ADD_FAILURE() << "Should not reach withResourceKeyDo body for removed key";
 | 
						|
  }),
 | 
						|
                    Failed<ResourceTrackerDefunct>())
 | 
						|
      << "withResourceKeyDo on MR with removed tracker should have failed";
 | 
						|
  EXPECT_THAT_ERROR(MR->notifyResolved({{Foo, FooSym}}),
 | 
						|
                    Failed<ResourceTrackerDefunct>())
 | 
						|
      << "notifyResolved on MR with removed tracker should have failed";
 | 
						|
 | 
						|
  MR->failMaterialization();
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ResourceTrackerStandardTest, JITDylibClear) {
 | 
						|
  SimpleResourceManager<> SRM(ES);
 | 
						|
 | 
						|
  // Add materializer for Foo.
 | 
						|
  cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
 | 
						|
      SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
 | 
						|
      [&](std::unique_ptr<MaterializationResponsibility> R) {
 | 
						|
        cantFail(R->withResourceKeyDo(
 | 
						|
            [&](ResourceKey K) { ++SRM.getRecordedResources()[K]; }));
 | 
						|
        cantFail(R->notifyResolved({{Foo, FooSym}}));
 | 
						|
        cantFail(R->notifyEmitted());
 | 
						|
      })));
 | 
						|
 | 
						|
  // Add materializer for Bar.
 | 
						|
  cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
 | 
						|
      SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
 | 
						|
      [&](std::unique_ptr<MaterializationResponsibility> R) {
 | 
						|
        cantFail(R->withResourceKeyDo(
 | 
						|
            [&](ResourceKey K) { ++SRM.getRecordedResources()[K]; }));
 | 
						|
        cantFail(R->notifyResolved({{Bar, BarSym}}));
 | 
						|
        cantFail(R->notifyEmitted());
 | 
						|
      })));
 | 
						|
 | 
						|
  EXPECT_TRUE(SRM.getRecordedResources().empty())
 | 
						|
      << "Expected no resources recorded yet.";
 | 
						|
 | 
						|
  cantFail(
 | 
						|
      ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo, Bar})));
 | 
						|
 | 
						|
  auto JDResourceKey = JD.getDefaultResourceTracker()->getKeyUnsafe();
 | 
						|
  EXPECT_EQ(SRM.getRecordedResources().size(), 1U)
 | 
						|
      << "Expected exactly one entry (for JD's ResourceKey)";
 | 
						|
  EXPECT_EQ(SRM.getRecordedResources().count(JDResourceKey), 1U)
 | 
						|
      << "Expected an entry for JD's ResourceKey";
 | 
						|
  EXPECT_EQ(SRM.getRecordedResources()[JDResourceKey], 2U)
 | 
						|
      << "Expected value of 2 for JD's ResourceKey "
 | 
						|
         "(+1 for each of Foo and Bar)";
 | 
						|
 | 
						|
  cantFail(JD.clear());
 | 
						|
 | 
						|
  EXPECT_TRUE(SRM.getRecordedResources().empty())
 | 
						|
      << "Expected no resources recorded after clear";
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ResourceTrackerStandardTest,
 | 
						|
       BasicDefineAndExplicitTransferBeforeMaterializing) {
 | 
						|
 | 
						|
  bool ResourceManagerGotTransfer = false;
 | 
						|
  SimpleResourceManager<> SRM(ES);
 | 
						|
  SRM.setHandleTransfer([&](ResourceKey DstKey, ResourceKey SrcKey) {
 | 
						|
    ResourceManagerGotTransfer = true;
 | 
						|
    auto &RR = SRM.getRecordedResources();
 | 
						|
    EXPECT_EQ(RR.size(), 0U) << "Expected no resources recorded yet";
 | 
						|
  });
 | 
						|
 | 
						|
  auto MakeMU = [&](SymbolStringPtr Name, JITEvaluatedSymbol Sym) {
 | 
						|
    return std::make_unique<SimpleMaterializationUnit>(
 | 
						|
        SymbolFlagsMap({{Name, Sym.getFlags()}}),
 | 
						|
        [=, &SRM](std::unique_ptr<MaterializationResponsibility> R) {
 | 
						|
          cantFail(R->withResourceKeyDo(
 | 
						|
              [&](ResourceKey K) { SRM.recordResource(K); }));
 | 
						|
          cantFail(R->notifyResolved({{Name, Sym}}));
 | 
						|
          cantFail(R->notifyEmitted());
 | 
						|
        });
 | 
						|
  };
 | 
						|
 | 
						|
  auto FooRT = JD.createResourceTracker();
 | 
						|
  cantFail(JD.define(MakeMU(Foo, FooSym), FooRT));
 | 
						|
 | 
						|
  auto BarRT = JD.createResourceTracker();
 | 
						|
  cantFail(JD.define(MakeMU(Bar, BarSym), BarRT));
 | 
						|
 | 
						|
  BarRT->transferTo(*FooRT);
 | 
						|
 | 
						|
  EXPECT_TRUE(ResourceManagerGotTransfer)
 | 
						|
      << "ResourceManager did not receive transfer";
 | 
						|
  EXPECT_TRUE(BarRT->isDefunct()) << "BarRT should now be defunct";
 | 
						|
 | 
						|
  cantFail(
 | 
						|
      ES.lookup(makeJITDylibSearchOrder({&JD}), SymbolLookupSet({Foo, Bar})));
 | 
						|
 | 
						|
  EXPECT_EQ(SRM.getRecordedResources().size(), 1U)
 | 
						|
      << "Expected exactly one entry (for FooRT's Key)";
 | 
						|
  EXPECT_EQ(SRM.getRecordedResources().count(FooRT->getKeyUnsafe()), 1U)
 | 
						|
      << "Expected an entry for FooRT's ResourceKey";
 | 
						|
  EXPECT_EQ(SRM.getRecordedResources().count(BarRT->getKeyUnsafe()), 0U)
 | 
						|
      << "Expected no entry for BarRT's ResourceKey";
 | 
						|
 | 
						|
  // We need to explicitly destroy FooRT or its resources will be implicitly
 | 
						|
  // transferred to the default tracker triggering a second call to our
 | 
						|
  // transfer function above (which expects only one call).
 | 
						|
  cantFail(FooRT->remove());
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ResourceTrackerStandardTest,
 | 
						|
       BasicDefineAndExplicitTransferAfterMaterializing) {
 | 
						|
 | 
						|
  bool ResourceManagerGotTransfer = false;
 | 
						|
  SimpleResourceManager<> SRM(ES);
 | 
						|
  SRM.setHandleTransfer([&](ResourceKey DstKey, ResourceKey SrcKey) {
 | 
						|
    ResourceManagerGotTransfer = true;
 | 
						|
    SRM.transferResources(DstKey, SrcKey);
 | 
						|
  });
 | 
						|
 | 
						|
  auto MakeMU = [&](SymbolStringPtr Name, JITEvaluatedSymbol Sym) {
 | 
						|
    return std::make_unique<SimpleMaterializationUnit>(
 | 
						|
        SymbolFlagsMap({{Name, Sym.getFlags()}}),
 | 
						|
        [=, &SRM](std::unique_ptr<MaterializationResponsibility> R) {
 | 
						|
          cantFail(R->withResourceKeyDo(
 | 
						|
              [&](ResourceKey K) { SRM.recordResource(K, 1); }));
 | 
						|
          cantFail(R->notifyResolved({{Name, Sym}}));
 | 
						|
          cantFail(R->notifyEmitted());
 | 
						|
        });
 | 
						|
  };
 | 
						|
 | 
						|
  auto FooRT = JD.createResourceTracker();
 | 
						|
  cantFail(JD.define(MakeMU(Foo, FooSym), FooRT));
 | 
						|
 | 
						|
  auto BarRT = JD.createResourceTracker();
 | 
						|
  cantFail(JD.define(MakeMU(Bar, BarSym), BarRT));
 | 
						|
 | 
						|
  EXPECT_EQ(SRM.getRecordedResources().size(), 0U)
 | 
						|
      << "Expected no recorded resources yet";
 | 
						|
 | 
						|
  cantFail(
 | 
						|
      ES.lookup(makeJITDylibSearchOrder({&JD}), SymbolLookupSet({Foo, Bar})));
 | 
						|
 | 
						|
  EXPECT_EQ(SRM.getRecordedResources().size(), 2U)
 | 
						|
      << "Expected recorded resources for both Foo and Bar";
 | 
						|
 | 
						|
  BarRT->transferTo(*FooRT);
 | 
						|
 | 
						|
  EXPECT_TRUE(ResourceManagerGotTransfer)
 | 
						|
      << "ResourceManager did not receive transfer";
 | 
						|
  EXPECT_TRUE(BarRT->isDefunct()) << "BarRT should now be defunct";
 | 
						|
 | 
						|
  EXPECT_EQ(SRM.getRecordedResources().size(), 1U)
 | 
						|
      << "Expected recorded resources for Foo only";
 | 
						|
  EXPECT_EQ(SRM.getRecordedResources().count(FooRT->getKeyUnsafe()), 1U)
 | 
						|
      << "Expected recorded resources for Foo";
 | 
						|
  EXPECT_EQ(SRM.getRecordedResources()[FooRT->getKeyUnsafe()], 2U)
 | 
						|
      << "Expected resources value for for Foo to be '2'";
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ResourceTrackerStandardTest,
 | 
						|
       BasicDefineAndExplicitTransferWhileMaterializing) {
 | 
						|
 | 
						|
  bool ResourceManagerGotTransfer = false;
 | 
						|
  SimpleResourceManager<> SRM(ES);
 | 
						|
  SRM.setHandleTransfer([&](ResourceKey DstKey, ResourceKey SrcKey) {
 | 
						|
    ResourceManagerGotTransfer = true;
 | 
						|
    SRM.transferResources(DstKey, SrcKey);
 | 
						|
  });
 | 
						|
 | 
						|
  auto FooRT = JD.createResourceTracker();
 | 
						|
  std::unique_ptr<MaterializationResponsibility> FooMR;
 | 
						|
  cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
 | 
						|
                         SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
 | 
						|
                         [&](std::unique_ptr<MaterializationResponsibility> R) {
 | 
						|
                           FooMR = std::move(R);
 | 
						|
                         }),
 | 
						|
                     FooRT));
 | 
						|
 | 
						|
  auto BarRT = JD.createResourceTracker();
 | 
						|
 | 
						|
  ES.lookup(
 | 
						|
      LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo),
 | 
						|
      SymbolState::Ready,
 | 
						|
      [](Expected<SymbolMap> Result) { cantFail(Result.takeError()); },
 | 
						|
      NoDependenciesToRegister);
 | 
						|
 | 
						|
  cantFail(FooMR->withResourceKeyDo([&](ResourceKey K) {
 | 
						|
    EXPECT_EQ(FooRT->getKeyUnsafe(), K)
 | 
						|
        << "Expected FooRT's ResourceKey for Foo here";
 | 
						|
    SRM.recordResource(K, 1);
 | 
						|
  }));
 | 
						|
 | 
						|
  EXPECT_EQ(SRM.getRecordedResources().size(), 1U)
 | 
						|
      << "Expected one recorded resource here";
 | 
						|
  EXPECT_EQ(SRM.getRecordedResources()[FooRT->getKeyUnsafe()], 1U)
 | 
						|
      << "Expected Resource value for FooRT to be '1' here";
 | 
						|
 | 
						|
  FooRT->transferTo(*BarRT);
 | 
						|
 | 
						|
  EXPECT_TRUE(ResourceManagerGotTransfer)
 | 
						|
      << "Expected resource manager to receive handleTransferResources call";
 | 
						|
 | 
						|
  cantFail(FooMR->withResourceKeyDo([&](ResourceKey K) {
 | 
						|
    EXPECT_EQ(BarRT->getKeyUnsafe(), K)
 | 
						|
        << "Expected BarRT's ResourceKey for Foo here";
 | 
						|
    SRM.recordResource(K, 1);
 | 
						|
  }));
 | 
						|
 | 
						|
  EXPECT_EQ(SRM.getRecordedResources().size(), 1U)
 | 
						|
      << "Expected one recorded resource here";
 | 
						|
  EXPECT_EQ(SRM.getRecordedResources().count(BarRT->getKeyUnsafe()), 1U)
 | 
						|
      << "Expected RecordedResources to contain an entry for BarRT";
 | 
						|
  EXPECT_EQ(SRM.getRecordedResources()[BarRT->getKeyUnsafe()], 2U)
 | 
						|
      << "Expected Resource value for BarRT to be '2' here";
 | 
						|
 | 
						|
  cantFail(FooMR->notifyResolved({{Foo, FooSym}}));
 | 
						|
  cantFail(FooMR->notifyEmitted());
 | 
						|
}
 | 
						|
 | 
						|
} // namespace
 |