From 5498c84ed7eafaacd997f88d9323f2d934c143c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 18 Dec 2018 12:25:54 +0100 Subject: [PATCH] [apps/regression] Add tests about regression navigation --- apps/Makefile | 5 + apps/regression/graph_controller.h | 7 +- apps/regression/test/graph.cpp | 176 +++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 apps/regression/test/graph.cpp diff --git a/apps/Makefile b/apps/Makefile index d6e8cffac..98141b448 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -86,4 +86,9 @@ $(app_objs): $(app_image_objs) epsilon.$(EXE): $(app_objs) $(app_image_objs) +TO_REMOVE := apps/main.o apps/i18n.o +TMP := $(app_objs) $(app_image_objs) +VAR := $(filter-out $(TO_REMOVE), $(TMP)) +test.$(EXE): $(VAR) + products += epsilon.$(EXE) $(app_objs) $(call INLINER_PRODUCTS,$(app_images)) diff --git a/apps/regression/graph_controller.h b/apps/regression/graph_controller.h index d5b45feef..b30ac092e 100644 --- a/apps/regression/graph_controller.h +++ b/apps/regression/graph_controller.h @@ -23,6 +23,11 @@ public: void viewWillAppear() override; void selectRegressionCurve(); int selectedSeriesIndex() const { return *m_selectedSeriesIndex; } + + // moveCursorHorizontally and Vertically are public to be used in tests + bool moveCursorHorizontally(int direction) override; + bool moveCursorVertically(int direction) override; + private: constexpr static int k_maxLegendLength = 16; constexpr static int k_maxNumberOfCharacters = 50; @@ -35,7 +40,6 @@ private: // SimpleInteractiveCurveViewController void reloadBannerView() override; - bool moveCursorHorizontally(int direction) override; Shared::InteractiveCurveViewRange * interactiveCurveViewRange() override; Shared::CurveView * curveView() override; bool handleEnter() override; @@ -43,7 +47,6 @@ private: // InteractiveCurveViewController void initRangeParameters() override; void initCursorParameters() override; - bool moveCursorVertically(int direction) override; uint32_t modelVersion() override; uint32_t rangeVersion() override; bool isCursorVisible() override; diff --git a/apps/regression/test/graph.cpp b/apps/regression/test/graph.cpp new file mode 100644 index 000000000..1162e3451 --- /dev/null +++ b/apps/regression/test/graph.cpp @@ -0,0 +1,176 @@ +#include +#include +#include +#include "../model/model.h" +#include "../graph_controller.h" +#include "../regression_context.h" +#include "../store.h" + +using namespace Poincare; +using namespace Regression; + +void load_in_store( + Regression::Store * store, + double * x0, double * y0, int numberOfPoints0, + double * x1 = nullptr, double * y1 = nullptr, int numberOfPoints1 = 0, + double * x2 = nullptr, double * y2 = nullptr, int numberOfPoints2 = 0) +{ + // Set the points and the regression type + if (numberOfPoints0 != 0 && x0 != nullptr && y0 != nullptr) { + for (int i = 0; i < numberOfPoints0; i++) { + store->set(x0[i], 0, 0, i); + store->set(y0[i], 0, 1, i); + } + } + if (numberOfPoints1 != 0 && x1 != nullptr && y1 != nullptr) { + for (int i = 0; i < numberOfPoints1; i++) { + store->set(x1[i], 1, 0, i); + store->set(y1[i], 1, 1, i); + } + } + if (numberOfPoints2 != 0 && x2 != nullptr && y2 != nullptr) { + for (int i = 0; i < numberOfPoints2; i++) { + store->set(x2[i], 2, 0, i); + store->set(y2[i], 2, 1, i); + } + } +} + +class NavigationEvent { +public: + enum class Direction { + Up, + Right, + Down, + Left + }; + NavigationEvent(Direction d, int series, int dot) : + direction(d), + expectedSelectedSeries(series), + expectedSelectedDot(dot) + {} + Direction direction; + int expectedSelectedSeries; + int expectedSelectedDot; +}; + +void assert_navigation_is( + int numberOfEvents, + NavigationEvent * events, + int startingDotSelection, + int startingSeriesSelection, + double * x0, double * y0, int numberOfPoints0, + double * x1 = nullptr, double * y1 = nullptr, int numberOfPoints1 = 0, + double * x2 = nullptr, double * y2 = nullptr, int numberOfPoints2 = 0) +{ + assert(startingDotSelection >= 0); + Store store; + Shared::CurveViewCursor cursor; + uint32_t dummy; + + int selectedDotIndex = startingDotSelection; + int selectedSeriesIndex = startingSeriesSelection; + + load_in_store(&store, x0, y0, numberOfPoints0, x1, y1, numberOfPoints1, x2, y2, numberOfPoints2); + + if (selectedDotIndex < store.numberOfPairsOfSeries(selectedSeriesIndex)) { + cursor.moveTo( + store.get(selectedSeriesIndex, 0, selectedDotIndex), + store.get(selectedSeriesIndex, 1, selectedDotIndex)); + } else { + cursor.moveTo( + store.meanOfColumn(selectedSeriesIndex, 0), + store.meanOfColumn(selectedSeriesIndex, 1)); + } + + AppsContainerStorage container; + // We do not really care about the snapshot + App app(&container, container.appSnapshotAtIndex(0)); + + GraphController graphController( + &app, &app, nullptr, + &store, + &cursor, + &dummy, &dummy, + &selectedDotIndex, + &selectedSeriesIndex); + + + for (int i = 0; i < numberOfEvents; i++) { + NavigationEvent event = events[i]; + if (event.direction == NavigationEvent::Direction::Up) { + graphController.moveCursorVertically(1); + } else if (event.direction == NavigationEvent::Direction::Right) { + graphController.moveCursorHorizontally(1); + } else if (event.direction == NavigationEvent::Direction::Down) { + graphController.moveCursorVertically(-1); + } else { + assert(event.direction == NavigationEvent::Direction::Left); + graphController.moveCursorHorizontally(-1); + } + quiz_assert(event.expectedSelectedDot == selectedDotIndex); + quiz_assert(event.expectedSelectedSeries == selectedSeriesIndex); + } +} + +QUIZ_CASE(regression_navigation_1) { + constexpr int numberOfPoints0 = 4; + double x0[numberOfPoints0] = {2.0, 3.0, 2.0, 1.0}; + double y0[numberOfPoints0] = {0.0, 1.0, 0.5, 5.0}; + + constexpr int numberOfPoints1 = 3; + double x1[numberOfPoints1] = {1.0, 10.0, 2.0}; + double y1[numberOfPoints1] = {0.0, 25.0, 0.5}; + + constexpr int numberOfEvents = 7; + NavigationEvent events[numberOfEvents] = { + NavigationEvent(NavigationEvent::Direction::Down, 0, -1), + NavigationEvent(NavigationEvent::Direction::Down, 0, 2), + NavigationEvent(NavigationEvent::Direction::Down, 1, 2), + NavigationEvent(NavigationEvent::Direction::Down, 0, 0), + NavigationEvent(NavigationEvent::Direction::Down, 1, 0), + NavigationEvent(NavigationEvent::Direction::Down, 1, -1), + NavigationEvent(NavigationEvent::Direction::Down, 1, -1) + }; + assert_navigation_is(numberOfEvents, events, numberOfPoints0, 0, x0, y0, numberOfPoints0, x1, y1, numberOfPoints1); +} + +QUIZ_CASE(regression_navigation_2) { + constexpr int numberOfPoints0 = 4; + double x0[numberOfPoints0] = {8.0, 9.0, 10.0, 10.0}; + double y0[numberOfPoints0] = {2.0, 5.0, 1.0, 2.0}; + + constexpr int numberOfPoints1 = 3; + double x1[numberOfPoints1] = {10.0, 12.0, 5.0}; + double y1[numberOfPoints1] = {2.0, 0.0, 8.0}; + + constexpr int numberOfEvents = 6; + NavigationEvent events[numberOfEvents] = { + /* FIXME + * Because of double computation error, the regression curve of the series 0 + * is above its mean point. + NavigationEvent(NavigationEvent::Direction::Down, 1, -1), + * */ + NavigationEvent(NavigationEvent::Direction::Down, 0, -1), + NavigationEvent(NavigationEvent::Direction::Down, 0, numberOfPoints0), + NavigationEvent(NavigationEvent::Direction::Down, 0, -1), + NavigationEvent(NavigationEvent::Direction::Down, 0, 3), + NavigationEvent(NavigationEvent::Direction::Down, 1, 0), + NavigationEvent(NavigationEvent::Direction::Down, 0, 2) + }; + assert_navigation_is(numberOfEvents, events, numberOfPoints1, 1, x0, y0, numberOfPoints0, x1, y1, numberOfPoints1); +} + +QUIZ_CASE(regression_navigation_3) { + constexpr int numberOfPoints = 4; + double x[numberOfPoints] = {1.0, 2.0, 3.0, 4.0}; + double y[numberOfPoints] = {2.0, 2.0, 2.0, 2.0}; + + constexpr int numberOfEvents = 3; + NavigationEvent events[numberOfEvents] = { + NavigationEvent(NavigationEvent::Direction::Down, 0, -1), + NavigationEvent(NavigationEvent::Direction::Down, 1, -1), + NavigationEvent(NavigationEvent::Direction::Down, 2, -1), + }; + assert_navigation_is(numberOfEvents, events, 2, 0, x, y, numberOfPoints, x, y, numberOfPoints, x, y, numberOfPoints); +}