1 | #--
|
---|
2 | #
|
---|
3 | # Author:: Kenta MURATA.
|
---|
4 | # Copyright:: Copyright (c) 2000-2002 Kenta MURATA. All rights reserved.
|
---|
5 | # License:: Ruby license.
|
---|
6 |
|
---|
7 | require "gtk2"
|
---|
8 | require "test/unit/ui/testrunnermediator"
|
---|
9 | require "test/unit/ui/testrunnerutilities"
|
---|
10 |
|
---|
11 | module Test
|
---|
12 | module Unit
|
---|
13 | module UI
|
---|
14 | module GTK2
|
---|
15 |
|
---|
16 | Gtk.init
|
---|
17 |
|
---|
18 | class EnhancedLabel < Gtk::Label
|
---|
19 | def set_text(text)
|
---|
20 | super(text.gsub(/\n\t/, "\n "))
|
---|
21 | end
|
---|
22 | end
|
---|
23 |
|
---|
24 | class FaultList < Gtk::TreeView
|
---|
25 | def initialize
|
---|
26 | @faults = []
|
---|
27 | @model = Gtk::ListStore.new(String, String)
|
---|
28 | super(@model)
|
---|
29 | column = Gtk::TreeViewColumn.new
|
---|
30 | column.visible = false
|
---|
31 | append_column(column)
|
---|
32 | renderer = Gtk::CellRendererText.new
|
---|
33 | column = Gtk::TreeViewColumn.new("Failures", renderer, {:text => 1})
|
---|
34 | append_column(column)
|
---|
35 | selection.mode = Gtk::SELECTION_SINGLE
|
---|
36 | set_rules_hint(true)
|
---|
37 | set_headers_visible(false)
|
---|
38 | end # def initialize
|
---|
39 |
|
---|
40 | def add_fault(fault)
|
---|
41 | @faults.push(fault)
|
---|
42 | iter = @model.append
|
---|
43 | iter.set_value(0, (@faults.length - 1).to_s)
|
---|
44 | iter.set_value(1, fault.short_display)
|
---|
45 | end # def add_fault(fault)
|
---|
46 |
|
---|
47 | def get_fault(iter)
|
---|
48 | @faults[iter.get_value(0).to_i]
|
---|
49 | end # def get_fault
|
---|
50 |
|
---|
51 | def clear
|
---|
52 | model.clear
|
---|
53 | end # def clear
|
---|
54 | end
|
---|
55 |
|
---|
56 | class TestRunner
|
---|
57 | extend TestRunnerUtilities
|
---|
58 |
|
---|
59 | def lazy_initialize(symbol)
|
---|
60 | if !instance_eval("defined?(@#{symbol})") then
|
---|
61 | yield
|
---|
62 | end
|
---|
63 | return instance_eval("@#{symbol}")
|
---|
64 | end
|
---|
65 | private :lazy_initialize
|
---|
66 |
|
---|
67 | def status_entry
|
---|
68 | lazy_initialize(:status_entry) do
|
---|
69 | @status_entry = Gtk::Entry.new
|
---|
70 | @status_entry.editable = false
|
---|
71 | end
|
---|
72 | end
|
---|
73 | private :status_entry
|
---|
74 |
|
---|
75 | def status_panel
|
---|
76 | lazy_initialize(:status_panel) do
|
---|
77 | @status_panel = Gtk::HBox.new
|
---|
78 | @status_panel.border_width = 10
|
---|
79 | @status_panel.pack_start(status_entry, true, true, 0)
|
---|
80 | end
|
---|
81 | end
|
---|
82 | private :status_panel
|
---|
83 |
|
---|
84 | def fault_detail_label
|
---|
85 | lazy_initialize(:fault_detail_label) do
|
---|
86 | @fault_detail_label = EnhancedLabel.new("")
|
---|
87 | # style = Gtk::Style.new
|
---|
88 | # font = Gdk::Font.
|
---|
89 | # font_load("-*-Courier 10 Pitch-medium-r-normal--*-120-*-*-*-*-*-*")
|
---|
90 | # style.set_font(font)
|
---|
91 | # @fault_detail_label.style = style
|
---|
92 | @fault_detail_label.justify = Gtk::JUSTIFY_LEFT
|
---|
93 | @fault_detail_label.wrap = false
|
---|
94 | end
|
---|
95 | end
|
---|
96 | private :fault_detail_label
|
---|
97 |
|
---|
98 | def inner_detail_sub_panel
|
---|
99 | lazy_initialize(:inner_detail_sub_panel) do
|
---|
100 | @inner_detail_sub_panel = Gtk::HBox.new
|
---|
101 | @inner_detail_sub_panel.pack_start(fault_detail_label, false, false, 0)
|
---|
102 | end
|
---|
103 | end
|
---|
104 | private :inner_detail_sub_panel
|
---|
105 |
|
---|
106 | def outer_detail_sub_panel
|
---|
107 | lazy_initialize(:outer_detail_sub_panel) do
|
---|
108 | @outer_detail_sub_panel = Gtk::VBox.new
|
---|
109 | @outer_detail_sub_panel.pack_start(inner_detail_sub_panel, false, false, 0)
|
---|
110 | end
|
---|
111 | end
|
---|
112 | private :outer_detail_sub_panel
|
---|
113 |
|
---|
114 | def detail_scrolled_window
|
---|
115 | lazy_initialize(:detail_scrolled_window) do
|
---|
116 | @detail_scrolled_window = Gtk::ScrolledWindow.new
|
---|
117 | @detail_scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC)
|
---|
118 | @detail_scrolled_window.
|
---|
119 | set_size_request(400, @detail_scrolled_window.allocation.height)
|
---|
120 | @detail_scrolled_window.add_with_viewport(outer_detail_sub_panel)
|
---|
121 | end
|
---|
122 | end
|
---|
123 | private :detail_scrolled_window
|
---|
124 |
|
---|
125 | def detail_panel
|
---|
126 | lazy_initialize(:detail_panel) do
|
---|
127 | @detail_panel = Gtk::HBox.new
|
---|
128 | @detail_panel.border_width = 10
|
---|
129 | @detail_panel.pack_start(detail_scrolled_window, true, true, 0)
|
---|
130 | end
|
---|
131 | end
|
---|
132 | private :detail_panel
|
---|
133 |
|
---|
134 | def fault_list
|
---|
135 | lazy_initialize(:fault_list) do
|
---|
136 | @fault_list = FaultList.new
|
---|
137 | end
|
---|
138 | end
|
---|
139 | private :fault_list
|
---|
140 |
|
---|
141 | def list_scrolled_window
|
---|
142 | lazy_initialize(:list_scrolled_window) do
|
---|
143 | @list_scrolled_window = Gtk::ScrolledWindow.new
|
---|
144 | @list_scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC)
|
---|
145 | @list_scrolled_window.
|
---|
146 | set_size_request(@list_scrolled_window.allocation.width, 150)
|
---|
147 | @list_scrolled_window.add_with_viewport(fault_list)
|
---|
148 | end
|
---|
149 | end
|
---|
150 | private :list_scrolled_window
|
---|
151 |
|
---|
152 | def list_panel
|
---|
153 | lazy_initialize(:list_panel) do
|
---|
154 | @list_panel = Gtk::HBox.new
|
---|
155 | @list_panel.border_width = 10
|
---|
156 | @list_panel.pack_start(list_scrolled_window, true, true, 0)
|
---|
157 | end
|
---|
158 | end
|
---|
159 | private :list_panel
|
---|
160 |
|
---|
161 | def error_count_label
|
---|
162 | lazy_initialize(:error_count_label) do
|
---|
163 | @error_count_label = Gtk::Label.new("0")
|
---|
164 | @error_count_label.justify = Gtk::JUSTIFY_LEFT
|
---|
165 | end
|
---|
166 | end
|
---|
167 | private :error_count_label
|
---|
168 |
|
---|
169 | def failure_count_label
|
---|
170 | lazy_initialize(:failure_count_label) do
|
---|
171 | @failure_count_label = Gtk::Label.new("0")
|
---|
172 | @failure_count_label.justify = Gtk::JUSTIFY_LEFT
|
---|
173 | end
|
---|
174 | end
|
---|
175 | private :failure_count_label
|
---|
176 |
|
---|
177 | def assertion_count_label
|
---|
178 | lazy_initialize(:assertion_count_label) do
|
---|
179 | @assertion_count_label = Gtk::Label.new("0")
|
---|
180 | @assertion_count_label.justify = Gtk::JUSTIFY_LEFT
|
---|
181 | end
|
---|
182 | end
|
---|
183 | private :assertion_count_label
|
---|
184 |
|
---|
185 | def run_count_label
|
---|
186 | lazy_initialize(:run_count_label) do
|
---|
187 | @run_count_label = Gtk::Label.new("0")
|
---|
188 | @run_count_label.justify = Gtk::JUSTIFY_LEFT
|
---|
189 | end
|
---|
190 | end
|
---|
191 | private :run_count_label
|
---|
192 |
|
---|
193 | def info_panel
|
---|
194 | lazy_initialize(:info_panel) do
|
---|
195 | @info_panel = Gtk::HBox.new(false, 0)
|
---|
196 | @info_panel.border_width = 10
|
---|
197 | @info_panel.pack_start(Gtk::Label.new("Runs:"), false, false, 0)
|
---|
198 | @info_panel.pack_start(run_count_label, true, false, 0)
|
---|
199 | @info_panel.pack_start(Gtk::Label.new("Assertions:"), false, false, 0)
|
---|
200 | @info_panel.pack_start(assertion_count_label, true, false, 0)
|
---|
201 | @info_panel.pack_start(Gtk::Label.new("Failures:"), false, false, 0)
|
---|
202 | @info_panel.pack_start(failure_count_label, true, false, 0)
|
---|
203 | @info_panel.pack_start(Gtk::Label.new("Errors:"), false, false, 0)
|
---|
204 | @info_panel.pack_start(error_count_label, true, false, 0)
|
---|
205 | end
|
---|
206 | end # def info_panel
|
---|
207 | private :info_panel
|
---|
208 |
|
---|
209 | def green_style
|
---|
210 | lazy_initialize(:green_style) do
|
---|
211 | @green_style = Gtk::Style.new
|
---|
212 | @green_style.set_bg(Gtk::STATE_PRELIGHT, 0x0000, 0xFFFF, 0x0000)
|
---|
213 | end
|
---|
214 | end # def green_style
|
---|
215 | private :green_style
|
---|
216 |
|
---|
217 | def red_style
|
---|
218 | lazy_initialize(:red_style) do
|
---|
219 | @red_style = Gtk::Style.new
|
---|
220 | @red_style.set_bg(Gtk::STATE_PRELIGHT, 0xFFFF, 0x0000, 0x0000)
|
---|
221 | end
|
---|
222 | end # def red_style
|
---|
223 | private :red_style
|
---|
224 |
|
---|
225 | def test_progress_bar
|
---|
226 | lazy_initialize(:test_progress_bar) {
|
---|
227 | @test_progress_bar = Gtk::ProgressBar.new
|
---|
228 | @test_progress_bar.fraction = 0.0
|
---|
229 | @test_progress_bar.
|
---|
230 | set_size_request(@test_progress_bar.allocation.width,
|
---|
231 | info_panel.size_request[1])
|
---|
232 | @test_progress_bar.style = green_style
|
---|
233 | }
|
---|
234 | end # def test_progress_bar
|
---|
235 | private :test_progress_bar
|
---|
236 |
|
---|
237 | def progress_panel
|
---|
238 | lazy_initialize(:progress_panel) do
|
---|
239 | @progress_panel = Gtk::HBox.new(false, 10)
|
---|
240 | @progress_panel.border_width = 10
|
---|
241 | @progress_panel.pack_start(test_progress_bar, true, true, 0)
|
---|
242 | end
|
---|
243 | end # def progress_panel
|
---|
244 |
|
---|
245 | def run_button
|
---|
246 | lazy_initialize(:run_button) do
|
---|
247 | @run_button = Gtk::Button.new("Run")
|
---|
248 | end
|
---|
249 | end # def run_button
|
---|
250 |
|
---|
251 | def suite_name_entry
|
---|
252 | lazy_initialize(:suite_name_entry) do
|
---|
253 | @suite_name_entry = Gtk::Entry.new
|
---|
254 | @suite_name_entry.editable = false
|
---|
255 | end
|
---|
256 | end # def suite_name_entry
|
---|
257 | private :suite_name_entry
|
---|
258 |
|
---|
259 | def suite_panel
|
---|
260 | lazy_initialize(:suite_panel) do
|
---|
261 | @suite_panel = Gtk::HBox.new(false, 10)
|
---|
262 | @suite_panel.border_width = 10
|
---|
263 | @suite_panel.pack_start(Gtk::Label.new("Suite:"), false, false, 0)
|
---|
264 | @suite_panel.pack_start(suite_name_entry, true, true, 0)
|
---|
265 | @suite_panel.pack_start(run_button, false, false, 0)
|
---|
266 | end
|
---|
267 | end # def suite_panel
|
---|
268 | private :suite_panel
|
---|
269 |
|
---|
270 | def main_panel
|
---|
271 | lazy_initialize(:main_panel) do
|
---|
272 | @main_panel = Gtk::VBox.new(false, 0)
|
---|
273 | @main_panel.pack_start(suite_panel, false, false, 0)
|
---|
274 | @main_panel.pack_start(progress_panel, false, false, 0)
|
---|
275 | @main_panel.pack_start(info_panel, false, false, 0)
|
---|
276 | @main_panel.pack_start(list_panel, false, false, 0)
|
---|
277 | @main_panel.pack_start(detail_panel, true, true, 0)
|
---|
278 | @main_panel.pack_start(status_panel, false, false, 0)
|
---|
279 | end
|
---|
280 | end # def main_panel
|
---|
281 | private :main_panel
|
---|
282 |
|
---|
283 | def main_window
|
---|
284 | lazy_initialize(:main_window) do
|
---|
285 | @main_window = Gtk::Window.new(Gtk::Window::TOPLEVEL)
|
---|
286 | @main_window.set_title("Test::Unit TestRunner")
|
---|
287 | @main_window.set_default_size(800, 600)
|
---|
288 | @main_window.set_resizable(true)
|
---|
289 | @main_window.add(main_panel)
|
---|
290 | end
|
---|
291 | end # def main_window
|
---|
292 | private :main_window
|
---|
293 |
|
---|
294 | def setup_ui
|
---|
295 | main_window.signal_connect("destroy", nil) { stop }
|
---|
296 | main_window.show_all
|
---|
297 | fault_list.selection.signal_connect("changed", nil) do
|
---|
298 | |selection, data|
|
---|
299 | if selection.selected then
|
---|
300 | show_fault(fault_list.get_fault(selection.selected))
|
---|
301 | else
|
---|
302 | clear_fault
|
---|
303 | end
|
---|
304 | end
|
---|
305 | end # def setup_ui
|
---|
306 | private :setup_ui
|
---|
307 |
|
---|
308 | def output_status(string)
|
---|
309 | status_entry.set_text(string)
|
---|
310 | end # def output_status(string)
|
---|
311 | private :output_status
|
---|
312 |
|
---|
313 | def finished(elapsed_time)
|
---|
314 | test_progress_bar.fraction = 1.0
|
---|
315 | output_status("Finished in #{elapsed_time} seconds")
|
---|
316 | end # def finished(elapsed_time)
|
---|
317 | private :finished
|
---|
318 |
|
---|
319 | def test_started(test_name)
|
---|
320 | output_status("Running #{test_name}...")
|
---|
321 | end # def test_started(test_name)
|
---|
322 | private :test_started
|
---|
323 |
|
---|
324 | def started(result)
|
---|
325 | @result = result
|
---|
326 | output_status("Started...")
|
---|
327 | end # def started(result)
|
---|
328 | private :started
|
---|
329 |
|
---|
330 | def test_finished(result)
|
---|
331 | test_progress_bar.fraction += 1.0 / @count
|
---|
332 | end # def test_finished(result)
|
---|
333 |
|
---|
334 | def result_changed(result)
|
---|
335 | run_count_label.label = result.run_count.to_s
|
---|
336 | assertion_count_label.label = result.assertion_count.to_s
|
---|
337 | failure_count_label.label = result.failure_count.to_s
|
---|
338 | error_count_label.label = result.error_count.to_s
|
---|
339 | end # def result_changed(result)
|
---|
340 | private :result_changed
|
---|
341 |
|
---|
342 | def clear_fault
|
---|
343 | raw_show_fault("")
|
---|
344 | end # def clear_fault
|
---|
345 | private :clear_fault
|
---|
346 |
|
---|
347 | def raw_show_fault(string)
|
---|
348 | fault_detail_label.set_text(string)
|
---|
349 | outer_detail_sub_panel.queue_resize
|
---|
350 | end # def raw_show_fault(string)
|
---|
351 | private :raw_show_fault
|
---|
352 |
|
---|
353 | def show_fault(fault)
|
---|
354 | raw_show_fault(fault.long_display)
|
---|
355 | end # def show_fault(fault)
|
---|
356 | private :show_fault
|
---|
357 |
|
---|
358 | def add_fault(fault)
|
---|
359 | if not @red then
|
---|
360 | test_progress_bar.style = red_style
|
---|
361 | @red = true
|
---|
362 | end
|
---|
363 | fault_list.add_fault(fault)
|
---|
364 | end # def add_fault(fault)
|
---|
365 | private :add_fault
|
---|
366 |
|
---|
367 | def reset_ui(count)
|
---|
368 | test_progress_bar.style = green_style
|
---|
369 | test_progress_bar.fraction = 0.0
|
---|
370 | @count = count + 1
|
---|
371 | @red = false
|
---|
372 |
|
---|
373 | run_count_label.set_text("0")
|
---|
374 | assertion_count_label.set_text("0")
|
---|
375 | failure_count_label.set_text("0")
|
---|
376 | error_count_label.set_text("0")
|
---|
377 |
|
---|
378 | fault_list.clear
|
---|
379 | end # def reset_ui(count)
|
---|
380 | private :reset_ui
|
---|
381 |
|
---|
382 | def stop
|
---|
383 | Gtk.main_quit
|
---|
384 | end # def stop
|
---|
385 | private :stop
|
---|
386 |
|
---|
387 | def run_test
|
---|
388 | @runner.raise(@restart_signal)
|
---|
389 | end
|
---|
390 | private :run_test
|
---|
391 |
|
---|
392 | def start_ui
|
---|
393 | @viewer.run
|
---|
394 | running = false
|
---|
395 | begin
|
---|
396 | loop do
|
---|
397 | if (running ^= true)
|
---|
398 | run_button.child.text = "Stop"
|
---|
399 | @mediator.run_suite
|
---|
400 | else
|
---|
401 | run_button.child.text = "Run"
|
---|
402 | @viewer.join
|
---|
403 | break
|
---|
404 | end
|
---|
405 | end
|
---|
406 | rescue @restart_signal
|
---|
407 | retry
|
---|
408 | rescue
|
---|
409 | end
|
---|
410 | end # def start_ui
|
---|
411 | private :start_ui
|
---|
412 |
|
---|
413 | def attach_to_mediator
|
---|
414 | run_button.signal_connect("clicked", nil) { run_test }
|
---|
415 | @mediator.add_listener(TestRunnerMediator::RESET, &method(:reset_ui))
|
---|
416 | @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started))
|
---|
417 | @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished))
|
---|
418 | @mediator.add_listener(TestResult::FAULT, &method(:add_fault))
|
---|
419 | @mediator.add_listener(TestResult::CHANGED, &method(:result_changed))
|
---|
420 | @mediator.add_listener(TestCase::STARTED, &method(:test_started))
|
---|
421 | @mediator.add_listener(TestCase::FINISHED, &method(:test_finished))
|
---|
422 | end # def attach_to_mediator
|
---|
423 | private :attach_to_mediator
|
---|
424 |
|
---|
425 | def setup_mediator
|
---|
426 | @mediator = TestRunnerMediator.new(@suite)
|
---|
427 | suite_name = @suite.to_s
|
---|
428 | if @suite.kind_of?(Module) then
|
---|
429 | suite_name = @suite.name
|
---|
430 | end
|
---|
431 | suite_name_entry.set_text(suite_name)
|
---|
432 | end # def setup_mediator
|
---|
433 | private :setup_mediator
|
---|
434 |
|
---|
435 | def start
|
---|
436 | setup_mediator
|
---|
437 | setup_ui
|
---|
438 | attach_to_mediator
|
---|
439 | start_ui
|
---|
440 | @result
|
---|
441 | end # def start
|
---|
442 |
|
---|
443 | def initialize(suite, output_level = NORMAL)
|
---|
444 | if suite.respond_to?(:suite) then
|
---|
445 | @suite = suite.suite
|
---|
446 | else
|
---|
447 | @suite = suite
|
---|
448 | end
|
---|
449 | @result = nil
|
---|
450 |
|
---|
451 | @runner = Thread.current
|
---|
452 | @restart_signal = Class.new(Exception)
|
---|
453 | @viewer = Thread.start do
|
---|
454 | @runner.join rescue @runner.run
|
---|
455 | Gtk.main
|
---|
456 | end
|
---|
457 | @viewer.join rescue nil # wait deadlock to handshake
|
---|
458 | end # def initialize(suite)
|
---|
459 |
|
---|
460 | end # class TestRunner
|
---|
461 |
|
---|
462 | end # module GTK2
|
---|
463 | end # module UI
|
---|
464 | end # module Unit
|
---|
465 | end # module Test
|
---|