• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import calendar
2import unittest
3
4from test import test_support
5from test.script_helper import assert_python_ok, assert_python_failure
6import locale
7import datetime
8import os
9
10result_2004_01_text = """\
11    January 2004
12Mo Tu We Th Fr Sa Su
13          1  2  3  4
14 5  6  7  8  9 10 11
1512 13 14 15 16 17 18
1619 20 21 22 23 24 25
1726 27 28 29 30 31
18"""
19
20result_2004_text = """\
21                                  2004
22
23      January                   February                   March
24Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
25          1  2  3  4                         1       1  2  3  4  5  6  7
26 5  6  7  8  9 10 11       2  3  4  5  6  7  8       8  9 10 11 12 13 14
2712 13 14 15 16 17 18       9 10 11 12 13 14 15      15 16 17 18 19 20 21
2819 20 21 22 23 24 25      16 17 18 19 20 21 22      22 23 24 25 26 27 28
2926 27 28 29 30 31         23 24 25 26 27 28 29      29 30 31
30
31       April                      May                       June
32Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
33          1  2  3  4                      1  2          1  2  3  4  5  6
34 5  6  7  8  9 10 11       3  4  5  6  7  8  9       7  8  9 10 11 12 13
3512 13 14 15 16 17 18      10 11 12 13 14 15 16      14 15 16 17 18 19 20
3619 20 21 22 23 24 25      17 18 19 20 21 22 23      21 22 23 24 25 26 27
3726 27 28 29 30            24 25 26 27 28 29 30      28 29 30
38                          31
39
40        July                     August                  September
41Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
42          1  2  3  4                         1             1  2  3  4  5
43 5  6  7  8  9 10 11       2  3  4  5  6  7  8       6  7  8  9 10 11 12
4412 13 14 15 16 17 18       9 10 11 12 13 14 15      13 14 15 16 17 18 19
4519 20 21 22 23 24 25      16 17 18 19 20 21 22      20 21 22 23 24 25 26
4626 27 28 29 30 31         23 24 25 26 27 28 29      27 28 29 30
47                          30 31
48
49      October                   November                  December
50Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
51             1  2  3       1  2  3  4  5  6  7             1  2  3  4  5
52 4  5  6  7  8  9 10       8  9 10 11 12 13 14       6  7  8  9 10 11 12
5311 12 13 14 15 16 17      15 16 17 18 19 20 21      13 14 15 16 17 18 19
5418 19 20 21 22 23 24      22 23 24 25 26 27 28      20 21 22 23 24 25 26
5525 26 27 28 29 30 31      29 30                     27 28 29 30 31
56"""
57
58result_2004_html = """\
59<?xml version="1.0" encoding="ascii"?>
60<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
61<html>
62<head>
63<meta http-equiv="Content-Type" content="text/html; charset=ascii" />
64<link rel="stylesheet" type="text/css" href="calendar.css" />
65<title>Calendar for 2004</title>
66</head>
67<body>
68<table border="0" cellpadding="0" cellspacing="0" class="year">
69<tr><th colspan="3" class="year">2004</th></tr><tr><td><table border="0" cellpadding="0" cellspacing="0" class="month">
70<tr><th colspan="7" class="month">January</th></tr>
71<tr><th class="mon">Mon</th><th class="tue">Tue</th><th class="wed">Wed</th><th class="thu">Thu</th><th class="fri">Fri</th><th class="sat">Sat</th><th class="sun">Sun</th></tr>
72<tr><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="thu">1</td><td class="fri">2</td><td class="sat">3</td><td class="sun">4</td></tr>
73<tr><td class="mon">5</td><td class="tue">6</td><td class="wed">7</td><td class="thu">8</td><td class="fri">9</td><td class="sat">10</td><td class="sun">11</td></tr>
74<tr><td class="mon">12</td><td class="tue">13</td><td class="wed">14</td><td class="thu">15</td><td class="fri">16</td><td class="sat">17</td><td class="sun">18</td></tr>
75<tr><td class="mon">19</td><td class="tue">20</td><td class="wed">21</td><td class="thu">22</td><td class="fri">23</td><td class="sat">24</td><td class="sun">25</td></tr>
76<tr><td class="mon">26</td><td class="tue">27</td><td class="wed">28</td><td class="thu">29</td><td class="fri">30</td><td class="sat">31</td><td class="noday">&nbsp;</td></tr>
77</table>
78</td><td><table border="0" cellpadding="0" cellspacing="0" class="month">
79<tr><th colspan="7" class="month">February</th></tr>
80<tr><th class="mon">Mon</th><th class="tue">Tue</th><th class="wed">Wed</th><th class="thu">Thu</th><th class="fri">Fri</th><th class="sat">Sat</th><th class="sun">Sun</th></tr>
81<tr><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="sun">1</td></tr>
82<tr><td class="mon">2</td><td class="tue">3</td><td class="wed">4</td><td class="thu">5</td><td class="fri">6</td><td class="sat">7</td><td class="sun">8</td></tr>
83<tr><td class="mon">9</td><td class="tue">10</td><td class="wed">11</td><td class="thu">12</td><td class="fri">13</td><td class="sat">14</td><td class="sun">15</td></tr>
84<tr><td class="mon">16</td><td class="tue">17</td><td class="wed">18</td><td class="thu">19</td><td class="fri">20</td><td class="sat">21</td><td class="sun">22</td></tr>
85<tr><td class="mon">23</td><td class="tue">24</td><td class="wed">25</td><td class="thu">26</td><td class="fri">27</td><td class="sat">28</td><td class="sun">29</td></tr>
86</table>
87</td><td><table border="0" cellpadding="0" cellspacing="0" class="month">
88<tr><th colspan="7" class="month">March</th></tr>
89<tr><th class="mon">Mon</th><th class="tue">Tue</th><th class="wed">Wed</th><th class="thu">Thu</th><th class="fri">Fri</th><th class="sat">Sat</th><th class="sun">Sun</th></tr>
90<tr><td class="mon">1</td><td class="tue">2</td><td class="wed">3</td><td class="thu">4</td><td class="fri">5</td><td class="sat">6</td><td class="sun">7</td></tr>
91<tr><td class="mon">8</td><td class="tue">9</td><td class="wed">10</td><td class="thu">11</td><td class="fri">12</td><td class="sat">13</td><td class="sun">14</td></tr>
92<tr><td class="mon">15</td><td class="tue">16</td><td class="wed">17</td><td class="thu">18</td><td class="fri">19</td><td class="sat">20</td><td class="sun">21</td></tr>
93<tr><td class="mon">22</td><td class="tue">23</td><td class="wed">24</td><td class="thu">25</td><td class="fri">26</td><td class="sat">27</td><td class="sun">28</td></tr>
94<tr><td class="mon">29</td><td class="tue">30</td><td class="wed">31</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td></tr>
95</table>
96</td></tr><tr><td><table border="0" cellpadding="0" cellspacing="0" class="month">
97<tr><th colspan="7" class="month">April</th></tr>
98<tr><th class="mon">Mon</th><th class="tue">Tue</th><th class="wed">Wed</th><th class="thu">Thu</th><th class="fri">Fri</th><th class="sat">Sat</th><th class="sun">Sun</th></tr>
99<tr><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="thu">1</td><td class="fri">2</td><td class="sat">3</td><td class="sun">4</td></tr>
100<tr><td class="mon">5</td><td class="tue">6</td><td class="wed">7</td><td class="thu">8</td><td class="fri">9</td><td class="sat">10</td><td class="sun">11</td></tr>
101<tr><td class="mon">12</td><td class="tue">13</td><td class="wed">14</td><td class="thu">15</td><td class="fri">16</td><td class="sat">17</td><td class="sun">18</td></tr>
102<tr><td class="mon">19</td><td class="tue">20</td><td class="wed">21</td><td class="thu">22</td><td class="fri">23</td><td class="sat">24</td><td class="sun">25</td></tr>
103<tr><td class="mon">26</td><td class="tue">27</td><td class="wed">28</td><td class="thu">29</td><td class="fri">30</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td></tr>
104</table>
105</td><td><table border="0" cellpadding="0" cellspacing="0" class="month">
106<tr><th colspan="7" class="month">May</th></tr>
107<tr><th class="mon">Mon</th><th class="tue">Tue</th><th class="wed">Wed</th><th class="thu">Thu</th><th class="fri">Fri</th><th class="sat">Sat</th><th class="sun">Sun</th></tr>
108<tr><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="sat">1</td><td class="sun">2</td></tr>
109<tr><td class="mon">3</td><td class="tue">4</td><td class="wed">5</td><td class="thu">6</td><td class="fri">7</td><td class="sat">8</td><td class="sun">9</td></tr>
110<tr><td class="mon">10</td><td class="tue">11</td><td class="wed">12</td><td class="thu">13</td><td class="fri">14</td><td class="sat">15</td><td class="sun">16</td></tr>
111<tr><td class="mon">17</td><td class="tue">18</td><td class="wed">19</td><td class="thu">20</td><td class="fri">21</td><td class="sat">22</td><td class="sun">23</td></tr>
112<tr><td class="mon">24</td><td class="tue">25</td><td class="wed">26</td><td class="thu">27</td><td class="fri">28</td><td class="sat">29</td><td class="sun">30</td></tr>
113<tr><td class="mon">31</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td></tr>
114</table>
115</td><td><table border="0" cellpadding="0" cellspacing="0" class="month">
116<tr><th colspan="7" class="month">June</th></tr>
117<tr><th class="mon">Mon</th><th class="tue">Tue</th><th class="wed">Wed</th><th class="thu">Thu</th><th class="fri">Fri</th><th class="sat">Sat</th><th class="sun">Sun</th></tr>
118<tr><td class="noday">&nbsp;</td><td class="tue">1</td><td class="wed">2</td><td class="thu">3</td><td class="fri">4</td><td class="sat">5</td><td class="sun">6</td></tr>
119<tr><td class="mon">7</td><td class="tue">8</td><td class="wed">9</td><td class="thu">10</td><td class="fri">11</td><td class="sat">12</td><td class="sun">13</td></tr>
120<tr><td class="mon">14</td><td class="tue">15</td><td class="wed">16</td><td class="thu">17</td><td class="fri">18</td><td class="sat">19</td><td class="sun">20</td></tr>
121<tr><td class="mon">21</td><td class="tue">22</td><td class="wed">23</td><td class="thu">24</td><td class="fri">25</td><td class="sat">26</td><td class="sun">27</td></tr>
122<tr><td class="mon">28</td><td class="tue">29</td><td class="wed">30</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td></tr>
123</table>
124</td></tr><tr><td><table border="0" cellpadding="0" cellspacing="0" class="month">
125<tr><th colspan="7" class="month">July</th></tr>
126<tr><th class="mon">Mon</th><th class="tue">Tue</th><th class="wed">Wed</th><th class="thu">Thu</th><th class="fri">Fri</th><th class="sat">Sat</th><th class="sun">Sun</th></tr>
127<tr><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="thu">1</td><td class="fri">2</td><td class="sat">3</td><td class="sun">4</td></tr>
128<tr><td class="mon">5</td><td class="tue">6</td><td class="wed">7</td><td class="thu">8</td><td class="fri">9</td><td class="sat">10</td><td class="sun">11</td></tr>
129<tr><td class="mon">12</td><td class="tue">13</td><td class="wed">14</td><td class="thu">15</td><td class="fri">16</td><td class="sat">17</td><td class="sun">18</td></tr>
130<tr><td class="mon">19</td><td class="tue">20</td><td class="wed">21</td><td class="thu">22</td><td class="fri">23</td><td class="sat">24</td><td class="sun">25</td></tr>
131<tr><td class="mon">26</td><td class="tue">27</td><td class="wed">28</td><td class="thu">29</td><td class="fri">30</td><td class="sat">31</td><td class="noday">&nbsp;</td></tr>
132</table>
133</td><td><table border="0" cellpadding="0" cellspacing="0" class="month">
134<tr><th colspan="7" class="month">August</th></tr>
135<tr><th class="mon">Mon</th><th class="tue">Tue</th><th class="wed">Wed</th><th class="thu">Thu</th><th class="fri">Fri</th><th class="sat">Sat</th><th class="sun">Sun</th></tr>
136<tr><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="sun">1</td></tr>
137<tr><td class="mon">2</td><td class="tue">3</td><td class="wed">4</td><td class="thu">5</td><td class="fri">6</td><td class="sat">7</td><td class="sun">8</td></tr>
138<tr><td class="mon">9</td><td class="tue">10</td><td class="wed">11</td><td class="thu">12</td><td class="fri">13</td><td class="sat">14</td><td class="sun">15</td></tr>
139<tr><td class="mon">16</td><td class="tue">17</td><td class="wed">18</td><td class="thu">19</td><td class="fri">20</td><td class="sat">21</td><td class="sun">22</td></tr>
140<tr><td class="mon">23</td><td class="tue">24</td><td class="wed">25</td><td class="thu">26</td><td class="fri">27</td><td class="sat">28</td><td class="sun">29</td></tr>
141<tr><td class="mon">30</td><td class="tue">31</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td></tr>
142</table>
143</td><td><table border="0" cellpadding="0" cellspacing="0" class="month">
144<tr><th colspan="7" class="month">September</th></tr>
145<tr><th class="mon">Mon</th><th class="tue">Tue</th><th class="wed">Wed</th><th class="thu">Thu</th><th class="fri">Fri</th><th class="sat">Sat</th><th class="sun">Sun</th></tr>
146<tr><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="wed">1</td><td class="thu">2</td><td class="fri">3</td><td class="sat">4</td><td class="sun">5</td></tr>
147<tr><td class="mon">6</td><td class="tue">7</td><td class="wed">8</td><td class="thu">9</td><td class="fri">10</td><td class="sat">11</td><td class="sun">12</td></tr>
148<tr><td class="mon">13</td><td class="tue">14</td><td class="wed">15</td><td class="thu">16</td><td class="fri">17</td><td class="sat">18</td><td class="sun">19</td></tr>
149<tr><td class="mon">20</td><td class="tue">21</td><td class="wed">22</td><td class="thu">23</td><td class="fri">24</td><td class="sat">25</td><td class="sun">26</td></tr>
150<tr><td class="mon">27</td><td class="tue">28</td><td class="wed">29</td><td class="thu">30</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td></tr>
151</table>
152</td></tr><tr><td><table border="0" cellpadding="0" cellspacing="0" class="month">
153<tr><th colspan="7" class="month">October</th></tr>
154<tr><th class="mon">Mon</th><th class="tue">Tue</th><th class="wed">Wed</th><th class="thu">Thu</th><th class="fri">Fri</th><th class="sat">Sat</th><th class="sun">Sun</th></tr>
155<tr><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="fri">1</td><td class="sat">2</td><td class="sun">3</td></tr>
156<tr><td class="mon">4</td><td class="tue">5</td><td class="wed">6</td><td class="thu">7</td><td class="fri">8</td><td class="sat">9</td><td class="sun">10</td></tr>
157<tr><td class="mon">11</td><td class="tue">12</td><td class="wed">13</td><td class="thu">14</td><td class="fri">15</td><td class="sat">16</td><td class="sun">17</td></tr>
158<tr><td class="mon">18</td><td class="tue">19</td><td class="wed">20</td><td class="thu">21</td><td class="fri">22</td><td class="sat">23</td><td class="sun">24</td></tr>
159<tr><td class="mon">25</td><td class="tue">26</td><td class="wed">27</td><td class="thu">28</td><td class="fri">29</td><td class="sat">30</td><td class="sun">31</td></tr>
160</table>
161</td><td><table border="0" cellpadding="0" cellspacing="0" class="month">
162<tr><th colspan="7" class="month">November</th></tr>
163<tr><th class="mon">Mon</th><th class="tue">Tue</th><th class="wed">Wed</th><th class="thu">Thu</th><th class="fri">Fri</th><th class="sat">Sat</th><th class="sun">Sun</th></tr>
164<tr><td class="mon">1</td><td class="tue">2</td><td class="wed">3</td><td class="thu">4</td><td class="fri">5</td><td class="sat">6</td><td class="sun">7</td></tr>
165<tr><td class="mon">8</td><td class="tue">9</td><td class="wed">10</td><td class="thu">11</td><td class="fri">12</td><td class="sat">13</td><td class="sun">14</td></tr>
166<tr><td class="mon">15</td><td class="tue">16</td><td class="wed">17</td><td class="thu">18</td><td class="fri">19</td><td class="sat">20</td><td class="sun">21</td></tr>
167<tr><td class="mon">22</td><td class="tue">23</td><td class="wed">24</td><td class="thu">25</td><td class="fri">26</td><td class="sat">27</td><td class="sun">28</td></tr>
168<tr><td class="mon">29</td><td class="tue">30</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td></tr>
169</table>
170</td><td><table border="0" cellpadding="0" cellspacing="0" class="month">
171<tr><th colspan="7" class="month">December</th></tr>
172<tr><th class="mon">Mon</th><th class="tue">Tue</th><th class="wed">Wed</th><th class="thu">Thu</th><th class="fri">Fri</th><th class="sat">Sat</th><th class="sun">Sun</th></tr>
173<tr><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="wed">1</td><td class="thu">2</td><td class="fri">3</td><td class="sat">4</td><td class="sun">5</td></tr>
174<tr><td class="mon">6</td><td class="tue">7</td><td class="wed">8</td><td class="thu">9</td><td class="fri">10</td><td class="sat">11</td><td class="sun">12</td></tr>
175<tr><td class="mon">13</td><td class="tue">14</td><td class="wed">15</td><td class="thu">16</td><td class="fri">17</td><td class="sat">18</td><td class="sun">19</td></tr>
176<tr><td class="mon">20</td><td class="tue">21</td><td class="wed">22</td><td class="thu">23</td><td class="fri">24</td><td class="sat">25</td><td class="sun">26</td></tr>
177<tr><td class="mon">27</td><td class="tue">28</td><td class="wed">29</td><td class="thu">30</td><td class="fri">31</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td></tr>
178</table>
179</td></tr></table></body>
180</html>
181"""
182
183
184class OutputTestCase(unittest.TestCase):
185    def normalize_calendar(self, s):
186        # Filters out locale dependent strings
187        def neitherspacenordigit(c):
188            return not c.isspace() and not c.isdigit()
189
190        lines = []
191        for line in s.splitlines(False):
192            # Drop texts, as they are locale dependent
193            if line and not filter(neitherspacenordigit, line):
194                lines.append(line)
195        return lines
196
197    def test_output(self):
198        self.assertEqual(
199            self.normalize_calendar(calendar.calendar(2004)),
200            self.normalize_calendar(result_2004_text)
201        )
202
203    def test_output_textcalendar(self):
204        self.assertEqual(
205            calendar.TextCalendar().formatyear(2004).strip(),
206            result_2004_text.strip()
207        )
208
209    def test_output_htmlcalendar(self):
210        self.assertEqual(
211            calendar.HTMLCalendar().formatyearpage(2004).strip(),
212            result_2004_html.strip()
213        )
214
215
216class CalendarTestCase(unittest.TestCase):
217    def test_isleap(self):
218        # Make sure that the return is right for a few years, and
219        # ensure that the return values are 1 or 0, not just true or
220        # false (see SF bug #485794).  Specific additional tests may
221        # be appropriate; this tests a single "cycle".
222        self.assertEqual(calendar.isleap(2000), 1)
223        self.assertEqual(calendar.isleap(2001), 0)
224        self.assertEqual(calendar.isleap(2002), 0)
225        self.assertEqual(calendar.isleap(2003), 0)
226
227    def test_setfirstweekday(self):
228        self.assertRaises(ValueError, calendar.setfirstweekday, 'flabber')
229        self.assertRaises(ValueError, calendar.setfirstweekday, -1)
230        self.assertRaises(ValueError, calendar.setfirstweekday, 200)
231        orig = calendar.firstweekday()
232        calendar.setfirstweekday(calendar.SUNDAY)
233        self.assertEqual(calendar.firstweekday(), calendar.SUNDAY)
234        calendar.setfirstweekday(calendar.MONDAY)
235        self.assertEqual(calendar.firstweekday(), calendar.MONDAY)
236        calendar.setfirstweekday(orig)
237
238    def test_enumerateweekdays(self):
239        self.assertRaises(IndexError, calendar.day_abbr.__getitem__, -10)
240        self.assertRaises(IndexError, calendar.day_name.__getitem__, 10)
241        self.assertEqual(len([d for d in calendar.day_abbr]), 7)
242
243    def test_days(self):
244        for attr in "day_name", "day_abbr":
245            value = getattr(calendar, attr)
246            self.assertEqual(len(value), 7)
247            self.assertEqual(len(value[:]), 7)
248            # ensure they're all unique
249            self.assertEqual(len(set(value)), 7)
250            # verify it "acts like a sequence" in two forms of iteration
251            self.assertEqual(value[::-1], list(reversed(value)))
252
253    def test_months(self):
254        for attr in "month_name", "month_abbr":
255            value = getattr(calendar, attr)
256            self.assertEqual(len(value), 13)
257            self.assertEqual(len(value[:]), 13)
258            self.assertEqual(value[0], "")
259            # ensure they're all unique
260            self.assertEqual(len(set(value)), 13)
261            # verify it "acts like a sequence" in two forms of iteration
262            self.assertEqual(value[::-1], list(reversed(value)))
263
264    def test_localecalendars(self):
265        # ensure that Locale{Text,HTML}Calendar resets the locale properly
266        # (it is still not thread-safe though)
267        old_october = calendar.TextCalendar().formatmonthname(2010, 10, 10)
268        try:
269            cal = calendar.LocaleTextCalendar(locale='')
270            local_weekday = cal.formatweekday(1, 10)
271            local_month = cal.formatmonthname(2010, 10, 10)
272        except locale.Error:
273            # cannot set the system default locale -- skip rest of test
274            raise unittest.SkipTest('cannot set the system default locale')
275        # should be encodable
276        local_weekday.encode('utf-8')
277        local_month.encode('utf-8')
278        self.assertEqual(len(local_weekday), 10)
279        self.assertGreaterEqual(len(local_month), 10)
280        cal = calendar.LocaleHTMLCalendar(locale='')
281        local_weekday = cal.formatweekday(1)
282        local_month = cal.formatmonthname(2010, 10)
283        # should be encodable
284        local_weekday.encode('utf-8')
285        local_month.encode('utf-8')
286        new_october = calendar.TextCalendar().formatmonthname(2010, 10, 10)
287        self.assertEqual(old_october, new_october)
288
289    def test_itermonthdates(self):
290        # ensure itermonthdates doesn't overflow after datetime.MAXYEAR
291        # see #15421
292        list(calendar.Calendar().itermonthdates(datetime.MAXYEAR, 12))
293
294    def test_itermonthdays(self):
295        for firstweekday in range(7):
296            cal = calendar.Calendar(firstweekday)
297            # Test the extremes, see #28253 and #26650
298            for y, m in [(1, 1), (9999, 12)]:
299                days = list(cal.itermonthdays(y, m))
300                self.assertIn(len(days), (35, 42))
301        # Test a short month
302        cal = calendar.Calendar(firstweekday=3)
303        days = list(cal.itermonthdays(2001, 2))
304        self.assertEqual(days, list(range(1, 29)))
305
306    def test_itermonthdays2(self):
307        for firstweekday in range(7):
308            cal = calendar.Calendar(firstweekday)
309            # Test the extremes, see #28253 and #26650
310            for y, m in [(1, 1), (9999, 12)]:
311                days = list(cal.itermonthdays2(y, m))
312                self.assertEqual(days[0][1], firstweekday)
313                self.assertEqual(days[-1][1], (firstweekday - 1) % 7)
314
315
316class MonthCalendarTestCase(unittest.TestCase):
317    def setUp(self):
318        self.oldfirstweekday = calendar.firstweekday()
319        calendar.setfirstweekday(self.firstweekday)
320
321    def tearDown(self):
322        calendar.setfirstweekday(self.oldfirstweekday)
323
324    def check_weeks(self, year, month, weeks):
325        cal = calendar.monthcalendar(year, month)
326        self.assertEqual(len(cal), len(weeks))
327        for i in xrange(len(weeks)):
328            self.assertEqual(weeks[i], sum(day != 0 for day in cal[i]))
329
330
331class MondayTestCase(MonthCalendarTestCase):
332    firstweekday = calendar.MONDAY
333
334    def test_february(self):
335        # A 28-day february starting on monday (7+7+7+7 days)
336        self.check_weeks(1999, 2, (7, 7, 7, 7))
337
338        # A 28-day february starting on tuesday (6+7+7+7+1 days)
339        self.check_weeks(2005, 2, (6, 7, 7, 7, 1))
340
341        # A 28-day february starting on sunday (1+7+7+7+6 days)
342        self.check_weeks(1987, 2, (1, 7, 7, 7, 6))
343
344        # A 29-day february starting on monday (7+7+7+7+1 days)
345        self.check_weeks(1988, 2, (7, 7, 7, 7, 1))
346
347        # A 29-day february starting on tuesday (6+7+7+7+2 days)
348        self.check_weeks(1972, 2, (6, 7, 7, 7, 2))
349
350        # A 29-day february starting on sunday (1+7+7+7+7 days)
351        self.check_weeks(2004, 2, (1, 7, 7, 7, 7))
352
353    def test_april(self):
354        # A 30-day april starting on monday (7+7+7+7+2 days)
355        self.check_weeks(1935, 4, (7, 7, 7, 7, 2))
356
357        # A 30-day april starting on tuesday (6+7+7+7+3 days)
358        self.check_weeks(1975, 4, (6, 7, 7, 7, 3))
359
360        # A 30-day april starting on sunday (1+7+7+7+7+1 days)
361        self.check_weeks(1945, 4, (1, 7, 7, 7, 7, 1))
362
363        # A 30-day april starting on saturday (2+7+7+7+7 days)
364        self.check_weeks(1995, 4, (2, 7, 7, 7, 7))
365
366        # A 30-day april starting on friday (3+7+7+7+6 days)
367        self.check_weeks(1994, 4, (3, 7, 7, 7, 6))
368
369    def test_december(self):
370        # A 31-day december starting on monday (7+7+7+7+3 days)
371        self.check_weeks(1980, 12, (7, 7, 7, 7, 3))
372
373        # A 31-day december starting on tuesday (6+7+7+7+4 days)
374        self.check_weeks(1987, 12, (6, 7, 7, 7, 4))
375
376        # A 31-day december starting on sunday (1+7+7+7+7+2 days)
377        self.check_weeks(1968, 12, (1, 7, 7, 7, 7, 2))
378
379        # A 31-day december starting on thursday (4+7+7+7+6 days)
380        self.check_weeks(1988, 12, (4, 7, 7, 7, 6))
381
382        # A 31-day december starting on friday (3+7+7+7+7 days)
383        self.check_weeks(2017, 12, (3, 7, 7, 7, 7))
384
385        # A 31-day december starting on saturday (2+7+7+7+7+1 days)
386        self.check_weeks(2068, 12, (2, 7, 7, 7, 7, 1))
387
388
389class SundayTestCase(MonthCalendarTestCase):
390    firstweekday = calendar.SUNDAY
391
392    def test_february(self):
393        # A 28-day february starting on sunday (7+7+7+7 days)
394        self.check_weeks(2009, 2, (7, 7, 7, 7))
395
396        # A 28-day february starting on monday (6+7+7+7+1 days)
397        self.check_weeks(1999, 2, (6, 7, 7, 7, 1))
398
399        # A 28-day february starting on saturday (1+7+7+7+6 days)
400        self.check_weeks(1997, 2, (1, 7, 7, 7, 6))
401
402        # A 29-day february starting on sunday (7+7+7+7+1 days)
403        self.check_weeks(2004, 2, (7, 7, 7, 7, 1))
404
405        # A 29-day february starting on monday (6+7+7+7+2 days)
406        self.check_weeks(1960, 2, (6, 7, 7, 7, 2))
407
408        # A 29-day february starting on saturday (1+7+7+7+7 days)
409        self.check_weeks(1964, 2, (1, 7, 7, 7, 7))
410
411    def test_april(self):
412        # A 30-day april starting on sunday (7+7+7+7+2 days)
413        self.check_weeks(1923, 4, (7, 7, 7, 7, 2))
414
415        # A 30-day april starting on monday (6+7+7+7+3 days)
416        self.check_weeks(1918, 4, (6, 7, 7, 7, 3))
417
418        # A 30-day april starting on saturday (1+7+7+7+7+1 days)
419        self.check_weeks(1950, 4, (1, 7, 7, 7, 7, 1))
420
421        # A 30-day april starting on friday (2+7+7+7+7 days)
422        self.check_weeks(1960, 4, (2, 7, 7, 7, 7))
423
424        # A 30-day april starting on thursday (3+7+7+7+6 days)
425        self.check_weeks(1909, 4, (3, 7, 7, 7, 6))
426
427    def test_december(self):
428        # A 31-day december starting on sunday (7+7+7+7+3 days)
429        self.check_weeks(2080, 12, (7, 7, 7, 7, 3))
430
431        # A 31-day december starting on monday (6+7+7+7+4 days)
432        self.check_weeks(1941, 12, (6, 7, 7, 7, 4))
433
434        # A 31-day december starting on saturday (1+7+7+7+7+2 days)
435        self.check_weeks(1923, 12, (1, 7, 7, 7, 7, 2))
436
437        # A 31-day december starting on wednesday (4+7+7+7+6 days)
438        self.check_weeks(1948, 12, (4, 7, 7, 7, 6))
439
440        # A 31-day december starting on thursday (3+7+7+7+7 days)
441        self.check_weeks(1927, 12, (3, 7, 7, 7, 7))
442
443        # A 31-day december starting on friday (2+7+7+7+7+1 days)
444        self.check_weeks(1995, 12, (2, 7, 7, 7, 7, 1))
445
446
447class MonthRangeTestCase(unittest.TestCase):
448    def test_january(self):
449        # Tests valid lower boundary case.
450        self.assertEqual(calendar.monthrange(2004,1), (3,31))
451
452    def test_february_leap(self):
453        # Tests February during leap year.
454        self.assertEqual(calendar.monthrange(2004,2), (6,29))
455
456    def test_february_nonleap(self):
457        # Tests February in non-leap year.
458        self.assertEqual(calendar.monthrange(2010,2), (0,28))
459
460    def test_december(self):
461        # Tests valid upper boundary case.
462        self.assertEqual(calendar.monthrange(2004,12), (2,31))
463
464    def test_zeroth_month(self):
465        # Tests low invalid boundary case.
466        with self.assertRaises(calendar.IllegalMonthError):
467            calendar.monthrange(2004, 0)
468
469    def test_thirteenth_month(self):
470        # Tests high invalid boundary case.
471        with self.assertRaises(calendar.IllegalMonthError):
472            calendar.monthrange(2004, 13)
473
474class LeapdaysTestCase(unittest.TestCase):
475    def test_no_range(self):
476        # test when no range i.e. two identical years as args
477        self.assertEqual(calendar.leapdays(2010,2010), 0)
478
479    def test_no_leapdays(self):
480        # test when no leap years in range
481        self.assertEqual(calendar.leapdays(2010,2011), 0)
482
483    def test_no_leapdays_upper_boundary(self):
484        # test no leap years in range, when upper boundary is a leap year
485        self.assertEqual(calendar.leapdays(2010,2012), 0)
486
487    def test_one_leapday_lower_boundary(self):
488        # test when one leap year in range, lower boundary is leap year
489        self.assertEqual(calendar.leapdays(2012,2013), 1)
490
491    def test_several_leapyears_in_range(self):
492        self.assertEqual(calendar.leapdays(1997,2020), 5)
493
494
495def conv(s):
496    return s.replace('\n', os.linesep)
497
498class CommandLineTestCase(unittest.TestCase):
499    def run_ok(self, *args):
500        return assert_python_ok('-m', 'calendar', *args)[1]
501
502    def assertFailure(self, *args):
503        rc, stdout, stderr = assert_python_failure('-m', 'calendar', *args)
504        self.assertIn(b'Usage:', stderr)
505        self.assertEqual(rc, 2)
506
507    def test_help(self):
508        stdout = self.run_ok('-h')
509        self.assertIn(b'Usage:', stdout)
510        self.assertIn(b'calendar.py', stdout)
511        self.assertIn(b'--help', stdout)
512
513    def test_illegal_arguments(self):
514        self.assertFailure('-z')
515        #self.assertFailure('spam')
516        #self.assertFailure('2004', 'spam')
517        self.assertFailure('-t', 'html', '2004', '1')
518
519    def test_output_current_year(self):
520        stdout = self.run_ok()
521        year = datetime.datetime.now().year
522        self.assertIn((' %s' % year).encode(), stdout)
523        self.assertIn(b'January', stdout)
524        self.assertIn(b'Mo Tu We Th Fr Sa Su', stdout)
525
526    def test_output_year(self):
527        stdout = self.run_ok('2004')
528        self.assertEqual(stdout.strip(), conv(result_2004_text).strip())
529
530    def test_output_month(self):
531        stdout = self.run_ok('2004', '1')
532        self.assertEqual(stdout.strip(), conv(result_2004_01_text).strip())
533
534    def test_option_encoding(self):
535        self.assertFailure('-e')
536        self.assertFailure('--encoding')
537        stdout = self.run_ok('--encoding', 'utf-16-le', '2004')
538        self.assertEqual(stdout.strip(), conv(result_2004_text.encode('utf-16-le')).strip())
539
540    def test_option_locale(self):
541        self.assertFailure('-L')
542        self.assertFailure('--locale')
543        self.assertFailure('-L', 'en')
544        lang, enc = locale.getdefaultlocale()
545        lang = lang or 'C'
546        enc = enc or 'UTF-8'
547        try:
548            oldlocale = locale.getlocale(locale.LC_TIME)
549            try:
550                locale.setlocale(locale.LC_TIME, (lang, enc))
551            finally:
552                locale.setlocale(locale.LC_TIME, oldlocale)
553        except (locale.Error, ValueError):
554            self.skipTest('cannot set the system default locale')
555        stdout = self.run_ok('--locale', lang, '--encoding', enc, '2004')
556        self.assertIn('2004'.encode(enc), stdout)
557
558    def test_option_width(self):
559        self.assertFailure('-w')
560        self.assertFailure('--width')
561        self.assertFailure('-w', 'spam')
562        stdout = self.run_ok('--width', '3', '2004')
563        self.assertIn(b'Mon Tue Wed Thu Fri Sat Sun', stdout)
564
565    def test_option_lines(self):
566        self.assertFailure('-l')
567        self.assertFailure('--lines')
568        self.assertFailure('-l', 'spam')
569        stdout = self.run_ok('--lines', '2', '2004')
570        self.assertIn(conv('December\n\nMo Tu We'), stdout)
571
572    def test_option_spacing(self):
573        self.assertFailure('-s')
574        self.assertFailure('--spacing')
575        self.assertFailure('-s', 'spam')
576        stdout = self.run_ok('--spacing', '8', '2004')
577        self.assertIn(b'Su        Mo', stdout)
578
579    def test_option_months(self):
580        self.assertFailure('-m')
581        self.assertFailure('--month')
582        self.assertFailure('-m', 'spam')
583        stdout = self.run_ok('--months', '1', '2004')
584        self.assertIn(conv('\nMo Tu We Th Fr Sa Su\n'), stdout)
585
586    def test_option_type(self):
587        self.assertFailure('-t')
588        self.assertFailure('--type')
589        self.assertFailure('-t', 'spam')
590        stdout = self.run_ok('--type', 'text', '2004')
591        self.assertEqual(stdout.strip(), conv(result_2004_text).strip())
592        stdout = self.run_ok('--type', 'html', '2004')
593        self.assertEqual(stdout[:6], b'<?xml ')
594        self.assertIn(b'<title>Calendar for 2004</title>', stdout)
595
596    def test_html_output_current_year(self):
597        stdout = self.run_ok('--type', 'html')
598        year = datetime.datetime.now().year
599        self.assertIn(('<title>Calendar for %s</title>' % year).encode(),
600                      stdout)
601        self.assertIn(b'<tr><th colspan="7" class="month">January</th></tr>',
602                      stdout)
603
604    def test_html_output_year_encoding(self):
605        stdout = self.run_ok('-t', 'html', '--encoding', 'ascii', '2004')
606        self.assertEqual(stdout.strip(), conv(result_2004_html).strip())
607
608    def test_html_output_year_css(self):
609        self.assertFailure('-t', 'html', '-c')
610        self.assertFailure('-t', 'html', '--css')
611        stdout = self.run_ok('-t', 'html', '--css', 'custom.css', '2004')
612        self.assertIn(b'<link rel="stylesheet" type="text/css" '
613                      b'href="custom.css" />', stdout)
614
615
616def test_main():
617    test_support.run_unittest(
618        OutputTestCase,
619        CalendarTestCase,
620        MondayTestCase,
621        SundayTestCase,
622        MonthRangeTestCase,
623        LeapdaysTestCase,
624        CommandLineTestCase,
625    )
626
627
628if __name__ == "__main__":
629    test_main()
630    unittest.main()
631