htty 1.4.1 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
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'