te3270 0.8.1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|