TraDemGen Logo  1.00.3
C++ Simulated Travel Demand Generation Library
DemandGenerationTestSuite.cpp
Go to the documentation of this file.
1 
5 // //////////////////////////////////////////////////////////////////////
6 // Import section
7 // //////////////////////////////////////////////////////////////////////
8 // STL
9 #include <sstream>
10 #include <fstream>
11 #include <map>
12 #include <cmath>
13 // Boost Unit Test Framework (UTF)
14 #define BOOST_TEST_DYN_LINK
15 #define BOOST_TEST_MAIN
16 #define BOOST_TEST_MODULE DemandGenerationTest
17 #include <boost/test/unit_test.hpp>
18 // StdAir
19 #include <stdair/stdair_basic_types.hpp>
20 #include <stdair/basic/BasConst_General.hpp>
21 #include <stdair/basic/BasLogParams.hpp>
22 #include <stdair/basic/BasDBParams.hpp>
23 #include <stdair/basic/BasFileMgr.hpp>
24 #include <stdair/basic/ProgressStatusSet.hpp>
25 #include <stdair/bom/EventStruct.hpp>
26 #include <stdair/bom/BookingRequestStruct.hpp>
27 #include <stdair/service/Logger.hpp>
28 // TraDemGen
33 
34 namespace boost_utf = boost::unit_test;
35 
36 // (Boost) Unit Test XML Report
37 std::ofstream utfReportStream ("DemandGenerationTestSuite_utfresults.xml");
38 
42 struct UnitTestConfig {
44  UnitTestConfig() {
45  boost_utf::unit_test_log.set_stream (utfReportStream);
46 #if defined(BOOST_VERSION) && BOOST_VERSION >= 105900
47  boost_utf::unit_test_log.set_format (boost_utf::OF_XML);
48 #else // BOOST_VERSION
49  boost_utf::unit_test_log.set_format (boost_utf::XML);
50 #endif // BOOST_VERSION
51  boost_utf::unit_test_log.set_threshold_level (boost_utf::log_test_units);
52  //boost_utf::unit_test_log.set_threshold_level (boost_utf::log_successful_tests);
53  }
54 
56  ~UnitTestConfig() {
57  }
58 };
59 
60 // Specific type definitions
61 typedef std::pair<stdair::Count_T, stdair::Count_T> NbOfEventsPair_T;
62 typedef std::map<const stdair::DemandStreamKeyStr_T,
63  NbOfEventsPair_T> NbOfEventsByDemandStreamMap_T;
64 
65 // //////////////////////////////////////////////////////////////////////
69 void testDemandGenerationHelper (const unsigned short iTestFlag,
70  const stdair::Filename_T& iDemandInputFilename,
71  const stdair::DemandGenerationMethod& iDemandGenerationMethod,
72  const bool isBuiltin) {
73 
74  // Seed for the random generation
75  const stdair::RandomSeed_T lRandomSeed = stdair::DEFAULT_RANDOM_SEED;
76 
77  // Output log File
78  std::ostringstream oStr;
79  oStr << "DemandGenerationTestSuite_" << iTestFlag << ".log";
80  const stdair::Filename_T lLogFilename (oStr.str());
81 
82  // Set the log parameters
83  std::ofstream logOutputFile;
84  // Open and clean the log outputfile
85  logOutputFile.open (lLogFilename.c_str());
86  logOutputFile.clear();
87 
88  // Initialise the TraDemGen service object
89  const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
90  TRADEMGEN::TRADEMGEN_Service trademgenService (lLogParams, lRandomSeed);
91 
101  NbOfEventsByDemandStreamMap_T lNbOfEventsMap;
102 
103  // Total number of events
104  stdair::Count_T lRefExpectedNbOfEvents (0);
105  stdair::Count_T lRefActualNbOfEvents (0);
106 
107  // Check whether or not a (CSV) input file should be read
108  if (isBuiltin == true) {
109 
110  // Build the default sample BOM tree (filled with demand streams) for TraDemGen
111  trademgenService.buildSampleBom();
112 
113  lNbOfEventsMap.insert (NbOfEventsByDemandStreamMap_T::
114  value_type ("SIN-BKK 2010-Feb-08 Y",
115  NbOfEventsPair_T (4, 60)));
116  lNbOfEventsMap.insert (NbOfEventsByDemandStreamMap_T::
117  value_type ("BKK-HKG 2010-Feb-08 Y",
118  NbOfEventsPair_T (4, 60)));
119  lNbOfEventsMap.insert (NbOfEventsByDemandStreamMap_T::
120  value_type ("SIN-HKG 2010-Feb-08 Y",
121  NbOfEventsPair_T (4, 60)));
122 
123  // Total number of events, for the 3 demand streams: 180
124  lRefExpectedNbOfEvents = 180;
125  lRefActualNbOfEvents = 186;
126 
127  } else {
128 
129  // Create the DemandStream objects, and insert them within the BOM tree
130  const TRADEMGEN::DemandFilePath lDemandFilePath (iDemandInputFilename);
131  trademgenService.parseAndLoad (lDemandFilePath);
132 
133  lNbOfEventsMap.insert (NbOfEventsByDemandStreamMap_T::
134  value_type ("SIN-HND 2010-Feb-08 Y",
135  NbOfEventsPair_T (1, 10)));
136  lNbOfEventsMap.insert (NbOfEventsByDemandStreamMap_T::
137  value_type ("SIN-HND 2010-Feb-09 Y",
138  NbOfEventsPair_T (1, 10)));
139  lNbOfEventsMap.insert (NbOfEventsByDemandStreamMap_T::
140  value_type ("SIN-BKK 2010-Feb-08 Y",
141  NbOfEventsPair_T (1, 10)));
142  lNbOfEventsMap.insert (NbOfEventsByDemandStreamMap_T::
143  value_type ("SIN-BKK 2010-Feb-09 Y",
144  NbOfEventsPair_T (1, 10)));
145 
146  // Total number of events, for the 4 demand streams: 40
147  lRefExpectedNbOfEvents = 40;
148  lRefActualNbOfEvents = 40;
149  }
150 
151  // Retrieve the expected (mean value of the) number of events to be
152  // generated
153  const stdair::Count_T& lExpectedNbOfEventsToBeGenerated =
154  trademgenService.getExpectedTotalNumberOfRequestsToBeGenerated();
155 
156  BOOST_CHECK_EQUAL (lRefExpectedNbOfEvents,
157  std::floor (lExpectedNbOfEventsToBeGenerated));
158 
159  BOOST_CHECK_MESSAGE (lRefExpectedNbOfEvents ==
160  std::floor (lExpectedNbOfEventsToBeGenerated),
161  "Expected total number of requests to be generated: "
162  << lExpectedNbOfEventsToBeGenerated
163  << " (=> "
164  << std::floor (lExpectedNbOfEventsToBeGenerated)
165  << "). Reference value: " << lRefExpectedNbOfEvents);
166 
172  const stdair::Count_T& lActualNbOfEventsToBeGenerated =
173  trademgenService.generateFirstRequests(iDemandGenerationMethod);
174 
175  // DEBUG
176  STDAIR_LOG_DEBUG ("Expected number of events: "
177  << lExpectedNbOfEventsToBeGenerated << ", actual: "
178  << lActualNbOfEventsToBeGenerated);
179 
180  // Total number of events, for all the demand streams:
181  BOOST_CHECK_GE (lRefActualNbOfEvents, lActualNbOfEventsToBeGenerated - 10.0);
182  BOOST_CHECK_LE (lRefActualNbOfEvents, lActualNbOfEventsToBeGenerated + 10.0);
183 
184  BOOST_CHECK_MESSAGE (lRefActualNbOfEvents<=lActualNbOfEventsToBeGenerated+10.0
185  &&lRefActualNbOfEvents>=lActualNbOfEventsToBeGenerated-10.0,
186  "Actual total number of requests to be generated: "
187  << lExpectedNbOfEventsToBeGenerated
188  << " (=> "
189  << std::floor (lExpectedNbOfEventsToBeGenerated)
190  << "). Reference value: " << lRefActualNbOfEvents);
191 
193  const bool isQueueDone = trademgenService.isQueueDone();
194  BOOST_REQUIRE_MESSAGE (isQueueDone == false,
195  "The event queue should not be empty.");
196 
204  stdair::Count_T idx = 1;
205  while (trademgenService.isQueueDone() == false) {
206 
207  // Get the next event from the event queue
208  stdair::EventStruct lEventStruct;
209  stdair::ProgressStatusSet lPPS = trademgenService.popEvent (lEventStruct);
210 
211  // DEBUG
212  STDAIR_LOG_DEBUG ("Poped event: '" << lEventStruct.describe() << "'.");
213 
214  // Extract the corresponding demand/booking request
215  const stdair::BookingRequestStruct& lPoppedRequest =
216  lEventStruct.getBookingRequest();
217 
218  // DEBUG
219  STDAIR_LOG_DEBUG ("Poped booking request: '"
220  << lPoppedRequest.describe() << "'.");
221 
222  // Retrieve the corresponding demand stream
223  const stdair::DemandGeneratorKey_T& lDemandStreamKey =
224  lPoppedRequest.getDemandGeneratorKey();
225 
226  // Check that the number of booking requests to be generated are correct
227  const NbOfEventsByDemandStreamMap_T::iterator itNbOfEventsMap =
228  lNbOfEventsMap.find (lDemandStreamKey);
229  BOOST_REQUIRE_MESSAGE (itNbOfEventsMap != lNbOfEventsMap.end(),
230  "The demand stream key '" << lDemandStreamKey
231  << "' is not expected in that test");
232 
242  const NbOfEventsPair_T& lNbOfEventsPair = itNbOfEventsMap->second;
243  stdair::Count_T lCurrentNbOfEvents = lNbOfEventsPair.first;
244  const stdair::Count_T& lExpectedTotalNbOfEvents = lNbOfEventsPair.second;
245 
246  // Assess whether more events should be generated for that demand stream
247  const bool stillHavingRequestsToBeGenerated = trademgenService.
248  stillHavingRequestsToBeGenerated (lDemandStreamKey, lPPS,
249  iDemandGenerationMethod);
250 
257  if (lCurrentNbOfEvents == 1) {
263  const stdair::ProgressStatus& lDemandStreamProgressStatus =
264  lPPS.getSpecificGeneratorStatus();
265  const stdair::Count_T& lNbOfRequests =
266  lDemandStreamProgressStatus.getExpectedNb();
267 
268  BOOST_CHECK_EQUAL (lNbOfRequests, lExpectedTotalNbOfEvents);
269  BOOST_CHECK_MESSAGE (lNbOfRequests == lExpectedTotalNbOfEvents,
270  "[" << lDemandStreamKey
271  << "] Total number of requests to be generated: "
272  << lNbOfRequests << "). Expected value: "
273  << lExpectedTotalNbOfEvents);
274  }
275 
276  // DEBUG
277  STDAIR_LOG_DEBUG ("=> [" << lDemandStreamKey << "][" << lCurrentNbOfEvents
278  << "/" << lExpectedTotalNbOfEvents
279  << "] is now processed. "
280  << "Still generate events for that demand stream? "
281  << stillHavingRequestsToBeGenerated);
282 
283  // If there are still events to be generated for that demand stream,
284  // generate and add them to the event queue
285  if (stillHavingRequestsToBeGenerated == true) {
286  const stdair::BookingRequestPtr_T lNextRequest_ptr =
287  trademgenService.generateNextRequest (lDemandStreamKey,
288  iDemandGenerationMethod);
289  assert (lNextRequest_ptr != NULL);
290 
296  const stdair::Duration_T lDuration =
297  lNextRequest_ptr->getRequestDateTime()
298  - lPoppedRequest.getRequestDateTime();
299  BOOST_REQUIRE_GT (lDuration.total_milliseconds(), 0);
300  BOOST_REQUIRE_MESSAGE (lDuration.total_milliseconds() > 0,
301  "[" << lDemandStreamKey
302  << "] The date-time of the generated event ("
303  << lNextRequest_ptr->getRequestDateTime()
304  << ") is lower than the date-time "
305  << "of the current event ("
306  << lPoppedRequest.getRequestDateTime() << ")");
307 
308  // DEBUG
309  STDAIR_LOG_DEBUG ("[" << lDemandStreamKey << "][" << lCurrentNbOfEvents
310  << "/" << lExpectedTotalNbOfEvents
311  << "] Added request: '" << lNextRequest_ptr->describe()
312  << "'. Is queue done? "
313  << trademgenService.isQueueDone());
314 
315  // Keep, within the dedicated map, the current counters of events updated.
316  ++lCurrentNbOfEvents;
317  itNbOfEventsMap->second = NbOfEventsPair_T (lCurrentNbOfEvents,
318  lExpectedTotalNbOfEvents);
319  }
320 
321  // Iterate
322  ++idx;
323  }
324  // Compensate for the last iteration
325  --idx;
326 
327  if (iDemandGenerationMethod == stdair::DemandGenerationMethod::STA_ORD) {
328  //
329  BOOST_CHECK_GE (idx, lRefActualNbOfEvents - 10.0);
330  BOOST_CHECK_LE (idx, lRefActualNbOfEvents + 10.0);
331  BOOST_CHECK_MESSAGE (idx >= lRefActualNbOfEvents - 10.0
332  && idx <= lRefActualNbOfEvents + 10.0,
333  "The total actual number of events is "
334  << lRefActualNbOfEvents << ", but " << idx
335  << " events have been generated");
336  }
337 
340  trademgenService.reset();
341 
342  // DEBUG
343  STDAIR_LOG_DEBUG ("End of the simulation");
344 
345  // Close the log file
346  logOutputFile.close();
347 
348 }
349 
350 
351 // /////////////// Main: Unit Test Suite //////////////
352 
353 // Set the UTF configuration (re-direct the output to a specific file)
354 BOOST_GLOBAL_FIXTURE (UnitTestConfig);
355 
356 // Start the test suite
357 BOOST_AUTO_TEST_SUITE (master_test_suite)
358 
359 
362 BOOST_AUTO_TEST_CASE (trademgen_simple_simulation_test) {
363 
364  // Input file name
365  const stdair::Filename_T lInputFilename (STDAIR_SAMPLE_DIR "/demand01.csv");
366 
367  // Generate the date time of the requests with the statistic order method.
368  const stdair::DemandGenerationMethod lDemandGenerationMethod (stdair::DemandGenerationMethod::STA_ORD);
369 
370  // State whether the BOM tree should be built-in or parsed from an input file
371  const bool isBuiltin = false;
372  BOOST_CHECK_NO_THROW (testDemandGenerationHelper(0,
373  lInputFilename,
374  lDemandGenerationMethod,
375  isBuiltin));
376 
377 }
378 
382 BOOST_AUTO_TEST_CASE (trademgen_missing_input_file_test) {
383 
384  // Input file name
385  const stdair::Filename_T lInputFilename (STDAIR_SAMPLE_DIR "/missingFile.csv");
386 
387  // Generate the date time of the requests with the statistic order method.
388  const stdair::DemandGenerationMethod lDemandGenerationMethod (stdair::DemandGenerationMethod::STA_ORD);
389 
390  // State whether the BOM tree should be built-in or parsed from an input file
391  const bool isBuiltin = false;
392  BOOST_CHECK_THROW (testDemandGenerationHelper(1,
393  lInputFilename,
394  lDemandGenerationMethod,
395  isBuiltin),
397 
398 }
399 
403 BOOST_AUTO_TEST_CASE (trademgen_default_bom_simulation_test) {
404 
405  // Generate the date time of the requests with the statistic order method.
406  const stdair::DemandGenerationMethod lDemandGenerationMethod (stdair::DemandGenerationMethod::STA_ORD);
407 
408  // State whether the BOM tree should be built-in or parsed from an input file
409  const bool isBuiltin = true;
410  BOOST_CHECK_NO_THROW (testDemandGenerationHelper(2,
411  " " ,
412  lDemandGenerationMethod,
413  isBuiltin));
414 
415 }
416 
420 BOOST_AUTO_TEST_CASE (trademgen_poisson_process_test) {
421 
422  // Generate the date time of the requests with the poisson process.
423  const stdair::DemandGenerationMethod lDemandGenerationMethod (stdair::DemandGenerationMethod::POI_PRO);
424 
425  // State whether the BOM tree should be built-in or parsed from an input file
426  const bool isBuiltin = true;
427  BOOST_CHECK_NO_THROW (testDemandGenerationHelper(3,
428  " " ,
429  lDemandGenerationMethod,
430  isBuiltin));
431 
432 }
433 
434 // End the test suite
435 BOOST_AUTO_TEST_SUITE_END()
436 
437 
#define STDAIR_SAMPLE_DIR
class holding the services related to Travel Demand Generation.