Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvng <viktor.govako@gmail.com>2013-06-24 19:53:50 +0400
committerAlex Zolotarev <alex@maps.me>2015-09-23 01:56:49 +0300
commit8a6201deadd0affd932dae545b5200857d79758f (patch)
tree6b51bb1374640d756bf9381edca64c699158274c /map/mwm_tests
parentd2d74c74413ef496b946ea87a2d50517fd2ab320 (diff)
Move "heavy" tests to separate executable mwm_tests.
Diffstat (limited to 'map/mwm_tests')
-rw-r--r--map/mwm_tests/multithread_mwm_test.cpp89
-rw-r--r--map/mwm_tests/mwm_foreach_test.cpp330
-rw-r--r--map/mwm_tests/mwm_tests.pro25
3 files changed, 444 insertions, 0 deletions
diff --git a/map/mwm_tests/multithread_mwm_test.cpp b/map/mwm_tests/multithread_mwm_test.cpp
new file mode 100644
index 0000000000..ff2df972ab
--- /dev/null
+++ b/map/mwm_tests/multithread_mwm_test.cpp
@@ -0,0 +1,89 @@
+#include "../../testing/testing.hpp"
+
+#include "../../map/feature_vec_model.hpp"
+
+#include "../../base/thread.hpp"
+
+
+namespace
+{
+ typedef model::FeaturesFetcher SourceT;
+
+ class FeaturesLoader : public threads::IRoutine
+ {
+ SourceT const & m_src;
+ int m_scale;
+
+ // Get random rect inside m_src.
+ m2::RectD GetRandomRect() const
+ {
+ int const count = max(1, rand() % 50);
+
+ int const x = rand() % count;
+ int const y = rand() % count;
+
+ m2::RectD const r = m_src.GetWorldRect();
+ double const sizeX = r.SizeX() / count;
+ double const sizeY = r.SizeY() / count;
+
+ double const minX = r.minX() + x * sizeX;
+ double const minY = r.minY() + y * sizeY;
+
+ return m2::RectD(minX, minY, minX + sizeX, minY + sizeY);
+ }
+
+ public:
+ FeaturesLoader(SourceT const & src) : m_src(src) {}
+
+ virtual void Do()
+ {
+ size_t const count = 2000;
+
+ for (size_t i = 0; i < count; ++i)
+ {
+ m2::RectD const r = GetRandomRect();
+ m_scale = scales::GetScaleLevel(r);
+
+ m_src.ForEachFeature_TileDrawing(r, *this, m_scale);
+ }
+ }
+
+ void operator() (FeatureType const & f)
+ {
+ // Force load feature.
+ // We check asserts here. There is no any other constrains here.
+ (void)f.IsEmptyGeometry(m_scale);
+ }
+ };
+
+ void RunTest(string const & file)
+ {
+ SourceT src;
+ src.InitClassificator();
+ src.AddMap(file + DATA_FILE_EXTENSION);
+
+ // Check that country rect is valid and not infinity.
+ m2::RectD const r = src.GetWorldRect();
+ TEST ( r.IsValid(), () );
+
+ m2::RectD world(MercatorBounds::FullRect());
+ world.Inflate(-10.0, -10.0);
+
+ TEST ( world.IsRectInside(r), () );
+
+ srand(666);
+
+ size_t const count = 20;
+ threads::ThreadPool pool(count);
+
+ for (size_t i = 0; i < count; ++i)
+ pool.Add(new FeaturesLoader(src));
+
+ pool.Join();
+ }
+}
+
+UNIT_TEST(Threading_ForEachFeature)
+{
+ RunTest("minsk-pass");
+}
diff --git a/map/mwm_tests/mwm_foreach_test.cpp b/map/mwm_tests/mwm_foreach_test.cpp
new file mode 100644
index 0000000000..bbab151564
--- /dev/null
+++ b/map/mwm_tests/mwm_foreach_test.cpp
@@ -0,0 +1,330 @@
+#include "../../testing/testing.hpp"
+
+#include "../../platform/platform.hpp"
+
+#include "../../map/feature_vec_model.hpp"
+
+#include "../../indexer/data_header.hpp"
+#include "../../indexer/scales.hpp"
+#include "../../indexer/feature_visibility.hpp"
+#include "../../indexer/feature_processor.hpp"
+#include "../../indexer/classificator.hpp"
+
+#include "../../geometry/rect_intersect.hpp"
+#include "../../geometry/robust_orientation.hpp"
+
+#include "../../base/logging.hpp"
+
+#include "../../std/string.hpp"
+#include "../../std/algorithm.hpp"
+#include "../../std/iostream.hpp"
+
+
+typedef vector<pair<FeatureType, string> > feature_cont_t;
+
+class AccumulatorBase
+{
+ mutable string m_dbgString;
+ feature_cont_t & m_cont;
+
+protected:
+ int m_scale;
+
+ bool is_drawable(FeatureType const & f) const
+ {
+ m_dbgString = f.DebugString(m_scale);
+ CHECK(m_dbgString == f.DebugString(m_scale), ());
+
+ // Feature that doesn't have any geometry for m_scale returns empty DebugString().
+ return (!f.IsEmptyGeometry(m_scale) && feature::IsDrawableForIndex(f, m_scale));
+ }
+
+ void add(FeatureType const & f) const
+ {
+ m_cont.push_back(make_pair(f, m_dbgString));
+ }
+
+public:
+ AccumulatorBase(m2::RectD const & r, feature_cont_t & cont)
+ : m_cont(cont)
+ {
+ m_scale = scales::GetScaleLevel(r);
+ }
+
+ void operator() (FeatureType const & f) const
+ {
+ if (is_drawable(f))
+ add(f);
+ }
+};
+
+class IntersectCheck
+{
+ m2::RectD m_rect;
+
+ m2::PointD m_prev;
+ bool m_isPrev, m_intersect;
+
+public:
+ IntersectCheck(m2::RectD const & r)
+ : m_rect(r), m_isPrev(false), m_intersect(false)
+ {
+ }
+
+ void TestPoint(m2::PointD const & p)
+ {
+ m_intersect = m_rect.IsPointInside(p);
+ }
+
+ void operator() (CoordPointT const & p)
+ {
+ if (m_intersect) return;
+
+ m2::PointD pt(p.first, p.second);
+ if (m_isPrev)
+ {
+ m2::PointD d1 = m_prev;
+ m2::PointD d2 = pt;
+ m_intersect = m2::Intersect(m_rect, d1, d2);
+ }
+ else
+ m_isPrev = true;
+
+ m_prev = pt;
+ }
+
+ void operator() (m2::PointD const & p1, m2::PointD const & p2, m2::PointD const & p3)
+ {
+ if (m_intersect) return;
+
+ m2::PointD arrP[] = { p1, p2, p3 };
+
+ // make right-oriented triangle
+ if (m2::robust::OrientedS(arrP[0], arrP[1], arrP[2]) < 0.0)
+ swap(arrP[1], arrP[2]);
+
+ bool isInside = true;
+ m2::PointD const pt = m_rect.LeftTop();
+
+ for (size_t i = 0; i < 3; ++i)
+ {
+ // intersect edge with rect
+ m_intersect = m2::Intersect(m_rect, arrP[i], arrP[(i + 1) % 3]);
+ if (m_intersect)
+ break;
+
+ if (isInside)
+ {
+ // or check if rect inside triangle (any point of rect)
+ double const s = m2::robust::OrientedS(arrP[i], arrP[(i + 1) % 3], pt);
+ isInside = (s >= 0.0);
+ }
+ }
+
+ m_intersect = m_intersect || isInside;
+ }
+
+ bool IsIntersect() const { return m_intersect; }
+};
+
+class AccumulatorEtalon : public AccumulatorBase
+{
+ typedef AccumulatorBase base_type;
+
+ m2::RectD m_rect;
+
+ bool is_intersect(FeatureType const & f) const
+ {
+ IntersectCheck check(m_rect);
+
+ using namespace feature;
+ switch (f.GetFeatureType())
+ {
+ case GEOM_POINT: check.TestPoint(f.GetCenter()); break;
+ case GEOM_LINE: f.ForEachPointRef(check, m_scale); break;
+ case GEOM_AREA: f.ForEachTriangleRef(check, m_scale); break;
+ default:
+ CHECK ( false, () );
+ }
+
+ return check.IsIntersect();
+ }
+
+public:
+ AccumulatorEtalon(m2::RectD const & r, feature_cont_t & cont)
+ : base_type(r, cont), m_rect(r)
+ {
+ }
+
+ void operator() (FeatureType const & f, uint64_t /*offset*/) const
+ {
+ if (is_drawable(f) && is_intersect(f))
+ add(f);
+ }
+};
+
+// invoke this comparator to ensure that "sort" and "compare_sequence" use equal criterion
+struct compare_strings
+{
+ int compare(string const & r1, string const & r2) const
+ {
+ if (r1 < r2)
+ return -1;
+ if (r2 < r1)
+ return 1;
+ return 0;
+ }
+ template <class T>
+ int compare(T const & r1, T const & r2) const
+ {
+ return compare(r1.second, r2.second);
+ }
+ template <class T>
+ bool operator() (T const & r1, T const & r2) const
+ {
+ return (compare(r1, r2) == -1);
+ }
+};
+
+template <class TAccumulator, class TSource>
+void for_each_in_rect(TSource & src, feature_cont_t & cont, m2::RectD const & rect)
+{
+ cont.clear();
+ TAccumulator acc(rect, cont);
+ src.ForEachFeature(rect, acc);
+ sort(cont.begin(), cont.end(), compare_strings());
+}
+
+class file_source_t
+{
+ ModelReaderPtr m_file;
+public:
+ file_source_t(ModelReaderPtr const & file) : m_file(file) {}
+
+ template <class ToDo>
+ void ForEachFeature(m2::RectD const & /*rect*/, ToDo toDo)
+ {
+ feature::ForEachFromDat(m_file, toDo);
+ }
+};
+
+/// "test" should contain all elements from etalon
+template <class TCont, class TCompare>
+bool compare_sequence(TCont const & etalon, TCont const & test, TCompare comp, size_t & errInd)
+{
+ if (test.size() < etalon.size())
+ return false;
+
+ typedef typename TCont::const_iterator iter_t;
+
+ iter_t i1 = etalon.begin();
+ iter_t i2 = test.begin();
+ while (i1 != etalon.end() && i2 != test.end())
+ {
+ switch (comp.compare(*i1, *i2))
+ {
+ case 0:
+ ++i1;
+ ++i2;
+ break;
+ case -1:
+ {
+ errInd = distance(etalon.begin(), i1);
+ return false;
+ }
+ case 1:
+ ++i2;
+ break;
+ }
+ }
+
+ return true;
+}
+
+namespace
+{
+ class FindOffset
+ {
+ int m_level;
+ pair<FeatureType, string> const & m_test;
+
+ public:
+ FindOffset(int level, pair<FeatureType, string> const & test)
+ : m_level(level), m_test(test)
+ {}
+
+ void operator() (FeatureType const & f, uint64_t offset)
+ {
+ string const s = f.DebugString(m_level);
+ if (s == m_test.second)
+ {
+ cout << s << endl << "Feature offset = " << offset << endl;
+
+ cout << "Feature classificator types:\n";
+
+ feature::TypesHolder types(f);
+ for (size_t i = 0; i < types.Size(); ++i)
+ cout << classif().GetFullObjectName(types[i]) << endl;
+ }
+ }
+ };
+
+ void RunTest(string const & file)
+ {
+ model::FeaturesFetcher src1;
+ src1.InitClassificator();
+ src1.AddMap(file);
+
+ vector<m2::RectD> rects;
+ rects.push_back(src1.GetWorldRect());
+
+ ModelReaderPtr reader = GetPlatform().GetReader(file);
+
+ while (!rects.empty())
+ {
+ m2::RectD r = rects.back();
+ rects.pop_back();
+
+ feature_cont_t v1, v2;
+ for_each_in_rect<AccumulatorBase>(src1, v1, r);
+
+ file_source_t src2(reader);
+ for_each_in_rect<AccumulatorEtalon>(src2, v2, r);
+
+ int const level = scales::GetScaleLevel(r);
+
+ size_t const emptyInd = size_t(-1);
+ size_t errInd = emptyInd;
+ if (!compare_sequence(v2, v1, compare_strings(), errInd))
+ {
+ if (errInd != emptyInd)
+ src2.ForEachFeature(r, FindOffset(level, v2[errInd]));
+
+ TEST(false, ("Failed for rect: ", r, "; Scale level = ", level, ". Etalon size = ", v2.size(), ". Index size = ", v1.size()));
+ }
+
+ if (!v2.empty() && (level < scales::GetUpperScale()))
+ {
+ m2::RectD r1, r2;
+ r.DivideByGreaterSize(r1, r2);
+ rects.push_back(r1);
+ rects.push_back(r2);
+ }
+ }
+ }
+
+ void RunTestForChoice(string const & fName)
+ {
+// cout << "Run " << fName << "? (y/n)\n";
+// char c;
+// cin >> c;
+// if (c == 'y')
+ RunTest(fName + DATA_FILE_EXTENSION);
+ }
+}
+
+UNIT_TEST(ForEach_QueryResults)
+{
+ RunTestForChoice("minsk-pass");
+ //RunTestForChoice("london-center");
+}
diff --git a/map/mwm_tests/mwm_tests.pro b/map/mwm_tests/mwm_tests.pro
new file mode 100644
index 0000000000..5b4beb6c16
--- /dev/null
+++ b/map/mwm_tests/mwm_tests.pro
@@ -0,0 +1,25 @@
+# Map library tests.
+
+TARGET = mwm_tests
+CONFIG += console
+CONFIG -= app_bundle
+TEMPLATE = app
+
+ROOT_DIR = ../..
+DEPENDENCIES = map gui search storage graphics indexer platform anim geometry coding base \
+ freetype fribidi expat protobuf tomcrypt jansson zlib
+
+include($$ROOT_DIR/common.pri)
+
+QT *= core opengl
+
+win32* {
+ LIBS *= -lShell32 -lOpengl32
+ win32-g++: LIBS *= -lpthread
+}
+macx*: LIBS *= "-framework Foundation" "-framework IOKit"
+
+SOURCES += \
+ ../../testing/testingmain.cpp \
+ mwm_foreach_test.cpp \
+ multithread_mwm_test.cpp \