-
-
Notifications
You must be signed in to change notification settings - Fork 322
Expand file tree
/
Copy pathContentManagerAnalyzerTests.cs
More file actions
153 lines (134 loc) · 6.57 KB
/
Copy pathContentManagerAnalyzerTests.cs
File metadata and controls
153 lines (134 loc) · 6.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using NUnit.Framework;
using SMAPI.ModBuildConfig.Analyzer.Tests.Framework;
using StardewModdingAPI.ModBuildConfig.Analyzer;
namespace SMAPI.ModBuildConfig.Analyzer.Tests
{
/// <summary>Unit tests for <see cref="ContentManagerAnalyzer"/>.</summary>
[TestFixture]
public class ContentManagerAnalyzerTests : DiagnosticVerifier
{
/*********
** Fields
*********/
/// <summary>Sample C# mod code, with a {{test-code}} placeholder for the code in the Entry method to test.</summary>
const string SampleProgram = @"
using System;
using System.Collections.Generic;
using StardewValley;
using Netcode;
using SObject = StardewValley.Object;
namespace SampleMod
{
class ModEntry
{
public void Entry()
{
{{test-code}}
}
}
}
";
const string SampleUnrelatedGoodProgram = @"
using System;
using System.Collections.Generic;
namespace Sample;
class Loader
{
public T Load<T>(string arg)
{
return default(T);
}
}
class ModEntry
{
public void Entry()
{
var loader = new Loader();
var test = loader.Load<Dictionary<int,string>>(""Data\Fish"");
}
}
";
/// <summary>The line number where the unit tested code is injected into <see cref="SampleProgram"/>.</summary>
private const int SampleCodeLine = 14;
/// <summary>The column number where the unit tested code is injected into <see cref="SampleProgram"/>.</summary>
private const int SampleCodeColumn = 25;
/*********
** Unit tests
*********/
/// <summary>Test that no diagnostics are raised for an empty code block.</summary>
[TestCase]
public void EmptyCode_HasNoDiagnostics()
{
// arrange
string test = @"";
// assert
this.VerifyCSharpDiagnostic(test);
}
/// <summary>Test that the expected diagnostic message is raised for avoidable net field references.</summary>
/// <param name="codeText">The code line to test.</param>
/// <param name="column">The column within the code line where the diagnostic message should be reported.</param>
/// <param name="expression">The expression which should be reported.</param>
/// <param name="netType">The net type name which should be reported.</param>
/// <param name="suggestedProperty">The suggested property name which should be reported.</param>
[TestCase("Game1.content.Load<Dictionary<int, string>>(\"Data\\\\Fish\");", 0, "Data\\Fish", "System.Collections.Generic.Dictionary<int, string>", "System.Collections.Generic.Dictionary<string, string>")]
public void BadType_RaisesDiagnostic(string codeText, int column, string assetName, string expectedType, string suggestedType)
{
// arrange
string code = SampleProgram.Replace("{{test-code}}", codeText);
DiagnosticResult expected = new()
{
Id = "AvoidContentManagerBadType",
Message = $"'{assetName}' uses the {suggestedType} type, but {expectedType} is in use instead. See https://smapi.io/package/avoid-contentmanager-type for details.",
Severity = DiagnosticSeverity.Error,
Locations = [new DiagnosticResultLocation("Test0.cs", SampleCodeLine, SampleCodeColumn + column)]
};
DiagnosticResult preferDataLoader = new()
{
Id = "PreferContentManagerDataLoader",
Message = $"'{assetName}' can be accessed using 'DataLoader.{assetName[5..]}(LocalizedContentManager content)' instead. See https://smapi.io/package/prefer-contentmanager-dataloader for details.",
Severity = DiagnosticSeverity.Info,
Locations = [new DiagnosticResultLocation("Test0.cs", SampleCodeLine, SampleCodeColumn + column)]
};
// assert
this.VerifyCSharpDiagnostic(code, expected, preferDataLoader);
}
/// <summary>Test that the expected diagnostic message is raised for avoidable net field references.</summary>
/// <param name="codeText">The code line to test.</param>
/// <param name="column">The column within the code line where the diagnostic message should be reported.</param>
/// <param name="expression">The expression which should be reported.</param>
/// <param name="netType">The net type name which should be reported.</param>
/// <param name="suggestedProperty">The suggested property name which should be reported.</param>
[TestCase("Game1.content.Load<Dictionary<string, string>>(\"Data\\\\Fish\");", 0, "Data\\Fish")]
public void PreferDataLoader_RaisesDiagnostic(string codeText, int column, string assetName)
{
// arrange
string code = SampleProgram.Replace("{{test-code}}", codeText);
DiagnosticResult preferDataLoader = new()
{
Id = "PreferContentManagerDataLoader",
Message = $"'{assetName}' can be accessed using 'DataLoader.{assetName[5..]}(LocalizedContentManager content)' instead. See https://smapi.io/package/prefer-contentmanager-dataloader for details.",
Severity = DiagnosticSeverity.Info,
Locations = [new DiagnosticResultLocation("Test0.cs", SampleCodeLine, SampleCodeColumn + column)]
};
// assert
this.VerifyCSharpDiagnostic(code, preferDataLoader);
}
[TestCase("Game1.content.Load<Dictionary<string, string>>(\"Data\\\\Custom_Asset\");", true)]
[TestCase(SampleUnrelatedGoodProgram, false)]
public void ValidCode_HasNoDiagnostics(string codeText, bool useWrapper)
{
string code = useWrapper ? SampleProgram.Replace("{{test-code}}", codeText) : codeText;
this.VerifyCSharpDiagnostic(code);
}
/*********
** Helpers
*********/
/// <summary>Get the analyzer being tested.</summary>
protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer()
{
return new ContentManagerAnalyzer();
}
}
}