blob: 7aa7dd3106ab219b0edecfe5a7d8760dfae6c85f [file]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_MOCK_SYMBOL_FACTORY_H_
#define SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_MOCK_SYMBOL_FACTORY_H_
#include <map>
#include "src/developer/debug/zxdb/common/ref_ptr_to.h"
#include "src/developer/debug/zxdb/symbols/lazy_symbol.h"
#include "src/developer/debug/zxdb/symbols/symbol.h"
#include "src/developer/debug/zxdb/symbols/symbol_factory.h"
namespace zxdb {
// Symbols have a backpointer to their SymbolFactory, yet the mock symbol factory must contain
// owning references to the symbols it vends. This creates a reference cycle that will leak.
//
// To get around this, the MockSymbolFactory is not actually a SymbolFactory implementation, but a
// non-reference-counted wrapper object you should create on the stack (or as a member of your test
// harness). It will clear all of the symbol references in the actual SymbolFactory implementation
// when it goes out of scope, breaking the reference cycle.
class MockSymbolFactory {
public:
MockSymbolFactory() = default;
~MockSymbolFactory() {
// Break the reference cycles.
factory_->ClearSymbols();
}
fxl::RefPtr<SymbolFactory> factory_ref() const { return factory_; }
SymbolFactory* factory() { return factory_.get(); }
const SymbolFactory* factory() const { return factory_.get(); }
void SetMockSymbol(uint64_t die_offset, fxl::RefPtr<Symbol> symbol) {
factory_->SetMockSymbol(die_offset, symbol);
}
private:
class FactoryImpl : public SymbolFactory {
public:
// SymbolFactory implementation:
fxl::RefPtr<Symbol> CreateSymbol(uint64_t die_offset) const override {
if (auto found = symbols_.find(die_offset); found != symbols_.end())
return found->second;
// Never return null on failure, error is indicated by a default-constructed Symbol.
return fxl::MakeRefCounted<Symbol>();
}
// Adds a mock symbol to the factory that will be returned when queried for the given offset.
//
// This also updates the symbol's UncachedLazySymbol to point to this factory so round-trip
// queries will work. This creates a reference cycle as mentioned at the top of the file.
void SetMockSymbol(uint64_t die_offset, fxl::RefPtr<Symbol> symbol) {
symbol->set_lazy_this(UncachedLazySymbol(RefPtrTo(this), die_offset));
symbols_[die_offset] = std::move(symbol);
}
// Releases all references to mock symbols.
void ClearSymbols() { symbols_.clear(); }
private:
std::map<uint64_t, fxl::RefPtr<Symbol>> symbols_;
};
fxl::RefPtr<FactoryImpl> factory_ = fxl::MakeRefCounted<FactoryImpl>();
};
} // namespace zxdb
#endif // SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_MOCK_SYMBOL_FACTORY_H_