sapphire 0.7.26 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. data/lib/sapphire.rb +51 -40
  2. data/lib/sapphire/Adapters/Selenium/RubySeleniumWebDriver.rb +24 -68
  3. data/lib/sapphire/DSL.rb +18 -16
  4. data/lib/sapphire/DSL/Browser/Create.rb +10 -10
  5. data/lib/sapphire/DSL/Browser/ExecuteAgainstControl.rb +20 -20
  6. data/lib/sapphire/DSL/Browser/Fluff/By.rb +10 -10
  7. data/lib/sapphire/DSL/Browser/Fluff/To.rb +10 -10
  8. data/lib/sapphire/DSL/Browser/Fluff/With.rb +10 -10
  9. data/lib/sapphire/DSL/Browser/Nouns/Browser.rb +17 -17
  10. data/lib/sapphire/DSL/Browser/Nouns/Enter.rb +10 -10
  11. data/lib/sapphire/DSL/Browser/Tracker.rb +15 -15
  12. data/lib/sapphire/DSL/Browser/Verbs/Accept.rb +8 -8
  13. data/lib/sapphire/DSL/Browser/Verbs/Check.rb +10 -10
  14. data/lib/sapphire/DSL/Browser/Verbs/Clear.rb +8 -8
  15. data/lib/sapphire/DSL/Browser/Verbs/Click.rb +10 -10
  16. data/lib/sapphire/DSL/Browser/Verbs/Compare.rb +18 -18
  17. data/lib/sapphire/DSL/Browser/Verbs/Complete.rb +13 -13
  18. data/lib/sapphire/DSL/Browser/Verbs/Exists.rb +16 -16
  19. data/lib/sapphire/DSL/Browser/Verbs/Exit.rb +11 -11
  20. data/lib/sapphire/DSL/Browser/Verbs/MouseOver.rb +10 -10
  21. data/lib/sapphire/DSL/Browser/Verbs/Navigate.rb +10 -10
  22. data/lib/sapphire/DSL/Browser/Verbs/Press.rb +8 -8
  23. data/lib/sapphire/DSL/Browser/Verbs/Reload.rb +11 -11
  24. data/lib/sapphire/DSL/Browser/Verbs/Set.rb +10 -10
  25. data/lib/sapphire/DSL/Browser/Verbs/Uncheck.rb +10 -10
  26. data/lib/sapphire/DSL/Comparisons/CheckedComparison.rb +17 -17
  27. data/lib/sapphire/DSL/Comparisons/Comparison.rb +50 -50
  28. data/lib/sapphire/DSL/Comparisons/ContainsComparison.rb +17 -17
  29. data/lib/sapphire/DSL/Comparisons/DifferComparison.rb +17 -17
  30. data/lib/sapphire/DSL/Comparisons/EqualsComparison.rb +16 -16
  31. data/lib/sapphire/DSL/Comparisons/NotComparison.rb +20 -20
  32. data/lib/sapphire/DSL/Comparisons/SelectedComparison.rb +17 -17
  33. data/lib/sapphire/DSL/Comparisons/StartsWithComparison.rb +17 -17
  34. data/lib/sapphire/DSL/Comparisons/VisibleComparison.rb +17 -17
  35. data/lib/sapphire/DSL/Configuration/ConfiguredBrowser.rb +12 -12
  36. data/lib/sapphire/DSL/Configuration/ConfiguredUser.rb +10 -10
  37. data/lib/sapphire/DSL/Configuration/Use.rb +18 -18
  38. data/lib/sapphire/DSL/Data/Find.rb +10 -10
  39. data/lib/sapphire/DSL/Data/GetPageField.rb +13 -13
  40. data/lib/sapphire/DSL/Data/Verify.rb +10 -10
  41. data/lib/sapphire/DSL/Evaluations/ControlEvaluation.rb +13 -0
  42. data/lib/sapphire/DSL/Evaluations/Evaluation.rb +55 -45
  43. data/lib/sapphire/DSL/Evaluations/FieldNotDefinedEvaluation.rb +20 -20
  44. data/lib/sapphire/DSL/Evaluations/FieldNotFoundEvaluation.rb +22 -22
  45. data/lib/sapphire/DSL/Evaluators/Contain.rb +10 -10
  46. data/lib/sapphire/DSL/Evaluators/Count.rb +8 -8
  47. data/lib/sapphire/DSL/Evaluators/Differ.rb +10 -10
  48. data/lib/sapphire/DSL/Evaluators/Exist.rb +9 -9
  49. data/lib/sapphire/DSL/Evaluators/In.rb +10 -10
  50. data/lib/sapphire/DSL/Evaluators/Selected.rb +10 -10
  51. data/lib/sapphire/DSL/Evaluators/Show.rb +10 -10
  52. data/lib/sapphire/DSL/Evaluators/Transition.rb +10 -10
  53. data/lib/sapphire/DSL/Evaluators/Validate.rb +8 -8
  54. data/lib/sapphire/DSL/Events/Data.rb +12 -0
  55. data/lib/sapphire/DSL/Events/DataSegment.rb +18 -0
  56. data/lib/sapphire/DSL/Events/Event.rb +11 -3
  57. data/lib/sapphire/DSL/Events/Expect.rb +3 -11
  58. data/lib/sapphire/DSL/Events/Expectation.rb +14 -0
  59. data/lib/sapphire/DSL/Events/For.rb +11 -0
  60. data/lib/sapphire/DSL/Events/From.rb +9 -0
  61. data/lib/sapphire/DSL/Events/Where.rb +11 -0
  62. data/lib/sapphire/DSL/Profiles/Profile.rb +26 -0
  63. data/lib/sapphire/DSL/Profiles/Table.rb +9 -0
  64. data/lib/sapphire/DSL/Scenarios/Is.rb +9 -9
  65. data/lib/sapphire/DSL/Scenarios/Pending.rb +28 -28
  66. data/lib/sapphire/DSL/Scenarios/and.rb +25 -25
  67. data/lib/sapphire/DSL/Scenarios/dsl.rb +59 -59
  68. data/lib/sapphire/DSL/Scenarios/runner.rb +40 -40
  69. data/lib/sapphire/Data.rb +1 -1
  70. data/lib/sapphire/DataAbstractions/Database.rb +57 -57
  71. data/lib/sapphire/DataAbstractions/Query.rb +20 -20
  72. data/lib/sapphire/Extensions/Class.rb +2 -2
  73. data/lib/sapphire/Extensions/Hash.rb +112 -112
  74. data/lib/sapphire/Extensions/Module.rb +11 -0
  75. data/lib/sapphire/Extensions/Numeric.rb +6 -6
  76. data/lib/sapphire/Extensions/Object.rb +4 -0
  77. data/lib/sapphire/Extensions/String.rb +30 -23
  78. data/lib/sapphire/Extensions/Symbol.rb +1 -1
  79. data/lib/sapphire/JobAbstractions/Job.rb +32 -32
  80. data/lib/sapphire/Observable.rb +87 -0
  81. data/lib/sapphire/Observers.rb +2 -0
  82. data/lib/sapphire/Observers/FailedControlHighlighter.rb +41 -0
  83. data/lib/sapphire/Observers/Highlighter.rb +40 -0
  84. data/lib/sapphire/Observers/Observer.rb +23 -0
  85. data/lib/sapphire/Observers/ObserverRepository.rb +37 -0
  86. data/lib/sapphire/Observers/PassedControlHighlighter.rb +42 -0
  87. data/lib/sapphire/Observers/VerboseObserver.rb +36 -0
  88. data/lib/sapphire/TeamCity.rb +10 -10
  89. data/lib/sapphire/Testing.rb +3 -3
  90. data/lib/sapphire/Testing/RakeTask.rb +108 -108
  91. data/lib/sapphire/Testing/ResultList.rb +18 -18
  92. data/lib/sapphire/Testing/ScenarioResult.rb +36 -36
  93. data/lib/sapphire/Testing/TestResult.rb +21 -21
  94. data/lib/sapphire/Testing/TestRunnerAdapter.rb +85 -85
  95. data/lib/sapphire/UI/ProcessBuilder.rb +173 -173
  96. data/lib/sapphire/Virtualization.rb +7 -7
  97. data/lib/sapphire/Web.rb +2 -2
  98. data/lib/sapphire/WebAbstractions/Controls/AlertBox.rb +20 -20
  99. data/lib/sapphire/WebAbstractions/Controls/Base/Control.rb +43 -26
  100. data/lib/sapphire/WebAbstractions/Controls/Button.rb +7 -7
  101. data/lib/sapphire/WebAbstractions/Controls/CheckBox.rb +3 -3
  102. data/lib/sapphire/WebAbstractions/Controls/Date.rb +11 -11
  103. data/lib/sapphire/WebAbstractions/Controls/DropDown.rb +6 -8
  104. data/lib/sapphire/WebAbstractions/Controls/Hyperlink.rb +8 -8
  105. data/lib/sapphire/WebAbstractions/Controls/Image.rb +19 -19
  106. data/lib/sapphire/WebAbstractions/Controls/Label.rb +8 -8
  107. data/lib/sapphire/WebAbstractions/Controls/List.rb +16 -16
  108. data/lib/sapphire/WebAbstractions/Controls/RadioButton.rb +2 -2
  109. data/lib/sapphire/WebAbstractions/Controls/Title.rb +12 -12
  110. data/lib/sapphire/version.rb +1 -1
  111. metadata +26 -8
@@ -1,19 +1,19 @@
1
- module Sapphire
2
- module Testing
3
- class ResultsList
4
-
5
- attr_reader :myId
6
- attr_reader :text
7
- attr_reader :children
8
-
9
- def initialize(text, results, id)
10
- @myId = id
11
- @text = text
12
- @children = results
13
- @expanded = true
14
- @count = results.length
15
- end
16
-
17
- end
18
- end
1
+ module Sapphire
2
+ module Testing
3
+ class ResultsList
4
+
5
+ attr_reader :myId
6
+ attr_reader :text
7
+ attr_reader :children
8
+
9
+ def initialize(text, results, id)
10
+ @myId = id
11
+ @text = text
12
+ @children = results
13
+ @expanded = true
14
+ @count = results.length
15
+ end
16
+
17
+ end
18
+ end
19
19
  end
@@ -1,36 +1,36 @@
1
- module Sapphire
2
- module Testing
3
- class ScenarioResult
4
-
5
- attr_reader :results
6
- attr_accessor :myId
7
- attr_reader :type
8
- attr_reader :time
9
- attr_reader :parent
10
-
11
- def initialize(text)
12
- @text = text
13
- @results = []
14
- @leaf = true
15
- @myId = -1
16
- @type = 'pass'
17
- @time = 0
18
- end
19
-
20
- def AddChild(result)
21
- result.parent = self
22
- @results << result
23
- @time += result.time
24
- end
25
-
26
- def set_id(id)
27
- @myId = id
28
- end
29
-
30
- def set_type(type)
31
- @type = type
32
- end
33
-
34
- end
35
- end
36
- end
1
+ module Sapphire
2
+ module Testing
3
+ class ScenarioResult
4
+
5
+ attr_reader :results
6
+ attr_accessor :myId
7
+ attr_reader :type
8
+ attr_reader :time
9
+ attr_reader :parent
10
+
11
+ def initialize(text)
12
+ @text = text
13
+ @results = []
14
+ @leaf = true
15
+ @myId = -1
16
+ @type = 'pass'
17
+ @time = 0
18
+ end
19
+
20
+ def AddChild(result)
21
+ result.parent = self
22
+ @results << result
23
+ @time += result.time
24
+ end
25
+
26
+ def set_id(id)
27
+ @myId = id
28
+ end
29
+
30
+ def set_type(type)
31
+ @type = type
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -1,22 +1,22 @@
1
- module Sapphire
2
- module Testing
3
- class TestResult
4
-
5
- attr_reader :execution_time
6
- attr_reader :message
7
- attr_reader :item
8
- attr_reader :type
9
- attr_reader :stack
10
- attr_reader :messages
11
-
12
- def initialize(type, item, message, stack, execution_time)
13
- @item = item
14
- @execution_time = execution_time
15
- @messages = message
16
- @stack = stack
17
- @type = type
18
- end
19
-
20
- end
21
- end
1
+ module Sapphire
2
+ module Testing
3
+ class TestResult
4
+
5
+ attr_reader :execution_time
6
+ attr_reader :message
7
+ attr_reader :item
8
+ attr_reader :type
9
+ attr_reader :stack
10
+ attr_reader :messages
11
+
12
+ def initialize(type, item, message, stack, execution_time)
13
+ @item = item
14
+ @execution_time = execution_time
15
+ @messages = message
16
+ @stack = stack
17
+ @type = type
18
+ end
19
+
20
+ end
21
+ end
22
22
  end
@@ -1,85 +1,85 @@
1
- module Sapphire
2
- module Testing
3
- module TestRunnerAdapter
4
-
5
- def Report(&block)
6
- $instances.each do |reporter|
7
- block.call reporter
8
- end
9
- end
10
-
11
- def execute()
12
- Report do |reporter| reporter.ScenarioStart(self) end
13
-
14
- self.backgrounds.each do |background|
15
-
16
- background.execute
17
-
18
- background.and.each do |background_and|
19
-
20
- background_and.execute
21
-
22
- end
23
-
24
- end
25
-
26
- self.givens.each do |given|
27
- given.when.each do |when_|
28
-
29
- if when_.value.is_a? Pending
30
- given.pend()
31
-
32
- given.and.each do |given_and|
33
-
34
- given_and.pend()
35
-
36
- end
37
- else
38
- given.execute()
39
-
40
- given.and.each do |given_and|
41
-
42
- given_and.execute()
43
-
44
- end
45
- end
46
-
47
- when_.execute
48
-
49
- when_.and.each do |when_and|
50
-
51
- when_and.execute
52
-
53
- end
54
-
55
- when_.then.each do |then_|
56
-
57
- then_.execute
58
-
59
- then_.and.each do |then_and|
60
-
61
- then_and.execute
62
-
63
- end
64
-
65
- end
66
-
67
- end
68
-
69
- if(given.finally)
70
-
71
- given.finally.execute
72
-
73
- end
74
-
75
- end
76
-
77
- Report do |reporter| reporter.ScenarioComplete(self) end
78
-
79
- end
80
- end
81
- end
82
- end
83
-
84
-
85
-
1
+ module Sapphire
2
+ module Testing
3
+ module TestRunnerAdapter
4
+
5
+ def Report(&block)
6
+ $instances.each do |reporter|
7
+ block.call reporter
8
+ end
9
+ end
10
+
11
+ def execute()
12
+ Report do |reporter| reporter.ScenarioStart(self) end
13
+
14
+ self.backgrounds.each do |background|
15
+
16
+ background.execute
17
+
18
+ background.and.each do |background_and|
19
+
20
+ background_and.execute
21
+
22
+ end
23
+
24
+ end
25
+
26
+ self.givens.each do |given|
27
+ given.when.each do |when_|
28
+
29
+ if when_.value.is_a? Pending
30
+ given.pend()
31
+
32
+ given.and.each do |given_and|
33
+
34
+ given_and.pend()
35
+
36
+ end
37
+ else
38
+ given.execute()
39
+
40
+ given.and.each do |given_and|
41
+
42
+ given_and.execute()
43
+
44
+ end
45
+ end
46
+
47
+ when_.execute
48
+
49
+ when_.and.each do |when_and|
50
+
51
+ when_and.execute
52
+
53
+ end
54
+
55
+ when_.then.each do |then_|
56
+
57
+ then_.execute
58
+
59
+ then_.and.each do |then_and|
60
+
61
+ then_and.execute
62
+
63
+ end
64
+
65
+ end
66
+
67
+ end
68
+
69
+ if(given.finally)
70
+
71
+ given.finally.execute
72
+
73
+ end
74
+
75
+ end
76
+
77
+ Report do |reporter| reporter.ScenarioComplete(self) end
78
+
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+
85
+
@@ -1,174 +1,174 @@
1
- module ChildProcess
2
- module Windows
3
- class ProcessBuilder
4
- attr_accessor :inherit, :detach, :duplex, :environment, :stdout, :stderr
5
- attr_reader :stdin
6
-
7
- def initialize(args)
8
- @args = args
9
-
10
- @inherit = false
11
- @detach = false
12
- @duplex = false
13
- @environment = nil
14
-
15
- @stdout = nil
16
- @stderr = nil
17
- @stdin = nil
18
-
19
- @flags = 0
20
- @cmd_ptr = nil
21
- @env_ptr = nil
22
- end
23
-
24
- def start
25
- create_command_pointer
26
- create_environment_pointer
27
-
28
- setup_detach
29
- setup_io
30
-
31
- pid = create_process
32
- close_handles
33
-
34
- pid
35
- end
36
-
37
- private
38
-
39
- def create_command_pointer
40
- string = @args.map { |arg| quote_if_necessary(arg.to_s) }.join ' '
41
- @cmd_ptr = FFI::MemoryPointer.from_string string
42
- end
43
-
44
- def create_environment_pointer
45
- return unless @environment.kind_of?(Hash) && @environment.any?
46
-
47
- # inherited env
48
- strings = ENV.map { |k,v| "#{k}=#{v}\0" }
49
-
50
- # extras
51
- @environment.each do |key, value|
52
- if key.include?("=")
53
- raise InvalidEnvironmentVariableName, key
54
- end
55
-
56
- strings << "#{key}=#{value}\0"
57
- end
58
-
59
- strings << "\0" # terminate the env block
60
- env_str = strings.join
61
-
62
- @env_ptr = FFI::MemoryPointer.new(:long, env_str.bytesize)
63
- @env_ptr.put_bytes 0, env_str, 0, env_str.bytesize
64
- end
65
-
66
- def create_process
67
- startup_info[:lpDesktop] = FFI::MemoryPointer.from_string("test") if $isVirtual
68
-
69
- ok = Lib.create_process(
70
- nil, # application name
71
- @cmd_ptr, # command line
72
- nil, # process attributes
73
- nil, # thread attributes
74
- @inherit, # inherit handles
75
- @flags, # creation flags
76
- @env_ptr, # environment
77
- nil, # current directory
78
- startup_info, # startup info
79
- process_info # process info
80
- )
81
-
82
- ok or raise LaunchError, Lib.last_error_message
83
-
84
- process_info[:dwProcessId]
85
- end
86
-
87
- def startup_info
88
- @startup_info ||= StartupInfo.new
89
- end
90
-
91
- def process_info
92
- @process_info ||= ProcessInfo.new
93
- end
94
-
95
- def setup_detach
96
- @flags |= DETACHED_PROCESS if @detach
97
- end
98
-
99
- def setup_io
100
- if @stdout || @stderr
101
- startup_info[:dwFlags] ||= 0
102
- startup_info[:dwFlags] |= STARTF_USESTDHANDLES
103
-
104
- @inherit = true
105
-
106
- if @stdout
107
- startup_info[:hStdOutput] = std_stream_handle_for(@stdout)
108
- end
109
-
110
- if @stderr
111
- startup_info[:hStdError] = std_stream_handle_for(@stderr)
112
- end
113
- end
114
-
115
- setup_stdin if @duplex
116
- end
117
-
118
- def setup_stdin
119
- read_pipe_ptr = FFI::MemoryPointer.new(:pointer)
120
- write_pipe_ptr = FFI::MemoryPointer.new(:pointer)
121
- sa = SecurityAttributes.new(:inherit => true)
122
-
123
- ok = Lib.create_pipe(read_pipe_ptr, write_pipe_ptr, sa, 0)
124
- Lib.check_error ok
125
-
126
- @read_pipe = read_pipe_ptr.read_pointer
127
- @write_pipe = write_pipe_ptr.read_pointer
128
-
129
- @inherit = true
130
- Lib.set_handle_inheritance @read_pipe, true
131
- Lib.set_handle_inheritance @write_pipe, false
132
-
133
- startup_info[:hStdInput] = @read_pipe
134
- end
135
-
136
- def std_stream_handle_for(io)
137
- handle = Lib.handle_for(io)
138
-
139
- begin
140
- Lib.set_handle_inheritance handle, true
141
- rescue ChildProcess::Error
142
- # If the IO was set to close on exec previously, this call will fail.
143
- # That's probably OK, since the user explicitly asked for it to be
144
- # closed (at least I have yet to find other cases where this will
145
- # happen...)
146
- end
147
-
148
- handle
149
- end
150
-
151
- def close_handles
152
- Lib.close_handle process_info[:hProcess]
153
- Lib.close_handle process_info[:hThread]
154
-
155
- if @duplex
156
- @stdin = Lib.io_for(Lib.duplicate_handle(@write_pipe), File::WRONLY)
157
- Lib.close_handle @read_pipe
158
- Lib.close_handle @write_pipe
159
- end
160
- end
161
-
162
- def quote_if_necessary(str)
163
- quote = str.start_with?('"') ? "'" : '"'
164
-
165
- case str
166
- when /[\s\\'"]/
167
- [quote, str, quote].join
168
- else
169
- str
170
- end
171
- end
172
- end # ProcessBuilder
173
- end # Windows
1
+ module ChildProcess
2
+ module Windows
3
+ class ProcessBuilder
4
+ attr_accessor :inherit, :detach, :duplex, :environment, :stdout, :stderr
5
+ attr_reader :stdin
6
+
7
+ def initialize(args)
8
+ @args = args
9
+
10
+ @inherit = false
11
+ @detach = false
12
+ @duplex = false
13
+ @environment = nil
14
+
15
+ @stdout = nil
16
+ @stderr = nil
17
+ @stdin = nil
18
+
19
+ @flags = 0
20
+ @cmd_ptr = nil
21
+ @env_ptr = nil
22
+ end
23
+
24
+ def start
25
+ create_command_pointer
26
+ create_environment_pointer
27
+
28
+ setup_detach
29
+ setup_io
30
+
31
+ pid = create_process
32
+ close_handles
33
+
34
+ pid
35
+ end
36
+
37
+ private
38
+
39
+ def create_command_pointer
40
+ string = @args.map { |arg| quote_if_necessary(arg.to_s) }.join ' '
41
+ @cmd_ptr = FFI::MemoryPointer.from_string string
42
+ end
43
+
44
+ def create_environment_pointer
45
+ return unless @environment.kind_of?(Hash) && @environment.any?
46
+
47
+ # inherited env
48
+ strings = ENV.map { |k,v| "#{k}=#{v}\0" }
49
+
50
+ # extras
51
+ @environment.each do |key, value|
52
+ if key.include?("=")
53
+ raise InvalidEnvironmentVariableName, key
54
+ end
55
+
56
+ strings << "#{key}=#{value}\0"
57
+ end
58
+
59
+ strings << "\0" # terminate the env block
60
+ env_str = strings.join
61
+
62
+ @env_ptr = FFI::MemoryPointer.new(:long, env_str.bytesize)
63
+ @env_ptr.put_bytes 0, env_str, 0, env_str.bytesize
64
+ end
65
+
66
+ def create_process
67
+ @startup_info[:lpDesktop] = FFI::MemoryPointer.from_string("test") if $isVirtual
68
+
69
+ ok = Lib.create_process(
70
+ nil, # application name
71
+ @cmd_ptr, # command line
72
+ nil, # process attributes
73
+ nil, # thread attributes
74
+ @inherit, # inherit handles
75
+ @flags, # creation flags
76
+ @env_ptr, # environment
77
+ nil, # current directory
78
+ startup_info, # startup info
79
+ process_info # process info
80
+ )
81
+
82
+ ok or raise LaunchError, Lib.last_error_message
83
+
84
+ process_info[:dwProcessId]
85
+ end
86
+
87
+ def startup_info
88
+ @startup_info ||= StartupInfo.new
89
+ end
90
+
91
+ def process_info
92
+ @process_info ||= ProcessInfo.new
93
+ end
94
+
95
+ def setup_detach
96
+ @flags |= DETACHED_PROCESS if @detach
97
+ end
98
+
99
+ def setup_io
100
+ if @stdout || @stderr
101
+ startup_info[:dwFlags] ||= 0
102
+ startup_info[:dwFlags] |= STARTF_USESTDHANDLES
103
+
104
+ @inherit = true
105
+
106
+ if @stdout
107
+ startup_info[:hStdOutput] = std_stream_handle_for(@stdout)
108
+ end
109
+
110
+ if @stderr
111
+ startup_info[:hStdError] = std_stream_handle_for(@stderr)
112
+ end
113
+ end
114
+
115
+ setup_stdin if @duplex
116
+ end
117
+
118
+ def setup_stdin
119
+ read_pipe_ptr = FFI::MemoryPointer.new(:pointer)
120
+ write_pipe_ptr = FFI::MemoryPointer.new(:pointer)
121
+ sa = SecurityAttributes.new(:inherit => true)
122
+
123
+ ok = Lib.create_pipe(read_pipe_ptr, write_pipe_ptr, sa, 0)
124
+ Lib.check_error ok
125
+
126
+ @read_pipe = read_pipe_ptr.read_pointer
127
+ @write_pipe = write_pipe_ptr.read_pointer
128
+
129
+ @inherit = true
130
+ Lib.set_handle_inheritance @read_pipe, true
131
+ Lib.set_handle_inheritance @write_pipe, false
132
+
133
+ startup_info[:hStdInput] = @read_pipe
134
+ end
135
+
136
+ def std_stream_handle_for(io)
137
+ handle = Lib.handle_for(io)
138
+
139
+ begin
140
+ Lib.set_handle_inheritance handle, true
141
+ rescue ChildProcess::Error
142
+ # If the IO was set to close on exec previously, this call will fail.
143
+ # That's probably OK, since the user explicitly asked for it to be
144
+ # closed (at least I have yet to find other cases where this will
145
+ # happen...)
146
+ end
147
+
148
+ handle
149
+ end
150
+
151
+ def close_handles
152
+ Lib.close_handle process_info[:hProcess]
153
+ Lib.close_handle process_info[:hThread]
154
+
155
+ if @duplex
156
+ @stdin = Lib.io_for(Lib.duplicate_handle(@write_pipe), File::WRONLY)
157
+ Lib.close_handle @read_pipe
158
+ Lib.close_handle @write_pipe
159
+ end
160
+ end
161
+
162
+ def quote_if_necessary(str)
163
+ quote = str.start_with?('"') ? "'" : '"'
164
+
165
+ case str
166
+ when /[\s\\'"]/
167
+ [quote, str, quote].join
168
+ else
169
+ str
170
+ end
171
+ end
172
+ end # ProcessBuilder
173
+ end # Windows
174
174
  end # ChildProcess