sapphire 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/sapphire +5 -5
- data/lib/sapphire.rb +4 -0
- data/lib/sapphire/DSL/Browser/Virtually.rb +15 -0
- data/lib/sapphire/DSL/Scenarios/background.rb +10 -0
- data/lib/sapphire/DSL/Scenarios/dsl.rb +1 -2
- data/lib/sapphire/DSL/Scenarios/scenario.rb +1 -0
- data/lib/sapphire/DSL/Scenarios/then.rb +2 -2
- data/lib/sapphire/DSL/TestPlans/TestPlan.rb +8 -7
- data/lib/sapphire/TeamCity/TeamCityReporter.rb +59 -17
- data/lib/sapphire/Testing/ConsoleReporter.rb +4 -0
- data/lib/sapphire/Testing/Executable.rb +1 -1
- data/lib/sapphire/Testing/HtmlReporter.rb +3 -0
- data/lib/sapphire/Testing/TestRunnerAdapter.rb +6 -4
- data/lib/sapphire/UI/Functions.rb +286 -0
- data/lib/sapphire/UI/VirtualUI.rb +68 -0
- data/lib/sapphire/version.rb +1 -1
- metadata +11 -8
data/bin/sapphire
CHANGED
@@ -3,24 +3,24 @@ $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
|
3
3
|
require 'sapphire'
|
4
4
|
include Sapphire::Sapphire
|
5
5
|
|
6
|
-
reporter =
|
6
|
+
reporter = TeamCityReporter.new()
|
7
7
|
|
8
8
|
ARGV.each do |arg|
|
9
9
|
if !arg.end_with? ".rb"
|
10
10
|
next
|
11
11
|
end
|
12
12
|
require arg
|
13
|
-
Runner.instance.last_scenario.file_name = arg
|
13
|
+
Runner.instance.last_scenario.file_name = arg if Runner.instance.last_scenario and Runner.instance.last_scenario.file_name == ""
|
14
14
|
end
|
15
15
|
|
16
|
+
reporter.BeginTesting
|
17
|
+
|
16
18
|
if Runner.instance.test_plans.count > 0
|
17
|
-
Runner.instance.last_test_plan.execute
|
19
|
+
Runner.instance.last_test_plan.execute
|
18
20
|
else
|
19
21
|
Runner.instance.scenarios.each do |scenario|
|
20
22
|
scenario.execute reporter
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
24
|
-
|
25
|
-
|
26
26
|
reporter.OutputResults
|
data/lib/sapphire.rb
CHANGED
@@ -11,6 +11,7 @@ require 'colorize'
|
|
11
11
|
require File.expand_path(File.dirname(__FILE__) +'/sapphire/Strategies/Strategy.rb', __FILE__)
|
12
12
|
require File.expand_path(File.dirname(__FILE__) +'/sapphire/Testing/Reporter.rb', __FILE__)
|
13
13
|
Dir[File.dirname(__FILE__) + '/sapphire/Testing/*.rb'].each {|file| require file }
|
14
|
+
Dir[File.dirname(__FILE__) + '/sapphire/TeamCity/*.rb'].each {|file| require file }
|
14
15
|
Dir[File.dirname(__FILE__) + '/sapphire/Configuration/*.rb'].each {|file| require file }
|
15
16
|
Dir[File.dirname(__FILE__) + '/sapphire/WebAbstractions/Controls/Base/*.rb'].each {|file| require file }
|
16
17
|
Dir[File.dirname(__FILE__) + '/sapphire/WebAbstractions/Controls/*.rb'].each {|file| require file }
|
@@ -22,6 +23,7 @@ Dir[File.dirname(__FILE__) + '/sapphire/DSL/Configuration/*.rb'].each {|file| re
|
|
22
23
|
Dir[File.dirname(__FILE__) + '/sapphire/DSL/Data/*.rb'].each {|file| require file }
|
23
24
|
Dir[File.dirname(__FILE__) + '/sapphire/DSL/Scenarios/*.rb'].each {|file| require file }
|
24
25
|
Dir[File.dirname(__FILE__) + '/sapphire/DSL/TestPlans/*.rb'].each {|file| require file }
|
26
|
+
Dir[File.dirname(__FILE__) + '/sapphire/UI/*.rb'].each {|file| require file }
|
25
27
|
|
26
28
|
module Sapphire
|
27
29
|
module Sapphire
|
@@ -37,5 +39,7 @@ module Sapphire
|
|
37
39
|
include JobAbstractions
|
38
40
|
include WebAbstractions
|
39
41
|
include Testing
|
42
|
+
include Testing::TeamCity
|
43
|
+
include UI
|
40
44
|
end
|
41
45
|
end
|
@@ -6,6 +6,7 @@ class Background
|
|
6
6
|
attr_reader :block
|
7
7
|
attr_reader :parent
|
8
8
|
attr_reader :results
|
9
|
+
attr_reader :and
|
9
10
|
|
10
11
|
def initialize(parent, pre, text, &block)
|
11
12
|
@block = block
|
@@ -13,6 +14,7 @@ class Background
|
|
13
14
|
@text = pre + text.to_s
|
14
15
|
@parent = parent
|
15
16
|
@results = []
|
17
|
+
@and = []
|
16
18
|
end
|
17
19
|
|
18
20
|
def AddResult(result)
|
@@ -21,4 +23,12 @@ class Background
|
|
21
23
|
self.parent.result.AddChild(result)
|
22
24
|
end
|
23
25
|
|
26
|
+
def add_and(pre, text, &block)
|
27
|
+
if(self.value.is_a? Pending)
|
28
|
+
self.and << And.new(self, Pending.new(pre + text), &block)
|
29
|
+
else
|
30
|
+
self.and << And.new(self, pre + text, &block)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
24
34
|
end
|
@@ -20,7 +20,7 @@ module Sapphire
|
|
20
20
|
def And(text, &block)
|
21
21
|
|
22
22
|
if(Runner.instance.last_scenario.last_given == nil && Runner.instance.last_scenario.last_background != nil)
|
23
|
-
Runner.instance.last_scenario.
|
23
|
+
Runner.instance.last_scenario.last_background.add_and("And ", text, &block)
|
24
24
|
return
|
25
25
|
end
|
26
26
|
|
@@ -51,7 +51,6 @@ module Sapphire
|
|
51
51
|
def Scenario(text, &block)
|
52
52
|
Runner.instance.add_scenario(Scenario.new(text, &block))
|
53
53
|
Runner.instance.last_scenario.block.call
|
54
|
-
#Runner.instance.last_scenario.execute 1
|
55
54
|
end
|
56
55
|
end
|
57
56
|
end
|
@@ -19,10 +19,10 @@ class Then
|
|
19
19
|
|
20
20
|
def add_and(pre, text, &block)
|
21
21
|
if(!self.value.instance_of? Pending)
|
22
|
-
x =
|
22
|
+
x = And.new(self, pre + text, &block)
|
23
23
|
self.and << x
|
24
24
|
else
|
25
|
-
self.and <<
|
25
|
+
self.and << And.new(self, Pending.new(pre + text), &block)
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -3,9 +3,8 @@ module Sapphire
|
|
3
3
|
module TestPlans
|
4
4
|
|
5
5
|
def TestPlan(text, &block)
|
6
|
-
reporter =
|
7
|
-
Runner.instance.add_test_plan(TestPlan.new(text, &block))
|
8
|
-
Runner.instance.last_test_plan.execute reporter
|
6
|
+
reporter = TeamCityReporter.new()
|
7
|
+
Runner.instance.add_test_plan(TestPlan.new(text, reporter, &block))
|
9
8
|
end
|
10
9
|
|
11
10
|
class TestPlan
|
@@ -14,10 +13,11 @@ module Sapphire
|
|
14
13
|
attr_reader :value
|
15
14
|
attr_reader :text
|
16
15
|
|
17
|
-
def initialize(text, &block)
|
16
|
+
def initialize(text, reporter, &block)
|
18
17
|
@value = text
|
19
18
|
@text = text.to_s
|
20
19
|
@block = block
|
20
|
+
@reporter = reporter
|
21
21
|
|
22
22
|
@items = []
|
23
23
|
@handlers = []
|
@@ -36,7 +36,7 @@ module Sapphire
|
|
36
36
|
@handlers.each do |handler|
|
37
37
|
handler.keys.each do |handler_key|
|
38
38
|
if(handler_key == key)
|
39
|
-
handler[handler_key].Handle item[key]
|
39
|
+
handler[handler_key].Handle item[key], @reporter
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
@@ -47,10 +47,11 @@ module Sapphire
|
|
47
47
|
@handlers << handler
|
48
48
|
end
|
49
49
|
|
50
|
-
def execute
|
50
|
+
def execute
|
51
|
+
@reporter.BeginTesting
|
51
52
|
$stdout.puts ""
|
52
53
|
@block.call
|
53
|
-
reporter.OutputResults
|
54
|
+
@reporter.OutputResults
|
54
55
|
end
|
55
56
|
end
|
56
57
|
end
|
@@ -2,7 +2,7 @@ require 'teamcity/utils/logger_util'
|
|
2
2
|
require 'teamcity/rake_exceptions'
|
3
3
|
require 'teamcity/rakerunner_consts'
|
4
4
|
|
5
|
-
SPEC_FORMATTER_LOG = ::Rake::TeamCity::Utils::
|
5
|
+
SPEC_FORMATTER_LOG = ::Rake::TeamCity::Utils::RakeFileLogger.new
|
6
6
|
SPEC_FORMATTER_LOG.log_msg("spec formatter.rb loaded.")
|
7
7
|
|
8
8
|
require 'teamcity/runner_common'
|
@@ -50,13 +50,13 @@ module Sapphire
|
|
50
50
|
# Initializes
|
51
51
|
@groups_stack = []
|
52
52
|
|
53
|
-
@example_count = 100
|
54
53
|
if ::Rake::TeamCity.is_in_idea_mode
|
55
|
-
log(@message_factory.create_tests_count(@example_count))
|
54
|
+
#log(@message_factory.create_tests_count(@example_count))
|
56
55
|
elsif ::Rake::TeamCity.is_in_buildserver_mode
|
57
|
-
log(@message_factory.create_progress_message("Starting
|
56
|
+
log(@message_factory.create_progress_message("Starting..."))
|
58
57
|
end
|
59
58
|
|
59
|
+
@current = 0
|
60
60
|
end
|
61
61
|
|
62
62
|
def PrintItem(result, depth)
|
@@ -64,11 +64,13 @@ module Sapphire
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def ScenarioStart(scenario)
|
67
|
-
@message_factory.create_suite_started(scenario.text
|
67
|
+
log(@message_factory.create_suite_started("Scenario: " + scenario.text))
|
68
68
|
end
|
69
69
|
|
70
70
|
def ScenarioComplete(scenario)
|
71
|
-
@message_factory.create_suite_finished(
|
71
|
+
log(@message_factory.create_suite_finished("Finally"))
|
72
|
+
log(@message_factory.create_suite_finished("Assuming"))
|
73
|
+
log(@message_factory.create_suite_finished("Scenario: " + scenario.text))
|
72
74
|
end
|
73
75
|
|
74
76
|
def PrintHeader()
|
@@ -92,25 +94,65 @@ module Sapphire
|
|
92
94
|
end
|
93
95
|
|
94
96
|
def TestStarted(test)
|
95
|
-
|
97
|
+
|
98
|
+
if test.is_a? Given and @current > 0
|
99
|
+
log(@message_factory.create_suite_finished("Then"))
|
100
|
+
log(@message_factory.create_suite_finished("When"))
|
101
|
+
log(@message_factory.create_suite_finished("Given"))
|
102
|
+
elsif test.is_a? Finally
|
103
|
+
log(@message_factory.create_suite_finished("Then"))
|
104
|
+
log(@message_factory.create_suite_finished("When"))
|
105
|
+
log(@message_factory.create_suite_finished("Given"))
|
106
|
+
end
|
107
|
+
|
108
|
+
@current = 1
|
109
|
+
|
110
|
+
if test.is_a? Given
|
111
|
+
log(@message_factory.create_suite_started("Given"))
|
112
|
+
elsif test.is_a? When
|
113
|
+
log(@message_factory.create_suite_started("When"))
|
114
|
+
elsif test.is_a? Then
|
115
|
+
log(@message_factory.create_suite_started("Then"))
|
116
|
+
elsif test.is_a? Background
|
117
|
+
log(@message_factory.create_suite_started("Assuming"))
|
118
|
+
elsif test.is_a? Finally
|
119
|
+
log(@message_factory.create_suite_started("Finally"))
|
120
|
+
end
|
121
|
+
|
122
|
+
@current = @current + 1
|
123
|
+
|
124
|
+
log(@message_factory.create_test_started(test.text))
|
96
125
|
end
|
97
126
|
|
98
127
|
def TestCompleted(test)
|
99
128
|
if test.type == "pending"
|
100
|
-
@message_factory.
|
101
|
-
|
102
|
-
|
129
|
+
log(@message_factory.create_test_ignored(test.text, "Pending: Not Yet Implemented"))
|
130
|
+
elsif test.type == "pass"
|
131
|
+
log(@message_factory.create_test_finished(test.text, test.time))
|
132
|
+
elsif test.type == "fail"
|
133
|
+
|
134
|
+
if test.messages.is_a? Array
|
135
|
+
messages = test.messages.join("\n")
|
136
|
+
else
|
137
|
+
messages = test.messages
|
138
|
+
end
|
139
|
+
stack = ""
|
140
|
+
test.stack.each do |line|
|
141
|
+
if (!line.include? "sapphire")
|
142
|
+
stack += line + "\n"
|
143
|
+
end
|
103
144
|
end
|
104
|
-
|
105
|
-
@message_factory.create_test_finished(test.text, test.time)
|
106
|
-
return
|
145
|
+
log(@message_factory.create_test_failed(test.text, messages, stack))
|
107
146
|
end
|
108
|
-
|
109
|
-
|
110
|
-
@message_factory.
|
147
|
+
|
148
|
+
if test.item.is_a? Finally
|
149
|
+
log(@message_factory.create_suite_finished("Finally"))
|
111
150
|
end
|
112
151
|
|
113
|
-
|
152
|
+
end
|
153
|
+
|
154
|
+
def BeginTesting
|
155
|
+
log(@message_factory.create_test_reported_attached)
|
114
156
|
end
|
115
157
|
end
|
116
158
|
end
|
@@ -3,7 +3,7 @@ module Sapphire
|
|
3
3
|
module Executable
|
4
4
|
def execute(reporter)
|
5
5
|
start = Time.now
|
6
|
-
reporter.TestStarted(self
|
6
|
+
reporter.TestStarted(self)
|
7
7
|
begin
|
8
8
|
if(self.value.is_a? Pending)
|
9
9
|
result = ResultTree.new(self.text, TestResult.new("pending", self, "Pending", "", Time.now - start))
|
@@ -4,18 +4,20 @@ module Sapphire
|
|
4
4
|
|
5
5
|
def execute(reporter)
|
6
6
|
reporter.ScenarioStart self
|
7
|
-
@failures = []
|
8
|
-
@pendings = []
|
9
|
-
@success = []
|
10
7
|
|
11
8
|
self.backgrounds.each do |b|
|
12
9
|
|
13
10
|
b.execute reporter
|
14
11
|
|
12
|
+
b.and.each do |g_a|
|
13
|
+
|
14
|
+
g_a.execute reporter
|
15
|
+
|
16
|
+
end
|
17
|
+
|
15
18
|
end
|
16
19
|
|
17
20
|
self.givens.each do |g|
|
18
|
-
|
19
21
|
g.when.each do |w|
|
20
22
|
|
21
23
|
g.execute reporter
|
@@ -0,0 +1,286 @@
|
|
1
|
+
module ChildProcess
|
2
|
+
module Windows
|
3
|
+
module Lib
|
4
|
+
|
5
|
+
def self.create_proc(cmd, opts = {})
|
6
|
+
cmd_ptr = FFI::MemoryPointer.from_string cmd
|
7
|
+
|
8
|
+
flags = 0
|
9
|
+
inherit = !!opts[:inherit]
|
10
|
+
|
11
|
+
flags |= DETACHED_PROCESS if opts[:detach]
|
12
|
+
|
13
|
+
si = StartupInfo.new
|
14
|
+
pi = ProcessInfo.new
|
15
|
+
|
16
|
+
if opts[:stdout] || opts[:stderr]
|
17
|
+
si[:dwFlags] ||= 0
|
18
|
+
si[:dwFlags] |= STARTF_USESTDHANDLES
|
19
|
+
inherit = true
|
20
|
+
|
21
|
+
si[:hStdOutput] = handle_for(opts[:stdout].fileno) if opts[:stdout]
|
22
|
+
si[:hStdError] = handle_for(opts[:stderr].fileno) if opts[:stderr]
|
23
|
+
end
|
24
|
+
|
25
|
+
if opts[:duplex]
|
26
|
+
read_pipe_ptr = FFI::MemoryPointer.new(:pointer)
|
27
|
+
write_pipe_ptr = FFI::MemoryPointer.new(:pointer)
|
28
|
+
sa = SecurityAttributes.new(:inherit => true)
|
29
|
+
|
30
|
+
ok = create_pipe(read_pipe_ptr, write_pipe_ptr, sa, 0)
|
31
|
+
ok or raise Error, last_error_message
|
32
|
+
|
33
|
+
read_pipe = read_pipe_ptr.read_pointer
|
34
|
+
write_pipe = write_pipe_ptr.read_pointer
|
35
|
+
|
36
|
+
si[:hStdInput] = read_pipe
|
37
|
+
end
|
38
|
+
|
39
|
+
si[:lpDesktop] = FFI::MemoryPointer.from_string("test") if $isVirtual
|
40
|
+
|
41
|
+
ok = create_process(nil, cmd_ptr, nil, nil, inherit, flags, nil, nil, si, pi)
|
42
|
+
ok or raise Error, last_error_message
|
43
|
+
|
44
|
+
close_handle pi[:hProcess]
|
45
|
+
close_handle pi[:hThread]
|
46
|
+
|
47
|
+
if opts[:duplex]
|
48
|
+
opts[:stdin] = io_for(duplicate_handle(write_pipe), File::WRONLY)
|
49
|
+
close_handle read_pipe
|
50
|
+
close_handle write_pipe
|
51
|
+
end
|
52
|
+
|
53
|
+
pi[:dwProcessId]
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.last_error_message
|
57
|
+
errnum = get_last_error
|
58
|
+
buf = FFI::MemoryPointer.new :char, 512
|
59
|
+
|
60
|
+
size = format_message(
|
61
|
+
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
62
|
+
nil, errnum, 0, buf, buf.size, nil
|
63
|
+
)
|
64
|
+
|
65
|
+
buf.read_string(size).strip
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.handle_for(fd_or_io)
|
69
|
+
case fd_or_io
|
70
|
+
when IO
|
71
|
+
handle = get_osfhandle(fd.fileno)
|
72
|
+
when Fixnum
|
73
|
+
handle = get_osfhandle(fd_or_io)
|
74
|
+
else
|
75
|
+
if fd_or_io.respond_to?(:to_io)
|
76
|
+
io = fd_or_io.to_io
|
77
|
+
|
78
|
+
unless io.kind_of?(IO)
|
79
|
+
raise TypeError, "expected #to_io to return an instance of IO"
|
80
|
+
end
|
81
|
+
|
82
|
+
handle = get_osfhandle(io.fileno)
|
83
|
+
else
|
84
|
+
raise TypeError, "invalid type: #{fd_or_io.inspect}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
if handle == INVALID_HANDLE_VALUE
|
89
|
+
raise Error, last_error_message
|
90
|
+
end
|
91
|
+
|
92
|
+
handle
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.io_for(handle, flags = File::RDONLY)
|
96
|
+
fd = open_osfhandle(handle, flags)
|
97
|
+
if fd == -1
|
98
|
+
raise Error, last_error_message
|
99
|
+
end
|
100
|
+
|
101
|
+
::IO.for_fd fd, flags
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.duplicate_handle(handle)
|
105
|
+
dup = FFI::MemoryPointer.new(:pointer)
|
106
|
+
proc = current_process
|
107
|
+
|
108
|
+
ok = _duplicate_handle(
|
109
|
+
proc, handle, proc, dup, 0, false, DUPLICATE_SAME_ACCESS)
|
110
|
+
|
111
|
+
ok or raise Error, last_error_message
|
112
|
+
|
113
|
+
dup.read_pointer
|
114
|
+
ensure
|
115
|
+
close_handle proc
|
116
|
+
end
|
117
|
+
|
118
|
+
#
|
119
|
+
# BOOL WINAPI CreateProcess(
|
120
|
+
# __in_opt LPCTSTR lpApplicationName,
|
121
|
+
# __inout_opt LPTSTR lpCommandLine,
|
122
|
+
# __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
123
|
+
# __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
124
|
+
# __in BOOL bInheritHandles,
|
125
|
+
# __in DWORD dwCreationFlags,
|
126
|
+
# __in_opt LPVOID lpEnvironment,
|
127
|
+
# __in_opt LPCTSTR lpCurrentDirectory,
|
128
|
+
# __in LPSTARTUPINFO lpStartupInfo,
|
129
|
+
# __out LPPROCESS_INFORMATION lpProcessInformation
|
130
|
+
# );
|
131
|
+
#
|
132
|
+
|
133
|
+
attach_function :create_process, :CreateProcessA, [
|
134
|
+
:pointer,
|
135
|
+
:pointer,
|
136
|
+
:pointer,
|
137
|
+
:pointer,
|
138
|
+
:bool,
|
139
|
+
:ulong,
|
140
|
+
:pointer,
|
141
|
+
:pointer,
|
142
|
+
:pointer,
|
143
|
+
:pointer],
|
144
|
+
:bool
|
145
|
+
|
146
|
+
#
|
147
|
+
# DWORD WINAPI GetLastError(void);
|
148
|
+
#
|
149
|
+
|
150
|
+
attach_function :get_last_error, :GetLastError, [], :ulong
|
151
|
+
|
152
|
+
#
|
153
|
+
# DWORD WINAPI FormatMessage(
|
154
|
+
# __in DWORD dwFlags,
|
155
|
+
# __in_opt LPCVOID lpSource,
|
156
|
+
# __in DWORD dwMessageId,
|
157
|
+
# __in DWORD dwLanguageId,
|
158
|
+
# __out LPTSTR lpBuffer,
|
159
|
+
# __in DWORD nSize,
|
160
|
+
# __in_opt va_list *Arguments
|
161
|
+
# );
|
162
|
+
#
|
163
|
+
|
164
|
+
attach_function :format_message, :FormatMessageA, [
|
165
|
+
:ulong,
|
166
|
+
:pointer,
|
167
|
+
:ulong,
|
168
|
+
:ulong,
|
169
|
+
:pointer,
|
170
|
+
:ulong,
|
171
|
+
:pointer],
|
172
|
+
:ulong
|
173
|
+
|
174
|
+
|
175
|
+
attach_function :close_handle, :CloseHandle, [:pointer], :bool
|
176
|
+
|
177
|
+
#
|
178
|
+
# HANDLE WINAPI OpenProcess(
|
179
|
+
# __in DWORD dwDesiredAccess,
|
180
|
+
# __in BOOL bInheritHandle,
|
181
|
+
# __in DWORD dwProcessId
|
182
|
+
# );
|
183
|
+
#
|
184
|
+
|
185
|
+
attach_function :open_process, :OpenProcess, [:ulong, :bool, :ulong], :pointer
|
186
|
+
|
187
|
+
#
|
188
|
+
# DWORD WINAPI WaitForSingleObject(
|
189
|
+
# __in HANDLE hHandle,
|
190
|
+
# __in DWORD dwMilliseconds
|
191
|
+
# );
|
192
|
+
#
|
193
|
+
|
194
|
+
attach_function :wait_for_single_object, :WaitForSingleObject, [:pointer, :ulong], :wait_status
|
195
|
+
|
196
|
+
#
|
197
|
+
# BOOL WINAPI GetExitCodeProcess(
|
198
|
+
# __in HANDLE hProcess,
|
199
|
+
# __out LPDWORD lpExitCode
|
200
|
+
# );
|
201
|
+
#
|
202
|
+
|
203
|
+
attach_function :get_exit_code, :GetExitCodeProcess, [:pointer, :pointer], :bool
|
204
|
+
|
205
|
+
#
|
206
|
+
# BOOL WINAPI GenerateConsoleCtrlEvent(
|
207
|
+
# __in DWORD dwCtrlEvent,
|
208
|
+
# __in DWORD dwProcessGroupId
|
209
|
+
# );
|
210
|
+
#
|
211
|
+
|
212
|
+
attach_function :generate_console_ctrl_event, :GenerateConsoleCtrlEvent, [:ulong, :ulong], :bool
|
213
|
+
|
214
|
+
#
|
215
|
+
# BOOL WINAPI TerminateProcess(
|
216
|
+
# __in HANDLE hProcess,
|
217
|
+
# __in UINT uExitCode
|
218
|
+
# );
|
219
|
+
#
|
220
|
+
|
221
|
+
attach_function :terminate_process, :TerminateProcess, [:pointer, :uint], :bool
|
222
|
+
|
223
|
+
#
|
224
|
+
# long _get_osfhandle(
|
225
|
+
# int fd
|
226
|
+
# );
|
227
|
+
#
|
228
|
+
|
229
|
+
attach_function :get_osfhandle, :_get_osfhandle, [:int], :long
|
230
|
+
|
231
|
+
#
|
232
|
+
# int _open_osfhandle (
|
233
|
+
# intptr_t osfhandle,
|
234
|
+
# int flags
|
235
|
+
# );
|
236
|
+
#
|
237
|
+
|
238
|
+
attach_function :open_osfhandle, :_open_osfhandle, [:pointer, :int], :int
|
239
|
+
|
240
|
+
# BOOL WINAPI SetHandleInformation(
|
241
|
+
# __in HANDLE hObject,
|
242
|
+
# __in DWORD dwMask,
|
243
|
+
# __in DWORD dwFlags
|
244
|
+
# );
|
245
|
+
|
246
|
+
attach_function :set_handle_information, :SetHandleInformation, [:long, :ulong, :ulong], :bool
|
247
|
+
|
248
|
+
# BOOL WINAPI CreatePipe(
|
249
|
+
# __out PHANDLE hReadPipe,
|
250
|
+
# __out PHANDLE hWritePipe,
|
251
|
+
# __in_opt LPSECURITY_ATTRIBUTES lpPipeAttributes,
|
252
|
+
# __in DWORD nSize
|
253
|
+
# );
|
254
|
+
|
255
|
+
attach_function :create_pipe, :CreatePipe, [:pointer, :pointer, :pointer, :ulong], :bool
|
256
|
+
|
257
|
+
#
|
258
|
+
# HANDLE WINAPI GetCurrentProcess(void);
|
259
|
+
#
|
260
|
+
|
261
|
+
attach_function :current_process, :GetCurrentProcess, [], :pointer
|
262
|
+
|
263
|
+
#
|
264
|
+
# BOOL WINAPI DuplicateHandle(
|
265
|
+
# __in HANDLE hSourceProcessHandle,
|
266
|
+
# __in HANDLE hSourceHandle,
|
267
|
+
# __in HANDLE hTargetProcessHandle,
|
268
|
+
# __out LPHANDLE lpTargetHandle,
|
269
|
+
# __in DWORD dwDesiredAccess,
|
270
|
+
# __in BOOL bInheritHandle,
|
271
|
+
# __in DWORD dwOptions
|
272
|
+
# );
|
273
|
+
#
|
274
|
+
|
275
|
+
attach_function :_duplicate_handle, :DuplicateHandle, [
|
276
|
+
:pointer,
|
277
|
+
:pointer,
|
278
|
+
:pointer,
|
279
|
+
:pointer,
|
280
|
+
:ulong,
|
281
|
+
:bool,
|
282
|
+
:ulong
|
283
|
+
], :bool
|
284
|
+
end # Lib
|
285
|
+
end # Windows
|
286
|
+
end # ChildProcess
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Sapphire
|
4
|
+
module UI
|
5
|
+
extend FFI::Library
|
6
|
+
|
7
|
+
ffi_lib 'user32'
|
8
|
+
ffi_convention :stdcall
|
9
|
+
attach_function :CreateDesktop, :CreateDesktopA, [ :string, :pointer, :pointer, :int, :long, :pointer ], :int
|
10
|
+
attach_function :CloseDesktop, [ :int ], :bool
|
11
|
+
|
12
|
+
ffi_lib 'kernel32'
|
13
|
+
attach_function :CreateProcess, :CreateProcessA, [ :pointer, :pointer, :pointer, :pointer, :int, :ushort, :pointer, :pointer, :pointer, :pointer], :int
|
14
|
+
attach_function :GetLastError, [ ], :ushort
|
15
|
+
|
16
|
+
class StartUpInfo < FFI::Struct
|
17
|
+
layout :cb, :ushort,
|
18
|
+
:lpReserved, :pointer,
|
19
|
+
:lpDesktop, :pointer,
|
20
|
+
:lpTitle, :pointer,
|
21
|
+
:dwX, :ushort,
|
22
|
+
:dwY, :ushort,
|
23
|
+
:dwXSize, :ushort,
|
24
|
+
:dwYSize, :ushort,
|
25
|
+
:dwXCountChars, :ushort,
|
26
|
+
:dwYCountChars, :ushort,
|
27
|
+
:dwFillAttribute, :ushort,
|
28
|
+
:dwFlags, :ushort,
|
29
|
+
:wShowWindow, :short,
|
30
|
+
:cbReserved2, :short,
|
31
|
+
:lpReserved2, :pointer,
|
32
|
+
:hStdInput, :pointer,
|
33
|
+
:hStdOutput, :pointer,
|
34
|
+
:hStdError, :pointer
|
35
|
+
end
|
36
|
+
|
37
|
+
class ProcessInformation < FFI::Struct
|
38
|
+
layout :hProcess, :pointer,
|
39
|
+
:hThread, :pointer,
|
40
|
+
:dwProcessId, :ushort,
|
41
|
+
:dwThreadId, :ushort
|
42
|
+
end
|
43
|
+
|
44
|
+
class VirtualUI
|
45
|
+
|
46
|
+
def Create()
|
47
|
+
|
48
|
+
@off_screen = UI::CreateDesktop("test", nil, nil, 0, 0x02000000, nil)
|
49
|
+
|
50
|
+
if(@off_screen == nil)
|
51
|
+
raise "Could not create a virtual desktop :("
|
52
|
+
end
|
53
|
+
|
54
|
+
$isVirtual = true
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
def Close()
|
59
|
+
$isVirtual = false
|
60
|
+
result = UI::CloseDesktop(@off_screen)
|
61
|
+
|
62
|
+
if(result == 0)
|
63
|
+
raise "Could not close the virtual desktop :("
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/sapphire/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sapphire
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-09-
|
12
|
+
date: 2011-09-30 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: selenium-webdriver
|
16
|
-
requirement: &
|
16
|
+
requirement: &9888888 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *9888888
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: colorize
|
27
|
-
requirement: &
|
27
|
+
requirement: &9888636 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *9888636
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: win32console
|
38
|
-
requirement: &
|
38
|
+
requirement: &9888384 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *9888384
|
47
47
|
description: An automated web acceptance test framework for non-technical resources
|
48
48
|
using selenium-wedriver.
|
49
49
|
email:
|
@@ -91,6 +91,7 @@ files:
|
|
91
91
|
- lib/sapphire/DSL/Browser/Tracker.rb
|
92
92
|
- lib/sapphire/DSL/Browser/Transition.rb
|
93
93
|
- lib/sapphire/DSL/Browser/Uncheck.rb
|
94
|
+
- lib/sapphire/DSL/Browser/Virtually.rb
|
94
95
|
- lib/sapphire/DSL/Browser/With.rb
|
95
96
|
- lib/sapphire/DSL/Configuration/ConfiguredBrowser.rb
|
96
97
|
- lib/sapphire/DSL/Configuration/ConfiguredUser.rb
|
@@ -138,6 +139,8 @@ files:
|
|
138
139
|
- lib/sapphire/Testing/ScenarioResult.rb
|
139
140
|
- lib/sapphire/Testing/TestResult.rb
|
140
141
|
- lib/sapphire/Testing/TestRunnerAdapter.rb
|
142
|
+
- lib/sapphire/UI/Functions.rb
|
143
|
+
- lib/sapphire/UI/VirtualUI.rb
|
141
144
|
- lib/sapphire/version.rb
|
142
145
|
- lib/sapphire/WebAbstractions/Controls/Base/Control.rb
|
143
146
|
- lib/sapphire/WebAbstractions/Controls/Base/Page.rb
|