relevance-tarantula 0.2.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,47 +4,64 @@ describe "Relevance::Tarantula::Link" do
4
4
  include ActionView::Helpers::UrlHelper
5
5
 
6
6
  it "does not raise an error when initializing without href attribtue" do
7
- link = Relevance::Tarantula::Link.new(Hpricot('<a="/foo">foo</a>').at('a'))
7
+ link = make_link(Hpricot('<a="/foo">foo</a>').at('a'))
8
8
  link.href.should == nil
9
9
  link.method.should == :get
10
10
  end
11
11
 
12
12
  it "parses anchor tags" do
13
- link = Relevance::Tarantula::Link.new(Hpricot('<a href="/foo">foo</a>').at('a'))
13
+ link = make_link(Hpricot('<a href="/foo">foo</a>').at('a'))
14
14
  link.href.should == '/foo'
15
15
  link.method.should == :get
16
16
  end
17
17
 
18
18
  it "parses anchor tags with POST 'method'" do
19
- link = Relevance::Tarantula::Link.new(Hpricot(%Q{<a href="/foo" onclick="#{method_javascript_function(:post)}">foo</a>}).at('a'))
19
+ link = make_link(Hpricot(%Q{<a href="/foo" onclick="#{method_javascript_function(:post)}">foo</a>}).at('a'))
20
20
  link.href.should == '/foo'
21
21
  link.method.should == :post
22
22
  end
23
23
 
24
24
  it "parses anchor tags with PUT 'method'" do
25
- link = Relevance::Tarantula::Link.new(Hpricot(%Q{<a href="/foo" onclick="#{method_javascript_function(:put)}">foo</a>}).at('a'))
25
+ link = make_link(Hpricot(%Q{<a href="/foo" onclick="#{method_javascript_function(:put)}">foo</a>}).at('a'))
26
26
  link.href.should == '/foo'
27
27
  link.method.should == :put
28
28
  end
29
29
 
30
30
  it "parses anchor tags with DELETE 'method'" do
31
- link = Relevance::Tarantula::Link.new(Hpricot(%Q{<a href="/foo" onclick="#{method_javascript_function(:delete)}">foo</a>}).at('a'))
31
+ link = make_link(Hpricot(%Q{<a href="/foo" onclick="#{method_javascript_function(:delete)}">foo</a>}).at('a'))
32
32
  link.href.should == '/foo'
33
33
  link.method.should == :delete
34
34
  end
35
35
 
36
36
  it "parses link tags with text" do
37
- link = Relevance::Tarantula::Link.new(Hpricot('<link href="/bar">bar</a>').at('link'))
37
+ link = make_link(Hpricot('<link href="/bar">bar</a>').at('link'))
38
38
  link.href.should == '/bar'
39
39
  link.method.should == :get
40
40
  end
41
41
 
42
42
  it "parses link tags without text" do
43
- link = Relevance::Tarantula::Link.new(Hpricot('<link href="/bar" />').at('link'))
43
+ link = make_link(Hpricot('<link href="/bar" />').at('link'))
44
44
  link.href.should == '/bar'
45
45
  link.method.should == :get
46
46
  end
47
47
 
48
+ it 'remembers link referrer if there is one' do
49
+ link = make_link('/url', stub_everything, '/some-referrer')
50
+ link.referrer.should == '/some-referrer'
51
+ end
52
+
53
+ it "does two things when crawled: follow, log, and handle" do
54
+ crawler = Relevance::Tarantula::Crawler.new
55
+ link = make_link('/foo', crawler)
56
+
57
+ response = stub(:code => "200")
58
+ crawler.expects(:follow).returns(response)
59
+ link.expects(:log)
60
+ crawler.expects(:handle_link_results)
61
+
62
+ link.crawl
63
+ end
64
+
48
65
  # method_javascript_function needs this method
49
66
  def protect_against_forgery?
50
67
  false
@@ -10,6 +10,9 @@ class Relevance::Tarantula::Attack
10
10
  def ==(other)
11
11
  Relevance::Tarantula::Attack === other && HASHABLE_ATTRS.all? { |attr| send(attr) == other.send(attr)}
12
12
  end
13
+ def input(input_field=nil)
14
+ @input
15
+ end
13
16
  end
14
17
 
15
18
 
@@ -4,7 +4,7 @@ class Relevance::Tarantula::AttackHandler
4
4
  include ERB::Util
5
5
 
6
6
  def attacks
7
- Relevance::Tarantula::AttackFormSubmission.attacks.select(&:output)
7
+ Relevance::Tarantula::FormSubmission.attacks.select(&:output)
8
8
  end
9
9
 
10
10
  def handle(result)
@@ -0,0 +1,40 @@
1
+ class Relevance::Tarantula::BasicAttack
2
+ ATTRS = [:name, :output, :description]
3
+
4
+ attr_reader *ATTRS
5
+
6
+ def initialize
7
+ @name = "Tarantula Basic Fuzzer"
8
+ @output = nil
9
+ @description = "Supplies purely random but simplistically generated form input."
10
+ end
11
+
12
+ def ==(other)
13
+ Relevance::Tarantula::BasicAttack === other && ATTRS.all? { |attr| send(attr) == other.send(attr)}
14
+ end
15
+
16
+ def input(input_field)
17
+ case input_field['name']
18
+ when /amount/ then random_int
19
+ when /_id$/ then random_whole_number
20
+ when /uploaded_data/ then nil
21
+ when nil then input['value']
22
+ else
23
+ random_int
24
+ end
25
+ end
26
+
27
+ def big_number
28
+ 10000 # arbitrary
29
+ end
30
+
31
+ def random_int
32
+ rand(big_number) - (big_number/2)
33
+ end
34
+
35
+ def random_whole_number
36
+ rand(big_number)
37
+ end
38
+ end
39
+
40
+
@@ -10,7 +10,7 @@ class Relevance::Tarantula::Crawler
10
10
  class CrawlTimeout < RuntimeError; end
11
11
 
12
12
  attr_accessor :proxy, :handlers, :skip_uri_patterns, :log_grabber,
13
- :reporters, :links_to_crawl, :links_queued, :forms_to_crawl,
13
+ :reporters, :crawl_queue, :links_queued,
14
14
  :form_signatures_queued, :max_url_length, :response_code_handler,
15
15
  :times_to_crawl, :fuzzers, :test_name, :crawl_timeout
16
16
  attr_reader :transform_url_patterns, :referrers, :failures, :successes, :crawl_start_times, :crawl_end_times
@@ -22,8 +22,7 @@ class Relevance::Tarantula::Crawler
22
22
  @handlers = [@response_code_handler = Result]
23
23
  @links_queued = Set.new
24
24
  @form_signatures_queued = Set.new
25
- @links_to_crawl = []
26
- @forms_to_crawl = []
25
+ @crawl_queue = []
27
26
  @crawl_start_times, @crawl_end_times = [], []
28
27
  @crawl_timeout = 20.minutes
29
28
  @referrers = {}
@@ -55,8 +54,7 @@ class Relevance::Tarantula::Crawler
55
54
  def crawl(url = "/")
56
55
  orig_links_queued = @links_queued.dup
57
56
  orig_form_signatures_queued = @form_signatures_queued.dup
58
- orig_links_to_crawl = @links_to_crawl.dup
59
- orig_forms_to_crawl = @forms_to_crawl.dup
57
+ orig_crawl_queue = @crawl_queue.dup
60
58
  @times_to_crawl.times do |num|
61
59
  queue_link url
62
60
 
@@ -71,8 +69,7 @@ class Relevance::Tarantula::Crawler
71
69
  if num + 1 < @times_to_crawl
72
70
  @links_queued = orig_links_queued
73
71
  @form_signatures_queued = orig_form_signatures_queued
74
- @links_to_crawl = orig_links_to_crawl
75
- @forms_to_crawl = orig_forms_to_crawl
72
+ @crawl_queue = orig_crawl_queue
76
73
  @referrers = {}
77
74
  end
78
75
  end
@@ -83,23 +80,20 @@ class Relevance::Tarantula::Crawler
83
80
  end
84
81
 
85
82
  def finished?
86
- @links_to_crawl.empty? && @forms_to_crawl.empty?
83
+ @crawl_queue.empty?
87
84
  end
88
85
 
89
86
  def do_crawl(number)
90
87
  while (!finished?)
91
88
  @crawl_start_times << Time.now
92
- crawl_queued_links(number)
93
- crawl_queued_forms(number)
89
+ crawl_the_queue(number)
94
90
  @crawl_end_times << Time.now
95
91
  end
96
92
  end
97
93
 
98
- def crawl_queued_links(number = 0)
99
- while (link = @links_to_crawl.pop)
100
- response = proxy.send(link.method, link.href)
101
- log "Response #{response.code} for #{link}"
102
- handle_link_results(link, response)
94
+ def crawl_the_queue(number = 0)
95
+ while (request = @crawl_queue.pop)
96
+ request.crawl
103
97
  blip(number)
104
98
  end
105
99
  end
@@ -110,15 +104,10 @@ class Relevance::Tarantula::Crawler
110
104
  end
111
105
  end
112
106
 
113
- def handle_link_results(link, response)
107
+ def handle_link_results(link, result)
114
108
  handlers.each do |h|
115
109
  begin
116
- save_result h.handle(Result.new(:method => link.method,
117
- :url => link.href,
118
- :response => response,
119
- :log => grab_log!,
120
- :referrer => referrers[link],
121
- :test_name => test_name).freeze)
110
+ save_result h.handle(result)
122
111
  rescue Exception => e
123
112
  log "error handling #{link} #{e.message}"
124
113
  # TODO: pass to results
@@ -126,23 +115,14 @@ class Relevance::Tarantula::Crawler
126
115
  end
127
116
  end
128
117
 
129
- def crawl_form(form)
130
- response = proxy.send(form.method, form.action, form.data)
131
- log "Response #{response.code} for #{form}"
132
- response
133
- rescue ActiveRecord::RecordNotFound => e
134
- log "Skipping #{form.action}, presumed ok that record is missing"
135
- Relevance::Tarantula::Response.new(:code => "404", :body => e.message, :content_type => "text/plain")
136
- end
137
-
138
- def crawl_queued_forms(number = 0)
139
- while (form = @forms_to_crawl.pop)
140
- response = crawl_form(form)
141
- handle_form_results(form, response)
142
- blip(number)
143
- end
118
+ def follow(method, url, data=nil)
119
+ proxy.send(method, url, data)
144
120
  end
145
121
 
122
+ def submit(method, action, data)
123
+ proxy.send(method, action, data)
124
+ end
125
+
146
126
  def elasped_time_for_pass(num)
147
127
  Time.now - crawl_start_times[num]
148
128
  end
@@ -150,6 +130,14 @@ class Relevance::Tarantula::Crawler
150
130
  def grab_log!
151
131
  @log_grabber && @log_grabber.grab!
152
132
  end
133
+
134
+ def make_result(options)
135
+ defaults = {
136
+ :log => grab_log!,
137
+ :test_name => test_name
138
+ }
139
+ Result.new(defaults.merge(options)).freeze
140
+ end
153
141
 
154
142
  def handle_form_results(form, response)
155
143
  handlers.each do |h|
@@ -193,23 +181,21 @@ class Relevance::Tarantula::Crawler
193
181
  end
194
182
 
195
183
  def queue_link(dest, referrer = nil)
196
- dest = Link.new(dest)
197
- dest.href = transform_url(dest.href)
184
+ dest = Link.new(dest, self, referrer)
198
185
  return if should_skip_link?(dest)
199
- @referrers[dest] = referrer if referrer
200
- @links_to_crawl << dest
186
+ @crawl_queue << dest
201
187
  @links_queued << dest
202
188
  dest
203
189
  end
204
190
 
205
191
  def queue_form(form, referrer = nil)
206
192
  fuzzers.each do |fuzzer|
207
- fuzzer.mutate(Form.new(form)).each do |fs|
208
- # fs = fuzzer.new(Form.new(form))
193
+ fuzzer.mutate(Form.new(form, self, referrer)).each do |fs|
194
+ # fs = fuzzer.new(Form.new(form, self, referrer))
209
195
  fs.action = transform_url(fs.action)
210
196
  return if should_skip_form_submission?(fs)
211
197
  @referrers[fs.action] = referrer if referrer
212
- @forms_to_crawl << fs
198
+ @crawl_queue << fs
213
199
  @form_signatures_queued << fs.signature
214
200
  end
215
201
  end
@@ -234,6 +220,7 @@ class Relevance::Tarantula::Crawler
234
220
  end
235
221
 
236
222
  def report_results
223
+ puts "Crawled #{total_links_count} links and forms."
237
224
  generate_reports
238
225
  end
239
226
 
@@ -242,7 +229,7 @@ class Relevance::Tarantula::Crawler
242
229
  end
243
230
 
244
231
  def links_remaining_count
245
- @links_to_crawl.size + @forms_to_crawl.size
232
+ @crawl_queue.size
246
233
  end
247
234
 
248
235
  def links_completed_count
@@ -251,7 +238,7 @@ class Relevance::Tarantula::Crawler
251
238
 
252
239
  def blip(number = 0)
253
240
  unless verbose
254
- print "\r #{links_completed_count} of #{total_links_count} links completed "
241
+ print "\r #{links_completed_count} of #{total_links_count} links completed " if $stdout.tty?
255
242
  timeout_if_too_long(number)
256
243
  end
257
244
  end
@@ -2,8 +2,10 @@ class Relevance::Tarantula::Form
2
2
  extend Forwardable
3
3
  def_delegators("@tag", :search)
4
4
 
5
- def initialize(tag)
6
- @tag = tag
5
+ attr_accessor :crawler, :referrer
6
+
7
+ def initialize(tag, crawler, referrer)
8
+ @tag, @crawler, @referrer = tag, crawler, referrer
7
9
  end
8
10
 
9
11
  def action
@@ -1,25 +1,58 @@
1
1
  class Relevance::Tarantula::FormSubmission
2
- attr_accessor :method, :action, :data
3
- def initialize(form)
2
+ include Relevance::Tarantula
3
+ attr_accessor :method, :action, :data, :attack, :form
4
+
5
+ class << self
6
+ def attacks
7
+ # normalize from hash input to Attack
8
+ @attacks = @attacks.map do |val|
9
+ Hash === val ? Relevance::Tarantula::Attack.new(val) : val
10
+ end
11
+ @attacks
12
+ end
13
+ def attacks=(atts)
14
+ # normalize from hash input to Attack
15
+ @attacks = atts.map do |val|
16
+ Hash === val ? Relevance::Tarantula::Attack.new(val) : val
17
+ end
18
+ end
19
+ end
20
+ @attacks = [Relevance::Tarantula::BasicAttack.new]
21
+
22
+ def initialize(form, attack = Relevance::Tarantula::BasicAttack.new)
23
+ @form = form
4
24
  @method = form.method
5
25
  @action = form.action
26
+ @attack = attack
6
27
  @data = mutate_selects(form).merge(mutate_text_areas(form)).merge(mutate_inputs(form))
7
28
  end
8
29
 
30
+ def crawl
31
+ begin
32
+ response = form.crawler.submit(method, action, data)
33
+ log "Response #{response.code} for #{self}"
34
+ rescue ActiveRecord::RecordNotFound => e
35
+ log "Skipping #{action}, presumed ok that record is missing"
36
+ response = Relevance::Tarantula::Response.new(:code => "404", :body => e.message, :content_type => "text/plain")
37
+ end
38
+ form.crawler.handle_form_results(self, response)
39
+ response
40
+ end
41
+
9
42
  def self.mutate(form)
10
- [self.new(form)]
43
+ attacks.map{|attack| new(form, attack)} if attacks
11
44
  end
12
-
45
+
13
46
  def to_s
14
- "#{action} #{method} #{data.inspect}"
47
+ "#{action} #{method} #{data.inspect} #{attack.inspect}"
15
48
  end
16
-
49
+
17
50
  # a form's signature is what makes it unique (e.g. action + fields)
18
51
  # used to keep track of which forms we have submitted already
19
52
  def signature
20
- [action, data.keys.sort]
53
+ [action, data.keys.sort, attack.name]
21
54
  end
22
-
55
+
23
56
  def create_random_data_for(form, tag_selector)
24
57
  form.search(tag_selector).inject({}) do |form_args, input|
25
58
  # TODO: test
@@ -35,37 +68,21 @@ class Relevance::Tarantula::FormSubmission
35
68
  def mutate_text_areas(form)
36
69
  create_random_data_for(form, 'textarea')
37
70
  end
38
-
71
+
39
72
  def mutate_selects(form)
40
73
  form.search('select').inject({}) do |form_args, select|
41
74
  options = select.search('option')
42
75
  option = options.rand
43
- form_args[select['name']] = option['value']
76
+ form_args[select['name']] = option['value']
44
77
  form_args
45
78
  end
46
79
  end
47
-
80
+
48
81
  def random_data(input)
49
82
  case input['name']
50
- when /amount/ then random_int
51
- when /_id$/ then random_whole_number
52
- when /uploaded_data/ then nil
53
- when /^_method$/ then input['value']
54
- when nil then input['value']
55
- else
56
- random_int
83
+ when /^_method$/ then input['value']
84
+ else
85
+ attack.input(input)
57
86
  end
58
87
  end
59
-
60
- def big_number
61
- 10000 # arbitrary
62
- end
63
-
64
- def random_int
65
- rand(big_number) - (big_number/2)
66
- end
67
-
68
- def random_whole_number
69
- rand(big_number)
70
- end
71
88
  end
@@ -1,4 +1,5 @@
1
1
  class Relevance::Tarantula::Link
2
+ include Relevance::Tarantula
2
3
 
3
4
  class << self
4
5
  include ActionView::Helpers::UrlHelper
@@ -17,18 +18,33 @@ class Relevance::Tarantula::Link
17
18
  METHOD_REGEXPS[m] = /#{s}/
18
19
  end
19
20
 
20
- attr_accessor :href
21
+ attr_accessor :href, :crawler, :referrer
21
22
 
22
- def initialize(link)
23
+ def initialize(link, crawler, referrer)
24
+ @crawler, @referrer = crawler, referrer
25
+
23
26
  if String === link || link.nil?
24
- @href = link
27
+ @href = transform_url(link)
25
28
  @method = :get
26
29
  else # should be a tag
27
- @href = link['href'] ? link['href'].downcase : nil
30
+ @href = link['href'] ? transform_url(link['href'].downcase) : nil
28
31
  @tag = link
29
32
  end
30
33
  end
31
34
 
35
+ def crawl
36
+ response = crawler.follow(method, href)
37
+ log "Response #{response.code} for #{self}"
38
+ crawler.handle_link_results(self, make_result(response))
39
+ end
40
+
41
+ def make_result(response)
42
+ crawler.make_result(:method => method,
43
+ :url => href,
44
+ :response => response,
45
+ :referrer => referrer)
46
+ end
47
+
32
48
  def method
33
49
  @method ||= begin
34
50
  (@tag &&
@@ -39,6 +55,10 @@ class Relevance::Tarantula::Link
39
55
  end
40
56
  end
41
57
 
58
+ def transform_url(link)
59
+ crawler.transform_url(link)
60
+ end
61
+
42
62
  def ==(obj)
43
63
  obj.respond_to?(:href) && obj.respond_to?(:method) &&
44
64
  self.href.to_s == obj.href.to_s && self.method.to_s == obj.method.to_s
@@ -41,7 +41,7 @@ class Relevance::Tarantula::RailsIntegrationProxy
41
41
  if response.code == '404'
42
42
  if File.exist?(static_content_path(url))
43
43
  case ext = File.extension(url)
44
- when /html|te?xt|css|js|jpe?g|gif|psd|png|eps|pdf/
44
+ when /html|te?xt|css|js|jpe?g|gif|psd|png|eps|pdf|ico/
45
45
  response.body = static_content_file(url)
46
46
  response.headers["type"] = "text/#{ext}" # readable as response.content_type
47
47
  response.meta.attr_accessor :code
@@ -49,10 +49,10 @@ require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "log_gra
49
49
  require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "invalid_html_handler"))
50
50
  require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "transform"))
51
51
  require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "crawler"))
52
+ require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "basic_attack"))
52
53
  require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "form"))
53
54
  require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "form_submission"))
54
55
  require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "attack"))
55
- require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "attack_form_submission"))
56
56
  require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "attack_handler"))
57
57
  require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "link"))
58
58
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: relevance-tarantula
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Relevance, Inc.
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-08-21 00:00:00 -07:00
12
+ date: 2009-09-24 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -51,8 +51,8 @@ files:
51
51
  - examples/relevance/core_extensions/file_example.rb
52
52
  - examples/relevance/core_extensions/response_example.rb
53
53
  - examples/relevance/core_extensions/test_case_example.rb
54
- - examples/relevance/tarantula/attack_form_submission_example.rb
55
54
  - examples/relevance/tarantula/attack_handler_example.rb
55
+ - examples/relevance/tarantula/basic_attack_example.rb
56
56
  - examples/relevance/tarantula/crawler_example.rb
57
57
  - examples/relevance/tarantula/form_example.rb
58
58
  - examples/relevance/tarantula/form_submission_example.rb
@@ -84,8 +84,8 @@ files:
84
84
  - lib/relevance/core_extensions/test_case.rb
85
85
  - lib/relevance/tarantula.rb
86
86
  - lib/relevance/tarantula/attack.rb
87
- - lib/relevance/tarantula/attack_form_submission.rb
88
87
  - lib/relevance/tarantula/attack_handler.rb
88
+ - lib/relevance/tarantula/basic_attack.rb
89
89
  - lib/relevance/tarantula/crawler.rb
90
90
  - lib/relevance/tarantula/detail.html.erb
91
91
  - lib/relevance/tarantula/form.rb
@@ -107,7 +107,7 @@ files:
107
107
  - lib/relevance/tarantula/transform.rb
108
108
  - tasks/tarantula_tasks.rake
109
109
  - template/tarantula_test.rb
110
- has_rdoc: true
110
+ has_rdoc: false
111
111
  homepage: http://github.com/relevance/tarantula
112
112
  licenses:
113
113
  post_install_message:
@@ -132,7 +132,7 @@ requirements: []
132
132
  rubyforge_project: thinkrelevance
133
133
  rubygems_version: 1.3.5
134
134
  signing_key:
135
- specification_version: 2
135
+ specification_version: 3
136
136
  summary: A big hairy fuzzy spider that crawls your site, wreaking havoc
137
137
  test_files:
138
138
  - examples/example_helper.rb
@@ -140,8 +140,8 @@ test_files:
140
140
  - examples/relevance/core_extensions/file_example.rb
141
141
  - examples/relevance/core_extensions/response_example.rb
142
142
  - examples/relevance/core_extensions/test_case_example.rb
143
- - examples/relevance/tarantula/attack_form_submission_example.rb
144
143
  - examples/relevance/tarantula/attack_handler_example.rb
144
+ - examples/relevance/tarantula/basic_attack_example.rb
145
145
  - examples/relevance/tarantula/crawler_example.rb
146
146
  - examples/relevance/tarantula/form_example.rb
147
147
  - examples/relevance/tarantula/form_submission_example.rb
@@ -1,79 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "example_helper.rb"))
2
-
3
- describe "Relevance::Tarantula::AttackFormSubmission" do
4
-
5
- # TODO: add more from field types to this example form as needed
6
- before do
7
- @tag = Hpricot(<<END)
8
- <form action="/session" method="post">
9
- <input id="email" name="email" size="30" type="text" />
10
- <textarea id="comment" name="comment"value="1" />
11
- <input name="commit" type="submit" value="Postit" />
12
- <input name="secret" type="hidden" value="secret" />
13
- <select id="foo_opened_on_1i" name="foo[opened_on(1i)]">
14
- <option value="2003">2003</option>
15
- <option value="2004">2004</option>
16
- </select>
17
- </form>
18
- END
19
- @form = Relevance::Tarantula::Form.new(@tag.at('form'))
20
- @fs = Relevance::Tarantula::AttackFormSubmission.new(@form, Relevance::Tarantula::Attack.new({:name => 'foo_name', :input => 'foo_code', :output => 'foo_code'}))
21
- end
22
-
23
- it "can mutate text areas" do
24
- @fs.mutate_text_areas(@form).should == {"comment" => "foo_code"}
25
- end
26
-
27
- it "can mutate selects" do
28
- Hpricot::Elements.any_instance.stubs(:rand).returns(stub(:[] => "2006-stub"))
29
- @fs.mutate_selects(@form).should == {"foo[opened_on(1i)]" => "2006-stub"}
30
- end
31
-
32
- it "can mutate inputs" do
33
- @fs.mutate_inputs(@form).should == {"commit"=>"foo_code", "secret"=>"foo_code", "email"=>"foo_code"}
34
- end
35
-
36
- it "has a signature based on action, fields, and attack name" do
37
- @fs.signature.should == ['/session', [
38
- "comment",
39
- "commit",
40
- "email",
41
- "foo[opened_on(1i)]",
42
- "secret"],
43
- "foo_name"
44
- ]
45
- end
46
-
47
- it "has a friendly to_s" do
48
- @fs.to_s.should =~ %r{^/session post}
49
- end
50
-
51
- it "processes all its attacks" do
52
- Relevance::Tarantula::AttackFormSubmission.stubs(:attacks).returns([
53
- Relevance::Tarantula::Attack.new({:name => 'foo_name1', :input => 'foo_input', :output => 'foo_output'}),
54
- Relevance::Tarantula::Attack.new({:name => 'foo_name2', :input => 'foo_input', :output => 'foo_output'}),
55
- ])
56
- Relevance::Tarantula::AttackFormSubmission.mutate(@form).size.should == 2
57
- end
58
-
59
- it "maps hash attacks to Attack instances" do
60
- Relevance::Tarantula::AttackFormSubmission.instance_variable_set("@attacks", [{ :name => "attack name"}])
61
- Relevance::Tarantula::AttackFormSubmission.attacks.should == [Relevance::Tarantula::Attack.new({:name => "attack name"})]
62
- end
63
- end
64
-
65
- describe "Relevance::Tarantula::AttackFormSubmission for a crummy form" do
66
- before do
67
- @tag = Hpricot(<<END)
68
- <form action="/session" method="post">
69
- <input value="no_name" />
70
- </form>
71
- END
72
- @form = Relevance::Tarantula::Form.new(@tag.at('form'))
73
- @fs = Relevance::Tarantula::AttackFormSubmission.new(@form, {:name => 'foo_name', :input => 'foo_code', :output => 'foo_code'})
74
- end
75
-
76
- it "ignores unnamed inputs" do
77
- @fs.mutate_inputs(@form).should == {}
78
- end
79
- end