require 'spec_helper' require 'ronin/exploits/mixins/html' require 'ronin/exploits/exploit' describe Ronin::Exploits::Mixins::HTML do module TestHTMLMixin class TestExploit < Ronin::Exploits::Exploit include Ronin::Exploits::Mixins::HTML end end let(:test_exploit) { TestHTMLMixin::TestExploit } subject { test_exploit.new } describe "#attr_name" do let(:name) { 'foo' } it "must return the name as is" do expect(subject.attr_name(name)).to eq(name) end context "when given a Symbol" do let(:name) { :foo } it "must return the String version of the Symbol" do expect(subject.attr_name(name)).to eq(name.to_s) end end context "when given `name_case: :lower`" do let(:name) { 'FOO' } it "must convert the name to lower-case" do expect(subject.attr_name(name, name_case: :lower)).to eq(name.downcase) end end context "when given `name_case: :upper`" do it "must convert the name to upper-case" do expect(subject.attr_name(name, name_case: :upper)).to eq(name.upcase) end end context "when given `name_case: :random`" do it "must randomize the case of the name" do expect(subject.attr_name(name, name_case: :random)).to match( /\A(?:Foo|fOo|foO|FOo|FoO|fOO|FOO)\z/ ) end end end describe "#attr" do let(:name) { 'foo' } let(:value) { 'bar' } it "must return name=\"value\"" do expect(subject.attr(name,value)).to eq("#{name}=\"#{value}\"") end context "when given a Symbol for the name" do let(:name) { :foo } it "must accept a Symbol for the name" do expect(subject.attr(name,value)).to eq("#{name}=\"#{value}\"") end end context "when given a non-String for the value" do let(:value) { 42 } it "must accept a non-String for the value" do expect(subject.attr(name,value)).to eq("#{name}=\"#{value}\"") end end context "when given `name_case: :lower`" do let(:name) { 'FOO' } it "must convert the name to lower-case" do expect(subject.attr(name,value, name_case: :lower)).to eq( "#{name.downcase}=\"#{value}\"" ) end end context "when given `name_case: :upper`" do it "must convert the name to upper-case" do expect(subject.attr(name,value, name_case: :upper)).to eq( "#{name.upcase}=\"#{value}\"" ) end end context "when given `name_case: :random`" do it "must randomize the case of the name" do expect(subject.attr(name,value, name_case: :random)).to match( /\A(?:Foo|fOo|foO|FOo|FoO|fOO|FOO)=\"#{value}\"\z/ ) end end context "when given `quote: double`" do it "must quote the value with double quotes" do expect(subject.attr(name,value, quote: :double)).to eq( "#{name}=\"#{value}\"" ) end context "and when the value contains a double quote" do let(:value) { "bar\"baz" } it "must replace any double quotes with "" do expect(subject.attr(name,value)).to eq("#{name}=\"bar"baz\"") end end end context "when given `quote: single`" do it "must quote the value with single quotes" do expect(subject.attr(name,value, quote: :single)).to eq( "#{name}='#{value}'" ) end context "and when the value contains a single quote" do let(:value) { "bar'baz" } it "must replace any double quotes with ';" do expect(subject.attr(name,value, quote: :single)).to eq( "#{name}='bar'baz'" ) end end end context "when given `quote: backtick`" do it "must quote the value with backticks" do expect(subject.attr(name,value, quote: :backtick)).to eq( "#{name}=`#{value}`" ) end end context "when given `quote: nil`" do it "must not quote the value" do expect(subject.attr(name,value, quote: nil)).to eq( "#{name}=#{value}" ) end context "and when the value contains a space" do let(:value) { "bar baz" } it "must replace any spaces with &#nbsp;;" do expect(subject.attr(name,value, quote: nil)).to eq( "#{name}=bar baz" ) end end end end describe "#attr_list" do let(:name1) { 'foo' } let(:value1) { 'bar' } let(:name2) { 'baz' } let(:value2) { 'qux' } let(:attrs) { {name1 => value1, name2 => value2} } it "must return name=\"value\" ..." do expect(subject.attr_list(attrs)).to eq( "#{name1}=\"#{value1}\" #{name2}=\"#{value2}\"" ) end context "when the attributes have Symbol names" do let(:name1) { :foo } let(:name2) { :baz } it "must accept Symbols for attribute names" do expect(subject.attr_list(attrs)).to eq( "#{name1}=\"#{value1}\" #{name2}=\"#{value2}\"" ) end end context "when the attributes contains non-String values" do let(:value1) { 42 } let(:value2) { :qux } it "must accept non-Strings for attribute values" do expect(subject.attr_list(attrs)).to eq( "#{name1}=\"#{value1}\" #{name2}=\"#{value2}\"" ) end end context "when given `name_case: :lower`" do let(:name1) { 'FOO' } let(:name2) { 'BAZ' } it "must convert the attribute names to lower-case" do expect(subject.attr_list(attrs, name_case: :lower)).to eq( "#{name1.downcase}=\"#{value1}\" #{name2.downcase}=\"#{value2}\"" ) end end context "when given `name_case: :upper`" do it "must convert the attribute names to upper-case" do expect(subject.attr_list(attrs, name_case: :upper)).to eq( "#{name1.upcase}=\"#{value1}\" #{name2.upcase}=\"#{value2}\"" ) end end context "when given `name_case: :random`" do it "must randomize the case of each attribute name" do expect(subject.attr_list(attrs, name_case: :random)).to match( /\A(?:Foo|fOo|foO|FOo|FoO|fOO|FOO)=\"#{value1}\" (?:Baz|bAz|baZ|BAz|BaZ|bAZ|BAZ)=\"#{value2}\"\z/ ) end end context "when given `quote: double`" do it "must quote the attribute values with double quotes" do expect(subject.attr_list(attrs, quote: :double)).to eq( "#{name1}=\"#{value1}\" #{name2}=\"#{value2}\"" ) end context "and when an attribute value contains a double quote" do let(:value1) { "bar\"baz" } it "must replace any double quotes with "" do expect(subject.attr_list(attrs)).to eq( "#{name1}=\"bar"baz\" #{name2}=\"#{value2}\"" ) end end end context "when given `quote: single`" do it "must quote the attribute values with single quotes" do expect(subject.attr_list(attrs, quote: :single)).to eq( "#{name1}='#{value1}' #{name2}='#{value2}'" ) end context "and when an attribute value contains a single quote" do let(:value1) { "bar'baz" } it "must replace any double quotes with ';" do expect(subject.attr_list(attrs, quote: :single)).to eq( "#{name1}='bar'baz' #{name2}='#{value2}'" ) end end end context "when given `quote: backtick`" do it "must quote the attribute values with backticks" do expect(subject.attr_list(attrs, quote: :backtick)).to eq( "#{name1}=`#{value1}` #{name2}=`#{value2}`" ) end end context "when given `quote: nil`" do it "must not quote the attribute values" do expect(subject.attr_list(attrs, quote: nil)).to eq( "#{name1}=#{value1} #{name2}=#{value2}" ) end context "and when the value contains a space" do let(:value1) { "bar baz" } it "must replace any spaces with &#nbsp;;" do expect(subject.attr_list(attrs, quote: nil)).to eq( "#{name1}=bar baz #{name2}=#{value2}" ) end end end end describe "#tag_name" do let(:name) { 'foo' } it "must return the name as is" do expect(subject.tag_name(name)).to eq(name) end context "when given a Symbol" do let(:name) { :foo } it "must return the String version of the Symbol" do expect(subject.tag_name(name)).to eq(name.to_s) end end context "when given `name_case: :lower`" do let(:name) { 'FOO' } it "must convert the name to lower-case" do expect(subject.tag_name(name, name_case: :lower)).to eq(name.downcase) end end context "when given `name_case: :upper`" do it "must convert the name to upper-case" do expect(subject.tag_name(name, name_case: :upper)).to eq(name.upcase) end end context "when given `name_case: :random`" do it "must randomize the case of the name" do expect(subject.tag_name(name, name_case: :random)).to match( /\A(?:Foo|fOo|foO|FOo|FoO|fOO|FOO)\z/ ) end end end describe "#tag" do let(:name) { 'div' } context "when no block or the `text:` keyword argument is given" do it "must return " do expect(subject.tag(name)).to eq("<#{name}/>") end context "when given a Symbol" do let(:name) { :div } it "must return the String version of the Symbol" do expect(subject.tag(name)).to eq("<#{name}/>") end end context "when given `tag_case: :lower`" do let(:name) { 'DIV' } it "must convert the name to lower-case" do expect(subject.tag(name, tag_case: :lower)).to eq("<#{name.downcase}/>") end end context "when given `tag_case: :upper`" do it "must convert the name to upper-case" do expect(subject.tag(name, tag_case: :upper)).to eq("<#{name.upcase}/>") end end context "when given `tag_case: :random`" do it "must randomize the case of the name" do expect(subject.tag(name, tag_case: :random)).to match( /\A<(?:Div|dIv|diV|DIv|DiV|dIV|DIV)\/>\z/ ) end end context "when additional attributes are given" do let(:attr1) { :foo } let(:value1) { 'bar' } let(:attr2) { :baz } let(:value2) { 'qux' } let(:attrs) do {attr1 => value1, attr2 => value2} end it "must add an attributes list after the tag name" do expect(subject.tag(name,**attrs)).to eq("<#{name} #{attr1}=\"#{value1}\" #{attr2}=\"#{value2}\"/>") end context "when given `attr_case: :lower`" do let(:attr1) { :FOO } let(:attr2) { :BAZ } it "must convert the attribute names to lower-case" do expect(subject.tag(name, **attrs, attr_case: :lower)).to eq( "<#{name} #{attr1.downcase}=\"#{value1}\" #{attr2.downcase}=\"#{value2}\"/>" ) end end context "when given `attr_case: :upper`" do it "must convert the attribute names to upper-case" do expect(subject.tag(name, **attrs, attr_case: :upper)).to eq( "<#{name} #{attr1.upcase}=\"#{value1}\" #{attr2.upcase}=\"#{value2}\"/>" ) end end context "when given `attr_case: :random`" do it "must randomize the case of each attribute name" do expect(subject.tag(name, **attrs, attr_case: :random)).to match( /\A<#{name} (?:Foo|fOo|foO|FOo|FoO|fOO|FOO)=\"#{value1}\" (?:Baz|bAz|baZ|BAz|BaZ|bAZ|BAZ)=\"#{value2}\"\/>\z/ ) end end context "when given `attr_quote: double`" do it "must quote the attribute values with double quotes" do expect(subject.tag(name, **attrs, attr_quote: :double)).to eq( "<#{name} #{attr1}=\"#{value1}\" #{attr2}=\"#{value2}\"/>" ) end context "and when an attribute value contains a double quote" do let(:value1) { "bar\"baz" } it "must replace any double quotes with "" do expect(subject.tag(name, **attrs)).to eq( "<#{name} #{attr1}=\"bar"baz\" #{attr2}=\"#{value2}\"/>" ) end end end context "when given `attr_quote: single`" do it "must quote the attribute values with single quotes" do expect(subject.tag(name, **attrs, attr_quote: :single)).to eq( "<#{name} #{attr1}='#{value1}' #{attr2}='#{value2}'/>" ) end context "and when an attribute value contains a single quote" do let(:value1) { "bar'baz" } it "must replace any double quotes with ';" do expect(subject.tag(name, **attrs, attr_quote: :single)).to eq( "<#{name} #{attr1}='bar'baz' #{attr2}='#{value2}'/>" ) end end end context "when given `attr_quote: :backtick`" do it "must quote the attribute values with backticks" do expect(subject.tag(name, **attrs, attr_quote: :backtick)).to eq( "<#{name} #{attr1}=`#{value1}` #{attr2}=`#{value2}`/>" ) end end context "when given `attr_quote: nil`" do it "must not quote the attribute values" do expect(subject.tag(name, **attrs, attr_quote: nil)).to eq( "<#{name} #{attr1}=#{value1} #{attr2}=#{value2}/>" ) end context "and when the value contains a space" do let(:value1) { "bar baz" } it "must replace any spaces with &#nbsp;;" do expect(subject.tag(name, **attrs, attr_quote: nil)).to eq( "<#{name} #{attr1}=bar baz #{attr2}=#{value2}/>" ) end end end end end context "when given the `text:` keyword argument" do let(:inner_text) { 'loren ipsum' } it "must return ..." do expect(subject.tag(name, text: inner_text)).to eq( "<#{name}>#{inner_text}" ) end context "when given a Symbol" do let(:name) { :div } it "must return the String version of the Symbol" do expect(subject.tag(name, text: inner_text)).to eq( "<#{name}>#{inner_text}" ) end end context "when given `tag_case: :lower`" do let(:name) { 'DIV' } it "must convert the tag names to lower-case" do expect(subject.tag(name, tag_case: :lower, text: inner_text)).to eq( "<#{name.downcase}>#{inner_text}" ) end end context "when given `tag_case: :upper`" do it "must convert the tag names to upper-case" do expect(subject.tag(name, tag_case: :upper, text: inner_text)).to eq( "<#{name.upcase}>#{inner_text}" ) end end context "when given `tag_case: :random`" do it "must randomize the case of the tag names" do expect(subject.tag(name, tag_case: :random, text: inner_text)).to match( /\A<(?:Div|dIv|diV|DIv|DiV|dIV|DIV)>#{inner_text}<\/(?:Div|dIv|diV|DIv|DiV|dIV|DIV)>\z/ ) end end context "when additional attributes are given" do let(:attr1) { :foo } let(:value1) { 'bar' } let(:attr2) { :baz } let(:value2) { 'qux' } let(:attrs) do {attr1 => value1, attr2 => value2} end it "must add an attributes list after the tag name" do expect(subject.tag(name,**attrs, text: inner_text)).to eq( "<#{name} #{attr1}=\"#{value1}\" #{attr2}=\"#{value2}\">#{inner_text}" ) end context "when given `attr_case: :lower`" do let(:attr1) { :FOO } let(:attr2) { :BAZ } it "must convert the attribute names to lower-case" do expect(subject.tag(name, **attrs, attr_case: :lower, text: inner_text)).to eq( "<#{name} #{attr1.downcase}=\"#{value1}\" #{attr2.downcase}=\"#{value2}\">#{inner_text}" ) end end context "when given `attr_case: :upper`" do it "must convert the attribute names to upper-case" do expect(subject.tag(name, **attrs, attr_case: :upper, text: inner_text)).to eq( "<#{name} #{attr1.upcase}=\"#{value1}\" #{attr2.upcase}=\"#{value2}\">#{inner_text}" ) end end context "when given `attr_case: :random`" do it "must randomize the case of each attribute name" do expect(subject.tag(name, **attrs, attr_case: :random, text: inner_text)).to match( /\A<#{name} (?:Foo|fOo|foO|FOo|FoO|fOO|FOO)=\"#{value1}\" (?:Baz|bAz|baZ|BAz|BaZ|bAZ|BAZ)=\"#{value2}\">#{inner_text}<\/#{name}>\z/ ) end end context "when given `attr_quote: double`" do it "must quote the attribute values with double quotes" do expect(subject.tag(name, **attrs, attr_quote: :double, text: inner_text)).to eq( "<#{name} #{attr1}=\"#{value1}\" #{attr2}=\"#{value2}\">#{inner_text}" ) end context "and when an attribute value contains a double quote" do let(:value1) { "bar\"baz" } it "must replace any double quotes with "" do expect(subject.tag(name, **attrs, text: inner_text)).to eq( "<#{name} #{attr1}=\"bar"baz\" #{attr2}=\"#{value2}\">#{inner_text}" ) end end end context "when given `attr_quote: single`" do it "must quote the attribute values with single quotes" do expect(subject.tag(name, **attrs, attr_quote: :single, text: inner_text)).to eq( "<#{name} #{attr1}='#{value1}' #{attr2}='#{value2}'>#{inner_text}" ) end context "and when an attribute value contains a single quote" do let(:value1) { "bar'baz" } it "must replace any double quotes with ';" do expect(subject.tag(name, **attrs, attr_quote: :single, text: inner_text)).to eq( "<#{name} #{attr1}='bar'baz' #{attr2}='#{value2}'>#{inner_text}" ) end end end context "when given `attr_quote: :backtick`" do it "must quote the attribute values with backticks" do expect(subject.tag(name, **attrs, attr_quote: :backtick, text: inner_text)).to eq( "<#{name} #{attr1}=`#{value1}` #{attr2}=`#{value2}`>#{inner_text}" ) end end context "when given `attr_quote: nil`" do it "must not quote the attribute values" do expect(subject.tag(name, **attrs, attr_quote: nil, text: inner_text)).to eq( "<#{name} #{attr1}=#{value1} #{attr2}=#{value2}>#{inner_text}" ) end context "and when the value contains a space" do let(:value1) { "bar baz" } it "must replace any spaces with &#nbsp;;" do expect(subject.tag(name, **attrs, attr_quote: nil, text: inner_text)).to eq( "<#{name} #{attr1}=bar baz #{attr2}=#{value2}>#{inner_text}" ) end end end end end context "when given a block" do let(:inner_html) { '..." do expect(subject.tag(name) { inner_html }).to eq( "<#{name}>#{inner_html}" ) end context "when given a Symbol" do let(:name) { :div } it "must return the String version of the Symbol" do expect(subject.tag(name) { inner_html }).to eq( "<#{name}>#{inner_html}" ) end end context "when given `tag_case: :lower`" do let(:name) { 'DIV' } it "must convert the tag names to lower-case" do expect(subject.tag(name, tag_case: :lower) { inner_html }).to eq( "<#{name.downcase}>#{inner_html}" ) end end context "when given `tag_case: :upper`" do it "must convert the tag names to upper-case" do expect(subject.tag(name, tag_case: :upper) { inner_html }).to eq( "<#{name.upcase}>#{inner_html}" ) end end context "when given `tag_case: :random`" do it "must randomize the case of the tag names" do expect(subject.tag(name, tag_case: :random) { inner_html }).to match( /\A<(?:Div|dIv|diV|DIv|DiV|dIV|DIV)>#{inner_html}<\/(?:Div|dIv|diV|DIv|DiV|dIV|DIV)>\z/ ) end end context "when additional attributes are given" do let(:attr1) { :foo } let(:value1) { 'bar' } let(:attr2) { :baz } let(:value2) { 'qux' } let(:attrs) do {attr1 => value1, attr2 => value2} end it "must add an attributes list after the tag name" do expect(subject.tag(name,**attrs) { inner_html }).to eq( "<#{name} #{attr1}=\"#{value1}\" #{attr2}=\"#{value2}\">#{inner_html}" ) end context "when given `attr_case: :lower`" do let(:attr1) { :FOO } let(:attr2) { :BAZ } it "must convert the attribute names to lower-case" do expect(subject.tag(name, **attrs, attr_case: :lower) { inner_html }).to eq( "<#{name} #{attr1.downcase}=\"#{value1}\" #{attr2.downcase}=\"#{value2}\">#{inner_html}" ) end end context "when given `attr_case: :upper`" do it "must convert the attribute names to upper-case" do expect(subject.tag(name, **attrs, attr_case: :upper) { inner_html }).to eq( "<#{name} #{attr1.upcase}=\"#{value1}\" #{attr2.upcase}=\"#{value2}\">#{inner_html}" ) end end context "when given `attr_case: :random`" do it "must randomize the case of each attribute name" do expect(subject.tag(name, **attrs, attr_case: :random) { inner_html }).to match( /\A<#{name} (?:Foo|fOo|foO|FOo|FoO|fOO|FOO)=\"#{value1}\" (?:Baz|bAz|baZ|BAz|BaZ|bAZ|BAZ)=\"#{value2}\">#{inner_html}<\/#{name}>\z/ ) end end context "when given `attr_quote: double`" do it "must quote the attribute values with double quotes" do expect(subject.tag(name, **attrs, attr_quote: :double) { inner_html }).to eq( "<#{name} #{attr1}=\"#{value1}\" #{attr2}=\"#{value2}\">#{inner_html}" ) end context "and when an attribute value contains a double quote" do let(:value1) { "bar\"baz" } it "must replace any double quotes with "" do expect(subject.tag(name, **attrs) { inner_html }).to eq( "<#{name} #{attr1}=\"bar"baz\" #{attr2}=\"#{value2}\">#{inner_html}" ) end end end context "when given `attr_quote: single`" do it "must quote the attribute values with single quotes" do expect(subject.tag(name, **attrs, attr_quote: :single) { inner_html }).to eq( "<#{name} #{attr1}='#{value1}' #{attr2}='#{value2}'>#{inner_html}" ) end context "and when an attribute value contains a single quote" do let(:value1) { "bar'baz" } it "must replace any double quotes with ';" do expect(subject.tag(name, **attrs, attr_quote: :single) { inner_html }).to eq( "<#{name} #{attr1}='bar'baz' #{attr2}='#{value2}'>#{inner_html}" ) end end end context "when given `attr_quote: :backtick`" do it "must quote the attribute values with backticks" do expect(subject.tag(name, **attrs, attr_quote: :backtick) { inner_html }).to eq( "<#{name} #{attr1}=`#{value1}` #{attr2}=`#{value2}`>#{inner_html}" ) end end context "when given `attr_quote: nil`" do it "must not quote the attribute values" do expect(subject.tag(name, **attrs, attr_quote: nil) { inner_html }).to eq( "<#{name} #{attr1}=#{value1} #{attr2}=#{value2}>#{inner_html}" ) end context "and when the value contains a space" do let(:value1) { "bar baz" } it "must replace any spaces with &#nbsp;;" do expect(subject.tag(name, **attrs, attr_quote: nil) { inner_html }).to eq( "<#{name} #{attr1}=bar baz #{attr2}=#{value2}>#{inner_html}" ) end end end end end end end