cosmos 3.8.0 → 3.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/autohotkey/tools/packet_viewer.ahk +4 -0
- data/cosmos.gemspec +1 -1
- data/data/crc.txt +277 -277
- data/demo/Gemfile +2 -2
- data/demo/config/data/crc.txt +176 -176
- data/demo/config/targets/INST/cmd_tlm/_ccsds_cmd.txt +2 -2
- data/demo/config/targets/INST/cmd_tlm/inst_cmds.txt +4 -4
- data/demo/procedures/example_test.rb +4 -0
- data/install/Gemfile +1 -1
- data/install/config/data/crc.txt +112 -112
- data/lib/cosmos/config/config_parser.rb +35 -1
- data/lib/cosmos/core_ext/string.rb +21 -17
- data/lib/cosmos/core_ext/time.rb +6 -2
- data/lib/cosmos/gui/opengl/gl_viewer.rb +4 -4
- data/lib/cosmos/gui/opengl/stl_shape.rb +5 -1
- data/lib/cosmos/gui/qt.rb +0 -26
- data/lib/cosmos/io/io_multiplexer.rb +27 -45
- data/lib/cosmos/packets/packet.rb +64 -24
- data/lib/cosmos/packets/packet_config.rb +254 -54
- data/lib/cosmos/packets/packet_item.rb +39 -10
- data/lib/cosmos/packets/parsers/packet_item_parser.rb +7 -2
- data/lib/cosmos/script/commands.rb +5 -0
- data/lib/cosmos/script/scripting.rb +5 -5
- data/lib/cosmos/script/telemetry.rb +5 -0
- data/lib/cosmos/tools/cmd_tlm_server/api.rb +22 -0
- data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +38 -10
- data/lib/cosmos/tools/packet_viewer/packet_viewer.rb +48 -9
- data/lib/cosmos/tools/test_runner/test_runner.rb +76 -14
- data/lib/cosmos/tools/tlm_viewer/widgets/linegraph_widget.rb +11 -2
- data/lib/cosmos/tools/tlm_viewer/widgets/timegraph_widget.rb +15 -12
- data/lib/cosmos/top_level.rb +29 -32
- data/lib/cosmos/version.rb +4 -4
- data/spec/config/config_parser_spec.rb +8 -15
- data/spec/core_ext/socket_spec.rb +2 -2
- data/spec/core_ext/string_spec.rb +10 -0
- data/spec/core_ext/time_spec.rb +12 -4
- data/spec/io/io_multiplexer_spec.rb +11 -3
- data/spec/packets/packet_spec.rb +30 -0
- data/spec/script/commands_spec.rb +2 -1
- data/spec/script/scripting_spec.rb +22 -0
- data/spec/script/telemetry_spec.rb +2 -1
- data/spec/spec_helper.rb +2 -2
- data/spec/tools/cmd_tlm_server/router_thread_spec.rb +2 -2
- data/spec/top_level/top_level_spec.rb +4 -2
- metadata +5 -5
@@ -103,7 +103,11 @@ module Cosmos
|
|
103
103
|
@select_keyseq = Qt::KeySequence.new(tr('Ctrl+S'))
|
104
104
|
@select.shortcut = @select_keyseq
|
105
105
|
@select.statusTip = tr('Select Test Suites/Groups/Cases')
|
106
|
-
@select.connect(SIGNAL('triggered()')) { show_select}
|
106
|
+
@select.connect(SIGNAL('triggered()')) { show_select }
|
107
|
+
|
108
|
+
@file_options = Qt::Action.new(tr('O&ptions'), self)
|
109
|
+
@file_options.statusTip = tr('Application Options')
|
110
|
+
@file_options.connect(SIGNAL('triggered()')) { file_options() }
|
107
111
|
|
108
112
|
# Script Actions
|
109
113
|
@test_results_log_message = Qt::Action.new(tr('Log Message to Test Results'), self)
|
@@ -141,21 +145,23 @@ module Cosmos
|
|
141
145
|
|
142
146
|
def initialize_menus
|
143
147
|
# File Menu
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
148
|
+
file_menu = menuBar.addMenu(tr('&File'))
|
149
|
+
file_menu.addAction(@show_last)
|
150
|
+
file_menu.addAction(@select)
|
151
|
+
file_menu.addSeparator()
|
152
|
+
file_menu.addAction(@file_options)
|
153
|
+
file_menu.addSeparator()
|
154
|
+
file_menu.addAction(@exit_action)
|
149
155
|
|
150
156
|
# Script Menu
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
157
|
+
script_menu = menuBar.addMenu(tr('&Script'))
|
158
|
+
script_menu.addAction(@test_results_log_message)
|
159
|
+
script_menu.addAction(@script_log_message)
|
160
|
+
script_menu.addAction(@show_call_stack)
|
161
|
+
script_menu.addAction(@toggle_debug)
|
162
|
+
script_menu.addAction(@script_disconnect)
|
163
|
+
script_menu.addSeparator()
|
164
|
+
script_menu.addAction(@script_audit)
|
159
165
|
|
160
166
|
# Help Menu
|
161
167
|
@about_string = "Test Runner provides a framework for developing high " \
|
@@ -816,6 +822,7 @@ module Cosmos
|
|
816
822
|
Qt::DialogButtonBox::Cancel)
|
817
823
|
connect(button_box, SIGNAL('rejected()'), box, SLOT('reject()'))
|
818
824
|
connect(button_box, SIGNAL('accepted()')) do
|
825
|
+
ScriptRunnerFrame.instance = @script_runner_frame
|
819
826
|
Cosmos.module_eval("class CustomTestSuite < TestSuite; end")
|
820
827
|
tree.topLevelItems do |suite_node|
|
821
828
|
next if suite_node.checkState == Qt::Unchecked
|
@@ -880,6 +887,7 @@ module Cosmos
|
|
880
887
|
@test_runner_chooser.test_suites = @@suites
|
881
888
|
@test_runner_chooser.select_suite("CustomTestSuite")
|
882
889
|
end
|
890
|
+
ScriptRunnerFrame.instance = nil
|
883
891
|
box.accept
|
884
892
|
end
|
885
893
|
dialog_layout.addWidget(button_box)
|
@@ -890,6 +898,60 @@ module Cosmos
|
|
890
898
|
dialog.dispose
|
891
899
|
end
|
892
900
|
|
901
|
+
def file_options
|
902
|
+
dialog = Qt::Dialog.new(self)
|
903
|
+
dialog.setWindowTitle('Test Runner Options')
|
904
|
+
layout = Qt::VBoxLayout.new
|
905
|
+
|
906
|
+
form = Qt::FormLayout.new
|
907
|
+
box = Qt::DoubleSpinBox.new
|
908
|
+
box.setRange(0, 60)
|
909
|
+
box.setValue(ScriptRunnerFrame.line_delay)
|
910
|
+
form.addRow(tr("&Delay between each script line:"), box)
|
911
|
+
monitor = Qt::CheckBox.new
|
912
|
+
form.addRow(tr("&Monitor limits:"), monitor)
|
913
|
+
pause_on_red = Qt::CheckBox.new
|
914
|
+
form.addRow(tr("Pause on &red limit:"), pause_on_red)
|
915
|
+
if ScriptRunnerFrame.monitor_limits
|
916
|
+
monitor.setCheckState(Qt::Checked)
|
917
|
+
pause_on_red.setCheckState(Qt::Checked) if ScriptRunnerFrame.pause_on_red
|
918
|
+
else
|
919
|
+
pause_on_red.setEnabled(false)
|
920
|
+
end
|
921
|
+
monitor.connect(SIGNAL('stateChanged(int)')) do
|
922
|
+
if monitor.isChecked()
|
923
|
+
pause_on_red.setEnabled(true)
|
924
|
+
else
|
925
|
+
pause_on_red.setCheckState(Qt::Unchecked)
|
926
|
+
pause_on_red.setEnabled(false)
|
927
|
+
end
|
928
|
+
end
|
929
|
+
layout.addLayout(form)
|
930
|
+
|
931
|
+
divider = Qt::Frame.new
|
932
|
+
divider.setFrameStyle(Qt::Frame::HLine | Qt::Frame::Raised)
|
933
|
+
divider.setLineWidth(1)
|
934
|
+
layout.addWidget(divider)
|
935
|
+
|
936
|
+
ok = Qt::PushButton.new('Ok')
|
937
|
+
ok.setDefault(true)
|
938
|
+
ok.connect(SIGNAL('clicked(bool)')) do
|
939
|
+
ScriptRunnerFrame.line_delay = box.value
|
940
|
+
ScriptRunnerFrame.monitor_limits = (monitor.checkState == Qt::Checked)
|
941
|
+
ScriptRunnerFrame.pause_on_red = (pause_on_red.checkState == Qt::Checked)
|
942
|
+
dialog.accept
|
943
|
+
end
|
944
|
+
cancel = Qt::PushButton.new('Cancel')
|
945
|
+
cancel.connect(SIGNAL('clicked(bool)')) { dialog.reject }
|
946
|
+
button_layout = Qt::HBoxLayout.new
|
947
|
+
button_layout.addWidget(ok)
|
948
|
+
button_layout.addWidget(cancel)
|
949
|
+
layout.addLayout(button_layout)
|
950
|
+
dialog.setLayout(layout)
|
951
|
+
dialog.exec
|
952
|
+
dialog.dispose
|
953
|
+
end
|
954
|
+
|
893
955
|
def process_config(filename)
|
894
956
|
ScriptRunnerFrame.instance = @script_runner_frame
|
895
957
|
|
@@ -33,10 +33,19 @@ module Cosmos
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def value=(data)
|
36
|
-
|
36
|
+
if data.is_a?(Array)
|
37
|
+
data2 = data.map(&:to_f)
|
38
|
+
data2.reject!{|val| val.nan? or val.infinite?}
|
39
|
+
@data.push(data2).flatten!
|
40
|
+
else
|
41
|
+
data2 = data.to_f
|
42
|
+
if !data2.infinite? and !data2.nan?
|
43
|
+
@data << data2
|
44
|
+
end
|
45
|
+
end
|
37
46
|
|
38
47
|
if @data.length > @num_samples
|
39
|
-
@data = @data
|
48
|
+
@data = @data.last(@num_samples)
|
40
49
|
end
|
41
50
|
if not @data.empty?
|
42
51
|
self.clear_lines
|
@@ -66,21 +66,24 @@ module Cosmos
|
|
66
66
|
# Don't regraph old data
|
67
67
|
return if @time[-1] == t_sec
|
68
68
|
|
69
|
-
|
70
|
-
|
69
|
+
data2 = data.to_f
|
70
|
+
if data2.infinite? or data2.nan?
|
71
|
+
# create time array
|
72
|
+
@time << t_sec
|
71
73
|
|
72
|
-
|
73
|
-
|
74
|
+
# create data array and graph
|
75
|
+
@data << data2
|
74
76
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
77
|
+
# truncate data if necessary
|
78
|
+
if @data.length > @num_samples
|
79
|
+
@data = @data[1..-1]
|
80
|
+
@time = @time[1..-1]
|
81
|
+
end
|
80
82
|
|
81
|
-
|
82
|
-
|
83
|
-
|
83
|
+
self.clear_lines
|
84
|
+
self.add_line('line', @data, @time)
|
85
|
+
self.graph
|
86
|
+
end
|
84
87
|
end
|
85
88
|
|
86
89
|
end
|
data/lib/cosmos/top_level.rb
CHANGED
@@ -162,11 +162,12 @@ module Cosmos
|
|
162
162
|
# No Gemfile - so no gem based extensions
|
163
163
|
end
|
164
164
|
|
165
|
+
# Check CORE
|
165
166
|
filename = File.join(::Cosmos::PATH, 'data', name)
|
166
167
|
return filename if File.exist? filename
|
167
168
|
|
168
|
-
# Check
|
169
|
-
filename = Cosmos.path('data'
|
169
|
+
# Check relative to executing file
|
170
|
+
filename = Cosmos.path($0, 'config/data/' + name)
|
170
171
|
return filename if File.exist? filename
|
171
172
|
|
172
173
|
nil
|
@@ -304,7 +305,7 @@ module Cosmos
|
|
304
305
|
if real_lines > 0
|
305
306
|
Logger.error output
|
306
307
|
self.write_unexpected_file(output)
|
307
|
-
if defined? ::Qt and
|
308
|
+
if defined? ::Qt and $qApp
|
308
309
|
Qt.execute_in_main_thread(false) do
|
309
310
|
dialog = Qt::Dialog.new do |box|
|
310
311
|
box.setWindowTitle('Unexpected text output')
|
@@ -528,7 +529,7 @@ module Cosmos
|
|
528
529
|
Logger.level = Logger::FATAL unless try_gui
|
529
530
|
Logger.fatal "Fatal Exception! Exiting..."
|
530
531
|
Logger.fatal error.formatted
|
531
|
-
if defined? ExceptionDialog and try_gui and
|
532
|
+
if defined? ExceptionDialog and try_gui and $qApp
|
532
533
|
Qt.execute_in_main_thread(true) {||ExceptionDialog.new(nil, error, '', true, false, log_file)}
|
533
534
|
else
|
534
535
|
if $stdout != STDOUT
|
@@ -618,39 +619,35 @@ module Cosmos
|
|
618
619
|
# @param filename [String] Name of the file to open in the editor
|
619
620
|
def self.open_in_text_editor(filename)
|
620
621
|
if filename
|
621
|
-
if
|
622
|
-
|
623
|
-
self.run_process("cmd /c \"start wordpad \"#{filename.gsub('/','\\')}\"\"")
|
624
|
-
else
|
625
|
-
self.run_process("cmd /c \"start \"\" \"#{filename.gsub('/','\\')}\"\"")
|
626
|
-
end
|
627
|
-
elsif Kernel.is_mac?
|
628
|
-
self.run_process("open -a TextEdit \"#{filename}\"")
|
622
|
+
if ENV['COSMOS_TEXT']
|
623
|
+
self.run_process("#{ENV['COSMOS_TEXT']} \"#{filename}\"")
|
629
624
|
else
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
editor = ENV['EDITOR']
|
634
|
-
editor = 'vi' unless editor
|
635
|
-
which_xterm = `which xterm 2>&1`.chomp
|
636
|
-
if which_xterm =~ /Command not found/i or which_xterm =~ /no .* in/i
|
637
|
-
# No xterm
|
638
|
-
which_gnome_terminal = `which gnome-terminal 2>&1`.chomp
|
639
|
-
if which_gnome_terminal =~ /Command not found/i or which_gnome_terminal =~ /no .* in/i
|
640
|
-
# No gnome-terminal - Do nothing
|
641
|
-
else
|
642
|
-
# Have gnome-terminal
|
643
|
-
system_call = "gnome-terminal -e #{editor} \"#{filename}\""
|
644
|
-
end
|
625
|
+
if Kernel.is_windows?
|
626
|
+
if File.extname(filename).to_s.downcase == '.csv'
|
627
|
+
self.run_process("cmd /c \"start wordpad \"#{filename.gsub('/','\\')}\"\"")
|
645
628
|
else
|
646
|
-
|
647
|
-
system_call = "xterm -e #{editor} \"#{filename}\""
|
629
|
+
self.run_process("cmd /c \"start \"\" \"#{filename.gsub('/','\\')}\"\"")
|
648
630
|
end
|
631
|
+
elsif Kernel.is_mac?
|
632
|
+
self.run_process("open -a TextEdit \"#{filename}\"")
|
649
633
|
else
|
650
|
-
|
651
|
-
|
634
|
+
which_gedit = `which gedit 2>&1`.chomp
|
635
|
+
if which_gedit.to_s.strip == "" or which_gedit =~ /Command not found/i or which_gedit =~ /no .* in/i
|
636
|
+
# No gedit
|
637
|
+
['xterm', 'gnome-terminal', 'urxvt', 'rxvt'].each do |terminal|
|
638
|
+
which_terminal = `which #{terminal} 2>&1`.chomp
|
639
|
+
next if which_terminal.to_s.strip == "" or which_terminal =~ /Command not found/i or which_terminal =~ /no .* in/i
|
640
|
+
editor = ENV['VISUAL']
|
641
|
+
editor = ENV['EDITOR'] unless editor
|
642
|
+
editor = 'vi' unless editor
|
643
|
+
self.run_process("#{terminal} -e \"#{editor} '#{filename}'\"")
|
644
|
+
break
|
645
|
+
end
|
646
|
+
else
|
647
|
+
# Have gedit
|
648
|
+
self.run_process("gedit \"#{filename}\"")
|
649
|
+
end
|
652
650
|
end
|
653
|
-
self.run_process(system_call)
|
654
651
|
end
|
655
652
|
end
|
656
653
|
end
|
data/lib/cosmos/version.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
2
|
|
3
|
-
COSMOS_VERSION = '3.8.
|
3
|
+
COSMOS_VERSION = '3.8.1'
|
4
4
|
module Cosmos
|
5
5
|
module Version
|
6
6
|
MAJOR = '3'
|
7
7
|
MINOR = '8'
|
8
|
-
PATCH = '
|
9
|
-
BUILD = '
|
8
|
+
PATCH = '1'
|
9
|
+
BUILD = 'fa125f2a38e0aa28f6d3000a80ea5167115172d7'
|
10
10
|
end
|
11
|
-
VERSION = '3.8.
|
11
|
+
VERSION = '3.8.1'
|
12
12
|
end
|
@@ -221,11 +221,6 @@ module Cosmos
|
|
221
221
|
expect(ConfigParser.handle_nil("HI")).to eql "HI"
|
222
222
|
expect(ConfigParser.handle_nil(5.0)).to eql 5.0
|
223
223
|
end
|
224
|
-
|
225
|
-
#it "should complain if it can't convert" do
|
226
|
-
# expect { ConfigParser.handle_nil(0) }.to raise_error(ArgumentError, "Value is not nil: 0")
|
227
|
-
# expect { ConfigParser.handle_nil(false) }.to raise_error(ArgumentError, "Value is not nil: false")
|
228
|
-
#end
|
229
224
|
end
|
230
225
|
|
231
226
|
describe "self.handle_true_false" do
|
@@ -245,11 +240,6 @@ module Cosmos
|
|
245
240
|
expect(ConfigParser.handle_true_false("HI")).to eql "HI"
|
246
241
|
expect(ConfigParser.handle_true_false(5.0)).to eql 5.0
|
247
242
|
end
|
248
|
-
|
249
|
-
#it "should complain if it can't convert" do
|
250
|
-
# expect { ConfigParser.handle_true_false(0) }.to raise_error(ArgumentError, "Value neither true or false: 0")
|
251
|
-
# expect { ConfigParser.handle_true_false(nil) }.to raise_error(ArgumentError, "Value neither true or false: ")
|
252
|
-
#end
|
253
243
|
end
|
254
244
|
|
255
245
|
describe "self.handle_true_false_nil" do
|
@@ -281,15 +271,18 @@ module Cosmos
|
|
281
271
|
expect(ConfigParser.handle_true_false("HI")).to eql "HI"
|
282
272
|
expect(ConfigParser.handle_true_false(5.0)).to eql 5.0
|
283
273
|
end
|
284
|
-
|
285
|
-
#it "should complain if it can't convert" do
|
286
|
-
# expect { ConfigParser.handle_true_false_nil(0) }.to raise_error(ArgumentError, "Value neither true, false, or nil: 0")
|
287
|
-
# expect { ConfigParser.handle_true_false_nil(1) }.to raise_error(ArgumentError, "Value neither true, false, or nil: 1")
|
288
|
-
#end
|
289
274
|
end
|
290
275
|
|
291
276
|
describe "self.handle_defined_constants" do
|
292
277
|
it "converts string constants to numbers" do
|
278
|
+
(1..64).each do |val|
|
279
|
+
# Unsigned
|
280
|
+
expect(ConfigParser.handle_defined_constants("MIN", :UINT, val)).to eql 0
|
281
|
+
expect(ConfigParser.handle_defined_constants("MAX", :UINT, val)).to eql (2**val - 1)
|
282
|
+
# Signed
|
283
|
+
expect(ConfigParser.handle_defined_constants("MIN", :INT, val)).to eql -((2**val) / 2)
|
284
|
+
expect(ConfigParser.handle_defined_constants("MAX", :INT, val)).to eql ((2**val) / 2 - 1)
|
285
|
+
end
|
293
286
|
[8,16,32,64].each do |val|
|
294
287
|
# Unsigned
|
295
288
|
expect(ConfigParser.handle_defined_constants("MIN_UINT#{val}")).to eql 0
|
@@ -25,8 +25,8 @@ describe Socket do
|
|
25
25
|
|
26
26
|
describe "lookup_hostname_from_ip" do
|
27
27
|
it "returns the hostname for the ip address" do
|
28
|
-
ipaddr = Resolv.getaddress "
|
29
|
-
expect(Socket.lookup_hostname_from_ip(ipaddr)).to match "
|
28
|
+
ipaddr = Resolv.getaddress "localhost"
|
29
|
+
expect(Socket.lookup_hostname_from_ip(ipaddr)).to match "localhost"
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
@@ -194,6 +194,16 @@ describe String do
|
|
194
194
|
it "converts an array" do
|
195
195
|
expect("[0,1,2,3]".convert_to_value).to eql [0,1,2,3]
|
196
196
|
end
|
197
|
+
|
198
|
+
it "just returns the string if something goes wrong" do
|
199
|
+
expect("[.a,2,3]".convert_to_value).to eql "[.a,2,3]"
|
200
|
+
end
|
201
|
+
|
202
|
+
it "doesn't match multiline strings" do
|
203
|
+
expect("12345\n12345".convert_to_value).to eql "12345\n12345"
|
204
|
+
expect("5.123\n5.123".convert_to_value).to eql "5.123\n5.123"
|
205
|
+
expect("[0,1,2,3]\n[0,1,2,3]".convert_to_value).to eql "[0,1,2,3]\n[0,1,2,3]"
|
206
|
+
end
|
197
207
|
end
|
198
208
|
|
199
209
|
describe "hex_to_byte_string" do
|
data/spec/core_ext/time_spec.rb
CHANGED
@@ -113,12 +113,20 @@ describe Time do
|
|
113
113
|
end
|
114
114
|
|
115
115
|
describe "formatted" do
|
116
|
-
it "formats the Time" do
|
117
|
-
expect(Time.new(2020,1,2,3,4,5.
|
116
|
+
it "formats the Time with date and fractional seconds" do
|
117
|
+
expect(Time.new(2020,1,2,3,4,5.123456).formatted(true, 6)).to eql "2020/01/02 03:04:05.123456"
|
118
118
|
end
|
119
119
|
|
120
|
-
it "formats the Time
|
121
|
-
expect(Time.new(2020,1,2,3,4,5.
|
120
|
+
it "formats the Time with date and no fractional seconds" do
|
121
|
+
expect(Time.new(2020,1,2,3,4,5.123456).formatted(true, 0)).to eql "2020/01/02 03:04:05"
|
122
|
+
end
|
123
|
+
|
124
|
+
it "formats the Time without the date and fractional seconds" do
|
125
|
+
expect(Time.new(2020,1,2,3,4,5.123456).formatted(false, 2)).to eql "03:04:05.12"
|
126
|
+
end
|
127
|
+
|
128
|
+
it "formats the Time without the date and no fractional seconds" do
|
129
|
+
expect(Time.new(2020,1,2,3,4,5.123456).formatted(false, 0)).to eql "03:04:05"
|
122
130
|
end
|
123
131
|
end
|
124
132
|
|
@@ -18,6 +18,15 @@ module Cosmos
|
|
18
18
|
@io = IoMultiplexer.new
|
19
19
|
end
|
20
20
|
|
21
|
+
describe "stream_operator" do
|
22
|
+
it "supports the << operator" do
|
23
|
+
@io.add_stream(STDOUT)
|
24
|
+
expect($stdout).to receive(:<<).with("TEST").and_return($stdout)
|
25
|
+
result = (@io << "TEST")
|
26
|
+
expect(result).to eql(@io)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
21
30
|
describe "add_stream" do
|
22
31
|
it "adds a single stream" do
|
23
32
|
@io.add_stream(STDOUT)
|
@@ -64,10 +73,10 @@ module Cosmos
|
|
64
73
|
describe "write write_nonblock" do
|
65
74
|
it "defers to the stream" do
|
66
75
|
@io.add_stream(STDOUT)
|
67
|
-
expect($stdout).to receive(:write).with("TEST")
|
76
|
+
expect($stdout).to receive(:write).with("TEST").and_return(4)
|
68
77
|
len = @io.write "TEST"
|
69
78
|
expect(len).to eql 4
|
70
|
-
expect($stdout).to receive(:write_nonblock).with("TEST")
|
79
|
+
expect($stdout).to receive(:write_nonblock).with("TEST").and_return(4)
|
71
80
|
len = @io.write_nonblock "TEST"
|
72
81
|
expect(len).to eql 4
|
73
82
|
end
|
@@ -88,7 +97,6 @@ module Cosmos
|
|
88
97
|
File.delete("unittest.txt")
|
89
98
|
end
|
90
99
|
end
|
91
|
-
|
92
100
|
end
|
93
101
|
end
|
94
102
|
|
data/spec/packets/packet_spec.rb
CHANGED
@@ -370,6 +370,36 @@ module Cosmos
|
|
370
370
|
expect(@p.read_item(i, :CONVERTED, "\x02")).to eql 1
|
371
371
|
end
|
372
372
|
|
373
|
+
it "prevents the read conversion cache from being corrupted" do
|
374
|
+
@p.append_item("item",8,:UINT)
|
375
|
+
i = @p.get_item("ITEM")
|
376
|
+
i.read_conversion = GenericConversion.new("'A String'")
|
377
|
+
i.units = "with units"
|
378
|
+
value = @p.read_item(i, :CONVERTED)
|
379
|
+
expect(value).to eql 'A String'
|
380
|
+
value << 'That got modified'
|
381
|
+
value = @p.read_item(i, :WITH_UNITS)
|
382
|
+
expect(value).to eql 'A String with units'
|
383
|
+
value << 'That got modified'
|
384
|
+
expect(@p.read_item(i, :WITH_UNITS)).to eql 'A String with units'
|
385
|
+
value = @p.read_item(i, :WITH_UNITS)
|
386
|
+
value << ' more things'
|
387
|
+
expect(@p.read_item(i, :WITH_UNITS)).to eql 'A String with units'
|
388
|
+
|
389
|
+
@p.buffer = "\x00"
|
390
|
+
i.read_conversion = GenericConversion.new("['A', 'B', 'C']")
|
391
|
+
value = @p.read_item(i, :CONVERTED)
|
392
|
+
expect(value).to eql ['A', 'B', 'C']
|
393
|
+
value << 'D'
|
394
|
+
value = @p.read_item(i, :WITH_UNITS)
|
395
|
+
expect(value).to eql ['A with units', 'B with units', 'C with units']
|
396
|
+
value << 'D'
|
397
|
+
expect(@p.read_item(i, :WITH_UNITS)).to eql ['A with units', 'B with units', 'C with units']
|
398
|
+
value = @p.read_item(i, :WITH_UNITS)
|
399
|
+
value << 'D'
|
400
|
+
expect(@p.read_item(i, :WITH_UNITS)).to eql ['A with units', 'B with units', 'C with units']
|
401
|
+
end
|
402
|
+
|
373
403
|
it "reads the CONVERTED value with states" do
|
374
404
|
@p.append_item("item",8,:UINT)
|
375
405
|
i = @p.get_item("ITEM")
|