configtoolkit 1.2.0 → 2.0.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.
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