#!/usr/bin/env ruby
$:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/
require 'puppettest'
require 'puppettest/fileparsing'
require 'puppet'
require 'puppet/util/fileparsing'
class TestUtilFileParsing < Test::Unit::TestCase
include PuppetTest
include PuppetTest::FileParsing
class FParser
include Puppet::Util::FileParsing
end
def setup
super
@parser = FParser.new
end
def test_lines
assert_equal("\n", @parser.line_separator,
"Default separator was incorrect")
{"\n" => ["one two\nthree four", "one two\nthree four\n"],
"\t" => ["one two\tthree four", "one two\tthree four\t"],
}.each do |sep, tests|
assert_nothing_raised do
@parser.line_separator = sep
end
assert_equal(sep, @parser.line_separator,
"Did not set separator")
tests.each do |test|
assert_equal(["one two", "three four"], @parser.lines(test),
"Incorrectly parsed %s" % test.inspect)
end
end
end
# Make sure parse calls the appropriate methods or errors out
def test_parse
@parser.meta_def(:parse_line) do |line|
line.split(/\s+/)
end
text = "one line\ntwo line"
should = [%w{one line}, %w{two line}]
ret = nil
assert_nothing_raised do
ret = @parser.parse(text)
end
assert_equal(should, ret)
end
# Make sure we correctly handle different kinds of text lines.
def test_text_line
comment = "# this is a comment"
# Make sure it fails if no regex is passed
assert_raise(ArgumentError) do
@parser.text_line :comment
end
# define a text matching comment record
assert_nothing_raised do
@parser.text_line :comment, :match => /^#/
end
# Make sure it matches
assert_nothing_raised do
assert_equal({:record_type => :comment, :line => comment},
@parser.parse_line(comment))
end
# But not something else
assert_nothing_raised do
assert_nil(@parser.parse_line("some other text"))
end
# Now define another type and make sure we get the right one back
assert_nothing_raised do
@parser.text_line :blank, :match => /^\s*$/
end
# The comment should still match
assert_nothing_raised do
assert_equal({:record_type => :comment, :line => comment},
@parser.parse_line(comment))
end
# As should our new line type
assert_nothing_raised do
assert_equal({:record_type => :blank, :line => ""},
@parser.parse_line(""))
end
end
def test_parse_line
Puppet[:trace] = false
comment = "# this is a comment"
# Make sure it fails if we don't have any record types defined
assert_raise(Puppet::DevError) do
@parser.parse_line(comment)
end
# Now define a text matching comment record
assert_nothing_raised do
@parser.text_line :comment, :match => /^#/
end
# And make sure we can't define another one with the same name
assert_raise(ArgumentError) do
@parser.text_line :comment, :match => /^"/
end
result = nil
assert_nothing_raised("Did not parse text line") do
result = @parser.parse_line comment
end
assert_equal({:record_type => :comment, :line => comment}, result)
# Make sure we just return nil on unmatched lines.
assert_nothing_raised("Did not parse text line") do
result = @parser.parse_line "No match for this"
end
assert_nil(result, "Somehow matched an empty line")
# Now define another type of comment, and make sure both types get
# correctly returned as comments
assert_nothing_raised do
@parser.text_line :comment2, :match => /^"/
end
assert_nothing_raised("Did not parse old comment") do
assert_equal({:record_type => :comment, :line => comment},
@parser.parse_line(comment))
end
comment = '" another type of comment'
assert_nothing_raised("Did not parse new comment") do
assert_equal({:record_type => :comment2, :line => comment},
@parser.parse_line(comment))
end
# Now define two overlapping record types and make sure we keep the
# correct order. We do first match, not longest match.
assert_nothing_raised do
@parser.text_line :one, :match => /^y/
@parser.text_line :two, :match => /^yay/
end
assert_nothing_raised do
assert_equal({:record_type => :one, :line => "yayness"},
@parser.parse_line("yayness"))
end
end
def test_record_line
tabrecord = "tab separated content"
spacerecord = "space separated content"
# Make sure we always require an appropriate set of options
[{:separator => "\t"}, {}, {:fields => %w{record_type}}].each do |opts|
assert_raise(ArgumentError, "Accepted %s" % opts.inspect) do
@parser.record_line :record, opts
end
end
# Verify that our default separator is tabs
tabs = nil
assert_nothing_raised do
tabs = @parser.record_line :tabs, :fields => [:name, :first, :second]
end
# Make sure out tab line gets matched
tabshould = {:record_type => :tabs, :name => "tab", :first => "separated",
:second => "content"}
assert_nothing_raised do
assert_equal(tabshould, @parser.handle_record_line(tabrecord, tabs))
end
# Now add our space-separated record type
spaces = nil
assert_nothing_raised do
spaces = @parser.record_line :spaces, :fields => [:name, :first, :second]
end
# Now make sure both lines parse correctly
spaceshould = {:record_type => :spaces, :name => "space",
:first => "separated", :second => "content"}
assert_nothing_raised do
assert_equal(tabshould, @parser.handle_record_line(tabrecord, tabs))
assert_equal(spaceshould, @parser.handle_record_line(spacerecord, spaces))
end
end
def test_to_line
@parser.text_line :comment, :match => /^#/
@parser.text_line :blank, :match => /^\s*$/
@parser.record_line :record, :fields => %w{name one two}, :joiner => "\t"
johnny = {:record_type => :record, :name => "johnny", :one => "home",
:two => "yay"}
bill = {:record_type => :record, :name => "bill", :one => "work",
:two => "boo"}
records = {
:comment => {:record_type => :comment, :line => "# This is a file"},
:blank => {:record_type => :blank, :line => ""},
:johnny => johnny,
:bill => bill
}
lines = {
:comment => "# This is a file",
:blank => "",
:johnny => "johnny home yay",
:bill => "bill work boo"
}
records.each do |name, details|
result = nil
assert_nothing_raised do
result = @parser.to_line(details)
end
assert_equal(lines[name], result)
end
order = [:comment, :blank, :johnny, :bill]
file = order.collect { |name| lines[name] }.join("\n")
ordered_records = order.collect { |name| records[name] }
# Make sure we default to a trailing separator
assert_equal(true, @parser.trailing_separator,
"Did not default to a trailing separtor")
# Start without a trailing separator
@parser.trailing_separator = false
assert_nothing_raised do
assert_equal(file, @parser.to_file(ordered_records))
end
# Now with a trailing separator
file += "\n"
@parser.trailing_separator = true
assert_nothing_raised do
assert_equal(file, @parser.to_file(ordered_records))
end
# Now try it with a different separator, so we're not just catching
# defaults
file.gsub!("\n", "\t")
@parser.line_separator = "\t"
assert_nothing_raised do
assert_equal(file, @parser.to_file(ordered_records))
end
end
# Make sure fields that are marked absent get replaced with the appropriate
# string.
def test_absent_fields
record = nil
assert_nothing_raised do
record = @parser.record_line :record, :fields => %w{one two three},
:optional => %w{two three}
end
assert_equal("", record.absent, "Did not set a default absent string")
result = nil
assert_nothing_raised do
result = @parser.to_line(:record_type => :record,
:one => "a", :two => :absent, :three => "b")
end
assert_equal("a b", result, "Absent was not correctly replaced")
# Now try using a different replacement character
record.absent = "*" # Because cron is a pain in my ass
assert_nothing_raised do
result = @parser.to_line(:record_type => :record,
:one => "a", :two => :absent, :three => "b")
end
assert_equal("a * b", result, "Absent was not correctly replaced")
# Make sure we deal correctly with the string 'absent'
assert_nothing_raised do
result = @parser.to_line(:record_type => :record,
:one => "a", :two => "b", :three => 'absent')
end
assert_equal("a b absent", result, "Replaced string 'absent'")
# And, of course, make sure we can swap things around.
assert_nothing_raised do
result = @parser.to_line(:record_type => :record,
:one => "a", :two => "b", :three => :absent)
end
assert_equal("a b *", result, "Absent was not correctly replaced")
end
# Make sure we can specify a different join character than split character
def test_split_join_record_line
check = proc do |start, record, final|
# Check parsing first
result = @parser.parse_line(start)
[:one, :two].each do |param|
assert_equal(record[param], result[param],
"Did not correctly parse %s" % start.inspect)
end
# And generating
assert_equal(final, @parser.to_line(result),
"Did not correctly generate %s from %s" %
[final.inspect, record.inspect])
end
# First try it with symmetric characters
@parser.record_line :symmetric, :fields => %w{one two},
:separator => " "
check.call "a b", {:one => "a", :two => "b"}, "a b"
@parser.clear_records
# Now assymetric but both strings
@parser.record_line :asymmetric, :fields => %w{one two},
:separator => "\t", :joiner => " "
check.call "a\tb", {:one => "a", :two => "b"}, "a b"
@parser.clear_records
# And assymmetric with a regex
@parser.record_line :asymmetric2, :fields => %w{one two},
:separator => /\s+/, :joiner => " "
check.call "a\tb", {:one => "a", :two => "b"}, "a b"
check.call "a b", {:one => "a", :two => "b"}, "a b"
end
# Make sure we correctly regenerate files.
def test_to_file
@parser.text_line :comment, :match => /^#/
@parser.text_line :blank, :match => /^\s*$/
@parser.record_line :record, :fields => %w{name one two}
text = "# This is a comment
johnny one two
billy three four\n"
# Just parse and generate, to make sure it's isomorphic.
assert_nothing_raised do
assert_equal(text, @parser.to_file(@parser.parse(text)),
"parsing was not isomorphic")
end
end
def test_valid_attrs
@parser.record_line :record, :fields => %w{one two three}
assert(@parser.valid_attr?(:record, :one),
"one was considered invalid")
assert(@parser.valid_attr?(:record, :ensure),
"ensure was considered invalid")
assert(! @parser.valid_attr?(:record, :four),
"four was considered valid")
end
def test_record_blocks
options = nil
assert_nothing_raised do
# Just do a simple test
options = @parser.record_line :record,
:fields => %w{name alias info} do |line|
line = line.dup
ret = {}
if line.sub!(/(\w+)\s*/, '')
ret[:name] = $1
else
return nil
end
if line.sub!(/(#.+)/, '')
desc = $1.sub(/^#\s*/, '')
ret[:description] = desc unless desc == ""
end
if line != ""
ret[:alias] = line.split(/\s+/)
end
return ret
end
end
values = {
:name => "tcpmux",
:description => "TCP port service multiplexer",
:alias => ["sink"]
}
{
"tcpmux " => [:name],
"tcpmux" => [:name],
"tcpmux sink" => [:name, :port, :protocols, :alias],
"tcpmux # TCP port service multiplexer" =>
[:name, :description, :port, :protocols],
"tcpmux sink # TCP port service multiplexer" =>
[:name, :description, :port, :alias, :protocols],
"tcpmux sink null # TCP port service multiplexer" =>
[:name, :description, :port, :alias, :protocols],
}.each do |line, should|
result = nil
assert_nothing_raised do
result = @parser.handle_record_line(line, options)
end
assert(result, "Did not get a result back for '%s'" % line)
should.each do |field|
if field == :alias and line =~ /null/
assert_equal(%w{sink null}, result[field],
"Field %s was not right in '%s'" % [field, line])
else
assert_equal(values[field], result[field],
"Field %s was not right in '%s'" % [field, line])
end
end
end
end
# Make sure we correctly handle optional fields. We'll skip this
# functionality until we really know we need it.
def test_optional_fields
assert_nothing_raised do
@parser.record_line :record,
:fields => %w{one two three four},
:optional => %w{three four},
:absent => "*",
:separator => " " # A single space
end
["a b c d", "a b * d", "a b * *", "a b c *"].each do |line|
record = nil
assert_nothing_raised do
record = @parser.parse_line(line)
end
# Now regenerate the line
newline = nil
assert_nothing_raised do
newline = @parser.to_line(record)
end
# And make sure they're equal
assert_equal(line, newline)
end
# Now make sure it pukes if we don't provide the required fields
assert_raise(ArgumentError) do
@parser.to_line(:record_type => :record, :one => "yay")
end
end
def test_record_rts
# Start with the default
assert_nothing_raised do
@parser.record_line :record,
:fields => %w{one two three four},
:optional => %w{three four}
end
assert_equal("a b ",
@parser.to_line(:record_type => :record, :one => "a", :two => "b")
)
# Now say yes to removing
@parser.clear_records
assert_nothing_raised do
@parser.record_line :record,
:fields => %w{one two three four},
:optional => %w{three four},
:rts => true
end
assert_equal("a b",
@parser.to_line(:record_type => :record, :one => "a", :two => "b")
)
# Lastly, try a regex
@parser.clear_records
assert_nothing_raised do
@parser.record_line :record,
:fields => %w{one two three four},
:optional => %w{three four},
:absent => "*",
:rts => /[ *]+$/
end
assert_equal("a b",
@parser.to_line(:record_type => :record, :one => "a", :two => "b")
)
end
# Make sure the last field can contain the separator, as crontabs do, and
# that we roll them all up by default.
def test_field_rollups
@parser.record_line :yes, :fields => %w{name one two}
result = nil
assert_nothing_raised do
result = @parser.send(:parse_line, "Name One Two Three")
end
assert_equal("Two Three", result[:two],
"Did not roll up last fields by default")
@parser = FParser.new
assert_nothing_raised("Could not create record that rolls up fields") do
@parser.record_line :no, :fields => %w{name one two}, :rollup => false
end
result = nil
assert_nothing_raised do
result = @parser.send(:parse_line, "Name One Two Three")
end
assert_equal("Two", result[:two],
"Rolled up last fields when rollup => false")
end
def test_text_blocks
record = nil
assert_nothing_raised do
record = @parser.text_line :name, :match => %r{^#} do |line|
{:line => line.upcase}
end
end
assert(record.respond_to?(:process),
"Block was not used with text line")
assert_equal("YAYNESS", record.process("yayness")[:line],
"Did not call process method")
end
def test_hooks
record = nil
# First try it with a normal record
assert_nothing_raised("Could not set hooks") do
record = @parser.record_line :yay, :fields => %w{one two},
:post_parse => proc { |hash| hash[:posted] = true },
:pre_gen => proc { |hash| hash[:one] = hash[:one].upcase },
:to_line => proc { |hash| "# Line\n" + join(hash) }
end
assert(record.respond_to?(:post_parse), "did not create method for post-hook")
assert(record.respond_to?(:pre_gen), "did not create method for pre-hook")
result = nil
assert_nothing_raised("Could not process line with hooks") do
result = @parser.parse_line("one two")
end
assert(result[:posted], "Did not run post-hook")
old_result = result
# Now make sure our pre-gen hook is called
assert_nothing_raised("Could not generate line with hooks") do
result = @parser.to_line(result)
end
assert_equal("# Line\nONE two", result, "did not call pre-gen hook")
assert_equal("one", old_result[:one], "passed original hash to pre hook")
end
end
class TestUtilFileRecord < Test::Unit::TestCase
include PuppetTest
include PuppetTest::FileParsing
Record = Puppet::Util::FileParsing::FileRecord
def test_new_filerecord
[ [:fake, {}],
[nil, ]
].each do |args|
assert_raise(ArgumentError, "Did not fail on %s" % args.inspect) do
Record.new(*args)
end
end
# Make sure the fields get turned into symbols
record = nil
assert_nothing_raised do
record = Record.new(:record, :fields => %w{one two})
end
assert_equal([:one, :two], record.fields,
"Did not symbolize fields")
# Make sure we fail on invalid fields
[:record_type, :target, :on_disk].each do |field|
assert_raise(ArgumentError, "Did not fail on invalid field %s" % field) {
Record.new(:record, :fields => [field])
}
end
end
def test_defaults
record = Record.new(:text, :match => %r{^#})
[:absent, :separator, :joiner, :optional].each do |field|
assert_nil(record.send(field), "%s was not nil" % field)
end
record = Record.new(:record, :fields => %w{fields})
{:absent => "", :separator => /\s+/, :joiner => " ",
:optional => []}.each do |field, default|
assert_equal(default, record.send(field), "%s was not default" % field)
end
end
def test_block
record = nil
assert_nothing_raised("Could not pass a block when creating record") do
record = Record.new(:record, :fields => %w{one}) do |line|
return line.upcase
end
end
line = "This is a line"
assert(record.respond_to?(:process),
"Record did not define :process method")
assert_equal(line.upcase, record.process(line),
"Record did not process line correctly")
end
# Make sure we can declare that we want the block to be instance-eval'ed instead of
# defining the 'process' method.
def test_instance_block
record = nil
assert_nothing_raised("Could not pass a block when creating record") do
record = Record.new(:record, :block_eval => :instance, :fields => %w{one}) do
def process(line)
line.upcase
end
def to_line(details)
details.upcase
end
end
end
assert(record.respond_to?(:process), "Block was not instance-eval'ed and process was not defined")
assert(record.respond_to?(:to_line), "Block was not instance-eval'ed and to_line was not defined")
line = "some text"
assert_equal(line.upcase, record.process(line), "Instance-eval'ed record did not call :process correctly")
assert_equal(line.upcase, record.to_line(line), "Instance-eval'ed record did not call :to_line correctly")
end
end
# $Id: fileparsing.rb 2407 2007-04-23 18:01:36Z luke $
syntax highlighted by Code2HTML, v. 0.9.1