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.
@@ -0,0 +1,97 @@
1
+ module Nobbie
2
+ module Wx
3
+ module Command
4
+
5
+ class SelectCommand < ComponentAwareCommand #:nodoc:
6
+ def initialize(path, value)
7
+ super(path)
8
+ @value = value
9
+ end
10
+
11
+ def execute
12
+ if component.is_a?(Menu)
13
+ return handle_menu
14
+ end
15
+
16
+ ensure_enabled
17
+
18
+ if component.is_a?(Notebook)
19
+ handle_notebook
20
+ elsif component.is_a?(ComboBox)
21
+ handle_combo_box
22
+ elsif component.is_a?(ListBox) || component.is_a?(Choice)
23
+ handle_list_box_or_choice
24
+ else
25
+ handle_unsupported_operation_for_component
26
+ end
27
+ nil
28
+ end
29
+
30
+ def describe
31
+ "Select '#{@value}' in #{@path}"
32
+ end
33
+
34
+ private
35
+
36
+ def handle_menu
37
+ id = component.find_item(@value)
38
+ handle_value_not_found unless id > -1
39
+ ensure_enabled(id)
40
+
41
+ #todo: should this be a MenuEvent?
42
+ #todo: find a way to avoid using APPLICATION_UNDER_TEST
43
+ APPLICATION_UNDER_TEST.get_top_window.process_event(CommandEvent.new(EVT_COMMAND_MENU_SELECTED, id))
44
+
45
+ return ''
46
+ end
47
+
48
+ def handle_notebook
49
+ component.page_count.times {|i|
50
+ if component.page(i).name == @value
51
+ highlight(component.page(i)) {
52
+ component.selection = i
53
+ }
54
+ return ''
55
+ end
56
+ }
57
+
58
+ handle_value_not_found
59
+ end
60
+
61
+ #todo: remove duplication for event raising
62
+ def handle_combo_box
63
+ highlight {
64
+ index = component.find_string(@value)
65
+ handle_value_not_found unless index > -1
66
+
67
+ event = CommandEvent.new(EVT_COMMAND_COMBOBOX_SELECTED, component.get_id)
68
+ component.selection = index
69
+ event.event_object = component
70
+
71
+ #todo: should this use process_event
72
+ component.command(event)
73
+ }
74
+ end
75
+
76
+ #todo: remove duplication for event raising
77
+ def handle_list_box_or_choice
78
+ highlight {
79
+ index = component.find_string(@value)
80
+ handle_value_not_found unless index > -1
81
+
82
+ event_type = (component.is_a?(ListBox) ? EVT_COMMAND_LISTBOX_SELECTED : EVT_COMMAND_CHOICE_SELECTED)
83
+
84
+ event = CommandEvent.new(event_type, component.get_id)
85
+ event.int = 1 #no idea why this works .. but it is needed
86
+ event.string = @value
87
+ component.selection = index
88
+ event.event_object = component
89
+
90
+ component.process_event(event)
91
+ }
92
+ end
93
+ end
94
+
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,73 @@
1
+ module Nobbie
2
+ module Wx
3
+ module Command
4
+
5
+ class TypeIntoCommand < ComponentAwareCommand #:nodoc:
6
+ def initialize(path, value)
7
+ super(path)
8
+ @value = value
9
+ end
10
+
11
+ def execute
12
+ highlight {
13
+ if component.is_a?(TextCtrl) || component.is_a?(ComboBox)
14
+ handle_text_ctrl_or_combo_box
15
+ else
16
+ handle_unsupported_operation_for_component
17
+ end
18
+ }
19
+ end
20
+
21
+ def describe
22
+ "Type '#{@value}' into #{@path}"
23
+ end
24
+
25
+ private
26
+
27
+ def handle_text_ctrl_or_combo_box
28
+ ensure_enabled
29
+
30
+ Kernel.raise(ComponentReadOnlyException, "cannot type, component is readonly") if readonly
31
+
32
+ #todo: resolve issue with events when value does not change
33
+ #this is required because windows raises the event when the value is the same, OSX does not.
34
+ #return if component.value == @value
35
+
36
+ #todo: consider using 'clear' .. but symantics different for ComboBox (ControlWithItems)
37
+ type('')
38
+
39
+ @value.length.times {|n| type(@value[0..n]) }
40
+ nil
41
+ end
42
+
43
+ def readonly
44
+ if component.is_a?(TextCtrl)
45
+ return !component.is_editable
46
+ end
47
+
48
+ if component.is_a?(ComboBox)
49
+ return (component.get_window_style & CB_READONLY).nonzero?
50
+ end
51
+ end
52
+
53
+ def type(text)
54
+ #todo: this isnt quite right .. should really use append (but combo's don't support it)
55
+
56
+ #todo: find a nicer way to handle OS specific bits ...
57
+ if Platform.windows?
58
+ event = CommandEvent.new(EVT_COMMAND_TEXT_UPDATED, component.get_id)
59
+ event.string = text
60
+ event.event_object = component
61
+
62
+ #todo: should this use process_event
63
+ component.command(event) if component.is_a?(ComboBox)
64
+ end
65
+ component.value = text
66
+ component.refresh
67
+ component.update
68
+ end
69
+ end
70
+
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,25 @@
1
+ module Nobbie
2
+ module Wx
3
+ module Command
4
+
5
+ class Executor #:nodoc:
6
+ def execute(command)
7
+ puts "\n> #{command.describe}"
8
+ result = command.execute
9
+ puts "< #{render(result)}"
10
+ result
11
+ end
12
+
13
+ private
14
+
15
+ def render(component)
16
+ #todo: this needs improving to support other components
17
+ return '' if component.nil?
18
+ return component.value if component.respond_to?(:get_value)
19
+ return component.inspect
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,52 @@
1
+ require 'nobbie/wx/command'
2
+
3
+ command = File.dirname(__FILE__) + File::SEPARATOR + 'command'
4
+ Dir.glob("#{command}/**/*.rb") {|f| require "#{f}" }
5
+
6
+ require 'nobbie/wx/command_executor'
7
+
8
+ module Nobbie
9
+ module Wx
10
+ module Command
11
+
12
+ class Factory
13
+ def create_type_into_command(path, value)
14
+ TypeIntoCommand.new(path, value)
15
+ end
16
+
17
+ def create_get_component_command(path)
18
+ GetComponentCommand.new(path)
19
+ end
20
+
21
+ def create_click_on_command(path)
22
+ ClickOnCommand.new(path)
23
+ end
24
+
25
+ def create_get_selected_values_command(path)
26
+ GetSelectedValuesCommand.new(path)
27
+ end
28
+
29
+ def create_select_command(path, value)
30
+ SelectCommand.new(path, value)
31
+ end
32
+
33
+ def create_is_chosen_command(path)
34
+ IsChosenCommand.new(path)
35
+ end
36
+
37
+ def create_choose_command(path)
38
+ ChooseCommand.new(path)
39
+ end
40
+
41
+ def create_is_enabled_command(path)
42
+ IsEnabledCommand.new(path)
43
+ end
44
+
45
+ def create_get_options_command(path)
46
+ GetOptionsCommand.new(path)
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,7 @@
1
+ require 'nobbie/wx/operations'
2
+
3
+ include Nobbie::Wx::Operations
4
+
5
+ def with_application
6
+ Nobbie::Wx::ApplicationLauncher.new.with_application { yield }
7
+ end
@@ -0,0 +1,42 @@
1
+ module Nobbie
2
+ module Wx
3
+
4
+ class ComponentNotFoundException < RuntimeError; end
5
+ class ValueNotFoundException < RuntimeError; end
6
+ class ComponentDisabledException < RuntimeError; end
7
+ class UnsupportedOperationForComponentException < RuntimeError; end
8
+ class ComponentReadOnlyException < RuntimeError; end
9
+
10
+ class ElementPathBuilder
11
+ def initialize(name)
12
+ @name = name
13
+ end
14
+
15
+ # Finds the component specified in the path. This implementation is about as dumb as its gets, but does
16
+ # handle named components and menus.
17
+ def find_component
18
+ #todo: make me properly navigate component tree
19
+ #todo: I should blow up if multiple windows with the same name are found ....
20
+
21
+ #todo: shouldn''t need to pass AUT.gtw here ... nil should search all
22
+ component = Window.find_window_by_name(@name, APPLICATION_UNDER_TEST.get_top_window)
23
+ return component unless component.nil?
24
+
25
+ menu_bar = APPLICATION_UNDER_TEST.get_top_window.get_menu_bar
26
+ unless menu_bar.nil?
27
+ component = menu_bar.get_menu(menu_bar.find_menu(@name))
28
+ end
29
+
30
+ #todo: pull this up ...
31
+ Kernel.raise(ComponentNotFoundException, "cannot find component with name: #{to_s}") if component.nil?
32
+
33
+ component
34
+ end
35
+
36
+ def to_s
37
+ "'#{@name}'"
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,31 @@
1
+ module Nobbie
2
+ module Wx
3
+
4
+ class ChoosableOperations
5
+ def initialize(operations, path)
6
+ @operations = operations
7
+ @path = path
8
+ end
9
+
10
+ # Chooses the component specified in the path.
11
+ # Supported components: RadioButton, CheckBox
12
+ def choose
13
+ execute(@operations.command_factory.create_choose_command(@path))
14
+ end
15
+
16
+ # Determines if the component specified in the path is chosen.
17
+ # Supported components: RadioButton, CheckBox
18
+ def chosen?
19
+ execute(@operations.command_factory.create_is_chosen_command(@path))
20
+ end
21
+
22
+ private
23
+
24
+ #todo: pullup execute
25
+ def execute(command)
26
+ Command::Executor.new.execute(command)
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,37 @@
1
+ module Nobbie
2
+ module Wx
3
+
4
+ class SelectOperations
5
+ def initialize(operations, path)
6
+ @operations = operations
7
+ @path = path
8
+ end
9
+
10
+ # Retrieves the currently selected value for the component specified in the path.
11
+ # Supported components: Notebook, ComboBox, ListBox, Choice
12
+ def selected_value
13
+ execute(@operations.command_factory.create_get_selected_values_command(@path))
14
+ end
15
+
16
+ # Selects the given value for the component specified in the path.
17
+ # Supported components: Notebook, Menu, ComboBox, ListBox, Choice
18
+ def choose(value)
19
+ execute(@operations.command_factory.create_select_command(@path, value))
20
+ end
21
+
22
+ # Retrieves available options for the component specified in the path.
23
+ # Supported components: Notebook, ComboBox, ListBox, Choice
24
+ def options
25
+ execute(@operations.command_factory.create_get_options_command(@path))
26
+ end
27
+
28
+ private
29
+
30
+ #todo: pullup execute
31
+ def execute(command)
32
+ Command::Executor.new.execute(command)
33
+ end
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,75 @@
1
+ module Nobbie
2
+ module Wx
3
+
4
+ module ApplicationUnderTest #:nodoc:
5
+ def init_timer
6
+ @aut_timer = Timer.new(self, -1)
7
+ @aut_timer.start(10)
8
+ evt_timer(@aut_timer.object_id) {|e| self.yield; Thread.pass }
9
+ end
10
+
11
+ #todo: think about adding evt_idle here as well.
12
+ end
13
+
14
+ class ApplicationLauncher #:nodoc:
15
+
16
+ AUT_NOT_WX_APP = "APPLICATION_UNDER_TEST must be an instance of a Wx::App"
17
+ AUT_NOT_DEFINED = "APPLICATION_UNDER_TEST must be set to be an instance of the application you wish to test"
18
+
19
+ def initialize
20
+ begin
21
+ app = get_application
22
+ unless app.is_a?(Wxruby2::App)
23
+ handle(AUT_NOT_WX_APP)
24
+ end
25
+ rescue NameError => e
26
+ handle(AUT_NOT_DEFINED)
27
+ end
28
+ @app = app
29
+ end
30
+
31
+ def with_application
32
+ start
33
+ result = yield
34
+ stop
35
+ result
36
+ end
37
+
38
+ def start
39
+ puts "\n>> Starting application: #{@app.class}"
40
+ start = Time.now
41
+
42
+ @app_thread = Thread.new {
43
+ @app.extend(ApplicationUnderTest)
44
+ @app.init_timer
45
+ @app.main_loop
46
+ }
47
+
48
+ @app_thread.priority = -1
49
+
50
+ sleep 1
51
+ finish = Time.now
52
+ puts "\n>> Took #{finish-start} seconds to start application"
53
+ Thread.pass
54
+ end
55
+
56
+ def stop
57
+ puts "\n>> Stopping application: #{@app.class}\n"
58
+
59
+ #todo: tbis would seem a polite way to exit .. but causes Bus/Segmentation Errors on OSX.
60
+ #@app.top_window.destroy
61
+ #@app.exit_main_loop
62
+ #@app = nil
63
+ end
64
+
65
+ def handle(message)
66
+ Kernel.raise message
67
+ end
68
+
69
+ def get_application
70
+ APPLICATION_UNDER_TEST
71
+ end
72
+ end
73
+
74
+ end
75
+ end