Skip to content

Commit b772bfd

Browse files
author
machibuse
committed
Add Unit Tests
1 parent 05e366e commit b772bfd

18 files changed

Lines changed: 347 additions & 114 deletions

File tree

.github/workflows/release.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ jobs:
3030
- name: Build project
3131
run: dotnet build Source/Porticle.Grpc.sln --configuration Release --no-restore
3232

33+
- name: Run tests
34+
run: dotnet test Source/Porticle.Grpc.UnitTests/Porticle.Grpc.UnitTests.csproj --configuration Release --no-build --verbosity normal
35+
3336
- name: Pack NuGet package
3437
run: dotnet pack Source/Porticle.Grpc.GuidMapper/Porticle.Grpc.GuidMapper.csproj --configuration Release --no-build --output ./nuget --property:PackageVersion=${{ env.VERSION }}
3538

README.md

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -51,41 +51,40 @@ message User {
5151
// Guid of the user object
5252
string id = 1;
5353
54-
// Optional reference ID
55-
google.protobuf.StringValue optional_reference_id = 4;
56-
57-
// Name
58-
string name = 2;
54+
// Optional parent UserId
55+
google.protobuf.StringValue optional_parent_user_id = 2;
5956
6057
// Optional description
6158
google.protobuf.StringValue description = 3;
59+
60+
// List of roles
61+
repeated string role_ids = 4;
6262
}
6363
```
64-
Will result in generated code like this
64+
Will result in generated code like this, everything is a string
6565
```csharp
6666
/// <summary>Guid of the user object</summary>
6767
public string Id {
6868
get { return id_; }
6969
set { id_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); }
7070
}
7171

72-
/// <summary>Optional reference ID</summary>
73-
public string OptionalReferenceId {
74-
get { return optionalReferenceId_; }
75-
set { optionalReferenceId_ = value; }
76-
}
77-
78-
/// <summary>Name</summary>
79-
public string Name {
80-
get { return name_; }
81-
set { name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); }
72+
/// <summary>Optional Guid of the parent UserId</summary>
73+
public string OptionalParentUserId {
74+
get { return optionalParentUserId_; }
75+
set { optionalParentUserId_ = value; }
8276
}
8377

84-
/// <summary>Optional description</summary>
78+
/// <summary>Optional description string</summary>
8579
public string Description {
8680
get { return description_; }
8781
set { description_ = value; }
8882
}
83+
84+
/// <summary>List of roles</summary>
85+
public pbc::RepeatedField<string> RoleIds {
86+
get { return roleIds_; }
87+
}
8988
```
9089

9190
### With GuidMapper
@@ -98,41 +97,48 @@ message User {
9897
// [GrpcGuid] Guid of the user object
9998
string id = 1;
10099
101-
// [GrpcGuid] Optional reference ID
102-
google.protobuf.StringValue optional_reference_id = 4;
103-
104-
// Name
105-
string name = 2;
100+
// [GrpcGuid] Optional Guid of the parent UserId
101+
google.protobuf.StringValue optional_parent_user_id = 2;
106102
107-
// [NullableString] Optional description
103+
// [NullableString] Optional description string
108104
google.protobuf.StringValue description = 3;
105+
106+
// [GrpcGuid] List of roles
107+
repeated string role_ids = 4;
109108
}
110109
```
111-
Will result in generated code like this
110+
Will result in generated code like this, using string? Guid and Guid?
112111
```csharp
113112
/// <summary>[GrpcGuid] Guid of the user object</summary>
114113
public global::System.Guid Id {
115-
get {return global::System.Guid.Parse(id_); }
114+
get { return global::System.Guid.Parse(id_); }
116115
set { id_ = (value).ToString("D"); }
117116
}
118117

119-
/// <summary>[GrpcGuid] Optional reference ID</summary>
120-
public global::System.Guid? OptionalReferenceId {
121-
get {if(optionalReferenceId_==null)return default; return global::System.Guid.Parse(optionalReferenceId_); }
122-
set { optionalReferenceId_ = (value)?.ToString("D"); }
118+
/// <summary>[GrpcGuid] Optional Guid of the parent UserId</summary>
119+
public global::System.Guid? OptionalParentUserId {
120+
get { if(optionalParentUserId_==null) return default; return global::System.Guid.Parse(optionalParentUserId_); }
121+
set { optionalParentUserId_ = (value)?.ToString("D"); }
123122
}
124123

125-
/// <summary>Name</summary>
126-
public string Name {
127-
get { return name_; }
128-
set { name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); }
129-
}
130124

131125
#nullable enable
132-
/// <summary>[NullableString] Optional description</summary>
126+
/// <summary>[NullableString] Optional description string</summary>
133127
public string? Description {
134128
get { return description_; }
135129
set { description_ = value; }
136130
}
137131
#nullable disable
132+
133+
/// <summary>[GrpcGuid] List of roles</summary>
134+
public IList<Guid> RoleIds {
135+
get {return new RepeatedFieldGuidWrapper(roleIds_); }
136+
}
138137
```
138+
139+
## What currently is not Possible?
140+
141+
- Mapping `repeated google.protobuf.StringValue` to `List<Guid?>` or `List<string?>` because grpc internally uses `RepeatedField<string>` instead of `RepeatedField<StringValue>`.
142+
This may be a bug in protoc compiler, because it is also not possible to add `null` to `repeated google.protobuf.StringValue` because ther is a not null check in the Add function in `RepeatedField<T>`
143+
144+
- This Tool actually don't works when protoc / Grpc.Tools is compiled with GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE

Source/.idea/.idea.Porticle.Grpc/.idea/indexLayout.xml

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Source/Porticle.Grpc.GuidMapper.Tests/Class1.cs

Lines changed: 0 additions & 5 deletions
This file was deleted.

Source/Porticle.Grpc.GuidMapper.Tests/Porticle.Grpc.GuidMapper.Tests.csproj

Lines changed: 0 additions & 9 deletions
This file was deleted.

Source/Porticle.Grpc.GuidMapper/ClassVisitor.cs

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@ public class ClassVisitor : CSharpSyntaxRewriter
88
{
99
public override SyntaxNode? VisitClassDeclaration(ClassDeclarationSyntax node)
1010
{
11-
Console.WriteLine("Visit Class "+node.Identifier.ValueText);
1211
var marker = "[Porticle.Grpc.GuidMapper]";
1312

14-
// Skip if marker exists
1513
if (node.GetLeadingTrivia().ToFullString().Contains(marker))
1614
{
17-
Console.WriteLine("Class Already Patched");
15+
// Skip if marker exists - class alreqady patched
1816
return node;
1917
}
2018

@@ -29,20 +27,7 @@ public class ClassVisitor : CSharpSyntaxRewriter
2927
{
3028
node = node.AddMembers(ClassFromSource(ListWrappers.RepeatedFieldGuidWrapper));
3129
}
32-
33-
if (propertyVisitor.NeedNullableGuidConverter)
34-
{
35-
node = node.AddMembers(ClassFromSource(ListWrappers.RepeatedFieldNullableGuidWrapper));
36-
}
37-
38-
if (propertyVisitor.NeedNullableStringConverter)
39-
{
40-
node = node.AddMembers(ClassFromSource(ListWrappers.RepeatedFieldNullableStringWrapper));
41-
}
42-
43-
44-
45-
30+
4631
Console.WriteLine("Visit Methods for "+propertyVisitor.ReplaceProps.Count+" props");
4732
var methodVisitor = new MethodVisitor(propertyVisitor.ReplaceProps);
4833
node = (ClassDeclarationSyntax)methodVisitor.Visit(node);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace Porticle.Grpc.GuidMapper;
2+
3+
public static class Extensions
4+
{
5+
public static T CheckNotNull<T>(this T? value, string valueDescription) where T : class
6+
{
7+
if (value == null)
8+
{
9+
throw new TypeMapperException(valueDescription);
10+
}
11+
12+
return value;
13+
}
14+
15+
16+
17+
18+
}

Source/Porticle.Grpc.GuidMapper/ListWrappers.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
public static class ListWrappers
44
{
55
public static string RepeatedFieldGuidWrapper = "class RepeatedFieldGuidWrapper : System.Collections.Generic.IList<System.Guid>\n{\n private readonly Google.Protobuf.Collections.RepeatedField<string> _internList;\n\n public RepeatedFieldGuidWrapper(Google.Protobuf.Collections.RepeatedField<string> internList)\n {\n this._internList = internList;\n }\n\n public System.Collections.Generic.IEnumerator<System.Guid> GetEnumerator()\n {\n using var enumerator = _internList.GetEnumerator();\n while (enumerator.MoveNext())\n {\n yield return System.Guid.Parse(enumerator.Current);\n }\n }\n\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\n {\n return GetEnumerator();\n }\n\n public void Add(System.Guid item)\n {\n _internList.Add(item.ToString(\"D\"));\n }\n\n public void Clear()\n {\n _internList.Clear();\n }\n\n public bool Contains(System.Guid item)\n {\n return _internList.Contains(item.ToString(\"D\"));\n }\n\n public void CopyTo(System.Guid[] array, int arrayIndex)\n {\n System.Linq.Enumerable.ToArray(System.Linq.Enumerable.Select(_internList, System.Guid.Parse)).CopyTo(array, arrayIndex);\n }\n\n public bool Remove(System.Guid item)\n {\n return _internList.Remove(item.ToString(\"D\"));\n }\n\n public int Count => _internList.Count;\n \n public bool IsReadOnly => _internList.IsReadOnly;\n \n public int IndexOf(System.Guid item)\n {\n return _internList.IndexOf(item.ToString(\"D\"));\n }\n\n public void Insert(int index, System.Guid item)\n {\n _internList.Insert(index, item.ToString(\"D\"));\n }\n\n public void RemoveAt(int index)\n {\n _internList.RemoveAt(index);\n }\n\n public System.Guid this[int index]\n {\n get => System.Guid.Parse(_internList[index]);\n set => _internList[index] = value.ToString(\"D\");\n }\n}";
6-
public static string RepeatedFieldNullableGuidWrapper = "class RepeatedFieldNullableGuidWrapper : System.Collections.Generic.IList<System.Guid?>\n{\n private readonly Google.Protobuf.Collections.RepeatedField<string> _internList;\n\n public RepeatedFieldNullableGuidWrapper(Google.Protobuf.Collections.RepeatedField<string> internList)\n {\n this._internList = internList;\n }\n\n public System.Collections.Generic.IEnumerator<System.Guid?> GetEnumerator()\n {\n using var enumerator = _internList.GetEnumerator();\n while (enumerator.MoveNext())\n {\n yield return string.IsNullOrWhiteSpace(enumerator.Current) ? null : System.Guid.Parse(enumerator.Current);\n }\n }\n\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\n {\n return GetEnumerator();\n }\n\n public void Add(System.Guid? item)\n {\n _internList.Add(item?.ToString(\"D\")!);\n }\n\n public void Clear()\n {\n _internList.Clear();\n }\n\n public bool Contains(System.Guid? item)\n {\n return _internList.Contains(item?.ToString(\"D\")!);\n }\n\n public void CopyTo(System.Guid?[] array, int arrayIndex)\n {\n System.Linq.Enumerable.ToArray(System.Linq.Enumerable.Select(_internList, s => string.IsNullOrWhiteSpace(s) ? null : (System.Guid?)System.Guid.Parse(s!))).CopyTo(array, arrayIndex);\n }\n\n public bool Remove(System.Guid? item)\n {\n return _internList.Remove(item?.ToString(\"D\")!);\n }\n\n public int Count => _internList.Count;\n \n public bool IsReadOnly => _internList.IsReadOnly;\n \n public int IndexOf(System.Guid? item)\n {\n return _internList.IndexOf(item?.ToString(\"D\")!);\n }\n\n public void Insert(int index, System.Guid? item)\n {\n _internList.Insert(index, item?.ToString(\"D\")!);\n }\n\n public void RemoveAt(int index)\n {\n _internList.RemoveAt(index);\n }\n\n public System.Guid? this[int index]\n {\n get => string.IsNullOrWhiteSpace(_internList[index])?null : System.Guid.Parse(_internList[index]);\n set => _internList[index] = value?.ToString(\"D\")!;\n }\n}";
7-
public static string RepeatedFieldNullableStringWrapper = "class RepeatedFieldNullableStringWrapper : System.Collections.Generic.IList<string?>\n{\n private readonly Google.Protobuf.Collections.RepeatedField<string> _internList;\n\n public RepeatedFieldNullableStringWrapper(Google.Protobuf.Collections.RepeatedField<string> internList)\n {\n this._internList = internList;\n }\n\n public System.Collections.Generic.IEnumerator<string?> GetEnumerator()\n {\n using var enumerator = _internList.GetEnumerator();\n while (enumerator.MoveNext())\n {\n yield return enumerator.Current;\n }\n }\n\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\n {\n return GetEnumerator();\n }\n\n public void Add(string? item)\n {\n _internList.Add(item!);\n }\n\n public void Clear()\n {\n _internList.Clear();\n }\n\n public bool Contains(string? item)\n {\n return _internList.Contains(item!);\n }\n\n public void CopyTo(string?[] array, int arrayIndex)\n {\n System.Linq.Enumerable.ToArray(_internList).CopyTo(array, arrayIndex);\n }\n\n public bool Remove(string? item)\n {\n return _internList.Remove(item!);\n }\n\n public int Count => _internList.Count;\n \n public bool IsReadOnly => _internList.IsReadOnly;\n \n public int IndexOf(string? item)\n {\n return _internList.IndexOf(item!);\n }\n\n public void Insert(int index, string? item)\n {\n _internList.Insert(index, item!);\n }\n\n public void RemoveAt(int index)\n {\n _internList.RemoveAt(index);\n }\n\n public string? this[int index]\n {\n get => _internList[index];\n set => _internList[index] = value!;\n }\n}";
6+
7+
// not used, because it cant work because of a bug in grpc code generation
8+
//// public static string RepeatedFieldNullableGuidWrapper = "class RepeatedFieldNullableGuidWrapper : System.Collections.Generic.IList<System.Guid?>\n{\n private readonly Google.Protobuf.Collections.RepeatedField<string> _internList;\n\n public RepeatedFieldNullableGuidWrapper(Google.Protobuf.Collections.RepeatedField<string> internList)\n {\n this._internList = internList;\n }\n\n public System.Collections.Generic.IEnumerator<System.Guid?> GetEnumerator()\n {\n using var enumerator = _internList.GetEnumerator();\n while (enumerator.MoveNext())\n {\n yield return string.IsNullOrWhiteSpace(enumerator.Current) ? null : System.Guid.Parse(enumerator.Current);\n }\n }\n\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\n {\n return GetEnumerator();\n }\n\n public void Add(System.Guid? item)\n {\n _internList.Add(item?.ToString(\"D\")!);\n }\n\n public void Clear()\n {\n _internList.Clear();\n }\n\n public bool Contains(System.Guid? item)\n {\n return _internList.Contains(item?.ToString(\"D\")!);\n }\n\n public void CopyTo(System.Guid?[] array, int arrayIndex)\n {\n System.Linq.Enumerable.ToArray(System.Linq.Enumerable.Select(_internList, s => string.IsNullOrWhiteSpace(s) ? null : (System.Guid?)System.Guid.Parse(s!))).CopyTo(array, arrayIndex);\n }\n\n public bool Remove(System.Guid? item)\n {\n return _internList.Remove(item?.ToString(\"D\")!);\n }\n\n public int Count => _internList.Count;\n \n public bool IsReadOnly => _internList.IsReadOnly;\n \n public int IndexOf(System.Guid? item)\n {\n return _internList.IndexOf(item?.ToString(\"D\")!);\n }\n\n public void Insert(int index, System.Guid? item)\n {\n _internList.Insert(index, item?.ToString(\"D\")!);\n }\n\n public void RemoveAt(int index)\n {\n _internList.RemoveAt(index);\n }\n\n public System.Guid? this[int index]\n {\n get => string.IsNullOrWhiteSpace(_internList[index])?null : System.Guid.Parse(_internList[index]);\n set => _internList[index] = value?.ToString(\"D\")!;\n }\n}";
9+
//// public static string RepeatedFieldNullableStringWrapper = "class RepeatedFieldNullableStringWrapper : System.Collections.Generic.IList<string?>\n{\n private readonly Google.Protobuf.Collections.RepeatedField<string> _internList;\n\n public RepeatedFieldNullableStringWrapper(Google.Protobuf.Collections.RepeatedField<string> internList)\n {\n this._internList = internList;\n }\n\n public System.Collections.Generic.IEnumerator<string?> GetEnumerator()\n {\n using var enumerator = _internList.GetEnumerator();\n while (enumerator.MoveNext())\n {\n yield return enumerator.Current;\n }\n }\n\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\n {\n return GetEnumerator();\n }\n\n public void Add(string? item)\n {\n _internList.Add(item!);\n }\n\n public void Clear()\n {\n _internList.Clear();\n }\n\n public bool Contains(string? item)\n {\n return _internList.Contains(item!);\n }\n\n public void CopyTo(string?[] array, int arrayIndex)\n {\n System.Linq.Enumerable.ToArray(_internList).CopyTo(array, arrayIndex);\n }\n\n public bool Remove(string? item)\n {\n return _internList.Remove(item!);\n }\n\n public int Count => _internList.Count;\n \n public bool IsReadOnly => _internList.IsReadOnly;\n \n public int IndexOf(string? item)\n {\n return _internList.IndexOf(item!);\n }\n\n public void Insert(int index, string? item)\n {\n _internList.Insert(index, item!);\n }\n\n public void RemoveAt(int index)\n {\n _internList.RemoveAt(index);\n }\n\n public string? this[int index]\n {\n get => _internList[index];\n set => _internList[index] = value!;\n }\n}";
810
}

Source/Porticle.Grpc.GuidMapper/Porticle.Grpc.GuidMapper.csproj

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,14 @@
1616
<PackageReleaseNotes>First test version</PackageReleaseNotes>
1717
<IncludeBuildOutput>false</IncludeBuildOutput>
1818
<DevelopmentDependency>true</DevelopmentDependency>
19-
<Version>1.0.25</Version>
19+
<Version>1.0.26</Version>
2020
<SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
21-
<TargetFrameworks>net9.0;net8.0</TargetFrameworks>
21+
<TargetFrameworks>net9.0;net8.0</TargetFrameworks>
22+
<PackageReadmeFile>readme.md</PackageReadmeFile>
23+
</PropertyGroup>
24+
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
25+
<WarningsAsErrors>NU1605</WarningsAsErrors>
26+
<NoWarn>1701;1702;NU5119</NoWarn>
2227
</PropertyGroup>
2328

2429
<ItemGroup>
@@ -30,10 +35,9 @@
3035
<None Include="pinky32.png" Pack="True" PackagePath="/" />
3136
</ItemGroup>
3237

38+
3339
<ItemGroup>
34-
<None Include="Porticle.Grpc.GuidMapper.targets" Pack="true" PackagePath="buildTransitive" />
35-
</ItemGroup>
36-
<ItemGroup>
40+
<None Include="..\..\readme.md" Pack="true" PackagePath="\"/>
3741
<None Include="Porticle.Grpc.GuidMapper.targets" Pack="true" PackagePath="buildTransitive" />
3842
<None Include="$(OutputPath)**\*" Pack="true" PackagePath="tools\$(TargetFramework)\" />
3943
</ItemGroup>

Source/Porticle.Grpc.GuidMapper/Program.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,21 @@
1616
}
1717

1818
var basename = Path.GetFileNameWithoutExtension(args[0]);
19+
20+
if (string.IsNullOrWhiteSpace(basename))
21+
{
22+
Console.WriteLine("Warning: Nothing to preprocess - no filename given");
23+
return;
24+
}
25+
1926
var directory = Path.GetDirectoryName(args[0])!;
2027
string[] filenames = [StringUtils.LowerUnderscoreToUpperCamelProtocWay(basename) + ".cs", StringUtils.LowerUnderscoreToUpperCamelGrpcWay(basename) + "Grpc.cs"];
2128

29+
Console.WriteLine($"GRPC Post-processing for: {string.Join(", ",filenames)}");
2230

2331
foreach (var filename in filenames)
2432
{
2533
var filePath = Path.Combine(directory, filename);
26-
Console.WriteLine($"Post-processing file: {filePath}");
2734

2835
var originalCode = File.ReadAllText(filePath);
2936
var tree = CSharpSyntaxTree.ParseText(originalCode);
@@ -33,13 +40,6 @@
3340
var classVisitor = new ClassVisitor();
3441
root = classVisitor.Visit(root);
3542

36-
37-
// // das ganze noch für GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
38-
// var options = new CSharpParseOptions();
39-
// options = options.WithPreprocessorSymbols("GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE");
40-
// root = CSharpSyntaxTree.ParseText(root.ToFullString(), options).GetRoot();
41-
// root = methodVisitor.Visit(root);
42-
4343
File.WriteAllText(filePath, root.ToFullString());
4444
Console.WriteLine("Post-processing complete.");
45-
}
45+
}

0 commit comments

Comments
 (0)