require 'spec_helper' describe Arachni::Element::XML do inputtable_source = 'value1value2' it_should_behave_like 'element' it_should_behave_like 'with_source' it_should_behave_like 'with_auditor' it_should_behave_like 'submittable' it_should_behave_like 'inputtable' it_should_behave_like 'mutable', inputs: described_class.parse_inputs( inputtable_source ) it_should_behave_like 'auditable' before :each do @framework ||= Arachni::Framework.new @auditor = Auditor.new( Arachni::Page.from_url( url ), @framework ) end after :each do @framework.reset reset_options end let(:auditor) { @auditor } def auditable_extract_parameters( resource ) described_class.parse_inputs( resource.body ) end def run http.run end before :each do reset_options end subject { described_class.new( url: "#{url}submit", source: source ) } let(:auditable) { inputtable } let(:mutable) { inputtable } let(:inputtable) do described_class.new( url: "#{url}submit", source: 'value1value2' ) end let(:inputs) { described_class.parse_inputs( source ) } let(:source) do < Everyday Italian Giada De Laurentiis 2005 30.00 Harry Potter J K. Rowling 2005 29.99 XQuery Kick Start James McGovern Per Bothner Kurt Cagle James Linn Vaidyanathan Nagarajan 2003 49.99 Learning XML Erik T. Ray 2003 39.95 EOXML end let(:url) { utilities.normalize_url( web_server_url_for( :xml ) ) } let(:http) { Arachni::HTTP::Client } let(:utilities) { Arachni::Utilities } it 'is assigned to Arachni::Link for easy access' do expect(Arachni::XML).to eq(described_class) end describe '#initialize' do describe ':source' do it 'parses it into #inputs' do expect(subject.inputs).to eq(described_class.parse_inputs( source )) end context 'when missing' do it 'fails' do expect do described_class.new( url: "#{url}submit" ) end.to raise_error Arachni::Element::Capabilities::WithSource::Error::MissingSource end end end end describe '#simple' do it 'should return a simplified version as a hash' do expect(subject.simple).to eq({ subject.action => subject.inputs }) end end describe '#to_xml' do it 'returns the updated XML' do subject.inputs.each do |name, _| s = subject.dup s[name] = "#{name} value" expect(Nokogiri::XML(s.to_xml).css(name).first.content).to eq("#{name} value") end end end describe '#to_s' do it 'returns #to_xml' do expect(subject.to_s).to eq(subject.to_xml) end end describe '#type' do it 'should be "link"' do expect(subject.type).to eq(:xml) end end describe '#to_rpc_data' do it "includes 'source'" do expect(subject.to_rpc_data['source']).to eq(source) end end describe '.from_request' do subject { described_class.from_request( url, request ) } context 'when the request has an XML body' do let(:request) do Arachni::HTTP::Request.new( url: "#{url}-1", method: :post, body: source ) end it 'parses a request into an element' do expect(subject.url).to eq(url) expect(subject.action).to eq(request.url) expect(subject.source).to eq(request.body) expect(subject.method).to eq(request.method) end end context 'when the body is empty' do let(:request) do Arachni::HTTP::Request.new( url: "#{url}-1", method: :post ) end it 'returns nil' do expect(subject).to be_nil end end context 'when there are no inputs' do let(:request) do Arachni::HTTP::Request.new( url: "#{url}-1", method: :post, body: 'stuff' ) end it 'returns nil' do expect(subject).to be_nil end end context 'when it is' do context "equal to #{described_class::MAX_SIZE}" do let(:size) { described_class::MAX_SIZE } it 'returns nil' end context "larger than #{described_class::MAX_SIZE}" do let(:size) { described_class::MAX_SIZE + 1 } it 'returns nil' end context "smaller than #{described_class::MAX_SIZE}" do let(:size) { described_class::MAX_SIZE - 1 } it 'leaves parses it' end end end describe '.parse_inputs' do it 'parses an XML document into a hash of inputs' do expect(described_class.parse_inputs( source )).to eq({ 'bookstore > book:nth-of-type(1) > title > text()' => 'Everyday Italian', 'bookstore > book:nth-of-type(1) > title > @lang' => 'en', 'bookstore > book:nth-of-type(1) > author > text()' => 'Giada De Laurentiis', 'bookstore > book:nth-of-type(1) > year > text()' => '2005', 'bookstore > book:nth-of-type(1) > price > text()' => '30.00', 'bookstore > book:nth-of-type(1) > @category' => 'COOKING', 'bookstore > book:nth-of-type(2) > title > text()' => 'Harry Potter', 'bookstore > book:nth-of-type(2) > title > @lang' => 'en', 'bookstore > book:nth-of-type(2) > author > text()' => 'J K. Rowling', 'bookstore > book:nth-of-type(2) > year > text()' => '2005', 'bookstore > book:nth-of-type(2) > price > text()' => '29.99', 'bookstore > book:nth-of-type(2) > @category' => 'CHILDREN', 'bookstore > book:nth-of-type(3) > title > text()' => 'XQuery Kick Start', 'bookstore > book:nth-of-type(3) > title > @lang' => 'en', 'bookstore > book:nth-of-type(3) > author:nth-of-type(1) > text()' => 'James McGovern', 'bookstore > book:nth-of-type(3) > author:nth-of-type(2) > text()' => 'Per Bothner', 'bookstore > book:nth-of-type(3) > author:nth-of-type(3) > text()' => 'Kurt Cagle', 'bookstore > book:nth-of-type(3) > author:nth-of-type(4) > text()' => 'James Linn', 'bookstore > book:nth-of-type(3) > author:nth-of-type(5) > text()' => 'Vaidyanathan Nagarajan', 'bookstore > book:nth-of-type(3) > year > text()' => '2003', 'bookstore > book:nth-of-type(3) > price > text()' => '49.99', 'bookstore > book:nth-of-type(3) > @category' => 'WEB', 'bookstore > book:nth-of-type(4) > title > text()' => 'Learning XML', 'bookstore > book:nth-of-type(4) > title > @lang' => 'en', 'bookstore > book:nth-of-type(4) > author > text()' => 'Erik T. Ray', 'bookstore > book:nth-of-type(4) > year > text()' => '2003', 'bookstore > book:nth-of-type(4) > price > text()' => '39.95', 'bookstore > book:nth-of-type(4) > @category' => 'WEB' }) end end describe '#transform_xml' do it 'assigns a callback to process the resulting XML' do subject.transform_xml do |xml| expect(xml).to eq(Nokogiri::XML( subject.source ).to_xml) 'stuff' end expect(subject.to_xml).to eq('stuff') end end describe '.encode' do it 'returns the string as is' do expect(described_class.encode( 'stuff' )).to eq('stuff') end end describe '#encode' do it 'returns the string as is' do expect(subject.encode( 'stuff' )).to eq('stuff') end end describe '.decode' do it 'returns the string as is' do expect(described_class.decode( 'stuff' )).to eq('stuff') end end describe '#decode' do it 'returns the string as is' do expect(subject.decode( 'stuff' )).to eq('stuff') end end end