mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-30 22:20:21 +00:00
Add simple test for the dive planner
This sets up a standard dive scenario (30 minutes at 260ft/79m, EAN36 and Oxygen as deco gases, last stop at 20ft/6m) and calls the planner to set up a dive plan given certain standard gases. Instead of trying to verify the complete plans it checks that we switch to the deco gases at the right depth and the complete duration of the dive matches our expectation. The test intentionally fails right now for imperial as we have the wrong switch depth for Oxygen. See how useful tests are? On the downside, the test does NOT produce the same plan as Subsurface when I try to create a consistent setup for both - and I have not been able to figure out why. There must be some other parameters that I'm not setting, but I haven't identified them, yet. It's very small differences, for example in the metric case the stops at 21m, 9m, and 6m are each one minute shorter in the test than it what Subsurface calculates. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
parent
17ef6774e0
commit
35dc814105
7 changed files with 148 additions and 2 deletions
|
@ -520,6 +520,7 @@ if(NOT NO_TESTS)
|
||||||
TEST(TestProfile testprofile.cpp)
|
TEST(TestProfile testprofile.cpp)
|
||||||
TEST(TestGpsCoords testgpscoords.cpp)
|
TEST(TestGpsCoords testgpscoords.cpp)
|
||||||
TEST(TestParse testparse.cpp)
|
TEST(TestParse testparse.cpp)
|
||||||
|
TEST(TestPlan testplan.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# install a few things so that one can run Subsurface from the build
|
# install a few things so that one can run Subsurface from the build
|
||||||
|
|
14
dive.c
14
dive.c
|
@ -3119,3 +3119,17 @@ void delete_current_divecomputer(void)
|
||||||
if (dc_number == count_divecomputers())
|
if (dc_number == count_divecomputers())
|
||||||
dc_number--;
|
dc_number--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* helper function to make it easier to work with our structures
|
||||||
|
* we don't interpolate here, just use the value from the last sample up to that time */
|
||||||
|
int get_depth_at_time(struct divecomputer *dc, int time)
|
||||||
|
{
|
||||||
|
int depth = 0;
|
||||||
|
if (dc && dc->sample)
|
||||||
|
for (int i = 0; i < dc->samples; i++) {
|
||||||
|
if (dc->sample[i].time.seconds > time)
|
||||||
|
break;
|
||||||
|
depth = dc->sample[i].depth.mm;
|
||||||
|
}
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
|
1
dive.h
1
dive.h
|
@ -393,6 +393,7 @@ extern timestamp_t picture_get_timestamp(char *filename);
|
||||||
extern void dive_set_geodata_from_picture(struct dive *d, struct picture *pic);
|
extern void dive_set_geodata_from_picture(struct dive *d, struct picture *pic);
|
||||||
|
|
||||||
extern int explicit_first_cylinder(struct dive *dive, struct divecomputer *dc);
|
extern int explicit_first_cylinder(struct dive *dive, struct divecomputer *dc);
|
||||||
|
extern int get_depth_at_time(struct divecomputer *dc, int time);
|
||||||
|
|
||||||
static inline int get_surface_pressure_in_mbar(const struct dive *dive, bool non_null)
|
static inline int get_surface_pressure_in_mbar(const struct dive *dive, bool non_null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -857,7 +857,6 @@ bool plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool
|
||||||
int bottom_depth;
|
int bottom_depth;
|
||||||
int bottom_gi;
|
int bottom_gi;
|
||||||
int bottom_stopidx;
|
int bottom_stopidx;
|
||||||
|
|
||||||
bool is_final_plan = true;
|
bool is_final_plan = true;
|
||||||
int deco_time;
|
int deco_time;
|
||||||
int previous_deco_time;
|
int previous_deco_time;
|
||||||
|
|
|
@ -11,7 +11,6 @@ extern "C" {
|
||||||
extern int validate_gas(const char *text, struct gasmix *gas);
|
extern int validate_gas(const char *text, struct gasmix *gas);
|
||||||
extern int validate_po2(const char *text, int *mbar_po2);
|
extern int validate_po2(const char *text, int *mbar_po2);
|
||||||
extern timestamp_t current_time_notz(void);
|
extern timestamp_t current_time_notz(void);
|
||||||
extern void show_planned_dive(char **error_string_p);
|
|
||||||
extern void set_last_stop(bool last_stop_6m);
|
extern void set_last_stop(bool last_stop_6m);
|
||||||
extern void set_verbatim(bool verbatim);
|
extern void set_verbatim(bool verbatim);
|
||||||
extern void set_display_runtime(bool display);
|
extern void set_display_runtime(bool display);
|
||||||
|
|
119
tests/testplan.cpp
Normal file
119
tests/testplan.cpp
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
#include "dive.h"
|
||||||
|
#include "testplan.h"
|
||||||
|
#include "planner.h"
|
||||||
|
#include "units.h"
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
// testing the dive plan algorithm
|
||||||
|
extern bool plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool show_disclaimer);
|
||||||
|
|
||||||
|
void setupPrefs()
|
||||||
|
{
|
||||||
|
prefs = default_prefs;
|
||||||
|
prefs.ascrate50 = feet_to_mm(30) / 60;
|
||||||
|
prefs.ascrate75 = prefs.ascrate50;
|
||||||
|
prefs.ascratestops = prefs.ascrate50;
|
||||||
|
prefs.ascratelast6m = feet_to_mm(10) / 60;
|
||||||
|
prefs.last_stop = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupPlan(struct diveplan *dp)
|
||||||
|
{
|
||||||
|
dp->salinity = 10030;
|
||||||
|
dp->surface_pressure = 1013;
|
||||||
|
dp->gfhigh = 100;
|
||||||
|
dp->gflow = 100;
|
||||||
|
dp->bottomsac = 0;
|
||||||
|
dp->decosac = 0;
|
||||||
|
|
||||||
|
struct gasmix bottomgas = { {150}, {450} };
|
||||||
|
struct gasmix ean36 = { {360}, {0} };
|
||||||
|
struct gasmix oxygen = { {1000}, {0} };
|
||||||
|
pressure_t po2 = { 1600 };
|
||||||
|
displayed_dive.cylinder[0].gasmix = bottomgas;
|
||||||
|
displayed_dive.cylinder[1].gasmix = ean36;
|
||||||
|
displayed_dive.cylinder[2].gasmix = oxygen;
|
||||||
|
reset_cylinders(&displayed_dive, true);
|
||||||
|
free_dps(dp);
|
||||||
|
|
||||||
|
int droptime = M_OR_FT(79, 260) * 60 / M_OR_FT(23, 75);
|
||||||
|
plan_add_segment(dp, droptime, M_OR_FT(79, 260), bottomgas, 0, 1);
|
||||||
|
plan_add_segment(dp, 30*60 - droptime, M_OR_FT(79, 260), bottomgas, 0, 1);
|
||||||
|
plan_add_segment(dp, 0, gas_mod(&ean36, po2, M_OR_FT(3,10)).mm, ean36, 0, 1);
|
||||||
|
plan_add_segment(dp, 0, gas_mod(&oxygen, po2, M_OR_FT(3,10)).mm, oxygen, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestPlan::testMetric()
|
||||||
|
{
|
||||||
|
char *cache = NULL;
|
||||||
|
|
||||||
|
setupPrefs();
|
||||||
|
prefs.unit_system = METRIC;
|
||||||
|
prefs.units.length = units::METERS;
|
||||||
|
prefs.deco_mode = BUEHLMANN;
|
||||||
|
|
||||||
|
struct diveplan testPlan = { 0 };
|
||||||
|
setupPlan(&testPlan);
|
||||||
|
|
||||||
|
plan(&testPlan, &cache, 1, 0);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
free(displayed_dive.notes);
|
||||||
|
displayed_dive.notes = NULL;
|
||||||
|
save_dive(stdout, &displayed_dive);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// check first gas change to EAN36 at 33m
|
||||||
|
struct event *ev = displayed_dive.dc.events;
|
||||||
|
QVERIFY(ev != NULL);
|
||||||
|
QCOMPARE(ev->gas.index, 1);
|
||||||
|
QCOMPARE(ev->value, 36);
|
||||||
|
QCOMPARE(get_depth_at_time(&displayed_dive.dc, ev->time.seconds), 33000);
|
||||||
|
// check second gas change to Oxygen at 6m
|
||||||
|
ev = ev->next;
|
||||||
|
QVERIFY(ev != NULL);
|
||||||
|
QCOMPARE(ev->gas.index, 2);
|
||||||
|
QCOMPARE(ev->value, 100);
|
||||||
|
QCOMPARE(get_depth_at_time(&displayed_dive.dc, ev->time.seconds), 6000);
|
||||||
|
// check expected run time of 105 minutes
|
||||||
|
QCOMPARE(displayed_dive.dc.duration.seconds, 104u * 60u);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestPlan::testImperial()
|
||||||
|
{
|
||||||
|
char *cache = NULL;
|
||||||
|
|
||||||
|
setupPrefs();
|
||||||
|
prefs.unit_system = IMPERIAL;
|
||||||
|
prefs.units.length = units::FEET;
|
||||||
|
prefs.deco_mode = BUEHLMANN;
|
||||||
|
|
||||||
|
struct diveplan testPlan = { 0 };
|
||||||
|
setupPlan(&testPlan);
|
||||||
|
|
||||||
|
plan(&testPlan, &cache, 1, 0);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
free(displayed_dive.notes);
|
||||||
|
displayed_dive.notes = NULL;
|
||||||
|
save_dive(stdout, &displayed_dive);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// check first gas change to EAN36 at 33m
|
||||||
|
struct event *ev = displayed_dive.dc.events;
|
||||||
|
QVERIFY(ev != NULL);
|
||||||
|
QCOMPARE(ev->gas.index, 1);
|
||||||
|
QCOMPARE(ev->value, 36);
|
||||||
|
QCOMPARE(get_depth_at_time(&displayed_dive.dc, ev->time.seconds), 33528);
|
||||||
|
// check second gas change to Oxygen at 6m
|
||||||
|
ev = ev->next;
|
||||||
|
QVERIFY(ev != NULL);
|
||||||
|
QCOMPARE(ev->gas.index, 2);
|
||||||
|
QCOMPARE(ev->value, 100);
|
||||||
|
QCOMPARE(get_depth_at_time(&displayed_dive.dc, ev->time.seconds), 6096);
|
||||||
|
// check expected run time of 105 minutes
|
||||||
|
QCOMPARE(displayed_dive.dc.duration.seconds, 105u * 60u);
|
||||||
|
}
|
||||||
|
|
||||||
|
QTEST_MAIN(TestPlan)
|
13
tests/testplan.h
Normal file
13
tests/testplan.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef TESTPLAN_H
|
||||||
|
#define TESTPLAN_H
|
||||||
|
|
||||||
|
#include <QTest>
|
||||||
|
|
||||||
|
class TestPlan : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
private slots:
|
||||||
|
void testImperial();
|
||||||
|
void testMetric();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TESTPLAN_H
|
Loading…
Reference in a new issue