dfect 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CREDITS CHANGED
@@ -1,2 +1,20 @@
1
- - François Beausoleil <http://github.com/francois>
2
- - Iñaki Baz Castillo <http://github.com/ibc>
1
+ %#----------------------------------------------------------------------------
2
+ ## AUTHORS
3
+ %#----------------------------------------------------------------------------
4
+
5
+ Suraj N. Kurapati
6
+
7
+ %#----------------------------------------------------------------------------
8
+ ## CREDITS
9
+ %#----------------------------------------------------------------------------
10
+
11
+ François Beausoleil,
12
+ Iñaki Baz Castillo,
13
+ Sean O'Halpin
14
+
15
+ %#----------------------------------------------------------------------------
16
+ ## LICENSE
17
+ %#----------------------------------------------------------------------------
18
+
19
+ %# See the file named "LICENSE".
20
+ %< "LICENSE"
data/bin/dfect CHANGED
@@ -1,57 +1,26 @@
1
1
  #!/usr/bin/env ruby
2
- #
3
- # Usage:
4
- #
5
- # dfect [Options] FILE_OR_GLOB...
6
- #
7
- # FILE_OR_GLOB : A file or file globbing pattern that
8
- # describes a set of files to evaluate.
9
- #
10
- #
11
- # Options:
12
- #
13
- # -d, --debug : Launch interactive debugger
14
- # during assertion failures.
15
- #
16
- # -q, --quiet : Do not show execution report.
17
- #
18
- # -h, --help : Show this message and exit.
19
- #
20
- # -v, --version : Show version number and exit.
21
- #
22
2
 
23
- $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
24
3
  require 'dfect'
25
4
 
26
- # parse command line
27
5
  if ARGV.delete('-h') or ARGV.delete('--help')
28
- puts
29
- puts Dfect.inspect
30
- puts Dfect::TAGLINE
31
- puts
32
- puts
33
- puts File.read(__FILE__)[/^#(\r?\n)(.*?)\1\1/m, 2].gsub(/^# ?/, '')
34
- puts
35
- puts
36
- puts 'Read the user manual for more information:'
37
- puts
38
- puts " #{Dfect::INSTDIR}/doc/index.html"
39
- puts
40
- puts " #{Dfect::WEBSITE}"
41
- puts
6
+ # try to display UNIX version of help manual
7
+ man_path = File.join(Dfect::INSTDIR, 'man')
8
+ unless system 'man', '-M', man_path, '-a', 'dfect'
9
+ # try to display HTML version of help manual
10
+ man_html = man_path + '.html'
11
+ unless %w[$BROWSER open start].any? {|b| system "#{b} #{man_html}" }
12
+ # no luck; direct user to project website
13
+ puts "See #{Dfect::WEBSITE}"
14
+ end
15
+ end
42
16
  exit
43
17
  elsif ARGV.delete('-v') or ARGV.delete('--version')
44
18
  puts Dfect::VERSION
45
19
  exit
46
20
  end
47
21
 
48
- if ARGV.delete('-d') or ARGV.delete('--debug')
49
- Dfect.options[:debug] = true
50
- end
51
-
52
- if ARGV.delete('-q') or ARGV.delete('--quiet')
53
- Dfect.options[:quiet] = true
54
- end
22
+ Dfect.options[:debug] = ARGV.delete('-d') || ARGV.delete('--debug')
23
+ Dfect.options[:quiet] = ARGV.delete('-q') || ARGV.delete('--quiet')
55
24
 
56
25
  require 'dfect/auto'
57
26
  ARGV.each {|glob| Dir[glob].each {|test| load test } }
@@ -0,0 +1,24 @@
1
+ # Provides full name aliases for Dfect's default abbreviated vocabulary.
2
+
3
+ require 'dfect'
4
+
5
+ module Dfect
6
+ full_names = {
7
+ 'D' => 'Describe',
8
+ 'T' => 'True',
9
+ 'F' => 'False',
10
+ 'E' => 'Error',
11
+ 'C' => 'Catch',
12
+ 'S' => 'Share',
13
+ 'L' => 'Log',
14
+ }
15
+
16
+ instance_methods(false).each do |meth_name|
17
+ if full_name = meth_name.to_s.sub!(/^[A-Z]/) {|abbr| full_names[abbr] }
18
+ alias_method full_name, meth_name
19
+ end
20
+ end
21
+
22
+ # for hooks
23
+ Describe = D
24
+ end
@@ -18,12 +18,12 @@ module Dfect
18
18
  ##
19
19
  # Number of this release of this project.
20
20
  #
21
- VERSION = "2.1.0"
21
+ VERSION = "2.2.0"
22
22
 
23
23
  ##
24
24
  # Date of this release of this project.
25
25
  #
26
- RELDATE = "2010-03-31"
26
+ RELDATE = "2010-04-28"
27
27
 
28
28
  ##
29
29
  # Description of this release of this project.
@@ -74,29 +74,20 @@ module Dfect
74
74
  # }
75
75
  #
76
76
  DEVTIME = {
77
- "inochi" => [ "~> 2" ], # for managing this project
77
+ "inochi" => [ ">= 3.0.0", "< 4" ],
78
78
  }
79
79
 
80
- ##
81
- # Loads the correct version (as defined by the {RUNTIME} or {DEVTIME}
82
- # constant in this module) of the given gem or the gem that contains
83
- # the given library.
84
- #
85
- def self.require gem_name_or_library
86
- # prepare the correct version of the gem for loading
87
- if respond_to? :gem
88
- gem_name = gem_name_or_library.to_s.sub(%r{/.*$}, '')
89
- if gem_version = RUNTIME[gem_name] || DEVTIME[gem_name]
80
+ # establish gem version dependencies
81
+ if respond_to? :gem
82
+ [RUNTIME, DEVTIME].each do |deps|
83
+ deps.each do |gem_name, gem_version|
90
84
  begin
91
- gem gem_name, *gem_version
85
+ gem gem_name, *Array(gem_version)
92
86
  rescue LoadError => error
93
87
  warn "#{self.inspect}: #{error}"
94
88
  end
95
89
  end
96
90
  end
97
-
98
- # do the loading
99
- super
100
91
  end
101
92
 
102
93
  end
@@ -0,0 +1,947 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv='content-type' value='text/html;charset=utf8'>
5
+ <meta name='generator' value='Ronn/v0.5'>
6
+ <title>dfect(1) - Assertion testing library for Ruby</title>
7
+ <style type='text/css'>
8
+ body {margin:0}
9
+ #man, #man code, #man pre, #man tt, #man kbd, #man samp {
10
+ font-family:consolas,monospace;
11
+ font-size:16px;
12
+ line-height:1.3;
13
+ color:#343331;
14
+ background:#fff; }
15
+ #man { max-width:87ex; margin:0 3ex 1ex 1ex; text-align:justify; }
16
+ #man div.man-navigation {
17
+ position:fixed;
18
+ top:0;
19
+ left:91ex;
20
+ height:100%;
21
+ width:100%;
22
+ padding:1ex 0 0 2ex;
23
+ border-left:0.5ex solid #DCDCDC;
24
+ background-color: #F5F5F5;
25
+ }
26
+ #man div.man-navigation a { display:block; margin-bottom:1.5ex }
27
+ #man h1, #man h2, #man h3 { color:#232221;clear:left }
28
+ #man h1 { font-size:28px; margin:15px 0 30px 0; text-align:center }
29
+ #man h2 { font-size:18px; margin-bottom:0; margin-top:10px; line-height:1.3; }
30
+ #man h3 { font-size:16px; margin:0 0 0 4ex; }
31
+ #man p, #man ul, #man ol, #man dl, #man pre { margin:0 0 18px 0; }
32
+ #man pre {
33
+ color:#333231;
34
+ background:#edeceb;
35
+ padding:5px 7px;
36
+ margin:0px 0 20px 0;
37
+ border-left:2ex solid #ddd}
38
+ #man pre + h2, #man pre + h3 {
39
+ margin-top:22px;
40
+ }
41
+ #man h2 + pre, #man h3 + pre {
42
+ margin-top:5px;
43
+ }
44
+ #man > p, #man > ul, #man > ol, #man > dl, #man > pre { margin-left:8ex; }
45
+ #man dt { margin:0; clear:left }
46
+ #man dt.flush { float:left; width:8ex }
47
+ #man dd { margin:0 0 0 9ex }
48
+ #man code, #man strong, #man b { font-weight:bold; color:#131211; }
49
+ #man pre code { font-weight:normal; color:#232221; background:inherit }
50
+ #man em, var, u {
51
+ font-style:normal; color:#333231; border-bottom:1px solid #999; }
52
+ #man h1.man-title { display:none; }
53
+ #man ol.man, #man ol.man li { margin:2px 0 10px 0; padding:0;
54
+ float:left; width:33%; list-style-type:none;
55
+ text-transform:uppercase; font-size:18px; color:#999;
56
+ letter-spacing:1px;}
57
+ #man ol.man { width:100%; }
58
+ #man ol.man li.tl { text-align:left }
59
+ #man ol.man li.tc { text-align:center;letter-spacing:4px }
60
+ #man ol.man li.tr { text-align:right; float: right }
61
+ #man ol.man a { color:#999 }
62
+ #man ol.man a:hover { color:#333231 }
63
+ #man img { display:block; margin:auto }
64
+ </style>
65
+ <style type='text/css' media='print'>
66
+ #man { max-width:none }
67
+ #man div.man-navigation { display:none }
68
+ #man a[href]:not([href^="#"]):not([data-bare-link]):after {
69
+ content:" " attr(href);
70
+ }
71
+ </style>
72
+ </head>
73
+ <body>
74
+ <div id='man'>
75
+
76
+ <div class='man-navigation'><a href='#NAME'>NAME</a> <a href='#SYNOPSIS'>SYNOPSIS</a> <a href='#DESCRIPTION'>DESCRIPTION</a> <a href='#OPTIONS'>OPTIONS</a> <a href='#TESTS'>TESTS</a> <a href='#ASSERTIONS'>ASSERTIONS</a> <a href='#EMULATION'>EMULATION</a> <a href='#EXAMPLES'>EXAMPLES</a> <a href='#HACKING'>HACKING</a> <a href='#VERSIONS'>VERSIONS</a> <a href='#AUTHORS'>AUTHORS</a> <a href='#CREDITS'>CREDITS</a> <a href='#LICENSE'>LICENSE</a> <a href='#SEE-ALSO'>SEE ALSO</a></div>
77
+
78
+ <h1 class='man-title'>dfect(1)</h1>
79
+
80
+ <ol class='head man'>
81
+ <li class='tl'>dfect(1)</li>
82
+ <li class='tc'>Version 2.2.0</li>
83
+ <li class='tr'>dfect(1)</li>
84
+ </ol>
85
+
86
+ <h2 id='NAME'>NAME</h2>
87
+ <p><code>dfect</code> - Assertion testing library for Ruby</p>
88
+
89
+ <p>Dfect is an assertion testing library for Ruby that emphasizes a simple
90
+ assertion vocabulary, instant debuggability of failures, and flexibility in
91
+ composing tests.</p>
92
+
93
+ <h3 id="Features">Features</h3>
94
+
95
+ <ul>
96
+ <li><p>Adds only 7 mnemonic method names to your memory:</p>
97
+
98
+ <p><code>D</code>escribe, <code>T</code>rue, <code>F</code>alse, <code>E</code>rror, <code>C</code>atch, <code>S</code>hare, and <code>L</code>og.</p></li>
99
+ <li><p>Lets you debug assertion failures interactively.</p></li>
100
+ <li><p>Lets you nest tests, assertions, and execution hooks.</p></li>
101
+ <li><p>Maintains a detailed report of assertion failures.</p></li>
102
+ <li><p>Implemented in 375 lines of code.</p></li>
103
+ </ul>
104
+
105
+
106
+ <h3 id="Resources">Resources</h3>
107
+
108
+ <dl>
109
+ <dt>Issue tracker (report bugs, request features, get help)</dt><dd><p><a href="http://github.com/sunaku/dfect/issues" data-bare-link="true">http://github.com/sunaku/dfect/issues</a></p></dd>
110
+ <dt>Source code (browse online or obtain with <a href="http://git-scm.com">Git</a>)</dt><dd><p><a href="http://github.com/sunaku/dfect" data-bare-link="true">http://github.com/sunaku/dfect</a></p></dd>
111
+ <dt>API documentation</dt><dd><p><a href="http://snk.tuxfamily.org/lib/dfect/api/" data-bare-link="true">http://snk.tuxfamily.org/lib/dfect/api/</a></p></dd>
112
+ <dt>Announcements feed</dt><dd><p><a href="http://snk.tuxfamily.org/lib/dfect/ann.xml" data-bare-link="true">http://snk.tuxfamily.org/lib/dfect/ann.xml</a></p></dd>
113
+ <dt>Official website</dt><dd><p><a href="http://snk.tuxfamily.org/lib/ember/" data-bare-link="true">http://snk.tuxfamily.org/lib/ember/</a></p></dd>
114
+ </dl>
115
+
116
+
117
+ <h3 id="Setup">Setup</h3>
118
+
119
+ <p>Prerequisites:</p>
120
+
121
+ <ul>
122
+ <li><p><a href="http://ruby-lang.org">Ruby</a> 1.8.6 or newer.</p></li>
123
+ <li><p><a href="http://rubygems.org">RubyGems</a> 1.3.6 or newer.</p></li>
124
+ <li><p><a href="http://github.com/mark-moseley/ruby-debug">ruby-debug</a> will be used to help you debug assertion
125
+ failures interactively if it is installed. Otherwise, the
126
+ standard interactive Ruby shell (IRB) will be used instead.</p></li>
127
+ </ul>
128
+
129
+
130
+ <p>Installing:</p>
131
+
132
+ <pre><code>gem install dfect
133
+ </code></pre>
134
+
135
+ <p>Upgrading:</p>
136
+
137
+ <pre><code>gem update dfect
138
+ </code></pre>
139
+
140
+ <p>Removing:</p>
141
+
142
+ <pre><code>gem uninstall dfect
143
+ </code></pre>
144
+
145
+ <h2 id="SYNOPSIS">SYNOPSIS</h2>
146
+
147
+ <p><code>dfect</code> [<var>OPTIONS</var>] (<var>FILE</var>|<var>GLOB</var>) ...</p>
148
+
149
+ <h2 id="DESCRIPTION">DESCRIPTION</h2>
150
+
151
+ <p>Evaluates the given <var>FILE</var>s and also files matching the given <var>GLOB</var> patterns.</p>
152
+
153
+ <p>The exit status of this command reflects the number of errors and assertion
154
+ failures up to a maximum of 255 (to avoid 8-bit unsigned integer overflow).</p>
155
+
156
+ <h2 id="OPTIONS">OPTIONS</h2>
157
+
158
+ <dl>
159
+ <dt><code>-d</code>, <code>--debug</code></dt><dd><p>Launch interactive debugger upon assertion failures.</p></dd>
160
+ <dt><code>-q</code>, <code>--quiet</code></dt><dd><p>Do not print execution report.</p></dd>
161
+ <dt><code>-h</code>, <code>--help</code></dt><dd><p>Display this manual and exit.</p></dd>
162
+ <dt><code>-v</code>, <code>--version</code></dt><dd><p>Print version number and exit.</p></dd>
163
+ </dl>
164
+
165
+
166
+ <h2 id="TESTS">TESTS</h2>
167
+
168
+ <p>The <code>D()</code> method defines a new Dfect <strong>test</strong>, which is analagous to the
169
+ concept of <strong>test case</strong> in <a href="http://en.wikipedia.org/wiki/XUnit">xUnit</a> or <strong>describe</strong> in <a href="http://rspec.info">RSpec</a>. A test may
170
+ contain nested tests.</p>
171
+
172
+ <pre><code>D "outer test" do
173
+ # assertions and logic here
174
+
175
+ D "inner test" do
176
+ # more assertions and logic here
177
+ end
178
+ end
179
+ </code></pre>
180
+
181
+ <h3 id="Execution">Execution</h3>
182
+
183
+ <p>Tests are executed in depth-first order.</p>
184
+
185
+ <p>You can configure the test execution process using:</p>
186
+
187
+ <pre><code>Dfect.options = your_options_hash
188
+ </code></pre>
189
+
190
+ <p>You can execute all tests defined thus far using:</p>
191
+
192
+ <pre><code>Dfect.run
193
+ </code></pre>
194
+
195
+ <p>You can stop the execution at any time using:</p>
196
+
197
+ <pre><code>Dfect.stop
198
+ </code></pre>
199
+
200
+ <p>You can view the results of execution using:</p>
201
+
202
+ <pre><code>puts Dfect.report.to_yaml
203
+ </code></pre>
204
+
205
+ <p>You can mix-in the <code>Dfect</code> module into your program and execute all tests
206
+ defined by your program before it terminates by simply adding the following
207
+ line at the top of your program:</p>
208
+
209
+ <pre><code>require 'dfect/auto'
210
+ </code></pre>
211
+
212
+ <p>See the API documentation for more information and examples.</p>
213
+
214
+ <h3 id="Hooks">Hooks</h3>
215
+
216
+ <p>The <code>D()</code> method provides several entry points (hooks) into the test
217
+ execution process:</p>
218
+
219
+ <pre><code>D "outer test" do
220
+ D .&lt; { puts "before each nested test" }
221
+ D .&gt; { puts "after each nested test" }
222
+ D .&lt;&lt; { puts "before all nested tests" }
223
+ D .&gt;&gt; { puts "after all nested tests" }
224
+
225
+ D "inner test" do
226
+ # assertions and logic here
227
+ end
228
+ end
229
+ </code></pre>
230
+
231
+ <p>A hook method may be called multiple times. Each call registers
232
+ additional logic to execute during the hook:</p>
233
+
234
+ <pre><code>D .&lt; { puts "do something" }
235
+ D .&lt; { puts "do something more!" }
236
+ </code></pre>
237
+
238
+ <h3 id="Logging">Logging</h3>
239
+
240
+ <p>The <code>L()</code> method lets you insert log messages, composed of arbitrary
241
+ Ruby objects, into the test execution report.</p>
242
+
243
+ <h3 id="Sharing">Sharing</h3>
244
+
245
+ <dl>
246
+ <dt class="flush"><code>S()</code></dt><dd><p>Mechanism for sharing code. When called with a block, it shares the given
247
+ block (under a given identifier) for injection into other tests. When
248
+ called without a block, it injects a previously shared block (under a given
249
+ identifier) into the environment where it is called.</p></dd>
250
+ <dt class="flush"><code>S!()</code></dt><dd><p>Combination of the two uses of the <code>S()</code> method: it lets you simultaneously
251
+ share a block of code while injecting it into the environment where that
252
+ method is called.</p></dd>
253
+ <dt class="flush"><code>S?()</code></dt><dd><p>Checks whether any code has been shared under a given identifier.</p></dd>
254
+ </dl>
255
+
256
+
257
+ <h3 id="Insulation">Insulation</h3>
258
+
259
+ <p>The <code>D!()</code> method defines a new test that is explicitly insulated from
260
+ the tests that contain it and also from the top-level Ruby environment.
261
+ Root-level calls to the <code>D()</code> method are insulated by default.</p>
262
+
263
+ <p>Inside an insulated test, you are free to mix-in any modules your test
264
+ logic needs and also define your own constants, methods, and classes.</p>
265
+
266
+ <h2 id="ASSERTIONS">ASSERTIONS</h2>
267
+
268
+ <p>The following methods accept a block parameter and assert something about the
269
+ result of executing that block. They also accept an optional message, which
270
+ is shown in failure reports (see <strong>Failures</strong> below) if they fail.</p>
271
+
272
+ <dl>
273
+ <dt class="flush"><code>T()</code></dt><dd><p>assert true (not <code>nil</code> and not <code>false</code>)</p></dd>
274
+ <dt class="flush"><code>F()</code></dt><dd><p>assert not true (<code>nil</code> or <code>false</code>)</p></dd>
275
+ <dt class="flush"><code>E()</code></dt><dd><p>assert that an execption is raised</p></dd>
276
+ <dt class="flush"><code>C()</code></dt><dd><p>assert that a symbol is thrown</p></dd>
277
+ </dl>
278
+
279
+
280
+ <h3 id="Negation">Negation</h3>
281
+
282
+ <p>The following methods are the <em>opposite</em> of normal assertions. They also
283
+ accept an optional message, which is shown in failure reports (see
284
+ <strong>Failures</strong> below) if they fail.</p>
285
+
286
+ <dl>
287
+ <dt class="flush"><code>T!()</code></dt><dd><p>same as <code>F()</code></p></dd>
288
+ <dt class="flush"><code>F!()</code></dt><dd><p>same as <code>T()</code></p></dd>
289
+ <dt class="flush"><code>E!()</code></dt><dd><p>assert that an exception is <em>not</em> raised</p></dd>
290
+ <dt class="flush"><code>C!()</code></dt><dd><p>assert that a symbol is <em>not</em> thrown</p></dd>
291
+ </dl>
292
+
293
+
294
+ <h3 id="Sampling">Sampling</h3>
295
+
296
+ <p>The following methods let you <em>check the outcome</em> of an assertion without
297
+ recording a success or failure in the test execution report.</p>
298
+
299
+ <dl>
300
+ <dt class="flush"><code>T?()</code></dt><dd><p>returns true if <code>T()</code> passes; false otherwise</p></dd>
301
+ <dt class="flush"><code>F?()</code></dt><dd><p>returns true if <code>F()</code> passes; false otherwise</p></dd>
302
+ <dt class="flush"><code>E?()</code></dt><dd><p>returns true if <code>E()</code> passes; false otherwise</p></dd>
303
+ <dt class="flush"><code>C?()</code></dt><dd><p>returns true if <code>C()</code> passes; false otherwise</p></dd>
304
+ </dl>
305
+
306
+
307
+ <h3 id="Failures">Failures</h3>
308
+
309
+ <p>When an assertion fails, details about the failure will be shown:</p>
310
+
311
+ <pre><code>- fail: block must yield true (!nil &amp;&amp; !false)
312
+ code: |-
313
+ [12..22] in test/simple.rb
314
+ 12
315
+ 13 D "with more nested tests" do
316
+ 14 x = 5
317
+ 15
318
+ 16 T { x &gt; 2 } # passes
319
+ =&gt; 17 F { x &gt; 2 } # fails
320
+ 18 E { x.hello } # passes
321
+ 19 end
322
+ 20 end
323
+ 21
324
+ 22 # equivalent of before(:each) or setup()
325
+ vars:
326
+ x: 5
327
+ y: 83
328
+ call:
329
+ - test/simple.rb:17
330
+ - test/simple.rb:3
331
+ </code></pre>
332
+
333
+ <p>You will then be placed into a debugger to investigate the failure if
334
+ the <code>:debug</code> option is enabled in the <code>Dfect.options</code> hash.</p>
335
+
336
+ <p>Details about all assertion failures and a trace of all tests executed
337
+ are stored by Dfect and provided by the <code>Dfect.report()</code> method.</p>
338
+
339
+ <h2 id="EMULATION">EMULATION</h2>
340
+
341
+ <p>Dfect provides emulation layers for several popular testing libraries:</p>
342
+
343
+ <dl>
344
+ <dt>dfect/unit</dt><dd><p><a href="http://ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html">Test::Unit</a> emulation layer</p></dd>
345
+ <dt>dfect/mini</dt><dd><p><a href="http://blog.zenspider.com/minitest/">Minitest</a> emulation layer</p></dd>
346
+ <dt>dfect/spec</dt><dd><p><a href="http://rspec.info">RSpec</a> emulation layer</p></dd>
347
+ </dl>
348
+
349
+
350
+ <p>Simply load one of these emulation layers into your test suite and you can
351
+ write your tests using the familiar syntax of that testing library. See
352
+ their source code for more information.</p>
353
+
354
+ <h2 id="EXAMPLES">EXAMPLES</h2>
355
+
356
+ <p>Begin by loading Dfect into your program:</p>
357
+
358
+ <pre><code>require 'rubygems' # might not be necessary; see HACKING
359
+ require 'dfect'
360
+ </code></pre>
361
+
362
+ <p>You now have access to the <code>Dfect</code> module, which provides methods that can
363
+ be either mixed-in or called directly, according to your preference:</p>
364
+
365
+ <pre><code>Dfect.D "hello" do # D() is a class method
366
+ puts "world"
367
+ end
368
+
369
+ # the above is same as:
370
+
371
+ include Dfect # mix-in the Dfect API
372
+
373
+ D "hello" do # D() is an instance method
374
+ puts "world"
375
+ end
376
+ </code></pre>
377
+
378
+ <h3 id="Logging-information-in-the-execution-report">Logging information in the execution report</h3>
379
+
380
+ <p>When the following test is run:</p>
381
+
382
+ <pre><code>require 'dfect/auto'
383
+
384
+ D 'Wizard' do
385
+ L 'Preparing spell to defeat mortal foes...'
386
+ end
387
+
388
+ D 'Magician' do
389
+ L 'Preparing rabbits to pull from hat...', rand(15)
390
+ end
391
+
392
+ D 'Calculator' do
393
+ L Math::PI, [1, 2, 3, ['a', 'b', 'c']], {:foo =&gt; 'bar!'}
394
+ end
395
+ </code></pre>
396
+
397
+ <p>Dfect will output the following:</p>
398
+
399
+ <pre><code>---
400
+ - Wizard:
401
+ - Preparing spell to defeat mortal foes...
402
+ - Magician:
403
+ - Preparing rabbits to pull from hat...
404
+ - 0
405
+ - Calculator:
406
+ - 3.14159265358979
407
+ - - 1
408
+ - 2
409
+ - 3
410
+ - - a
411
+ - b
412
+ - c
413
+ - foo: bar!
414
+ ---
415
+ time: 0.000182276
416
+ </code></pre>
417
+
418
+ <h3 id="Sharing-code-between-tests">Sharing code between tests</h3>
419
+
420
+ <p>When the following test is run:</p>
421
+
422
+ <pre><code>require 'dfect/auto'
423
+
424
+ S :knowledge do
425
+ L 'Knowledge is power!'
426
+ end
427
+
428
+ D 'Healer' do
429
+ S :knowledge
430
+ end
431
+
432
+ D 'Warrior' do
433
+ S! :strength do
434
+ L 'Strength is power!'
435
+ end
436
+ end
437
+
438
+ D 'Wizard' do
439
+ S :knowledge
440
+ S :strength
441
+ end
442
+
443
+ D 'King' do
444
+ T { S? :knowledge }
445
+ T { S? :strength }
446
+ F { S? :power }
447
+ L 'Power is power!'
448
+ end
449
+ </code></pre>
450
+
451
+ <p>Dfect will output the following:</p>
452
+
453
+ <pre><code>---
454
+ - Healer:
455
+ - Knowledge is power!
456
+ - Warrior:
457
+ - Strength is power!
458
+ - Wizard:
459
+ - Knowledge is power!
460
+ - Strength is power!
461
+ - King:
462
+ - Power is power!
463
+ ---
464
+ pass: 3
465
+ time: 0.000436242
466
+ </code></pre>
467
+
468
+ <h3 id="Insulated-and-uninsulated-tests">Insulated and uninsulated tests</h3>
469
+
470
+ <p>When the following test is run:</p>
471
+
472
+ <pre><code>require 'dfect/auto'
473
+
474
+ D "a root-level test" do
475
+ @outside = 1
476
+ T { defined? @outside }
477
+ T { @outside == 1 }
478
+
479
+ D "an inner, non-insulated test" do
480
+ T { defined? @outside }
481
+ T { @outside == 1 }
482
+ end
483
+
484
+ D! "an inner, insulated test" do
485
+ F { defined? @outside }
486
+ F { @outside == 1 }
487
+
488
+ @inside = 2
489
+ T { defined? @inside }
490
+ T { @inside == 2 }
491
+ end
492
+
493
+ F { defined? @inside }
494
+ F { @inside == 2 }
495
+ end
496
+ </code></pre>
497
+
498
+ <p>Dfect will output the following:</p>
499
+
500
+ <pre><code>---
501
+ - a root-level test:
502
+ - an inner, non-insulated test: []
503
+
504
+ - an inner, insulated test: []
505
+
506
+ ---
507
+ pass: 10
508
+ time: 0.000504211
509
+ </code></pre>
510
+
511
+ <h2 id="HACKING">HACKING</h2>
512
+
513
+ <p>This section is meant for people who want to develop Dfect's source code.</p>
514
+
515
+ <h3 id="Prerequisites">Prerequisites</h3>
516
+
517
+ <p>Install Ruby libraries necessary for development:</p>
518
+
519
+ <pre><code>gem install dfect --development
520
+ </code></pre>
521
+
522
+ <h3 id="Infrastructure">Infrastructure</h3>
523
+
524
+ <p><a href="http://snk.tuxfamily.org/lib/inochi/">Inochi</a> serves as the project infrastructure for Dfect. It handles tasks
525
+ such as building this help manual and API documentation, and packaging,
526
+ announcing, and publishing new releases. See its help manual and list of
527
+ tasks to get started:</p>
528
+
529
+ <pre><code>inochi --help # display help manual
530
+ inochi --tasks # list available tasks
531
+ </code></pre>
532
+
533
+ <h3 id="-LOAD_PATH-setup">$LOAD_PATH setup</h3>
534
+
535
+ <p>Ensure that the <code>lib/</code> directory is listed in Ruby's <code>$LOAD_PATH</code> before you
536
+ use any libraries therein or run any executables in the <code>bin/</code> directory.</p>
537
+
538
+ <p>This can be achieved by passing an option to Ruby:</p>
539
+
540
+ <pre><code>ruby -Ilib bin/dfect
541
+ irb -Ilib -r dfect
542
+ </code></pre>
543
+
544
+ <p>Or by setting the <code>$RUBYLIB</code> environment variable:</p>
545
+
546
+ <pre><code>export RUBYLIB=lib # bash, ksh, zsh
547
+ setenv RUBYLIB lib # csh
548
+ set -x RUBYLIB lib # fish
549
+
550
+ ruby bin/dfect
551
+ irb -r dfect
552
+ </code></pre>
553
+
554
+ <p>Or by installing the <a href="http://github.com/chneukirchen/rup">ruby-wrapper</a> tool.</p>
555
+
556
+ <h3 id="RubyGems-setup">RubyGems setup</h3>
557
+
558
+ <p>If you use Ruby 1.8 or older, then ensure that RubyGems is activated before
559
+ you use any libraries in the <code>lib/</code> directory or run any executables in the
560
+ <code>bin/</code> directory.</p>
561
+
562
+ <p>This can be achieved by passing an option to Ruby:</p>
563
+
564
+ <pre><code>ruby -rubygems bin/dfect
565
+ irb -rubygems -r dfect
566
+ </code></pre>
567
+
568
+ <p>Or by setting the <code>$RUBYOPT</code> environment variable:</p>
569
+
570
+ <pre><code>export RUBYOPT=-rubygems # bash, ksh, zsh
571
+ setenv RUBYOPT -rubygems # csh
572
+ set -x RUBYOPT -rubygems # fish
573
+ </code></pre>
574
+
575
+ <h3 id="Running-tests">Running tests</h3>
576
+
577
+ <p>Simply execute the included test runner, which sets up Ruby's <code>$LOAD_PATH</code> for
578
+ testing, loads the included <code>test/test_helper.rb</code> file, and then evaluates all
579
+ <code>test/**/*_test.rb</code> files:</p>
580
+
581
+ <pre><code>test/runner
582
+ </code></pre>
583
+
584
+ <p>Its exit status will indicate whether all tests have passed. It may also
585
+ print additional pass/fail information depending on the testing library used
586
+ in the <code>test/test_helper.rb</code> file.</p>
587
+
588
+ <h3 id="Contributing">Contributing</h3>
589
+
590
+ <p>Fork this project on GitHub (see <strong>Resources</strong> above) and send a pull request.</p>
591
+
592
+ <h2 id="VERSIONS">VERSIONS</h2>
593
+
594
+ <p>This section contains release notes of current and past releases.</p>
595
+
596
+ <h3 id="Version-2-2-0-2010-04-28-">Version 2.2.0 (2010-04-28)</h3>
597
+
598
+ <p>This release adds a UNIX manual page and a sub-library for full method names.</p>
599
+
600
+ <p>New features:</p>
601
+
602
+ <ul>
603
+ <li><p>Add <code>dfect/full</code> sub-library that provides full name aliases to Dfect's
604
+ abbreviated vocabulary:</p>
605
+
606
+ <p><code>D</code>escribe, <code>T</code>rue, <code>F</code>alse, <code>E</code>rror, <code>C</code>atch, <code>S</code>hare, and <code>L</code>og.</p></li>
607
+ <li><p>Run <code>dfect --help</code> to see the UNIX manual page!</p></li>
608
+ </ul>
609
+
610
+
611
+ <p>Housekeeping:</p>
612
+
613
+ <ul>
614
+ <li>Upgrade to Inochi 3.0.0 and revise the help manual.</li>
615
+ </ul>
616
+
617
+
618
+ <h3 id="Version-2-1-0-2010-03-31-">Version 2.1.0 (2010-03-31)</h3>
619
+
620
+ <p>This release adds a command-line test runner and performs some minor
621
+ housekeeping.</p>
622
+
623
+ <p>New features:</p>
624
+
625
+ <ul>
626
+ <li>Add <code>bin/dfect</code> executable as command-line interface to this library.</li>
627
+ </ul>
628
+
629
+
630
+ <p>Housekeeping:</p>
631
+
632
+ <ul>
633
+ <li><p>Do not <code>require 'rubygems'</code> before loading the "ruby-debug" library.</p></li>
634
+ <li><p>Upgrade to Inochi 2.0.0-rc2 for managing this project.</p></li>
635
+ </ul>
636
+
637
+
638
+ <h3 id="Version-2-0-0-2010-03-21-">Version 2.0.0 (2010-03-21)</h3>
639
+
640
+ <p>This release adds the ability to insulate tests from each other, share code
641
+ between them, makes the order of parameters consistent in the API, improves
642
+ user interactivity, fixes some bugs, and revises the user manual.</p>
643
+
644
+ <p>Incompatible changes:</p>
645
+
646
+ <ul>
647
+ <li><p>Root-level calls to the <code>Dfect::D()</code>
648
+ method are automatically insulated now.</p></li>
649
+ <li><p>The <code>Dfect::E()</code> methods now expects its optional message
650
+ parameter to be the <em>last parameter</em> in the parameter list.</p></li>
651
+ <li><p>The <code>Dfect::C()</code> methods now expect their first parameter to
652
+ be a symbol instead of the optional message to be shown in
653
+ case of assertion failure.</p></li>
654
+ <li><p>The <code>Dfect::R()</code> has been renamed to <code>Dfect::L()</code>,
655
+ which is a mnemonic for "Logging".</p></li>
656
+ <li><p>Shorten names of hash keys in the execution trace for brevity
657
+ and rename <code>:raise</code> key in report statistics to <code>:error</code>.</p></li>
658
+ <li><p>Only the most helpful subset of the failure details is shown before
659
+ placing the user into a debugger because they can query the omitted
660
+ information (on demand) inside the debugger.</p></li>
661
+ <li><p>The execution trace is only shown if all tests passed in <code>Dfect::run()</code>.</p></li>
662
+ <li><p>The <code>:debug</code> option is now set to Ruby's <code>$DEBUG</code> global by default.</p></li>
663
+ </ul>
664
+
665
+
666
+ <p>New features:</p>
667
+
668
+ <ul>
669
+ <li><p>Print failures as they occur instead of waiting until the end.</p></li>
670
+ <li><p>Allow passing condition as argument to true/false assertions instead
671
+ of requiring the condition to be passed as a code block, and also fall
672
+ back to the binding of inner-most enclosing test or hook when
673
+ debugging or constructing a failure report for an assertion that was
674
+ not given a block.</p>
675
+
676
+ <p>This allows you to reduce "line noise" in your tests:</p>
677
+
678
+ <pre><code>D "Lottery" do
679
+ winning_ticket = rand()
680
+
681
+ D "My chances of winning" do
682
+ my_ticket = rand()
683
+ F my_ticket == winning_ticket, "I won?! Dream on."
684
+ end
685
+ end
686
+ </code></pre></li>
687
+ <li><p>Add <code>Dfect::S()</code> methods for sharing code between tests.</p></li>
688
+ <li><p>Add <code>Dfect::D!()</code> method to explicitly insulate a test from other
689
+ tests, the top-level Ruby environment, and the code being tested.</p></li>
690
+ <li><p>Add <code>Dfect::info()</code> method which returns the details of
691
+ the failure that is currently being debugged by the user.</p></li>
692
+ <li><p>Add instance variables to the <code>:vars</code> section of a failure report.</p></li>
693
+ <li><p>Add <code>setup!()</code> and <code>teardown!()</code> methods for before-all and
694
+ after-all hooks in the dfect/unit emulation library.</p></li>
695
+ <li><p>Add test execution time to statistics hash (under the <code>:time</code> key).</p></li>
696
+ </ul>
697
+
698
+
699
+ <p>Bug fixes:</p>
700
+
701
+ <ul>
702
+ <li><p>Do not print any output when <code>:quiet</code> option is active.</p></li>
703
+ <li><p>Allow passing multiple strings/objects to <code>Dfect::D()</code> like in RSpec.</p></li>
704
+ <li><p>Make before and after hook methods mixin-able like assertions.</p></li>
705
+ <li><p>Do not assume that <code>Module#to_s</code> is the same as <code>Module#name</code>.</p></li>
706
+ </ul>
707
+
708
+
709
+ <p>Housekeeping:</p>
710
+
711
+ <ul>
712
+ <li><p>Upgrade to Inochi 2.0.0-rc1 for managing this project.</p></li>
713
+ <li><p>Make emulation libraries modify Dfect module instead of Kernel.</p></li>
714
+ <li><p>Do not pollute the user's output with our <code>Class#to_yaml</code> workaround.</p></li>
715
+ <li><p>Remove "Motivation" section from user manual. It was too fanatic!</p></li>
716
+ </ul>
717
+
718
+
719
+ <h3 id="Version-1-1-0-2009-10-27-">Version 1.1.0 (2009-10-27)</h3>
720
+
721
+ <p>This release adds a new method for emitting status messages and does some
722
+ internal housekeeping.</p>
723
+
724
+ <p>Thank you:</p>
725
+
726
+ <ul>
727
+ <li>Iñaki Baz Castillo used Dfect and suggested new features.</li>
728
+ </ul>
729
+
730
+
731
+ <p>New features:</p>
732
+
733
+ <ul>
734
+ <li>Add <code>Dfect::S()</code> method for adding status messages to the
735
+ execution report. This feature was <a href="http://github.com/sunaku/dfect/issues/1">requested
736
+ by</a> Iñaki Baz Castillo.</li>
737
+ </ul>
738
+
739
+
740
+ <p>Housekeeping:</p>
741
+
742
+ <ul>
743
+ <li><p>Remove unused require of 'delegate' standard library in 'dfect/spec'
744
+ RSpec emulation layer.</p></li>
745
+ <li><p>Mention emulation layers for popular testing libraries.</p></li>
746
+ <li><p>Mention that assertions take an optional message parameter.</p></li>
747
+ <li><p>Replace sample unit test with Dfect test suite.</p></li>
748
+ <li><p>Upgrade user manual to ERBook 9.0.0.</p></li>
749
+ </ul>
750
+
751
+
752
+ <h3 id="Version-1-0-1-2009-10-07-">Version 1.0.1 (2009-10-07)</h3>
753
+
754
+ <p>This release fixes a bug in the <a href="http://ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html">Test::Unit</a> emulation library and revises the
755
+ user manual.</p>
756
+
757
+ <p>Bug fixes:</p>
758
+
759
+ <ul>
760
+ <li>The parameters for the <code>assert_equal()</code> method in the
761
+ dfect/unit library were in the wrong order.</li>
762
+ </ul>
763
+
764
+
765
+ <p>Housekeeping:</p>
766
+
767
+ <ul>
768
+ <li><p>Revise user manual to better fit jQuery UI tabs.</p></li>
769
+ <li><p>Justify the use of <code>eval()</code> in emulation libraries.</p></li>
770
+ <li><p>Use simpler Copyright reminder at the top of every file.</p></li>
771
+ <li><p>Make SLOC count in user manual reflect the <em>core</em> library only.</p></li>
772
+ <li><p>Mark code spans with <code>{:lang=ruby}</code> instead of HTML <code>&lt;code/&gt;</code> tags.</p></li>
773
+ <li><p>Open source is for fun, so <a href="http://loiclemeur.com/english/2009/03/never-criticize-your-competitors.html">be nice</a> and speak of "related works" instead of "competitors".</p></li>
774
+ </ul>
775
+
776
+
777
+ <h3 id="Version-1-0-0-2009-05-03-">Version 1.0.0 (2009-05-03)</h3>
778
+
779
+ <p>This release improves default choices, adds emulation layers to mimic other
780
+ testing libraries, and fixes some bugs.</p>
781
+
782
+ <p>Incompatible changes:</p>
783
+
784
+ <ul>
785
+ <li><p>The <code>:debug</code> option is now enabled by default and is no longer linked to
786
+ the value of <code>$DEBUG</code>.</p></li>
787
+ <li><p><code>Dfect.run()</code> now appends to previous results by default.</p>
788
+
789
+ <p>This behavior can be disabled by passing <code>false</code> to the method.</p></li>
790
+ </ul>
791
+
792
+
793
+ <p>New features:</p>
794
+
795
+ <ul>
796
+ <li>Add emulation layers to mimic other testing libraries:
797
+
798
+ <ul>
799
+ <li>dfect/unit --- <a href="http://ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html">Test::Unit</a></li>
800
+ <li>dfect/mini --- <a href="http://blog.zenspider.com/minitest/">Minitest</a></li>
801
+ <li>dfect/spec --- <a href="http://rspec.info">RSpec</a></li>
802
+ </ul>
803
+ </li>
804
+ </ul>
805
+
806
+
807
+ <p>Bug fixes:</p>
808
+
809
+ <ul>
810
+ <li>Do not blindly replace <code>Class#to_yaml</code>; it might be fixed someday.</li>
811
+ </ul>
812
+
813
+
814
+ <p>Housekeeping:</p>
815
+
816
+ <ul>
817
+ <li><p>Add "Motivation" section in user manual to promote interactive
818
+ debugging.</p></li>
819
+ <li><p>Add brief History of this project's inception.</p></li>
820
+ <li><p>Remove redundant assertions for F!() and T!() methods in test suite.</p></li>
821
+ <li><p>Add copyright notice at the top of every file.</p></li>
822
+ </ul>
823
+
824
+
825
+ <h3 id="Version-0-1-0-2009-04-28-">Version 0.1.0 (2009-04-28)</h3>
826
+
827
+ <p>This release adds new variations to assertion methods, fixes several bugs,
828
+ and improves test coverage.</p>
829
+
830
+ <p>Thank you:</p>
831
+
832
+ <ul>
833
+ <li>François Beausoleil contributed patches for both code <em>and</em> tests! :-)</li>
834
+ </ul>
835
+
836
+
837
+ <p>New features:</p>
838
+
839
+ <ul>
840
+ <li><p>Added negation (m!) and sampling (m?) variations to normal assertion
841
+ methods. These new methods implement assertion functionality missing so
842
+ far (previously we could not assert that a given exception was NOT thrown)
843
+ and thereby allow us to fully test Dfect using itself.</p></li>
844
+ <li><p>Added documentation on how to insulate tests from the global Ruby
845
+ namespace.</p></li>
846
+ </ul>
847
+
848
+
849
+ <p>Bug fixes:</p>
850
+
851
+ <ul>
852
+ <li><p>The <code>E()</code> method did not consider the case where a block does not raise
853
+ anything as a failure. ---<em>François Beausoleil</em></p></li>
854
+ <li><p>When creating a report about an assertion failure, an exception would be
855
+ thrown if any local variables pointed to an empty array.</p></li>
856
+ <li><p>The <code>Dfect::&lt;()</code> method broke the inheritance-checking behavior of the &lt;
857
+ class method.</p>
858
+
859
+ <p>Added a bypass to the originial behavior so that <code>RCov::XX</code> can properly
860
+ generate a report about code that uses Dfect.</p></li>
861
+ <li><p>Added workaround for YAML error when serializing a class object:</p>
862
+
863
+ <pre><code>TypeError: can't dump anonymous class Class
864
+ </code></pre></li>
865
+ </ul>
866
+
867
+
868
+ <p>Housekeeping:</p>
869
+
870
+ <ul>
871
+ <li>Filled the big holes in test coverage. Everything except the runtime
872
+ debugging logic is now covered by the unit tests.</li>
873
+ </ul>
874
+
875
+
876
+ <h3 id="Version-0-0-0-2009-04-13-">Version 0.0.0 (2009-04-13)</h3>
877
+
878
+ <p>For the longest time, I took <a href="http://ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html">Test::Unit</a> and <a href="http://rspec.info">RSpec</a> for granted. They were
879
+ the epitomy of modern Ruby practice; the insurmountable status quo;
880
+ immortalized in books, conferences, and blogs alike.</p>
881
+
882
+ <p>Why would <em>anyone</em> think of using anything remotely different, let alone be
883
+ foolish enough to write an alternative testing library when these are clearly
884
+ <em>good enough</em>?</p>
885
+
886
+ <p>Recent experiments in assertion testing libraries smashed my world view:</p>
887
+
888
+ <ul>
889
+ <li><a href="http://assert2.rubyforge.org">assert{ 2.0 }</a></li>
890
+ <li><a href="http://github.com/ahoward/testy/tree/master">Testy</a></li>
891
+ <li><a href="http://www.ruby-forum.com/topic/183354">Verify</a></li>
892
+ </ul>
893
+
894
+
895
+ <p>The status quo was certainly <em>not</em> "good enough", as I had so blindly
896
+ believed all these years. In fact, they were <em>verbose</em> behemoths that chose
897
+ to encode endless permutations of conjecture into methods.</p>
898
+
899
+ <p>Empowered by this revelation and inspired by <a href="http://www.ruby-forum.com/topic/183354#801895">Sean O'Halpin's musing</a> on alternative names for
900
+ assertion methods, I rose to challenge the status quo.</p>
901
+
902
+ <p>And so I present to you the first public release of "Dfect".</p>
903
+
904
+ <h2 id="AUTHORS">AUTHORS</h2>
905
+
906
+ <p>Suraj N. Kurapati</p>
907
+
908
+ <h2 id="CREDITS">CREDITS</h2>
909
+
910
+ <p>François Beausoleil,
911
+ Iñaki Baz Castillo,
912
+ Sean O'Halpin</p>
913
+
914
+ <h2 id="LICENSE">LICENSE</h2>
915
+
916
+ <p>(the ISC license)</p>
917
+
918
+ <p>Copyright 2009 Suraj N. Kurapati <a href="&#x6d;&#97;&#x69;&#x6c;&#x74;&#111;&#x3a;&#115;&#x75;&#110;&#97;&#x6b;&#117;&#64;&#103;&#x6d;&#x61;&#105;&#108;&#46;&#x63;&#111;&#x6d;" data-bare-link="true">&#115;&#x75;&#x6e;&#x61;&#107;&#x75;&#64;&#x67;&#109;&#x61;&#105;&#x6c;&#46;&#99;&#111;&#109;</a></p>
919
+
920
+ <p>Permission to use, copy, modify, and/or distribute this software for any
921
+ purpose with or without fee is hereby granted, provided that the above
922
+ copyright notice and this permission notice appear in all copies.</p>
923
+
924
+ <p>THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
925
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
926
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
927
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
928
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
929
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
930
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.</p>
931
+
932
+ <h2 id="SEE-ALSO">SEE ALSO</h2>
933
+
934
+ <p><a href="http://assert2.rubyforge.org">assert{ 2.0 }</a>,
935
+ <a href="http://github.com/ahoward/testy/tree/master">Testy</a>,
936
+ <a href="http://www.ruby-forum.com/topic/183354">Verify</a></p>
937
+
938
+
939
+ <ol class='foot man'>
940
+ <li class='tl'></li>
941
+ <li class='tc'>April 2010</li>
942
+ <li class='tr'>dfect(1)</li>
943
+ </ol>
944
+
945
+ </div>
946
+ </body>
947
+ </html>