Skip to content

Commit 83c2f31

Browse files
drewnoakesvbjay
andcommitted
Quote GitConfigItem values in output as needed
Co-authored-by: Jay Asbury <[email protected]>
1 parent fd23ebf commit 83c2f31

6 files changed

+99
-3
lines changed

GitExtUtils/GitArgumentBuilder.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,14 @@ public override string ToString()
175175
{
176176
var arguments = base.ToString();
177177

178-
var capacity = _command.Length + 1 + arguments.Length + 1 + _configItems.Sum(i => i.Key.Length + i.Value.Length + 5);
178+
// 7 = "-c " + "=" + " " + 2 (for possible quotes of value)
179+
var capacity = _configItems.Sum(i => i.Key.Length + i.Value.Length + 7) + _command.Length + 1 + arguments.Length;
179180

180181
var str = new StringBuilder(capacity);
181182

182183
foreach (var (key, value) in _configItems)
183184
{
184-
str.Append("-c ").Append(key).Append('=').Append(value);
185-
str.Append(' ');
185+
str.Append("-c ").Append(key).Append('=').AppendQuoted(value).Append(' ');
186186
}
187187

188188
str.Append(_command);

GitExtUtils/GitExtUtils.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
<Compile Include="Linq\LinqExtensions.cs" />
6363
<Compile Include="MruCache.cs" />
6464
<Compile Include="Properties\AssemblyInfo.cs" />
65+
<Compile Include="StringBuilderExtensions.cs" />
6566
</ItemGroup>
6667
<ItemGroup>
6768
<None Include="app.config" />
+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System.Text;
2+
using JetBrains.Annotations;
3+
4+
namespace GitCommands
5+
{
6+
public static class StringBuilderExtensions
7+
{
8+
private static readonly char[] _whiteSpaceChars = { ' ', '\r', '\n', '\t' };
9+
10+
[NotNull]
11+
public static StringBuilder AppendQuoted([NotNull] this StringBuilder builder, [NotNull] string s)
12+
{
13+
if (NeedsEscaping())
14+
{
15+
builder.Append('"').Append(s).Append('"');
16+
}
17+
else
18+
{
19+
builder.Append(s);
20+
}
21+
22+
return builder;
23+
24+
bool NeedsEscaping()
25+
{
26+
if (string.IsNullOrWhiteSpace(s))
27+
{
28+
// Quote empty or white space strings
29+
return true;
30+
}
31+
32+
if (s.IndexOfAny(_whiteSpaceChars) == -1)
33+
{
34+
// Doesn't contain any white space
35+
return false;
36+
}
37+
38+
if (s.Length > 1 && s[0] == '"' && s[s.Length - 1] == '"')
39+
{
40+
// String is already quoted
41+
return false;
42+
}
43+
44+
return true;
45+
}
46+
}
47+
}
48+
}

UnitTests/GitExtUtils/GitArgumentBuilderTests.cs

+26
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,32 @@ public void Command_with_custom_config_item()
4949
args.ToString());
5050
}
5151

52+
[Test]
53+
public void Command_with_custom_config_item_quoted()
54+
{
55+
var args = new GitArgumentBuilder("foo")
56+
{
57+
new GitConfigItem("bar", "baz bax")
58+
};
59+
60+
Assert.AreEqual(
61+
"-c bar=\"baz bax\" foo",
62+
args.ToString());
63+
}
64+
65+
[Test]
66+
public void Command_with_custom_config_item_already_quoted()
67+
{
68+
var args = new GitArgumentBuilder("foo")
69+
{
70+
new GitConfigItem("bar", "\"baz bax\"")
71+
};
72+
73+
Assert.AreEqual(
74+
"-c bar=\"baz bax\" foo",
75+
args.ToString());
76+
}
77+
5278
[Test]
5379
public void Command_with_custom_config_item_and_argument()
5480
{

UnitTests/GitUITests/GitUITests.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
<Compile Include="LinqExtensionsTests.cs" />
7373
<Compile Include="SpellChecker\WordAtCursorExtractorTests.cs" />
7474
<Compile Include="SplitterManagerTest.cs" />
75+
<Compile Include="StringBuilderExtensionsTests.cs" />
7576
<Compile Include="ThreadHelperTests.cs" />
7677
<Compile Include="TranslationTest.cs" />
7778
<Compile Include="UITest.cs" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System.Text;
2+
using GitCommands;
3+
using NUnit.Framework;
4+
5+
namespace GitUITests
6+
{
7+
public sealed class StringBuilderExtensionsTests
8+
{
9+
[TestCase("foo", "foo")]
10+
[TestCase("\"foo bar\"", "foo bar")]
11+
[TestCase("\"foo\tbar\"", "foo\tbar")]
12+
[TestCase("\"foo bar\"", "\"foo bar\"")]
13+
[TestCase("\"\"", "")]
14+
[TestCase("\" \"", " ")]
15+
public void AppendQuoted(string expected, string source)
16+
{
17+
Assert.AreEqual(expected, new StringBuilder().AppendQuoted(source).ToString());
18+
}
19+
}
20+
}

0 commit comments

Comments
 (0)