diff --git a/map/framework.cpp b/map/framework.cpp index 42f82a8551..66b5a473b0 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -6,6 +6,7 @@ #include "map/user_mark.hpp" #include "defines.hpp" +#include "private.h" #include "routing/online_absent_fetcher.hpp" #include "routing/osrm_router.hpp" @@ -158,17 +159,6 @@ void CancelQuery(weak_ptr & handle) queryHandle->Cancel(); handle.reset(); } - -class StubSocket final : public platform::Socket -{ -public: - // Socket overrides - bool Open(string const & host, uint16_t port) override { return false; } - void Close() override {} - bool Read(uint8_t * data, uint32_t count) override { return false; } - bool Write(uint8_t const * data, uint32_t count) override { return false; } - void SetTimeout(uint32_t milliseconds) override {} -}; } // namespace pair Framework::RegisterMap( @@ -248,9 +238,9 @@ bool Framework::IsTrackingReporterEnabled() const if (!m_routingSession.IsOnRoute()) return false; - bool allowStat = false; - UNUSED_VALUE(settings::Get(tracking::Reporter::kEnabledSettingsKey, allowStat)); - return allowStat; + bool enableTracking = false; + UNUSED_VALUE(settings::Get(tracking::Reporter::kEnableTrackingKey, enableTracking)); + return enableTracking; } void Framework::OnUserPositionChanged(m2::PointD const & position) @@ -343,7 +333,8 @@ Framework::Framework() , m_storage(platform::migrate::NeedMigrate() ? COUNTRIES_OBSOLETE_FILE : COUNTRIES_FILE) , m_bmManager(*this) , m_isRenderingEnabled(true) - , m_trackingReporter(make_unique(), tracking::Reporter::kPushDelayMs) + , m_trackingReporter(platform::CreateSocket(), TRACKING_REALTIME_HOST, TRACKING_REALTIME_PORT, + tracking::Reporter::kPushDelayMs) , m_displacementModeManager([this](bool show) { int const mode = show ? dp::displacement::kHotelMode : dp::displacement::kDefaultMode; CallDrapeFunction(bind(&df::DrapeEngine::SetDisplacementMode, _1, mode)); diff --git a/platform/platform_tests_support/test_socket.cpp b/platform/platform_tests_support/test_socket.cpp index 3924da379c..df36d2a1e0 100644 --- a/platform/platform_tests_support/test_socket.cpp +++ b/platform/platform_tests_support/test_socket.cpp @@ -27,8 +27,9 @@ bool TestSocket::Read(uint8_t * data, uint32_t count) if (!m_isConnected) return false; - lock_guard lg(m_inputMutex); + unique_lock lock(m_inputMutex); + m_inputCondition.wait_for(lock, milliseconds(m_timeoutMs), [this]() { return !m_input.empty(); }); if (m_input.size() < count) return false; @@ -51,7 +52,6 @@ bool TestSocket::Write(uint8_t const * data, uint32_t count) } void TestSocket::SetTimeout(uint32_t milliseconds) { m_timeoutMs = milliseconds; } - size_t TestSocket::ReadServer(vector & destination) { unique_lock lock(m_outputMutex); diff --git a/platform/platform_tests_support/test_socket.hpp b/platform/platform_tests_support/test_socket.hpp index 8d19071121..66613791dd 100644 --- a/platform/platform_tests_support/test_socket.hpp +++ b/platform/platform_tests_support/test_socket.hpp @@ -28,6 +28,13 @@ public: // Waits for some data or timeout. // Returns size of read data. size_t ReadServer(vector & destination); + template + void WriteServer(Container const & answer) + { + lock_guard lg(m_inputMutex); + m_input.insert(m_input.begin(), begin(answer), end(answer)); + m_inputCondition.notify_one(); + } private: atomic m_isConnected = {false}; @@ -35,6 +42,7 @@ private: deque m_input; mutex m_inputMutex; + condition_variable m_inputCondition; vector m_output; mutex m_outputMutex; diff --git a/platform/socket.hpp b/platform/socket.hpp index 9e0c2f75d3..ab955523d2 100644 --- a/platform/socket.hpp +++ b/platform/socket.hpp @@ -1,5 +1,6 @@ #pragma once +#include "std/cstdint.hpp" #include "std/string.hpp" #include "std/unique_ptr.hpp" @@ -25,5 +26,16 @@ public: virtual void SetTimeout(uint32_t milliseconds) = 0; }; +class StubSocket final : public Socket +{ +public: + // Socket overrides: + bool Open(string const & host, uint16_t port) override { return false; } + void Close() override {} + bool Read(uint8_t * data, uint32_t count) override { return false; } + bool Write(uint8_t const * data, uint32_t count) override { return false; } + void SetTimeout(uint32_t milliseconds) override {} +}; + unique_ptr CreateSocket(); } // namespace platform diff --git a/tracking/connection.cpp b/tracking/connection.cpp index 550a797afc..26cbfadba3 100644 --- a/tracking/connection.cpp +++ b/tracking/connection.cpp @@ -1,5 +1,8 @@ -#include "connection.hpp" +#include "tracking/connection.hpp" +#include "tracking/protocol.hpp" + +#include "platform/platform.hpp" #include "platform/socket.hpp" namespace @@ -22,19 +25,27 @@ Connection::Connection(unique_ptr socket, string const & host, bool Connection::Reconnect() { m_socket->Close(); - return m_socket->Open(m_host, m_port); + + if (!m_socket->Open(m_host, m_port)) + return false; + + auto packet = Protocol::CreateAuthPacket(GetPlatform().UniqueClientId()); + if (!m_socket->Write(packet.data(), static_cast(packet.size()))) + return false; + + string check(begin(Protocol::kFail), end(Protocol::kFail)); + bool const isSuccess = + m_socket->Read(reinterpret_cast(&check[0]), static_cast(check.size())); + if (!isSuccess || check != string(begin(Protocol::kOk), end(Protocol::kOk))) + return false; + + return true; } // TODO: implement historical bool Connection::Send(boost::circular_buffer const & points) { - ASSERT(m_buffer.empty(), ()); - - MemWriter writer(m_buffer); - using coding::TrafficGPSEncoder; - TrafficGPSEncoder::SerializeDataPoints(TrafficGPSEncoder::kLatestVersion, writer, points); - bool const isSuccess = m_socket->Write(m_buffer.data(), m_buffer.size()); - m_buffer.clear(); - return isSuccess; + auto packet = Protocol::CreateDataPacket(points); + return m_socket->Write(packet.data(), static_cast(packet.size())); } } // namespace tracking diff --git a/tracking/connection.hpp b/tracking/connection.hpp index a87f3dbbf1..48445444bd 100644 --- a/tracking/connection.hpp +++ b/tracking/connection.hpp @@ -31,6 +31,5 @@ private: string const m_host; uint16_t const m_port; bool const m_isHistorical; - vector m_buffer; }; } // namespace tracking diff --git a/tracking/protocol.cpp b/tracking/protocol.cpp new file mode 100644 index 0000000000..ada9a49842 --- /dev/null +++ b/tracking/protocol.cpp @@ -0,0 +1,62 @@ +#include "tracking/protocol.hpp" + +#include "coding/endianness.hpp" + +#include "base/assert.hpp" + +#include "std/cstdint.hpp" + +namespace tracking +{ +uint8_t const Protocol::kOk[4] = {'O', 'K', '\n', '\n'}; +uint8_t const Protocol::kFail[4] = {'F', 'A', 'I', 'L'}; + +static_assert(sizeof(Protocol::kFail) >= sizeof(Protocol::kOk), ""); + +vector Protocol::CreateAuthPacket(string const & clientId) +{ + vector packet; + + InitHeader(packet, PacketType::CurrentAuth, static_cast(clientId.size())); + packet.insert(packet.end(), begin(clientId), end(clientId)); + + return packet; +} + +vector Protocol::CreateDataPacket(DataElements const & points) +{ + vector buffer; + MemWriter writer(buffer); + Encoder::SerializeDataPoints(Encoder::kLatestVersion, writer, points); + + vector packet; + InitHeader(packet, PacketType::CurrentData, static_cast(buffer.size())); + packet.insert(packet.end(), begin(buffer), end(buffer)); + + return packet; +} + +void Protocol::InitHeader(vector & packet, PacketType type, uint32_t payloadSize) +{ + packet.resize(sizeof(uint32_t)); + uint32_t & size = *reinterpret_cast(packet.data()); + size = payloadSize; + + ASSERT_LESS(size, 0x00FFFFFF, ()); + + if (!IsBigEndian()) + size = ReverseByteOrder(size); + + packet[0] = static_cast(type); +} + +string DebugPrint(Protocol::PacketType type) +{ + switch (type) + { + case Protocol::PacketType::AuthV0: return "AuthV0"; + case Protocol::PacketType::DataV0: return "DataV0"; + default: return "Unknown"; + } +} +} // namespace tracking diff --git a/tracking/protocol.hpp b/tracking/protocol.hpp new file mode 100644 index 0000000000..6b15b7bdeb --- /dev/null +++ b/tracking/protocol.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "coding/traffic.hpp" + +#include "std/string.hpp" +#include "std/vector.hpp" + +#include "boost/circular_buffer.hpp" + +namespace tracking +{ +class Protocol +{ +public: + using Encoder = coding::TrafficGPSEncoder; + using DataElements = boost::circular_buffer; + + static uint8_t const kOk[4]; + static uint8_t const kFail[4]; + + enum class PacketType + { + AuthV0 = 0x81, + DataV0 = 0x82, + + CurrentAuth = AuthV0, + CurrentData = DataV0 + }; + + static vector CreateAuthPacket(string const & clientId); + static vector CreateDataPacket(DataElements const & points); + +private: + static void InitHeader(vector & packet, PacketType type, uint32_t payloadSize); +}; + +string DebugPrint(Protocol::PacketType type); +} // namespace tracking diff --git a/tracking/reporter.cpp b/tracking/reporter.cpp index b161b4e3d6..35b59c65ae 100644 --- a/tracking/reporter.cpp +++ b/tracking/reporter.cpp @@ -8,8 +8,6 @@ #include "std/target_os.hpp" -#include "private.h" - namespace { double constexpr kRequiredHorizontalAccuracy = 10.0; @@ -25,21 +23,22 @@ namespace tracking // Keys saved for existing users, so can' fix it easy, need migration. // Use this hack until change to special traffic key. #if defined(OMIM_OS_IPHONE) -const char Reporter::kEnabledSettingsKey[] = "StatisticsEnabled"; +const char Reporter::kEnableTrackingKey[] = "StatisticsEnabled"; #elif defined(OMIM_OS_ANDROID) -const char Reporter::kEnabledSettingsKey[] = "AllowStat"; +const char Reporter::kEnableTrackingKey[] = "AllowStat"; #else -const char Reporter::kEnabledSettingsKey[] = "AllowStat"; +const char Reporter::kEnableTrackingKey[] = "AllowStat"; #endif // static milliseconds const Reporter::kPushDelayMs = milliseconds(10000); -Reporter::Reporter(unique_ptr socket, milliseconds pushDelay) - : m_realtimeSender(move(socket), TRACKING_REALTIME_HOST, TRACKING_REALTIME_PORT, false) +Reporter::Reporter(unique_ptr socket, string const & host, uint16_t port, + milliseconds pushDelay) + : m_realtimeSender(move(socket), host, port, false) , m_pushDelay(pushDelay) , m_points(kRealTimeBufferSize) - , m_thread([this]{Run();}) + , m_thread([this] { Run(); }) { } @@ -82,8 +81,15 @@ void Reporter::Run() m_input.clear(); lock.unlock(); - if (SendPoints()) - m_points.clear(); + if (m_points.empty() && m_idleFn) + { + m_idleFn(); + } + else + { + if (SendPoints()) + m_points.clear(); + } lock.lock(); auto const passedMs = duration_cast(steady_clock::now() - startTime); diff --git a/tracking/reporter.hpp b/tracking/reporter.hpp index 2c85b69969..380a3cd460 100644 --- a/tracking/reporter.hpp +++ b/tracking/reporter.hpp @@ -7,6 +7,7 @@ #include "std/chrono.hpp" #include "std/condition_variable.hpp" #include "std/mutex.hpp" +#include "std/string.hpp" #include "std/unique_ptr.hpp" #include "std/vector.hpp" @@ -28,13 +29,16 @@ class Reporter final { public: static milliseconds const kPushDelayMs; - static const char kEnabledSettingsKey[]; + static const char kEnableTrackingKey[]; - Reporter(unique_ptr socket, milliseconds pushDelay); + Reporter(unique_ptr socket, string const & host, uint16_t port, + milliseconds pushDelay); ~Reporter(); void AddLocation(location::GpsInfo const & info); + inline void SetIdleFunc(function fn) { m_idleFn = fn; } + private: void Run(); bool SendPoints(); @@ -43,6 +47,9 @@ private: milliseconds m_pushDelay; bool m_wasConnected = false; double m_lastConnectionAttempt = 0.0; + // Function to be called every |kPushDelayMs| in + // case no points were sent. + function m_idleFn; // Input buffer for incoming points. Worker thread steals it contents. vector m_input; // Last collected points, sends periodically to server. diff --git a/tracking/tracking.pro b/tracking/tracking.pro index 2418e67637..42e7d13953 100644 --- a/tracking/tracking.pro +++ b/tracking/tracking.pro @@ -8,8 +8,10 @@ include($$ROOT_DIR/common.pri) SOURCES += \ connection.cpp \ + protocol.cpp \ reporter.cpp \ HEADERS += \ connection.hpp \ + protocol.hpp \ reporter.hpp \ diff --git a/tracking/tracking_tests/protocol_test.cpp b/tracking/tracking_tests/protocol_test.cpp new file mode 100644 index 0000000000..f3b72d6160 --- /dev/null +++ b/tracking/tracking_tests/protocol_test.cpp @@ -0,0 +1,34 @@ +#include "testing/testing.hpp" + +#include "tracking/protocol.hpp" + +using namespace tracking; + +UNIT_TEST(Protocol_CreateAuthPacket) +{ + auto packet = Protocol::CreateAuthPacket("AAA"); + TEST_EQUAL(packet.size(), 7, ()); + TEST_EQUAL(Protocol::PacketType(packet[0]), Protocol::PacketType::CurrentAuth, ()); + TEST_EQUAL(packet[1], 0x00, ()); + TEST_EQUAL(packet[2], 0x00, ()); + TEST_EQUAL(packet[3], 0x03, ()); + TEST_EQUAL(packet[4], 'A', ()); + TEST_EQUAL(packet[5], 'A', ()); + TEST_EQUAL(packet[6], 'A', ()); +} + +UNIT_TEST(Protocol_CreateDataPacket) +{ + Protocol::DataElements buffer(5); + buffer.push_back(Protocol::DataElements::value_type(1, ms::LatLon(10, 10))); + buffer.push_back(Protocol::DataElements::value_type(2, ms::LatLon(15, 15))); + auto packet = Protocol::CreateDataPacket(buffer); + TEST_EQUAL(packet.size(), 26, ()); + TEST_EQUAL(Protocol::PacketType(packet[0]), Protocol::PacketType::CurrentData, ()); + TEST_EQUAL(packet[1], 0x00, ()); + TEST_EQUAL(packet[2], 0x00, ()); + TEST_EQUAL(packet[3], 22, ()); + TEST_EQUAL(packet[4], 1, ()); + TEST_EQUAL(packet[5], 227, ()); + TEST_EQUAL(packet[6], 241, ()); +} diff --git a/tracking/tracking_tests/reporter_test.cpp b/tracking/tracking_tests/reporter_test.cpp index 685b4f19f7..bdd47a60a5 100644 --- a/tracking/tracking_tests/reporter_test.cpp +++ b/tracking/tracking_tests/reporter_test.cpp @@ -1,4 +1,7 @@ +#include "testing/testing.hpp" + #include "tracking/reporter.hpp" +#include "tracking/protocol.hpp" #include "coding/traffic.hpp" @@ -6,8 +9,6 @@ #include "platform/platform_tests_support/test_socket.hpp" #include "platform/socket.hpp" -#include "testing/testing.hpp" - #include "base/math.hpp" #include "base/thread.hpp" @@ -28,13 +29,36 @@ void TransferLocation(Reporter & reporter, TestSocket & testSocket, double times gpsInfo.m_horizontalAccuracy = 1.0; reporter.AddLocation(gpsInfo); + using Packet = tracking::Protocol::PacketType; vector buffer; - size_t const readSize = testSocket.ReadServer(buffer); - TEST_GREATER(readSize, 0, ()); + size_t readSize = 0; + size_t attempts = 3; + do + { + readSize = testSocket.ReadServer(buffer); + if (attempts-- && readSize == 0) + continue; + switch (Packet(buffer[0])) + { + case Packet::CurrentAuth: + { + buffer.clear(); + testSocket.WriteServer(tracking::Protocol::kOk); + break; + } + case Packet::CurrentData: + { + readSize = 0; + break; + } + } + } while (readSize); + TEST(!buffer.empty(), ()); vector points; MemReader memReader(buffer.data(), buffer.size()); ReaderSource src(memReader); + src.Skip(sizeof(uint32_t /* header */)); coding::TrafficGPSEncoder::DeserializeDataPoints(coding::TrafficGPSEncoder::kLatestVersion, src, points); @@ -51,7 +75,7 @@ UNIT_TEST(Reporter_TransferLocations) auto socket = make_unique(); TestSocket & testSocket = *socket.get(); - Reporter reporter(move(socket), milliseconds(10) /* pushDelay */); + Reporter reporter(move(socket), "localhost", 0, milliseconds(10) /* pushDelay */); TransferLocation(reporter, testSocket, 1.0, 2.0, 3.0); TransferLocation(reporter, testSocket, 4.0, 5.0, 6.0); TransferLocation(reporter, testSocket, 7.0, 8.0, 9.0); diff --git a/tracking/tracking_tests/tracking_tests.pro b/tracking/tracking_tests/tracking_tests.pro index 81465b60aa..6009b5ffda 100644 --- a/tracking/tracking_tests/tracking_tests.pro +++ b/tracking/tracking_tests/tracking_tests.pro @@ -26,4 +26,5 @@ win*|linux* { SOURCES += \ $$ROOT_DIR/testing/testingmain.cpp \ - reporter_test.cpp + protocol_test.cpp \ + reporter_test.cpp \ diff --git a/xcode/tracking/tracking.xcodeproj/project.pbxproj b/xcode/tracking/tracking.xcodeproj/project.pbxproj index 669aa4f959..9a1c80a119 100644 --- a/xcode/tracking/tracking.xcodeproj/project.pbxproj +++ b/xcode/tracking/tracking.xcodeproj/project.pbxproj @@ -19,7 +19,10 @@ 675E88981DB7B08500F8EBDA /* libplatform_tests_support.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 675E88961DB7B08500F8EBDA /* libplatform_tests_support.a */; }; 675E88991DB7B08500F8EBDA /* libtomcrypt.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 675E88971DB7B08500F8EBDA /* libtomcrypt.a */; }; 675E88A21DB7B10300F8EBDA /* libtracking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 675E88501DB7AC0300F8EBDA /* libtracking.a */; }; - 67B6E7B81DB8BBA900745F8A /* testingmain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 67B6E7B71DB8BBA900745F8A /* testingmain.cpp */; }; + 6772590D1DB90F8F00BF54EE /* testingmain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 67B6E7B71DB8BBA900745F8A /* testingmain.cpp */; }; + 6772592D1DBA26FD00BF54EE /* protocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6772592B1DBA26FD00BF54EE /* protocol.cpp */; }; + 6772592E1DBA26FD00BF54EE /* protocol.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 6772592C1DBA26FD00BF54EE /* protocol.hpp */; }; + 67EC0CB71DBE4A320021F484 /* protocol_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 67EC0CB61DBE4A320021F484 /* protocol_test.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -37,7 +40,10 @@ 675E88911DB7B03400F8EBDA /* libplatform.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libplatform.a; path = "/Users/darkserj/mapsme/omim/xcode/platform/../../../omim-xcode-build/Debug/libplatform.a"; sourceTree = ""; }; 675E88961DB7B08500F8EBDA /* libplatform_tests_support.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libplatform_tests_support.a; path = "/Users/darkserj/mapsme/omim/xcode/platform/../../../omim-xcode-build/Debug/libplatform_tests_support.a"; sourceTree = ""; }; 675E88971DB7B08500F8EBDA /* libtomcrypt.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtomcrypt.a; path = "/Users/darkserj/mapsme/omim/xcode/tomcrypt/../../../omim-xcode-build/Debug/libtomcrypt.a"; sourceTree = ""; }; + 6772592B1DBA26FD00BF54EE /* protocol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = protocol.cpp; sourceTree = ""; }; + 6772592C1DBA26FD00BF54EE /* protocol.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = protocol.hpp; sourceTree = ""; }; 67B6E7B71DB8BBA900745F8A /* testingmain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = testingmain.cpp; path = ../../testing/testingmain.cpp; sourceTree = ""; }; + 67EC0CB61DBE4A320021F484 /* protocol_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = protocol_test.cpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -92,6 +98,8 @@ 675E88611DB7AC9000F8EBDA /* connection.hpp */, 675E88621DB7AC9000F8EBDA /* reporter.cpp */, 675E88631DB7AC9000F8EBDA /* reporter.hpp */, + 6772592B1DBA26FD00BF54EE /* protocol.cpp */, + 6772592C1DBA26FD00BF54EE /* protocol.hpp */, ); name = tracking; path = ../../tracking; @@ -102,6 +110,7 @@ children = ( 67B6E7B71DB8BBA900745F8A /* testingmain.cpp */, 675E88841DB7AD1000F8EBDA /* reporter_test.cpp */, + 67EC0CB61DBE4A320021F484 /* protocol_test.cpp */, ); name = tracking_tests; path = ../../tracking/tracking_tests; @@ -127,6 +136,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 6772592E1DBA26FD00BF54EE /* protocol.hpp in Headers */, 675E88651DB7AC9000F8EBDA /* connection.hpp in Headers */, 675E88671DB7AC9000F8EBDA /* reporter.hpp in Headers */, ); @@ -223,8 +233,8 @@ buildActionMask = 2147483647; files = ( 675E88661DB7AC9000F8EBDA /* reporter.cpp in Sources */, - 67B6E7B81DB8BBA900745F8A /* testingmain.cpp in Sources */, 675E88641DB7AC9000F8EBDA /* connection.cpp in Sources */, + 6772592D1DBA26FD00BF54EE /* protocol.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -232,7 +242,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 67EC0CB71DBE4A320021F484 /* protocol_test.cpp in Sources */, 675E88891DB7AD3100F8EBDA /* reporter_test.cpp in Sources */, + 6772590D1DB90F8F00BF54EE /* testingmain.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -352,6 +364,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; GCC_INLINES_ARE_PRIVATE_EXTERN = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "OMIM_UNIT_TEST_WITH_QT_EVENT_LOOP=1", + ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; INFOPLIST_FILE = "$(SRCROOT)/../../iphone/Maps/MAPSME.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -369,6 +385,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; GCC_INLINES_ARE_PRIVATE_EXTERN = NO; + GCC_PREPROCESSOR_DEFINITIONS = "OMIM_UNIT_TEST_WITH_QT_EVENT_LOOP=1"; GCC_SYMBOLS_PRIVATE_EXTERN = NO; INFOPLIST_FILE = "$(SRCROOT)/../../iphone/Maps/MAPSME.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0;