Skip to content

Commit c1f7e67

Browse files
committed
feat: flow measures can have description
1 parent a3fcf8b commit c1f7e67

5 files changed

Lines changed: 238 additions & 0 deletions

File tree

include/ECFMP/flowmeasure/Measure.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,5 +73,10 @@ namespace ECFMP::FlowMeasure {
7373
* Throws an IllegalFlowMeasureValueException exception otherwise.
7474
*/
7575
[[nodiscard]] virtual auto SetValue() const -> const std::set<std::string>& = 0;
76+
77+
/**
78+
* Returns a string representation of the measure.
79+
*/
80+
[[nodiscard]] virtual auto MeasureDescription() const noexcept -> std::string = 0;
7681
};
7782
}// namespace ECFMP::FlowMeasure

include/mock/MeasureMock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace ECFMP::Mock::FlowMeasure {
1111
MOCK_METHOD(int, IntegerValue, (), (const, override));
1212
MOCK_METHOD(double, DoubleValue, (), (const, override));
1313
MOCK_METHOD(const std::set<std::string>&, SetValue, (), (const, override));
14+
MOCK_METHOD(std::string, MeasureDescription, (), (const, noexcept, override));
1415
};
1516

1617
}// namespace ECFMP::Mock::FlowMeasure

src/flowmeasure/ConcreteMeasure.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
#include "ConcreteMeasure.h"
2+
#include "ECFMP/flowmeasure/Measure.h"
3+
#include <stdexcept>
4+
#include <string>
25

36
namespace ECFMP::FlowMeasure {
47

@@ -49,4 +52,89 @@ namespace ECFMP::FlowMeasure {
4952
throw IllegalFlowMeasureValueException();
5053
}
5154
}
55+
56+
auto ConcreteMeasure::MeasureDescription() const noexcept -> std::string
57+
{
58+
// No value type associated with these
59+
if (type == MeasureType::GroundStop || type == MeasureType::Prohibit) {
60+
return MeasureTypeToString(type);
61+
}
62+
63+
return MeasureTypeToString(type) + ": " + MeasureValueToString(type);
64+
}
65+
66+
auto ConcreteMeasure::MeasureTypeToString(MeasureType type) -> std::string
67+
{
68+
switch (type) {
69+
case MeasureType::MinimumDepartureInterval:
70+
return "Minimum Departure Interval";
71+
case MeasureType::AverageDepartureInterval:
72+
return "Average Departure Interval";
73+
case MeasureType::PerHour:
74+
return "Per Hour";
75+
case MeasureType::MilesInTrail:
76+
return "Miles in Trail";
77+
case MeasureType::MaxIndicatedAirspeed:
78+
return "Max IAS";
79+
case MeasureType::IndicatedAirspeedReduction:
80+
return "IAS Reduction";
81+
case MeasureType::MaxMach:
82+
return "Max Mach";
83+
case MeasureType::MachReduction:
84+
return "Mach Reduction";
85+
case MeasureType::MandatoryRoute:
86+
return "Mandatory Route(s)";
87+
case MeasureType::Prohibit:
88+
return "Prohibit";
89+
case MeasureType::GroundStop:
90+
return "Ground Stop";
91+
default:
92+
return "Unknown";
93+
}
94+
}
95+
96+
auto ConcreteMeasure::MeasureValueToString(MeasureType measureType) const -> std::string
97+
{
98+
switch (measureType) {
99+
case MeasureType::MinimumDepartureInterval:
100+
case MeasureType::AverageDepartureInterval: {
101+
const auto extraSeconds = intValue % 60;
102+
const auto minutes = intValue / 60;
103+
104+
if (minutes == 0) {
105+
return std::to_string(extraSeconds) + " seconds";
106+
}
107+
108+
if (extraSeconds == 0) {
109+
return std::to_string(minutes) + " minutes";
110+
}
111+
112+
return std::to_string(minutes) + " minutes " + std::to_string(extraSeconds) + " seconds";
113+
}
114+
case MeasureType::PerHour:
115+
case MeasureType::MilesInTrail:
116+
return std::to_string(intValue);
117+
case MeasureType::MaxIndicatedAirspeed:
118+
case MeasureType::IndicatedAirspeedReduction:
119+
return std::to_string(intValue) + "kts";
120+
case MeasureType::MaxMach:
121+
case MeasureType::MachReduction: {
122+
std::stringstream stream;
123+
stream << std::fixed << std::setprecision(2) << doubleValue;
124+
return stream.str();
125+
}
126+
case MeasureType::MandatoryRoute: {
127+
std::string routeString;
128+
for (const auto& route: setValue) {
129+
routeString += route + ", ";
130+
}
131+
return routeString.substr(0, routeString.size() - 2);
132+
}
133+
case MeasureType::Prohibit:
134+
case MeasureType::GroundStop:
135+
throw std::logic_error("MeasureType::Prohibit and MeasureType::GroundStop have no value");
136+
}
137+
138+
return "Unknown";
139+
}
52140
}// namespace ECFMP::FlowMeasure

src/flowmeasure/ConcreteMeasure.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@ namespace ECFMP::FlowMeasure {
2323
[[nodiscard]] auto IntegerValue() const -> int override;
2424
[[nodiscard]] auto DoubleValue() const -> double override;
2525
[[nodiscard]] auto SetValue() const -> const std::set<std::string>& override;
26+
[[nodiscard]] auto MeasureDescription() const noexcept -> std::string override;
2627

2728
private:
29+
[[nodiscard]] static auto MeasureTypeToString(MeasureType type) -> std::string;
30+
[[nodiscard]] auto MeasureValueToString(MeasureType type) const -> std::string;
2831
inline void AssertMeasureType(MeasureValueType allowedType) const;
2932

3033
// Type of the measure

test/flowmeasure/ConcreteMeasureTest.cpp

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "flowmeasure/ConcreteMeasure.h"
2+
#include "ECFMP/flowmeasure/FlowMeasure.h"
23
#include "flowmeasure/ConcreteMeasureFactory.h"
34

45
namespace ECFMPTest::FlowMeasure {
@@ -173,4 +174,144 @@ namespace ECFMPTest::FlowMeasure {
173174
return "type_" + std::to_string((int) info.param.measureType);
174175
}
175176
);
177+
178+
struct ConcreteMeasureDescriptionTestCase {
179+
// Test description
180+
std::string testDescription;
181+
182+
// The type of measure
183+
std::function<ECFMP::FlowMeasure::ConcreteMeasure()> measureGenerator;
184+
185+
// The expected description
186+
std::string expectedDescription;
187+
};
188+
189+
class ConcreteMeasureDescriptionTest : public testing::TestWithParam<ConcreteMeasureDescriptionTestCase>
190+
{
191+
public:
192+
};
193+
194+
TEST_P(ConcreteMeasureDescriptionTest, ItHasAnAppropriateDescription)
195+
{
196+
auto measure = GetParam().measureGenerator();
197+
EXPECT_EQ(GetParam().expectedDescription, measure.MeasureDescription());
198+
}
199+
200+
INSTANTIATE_TEST_SUITE_P(
201+
ConcreteMeasureDescriptionTestCases, ConcreteMeasureDescriptionTest,
202+
testing::Values(
203+
ConcreteMeasureDescriptionTestCase{
204+
"minimum_departure_interval_seconds_only",
205+
[]() {
206+
return ECFMP::FlowMeasure::MinimumDepartureInterval(5);
207+
},
208+
"Minimum Departure Interval: 5 seconds"},
209+
ConcreteMeasureDescriptionTestCase{
210+
"minimum_departure_interval_minutes_only",
211+
[]() {
212+
return ECFMP::FlowMeasure::MinimumDepartureInterval(300);
213+
},
214+
"Minimum Departure Interval: 5 minutes"},
215+
ConcreteMeasureDescriptionTestCase{
216+
"minimum_departure_interval_minutes_and_seconds",
217+
[]() {
218+
return ECFMP::FlowMeasure::MinimumDepartureInterval(305);
219+
},
220+
"Minimum Departure Interval: 5 minutes 5 seconds"},
221+
ConcreteMeasureDescriptionTestCase{
222+
"average_departure_interval_seconds_only",
223+
[]() {
224+
return ECFMP::FlowMeasure::AverageDepartureInterval(5);
225+
},
226+
"Average Departure Interval: 5 seconds"},
227+
ConcreteMeasureDescriptionTestCase{
228+
"average_departure_interval_minutes_only",
229+
[]() {
230+
return ECFMP::FlowMeasure::AverageDepartureInterval(300);
231+
},
232+
"Average Departure Interval: 5 minutes"},
233+
ConcreteMeasureDescriptionTestCase{
234+
"average_departure_interval_minutes_and_seconds",
235+
[]() {
236+
return ECFMP::FlowMeasure::AverageDepartureInterval(305);
237+
},
238+
"Average Departure Interval: 5 minutes 5 seconds"},
239+
ConcreteMeasureDescriptionTestCase{
240+
"per_hour",
241+
[]() {
242+
return ECFMP::FlowMeasure::PerHour(5);
243+
},
244+
"Per Hour: 5"},
245+
ConcreteMeasureDescriptionTestCase{
246+
"miles_in_trail",
247+
[]() {
248+
return ECFMP::FlowMeasure::MilesInTrail(5);
249+
},
250+
"Miles in Trail: 5"},
251+
// Max ias
252+
ConcreteMeasureDescriptionTestCase{
253+
"max_ias",
254+
[]() {
255+
return ECFMP::FlowMeasure::MaxIndicatedAirspeed(5);
256+
},
257+
"Max IAS: 5kts"},
258+
ConcreteMeasureDescriptionTestCase{
259+
"ias_reduction",
260+
[]() {
261+
return ECFMP::FlowMeasure::IndicatedAirspeedReduction(5);
262+
},
263+
"IAS Reduction: 5kts"},
264+
ConcreteMeasureDescriptionTestCase{
265+
"max_mach",
266+
[]() {
267+
return ECFMP::FlowMeasure::MaxMach(0.89123);
268+
},
269+
"Max Mach: 0.89"},
270+
ConcreteMeasureDescriptionTestCase{
271+
"mach_reduction",
272+
[]() {
273+
return ECFMP::FlowMeasure::MachReduction(0.89123);
274+
},
275+
"Mach Reduction: 0.89"},
276+
ConcreteMeasureDescriptionTestCase{
277+
"mandatory_route",
278+
[]() {
279+
return ECFMP::FlowMeasure::MandatoryRoute(std::set<std::string>({"foo boo", "bar"}));
280+
},
281+
"Mandatory Route(s): bar, foo boo"},
282+
ConcreteMeasureDescriptionTestCase{
283+
"mandatory_route_empty",
284+
[]() {
285+
return ECFMP::FlowMeasure::MandatoryRoute(std::set<std::string>());
286+
},
287+
"Mandatory Route(s): "},
288+
ConcreteMeasureDescriptionTestCase{
289+
"mandatory_route_single",
290+
[]() {
291+
return ECFMP::FlowMeasure::MandatoryRoute(std::set<std::string>({"foo boo"}));
292+
},
293+
"Mandatory Route(s): foo boo"},
294+
ConcreteMeasureDescriptionTestCase{
295+
"mandatory_route_single_empty",
296+
[]() {
297+
return ECFMP::FlowMeasure::MandatoryRoute(std::set<std::string>({" "}));
298+
},
299+
"Mandatory Route(s): "},
300+
ConcreteMeasureDescriptionTestCase{
301+
"prohibit",
302+
[]() {
303+
return ECFMP::FlowMeasure::Prohibit();
304+
},
305+
"Prohibit"},
306+
ConcreteMeasureDescriptionTestCase{
307+
"ground_stop",
308+
[]() {
309+
return ECFMP::FlowMeasure::GroundStop();
310+
},
311+
"Ground Stop"}
312+
),
313+
[](const ::testing::TestParamInfo<ConcreteMeasureDescriptionTest::ParamType>& info) {
314+
return info.param.testDescription;
315+
}
316+
);
176317
}// namespace ECFMPTest::FlowMeasure

0 commit comments

Comments
 (0)