#include "testing/testing.hpp" #include "generator/generator_tests_support/test_feature.hpp" #include "editor/editor_storage.hpp" #include "editor/editor_tests/osm_editor_test.hpp" #include "editor/editor_tests_support/helpers.hpp" #include "editor/osm_editor.hpp" #include "search/editor_delegate.hpp" #include "indexer/classificator.hpp" #include "indexer/classificator_loader.hpp" #include "indexer/feature_source.hpp" #include "indexer/ftypes_matcher.hpp" #include "indexer/scales.hpp" #include "platform/platform_tests_support/async_gui_thread.hpp" #include "platform/platform_tests_support/scoped_file.hpp" #include "base/logging.hpp" #include "base/scope_guard.hpp" #include namespace editor { namespace testing { using namespace generator::tests_support; using namespace editor::tests_support; using platform::tests_support::ScopedFile; namespace { class IsCafeChecker : public ftypes::BaseChecker { public: static IsCafeChecker const & Instance() { static const IsCafeChecker instance; return instance; } private: IsCafeChecker() { Classificator const & c = classif(); m_types.push_back(c.GetTypeByPath({"amenity", "cafe"})); } }; class TestCafe : public TestPOI { public: TestCafe(m2::PointD const & center, std::string const & name, std::string const & lang) : TestPOI(center, name, lang) { SetTypes({{"amenity", "cafe"}}); } }; class OptionalSaveStorage : public editor::InMemoryStorage { public: void AllowSave(bool allow) { m_allowSave = allow; } // StorageBase overrides: bool Save(pugi::xml_document const & doc) override { if (!m_allowSave) return false; return InMemoryStorage::Save(doc); } bool Reset() override { if (!m_allowSave) return false; return InMemoryStorage::Reset(); } private: bool m_allowSave = true; }; class ScopedOptionalSaveStorage { public: ScopedOptionalSaveStorage() { auto & editor = osm::Editor::Instance(); editor.SetStorageForTesting(std::unique_ptr(m_storage)); } ~ScopedOptionalSaveStorage() { auto & editor = osm::Editor::Instance(); editor.SetStorageForTesting(std::make_unique()); } void AllowSave(bool allow) { m_storage->AllowSave(allow); } private: OptionalSaveStorage * m_storage = new OptionalSaveStorage; }; template void ForEachCafeAtPoint(DataSource & dataSource, m2::PointD const & mercator, Fn && fn) { m2::RectD const rect = mercator::RectByCenterXYAndSizeInMeters(mercator, 0.2 /* rect width */); auto const f = [&fn](FeatureType & ft) { if (IsCafeChecker::Instance()(ft)) { fn(ft); } }; dataSource.ForEachInRect(f, rect, scales::GetUpperScale()); } void FillEditableMapObject(osm::Editor const & editor, FeatureType & ft, osm::EditableMapObject & emo) { emo.SetFromFeatureType(ft); emo.SetHouseNumber(ft.GetHouseNumber()); emo.SetEditableProperties(editor.GetEditableProperties(ft)); } void SetBuildingLevels(osm::EditableMapObject & emo, std::string s) { emo.SetMetadata(feature::Metadata::FMD_BUILDING_LEVELS, std::move(s)); } void SetBuildingLevelsToOne(FeatureType & ft) { EditFeature(ft, [](osm::EditableMapObject & emo) { SetBuildingLevels(emo, "1"); }); } void CreateCafeAtPoint(m2::PointD const & point, MwmSet::MwmId const & mwmId, osm::EditableMapObject &emo) { auto & editor = osm::Editor::Instance(); editor.CreatePoint(classif().GetTypeByPath({"amenity", "cafe"}), point, mwmId, emo); emo.SetHouseNumber("12"); TEST_EQUAL(editor.SaveEditedFeature(emo), osm::Editor::SaveResult::SavedSuccessfully, ()); } void GenerateUploadedFeature(MwmSet::MwmId const & mwmId, osm::EditableMapObject const & emo, pugi::xml_document & out) { pugi::xml_node root = out.append_child("omaps"); root.append_attribute("format_version") = 1; pugi::xml_node mwmNode = root.append_child("mwm"); mwmNode.append_attribute("name") = mwmId.GetInfo()->GetCountryName().c_str(); mwmNode.append_attribute("version") = static_cast(mwmId.GetInfo()->GetVersion()); pugi::xml_node created = mwmNode.append_child("create"); editor::XMLFeature xf = editor::ToXML(emo, true); xf.SetMWMFeatureIndex(emo.GetID().m_index); xf.SetModificationTime(time(nullptr)); xf.SetUploadTime(time(nullptr)); xf.SetUploadStatus("Uploaded"); xf.AttachToParentNode(created); } uint32_t CountFeaturesInRect(MwmSet::MwmId const & mwmId, m2::RectD const & rect) { auto & editor = osm::Editor::Instance(); int unused = 0; uint32_t counter = 0; editor.ForEachCreatedFeature(mwmId, [&counter](uint32_t index) { ++counter; }, rect, unused); return counter; } uint32_t CountFeatureTypeInRectByDataSource(DataSource const & dataSource, m2::RectD const & rect) { auto const scale = scales::GetUpperScale(); uint32_t counter = 0; dataSource.ForEachInRect([&counter](FeatureType const &) { ++counter; }, rect, scale); return counter; } } // namespace EditorTest::EditorTest() { try { classificator::Load(); } catch (RootException const & e) { LOG(LERROR, ("Classificator read error: ", e.what())); } editor::tests_support::SetUpEditorForTesting(std::make_unique(m_dataSource)); } EditorTest::~EditorTest() { editor::tests_support::TearDownEditorForTesting(); m_dataSource.ClearCache(); for (auto const & file : m_mwmFiles) Cleanup(file); } void EditorTest::GetFeatureTypeInfoTest() { auto & editor = osm::Editor::Instance(); { MwmSet::MwmId mwmId; TEST(!editor.GetFeatureTypeInfo((*editor.m_features.Get()), mwmId, 0), ()); } auto const mwmId = ConstructTestMwm([](TestMwmBuilder & builder) { TestCafe cafe(m2::PointD(1.0, 1.0), "London Cafe", "en"); builder.Add(cafe); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor](FeatureType & ft) { auto const featuresBefore = editor.m_features.Get(); TEST(!editor.GetFeatureTypeInfo(*featuresBefore, ft.GetID().m_mwmId, ft.GetID().m_index), ()); SetBuildingLevelsToOne(ft); auto const featuresAfter = editor.m_features.Get(); auto const fti = editor.GetFeatureTypeInfo(*featuresAfter, ft.GetID().m_mwmId, ft.GetID().m_index); TEST_NOT_EQUAL(fti, nullptr, ()); TEST_EQUAL(fti->m_object.GetID(), ft.GetID(), ()); }); } void EditorTest::GetEditedFeatureTest() { auto & editor = osm::Editor::Instance(); { FeatureID feature; TEST(!editor.GetEditedFeature(feature), ()); } auto const mwmId = ConstructTestMwm([](TestMwmBuilder & builder) { TestCafe cafe(m2::PointD(1.0, 1.0), "London Cafe", "en"); builder.Add(cafe); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor](FeatureType & ft) { TEST(!editor.GetEditedFeature(ft.GetID()), ()); SetBuildingLevelsToOne(ft); auto savedEmo = editor.GetEditedFeature(ft.GetID()); TEST(savedEmo, ()); TEST_EQUAL(savedEmo->GetMetadata(feature::Metadata::FMD_BUILDING_LEVELS), "1", ()); TEST_EQUAL(ft.GetID(), savedEmo->GetID(), ()); }); } void EditorTest::SetIndexTest() { // osm::Editor::SetIndex was called in constructor. auto & editor = osm::Editor::Instance(); auto const gbMwmId = BuildMwm("GB", [](TestMwmBuilder & builder) { TestCafe cafe({1.0, 1.0}, "London Cafe", "en"); TestStreet street({{0.0, 0.0}, {1.0, 1.0}, {2.0, 2.0}}, "Test street", "en"); cafe.SetStreetName(street.GetName("en")); builder.Add(street); builder.Add(cafe); builder.Add(TestCafe({3.0, 3.0}, "London Cafe", "en")); builder.Add(TestCafe({4.0, 4.0}, "London Cafe", "en")); builder.Add(TestCafe({4.0, 4.0}, "London Cafe", "en")); builder.Add(TestCafe({4.0, 4.0}, "London Cafe", "en")); }); auto const mwmId = editor.GetMwmIdByMapName("GB"); TEST_EQUAL(gbMwmId, mwmId, ()); osm::EditableMapObject emo; CreateCafeAtPoint({2.0, 2.0}, gbMwmId, emo); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor](FeatureType & ft) { auto const firstPtr = editor.GetOriginalMapObject(ft.GetID()); TEST(firstPtr, ()); SetBuildingLevelsToOne(ft); auto const secondPtr = editor.GetOriginalMapObject(ft.GetID()); TEST(secondPtr, ()); TEST_EQUAL(firstPtr->GetID(), secondPtr->GetID(), ()); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor](FeatureType & ft) { TEST_EQUAL(editor.GetOriginalFeatureStreet(ft.GetID()), "Test street", ()); EditFeature(ft, [](osm::EditableMapObject & emo) { osm::LocalizedStreet ls{"Some street", ""}; emo.SetStreet(ls); }); TEST_EQUAL(editor.GetOriginalFeatureStreet(ft.GetID()), "Test street", ()); }); uint32_t counter = 0; editor.ForEachFeatureAtPoint([&counter](FeatureType & ft) { ++counter; }, {100.0, 100.0}); TEST_EQUAL(counter, 0, ()); counter = 0; editor.ForEachFeatureAtPoint([&counter](FeatureType & ft) { ++counter; }, {3.0, 3.0}); TEST_EQUAL(counter, 1, ()); counter = 0; editor.ForEachFeatureAtPoint([&counter](FeatureType & ft) { ++counter; }, {1.0, 1.0}); TEST_EQUAL(counter, 2, ()); counter = 0; editor.ForEachFeatureAtPoint([&counter](FeatureType & ft) { ++counter; }, {4.0, 4.0}); TEST_EQUAL(counter, 3, ()); } void EditorTest::GetEditedFeatureStreetTest() { auto & editor = osm::Editor::Instance(); { FeatureID feature; std::string street; TEST(!editor.GetEditedFeatureStreet(feature, street), ()); } auto const mwmId = ConstructTestMwm([](TestMwmBuilder & builder) { TestCafe cafe(m2::PointD(1.0, 1.0), "London Cafe", "en"); builder.Add(cafe); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor](FeatureType & ft) { std::string street; TEST(!editor.GetEditedFeatureStreet(ft.GetID(), street), ()); osm::LocalizedStreet ls{"some street", ""}; EditFeature(ft, [&ls](osm::EditableMapObject & emo) { emo.SetStreet(ls); }); TEST(editor.GetEditedFeatureStreet(ft.GetID(), street), ()); TEST_EQUAL(street, ls.m_defaultName, ()); }); } void EditorTest::GetFeatureStatusTest() { auto & editor = osm::Editor::Instance(); auto const mwmId = ConstructTestMwm([](TestMwmBuilder & builder) { TestCafe cafe(m2::PointD(1.0, 1.0), "London Cafe", "en"); TestCafe unnamedCafe(m2::PointD(2.0, 2.0), "", "en"); builder.Add(cafe); builder.Add(unnamedCafe); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor](FeatureType & ft) { TEST_EQUAL(editor.GetFeatureStatus(ft.GetID()), FeatureStatus::Untouched, ()); osm::EditableMapObject emo; FillEditableMapObject(editor, ft, emo); SetBuildingLevels(emo, "1"); TEST_EQUAL(editor.SaveEditedFeature(emo), osm::Editor::SaveResult::SavedSuccessfully, ()); TEST_EQUAL(editor.GetFeatureStatus(ft.GetID()), FeatureStatus::Modified, ()); editor.MarkFeatureAsObsolete(emo.GetID()); TEST_EQUAL(editor.GetFeatureStatus(emo.GetID()), FeatureStatus::Obsolete, ()); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(2.0, 2.0), [&editor](FeatureType & ft) { TEST_EQUAL(editor.GetFeatureStatus(ft.GetID()), FeatureStatus::Untouched, ()); editor.DeleteFeature(ft.GetID()); TEST_EQUAL(editor.GetFeatureStatus(ft.GetID()), FeatureStatus::Deleted, ()); }); osm::EditableMapObject emo; CreateCafeAtPoint({1.5, 1.5}, mwmId, emo); TEST_EQUAL(editor.GetFeatureStatus(emo.GetID()), FeatureStatus::Created, ()); } void EditorTest::IsFeatureUploadedTest() { auto & editor = osm::Editor::Instance(); auto const mwmId = ConstructTestMwm([](TestMwmBuilder & builder) { TestCafe cafe(m2::PointD(1.0, 1.0), "London Cafe", "en"); builder.Add(cafe); builder.Add(TestPOI(m2::PointD(10, 10), "Corner Post", "default")); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor](FeatureType & ft) { TEST(!editor.IsFeatureUploaded(ft.GetID().m_mwmId, ft.GetID().m_index), ()); }); osm::EditableMapObject emo; CreateCafeAtPoint({3.0, 3.0}, mwmId, emo); TEST(!editor.IsFeatureUploaded(emo.GetID().m_mwmId, emo.GetID().m_index), ()); pugi::xml_document doc; GenerateUploadedFeature(mwmId, emo, doc); editor.m_storage->Save(doc); editor.LoadEdits(); TEST(editor.IsFeatureUploaded(emo.GetID().m_mwmId, emo.GetID().m_index), ()); } void EditorTest::DeleteFeatureTest() { auto & editor = osm::Editor::Instance(); auto const mwmId = ConstructTestMwm([](TestMwmBuilder & builder) { TestCafe cafe(m2::PointD(1.0, 1.0), "London Cafe", "en"); builder.Add(cafe); builder.Add(TestPOI(m2::PointD(10, 10), "Corner Post", "default")); }); osm::EditableMapObject emo; CreateCafeAtPoint({3.0, 3.0}, mwmId, emo); auto ft = editor.GetEditedFeature(emo.GetID()); editor.DeleteFeature(ft->GetID()); TEST_EQUAL(editor.GetFeatureStatus(ft->GetID()), FeatureStatus::Untouched, ()); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor](FeatureType & ft) { editor.DeleteFeature(ft.GetID()); TEST_EQUAL(editor.GetFeatureStatus(ft.GetID()), FeatureStatus::Deleted, ()); }); } void EditorTest::ClearAllLocalEditsTest() { auto & editor = osm::Editor::Instance(); auto const mwmId = ConstructTestMwm([](TestMwmBuilder & builder) { TestCafe cafe(m2::PointD(1.0, 1.0), "London Cafe", "en"); builder.Add(cafe); builder.Add(TestPOI(m2::PointD(10, 10), "Corner Post", "default")); }); osm::EditableMapObject emo; CreateCafeAtPoint({3.0, 3.0}, mwmId, emo); TEST(!editor.m_features.Get()->empty(), ()); editor.ClearAllLocalEdits(); TEST(editor.m_features.Get()->empty(), ()); } void EditorTest::GetFeaturesByStatusTest() { auto & editor = osm::Editor::Instance(); { MwmSet::MwmId mwmId; auto const features = editor.GetFeaturesByStatus(mwmId, FeatureStatus::Untouched); TEST(features.empty(), ()); } auto const mwmId = ConstructTestMwm([](TestMwmBuilder & builder) { TestCafe cafe(m2::PointD(1.0, 1.0), "London Cafe", "en"); TestCafe unnamedCafe(m2::PointD(2.0, 2.0), "", "en"); TestCafe someCafe(m2::PointD(3.0, 3.0), "Some cafe", "en"); builder.Add(cafe); builder.Add(unnamedCafe); builder.Add(someCafe); builder.Add(TestPOI(m2::PointD(10, 10), "Corner Post", "default")); }); FeatureID modifiedId, deletedId, obsoleteId, createdId; ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor, &modifiedId](FeatureType & ft) { osm::EditableMapObject emo; FillEditableMapObject(editor, ft, emo); SetBuildingLevels(emo, "1"); TEST_EQUAL(editor.SaveEditedFeature(emo), osm::Editor::SaveResult::SavedSuccessfully, ()); modifiedId = emo.GetID(); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(2.0, 2.0), [&editor, &deletedId](FeatureType & ft) { editor.DeleteFeature(ft.GetID()); deletedId = ft.GetID(); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(3.0, 3.0), [&editor, &obsoleteId](FeatureType & ft) { editor.MarkFeatureAsObsolete(ft.GetID()); obsoleteId = ft.GetID(); }); osm::EditableMapObject emo; CreateCafeAtPoint({4.0, 4.0}, mwmId, emo); createdId = emo.GetID(); auto const modified = editor.GetFeaturesByStatus(mwmId, FeatureStatus::Modified); auto const deleted = editor.GetFeaturesByStatus(mwmId, FeatureStatus::Deleted); auto const obsolete = editor.GetFeaturesByStatus(mwmId, FeatureStatus::Obsolete); auto const created = editor.GetFeaturesByStatus(mwmId, FeatureStatus::Created); TEST_EQUAL(modified.size(), 1, ()); TEST_EQUAL(deleted.size(), 1, ()); TEST_EQUAL(obsolete.size(), 1, ()); TEST_EQUAL(created.size(), 1, ()); TEST_EQUAL(modified.front(), modifiedId.m_index, ()); TEST_EQUAL(deleted.front(), deletedId.m_index, ()); TEST_EQUAL(obsolete.front(), obsoleteId.m_index, ()); TEST_EQUAL(created.front(), createdId.m_index, ()); } void EditorTest::OnMapDeregisteredTest() { auto & editor = osm::Editor::Instance(); m_dataSource.AddObserver(editor); SCOPE_GUARD(removeObs, [&] { m_dataSource.RemoveObserver(editor); }); auto gbMwmId = BuildMwm("GB", [](TestMwmBuilder & builder) { TestCafe cafeLondon(m2::PointD(1.0, 1.0), "London Cafe", "en"); builder.Add(cafeLondon); }); auto const rfMwmId = BuildMwm("RF", [](TestMwmBuilder & builder) { TestCafe cafeMoscow(m2::PointD(2.0, 2.0), "Moscow Cafe", "en"); builder.Add(cafeMoscow); }); auto nzMwmId = BuildMwm("NZ", [](TestMwmBuilder & builder) { }); m_dataSource.DeregisterMap(nzMwmId.GetInfo()->GetLocalFile().GetCountryFile()); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [](FeatureType & ft) { SetBuildingLevelsToOne(ft); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(2.0, 2.0), [](FeatureType & ft) { SetBuildingLevelsToOne(ft); }); TEST_EQUAL(editor.m_features.Get()->size(), 2, (editor.m_features.Get()->size())); { platform::tests_support::AsyncGuiThread guiThread; m_dataSource.DeregisterMap(gbMwmId.GetInfo()->GetLocalFile().GetCountryFile()); } // The map is deregistered but the edits are not deleted until // LoadEdits() is called again, either on the next startup or // on registering a new map. TEST_EQUAL(editor.m_features.Get()->size(), 2, ()); { platform::tests_support::AsyncGuiThread guiThread; auto result = m_dataSource.RegisterMap(gbMwmId.GetInfo()->GetLocalFile()); TEST_EQUAL(result.second, MwmSet::RegResult::Success, ()); gbMwmId = result.first; TEST(gbMwmId.IsAlive(), ()); } // The same map was registered: the edits are still here. TEST_EQUAL(editor.m_features.Get()->size(), 2, ()); { platform::tests_support::AsyncGuiThread guiThread; m_dataSource.DeregisterMap(gbMwmId.GetInfo()->GetLocalFile().GetCountryFile()); } TEST_EQUAL(editor.m_features.Get()->size(), 2, ()); { platform::tests_support::AsyncGuiThread guiThread; auto result = m_dataSource.RegisterMap(nzMwmId.GetInfo()->GetLocalFile()); TEST_EQUAL(result.second, MwmSet::RegResult::Success, ()); nzMwmId = result.first; TEST(nzMwmId.IsAlive(), ()); } // Another map was registered: all edits are reloaded and // the edits for the deleted map are removed. TEST_EQUAL(editor.m_features.Get()->size(), 1, ()); auto const editedMwmId = editor.m_features.Get()->find(rfMwmId); bool const result = (editedMwmId != editor.m_features.Get()->end()); TEST(result, ()); } void EditorTest::RollBackChangesTest() { auto & editor = osm::Editor::Instance(); auto const mwmId = ConstructTestMwm([](TestMwmBuilder & builder) { TestCafe cafe(m2::PointD(1.0, 1.0), "London Cafe", "en"); builder.Add(cafe); }); std::string const houseNumber = "4a"; ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor, &houseNumber](FeatureType & ft) { osm::EditableMapObject emo; FillEditableMapObject(editor, ft, emo); emo.SetHouseNumber(houseNumber); TEST_EQUAL(editor.SaveEditedFeature(emo), osm::Editor::SaveResult::SavedSuccessfully, ()); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&houseNumber](FeatureType & ft) { TEST_EQUAL(ft.GetHouseNumber(), houseNumber, ()); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor](FeatureType & ft) { editor.RollBackChanges(ft.GetID()); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [](FeatureType & ft) { TEST_EQUAL(ft.GetHouseNumber(), "", ()); }); } void EditorTest::HaveMapEditsOrNotesToUploadTest() { auto & editor = osm::Editor::Instance(); auto const mwmId = ConstructTestMwm([](TestMwmBuilder & builder) { TestCafe cafe(m2::PointD(1.0, 1.0), "London Cafe", "en"); builder.Add(cafe); }); TEST(!editor.HaveMapEditsOrNotesToUpload(), ()); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [](FeatureType & ft) { SetBuildingLevelsToOne(ft); }); TEST(editor.HaveMapEditsOrNotesToUpload(), ()); editor.ClearAllLocalEdits(); TEST(!editor.HaveMapEditsOrNotesToUpload(), ()); ScopedFile sf("test_notes.xml", ScopedFile::Mode::DoNotCreate); editor.m_notes = Notes::MakeNotes(sf.GetFullPath(), true); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor](FeatureType & ft) { using NoteType = osm::Editor::NoteProblemType; feature::TypesHolder typesHolder; std::string defaultName; editor.CreateNote({1.0, 1.0}, ft.GetID(), typesHolder, defaultName, NoteType::PlaceDoesNotExist, "exploded"); }); TEST(editor.HaveMapEditsOrNotesToUpload(), ()); } void EditorTest::HaveMapEditsToUploadTest() { auto & editor = osm::Editor::Instance(); auto const gbMwmId = BuildMwm("GB", [](TestMwmBuilder & builder) { TestCafe cafeLondon(m2::PointD(1.0, 1.0), "London Cafe", "en"); builder.Add(cafeLondon); }); auto const rfMwmId = BuildMwm("RF", [](TestMwmBuilder & builder) { TestCafe cafeMoscow(m2::PointD(2.0, 2.0), "Moscow Cafe", "ru"); builder.Add(cafeMoscow); }); TEST(!editor.HaveMapEditsToUpload(gbMwmId), ()); TEST(!editor.HaveMapEditsToUpload(rfMwmId), ()); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [](FeatureType & ft) { SetBuildingLevelsToOne(ft); }); TEST(editor.HaveMapEditsToUpload(gbMwmId), ()); TEST(!editor.HaveMapEditsToUpload(rfMwmId), ()); ForEachCafeAtPoint(m_dataSource, m2::PointD(2.0, 2.0), [](FeatureType & ft) { SetBuildingLevelsToOne(ft); }); TEST(editor.HaveMapEditsToUpload(gbMwmId), ()); TEST(editor.HaveMapEditsToUpload(rfMwmId), ()); } void EditorTest::GetStatsTest() { auto & editor = osm::Editor::Instance(); auto const mwmId = ConstructTestMwm([](TestMwmBuilder & builder) { builder.Add(TestCafe(m2::PointD(1.0, 1.0), "London Cafe", "en")); builder.Add(TestCafe(m2::PointD(2.0, 2.0), "London Cafe", "en")); builder.Add(TestCafe(m2::PointD(3.0, 3.0), "London Cafe", "en")); builder.Add(TestCafe(m2::PointD(4.0, 4.0), "London Cafe", "en")); builder.Add(TestCafe(m2::PointD(5.0, 5.0), "London Cafe", "en")); builder.Add(TestPOI(m2::PointD(10, 10), "Corner Post", "default")); }); auto stats = editor.GetStats(); TEST(stats.m_edits.empty(), ()); TEST_EQUAL(stats.m_uploadedCount, 0, ()); TEST_EQUAL(stats.m_lastUploadTimestamp, base::INVALID_TIME_STAMP, ()); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [](FeatureType & ft) { SetBuildingLevelsToOne(ft); }); stats = editor.GetStats(); TEST_EQUAL(stats.m_edits.size(), 1, ()); ForEachCafeAtPoint(m_dataSource, m2::PointD(4.0, 4.0), [](FeatureType & ft) { SetBuildingLevelsToOne(ft); }); stats = editor.GetStats(); TEST_EQUAL(stats.m_edits.size(), 2, ()); ForEachCafeAtPoint(m_dataSource, m2::PointD(5.0, 5.0), [](FeatureType & ft) { SetBuildingLevelsToOne(ft); }); stats = editor.GetStats(); TEST_EQUAL(stats.m_edits.size(), 3, ()); TEST_EQUAL(stats.m_uploadedCount, 0, ()); TEST_EQUAL(stats.m_lastUploadTimestamp, base::INVALID_TIME_STAMP, ()); osm::EditableMapObject emo; CreateCafeAtPoint({6.0, 6.0}, mwmId, emo); pugi::xml_document doc; GenerateUploadedFeature(mwmId, emo, doc); editor.m_storage->Save(doc); editor.LoadEdits(); stats = editor.GetStats(); TEST_EQUAL(stats.m_edits.size(), 1, ()); TEST_EQUAL(stats.m_uploadedCount, 1, ()); TEST_NOT_EQUAL(stats.m_lastUploadTimestamp, base::INVALID_TIME_STAMP, ()); } void EditorTest::IsCreatedFeatureTest() { auto & editor = osm::Editor::Instance(); auto const mwmId = ConstructTestMwm([](TestMwmBuilder & builder) { builder.Add(TestCafe(m2::PointD(1.0, 1.0), "London Cafe", "en")); builder.Add(TestPOI(m2::PointD(10, 10), "Corner Post", "default")); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor](FeatureType & ft) { TEST(!editor.IsCreatedFeature(ft.GetID()), ()); SetBuildingLevelsToOne(ft); TEST(!editor.IsCreatedFeature(ft.GetID()), ()); }); osm::EditableMapObject emo; TEST(!editor.IsCreatedFeature(emo.GetID()), ()); CreateCafeAtPoint({2.0, 2.0}, mwmId, emo); TEST(editor.IsCreatedFeature(emo.GetID()), ()); } void EditorTest::ForEachFeatureInMwmRectAndScaleTest() { auto const mwmId = ConstructTestMwm([](TestMwmBuilder & builder) { builder.Add(TestCafe(m2::PointD(1.0, 1.0), "Untouched Cafe", "en")); builder.Add(TestCafe(m2::PointD(3.0, 3.0), "Cafe to modify", "en")); builder.Add(TestCafe(m2::PointD(5.0, 5.0), "Cafe to delete", "en")); builder.Add(TestPOI(m2::PointD(100.0, 100.0), "Corner Post", "default")); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(3.0, 3.0), [](FeatureType & ft) { auto & editor = osm::Editor::Instance(); TEST_EQUAL(editor.GetFeatureStatus(ft.GetID()), FeatureStatus::Untouched, ()); osm::EditableMapObject emo; FillEditableMapObject(editor, ft, emo); SetBuildingLevels(emo, "1"); TEST_EQUAL(editor.SaveEditedFeature(emo), osm::Editor::SaveResult::SavedSuccessfully, ()); TEST_EQUAL(editor.GetFeatureStatus(ft.GetID()), FeatureStatus::Modified, ()); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(5.0, 5.0), [](FeatureType & ft) { auto & editor = osm::Editor::Instance(); TEST_EQUAL(editor.GetFeatureStatus(ft.GetID()), FeatureStatus::Untouched, ()); editor.DeleteFeature(ft.GetID()); TEST_EQUAL(editor.GetFeatureStatus(ft.GetID()), FeatureStatus::Deleted, ()); }); { osm::EditableMapObject emo; CreateCafeAtPoint({7.0, 7.0}, mwmId, emo); } { osm::EditableMapObject emo; CreateCafeAtPoint({9.0, 9.0}, mwmId, emo); } // Finds created features only. TEST_EQUAL(CountFeaturesInRect(mwmId, {0.0, 0.0, 2.0, 2.0}), 0, ()); TEST_EQUAL(CountFeaturesInRect(mwmId, {2.0, 2.0, 4.0, 4.0}), 0, ()); TEST_EQUAL(CountFeaturesInRect(mwmId, {4.0, 4.0, 6.0, 6.0}), 0, ()); TEST_EQUAL(CountFeaturesInRect(mwmId, {6.0, 6.0, 8.0, 8.0}), 1, ()); TEST_EQUAL(CountFeaturesInRect(mwmId, {8.0, 8.0, 10.0, 10.0}), 1, ()); TEST_EQUAL(CountFeaturesInRect(mwmId, {0.0, 0.0, 10.0, 10.0}), 2, ()); // Finds all features except deleted. TEST_EQUAL(CountFeatureTypeInRectByDataSource(m_dataSource, {0.0, 0.0, 2.0, 2.0}), 1, ()); TEST_EQUAL(CountFeatureTypeInRectByDataSource(m_dataSource, {2.0, 2.0, 4.0, 4.0}), 1, ()); TEST_EQUAL(CountFeatureTypeInRectByDataSource(m_dataSource, {4.0, 4.0, 6.0, 6.0}), 0, ()); TEST_EQUAL(CountFeatureTypeInRectByDataSource(m_dataSource, {6.0, 6.0, 8.0, 8.0}), 1, ()); TEST_EQUAL(CountFeatureTypeInRectByDataSource(m_dataSource, {8.0, 8.0, 10.0, 10.0}), 1, ()); TEST_EQUAL(CountFeatureTypeInRectByDataSource(m_dataSource, {0.0, 0.0, 10.0, 10.0}), 4, ()); } void EditorTest::CreateNoteTest() { auto & editor = osm::Editor::Instance(); auto const mwmId = ConstructTestMwm([](TestMwmBuilder & builder) { builder.Add(TestCafe(m2::PointD(1.0, 1.0), "London Cafe", "en")); builder.Add(TestCafe(m2::PointD(2.0, 2.0), "Cafe", "en")); }); auto const createAndCheckNote = [&editor](FeatureID const & fId, ms::LatLon const & pos, osm::Editor::NoteProblemType const noteType) { ScopedFile sf("test_notes.xml", ScopedFile::Mode::DoNotCreate); editor.m_notes = Notes::MakeNotes(sf.GetFullPath(), true); feature::TypesHolder holder; holder.Assign(classif().GetTypeByPath({"amenity", "restaurant"})); std::string defaultName = "Test name"; editor.CreateNote(pos, fId, holder, defaultName, noteType, "with comment"); auto const notes = editor.m_notes->GetNotes(); TEST_EQUAL(notes.size(), 1, ()); auto const & note = notes.front(); TEST(note.m_point.EqualDxDy(pos, 1e-10), ()); TEST(note.m_note.find("with comment") != std::string::npos, ()); TEST(note.m_note.find("OSM snapshot date") != std::string::npos, ()); TEST(note.m_note.find("restaurant") != std::string::npos, ()); TEST(note.m_note.find("Test name") != std::string::npos, ()); }; // Should match a piece of text in the editor note. constexpr char const * kPlaceDoesNotExistMessage = "The place has gone or never existed"; ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor, &createAndCheckNote](FeatureType & ft) { createAndCheckNote(ft.GetID(), {1.0, 1.0}, osm::Editor::NoteProblemType::PlaceDoesNotExist); auto notes = editor.m_notes->GetNotes(); TEST_NOT_EQUAL(notes.front().m_note.find(kPlaceDoesNotExistMessage), std::string::npos, ()); TEST_EQUAL(editor.GetFeatureStatus(ft.GetID()), FeatureStatus::Obsolete, ()); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(2.0, 2.0), [&editor, &createAndCheckNote](FeatureType & ft) { createAndCheckNote(ft.GetID(), {2.0, 2.0}, osm::Editor::NoteProblemType::General); TEST_NOT_EQUAL(editor.GetFeatureStatus(ft.GetID()), FeatureStatus::Obsolete, ()); auto notes = editor.m_notes->GetNotes(); TEST_EQUAL(notes.front().m_note.find(kPlaceDoesNotExistMessage), std::string::npos, ()); }); } void EditorTest::LoadMapEditsTest() { auto & editor = osm::Editor::Instance(); auto const gbMwmId = BuildMwm("GB", [](TestMwmBuilder & builder) { builder.Add(TestCafe(m2::PointD(0.0, 0.0), "London Cafe", "en")); builder.Add(TestCafe(m2::PointD(1.0, 1.0), "London Cafe", "en")); builder.Add(TestPOI(m2::PointD(100, 100), "Corner Post", "default")); }); auto const rfMwmId = BuildMwm("RF", [](TestMwmBuilder & builder) { builder.Add(TestCafe(m2::PointD(2.0, 2.0), "Moscow Cafe1", "en")); builder.Add(TestCafe(m2::PointD(7.0, 7.0), "Moscow Cafe2", "en")); builder.Add(TestCafe(m2::PointD(4.0, 4.0), "Moscow Cafe3", "en")); builder.Add(TestCafe(m2::PointD(6.0, 6.0), "Moscow Cafe4", "en")); builder.Add(TestPOI(m2::PointD(100, 100), "Corner Post", "default")); }); std::vector features; ForEachCafeAtPoint(m_dataSource, m2::PointD(0.0, 0.0), [&features](FeatureType & ft) { SetBuildingLevelsToOne(ft); features.emplace_back(ft.GetID()); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor, &features](FeatureType & ft) { editor.DeleteFeature(ft.GetID()); features.emplace_back(ft.GetID()); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(2.0, 2.0), [&editor, &features](FeatureType & ft) { editor.MarkFeatureAsObsolete(ft.GetID()); features.emplace_back(ft.GetID()); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(7.0, 7.0), [&features](FeatureType & ft) { SetBuildingLevelsToOne(ft); features.emplace_back(ft.GetID()); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(4.0, 4.0), [&editor, &features](FeatureType & ft) { editor.DeleteFeature(ft.GetID()); features.emplace_back(ft.GetID()); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(6.0, 6.0), [&features](FeatureType & ft) { SetBuildingLevelsToOne(ft); features.emplace_back(ft.GetID()); }); osm::EditableMapObject emo; CreateCafeAtPoint({5.0, 5.0}, rfMwmId, emo); features.emplace_back(emo.GetID()); editor.Save((*editor.m_features.Get())); editor.LoadEdits(); auto const fillLoaded = [&editor](std::vector & loadedFeatures) { loadedFeatures.clear(); for (auto const & mwm : *(editor.m_features.Get())) { for (auto const & index : mwm.second) { loadedFeatures.emplace_back(index.second.m_object.GetID()); } } }; std::vector loadedFeatures; fillLoaded(loadedFeatures); sort(loadedFeatures.begin(), loadedFeatures.end()); sort(features.begin(), features.end()); TEST_EQUAL(features, loadedFeatures, ()); m_dataSource.DeregisterMap(m_mwmFiles.back().GetCountryFile()); TEST(RemoveMwm(rfMwmId), ()); auto const newRfMwmId = BuildMwm("RF", [](TestMwmBuilder & builder) { builder.Add(TestCafe(m2::PointD(2.0, 2.0), "Moscow Cafe1", "en")); builder.Add(TestCafe(m2::PointD(7.0, 7.0), "Moscow Cafe2", "en")); builder.Add(TestCafe(m2::PointD(4.0, 4.0), "Moscow Cafe3", "en")); builder.Add(TestCafe(m2::PointD(6.0, 6.0), "Moscow Cafe4", "en")); }, 1); editor.LoadEdits(); fillLoaded(loadedFeatures); TEST_EQUAL(features.size(), loadedFeatures.size(), ()); m_dataSource.DeregisterMap(m_mwmFiles.back().GetCountryFile()); TEST(RemoveMwm(newRfMwmId), ()); TEST_EQUAL(editor.m_features.Get()->size(), 2, ()); editor.LoadEdits(); fillLoaded(loadedFeatures); TEST_EQUAL(editor.m_features.Get()->size(), 1, ()); TEST_EQUAL(loadedFeatures.size(), 2, ()); osm::EditableMapObject gbEmo; CreateCafeAtPoint({3.0, 3.0}, gbMwmId, gbEmo); pugi::xml_document doc; GenerateUploadedFeature(gbMwmId, gbEmo, doc); editor.m_storage->Save(doc); editor.LoadEdits(); fillLoaded(loadedFeatures); TEST_EQUAL(editor.m_features.Get()->size(), 1, ()); TEST_EQUAL(loadedFeatures.size(), 1, ()); m_dataSource.DeregisterMap(m_mwmFiles.back().GetCountryFile()); TEST(RemoveMwm(gbMwmId), ()); auto const newGbMwmId = BuildMwm("GB", [](TestMwmBuilder & builder) { builder.Add(TestCafe(m2::PointD(0.0, 0.0), "London Cafe", "en")); builder.Add(TestCafe(m2::PointD(1.0, 1.0), "London Cafe", "en")); }, 1); newGbMwmId.GetInfo()->m_version.SetSecondsSinceEpoch(time(nullptr) + 1); editor.LoadEdits(); TEST(editor.m_features.Get()->empty(), ()); } void EditorTest::SaveEditedFeatureTest() { auto & editor = osm::Editor::Instance(); auto const mwmId = ConstructTestMwm([](TestMwmBuilder & builder) { builder.Add(TestCafe(m2::PointD(1.0, 1.0), "London Cafe1", "en")); builder.Add(TestPOI(m2::PointD(10, 10), "Corner Post", "default")); }); osm::EditableMapObject emo; editor.CreatePoint(classif().GetTypeByPath({"amenity", "cafe"}), {4.0, 4.0}, mwmId, emo); emo.SetHouseNumber("12"); TEST_EQUAL(editor.GetFeatureStatus(emo.GetID()), FeatureStatus::Untouched, ()); TEST_EQUAL(editor.SaveEditedFeature(emo), osm::Editor::SaveResult::SavedSuccessfully, ()); TEST_EQUAL(editor.GetFeatureStatus(emo.GetID()), FeatureStatus::Created, ()); TEST_EQUAL(editor.SaveEditedFeature(emo), osm::Editor::SaveResult::NothingWasChanged, ()); TEST_EQUAL(editor.GetFeatureStatus(emo.GetID()), FeatureStatus::Created, ()); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor](FeatureType & ft) { osm::EditableMapObject emo; FillEditableMapObject(editor, ft, emo); TEST_EQUAL(editor.SaveEditedFeature(emo), osm::Editor::SaveResult::NothingWasChanged, ()); TEST_EQUAL(editor.GetFeatureStatus(emo.GetID()), FeatureStatus::Untouched, ()); emo.SetHouseNumber("4a"); TEST_EQUAL(editor.SaveEditedFeature(emo), osm::Editor::SaveResult::SavedSuccessfully, ()); TEST_EQUAL(editor.GetFeatureStatus(emo.GetID()), FeatureStatus::Modified, ()); TEST_EQUAL(editor.SaveEditedFeature(emo), osm::Editor::SaveResult::NothingWasChanged, ()); TEST_EQUAL(editor.GetFeatureStatus(emo.GetID()), FeatureStatus::Modified, ()); emo.SetHouseNumber(""); TEST_EQUAL(editor.SaveEditedFeature(emo), osm::Editor::SaveResult::SavedSuccessfully, ()); TEST_EQUAL(editor.GetFeatureStatus(emo.GetID()), FeatureStatus::Untouched, ()); }); } void EditorTest::SaveTransactionTest() { ScopedOptionalSaveStorage optionalSaveStorage; auto & editor = osm::Editor::Instance(); auto const mwmId = BuildMwm("GB", [](TestMwmBuilder & builder) { builder.Add(TestCafe(m2::PointD(1.0, 1.0), "London Cafe1", "en")); builder.Add(TestCafe(m2::PointD(4.0, 4.0), "London Cafe2", "en")); builder.Add(TestPOI(m2::PointD(6.0, 6.0), "Corner Post", "default")); }); auto const rfMwmId = BuildMwm("RF", [](TestMwmBuilder & builder) { builder.Add(TestCafe(m2::PointD(10.0, 10.0), "Moscow Cafe1", "en")); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [](FeatureType & ft) { SetBuildingLevelsToOne(ft); }); ForEachCafeAtPoint(m_dataSource, m2::PointD(10.0, 10.0), [](FeatureType & ft) { SetBuildingLevelsToOne(ft); }); auto const features = editor.m_features.Get(); TEST_EQUAL(features->size(), 2, ()); TEST_EQUAL(features->begin()->second.size(), 1, ()); TEST_EQUAL(features->rbegin()->second.size(), 1, ()); optionalSaveStorage.AllowSave(false); { auto saveResult = osm::Editor::SaveResult::NothingWasChanged; ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&saveResult](FeatureType & ft) { auto & editor = osm::Editor::Instance(); osm::EditableMapObject emo; emo.SetFromFeatureType(ft); emo.SetEditableProperties(editor.GetEditableProperties(ft)); SetBuildingLevels(emo, "5"); saveResult = editor.SaveEditedFeature(emo); }); TEST_EQUAL(saveResult, osm::Editor::SaveResult::NoFreeSpaceError, ()); auto const features = editor.m_features.Get(); auto const mwmIt = features->find(mwmId); TEST(mwmIt != features->end(), ()); TEST_EQUAL(mwmIt->second.size(), 1, ()); } { auto saveResult = osm::Editor::SaveResult::NothingWasChanged; ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&saveResult](FeatureType & ft) { auto & editor = osm::Editor::Instance(); osm::EditableMapObject emo; emo.SetFromFeatureType(ft); emo.SetEditableProperties(editor.GetEditableProperties(ft)); SetBuildingLevels(emo, ""); saveResult = editor.SaveEditedFeature(emo); }); TEST_EQUAL(saveResult, osm::Editor::SaveResult::SavingError, ()); auto const features = editor.m_features.Get(); auto const mwmIt = features->find(mwmId); TEST(mwmIt != features->end(), ()); TEST_EQUAL(mwmIt->second.size(), 1, ()); auto const featureInfo = mwmIt->second.begin()->second; TEST_EQUAL(featureInfo.m_status, FeatureStatus::Modified, ()); } { ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor](FeatureType & ft) { editor.DeleteFeature(ft.GetID()); }); auto const features = editor.m_features.Get(); auto const mwmIt = features->find(mwmId); TEST(mwmIt != features->end(), ()); TEST_EQUAL(mwmIt->second.size(), 1, ()); auto const featureInfo = mwmIt->second.begin()->second; TEST_EQUAL(featureInfo.m_status, FeatureStatus::Modified, ()); } { ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor](FeatureType & ft) { editor.MarkFeatureAsObsolete(ft.GetID()); }); auto const features = editor.m_features.Get(); auto const mwmIt = features->find(mwmId); TEST(mwmIt != features->end(), ()); TEST_EQUAL(mwmIt->second.size(), 1, ()); auto const featureInfo = mwmIt->second.begin()->second; TEST_EQUAL(featureInfo.m_status, FeatureStatus::Modified, ()); } { ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor](FeatureType & ft) { using NoteType = osm::Editor::NoteProblemType; feature::TypesHolder typesHolder; std::string defaultName; editor.CreateNote({1.0, 1.0}, ft.GetID(), typesHolder, defaultName, NoteType::PlaceDoesNotExist, "exploded"); }); TEST_EQUAL(editor.m_notes->NotUploadedNotesCount(), 0, ()); auto const features = editor.m_features.Get(); auto const mwmIt = features->find(mwmId); TEST(mwmIt != features->end(), ()); TEST_EQUAL(mwmIt->second.size(), 1, ()); auto const featureInfo = mwmIt->second.begin()->second; TEST_EQUAL(featureInfo.m_status, FeatureStatus::Modified, ()); } { ForEachCafeAtPoint(m_dataSource, m2::PointD(1.0, 1.0), [&editor](FeatureType & ft) { editor.RollBackChanges(ft.GetID()); }); auto const features = editor.m_features.Get(); auto const mwmIt = features->find(mwmId); TEST(mwmIt != features->end(), ()); TEST_EQUAL(mwmIt->second.size(), 1, ()); auto const featureInfo = mwmIt->second.begin()->second; TEST_EQUAL(featureInfo.m_status, FeatureStatus::Modified, ()); } { editor.ClearAllLocalEdits(); TEST_EQUAL(editor.m_features.Get()->size(), 2, ()); } { { platform::tests_support::AsyncGuiThread guiThread; editor.OnMapDeregistered(mwmId.GetInfo()->GetLocalFile()); } auto const features = editor.m_features.Get(); auto const mwmIt = features->find(mwmId); TEST(mwmIt != features->end(), ()); TEST_EQUAL(mwmIt->second.size(), 1, ()); auto const featureInfo = mwmIt->second.begin()->second; TEST_EQUAL(featureInfo.m_status, FeatureStatus::Modified, ()); } optionalSaveStorage.AllowSave(true); editor.ClearAllLocalEdits(); TEST(editor.m_features.Get()->empty(), ()); } void EditorTest::Cleanup(platform::LocalCountryFile const & map) { platform::CountryIndexes::DeleteFromDisk(map); map.DeleteFromDisk(MapFileType::Map); } bool EditorTest::RemoveMwm(MwmSet::MwmId const & mwmId) { auto const & file = mwmId.GetInfo()->GetLocalFile(); auto const it = find(m_mwmFiles.begin(), m_mwmFiles.end(), file); if (it == m_mwmFiles.end()) return false; Cleanup(*it); m_mwmFiles.erase(it); return true; } void EditorTest::LoadExistingEditsXml() { char const * data = R"( )"; ConstructTestMwm([](editor::testing::TestMwmBuilder &) { }); pugi::xml_document doc; TEST(doc.load_string(data), ()); auto memStorage = std::make_unique(); memStorage->Save(doc); auto & editor = osm::Editor::Instance(); editor.SetStorageForTesting(std::move(memStorage)); editor.LoadEdits(); TEST_EQUAL(editor.m_features.Get()->size(), 1, ()); } } // namespace testing } // namespace editor namespace { using editor::testing::EditorTest; UNIT_CLASS_TEST(EditorTest, GetFeatureTypeInfoTest) { EditorTest::GetFeatureTypeInfoTest(); } UNIT_CLASS_TEST(EditorTest, SetIndexTest) { EditorTest::SetIndexTest(); } UNIT_CLASS_TEST(EditorTest, GetFeatureStatusTest) { EditorTest::GetFeatureStatusTest(); } UNIT_CLASS_TEST(EditorTest, IsFeatureUploadedTest) { EditorTest::IsFeatureUploadedTest(); } UNIT_CLASS_TEST(EditorTest, DeleteFeatureTest) { EditorTest::DeleteFeatureTest(); } UNIT_CLASS_TEST(EditorTest, ClearAllLocalEditsTest) { EditorTest::ClearAllLocalEditsTest(); } UNIT_CLASS_TEST(EditorTest, GetEditedFeatureStreetTest) { EditorTest::GetEditedFeatureStreetTest(); } UNIT_CLASS_TEST(EditorTest, GetEditedFeatureTest) { EditorTest::GetEditedFeatureTest(); } UNIT_CLASS_TEST(EditorTest, GetFeaturesByStatusTest) { EditorTest::GetFeaturesByStatusTest(); } UNIT_CLASS_TEST(EditorTest, OnMapDeregisteredTest) { EditorTest::OnMapDeregisteredTest(); } UNIT_CLASS_TEST(EditorTest, RollBackChangesTest) { EditorTest::RollBackChangesTest(); } UNIT_CLASS_TEST(EditorTest, HaveMapEditsOrNotesToUploadTest) { EditorTest::HaveMapEditsOrNotesToUploadTest(); } UNIT_CLASS_TEST(EditorTest, HaveMapEditsToUploadTest) { EditorTest::HaveMapEditsToUploadTest(); } UNIT_CLASS_TEST(EditorTest, GetStatsTest) { EditorTest::GetStatsTest(); } UNIT_CLASS_TEST(EditorTest, IsCreatedFeatureTest) { EditorTest::IsCreatedFeatureTest(); } UNIT_CLASS_TEST(EditorTest, ForEachFeatureInMwmRectAndScaleTest) { EditorTest::ForEachFeatureInMwmRectAndScaleTest(); } UNIT_CLASS_TEST(EditorTest, CreateNoteTest) { EditorTest::CreateNoteTest(); } UNIT_CLASS_TEST(EditorTest, LoadMapEditsTest) { EditorTest::LoadMapEditsTest(); } UNIT_CLASS_TEST(EditorTest, SaveEditedFeatureTest) { EditorTest::SaveEditedFeatureTest(); } UNIT_CLASS_TEST(EditorTest, SaveTransactionTest) { EditorTest::SaveTransactionTest(); } UNIT_CLASS_TEST(EditorTest, LoadEditsXml) { LoadExistingEditsXml(); } } // namespace