bryan-ash-wx-nobbie 0.0.3.2
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/KNOWN_ISSUES +24 -0
- data/README +153 -0
- data/lib/nobbie/wx/acceptance_test.rb +19 -0
- data/lib/nobbie/wx/command.rb +63 -0
- data/lib/nobbie/wx/command/choose.rb +38 -0
- data/lib/nobbie/wx/command/click_on.rb +35 -0
- data/lib/nobbie/wx/command/get_component.rb +17 -0
- data/lib/nobbie/wx/command/get_options.rb +27 -0
- data/lib/nobbie/wx/command/get_selected_values.rb +25 -0
- data/lib/nobbie/wx/command/is_chosen.rb +21 -0
- data/lib/nobbie/wx/command/is_enabled.rb +18 -0
- data/lib/nobbie/wx/command/select.rb +97 -0
- data/lib/nobbie/wx/command/type_into.rb +73 -0
- data/lib/nobbie/wx/command_executor.rb +25 -0
- data/lib/nobbie/wx/command_factory.rb +52 -0
- data/lib/nobbie/wx/driven.rb +7 -0
- data/lib/nobbie/wx/impl/element/element_path_builder.rb +42 -0
- data/lib/nobbie/wx/impl/operation/choosable.rb +31 -0
- data/lib/nobbie/wx/impl/operation/select.rb +37 -0
- data/lib/nobbie/wx/launcher.rb +75 -0
- data/lib/nobbie/wx/operations.rb +85 -0
- data/lib/nobbie/wx/platform.rb +31 -0
- data/test/all_tests.rb +8 -0
- data/test/suite/app.rb +144 -0
- data/test/suite/nobbie_test_case.rb +46 -0
- data/test/suite/test_choose.rb +52 -0
- data/test/suite/test_click.rb +28 -0
- data/test/suite/test_enabled.rb +13 -0
- data/test/suite/test_launcher.rb +22 -0
- data/test/suite/test_operations.rb +27 -0
- data/test/suite/test_selection.rb +138 -0
- data/test/suite/test_type.rb +58 -0
- metadata +105 -0
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'nobbie/wx/platform'
|
2
|
+
require 'nobbie/wx/command_factory'
|
3
|
+
require 'nobbie/wx/launcher'
|
4
|
+
|
5
|
+
impl = File.dirname(__FILE__) + File::SEPARATOR + 'impl'
|
6
|
+
Dir.glob("#{impl}/**/*.rb") {|f| require "#{f}" }
|
7
|
+
|
8
|
+
module Nobbie
|
9
|
+
module Wx
|
10
|
+
|
11
|
+
module Operations
|
12
|
+
|
13
|
+
# Types text into the component specified in the path.
|
14
|
+
# Supported components: TextCtrl, ComboBox
|
15
|
+
def type(text, path)
|
16
|
+
execute(command_factory.create_type_into_command(coerce_path(path), text))
|
17
|
+
end
|
18
|
+
|
19
|
+
# Clicks the component specified in the path.
|
20
|
+
# Supported components: Button
|
21
|
+
def click(path)
|
22
|
+
execute(command_factory.create_click_on_command(coerce_path(path)))
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns the component specified in the path. Useful for performing operations that Nobbie does not
|
26
|
+
# currently support.
|
27
|
+
# Supported components: Any
|
28
|
+
def component(path)
|
29
|
+
execute(command_factory.create_get_component_command(coerce_path(path)))
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns a SelectionOperations[link:classes/Nobbie/Wx/SelectOperations.html] for interacting with
|
33
|
+
# the component specified in the path
|
34
|
+
def selection(path)
|
35
|
+
SelectOperations.new(self, coerce_path(path))
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns a ChoosableOperations[link:classes/Nobbie/Wx/ChoosableOperations.html] for interacting with
|
39
|
+
# the component specified in the path
|
40
|
+
def choosable(path)
|
41
|
+
ChoosableOperations.new(self, coerce_path((path)))
|
42
|
+
end
|
43
|
+
|
44
|
+
# Determines if the component specified in the path is currently enabled.
|
45
|
+
# Supported components: Any
|
46
|
+
def enabled?(path)
|
47
|
+
execute(command_factory.create_is_enabled_command(coerce_path(path)))
|
48
|
+
end
|
49
|
+
|
50
|
+
# Creates an instance of the default {path builder}[link:classes/Nobbie/Wx/ElementPathBuilder.html].
|
51
|
+
# Override this method if you wish to provide an alternative default path builder (because coerce_path
|
52
|
+
# uses in_() internally).
|
53
|
+
def in_(name)
|
54
|
+
ElementPathBuilder.new(name)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Creates an instance of the default {command factory}[link:classes/Nobbie/Wx/CommandFactory.html].
|
58
|
+
# Override this method if you wish to provide an alternative command factory.
|
59
|
+
def command_factory
|
60
|
+
Command::Factory.new
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def coerce_path(path)
|
66
|
+
return path if path.respond_to?(:find_component)
|
67
|
+
|
68
|
+
if path.is_a?(Hash) && path.has_key?(:in)
|
69
|
+
return path[:in].is_a?(String) ? in_(path[:in]) : path[:in]
|
70
|
+
end
|
71
|
+
|
72
|
+
return in_(path.id2name) if path.is_a?(Symbol)
|
73
|
+
return in_(path) if path.is_a?(String)
|
74
|
+
|
75
|
+
Kernel.raise("Unable to coerce path: #{path}")
|
76
|
+
end
|
77
|
+
|
78
|
+
#todo: pull up
|
79
|
+
def execute(command)
|
80
|
+
Command::Executor.new.execute(command)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'wx'
|
3
|
+
|
4
|
+
#todo: move this into Nobbie::Wx namespace ... once name clash is fixed
|
5
|
+
class Platform #:nodoc:
|
6
|
+
include Wx
|
7
|
+
|
8
|
+
WINDOWS = 'WXMSW'
|
9
|
+
MAC = 'WXMAC'
|
10
|
+
SUPPORTED_PLATFORMS = [WINDOWS, MAC]
|
11
|
+
|
12
|
+
def self.windows?
|
13
|
+
name == WINDOWS
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.ensure_supported
|
17
|
+
Kernel.raise "Sorry '#{name}' is not currently supported, Nobbie-Wx is only available for the following platforms: [#{SUPPORTED_PLATFORMS.join(',')}]" unless supported?
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def self.supported?
|
23
|
+
SUPPORTED_PLATFORMS.include?(name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.name
|
27
|
+
Wx::PLATFORM
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Platform.ensure_supported
|
data/test/all_tests.rb
ADDED
data/test/suite/app.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'wx'
|
3
|
+
require 'wx_sugar'
|
4
|
+
|
5
|
+
include Wx
|
6
|
+
|
7
|
+
class TestFrame < Frame
|
8
|
+
def initialize(*args)
|
9
|
+
super
|
10
|
+
|
11
|
+
#todo: sort out all this :minsize => true stuff out .. need some way to specify defaults
|
12
|
+
|
13
|
+
panel = add(Panel, :proportion => 1)
|
14
|
+
panel.arrange_vertically(:padding => 4)
|
15
|
+
|
16
|
+
test_notebook = name('test_notebook', panel.add(Notebook, :minsize => true, :proportion => 2))
|
17
|
+
|
18
|
+
test_notebook.add_page(name('type', test_notebook.add(Panel) {|p| p.arrange_vertically
|
19
|
+
listen(:text, name('text_ctrl', p.add(TextCtrl[:value => 'text_ctrl'], :minsize => true)), :update)
|
20
|
+
listen(:text, name('readonly_text_ctrl', p.add(TextCtrl[:value => 'readonly_text_ctrl', :style => TE_READONLY], :minsize => true)), :update)
|
21
|
+
listen(:text, disable(name('disabled_text_ctrl', p.add(TextCtrl[:value => 'disabled_text_ctrl'], :minsize => true))), :update)
|
22
|
+
|
23
|
+
listen(:text, name('combo_box', p.add(ComboBox[:value => 'combo_box'], :minsize => true)), :update)
|
24
|
+
readonly_combo_box = name('readonly_combo_box', p.add(ComboBox[:style => CB_READONLY], :minsize => true))
|
25
|
+
readonly_combo_box.append('readonly_combo_box')
|
26
|
+
readonly_combo_box.selection = 0
|
27
|
+
listen(:text, readonly_combo_box, :update)
|
28
|
+
listen(:text, disable(name('disabled_combo_box', p.add(ComboBox[:value => 'disabled_combo_box'], :minsize => true))), :update)
|
29
|
+
}), 'type')
|
30
|
+
|
31
|
+
test_notebook.add_page(name('click', test_notebook.add(Panel, :minsize => true) {|p| p.arrange_vertically
|
32
|
+
listen(:button, name('button', p.add(Button[:label => 'regular_button'], :minsize => true)), :update)
|
33
|
+
listen(:button, name('labelled_button_name', p.add(Button[:label => 'labelled_button'], :minsize => true)), :update)
|
34
|
+
listen(:button, disable(name('disabled_button', p.add(Button[:label => 'disabled_button'], :minsize => true))), :update)
|
35
|
+
name('static_text', p.add(StaticText[:label => 'static_text'], :minsize => true))
|
36
|
+
}), 'click')
|
37
|
+
|
38
|
+
test_notebook.add_page(name('selection', test_notebook.add(Panel) {|p| p.arrange_vertically
|
39
|
+
notebook = name('notebook', p.add(Notebook, :minsize => true))
|
40
|
+
notebook.add_page(name('notebook_page1', notebook.add(Panel)), 'notebook_page1')
|
41
|
+
notebook.add_page(name('notebook_page2', notebook.add(Panel)), 'notebook_page2')
|
42
|
+
notebook.evt_notebook_page_changing(notebook.get_id()) {|e| update(e) }
|
43
|
+
|
44
|
+
disabled_notebook = disable(name('disabled_notebook', p.add(Notebook, :minsize => true)))
|
45
|
+
disabled_notebook.add_page(name('disabled_notebook_page1', disabled_notebook.add(Panel)), 'disabled_notebook_page1')
|
46
|
+
disabled_notebook.add_page(name('disabled_notebook_page2', disabled_notebook.add(Panel)), 'disabled_notebook_page2')
|
47
|
+
disabled_notebook.evt_notebook_page_changing(disabled_notebook.get_id()) {|e| update(e) }
|
48
|
+
|
49
|
+
#todo: make me have a visible name on screen
|
50
|
+
combo_box_with_items = name('combo_box_with_items', p.add(ComboBox, :minsize => true))
|
51
|
+
combo_box_with_items.append('combo_box_item')
|
52
|
+
listen(:combobox, combo_box_with_items, :update)
|
53
|
+
|
54
|
+
disabled_combo_box_with_items = disable(name('disabled_combo_box_with_items', p.add(ComboBox, :minsize => true)))
|
55
|
+
disabled_combo_box_with_items.append('disabled_combo_box_item1')
|
56
|
+
disabled_combo_box_with_items.append('disabled_combo_box_item2')
|
57
|
+
listen(:combobox, disabled_combo_box_with_items, :update)
|
58
|
+
|
59
|
+
list_box_with_items = name('list_box_with_items', p.add(ListBox, :minsize => true))
|
60
|
+
list_box_with_items.append('list_box_item')
|
61
|
+
listen(:listbox, list_box_with_items, :update)
|
62
|
+
|
63
|
+
disabled_list_box_with_items = disable(name('disabled_list_box_with_items', p.add(ListBox, :minsize => true)))
|
64
|
+
disabled_list_box_with_items.append('disabled_list_box_item1')
|
65
|
+
disabled_list_box_with_items.append('disabled_list_box_item2')
|
66
|
+
listen(:listbox, disabled_list_box_with_items, :update)
|
67
|
+
|
68
|
+
choice_with_items = name('choice_with_items', p.add(Choice, :minsize => true))
|
69
|
+
choice_with_items.append('choice_item')
|
70
|
+
listen(:choice, choice_with_items, :update)
|
71
|
+
|
72
|
+
disabled_choice_with_items = disable(name('disabled_choice_with_items', p.add(Choice, :minsize => true)))
|
73
|
+
disabled_choice_with_items.append('disabled_choice_item1')
|
74
|
+
disabled_choice_with_items.append('disabled_choice_item2')
|
75
|
+
listen(:choice, disabled_choice_with_items, :update)
|
76
|
+
|
77
|
+
}), 'selection')
|
78
|
+
|
79
|
+
test_notebook.add_page(name('choose', test_notebook.add(Panel) {|p| p.arrange_vertically
|
80
|
+
#todo: make me have a visible name on screen
|
81
|
+
listen(:radiobutton, name('radio_button', p.add(RadioButton, :minsize => true)), :update)
|
82
|
+
|
83
|
+
#todo: make me have a visible name on screen
|
84
|
+
listen(:radiobutton, disable(name('disabled_radio_button', p.add(RadioButton, :minsize => true))), :update)
|
85
|
+
|
86
|
+
#todo: make me have a visible name on screen
|
87
|
+
listen(:checkbox, name('check_box', p.add(CheckBox, :minsize => true)), :update)
|
88
|
+
|
89
|
+
#todo: make me have a visible name on screen
|
90
|
+
listen(:checkbox, disable(name('disabled_check_box', p.add(CheckBox, :minsize => true))), :update)
|
91
|
+
|
92
|
+
}), 'choose')
|
93
|
+
|
94
|
+
@log = name('log', panel.add(TextCtrl[:style => TE_READONLY | TE_MULTILINE], :minsize => true, :proportion => 1))
|
95
|
+
|
96
|
+
menu_bar = MenuBar.new
|
97
|
+
file_menu = Menu.new
|
98
|
+
|
99
|
+
#todo: remove these crappy id's ... there must be a nice sugary way to build menu's
|
100
|
+
file_new = file_menu.append(101, "&New...\tCtrl+N")
|
101
|
+
file_disabled = file_menu.append(102, "&disabled")
|
102
|
+
|
103
|
+
menu_bar.append(file_menu, '&File')
|
104
|
+
set_menu_bar(menu_bar)
|
105
|
+
|
106
|
+
#todo: make disable() handle menus ...
|
107
|
+
menu_bar.enable(102, false)
|
108
|
+
|
109
|
+
#todo: make update() handle menus ...
|
110
|
+
listen(:menu, @file_new) {|e| log('file_new') }
|
111
|
+
end
|
112
|
+
|
113
|
+
def on_init
|
114
|
+
self.update
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def name(name, component)
|
120
|
+
component.name = name
|
121
|
+
component
|
122
|
+
end
|
123
|
+
|
124
|
+
def disable(component)
|
125
|
+
component.disable
|
126
|
+
component
|
127
|
+
end
|
128
|
+
|
129
|
+
def log(text)
|
130
|
+
@log.append_text(text)
|
131
|
+
end
|
132
|
+
|
133
|
+
def update(e)
|
134
|
+
@log.append_text("#{e.event_object.name}: #{e.string}\n")
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
class TestApp < App
|
139
|
+
def on_init
|
140
|
+
TestFrame.new(nil, :title => 'test', :size => [1024, 768]).show
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
TestApp.new.main_loop if __FILE__ == $0
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module NobbieTestCase
|
2
|
+
include Nobbie::Wx
|
3
|
+
|
4
|
+
def setup
|
5
|
+
puts "\n[Started: #{name}]"
|
6
|
+
begin
|
7
|
+
select_tab_for_test
|
8
|
+
rescue ValueNotFoundException
|
9
|
+
#ok - this test doesn't have its own tab'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
puts "\n[Finished: #{name}]"
|
15
|
+
end
|
16
|
+
|
17
|
+
def select_tab_for_test
|
18
|
+
clear_events
|
19
|
+
tab = self.class.name.gsub('Test', '').downcase
|
20
|
+
selection(:in => 'test_notebook').choose tab
|
21
|
+
assert_equal tab, selection(:in => 'test_notebook').selected_value
|
22
|
+
end
|
23
|
+
|
24
|
+
def text(component)
|
25
|
+
component.nil? ? nil : component.value
|
26
|
+
end
|
27
|
+
|
28
|
+
def clear_events
|
29
|
+
log.clear
|
30
|
+
end
|
31
|
+
|
32
|
+
def assert_exception(e)
|
33
|
+
assert_raise e do yield end
|
34
|
+
assert_events
|
35
|
+
end
|
36
|
+
|
37
|
+
def assert_events(expected_items=[])
|
38
|
+
expected_items = [expected_items] unless expected_items.is_a?(Array)
|
39
|
+
actual_items = text(log).split("\n")
|
40
|
+
assert_equal expected_items, actual_items
|
41
|
+
end
|
42
|
+
|
43
|
+
def log
|
44
|
+
component 'log'
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class TestChoose < Test::Unit::TestCase
|
2
|
+
include NobbieTestCase
|
3
|
+
|
4
|
+
#todo: rename file to choosable
|
5
|
+
#todo: should be TestChoosable
|
6
|
+
def test_choose_with_radio_button
|
7
|
+
assert !choosable('radio_button').chosen?
|
8
|
+
choosable('radio_button').choose
|
9
|
+
assert choosable('radio_button').chosen?
|
10
|
+
assert_events 'radio_button: '
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_choose_with_check_box
|
14
|
+
assert !choosable('check_box').chosen?
|
15
|
+
choosable('check_box').choose
|
16
|
+
assert choosable('check_box').chosen?
|
17
|
+
assert_events 'check_box: '
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_choose_with_component_disabled_radio_button
|
21
|
+
assert_exception ComponentDisabledException do choosable('disabled_radio_button').choose end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_choose_with_component_disabled_check_box
|
25
|
+
assert_exception ComponentDisabledException do choosable('disabled_check_box').choose end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_choose_with_unsupported_operation_for_component
|
29
|
+
assert_exception UnsupportedOperationForComponentException do choosable('button').choose end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_choose_with_component_not_found
|
33
|
+
assert_exception ComponentNotFoundException do choosable('missing').choose end
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_chosen_with_unsupported_operation_for_component
|
37
|
+
assert_exception UnsupportedOperationForComponentException do choosable('button').chosen? end
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_chosen_with_component_not_found
|
41
|
+
assert_exception ComponentNotFoundException do choosable('missing').chosen? end
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_chosen_with_component_disabled_radio_button
|
45
|
+
assert !choosable('disabled_radio_button').chosen?
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_chosen_with_component_disabled_check_box
|
49
|
+
assert !choosable('disabled_check_box').chosen?
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class TestClick < Test::Unit::TestCase
|
2
|
+
include NobbieTestCase
|
3
|
+
|
4
|
+
def test_click_with_named_button
|
5
|
+
click 'button'
|
6
|
+
#todo: improve event detail
|
7
|
+
assert_events 'button: '
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_click_with_labelled_button
|
11
|
+
click 'labelled_button'
|
12
|
+
#todo: improve event detail
|
13
|
+
assert_events 'labelled_button_name: '
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_click_with_component_not_found
|
17
|
+
assert_exception ComponentNotFoundException do click 'missing' end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_click_with_component_disabled
|
21
|
+
assert_exception ComponentDisabledException do click 'disabled_button' end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_click_with_unsupported_operation_for_component
|
25
|
+
assert_exception UnsupportedOperationForComponentException do click 'static_text' end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class TestEnabled < Test::Unit::TestCase
|
2
|
+
include NobbieTestCase
|
3
|
+
|
4
|
+
def test_enabled
|
5
|
+
assert enabled?('text_ctrl')
|
6
|
+
assert !enabled?('disabled_text_ctrl')
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_enabled_with_component_not_found
|
10
|
+
assert_exception ComponentNotFoundException do enabled?('missing') end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class TestLauncher < Test::Unit::TestCase
|
2
|
+
|
3
|
+
def test_application_under_test_is_not_defined
|
4
|
+
begin
|
5
|
+
Nobbie::Wx::ApplicationLauncher.module_eval('def get_application; raise NameError.new; end;')
|
6
|
+
Nobbie::Wx::ApplicationLauncher.new
|
7
|
+
fail
|
8
|
+
rescue RuntimeError => e
|
9
|
+
assert_equal Nobbie::Wx::ApplicationLauncher::AUT_NOT_DEFINED, e.message
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_application_under_test_is_not_a_wx_app
|
14
|
+
begin
|
15
|
+
Nobbie::Wx::ApplicationLauncher.module_eval('def get_application; String.new; end;')
|
16
|
+
Nobbie::Wx::ApplicationLauncher.new
|
17
|
+
fail
|
18
|
+
rescue RuntimeError => e
|
19
|
+
assert_equal Nobbie::Wx::ApplicationLauncher::AUT_NOT_WX_APP, e.message
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class UserPathBuilder
|
2
|
+
def find_component
|
3
|
+
"something"
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
class TestOperations < Test::Unit::TestCase
|
8
|
+
|
9
|
+
def test_coerce_path
|
10
|
+
assert_path component('text_ctrl')
|
11
|
+
assert_path component(:in => 'text_ctrl')
|
12
|
+
assert_path component(in_('text_ctrl'))
|
13
|
+
assert_path component(Nobbie::Wx::ElementPathBuilder.new('text_ctrl'))
|
14
|
+
assert_path component(UserPathBuilder.new)
|
15
|
+
assert_path component(:text_ctrl)
|
16
|
+
begin
|
17
|
+
component(Hash.new)
|
18
|
+
fail
|
19
|
+
rescue RuntimeError => e
|
20
|
+
assert_equal 'Unable to coerce path: ', e.message
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def assert_path(path)
|
25
|
+
assert_not_nil path
|
26
|
+
end
|
27
|
+
end
|