3 require File.dirname(__FILE__) + '/../lib/puppettest'
6 require 'puppettest/fileparsing'
8 require 'puppet/util/fileparsing'
10 class TestUtilFileParsing < Test::Unit::TestCase
12 include PuppetTest::FileParsing
15 include Puppet::Util::FileParsing
24 assert_equal("\n", @parser.line_separator,
25 "Default separator was incorrect")
27 {"\n" => ["one two\nthree four", "one two\nthree four\n"],
28 "\t" => ["one two\tthree four", "one two\tthree four\t"],
29 }.each do |sep, tests|
30 assert_nothing_raised do
31 @parser.line_separator = sep
33 assert_equal(sep, @parser.line_separator,
34 "Did not set separator")
37 assert_equal(["one two", "three four"], @parser.lines(test),
38 "Incorrectly parsed %s" % test.inspect)
43 # Make sure parse calls the appropriate methods or errors out
45 @parser.meta_def(:parse_line) do |line|
49 text = "one line\ntwo line"
50 should = [%w{one line}, %w{two line}]
52 assert_nothing_raised do
53 ret = @parser.parse(text)
56 assert_equal(should, ret)
59 # Make sure we correctly handle different kinds of text lines.
61 comment = "# this is a comment"
63 # Make sure it fails if no regex is passed
64 assert_raise(ArgumentError) do
65 @parser.text_line :comment
68 # define a text matching comment record
69 assert_nothing_raised do
70 @parser.text_line :comment, :match => /^#/
73 # Make sure it matches
74 assert_nothing_raised do
75 assert_equal({:record_type => :comment, :line => comment},
76 @parser.parse_line(comment))
79 # But not something else
80 assert_nothing_raised do
81 assert_nil(@parser.parse_line("some other text"))
84 # Now define another type and make sure we get the right one back
85 assert_nothing_raised do
86 @parser.text_line :blank, :match => /^\s*$/
89 # The comment should still match
90 assert_nothing_raised do
91 assert_equal({:record_type => :comment, :line => comment},
92 @parser.parse_line(comment))
95 # As should our new line type
96 assert_nothing_raised do
97 assert_equal({:record_type => :blank, :line => ""},
98 @parser.parse_line(""))
104 Puppet[:trace] = false
106 comment = "# this is a comment"
108 # Make sure it fails if we don't have any record types defined
109 assert_raise(Puppet::DevError) do
110 @parser.parse_line(comment)
113 # Now define a text matching comment record
114 assert_nothing_raised do
115 @parser.text_line :comment, :match => /^#/
118 # And make sure we can't define another one with the same name
119 assert_raise(ArgumentError) do
120 @parser.text_line :comment, :match => /^"/
124 assert_nothing_raised("Did not parse text line") do
125 result = @parser.parse_line comment
128 assert_equal({:record_type => :comment, :line => comment}, result)
130 # Make sure we just return nil on unmatched lines.
131 assert_nothing_raised("Did not parse text line") do
132 result = @parser.parse_line "No match for this"
135 assert_nil(result, "Somehow matched an empty line")
137 # Now define another type of comment, and make sure both types get
138 # correctly returned as comments
139 assert_nothing_raised do
140 @parser.text_line :comment2, :match => /^"/
143 assert_nothing_raised("Did not parse old comment") do
144 assert_equal({:record_type => :comment, :line => comment},
145 @parser.parse_line(comment))
147 comment = '" another type of comment'
148 assert_nothing_raised("Did not parse new comment") do
149 assert_equal({:record_type => :comment2, :line => comment},
150 @parser.parse_line(comment))
153 # Now define two overlapping record types and make sure we keep the
154 # correct order. We do first match, not longest match.
155 assert_nothing_raised do
156 @parser.text_line :one, :match => /^y/
157 @parser.text_line :two, :match => /^yay/
160 assert_nothing_raised do
161 assert_equal({:record_type => :one, :line => "yayness"},
162 @parser.parse_line("yayness"))
168 tabrecord = "tab separated content"
169 spacerecord = "space separated content"
171 # Make sure we always require an appropriate set of options
172 [{:separator => "\t"}, {}, {:fields => %w{record_type}}].each do |opts|
173 assert_raise(ArgumentError, "Accepted %s" % opts.inspect) do
174 @parser.record_line :record, opts
178 # Verify that our default separator is tabs
180 assert_nothing_raised do
181 tabs = @parser.record_line :tabs, :fields => [:name, :first, :second]
184 # Make sure out tab line gets matched
185 tabshould = {:record_type => :tabs, :name => "tab", :first => "separated",
186 :second => "content"}
187 assert_nothing_raised do
188 assert_equal(tabshould, @parser.handle_record_line(tabrecord, tabs))
191 # Now add our space-separated record type
193 assert_nothing_raised do
194 spaces = @parser.record_line :spaces, :fields => [:name, :first, :second]
197 # Now make sure both lines parse correctly
198 spaceshould = {:record_type => :spaces, :name => "space",
199 :first => "separated", :second => "content"}
201 assert_nothing_raised do
202 assert_equal(tabshould, @parser.handle_record_line(tabrecord, tabs))
203 assert_equal(spaceshould, @parser.handle_record_line(spacerecord, spaces))
208 @parser.text_line :comment, :match => /^#/
209 @parser.text_line :blank, :match => /^\s*$/
210 @parser.record_line :record, :fields => %w{name one two}, :joiner => "\t"
212 johnny = {:record_type => :record, :name => "johnny", :one => "home",
214 bill = {:record_type => :record, :name => "bill", :one => "work",
218 :comment => {:record_type => :comment, :line => "# This is a file"},
219 :blank => {:record_type => :blank, :line => ""},
225 :comment => "# This is a file",
227 :johnny => "johnny home yay",
228 :bill => "bill work boo"
231 records.each do |name, details|
233 assert_nothing_raised do
234 result = @parser.to_line(details)
237 assert_equal(lines[name], result)
239 order = [:comment, :blank, :johnny, :bill]
241 file = order.collect { |name| lines[name] }.join("\n")
243 ordered_records = order.collect { |name| records[name] }
245 # Make sure we default to a trailing separator
246 assert_equal(true, @parser.trailing_separator,
247 "Did not default to a trailing separtor")
249 # Start without a trailing separator
250 @parser.trailing_separator = false
251 assert_nothing_raised do
252 assert_equal(file, @parser.to_file(ordered_records))
255 # Now with a trailing separator
257 @parser.trailing_separator = true
258 assert_nothing_raised do
259 assert_equal(file, @parser.to_file(ordered_records))
262 # Now try it with a different separator, so we're not just catching
264 file.gsub!("\n", "\t")
265 @parser.line_separator = "\t"
266 assert_nothing_raised do
267 assert_equal(file, @parser.to_file(ordered_records))
271 # Make sure fields that are marked absent get replaced with the appropriate
273 def test_absent_fields
275 assert_nothing_raised do
276 record = @parser.record_line :record, :fields => %w{one two three},
277 :optional => %w{two three}
279 assert_equal("", record.absent, "Did not set a default absent string")
282 assert_nothing_raised do
283 result = @parser.to_line(:record_type => :record,
284 :one => "a", :two => :absent, :three => "b")
287 assert_equal("a b", result, "Absent was not correctly replaced")
289 # Now try using a different replacement character
290 record.absent = "*" # Because cron is a pain in my ass
291 assert_nothing_raised do
292 result = @parser.to_line(:record_type => :record,
293 :one => "a", :two => :absent, :three => "b")
296 assert_equal("a * b", result, "Absent was not correctly replaced")
298 # Make sure we deal correctly with the string 'absent'
299 assert_nothing_raised do
300 result = @parser.to_line(:record_type => :record,
301 :one => "a", :two => "b", :three => 'absent')
304 assert_equal("a b absent", result, "Replaced string 'absent'")
306 # And, of course, make sure we can swap things around.
307 assert_nothing_raised do
308 result = @parser.to_line(:record_type => :record,
309 :one => "a", :two => "b", :three => :absent)
312 assert_equal("a b *", result, "Absent was not correctly replaced")
315 # Make sure we can specify a different join character than split character
316 def test_split_join_record_line
317 check = proc do |start, record, final|
318 # Check parsing first
319 result = @parser.parse_line(start)
320 [:one, :two].each do |param|
321 assert_equal(record[param], result[param],
322 "Did not correctly parse %s" % start.inspect)
326 assert_equal(final, @parser.to_line(result),
327 "Did not correctly generate %s from %s" %
328 [final.inspect, record.inspect])
331 # First try it with symmetric characters
332 @parser.record_line :symmetric, :fields => %w{one two},
335 check.call "a b", {:one => "a", :two => "b"}, "a b"
336 @parser.clear_records
338 # Now assymetric but both strings
339 @parser.record_line :asymmetric, :fields => %w{one two},
340 :separator => "\t", :joiner => " "
342 check.call "a\tb", {:one => "a", :two => "b"}, "a b"
343 @parser.clear_records
345 # And assymmetric with a regex
346 @parser.record_line :asymmetric2, :fields => %w{one two},
347 :separator => /\s+/, :joiner => " "
349 check.call "a\tb", {:one => "a", :two => "b"}, "a b"
350 check.call "a b", {:one => "a", :two => "b"}, "a b"
353 # Make sure we correctly regenerate files.
355 @parser.text_line :comment, :match => /^#/
356 @parser.text_line :blank, :match => /^\s*$/
357 @parser.record_line :record, :fields => %w{name one two}
359 text = "# This is a comment
364 # Just parse and generate, to make sure it's isomorphic.
365 assert_nothing_raised do
366 assert_equal(text, @parser.to_file(@parser.parse(text)),
367 "parsing was not isomorphic")
372 @parser.record_line :record, :fields => %w{one two three}
374 assert(@parser.valid_attr?(:record, :one),
375 "one was considered invalid")
377 assert(@parser.valid_attr?(:record, :ensure),
378 "ensure was considered invalid")
380 assert(! @parser.valid_attr?(:record, :four),
381 "four was considered valid")
384 def test_record_blocks
386 assert_nothing_raised do
387 # Just do a simple test
388 options = @parser.record_line :record,
389 :fields => %w{name alias info} do |line|
392 if line.sub!(/(\w+)\s*/, '')
398 if line.sub!(/(#.+)/, '')
399 desc = $1.sub(/^#\s*/, '')
400 ret[:description] = desc unless desc == ""
404 ret[:alias] = line.split(/\s+/)
413 :description => "TCP port service multiplexer",
419 "tcpmux " => [:name],
421 "tcpmux sink" => [:name, :port, :protocols, :alias],
422 "tcpmux # TCP port service multiplexer" =>
423 [:name, :description, :port, :protocols],
424 "tcpmux sink # TCP port service multiplexer" =>
425 [:name, :description, :port, :alias, :protocols],
426 "tcpmux sink null # TCP port service multiplexer" =>
427 [:name, :description, :port, :alias, :protocols],
428 }.each do |line, should|
430 assert_nothing_raised do
431 result = @parser.handle_record_line(line, options)
433 assert(result, "Did not get a result back for '%s'" % line)
434 should.each do |field|
435 if field == :alias and line =~ /null/
436 assert_equal(%w{sink null}, result[field],
437 "Field %s was not right in '%s'" % [field, line])
439 assert_equal(values[field], result[field],
440 "Field %s was not right in '%s'" % [field, line])
448 # Make sure we correctly handle optional fields. We'll skip this
449 # functionality until we really know we need it.
450 def test_optional_fields
451 assert_nothing_raised do
452 @parser.record_line :record,
453 :fields => %w{one two three four},
454 :optional => %w{three four},
456 :separator => " " # A single space
460 "a b * d" => [:three],
461 "a b * *" => [:three, :four],
463 }.each do |line, absentees|
465 assert_nothing_raised do
466 record = @parser.parse_line(line)
469 # Absent field is :absent, not "*" inside the record
470 absentees.each do |absentee|
471 assert_equal(:absent, record[absentee])
474 # Now regenerate the line
476 assert_nothing_raised do
477 newline = @parser.to_line(record)
480 # And make sure they're equal
481 assert_equal(line, newline)
484 # Now make sure it pukes if we don't provide the required fields
485 assert_raise(ArgumentError) do
486 @parser.to_line(:record_type => :record, :one => "yay")
491 # Start with the default
492 assert_nothing_raised do
493 @parser.record_line :record,
494 :fields => %w{one two three four},
495 :optional => %w{three four}
499 @parser.to_line(:record_type => :record, :one => "a", :two => "b")
502 # Now say yes to removing
503 @parser.clear_records
504 assert_nothing_raised do
505 @parser.record_line :record,
506 :fields => %w{one two three four},
507 :optional => %w{three four},
512 @parser.to_line(:record_type => :record, :one => "a", :two => "b")
515 # Lastly, try a regex
516 @parser.clear_records
517 assert_nothing_raised do
518 @parser.record_line :record,
519 :fields => %w{one two three four},
520 :optional => %w{three four},
526 @parser.to_line(:record_type => :record, :one => "a", :two => "b")
530 # Make sure the last field can contain the separator, as crontabs do, and
531 # that we roll them all up by default.
532 def test_field_rollups
533 @parser.record_line :yes, :fields => %w{name one two}
536 assert_nothing_raised do
537 result = @parser.send(:parse_line, "Name One Two Three")
539 assert_equal("Two Three", result[:two],
540 "Did not roll up last fields by default")
542 @parser = FParser.new
543 assert_nothing_raised("Could not create record that rolls up fields") do
544 @parser.record_line :no, :fields => %w{name one two}, :rollup => false
548 assert_nothing_raised do
549 result = @parser.send(:parse_line, "Name One Two Three")
551 assert_equal("Two", result[:two],
552 "Rolled up last fields when rollup => false")
557 assert_nothing_raised do
558 record = @parser.text_line :name, :match => %r{^#} do |line|
559 {:line => line.upcase}
563 assert(record.respond_to?(:process),
564 "Block was not used with text line")
566 assert_equal("YAYNESS", record.process("yayness")[:line],
567 "Did not call process method")
572 # First try it with a normal record
573 assert_nothing_raised("Could not set hooks") do
574 record = @parser.record_line :yay, :fields => %w{one two},
575 :post_parse => proc { |hash| hash[:posted] = true },
576 :pre_gen => proc { |hash| hash[:one] = hash[:one].upcase },
577 :to_line => proc { |hash| "# Line\n" + join(hash) }
580 assert(record.respond_to?(:post_parse), "did not create method for post-hook")
581 assert(record.respond_to?(:pre_gen), "did not create method for pre-hook")
584 assert_nothing_raised("Could not process line with hooks") do
585 result = @parser.parse_line("one two")
588 assert(result[:posted], "Did not run post-hook")
591 # Now make sure our pre-gen hook is called
592 assert_nothing_raised("Could not generate line with hooks") do
593 result = @parser.to_line(result)
595 assert_equal("# Line\nONE two", result, "did not call pre-gen hook")
596 assert_equal("one", old_result[:one], "passed original hash to pre hook")
600 class TestUtilFileRecord < Test::Unit::TestCase
602 include PuppetTest::FileParsing
604 Record = Puppet::Util::FileParsing::FileRecord
605 def test_new_filerecord
609 assert_raise(ArgumentError, "Did not fail on %s" % args.inspect) do
614 # Make sure the fields get turned into symbols
616 assert_nothing_raised do
617 record = Record.new(:record, :fields => %w{one two})
619 assert_equal([:one, :two], record.fields,
620 "Did not symbolize fields")
622 # Make sure we fail on invalid fields
623 [:record_type, :target, :on_disk].each do |field|
624 assert_raise(ArgumentError, "Did not fail on invalid field %s" % field) {
625 Record.new(:record, :fields => [field])
631 record = Record.new(:text, :match => %r{^#})
632 [:absent, :separator, :joiner, :optional].each do |field|
633 assert_nil(record.send(field), "%s was not nil" % field)
636 record = Record.new(:record, :fields => %w{fields})
637 {:absent => "", :separator => /\s+/, :joiner => " ",
638 :optional => []}.each do |field, default|
639 assert_equal(default, record.send(field), "%s was not default" % field)
645 assert_nothing_raised("Could not pass a block when creating record") do
646 record = Record.new(:record, :fields => %w{one}) do |line|
651 line = "This is a line"
653 assert(record.respond_to?(:process),
654 "Record did not define :process method")
656 assert_equal(line.upcase, record.process(line),
657 "Record did not process line correctly")
660 # Make sure we can declare that we want the block to be instance-eval'ed instead of
661 # defining the 'process' method.
662 def test_instance_block
664 assert_nothing_raised("Could not pass a block when creating record") do
665 record = Record.new(:record, :block_eval => :instance, :fields => %w{one}) do
676 assert(record.respond_to?(:process), "Block was not instance-eval'ed and process was not defined")
677 assert(record.respond_to?(:to_line), "Block was not instance-eval'ed and to_line was not defined")
680 assert_equal(line.upcase, record.process(line), "Instance-eval'ed record did not call :process correctly")
681 assert_equal(line.upcase, record.to_line(line), "Instance-eval'ed record did not call :to_line correctly")