• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import calendar
2import unittest
3
4from test import support
5from test.support.script_helper import assert_python_ok, assert_python_failure
6import time
7import locale
8import sys
9import datetime
10import os
11
12# From https://en.wikipedia.org/wiki/Leap_year_starting_on_Saturday
13result_0_02_text = """\
14     February 0
15Mo Tu We Th Fr Sa Su
16    1  2  3  4  5  6
17 7  8  9 10 11 12 13
1814 15 16 17 18 19 20
1921 22 23 24 25 26 27
2028 29
21"""
22
23result_0_text = """\
24                                   0
25
26      January                   February                   March
27Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
28                1  2          1  2  3  4  5  6             1  2  3  4  5
29 3  4  5  6  7  8  9       7  8  9 10 11 12 13       6  7  8  9 10 11 12
3010 11 12 13 14 15 16      14 15 16 17 18 19 20      13 14 15 16 17 18 19
3117 18 19 20 21 22 23      21 22 23 24 25 26 27      20 21 22 23 24 25 26
3224 25 26 27 28 29 30      28 29                     27 28 29 30 31
3331
34
35       April                      May                       June
36Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
37                1  2       1  2  3  4  5  6  7                1  2  3  4
38 3  4  5  6  7  8  9       8  9 10 11 12 13 14       5  6  7  8  9 10 11
3910 11 12 13 14 15 16      15 16 17 18 19 20 21      12 13 14 15 16 17 18
4017 18 19 20 21 22 23      22 23 24 25 26 27 28      19 20 21 22 23 24 25
4124 25 26 27 28 29 30      29 30 31                  26 27 28 29 30
42
43        July                     August                  September
44Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
45                1  2          1  2  3  4  5  6                   1  2  3
46 3  4  5  6  7  8  9       7  8  9 10 11 12 13       4  5  6  7  8  9 10
4710 11 12 13 14 15 16      14 15 16 17 18 19 20      11 12 13 14 15 16 17
4817 18 19 20 21 22 23      21 22 23 24 25 26 27      18 19 20 21 22 23 24
4924 25 26 27 28 29 30      28 29 30 31               25 26 27 28 29 30
5031
51
52      October                   November                  December
53Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
54                   1             1  2  3  4  5                   1  2  3
55 2  3  4  5  6  7  8       6  7  8  9 10 11 12       4  5  6  7  8  9 10
56 9 10 11 12 13 14 15      13 14 15 16 17 18 19      11 12 13 14 15 16 17
5716 17 18 19 20 21 22      20 21 22 23 24 25 26      18 19 20 21 22 23 24
5823 24 25 26 27 28 29      27 28 29 30               25 26 27 28 29 30 31
5930 31
60"""
61
62result_2004_01_text = """\
63    January 2004
64Mo Tu We Th Fr Sa Su
65          1  2  3  4
66 5  6  7  8  9 10 11
6712 13 14 15 16 17 18
6819 20 21 22 23 24 25
6926 27 28 29 30 31
70"""
71
72result_2004_text = """\
73                                  2004
74
75      January                   February                   March
76Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
77          1  2  3  4                         1       1  2  3  4  5  6  7
78 5  6  7  8  9 10 11       2  3  4  5  6  7  8       8  9 10 11 12 13 14
7912 13 14 15 16 17 18       9 10 11 12 13 14 15      15 16 17 18 19 20 21
8019 20 21 22 23 24 25      16 17 18 19 20 21 22      22 23 24 25 26 27 28
8126 27 28 29 30 31         23 24 25 26 27 28 29      29 30 31
82
83       April                      May                       June
84Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
85          1  2  3  4                      1  2          1  2  3  4  5  6
86 5  6  7  8  9 10 11       3  4  5  6  7  8  9       7  8  9 10 11 12 13
8712 13 14 15 16 17 18      10 11 12 13 14 15 16      14 15 16 17 18 19 20
8819 20 21 22 23 24 25      17 18 19 20 21 22 23      21 22 23 24 25 26 27
8926 27 28 29 30            24 25 26 27 28 29 30      28 29 30
90                          31
91
92        July                     August                  September
93Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
94          1  2  3  4                         1             1  2  3  4  5
95 5  6  7  8  9 10 11       2  3  4  5  6  7  8       6  7  8  9 10 11 12
9612 13 14 15 16 17 18       9 10 11 12 13 14 15      13 14 15 16 17 18 19
9719 20 21 22 23 24 25      16 17 18 19 20 21 22      20 21 22 23 24 25 26
9826 27 28 29 30 31         23 24 25 26 27 28 29      27 28 29 30
99                          30 31
100
101      October                   November                  December
102Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
103             1  2  3       1  2  3  4  5  6  7             1  2  3  4  5
104 4  5  6  7  8  9 10       8  9 10 11 12 13 14       6  7  8  9 10 11 12
10511 12 13 14 15 16 17      15 16 17 18 19 20 21      13 14 15 16 17 18 19
10618 19 20 21 22 23 24      22 23 24 25 26 27 28      20 21 22 23 24 25 26
10725 26 27 28 29 30 31      29 30                     27 28 29 30 31
108"""
109
110
111default_format = dict(year="year", month="month", encoding="ascii")
112
113result_2004_html = """\
114<?xml version="1.0" encoding="{encoding}"?>
115<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
116<html>
117<head>
118<meta http-equiv="Content-Type" content="text/html; charset={encoding}" />
119<link rel="stylesheet" type="text/css" href="calendar.css" />
120<title>Calendar for 2004</title>
121</head>
122<body>
123<table border="0" cellpadding="0" cellspacing="0" class="{year}">
124<tr><th colspan="3" class="{year}">2004</th></tr><tr><td><table border="0" cellpadding="0" cellspacing="0" class="{month}">
125<tr><th colspan="7" class="{month}">January</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}">February</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</table>
142</td><td><table border="0" cellpadding="0" cellspacing="0" class="{month}">
143<tr><th colspan="7" class="{month}">March</th></tr>
144<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>
145<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>
146<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>
147<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>
148<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>
149<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>
150</table>
151</td></tr><tr><td><table border="0" cellpadding="0" cellspacing="0" class="{month}">
152<tr><th colspan="7" class="{month}">April</th></tr>
153<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>
154<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>
155<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>
156<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>
157<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>
158<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>
159</table>
160</td><td><table border="0" cellpadding="0" cellspacing="0" class="{month}">
161<tr><th colspan="7" class="{month}">May</th></tr>
162<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>
163<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>
164<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>
165<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>
166<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>
167<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>
168<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>
169</table>
170</td><td><table border="0" cellpadding="0" cellspacing="0" class="{month}">
171<tr><th colspan="7" class="{month}">June</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="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>
174<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>
175<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>
176<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>
177<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>
178</table>
179</td></tr><tr><td><table border="0" cellpadding="0" cellspacing="0" class="{month}">
180<tr><th colspan="7" class="{month}">July</th></tr>
181<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>
182<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>
183<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>
184<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>
185<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>
186<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>
187</table>
188</td><td><table border="0" cellpadding="0" cellspacing="0" class="{month}">
189<tr><th colspan="7" class="{month}">August</th></tr>
190<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>
191<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>
192<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>
193<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>
194<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>
195<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>
196<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>
197</table>
198</td><td><table border="0" cellpadding="0" cellspacing="0" class="{month}">
199<tr><th colspan="7" class="{month}">September</th></tr>
200<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>
201<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>
202<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>
203<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>
204<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>
205<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>
206</table>
207</td></tr><tr><td><table border="0" cellpadding="0" cellspacing="0" class="{month}">
208<tr><th colspan="7" class="{month}">October</th></tr>
209<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>
210<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>
211<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>
212<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>
213<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>
214<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>
215</table>
216</td><td><table border="0" cellpadding="0" cellspacing="0" class="{month}">
217<tr><th colspan="7" class="{month}">November</th></tr>
218<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>
219<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>
220<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>
221<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>
222<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>
223<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>
224</table>
225</td><td><table border="0" cellpadding="0" cellspacing="0" class="{month}">
226<tr><th colspan="7" class="{month}">December</th></tr>
227<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>
228<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>
229<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>
230<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>
231<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>
232<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>
233</table>
234</td></tr></table></body>
235</html>
236"""
237
238result_2004_days = [
239    [[[0, 0, 0, 1, 2, 3, 4],
240      [5, 6, 7, 8, 9, 10, 11],
241      [12, 13, 14, 15, 16, 17, 18],
242      [19, 20, 21, 22, 23, 24, 25],
243      [26, 27, 28, 29, 30, 31, 0]],
244     [[0, 0, 0, 0, 0, 0, 1],
245      [2, 3, 4, 5, 6, 7, 8],
246      [9, 10, 11, 12, 13, 14, 15],
247      [16, 17, 18, 19, 20, 21, 22],
248      [23, 24, 25, 26, 27, 28, 29]],
249     [[1, 2, 3, 4, 5, 6, 7],
250      [8, 9, 10, 11, 12, 13, 14],
251      [15, 16, 17, 18, 19, 20, 21],
252      [22, 23, 24, 25, 26, 27, 28],
253      [29, 30, 31, 0, 0, 0, 0]]],
254    [[[0, 0, 0, 1, 2, 3, 4],
255      [5, 6, 7, 8, 9, 10, 11],
256      [12, 13, 14, 15, 16, 17, 18],
257      [19, 20, 21, 22, 23, 24, 25],
258      [26, 27, 28, 29, 30, 0, 0]],
259     [[0, 0, 0, 0, 0, 1, 2],
260      [3, 4, 5, 6, 7, 8, 9],
261      [10, 11, 12, 13, 14, 15, 16],
262      [17, 18, 19, 20, 21, 22, 23],
263      [24, 25, 26, 27, 28, 29, 30],
264      [31, 0, 0, 0, 0, 0, 0]],
265     [[0, 1, 2, 3, 4, 5, 6],
266      [7, 8, 9, 10, 11, 12, 13],
267      [14, 15, 16, 17, 18, 19, 20],
268      [21, 22, 23, 24, 25, 26, 27],
269      [28, 29, 30, 0, 0, 0, 0]]],
270    [[[0, 0, 0, 1, 2, 3, 4],
271      [5, 6, 7, 8, 9, 10, 11],
272      [12, 13, 14, 15, 16, 17, 18],
273      [19, 20, 21, 22, 23, 24, 25],
274      [26, 27, 28, 29, 30, 31, 0]],
275     [[0, 0, 0, 0, 0, 0, 1],
276      [2, 3, 4, 5, 6, 7, 8],
277      [9, 10, 11, 12, 13, 14, 15],
278      [16, 17, 18, 19, 20, 21, 22],
279      [23, 24, 25, 26, 27, 28, 29],
280      [30, 31, 0, 0, 0, 0, 0]],
281     [[0, 0, 1, 2, 3, 4, 5],
282      [6, 7, 8, 9, 10, 11, 12],
283      [13, 14, 15, 16, 17, 18, 19],
284      [20, 21, 22, 23, 24, 25, 26],
285      [27, 28, 29, 30, 0, 0, 0]]],
286    [[[0, 0, 0, 0, 1, 2, 3],
287      [4, 5, 6, 7, 8, 9, 10],
288      [11, 12, 13, 14, 15, 16, 17],
289      [18, 19, 20, 21, 22, 23, 24],
290      [25, 26, 27, 28, 29, 30, 31]],
291     [[1, 2, 3, 4, 5, 6, 7],
292      [8, 9, 10, 11, 12, 13, 14],
293      [15, 16, 17, 18, 19, 20, 21],
294      [22, 23, 24, 25, 26, 27, 28],
295      [29, 30, 0, 0, 0, 0, 0]],
296     [[0, 0, 1, 2, 3, 4, 5],
297      [6, 7, 8, 9, 10, 11, 12],
298      [13, 14, 15, 16, 17, 18, 19],
299      [20, 21, 22, 23, 24, 25, 26],
300      [27, 28, 29, 30, 31, 0, 0]]]
301]
302
303result_2004_dates = \
304    [[['12/29/03 12/30/03 12/31/03 01/01/04 01/02/04 01/03/04 01/04/04',
305       '01/05/04 01/06/04 01/07/04 01/08/04 01/09/04 01/10/04 01/11/04',
306       '01/12/04 01/13/04 01/14/04 01/15/04 01/16/04 01/17/04 01/18/04',
307       '01/19/04 01/20/04 01/21/04 01/22/04 01/23/04 01/24/04 01/25/04',
308       '01/26/04 01/27/04 01/28/04 01/29/04 01/30/04 01/31/04 02/01/04'],
309      ['01/26/04 01/27/04 01/28/04 01/29/04 01/30/04 01/31/04 02/01/04',
310       '02/02/04 02/03/04 02/04/04 02/05/04 02/06/04 02/07/04 02/08/04',
311       '02/09/04 02/10/04 02/11/04 02/12/04 02/13/04 02/14/04 02/15/04',
312       '02/16/04 02/17/04 02/18/04 02/19/04 02/20/04 02/21/04 02/22/04',
313       '02/23/04 02/24/04 02/25/04 02/26/04 02/27/04 02/28/04 02/29/04'],
314      ['03/01/04 03/02/04 03/03/04 03/04/04 03/05/04 03/06/04 03/07/04',
315       '03/08/04 03/09/04 03/10/04 03/11/04 03/12/04 03/13/04 03/14/04',
316       '03/15/04 03/16/04 03/17/04 03/18/04 03/19/04 03/20/04 03/21/04',
317       '03/22/04 03/23/04 03/24/04 03/25/04 03/26/04 03/27/04 03/28/04',
318       '03/29/04 03/30/04 03/31/04 04/01/04 04/02/04 04/03/04 04/04/04']],
319     [['03/29/04 03/30/04 03/31/04 04/01/04 04/02/04 04/03/04 04/04/04',
320       '04/05/04 04/06/04 04/07/04 04/08/04 04/09/04 04/10/04 04/11/04',
321       '04/12/04 04/13/04 04/14/04 04/15/04 04/16/04 04/17/04 04/18/04',
322       '04/19/04 04/20/04 04/21/04 04/22/04 04/23/04 04/24/04 04/25/04',
323       '04/26/04 04/27/04 04/28/04 04/29/04 04/30/04 05/01/04 05/02/04'],
324      ['04/26/04 04/27/04 04/28/04 04/29/04 04/30/04 05/01/04 05/02/04',
325       '05/03/04 05/04/04 05/05/04 05/06/04 05/07/04 05/08/04 05/09/04',
326       '05/10/04 05/11/04 05/12/04 05/13/04 05/14/04 05/15/04 05/16/04',
327       '05/17/04 05/18/04 05/19/04 05/20/04 05/21/04 05/22/04 05/23/04',
328       '05/24/04 05/25/04 05/26/04 05/27/04 05/28/04 05/29/04 05/30/04',
329       '05/31/04 06/01/04 06/02/04 06/03/04 06/04/04 06/05/04 06/06/04'],
330      ['05/31/04 06/01/04 06/02/04 06/03/04 06/04/04 06/05/04 06/06/04',
331       '06/07/04 06/08/04 06/09/04 06/10/04 06/11/04 06/12/04 06/13/04',
332       '06/14/04 06/15/04 06/16/04 06/17/04 06/18/04 06/19/04 06/20/04',
333       '06/21/04 06/22/04 06/23/04 06/24/04 06/25/04 06/26/04 06/27/04',
334       '06/28/04 06/29/04 06/30/04 07/01/04 07/02/04 07/03/04 07/04/04']],
335     [['06/28/04 06/29/04 06/30/04 07/01/04 07/02/04 07/03/04 07/04/04',
336       '07/05/04 07/06/04 07/07/04 07/08/04 07/09/04 07/10/04 07/11/04',
337       '07/12/04 07/13/04 07/14/04 07/15/04 07/16/04 07/17/04 07/18/04',
338       '07/19/04 07/20/04 07/21/04 07/22/04 07/23/04 07/24/04 07/25/04',
339       '07/26/04 07/27/04 07/28/04 07/29/04 07/30/04 07/31/04 08/01/04'],
340      ['07/26/04 07/27/04 07/28/04 07/29/04 07/30/04 07/31/04 08/01/04',
341       '08/02/04 08/03/04 08/04/04 08/05/04 08/06/04 08/07/04 08/08/04',
342       '08/09/04 08/10/04 08/11/04 08/12/04 08/13/04 08/14/04 08/15/04',
343       '08/16/04 08/17/04 08/18/04 08/19/04 08/20/04 08/21/04 08/22/04',
344       '08/23/04 08/24/04 08/25/04 08/26/04 08/27/04 08/28/04 08/29/04',
345       '08/30/04 08/31/04 09/01/04 09/02/04 09/03/04 09/04/04 09/05/04'],
346      ['08/30/04 08/31/04 09/01/04 09/02/04 09/03/04 09/04/04 09/05/04',
347       '09/06/04 09/07/04 09/08/04 09/09/04 09/10/04 09/11/04 09/12/04',
348       '09/13/04 09/14/04 09/15/04 09/16/04 09/17/04 09/18/04 09/19/04',
349       '09/20/04 09/21/04 09/22/04 09/23/04 09/24/04 09/25/04 09/26/04',
350       '09/27/04 09/28/04 09/29/04 09/30/04 10/01/04 10/02/04 10/03/04']],
351     [['09/27/04 09/28/04 09/29/04 09/30/04 10/01/04 10/02/04 10/03/04',
352       '10/04/04 10/05/04 10/06/04 10/07/04 10/08/04 10/09/04 10/10/04',
353       '10/11/04 10/12/04 10/13/04 10/14/04 10/15/04 10/16/04 10/17/04',
354       '10/18/04 10/19/04 10/20/04 10/21/04 10/22/04 10/23/04 10/24/04',
355       '10/25/04 10/26/04 10/27/04 10/28/04 10/29/04 10/30/04 10/31/04'],
356      ['11/01/04 11/02/04 11/03/04 11/04/04 11/05/04 11/06/04 11/07/04',
357       '11/08/04 11/09/04 11/10/04 11/11/04 11/12/04 11/13/04 11/14/04',
358       '11/15/04 11/16/04 11/17/04 11/18/04 11/19/04 11/20/04 11/21/04',
359       '11/22/04 11/23/04 11/24/04 11/25/04 11/26/04 11/27/04 11/28/04',
360       '11/29/04 11/30/04 12/01/04 12/02/04 12/03/04 12/04/04 12/05/04'],
361      ['11/29/04 11/30/04 12/01/04 12/02/04 12/03/04 12/04/04 12/05/04',
362       '12/06/04 12/07/04 12/08/04 12/09/04 12/10/04 12/11/04 12/12/04',
363       '12/13/04 12/14/04 12/15/04 12/16/04 12/17/04 12/18/04 12/19/04',
364       '12/20/04 12/21/04 12/22/04 12/23/04 12/24/04 12/25/04 12/26/04',
365       '12/27/04 12/28/04 12/29/04 12/30/04 12/31/04 01/01/05 01/02/05']]]
366
367
368class OutputTestCase(unittest.TestCase):
369    def normalize_calendar(self, s):
370        # Filters out locale dependent strings
371        def neitherspacenordigit(c):
372            return not c.isspace() and not c.isdigit()
373
374        lines = []
375        for line in s.splitlines(keepends=False):
376            # Drop texts, as they are locale dependent
377            if line and not filter(neitherspacenordigit, line):
378                lines.append(line)
379        return lines
380
381    def check_htmlcalendar_encoding(self, req, res):
382        cal = calendar.HTMLCalendar()
383        format_ = default_format.copy()
384        format_["encoding"] = req or 'utf-8'
385        output = cal.formatyearpage(2004, encoding=req)
386        self.assertEqual(
387            output,
388            result_2004_html.format(**format_).encode(res)
389        )
390
391    def test_output(self):
392        self.assertEqual(
393            self.normalize_calendar(calendar.calendar(2004)),
394            self.normalize_calendar(result_2004_text)
395        )
396        self.assertEqual(
397            self.normalize_calendar(calendar.calendar(0)),
398            self.normalize_calendar(result_0_text)
399        )
400
401    def test_output_textcalendar(self):
402        self.assertEqual(
403            calendar.TextCalendar().formatyear(2004),
404            result_2004_text
405        )
406        self.assertEqual(
407            calendar.TextCalendar().formatyear(0),
408            result_0_text
409        )
410
411    def test_output_htmlcalendar_encoding_ascii(self):
412        self.check_htmlcalendar_encoding('ascii', 'ascii')
413
414    def test_output_htmlcalendar_encoding_utf8(self):
415        self.check_htmlcalendar_encoding('utf-8', 'utf-8')
416
417    def test_output_htmlcalendar_encoding_default(self):
418        self.check_htmlcalendar_encoding(None, sys.getdefaultencoding())
419
420    def test_yeardatescalendar(self):
421        def shrink(cal):
422            return [[[' '.join('{:02d}/{:02d}/{}'.format(
423                                d.month, d.day, str(d.year)[-2:]) for d in z)
424                            for z in y] for y in x] for x in cal]
425        self.assertEqual(
426            shrink(calendar.Calendar().yeardatescalendar(2004)),
427            result_2004_dates
428        )
429
430    def test_yeardayscalendar(self):
431        self.assertEqual(
432            calendar.Calendar().yeardayscalendar(2004),
433            result_2004_days
434        )
435
436    def test_formatweekheader_short(self):
437        self.assertEqual(
438            calendar.TextCalendar().formatweekheader(2),
439            'Mo Tu We Th Fr Sa Su'
440        )
441
442    def test_formatweekheader_long(self):
443        self.assertEqual(
444            calendar.TextCalendar().formatweekheader(9),
445            '  Monday   Tuesday  Wednesday  Thursday '
446            '  Friday   Saturday   Sunday '
447        )
448
449    def test_formatmonth(self):
450        self.assertEqual(
451            calendar.TextCalendar().formatmonth(2004, 1),
452            result_2004_01_text
453        )
454        self.assertEqual(
455            calendar.TextCalendar().formatmonth(0, 2),
456            result_0_02_text
457        )
458
459    def test_formatmonthname_with_year(self):
460        self.assertEqual(
461            calendar.HTMLCalendar().formatmonthname(2004, 1, withyear=True),
462            '<tr><th colspan="7" class="month">January 2004</th></tr>'
463        )
464
465    def test_formatmonthname_without_year(self):
466        self.assertEqual(
467            calendar.HTMLCalendar().formatmonthname(2004, 1, withyear=False),
468            '<tr><th colspan="7" class="month">January</th></tr>'
469        )
470
471    def test_prweek(self):
472        with support.captured_stdout() as out:
473            week = [(1,0), (2,1), (3,2), (4,3), (5,4), (6,5), (7,6)]
474            calendar.TextCalendar().prweek(week, 1)
475            self.assertEqual(out.getvalue(), " 1  2  3  4  5  6  7")
476
477    def test_prmonth(self):
478        with support.captured_stdout() as out:
479            calendar.TextCalendar().prmonth(2004, 1)
480            self.assertEqual(out.getvalue(), result_2004_01_text)
481
482    def test_pryear(self):
483        with support.captured_stdout() as out:
484            calendar.TextCalendar().pryear(2004)
485            self.assertEqual(out.getvalue(), result_2004_text)
486
487    def test_format(self):
488        with support.captured_stdout() as out:
489            calendar.format(["1", "2", "3"], colwidth=3, spacing=1)
490            self.assertEqual(out.getvalue().strip(), "1   2   3")
491
492class CalendarTestCase(unittest.TestCase):
493    def test_isleap(self):
494        # Make sure that the return is right for a few years, and
495        # ensure that the return values are 1 or 0, not just true or
496        # false (see SF bug #485794).  Specific additional tests may
497        # be appropriate; this tests a single "cycle".
498        self.assertEqual(calendar.isleap(2000), 1)
499        self.assertEqual(calendar.isleap(2001), 0)
500        self.assertEqual(calendar.isleap(2002), 0)
501        self.assertEqual(calendar.isleap(2003), 0)
502
503    def test_setfirstweekday(self):
504        self.assertRaises(TypeError, calendar.setfirstweekday, 'flabber')
505        self.assertRaises(ValueError, calendar.setfirstweekday, -1)
506        self.assertRaises(ValueError, calendar.setfirstweekday, 200)
507        orig = calendar.firstweekday()
508        calendar.setfirstweekday(calendar.SUNDAY)
509        self.assertEqual(calendar.firstweekday(), calendar.SUNDAY)
510        calendar.setfirstweekday(calendar.MONDAY)
511        self.assertEqual(calendar.firstweekday(), calendar.MONDAY)
512        calendar.setfirstweekday(orig)
513
514    def test_illegal_weekday_reported(self):
515        with self.assertRaisesRegex(calendar.IllegalWeekdayError, '123'):
516            calendar.setfirstweekday(123)
517
518    def test_enumerate_weekdays(self):
519        self.assertRaises(IndexError, calendar.day_abbr.__getitem__, -10)
520        self.assertRaises(IndexError, calendar.day_name.__getitem__, 10)
521        self.assertEqual(len([d for d in calendar.day_abbr]), 7)
522
523    def test_days(self):
524        for attr in "day_name", "day_abbr":
525            value = getattr(calendar, attr)
526            self.assertEqual(len(value), 7)
527            self.assertEqual(len(value[:]), 7)
528            # ensure they're all unique
529            self.assertEqual(len(set(value)), 7)
530            # verify it "acts like a sequence" in two forms of iteration
531            self.assertEqual(value[::-1], list(reversed(value)))
532
533    def test_months(self):
534        for attr in "month_name", "month_abbr":
535            value = getattr(calendar, attr)
536            self.assertEqual(len(value), 13)
537            self.assertEqual(len(value[:]), 13)
538            self.assertEqual(value[0], "")
539            # ensure they're all unique
540            self.assertEqual(len(set(value)), 13)
541            # verify it "acts like a sequence" in two forms of iteration
542            self.assertEqual(value[::-1], list(reversed(value)))
543
544    def test_locale_calendars(self):
545        # ensure that Locale{Text,HTML}Calendar resets the locale properly
546        # (it is still not thread-safe though)
547        old_october = calendar.TextCalendar().formatmonthname(2010, 10, 10)
548        try:
549            cal = calendar.LocaleTextCalendar(locale='')
550            local_weekday = cal.formatweekday(1, 10)
551            local_month = cal.formatmonthname(2010, 10, 10)
552        except locale.Error:
553            # cannot set the system default locale -- skip rest of test
554            raise unittest.SkipTest('cannot set the system default locale')
555        self.assertIsInstance(local_weekday, str)
556        self.assertIsInstance(local_month, str)
557        self.assertEqual(len(local_weekday), 10)
558        self.assertGreaterEqual(len(local_month), 10)
559        cal = calendar.LocaleHTMLCalendar(locale='')
560        local_weekday = cal.formatweekday(1)
561        local_month = cal.formatmonthname(2010, 10)
562        self.assertIsInstance(local_weekday, str)
563        self.assertIsInstance(local_month, str)
564        new_october = calendar.TextCalendar().formatmonthname(2010, 10, 10)
565        self.assertEqual(old_october, new_october)
566
567    def test_locale_html_calendar_custom_css_class_month_name(self):
568        try:
569            cal = calendar.LocaleHTMLCalendar(locale='')
570            local_month = cal.formatmonthname(2010, 10, 10)
571        except locale.Error:
572            # cannot set the system default locale -- skip rest of test
573            raise unittest.SkipTest('cannot set the system default locale')
574        self.assertIn('class="month"', local_month)
575        cal.cssclass_month_head = "text-center month"
576        local_month = cal.formatmonthname(2010, 10, 10)
577        self.assertIn('class="text-center month"', local_month)
578
579    def test_locale_html_calendar_custom_css_class_weekday(self):
580        try:
581            cal = calendar.LocaleHTMLCalendar(locale='')
582            local_weekday = cal.formatweekday(6)
583        except locale.Error:
584            # cannot set the system default locale -- skip rest of test
585            raise unittest.SkipTest('cannot set the system default locale')
586        self.assertIn('class="sun"', local_weekday)
587        cal.cssclasses_weekday_head = ["mon2", "tue2", "wed2", "thu2", "fri2", "sat2", "sun2"]
588        local_weekday = cal.formatweekday(6)
589        self.assertIn('class="sun2"', local_weekday)
590
591    def test_itermonthdays3(self):
592        # ensure itermonthdays3 doesn't overflow after datetime.MAXYEAR
593        list(calendar.Calendar().itermonthdays3(datetime.MAXYEAR, 12))
594
595    def test_itermonthdays4(self):
596        cal = calendar.Calendar(firstweekday=3)
597        days = list(cal.itermonthdays4(2001, 2))
598        self.assertEqual(days[0], (2001, 2, 1, 3))
599        self.assertEqual(days[-1], (2001, 2, 28, 2))
600
601    def test_itermonthdays(self):
602        for firstweekday in range(7):
603            cal = calendar.Calendar(firstweekday)
604            # Test the extremes, see #28253 and #26650
605            for y, m in [(1, 1), (9999, 12)]:
606                days = list(cal.itermonthdays(y, m))
607                self.assertIn(len(days), (35, 42))
608        # Test a short month
609        cal = calendar.Calendar(firstweekday=3)
610        days = list(cal.itermonthdays(2001, 2))
611        self.assertEqual(days, list(range(1, 29)))
612
613    def test_itermonthdays2(self):
614        for firstweekday in range(7):
615            cal = calendar.Calendar(firstweekday)
616            # Test the extremes, see #28253 and #26650
617            for y, m in [(1, 1), (9999, 12)]:
618                days = list(cal.itermonthdays2(y, m))
619                self.assertEqual(days[0][1], firstweekday)
620                self.assertEqual(days[-1][1], (firstweekday - 1) % 7)
621
622
623class MonthCalendarTestCase(unittest.TestCase):
624    def setUp(self):
625        self.oldfirstweekday = calendar.firstweekday()
626        calendar.setfirstweekday(self.firstweekday)
627
628    def tearDown(self):
629        calendar.setfirstweekday(self.oldfirstweekday)
630
631    def check_weeks(self, year, month, weeks):
632        cal = calendar.monthcalendar(year, month)
633        self.assertEqual(len(cal), len(weeks))
634        for i in range(len(weeks)):
635            self.assertEqual(weeks[i], sum(day != 0 for day in cal[i]))
636
637
638class MondayTestCase(MonthCalendarTestCase):
639    firstweekday = calendar.MONDAY
640
641    def test_february(self):
642        # A 28-day february starting on monday (7+7+7+7 days)
643        self.check_weeks(1999, 2, (7, 7, 7, 7))
644
645        # A 28-day february starting on tuesday (6+7+7+7+1 days)
646        self.check_weeks(2005, 2, (6, 7, 7, 7, 1))
647
648        # A 28-day february starting on sunday (1+7+7+7+6 days)
649        self.check_weeks(1987, 2, (1, 7, 7, 7, 6))
650
651        # A 29-day february starting on monday (7+7+7+7+1 days)
652        self.check_weeks(1988, 2, (7, 7, 7, 7, 1))
653
654        # A 29-day february starting on tuesday (6+7+7+7+2 days)
655        self.check_weeks(1972, 2, (6, 7, 7, 7, 2))
656
657        # A 29-day february starting on sunday (1+7+7+7+7 days)
658        self.check_weeks(2004, 2, (1, 7, 7, 7, 7))
659
660    def test_april(self):
661        # A 30-day april starting on monday (7+7+7+7+2 days)
662        self.check_weeks(1935, 4, (7, 7, 7, 7, 2))
663
664        # A 30-day april starting on tuesday (6+7+7+7+3 days)
665        self.check_weeks(1975, 4, (6, 7, 7, 7, 3))
666
667        # A 30-day april starting on sunday (1+7+7+7+7+1 days)
668        self.check_weeks(1945, 4, (1, 7, 7, 7, 7, 1))
669
670        # A 30-day april starting on saturday (2+7+7+7+7 days)
671        self.check_weeks(1995, 4, (2, 7, 7, 7, 7))
672
673        # A 30-day april starting on friday (3+7+7+7+6 days)
674        self.check_weeks(1994, 4, (3, 7, 7, 7, 6))
675
676    def test_december(self):
677        # A 31-day december starting on monday (7+7+7+7+3 days)
678        self.check_weeks(1980, 12, (7, 7, 7, 7, 3))
679
680        # A 31-day december starting on tuesday (6+7+7+7+4 days)
681        self.check_weeks(1987, 12, (6, 7, 7, 7, 4))
682
683        # A 31-day december starting on sunday (1+7+7+7+7+2 days)
684        self.check_weeks(1968, 12, (1, 7, 7, 7, 7, 2))
685
686        # A 31-day december starting on thursday (4+7+7+7+6 days)
687        self.check_weeks(1988, 12, (4, 7, 7, 7, 6))
688
689        # A 31-day december starting on friday (3+7+7+7+7 days)
690        self.check_weeks(2017, 12, (3, 7, 7, 7, 7))
691
692        # A 31-day december starting on saturday (2+7+7+7+7+1 days)
693        self.check_weeks(2068, 12, (2, 7, 7, 7, 7, 1))
694
695
696class SundayTestCase(MonthCalendarTestCase):
697    firstweekday = calendar.SUNDAY
698
699    def test_february(self):
700        # A 28-day february starting on sunday (7+7+7+7 days)
701        self.check_weeks(2009, 2, (7, 7, 7, 7))
702
703        # A 28-day february starting on monday (6+7+7+7+1 days)
704        self.check_weeks(1999, 2, (6, 7, 7, 7, 1))
705
706        # A 28-day february starting on saturday (1+7+7+7+6 days)
707        self.check_weeks(1997, 2, (1, 7, 7, 7, 6))
708
709        # A 29-day february starting on sunday (7+7+7+7+1 days)
710        self.check_weeks(2004, 2, (7, 7, 7, 7, 1))
711
712        # A 29-day february starting on monday (6+7+7+7+2 days)
713        self.check_weeks(1960, 2, (6, 7, 7, 7, 2))
714
715        # A 29-day february starting on saturday (1+7+7+7+7 days)
716        self.check_weeks(1964, 2, (1, 7, 7, 7, 7))
717
718    def test_april(self):
719        # A 30-day april starting on sunday (7+7+7+7+2 days)
720        self.check_weeks(1923, 4, (7, 7, 7, 7, 2))
721
722        # A 30-day april starting on monday (6+7+7+7+3 days)
723        self.check_weeks(1918, 4, (6, 7, 7, 7, 3))
724
725        # A 30-day april starting on saturday (1+7+7+7+7+1 days)
726        self.check_weeks(1950, 4, (1, 7, 7, 7, 7, 1))
727
728        # A 30-day april starting on friday (2+7+7+7+7 days)
729        self.check_weeks(1960, 4, (2, 7, 7, 7, 7))
730
731        # A 30-day april starting on thursday (3+7+7+7+6 days)
732        self.check_weeks(1909, 4, (3, 7, 7, 7, 6))
733
734    def test_december(self):
735        # A 31-day december starting on sunday (7+7+7+7+3 days)
736        self.check_weeks(2080, 12, (7, 7, 7, 7, 3))
737
738        # A 31-day december starting on monday (6+7+7+7+4 days)
739        self.check_weeks(1941, 12, (6, 7, 7, 7, 4))
740
741        # A 31-day december starting on saturday (1+7+7+7+7+2 days)
742        self.check_weeks(1923, 12, (1, 7, 7, 7, 7, 2))
743
744        # A 31-day december starting on wednesday (4+7+7+7+6 days)
745        self.check_weeks(1948, 12, (4, 7, 7, 7, 6))
746
747        # A 31-day december starting on thursday (3+7+7+7+7 days)
748        self.check_weeks(1927, 12, (3, 7, 7, 7, 7))
749
750        # A 31-day december starting on friday (2+7+7+7+7+1 days)
751        self.check_weeks(1995, 12, (2, 7, 7, 7, 7, 1))
752
753class TimegmTestCase(unittest.TestCase):
754    TIMESTAMPS = [0, 10, 100, 1000, 10000, 100000, 1000000,
755                  1234567890, 1262304000, 1275785153,]
756    def test_timegm(self):
757        for secs in self.TIMESTAMPS:
758            tuple = time.gmtime(secs)
759            self.assertEqual(secs, calendar.timegm(tuple))
760
761class MonthRangeTestCase(unittest.TestCase):
762    def test_january(self):
763        # Tests valid lower boundary case.
764        self.assertEqual(calendar.monthrange(2004,1), (3,31))
765
766    def test_february_leap(self):
767        # Tests February during leap year.
768        self.assertEqual(calendar.monthrange(2004,2), (6,29))
769
770    def test_february_nonleap(self):
771        # Tests February in non-leap year.
772        self.assertEqual(calendar.monthrange(2010,2), (0,28))
773
774    def test_december(self):
775        # Tests valid upper boundary case.
776        self.assertEqual(calendar.monthrange(2004,12), (2,31))
777
778    def test_zeroth_month(self):
779        # Tests low invalid boundary case.
780        with self.assertRaises(calendar.IllegalMonthError):
781            calendar.monthrange(2004, 0)
782
783    def test_thirteenth_month(self):
784        # Tests high invalid boundary case.
785        with self.assertRaises(calendar.IllegalMonthError):
786            calendar.monthrange(2004, 13)
787
788    def test_illegal_month_reported(self):
789        with self.assertRaisesRegex(calendar.IllegalMonthError, '65'):
790            calendar.monthrange(2004, 65)
791
792class LeapdaysTestCase(unittest.TestCase):
793    def test_no_range(self):
794        # test when no range i.e. two identical years as args
795        self.assertEqual(calendar.leapdays(2010,2010), 0)
796
797    def test_no_leapdays(self):
798        # test when no leap years in range
799        self.assertEqual(calendar.leapdays(2010,2011), 0)
800
801    def test_no_leapdays_upper_boundary(self):
802        # test no leap years in range, when upper boundary is a leap year
803        self.assertEqual(calendar.leapdays(2010,2012), 0)
804
805    def test_one_leapday_lower_boundary(self):
806        # test when one leap year in range, lower boundary is leap year
807        self.assertEqual(calendar.leapdays(2012,2013), 1)
808
809    def test_several_leapyears_in_range(self):
810        self.assertEqual(calendar.leapdays(1997,2020), 5)
811
812
813def conv(s):
814    return s.replace('\n', os.linesep).encode()
815
816class CommandLineTestCase(unittest.TestCase):
817    def run_ok(self, *args):
818        return assert_python_ok('-m', 'calendar', *args)[1]
819
820    def assertFailure(self, *args):
821        rc, stdout, stderr = assert_python_failure('-m', 'calendar', *args)
822        self.assertIn(b'usage:', stderr)
823        self.assertEqual(rc, 2)
824
825    def test_help(self):
826        stdout = self.run_ok('-h')
827        self.assertIn(b'usage:', stdout)
828        self.assertIn(b'calendar.py', stdout)
829        self.assertIn(b'--help', stdout)
830
831    def test_illegal_arguments(self):
832        self.assertFailure('-z')
833        self.assertFailure('spam')
834        self.assertFailure('2004', 'spam')
835        self.assertFailure('-t', 'html', '2004', '1')
836
837    def test_output_current_year(self):
838        stdout = self.run_ok()
839        year = datetime.datetime.now().year
840        self.assertIn((' %s' % year).encode(), stdout)
841        self.assertIn(b'January', stdout)
842        self.assertIn(b'Mo Tu We Th Fr Sa Su', stdout)
843
844    def test_output_year(self):
845        stdout = self.run_ok('2004')
846        self.assertEqual(stdout, conv(result_2004_text))
847
848    def test_output_month(self):
849        stdout = self.run_ok('2004', '1')
850        self.assertEqual(stdout, conv(result_2004_01_text))
851
852    def test_option_encoding(self):
853        self.assertFailure('-e')
854        self.assertFailure('--encoding')
855        stdout = self.run_ok('--encoding', 'utf-16-le', '2004')
856        self.assertEqual(stdout, result_2004_text.encode('utf-16-le'))
857
858    def test_option_locale(self):
859        self.assertFailure('-L')
860        self.assertFailure('--locale')
861        self.assertFailure('-L', 'en')
862        lang, enc = locale.getdefaultlocale()
863        lang = lang or 'C'
864        enc = enc or 'UTF-8'
865        try:
866            oldlocale = locale.getlocale(locale.LC_TIME)
867            try:
868                locale.setlocale(locale.LC_TIME, (lang, enc))
869            finally:
870                locale.setlocale(locale.LC_TIME, oldlocale)
871        except (locale.Error, ValueError):
872            self.skipTest('cannot set the system default locale')
873        stdout = self.run_ok('--locale', lang, '--encoding', enc, '2004')
874        self.assertIn('2004'.encode(enc), stdout)
875
876    def test_option_width(self):
877        self.assertFailure('-w')
878        self.assertFailure('--width')
879        self.assertFailure('-w', 'spam')
880        stdout = self.run_ok('--width', '3', '2004')
881        self.assertIn(b'Mon Tue Wed Thu Fri Sat Sun', stdout)
882
883    def test_option_lines(self):
884        self.assertFailure('-l')
885        self.assertFailure('--lines')
886        self.assertFailure('-l', 'spam')
887        stdout = self.run_ok('--lines', '2', '2004')
888        self.assertIn(conv('December\n\nMo Tu We'), stdout)
889
890    def test_option_spacing(self):
891        self.assertFailure('-s')
892        self.assertFailure('--spacing')
893        self.assertFailure('-s', 'spam')
894        stdout = self.run_ok('--spacing', '8', '2004')
895        self.assertIn(b'Su        Mo', stdout)
896
897    def test_option_months(self):
898        self.assertFailure('-m')
899        self.assertFailure('--month')
900        self.assertFailure('-m', 'spam')
901        stdout = self.run_ok('--months', '1', '2004')
902        self.assertIn(conv('\nMo Tu We Th Fr Sa Su\n'), stdout)
903
904    def test_option_type(self):
905        self.assertFailure('-t')
906        self.assertFailure('--type')
907        self.assertFailure('-t', 'spam')
908        stdout = self.run_ok('--type', 'text', '2004')
909        self.assertEqual(stdout, conv(result_2004_text))
910        stdout = self.run_ok('--type', 'html', '2004')
911        self.assertEqual(stdout[:6], b'<?xml ')
912        self.assertIn(b'<title>Calendar for 2004</title>', stdout)
913
914    def test_html_output_current_year(self):
915        stdout = self.run_ok('--type', 'html')
916        year = datetime.datetime.now().year
917        self.assertIn(('<title>Calendar for %s</title>' % year).encode(),
918                      stdout)
919        self.assertIn(b'<tr><th colspan="7" class="month">January</th></tr>',
920                      stdout)
921
922    def test_html_output_year_encoding(self):
923        stdout = self.run_ok('-t', 'html', '--encoding', 'ascii', '2004')
924        self.assertEqual(stdout,
925                         result_2004_html.format(**default_format).encode('ascii'))
926
927    def test_html_output_year_css(self):
928        self.assertFailure('-t', 'html', '-c')
929        self.assertFailure('-t', 'html', '--css')
930        stdout = self.run_ok('-t', 'html', '--css', 'custom.css', '2004')
931        self.assertIn(b'<link rel="stylesheet" type="text/css" '
932                      b'href="custom.css" />', stdout)
933
934
935class MiscTestCase(unittest.TestCase):
936    def test__all__(self):
937        not_exported = {
938            'mdays', 'January', 'February', 'EPOCH', 'MONDAY', 'TUESDAY',
939            'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY',
940            'different_locale', 'c', 'prweek', 'week', 'format',
941            'formatstring', 'main', 'monthlen', 'prevmonth', 'nextmonth'}
942        support.check__all__(self, calendar, not_exported=not_exported)
943
944
945class TestSubClassingCase(unittest.TestCase):
946
947    def setUp(self):
948
949        class CustomHTMLCal(calendar.HTMLCalendar):
950            cssclasses = [style + " text-nowrap" for style in
951                          calendar.HTMLCalendar.cssclasses]
952            cssclasses_weekday_head = ["red", "blue", "green", "lilac",
953                                       "yellow", "orange", "pink"]
954            cssclass_month_head = "text-center month-head"
955            cssclass_month = "text-center month"
956            cssclass_year = "text-italic "
957            cssclass_year_head = "lead "
958
959        self.cal = CustomHTMLCal()
960
961    def test_formatmonthname(self):
962        self.assertIn('class="text-center month-head"',
963                      self.cal.formatmonthname(2017, 5))
964
965    def test_formatmonth(self):
966        self.assertIn('class="text-center month"',
967                      self.cal.formatmonth(2017, 5))
968
969    def test_formatweek(self):
970        weeks = self.cal.monthdays2calendar(2017, 5)
971        self.assertIn('class="wed text-nowrap"', self.cal.formatweek(weeks[0]))
972
973    def test_formatweek_head(self):
974        header = self.cal.formatweekheader()
975        for color in self.cal.cssclasses_weekday_head:
976            self.assertIn('<th class="%s">' % color, header)
977
978    def test_format_year(self):
979        self.assertIn(
980            ('<table border="0" cellpadding="0" cellspacing="0" class="%s">' %
981             self.cal.cssclass_year), self.cal.formatyear(2017))
982
983    def test_format_year_head(self):
984        self.assertIn('<tr><th colspan="%d" class="%s">%s</th></tr>' % (
985            3, self.cal.cssclass_year_head, 2017), self.cal.formatyear(2017))
986
987if __name__ == "__main__":
988    unittest.main()
989