lwes 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|