2222
2323#![ deny( unsafe_code) ]
2424
25- use percent_encoding:: { utf8_percent_encode, AsciiSet , CONTROLS } ;
2625use std:: fmt:: { Debug , Display , Formatter } ;
2726
27+ use percent_encoding:: { utf8_percent_encode, AsciiSet , CONTROLS } ;
28+
2829/// https://url.spec.whatwg.org/#fragment-percent-encode-set
2930const FRAGMENT : & AsciiSet = & CONTROLS . add ( b' ' ) . add ( b'"' ) . add ( b'<' ) . add ( b'>' ) . add ( b'`' ) ;
3031
@@ -100,11 +101,7 @@ impl QueryString {
100101 /// "https://example.com/?q=%F0%9F%8D%8E%20apple&category=fruits%20and%20vegetables&works=true"
101102 /// );
102103 /// ```
103- pub fn with_opt_value < K : ToString , V : ToString > (
104- self ,
105- key : K ,
106- value : Option < V > ,
107- ) -> Self {
104+ pub fn with_opt_value < K : ToString , V : ToString > ( self , key : K , value : Option < V > ) -> Self {
108105 if let Some ( value) = value {
109106 self . with_value ( key, value)
110107 } else {
@@ -152,11 +149,7 @@ impl QueryString {
152149 /// "https://example.com/?q=%F0%9F%8D%8E%20apple"
153150 /// );
154151 /// ```
155- pub fn push_opt < K : ToString , V : ToString > (
156- & mut self ,
157- key : K ,
158- value : Option < V > ,
159- ) -> & Self {
152+ pub fn push_opt < K : ToString , V : ToString > ( & mut self , key : K , value : Option < V > ) -> & Self {
160153 if let Some ( value) = value {
161154 self . push ( key, value)
162155 } else {
@@ -221,7 +214,7 @@ impl QueryString {
221214impl Display for QueryString {
222215 fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
223216 if self . pairs . is_empty ( ) {
224- return Ok ( ( ) ) ;
217+ Ok ( ( ) )
225218 } else {
226219 write ! ( f, "?" ) ?;
227220 for ( i, pair) in self . pairs . iter ( ) . enumerate ( ) {
@@ -250,6 +243,14 @@ struct Kvp {
250243mod tests {
251244 use super :: * ;
252245
246+ #[ test]
247+ fn test_empty ( ) {
248+ let qs = QueryString :: new ( ) ;
249+ assert_eq ! ( qs. to_string( ) , "" ) ;
250+ assert_eq ! ( qs. len( ) , 0 ) ;
251+ assert ! ( qs. is_empty( ) ) ;
252+ }
253+
253254 #[ test]
254255 fn test_simple ( ) {
255256 let qs = QueryString :: new ( )
@@ -259,6 +260,8 @@ mod tests {
259260 qs. to_string( ) ,
260261 "?q=apple???&category=fruits%20and%20vegetables"
261262 ) ;
263+ assert_eq ! ( qs. len( ) , 2 ) ;
264+ assert ! ( !qs. is_empty( ) ) ;
262265 }
263266
264267 #[ test]
@@ -267,7 +270,10 @@ mod tests {
267270 . with_value ( "q" , "Grünkohl" )
268271 . with_value ( "category" , "Gemüse" )
269272 . with_value ( "answer" , 42 ) ;
270- assert_eq ! ( qs. to_string( ) , "?q=Gr%C3%BCnkohl&category=Gem%C3%BCse&answer=42" ) ;
273+ assert_eq ! (
274+ qs. to_string( ) ,
275+ "?q=Gr%C3%BCnkohl&category=Gem%C3%BCse&answer=42"
276+ ) ;
271277 }
272278
273279 #[ test]
@@ -291,5 +297,33 @@ mod tests {
291297 qs. to_string( ) ,
292298 "?q=celery&category=fruits%20and%20vegetables"
293299 ) ;
300+ assert_eq ! ( qs. len( ) , 2 ) ; // not three!
301+ }
302+
303+ #[ test]
304+ fn test_push_optional ( ) {
305+ let mut qs = QueryString :: new ( ) ;
306+ qs. push ( "a" , "apple" ) ;
307+ qs. push_opt ( "b" , None :: < String > ) ;
308+ qs. push_opt ( "c" , Some ( "🍎 apple" ) ) ;
309+
310+ assert_eq ! (
311+ format!( "https://example.com/{qs}" ) ,
312+ "https://example.com/?a=apple&c=%F0%9F%8D%8E%20apple"
313+ ) ;
314+ }
315+
316+ #[ test]
317+ fn test_append ( ) {
318+ let qs = QueryString :: new ( ) . with_value ( "q" , "apple" ) ;
319+ let more = QueryString :: new ( ) . with_value ( "q" , "pear" ) ;
320+
321+ let mut qs = qs. append_into ( more) ;
322+ qs. append ( QueryString :: new ( ) . with_value ( "answer" , "42" ) ) ;
323+
324+ assert_eq ! (
325+ format!( "https://example.com/{qs}" ) ,
326+ "https://example.com/?q=apple&q=pear&answer=42"
327+ ) ;
294328 }
295329}
0 commit comments