lwes 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +339 -0
- data/ChangeLog +2 -0
- data/README +100 -0
- data/Rakefile +11 -0
- data/examples/demo.rb +36 -0
- data/examples/my_events.esf +17 -0
- data/ext/lwes/emitter.c +366 -0
- data/ext/lwes/extconf.rb +55 -0
- data/ext/lwes/lwes.c +27 -0
- data/ext/lwes/lwes_ruby.h +40 -0
- data/ext/lwes/numeric.c +207 -0
- data/ext/lwes/type_db.c +147 -0
- data/lib/lwes.rb +6 -0
- data/lib/lwes/emitter.rb +19 -0
- data/lib/lwes/struct.rb +116 -0
- data/lib/lwes/type_db.rb +24 -0
- data/lwes.gemspec +43 -0
- data/test/test_helper.rb +45 -0
- data/test/unit/test1.esf +33 -0
- data/test/unit/test2.esf +14 -0
- data/test/unit/test_emit_struct.rb +101 -0
- data/test/unit/test_emitter.rb +169 -0
- data/test/unit/test_struct.rb +207 -0
- data/test/unit/test_type_db.rb +61 -0
- metadata +84 -0
data/lib/lwes/struct.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
module LWES
|
2
|
+
class Struct
|
3
|
+
|
4
|
+
# creates a new Struct-based class, takes the following
|
5
|
+
# options hash:
|
6
|
+
#
|
7
|
+
# :db - pre-created LWES::TypeDB object
|
8
|
+
# this is required unless :file is given
|
9
|
+
# :file - pathname to the ESF file,
|
10
|
+
# this is required unless :db is given
|
11
|
+
# :class - Ruby base class name, if the ESF file only has one
|
12
|
+
# event defined (besides MetaEventInfo), then specifying
|
13
|
+
# it is optional, otherwise it is required when multiple
|
14
|
+
# events are defined in the same ESF :file given above
|
15
|
+
# :parent - parent class or module, the default is 'Object' putting
|
16
|
+
# the new class in the global namespace.
|
17
|
+
# :name - event name if it differs from the Ruby base class name
|
18
|
+
# given (or inferred) above. For DRY-ness, you are
|
19
|
+
# recommended to keep your event names and Ruby class
|
20
|
+
# names in sync and not need this option.
|
21
|
+
# :skip - Array of field names to skip from the Event defininition
|
22
|
+
# entirely, these could include fields that are only
|
23
|
+
# implemented by the Listener. This may also be a
|
24
|
+
# regular expression.
|
25
|
+
# :defaults - hash of default key -> value pairs to set at
|
26
|
+
# creation time
|
27
|
+
#
|
28
|
+
def self.new(options, &block)
|
29
|
+
db = options[:db]
|
30
|
+
db ||= begin
|
31
|
+
file = options[:file] or
|
32
|
+
raise ArgumentError, "TypeDB :db or ESF :file missing"
|
33
|
+
test ?r, file or
|
34
|
+
raise ArgumentError, "file #{file.inspect} not readable"
|
35
|
+
TypeDB.new(file)
|
36
|
+
end
|
37
|
+
dump = db.to_hash
|
38
|
+
klass = options[:class] || begin
|
39
|
+
# make it easier to deal with single event files
|
40
|
+
events = (dump.keys - [ :MetaEventInfo ])
|
41
|
+
events.size > 1 and
|
42
|
+
raise RuntimeError,
|
43
|
+
"multiple event defs available: #{events.inspect}\n" \
|
44
|
+
"pick one with :class"
|
45
|
+
events.first
|
46
|
+
end
|
47
|
+
|
48
|
+
name = options[:name] || klass
|
49
|
+
parent = options[:parent] || Object
|
50
|
+
event_def = dump[name.to_sym] or
|
51
|
+
raise RuntimeError, "#{name.inspect} not defined in #{file}"
|
52
|
+
|
53
|
+
# merge MetaEventInfo fields in
|
54
|
+
meta_event_info = dump[:MetaEventInfo]
|
55
|
+
alpha = proc { |a,b| a.first.to_s <=> b.first.to_s }
|
56
|
+
event_def = event_def.sort(&alpha)
|
57
|
+
if meta_event_info
|
58
|
+
seen = event_def.map { |(field, _)| field }
|
59
|
+
meta_event_info.sort(&alpha).each do |field_type|
|
60
|
+
seen.include?(field_type.first) or event_def << field_type
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
Array(options[:skip]).each do |x|
|
65
|
+
if Regexp === x
|
66
|
+
event_def.delete_if { |(f,_)| x =~ f.to_s }
|
67
|
+
else
|
68
|
+
if x.to_sym == :MetaEventInfo
|
69
|
+
meta_event_info.nil? and
|
70
|
+
raise RuntimeError, "MetaEventInfo not defined in #{file}"
|
71
|
+
meta_event_info.each do |(field,_)|
|
72
|
+
event_def.delete_if { |(f,_)| field == f }
|
73
|
+
end
|
74
|
+
else
|
75
|
+
event_def.delete_if { |(f,_)| f == x.to_sym }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
tmp = ::Struct.new(*(event_def.map { |(field,_)| field }))
|
81
|
+
tmp = parent.const_set(klass, tmp)
|
82
|
+
tmp.const_set :TYPE_DB, db
|
83
|
+
tmp.const_set :NAME, name.to_s
|
84
|
+
ed = tmp.const_set :EVENT_DEF, {}
|
85
|
+
event_def.each { |(field,type)| ed[field] = type }
|
86
|
+
type_list = event_def.map { |(field,type)| [ field, field.to_s, type ] }
|
87
|
+
tmp.const_set :TYPE_LIST, type_list
|
88
|
+
|
89
|
+
defaults = options[:defaults] || {}
|
90
|
+
defaults = tmp.const_set :DEFAULTS, defaults.dup
|
91
|
+
tmp.class_eval(&block) if block_given?
|
92
|
+
|
93
|
+
# define a parent-level method, eval is faster than define_method
|
94
|
+
eval <<EOS
|
95
|
+
class ::#{tmp.name}
|
96
|
+
class << self
|
97
|
+
alias _new new
|
98
|
+
undef_method :new
|
99
|
+
def new(*args)
|
100
|
+
if Hash === (init = args.first)
|
101
|
+
rv = _new()
|
102
|
+
DEFAULTS.merge(init).each_pair { |k,v| rv[k] = v }
|
103
|
+
rv
|
104
|
+
else
|
105
|
+
rv = _new(*args)
|
106
|
+
DEFAULTS.each_pair { |k,v| rv[k] ||= v }
|
107
|
+
rv
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
EOS
|
113
|
+
tmp
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/lib/lwes/type_db.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module LWES
|
2
|
+
class TypeDB
|
3
|
+
|
4
|
+
# create LWES::Struct-derived classes based on the contents
|
5
|
+
# of the TypeDB object. It is possible to place all classes
|
6
|
+
# into a namespace by specifying the :parent option to point
|
7
|
+
# to a class or module:
|
8
|
+
#
|
9
|
+
# module MyEvents; end
|
10
|
+
#
|
11
|
+
# type_db = LWES::TypeDB.new("my_events.esf")
|
12
|
+
# type_db.create_classes!(:parent => MyEvents)
|
13
|
+
#
|
14
|
+
# Assuming you had "Event1" and "Event2" defined in your "my_events.esf"
|
15
|
+
# file, then the classes MyEvents::Event1 and MyEvents::Event2 should
|
16
|
+
# now be accessible.
|
17
|
+
def create_classes!(options = {})
|
18
|
+
(to_hash.keys - [ :MetaEventInfo ]).map do |klass|
|
19
|
+
LWES::Struct.new({ :db => self, :class => klass }.merge(options))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
data/lwes.gemspec
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = %q{lwes}
|
3
|
+
s.version = "0.1.0"
|
4
|
+
s.date = Time.now
|
5
|
+
s.authors = ["Erik S. Chang", "Frank Maritato"]
|
6
|
+
s.email = %q{lwes-devel@lists.sourceforge.net}
|
7
|
+
s.summary = %q{Ruby API for the Light Weight Event System}
|
8
|
+
s.homepage = %q{http://www.lwes.org/}
|
9
|
+
s.extensions = %w(ext/lwes/extconf.rb)
|
10
|
+
s.description = %q{
|
11
|
+
The LWES Light-Weight Event System is a framework for allowing the exchange of
|
12
|
+
information from many machines to many machines in a controlled, platform
|
13
|
+
neutral, language neutral way. The exchange of information is done in a
|
14
|
+
connectless fashion using multicast or unicast UDP, and using self describing
|
15
|
+
data so that any platform or language can translate it to it's local dialect.
|
16
|
+
}.strip
|
17
|
+
s.files = %w(
|
18
|
+
COPYING
|
19
|
+
ChangeLog
|
20
|
+
README
|
21
|
+
Rakefile
|
22
|
+
examples/demo.rb
|
23
|
+
examples/my_events.esf
|
24
|
+
ext/lwes/emitter.c
|
25
|
+
ext/lwes/extconf.rb
|
26
|
+
ext/lwes/lwes.c
|
27
|
+
ext/lwes/lwes_ruby.h
|
28
|
+
ext/lwes/numeric.c
|
29
|
+
ext/lwes/type_db.c
|
30
|
+
lib/lwes.rb
|
31
|
+
lib/lwes/emitter.rb
|
32
|
+
lib/lwes/struct.rb
|
33
|
+
lib/lwes/type_db.rb
|
34
|
+
lwes.gemspec
|
35
|
+
test/test_helper.rb
|
36
|
+
test/unit/test1.esf
|
37
|
+
test/unit/test2.esf
|
38
|
+
test/unit/test_emit_struct.rb
|
39
|
+
test/unit/test_emitter.rb
|
40
|
+
test/unit/test_struct.rb
|
41
|
+
test/unit/test_type_db.rb
|
42
|
+
)
|
43
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'tempfile'
|
3
|
+
require 'test/unit'
|
4
|
+
require 'lwes'
|
5
|
+
|
6
|
+
unless defined?(LISTENER_DEFAULTS)
|
7
|
+
BEFORE_DELAY = ENV['BEFORE_DELAY'] ? ENV['BEFORE_DELAY'].to_f : 0.5
|
8
|
+
AFTER_DELAY = ENV['AFTER_DELAY'] ? ENV['AFTER_DELAY'].to_f : 0.5
|
9
|
+
LISTENER_DEFAULTS = {
|
10
|
+
:address => ENV["LWES_TEST_ADDRESS"] || "127.0.0.1",
|
11
|
+
:iface => ENV["LWES_TEST_IFACE"] || "0.0.0.0",
|
12
|
+
:port => ENV["LWES_TEST_PORT"] ? ENV["LWES_TEST_PORT"].to_i : 12345,
|
13
|
+
:ttl => 60, # nil for no ttl)
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def lwes_listener(&block)
|
18
|
+
cmd = "lwes-event-printing-listener" \
|
19
|
+
" -m #{@options[:address]}" \
|
20
|
+
" -i #{@options[:iface]}" \
|
21
|
+
" -p #{@options[:port]}"
|
22
|
+
out = Tempfile.new("out")
|
23
|
+
err = Tempfile.new("err")
|
24
|
+
$stdout.flush
|
25
|
+
$stderr.flush
|
26
|
+
pid = fork do
|
27
|
+
$stdout.reopen(out.path)
|
28
|
+
$stderr.reopen(err.path)
|
29
|
+
exec cmd
|
30
|
+
end
|
31
|
+
begin
|
32
|
+
# since everything executes asynchronously and our messaging,
|
33
|
+
# we need to ensure our listener is ready, then ensure our
|
34
|
+
# listener has printed something...
|
35
|
+
# XXX racy
|
36
|
+
sleep BEFORE_DELAY
|
37
|
+
yield
|
38
|
+
sleep AFTER_DELAY
|
39
|
+
ensure
|
40
|
+
Process.kill(:TERM, pid)
|
41
|
+
Process.waitpid2(pid)
|
42
|
+
assert_equal 0, err.size
|
43
|
+
end
|
44
|
+
out
|
45
|
+
end
|
data/test/unit/test1.esf
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# MetaEventInfo fields are allowed to be set in all other events, this
|
2
|
+
# can be though of as inheritance, in other words all other events in this
|
3
|
+
# file can have the fields defined in the MetaEventInfo
|
4
|
+
MetaEventInfo
|
5
|
+
{
|
6
|
+
ip_addr SenderIP; # sender_ip REQUIRED, CALCULATED
|
7
|
+
# ip address of the sender of the event
|
8
|
+
uint16 SenderPort; # sender_port REQUIRED, CALCULATED
|
9
|
+
# port of the sender of the event
|
10
|
+
int64 ReceiptTime; # time_received REQUIRED, CALCULATED
|
11
|
+
# time the event was received by the listener/journaller
|
12
|
+
uint16 SiteID; # receiver_id OPTIONAL, COMMAND_ARGS
|
13
|
+
# id of the listener/journaller
|
14
|
+
int16 enc; # encoding_type REQUIRED, FUNCTION_ARGS
|
15
|
+
# encoding type of strings in the event
|
16
|
+
string st; # sender_type OPTIONAL, FUNCTION_ARGS, 10
|
17
|
+
# sender type, this should be a short string which
|
18
|
+
# describes the sender type. (ie. "java", or "perl")
|
19
|
+
}
|
20
|
+
|
21
|
+
Event1
|
22
|
+
{
|
23
|
+
boolean t_bool; # test_bool OPTIONAL, CALCULATED
|
24
|
+
int16 t_int16; # test_int16 OPTIONAL, CALCULATED
|
25
|
+
uint16 t_uint16; # test_uint16 OPTIONAL, CALCULATED
|
26
|
+
int32 t_int32; # test_int32 OPTIONAL, CALCULATED
|
27
|
+
uint32 t_uint32; # test_uint32 OPTIONAL, CALCULATED
|
28
|
+
int64 t_int64; # test_int64 OPTIONAL, CALCULATED
|
29
|
+
uint64 t_uint64; # test_uint64 OPTIONAL, CALCULATED
|
30
|
+
ip_addr t_ip_addr; # test_ip_addr OPTIONAL, CALCULATED
|
31
|
+
string t_string; # test_string OPTIONAL, CALCULATED, 50
|
32
|
+
}
|
33
|
+
|
data/test/unit/test2.esf
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../test_helper"
|
2
|
+
|
3
|
+
class TestEmitStruct < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
assert_kind_of Class, self.class.const_get(:Event1)
|
7
|
+
# assert self.class.const_get(:Event1).kind_of?(Struct)
|
8
|
+
@options = LISTENER_DEFAULTS.dup
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_emit_struct_full
|
12
|
+
s = nil
|
13
|
+
out = lwes_listener do
|
14
|
+
assert_nothing_raised do
|
15
|
+
emitter = LWES::Emitter.new(@options)
|
16
|
+
s = Event1.new
|
17
|
+
s.t_bool = true
|
18
|
+
s.t_int16 = -1000
|
19
|
+
s.t_uint16 = 1000
|
20
|
+
s.t_int32 = -64444
|
21
|
+
s.t_uint32 = 64444
|
22
|
+
s.t_int64 = 10_000_000_000
|
23
|
+
s.t_uint64 = 10_000_000_000
|
24
|
+
s.t_ip_addr = '192.168.0.1'
|
25
|
+
s.t_string = "STRING"
|
26
|
+
emitter.emit(s)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
out = out.readlines
|
30
|
+
s.members.each do |m|
|
31
|
+
value = s[m.to_sym] or next
|
32
|
+
regex = /\b#{m} = #{value};/
|
33
|
+
assert_equal 1, out.grep(regex).size,
|
34
|
+
"#{regex.inspect} didn't match #{out.inspect}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_emit_from_class
|
39
|
+
opt = {
|
40
|
+
:t_bool => true,
|
41
|
+
:t_int16 => -1000,
|
42
|
+
:t_uint16 => 1000,
|
43
|
+
:t_int32 => -64444,
|
44
|
+
:t_uint32 => 64444,
|
45
|
+
:t_int64 => 10_000_000_000,
|
46
|
+
:t_uint64 => 10_000_000_000,
|
47
|
+
:t_ip_addr => '192.168.0.1',
|
48
|
+
:t_string => "STRING",
|
49
|
+
}
|
50
|
+
out = lwes_listener do
|
51
|
+
assert_nothing_raised do
|
52
|
+
emitter = LWES::Emitter.new(@options)
|
53
|
+
emitter.emit(Event1, opt)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
out = out.readlines
|
57
|
+
opt.each do |m, value|
|
58
|
+
regex = /\b#{m} = #{value};/
|
59
|
+
assert_equal 1, out.grep(regex).size,
|
60
|
+
"#{regex.inspect} didn't match #{out.inspect}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_emit_from_class_bad_type
|
65
|
+
out = lwes_listener do
|
66
|
+
e = assert_raises(TypeError) do
|
67
|
+
emitter = LWES::Emitter.new(@options)
|
68
|
+
opt = {
|
69
|
+
:t_int16 => -1000,
|
70
|
+
:t_uint16 => 1000,
|
71
|
+
:t_int32 => -64444,
|
72
|
+
:t_uint32 => 64444,
|
73
|
+
:t_int64 => 10_000_000_000,
|
74
|
+
:t_uint64 => 10_000_000_000,
|
75
|
+
:t_ip_addr => '192.168.0.1',
|
76
|
+
:t_string => true, #"STRING",
|
77
|
+
}
|
78
|
+
emitter.emit(Event1, opt)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
assert out.readlines.empty?
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_emit_alt_class_name
|
85
|
+
out = lwes_listener do
|
86
|
+
emitter = LWES::Emitter.new(@options)
|
87
|
+
emitter.emit(Event, :t_uint32 => 16384)
|
88
|
+
end
|
89
|
+
out = out.readlines
|
90
|
+
assert_match %r{^Event1\[\d+\]}, out.first
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
ESF_FILE = "#{File.dirname(__FILE__)}/test1.esf"
|
96
|
+
LWES::Struct.new(:file=>ESF_FILE,
|
97
|
+
:parent => TestEmitStruct)
|
98
|
+
LWES::Struct.new(:file=>ESF_FILE,
|
99
|
+
:parent => TestEmitStruct,
|
100
|
+
:name => "Event1",
|
101
|
+
:class => "Event")
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../test_helper"
|
2
|
+
require 'ipaddr'
|
3
|
+
|
4
|
+
class TestEmitter < Test::Unit::TestCase
|
5
|
+
def test_constants
|
6
|
+
assert_instance_of Module, LWES, "LWES is not a module"
|
7
|
+
assert_instance_of Class, LWES::Emitter, "LWES::Emitter is not a class"
|
8
|
+
end
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@options = LISTENER_DEFAULTS.dup
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_initialize
|
15
|
+
assert_instance_of LWES::Emitter, LWES::Emitter.new(@options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_initialize_with_heartbeat
|
19
|
+
heartbeat = @options.merge(:heartbeat => 30)
|
20
|
+
assert_instance_of LWES::Emitter, LWES::Emitter.new(heartbeat)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_initialize_no_ttl
|
24
|
+
no_ttl = @options.dup
|
25
|
+
no_ttl.delete(:ttl)
|
26
|
+
assert_instance_of LWES::Emitter, LWES::Emitter.new(no_ttl)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_initialize_invalid
|
30
|
+
assert_raises(TypeError) {
|
31
|
+
LWES::Emitter.new(@options.merge(:address => nil))
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_initialize_empty_options
|
36
|
+
assert_raises(TypeError) { LWES::Emitter.new({}) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_emit_invalid
|
40
|
+
emitter = LWES::Emitter.new(@options)
|
41
|
+
assert_raises(TypeError) { emitter.emit "Invalid", nil }
|
42
|
+
assert_raises(ArgumentError) { emitter.emit nil, { :hello => "world" }}
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_emit_empty_hash
|
46
|
+
emitter = LWES::Emitter.new(@options)
|
47
|
+
assert_nothing_raised { emitter.emit("Valid", Hash.new) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_emit_non_empty_hashes
|
51
|
+
emitter = LWES::Emitter.new(@options)
|
52
|
+
out = lwes_listener do
|
53
|
+
assert_nothing_raised {
|
54
|
+
emitter.emit("ASDF", { :foo => "FOO", :nr => [ :int16, 50 ] })
|
55
|
+
}
|
56
|
+
end
|
57
|
+
lines = out.readlines
|
58
|
+
assert_match %r{\AASDF\b}, lines.first
|
59
|
+
assert ! lines.grep(/foo = FOO;/).empty?
|
60
|
+
assert ! lines.grep(/nr = 50;/).empty?
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_emit_ip_addr_string
|
64
|
+
emitter = LWES::Emitter.new(@options)
|
65
|
+
event = { :string_ip => [ :ip_addr, "192.168.1.1" ] }
|
66
|
+
out = lwes_listener do
|
67
|
+
assert_nothing_raised { emitter.emit("STRING_IP", event) }
|
68
|
+
end
|
69
|
+
lines = out.readlines
|
70
|
+
assert_equal 1, lines.grep(/string_ip = 192.168.1.1/).size
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_emit_ip_addr_int
|
74
|
+
emitter = LWES::Emitter.new(@options)
|
75
|
+
event = { :int_ip => [ :ip_addr, IPAddr.new("192.168.1.1").to_i ] }
|
76
|
+
out = lwes_listener do
|
77
|
+
assert_nothing_raised { emitter.emit("INT_IP", event) }
|
78
|
+
end
|
79
|
+
lines = out.readlines
|
80
|
+
assert_equal 1, lines.grep(/int_ip = 192.168.1.1/).size
|
81
|
+
end
|
82
|
+
|
83
|
+
def TODO_emit_ip_addr_object
|
84
|
+
emitter = LWES::Emitter.new(@options)
|
85
|
+
event = { :ip => IPAddr.new("192.168.1.1") }
|
86
|
+
out = lwes_listener do
|
87
|
+
assert_nothing_raised { emitter.emit("IP", event) }
|
88
|
+
end
|
89
|
+
lines = out.readlines
|
90
|
+
assert_equal 1, lines.grep(/\bip = 192.168.1.1/).size
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_emit_invalid
|
94
|
+
emitter = LWES::Emitter.new(@options)
|
95
|
+
assert_raises(ArgumentError) { emitter.emit("JUNK", :junk => %r{junk}) }
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_emit_booleans
|
99
|
+
emitter = LWES::Emitter.new(@options)
|
100
|
+
event = { :true => true, :false => false }
|
101
|
+
out = lwes_listener do
|
102
|
+
assert_nothing_raised { emitter.emit("BOOLS", event)
|
103
|
+
}
|
104
|
+
end
|
105
|
+
lines = out.readlines
|
106
|
+
assert_equal 1, lines.grep(/true = true;/).size
|
107
|
+
assert_equal 1, lines.grep(/false = false;/).size
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_emit_numeric_ranges
|
111
|
+
check_min_max(:int16, -0x7fff - 1, 0x7fff)
|
112
|
+
check_min_max(:int32, -0x7fffffff - 1, 0x7fffffff)
|
113
|
+
check_min_max(:int64, -0x7fffffffffffffff - 1, 0x7fffffffffffffff)
|
114
|
+
check_min_max(:uint16, 0, 0xffff)
|
115
|
+
check_min_max(:uint32, 0, 0xffffffff)
|
116
|
+
check_min_max(:uint64, 0, 0xffffffffffffffff)
|
117
|
+
huge = 0xffffffffffffffffffffffffffffffff
|
118
|
+
tiny = -0xffffffffffffffffffffffffffffffff
|
119
|
+
[ :int16, :int32, :int64, :uint16, :uint32, :uint64 ].each do |type|
|
120
|
+
emitter = LWES::Emitter.new(@options)
|
121
|
+
assert_raises(RangeError) {
|
122
|
+
emitter.emit("way over", { type => [ type, huge ] })
|
123
|
+
}
|
124
|
+
assert_raises(RangeError) {
|
125
|
+
emitter.emit("way under", { type => [ type, tiny ] })
|
126
|
+
}
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def check_min_max(type, min, max)
|
131
|
+
emitter = LWES::Emitter.new(@options)
|
132
|
+
out = lwes_listener do
|
133
|
+
assert_raises(RangeError) {
|
134
|
+
emitter.emit("over", { type => [ type, max + 1] })
|
135
|
+
}
|
136
|
+
assert_raises(RangeError, "type=#{type} min=#{min}") {
|
137
|
+
emitter.emit("under", { type => [ type, min - 1 ] })
|
138
|
+
}
|
139
|
+
assert_nothing_raised {
|
140
|
+
emitter.emit("zero", { type => [ type, 0 ] })
|
141
|
+
}
|
142
|
+
assert_nothing_raised {
|
143
|
+
emitter.emit("min", { type => [ type, min ] })
|
144
|
+
}
|
145
|
+
assert_nothing_raised {
|
146
|
+
emitter.emit("max", { type => [ type, max ] })
|
147
|
+
}
|
148
|
+
end
|
149
|
+
lines = out.readlines
|
150
|
+
assert lines.grep(/\Aover/).empty?
|
151
|
+
assert lines.grep(/\Aunder/).empty?
|
152
|
+
assert_equal 1, lines.grep(/\Amax/).size
|
153
|
+
assert_equal 1, lines.grep(/\Amin/).size
|
154
|
+
assert_equal 1, lines.grep(/\Azero/).size
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_emit_uint64
|
158
|
+
emitter = LWES::Emitter.new(@options)
|
159
|
+
assert_nothing_raised {
|
160
|
+
emitter.emit("Foo", { :uint64 => [ :uint64, 10_000_000_000 ] })
|
161
|
+
}
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_close
|
165
|
+
emitter = LWES::Emitter.new(@options)
|
166
|
+
assert_nil emitter.close
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|