text: from datetime import datetime
  import unittest
  
  from scheduler import Scheduler
  from rules import *
  
  
  #TODO: test tz-aware datetime strings
  
  
  class TestBasicCronRule(unittest.TestCase):
  
      def test_parse_field(self):
          strs = {
              "5": [5],
              "2-9": xrange(2, 10),
              "20-30": xrange(20, 31),
              "20-30/2": xrange(20, 31, 2),
              "*": xrange(0, 60),
              "*/3": xrange(0, 60, 3),
              "1,2-10/2,13-15": [1, 2, 4, 6, 8, 10, 13, 14, 15]
          }
          for f, v in strs.items():
              rule = BasicCronRule.parse_field(f, 0, 59)
              self.assertTrue(all([x in rule for x in v]))
  
          with self.assertRaises(InvalidFieldError):
              BasicCronRule.parse_field("1-*", 0, 0)
  
  
      def test_parse(self):
          rule = BasicCronRule("* 7-19 * * 1-5 */2", start_year=1999, stop_year=2021)
  
          self.assertTrue( all([m in rule.rulesets["minutes"] for m in xrange(0, 60)]) )
          self.assertTrue( all([h in rule.rulesets["hours"] for h in xrange(7, 20)]) )
          self.assertTrue( all([d in rule.rulesets["dom"] for d in xrange(1, 32)]) )
          self.assertTrue( all([m in rule.rulesets["month"] for m in xrange(1, 13)]) )
          self.assertTrue( all([d in rule.rulesets["dow"] for d in xrange(1, 6)]) )
          self.assertTrue( all([y in rule.rulesets["year"] for y in xrange(1999, 2021, 2)]) )
          self.assertFalse( all([y in rule.rulesets["year"] for y in xrange(1999, 2021)]) )
          self.assertFalse( all([y in rule.rulesets["year"] for y in xrange(1999, 2024, 2)]) )
  
          with self.assertRaises(InvalidCronStringError):
              BasicCronRule.parse("1-* * * * * *")
  
  
      def test_is_holiday(self):
          rule = BasicCronRule("* 7-19 * * 1-5 * ")
  
          self.assertFalse(rule.is_holiday("* * * * * *"))
          self.assertFalse(rule.is_holiday("* * 12 25 * *"))
          self.assertTrue(rule.is_holiday("* * 4 7 * 2015"))
          self.assertFalse(rule.is_holiday("* * 4-6 7 * 2015"))
          self.assertFalse(rule.is_holiday("*/2 * 4 7 * 2015"))
  
          self.assertEqual(rule.holiday_tuple("* * 4 7 * 2015"), (4, 7, 2015))
  
  
      def test_contains(self):
          # Weekday
          rule = BasicCronRule("* 7-19 * * * *")
          self.assertTrue(rule.contains(datetime(2014, 12, 19, 12, 0)))
  
          # Weekday Night
          rule = BasicCronRule("* 20-23 * * * *")
          self.assertTrue(rule.contains(datetime(2014, 12, 19, 21, 30)))
  
          # Weekend
          rule = BasicCronRule("* 0-8 * * 6-7 *")
          self.assertTrue(rule.contains(datetime(2014, 12, 20, 8, 30)))
  
          #Weekend Night
          rule = BasicCronRule("* 17-23 * * 6-7 *")
          self.assertTrue(rule.contains(datetime(2014, 12, 20, 17, 30)))
  
          # Christmas (Thursday)
          rule = BasicCronRule("* * 25 12 * *")
          self.assertTrue(rule.contains(datetime(2014, 12, 25, 12, 0)))
  
  
  class TestCronRangeRule(unittest.TestCase):
  
      def test_parse_field(self):
          strs = {
              "5": [5],
              "2-9": xrange(2, 10),
              "20-30": xrange(20, 31),
              "20-30/2": xrange(20, 31, 2),
              "*": xrange(0, 60),
              "*/3": xrange(0, 60, 3)
          }
  
          for f, v in strs.items():
              rule = BasicCronRule.parse_field(f, 0, 59)
              self.assertTrue(all([x in rule for x in v]))
  
          hhmm = CronRangeRule.parse_field("13:45")
  
          self.assertEqual(hhmm.hour, 13)
          self.assertEqual(hhmm.minute, 45)
  
  
      def test_parse(self):
          rule = CronRangeRule("7:30 19:15 * * 1-5 * ")
  
          self.assertTrue( rule.rulesets["start"].hour == 7 and rule.rulesets["start"].minute == 30 )
          self.assertTrue( rule.rulesets["stop"].hour == 19 and rule.rulesets["stop"].minute == 15 )
          self.assertTrue( all([d in rule.rulesets["dom"] for d in xrange(1, 32)]) )
          self.assertTrue( all([m in rule.rulesets["month"] for m in xrange(1, 13)]) )
          self.assertTrue( all([d in rule.rulesets["dow"] for d in xrange(1, 6)]) )
          self.assertTrue( all([y in rule.rulesets["year"] for y in xrange(2000, 2021)]) )
  
          with self.assertRaises(InvalidCronStringError):
              CronRangeRule.parse("1:23 12:34 */ * * *")
  
          with self.assertRaises(InvalidCronStringError):
              CronRangeRule.parse("* * * * * *")
  
  
      def test_contains(self):
          # Weekday
          rule = CronRangeRule("7:30 19:15 * * * *")
          self.assertTrue(rule.contains(datetime(2014, 12, 19, 12, 0)))
          self.assertTrue(rule.contains(datetime(2014, 12, 19, 7, 30)))
          self.assertFalse(rule.contains(datetime(2014, 12, 19, 19, 20)))
  
          # Weekday Night
          rule = CronRangeRule("20:00 23:59 * * * *")
          self.assertTrue(rule.contains(datetime(2014, 12, 19, 21, 30)))
          self.assertFalse(rule.contains(datetime(2014, 12, 19, 19, 59)))
  
          # Weekend
          rule = CronRangeRule("00:00 08:00 * * 6-7 *")
          self.assertTrue(rule.contains(datetime(2014, 12, 20, 8, 0)))
          self.assertFalse(rule.contains(datetime(2014, 12, 20, 8, 1)))
          self.assertFalse(rule.contains(datetime(2014, 12, 17, 7, 0)))
  
  
      def test_looks_like_range_rule(self):
          self.assertTrue(CronRangeRule.looks_like_range_rule("7:30 19:00 * * * *"))
          self.assertFalse(CronRangeRule.looks_like_range_rule("* * * * * *"))
          self.assertFalse(CronRangeRule.looks_like_range_rule("* 19:00 * * * *"))
          self.assertFalse(CronRangeRule.looks_like_range_rule("7:30 * * * * *"))
  
  
      def test_is_valid(self):
          self.assertTrue(CronRangeRule.is_valid("7:30 19:00 * * * *"))
          self.assertFalse(CronRangeRule.is_valid("7:30 19:00 * */ * *"))
          self.assertFalse(CronRangeRule.is_valid("* * * * * *"))
          self.assertFalse(CronRangeRule.is_valid("* 19:00 * * * *"))
          self.assertFalse(CronRangeRule.is_valid("7:30 * * * * *"))
  
  
  class TestScheduler(unittest.TestCase):
  
      def test_holiday_rules(self):
          rules = [("open", "* 7-19 * * * *"), ("closed", "* 0-6 * * * *"), ("closed", "* 20-23 * * * *")]
          exceptions = [("closed", "* 0-8 * * 6-7 *"), ("closed", "* 17-23 * * 6-7 *"), ("closed", "* * 25 12 * *"), ("closed", "* * 4 7 * *")]
  
          for m in xrange(1, 12):
              exceptions.append(("closed", "* * 1 %s * 2014" % m))
  
          cp = Scheduler(rules, exceptions)
  
          # Weekday
          self.assertEqual(cp.get_matching_rules(datetime(2014, 12, 19, 12, 0))[0], "open")
  
          # Weekday Night
          self.assertEqual(cp.get_matching_rules(datetime(2014, 12, 19, 21, 30))[0], "closed")
  
          # Weekend
          self.assertEqual(cp.get_matching_rules(datetime(2014, 12, 20, 8, 30))[0], "closed")
  
          #Weekend Night
          self.assertEqual(cp.get_matching_rules(datetime(2014, 12, 20, 17, 30))[0], "closed")
  
          # First of April (Tuesday)
          self.assertEqual(cp.get_matching_rules(datetime(2014, 4, 1, 12, 0))[0], "closed")
  
  
  
      def test_get_matching_rules(self):
          cp = Scheduler(
              [("open", "7:00 19:30 * * * *"), ("closed", "* 6 * * * *"), ("closed", "19:31 23:59 * * * *")],
              [("closed", "0:00 8:30 * * 6-7 *"), ("closed", "18:30 23:59 * * 6-7 *"), ("closed", "* * 24,25 12 * *"), ("closed", "* * 4 7 * *"), ("closed", "* * 5 4 * 2015")]
          )
  
  
          # Weekday
          self.assertEqual(cp.get_matching_rules(datetime(2014, 12, 19, 18, 31))[0], "open")
  
          # Weekday Night
          self.assertEqual(cp.get_matching_rules(datetime(2014, 12, 19, 19, 31))[0], "closed")
  
          # Weekend Morning
          self.assertEqual(cp.get_matching_rules(datetime(2014, 12, 20, 8, 0))[0], "closed")
  
          # Weekend Day
          self.assertEqual(cp.get_matching_rules(datetime(2014, 12, 20, 12, 0))[0], "open")
  
          # #Weekend Night
          self.assertEqual(cp.get_matching_rules(datetime(2014, 12, 20, 18, 31))[0], "closed")
  
          # Christmas (Thursday)
          self.assertEqual(cp.get_matching_rules(datetime(2014, 12, 25, 12, 0))[0], "closed")
  
          # Christmas Eve (Wednesday)
          self.assertEqual(cp.get_matching_rules(datetime(2014, 12, 24, 12, 0))[0], "closed")
  
          # Easter (Sunday)
          self.assertEqual(cp.get_matching_rules(datetime(2015, 4, 5, 12, 0))[0], "closed")
  
  
      def test_start_stop(self):
          cp = Scheduler(
              [("odd_year", "* * * * * *")],
              [("even_year", "* * * * * */2")],
              start_year=1990, stop_year=1999
          )
  
          self.assertEqual(cp.get_matching_rules(datetime(1991, 12, 19, 18, 31))[0], "odd_year")
          self.assertEqual(cp.get_matching_rules(datetime(1992, 12, 19, 18, 31))[0], "even_year")
          self.assertEqual(cp.get_matching_rules(datetime(2000, 12, 19, 18, 31)), [])
  
  
  
  if __name__ == "__main__":
      suite = unittest.TestSuite()
      # suite.addTest(TestBasicCronRule('test_parse_field'))
      # suite = unittest.TestLoader().loadTestsFromTestCase(TestBasicScheduler)
      suite = unittest.TestLoader().loadTestsFromNames(['tests'])
      runner = unittest.TextTestRunner()
      runner.run(suite)
  