test-unit-ext 0.4.0 → 0.5.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/NEWS.en CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  = NEWS
4
4
 
5
+ == 0.5.0: 2008-04-07
6
+
7
+ * Update document.
8
+ * Support pend.
9
+ * Support notify.
10
+
5
11
  == 0.4.0: 2008-03-17
6
12
 
7
13
  * Changed XML report format.
data/NEWS.ja CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  = NEWS.ja
4
4
 
5
+ == 0.5.0: 2008-04-07
6
+
7
+ * ドキュメントの更新
8
+ * pend(保留)のサポート
9
+ * notify(通知)のサポート
10
+
5
11
  == 0.4.0: 2008-03-17
6
12
 
7
13
  * XML出力形式の変更
data/README.en CHANGED
@@ -14,9 +14,12 @@ TestUnitExt provides some useful features:
14
14
 
15
15
  * Emacs friendly backtrace format.
16
16
  * runs tests depending on priority.
17
- * supports metadata for each test.
17
+ * supports attributes for each test.
18
18
  * always shows tests result even if tests are interrupted.
19
19
  * colorized output.
20
+ * outputs diff between expected and actual value.
21
+ * reports test result as XML format.
22
+ * adds pending/notification methods.
20
23
 
21
24
  == Author
22
25
 
@@ -42,10 +45,185 @@ None
42
45
 
43
46
  require 'test-unit-ext'
44
47
 
45
- === Priority
48
+ == Reference
46
49
 
47
50
  === Attributes
48
51
 
52
+ You can add attributes to your test to get more useful
53
+ information on failure. For example, you can add Bug ID like
54
+ the following
55
+
56
+ class MyTest < Test::Unit::TestCase
57
+ bug 123
58
+ def test_invalid_input
59
+ assert_equal("OK", input)
60
+ end
61
+ end
62
+
63
+ In the above example, test_invalid_input test has an
64
+ attribute that the test is for Bug #123.
65
+
66
+ You can also write like the following:
67
+
68
+ class MyTest < Test::Unit::TestCase
69
+ attribute :bug, 123
70
+ def test_invalid_input
71
+ assert_equal("OK", input)
72
+ end
73
+ end
74
+
75
+ That is, bug method is a convenience method. You can add any
76
+ attributes to your test if you use attribute method.
77
+
78
+ === Priority
79
+
80
+ It will be difficult that you drop into test and develop
81
+ cycle when you have many tests and the tests take much
82
+ time. To reduce the problem, you can select some tests from
83
+ all tests and reduce elapsed time each test. It's a problem
84
+ that which tests are selected in each test.
85
+
86
+ In TestUnitExt, each test has its priority and runs tests
87
+ are selected by probabilistic method. --priority command
88
+ line option enables this feature.
89
+
90
+ A test that has higher priority will be ran in higher
91
+ ratio. Each test doesn't run all tests but tests that are
92
+ ran each test are changed in each test. All tests will be
93
+ ran after some test and develop cycles.
94
+
95
+ Tests that aren't succeeded in the previous test are ran in
96
+ the current test in spite of its priority. This means that
97
+ important tests are ran without you do something. You will
98
+ keep your lightweight test and develop cycles without
99
+ additional works.
100
+
101
+ Here are a sample priority specification. Priority
102
+ specification effects followed tests like public and
103
+ private.
104
+
105
+ class MyTest < Test::Unit::TestCase
106
+ priority :must
107
+ def test_must
108
+ # will be always ran
109
+ end
110
+
111
+ def test_must2
112
+ # will be always ran too
113
+ end
114
+
115
+ priority :import
116
+ def test_import
117
+ # will be almost ran
118
+ end
119
+
120
+ priority :high
121
+ def test_high
122
+ # will be ran in high probability
123
+ end
124
+
125
+ priority :normal
126
+ def test_normal
127
+ # will be ran in fifty-fifty probability
128
+ # tests without priority specification has normal priority
129
+ end
130
+
131
+ priority :low
132
+ def test_low
133
+ # will be sometimes ran
134
+ end
135
+
136
+ priority :never
137
+ def test_never
138
+ # never be ran
139
+ end
140
+ end
141
+
142
+ === Pending
143
+
144
+ You may write a test for a function that is not
145
+ implemented. In the case, the test will be failed. It's
146
+ correct that the test is failed but the test means 'the
147
+ function is not implemented'. To state your intent, pend
148
+ method is provided.
149
+
150
+ Please state your intent by your test code by using the
151
+ method.
152
+
153
+ class MyTest < Test::Unit::TestCase
154
+ def test_minor_function
155
+ pend("Should implement")
156
+ assert_equal("Good!", MyModule.minor_function)
157
+ end
158
+ end
159
+
160
+ === Notification
161
+
162
+ You may put some messages in test. For example, "this test
163
+ is omitted because XXX module is not found on the
164
+ environment."
165
+
166
+ Those messages can be displayed by puts but it causes test
167
+ result output. To prevent this, notify method is
168
+ provided. notify method doesn't display those messages in
169
+ the place but display those messages in test result summary
170
+ like "failure", "error" and so on. You can leave those
171
+ messages without breaking test result output by using notify
172
+ method.
173
+
174
+ class MyTest < Test::Unit::TestCase
175
+ def test_with_other_module
176
+ unless MyModule.have_XXX?
177
+ notify("XXX module isn't found. skip this test.")
178
+ return
179
+ end
180
+ assert_equal("XXX Module!!!", MyModule.use_XXX)
181
+ end
182
+ end
183
+
184
+ === XML report
185
+
186
+ Test result can be reported as XML format if --xml-report
187
+ option is specified. A reported XML has the following
188
+ structure:
189
+
190
+ <report>
191
+ <result>
192
+ <test-case>
193
+ <name>TEST CASE NAME</name>
194
+ <description>DESCRIPTION OF TEST CASE (if exists)</description>
195
+ </test-case>
196
+ <test>
197
+ <name>TEST NAME</name>
198
+ <description>DESCRIPTION OF TEST CASE (if exists)</description>
199
+ <option><!-- ATTRIBUTE INFORMATION (if exists) -->
200
+ <name>ATTRIBUTE NAME (e.g.: bug)</name>
201
+ <value>ATTRIBUTE VALUE (e.g.: 1234)</value>
202
+ </option>
203
+ <option>
204
+ ...
205
+ </option>
206
+ </test>
207
+ <status>TEST RESULT ([success|failure|error|pending|notification])</status>
208
+ <detail>DETAIL OF TEST RESULT (if exists)</detail>
209
+ <backtrace><!-- BACKTRACE (if exists) -->
210
+ <entry>
211
+ <file>FILE NAME</file>
212
+ <line>LINE</line>
213
+ <info>ADDITIONAL INFORMATION</info>
214
+ </entry>
215
+ <entry>
216
+ ...
217
+ </entry>
218
+ </backtrace>
219
+ <elapsed>ELAPSED TIME (e.g.: 0.000010)</elapsed>
220
+ </result>
221
+ <result>
222
+ ...
223
+ </result>
224
+ ...
225
+ </report>
226
+
49
227
  == Thanks
50
228
 
51
229
  * ...
data/README.ja CHANGED
@@ -14,9 +14,12 @@ TestUnitExtはいくつかの有用な機能を提供します。
14
14
 
15
15
  * Emacsにやさしいバックトレースフォーマット
16
16
  * 優先度に応じたテストの実行
17
- * 各テストへのメタデータの付加
17
+ * 各テストへの属性の付加
18
18
  * テストを途中終了(Ctrl+C)しても結果を表示
19
19
  * 色付き出力
20
+ * テスト結果のdiff出力
21
+ * テスト結果のXMLでの出力
22
+ * 保留(pending)・通知(notification)用メソッドの追加
20
23
 
21
24
  == 作者
22
25
 
@@ -42,10 +45,185 @@ Ruby's.
42
45
 
43
46
  require 'test-unit-ext'
44
47
 
45
- === 優先度
48
+ == リファレンス
46
49
 
47
50
  === 属性
48
51
 
52
+ テストに属性を加えて、テスト失敗時により有益な情報を利用する
53
+ ことができます。例えば、以下のようにテストにBug IDの情報を付
54
+ 加することができます。
55
+
56
+ class MyTest < Test::Unit::TestCase
57
+ bug 123
58
+ def test_invalid_input
59
+ assert_equal("OK", input)
60
+ end
61
+ end
62
+
63
+ この例では、test_invalid_inputテストがBug #123のテストである
64
+ という情報を付加しています。
65
+
66
+ これは以下のように書くこともできます。
67
+
68
+ class MyTest < Test::Unit::TestCase
69
+ attribute :bug, 123
70
+ def test_invalid_input
71
+ assert_equal("OK", input)
72
+ end
73
+ end
74
+
75
+ つまり、bugメソッドは便利のために用意されたメソッドです。
76
+ attributeメソッドを使うことで任意の属性を付加することができ
77
+ ます。
78
+
79
+ === 優先度
80
+
81
+ テストが多くなるとテスト時間が長くなり、テストと開発をリズム
82
+ 良く繰り返すことが難しくなります。それを軽減するために、開発
83
+ 時のテストでは毎回全てのテストを実行するのではなく、一部のテ
84
+ ストのみ実行して1回のテスト時間を短くすることができます。問題
85
+ は各テストでどのテストを実行するかです。
86
+
87
+ TestUnitExtでは属性としてテストに優先度を付け、それに従って毎
88
+ 回実行するテストを確率的に選択します。コマンドラインオプショ
89
+ ンで--priorityを指定するとこの機能が有効になります。
90
+
91
+ 優先度が高いテスト程高い確率で実行され、そうではないテストは
92
+ 低い頻度で実行されます。各テストでは全てのテストは実行しない
93
+ が、各テストで実行するテストがその都度変わるため、何度も走ら
94
+ せることにより結果的にテスト全体を実行することになります。
95
+
96
+ また、前回成功しなかったテストは確実に実行するため、明示的に
97
+ 優先度を上げなくても失敗している(現在注目すべき重要な)テス
98
+ トは毎回必ず実行します。これにより、プログラマの負荷をあげる
99
+ ことなくテストのメリットを受けたまま、テストと開発のリズムを
100
+ 保つことができます。
101
+
102
+ 優先度は以下のように指定します。優先度指定はpublicやprivateの
103
+ ように、以降のメソッド定義に影響します。
104
+
105
+ class MyTest < Test::Unit::TestCase
106
+ priority :must
107
+ def test_must
108
+ # 必ず実行
109
+ end
110
+
111
+ def test_must2
112
+ # これも必ず実行
113
+ end
114
+
115
+ priority :import
116
+ def test_import
117
+ # 高い確率で実行
118
+ end
119
+
120
+ priority :high
121
+ def test_high
122
+ # やや高い確率で実行
123
+ end
124
+
125
+ priority :normal
126
+ def test_normal
127
+ # 半々の確率で実行
128
+ # 優先度を指定していないときはnormal
129
+ end
130
+
131
+ priority :low
132
+ def test_low
133
+ # たまに実行
134
+ end
135
+
136
+ priority :never
137
+ def test_never
138
+ # 実行しない
139
+ end
140
+ end
141
+
142
+ === 保留
143
+
144
+ 現在はまだ実装していない機能をテストとして書くことも場合もあ
145
+ ります。その場合、まだ実装していない機能のテストは失敗します。
146
+ たしかにテストは失敗なのですが、そのテストは「実装が間違って
147
+ いる」ではなく、「まだ実装していない」を意図しています。これ
148
+ を明示的に表現するために新しくpendというメソッドを用意してい
149
+ ます。
150
+
151
+ 「現在はまだ実装していない」という場合はこのメソッドを使って、
152
+ その意図をコードで表現してください。
153
+
154
+ class MyTest < Test::Unit::TestCase
155
+ def test_minor_function
156
+ pend("Should implement")
157
+ assert_equal("Good!", MyModule.minor_function)
158
+ end
159
+ end
160
+
161
+ === 通知
162
+
163
+ テスト中で何らかのメッセージを残したいことがあります。例えば、
164
+ 「この環境では○○モジュールがないからこのテストは省略しま
165
+ す」、という場合です。
166
+
167
+ それらのメッセージをputsで表示することもできますが、テスト結
168
+ 果の表示が乱れてしまいます。これを防ぐために、新しくnotifyメ
169
+ ソッドを用意しています。notifyを使うとメッセージはその場では
170
+ 表示されず、テスト終了後に他の「失敗」や「エラー」などと同じ
171
+ ように表示されます。これにより、テスト結果の表示を乱さずにメッ
172
+ セージを残すことができます。
173
+
174
+ class MyTest < Test::Unit::TestCase
175
+ def test_with_other_module
176
+ unless MyModule.have_XXX?
177
+ notify("XXX module isn't found. skip this test.")
178
+ return
179
+ end
180
+ assert_equal("XXX Module!!!", MyModule.use_XXX)
181
+ end
182
+ end
183
+
184
+ === XML出力
185
+
186
+ --xml-reportオプションを指定することでテスト結果をXML形式で出
187
+ 力することができます。出力されるXMLは以下のような構造になって
188
+ います。
189
+
190
+ <report>
191
+ <result>
192
+ <test-case>
193
+ <name>テストケース名</name>
194
+ <description>テストケースの説明(もしあれば)</description>
195
+ </test-case>
196
+ <test>
197
+ <name>テスト名</name>
198
+ <description>テストの説明(もしあれば)</description>
199
+ <option><!-- 属性情報(もしあれば) -->
200
+ <name>属性名(例: bug)</name>
201
+ <value>属性値(例: 1234)</value>
202
+ </option>
203
+ <option>
204
+ ...
205
+ </option>
206
+ </test>
207
+ <status>テスト結果([success|failure|error|pending|notification])</status>
208
+ <detail>テスト結果の詳細(もしあれば)</detail>
209
+ <backtrace><!-- バックトレース(もしあれば) -->
210
+ <entry>
211
+ <file>ファイル名</file>
212
+ <line>行</line>
213
+ <info>付加情報</info>
214
+ </entry>
215
+ <entry>
216
+ ...
217
+ </entry>
218
+ </backtrace>
219
+ <elapsed>実行時間(例: 0.000010)</elapsed>
220
+ </result>
221
+ <result>
222
+ ...
223
+ </result>
224
+ ...
225
+ </report>
226
+
49
227
  == 感謝
50
228
 
51
229
  * ...
@@ -9,16 +9,7 @@
9
9
  </head>
10
10
  <body>
11
11
  <h1><a name="label-0" id="label-0">NEWS</a></h1><!-- RDLabel: "NEWS" -->
12
- <h2><a name="label-1" id="label-1">0.4.0: 2008-03-17</a></h2><!-- RDLabel: "0.4.0: 2008-03-17" -->
13
- <ul>
14
- <li>Changed XML report format.</li>
15
- </ul>
16
- <h2><a name="label-2" id="label-2">0.3.0: 2008-03-10</a></h2><!-- RDLabel: "0.3.0: 2008-03-10" -->
17
- <ul>
18
- <li>Changed XML report format.</li>
19
- <li>Improved search method to find test result directory.</li>
20
- </ul>
21
- <h2><a name="label-3" id="label-3">0.2.0: 2008-03-03</a></h2><!-- RDLabel: "0.2.0: 2008-03-03" -->
12
+ <h2><a name="label-1" id="label-1">0.2.0: 2008-03-03</a></h2><!-- RDLabel: "0.2.0: 2008-03-03" -->
22
13
  <ul>
23
14
  <li>Supported XML report.
24
15
  <ul>
@@ -26,7 +17,7 @@
26
17
  </ul></li>
27
18
  <li>Supported diff output for assert_equal.</li>
28
19
  </ul>
29
- <h2><a name="label-4" id="label-4">0.1.0: 2008-02-21</a></h2><!-- RDLabel: "0.1.0: 2008-02-21" -->
20
+ <h2><a name="label-2" id="label-2">0.1.0: 2008-02-21</a></h2><!-- RDLabel: "0.1.0: 2008-02-21" -->
30
21
  <ul>
31
22
  <li>Initial release.</li>
32
23
  </ul>
@@ -9,16 +9,7 @@
9
9
  </head>
10
10
  <body>
11
11
  <h1><a name="label-0" id="label-0">NEWS</a></h1><!-- RDLabel: "NEWS" -->
12
- <h2><a name="label-1" id="label-1">0.4.0: 2008-03-17</a></h2><!-- RDLabel: "0.4.0: 2008-03-17" -->
13
- <ul>
14
- <li>Changed XML report format.</li>
15
- </ul>
16
- <h2><a name="label-2" id="label-2">0.3.0: 2008-03-10</a></h2><!-- RDLabel: "0.3.0: 2008-03-10" -->
17
- <ul>
18
- <li>Changed XML report format.</li>
19
- <li>Improved search method to find test result directory.</li>
20
- </ul>
21
- <h2><a name="label-3" id="label-3">0.2.0: 2008-03-03</a></h2><!-- RDLabel: "0.2.0: 2008-03-03" -->
12
+ <h2><a name="label-1" id="label-1">0.2.0: 2008-03-03</a></h2><!-- RDLabel: "0.2.0: 2008-03-03" -->
22
13
  <ul>
23
14
  <li>Supported XML report.
24
15
  <ul>
@@ -26,7 +17,7 @@
26
17
  </ul></li>
27
18
  <li>Supported diff output for assert_equal.</li>
28
19
  </ul>
29
- <h2><a name="label-4" id="label-4">0.1.0: 2008-02-21</a></h2><!-- RDLabel: "0.1.0: 2008-02-21" -->
20
+ <h2><a name="label-2" id="label-2">0.1.0: 2008-02-21</a></h2><!-- RDLabel: "0.1.0: 2008-02-21" -->
30
21
  <ul>
31
22
  <li>Initial release.</li>
32
23
  </ul>
@@ -9,16 +9,7 @@
9
9
  </head>
10
10
  <body>
11
11
  <h1><a name="label-0" id="label-0">NEWS.ja</a></h1><!-- RDLabel: "NEWS.ja" -->
12
- <h2><a name="label-1" id="label-1">0.4.0: 2008-03-17</a></h2><!-- RDLabel: "0.4.0: 2008-03-17" -->
13
- <ul>
14
- <li>XML出力形式の変更</li>
15
- </ul>
16
- <h2><a name="label-2" id="label-2">0.3.0: 2008-03-10</a></h2><!-- RDLabel: "0.3.0: 2008-03-10" -->
17
- <ul>
18
- <li>XML出力形式の変更</li>
19
- <li>テスト結果を保存するディレクトリの検索処理を改良</li>
20
- </ul>
21
- <h2><a name="label-3" id="label-3">0.2.0: 2008-03-03</a></h2><!-- RDLabel: "0.2.0: 2008-03-03" -->
12
+ <h2><a name="label-1" id="label-1">0.2.0: 2008-03-03</a></h2><!-- RDLabel: "0.2.0: 2008-03-03" -->
22
13
  <ul>
23
14
  <li>XML出力のサポート。
24
15
  <ul>
@@ -26,7 +17,7 @@
26
17
  </ul></li>
27
18
  <li>assert_equal時のdiff出力のサポート。</li>
28
19
  </ul>
29
- <h2><a name="label-4" id="label-4">0.1.0: 2008-02-21</a></h2><!-- RDLabel: "0.1.0: 2008-02-21" -->
20
+ <h2><a name="label-2" id="label-2">0.1.0: 2008-02-21</a></h2><!-- RDLabel: "0.1.0: 2008-02-21" -->
30
21
  <ul>
31
22
  <li>最初のリリース。</li>
32
23
  </ul>
@@ -32,7 +32,7 @@
32
32
  <h2><a name="label-7" id="label-7">Usage</a></h2><!-- RDLabel: "Usage" -->
33
33
  <pre>require 'test-unit-ext'</pre>
34
34
  <h3><a name="label-8" id="label-8">Priority</a></h3><!-- RDLabel: "Priority" -->
35
- <h3><a name="label-9" id="label-9">Attributes</a></h3><!-- RDLabel: "Attributes" -->
35
+ <h3><a name="label-9" id="label-9">Metadata</a></h3><!-- RDLabel: "Metadata" -->
36
36
  <h2><a name="label-10" id="label-10">Thanks</a></h2><!-- RDLabel: "Thanks" -->
37
37
  <ul>
38
38
  <li>...</li>
@@ -32,7 +32,7 @@
32
32
  <h2><a name="label-7" id="label-7">Usage</a></h2><!-- RDLabel: "Usage" -->
33
33
  <pre>require 'test-unit-ext'</pre>
34
34
  <h3><a name="label-8" id="label-8">Priority</a></h3><!-- RDLabel: "Priority" -->
35
- <h3><a name="label-9" id="label-9">Attributes</a></h3><!-- RDLabel: "Attributes" -->
35
+ <h3><a name="label-9" id="label-9">Metadata</a></h3><!-- RDLabel: "Metadata" -->
36
36
  <h2><a name="label-10" id="label-10">Thanks</a></h2><!-- RDLabel: "Thanks" -->
37
37
  <ul>
38
38
  <li>...</li>
@@ -32,7 +32,7 @@
32
32
  <h2><a name="label-7" id="label-7">使用法</a></h2><!-- RDLabel: "使用法" -->
33
33
  <pre>require 'test-unit-ext'</pre>
34
34
  <h3><a name="label-8" id="label-8">優先度</a></h3><!-- RDLabel: "優先度" -->
35
- <h3><a name="label-9" id="label-9">属性</a></h3><!-- RDLabel: "属性" -->
35
+ <h3><a name="label-9" id="label-9">メタデータ</a></h3><!-- RDLabel: "メタデータ" -->
36
36
  <h2><a name="label-10" id="label-10">感謝</a></h2><!-- RDLabel: "感謝" -->
37
37
  <ul>
38
38
  <li>...</li>
@@ -5,9 +5,11 @@ require "test-unit-ext/color"
5
5
  require "test-unit-ext/colorized-runner"
6
6
  require "test-unit-ext/diff"
7
7
  require "test-unit-ext/always-show-result"
8
+ require "test-unit-ext/attributes"
8
9
  require "test-unit-ext/priority"
9
10
  require "test-unit-ext/backtrace-filter"
10
11
  require "test-unit-ext/long-display-for-emacs"
11
- require "test-unit-ext/attributes"
12
12
  require "test-unit-ext/xml-report"
13
13
  require "test-unit-ext/assertions"
14
+ require "test-unit-ext/pending"
15
+ require "test-unit-ext/notification"
@@ -11,9 +11,9 @@ module Test
11
11
  diff = Diff.readable(expected, actual)
12
12
  if /^[\?\-\+].{79}/ =~ diff
13
13
  folded_diff = Diff.readable(fold(expected), fold(actual))
14
- diff = "#{diff}\nfolded diff:\n#{folded_diff}"
14
+ diff = "#{diff}\n\nfolded diff:\n#{folded_diff}"
15
15
  end
16
- raise $!, "#{$!.message}\ndiff:\n#{diff}", $@
16
+ raise $!, "#{$!.message}\n\ndiff:\n#{diff}", $@
17
17
  end
18
18
 
19
19
  def fold(string)
@@ -8,15 +8,25 @@ module Test
8
8
  def method_added(name)
9
9
  method_added_without_attributes(name)
10
10
  if defined?(@current_attributes)
11
- set_attributes(name, @current_attributes)
12
- @current_attributes = {}
11
+ attributes = {}
12
+ kept_attributes = {}
13
+ @current_attributes.each do |attribute_name, attribute|
14
+ attributes[attribute_name] = attribute[:value]
15
+ kept_attributes[attribute_name] = attribute if attribute[:keep]
16
+ end
17
+ set_attributes(name, attributes)
18
+ @current_attributes = kept_attributes
13
19
  end
14
20
  end
15
21
 
16
- def attribute(name, value, *tests)
22
+ def attribute(name, value, options={}, *tests)
23
+ unless options.is_a?(Hash)
24
+ tests << options
25
+ options = {}
26
+ end
17
27
  @current_attributes ||= {}
18
28
  if tests.empty?
19
- @current_attributes[name] = value
29
+ @current_attributes[name] = options.merge(:value => value)
20
30
  else
21
31
  tests.each do |test|
22
32
  set_attribute(test, {name => value})
@@ -41,6 +51,11 @@ module Test
41
51
  @attributes ||= {}
42
52
  @attributes[test_name]
43
53
  end
54
+
55
+ private
56
+ def normalize_test_name(test_name)
57
+ "test_#{test_name.to_s.sub(/^test_/, '')}"
58
+ end
44
59
  end
45
60
 
46
61
  alias_method :run_without_attributes, :run
@@ -11,6 +11,8 @@ module Test
11
11
  :default => {
12
12
  "success" => Color.new("green", :bold => true),
13
13
  "failure" => Color.new("red", :bold => true),
14
+ "pending" => Color.new("magenta", :bold => true),
15
+ "notification" => Color.new("cyan", :bold => true),
14
16
  "error" => Color.new("yellow", :bold => true),
15
17
  },
16
18
  }
@@ -59,7 +61,13 @@ module Test
59
61
 
60
62
  def result_color
61
63
  if @result.passed?
62
- @color_scheme["success"]
64
+ if @result.pending_count > 0
65
+ @color_scheme["pending"]
66
+ elsif @result.notification_count > 0
67
+ @color_scheme["notification"]
68
+ else
69
+ @color_scheme["success"]
70
+ end
63
71
  elsif @result.error_count > 0
64
72
  @color_scheme["error"]
65
73
  elsif @result.failure_count > 0
@@ -85,6 +93,7 @@ module Test
85
93
  end
86
94
 
87
95
  def guess_color_availability
96
+ return false unless @io.tty?
88
97
  term = ENV["TERM"]
89
98
  return true if term and (/term\z/ =~ term or term == "screen")
90
99
  return true if ENV["EMACS"] == "t"
@@ -153,9 +153,9 @@ module Test
153
153
  best_from, best_to, best_size = best_info
154
154
  while best_from > from_start and best_to > to_start and
155
155
  (should_junk ?
156
- @junks.has_key?(@to[best_to]) :
157
- !@junks.has_key?(@to[best_to])) and
158
- @from[best_from] == @to[best_to]
156
+ @junks.has_key?(@to[best_to - 1]) :
157
+ !@junks.has_key?(@to[best_to - 1])) and
158
+ @from[best_from - 1] == @to[best_to - 1]
159
159
  best_from -= 1
160
160
  best_to -= 1
161
161
  best_size += 1
@@ -174,27 +174,31 @@ module Test
174
174
  end
175
175
 
176
176
  def matches
177
- _matches = []
178
- queue = [[0, @from.size - 1, 0, @to.size - 1]]
177
+ indexed_matches = []
178
+ queue = [[0, @from.size, 0, @to.size]]
179
179
  until queue.empty?
180
180
  from_start, from_end, to_start, to_end = queue.pop
181
- match = longest_match(from_start, from_end, to_start, to_end)
181
+ match = longest_match(from_start, from_end - 1, to_start, to_end - 1)
182
182
  match_from_index, match_to_index, size = match
183
183
  unless size.zero?
184
- _matches << match
185
184
  if from_start < match_from_index and
186
185
  to_start < match_to_index
187
- queue.push([from_start, match_from_index - 1,
188
- to_start, match_to_index - 1])
186
+ queue.push([from_start, match_from_index,
187
+ to_start, match_to_index])
189
188
  end
190
- if match_from_index + size <= from_end and
191
- match_to_index + size <= to_end
189
+ indexed_matches << [match_from_index, match]
190
+ if match_from_index + size < from_end and
191
+ match_to_index + size < to_end
192
192
  queue.push([match_from_index + size, from_end,
193
193
  match_to_index + size, to_end])
194
194
  end
195
195
  end
196
196
  end
197
- _matches
197
+ indexed_matches.sort_by do |index, match|
198
+ index
199
+ end.collect do |index, match|
200
+ match
201
+ end
198
202
  end
199
203
 
200
204
  def determine_tag(from_index, to_index,
@@ -278,6 +282,10 @@ module Test
278
282
  tag(" ", contents)
279
283
  end
280
284
 
285
+ def tag_difference(contents)
286
+ tag("? ", contents)
287
+ end
288
+
281
289
  def diff_lines(from_start, from_end, to_start, to_end)
282
290
  best_ratio, cut_off = 0.74, 0.75
283
291
  from_equal_index = to_equal_index = nil
@@ -368,9 +376,13 @@ module Test
368
376
  to_tags = to_tags[common..-1].rstrip
369
377
 
370
378
  result = tag_deleted([from_line])
371
- result << "? #{"\t" * common}#{from_tags}" unless from_tags.empty?
379
+ unless from_tags.empty?
380
+ result.concat(tag_difference(["#{"\t" * common}#{from_tags}"]))
381
+ end
372
382
  result.concat(tag_inserted([to_line]))
373
- result << "? #{"\t" * common}#{to_tags}" unless to_tags.empty?
383
+ unless to_tags.empty?
384
+ result.concat(tag_difference(["#{"\t" * common}#{to_tags}"]))
385
+ end
374
386
  result
375
387
  end
376
388
 
@@ -0,0 +1,81 @@
1
+ module Test
2
+ module Unit
3
+ class TestResult
4
+ attr_reader :notifications
5
+
6
+ alias_method(:initialize_without_notifications, :initialize)
7
+ def initialize
8
+ initialize_without_notifications
9
+ @notifications = []
10
+ end
11
+
12
+ def add_notification(notification)
13
+ @notifications << notification
14
+ notify_listeners(FAULT, notification)
15
+ notify_listeners(CHANGED, self)
16
+ end
17
+
18
+ def notification_count
19
+ @notifications.size
20
+ end
21
+
22
+ alias_method(:to_s_without_notifications, :to_s)
23
+ def to_s
24
+ to_s_without_notifications + ", #{notification_count} notifications"
25
+ end
26
+ end
27
+
28
+ class Notification
29
+ attr_reader :test_name, :location, :message
30
+
31
+ SINGLE_CHARACTER = 'N'
32
+
33
+ # Creates a new Notification with the given location and
34
+ # message.
35
+ def initialize(test_name, location, message)
36
+ @test_name = test_name
37
+ @location = location
38
+ @message = message
39
+ end
40
+
41
+ # Returns a single character representation of a notification.
42
+ def single_character_display
43
+ SINGLE_CHARACTER
44
+ end
45
+
46
+ # Returns a brief version of the error description.
47
+ def short_display
48
+ "#@test_name: #{@message.split("\n")[0]}"
49
+ end
50
+
51
+ # Returns a verbose version of the error description.
52
+ def long_display
53
+ if location.size == 1
54
+ location_display = location[0].sub(/\A(.+:\d+).*/, ' [\\1]')
55
+ else
56
+ location_display = "\n" + location.join("\n")
57
+ end
58
+ "Notification:\n#{@test_name}#{location_display}:\n#{@message}"
59
+ end
60
+
61
+ # Overridden to return long_display.
62
+ def to_s
63
+ long_display
64
+ end
65
+ end
66
+
67
+ class NotifiedError < StandardError
68
+ end
69
+
70
+ module AssertionsWithNotify
71
+ def notify(message)
72
+ notification = Notification.new(name, caller[0, 1], message)
73
+ @_result.add_notification(notification)
74
+ end
75
+ end
76
+
77
+ class TestCase
78
+ include AssertionsWithNotify
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,99 @@
1
+ module Test
2
+ module Unit
3
+ class TestResult
4
+ attr_reader :pendings
5
+
6
+ alias_method(:initialize_without_pendings, :initialize)
7
+ def initialize
8
+ initialize_without_pendings
9
+ @pendings = []
10
+ end
11
+
12
+ def add_pending(pending)
13
+ @pendings << pending
14
+ notify_listeners(FAULT, pending)
15
+ notify_listeners(CHANGED, self)
16
+ end
17
+
18
+ def pending_count
19
+ @pendings.size
20
+ end
21
+
22
+ alias_method(:to_s_without_pendings, :to_s)
23
+ def to_s
24
+ to_s_without_pendings + ", #{pending_count} pendings"
25
+ end
26
+ end
27
+
28
+ class Pending
29
+ attr_reader :test_name, :location, :message
30
+
31
+ SINGLE_CHARACTER = 'P'
32
+
33
+ # Creates a new Pending with the given location and
34
+ # message.
35
+ def initialize(test_name, location, message)
36
+ @test_name = test_name
37
+ @location = location
38
+ @message = message
39
+ end
40
+
41
+ # Returns a single character representation of a pending.
42
+ def single_character_display
43
+ SINGLE_CHARACTER
44
+ end
45
+
46
+ # Returns a brief version of the error description.
47
+ def short_display
48
+ "#@test_name: #{@message.split("\n")[0]}"
49
+ end
50
+
51
+ # Returns a verbose version of the error description.
52
+ def long_display
53
+ if location.size == 1
54
+ location_display = location[0].sub(/\A(.+:\d+).*/, ' [\\1]')
55
+ else
56
+ location_display = "\n" + location.join("\n")
57
+ end
58
+ "Pending:\n#{@test_name}#{location_display}:\n#{@message}"
59
+ end
60
+
61
+ # Overridden to return long_display.
62
+ def to_s
63
+ long_display
64
+ end
65
+ end
66
+
67
+ class PendedError < StandardError
68
+ end
69
+
70
+ module AssertionsWithPend
71
+ def pend(message="Pended", &block)
72
+ if block_given?
73
+ begin
74
+ yield
75
+ rescue Exception
76
+ raise PendedError, message, $!.backtrace
77
+ end
78
+ flunk("Pending block should not be passed: #{message}")
79
+ else
80
+ raise PendedError.new(message)
81
+ end
82
+ end
83
+ end
84
+
85
+ class TestCase
86
+ include AssertionsWithPend
87
+
88
+ alias_method(:add_error_without_pending, :add_error)
89
+ def add_error(exception)
90
+ if exception.is_a?(PendedError)
91
+ pending = Pending.new(name, exception.backtrace, exception.message)
92
+ @_result.add_pending(pending)
93
+ else
94
+ add_error_without_pending(exception)
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -3,52 +3,23 @@ require "test/unit"
3
3
  require "fileutils"
4
4
  require "tmpdir"
5
5
 
6
+ require "test-unit-ext/attributes"
7
+
6
8
  module Test
7
9
  module Unit
8
10
  class TestCase
9
11
  class << self
10
- def inherited(sub)
11
- super
12
- sub.instance_variable_set("@priority_initialized", true)
13
- sub.instance_variable_set("@priority_table", {})
14
- sub.priority :normal
15
- end
16
-
17
- def include(*args)
18
- args.reverse_each do |mod|
19
- super(mod)
20
- next unless defined?(@priority_initialized)
21
- mod.instance_methods(false).each do |name|
22
- set_priority(name)
23
- end
24
- end
25
- end
26
-
27
- alias_method :method_added_without_priority, :method_added
28
- def method_added(name)
29
- method_added_without_priority(name)
30
- set_priority(name) if defined?(@priority_initialized)
31
- end
32
-
33
12
  def priority(name, *tests)
34
13
  singleton_class = (class << self; self; end)
35
14
  priority_check_method = priority_check_method_name(name)
36
15
  unless singleton_class.private_method_defined?(priority_check_method)
37
16
  raise ArgumentError, "unknown priority: #{name}"
38
17
  end
39
- if tests.empty?
40
- @current_priority = name
41
- else
42
- tests.each do |test|
43
- set_priority(test, name)
44
- end
45
- end
18
+ attribute(:priority, name, {:keep => true}, *tests)
46
19
  end
47
20
 
48
21
  def need_to_run?(test_name)
49
- normalized_test_name = normalize_test_name(test_name)
50
- priority = @priority_table[normalized_test_name]
51
- return true unless priority
22
+ priority = (attributes(test_name) || {})[:priority] || :normal
52
23
  __send__(priority_check_method_name(priority), test_name)
53
24
  end
54
25
 
@@ -57,10 +28,6 @@ module Test
57
28
  "run_priority_#{priority_name}?"
58
29
  end
59
30
 
60
- def normalize_test_name(test_name)
61
- "test_#{test_name.to_s.sub(/^test_/, '')}"
62
- end
63
-
64
31
  def set_priority(name, priority=@current_priority)
65
32
  @priority_table[normalize_test_name(name)] = priority
66
33
  end
@@ -1,3 +1,3 @@
1
1
  module TestUnitExt
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -74,6 +74,7 @@ class TestAttributes < Test::Unit::TestCase
74
74
  "#{__FILE__}:#{first_arg_end_line}:in `#{method_name}':\n" \
75
75
  "<2> expected but was\n" \
76
76
  "<1>.\n" \
77
+ "\n" \
77
78
  "diff:\n" \
78
79
  "- 2\n" \
79
80
  "+ 1",
@@ -84,6 +85,7 @@ class TestAttributes < Test::Unit::TestCase
84
85
  "#{__FILE__}:#{first_arg_end_line}:in `#{method_name}':\n" \
85
86
  "<0> expected but was\n" \
86
87
  "<11>.\n" \
88
+ "\n" \
87
89
  "diff:\n" \
88
90
  "- 0\n" \
89
91
  "+ 11"],
@@ -101,6 +103,7 @@ class TestAttributes < Test::Unit::TestCase
101
103
  "#{__FILE__}:#{first_arg_end_line}:in `#{method_name}':\n" \
102
104
  "<1> expected but was\n" \
103
105
  "<12>.\n" \
106
+ "\n" \
104
107
  "diff:\n" \
105
108
  "- 1\n" \
106
109
  "+ 12"],
@@ -72,6 +72,24 @@ class TestDiff < Test::Unit::TestCase
72
72
  [:equal, 4, 6, 3, 5],
73
73
  [:insert, 6, 6, 5, 6]],
74
74
  "qabxcd", "abycdf")
75
+
76
+ assert_operations([[:equal, 0, 23, 0, 23],
77
+ [:replace, 23, 24, 23, 24],
78
+ [:equal, 24, 35, 24, 35],
79
+ [:replace, 35, 36, 35, 36],
80
+ [:equal, 36, 45, 36, 45]],
81
+ "1 tests, 0 assertions, 1 failures, 0 pendings",
82
+ "1 tests, 0 assertions, 0 failures, 1 pendings")
83
+
84
+ assert_operations([[:equal, 0, 23, 0, 23],
85
+ [:replace, 23, 24, 23, 24],
86
+ [:equal, 24, 35, 24, 35],
87
+ [:replace, 35, 36, 35, 36],
88
+ [:equal, 36, 45, 36, 45]],
89
+ "1 tests, 0 assertions, 1 failures, 0 pendings",
90
+ "1 tests, 0 assertions, 0 failures, 1 pendings") do |x|
91
+ x == " "[0]
92
+ end
75
93
  end
76
94
 
77
95
  def test_grouped_operations
@@ -148,6 +166,15 @@ class TestDiff < Test::Unit::TestCase
148
166
  ["abcd abcd xyz abc"])
149
167
  end
150
168
 
169
+ def test_difference_readable_diff
170
+ assert_readable_diff("- 1 tests, 0 assertions, 1 failures, 0 pendings\n" \
171
+ "? ^ ^\n" \
172
+ "+ 1 tests, 0 assertions, 0 failures, 1 pendings\n" \
173
+ "? ^ ^",
174
+ ["1 tests, 0 assertions, 1 failures, 0 pendings"],
175
+ ["1 tests, 0 assertions, 0 failures, 1 pendings"])
176
+ end
177
+
151
178
  def test_complex_readable_diff
152
179
  assert_readable_diff(" aaa\n" \
153
180
  "- bbb\n" \
@@ -281,6 +308,15 @@ class TestDiff < Test::Unit::TestCase
281
308
  assert_equal(expected, matcher.instance_variable_get("@to_indexes"))
282
309
  end
283
310
 
311
+ def assert_find_best_match_position(expected, from, to,
312
+ from_start, from_end,
313
+ to_start, to_end, &junk_predicate)
314
+ matcher = Test::Diff::SequenceMatcher.new(from, to, &junk_predicate)
315
+ assert_equal(expected, matcher.send(:find_best_match_position,
316
+ from_start, from_end,
317
+ to_start, to_end))
318
+ end
319
+
284
320
  def assert_longest_match(expected, from, to,
285
321
  from_start, from_end,
286
322
  to_start, to_end, &junk_predicate)
@@ -294,8 +330,8 @@ class TestDiff < Test::Unit::TestCase
294
330
  assert_equal(expected, matcher.blocks)
295
331
  end
296
332
 
297
- def assert_operations(expected, from, to)
298
- matcher = Test::Diff::SequenceMatcher.new(from, to)
333
+ def assert_operations(expected, from, to, &junk_predicate)
334
+ matcher = Test::Diff::SequenceMatcher.new(from, to, &junk_predicate)
299
335
  assert_equal(expected, matcher.operations)
300
336
  end
301
337
 
@@ -0,0 +1,32 @@
1
+ require 'test-unit-ext'
2
+
3
+ class TestNotification < Test::Unit::TestCase
4
+ class TestCase < Test::Unit::TestCase
5
+ class << self
6
+ def suite
7
+ Test::Unit::TestSuite.new(name)
8
+ end
9
+ end
10
+
11
+ def test_notify
12
+ notify("1st notify")
13
+ notify("2nd notify. Reach here.")
14
+ end
15
+ end
16
+
17
+ def test_notify
18
+ result = run_test("test_notify")
19
+ assert_equal("1 tests, 0 assertions, 0 failures, 0 errors, 0 pendings, " \
20
+ "2 notifications",
21
+ result.to_s)
22
+ assert_equal(["1st notify", "2nd notify. Reach here."],
23
+ result.notifications.collect {|n| n.message})
24
+ end
25
+
26
+ private
27
+ def run_test(name)
28
+ result = Test::Unit::TestResult.new
29
+ TestCase.new(name).run(result) {}
30
+ result
31
+ end
32
+ end
@@ -0,0 +1,64 @@
1
+ require 'test-unit-ext'
2
+
3
+ class TestPending < Test::Unit::TestCase
4
+ class TestCase < Test::Unit::TestCase
5
+ class << self
6
+ def suite
7
+ Test::Unit::TestSuite.new(name)
8
+ end
9
+ end
10
+
11
+ def test_pend
12
+ pend("1st pend")
13
+ pend("2nd pend. Not reached here.")
14
+ end
15
+
16
+ def test_pend_with_failure_in_block
17
+ pend("Wait a minute") do
18
+ raise "Not implemented yet"
19
+ end
20
+ assert(true, "Not reached here.")
21
+ end
22
+
23
+ def test_pend_with_no_failure_in_block
24
+ pend("Wait a minute") do
25
+ "Nothing raised"
26
+ end
27
+ assert(true, "Reached here.")
28
+ end
29
+ end
30
+
31
+ def test_pend
32
+ result = run_test("test_pend")
33
+ assert_equal("1 tests, 0 assertions, 0 failures, 0 errors, 1 pendings, " \
34
+ "0 notifications",
35
+ result.to_s)
36
+ assert_equal(["1st pend"],
37
+ result.pendings.collect {|pending| pending.message})
38
+ end
39
+
40
+ def test_pend_with_failure_in_block
41
+ result = run_test("test_pend_with_failure_in_block")
42
+ assert_equal("1 tests, 0 assertions, 0 failures, 0 errors, 1 pendings, " \
43
+ "0 notifications",
44
+ result.to_s)
45
+ assert_equal(["Wait a minute"],
46
+ result.pendings.collect {|pending| pending.message})
47
+ end
48
+
49
+ def test_pend_with_no_failure_in_block
50
+ result = run_test("test_pend_with_no_failure_in_block")
51
+ assert_equal("1 tests, 1 assertions, 1 failures, 0 errors, 0 pendings, " \
52
+ "0 notifications",
53
+ result.to_s)
54
+ assert_equal(["Pending block should not be passed: Wait a minute."],
55
+ result.failures.collect {|failure| failure.message})
56
+ end
57
+
58
+ private
59
+ def run_test(name)
60
+ result = Test::Unit::TestResult.new
61
+ TestCase.new(name).run(result) {}
62
+ result
63
+ end
64
+ end
@@ -0,0 +1,88 @@
1
+ require 'test-unit-ext'
2
+
3
+ class TestPriority < Test::Unit::TestCase
4
+ class TestCase < Test::Unit::TestCase
5
+ class << self
6
+ def suite
7
+ Test::Unit::TestSuite.new(name)
8
+ end
9
+ end
10
+
11
+ priority :must
12
+ def test_must
13
+ assert(true)
14
+ end
15
+
16
+ def test_must_inherited
17
+ assert(true)
18
+ end
19
+
20
+ priority :important
21
+ def test_important
22
+ assert(true)
23
+ end
24
+
25
+ def test_important_inherited
26
+ assert(true)
27
+ end
28
+
29
+ priority :high
30
+ def test_high
31
+ assert(true)
32
+ end
33
+
34
+ def test_high_inherited
35
+ assert(true)
36
+ end
37
+
38
+ priority :normal
39
+ def test_normal
40
+ assert(true)
41
+ end
42
+
43
+ def test_normal_inherited
44
+ assert(true)
45
+ end
46
+
47
+ priority :low
48
+ def test_low
49
+ assert(true)
50
+ end
51
+
52
+ def test_low_inherited
53
+ assert(true)
54
+ end
55
+
56
+ priority :never
57
+ def test_never
58
+ assert(true)
59
+ end
60
+
61
+ def test_never_inherited
62
+ assert(true)
63
+ end
64
+ end
65
+
66
+ def test_priority
67
+ assert_priority("must", 1.0, 0.0001)
68
+ assert_priority("important", 0.9, 0.09)
69
+ assert_priority("high", 0.70, 0.1)
70
+ assert_priority("normal", 0.5, 0.1)
71
+ assert_priority("low", 0.25, 0.1)
72
+ assert_priority("never", 0.0, 0.0001)
73
+ end
74
+
75
+ def assert_priority(priority, expected, delta)
76
+ assert_need_to_run("test_#{priority}", expected, delta)
77
+ assert_need_to_run("test_#{priority}_inherited", expected, delta)
78
+ end
79
+
80
+ def assert_need_to_run(test_name, expected, delta)
81
+ n = 1000
82
+ n_need_to_run = 0
83
+ n.times do |i|
84
+ n_need_to_run +=1 if TestCase.need_to_run?(test_name)
85
+ end
86
+ assert_in_delta(expected, n_need_to_run.to_f / n, delta)
87
+ end
88
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: test-unit-ext
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kouhei Sutou
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-03-17 00:00:00 +09:00
12
+ date: 2008-04-07 00:00:00 +09:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -47,6 +47,8 @@ files:
47
47
  - lib/test-unit-ext/colorized-runner.rb
48
48
  - lib/test-unit-ext/diff.rb
49
49
  - lib/test-unit-ext/long-display-for-emacs.rb
50
+ - lib/test-unit-ext/notification.rb
51
+ - lib/test-unit-ext/pending.rb
50
52
  - lib/test-unit-ext/priority.rb
51
53
  - lib/test-unit-ext/version.rb
52
54
  - lib/test-unit-ext/xml-report.rb
@@ -55,6 +57,9 @@ files:
55
57
  - test/test_attributes.rb
56
58
  - test/test_color.rb
57
59
  - test/test_diff.rb
60
+ - test/test_notification.rb
61
+ - test/test_pending.rb
62
+ - test/test_priority.rb
58
63
  - test/test_xml_report.rb
59
64
  has_rdoc: true
60
65
  homepage: http://test-unit-ext.rubyforge.org/
@@ -84,7 +89,10 @@ signing_key:
84
89
  specification_version: 2
85
90
  summary: TestUnitExt extends the standard Test::Unit.
86
91
  test_files:
92
+ - test/test_pending.rb
87
93
  - test/test_diff.rb
94
+ - test/test_priority.rb
95
+ - test/test_notification.rb
96
+ - test/test_attributes.rb
88
97
  - test/test_color.rb
89
98
  - test/test_xml_report.rb
90
- - test/test_attributes.rb