Fixing bug in Schedule:solve problems when black repetitive interval list is empty

Change-Id: I508c47cf014700bd1ee01eec4e97cd9bc05e83a7
diff --git a/src/schedule.cpp b/src/schedule.cpp
index ac68bdd..b16cb6d 100644
--- a/src/schedule.cpp
+++ b/src/schedule.cpp
@@ -28,6 +28,34 @@
 namespace ndn {
 namespace gep {
 
+/**
+ * @brief Helper functon to calculate black interval results or white interval results
+ * @p list The RepetitiveInterval list, which can be white list or the black list
+ * @p tp The timestamp
+ * @p positiveR The positive result
+ * @p negativeR The negative result
+ */
+static void
+calIntervalResult(const std::set<RepetitiveInterval>& list, const TimeStamp& ts,
+                  Interval& positiveR, Interval& negativeR)
+{
+  Interval tempInterval;
+  bool isPositive;
+
+  for (const RepetitiveInterval& element : list) {
+    std::tie(isPositive, tempInterval) = element.getInterval(ts);
+    if (isPositive == true) {
+      positiveR || tempInterval;
+    }
+    else {
+      if (!negativeR.isValid())
+        negativeR = tempInterval;
+      else
+        negativeR && tempInterval;
+    }
+  }
+}
+
 BOOST_CONCEPT_ASSERT((WireEncodable<Schedule>));
 BOOST_CONCEPT_ASSERT((WireDecodable<Schedule>));
 
@@ -139,7 +167,7 @@
 }
 
 std::tuple<bool, Interval>
-Schedule::getCoveringInterval(const TimeStamp& tp) const
+Schedule::getCoveringInterval(const TimeStamp& ts) const
 {
   Interval blackPositiveResult(true);
   Interval whitePositiveResult(true);
@@ -147,58 +175,38 @@
   Interval blackNegativeResult;
   Interval whiteNegativeResult;
 
-  Interval tempInterval;
-  bool isPositive;
-
   // get the blackResult
-  for (const RepetitiveInterval& element : m_blackIntervalList) {
-    std::tie(isPositive, tempInterval) = element.getInterval(tp);
-    if (isPositive == true) {
-      // tempInterval is covering the time stamp, || to the black negative result
-      // get the union interval of all the black interval covering the timestamp
-      // return false and the union interval
-      blackPositiveResult || tempInterval;
-    }
-    else {
-      // tempInterval is not covering the time stamp, && to the black positive result
-      // get the intersection interval of all the black interval not covering the timestamp
-      // return true if white positive result is not empty, false if white positive result is empty
-      if (!blackNegativeResult.isValid())
-        blackNegativeResult = tempInterval;
-      else
-        blackNegativeResult && tempInterval;
-    }
-  }
+  calIntervalResult(m_blackIntervalList, ts,
+                    blackPositiveResult, blackNegativeResult);
 
-  // if black positive result is not full, the result must be false
+  // if black positive result is not empty, the result must be false
   if (!blackPositiveResult.isEmpty())
     return std::make_tuple(false, blackPositiveResult);
 
   // get the whiteResult
-  for (const RepetitiveInterval& element : m_whiteIntervalList) {
-    std::tie(isPositive, tempInterval) = element.getInterval(tp);
-    if (isPositive == true) {
-      // tempInterval is covering the time stamp, || to the white positive result
-      // get the union interval of all the white interval covering the timestamp
-      // return true
-      whitePositiveResult || tempInterval;
-    }
-    else {
-      // tempInterval is not covering the time, && to the white negative result
-      // get the intersection of all the white interval not covering the timestamp
-      // return false if positive result is empty, return true if positive result is not empty
-      if (!whiteNegativeResult.isValid())
-        whiteNegativeResult = tempInterval;
-      else
-        whiteNegativeResult && tempInterval;
-    }
+  calIntervalResult(m_whiteIntervalList, ts,
+                    whitePositiveResult, whiteNegativeResult);
+
+  if (whitePositiveResult.isEmpty() && !whiteNegativeResult.isValid()) {
+    // there is no white interval covering the timestamp
+    // return false and a 24-hour interval
+    return std::make_tuple(false, Interval(TimeStamp(ts.date(), boost::posix_time::hours(0)),
+                                           TimeStamp(ts.date(), boost::posix_time::hours(24))));
   }
 
-  // return false if positive result is empty, return true if positive result is not empty
-  if (!whitePositiveResult.isEmpty())
-    return std::make_tuple(true, whitePositiveResult && blackNegativeResult);
-  else
+  if (!whitePositiveResult.isEmpty()) {
+    // there is white interval covering the timestamp
+    // return ture and calculate the intersection
+    if (blackNegativeResult.isValid())
+      return std::make_tuple(true, whitePositiveResult && blackNegativeResult);
+    else
+      return std::make_tuple(true, whitePositiveResult);
+  }
+  else {
+    // there is no white interval covering the timestamp
+    // return false
     return std::make_tuple(false, whiteNegativeResult);
+  }
 }
 
 } // namespace gep
diff --git a/tests/unit-tests/schedule.t.cpp b/tests/unit-tests/schedule.t.cpp
index 22f2a10..0fb6c3f 100644
--- a/tests/unit-tests/schedule.t.cpp
+++ b/tests/unit-tests/schedule.t.cpp
@@ -30,10 +30,9 @@
 
 BOOST_AUTO_TEST_SUITE(TestSchedule)
 
-BOOST_AUTO_TEST_CASE(CalculateCoveringInterval)
+BOOST_AUTO_TEST_CASE(CalIntervalWithBlackAndWhite)
 {
   Schedule schedule;
-
   RepetitiveInterval interval1(from_iso_string("20150825T000000"),
                                from_iso_string("20150827T000000"),
                                5, 10, 2, RepetitiveInterval::RepeatUnit::DAY);
@@ -100,6 +99,97 @@
   BOOST_CHECK_EQUAL(to_iso_string(resultInterval.getEndTime()), "20150826T000000");
 }
 
+BOOST_AUTO_TEST_CASE(CalIntervalWithoutBlack)
+{
+  Schedule schedule;
+  RepetitiveInterval interval1(from_iso_string("20150825T000000"),
+                               from_iso_string("20150827T000000"),
+                               5, 10, 2, RepetitiveInterval::RepeatUnit::DAY);
+  RepetitiveInterval interval2(from_iso_string("20150825T000000"),
+                               from_iso_string("20150827T000000"),
+                               6, 8, 1, RepetitiveInterval::RepeatUnit::DAY);
+  RepetitiveInterval interval3(from_iso_string("20150825T000000"),
+                               from_iso_string("20150825T000000"),
+                               4, 7);
+
+  schedule.addWhiteInterval(interval1);
+  schedule.addWhiteInterval(interval2);
+  schedule.addWhiteInterval(interval3);
+
+  Interval resultInterval;
+  bool isPositive;
+
+  // tp1 --> positive 8.25 4-10
+  TimeStamp tp1 = from_iso_string("20150825T063000");
+  std::tie(isPositive, resultInterval) = schedule.getCoveringInterval(tp1);
+  BOOST_CHECK_EQUAL(isPositive, true);
+  BOOST_CHECK_EQUAL(to_iso_string(resultInterval.getStartTime()), "20150825T040000");
+  BOOST_CHECK_EQUAL(to_iso_string(resultInterval.getEndTime()), "20150825T100000");
+
+  // tp2 --> positive 8.26 6-8
+  TimeStamp tp2 = from_iso_string("20150826T073000");
+  std::tie(isPositive, resultInterval) = schedule.getCoveringInterval(tp2);
+  BOOST_CHECK_EQUAL(isPositive, true);
+  BOOST_CHECK_EQUAL(to_iso_string(resultInterval.getStartTime()), "20150826T060000");
+  BOOST_CHECK_EQUAL(to_iso_string(resultInterval.getEndTime()), "20150826T080000");
+
+  // tp3 --> positive 8.27 5-10
+  TimeStamp tp3 = from_iso_string("20150827T053000");
+  std::tie(isPositive, resultInterval) = schedule.getCoveringInterval(tp3);
+  BOOST_CHECK_EQUAL(isPositive, true);
+  BOOST_CHECK_EQUAL(to_iso_string(resultInterval.getStartTime()), "20150827T050000");
+  BOOST_CHECK_EQUAL(to_iso_string(resultInterval.getEndTime()), "20150827T100000");
+
+  // tp4 --> negative 8.25 10-24
+  TimeStamp tp4 = from_iso_string("20150825T113000");
+  std::tie(isPositive, resultInterval) = schedule.getCoveringInterval(tp4);
+  BOOST_CHECK_EQUAL(isPositive, false);
+  BOOST_CHECK_EQUAL(resultInterval.isEmpty(), false);
+  BOOST_CHECK_EQUAL(to_iso_string(resultInterval.getStartTime()), "20150825T100000");
+  BOOST_CHECK_EQUAL(to_iso_string(resultInterval.getEndTime()), "20150826T000000");
+
+  // tp5 --> negative 8.25 0-4
+  TimeStamp tp5 = from_iso_string("20150825T013000");
+  std::tie(isPositive, resultInterval) = schedule.getCoveringInterval(tp5);
+  BOOST_CHECK_EQUAL(isPositive, false);
+  BOOST_CHECK_EQUAL(resultInterval.isEmpty(), false);
+  BOOST_CHECK_EQUAL(to_iso_string(resultInterval.getStartTime()), "20150825T000000");
+  BOOST_CHECK_EQUAL(to_iso_string(resultInterval.getEndTime()), "20150825T040000");
+}
+
+BOOST_AUTO_TEST_CASE(CalIntervalWithoutWhite)
+{
+  Schedule schedule;
+  RepetitiveInterval interval1(from_iso_string("20150825T000000"),
+                               from_iso_string("20150827T000000"),
+                               5, 10, 2, RepetitiveInterval::RepeatUnit::DAY);
+  RepetitiveInterval interval2(from_iso_string("20150825T000000"),
+                               from_iso_string("20150827T000000"),
+                               6, 8, 1, RepetitiveInterval::RepeatUnit::DAY);
+
+  schedule.addBlackInterval(interval1);
+  schedule.addBlackInterval(interval2);
+
+  Interval resultInterval;
+  bool isPositive;
+
+  // tp1 --> negative 8.25 4-10
+  TimeStamp tp1 = from_iso_string("20150825T063000");
+  std::tie(isPositive, resultInterval) = schedule.getCoveringInterval(tp1);
+  BOOST_CHECK_EQUAL(isPositive, false);
+  BOOST_CHECK_EQUAL(resultInterval.isEmpty(), false);
+  BOOST_CHECK_EQUAL(to_iso_string(resultInterval.getStartTime()), "20150825T050000");
+  BOOST_CHECK_EQUAL(to_iso_string(resultInterval.getEndTime()), "20150825T100000");
+
+  // tp2 --> negative 8.25 0-4
+  TimeStamp tp2 = from_iso_string("20150825T013000");
+  std::tie(isPositive, resultInterval) = schedule.getCoveringInterval(tp2);
+  BOOST_CHECK_EQUAL(isPositive, false);
+  BOOST_CHECK_EQUAL(resultInterval.isEmpty(), false);
+  BOOST_CHECK_EQUAL(to_iso_string(resultInterval.getStartTime()), "20150825T000000");
+  BOOST_CHECK_EQUAL(to_iso_string(resultInterval.getEndTime()), "20150826T000000");
+}
+
 const uint8_t SCHEDULE[] = {
   0x8f, 0xc4,// Schedule
   0x8d, 0x90,// WhiteIntervalList