Skip to content

Commit e768edb

Browse files
committed
refactor: ReportGenerateServiceをセクション分割し比較ロジックとドキュメント/テストを改善
1 parent 8732294 commit e768edb

7 files changed

Lines changed: 372 additions & 180 deletions

File tree

FolderDiffIL4DotNet.Tests/Services/FolderDiffServiceTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,32 @@ public async Task ExecuteFolderDiffAsync_ClearsPreviousRunStateAtStart()
140140
Assert.Empty(_resultLists.NewFilesAbsolutePath);
141141
}
142142

143+
[Fact]
144+
public async Task ExecuteFolderDiffAsync_TextExtensionComparison_IsCaseInsensitive()
145+
{
146+
var oldDir = Path.Combine(_rootDir, "old-case-insensitive");
147+
var newDir = Path.Combine(_rootDir, "new-case-insensitive");
148+
var reportDir = Path.Combine(_rootDir, "report-case-insensitive");
149+
Directory.CreateDirectory(oldDir);
150+
Directory.CreateDirectory(newDir);
151+
Directory.CreateDirectory(reportDir);
152+
153+
const string fileRelativePath = "sample.TxT";
154+
WriteFile(oldDir, fileRelativePath, "before");
155+
WriteFile(newDir, fileRelativePath, "after");
156+
157+
var config = CreateConfig(maxParallelism: 1);
158+
config.TextFileExtensions = new List<string> { ".TXT" };
159+
using var progressReporter = new ProgressReportService();
160+
var service = new FolderDiffService(config, progressReporter, oldDir, newDir, reportDir, _serviceProvider, _resultLists, _logger);
161+
162+
await service.ExecuteFolderDiffAsync();
163+
164+
Assert.Equal(
165+
FileDiffResultLists.DiffDetailResult.TextMismatch,
166+
_resultLists.FileRelativePathToDiffDetailDictionary[fileRelativePath]);
167+
}
168+
143169
private static ConfigSettings CreateConfig(int maxParallelism) => new()
144170
{
145171
IgnoredExtensions = new List<string> { ".pdb" },

FolderDiffIL4DotNet.Tests/Services/ReportGenerateServiceTests.cs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,60 @@ public void GenerateDiffReport_HeaderShowsEmptyIlContainsIgnoreNote_WhenEnabledB
213213
Assert.Contains("IL line-ignore-by-contains is enabled, but no non-empty strings are configured.", reportText);
214214
}
215215

216+
[Fact]
217+
public void GenerateDiffReport_WritesAllMainSections()
218+
{
219+
var oldDir = Path.Combine(_rootDir, "old-sections");
220+
var newDir = Path.Combine(_rootDir, "new-sections");
221+
var reportDir = Path.Combine(_rootDir, "report-sections");
222+
Directory.CreateDirectory(oldDir);
223+
Directory.CreateDirectory(newDir);
224+
Directory.CreateDirectory(reportDir);
225+
226+
var oldSame = Path.Combine(oldDir, "same.txt");
227+
var newSame = Path.Combine(newDir, "same.txt");
228+
var oldModified = Path.Combine(oldDir, "modified.txt");
229+
var newModified = Path.Combine(newDir, "modified.txt");
230+
var oldRemoved = Path.Combine(oldDir, "removed.txt");
231+
var newAdded = Path.Combine(newDir, "added.txt");
232+
File.WriteAllText(oldSame, "same");
233+
File.WriteAllText(newSame, "same");
234+
File.WriteAllText(oldModified, "before");
235+
File.WriteAllText(newModified, "after");
236+
File.WriteAllText(oldRemoved, "removed");
237+
File.WriteAllText(newAdded, "added");
238+
239+
_resultLists.SetOldFilesAbsolutePath(new List<string> { oldSame, oldModified, oldRemoved });
240+
_resultLists.SetNewFilesAbsolutePath(new List<string> { newSame, newModified, newAdded });
241+
_resultLists.AddUnchangedFileRelativePath("same.txt");
242+
_resultLists.RecordDiffDetail("same.txt", FileDiffResultLists.DiffDetailResult.MD5Match);
243+
_resultLists.AddModifiedFileRelativePath("modified.txt");
244+
_resultLists.RecordDiffDetail("modified.txt", FileDiffResultLists.DiffDetailResult.TextMismatch);
245+
_resultLists.AddRemovedFileAbsolutePath(oldRemoved);
246+
_resultLists.AddAddedFileAbsolutePath(newAdded);
247+
_resultLists.RecordIgnoredFile("ignored.pdb", FileDiffResultLists.IgnoredFileLocation.Old);
248+
249+
var config = CreateConfig();
250+
config.ShouldIncludeIgnoredFiles = true;
251+
_service.GenerateDiffReport(
252+
oldDir,
253+
newDir,
254+
reportDir,
255+
appVersion: "test",
256+
elapsedTimeString: "00:00:01.000",
257+
computerName: "test-host",
258+
config);
259+
260+
var reportPath = Path.Combine(reportDir, "diff_report.md");
261+
var reportText = File.ReadAllText(reportPath);
262+
Assert.Contains("## [ x ] Ignored Files", reportText);
263+
Assert.Contains("## [ = ] Unchanged Files", reportText);
264+
Assert.Contains("## [ + ] Added Files", reportText);
265+
Assert.Contains("## [ - ] Removed Files", reportText);
266+
Assert.Contains("## [ * ] Modified Files", reportText);
267+
Assert.Contains("## Summary", reportText);
268+
}
269+
216270
[Fact]
217271
public void GenerateDiffReport_WritesSummaryWarning_WhenMd5MismatchExists()
218272
{

Program.cs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -303,17 +303,13 @@ static async Task<int> Main(string[] args)
303303
stopwatch.Stop();
304304
// フォルダ差分比較処理時間のコンソール出力
305305
{
306-
TimeSpan? lastRunDuration = stopwatch.Elapsed;
307-
308-
if (lastRunDuration.HasValue)
309-
{
310-
string hourString = $"{(int)Math.Floor(lastRunDuration.Value.TotalHours):00}";
311-
string minuteString = $"{lastRunDuration.Value.Minutes:00}";
312-
string secondString = $"{lastRunDuration.Value.Seconds:00}";
313-
string millisecondString = $"{lastRunDuration.Value.Milliseconds:000}";
314-
_elapsedTimeString = $"{hourString}:{minuteString}:{secondString}.{millisecondString}";
315-
_logger.LogMessage(AppLogLevel.Info, string.Format(Constants.LOG_ELAPSED_TIME, _elapsedTimeString), shouldOutputMessageToConsole: true);
316-
}
306+
TimeSpan lastRunDuration = stopwatch.Elapsed;
307+
string hourString = $"{(int)Math.Floor(lastRunDuration.TotalHours):00}";
308+
string minuteString = $"{lastRunDuration.Minutes:00}";
309+
string secondString = $"{lastRunDuration.Seconds:00}";
310+
string millisecondString = $"{lastRunDuration.Milliseconds:000}";
311+
_elapsedTimeString = $"{hourString}:{minuteString}:{secondString}.{millisecondString}";
312+
_logger.LogMessage(AppLogLevel.Info, string.Format(Constants.LOG_ELAPSED_TIME, _elapsedTimeString), shouldOutputMessageToConsole: true);
317313
}
318314
}
319315
#endregion

README.en.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ Relation to CI:
101101
- Uses `ILoggerService` (`LoggerService` implementation) via DI; the log file path is exposed through the read-only `LogFileAbsolutePath` property.
102102
- `Program` builds dependencies with `ServiceCollection` and resolves `ConfigService` / `FolderDiffService` / `ReportGenerateService` instead of directly constructing them with `new`.
103103
- Writes per-bucket listings to `Reports/<report label>/diff_report.md`; paths are relative for `Unchanged`/`Modified` and absolute for `Added`/`Removed`.
104+
- `ReportGenerateService.GenerateDiffReport` is split into private section writers (header/legend/body/summary) to improve readability and maintenance.
104105
- For `ILMatch` / `ILMismatch`, the report also includes the disassembler tool and version used (including cache hits).
105106
- Summarizes counts per bucket in the same report.
106107
- The report header lists only the disassembler labels actually observed during IL comparison (or `N/A` when not used).
@@ -111,7 +112,7 @@ Relation to CI:
111112

112113
1. **MD5 hash** – if hashes match, the file is `Unchanged (MD5Match)`.
113114
2. **IL diff** – if the file is a .NET assembly (detected via PE/CLR headers, regardless of extension), the app disassembles both versions with the same disassembler/version identity, strips `// MVID:` lines, and compares them line by line. If `ShouldIgnoreILLinesContainingConfiguredStrings` is enabled, lines containing any entry in `ILIgnoreLineContainingStrings` are also ignored (substring match). Matches become `Unchanged (ILMatch)`; mismatches become `Modified (ILMismatch)`.
114-
3. **Text diff** – if the extension appears in `TextFileExtensions`, a line-based text diff runs. Matches are `Unchanged (TextMatch)`; mismatches are `Modified (TextMismatch)`.
115+
3. **Text diff** – if the extension appears in `TextFileExtensions` (checked with `StringComparison.OrdinalIgnoreCase`), a line-based text diff runs. Matches are `Unchanged (TextMatch)`; mismatches are `Modified (TextMismatch)`.
115116
4. **Fallback** – remaining files are treated as `Modified (MD5Mismatch)`.
116117

117118
## Configuration (`config.json`)
@@ -218,7 +219,7 @@ Place `config.json` next to the executable. Example:
218219
| Key | Description |
219220
| --- | --- |
220221
| `IgnoredExtensions` | Excludes matching extensions from comparison (e.g., `.pdb`). |
221-
| `TextFileExtensions` | Treats matching extensions as text, diffed line by line. Include the dot (e.g., `.cs`, `.json`). |
222+
| `TextFileExtensions` | Treats matching extensions as text, diffed line by line. Include the dot (e.g., `.cs`, `.json`). Matching is case-insensitive (`StringComparison.OrdinalIgnoreCase`). |
222223
| `MaxLogGenerations` | Number of log files kept in rotation. |
223224
| `ShouldIncludeUnchangedFiles` | Whether to list `Unchanged` files inside `Reports/<label>/diff_report.md`. |
224225
| `ShouldIncludeIgnoredFiles` | Whether to output ignored files in the `## [ x ] Ignored Files` section (before `Unchanged`). |

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ CI との関係:
107107
- ログ出力は `ILoggerService``LoggerService` 実装)を DI で解決し、ログファイルパスは読み取り専用プロパティ(`LogFileAbsolutePath`)経由で参照
108108
- `Program``ServiceCollection` で依存関係を構成し、`ConfigService` / `FolderDiffService` / `ReportGenerateService` などを直接 `new` せず解決して実行
109109
- 比較結果区分ごとのファイル一覧を`Reports/<コマンドライン第3引数に指定したレポートのラベル>/diff_report.md`に出力(ファイルのパス、最終更新日時[`config.json`のShouldOutputFileTimestampsが `true` の場合]、判定根拠)
110+
- レポート生成は `ReportGenerateService.GenerateDiffReport` からヘッダ/レジェンド/各セクション/サマリーの private メソッドへ分割され、保守性を高めています。
110111
- Unchanged/Modified は相対パスで記載されます。
111112
- Added/Removed は絶対パスで記載されます。
112113
- `ILMatch` / `ILMismatch` には、逆アセンブルに使用したツール名/バージョンを併記します(キャッシュ利用時を含む)。
@@ -131,7 +132,7 @@ CI との関係:
131132
- 逆アセンブルに`dotnet-ildasm`を使用した場合、IL 先頭付近に「// MVID: {GUID}」が出力されることが多い一方、`ilspycmd`を使用した場合は出力されません。
132133
- 一致ならばUnchanged, ILMatch、不一致ならばModified, ILMismatchと判定し次のファイル比較へ
133134

134-
3) テキストベースのファイル(`config.json`のTextFileExtensionsに指定された拡張子か否かで判定)であれば行単位で比較します。
135+
3) テキストベースのファイル(`config.json`のTextFileExtensionsに指定された拡張子か否かを `StringComparison.OrdinalIgnoreCase` で判定)であれば行単位で比較します。
135136
- 一致ならばUnchanged, TextMatch、不一致ならばModified, TextMismatchと判定し次のファイル比較へ
136137

137138
4) Modified, MD5Mismatchと判定し次のファイル比較へ
@@ -240,7 +241,7 @@ CI との関係:
240241
| 項目 | 説明 |
241242
| --- | --- |
242243
| IgnoredExtensions | 指定拡張子は比較対象から除外する(例: `.pdb`)。 |
243-
| TextFileExtensions | 指定拡張子のファイルはテキストとして行単位で比較する。ピリオド(`.`)付きで指定すること(例: `.cs`, `.json`, `.xml`)。 |
244+
| TextFileExtensions | 指定拡張子のファイルはテキストとして行単位で比較する。ピリオド(`.`)付きで指定すること(例: `.cs`, `.json`, `.xml`)。比較は大文字小文字を区別せず(`StringComparison.OrdinalIgnoreCase`)行われる。 |
244245
| MaxLogGenerations | アプリケーションログのローテーション世代数。 |
245246
| ShouldIncludeUnchangedFiles | `Reports/<コマンドライン第3引数に指定したレポートのラベル>/diff_report.md`にUnchangedのファイル一覧を含めるか否か。 |
246247
| ShouldIncludeIgnoredFiles | IgnoredExtensions に該当して比較対象から除外されたファイルを `diff_report.md``## [ x ] Ignored Files` セクション(Unchanged の直前)に出力するか否か。 |

Services/FileDiffService.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@ public async Task<bool> FilesAreEqualAsync(string fileRelativePath, int maxParal
148148
}
149149

150150
// 3) テキスト拡張子ならテキスト比較: ネットワーク最適化時は逐次、それ以外は閾値に応じて並列比較を選択。
151-
if (_config.TextFileExtensions.Contains(Path.GetExtension(file1AbsolutePath).ToLower()))
151+
string fileExtension = Path.GetExtension(file1AbsolutePath);
152+
if (_config.TextFileExtensions.Any(configuredExtension => string.Equals(configuredExtension, fileExtension, StringComparison.OrdinalIgnoreCase)))
152153
{
153154
int textDiffParallelThresholdBytes = GetEffectiveBytesFromConfiguredKilobytes(
154155
configuredKilobytes: _config.TextDiffParallelThresholdKilobytes,

0 commit comments

Comments
 (0)