Skip to content

Commit 8bccb48

Browse files
jiridanekkornys
authored andcommitted
Improve option parsing to fix #11 and #12 (#14)
* Introduce dependency on System.AutoValue used by subsequent commits * Refactor msg-content-map-item parsing to use ParseItem method Issue #12 was caused by the fact that automatic casts were not performed by the orignal implementation of the msg-content-map-item parsing code. When call to AutoCast is added to ParseItem in a subsequent commit, that fixes the issue. * Fix parsing of key=~1 style of argument in test_direct_transient_list_message * Refactor SenderOptions.ParseItem and add additional tests * Refactor msg-annotation option parsing using ParseItem method This fixes #12 * Refactor msg-property option parsing using ParseItem method * Migrate msg-content-list-item to ParseValue and AutoCast methods Previously, all list items were sent as strings. This change adds automatic type cast there. This fixes #11
1 parent 70ef824 commit 8bccb48

File tree

6 files changed

+201
-67
lines changed

6 files changed

+201
-67
lines changed

src/dotNet/ClientLib/ClientLib.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@
5353
<Reference Include="System" />
5454
<Reference Include="System.Core" />
5555
<Reference Include="System.Transactions" />
56+
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51">
57+
<HintPath>..\..\..\packages\System.ValueTuple.4.5.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
58+
<Private>True</Private>
59+
</Reference>
5660
<Reference Include="System.Xml.Linq" />
5761
<Reference Include="System.Data.DataSetExtensions" />
5862
<Reference Include="Microsoft.CSharp" />

src/dotNet/ClientLib/OptionsParser.cs

Lines changed: 66 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -302,35 +302,8 @@ public SenderOptions() : base()
302302
(string subject) => { this.Subject = subject; });
303303
this.Add("msg-property=", "specify reply-to property",
304304
(string property) => {
305-
char[] delimiters = { '=', '~' };
306-
string[] pair = property.Split(delimiters);
307-
int valueIndex = pair.Length == 2 ? 1 : 2;
308-
if (pair.Length == 2 || pair.Length == 3)
309-
{
310-
double doubleVal;
311-
int intVal;
312-
bool boolVal;
313-
if (int.TryParse(pair[valueIndex], out intVal))
314-
{
315-
this.Properties.Add(pair[0], intVal);
316-
}
317-
else if (double.TryParse(pair[valueIndex], out doubleVal))
318-
{
319-
this.Properties.Add(pair[0], doubleVal);
320-
}
321-
else if (Boolean.TryParse(pair[valueIndex], out boolVal))
322-
{
323-
this.Properties.Add(pair[0], boolVal);
324-
}
325-
else
326-
{
327-
this.Properties.Add(pair[0], pair[valueIndex]);
328-
}
329-
}
330-
else
331-
{
332-
throw new ArgumentException();
333-
}
305+
var (key, value) = ParseItem(property);
306+
this.Properties.Add(key, value);
334307
});
335308
this.Add("property-type=", "specify message property type (overrides auto-cast feature)",
336309
(string propertyType) => { this.PropertyType = propertyType; });
@@ -364,54 +337,80 @@ public SenderOptions() : base()
364337
(string content) => { this.Content = content; });
365338
this.Add("L|msg-content-list-item=", "specify a multiple entries content",
366339
(string listItem) => {
367-
this.ListContent.Add(listItem);
340+
this.ListContent.Add(ParseValue(listItem));
368341
});
369342
this.Add("M|msg-content-map-item=", "KEY=VALUE specify a map content",
370343
(string mapItem) => {
371-
char[] delimiters = { '=', '~' };
372-
string[] pair = mapItem.Split(delimiters);
373-
if (pair.Length == 2)
374-
{
375-
this.MapContent.Add(pair[0], pair[1]);
376-
}
377-
else if (pair.Length == 3)
378-
{
379-
this.MapContent.Add(pair[0], pair[2]);
380-
}
381-
else
382-
{
383-
throw new ArgumentException();
384-
}
344+
var (key, value) = ParseItem(mapItem);
345+
this.MapContent.Add(key, value);
385346
});
386347
this.Add("msg-content-from-file=", "specify file name to load the content from",
387348
(string path) => { this.ContentFromFile = ReadInputFile(path); });
388349
this.Add("msg-annotation=", "specify amqp properties",
389350
(string annotation) => {
390-
char[] delimiters = { '=', '~' };
391-
string[] pair = annotation.Split(delimiters);
392-
if (pair.Length == 2)
393-
{
394-
double doubleVal;
395-
bool boolVal;
396-
if (double.TryParse(pair[1], out doubleVal))
397-
{
398-
this.MessageAnnotations[new Symbol(pair[0])] = doubleVal;
399-
}
400-
else if (Boolean.TryParse(pair[1], out boolVal))
401-
{
402-
this.MessageAnnotations[new Symbol(pair[0])] = boolVal;
403-
}
404-
else
405-
{
406-
this.MessageAnnotations[new Symbol(pair[0])] = pair[1];
407-
}
408-
}
409-
else
410-
{
411-
throw new ArgumentException();
412-
}
351+
var (key, value) = ParseItem(annotation);
352+
this.MessageAnnotations[new Symbol(key)] = value;
413353
});
414354
}
355+
356+
public static (string, object) ParseItem(string mapItem)
357+
{
358+
char[] delimiters = {'=', '~'};
359+
int i = mapItem.IndexOfAny(delimiters);
360+
361+
if (i == -1)
362+
{
363+
throw new ArgumentException();
364+
}
365+
366+
var key = mapItem.Substring(0, i);
367+
var value = mapItem.Substring(i+1);
368+
369+
if (mapItem[i] == '~')
370+
{
371+
return (key, AutoCast(value));
372+
}
373+
return (key, value);
374+
}
375+
376+
public static object ParseValue(string value)
377+
{
378+
if (value.Length >= 1 && value[0] == '~')
379+
{
380+
return AutoCast(value.Substring(1));
381+
}
382+
383+
return value;
384+
}
385+
386+
private static object AutoCast(string value)
387+
{
388+
int intVal;
389+
double doubleVal;
390+
bool boolVal;
391+
392+
if (int.TryParse(value, out intVal))
393+
{
394+
return intVal;
395+
}
396+
397+
if (double.TryParse(value, out doubleVal))
398+
{
399+
return doubleVal;
400+
}
401+
402+
if (Boolean.TryParse(value, out boolVal))
403+
{
404+
return boolVal;
405+
}
406+
407+
if (value == string.Empty)
408+
{
409+
return null;
410+
}
411+
412+
return value;
413+
}
415414
}
416415

417416
/// <summary>

src/dotNet/ClientLib/packages.config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
<packages>
33
<package id="AMQPNetLite" version="2.1.3" targetFramework="net45" />
44
<package id="Newtonsoft.Json" version="11.0.2" targetFramework="net45" />
5+
<package id="System.ValueTuple" version="4.5.0" targetFramework="net45" />
56
</packages>

test/ClientUnitTests/ClientUnitTests.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@
5252
<HintPath>..\..\packages\NUnit.3.10.1\lib\net45\nunit.framework.dll</HintPath>
5353
</Reference>
5454
<Reference Include="System" />
55+
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51">
56+
<HintPath>..\..\packages\System.ValueTuple.4.5.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
57+
<Private>True</Private>
58+
</Reference>
5559
</ItemGroup>
5660
<Choose>
5761
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
@@ -64,6 +68,7 @@
6468
<ItemGroup>
6569
<Compile Include="BasicBinTests.cs" />
6670
<Compile Include="ClientRunner.cs" />
71+
<Compile Include="OptionParserTests.cs" />
6772
<Compile Include="Properties\AssemblyInfo.cs" />
6873
<Compile Include="SendReceiveTests.cs" />
6974
</ItemGroup>
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
using System;
2+
using ClientLib;
3+
using NUnit.Framework;
4+
5+
namespace ClientUnitTests
6+
{
7+
// https://haacked.com/archive/2012/01/02/structuring-unit-tests.aspx/
8+
public class TheSenderOptionsItemParser
9+
{
10+
[Test]
11+
public void ThrowsOnEmptyString()
12+
{
13+
Assert.Throws<ArgumentException>(() => SenderOptions.ParseItem(""));
14+
}
15+
16+
[Test]
17+
public void ParsesEqualsStringAsString()
18+
{
19+
Assert.AreEqual(ValueTuple.Create("key", "aString"), SenderOptions.ParseItem("key=aString"));
20+
}
21+
22+
[Test]
23+
public void ParsesEqualsIntAsString()
24+
{
25+
Assert.AreEqual(ValueTuple.Create("key", "42"), SenderOptions.ParseItem("key=42"));
26+
}
27+
28+
[Test]
29+
public void ParsesEqualsTildeAsString()
30+
{
31+
Assert.AreEqual(ValueTuple.Create("key", "~1"), SenderOptions.ParseItem("key=~1"));
32+
}
33+
34+
[Test]
35+
public void ParsesDoubleTildeAsString()
36+
{
37+
Assert.AreEqual(ValueTuple.Create("key", "~1"), SenderOptions.ParseItem("key~~1"));
38+
}
39+
40+
[Test]
41+
public void ParsesDoubleEqualsAsString()
42+
{
43+
Assert.AreEqual(ValueTuple.Create("key", "=1"), SenderOptions.ParseItem("key==1"));
44+
}
45+
46+
[Test]
47+
public void ParsesTildeStringAsString()
48+
{
49+
Assert.AreEqual(ValueTuple.Create("key", "aString"), SenderOptions.ParseItem("key~aString"));
50+
}
51+
52+
[Test]
53+
public void ParsesEqualsEmptyAsEmptyString()
54+
{
55+
Assert.AreEqual(ValueTuple.Create("key", ""), SenderOptions.ParseItem("key="));
56+
}
57+
58+
/// <summary>
59+
/// Note: null key is not supported py ParseItem
60+
/// </summary>
61+
[Test]
62+
public void ParsesEmptyEqualsAsEmptyStringKey()
63+
{
64+
Assert.AreEqual(ValueTuple.Create("", "aString"), SenderOptions.ParseItem("=aString"));
65+
}
66+
67+
[Test]
68+
public void ParsesTildeEmptyAsNull()
69+
{
70+
Assert.AreEqual(ValueTuple.Create("key", (String) null), SenderOptions.ParseItem("key~"));
71+
}
72+
73+
[Test]
74+
public void ParsesTildeDoubleAsDouble()
75+
{
76+
Assert.AreEqual(ValueTuple.Create("key", 3.14d), SenderOptions.ParseItem("key~3.14"));
77+
}
78+
79+
[Test]
80+
public void ParsesTildeBoolAsBool()
81+
{
82+
Assert.AreEqual(ValueTuple.Create("key", false), SenderOptions.ParseItem("key~False"));
83+
}
84+
85+
[Test]
86+
public void ParseTildeStringAsString()
87+
{
88+
Assert.AreEqual(ValueTuple.Create("key", "aString"), SenderOptions.ParseItem("key~aString"));
89+
}
90+
91+
[Test]
92+
public void ParsesTildeIntAsInt()
93+
{
94+
Assert.AreEqual(ValueTuple.Create("key", 42), SenderOptions.ParseItem("key~42"));
95+
}
96+
}
97+
98+
public class TheSenderOptionsValueParser
99+
{
100+
[Test]
101+
public void ParsesEmtpyStringAsEmptyString()
102+
{
103+
Assert.AreEqual(string.Empty, SenderOptions.ParseValue(""));
104+
}
105+
106+
[Test]
107+
public void ParsesTildeAsNull()
108+
{
109+
Assert.AreEqual(null, SenderOptions.ParseValue("~"));
110+
}
111+
112+
[Test]
113+
public void ParsesDoubleTildeAsString()
114+
{
115+
Assert.AreEqual("~", SenderOptions.ParseValue("~~"));
116+
}
117+
118+
[Test]
119+
public void ParsesTildeIntAsInt()
120+
{
121+
Assert.AreEqual(42, SenderOptions.ParseValue("~42"));
122+
}
123+
}
124+
}

test/ClientUnitTests/packages.config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
<package id="NUnit" version="3.10.1" targetFramework="net45" />
44
<package id="NUnit3TestAdapter" version="3.10.0" targetFramework="net45" />
55
<package id="NUnitTestAdapter" version="2.1.1" targetFramework="net45" />
6+
<package id="System.ValueTuple" version="4.5.0" targetFramework="net45" />
67
</packages>

0 commit comments

Comments
 (0)