sapphire 0.3.1 → 0.4.0
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/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
|