Я пытаюсь протестировать класс, содержащий член сторонней библиотеки.
Я создал поддельную библиотеку для mimi c вышеупомянутого и использую директивы препроцессора для выбора между "реальным" и поддельные библиотеки во время компиляции - реальные для модуля производственной компиляции и поддельные для теста.
Проблема в том, что я вижу некоторые расхождения между тем, что выходит из препроцессора, и тем, что создает компоновщик.
Вот чрезвычайно урезанная версия установки, которую я имею:
Сторонняя библиотека - lib.hpp
Это библиотека только для заголовков, поэтому все функции встроены.
namespace lib {
class Foo {
public:
int returnSomething() const { return 42; }
};
}
Поддельная библиотека
В действительности она довольно короткая, поэтому я разбил ее на заголовочные и исходные файлы:
Header - fake_lib.hpp
namespace fake {
class FooBar {
public:
int returnSomething() const;
};
}
Источник - fake_lib. cpp
#include "fake_lib.hpp"
namespace fake {
int FooBar::returnSomething() const {
return 13;
}
}
Тестируемый класс - bar.hpp и bar. cpp
#ifdef SWITCH
#include "fake_lib.hpp"
#endif
// There is no #else here for the preprocessor because in my actual use case we
// need some times from the third_party libs whether we test or are in production
#include "lib.hpp"
class Bar {
public:
int get();
private:
#ifndef SWITCH
#warning "real"
lib::Foo m_foo;
#else
#warning "fake"
fake::FooBar m_foo;
#endif
};
#include "bar.hpp"
int Bar::get() {
return m_foo.returnSomething();
}
Exe
#include "bar.hpp"
#include <iostream>
int main() {
Bar bar;
std::cout << bar.get() << std::endl;
return 0;
}
Испытательный exe
#include "bar.hpp"
#include <iostream>
int main() {
Bar bar;
std::cout << bar.get() << std::endl;
return 0;
}
Это все построено через CMake, вот мой CMakeLists.txt:
cmake_minimum_required(VERSION 3.12)
project(fake_failure LANGUAGES CXX)
add_library(lib INTERFACE)
target_include_directories(lib INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/lib)
add_library(fake OBJECT fake/fake_lib.cpp)
target_include_directories(fake PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/fake)
add_library(bar OBJECT bar.cpp)
target_include_directories(bar PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(bar PUBLIC lib)
add_executable(main_exe main.cpp)
target_link_libraries(main_exe PRIVATE bar)
add_executable(fake_exe fake.cpp)
target_compile_definitions(fake_exe PRIVATE SWITCH)
target_link_libraries(fake_exe PRIVATE bar fake)
Желаемый результат
Когда main_exe
запущен, он должен вывести 42. Когда fake_exe
запущен, он должен напечатать 13.
Фактический результат
fake_exe
также распечатывает 42.
Теперь, просто чтобы убрать это с дороги - я могу это исправить и получить желаемое на данный момент, определив библиотеку stati c fake_bar
, которая добавляет макрос SWITCH
.
Что я хотел бы узнать
Когда я запускаю препроцессор вручную, я вижу этот член Bar
m_foo
, если он поддельного типа. Я предполагаю, что поскольку библиотека bar
компилируется без макроса SWITCH
, она использует встроенные определения, что означает, что созданный объектный файл имеет встроенные функции в виде символов. Почему компоновщик не выдает ошибку, если он не видит символы для фальшивого типа?
И почему при запуске gdb происходит взлом Bar
и выполнение print typeid(m_foo)
Я вижу это реального типа, даже если вывод препроцессора, о котором я упоминал выше, говорил иначе.
Вышеприведенное объяснило бы, почему компоновщик не выдает ошибок - он даже не пытается использовать поддельные символы. Но я не могу понять, почему.
Заранее спасибо!