This file is indexed.

/usr/share/doc/diveintopython-zh/html/unit_testing/stage_3.html is in diveintopython-zh 5.4b-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
<!DOCTYPE html
  PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   
      <title>14.3.&nbsp;roman.py, 第 3 阶段</title>
      <link rel="stylesheet" href="../diveintopython.css" type="text/css">
      <link rev="made" href="mailto:f8dy@diveintopython.org">
      <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
      <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
      <meta name="description" content="Python from novice to pro">
      <link rel="home" href="../toc/index.html" title="Dive Into Python">
      <link rel="up" href="stage_1.html" title="第&nbsp;14&nbsp;章&nbsp;测试优先编程">
      <link rel="previous" href="stage_2.html" title="14.2.&nbsp;roman.py, 第 2 阶段">
      <link rel="next" href="stage_4.html" title="14.4.&nbsp;roman.py, 第 4 阶段">
   </head>
   <body>
      <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
         <tr>
            <td id="breadcrumb" colspan="5" align="left" valign="top">导航:<a href="../index.html">起始页</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="stage_1.html">测试优先编程</a>&nbsp;&gt;&nbsp;<span class="thispage">roman.py, 第 3 阶段</span></td>
            <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="stage_2.html" title="上一页: “roman.py, 第 2 阶段”">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="stage_4.html" title="下一页: “roman.py, 第 4 阶段”">&gt;&gt;</a></td>
         </tr>
         <tr>
            <td colspan="3" id="logocontainer">
               <h1 id="logo"><a href="../index.html" accesskey="1">深入 Python :Dive Into Python 中文版</a></h1>
               <p id="tagline">Python 从新手到专家 [Dip_5.4b_CPyUG_Release]</p>
            </td>
            <td colspan="3" align="right">
               <form id="search" method="GET" action="http://www.google.com/custom">
                  <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=""> <input type="submit" value="搜索"><input type="hidden" name="domains" value="woodpecker.org.cn"><input type="hidden" name="sitesearch" value="www.woodpecker.org.cn/diveintopython"></p>
               </form>
            </td>
         </tr>
      </table>
      <!--#include virtual="/inc/ads" -->
      <div class="section" lang="zh_cn">
         <div class="titlepage">
            <div>
               <div>
                  <h2 class="title"><a name="roman.stage3"></a>14.3.&nbsp;<tt class="filename">roman.py</tt>, 第 3 阶段
                  </h2>
               </div>
            </div>
            <div></div>
         </div>
         <div class="abstract">
            <p>现在 <tt class="function">toRoman</tt> 对于有效的输入 (<tt class="literal">1</tt><tt class="literal">3999</tt> 整数) 已能正确工作,是正确处理那些无效输入 (任何其他输入) 的时候了。
            </p>
         </div>
         <div class="example"><a name="d0e33510"></a><h3 class="title">&nbsp;14.6.&nbsp;<tt class="filename">roman3.py</tt></h3>
            <p>这个文件可以在例子目录下的 <tt class="filename">py/roman/stage3/</tt> 目录中找到。
            </p>
            <p>如果您还没有下载本书附带的样例程序, 可以 <a href="http://www.woodpecker.org.cn/diveintopython/download/diveintopython-exampleszh-cn-5.4b.zip" title="Download example scripts">下载本程序和其他样例程序</a></p><pre class="programlisting">
<span class='pystring'>"""Convert to and from Roman numerals"""</span>

<span class='pycomment'>#Define exceptions</span>
<span class='pykeyword'>class</span><span class='pyclass'> RomanError</span>(Exception): <span class='pykeyword'>pass</span>
<span class='pykeyword'>class</span><span class='pyclass'> OutOfRangeError</span>(RomanError): <span class='pykeyword'>pass</span>
<span class='pykeyword'>class</span><span class='pyclass'> NotIntegerError</span>(RomanError): <span class='pykeyword'>pass</span>
<span class='pykeyword'>class</span><span class='pyclass'> InvalidRomanNumeralError</span>(RomanError): <span class='pykeyword'>pass</span>

<span class='pycomment'>#Define digit mapping</span>
romanNumeralMap = ((<span class='pystring'>'M'</span>,  1000),
                   (<span class='pystring'>'CM'</span>, 900),
                   (<span class='pystring'>'D'</span>,  500),
                   (<span class='pystring'>'CD'</span>, 400),
                   (<span class='pystring'>'C'</span>,  100),
                   (<span class='pystring'>'XC'</span>, 90),
                   (<span class='pystring'>'L'</span>,  50),
                   (<span class='pystring'>'XL'</span>, 40),
                   (<span class='pystring'>'X'</span>,  10),
                   (<span class='pystring'>'IX'</span>, 9),
                   (<span class='pystring'>'V'</span>,  5),
                   (<span class='pystring'>'IV'</span>, 4),
                   (<span class='pystring'>'I'</span>,  1))

<span class='pykeyword'>def</span><span class='pyclass'> toRoman</span>(n):
    <span class='pystring'>"""convert integer to Roman numeral"""</span>
    <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> (0 &lt; n &lt; 4000):                                             <a name="roman.stage3.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
        <span class='pykeyword'>raise</span> OutOfRangeError, <span class='pystring'>"number out of range (must be 1..3999)"</span> <a name="roman.stage3.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
    <span class='pykeyword'>if</span> int(n) &lt;&gt; n:                                                    <a name="roman.stage3.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
        <span class='pykeyword'>raise</span> NotIntegerError, <span class='pystring'>"non-integers can not be converted"</span>

    result = <span class='pystring'>""</span>                                                        <a name="roman.stage3.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
    <span class='pykeyword'>for</span> numeral, integer <span class='pykeyword'>in</span> romanNumeralMap:
        <span class='pykeyword'>while</span> n &gt;= integer:
            result += numeral
            n -= integer
    <span class='pykeyword'>return</span> result

<span class='pykeyword'>def</span><span class='pyclass'> fromRoman</span>(s):
    <span class='pystring'>"""convert Roman numeral to integer"""</span>
    <span class='pykeyword'>pass</span>
</pre><div class="calloutlist">
               <table border="0" summary="Callout list">
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.stage3.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">这个写法很 Pythonic:一次进行多个比较。这等价于<tt class="literal">if not ((0 &lt; n) and (n &lt; 4000))</tt>,但是更容易让人理解。这是在进行范围检查,可以将过大的数、负数和零查出来。
                     </td>
                  </tr>
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.stage3.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">你使用 <tt class="literal">raise</tt> 语句引发自己的异常。你可以引发任何内建异常或者已定义的自定义异常。第二个参数是可选的,如果给定,则会在异常未被处理时显示于追踪信息 (trackback) 之中。
                     </td>
                  </tr>
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.stage3.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">这是一个非整数检查。非整数无法转化为罗马数字表示。</td>
                  </tr>
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.stage3.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">函数的其他部分未被更改。</td>
                  </tr>
               </table>
            </div>
         </div>
         <div class="example"><a name="d0e33553"></a><h3 class="title">&nbsp;14.7.&nbsp;观察 <tt class="function">toRoman</tt> 如何处理无效输入
            </h3><pre class="screen">
<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> roman3</span>
<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">roman3.toRoman(4000)</span>
<span class="traceback">Traceback (most recent call last):
  File "&lt;interactive input&gt;", line 1, in ?
  File "roman3.py", line 27, in toRoman
    raise OutOfRangeError, "number out of range (must be 1..3999)"
OutOfRangeError: number out of range (must be 1..3999)</span>
<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">roman3.toRoman(1.5)</span>
<span class="traceback">Traceback (most recent call last):
  File "&lt;interactive input&gt;", line 1, in ?
  File "roman3.py", line 29, in toRoman
    raise NotIntegerError, "non-integers can not be converted"
NotIntegerError: non-integers can not be converted</span>
</pre></div>
         <div class="example"><a name="d0e33582"></a><h3 class="title">&nbsp;14.8.&nbsp;<tt class="filename">romantest3.py</tt> 测试 <tt class="filename">roman3.py</tt> 的结果
            </h3><pre class="screen"><span class="computeroutput">fromRoman should only accept uppercase input ... FAIL
toRoman should always return uppercase ... ok
fromRoman should fail with malformed antecedents ... FAIL
fromRoman should fail with repeated pairs of numerals ... FAIL
fromRoman should fail with too many repeated numerals ... FAIL
fromRoman should give known result with known input ... FAIL
toRoman should give known result with known input ... ok </span><a name="roman.stage3.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"><span class="computeroutput">
fromRoman(toRoman(n))==n for all n ... FAIL
toRoman should fail with non-integer input ... ok        </span><a name="roman.stage3.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"><span class="computeroutput">
toRoman should fail with negative input ... ok           </span><a name="roman.stage3.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"><span class="computeroutput">
toRoman should fail with large input ... ok
toRoman should fail with 0 input ... ok</span></pre><div class="calloutlist">
               <table border="0" summary="Callout list">
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.stage3.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left"><tt class="function">toRoman</tt> 仍然能通过<a href="testing_for_success.html#roman.testtoromanknownvalues.example" title="例&nbsp;13.2.&nbsp;testToRomanKnownValues">已知值测试</a>,这很令人鼓舞。所有<a href="stage_2.html" title="14.2.&nbsp;roman.py, 第 2 阶段">第 2 阶段</a>通过的测试仍然能通过,这说明新的代码没有对原有代码构成任何负面影响。
                     </td>
                  </tr>
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.stage3.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">更令人振奋的是所有的<a href="testing_for_failure.html#roman.tobadinput.example" title="例&nbsp;13.3.&nbsp;测试 toRoman 的无效输入">无效输入测试</a>现在都通过了。<tt class="function">testNonInteger</tt> 这个测试能够通过是因为有了 <tt class="literal">int(n) &lt;&gt; n</tt> 检查。当一个非整数传递给 <tt class="function">toRoman</tt> 时,<tt class="literal">int(n) &lt;&gt; n</tt> 检查出问题并引发 <tt class="errorcode">NotIntegerError</tt> 异常,这正是 <tt class="function">testNonInteger</tt> 所期待的。
                     </td>
                  </tr>
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.stage3.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left"><tt class="function">testNegative</tt> 这个测试能够通过是因为 <tt class="literal">not (0 &lt; n &lt; 4000)</tt> 检查引发了 <tt class="function">testNegative</tt> 期待的 <tt class="errorcode">OutOfRangeError</tt> 异常。
                     </td>
                  </tr>
               </table>
            </div><pre class="screen"><span class="computeroutput">
======================================================================
FAIL: fromRoman should only accept uppercase input
----------------------------------------------------------------------
</span><span class="traceback">Traceback (most recent call last):
  File "C:\docbook\dip\py\roman\stage3\romantest3.py", line 156, in testFromRomanCase
    roman3.fromRoman, numeral.lower())
  File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
    raise self.failureException, excName
AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
======================================================================
FAIL: fromRoman should fail with malformed antecedents
----------------------------------------------------------------------
</span><span class="traceback">Traceback (most recent call last):
  File "C:\docbook\dip\py\roman\stage3\romantest3.py", line 133, in testMalformedAntecedent
    self.assertRaises(roman3.InvalidRomanNumeralError, roman3.fromRoman, s)
  File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
    raise self.failureException, excName
AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
======================================================================
FAIL: fromRoman should fail with repeated pairs of numerals
----------------------------------------------------------------------
</span><span class="traceback">Traceback (most recent call last):
  File "C:\docbook\dip\py\roman\stage3\romantest3.py", line 127, in testRepeatedPairs
    self.assertRaises(roman3.InvalidRomanNumeralError, roman3.fromRoman, s)
  File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
    raise self.failureException, excName
AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
======================================================================
FAIL: fromRoman should fail with too many repeated numerals
----------------------------------------------------------------------
</span><span class="traceback">Traceback (most recent call last):
  File "C:\docbook\dip\py\roman\stage3\romantest3.py", line 122, in testTooManyRepeatedNumerals
    self.assertRaises(roman3.InvalidRomanNumeralError, roman3.fromRoman, s)
  File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
    raise self.failureException, excName
AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
======================================================================
FAIL: fromRoman should give known result with known input
----------------------------------------------------------------------
</span><span class="traceback">Traceback (most recent call last):
  File "C:\docbook\dip\py\roman\stage3\romantest3.py", line 99, in testFromRomanKnownValues
    self.assertEqual(integer, result)
  File "c:\python21\lib\unittest.py", line 273, in failUnlessEqual
    raise self.failureException, (msg or '%s != %s' % (first, second))
AssertionError: 1 != None</span><span class="computeroutput">
======================================================================
FAIL: fromRoman(toRoman(n))==n for all n
----------------------------------------------------------------------
</span><span class="traceback">Traceback (most recent call last):
  File "C:\docbook\dip\py\roman\stage3\romantest3.py", line 141, in testSanity
    self.assertEqual(integer, result)
  File "c:\python21\lib\unittest.py", line 273, in failUnlessEqual
    raise self.failureException, (msg or '%s != %s' % (first, second))
AssertionError: 1 != None</span><span class="computeroutput">
----------------------------------------------------------------------
Ran 12 tests in 0.401s

FAILED (failures=6)</span> <a name="roman.stage3.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></pre><div class="calloutlist">
               <table border="0" summary="Callout list">
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.stage3.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">你已将失败降至 6 个,而且它们都是关于 <tt class="function">fromRoman</tt> 的:已知值测试、三个独立的无效输入测试,大小写检查和完备性检查。这意味着 <tt class="function">toRoman</tt> 通过了所有可以独立通过的测试 (完备性测试也测试它,但需要 <tt class="function">fromRoman</tt> 编写后一起测试)。这就是说,你应该停止对 <tt class="function">toRoman</tt> 的代码编写。不必再推敲,不必再做额外的检查 “<span class="quote">恰到好处</span>”。停下来吧!现在,别再敲键盘了。
                     </td>
                  </tr>
               </table>
            </div>
         </div><a name="d0e33701"></a><table class="note" border="0" summary="">
            <tr>
               <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="注意" title="" width="24" height="24"></td>
            </tr>
            <tr>
               <td colspan="2" align="left" valign="top" width="99%">全面的单元测试能够告诉你的最重要的事情是什么时候停止编写代码。当一个函数的所有单元测试都通过了,停止编写这个函数。一旦整个模块的单元测试通过了,停止编写这个模块。</td>
            </tr>
         </table>
      </div>
      <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
         <tr>
            <td width="35%" align="left"><br><a class="NavigationArrow" href="stage_2.html">&lt;&lt;&nbsp;roman.py, 第 2 阶段</a></td>
            <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="stage_1.html#roman.stage1" title="14.1.&nbsp;roman.py, 第 1 阶段">1</a> <span class="divider">|</span> <a href="stage_2.html" title="14.2.&nbsp;roman.py, 第 2 阶段">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="stage_4.html" title="14.4.&nbsp;roman.py, 第 4 阶段">4</a> <span class="divider">|</span> <a href="stage_5.html" title="14.5.&nbsp;roman.py, 第 5 阶段">5</a>&nbsp;<span class="divider">|</span>&nbsp;
            </td>
            <td width="35%" align="right"><br><a class="NavigationArrow" href="stage_4.html">roman.py, 第 4 阶段&nbsp;&gt;&gt;</a></td>
         </tr>
         <tr>
            <td colspan="3"><br></td>
         </tr>
      </table>
      <div class="Footer">
         <p class="copyright">Copyright © 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
         <p class="copyright">Copyright © 2001, 2002, 2003, 2004, 2005, 2006, 2007 <a href="mailto:python-cn@googlegroups.com">CPyUG (邮件列表)</a></p>
      </div>
   </body>
</html>