Skip to content

Commit 48ad28a

Browse files
committed
* Abstract IO (File Creation) in SourceGeneration with FileAbstraction
* Add unit tests utilising `FileAbstraction` enables ability to refactor database access and source generation and ensure the results remain unchanged
1 parent 0c2e542 commit 48ad28a

File tree

89 files changed

+6225139
-75
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+6225139
-75
lines changed

.config/dotnet-tools.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"version": 1,
3+
"isRoot": true,
4+
"tools": {
5+
"diffenginetray": {
6+
"version": "9.0.3",
7+
"commands": [
8+
"DiffEngineTray"
9+
]
10+
}
11+
}
12+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
namespace NHapi.SourceGeneration;
2+
3+
using System;
4+
using System.IO;
5+
using System.Threading;
6+
using System.Threading.Tasks;
7+
8+
public static class FileAbstraction
9+
{
10+
private static readonly Action<string, byte[]> DefaultWriteAllBytesImplementation =
11+
(filePath, bytes) =>
12+
{
13+
using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite);
14+
fileStream.Write(bytes, 0, bytes.Length);
15+
};
16+
17+
private static readonly Func<string, byte[], CancellationToken, Task> DefaultWriteAllBytesAsyncImplementation =
18+
async (filePath, bytes, cancellationToken) =>
19+
{
20+
using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite);
21+
await fileStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);
22+
};
23+
24+
private static Action<string, byte[]> writeAllBytesImplementation;
25+
26+
private static Func<string, byte[], CancellationToken, Task> writeAllBytesAsyncImplementation;
27+
28+
/// <summary>
29+
/// Sets the implementation of <see cref="WriteAllBytes"/>.
30+
/// </summary>
31+
/// <param name="writeAllBytes">Implementation of <see cref="WriteAllBytes"/>.</param>
32+
/// <exception cref="ArgumentNullException">If <paramref name="writeAllBytes" /> is null.</exception>
33+
public static void UsingImplementation(Action<string, byte[]> writeAllBytes)
34+
{
35+
FileAbstraction.writeAllBytesImplementation =
36+
writeAllBytes ?? throw new ArgumentNullException(nameof(writeAllBytes));
37+
}
38+
39+
/// <summary>
40+
/// Sets the implementation of <see cref="WriteAllBytesAsync(string, byte[], CancellationToken)"/>.
41+
/// </summary>
42+
/// <param name="writeAllBytesAsync">Implementation of <see cref="WriteAllBytesAsync(string, byte[], CancellationToken)"/>.</param>
43+
/// <exception cref="ArgumentNullException">If <paramref name="writeAllBytesAsync" /> is null.</exception>
44+
public static void UsingImplementation(Func<string, byte[], CancellationToken, Task> writeAllBytesAsync)
45+
{
46+
FileAbstraction.writeAllBytesAsyncImplementation =
47+
writeAllBytesAsync ?? throw new ArgumentNullException(nameof(writeAllBytesAsync));
48+
}
49+
50+
/// <summary>
51+
/// Creates a new file, writes the specified byte array to the file, and then closes the file.
52+
/// If the target file already exists, it is overwritten.
53+
/// </summary>
54+
/// <param name="filePath">The file to write to.</param>
55+
/// <param name="bytes">The bytes to write to the file.</param>
56+
public static void WriteAllBytes(string filePath, byte[] bytes)
57+
{
58+
(writeAllBytesImplementation ?? DefaultWriteAllBytesImplementation)(filePath, bytes);
59+
}
60+
61+
/// <summary>
62+
/// Asynchronously creates a new file, writes the specified byte array to the file, and then closes the file.
63+
/// If the target file already exists, it is overwritten.
64+
/// </summary>
65+
/// <param name="filePath">The file to write to.</param>
66+
/// <param name="bytes">The bytes to write to the file.</param>
67+
/// <returns>A task that represents the asynchronous write operation.</returns>
68+
public static async Task WriteAllBytesAsync(string filePath, byte[] bytes)
69+
{
70+
await (writeAllBytesAsyncImplementation ??
71+
DefaultWriteAllBytesAsyncImplementation)(filePath, bytes, default).ConfigureAwait(false);
72+
}
73+
74+
/// <summary>
75+
/// Asynchronously creates a new file, writes the specified byte array to the file, and then closes the file.
76+
/// If the target file already exists, it is overwritten.
77+
/// </summary>
78+
/// <param name="filePath">The file to write to.</param>
79+
/// <param name="bytes">The bytes to write to the file.</param>
80+
/// <param name="cancellationToken">
81+
/// The token to monitor for cancellation requests.
82+
/// The default value is <see cref="P:System.Threading.CancellationToken.None" />.
83+
/// </param>
84+
/// <returns>A task that represents the asynchronous write operation.</returns>
85+
public static async Task WriteAllBytesAsync(
86+
string filePath,
87+
byte[] bytes,
88+
CancellationToken cancellationToken)
89+
{
90+
await (writeAllBytesAsyncImplementation ??
91+
DefaultWriteAllBytesAsyncImplementation)(filePath, bytes, cancellationToken)
92+
.ConfigureAwait(false);
93+
}
94+
}

src/NHapi.SourceGeneration/Generators/BaseDataTypeGenerator.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ public static void BuildBaseDataTypes(string baseDirectory, string version)
2121
private static void BuildFile(string dataType, string targetDir, string version)
2222
{
2323
var fileName = Path.Combine(targetDir, $"{dataType}.cs");
24+
25+
FileAbstraction.WriteAllBytes(
26+
fileName,
27+
Encoding.UTF8.GetBytes(GetClassSource(dataType, version)));
2428
}
2529

2630
private static string GetClassSource(string dataType, string version)

src/NHapi.SourceGeneration/Generators/DataTypeGenerator.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ namespace NHapi.SourceGeneration.Generators
2929
{
3030
using System;
3131
using System.Collections;
32+
using System.Collections.Generic;
3233
using System.Data.Common;
3334
using System.IO;
3435
using System.Linq;
@@ -83,7 +84,7 @@ public static void MakeAll(string baseDirectory, string version)
8384
Path.Combine(baseDirectory, PackageManager.GetVersionPackagePath(version), "Datatype"));
8485

8586
// get list of data types
86-
var types = new ArrayList();
87+
var types = new List<string>();
8788
var conn = NormativeDatabase.Instance.Connection;
8889
var stmt = TransactionManager.Manager.CreateStatement(conn);
8990

@@ -125,7 +126,7 @@ public static void MakeAll(string baseDirectory, string version)
125126
Log.Warn("No version " + version + " data types found in database " + conn.Database);
126127
}
127128

128-
foreach (var type in types.Cast<string>())
129+
foreach (var type in types)
129130
{
130131
if (!type.Equals("*"))
131132
{
@@ -263,6 +264,8 @@ public static void Make(FileInfo targetDirectory, string dataType, string versio
263264
if (source != null)
264265
{
265266
var targetFile = Path.Combine(targetDirectory.ToString(), $"{dataType}.cs");
267+
268+
FileAbstraction.WriteAllBytes(targetFile, Encoding.UTF8.GetBytes($"{source}}}"));
266269
}
267270
else
268271
{

src/NHapi.SourceGeneration/Generators/EventMappingGenerator.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ namespace NHapi.SourceGeneration.Generators
33
using System.Data.Common;
44
using System.Data.Odbc;
55
using System.IO;
6+
using System.Text;
67

78
using NHapi.Base;
89

@@ -32,17 +33,25 @@ public static void MakeAll(string baseDirectory, string version)
3233

3334
var targetFile = Path.Combine(targetDir.FullName, "EventMap.properties");
3435

35-
using (var sw = new StreamWriter(targetFile, false))
36+
var stringBuilder = new StringBuilder();
37+
38+
stringBuilder.AppendLine($"#event -> structure map for {version}");
39+
if (version == "2.1" || version == "2.2")
40+
{
41+
stringBuilder.AppendLine("#note: no mappings are defined for 2.1 and 2.2");
42+
}
43+
else
3644
{
37-
sw.WriteLine("#event -> structure map for " + version);
3845
while (rs.Read())
3946
{
40-
var messageType = string.Format("{0}_{1}", rs["message_typ_snd"], rs["event_code"]);
47+
var messageType = $"{rs["message_typ_snd"]}_{rs["event_code"]}";
4148
var structure = (string)rs["message_structure_snd"];
4249

43-
sw.WriteLine(string.Format("{0} {1}", messageType, structure));
50+
stringBuilder.AppendLine($"{messageType} {structure}");
4451
}
4552
}
53+
54+
FileAbstraction.WriteAllBytes(targetFile, Encoding.UTF8.GetBytes(stringBuilder.ToString()));
4655
}
4756
}
4857
}

src/NHapi.SourceGeneration/Generators/GroupGenerator.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -101,21 +101,21 @@ public static GroupDef WriteGroup(
101101

102102
var targetFile = Path.Combine(targetDir.FullName, $"{@group.Name}.cs");
103103

104-
using (var out_Renamed = new StreamWriter(targetFile))
105-
{
106-
out_Renamed.Write(MakePreamble(group, version));
107-
out_Renamed.Write(MakeConstructor(group, version));
104+
var stringBuilder = new StringBuilder();
108105

109-
var shallow = group.Structures;
110-
for (var i = 0; i < shallow.Length; i++)
111-
{
112-
out_Renamed.Write(MakeAccessor(group, i));
113-
}
106+
stringBuilder.Append(MakePreamble(group, version));
107+
stringBuilder.Append(MakeConstructor(group, version));
114108

115-
out_Renamed.Write("}\r\n"); // Closing class
116-
out_Renamed.Write("}\r\n"); // Closing namespace
109+
var shallow = group.Structures;
110+
for (var i = 0; i < shallow.Length; i++)
111+
{
112+
stringBuilder.Append(MakeAccessor(group, i));
117113
}
118114

115+
stringBuilder.Append("}\r\n"); // Closing class
116+
stringBuilder.Append("}\r\n"); // Closing namespace
117+
118+
FileAbstraction.WriteAllBytes(targetFile, Encoding.UTF8.GetBytes(stringBuilder.ToString()));
119119
return group;
120120
}
121121

src/NHapi.SourceGeneration/Generators/MessageGenerator.cs

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ namespace NHapi.SourceGeneration.Generators
2828
{
2929
using System;
3030
using System.Collections;
31+
using System.Collections.Generic;
3132
using System.Data.Common;
3233
using System.Data.Odbc;
3334
using System.IO;
@@ -76,8 +77,9 @@ public static void MakeAll(string baseDirectory, string version)
7677
temp_OleDbCommand = stmt;
7778
temp_OleDbCommand.CommandText = sql;
7879
var rs = temp_OleDbCommand.ExecuteReader();
79-
var messages = new ArrayList();
80-
var chapters = new ArrayList();
80+
81+
var messages = new List<string>();
82+
var chapters = new List<string>();
8183
while (rs.Read())
8284
{
8385
messages.Add(Convert.ToString(rs[1 - 1]));
@@ -94,8 +96,8 @@ public static void MakeAll(string baseDirectory, string version)
9496

9597
for (var i = 0; i < messages.Count; i++)
9698
{
97-
var message = (string)messages[i];
98-
var chapter = (string)chapters[i];
99+
var message = messages[i];
100+
var chapter = chapters[i];
99101
Make(message, baseDirectory, chapter, version);
100102
}
101103
}
@@ -126,21 +128,23 @@ public static void Make(string message, string baseDirectory, string chapter, st
126128
SourceGenerator.MakeDirectory(
127129
Path.Combine(baseDirectory, PackageManager.GetVersionPackagePath(version), "Message"));
128130

129-
Console.Out.WriteLine("Writing " + message + " to " + targetDir.FullName);
130-
using (var out_Renamed = new StreamWriter(targetDir.FullName + "/" + message + ".cs"))
131+
var targetFile = Path.Combine(targetDir.FullName, $"{message}.cs");
132+
133+
var stringBuilder = new StringBuilder();
134+
135+
stringBuilder.Append(MakePreamble(contents, message, chapter, version));
136+
stringBuilder.Append(MakeConstructor(contents, message, version));
137+
for (var i = 0; i < contents.Length; i++)
131138
{
132-
out_Renamed.Write(MakePreamble(contents, message, chapter, version));
133-
out_Renamed.Write(MakeConstructor(contents, message, version));
134-
for (var i = 0; i < contents.Length; i++)
135-
{
136-
var groupAccessor = GroupGenerator.MakeAccessor(@group, i);
137-
out_Renamed.Write(groupAccessor);
138-
}
139-
140-
// add implementation of model.control interface, if any
141-
out_Renamed.Write("}\r\n"); // End class
142-
out_Renamed.Write("}\r\n"); // End namespace
139+
var groupAccessor = GroupGenerator.MakeAccessor(@group, i);
140+
stringBuilder.Append(groupAccessor);
143141
}
142+
143+
// add implementation of model.control interface, if any
144+
stringBuilder.Append("}\r\n"); // End class
145+
stringBuilder.Append("}\r\n"); // End namespace
146+
147+
FileAbstraction.WriteAllBytes(targetFile, Encoding.UTF8.GetBytes(stringBuilder.ToString()));
144148
}
145149
catch (Exception e)
146150
{

src/NHapi.SourceGeneration/Generators/SegmentGenerator.cs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public static void MakeAll(string baseDirectory, string version)
115115
temp_OleDbCommand.CommandText = sql;
116116
var rs = temp_OleDbCommand.ExecuteReader();
117117

118-
var segments = new ArrayList();
118+
var segments = new List<string>();
119119
while (rs.Read())
120120
{
121121
var segName = Convert.ToString(rs[1 - 1]);
@@ -137,16 +137,12 @@ public static void MakeAll(string baseDirectory, string version)
137137
{
138138
try
139139
{
140-
var seg = (string)segments[i];
141-
var source = MakeSegment(seg, version);
140+
var segment = segments[i];
141+
var source = MakeSegment(segment, version);
142142

143-
var targetFile = Path.Combine(targetDir.ToString(), $"{GetSpecialFilename(seg)}.cs");
143+
var targetFile = Path.Combine(targetDir.ToString(), $"{GetSpecialFilename(segment)}.cs");
144144

145-
using (var w = new StreamWriter(targetFile))
146-
{
147-
w.Write(source);
148-
w.Write("}");
149-
}
145+
FileAbstraction.WriteAllBytes(targetFile, Encoding.UTF8.GetBytes($"{source}}}"));
150146
}
151147
catch (Exception e)
152148
{

src/NHapi.SourceGeneration/NHapi.SourceGeneration.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,8 @@
2727
<ProjectReference Include="..\NHapi.Base\NHapi.Base.csproj" />
2828
</ItemGroup>
2929

30+
<ItemGroup>
31+
<InternalsVisibleTo Include="NHapi.NUnit.SourceGeneration" />
32+
</ItemGroup>
33+
3034
</Project>

0 commit comments

Comments
 (0)