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"> </td><td class="noday"> </td><td class="noday"> </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"> </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"> </td><td class="noday"> </td><td class="noday"> </td><td class="noday"> </td><td class="noday"> </td><td class="noday"> </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"> </td><td class="noday"> </td><td class="noday"> </td><td class="noday"> </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"> </td><td class="noday"> </td><td class="noday"> </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"> </td><td class="noday"> </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"> </td><td class="noday"> </td><td class="noday"> </td><td class="noday"> </td><td class="noday"> </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"> </td><td class="noday"> </td><td class="noday"> </td><td class="noday"> </td><td class="noday"> </td><td class="noday"> </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"> </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"> </td><td class="noday"> </td><td class="noday"> </td><td class="noday"> </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"> </td><td class="noday"> </td><td class="noday"> </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"> </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"> </td><td class="noday"> </td><td class="noday"> </td><td class="noday"> </td><td class="noday"> </td><td class="noday"> </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"> </td><td class="noday"> </td><td class="noday"> </td><td class="noday"> </td><td class="noday"> </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"> </td><td class="noday"> </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"> </td><td class="noday"> </td><td class="noday"> </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"> </td><td class="noday"> </td><td class="noday"> </td><td class="noday"> </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"> </td><td class="noday"> </td><td class="noday"> </td><td class="noday"> </td><td class="noday"> </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"> </td><td class="noday"> </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"> </td><td class="noday"> </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_calendar_formatweekday(self): 568 try: 569 # formatweekday uses different day names based on the available width. 570 cal = calendar.LocaleTextCalendar(locale='en_US') 571 # For really short widths, the abbreviated name is truncated. 572 self.assertEqual(cal.formatweekday(0, 1), "M") 573 self.assertEqual(cal.formatweekday(0, 2), "Mo") 574 # For short widths, a centered, abbreviated name is used. 575 self.assertEqual(cal.formatweekday(0, 3), "Mon") 576 self.assertEqual(cal.formatweekday(0, 5), " Mon ") 577 self.assertEqual(cal.formatweekday(0, 8), " Mon ") 578 # For long widths, the full day name is used. 579 self.assertEqual(cal.formatweekday(0, 9), " Monday ") 580 self.assertEqual(cal.formatweekday(0, 10), " Monday ") 581 except locale.Error: 582 raise unittest.SkipTest('cannot set the en_US locale') 583 584 def test_locale_html_calendar_custom_css_class_month_name(self): 585 try: 586 cal = calendar.LocaleHTMLCalendar(locale='') 587 local_month = cal.formatmonthname(2010, 10, 10) 588 except locale.Error: 589 # cannot set the system default locale -- skip rest of test 590 raise unittest.SkipTest('cannot set the system default locale') 591 self.assertIn('class="month"', local_month) 592 cal.cssclass_month_head = "text-center month" 593 local_month = cal.formatmonthname(2010, 10, 10) 594 self.assertIn('class="text-center month"', local_month) 595 596 def test_locale_html_calendar_custom_css_class_weekday(self): 597 try: 598 cal = calendar.LocaleHTMLCalendar(locale='') 599 local_weekday = cal.formatweekday(6) 600 except locale.Error: 601 # cannot set the system default locale -- skip rest of test 602 raise unittest.SkipTest('cannot set the system default locale') 603 self.assertIn('class="sun"', local_weekday) 604 cal.cssclasses_weekday_head = ["mon2", "tue2", "wed2", "thu2", "fri2", "sat2", "sun2"] 605 local_weekday = cal.formatweekday(6) 606 self.assertIn('class="sun2"', local_weekday) 607 608 def test_itermonthdays3(self): 609 # ensure itermonthdays3 doesn't overflow after datetime.MAXYEAR 610 list(calendar.Calendar().itermonthdays3(datetime.MAXYEAR, 12)) 611 612 def test_itermonthdays4(self): 613 cal = calendar.Calendar(firstweekday=3) 614 days = list(cal.itermonthdays4(2001, 2)) 615 self.assertEqual(days[0], (2001, 2, 1, 3)) 616 self.assertEqual(days[-1], (2001, 2, 28, 2)) 617 618 def test_itermonthdays(self): 619 for firstweekday in range(7): 620 cal = calendar.Calendar(firstweekday) 621 # Test the extremes, see #28253 and #26650 622 for y, m in [(1, 1), (9999, 12)]: 623 days = list(cal.itermonthdays(y, m)) 624 self.assertIn(len(days), (35, 42)) 625 # Test a short month 626 cal = calendar.Calendar(firstweekday=3) 627 days = list(cal.itermonthdays(2001, 2)) 628 self.assertEqual(days, list(range(1, 29))) 629 630 def test_itermonthdays2(self): 631 for firstweekday in range(7): 632 cal = calendar.Calendar(firstweekday) 633 # Test the extremes, see #28253 and #26650 634 for y, m in [(1, 1), (9999, 12)]: 635 days = list(cal.itermonthdays2(y, m)) 636 self.assertEqual(days[0][1], firstweekday) 637 self.assertEqual(days[-1][1], (firstweekday - 1) % 7) 638 639 def test_iterweekdays(self): 640 week0 = list(range(7)) 641 for firstweekday in range(7): 642 cal = calendar.Calendar(firstweekday) 643 week = list(cal.iterweekdays()) 644 expected = week0[firstweekday:] + week0[:firstweekday] 645 self.assertEqual(week, expected) 646 647 648class MonthCalendarTestCase(unittest.TestCase): 649 def setUp(self): 650 self.oldfirstweekday = calendar.firstweekday() 651 calendar.setfirstweekday(self.firstweekday) 652 653 def tearDown(self): 654 calendar.setfirstweekday(self.oldfirstweekday) 655 656 def check_weeks(self, year, month, weeks): 657 cal = calendar.monthcalendar(year, month) 658 self.assertEqual(len(cal), len(weeks)) 659 for i in range(len(weeks)): 660 self.assertEqual(weeks[i], sum(day != 0 for day in cal[i])) 661 662 663class MondayTestCase(MonthCalendarTestCase): 664 firstweekday = calendar.MONDAY 665 666 def test_february(self): 667 # A 28-day february starting on monday (7+7+7+7 days) 668 self.check_weeks(1999, 2, (7, 7, 7, 7)) 669 670 # A 28-day february starting on tuesday (6+7+7+7+1 days) 671 self.check_weeks(2005, 2, (6, 7, 7, 7, 1)) 672 673 # A 28-day february starting on sunday (1+7+7+7+6 days) 674 self.check_weeks(1987, 2, (1, 7, 7, 7, 6)) 675 676 # A 29-day february starting on monday (7+7+7+7+1 days) 677 self.check_weeks(1988, 2, (7, 7, 7, 7, 1)) 678 679 # A 29-day february starting on tuesday (6+7+7+7+2 days) 680 self.check_weeks(1972, 2, (6, 7, 7, 7, 2)) 681 682 # A 29-day february starting on sunday (1+7+7+7+7 days) 683 self.check_weeks(2004, 2, (1, 7, 7, 7, 7)) 684 685 def test_april(self): 686 # A 30-day april starting on monday (7+7+7+7+2 days) 687 self.check_weeks(1935, 4, (7, 7, 7, 7, 2)) 688 689 # A 30-day april starting on tuesday (6+7+7+7+3 days) 690 self.check_weeks(1975, 4, (6, 7, 7, 7, 3)) 691 692 # A 30-day april starting on sunday (1+7+7+7+7+1 days) 693 self.check_weeks(1945, 4, (1, 7, 7, 7, 7, 1)) 694 695 # A 30-day april starting on saturday (2+7+7+7+7 days) 696 self.check_weeks(1995, 4, (2, 7, 7, 7, 7)) 697 698 # A 30-day april starting on friday (3+7+7+7+6 days) 699 self.check_weeks(1994, 4, (3, 7, 7, 7, 6)) 700 701 def test_december(self): 702 # A 31-day december starting on monday (7+7+7+7+3 days) 703 self.check_weeks(1980, 12, (7, 7, 7, 7, 3)) 704 705 # A 31-day december starting on tuesday (6+7+7+7+4 days) 706 self.check_weeks(1987, 12, (6, 7, 7, 7, 4)) 707 708 # A 31-day december starting on sunday (1+7+7+7+7+2 days) 709 self.check_weeks(1968, 12, (1, 7, 7, 7, 7, 2)) 710 711 # A 31-day december starting on thursday (4+7+7+7+6 days) 712 self.check_weeks(1988, 12, (4, 7, 7, 7, 6)) 713 714 # A 31-day december starting on friday (3+7+7+7+7 days) 715 self.check_weeks(2017, 12, (3, 7, 7, 7, 7)) 716 717 # A 31-day december starting on saturday (2+7+7+7+7+1 days) 718 self.check_weeks(2068, 12, (2, 7, 7, 7, 7, 1)) 719 720 721class SundayTestCase(MonthCalendarTestCase): 722 firstweekday = calendar.SUNDAY 723 724 def test_february(self): 725 # A 28-day february starting on sunday (7+7+7+7 days) 726 self.check_weeks(2009, 2, (7, 7, 7, 7)) 727 728 # A 28-day february starting on monday (6+7+7+7+1 days) 729 self.check_weeks(1999, 2, (6, 7, 7, 7, 1)) 730 731 # A 28-day february starting on saturday (1+7+7+7+6 days) 732 self.check_weeks(1997, 2, (1, 7, 7, 7, 6)) 733 734 # A 29-day february starting on sunday (7+7+7+7+1 days) 735 self.check_weeks(2004, 2, (7, 7, 7, 7, 1)) 736 737 # A 29-day february starting on monday (6+7+7+7+2 days) 738 self.check_weeks(1960, 2, (6, 7, 7, 7, 2)) 739 740 # A 29-day february starting on saturday (1+7+7+7+7 days) 741 self.check_weeks(1964, 2, (1, 7, 7, 7, 7)) 742 743 def test_april(self): 744 # A 30-day april starting on sunday (7+7+7+7+2 days) 745 self.check_weeks(1923, 4, (7, 7, 7, 7, 2)) 746 747 # A 30-day april starting on monday (6+7+7+7+3 days) 748 self.check_weeks(1918, 4, (6, 7, 7, 7, 3)) 749 750 # A 30-day april starting on saturday (1+7+7+7+7+1 days) 751 self.check_weeks(1950, 4, (1, 7, 7, 7, 7, 1)) 752 753 # A 30-day april starting on friday (2+7+7+7+7 days) 754 self.check_weeks(1960, 4, (2, 7, 7, 7, 7)) 755 756 # A 30-day april starting on thursday (3+7+7+7+6 days) 757 self.check_weeks(1909, 4, (3, 7, 7, 7, 6)) 758 759 def test_december(self): 760 # A 31-day december starting on sunday (7+7+7+7+3 days) 761 self.check_weeks(2080, 12, (7, 7, 7, 7, 3)) 762 763 # A 31-day december starting on monday (6+7+7+7+4 days) 764 self.check_weeks(1941, 12, (6, 7, 7, 7, 4)) 765 766 # A 31-day december starting on saturday (1+7+7+7+7+2 days) 767 self.check_weeks(1923, 12, (1, 7, 7, 7, 7, 2)) 768 769 # A 31-day december starting on wednesday (4+7+7+7+6 days) 770 self.check_weeks(1948, 12, (4, 7, 7, 7, 6)) 771 772 # A 31-day december starting on thursday (3+7+7+7+7 days) 773 self.check_weeks(1927, 12, (3, 7, 7, 7, 7)) 774 775 # A 31-day december starting on friday (2+7+7+7+7+1 days) 776 self.check_weeks(1995, 12, (2, 7, 7, 7, 7, 1)) 777 778class TimegmTestCase(unittest.TestCase): 779 TIMESTAMPS = [0, 10, 100, 1000, 10000, 100000, 1000000, 780 1234567890, 1262304000, 1275785153,] 781 def test_timegm(self): 782 for secs in self.TIMESTAMPS: 783 tuple = time.gmtime(secs) 784 self.assertEqual(secs, calendar.timegm(tuple)) 785 786class MonthRangeTestCase(unittest.TestCase): 787 def test_january(self): 788 # Tests valid lower boundary case. 789 self.assertEqual(calendar.monthrange(2004,1), (3,31)) 790 791 def test_february_leap(self): 792 # Tests February during leap year. 793 self.assertEqual(calendar.monthrange(2004,2), (6,29)) 794 795 def test_february_nonleap(self): 796 # Tests February in non-leap year. 797 self.assertEqual(calendar.monthrange(2010,2), (0,28)) 798 799 def test_december(self): 800 # Tests valid upper boundary case. 801 self.assertEqual(calendar.monthrange(2004,12), (2,31)) 802 803 def test_zeroth_month(self): 804 # Tests low invalid boundary case. 805 with self.assertRaises(calendar.IllegalMonthError): 806 calendar.monthrange(2004, 0) 807 808 def test_thirteenth_month(self): 809 # Tests high invalid boundary case. 810 with self.assertRaises(calendar.IllegalMonthError): 811 calendar.monthrange(2004, 13) 812 813 def test_illegal_month_reported(self): 814 with self.assertRaisesRegex(calendar.IllegalMonthError, '65'): 815 calendar.monthrange(2004, 65) 816 817class LeapdaysTestCase(unittest.TestCase): 818 def test_no_range(self): 819 # test when no range i.e. two identical years as args 820 self.assertEqual(calendar.leapdays(2010,2010), 0) 821 822 def test_no_leapdays(self): 823 # test when no leap years in range 824 self.assertEqual(calendar.leapdays(2010,2011), 0) 825 826 def test_no_leapdays_upper_boundary(self): 827 # test no leap years in range, when upper boundary is a leap year 828 self.assertEqual(calendar.leapdays(2010,2012), 0) 829 830 def test_one_leapday_lower_boundary(self): 831 # test when one leap year in range, lower boundary is leap year 832 self.assertEqual(calendar.leapdays(2012,2013), 1) 833 834 def test_several_leapyears_in_range(self): 835 self.assertEqual(calendar.leapdays(1997,2020), 5) 836 837 838def conv(s): 839 return s.replace('\n', os.linesep).encode() 840 841class CommandLineTestCase(unittest.TestCase): 842 def run_ok(self, *args): 843 return assert_python_ok('-m', 'calendar', *args)[1] 844 845 def assertFailure(self, *args): 846 rc, stdout, stderr = assert_python_failure('-m', 'calendar', *args) 847 self.assertIn(b'usage:', stderr) 848 self.assertEqual(rc, 2) 849 850 def test_help(self): 851 stdout = self.run_ok('-h') 852 self.assertIn(b'usage:', stdout) 853 self.assertIn(b'calendar.py', stdout) 854 self.assertIn(b'--help', stdout) 855 856 def test_illegal_arguments(self): 857 self.assertFailure('-z') 858 self.assertFailure('spam') 859 self.assertFailure('2004', 'spam') 860 self.assertFailure('-t', 'html', '2004', '1') 861 862 def test_output_current_year(self): 863 stdout = self.run_ok() 864 year = datetime.datetime.now().year 865 self.assertIn((' %s' % year).encode(), stdout) 866 self.assertIn(b'January', stdout) 867 self.assertIn(b'Mo Tu We Th Fr Sa Su', stdout) 868 869 def test_output_year(self): 870 stdout = self.run_ok('2004') 871 self.assertEqual(stdout, conv(result_2004_text)) 872 873 def test_output_month(self): 874 stdout = self.run_ok('2004', '1') 875 self.assertEqual(stdout, conv(result_2004_01_text)) 876 877 def test_option_encoding(self): 878 self.assertFailure('-e') 879 self.assertFailure('--encoding') 880 stdout = self.run_ok('--encoding', 'utf-16-le', '2004') 881 self.assertEqual(stdout, result_2004_text.encode('utf-16-le')) 882 883 def test_option_locale(self): 884 self.assertFailure('-L') 885 self.assertFailure('--locale') 886 self.assertFailure('-L', 'en') 887 888 lang, enc = locale.getlocale() 889 lang = lang or 'C' 890 enc = enc or 'UTF-8' 891 try: 892 oldlocale = locale.getlocale(locale.LC_TIME) 893 try: 894 locale.setlocale(locale.LC_TIME, (lang, enc)) 895 finally: 896 locale.setlocale(locale.LC_TIME, oldlocale) 897 except (locale.Error, ValueError): 898 self.skipTest('cannot set the system default locale') 899 stdout = self.run_ok('--locale', lang, '--encoding', enc, '2004') 900 self.assertIn('2004'.encode(enc), stdout) 901 902 def test_option_width(self): 903 self.assertFailure('-w') 904 self.assertFailure('--width') 905 self.assertFailure('-w', 'spam') 906 stdout = self.run_ok('--width', '3', '2004') 907 self.assertIn(b'Mon Tue Wed Thu Fri Sat Sun', stdout) 908 909 def test_option_lines(self): 910 self.assertFailure('-l') 911 self.assertFailure('--lines') 912 self.assertFailure('-l', 'spam') 913 stdout = self.run_ok('--lines', '2', '2004') 914 self.assertIn(conv('December\n\nMo Tu We'), stdout) 915 916 def test_option_spacing(self): 917 self.assertFailure('-s') 918 self.assertFailure('--spacing') 919 self.assertFailure('-s', 'spam') 920 stdout = self.run_ok('--spacing', '8', '2004') 921 self.assertIn(b'Su Mo', stdout) 922 923 def test_option_months(self): 924 self.assertFailure('-m') 925 self.assertFailure('--month') 926 self.assertFailure('-m', 'spam') 927 stdout = self.run_ok('--months', '1', '2004') 928 self.assertIn(conv('\nMo Tu We Th Fr Sa Su\n'), stdout) 929 930 def test_option_type(self): 931 self.assertFailure('-t') 932 self.assertFailure('--type') 933 self.assertFailure('-t', 'spam') 934 stdout = self.run_ok('--type', 'text', '2004') 935 self.assertEqual(stdout, conv(result_2004_text)) 936 stdout = self.run_ok('--type', 'html', '2004') 937 self.assertEqual(stdout[:6], b'<?xml ') 938 self.assertIn(b'<title>Calendar for 2004</title>', stdout) 939 940 def test_html_output_current_year(self): 941 stdout = self.run_ok('--type', 'html') 942 year = datetime.datetime.now().year 943 self.assertIn(('<title>Calendar for %s</title>' % year).encode(), 944 stdout) 945 self.assertIn(b'<tr><th colspan="7" class="month">January</th></tr>', 946 stdout) 947 948 def test_html_output_year_encoding(self): 949 stdout = self.run_ok('-t', 'html', '--encoding', 'ascii', '2004') 950 self.assertEqual(stdout, 951 result_2004_html.format(**default_format).encode('ascii')) 952 953 def test_html_output_year_css(self): 954 self.assertFailure('-t', 'html', '-c') 955 self.assertFailure('-t', 'html', '--css') 956 stdout = self.run_ok('-t', 'html', '--css', 'custom.css', '2004') 957 self.assertIn(b'<link rel="stylesheet" type="text/css" ' 958 b'href="custom.css" />', stdout) 959 960 961class MiscTestCase(unittest.TestCase): 962 def test__all__(self): 963 not_exported = { 964 'mdays', 'January', 'February', 'EPOCH', 965 'different_locale', 'c', 'prweek', 'week', 'format', 966 'formatstring', 'main', 'monthlen', 'prevmonth', 'nextmonth'} 967 support.check__all__(self, calendar, not_exported=not_exported) 968 969 970class TestSubClassingCase(unittest.TestCase): 971 972 def setUp(self): 973 974 class CustomHTMLCal(calendar.HTMLCalendar): 975 cssclasses = [style + " text-nowrap" for style in 976 calendar.HTMLCalendar.cssclasses] 977 cssclasses_weekday_head = ["red", "blue", "green", "lilac", 978 "yellow", "orange", "pink"] 979 cssclass_month_head = "text-center month-head" 980 cssclass_month = "text-center month" 981 cssclass_year = "text-italic " 982 cssclass_year_head = "lead " 983 984 self.cal = CustomHTMLCal() 985 986 def test_formatmonthname(self): 987 self.assertIn('class="text-center month-head"', 988 self.cal.formatmonthname(2017, 5)) 989 990 def test_formatmonth(self): 991 self.assertIn('class="text-center month"', 992 self.cal.formatmonth(2017, 5)) 993 994 def test_formatweek(self): 995 weeks = self.cal.monthdays2calendar(2017, 5) 996 self.assertIn('class="wed text-nowrap"', self.cal.formatweek(weeks[0])) 997 998 def test_formatweek_head(self): 999 header = self.cal.formatweekheader() 1000 for color in self.cal.cssclasses_weekday_head: 1001 self.assertIn('<th class="%s">' % color, header) 1002 1003 def test_format_year(self): 1004 self.assertIn( 1005 ('<table border="0" cellpadding="0" cellspacing="0" class="%s">' % 1006 self.cal.cssclass_year), self.cal.formatyear(2017)) 1007 1008 def test_format_year_head(self): 1009 self.assertIn('<tr><th colspan="%d" class="%s">%s</th></tr>' % ( 1010 3, self.cal.cssclass_year_head, 2017), self.cal.formatyear(2017)) 1011 1012if __name__ == "__main__": 1013 unittest.main() 1014