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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 0b8ddf072f9f9cd64003ca654af024ad1b6fe2c6
4
- data.tar.gz: e78254e04a34431a4da5c4376c860ef06f3c75e6
2
+ SHA256:
3
+ metadata.gz: ca80832f6e8d872ddeb31fbc12a29ad613ad33ef13b191b9c6cb2f289cbca413
4
+ data.tar.gz: 36961aadfe3fcf1bf2fc569d1622c48d943aa1b2cc71df24c56cb3232d7d572b
5
5
  SHA512:
6
- metadata.gz: 478e2822e1b6777d2c353084cadd5ec2bcbef3af290972e38ff9bdb8c676260a15227670a8e878d55e8bdcc22c90ac8f387a5ae9fb30d7da83c0ac0f5afa9ca9
7
- data.tar.gz: e94556825730d4176b08d98d880437e1028aac498df571c488b94a8d79f694b8f00c8f402ce8387240ff3a498b592e5c6600ea3cc9fa9fa2be7cdcb3309867cf
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. You have to have a supported emulator installed on the
4
- machines on which you use the gem. Currently the supported emulators are
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, [Virtel Web Access](http://www.virtelweb.com/solutions/3270-terminal-emulation.html),
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 three are commercial products and need to be purchased.
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. In these classes you can define
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. Just simply
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. This allows the gem to easily work with the DataMagic gem.
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
@@ -1,3 +1,3 @@
1
1
  module TE3270
2
- VERSION = "0.8.1"
2
+ VERSION = "0.9.0"
3
3
  end
@@ -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
@@ -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(extra_session).to receive(:Open).with('blah.edp').and_return(extra_session)
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)
@@ -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')
@@ -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", "~> 1.3"
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.8.1
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: 2017-03-06 00:00:00.000000000 Z
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: '1.3'
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: '1.3'
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
- rubyforge_project:
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