#!/usr/bin/env ruby #-- # Portions copyright 2004 by Jim Weirich (jim@weirichhouse.org). # Portions copyright 2005 by Sam Ruby (rubys@intertwingly.net). # All rights reserved. # Permission is granted for use, copying, modification, distribution, # and distribution of modified versions of this work as long as the # above copyright notice is included. #++ require 'test/unit' require 'test/preload' require 'builder' require 'builder/xmlmarkup' class TestMarkup < Test::Unit::TestCase def setup @xml = Builder::XmlMarkup.new end def test_create assert_not_nil @xml end def test_simple @xml.simple assert_equal "", @xml.target! end def test_value @xml.value("hi") assert_equal "hi", @xml.target! end def test_nested @xml.outer { |x| x.inner("x") } assert_equal "x", @xml.target! end def test_attributes @xml.ref(:id => 12) assert_equal %{}, @xml.target! end def test_string_attributes_are_quoted_by_default @xml.ref(:id => "H&R") assert_equal %{}, @xml.target! end def test_symbol_attributes_are_unquoted_by_default @xml.ref(:id => :"H&R") assert_equal %{}, @xml.target! end def test_attributes_quoted_can_be_turned_on @xml = Builder::XmlMarkup.new @xml.ref(:id => "") assert_equal %{}, @xml.target! end def test_mixed_attribute_quoting_with_nested_builders x = Builder::XmlMarkup.new(:target=>@xml) @xml.ref(:id=>:"H&R") { x.element(:tag=>"Long&Short") } assert_equal "", @xml.target! end def test_multiple_attributes @xml.ref(:id => 12, :name => "bill") assert_match %r{^$}, @xml.target! end def test_attributes_with_text @xml.a("link", :href=>"http://onestepback.org") assert_equal %{link}, @xml.target! end def test_complex @xml.body(:bg=>"#ffffff") { |x| x.title("T", :style=>"red") } assert_equal %{T}, @xml.target! end def test_funky_symbol @xml.tag!("non-ruby-token", :id=>1) { |x| x.ok } assert_equal %{}, @xml.target! end def test_tag_can_handle_private_method @xml.tag!("loop", :id=>1) { |x| x.ok } assert_equal %{}, @xml.target! end def test_no_explicit_marker @xml.p { |x| x.b("HI") } assert_equal "

HI

", @xml.target! end def test_reference_local_vars n = 3 @xml.ol { |x| n.times { x.li(n) } } assert_equal "
  1. 3
  2. 3
  3. 3
", @xml.target! end def test_reference_methods @xml.title { |x| x.a { x.b(name) } } assert_equal "<a><b>bob</b></a>", @xml.target! end def test_append_text @xml.p { |x| x.br; x.text! "HI" } assert_equal "


HI

", @xml.target! end def test_ambiguous_markup ex = assert_raise(ArgumentError) { @xml.h1("data1") { b } } assert_match /\btext\b/, ex.message assert_match /\bblock\b/, ex.message end def test_capitalized_method @xml.P { |x| x.B("hi"); x.BR(); x.EM { x.text! "world" } } assert_equal "

hi
world

", @xml.target! end def test_escaping @xml.div { |x| x.text! ""; x.em("H&R Block") } assert_equal %{
<hi>H&R Block
}, @xml.target! end def test_non_escaping @xml.div("ns:xml"=>:"&xml;") { |x| x << ""; x.em("H&R Block") } assert_equal %{
H&R Block
}, @xml.target! end def test_return_value str = @xml.x("men") assert_equal @xml.target!, str end def test_stacked_builders b = Builder::XmlMarkup.new( :target => @xml ) b.div { @xml.span { @xml.a("text", :href=>"ref") } } assert_equal "", @xml.target! end def name "bob" end end class TestAttributeEscaping < Test::Unit::TestCase def setup @xml = Builder::XmlMarkup.new end def test_element_gt @xml.title('1<2') assert_equal '1<2', @xml.target! end def test_element_amp @xml.title('AT&T') assert_equal 'AT&T', @xml.target! end def test_element_amp2 @xml.title('&') assert_equal '&amp;', @xml.target! end def test_attr_less @xml.a(:title => '2>1') assert_equal '', @xml.target! end def test_attr_amp @xml.a(:title => 'AT&T') assert_equal '', @xml.target! end def test_attr_quot @xml.a(:title => '"x"') assert_equal '', @xml.target! end end class TestNameSpaces < Test::Unit::TestCase def setup @xml = Builder::XmlMarkup.new(:indent=>2) end def test_simple_name_spaces @xml.rdf :RDF assert_equal "\n", @xml.target! end def test_long xml = Builder::XmlMarkup.new(:indent=>2) xml.instruct! xml.rdf :RDF, "xmlns:rdf" => :"&rdf;", "xmlns:rdfs" => :"&rdfs;", "xmlns:xsd" => :"&xsd;", "xmlns:owl" => :"&owl;" do xml.owl :Class, :'rdf:ID'=>'Bird' do xml.rdfs :label, 'bird' xml.rdfs :subClassOf do xml.owl :Restriction do xml.owl :onProperty, 'rdf:resource'=>'#wingspan' xml.owl :maxCardinality,1,'rdf:datatype'=>'&xsd;nonNegativeInteger' end end end end assert_match /^<\?xml/, xml.target! assert_match /\n/m, xml.target! end def test_ensure xml = Builder::XmlMarkup.new xml.html do xml.body do begin xml.p do raise Exception.new('boom') end rescue Exception => e xml.pre e end end end assert_match %r{

}, xml.target! assert_match %r{

}, xml.target! end end class TestDeclarations < Test::Unit::TestCase def setup @xml = Builder::XmlMarkup.new(:indent=>2) end def test_declare @xml.declare! :element assert_equal "\n", @xml.target! end def test_bare_arg @xml.declare! :element, :arg assert_equal"\n", @xml.target! end def test_string_arg @xml.declare! :element, "string" assert_equal"\n", @xml.target! end def test_mixed_args @xml.declare! :element, :x, "y", :z, "-//OASIS//DTD DocBook XML//EN" assert_equal "\n", @xml.target! end def test_nested_declarations @xml = Builder::XmlMarkup.new @xml.declare! :DOCTYPE, :chapter do |x| x.declare! :ELEMENT, :chapter, "(title,para+)".intern end assert_equal "]>", @xml.target! end def test_nested_indented_declarations @xml.declare! :DOCTYPE, :chapter do |x| x.declare! :ELEMENT, :chapter, "(title,para+)".intern end assert_equal "\n]>\n", @xml.target! end def test_complex_declaration @xml.declare! :DOCTYPE, :chapter do |x| x.declare! :ELEMENT, :chapter, "(title,para+)".intern x.declare! :ELEMENT, :title, "(#PCDATA)".intern x.declare! :ELEMENT, :para, "(#PCDATA)".intern end expected = %{ ]> } assert_equal expected, @xml.target! end end class TestSpecialMarkup < Test::Unit::TestCase def setup @xml = Builder::XmlMarkup.new(:indent=>2) end def test_comment @xml.comment!("COMMENT") assert_equal "\n", @xml.target! end def test_indented_comment @xml.p { @xml.comment! "OK" } assert_equal "

\n \n

\n", @xml.target! end def test_instruct @xml.instruct! :abc, :version=>"0.9" assert_equal "\n", @xml.target! end def test_indented_instruct @xml.p { @xml.instruct! :xml } assert_match %r{

\n <\?xml version="1.0" encoding="UTF-8"\?>\n

\n}, @xml.target! end def test_instruct_without_attributes @xml.instruct! :zz assert_equal "\n", @xml.target! end def test_xml_instruct @xml.instruct! assert_match /^<\?xml version="1.0" encoding="UTF-8"\?>$/, @xml.target! end def test_xml_instruct_with_overrides @xml.instruct! :xml, :encoding=>"UCS-2" assert_match /^<\?xml version="1.0" encoding="UCS-2"\?>$/, @xml.target! end def test_xml_instruct_with_standalong @xml.instruct! :xml, :encoding=>"UCS-2", :standalone=>"yes" assert_match /^<\?xml version="1.0" encoding="UCS-2" standalone="yes"\?>$/, @xml.target! end def test_no_blocks assert_raise(Builder::IllegalBlockError) do @xml.instruct! { |x| x.hi } end assert_raise(Builder::IllegalBlockError) do @xml.comment!(:element) { |x| x.hi } end end def test_cdata @xml.cdata!("TEST") assert_equal "\n", @xml.target! end def test_cdata_with_ampersand @xml.cdata!("TEST&CHECK") assert_equal "\n", @xml.target! end end class TestIndentedXmlMarkup < Test::Unit::TestCase def setup @xml = Builder::XmlMarkup.new(:indent=>2) end def test_one_level @xml.ol { |x| x.li "text" } assert_equal "
    \n
  1. text
  2. \n
\n", @xml.target! end def test_two_levels @xml.p { |x| x.ol { x.li "text" } x.br } assert_equal "

\n

    \n
  1. text
  2. \n
\n
\n

\n", @xml.target! end def test_initial_level @xml = Builder::XmlMarkup.new(:indent=>2, :margin=>4) @xml.name { |x| x.first("Jim") } assert_equal " \n Jim\n \n", @xml.target! end class TestUtfMarkup < Test::Unit::TestCase if ! String.method_defined?(:encode) def setup @old_kcode = $KCODE end def teardown $KCODE = @old_kcode end def test_use_entities_if_no_encoding_is_given_and_kcode_is_none $KCODE = 'NONE' xml = Builder::XmlMarkup.new xml.p("\xE2\x80\x99") assert_match(%r(

), xml.target!) # end def test_use_entities_if_encoding_is_utf_but_kcode_is_not $KCODE = 'NONE' xml = Builder::XmlMarkup.new xml.instruct!(:xml, :encoding => 'UTF-8') xml.p("\xE2\x80\x99") assert_match(%r(

), xml.target!) # end else # change in behavior. As there is no $KCODE anymore, the default # moves from "does not understand utf-8" to "supports utf-8". def test_use_entities_if_no_encoding_is_given_and_kcode_is_none xml = Builder::XmlMarkup.new xml.p("\xE2\x80\x99") assert_match("

\u2019

", xml.target!) # end def test_use_entities_if_encoding_is_utf_but_kcode_is_not xml = Builder::XmlMarkup.new xml.instruct!(:xml, :encoding => 'UTF-8') xml.p("\xE2\x80\x99") assert_match("

\u2019

", xml.target!) # end end def encode string, encoding if !String.method_defined?(:encode) $KCODE = encoding string elsif encoding == 'UTF8' string.force_encoding('UTF-8') else string end end def test_use_entities_if_kcode_is_utf_but_encoding_is_something_else xml = Builder::XmlMarkup.new xml.instruct!(:xml, :encoding => 'UTF-16') xml.p(encode("\xE2\x80\x99", 'UTF8')) assert_match(%r(

), xml.target!) # end def test_use_utf8_if_encoding_defaults_and_kcode_is_utf8 xml = Builder::XmlMarkup.new xml.p(encode("\xE2\x80\x99",'UTF8')) assert_equal encode("

\xE2\x80\x99

",'UTF8'), xml.target! end def test_use_utf8_if_both_encoding_and_kcode_are_utf8 xml = Builder::XmlMarkup.new xml.instruct!(:xml, :encoding => 'UTF-8') xml.p(encode("\xE2\x80\x99",'UTF8')) assert_match encode("

\xE2\x80\x99

",'UTF8'), xml.target! end def test_use_utf8_if_both_encoding_and_kcode_are_utf8_with_lowercase xml = Builder::XmlMarkup.new xml.instruct!(:xml, :encoding => 'utf-8') xml.p(encode("\xE2\x80\x99",'UTF8')) assert_match encode("

\xE2\x80\x99

",'UTF8'), xml.target! end end class TestXmlEvents < Test::Unit::TestCase def setup @handler = EventHandler.new @xe = Builder::XmlEvents.new(:target=>@handler) end def test_simple @xe.p assert_equal [:start, :p, nil], @handler.events.shift assert_equal [:end, :p], @handler.events.shift end def test_text @xe.p("HI") assert_equal [:start, :p, nil], @handler.events.shift assert_equal [:text, "HI"], @handler.events.shift assert_equal [:end, :p], @handler.events.shift end def test_attributes @xe.p("id"=>"2") ev = @handler.events.shift assert_equal [:start, :p], ev[0,2] assert_equal "2", ev[2]['id'] assert_equal [:end, :p], @handler.events.shift end def test_indented @xml = Builder::XmlEvents.new(:indent=>2, :target=>@handler) @xml.p { |x| x.b("HI") } assert_equal [:start, :p, nil], @handler.events.shift assert_equal "\n ", pop_text assert_equal [:start, :b, nil], @handler.events.shift assert_equal "HI", pop_text assert_equal [:end, :b], @handler.events.shift assert_equal "\n", pop_text assert_equal [:end, :p], @handler.events.shift end def pop_text result = '' while ! @handler.events.empty? && @handler.events[0][0] == :text result << @handler.events[0][1] @handler.events.shift end result end class EventHandler attr_reader :events def initialize @events = [] end def start_tag(sym, attrs) @events << [:start, sym, attrs] end def end_tag(sym) @events << [:end, sym] end def text(txt) @events << [:text, txt] end end end end