python (3.11.7)
       1  import calendar
       2  import unittest
       3  
       4  from test import support
       5  from test.support.script_helper import assert_python_ok, assert_python_failure
       6  import time
       7  import locale
       8  import sys
       9  import datetime
      10  import os
      11  
      12  # From https://en.wikipedia.org/wiki/Leap_year_starting_on_Saturday
      13  result_0_02_text = """\
      14       February 0
      15  Mo Tu We Th Fr Sa Su
      16      1  2  3  4  5  6
      17   7  8  9 10 11 12 13
      18  14 15 16 17 18 19 20
      19  21 22 23 24 25 26 27
      20  28 29
      21  """
      22  
      23  result_0_text = """\
      24                                     0
      25  
      26        January                   February                   March
      27  Mo 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
      30  10 11 12 13 14 15 16      14 15 16 17 18 19 20      13 14 15 16 17 18 19
      31  17 18 19 20 21 22 23      21 22 23 24 25 26 27      20 21 22 23 24 25 26
      32  24 25 26 27 28 29 30      28 29                     27 28 29 30 31
      33  31
      34  
      35         April                      May                       June
      36  Mo 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
      39  10 11 12 13 14 15 16      15 16 17 18 19 20 21      12 13 14 15 16 17 18
      40  17 18 19 20 21 22 23      22 23 24 25 26 27 28      19 20 21 22 23 24 25
      41  24 25 26 27 28 29 30      29 30 31                  26 27 28 29 30
      42  
      43          July                     August                  September
      44  Mo 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
      47  10 11 12 13 14 15 16      14 15 16 17 18 19 20      11 12 13 14 15 16 17
      48  17 18 19 20 21 22 23      21 22 23 24 25 26 27      18 19 20 21 22 23 24
      49  24 25 26 27 28 29 30      28 29 30 31               25 26 27 28 29 30
      50  31
      51  
      52        October                   November                  December
      53  Mo 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
      57  16 17 18 19 20 21 22      20 21 22 23 24 25 26      18 19 20 21 22 23 24
      58  23 24 25 26 27 28 29      27 28 29 30               25 26 27 28 29 30 31
      59  30 31
      60  """
      61  
      62  result_2004_01_text = """\
      63      January 2004
      64  Mo Tu We Th Fr Sa Su
      65            1  2  3  4
      66   5  6  7  8  9 10 11
      67  12 13 14 15 16 17 18
      68  19 20 21 22 23 24 25
      69  26 27 28 29 30 31
      70  """
      71  
      72  result_2004_text = """\
      73                                    2004
      74  
      75        January                   February                   March
      76  Mo 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
      79  12 13 14 15 16 17 18       9 10 11 12 13 14 15      15 16 17 18 19 20 21
      80  19 20 21 22 23 24 25      16 17 18 19 20 21 22      22 23 24 25 26 27 28
      81  26 27 28 29 30 31         23 24 25 26 27 28 29      29 30 31
      82  
      83         April                      May                       June
      84  Mo 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
      87  12 13 14 15 16 17 18      10 11 12 13 14 15 16      14 15 16 17 18 19 20
      88  19 20 21 22 23 24 25      17 18 19 20 21 22 23      21 22 23 24 25 26 27
      89  26 27 28 29 30            24 25 26 27 28 29 30      28 29 30
      90                            31
      91  
      92          July                     August                  September
      93  Mo 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
      96  12 13 14 15 16 17 18       9 10 11 12 13 14 15      13 14 15 16 17 18 19
      97  19 20 21 22 23 24 25      16 17 18 19 20 21 22      20 21 22 23 24 25 26
      98  26 27 28 29 30 31         23 24 25 26 27 28 29      27 28 29 30
      99                            30 31
     100  
     101        October                   November                  December
     102  Mo 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
     105  11 12 13 14 15 16 17      15 16 17 18 19 20 21      13 14 15 16 17 18 19
     106  18 19 20 21 22 23 24      22 23 24 25 26 27 28      20 21 22 23 24 25 26
     107  25 26 27 28 29 30 31      29 30                     27 28 29 30 31
     108  """
     109  
     110  
     111  default_format = dict(year="year", month="month", encoding="ascii")
     112  
     113  result_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  
     238  result_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  
     303  result_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  
     368  class ESC[4;38;5;81mOutputTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     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  
     492  class ESC[4;38;5;81mCalendarTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     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  
     648  class ESC[4;38;5;81mMonthCalendarTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     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  
     663  class ESC[4;38;5;81mMondayTestCase(ESC[4;38;5;149mMonthCalendarTestCase):
     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  
     721  class ESC[4;38;5;81mSundayTestCase(ESC[4;38;5;149mMonthCalendarTestCase):
     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  
     778  class ESC[4;38;5;81mTimegmTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     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  
     786  class ESC[4;38;5;81mMonthRangeTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     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  
     817  class ESC[4;38;5;81mLeapdaysTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     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  
     838  def conv(s):
     839      return s.replace('\n', os.linesep).encode()
     840  
     841  class ESC[4;38;5;81mCommandLineTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     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  
     961  class ESC[4;38;5;81mMiscTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     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  
     970  class ESC[4;38;5;81mTestSubClassingCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     971  
     972      def setUp(self):
     973  
     974          class ESC[4;38;5;81mCustomHTMLCal(ESC[4;38;5;149mcalendarESC[4;38;5;149m.ESC[4;38;5;149mHTMLCalendar):
     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  
    1012  if __name__ == "__main__":
    1013      unittest.main()