te3270 0.8.1 → 0.9.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.
- checksums.yaml +5 -5
- data/ChangeLog +8 -0
- data/README.md +22 -7
- data/lib/te3270/emulator_factory.rb +3 -1
- data/lib/te3270/emulators/bluezone.rb +282 -0
- data/lib/te3270/version.rb +1 -1
- data/spec/lib/te3270/emulators/bluezone_spec.rb +330 -0
- data/spec/lib/te3270_spec.rb +2 -2
- data/spec/spec_helper.rb +14 -0
- data/te3270.gemspec +1 -1
- metadata +10 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ca80832f6e8d872ddeb31fbc12a29ad613ad33ef13b191b9c6cb2f289cbca413
|
4
|
+
data.tar.gz: 36961aadfe3fcf1bf2fc569d1622c48d943aa1b2cc71df24c56cb3232d7d572b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '08839017d9d96ad934cbd2295a55aff3e3470aacbe8771139b7429d724119aa75f41a91e998e229e3d890d26d4718f22e690d84abfbb60dc0f938e1080b87ef7'
|
7
|
+
data.tar.gz: c13d41c841a084a4b04a6ba29cf27a35f03ae944c3f453563d8da140a492b7b43aa1ab808a7c9359ab7696a57fc00e8052eae2c6b386c816b336610cf0f3a4de
|
data/ChangeLog
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
=== Version 0.9.0 / 2020-03-19
|
2
|
+
* Enhancements
|
3
|
+
* Added support for BlueZone driver (Thanks Jonathan Knapp)
|
4
|
+
* Add troubleshooting info to README
|
5
|
+
* Fixes
|
6
|
+
* No longer limit bundler version in dev dependency
|
7
|
+
* Fix test that only runs on windows
|
8
|
+
|
1
9
|
=== Version 0.8.1 / 2017-03-06
|
2
10
|
* Fixes
|
3
11
|
* Fixed get_string method for Virtel (Thanks David West)
|
data/README.md
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
# TE3270
|
2
2
|
|
3
|
-
This gem can be used to drive a 3270 terminal emulator.
|
4
|
-
machines on which you use the gem.
|
3
|
+
This gem can be used to drive a 3270 terminal emulator. You have to have a supported emulator installed on the
|
4
|
+
machines on which you use the gem. Currently the supported emulators are
|
5
5
|
[EXTRA! X-treme](http://www.attachmate.com/Products/Terminal+Emulation/Extra/xtreme/extra-x-treme.htm) by
|
6
|
-
Attachmate, [Quick3270](http://www.dn-computing.com/Quick3270.htm) by DN-Computing,
|
6
|
+
Attachmate, [Quick3270](http://www.dn-computing.com/Quick3270.htm) by DN-Computing,
|
7
|
+
[Rocket BlueZone](https://www.rocketsoftware.com/products/rocket-bluezonepassport-terminal-emulator/rocket-bluezone-terminal-emulation),
|
8
|
+
[Virtel Web Access](http://www.virtelweb.com/solutions/3270-terminal-emulation.html),
|
7
9
|
and [X3270](http://x3270.bgp.nu/).
|
8
|
-
The first
|
10
|
+
The first four are commercial products and need to be purchased.
|
9
11
|
X3270 is open source. Support for other
|
10
12
|
emulators will be added as time permits.
|
11
13
|
|
@@ -29,7 +31,7 @@ Or install it yourself as:
|
|
29
31
|
|
30
32
|
## Usage
|
31
33
|
|
32
|
-
You can create classes that are similar to page-object classes.
|
34
|
+
You can create classes that are similar to page-object classes. In these classes you can define
|
33
35
|
the various fields that you wish to interact with on the screen.
|
34
36
|
|
35
37
|
class MainframeScreen
|
@@ -90,9 +92,9 @@ or you can use the version of `on` that takes a block like this:
|
|
90
92
|
screen.password = 'the_password'
|
91
93
|
end
|
92
94
|
|
93
|
-
There is also a way to pass in a `Hash` and have it populate an entire screen.
|
95
|
+
There is also a way to pass in a `Hash` and have it populate an entire screen. Just simply
|
94
96
|
ensure the key for an entry in the `Hash` matches the name you gave a text field and it will
|
95
|
-
find and set the value.
|
97
|
+
find and set the value. This allows the gem to easily work with the DataMagic gem.
|
96
98
|
|
97
99
|
# given this Hash
|
98
100
|
my_data = { userid: 'the_id', password: 'the_password' }
|
@@ -100,6 +102,19 @@ find and set the value. This allows the gem to easily work with the DataMagic g
|
|
100
102
|
# you can simply call this method
|
101
103
|
on(MainframeScreen).populate_screen_with my_data
|
102
104
|
|
105
|
+
## Troubleshooting
|
106
|
+
|
107
|
+
If you plan to use the BlueZone emulator support, make sure the version of BlueZone
|
108
|
+
that you install matches the architecture of the Ruby version you are using.
|
109
|
+
|
110
|
+
_ex: x86 for both or 64 bit for both_
|
111
|
+
|
112
|
+
Also, if you intend to take screenshots with BlueZone, Extra, or Quick emulators
|
113
|
+
you will need to use the x86 version of Ruby as the 64 bit version of
|
114
|
+
[win32screenshot](https://rubygems.org/gems/win32screenshot/) depends on
|
115
|
+
[rautomation](https://rubygems.org/gems/rautomation/) which
|
116
|
+
[does not support 64 bit installs](https://github.com/jarmo/RAutomation/issues/68)
|
117
|
+
at this time.
|
103
118
|
|
104
119
|
## Contributing
|
105
120
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'te3270/emulators/bluezone'
|
1
2
|
require 'te3270/emulators/extra'
|
2
3
|
require 'te3270/emulators/quick3270'
|
3
4
|
require 'te3270/emulators/x3270'
|
@@ -11,6 +12,7 @@ module TE3270
|
|
11
12
|
module EmulatorFactory
|
12
13
|
|
13
14
|
EMULATORS = {
|
15
|
+
bluezone: TE3270::Emulators::BlueZone,
|
14
16
|
extra: TE3270::Emulators::Extra,
|
15
17
|
quick3270: TE3270::Emulators::Quick3270,
|
16
18
|
x3270: TE3270::Emulators::X3270,
|
@@ -22,4 +24,4 @@ module TE3270
|
|
22
24
|
end
|
23
25
|
|
24
26
|
end
|
25
|
-
end
|
27
|
+
end
|
@@ -0,0 +1,282 @@
|
|
1
|
+
module TE3270
|
2
|
+
module Emulators
|
3
|
+
class BlueZoneError < StandardError; end
|
4
|
+
class InvalidVisibleStateError < BlueZoneError; end
|
5
|
+
class InvalidWindowStateError < BlueZoneError; end
|
6
|
+
class InvalidWriteMethodError < BlueZoneError; end
|
7
|
+
class SessionFileMissingError < BlueZoneError; end
|
8
|
+
class Win32OleRuntimeError < BlueZoneError; end
|
9
|
+
|
10
|
+
#
|
11
|
+
# This class has the code necessary to communicate with the terminal emulator called Rocket BlueZone.
|
12
|
+
# You can use this emulator by providing the +:bluezone+ parameter to the constructor of your screen
|
13
|
+
# object or by passing the same value to the +emulator_for+ method on the +TE3270+ module.
|
14
|
+
#
|
15
|
+
class BlueZone
|
16
|
+
attr_writer :connect_retry_timeout,
|
17
|
+
:max_column_length,
|
18
|
+
:max_wait_time,
|
19
|
+
:session_id,
|
20
|
+
:session_file,
|
21
|
+
:timeout,
|
22
|
+
:write_errors_to_ignore,
|
23
|
+
:write_method
|
24
|
+
|
25
|
+
#
|
26
|
+
# Initialize the emulator with defaults. This also loads libraries used
|
27
|
+
# to take screenshots on supported platforms.
|
28
|
+
#
|
29
|
+
def initialize
|
30
|
+
@connect_retry_timeout = 30
|
31
|
+
@max_column_length = 80
|
32
|
+
@max_wait_time = 100
|
33
|
+
@session_file = nil
|
34
|
+
@session_id = 1
|
35
|
+
@timeout = 10
|
36
|
+
@visible = true
|
37
|
+
@window_state = :normal
|
38
|
+
@write_errors_to_ignore = [5, 6]
|
39
|
+
@write_method = :full_string
|
40
|
+
|
41
|
+
if jruby?
|
42
|
+
require 'jruby-win32ole'
|
43
|
+
require 'java'
|
44
|
+
include_class 'java.awt.Dimension'
|
45
|
+
include_class 'java.awt.Rectangle'
|
46
|
+
include_class 'java.awt.Robot'
|
47
|
+
include_class 'java.awt.Toolkit'
|
48
|
+
include_class 'java.awt.event.InputEvent'
|
49
|
+
include_class 'java.awt.image.BufferedImage'
|
50
|
+
include_class 'javax.imageio.ImageIO'
|
51
|
+
else
|
52
|
+
require 'win32ole'
|
53
|
+
require 'win32/screenshot'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Creates a method to connect to BlueZone. This method expects a block in which certain
|
59
|
+
# platform specific values can be set. BlueZone can take the following parameters.
|
60
|
+
#
|
61
|
+
# * connect_retry_timeout - number of seconds to retry connecting to a session. Defaults to +30+.
|
62
|
+
# * max_column_length - number of columns in a terminal row. Defaults to +80+.
|
63
|
+
# * max_wait_time - number of milliseconds to wait before resuming script execution after sending keys from host. Defaults to +100+.
|
64
|
+
# * session_file - this value is required and should be the filename of the session.
|
65
|
+
# * session_id - numeric identifier for type of session to connect to. From BlueZone's docs: +1 for S1: 2 for S2; 3 for S3; etc.+ Defaults to +1+.
|
66
|
+
# * timeout - numeric number of seconds till system calls timeout. Defaults to +10+.
|
67
|
+
# * visible - determines if the emulator is visible or not. If not set it will default to +true+.
|
68
|
+
# * window_state - determines the state of the session window. Valid values are +:minimized+,
|
69
|
+
# +:normal+, and +:maximized+. If not set it will default to +:normal+.
|
70
|
+
# * write_errors_to_ignore - array of error codes to ignore during "char" write method. Defaults to +[5, 6]+.
|
71
|
+
# * write_method - write strings to the terminal all at once or one character at a time Valid values are +:full_string+,
|
72
|
+
# and +:char+. Default is +:full_string+.
|
73
|
+
#
|
74
|
+
# @example Example calling screen object constructor with a block
|
75
|
+
# screen_object = MyScreenObject.new(:bluezone)
|
76
|
+
# screen_object.connect do |emulator|
|
77
|
+
# emulator.session_file = 'path_to_session_file'
|
78
|
+
# emulator.visible = true
|
79
|
+
# emulator.window_state = :maximized
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
def connect
|
83
|
+
start_bluezone_system
|
84
|
+
yield self if block_given?
|
85
|
+
raise InvalidWriteMethodError unless [:char, :full_string].include?(@write_method)
|
86
|
+
raise SessionFileMissingError if @session_file.nil?
|
87
|
+
|
88
|
+
result = system.OpenSession(SESSION_TYPE[:Mainframe], @session_id, @session_file, @timeout, 1)
|
89
|
+
raise BlueZoneError, "Error opening session: #{result}; #{@session_file}" if result != 0
|
90
|
+
|
91
|
+
result = system.Connect('!', @connect_retry_timeout)
|
92
|
+
raise BlueZoneError, "Error connecting to session: #{result}" if result != 0
|
93
|
+
end
|
94
|
+
|
95
|
+
#
|
96
|
+
# Disconnects the BlueZone connection
|
97
|
+
#
|
98
|
+
def disconnect
|
99
|
+
system.CloseSession(SESSION_TYPE[:Mainframe], @session_id)
|
100
|
+
end
|
101
|
+
|
102
|
+
#
|
103
|
+
# Extracts text of specified length from a start point.
|
104
|
+
#
|
105
|
+
# @param [Fixnum] row the x coordinate of location on the screen.
|
106
|
+
# @param [Fixnum] column the y coordinate of location on the screen.
|
107
|
+
# @param [Fixnum] length the length of string to extract
|
108
|
+
# @return [String]
|
109
|
+
#
|
110
|
+
def get_string(row, column, length)
|
111
|
+
system.PSGetText(length, ((row - 1) * @max_column_length) + column)
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
# Puts string at the coordinates specified.
|
116
|
+
#
|
117
|
+
# @param [String|Fixnum] input the value to set; value is cast to string
|
118
|
+
# @param [Fixnum] row the x coordinate of the location on the screen.
|
119
|
+
# @param [Fixnum] column the y coordinate of the location on the screen.
|
120
|
+
#
|
121
|
+
def put_string(input, row, column)
|
122
|
+
input_as_string = input.to_s
|
123
|
+
|
124
|
+
if @write_method == :full_string
|
125
|
+
system.WriteScreen(input_as_string, row, column)
|
126
|
+
system.WaitReady(@timeout, @max_wait_time)
|
127
|
+
elsif @write_method == :char
|
128
|
+
input_as_string.chars.each_with_index do |char, index|
|
129
|
+
position = ((row - 1) * @max_column_length) + column + index
|
130
|
+
position_row = (position / @max_column_length.to_f).ceil
|
131
|
+
position_col = position % @max_column_length
|
132
|
+
position_col = position_col == 0 ? @max_column_length : position_col
|
133
|
+
result = system.WriteScreen(char, position_row, position_col)
|
134
|
+
break unless ([0] + @write_errors_to_ignore).include?(result)
|
135
|
+
system.WaitReady(@timeout, @max_wait_time)
|
136
|
+
end
|
137
|
+
else
|
138
|
+
raise InvalidWriteMethodError, @write_method
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
#
|
143
|
+
# Creates a method to take screenshot of the active screen. If you have set the +:visible+
|
144
|
+
# property to false it will be made visible prior to taking the screenshot and then changed
|
145
|
+
# to invisible after.
|
146
|
+
#
|
147
|
+
# @param [String] filename the path and name of the screenshot file to be saved
|
148
|
+
#
|
149
|
+
def screenshot(filename)
|
150
|
+
File.delete(filename) if File.exists?(filename)
|
151
|
+
original_visibility = @visible
|
152
|
+
self.visible = true
|
153
|
+
|
154
|
+
if jruby?
|
155
|
+
toolkit = Toolkit::getDefaultToolkit()
|
156
|
+
screen_size = toolkit.getScreenSize()
|
157
|
+
rect = Rectangle.new(screen_size)
|
158
|
+
robot = Robot.new
|
159
|
+
image = robot.createScreenCapture(rect)
|
160
|
+
f = java::io::File.new(filename)
|
161
|
+
ImageIO::write(image, "png", f)
|
162
|
+
else
|
163
|
+
hwnd = system.WindowHandle
|
164
|
+
Win32::Screenshot::Take.of(:window, hwnd: hwnd).write(filename)
|
165
|
+
end
|
166
|
+
|
167
|
+
self.visible = false unless original_visibility
|
168
|
+
end
|
169
|
+
|
170
|
+
#
|
171
|
+
# Sends keystrokes to the host, including function keys.
|
172
|
+
#
|
173
|
+
# @param [String] keys keystokes up to 255 in length
|
174
|
+
#
|
175
|
+
def send_keys(keys)
|
176
|
+
system.SendKey(keys)
|
177
|
+
system.WaitReady(@timeout, @max_wait_time)
|
178
|
+
end
|
179
|
+
|
180
|
+
#
|
181
|
+
# Returns the text of the active screen
|
182
|
+
#
|
183
|
+
# @return [String]
|
184
|
+
#
|
185
|
+
def text
|
186
|
+
system.PSText
|
187
|
+
end
|
188
|
+
|
189
|
+
#
|
190
|
+
# Sets the currently connected windows visibility.
|
191
|
+
#
|
192
|
+
# @param [Bool] value
|
193
|
+
#
|
194
|
+
def visible=(value)
|
195
|
+
raise InvalidVisibleStateError, value unless [false, true].include?(value)
|
196
|
+
|
197
|
+
@visible = value
|
198
|
+
window = system.Window
|
199
|
+
window.Visible = value
|
200
|
+
end
|
201
|
+
|
202
|
+
#
|
203
|
+
# Waits for the host to not send data for a specified number of seconds
|
204
|
+
#
|
205
|
+
# @param [Fixnum] seconds the maximum number of seconds to wait
|
206
|
+
#
|
207
|
+
def wait_for_host(seconds)
|
208
|
+
system.Wait(seconds)
|
209
|
+
end
|
210
|
+
|
211
|
+
#
|
212
|
+
# Wait for the string to appear at the specified location
|
213
|
+
#
|
214
|
+
# @param [String] str the string to wait for
|
215
|
+
# @param [Fixnum] row the x coordinate of location
|
216
|
+
# @param [Fixnum] column the y coordinate of location
|
217
|
+
#
|
218
|
+
def wait_for_string(str, row, column)
|
219
|
+
system.WaitForText(str, row, column, @timeout)
|
220
|
+
end
|
221
|
+
|
222
|
+
#
|
223
|
+
# Waits until the cursor is at the specified location.
|
224
|
+
#
|
225
|
+
# @param [Fixnum] row the x coordinate of the location
|
226
|
+
# @param [Fixnum] column the y coordinate of the location
|
227
|
+
#
|
228
|
+
def wait_until_cursor_at(row, column)
|
229
|
+
system.WaitCursor(@timeout, row, column, 3)
|
230
|
+
end
|
231
|
+
|
232
|
+
#
|
233
|
+
# Sets the currently connected windows state.
|
234
|
+
#
|
235
|
+
# @param [Symbol] state
|
236
|
+
#
|
237
|
+
def window_state=(state)
|
238
|
+
raise InvalidWindowStateError, state unless WINDOW_STATE.keys.include?(state)
|
239
|
+
|
240
|
+
@window_state = state
|
241
|
+
system.WindowState = WINDOW_STATE[state]
|
242
|
+
end
|
243
|
+
|
244
|
+
private
|
245
|
+
|
246
|
+
SESSION_TYPE = {
|
247
|
+
Mainframe: 0,
|
248
|
+
iSeries: 1,
|
249
|
+
VT: 2,
|
250
|
+
UTS: 3,
|
251
|
+
T27: 4,
|
252
|
+
'6530': 6
|
253
|
+
}.freeze
|
254
|
+
|
255
|
+
WINDOW_STATE = {
|
256
|
+
maximized: 2,
|
257
|
+
minimized: 1,
|
258
|
+
normal: 0
|
259
|
+
}.freeze
|
260
|
+
|
261
|
+
attr_reader :system
|
262
|
+
|
263
|
+
def jruby?
|
264
|
+
RUBY_PLATFORM == 'java'
|
265
|
+
end
|
266
|
+
|
267
|
+
def start_bluezone_system
|
268
|
+
begin
|
269
|
+
@system = WIN32OLE.new('BZWhll.WhllObj')
|
270
|
+
|
271
|
+
# Default window state.
|
272
|
+
# Once session is "connected" these will be applied unless overwritten.
|
273
|
+
self.window_state = @window_state
|
274
|
+
self.visible = @visible
|
275
|
+
rescue Win32OleRuntimeError => exception
|
276
|
+
$stderr.puts exception
|
277
|
+
raise MissingOleRuntimeError, 'Unable to find BZWhll.WhllObj OLE runtime. Did you install the same BlueZone Desktop architecture as your Ruby runtime? ex: x86 vs 64 bit'
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
data/lib/te3270/version.rb
CHANGED
@@ -0,0 +1,330 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TE3270::Emulators::BlueZone do
|
4
|
+
|
5
|
+
unless Gem.win_platform?
|
6
|
+
class WIN32OLE
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:bluezone) do
|
11
|
+
allow_any_instance_of(TE3270::Emulators::BlueZone).to receive(:require) unless Gem.win_platform?
|
12
|
+
TE3270::Emulators::BlueZone.new
|
13
|
+
end
|
14
|
+
|
15
|
+
before(:each) do
|
16
|
+
allow(WIN32OLE).to receive(:new).and_return bluezone_system
|
17
|
+
bluezone.instance_variable_set(:@session_file, 'the_file')
|
18
|
+
allow(File).to receive(:exists).and_return false
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
describe "global behaviors" do
|
23
|
+
it 'should start a new terminal' do
|
24
|
+
expect(WIN32OLE).to receive(:new).and_return(bluezone_system)
|
25
|
+
bluezone.connect
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should open a session' do
|
29
|
+
expect(bluezone_system).to receive(:OpenSession).and_return(0)
|
30
|
+
bluezone.connect
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should call a block allowing the session file to be set' do
|
34
|
+
expect(bluezone_system).to receive(:OpenSession).with(0, 1, 'blah.edp', 10, 1).and_return(0)
|
35
|
+
bluezone.connect do |platform|
|
36
|
+
platform.session_file = 'blah.edp'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should call a block with custom session number to be set' do
|
41
|
+
expect(bluezone_system).to receive(:OpenSession).with(0, 2, 'blah.edp', 10, 1).and_return(0)
|
42
|
+
bluezone.connect do |platform|
|
43
|
+
platform.session_id = 2
|
44
|
+
platform.session_file = 'blah.edp'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should raise an error when the session file is not set' do
|
49
|
+
bluezone.instance_variable_set(:@session_file, nil)
|
50
|
+
expect { bluezone.connect }.to raise_error(TE3270::Emulators::SessionFileMissingError)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should take the visible value from a block' do
|
54
|
+
expect(bluezone_window).to receive(:Visible=).with(false)
|
55
|
+
bluezone.connect do |platform|
|
56
|
+
platform.visible = false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should default to visible when not specified' do
|
61
|
+
expect(bluezone_window).to receive(:Visible=).with(true)
|
62
|
+
bluezone.connect
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should take the window state value from the block' do
|
66
|
+
expect(bluezone_system).to receive(:WindowState=).with(2)
|
67
|
+
bluezone.connect do |platform|
|
68
|
+
platform.window_state = :maximized
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should default to window state normal when not specified' do
|
73
|
+
expect(bluezone_system).to receive(:WindowState=).with(0)
|
74
|
+
bluezone.connect
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should get the connection for the active session' do
|
78
|
+
expect(bluezone_system).to receive(:Connect).with("!", 30).and_return(0)
|
79
|
+
bluezone.connect
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should get the connection with custom connection retry timeout for the active session' do
|
83
|
+
expect(bluezone_system).to receive(:Connect).with("!", 0).and_return(0)
|
84
|
+
bluezone.connect_retry_timeout = 0
|
85
|
+
bluezone.connect
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should disconnect from a session' do
|
89
|
+
expect(bluezone_system).to receive(:CloseSession).with(0, 1)
|
90
|
+
bluezone.connect
|
91
|
+
bluezone.disconnect
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should disconnect from a custom session id' do
|
95
|
+
expect(bluezone_system).to receive(:CloseSession).with(0, 2)
|
96
|
+
bluezone.connect do |platform|
|
97
|
+
platform.session_id = 2
|
98
|
+
end
|
99
|
+
bluezone.disconnect
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'should set write_method to :full_string by default' do
|
103
|
+
expect(bluezone.instance_variable_get(:@write_method)).to eq(:full_string)
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should allow setting write_method to :char' do
|
107
|
+
bluezone.connect do |platform|
|
108
|
+
platform.write_method = :char
|
109
|
+
end
|
110
|
+
expect(bluezone.instance_variable_get(:@write_method)).to eq(:char)
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'should raise InvalidWriteMethodError with invalid write_method' do
|
114
|
+
bluezone.instance_variable_set(:@write_method, nil)
|
115
|
+
expect { bluezone.connect }.to raise_error(TE3270::Emulators::InvalidWriteMethodError)
|
116
|
+
|
117
|
+
bluezone.instance_variable_set(:@write_method, :invalid)
|
118
|
+
expect { bluezone.connect }.to raise_error(TE3270::Emulators::InvalidWriteMethodError)
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should set write_errors_to_ignore to [5, 6] by default' do
|
122
|
+
bluezone = TE3270::Emulators::BlueZone.new
|
123
|
+
expect(bluezone.instance_variable_get(:@write_errors_to_ignore)).to eq([5, 6])
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should allow setting write_errors_to_ignore to array of integers' do
|
127
|
+
bluezone.connect do |platform|
|
128
|
+
platform.write_errors_to_ignore = [6, 7, 8]
|
129
|
+
end
|
130
|
+
expect(bluezone.instance_variable_get(:@write_errors_to_ignore)).to eq([6, 7, 8])
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "interacting with text fields" do
|
135
|
+
it 'should get the value from the screen' do
|
136
|
+
expect(bluezone_system).to receive(:PSGetText).with(10, 1532).and_return('blah')
|
137
|
+
bluezone.connect
|
138
|
+
expect(bluezone.get_string(20, 12, 10)).to eql 'blah'
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should get the value from the screen if columns were set to 100' do
|
142
|
+
expect(bluezone_system).to receive(:PSGetText).with(10, 1912).and_return('blah')
|
143
|
+
bluezone.connect do |platform|
|
144
|
+
platform.max_column_length = 100
|
145
|
+
end
|
146
|
+
expect(bluezone.get_string(20, 12, 10)).to eql 'blah'
|
147
|
+
end
|
148
|
+
|
149
|
+
describe "full_string write method" do
|
150
|
+
before(:each) do
|
151
|
+
bluezone.connect do |platform|
|
152
|
+
platform.write_method = :full_string
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'should put the value on the screen' do
|
157
|
+
expect(bluezone_system).to receive(:WriteScreen).with('blah', 1, 2)
|
158
|
+
expect(bluezone_system).to receive(:WaitReady).with(10, 100).once
|
159
|
+
bluezone.connect
|
160
|
+
bluezone.put_string('blah', 1, 2)
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'should put the value on the screen with reduced wait delay if overridden' do
|
164
|
+
expect(bluezone_system).to receive(:WriteScreen).with('blah', 1, 2)
|
165
|
+
expect(bluezone_system).to receive(:WaitReady).with(10, 111).once
|
166
|
+
bluezone.connect
|
167
|
+
bluezone.max_wait_time = 111
|
168
|
+
bluezone.put_string('blah', 1, 2)
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'should cast the value to a string before printing to the screen' do
|
172
|
+
expect(bluezone_system).to receive(:WriteScreen).with('1234', 1, 2)
|
173
|
+
expect(bluezone_system).to receive(:WaitReady).with(10, 100).once
|
174
|
+
bluezone.connect
|
175
|
+
bluezone.put_string(1234, 1, 2)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe "char write method" do
|
180
|
+
before(:each) do
|
181
|
+
bluezone.connect do |platform|
|
182
|
+
platform.write_method = :char
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'should put the value on the screen' do
|
187
|
+
expect(bluezone_system).to receive(:WriteScreen).with('b', 1, 2).once.and_return(0)
|
188
|
+
expect(bluezone_system).to receive(:WriteScreen).with('l', 1, 3).once.and_return(0)
|
189
|
+
expect(bluezone_system).to receive(:WriteScreen).with('a', 1, 4).once.and_return(0)
|
190
|
+
expect(bluezone_system).to receive(:WriteScreen).with('h', 1, 5).once.and_return(0)
|
191
|
+
expect(bluezone_system).to receive(:WaitReady).with(10, 100).exactly(4).times
|
192
|
+
bluezone.connect
|
193
|
+
bluezone.put_string('blah', 1, 2)
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'should put the value on the screen with reduced wait delay if overridden' do
|
197
|
+
expect(bluezone_system).to receive(:WriteScreen).with('b', 1, 2).once.and_return(0)
|
198
|
+
expect(bluezone_system).to receive(:WriteScreen).with('l', 1, 3).once.and_return(0)
|
199
|
+
expect(bluezone_system).to receive(:WriteScreen).with('a', 1, 4).once.and_return(0)
|
200
|
+
expect(bluezone_system).to receive(:WriteScreen).with('h', 1, 5).once.and_return(0)
|
201
|
+
expect(bluezone_system).to receive(:WaitReady).with(10, 111).exactly(4).times
|
202
|
+
bluezone.connect
|
203
|
+
bluezone.max_wait_time = 111
|
204
|
+
bluezone.put_string('blah', 1, 2)
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'should put the full string on the screen if allowed error codes returned' do
|
208
|
+
expect(bluezone_system).to receive(:WriteScreen).with('b', 1, 2).once.and_return(0)
|
209
|
+
expect(bluezone_system).to receive(:WriteScreen).with('l', 1, 3).once.and_return(6)
|
210
|
+
expect(bluezone_system).to receive(:WriteScreen).with('a', 1, 4).once.and_return(0)
|
211
|
+
expect(bluezone_system).to receive(:WriteScreen).with('h', 1, 5).once.and_return(6)
|
212
|
+
expect(bluezone_system).to receive(:WaitReady).with(10, 100).exactly(4).times
|
213
|
+
bluezone.connect
|
214
|
+
bluezone.put_string('blah', 1, 2)
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'should stop adding characters once an invalid error code is returned' do
|
218
|
+
expect(bluezone_system).to receive(:WriteScreen).with('b', 1, 2).once.and_return(4)
|
219
|
+
expect(bluezone_system).to receive(:WriteScreen).with('l', 1, 3).once.and_return(5)
|
220
|
+
expect(bluezone_system).to receive(:WriteScreen).with('a', 1, 4).once.and_return(10)
|
221
|
+
expect(bluezone_system).not_to receive(:WriteScreen).with('h', 1, 5)
|
222
|
+
expect(bluezone_system).to receive(:WaitReady).with(10, 100).exactly(2).times
|
223
|
+
bluezone.connect do |platform|
|
224
|
+
platform.write_errors_to_ignore = [4, 5, 6]
|
225
|
+
end
|
226
|
+
bluezone.put_string('blah', 1, 2)
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'should cast the value to a string before printing to the screen' do
|
230
|
+
expect(bluezone_system).to receive(:WriteScreen).with('1', 1, 2).once.and_return(0)
|
231
|
+
expect(bluezone_system).to receive(:WriteScreen).with('2', 1, 3).once.and_return(0)
|
232
|
+
expect(bluezone_system).to receive(:WriteScreen).with('3', 1, 4).once.and_return(0)
|
233
|
+
expect(bluezone_system).to receive(:WriteScreen).with('4', 1, 5).once.and_return(0)
|
234
|
+
expect(bluezone_system).to receive(:WaitReady).with(10, 100).exactly(4).times
|
235
|
+
bluezone.connect
|
236
|
+
bluezone.put_string(1234, 1, 2)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
describe "interacting with the screen" do
|
242
|
+
it 'should know how to send function keys' do
|
243
|
+
expect(bluezone_system).to receive(:SendKey).with('<Clear>')
|
244
|
+
expect(bluezone_system).to receive(:WaitReady).with(10, 100)
|
245
|
+
bluezone.connect
|
246
|
+
bluezone.send_keys(TE3270.Clear)
|
247
|
+
end
|
248
|
+
|
249
|
+
it 'should know how to send function keys with reduced wait delay if overridden' do
|
250
|
+
expect(bluezone_system).to receive(:SendKey).with('<Clear>')
|
251
|
+
expect(bluezone_system).to receive(:WaitReady).with(10, 111)
|
252
|
+
bluezone.connect
|
253
|
+
bluezone.max_wait_time = 111
|
254
|
+
bluezone.send_keys(TE3270.Clear)
|
255
|
+
end
|
256
|
+
|
257
|
+
it 'should wait for a string to appear' do
|
258
|
+
expect(bluezone_system).to receive(:WaitForText).with('The String', 3, 10, 10).and_return(0)
|
259
|
+
bluezone.connect
|
260
|
+
bluezone.wait_for_string('The String', 3, 10)
|
261
|
+
end
|
262
|
+
|
263
|
+
it 'should respect custom timeout for a string to appear' do
|
264
|
+
expect(bluezone_system).to receive(:WaitForText).with('The String', 3, 10, 24).and_return(0)
|
265
|
+
bluezone.connect
|
266
|
+
bluezone.timeout = 24
|
267
|
+
bluezone.wait_for_string('The String', 3, 10)
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'should wait for the host to be quiet' do
|
271
|
+
expect(bluezone_system).to receive(:Wait).with(4)
|
272
|
+
bluezone.connect
|
273
|
+
bluezone.wait_for_host(4)
|
274
|
+
end
|
275
|
+
|
276
|
+
it 'should wait until the cursor is at a position' do
|
277
|
+
expect(bluezone_system).to receive(:WaitCursor).with(10, 5, 8, 3).and_return(0)
|
278
|
+
bluezone.connect
|
279
|
+
bluezone.wait_until_cursor_at(5, 8)
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'should respect custom timeout while waiting until the cursor is at a position' do
|
283
|
+
expect(bluezone_system).to receive(:WaitCursor).with(24, 5, 8, 3).and_return(0)
|
284
|
+
bluezone.connect
|
285
|
+
bluezone.timeout = 24
|
286
|
+
bluezone.wait_until_cursor_at(5, 8)
|
287
|
+
end
|
288
|
+
|
289
|
+
it "should get the screen text" do
|
290
|
+
expect(bluezone_system).to receive(:PSText).and_return('blah')
|
291
|
+
bluezone.connect
|
292
|
+
expect(bluezone.text).to eql 'blah'
|
293
|
+
end
|
294
|
+
|
295
|
+
if Gem.win_platform?
|
296
|
+
it 'should take screenshots' do
|
297
|
+
take = double('Take')
|
298
|
+
expect(bluezone_system).to receive(:WindowHandle).and_return(123)
|
299
|
+
expect(Win32::Screenshot::Take).to receive(:of).with(:window, hwnd: 123).and_return(take)
|
300
|
+
expect(take).to receive(:write).with('image.png')
|
301
|
+
bluezone.connect
|
302
|
+
bluezone.screenshot('image.png')
|
303
|
+
end
|
304
|
+
|
305
|
+
it 'should make the window visible before taking a screenshot' do
|
306
|
+
take = double('Take')
|
307
|
+
expect(bluezone_system).to receive(:WindowHandle).and_return(123)
|
308
|
+
expect(Win32::Screenshot::Take).to receive(:of).with(:window, hwnd: 123).and_return(take)
|
309
|
+
expect(take).to receive(:write).with('image.png')
|
310
|
+
expect(bluezone_window).to receive(:Visible=).twice.with(true)
|
311
|
+
expect(bluezone_window).to receive(:Visible=).twice.with(false)
|
312
|
+
bluezone.connect do |emulator|
|
313
|
+
emulator.visible = false
|
314
|
+
end
|
315
|
+
bluezone.screenshot('image.png')
|
316
|
+
end
|
317
|
+
|
318
|
+
it 'should delete the file for the screenshot if it already exists' do
|
319
|
+
expect(File).to receive(:exists?).and_return(true)
|
320
|
+
expect(File).to receive(:delete)
|
321
|
+
take = double('Take')
|
322
|
+
expect(bluezone_system).to receive(:WindowHandle).and_return(123)
|
323
|
+
expect(Win32::Screenshot::Take).to receive(:of).with(:window, hwnd: 123).and_return(take)
|
324
|
+
expect(take).to receive(:write).with('image.png')
|
325
|
+
bluezone.connect
|
326
|
+
bluezone.screenshot('image.png')
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
data/spec/lib/te3270_spec.rb
CHANGED
@@ -84,13 +84,13 @@ describe TE3270 do
|
|
84
84
|
if Gem.win_platform?
|
85
85
|
it 'should accept a block when creating an emulator' do
|
86
86
|
expect(WIN32OLE).to receive(:new).and_return(extra_system)
|
87
|
-
expect(
|
87
|
+
expect(extra_system.Sessions).to receive(:Open).with('blah.edp').and_return(extra_session)
|
88
88
|
TE3270.emulator_for :extra do |emulator|
|
89
89
|
emulator.session_file = 'blah.edp'
|
90
90
|
end
|
91
91
|
end
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
it 'should allow one to disconnect using the module' do
|
95
95
|
expect(platform).to receive(:disconnect)
|
96
96
|
TE3270.disconnect(platform)
|
data/spec/spec_helper.rb
CHANGED
@@ -7,6 +7,20 @@ if Gem.win_platform?
|
|
7
7
|
require 'win32/screenshot'
|
8
8
|
end
|
9
9
|
|
10
|
+
def bluezone_system
|
11
|
+
@bluezone_system ||= double('system')
|
12
|
+
allow(@bluezone_system).to receive(:Connect).and_return(0)
|
13
|
+
allow(@bluezone_system).to receive(:OpenSession).and_return(0)
|
14
|
+
allow(@bluezone_system).to receive(:Window).and_return(bluezone_window)
|
15
|
+
allow(@bluezone_system).to receive(:WindowState=)
|
16
|
+
@bluezone_system
|
17
|
+
end
|
18
|
+
|
19
|
+
def bluezone_window
|
20
|
+
@bluezone_window ||= double('window')
|
21
|
+
allow(@bluezone_window).to receive(:Visible=)
|
22
|
+
@bluezone_window
|
23
|
+
end
|
10
24
|
|
11
25
|
def extra_system
|
12
26
|
@extra_system ||= double('system')
|
data/te3270.gemspec
CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_dependency 'watir', '~> 6.0'
|
25
25
|
spec.add_dependency 'win32screenshot' if Gem.win_platform?
|
26
26
|
|
27
|
-
spec.add_development_dependency "bundler"
|
27
|
+
spec.add_development_dependency "bundler"
|
28
28
|
spec.add_development_dependency "rake"
|
29
29
|
spec.add_development_dependency "rspec"
|
30
30
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: te3270
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeffrey S. Morgan
|
@@ -13,7 +13,7 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date:
|
16
|
+
date: 2020-03-19 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: page_navigation
|
@@ -47,16 +47,16 @@ dependencies:
|
|
47
47
|
name: bundler
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
requirements:
|
50
|
-
- - "
|
50
|
+
- - ">="
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version: '
|
52
|
+
version: '0'
|
53
53
|
type: :development
|
54
54
|
prerelease: false
|
55
55
|
version_requirements: !ruby/object:Gem::Requirement
|
56
56
|
requirements:
|
57
|
-
- - "
|
57
|
+
- - ">="
|
58
58
|
- !ruby/object:Gem::Version
|
59
|
-
version: '
|
59
|
+
version: '0'
|
60
60
|
- !ruby/object:Gem::Dependency
|
61
61
|
name: rake
|
62
62
|
requirement: !ruby/object:Gem::Requirement
|
@@ -111,6 +111,7 @@ files:
|
|
111
111
|
- lib/te3270.rb
|
112
112
|
- lib/te3270/accessors.rb
|
113
113
|
- lib/te3270/emulator_factory.rb
|
114
|
+
- lib/te3270/emulators/bluezone.rb
|
114
115
|
- lib/te3270/emulators/extra.rb
|
115
116
|
- lib/te3270/emulators/quick3270.rb
|
116
117
|
- lib/te3270/emulators/virtel.rb
|
@@ -120,6 +121,7 @@ files:
|
|
120
121
|
- lib/te3270/screen_populator.rb
|
121
122
|
- lib/te3270/version.rb
|
122
123
|
- spec/lib/te3270/accessors_spec.rb
|
124
|
+
- spec/lib/te3270/emulators/bluezone_spec.rb
|
123
125
|
- spec/lib/te3270/emulators/extra_spec.rb
|
124
126
|
- spec/lib/te3270/emulators/quick3270_spec.rb
|
125
127
|
- spec/lib/te3270/emulators/x3270_spec.rb
|
@@ -147,13 +149,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
149
|
- !ruby/object:Gem::Version
|
148
150
|
version: '0'
|
149
151
|
requirements: []
|
150
|
-
|
151
|
-
rubygems_version: 2.5.2
|
152
|
+
rubygems_version: 3.0.1
|
152
153
|
signing_key:
|
153
154
|
specification_version: 4
|
154
155
|
summary: Automates a 3270 Terminal Emulator
|
155
156
|
test_files:
|
156
157
|
- spec/lib/te3270/accessors_spec.rb
|
158
|
+
- spec/lib/te3270/emulators/bluezone_spec.rb
|
157
159
|
- spec/lib/te3270/emulators/extra_spec.rb
|
158
160
|
- spec/lib/te3270/emulators/quick3270_spec.rb
|
159
161
|
- spec/lib/te3270/emulators/x3270_spec.rb
|