htty 1.4.1 → 1.5.0

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.
Files changed (120) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -1
  3. data/.rspec +2 -0
  4. data/.travis.yml +21 -3
  5. data/.yardopts +1 -1
  6. data/Gemfile +2 -2
  7. data/Guardfile +12 -10
  8. data/History.markdown +14 -0
  9. data/{MIT-LICENSE.markdown → License.markdown} +1 -1
  10. data/README.markdown +50 -65
  11. data/Rakefile +2 -2
  12. data/htty.gemspec +2 -2
  13. data/lib/htty/cli.rb +59 -74
  14. data/lib/htty/cli/command.rb +21 -20
  15. data/lib/htty/cli/commands/body_edit.rb +89 -0
  16. data/lib/htty/cli/commands/query_add.rb +3 -0
  17. data/lib/htty/cli/commands/query_set.rb +3 -0
  18. data/lib/htty/cli/commands/userinfo_set.rb +8 -14
  19. data/lib/htty/cli/display.rb +14 -12
  20. data/lib/htty/cli/input_device.rb +75 -0
  21. data/lib/htty/cli/url_escaping.rb +2 -2
  22. data/lib/htty/headers.rb +81 -0
  23. data/lib/htty/no_header_error.rb +10 -0
  24. data/lib/htty/payload.rb +22 -9
  25. data/lib/htty/request.rb +67 -43
  26. data/lib/htty/requests_util.rb +22 -8
  27. data/lib/htty/response.rb +20 -1
  28. data/lib/htty/uri.rb +16 -0
  29. data/lib/htty/version.rb +1 -1
  30. data/spec/integration/htty/cli/commands/query_add_spec.rb +7 -1
  31. data/spec/integration/htty/cli/commands/query_remove_spec.rb +19 -1
  32. data/spec/integration/htty/cli/commands/query_set_spec.rb +9 -3
  33. data/spec/integration/htty/cli/commands/query_unset_spec.rb +8 -2
  34. data/spec/spec_helper.rb +69 -0
  35. data/spec/unit/htty/cli/commands/address_spec.rb +1 -1
  36. data/spec/unit/htty/cli/commands/body_clear_spec.rb +1 -1
  37. data/spec/unit/htty/cli/commands/body_edit_spec.rb +18 -0
  38. data/spec/unit/htty/cli/commands/body_request_spec.rb +1 -1
  39. data/spec/unit/htty/cli/commands/body_response_spec.rb +1 -1
  40. data/spec/unit/htty/cli/commands/body_set_spec.rb +1 -1
  41. data/spec/unit/htty/cli/commands/body_unset_spec.rb +1 -1
  42. data/spec/unit/htty/cli/commands/cd_spec.rb +1 -1
  43. data/spec/unit/htty/cli/commands/cookie_add_spec.rb +1 -1
  44. data/spec/unit/htty/cli/commands/cookie_remove_spec.rb +1 -1
  45. data/spec/unit/htty/cli/commands/cookies_add_spec.rb +1 -1
  46. data/spec/unit/htty/cli/commands/cookies_clear_spec.rb +1 -1
  47. data/spec/unit/htty/cli/commands/cookies_remove_all_spec.rb +1 -1
  48. data/spec/unit/htty/cli/commands/cookies_remove_spec.rb +1 -1
  49. data/spec/unit/htty/cli/commands/cookies_spec.rb +1 -1
  50. data/spec/unit/htty/cli/commands/cookies_use_spec.rb +1 -1
  51. data/spec/unit/htty/cli/commands/delete_spec.rb +1 -1
  52. data/spec/unit/htty/cli/commands/exit_spec.rb +1 -1
  53. data/spec/unit/htty/cli/commands/follow_spec.rb +1 -1
  54. data/spec/unit/htty/cli/commands/form_add_spec.rb +1 -1
  55. data/spec/unit/htty/cli/commands/form_clear_spec.rb +1 -1
  56. data/spec/unit/htty/cli/commands/form_remove_all_spec.rb +1 -1
  57. data/spec/unit/htty/cli/commands/form_remove_spec.rb +1 -1
  58. data/spec/unit/htty/cli/commands/form_spec.rb +1 -1
  59. data/spec/unit/htty/cli/commands/fragment_clear_spec.rb +1 -1
  60. data/spec/unit/htty/cli/commands/fragment_set_spec.rb +1 -1
  61. data/spec/unit/htty/cli/commands/fragment_unset_spec.rb +1 -1
  62. data/spec/unit/htty/cli/commands/get_spec.rb +1 -1
  63. data/spec/unit/htty/cli/commands/header_set_spec.rb +1 -1
  64. data/spec/unit/htty/cli/commands/header_unset_spec.rb +1 -1
  65. data/spec/unit/htty/cli/commands/headers_clear_spec.rb +1 -1
  66. data/spec/unit/htty/cli/commands/headers_request_spec.rb +1 -1
  67. data/spec/unit/htty/cli/commands/headers_response_spec.rb +1 -1
  68. data/spec/unit/htty/cli/commands/headers_set_spec.rb +1 -1
  69. data/spec/unit/htty/cli/commands/headers_unset_all_spec.rb +1 -1
  70. data/spec/unit/htty/cli/commands/headers_unset_spec.rb +1 -1
  71. data/spec/unit/htty/cli/commands/help_spec.rb +1 -1
  72. data/spec/unit/htty/cli/commands/history_spec.rb +1 -1
  73. data/spec/unit/htty/cli/commands/history_verbose_spec.rb +1 -1
  74. data/spec/unit/htty/cli/commands/host_set_spec.rb +1 -1
  75. data/spec/unit/htty/cli/commands/http_delete_spec.rb +1 -1
  76. data/spec/unit/htty/cli/commands/http_get_spec.rb +1 -1
  77. data/spec/unit/htty/cli/commands/http_head_spec.rb +1 -1
  78. data/spec/unit/htty/cli/commands/http_options_spec.rb +1 -1
  79. data/spec/unit/htty/cli/commands/http_patch_spec.rb +1 -1
  80. data/spec/unit/htty/cli/commands/http_post_spec.rb +1 -1
  81. data/spec/unit/htty/cli/commands/http_put_spec.rb +1 -1
  82. data/spec/unit/htty/cli/commands/http_trace_spec.rb +1 -1
  83. data/spec/unit/htty/cli/commands/patch_spec.rb +1 -1
  84. data/spec/unit/htty/cli/commands/path_set_spec.rb +1 -1
  85. data/spec/unit/htty/cli/commands/port_set_spec.rb +1 -1
  86. data/spec/unit/htty/cli/commands/post_spec.rb +1 -1
  87. data/spec/unit/htty/cli/commands/put_spec.rb +1 -1
  88. data/spec/unit/htty/cli/commands/query_add_spec.rb +1 -1
  89. data/spec/unit/htty/cli/commands/query_clear_spec.rb +1 -1
  90. data/spec/unit/htty/cli/commands/query_remove_spec.rb +1 -1
  91. data/spec/unit/htty/cli/commands/query_set_spec.rb +1 -1
  92. data/spec/unit/htty/cli/commands/query_unset_all_spec.rb +1 -1
  93. data/spec/unit/htty/cli/commands/query_unset_spec.rb +1 -1
  94. data/spec/unit/htty/cli/commands/quit_spec.rb +1 -1
  95. data/spec/unit/htty/cli/commands/reuse_spec.rb +1 -1
  96. data/spec/unit/htty/cli/commands/scheme_set_spec.rb +1 -1
  97. data/spec/unit/htty/cli/commands/shared_examples_for_commands.rb +55 -0
  98. data/spec/unit/htty/cli/commands/ssl_verification_off_spec.rb +1 -1
  99. data/spec/unit/htty/cli/commands/ssl_verification_on_spec.rb +1 -1
  100. data/spec/unit/htty/cli/commands/ssl_verification_spec.rb +1 -1
  101. data/spec/unit/htty/cli/commands/status_spec.rb +1 -1
  102. data/spec/unit/htty/cli/commands/undo_spec.rb +1 -1
  103. data/spec/unit/htty/cli/commands/userinfo_clear_spec.rb +1 -1
  104. data/spec/unit/htty/cli/commands/userinfo_set_spec.rb +23 -1
  105. data/spec/unit/htty/cli/commands/userinfo_unset_spec.rb +1 -1
  106. data/spec/unit/htty/cli/display_spec.rb +84 -0
  107. data/spec/unit/htty/cli_spec.rb +1 -1
  108. data/spec/unit/htty/command.rb +47 -0
  109. data/spec/unit/htty/{ordered_hash_spec.rb → headers_spec.rb} +4 -4
  110. data/spec/unit/htty/payload_spec.rb +60 -0
  111. data/spec/unit/htty/preferences_spec.rb +1 -1
  112. data/spec/unit/htty/request_follow_spec.rb +94 -0
  113. data/spec/unit/htty/request_spec.rb +5 -187
  114. data/spec/unit/htty/request_userinfo_spec.rb +208 -0
  115. data/spec/unit/htty/session_spec.rb +1 -1
  116. data/spec/unit/htty/shared_examples_for_requests.rb +32 -0
  117. data/spec/unit/htty/url_escaping.rb +70 -0
  118. data/spec/unit/htty/version_spec.rb +1 -1
  119. metadata +43 -30
  120. data/lib/htty/ordered_hash.rb +0 -68
@@ -0,0 +1,10 @@
1
+ module HTTY; end
2
+
3
+ # Indicates that an header could not be found in a HTTY::Payload
4
+ class HTTY::NoHeaderError < StandardError
5
+
6
+ def initialize(key)
7
+ super "header #{key} not found"
8
+ end
9
+
10
+ end
data/lib/htty/payload.rb CHANGED
@@ -1,4 +1,6 @@
1
- require File.expand_path("#{File.dirname __FILE__}/ordered_hash")
1
+ require File.expand_path("#{File.dirname __FILE__}/headers")
2
+ require File.expand_path("#{File.dirname __FILE__}/no_header_error")
3
+ require File.expand_path("#{File.dirname __FILE__}/cookies_util")
2
4
 
3
5
  module HTTY; end
4
6
 
@@ -20,6 +22,24 @@ class HTTY::Payload
20
22
  @headers.to_a
21
23
  end
22
24
 
25
+ def headers_with_key(key)
26
+ headers.select do |header_key, header_value|
27
+ key.downcase == header_key.downcase
28
+ end
29
+ end
30
+
31
+ def header(key, otherwise=:__no_default_value_given)
32
+ all_headers_with_key = headers_with_key(key)
33
+ return all_headers_with_key.last.last unless all_headers_with_key.empty?
34
+ raise otherwise if otherwise.is_a? Exception
35
+ return otherwise unless otherwise == :__no_default_value_given
36
+ raise HTTY::NoHeaderError.new(key)
37
+ end
38
+
39
+ def cookies_from(cookies_header_key)
40
+ HTTY::CookiesUtil.cookies_from_string header(cookies_header_key, nil)
41
+ end
42
+
23
43
  protected
24
44
 
25
45
  # Initializes a new HTTY::Payload with attribute values specified in the
@@ -31,17 +51,10 @@ protected
31
51
  # * <tt>:headers</tt>
32
52
  def initialize(attributes={})
33
53
  @body = attributes[:body]
34
- @headers = HTTY::OrderedHash.new
54
+ @headers = HTTY::Headers.new
35
55
  Array(attributes[:headers]).each do |name, value|
36
56
  @headers[name] = value
37
57
  end
38
58
  end
39
59
 
40
- # @private
41
- def initialize_copy(source)
42
- super
43
- @body = @body.dup if @body
44
- @headers = @headers.dup
45
- end
46
-
47
60
  end
data/lib/htty/request.rb CHANGED
@@ -6,6 +6,7 @@ require File.expand_path("#{File.dirname __FILE__}/cookies_util")
6
6
  require File.expand_path("#{File.dirname __FILE__}/no_location_header_error")
7
7
  require File.expand_path("#{File.dirname __FILE__}/no_response_error")
8
8
  require File.expand_path("#{File.dirname __FILE__}/no_set_cookie_header_error")
9
+ require File.expand_path("#{File.dirname __FILE__}/uri")
9
10
  require File.expand_path("#{File.dirname __FILE__}/payload")
10
11
  require File.expand_path("#{File.dirname __FILE__}/requests_util")
11
12
  require File.expand_path("#{File.dirname __FILE__}/response")
@@ -141,13 +142,6 @@ public
141
142
  establish_content_length
142
143
  end
143
144
 
144
- # @private
145
- def initialize_copy(source)
146
- super
147
- @response = @response.dup if @response
148
- @uri = @uri.dup
149
- end
150
-
151
145
  # Returns +true+ if _other_request_ is equivalent to the request.
152
146
  def ==(other_request)
153
147
  return false unless super(other_request)
@@ -229,9 +223,14 @@ public
229
223
  self
230
224
  end
231
225
 
226
+ # Returns true if has some cookies.
227
+ def cookies?
228
+ not cookies.empty?
229
+ end
230
+
232
231
  # Returns an array of the cookies belonging to the request.
233
232
  def cookies
234
- HTTY::CookiesUtil.cookies_from_string @headers[COOKIES_HEADER_NAME]
233
+ cookies_from(COOKIES_HEADER_NAME)
235
234
  end
236
235
 
237
236
  # Removes all #cookies.
@@ -267,14 +266,7 @@ public
267
266
  # HTTY::NoLocationHeaderError.
268
267
  def follow(response)
269
268
  raise HTTY::NoResponseError unless response
270
-
271
- location_header = response.headers.detect do |name, value|
272
- name == HTTY::Response::LOCATION_HEADER_NAME
273
- end
274
- unless location_header && location_header.last
275
- raise HTTY::NoLocationHeaderError
276
- end
277
- address location_header.last
269
+ response.follow_relative_to(self)
278
270
  end
279
271
 
280
272
  # Establishes a new #uri with the specified _fragment_.
@@ -302,13 +294,29 @@ public
302
294
  def header_set(name, value)
303
295
  return dup_without_response.header_set(name, value) if response
304
296
 
305
- name = name.to_s
297
+ name = name && name.to_s
298
+ value = value && value.to_s
299
+
300
+ # to avoid recursion when rebuild_uri
301
+ return self if @headers[name] == value
302
+
306
303
  if value.nil?
307
304
  @headers.delete name
305
+ if name.downcase == AUTHORIZATION_HEADER_NAME.downcase
306
+ return rebuild_uri :userinfo => nil
307
+ end
308
308
  return self
309
309
  end
310
310
 
311
- @headers[name] = value.to_s
311
+ @headers[name] = value
312
+ if name.downcase == AUTHORIZATION_HEADER_NAME.downcase
313
+ HTTY::Headers.credentials_from(value) do |username, password|
314
+ return rebuild_uri :userinfo => [
315
+ HTTY::URI.escape_component(username),
316
+ HTTY::URI.escape_component(password)
317
+ ].compact.join(':')
318
+ end
319
+ end
312
320
  self
313
321
  end
314
322
 
@@ -317,6 +325,14 @@ public
317
325
  header_set name, nil
318
326
  end
319
327
 
328
+ # Removes all #headers.
329
+ def headers_unset_all
330
+ return dup_without_response.headers_unset_all if response
331
+
332
+ @headers.clear
333
+ rebuild_uri :userinfo => nil
334
+ end
335
+
320
336
  # Returns an array of the headers belonging to the payload. If
321
337
  # _include_content_length_ is +false+, then a 'Content Length' header will be
322
338
  # omitted. If _include_content_length_ is not specified, then it will be
@@ -333,14 +349,6 @@ public
333
349
  super()
334
350
  end
335
351
 
336
- # Removes all #headers.
337
- def headers_unset_all
338
- return dup_without_response.headers_unset_all if response
339
-
340
- @headers.clear
341
- self
342
- end
343
-
344
352
  # Establishes a new #uri with the specified _host_.
345
353
  def host_set(host)
346
354
  rebuild_uri :host => host
@@ -383,8 +391,34 @@ public
383
391
  def query_add(name, value=nil)
384
392
  entries = current_query_entries
385
393
  entries << name + (value.nil? ? '' : "=#{value}")
386
- new_query = entries.empty? ? nil : entries.join('&')
387
- rebuild_uri :query => new_query
394
+ query_set_all(entries)
395
+ end
396
+
397
+ # Establishes a new #uri with the specified _value_ for the query-string
398
+ # parameter specified by _name_. The _value_ is optional.
399
+ #
400
+ # If there is more than one query-string parameter named _name_, they are
401
+ # replaced by a single one with the specified _value_.
402
+ def query_set(name, value=nil)
403
+ entries = current_query_entries
404
+ add_or_replace_field(entries, name, value)
405
+ query_set_all(entries)
406
+ end
407
+
408
+ # Establishes a new #uri with the query-string parameter specified by by
409
+ # _query_string_ parameter
410
+ def query_set_all(query_string)
411
+ # _query_string_ as an array of parameters is only for internal usage
412
+ query_string =
413
+ case query_string
414
+ when Array
415
+ query_string.empty? ? nil : query_string.join('&')
416
+ when String
417
+ query_string
418
+ else
419
+ nil
420
+ end
421
+ rebuild_uri :query => query_string
388
422
  end
389
423
 
390
424
  # Establishes a new #uri, removing the last query-string parameter specified
@@ -401,19 +435,7 @@ public
401
435
  break
402
436
  end
403
437
  end
404
- rebuild_uri :query => entries.join('&')
405
- end
406
-
407
- # Establishes a new #uri with the specified _value_ for the query-string
408
- # parameter specified by _name_. The _value_ is optional.
409
- #
410
- # If there is more than one query-string parameter named _name_, they are
411
- # replaced by a single one with the specified _value_.
412
- def query_set(name, value=nil)
413
- entries = current_query_entries
414
- add_or_replace_field(entries, name, value)
415
- new_query = entries.empty? ? nil : entries.join('&')
416
- rebuild_uri :query => new_query
438
+ query_set_all(entries)
417
439
  end
418
440
 
419
441
  # Establishes a new #uri without the query-string parameter specified by
@@ -427,7 +449,7 @@ public
427
449
  entries.delete_if do |entry|
428
450
  entry =~ field_matcher(name)
429
451
  end
430
- rebuild_uri :query => entries.join('&')
452
+ query_set_all(entries)
431
453
  end
432
454
 
433
455
  # Establishes a new #uri without a query string.
@@ -484,8 +506,10 @@ protected
484
506
  components = URI::HTTP::COMPONENT.inject({}) do |result, c|
485
507
  result.merge c => uri.send(c)
486
508
  end
509
+ components = components.merge(changed_components)
510
+ components[:query] = nil if components[:query] && components[:query].empty?
487
511
  self.class.send(:set_up_cookies_and_authentication, self) do
488
- @uri = self.class.build_uri(components.merge(changed_components))
512
+ @uri = self.class.build_uri(components)
489
513
  end
490
514
  end
491
515
 
@@ -13,28 +13,28 @@ module HTTY::RequestsUtil
13
13
  # Makes an HTTP DELETE request with the specified _request_.
14
14
  def self.delete(request)
15
15
  request(request) do |host|
16
- host.delete request.send(:path_query_and_fragment), request.headers
16
+ host.delete request.send(:path_query_and_fragment), headers_from(request)
17
17
  end
18
18
  end
19
19
 
20
20
  # Makes an HTTP GET request with the specified _request_.
21
21
  def self.get(request)
22
22
  request(request) do |host|
23
- host.request_get request.send(:path_query_and_fragment), request.headers
23
+ host.request_get request.send(:path_query_and_fragment), headers_from(request)
24
24
  end
25
25
  end
26
26
 
27
27
  # Makes an HTTP HEAD request with the specified _request_.
28
28
  def self.head(request)
29
29
  request(request) do |host|
30
- host.head request.send(:path_query_and_fragment), request.headers
30
+ host.head request.send(:path_query_and_fragment), headers_from(request)
31
31
  end
32
32
  end
33
33
 
34
34
  # Makes an HTTP OPTIONS request with the specified _request_.
35
35
  def self.options(request)
36
36
  request(request) do |host|
37
- host.options request.send(:path_query_and_fragment), request.headers
37
+ host.options request.send(:path_query_and_fragment), headers_from(request)
38
38
  end
39
39
  end
40
40
 
@@ -43,7 +43,7 @@ module HTTY::RequestsUtil
43
43
  request(request) do |host|
44
44
  host.patch request.send(:path_query_and_fragment),
45
45
  request.body,
46
- request.headers
46
+ headers_from(request)
47
47
  end
48
48
  end
49
49
 
@@ -52,7 +52,7 @@ module HTTY::RequestsUtil
52
52
  request(request) do |host|
53
53
  host.post request.send(:path_query_and_fragment),
54
54
  request.body,
55
- request.headers
55
+ headers_from(request)
56
56
  end
57
57
  end
58
58
 
@@ -61,14 +61,14 @@ module HTTY::RequestsUtil
61
61
  request(request) do |host|
62
62
  host.put request.send(:path_query_and_fragment),
63
63
  request.body,
64
- request.headers
64
+ headers_from(request)
65
65
  end
66
66
  end
67
67
 
68
68
  # Makes an HTTP TRACE request with the specified _request_.
69
69
  def self.trace(request)
70
70
  request(request) do |host|
71
- host.trace request.send(:path_query_and_fragment), request.headers
71
+ host.trace request.send(:path_query_and_fragment), headers_from(request)
72
72
  end
73
73
  end
74
74
 
@@ -106,4 +106,18 @@ private
106
106
  request
107
107
  end
108
108
 
109
+ def self.headers_from(request)
110
+ return request.headers unless HEADERS_MUST_BE_AN_HASH
111
+ return {} if request.headers.empty?
112
+ request.headers.flatten.each_slice(2).reduce({}) do |hash, pair|
113
+ hash[pair.first] = pair.last
114
+ hash
115
+ end
116
+ end
117
+
118
+ # starting from 2.0.0 net/http requires headers to be hashes
119
+ require 'rubygems' # Not necessary under Ruby v2
120
+ HEADERS_MUST_BE_AN_HASH =
121
+ Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.0.0')
122
+
109
123
  end
data/lib/htty/response.rb CHANGED
@@ -23,11 +23,30 @@ class HTTY::Response < HTTY::Payload
23
23
  def initialize(attributes={})
24
24
  super attributes
25
25
  @status = attributes[:status]
26
+ @already_followed = false
26
27
  end
27
28
 
28
29
  # Returns an array of the cookies belonging to the response.
29
30
  def cookies
30
- HTTY::CookiesUtil.cookies_from_string @headers[COOKIES_HEADER_NAME]
31
+ cookies_from(COOKIES_HEADER_NAME)
31
32
  end
32
33
 
34
+ def follow_relative_to(request)
35
+ return request if @already_followed
36
+ location_uri = URI.parse(location_header = location)
37
+ if location_uri.absolute?
38
+ request.address location_header
39
+ else
40
+ request.
41
+ path_set(location_uri.path).
42
+ query_set_all(location_uri.query).
43
+ fragment_set(location_uri.fragment)
44
+ end
45
+ ensure
46
+ @already_followed = true
47
+ end
48
+
49
+ def location
50
+ header(LOCATION_HEADER_NAME, HTTY::NoLocationHeaderError.new)
51
+ end
33
52
  end
data/lib/htty/uri.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'uri'
2
+
3
+ module HTTY; end
4
+
5
+ class HTTY::URI
6
+ # There's a lot of confusion about this, the default implementation
7
+ # of URI.escape is marked as "obsolete", CGI.escape does another work,
8
+ # a safe solution seems to use https://github.com/sporkmonger/addressable
9
+ # without adding a new dependecy I found that encode all not unreserved
10
+ # characters (unfortunately that doesn't mean all reserved characters) it's
11
+ # a pretty safe solution, see http://tools.ietf.org/html/rfc3986#section-2.3
12
+ # URI.escape(a, /[^-_.~a-zA-Z0-9]/)
13
+ def self.escape_component(component)
14
+ URI.escape(component, /[^-_.~a-zA-Z0-9]/) unless component.nil?
15
+ end
16
+ end
data/lib/htty/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module HTTY
2
2
 
3
3
  # The version of this release of _htty_.
4
- VERSION = '1.4.1' unless const_defined?(:VERSION)
4
+ VERSION = '1.5.0' unless const_defined?(:VERSION)
5
5
 
6
6
  end
@@ -1,4 +1,4 @@
1
- require 'rspec'
1
+ require 'spec_helper'
2
2
  require File.expand_path("#{File.dirname __FILE__}/../../../../../lib/htty/session")
3
3
  require File.expand_path("#{File.dirname __FILE__}/../../../../../lib/htty/cli/commands/query_add")
4
4
 
@@ -15,6 +15,12 @@ describe HTTY::CLI::Commands::QueryAdd do
15
15
  klass.new :session => session, :arguments => arguments
16
16
  end
17
17
 
18
+ describe 'without an argument' do
19
+ it 'should raise an error' do
20
+ expect{instance.perform}.to raise_error(ArgumentError)
21
+ end
22
+ end
23
+
18
24
  describe 'with key argument only' do
19
25
  describe 'without key already present' do
20
26
  it 'should add key' do
@@ -1,4 +1,4 @@
1
- require 'rspec'
1
+ require 'spec_helper'
2
2
  require File.expand_path("#{File.dirname __FILE__}/../../../../../lib/htty/session")
3
3
  require File.expand_path("#{File.dirname __FILE__}/../../../../../lib/htty/cli/commands/query_remove")
4
4
 
@@ -15,6 +15,24 @@ describe HTTY::CLI::Commands::QueryRemove do
15
15
  klass.new :session => session, :arguments => arguments
16
16
  end
17
17
 
18
+ describe 'with existing query string with only one key and value' do
19
+ before :each do
20
+ session.requests.last.uri.query = 'test=true'
21
+ end
22
+
23
+ describe 'with only key in query string' do
24
+ it 'should empty the query string' do
25
+ instance('test').perform
26
+ session.requests.last.uri.query.should be_nil
27
+ end
28
+
29
+ it 'should not leave a trailing question mark' do
30
+ instance('test').perform
31
+ session.requests.last.uri.to_s.should_not end_with('?')
32
+ end
33
+ end
34
+ end
35
+
18
36
  describe 'with existing query string with duplicate keys set' do
19
37
  before :each do
20
38
  session.requests.last.uri.query = 'test=true&test=false'