Skip to content

Commit ea41805

Browse files
committed
Migrate creator IL defaults to normalization
1 parent c6d3357 commit ea41805

17 files changed

Lines changed: 166 additions & 81 deletions

CHANGELOG.md

Lines changed: 8 additions & 8 deletions
Large diffs are not rendered by default.

FolderDiffIL4DotNet.Tests/Models/ConfigSettingsTests.InlineDiffAndMutation.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,10 @@ public void Readme_ValidatedConstraints_StayInSyncWithCurrentConfigValidationRul
176176
Assert.Contains("`--print-config` は、環境変数と対応 CLI オーバーライドを適用した builder 状態を、セマンティック検証なしでそのまま出力するため、範囲外を含む effective config の診断にも使えます。", userGuide, StringComparison.Ordinal);
177177
Assert.Contains("[`InlineDiffContextLines`](#config-en-inlinediffcontextlines) >= `0`", userGuide, StringComparison.Ordinal);
178178
Assert.Contains("[`ILCacheMaxMemoryMegabytes`](#config-en-ilcachemaxmemorymegabytes) >= `0`", userGuide, StringComparison.Ordinal);
179-
Assert.Contains("[`ILNormalizeContainingStrings`](#config-en-ilnormalizecontainingstrings) must contain at most `256` configured entries of at most `4096` characters each", userGuide, StringComparison.Ordinal);
179+
Assert.Contains("[`ILNormalizeContainingStrings`](#config-en-ilnormalizecontainingstrings) must contain at most `256` combined configured/profile entries of at most `4096` characters each", userGuide, StringComparison.Ordinal);
180180
Assert.Contains("[`InlineDiffContextLines`](#config-ja-inlinediffcontextlines) >= `0`", userGuide, StringComparison.Ordinal);
181181
Assert.Contains("[`ILCacheMaxMemoryMegabytes`](#config-ja-ilcachemaxmemorymegabytes) >= `0`", userGuide, StringComparison.Ordinal);
182-
Assert.Contains("[`ILNormalizeContainingStrings`](#config-ja-ilnormalizecontainingstrings) は設定値が最大 `256` 件かつ各値が最大 `4096` 文字", userGuide, StringComparison.Ordinal);
182+
Assert.Contains("[`ILNormalizeContainingStrings`](#config-ja-ilnormalizecontainingstrings) は設定値とプロファイル値の結合後が最大 `256` 件かつ各値が最大 `4096` 文字", userGuide, StringComparison.Ordinal);
183183
}
184184

185185
[Fact]

FolderDiffIL4DotNet.Tests/ProgramRunnerTests.CliOverrides.cs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,7 @@ await WithConfigFileAsync("{}", async () =>
716716
}
717717

718718
[Fact]
719-
public async Task RunAsync_PrintConfigFlag_WithCreatorIlIgnoreProfile_OutputsMergedIlFilters()
719+
public async Task RunAsync_PrintConfigFlag_WithCreatorIlIgnoreProfile_OutputsMergedIlNormalizations()
720720
{
721721
var logger = new TestLogger(logFileAbsolutePath: "test.log");
722722
var runner = new ProgramRunner(logger, new ConfigService());
@@ -727,7 +727,8 @@ public async Task RunAsync_PrintConfigFlag_WithCreatorIlIgnoreProfile_OutputsMer
727727
const string configJson = """
728728
{
729729
"ShouldIgnoreILLinesContainingConfiguredStrings": false,
730-
"ILIgnoreLineContainingStrings": ["existing-filter"]
730+
"ILIgnoreLineContainingStrings": ["existing-filter"],
731+
"ILNormalizeContainingStrings": ["existing-normalization"]
731732
}
732733
""";
733734

@@ -739,12 +740,14 @@ await WithConfigFileAsync(configJson, async () =>
739740

740741
Assert.Equal(0, exitCode);
741742
var output = sw.ToString();
742-
Assert.Contains("\"ShouldIgnoreILLinesContainingConfiguredStrings\": true", output, StringComparison.Ordinal);
743+
Assert.Contains("\"ShouldIgnoreILLinesContainingConfiguredStrings\": false", output, StringComparison.Ordinal);
744+
Assert.Contains("\"ShouldILNormalizeContainingConfiguredStrings\": true", output, StringComparison.Ordinal);
743745
Assert.Contains("existing-filter", output, StringComparison.Ordinal);
746+
Assert.Contains("existing-normalization", output, StringComparison.Ordinal);
744747
Assert.Contains("buildserver1_", output, StringComparison.Ordinal);
745-
Assert.DoesNotContain("// Method begins at Relative Virtual Address (RVA) 0x", output, StringComparison.Ordinal);
746-
Assert.DoesNotContain(".publickeytoken = ( ", output, StringComparison.Ordinal);
747-
Assert.DoesNotContain("TypeLibraryTimeStampAttribute", output, StringComparison.Ordinal);
748+
Assert.True(
749+
output.IndexOf("buildserver1_", StringComparison.Ordinal)
750+
< output.IndexOf("existing-normalization", StringComparison.Ordinal));
748751
Assert.DoesNotContain("// Code size ", output, StringComparison.Ordinal);
749752
Assert.Contains(@"A:\\temp\\develop\\", output, StringComparison.Ordinal);
750753
Assert.Contains(@"Z:\\temp\\develop\\", output, StringComparison.Ordinal);
@@ -773,7 +776,8 @@ await WithConfigFileAsync("{}", async () =>
773776

774777
Assert.Equal(0, exitCode);
775778
var output = sw.ToString();
776-
Assert.Contains("\"ShouldIgnoreILLinesContainingConfiguredStrings\": true", output, StringComparison.Ordinal);
779+
Assert.Contains("\"ShouldIgnoreILLinesContainingConfiguredStrings\": false", output, StringComparison.Ordinal);
780+
Assert.Contains("\"ShouldILNormalizeContainingConfiguredStrings\": true", output, StringComparison.Ordinal);
777781
Assert.Contains("buildserver1_", output, StringComparison.Ordinal);
778782
Assert.Contains(@"A:\\temp\\develop\\", output, StringComparison.Ordinal);
779783
Assert.Contains(@"Z:\\temp\\develop\\", output, StringComparison.Ordinal);

FolderDiffIL4DotNet.Tests/Runner/CliOverrideApplierTests.cs

Lines changed: 94 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
14
using FolderDiffIL4DotNet.Models;
25
using FolderDiffIL4DotNet.Runner;
6+
using FolderDiffIL4DotNet.Services;
37
using Xunit;
48

59
namespace FolderDiffIL4DotNet.Tests.Runner
@@ -99,22 +103,24 @@ public void Apply_DefaultOptions_DoesNotModifyBuilder()
99103
}
100104

101105
[Fact]
102-
public void Apply_CreatorIlIgnoreProfile_EnablesFilteringAndMergesStrings()
106+
public void Apply_CreatorIlIgnoreProfile_PrependsProfileBeforeConfiguredNormalizationStrings()
103107
{
104108
var builder = new ConfigSettingsBuilder
105109
{
106110
ShouldIgnoreILLinesContainingConfiguredStrings = false,
107-
ILIgnoreLineContainingStrings = new System.Collections.Generic.List<string> { "existing-filter" }
111+
ILIgnoreLineContainingStrings = new List<string> { "existing-filter" },
112+
ILNormalizeContainingStrings = new List<string> { "existing-normalization" }
108113
};
109114
var opts = DefaultOpts() with { CreatorIlIgnoreProfile = "creator-default" };
110115

111116
CliOverrideApplier.Apply(builder, opts);
112117

113-
Assert.True(builder.ShouldIgnoreILLinesContainingConfiguredStrings);
118+
Assert.False(builder.ShouldIgnoreILLinesContainingConfiguredStrings);
119+
Assert.True(builder.ShouldILNormalizeContainingConfiguredStrings);
120+
Assert.Contains("existing-filter", builder.ILIgnoreLineContainingStrings);
114121
Assert.Equal(
115122
new[]
116123
{
117-
"existing-filter",
118124
"buildserver1_",
119125
"buildserver2_",
120126
@"A:\temp\develop\",
@@ -142,13 +148,47 @@ public void Apply_CreatorIlIgnoreProfile_EnablesFilteringAndMergesStrings()
142148
@"W:\temp\develop\",
143149
@"X:\temp\develop\",
144150
@"Y:\temp\develop\",
145-
@"Z:\temp\develop\"
151+
@"Z:\temp\develop\",
152+
"existing-normalization"
146153
},
147-
builder.ILIgnoreLineContainingStrings);
148-
Assert.DoesNotContain("// Method begins at Relative Virtual Address (RVA) 0x", builder.ILIgnoreLineContainingStrings);
154+
builder.ILNormalizeContainingStrings);
155+
Assert.DoesNotContain("// Method begins at Relative Virtual Address (RVA) 0x", builder.ILNormalizeContainingStrings);
156+
Assert.DoesNotContain("// Code size ", builder.ILNormalizeContainingStrings);
157+
Assert.DoesNotContain("TypeLibraryTimeStampAttribute", builder.ILNormalizeContainingStrings);
149158
Assert.DoesNotContain(".publickeytoken = ( ", builder.ILIgnoreLineContainingStrings);
150-
Assert.DoesNotContain(".custom instance void class [System.Windows.Forms]System.Windows.Forms.AxHost/TypeLibraryTimeStampAttribute::.ctor(string) = ( ", builder.ILIgnoreLineContainingStrings);
151-
Assert.DoesNotContain("// Code size ", builder.ILIgnoreLineContainingStrings);
159+
}
160+
161+
[Fact]
162+
public void Apply_CreatorFlag_DoesNotSuppressPublicKeyTokenDifferences()
163+
{
164+
var builder = new ConfigSettingsBuilder();
165+
var opts = DefaultOpts() with { Creator = true };
166+
167+
CliOverrideApplier.Apply(builder, opts);
168+
169+
var oldLines = new[]
170+
{
171+
".assembly extern Vendor.Library",
172+
"{",
173+
" .publickeytoken = ( 12 34 56 78 90 AB CD EF )",
174+
"}"
175+
};
176+
var newLines = new[]
177+
{
178+
".assembly extern Vendor.Library",
179+
"{",
180+
" .publickeytoken = ( FE DC BA 09 87 65 43 21 )",
181+
"}"
182+
};
183+
184+
var areEqual = ILOutputService.StreamingFilteredSequenceEqual(
185+
oldLines,
186+
newLines,
187+
builder.ShouldIgnoreILLinesContainingConfiguredStrings,
188+
builder.ILIgnoreLineContainingStrings,
189+
builder.ILNormalizeContainingStrings);
190+
191+
Assert.False(areEqual);
152192
}
153193

154194
[Fact]
@@ -159,11 +199,51 @@ public void Apply_CreatorFlag_UsesDefaultProfile()
159199

160200
CliOverrideApplier.Apply(builder, opts);
161201

162-
Assert.True(builder.ShouldIgnoreILLinesContainingConfiguredStrings);
163-
Assert.Contains("buildserver1_", builder.ILIgnoreLineContainingStrings);
164-
Assert.Contains(@"A:\temp\develop\", builder.ILIgnoreLineContainingStrings);
165-
Assert.Contains(@"Z:\temp\develop\", builder.ILIgnoreLineContainingStrings);
166-
Assert.Equal(28, builder.ILIgnoreLineContainingStrings.Count);
202+
Assert.True(builder.ShouldILNormalizeContainingConfiguredStrings);
203+
Assert.Contains("buildserver1_", builder.ILNormalizeContainingStrings);
204+
Assert.Contains(@"A:\temp\develop\", builder.ILNormalizeContainingStrings);
205+
Assert.Contains(@"Z:\temp\develop\", builder.ILNormalizeContainingStrings);
206+
Assert.Equal(28, builder.ILNormalizeContainingStrings.Count);
207+
}
208+
209+
[Fact]
210+
public void Apply_CreatorFlag_PreservesDuplicateForValidationBeforeEffectiveDeduplication()
211+
{
212+
var builder = new ConfigSettingsBuilder
213+
{
214+
ILNormalizeContainingStrings = new List<string> { "buildserver1_" }
215+
};
216+
217+
CliOverrideApplier.Apply(builder, DefaultOpts() with { Creator = true });
218+
219+
Assert.Equal(2, builder.ILNormalizeContainingStrings.Count(value => value == "buildserver1_"));
220+
Assert.Contains(
221+
ILOutputService.ValidateILNormalizeContainingStrings(builder.ILNormalizeContainingStrings),
222+
warning => warning.Contains("configured more than once", StringComparison.Ordinal));
223+
}
224+
225+
[Fact]
226+
public void Apply_CreatorFlag_ProfileValuesCountTowardRuntimeNormalizationLimit()
227+
{
228+
var builder = new ConfigSettingsBuilder
229+
{
230+
ILNormalizeContainingStrings = Enumerable.Range(
231+
0,
232+
ConfigSettings.MaxILNormalizeContainingStringsCount)
233+
.Select(index => $"normalization-{index}")
234+
.ToList()
235+
};
236+
237+
CliOverrideApplier.Apply(builder, DefaultOpts() with { Creator = true });
238+
239+
ConfigValidationResult validation = builder.Validate();
240+
Assert.False(validation.IsValid);
241+
Assert.Contains(
242+
validation.Errors,
243+
error => error.Contains("Creator-profile values", StringComparison.Ordinal)
244+
&& error.Contains(
245+
$"at most {ConfigSettings.MaxILNormalizeContainingStringsCount} values",
246+
StringComparison.Ordinal));
167247
}
168248

169249
[Fact]

Models/ConfigSettings.ILSettings.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ public sealed partial class ConfigSettings
1717
/// <summary>Default value for <see cref="SkipIL"/>. / <see cref="SkipIL"/> の既定値。</summary>
1818
public const bool DefaultSkipIL = false;
1919
/// <summary>
20-
/// Maximum number of <see cref="ILNormalizeContainingStrings"/> entries.
21-
/// <see cref="ILNormalizeContainingStrings"/> の最大件数。
20+
/// Maximum number of <see cref="ILNormalizeContainingStrings"/> entries after creator-profile values are prepended.
21+
/// creator プロファイル値を先頭へ追加した後の <see cref="ILNormalizeContainingStrings"/> の最大件数。
2222
/// </summary>
2323
public const int MaxILNormalizeContainingStringsCount = 256;
2424
/// <summary>
@@ -75,10 +75,10 @@ public sealed partial class ConfigSettings
7575

7676
/// <summary>
7777
/// List of strings whose exact matching portions are normalized during IL comparison; surrounding whitespace is significant.
78-
/// At most <see cref="MaxILNormalizeContainingStringsCount"/> configured entries are allowed, each no longer than
78+
/// At most <see cref="MaxILNormalizeContainingStringsCount"/> combined configured/profile entries are allowed, each no longer than
7979
/// <see cref="MaxILNormalizeContainingStringLength"/> Unicode characters.
8080
/// IL 比較時に正確な一致部分を正規化する文字列リスト。前後空白も一致条件に含みます。
81-
/// 設定値は最大 <see cref="MaxILNormalizeContainingStringsCount"/> 件で、各値は
81+
/// 設定値とプロファイル値の結合後は最大 <see cref="MaxILNormalizeContainingStringsCount"/> 件で、各値は
8282
/// <see cref="MaxILNormalizeContainingStringLength"/> Unicode 文字以下です。
8383
/// </summary>
8484
public IReadOnlyList<string> ILNormalizeContainingStrings { get; }
@@ -92,7 +92,7 @@ public sealed partial class ConfigSettings
9292

9393
if (configuredStrings.Count > MaxILNormalizeContainingStringsCount)
9494
{
95-
return $"{nameof(ILNormalizeContainingStrings)} must contain at most {MaxILNormalizeContainingStringsCount} values (current count: {configuredStrings.Count}).";
95+
return $"{nameof(ILNormalizeContainingStrings)} must contain at most {MaxILNormalizeContainingStringsCount} values (current count: {configuredStrings.Count}). Creator-profile values prepended before configured values count toward this limit.";
9696
}
9797

9898
for (int index = 0; index < configuredStrings.Count; index++)

Models/IReadOnlyConfigSettings.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,10 @@ public interface IReadOnlyConfigSettings
8787

8888
/// <summary>
8989
/// List of strings whose exact matching portions are normalized during IL comparison; surrounding whitespace is significant.
90-
/// At most <see cref="ConfigSettings.MaxILNormalizeContainingStringsCount"/> configured entries of up to
90+
/// At most <see cref="ConfigSettings.MaxILNormalizeContainingStringsCount"/> combined configured/profile entries of up to
9191
/// <see cref="ConfigSettings.MaxILNormalizeContainingStringLength"/> Unicode characters each are allowed.
9292
/// IL 比較時に正確な一致部分を正規化する文字列リスト。前後空白も一致条件に含みます。
93-
/// 設定値は最大 <see cref="ConfigSettings.MaxILNormalizeContainingStringsCount"/> 件、
93+
/// 設定値とプロファイル値の結合後は最大 <see cref="ConfigSettings.MaxILNormalizeContainingStringsCount"/> 件、
9494
/// 各値は最大 <see cref="ConfigSettings.MaxILNormalizeContainingStringLength"/> Unicode 文字です。
9595
/// </summary>
9696
IReadOnlyList<string> ILNormalizeContainingStrings { get; }

PACKAGE_README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ nildiff "/old" "/new" "label" --config /path/to/config.json
5454

5555
When the report label is omitted, nildiff auto-generates a high-resolution timestamp label. Tokens beginning with `--` are treated as options, not report labels.
5656

57-
Individual settings can also be overridden via `FOLDERDIFF_*` environment variables (e.g. `FOLDERDIFF_MAXPARALLELISM=8`). For maintainer-only IL noise suppression, `--creator` applies the predefined `creator-default` `ILIgnoreLineContainingStrings` profile. See the [annotated sample config](https://github.com/Widthdom/FolderDiffIL4DotNet/blob/main/doc/config.sample.jsonc) for all available settings.
57+
Individual settings can also be overridden via `FOLDERDIFF_*` environment variables (e.g. `FOLDERDIFF_MAXPARALLELISM=8`). For maintainer-only IL noise normalization, `--creator` enables `ShouldILNormalizeContainingConfiguredStrings` and merges the predefined `creator-default` values into `ILNormalizeContainingStrings`. See the [annotated sample config](https://github.com/Widthdom/FolderDiffIL4DotNet/blob/main/doc/config.sample.jsonc) for all available settings.
5858

5959
The default user-local `config.json` location varies by OS:
6060

Runner/CliOverrideApplier.cs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,17 @@ internal static void Apply(ConfigSettingsBuilder builder, CliOptions opts)
4545

4646
if (creatorProfile != null)
4747
{
48-
builder.ShouldIgnoreILLinesContainingConfiguredStrings = true;
49-
var mergedStrings = new List<string>(builder.ILIgnoreLineContainingStrings);
50-
var seen = new HashSet<string>(mergedStrings, System.StringComparer.Ordinal);
51-
foreach (var value in CreatorPrivilegeIlIgnoreProfiles.GetStringsOrThrow(creatorProfile))
52-
{
53-
if (seen.Add(value))
54-
{
55-
mergedStrings.Add(value);
56-
}
57-
}
48+
builder.ShouldILNormalizeContainingConfiguredStrings = true;
49+
var configuredStrings = builder.ILNormalizeContainingStrings;
50+
var orderedStrings = new List<string>(
51+
CreatorPrivilegeIlIgnoreProfiles.GetStringsOrThrow(creatorProfile));
5852

59-
builder.ILIgnoreLineContainingStrings = mergedStrings;
53+
// Creator defaults form the normalization baseline. Keep configured values after
54+
// them, preserving duplicates so validation can report cross-source relationships.
55+
// creator 既定値を正規化の基盤として先に置き、設定値をその後へ追加します。
56+
// 重複は保持し、双方にまたがる重複・包含関係を検証できるようにします。
57+
orderedStrings.AddRange(configuredStrings);
58+
builder.ILNormalizeContainingStrings = orderedStrings;
6059
}
6160

6261
SpinnerThemes.Apply(builder, opts);

Runner/CreatorPrivilegeIlIgnoreProfiles.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
namespace FolderDiffIL4DotNet.Runner
88
{
99
/// <summary>
10-
/// Loads maintainer-managed IL ignore profiles from an embedded JSON catalog.
11-
/// メンテナー管理の IL 無視プロファイルを埋め込み JSON カタログから読み込みます。
10+
/// Loads maintainer-managed IL normalization profiles from an embedded JSON catalog.
11+
/// メンテナー管理の IL 正規化プロファイルを埋め込み JSON カタログから読み込みます。
1212
/// </summary>
1313
internal static class CreatorPrivilegeIlIgnoreProfiles
1414
{
@@ -27,8 +27,8 @@ internal static bool IsKnownProfile(string? profileName)
2727
}
2828

2929
/// <summary>
30-
/// Resolves a known profile to its IL ignore strings.
31-
/// 既知プロファイルを IL 無視文字列一覧へ解決します
30+
/// Resolves a known profile to its IL normalization strings.
31+
/// 既知プロファイルを IL 正規化文字列一覧へ解決します
3232
/// </summary>
3333
internal static IReadOnlyList<string> GetStringsOrThrow(string profileName)
3434
{

0 commit comments

Comments
 (0)