Skip to content
This repository was archived by the owner on Nov 20, 2018. It is now read-only.

Commit 3a33146

Browse files
committed
#269 Clean up QueryString APIs, add tests.
1 parent 5bce140 commit 3a33146

File tree

2 files changed

+179
-10
lines changed

2 files changed

+179
-10
lines changed

src/Microsoft.AspNet.Http.Abstractions/QueryString.cs

+68-10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Collections.Generic;
6+
using System.Text;
57
using Microsoft.Framework.Internal;
68
using Microsoft.Framework.WebEncoders;
79

@@ -33,16 +35,6 @@ public QueryString(string value)
3335
_value = value;
3436
}
3537

36-
/// <summary>
37-
/// Initialize a query string with a single given parameter name and value.
38-
/// </summary>
39-
/// <param name="name">The un-encoded parameter name</param>
40-
/// <param name="value">The un-encoded parameter value</param>
41-
public QueryString(string name, string value)
42-
{
43-
_value = "?" + UrlEncoder.Default.UrlEncode(name) + '=' + UrlEncoder.Default.UrlEncode(value);
44-
}
45-
4638
/// <summary>
4739
/// The escaped query string with the leading '?' character
4840
/// </summary>
@@ -114,6 +106,67 @@ public static QueryString FromUriComponent([NotNull] Uri uri)
114106
return new QueryString(queryValue);
115107
}
116108

109+
/// <summary>
110+
/// Create a query string with a single given parameter name and value.
111+
/// </summary>
112+
/// <param name="name">The un-encoded parameter name</param>
113+
/// <param name="value">The un-encoded parameter value</param>
114+
public static QueryString Create(string name, string value)
115+
{
116+
return new QueryString("?" + UrlEncoder.Default.UrlEncode(name) + '=' + UrlEncoder.Default.UrlEncode(value));
117+
}
118+
119+
/// <summary>
120+
/// Creates a query string composed from the given name value pairs.
121+
/// </summary>
122+
/// <param name="parameters"></param>
123+
/// <returns></returns>
124+
public static QueryString Create(IEnumerable<KeyValuePair<string, string>> parameters)
125+
{
126+
var builder = new StringBuilder();
127+
bool first = true;
128+
foreach (var pair in parameters)
129+
{
130+
builder.Append(first ? "?" : "&");
131+
first = false;
132+
builder.Append(UrlEncoder.Default.UrlEncode(pair.Key));
133+
builder.Append("=");
134+
builder.Append(UrlEncoder.Default.UrlEncode(pair.Value));
135+
}
136+
137+
return new QueryString(builder.ToString());
138+
}
139+
140+
public QueryString Add(QueryString other)
141+
{
142+
if (!HasValue || Value.Equals("?", StringComparison.Ordinal))
143+
{
144+
return other;
145+
}
146+
if (!other.HasValue || other.Value.Equals("?", StringComparison.Ordinal))
147+
{
148+
return this;
149+
}
150+
151+
// ?name1=value1 Add ?name2=value2 returns ?name1=value1&name2=value2
152+
return new QueryString(_value + "&" + other.Value.Substring(1));
153+
}
154+
155+
public QueryString Add(string name, string value)
156+
{
157+
if (!HasValue || Value.Equals("?", StringComparison.Ordinal))
158+
{
159+
return Create(name, value);
160+
}
161+
162+
var builder = new StringBuilder(Value);
163+
builder.Append("&");
164+
builder.Append(UrlEncoder.Default.UrlEncode(name));
165+
builder.Append("=");
166+
builder.Append(UrlEncoder.Default.UrlEncode(value));
167+
return new QueryString(builder.ToString());
168+
}
169+
117170
public bool Equals(QueryString other)
118171
{
119172
return string.Equals(_value, other._value);
@@ -142,5 +195,10 @@ public override int GetHashCode()
142195
{
143196
return !left.Equals(right);
144197
}
198+
199+
public static QueryString operator +(QueryString left, QueryString right)
200+
{
201+
return left.Add(right);
202+
}
145203
}
146204
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Threading.Tasks;
8+
using Microsoft.AspNet.Testing;
9+
using Xunit;
10+
11+
namespace Microsoft.AspNet.Http.Abstractions
12+
{
13+
public class QueryStringTests
14+
{
15+
[Fact]
16+
public void CtorThrows_IfQueryDoesNotHaveLeadingQuestionMark()
17+
{
18+
// Act and Assert
19+
ExceptionAssert.ThrowsArgument(() => new QueryString("hello"), "value", "The leading '?' must be included for a non-empty query.");
20+
}
21+
22+
[Fact]
23+
public void CtorNullOrEmpty_Success()
24+
{
25+
var query = new QueryString();
26+
Assert.False(query.HasValue);
27+
Assert.Null(query.Value);
28+
29+
query = new QueryString(null);
30+
Assert.False(query.HasValue);
31+
Assert.Null(query.Value);
32+
33+
query = new QueryString(string.Empty);
34+
Assert.False(query.HasValue);
35+
Assert.Equal(string.Empty, query.Value);
36+
}
37+
38+
[Fact]
39+
public void CtorJustAQuestionMark_Success()
40+
{
41+
var query = new QueryString("?");
42+
Assert.True(query.HasValue);
43+
Assert.Equal("?", query.Value);
44+
}
45+
46+
[Fact]
47+
public void ToString_EncodesHash()
48+
{
49+
var query = new QueryString("?Hello=Wor#ld");
50+
Assert.Equal("?Hello=Wor%23ld", query.ToString());
51+
}
52+
53+
[Theory]
54+
[InlineData("name", "value", "?name=value")]
55+
[InlineData("na me", "val ue", "?na%20me=val%20ue")]
56+
[InlineData("name", "", "?name=")]
57+
[InlineData("", "value", "?=value")]
58+
[InlineData("", "", "?=")]
59+
[InlineData(null, null, "?=")]
60+
public void CreateNameValue_Success(string name, string value, string exepcted)
61+
{
62+
var query = QueryString.Create(name, value);
63+
Assert.Equal(exepcted, query.Value);
64+
}
65+
66+
[Fact]
67+
public void CreateFromList_Success()
68+
{
69+
var query = QueryString.Create(new[]
70+
{
71+
new KeyValuePair<string, string>("key1", "value1"),
72+
new KeyValuePair<string, string>("key2", "value2"),
73+
new KeyValuePair<string, string>("key3", "value3"),
74+
});
75+
Assert.Equal("?key1=value1&key2=value2&key3=value3", query.Value);
76+
}
77+
78+
[Theory]
79+
[InlineData(null, null, null)]
80+
[InlineData("", "", "")]
81+
[InlineData(null, "?name2=value2", "?name2=value2")]
82+
[InlineData("", "?name2=value2", "?name2=value2")]
83+
[InlineData("?", "?name2=value2", "?name2=value2")]
84+
[InlineData("?name1=value1", null, "?name1=value1")]
85+
[InlineData("?name1=value1", "", "?name1=value1")]
86+
[InlineData("?name1=value1", "?", "?name1=value1")]
87+
[InlineData("?name1=value1", "?name2=value2", "?name1=value1&name2=value2")]
88+
public void AddQueryString_Success(string query1, string query2, string expected)
89+
{
90+
var q1 = new QueryString(query1);
91+
var q2 = new QueryString(query2);
92+
Assert.Equal(expected, q1.Add(q2).Value);
93+
Assert.Equal(expected, (q1 + q2).Value);
94+
}
95+
96+
[Theory]
97+
[InlineData(null, null, null, "?=")]
98+
[InlineData("", "", "", "?=")]
99+
[InlineData("?", "", "", "?=")]
100+
[InlineData("?", "name2", "value2", "?name2=value2")]
101+
[InlineData("?name1=value1", "name2", "value2", "?name1=value1&name2=value2")]
102+
[InlineData("?name1=value1", "na me2", "val ue2", "?name1=value1&na%20me2=val%20ue2")]
103+
[InlineData("?name1=value1", "", "", "?name1=value1&=")]
104+
public void AddNameValue_Success(string query1, string name2, string value2, string expected)
105+
{
106+
var q1 = new QueryString(query1);
107+
var q2 = q1.Add(name2, value2);
108+
Assert.Equal(expected, q2.Value);
109+
}
110+
}
111+
}

0 commit comments

Comments
 (0)