librex 0.0.12 → 0.0.13

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.
Files changed (27) hide show
  1. data/README.markdown +1 -1
  2. data/Rakefile +1 -1
  3. data/lib/rex/io/stream.rb +1 -1
  4. data/lib/rex/parser/nmap_xml.rb +4 -1
  5. data/lib/rex/post/meterpreter/extensions/stdapi/railgun.rb.ts.rb +6 -0
  6. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb.ut.rb +31 -0
  7. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/buffer_item.rb +47 -0
  8. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/buffer_item.rb.ut.rb +36 -0
  9. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/{model.rb → dll.rb} +4 -226
  10. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb +100 -0
  11. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb.ut.rb +42 -0
  12. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb +148 -0
  13. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb.ut.rb +127 -0
  14. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/multicall.rb +2 -1
  15. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb +3 -2
  16. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb +1 -1
  17. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb +75 -0
  18. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb.ut.rb +103 -0
  19. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +44 -0
  20. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +2 -2
  21. data/lib/rex/proto/dhcp/server.rb +7 -6
  22. data/lib/rex/proto/ntlm/utils.rb +505 -100
  23. data/lib/rex/proto/rfb/cipher.rb +6 -0
  24. data/lib/rex/proto/smb/client.rb +40 -332
  25. data/lib/rex/proto/smb/simpleclient.rb +3 -1
  26. data/lib/rex/proto/smb/utils.rb +0 -4
  27. metadata +14 -4
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), '..', '..', '..','..','..','..','..', 'lib'))
4
+
5
+ require 'rex/post/meterpreter/extensions/stdapi/railgun/dll_function'
6
+ require 'test/unit'
7
+
8
+ module Rex
9
+ module Post
10
+ module Meterpreter
11
+ module Extensions
12
+ module Stdapi
13
+ module Railgun
14
+ class DLLFunction::UnitTest < Test::Unit::TestCase
15
+
16
+ VALID_RETURN_TYPE = 'DWORD'
17
+ NON_RETURN_DATATYPE = 'INVALID_RETURN_TYPE'
18
+
19
+ VALID_DIRECTION = 'out'
20
+ UNKNOWN_DIRECTION = 'unknown'
21
+
22
+ VALID_DATATYPE = 'PBLOB'
23
+ UNKNOWN_DATATYPE = 'UNKNOWN_DATATYPE'
24
+
25
+ def test_initialize
26
+ # TODO: haven't gotten around to writing this yet. Feel free to
27
+ # skip("incomplete test coverage")
28
+ #
29
+ # assert_nothing_raised("valid initialization should not raise") do
30
+ # end
31
+ #
32
+ # assert_raised(ArgumentError, "check_type_exists should raise ArgumentError on unknown datatypes") do
33
+ # end
34
+
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,148 @@
1
+ # Copyright (c) 2010, patrickHVE@googlemail.com
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ # * Redistributions of source code must retain the above copyright
7
+ # notice, this list of conditions and the following disclaimer.
8
+ # * Redistributions in binary form must reproduce the above copyright
9
+ # notice, this list of conditions and the following disclaimer in the
10
+ # documentation and/or other materials provided with the distribution.
11
+ # * The names of the author may not be used to endorse or promote products
12
+ # derived from this software without specific prior written permission.
13
+ #
14
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ # DISCLAIMED. IN NO EVENT SHALL patrickHVE@googlemail.com BE LIABLE FOR ANY
18
+ # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20
+ # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21
+ # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
+
25
+ module Rex
26
+ module Post
27
+ module Meterpreter
28
+ module Extensions
29
+ module Stdapi
30
+ module Railgun
31
+
32
+ #
33
+ # shared functions
34
+ #
35
+ #
36
+ module DLLHelper
37
+
38
+ # converts ruby string to zero-terminated ASCII string
39
+ def str_to_ascii_z(str)
40
+ return str+"\x00"
41
+ end
42
+
43
+ # converts 0-terminated ASCII string to ruby string
44
+ def asciiz_to_str(asciiz)
45
+ zero_byte_idx = asciiz.index("\x00")
46
+ if zero_byte_idx != nil
47
+ return asciiz[0, zero_byte_idx]
48
+ else
49
+ return asciiz
50
+ end
51
+ end
52
+
53
+ # converts ruby string to zero-terminated WCHAR string
54
+ def str_to_uni_z(str)
55
+ enc = str.unpack("C*").pack("v*")
56
+ enc += "\x00\x00"
57
+ return enc
58
+ end
59
+
60
+ # converts 0-terminated UTF16 to ruby string
61
+ def uniz_to_str(uniz)
62
+ uniz.unpack("v*").pack("C*").unpack("A*")[0]
63
+ end
64
+
65
+ # parses a number param and returns the value
66
+ # raises an exception if the param cannot be converted to a number
67
+ # examples:
68
+ # nil => 0
69
+ # 3 => 3
70
+ # "MB_OK" => 0
71
+ # "SOME_CONSTANT | OTHER_CONSTANT" => 17
72
+ # "tuna" => !!!!!!!!!!Exception
73
+ #
74
+ # Parameter "win_consts" is a WinConstantManager
75
+ def param_to_number(v, win_consts = @win_consts)
76
+ if v.class == NilClass then
77
+ return 0
78
+ elsif v.class == Fixnum then
79
+ return v # ok, it's already a number
80
+ elsif v.class == Bignum then
81
+ return v # ok, it's already a number
82
+ elsif v.class == String then
83
+ dw = win_consts.parse(v) # might raise an exception
84
+ if dw != nil
85
+ return dw
86
+ else
87
+ raise ArgumentError, "Param #{v} (class #{v.class}) cannot be converted to a number. It's a string but matches no constants I know."
88
+ end
89
+ else
90
+ raise "Param #{v} (class #{v.class}) should be a number but isn't"
91
+ end
92
+ end
93
+
94
+ # assembles the buffers "in" and "inout"
95
+ def assemble_buffer(direction, function, args)
96
+ layout = {} # paramName => BufferItem
97
+ blob = ""
98
+ #puts " building buffer: #{direction}"
99
+ function.params.each_with_index do |param_desc, param_idx|
100
+ #puts " processing #{param_desc[0]} #{param_desc[1]} #{param_desc[2]}"
101
+ # we care only about inout buffers
102
+ if param_desc[2] == direction
103
+ buffer = nil
104
+ # Special case:
105
+ # The user can choose to supply a Null pointer instead of a buffer
106
+ # in this case we don't need space in any heap buffer
107
+ if param_desc[0][0,1] == 'P' # type is a pointer
108
+ if args[param_idx] == nil
109
+ next
110
+ end
111
+ end
112
+
113
+ case param_desc[0] # required argument type
114
+ when "PDWORD"
115
+ dw = param_to_number(args[param_idx])
116
+ buffer = [dw].pack('V')
117
+ when "PWCHAR"
118
+ raise "param #{param_desc[1]}: string expected" unless args[param_idx].class == String
119
+ buffer = str_to_uni_z(args[param_idx])
120
+ when "PCHAR"
121
+ raise "param #{param_desc[1]}: string expected" unless args[param_idx].class == String
122
+ buffer = str_to_ascii_z(args[param_idx])
123
+ when "PBLOB"
124
+ raise "param #{param_desc[1]}: please supply your BLOB as string!" unless args[param_idx].class == String
125
+ buffer = args[param_idx]
126
+ # other types (non-pointers) don't reference buffers
127
+ # and don't need any treatment here
128
+ end
129
+
130
+ if buffer != nil
131
+ #puts " adding #{buffer.length} bytes to heap blob"
132
+ layout[param_desc[1]] = BufferItem.new(param_idx, blob.length, buffer.length, param_desc[0])
133
+ blob += buffer
134
+ # sf: force 8 byte alignment to satisfy x64, wont matter on x86.
135
+ while( blob.length % 8 != 0 )
136
+ blob += "\x00"
137
+ end
138
+ #puts " heap blob size now #{blob.length}"
139
+ end
140
+ end
141
+ end
142
+ #puts " built buffer: #{direction}"
143
+ return [layout, blob]
144
+ end
145
+
146
+ end
147
+
148
+ end; end; end; end; end; end;
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), '..', '..', '..','..','..','..','..', 'lib'))
4
+
5
+ require 'rex/post/meterpreter/extensions/stdapi/railgun/dll_helper'
6
+ require 'rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager'
7
+ require 'rex/text'
8
+ require 'test/unit'
9
+
10
+ module Rex
11
+ module Post
12
+ module Meterpreter
13
+ module Extensions
14
+ module Stdapi
15
+ module Railgun
16
+ class DLLHelper::UnitTest < Test::Unit::TestCase
17
+
18
+ ###
19
+ # We will test against this instance of DLLHelper (a module)
20
+ #
21
+ # We freeze the instance and make the reference constant to ensure consistency
22
+ ##
23
+ TEST_DLL_HELPER = Object.new.extend(DLLHelper).freeze
24
+
25
+ def test_str_to_ascii_z
26
+ original_string = '23 Skidoo!'
27
+
28
+ # converts ruby string to zero-terminated ASCII string
29
+ zero_terminated_ascii_attempt = TEST_DLL_HELPER.str_to_ascii_z(original_string)
30
+
31
+ assert(zero_terminated_ascii_attempt.end_with?("\x00"),
32
+ "str_to_ascii_z should result in a 0 terminated string")
33
+
34
+ assert(zero_terminated_ascii_attempt.start_with?(original_string),
35
+ "str_to_ascii_z should still start with original string")
36
+
37
+ assert_equal(original_string.length + 1, zero_terminated_ascii_attempt.length,
38
+ "str_to_ascii_z should have length of original pluss room for a terminal 0")
39
+ end
40
+
41
+ def test_asciiz_to_str
42
+ target_string = '23 Skidoo!'
43
+ post_zero_noise = 'Loud noises!'
44
+ zero_terminated_string = target_string + "\x00" + post_zero_noise
45
+
46
+ actual_string = TEST_DLL_HELPER.asciiz_to_str(zero_terminated_string)
47
+
48
+ assert(actual_string.start_with?(target_string),
49
+ "asciiz_to_str should preserve string before zero")
50
+
51
+ assert(!actual_string.end_with?(post_zero_noise),
52
+ "asciiz_to_str should ignore characters after zero")
53
+
54
+ assert_equal(target_string, actual_string,
55
+ "asciiz_to_str should only return the contents of the string before (exclusive) the zero")
56
+
57
+ assert_equal(target_string, TEST_DLL_HELPER.asciiz_to_str(target_string),
58
+ "asciiz_to_str should return input verbatim should that input not be zero-terminated")
59
+
60
+ end
61
+
62
+ def test_str_to_uni_z
63
+ ruby_string = "If I were a rich man..."
64
+
65
+ target_zero_terminated_unicode = Rex::Text.to_unicode(ruby_string) + "\x00\x00"
66
+ actual_zero_terminated_unicode = TEST_DLL_HELPER.str_to_uni_z(ruby_string)
67
+
68
+ assert(actual_zero_terminated_unicode.end_with?("\x00\x00"),
69
+ "str_to_uni_z should result in a double-zero terminated string")
70
+
71
+ assert_equal(target_zero_terminated_unicode, actual_zero_terminated_unicode,
72
+ "str_to_uni_z should convert ruby string to zero-terminated WCHAR string")
73
+ end
74
+
75
+ def test_uniz_to_str
76
+ target_string = 'Foo bar baz'
77
+
78
+ zero_terminated_unicode = Rex::Text.to_unicode(target_string) + "\x00\x00"
79
+
80
+ assert_equal(target_string, TEST_DLL_HELPER.uniz_to_str(zero_terminated_unicode),
81
+ 'uniz_to_str should convert 0-terminated UTF16 to ruby string')
82
+
83
+ end
84
+
85
+ def test_assemble_buffer
86
+ # TODO: provide test coverage
87
+ #skip("Currently DLLHelper.assemble_buffer does not have coverage")
88
+ end
89
+
90
+ def test_param_to_number
91
+ consts_manager = WinConstManager.new
92
+
93
+ x_key = 'X'
94
+ x_value = 23
95
+
96
+ y_key = 'Y'
97
+ y_value = 5
98
+
99
+ logical_or = x_key + '|' + y_key
100
+ target_result_of_logical_or = x_value | y_value
101
+
102
+ consts_manager.add_const(y_key, y_value)
103
+ consts_manager.add_const(x_key, x_value)
104
+
105
+ assert_equal(x_value, TEST_DLL_HELPER.param_to_number(x_key, consts_manager),
106
+ "param_to_number should return the appropriate value for a given constant")
107
+
108
+ assert_equal(y_value, TEST_DLL_HELPER.param_to_number(y_key, consts_manager),
109
+ "param_to_number should return the appropriate value for a given constant")
110
+
111
+ assert_equal(0, TEST_DLL_HELPER.param_to_number(nil, consts_manager),
112
+ "param_to_number should return zero when given nil")
113
+
114
+ assert_equal(target_result_of_logical_or, TEST_DLL_HELPER.param_to_number(logical_or, consts_manager),
115
+ "param_to_number should perform an OR should the input be in the form '#{logical_or}'")
116
+
117
+ assert_raise(ArgumentError, 'param_to_number should raise an error when a given key does not exist') do
118
+ TEST_DLL_HELPER.param_to_number('DOESNT_EXIST', consts_manager)
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -26,7 +26,8 @@ require 'pp'
26
26
  require 'enumerator'
27
27
  require 'rex/post/meterpreter/extensions/stdapi/railgun/api_constants'
28
28
  require 'rex/post/meterpreter/extensions/stdapi/railgun/tlv'
29
- require 'rex/post/meterpreter/extensions/stdapi/railgun/model'
29
+ require 'rex/post/meterpreter/extensions/stdapi/railgun/dll_helper'
30
+ require 'rex/post/meterpreter/extensions/stdapi/railgun/buffer_item'
30
31
 
31
32
  module Rex
32
33
  module Post
@@ -28,11 +28,13 @@
28
28
 
29
29
  require 'pp'
30
30
  require 'enumerator'
31
+
31
32
  require 'rex/post/meterpreter/extensions/stdapi/railgun/api_constants'
32
33
  require 'rex/post/meterpreter/extensions/stdapi/railgun/tlv'
33
34
  require 'rex/post/meterpreter/extensions/stdapi/railgun/util'
34
- require 'rex/post/meterpreter/extensions/stdapi/railgun/model'
35
+ require 'rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager'
35
36
  require 'rex/post/meterpreter/extensions/stdapi/railgun/multicall'
37
+ require 'rex/post/meterpreter/extensions/stdapi/railgun/dll'
36
38
 
37
39
  module Rex
38
40
  module Post
@@ -45,7 +47,6 @@ module Railgun
45
47
  # The Railgun class to dynamically expose the Windows API.
46
48
  #
47
49
  class Railgun
48
-
49
50
  def initialize( client )
50
51
 
51
52
  @client = client
@@ -1,4 +1,4 @@
1
- require 'rex/post/meterpreter/extensions/stdapi/railgun/model'
1
+ require 'rex/post/meterpreter/extensions/stdapi/railgun/dll_helper'
2
2
 
3
3
  module Rex
4
4
  module Post
@@ -0,0 +1,75 @@
1
+ # Copyright (c) 2010, patrickHVE@googlemail.com
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ # * Redistributions of source code must retain the above copyright
7
+ # notice, this list of conditions and the following disclaimer.
8
+ # * Redistributions in binary form must reproduce the above copyright
9
+ # notice, this list of conditions and the following disclaimer in the
10
+ # documentation and/or other materials provided with the distribution.
11
+ # * The names of the author may not be used to endorse or promote products
12
+ # derived from this software without specific prior written permission.
13
+ #
14
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ # DISCLAIMED. IN NO EVENT SHALL patrickHVE@googlemail.com BE LIABLE FOR ANY
18
+ # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20
+ # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21
+ # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
+
25
+ module Rex
26
+ module Post
27
+ module Meterpreter
28
+ module Extensions
29
+ module Stdapi
30
+ module Railgun
31
+
32
+ #
33
+ # Manages our library of windows constants
34
+ #
35
+ class WinConstManager
36
+
37
+ def initialize(initial_consts = {})
38
+ @consts = {}
39
+
40
+ initial_consts.each_pair do |name, value|
41
+ add_const(name, value)
42
+ end
43
+
44
+ # Load utility
45
+ end
46
+
47
+ def add_const(name, value)
48
+ @consts[name] = value
49
+ end
50
+
51
+ # parses a string constaining constants and returns an integer
52
+ # the string can be either "CONST" or "CONST1 | CONST2"
53
+ #
54
+ # this function will NOT throw an exception but return "nil" if it can't parse a string
55
+ def parse(s)
56
+ if s.class != String
57
+ return nil # it's not even a string'
58
+ end
59
+ return_value = 0
60
+ for one_const in s.split('|')
61
+ one_const = one_const.strip()
62
+ if not @consts.has_key? one_const
63
+ return nil # at least one "Constant" is unknown to us
64
+ end
65
+ return_value |= @consts[one_const]
66
+ end
67
+ return return_value
68
+ end
69
+
70
+ def is_parseable(s)
71
+ return parse(s) != nil
72
+ end
73
+ end
74
+
75
+ end; end; end; end; end; end
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), '..', '..', '..','..','..','..','..', 'lib'))
4
+
5
+ require 'rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager'
6
+ require 'test/unit'
7
+
8
+ module Rex
9
+ module Post
10
+ module Meterpreter
11
+ module Extensions
12
+ module Stdapi
13
+ module Railgun
14
+ class WinConstManager::UnitTest < Test::Unit::TestCase
15
+ def test_is_parseable
16
+ const_manager = WinConstManager.new
17
+
18
+ first_key = 'SOME_NUMBER'
19
+ second_key = 'SOME_OTHER_NUMBER'
20
+ boolean_logic = first_key + ' | ' + second_key
21
+
22
+ # XXX: Should check (un)parseability before adding constants too?
23
+
24
+ const_manager.add_const(first_key, 43123)
25
+ const_manager.add_const(second_key, 234)
26
+
27
+ assert(const_manager.is_parseable(boolean_logic),
28
+ "is_parseable should consider boolean logic statements parseable")
29
+
30
+ assert(const_manager.is_parseable(first_key),
31
+ "is_parseable should consider constants parseable")
32
+
33
+ assert(! const_manager.is_parseable(5),
34
+ "is_parseable should not consider non-string keys as parseable")
35
+
36
+ assert(! const_manager.is_parseable('| FOO |'),
37
+ "is_parseable should not consider malformed boolean expressions parseable")
38
+ end
39
+
40
+ def test_add_const
41
+ target_key = 'VALID_KEY'
42
+ target_value = 23
43
+
44
+ const_manager = WinConstManager.new
45
+
46
+ const_manager.add_const(target_key, target_value)
47
+
48
+ assert_equal(target_value, const_manager.parse(target_key),
49
+ "add_const should add a constant/value pair that can be trieved with parse")
50
+
51
+ end
52
+
53
+ def test_initialization
54
+ target_key = 'VALID_KEY'
55
+ target_value = 23
56
+
57
+ const_manager = WinConstManager.new(target_key => target_value)
58
+
59
+ assert_equal(target_value, const_manager.parse(target_key),
60
+ "upon initialization, should add any provided constants.")
61
+ end
62
+
63
+ def test_parse
64
+ target_key = 'VALID_KEY'
65
+ target_value = 23
66
+ invalid_key = 8
67
+
68
+ const_manager = WinConstManager.new
69
+
70
+ const_manager.add_const(target_key, target_value)
71
+
72
+ assert_equal(target_value, const_manager.parse(target_key),
73
+ "parse should retrieve the corresponding value when a key is provided")
74
+
75
+ # From API: "should not throw an exception given an invalid key"
76
+ assert_nothing_thrown do
77
+ const_manager.parse(invalid_key)
78
+ end
79
+
80
+ assert_equal(nil, const_manager.parse(invalid_key),
81
+ "parse should return nil when an invalid key is provided")
82
+
83
+ x_key = 'X'
84
+ x_value = 228
85
+ y_key = 'Y'
86
+ y_value = 15
87
+
88
+ boolean_logic = x_key + ' | ' + y_key
89
+ target_boolean_logic_result = x_value | y_value
90
+
91
+ const_manager.add_const(x_key, x_value)
92
+ const_manager.add_const(y_key, y_value)
93
+
94
+ assert_equal(target_boolean_logic_result, const_manager.parse(boolean_logic),
95
+ "parse should evaluate boolean expressions consisting of OR")
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end