configtoolkit 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/FAQ.txt +113 -25
  2. data/Hash.txt +128 -0
  3. data/History.txt +45 -2
  4. data/KeyValue.txt +235 -0
  5. data/Manifest.txt +66 -4
  6. data/README.txt +666 -202
  7. data/Rakefile +3 -5
  8. data/Ruby.txt +172 -0
  9. data/YAML.txt +188 -0
  10. data/examples/hash_example.rb +71 -0
  11. data/examples/key_value_example.dump.cfg +5 -0
  12. data/examples/key_value_example.normal1.cfg +20 -0
  13. data/examples/key_value_example.normal2.cfg +15 -0
  14. data/examples/key_value_example.rb +72 -0
  15. data/examples/key_value_example.wacky.cfg +13 -0
  16. data/examples/load_example.rb +32 -0
  17. data/examples/load_example.yaml +34 -0
  18. data/examples/load_group_example.rb +28 -0
  19. data/examples/load_group_example.yaml +33 -0
  20. data/examples/machineconfig.rb +77 -0
  21. data/examples/ruby_example.rb +32 -0
  22. data/examples/ruby_example.rcfg +52 -0
  23. data/examples/usage_example.rb +93 -0
  24. data/examples/yaml_example.dump.yaml +12 -0
  25. data/examples/yaml_example.rb +48 -0
  26. data/examples/yaml_example.yaml +59 -0
  27. data/lib/configtoolkit.rb +1 -1
  28. data/lib/configtoolkit/baseconfig.rb +522 -418
  29. data/lib/configtoolkit/hasharrayvisitor.rb +242 -0
  30. data/lib/configtoolkit/hashreader.rb +41 -0
  31. data/lib/configtoolkit/hashwriter.rb +45 -0
  32. data/lib/configtoolkit/keyvalueconfig.rb +105 -0
  33. data/lib/configtoolkit/keyvaluereader.rb +597 -0
  34. data/lib/configtoolkit/keyvaluewriter.rb +157 -0
  35. data/lib/configtoolkit/prettyprintwriter.rb +167 -0
  36. data/lib/configtoolkit/reader.rb +62 -0
  37. data/lib/configtoolkit/rubyreader.rb +270 -0
  38. data/lib/configtoolkit/types.rb +42 -26
  39. data/lib/configtoolkit/writer.rb +116 -0
  40. data/lib/configtoolkit/yamlreader.rb +10 -6
  41. data/lib/configtoolkit/yamlwriter.rb +113 -71
  42. data/test/bad_array_index.rcfg +1 -0
  43. data/test/bad_containing_object_assignment.rcfg +2 -0
  44. data/test/bad_directive.cfg +1 -0
  45. data/test/bad_include1.cfg +2 -0
  46. data/test/bad_include2.cfg +3 -0
  47. data/test/bad_parameter_reference.rcfg +1 -0
  48. data/test/contained_sample.cfg +10 -0
  49. data/test/contained_sample.pretty_print +30 -0
  50. data/test/contained_sample.rcfg +22 -0
  51. data/test/contained_sample.yaml +22 -21
  52. data/test/containers.cfg +6 -0
  53. data/test/exta_string_after_container.cfg +2 -0
  54. data/test/extra_container_closing.cfg +2 -0
  55. data/test/extra_string_after_container.cfg +2 -0
  56. data/test/extra_string_after_nested_container.cfg +1 -0
  57. data/test/missing_array_closing.cfg +2 -0
  58. data/test/missing_array_element.cfg +2 -0
  59. data/test/missing_directive.cfg +1 -0
  60. data/test/missing_hash_closing.cfg +2 -0
  61. data/test/missing_hash_element.cfg +2 -0
  62. data/test/missing_hash_value.cfg +1 -0
  63. data/test/missing_include_argument.cfg +1 -0
  64. data/test/missing_key_value_delimiter.cfg +1 -0
  65. data/test/readerwritertest.rb +28 -7
  66. data/test/sample.cfg +10 -0
  67. data/test/sample.pretty_print +30 -0
  68. data/test/sample.rcfg +26 -0
  69. data/test/test_baseconfig.rb +152 -38
  70. data/test/test_hash.rb +82 -0
  71. data/test/test_keyvalue.rb +185 -0
  72. data/test/test_prettyprint.rb +28 -0
  73. data/test/test_ruby.rb +50 -0
  74. data/test/test_yaml.rb +33 -26
  75. data/test/wacky_sample1.cfg +16 -0
  76. data/test/wacky_sample2.cfg +5 -0
  77. data/test/wacky_sample3.cfg +4 -0
  78. data/test/wacky_sample4.cfg +1 -0
  79. metadata +101 -10
  80. data/lib/configtoolkit/toolkit.rb +0 -20
  81. data/test/common.rb +0 -5
@@ -0,0 +1 @@
1
+ config.unknown_array[0] = 2
@@ -0,0 +1,2 @@
1
+ config.first.second.flavor = "chocolate"
2
+ config.first.second = 2 # This is bad, because we are assigning to a containing object
@@ -0,0 +1 @@
1
+ *bogus directive
@@ -0,0 +1,2 @@
1
+ favorite_flavor = butter pecan
2
+ *include bad_include2.cfg
@@ -0,0 +1,3 @@
1
+ topping = sprinkles
2
+
3
+ bad line
@@ -0,0 +1 @@
1
+ config.bad_parameter_reference(10)
@@ -0,0 +1,10 @@
1
+ first.second.req_integer = 5
2
+ first.second.req_big_integer = 10000000000
3
+ first.second.req_float = 5.678
4
+ first.second.req_string = sample string
5
+ first.second.req_boolean = false
6
+ first.second.req_pathname = /usr/designingpatterns
7
+ first.second.req_uri = http://www.designingpatterns.com
8
+ first.second.req_symbol = sample_symbol
9
+ first.second.nested_config = {req_nested_integer => 33, req_nested_array => [{req_second_nested_pathname => /usr/designingpatterns/Applications, req_second_nested_array => [5, 19]}, {req_second_nested_pathname => /usr/designingpatterns/Applications/etc, req_second_nested_array => [200, 201]}]}
10
+ first.second.opt_integer = 42
@@ -0,0 +1,30 @@
1
+ first.second: {
2
+ req_integer : 5
3
+ req_big_integer: 10000000000
4
+ req_float : 5.678
5
+ req_string : sample string
6
+ req_boolean : false
7
+ req_pathname : /usr/designingpatterns
8
+ req_uri : http://www.designingpatterns.com
9
+ req_symbol : sample_symbol
10
+ nested_config : {
11
+ req_nested_integer: 33
12
+ req_nested_array : [
13
+ {
14
+ req_second_nested_pathname: /usr/designingpatterns/Applications
15
+ req_second_nested_array : [
16
+ 5,
17
+ 19
18
+ ]
19
+ },
20
+ {
21
+ req_second_nested_pathname: /usr/designingpatterns/Applications/etc
22
+ req_second_nested_array : [
23
+ 200,
24
+ 201
25
+ ]
26
+ }
27
+ ]
28
+ }
29
+ opt_integer : 42
30
+ }
@@ -0,0 +1,22 @@
1
+ config.first.second.req_integer = 5
2
+ config.first.second.req_big_integer = 10000000000
3
+ config.first.second.req_float = 5.678
4
+ config.first.second.req_string = "sample string"
5
+ config.first.second.req_boolean = false
6
+ config.first.second.req_pathname = "/usr/designingpatterns"
7
+ config.first.second.req_uri = "http://www.designingpatterns.com"
8
+ config.first.second.req_symbol = :sample_symbol
9
+ config.first.second.nested_config.req_nested_integer = 33
10
+ config.first.second.nested_config.req_nested_array =
11
+ [
12
+ {
13
+ :req_second_nested_pathname => "/usr/designingpatterns/Applications",
14
+ :req_second_nested_array => [5, 19]
15
+ },
16
+ {
17
+ :req_second_nested_pathname => "/usr/designingpatterns/Applications/etc",
18
+ :req_second_nested_array => [200, 201]
19
+ }
20
+ ]
21
+
22
+ config.first.second.opt_integer = 37 + config.first.second.req_integer
@@ -1,22 +1,23 @@
1
1
  ---
2
- contained_sample:
3
- opt_integer: 42
4
- req_uri: http://www.designingpatterns.com
5
- req_float: 5.678
6
- req_pathname: /usr/designingpatterns
7
- req_integer: 5
8
- req_string: sample string
9
- req_boolean: false
10
- req_symbol: sample_symbol
11
- req_big_integer: 10000000000
12
- nested_config:
13
- req_nested_array:
14
- - req_second_nested_pathname: /usr/designingpatterns/Applications
15
- req_second_nested_array:
16
- - 5
17
- - 19
18
- - req_second_nested_pathname: /usr/designingpatterns/Applications/etc
19
- req_second_nested_array:
20
- - 200
21
- - 201
22
- req_nested_integer: 33
2
+ first:
3
+ second:
4
+ opt_integer: 42
5
+ req_uri: http://www.designingpatterns.com
6
+ req_float: 5.678
7
+ req_pathname: /usr/designingpatterns
8
+ req_integer: 5
9
+ req_string: sample string
10
+ req_boolean: false
11
+ req_symbol: sample_symbol
12
+ req_big_integer: 10000000000
13
+ nested_config:
14
+ req_nested_array:
15
+ - req_second_nested_pathname: /usr/designingpatterns/Applications
16
+ req_second_nested_array:
17
+ - 5
18
+ - 19
19
+ - req_second_nested_pathname: /usr/designingpatterns/Applications/etc
20
+ req_second_nested_array:
21
+ - 200
22
+ - 201
23
+ req_nested_integer: 33
@@ -0,0 +1,6 @@
1
+ #
2
+ # Note that the "topping=" hash key has an equal sign in it, which
3
+ # should be handled correctly even though the hash key-value
4
+ # delimiter is =>.
5
+ #
6
+ favorite_ice_cream = {flavor => butter pecan, topping= => caramel}
@@ -0,0 +1,2 @@
1
+ favorite_pie = pecan
2
+ extra_abcd_string = {type => soft serve, flavor => cookie dough}abcd
@@ -0,0 +1,2 @@
1
+ favorite_pie = pecan
2
+ extra_} = {type => soft serve, flavor => cookie dough}}
@@ -0,0 +1,2 @@
1
+ favorite_pie = pecan
2
+ extra_abcd_string = {type => soft serve, flavor => cookie dough}abcd
@@ -0,0 +1 @@
1
+ extra_butterscotch = {type => soft serve, toppings => [sprinkles, cherries, oreos]butterscotch, flavor => cookie dough}
@@ -0,0 +1,2 @@
1
+ favorite_pie = pecan
2
+ missing_array_closing = [a, b, c
@@ -0,0 +1,2 @@
1
+ favorite_pie = pecan
2
+ missing_array_element = [a, , c]
@@ -0,0 +1 @@
1
+ *
@@ -0,0 +1,2 @@
1
+ favorite_pie = pecan
2
+ missing_hash_closing = {type => soft serve, topping => chocolate chips, flavor => cookie dough
@@ -0,0 +1,2 @@
1
+ favorite_pie = pecan
2
+ missing_hash_element = {type => soft serve, , flavor => cookie dough}
@@ -0,0 +1 @@
1
+ missing_topping_value = {type => soft serve, topping => , flavor => cookie dough
@@ -0,0 +1 @@
1
+ *include
@@ -0,0 +1 @@
1
+ favorite ice cream
@@ -8,7 +8,8 @@ require 'uri'
8
8
 
9
9
  class SampleSecondNestedConfig < ConfigToolkit::BaseConfig
10
10
  add_required_param(:req_second_nested_pathname, Pathname)
11
- add_required_param(:req_second_nested_array, Array)
11
+ add_required_param(:req_second_nested_array,
12
+ ConfigToolkit::ConstrainedArray.new(Integer))
12
13
  end
13
14
 
14
15
  class SampleNestedConfig < ConfigToolkit::BaseConfig
@@ -73,7 +74,7 @@ REFERENCE_CONTAINED_SAMPLE_CONFIG.nested_config.req_nested_array[0].req_second_n
73
74
  REFERENCE_CONTAINED_SAMPLE_CONFIG.nested_config.req_nested_array[1].req_second_nested_pathname = Pathname.new("/usr/designingpatterns/Applications/etc")
74
75
  REFERENCE_CONTAINED_SAMPLE_CONFIG.nested_config.req_nested_array[1].req_second_nested_array = [200, 201]
75
76
  REFERENCE_CONTAINED_SAMPLE_CONFIG.opt_integer = 42
76
- REFERENCE_CONTAINED_SAMPLE_CONFIG.instance_variable_set(:@containing_object_name, "contained_sample")
77
+ REFERENCE_CONTAINED_SAMPLE_CONFIG.instance_variable_set(:@containing_object_name, "first.second")
77
78
 
78
79
  module ReaderWriterTest
79
80
  def run_reader_test(reader_class,
@@ -85,15 +86,35 @@ module ReaderWriterTest
85
86
  assert_equal(reference_config, config)
86
87
  end
87
88
 
88
- def get_sorted_file_contents(file_name)
89
+ def get_sorted_file_contents(file_name, sort_type)
89
90
  file_contents = File.open(file_name, "r") do |file|
90
91
  file.read()
91
92
  end
92
93
 
93
- return file_contents.split("\n").sort().join("\n").to_s()
94
+ if(sort_type == :sort_lines)
95
+ return file_contents.split("\n").sort().join("\n")
96
+ elsif(sort_type == :sort_lines_and_line_contents)
97
+ return file_contents.split("\n").sort().map do |line|
98
+ line.split("").sort().join()
99
+ end.join("\n")
100
+ end
94
101
  end
95
102
 
103
+ #
104
+ # Often (always?), the output of a writer depends on the order in which it
105
+ # encounters parameters in the Hash that its write() method is
106
+ # passed. Of course, hash table elements have no guaranteed
107
+ # ordering, and so it is impossible to construct reference files
108
+ # since the order of the parameters in the file is undefined.
109
+ # So, the contents of the reference and dumped files are sorted
110
+ # before the comparison. If each parameter occupies at least one
111
+ # line, then just the lines need to be sorted (sort_type = :sort_lines).
112
+ # If multiple parameters can occur on the same line, then the lines
113
+ # need to be sorted, and the contents of each line must be
114
+ # sorted (sort_type = :sort_lines_and_line_contents).
115
+ #
96
116
  def run_writer_test(writer_class,
117
+ sort_type,
97
118
  reference_config,
98
119
  reference_file_name,
99
120
  dump_file_name,
@@ -101,8 +122,8 @@ module ReaderWriterTest
101
122
  writer = writer_class.new(*writer_constructor_args)
102
123
  reference_config.dump(writer)
103
124
 
104
- assert_equal(get_sorted_file_contents(reference_file_name),
105
- get_sorted_file_contents(dump_file_name))
125
+ assert_equal(get_sorted_file_contents(reference_file_name, sort_type),
126
+ get_sorted_file_contents(dump_file_name, sort_type))
106
127
  end
107
128
 
108
129
  def run_reader_writer_test(reader_class,
@@ -112,7 +133,7 @@ module ReaderWriterTest
112
133
  writer_constructor_args)
113
134
  writer = writer_class.new(*writer_constructor_args)
114
135
  reference_config.dump(writer)
115
-
136
+
116
137
  reader = reader_class.new(*reader_constructor_args)
117
138
  config = SampleConfig.load(reader, reference_config.containing_object_name)
118
139
 
data/test/sample.cfg ADDED
@@ -0,0 +1,10 @@
1
+ req_integer = 6
2
+ req_big_integer = 90000000000
3
+ req_float = 3.14
4
+ req_string = sample string2
5
+ req_boolean = true
6
+ req_pathname = /usr/designingpatterns/bin
7
+ req_uri = http://blogs.designingpatterns.com
8
+ req_symbol = sample_symbol2
9
+ nested_config = {req_nested_integer => 34, req_nested_array => [{req_second_nested_pathname => /usr/designingpatterns/Applications/pattmake, req_second_nested_array => [6, 20]}, {req_second_nested_pathname => /usr, req_second_nested_array => [205, 206]}]}
10
+ opt_integer = 56
@@ -0,0 +1,30 @@
1
+ {
2
+ req_integer : 6
3
+ req_big_integer: 90000000000
4
+ req_float : 3.14
5
+ req_string : sample string2
6
+ req_boolean : true
7
+ req_pathname : /usr/designingpatterns/bin
8
+ req_uri : http://blogs.designingpatterns.com
9
+ req_symbol : sample_symbol2
10
+ nested_config : {
11
+ req_nested_integer: 34
12
+ req_nested_array : [
13
+ {
14
+ req_second_nested_pathname: /usr/designingpatterns/Applications/pattmake
15
+ req_second_nested_array : [
16
+ 6,
17
+ 20
18
+ ]
19
+ },
20
+ {
21
+ req_second_nested_pathname: /usr
22
+ req_second_nested_array : [
23
+ 205,
24
+ 206
25
+ ]
26
+ }
27
+ ]
28
+ }
29
+ opt_integer : 56
30
+ }
data/test/sample.rcfg ADDED
@@ -0,0 +1,26 @@
1
+ require 'pathname'
2
+ require 'uri'
3
+
4
+ config.req_integer = 6
5
+ config.req_big_integer = 90000000000
6
+ config.req_float = 3.14
7
+ config.req_string = "sample string2"
8
+ config.req_boolean = true
9
+ config.req_pathname = Pathname.new("/usr/designingpatterns/bin")
10
+ config.req_uri = URI("http://blogs.designingpatterns.com")
11
+ config.req_symbol = :sample_symbol2
12
+ config.nested_config = {
13
+ :req_nested_integer => 34,
14
+ :req_nested_array => [
15
+ {
16
+ :req_second_nested_pathname => Pathname("/usr/designingpatterns/Applications/pattmake"),
17
+ :req_second_nested_array => [6, 20]
18
+ },
19
+ {
20
+ :req_second_nested_pathname => Pathname("/usr"),
21
+ :req_second_nested_array => [205, 206]
22
+ }
23
+ ]
24
+ }
25
+
26
+ config.opt_integer = 56
@@ -1,10 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'common'
4
-
5
3
  require 'configtoolkit'
6
4
  require 'configtoolkit/yamlreader'
7
5
  require 'configtoolkit/yamlwriter'
6
+ require 'configtoolkit/hasharrayvisitor'
7
+
8
+ require 'rubygems'
9
+ require 'assertions'
10
+ require 'relative'
8
11
 
9
12
  require 'pathname'
10
13
  require 'test/unit'
@@ -74,7 +77,7 @@ class BaseConfigTest < Test::Unit::TestCase
74
77
  end
75
78
  end
76
79
 
77
- MACHINES_CONFIG_FILE_NAME = get_test_config_file_name("machines.yaml")
80
+ MACHINES_CONFIG_FILE_NAME = File.expand_path_relative_to_caller("machines.yaml")
78
81
 
79
82
  #
80
83
  # Test whether the methods for MachineConfig's attributes
@@ -102,9 +105,31 @@ class BaseConfigTest < Test::Unit::TestCase
102
105
  #
103
106
  config_param_values.each do |param_name, param_value|
104
107
  assert_equal(nil, config.send(param_name))
108
+ assert_not(config.send("#{param_name}?"))
105
109
  setter = "#{param_name}=".to_sym()
110
+
106
111
  config.send(setter, param_value)
107
112
  assert_equal(param_value, config.send(param_name))
113
+ assert(config.send("#{param_name}?"))
114
+
115
+ #
116
+ # Verify that the single optional parameter, :behind_firewall,
117
+ # has a clear method, and that the clear method works
118
+ # properly. Verify that the required parameters do not have
119
+ # clear methods.
120
+ #
121
+ clear_method = "clear_#{param_name}".to_sym()
122
+ if(param_name == :behind_firewall)
123
+ config.send(clear_method)
124
+ assert_equal(nil, config.send(param_name))
125
+ assert_not(config.send("#{param_name}?"))
126
+
127
+ config.send(setter, param_value)
128
+ assert_equal(param_value, config.send(param_name))
129
+ assert(config.send("#{param_name}?"))
130
+ else
131
+ assert_not(config.respond_to?(clear_method))
132
+ end
108
133
  end
109
134
 
110
135
  #
@@ -116,6 +141,29 @@ class BaseConfigTest < Test::Unit::TestCase
116
141
  puts config
117
142
  end
118
143
 
144
+ def test_initialize
145
+ config = MachineConfig.new() do |config|
146
+ config.name = "apple"
147
+ config.architecture = "powerpc"
148
+ config.os = "AIX"
149
+ config.num_cpus = 32
150
+ config.behind_firewall = false
151
+ config.contains_sensitive_data = false
152
+ config.addresses = [
153
+ URI("http://default.designingpatterns.com"),
154
+ URI("http://apple.designingpatterns.com")
155
+ ]
156
+ end
157
+
158
+ reader = ConfigToolkit::YAMLReader.new(File.expand_path_relative_to_caller("machines.yaml"))
159
+ assert_equal(MachineConfig.load(reader), config)
160
+
161
+ assert_raise_message("missing parameter(s): name, architecture, os, num_cpus, contains_sensitive_data, addresses", ConfigToolkit::Error) do
162
+ config = MachineConfig.new() do
163
+ end
164
+ end
165
+ end
166
+
119
167
  def verify_correct_dump(config_file_name, containing_object_name)
120
168
  reader = ConfigToolkit::YAMLReader.new(config_file_name)
121
169
  config = MachineConfig.load(reader, containing_object_name)
@@ -134,21 +182,14 @@ class BaseConfigTest < Test::Unit::TestCase
134
182
  def verify_dump_error(config, message)
135
183
  dump_stream = StringIO.new()
136
184
  writer = ConfigToolkit::YAMLWriter.new(dump_stream, true)
137
-
138
- rescued_exception = false
139
- begin
185
+ assert_raise_message(message, ConfigToolkit::Error) do
140
186
  config.dump(writer)
141
- rescue ConfigToolkit::Error => e
142
- assert_equal(message, e.message)
143
- rescued_exception = true
144
187
  end
145
-
146
- assert(rescued_exception)
147
188
  end
148
189
 
149
190
  def test_dump
150
- verify_correct_dump(get_test_config_file_name("firewall.yaml"), "firewall")
151
- verify_correct_dump(get_test_config_file_name("webserver.yaml"), "")
191
+ verify_correct_dump(File.expand_path_relative_to_caller("firewall.yaml"), "firewall")
192
+ verify_correct_dump(File.expand_path_relative_to_caller("webserver.yaml"), "")
152
193
 
153
194
  #
154
195
  # Verify that dumping a config sets the config's optional
@@ -164,7 +205,7 @@ class BaseConfigTest < Test::Unit::TestCase
164
205
  dump_stream = StringIO.new()
165
206
  writer = ConfigToolkit::YAMLWriter.new(dump_stream, true)
166
207
  assert_equal(nil, config.behind_firewall)
167
- config.dump(dump_stream)
208
+ config.dump(writer)
168
209
  assert_equal(true, config.behind_firewall)
169
210
 
170
211
  config = MachineConfig.new()
@@ -177,7 +218,7 @@ class BaseConfigTest < Test::Unit::TestCase
177
218
  config.behind_firewall = false
178
219
  config.num_cpus = 2
179
220
  config.addresses = ["http://uniq.designingpatterns.com", "http://ftp.designingpatterns.com"]
180
- verify_dump_error(config, "BaseConfigTest::MachineConfig#validate_all_values dump error: a machine cannot contain sensitive data and not be behind the firewall")
221
+ verify_dump_error(config, "BaseConfigTest::MachineConfig#validate_all_values error: a machine cannot contain sensitive data and not be behind the firewall")
181
222
  end
182
223
 
183
224
  def verify_correct_load(config_file_name,
@@ -204,29 +245,17 @@ class BaseConfigTest < Test::Unit::TestCase
204
245
  def verify_load_error(config_file_name, containing_object_name, message)
205
246
  reader = ConfigToolkit::YAMLReader.new(config_file_name)
206
247
 
207
- rescued_exception = false
208
- begin
248
+ assert_raise_message(message, ConfigToolkit::Error) do
209
249
  config = MachineConfig.load(reader, containing_object_name)
210
- rescue ConfigToolkit::Error => e
211
- assert_equal(message, e.message)
212
- rescued_exception = true
213
250
  end
214
-
215
- assert(rescued_exception)
216
251
  end
217
252
 
218
253
  def verify_load_group_error(config_file_name, containing_object_name, message)
219
254
  reader = ConfigToolkit::YAMLReader.new(config_file_name)
220
255
 
221
- rescued_exception = false
222
- begin
256
+ assert_raise_message(message, ConfigToolkit::Error) do
223
257
  config = MachineConfig.load_group(reader, containing_object_name)
224
- rescue ConfigToolkit::Error => e
225
- assert_equal(message, e.message)
226
- rescued_exception = true
227
258
  end
228
-
229
- assert(rescued_exception)
230
259
  end
231
260
 
232
261
  #
@@ -274,13 +303,13 @@ class BaseConfigTest < Test::Unit::TestCase
274
303
  verify_correct_load(MACHINES_CONFIG_FILE_NAME, "test", config)
275
304
 
276
305
  verify_correct_load_group(MACHINES_CONFIG_FILE_NAME, "db_cluster1",
277
- "db1" => MachineConfig.load(ConfigToolkit::YAMLReader.new(MACHINES_CONFIG_FILE_NAME), "db1"),
278
- "db2" => MachineConfig.load(ConfigToolkit::YAMLReader.new(MACHINES_CONFIG_FILE_NAME), "db2"),
279
- "db3" => MachineConfig.load(ConfigToolkit::YAMLReader.new(MACHINES_CONFIG_FILE_NAME), "db3"))
306
+ :db1 => MachineConfig.load(ConfigToolkit::YAMLReader.new(MACHINES_CONFIG_FILE_NAME), "db1"),
307
+ :db2 => MachineConfig.load(ConfigToolkit::YAMLReader.new(MACHINES_CONFIG_FILE_NAME), "db2"),
308
+ :db3 => MachineConfig.load(ConfigToolkit::YAMLReader.new(MACHINES_CONFIG_FILE_NAME), "db3"))
280
309
  end
281
310
 
282
311
  def test_load_errors
283
- verify_load_error(get_test_config_file_name("bad_config.yaml"),
312
+ verify_load_error(File.expand_path_relative_to_caller("bad_config.yaml"),
284
313
  "",
285
314
  "ConfigToolkit::YAMLReader#read returned Array rather than Hash")
286
315
 
@@ -298,26 +327,111 @@ class BaseConfigTest < Test::Unit::TestCase
298
327
 
299
328
  verify_load_error(MACHINES_CONFIG_FILE_NAME,
300
329
  "bad_num_cpus",
301
- "error setting parameter bad_num_cpus.num_cpus with value -2: num_cpus must be greater than zero.")
330
+ "error setting bad_num_cpus.num_cpus with value -2: num_cpus must be greater than zero.")
302
331
 
303
332
  verify_load_error(MACHINES_CONFIG_FILE_NAME,
304
333
  "bad_addresses_element_type",
305
- "error setting parameter bad_addresses_element_type.addresses[0] with value 2: cannot convert from value class Fixnum to specified class URI.")
334
+ "error setting bad_addresses_element_type.addresses[0] with value 2: cannot convert from value class Fixnum to specified class URI.")
306
335
 
307
336
  verify_load_error(MACHINES_CONFIG_FILE_NAME,
308
337
  "bad_addresses_max_num_elements",
309
- "error setting parameter bad_addresses_max_num_elements.addresses with value [http://test.designingpatterns.com, http://bananna.designingpatterns.com, http://fruitsalad.designingpatterns.com, http://parfait.designingpatterns.com]: the number of elements (4) is greater than the specified maximum number of elements (3).")
338
+ "error setting bad_addresses_max_num_elements.addresses with value [http://test.designingpatterns.com, http://bananna.designingpatterns.com, http://fruitsalad.designingpatterns.com, http://parfait.designingpatterns.com]: the number of elements (4) is greater than the specified maximum number of elements (3).")
310
339
 
311
340
  verify_load_error(MACHINES_CONFIG_FILE_NAME,
312
341
  "bad_addresses_min_num_elements",
313
- "error setting parameter bad_addresses_min_num_elements.addresses with value [http://bananna.designingpatterns.com]: the number of elements (1) is less than the specified minimum number of elements (2).")
342
+ "error setting bad_addresses_min_num_elements.addresses with value [http://bananna.designingpatterns.com]: the number of elements (1) is less than the specified minimum number of elements (2).")
314
343
 
315
344
  verify_load_error(MACHINES_CONFIG_FILE_NAME,
316
345
  "bad_contains_sensitive_data_behind_firewall_combo",
317
- "BaseConfigTest::MachineConfig#validate_all_values load error for bad_contains_sensitive_data_behind_firewall_combo: a machine cannot contain sensitive data and not be behind the firewall")
346
+ "BaseConfigTest::MachineConfig#validate_all_values error for bad_contains_sensitive_data_behind_firewall_combo: a machine cannot contain sensitive data and not be behind the firewall")
318
347
 
319
348
  verify_load_group_error(MACHINES_CONFIG_FILE_NAME,
320
349
  "bad_group",
321
350
  "error: BaseConfigTest::MachineConfig.load_group found Array rather than Hash when reading the bad_group.bad_element containing object")
322
351
  end
352
+
353
+ class BadConfig < ConfigToolkit::BaseConfig
354
+ add_optional_param(:optional_param_with_default_value, String, "hello")
355
+ add_optional_param(:optional_param_without_default_value, String)
356
+ end
357
+
358
+ def test_configuration_definition
359
+ assert_raise_message("error setting default value for bad_param with value nil: cannot convert from value class NilClass to specified class Fixnum.", ConfigToolkit::Error) do
360
+ BadConfig.send(:add_optional_param, :bad_param, Fixnum, nil)
361
+ end
362
+
363
+ assert_raise_message("error setting default value for bad_param with value 1: cannot convert from value class Fixnum to specified class String.", ConfigToolkit::Error) do
364
+ BadConfig.send(:add_optional_param, :bad_param, String, 1)
365
+ end
366
+
367
+ #
368
+ # After initializing a BadConfig instance with no parameters:
369
+ # * optional_param_with_default_value should have its default value of
370
+ # "hello"
371
+ # * optional_param_without_default_value should have no value
372
+ #
373
+ config = BadConfig.new() do
374
+ end
375
+
376
+ assert(config.optional_param_with_default_value?)
377
+ assert_equal("hello", config.optional_param_with_default_value)
378
+
379
+ assert_not(config.optional_param_without_default_value?)
380
+ assert_equal(nil, config.optional_param_without_default_value)
381
+ end
382
+
383
+ class NestedConfig < ConfigToolkit::BaseConfig
384
+ add_required_param(:name, String)
385
+ end
386
+
387
+ class ConfigWithNestedConfig < ConfigToolkit::BaseConfig
388
+ add_optional_param(:nested_config,
389
+ NestedConfig,
390
+ NestedConfig.new() { |config| config.name = "stuff" })
391
+ end
392
+
393
+ def test_nested_config
394
+ #
395
+ # Test the basic setter functionality with nested config instances.
396
+ # In particular, verify that a default nested config parameter value
397
+ # correctly is set (with the value being duped).
398
+ #
399
+ config1 = ConfigWithNestedConfig.new() { |config| }
400
+ assert_equal("stuff", config1.nested_config.name)
401
+ config1.nested_config.name = "stuff2"
402
+ assert_equal("stuff2", config1.nested_config.name)
403
+
404
+ config2 = ConfigWithNestedConfig.new() { |config| }
405
+ assert_equal("stuff", config2.nested_config.name)
406
+ assert_equal("stuff2", config1.nested_config.name) # Should be unchanged
407
+ end
408
+
409
+ class ConfigWithNestedArray < ConfigToolkit::BaseConfig
410
+ add_optional_param(:nested_array, Array, [1, 2, 3])
411
+ end
412
+
413
+ def test_nested_array
414
+ #
415
+ # Test that Array (not ConfigToolkit::ConstrainedArray) can be
416
+ # specified as a parameter value class.
417
+ #
418
+ config1 = ConfigWithNestedArray.new() { |c| }
419
+ assert_equal([1, 2, 3], config1.nested_array)
420
+ config1.nested_array = ["a", "b", "c"]
421
+
422
+ config2 = ConfigWithNestedArray.new() { |c| }
423
+ assert_equal([1, 2, 3], config2.nested_array)
424
+ assert_equal(["a", "b", "c"], config1.nested_array) # Should be unchanged
425
+ end
426
+
427
+ def test_hash_array_visitor
428
+ #
429
+ # The core functionality adequately is tested by the various writer
430
+ # unit tests.
431
+ #
432
+ visitor = ConfigToolkit::HashArrayVisitor.new()
433
+ assert_raise_message("The argument to HashArrayVisitor::visit must be a Hash or Array; instead, a Fixnum (3) was passed!", ArgumentError) do
434
+ visitor.visit(3)
435
+ end
436
+ end
323
437
  end