Skip to content

Commit 105fce1

Browse files
committed
Implemented generating test stub for each public sub, function or property
1 parent f726824 commit 105fce1

File tree

4 files changed

+231
-19
lines changed

4 files changed

+231
-19
lines changed

RetailCoder.VBE/UI/CodeExplorer/Commands/AddTestModuleWithStubsCommand.cs

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System.Runtime.InteropServices;
2-
using NLog;
1+
using NLog;
32
using Rubberduck.Navigation.CodeExplorer;
43
using Rubberduck.Parsing.Symbols;
54
using Rubberduck.UI.Command;
@@ -19,17 +18,7 @@ public AddTestModuleWithStubsCommand(IVBE vbe, Command.AddTestModuleCommand newU
1918
_newUnitTestModuleCommand = newUnitTestModuleCommand;
2019
}
2120

22-
protected override bool EvaluateCanExecute(object parameter)
23-
{
24-
try
25-
{
26-
return GetDeclaration(parameter) != null || _vbe.VBProjects.Count == 1;
27-
}
28-
catch (COMException)
29-
{
30-
return false;
31-
}
32-
}
21+
protected override bool EvaluateCanExecute(object parameter) => parameter is CodeExplorerComponentViewModel;
3322

3423
protected override void OnExecute(object parameter)
3524
{

RetailCoder.VBE/UI/Command/AddTestModuleCommand.cs

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Collections.Generic;
12
using System.Linq;
23
using System.Runtime.InteropServices;
34
using NLog;
@@ -9,6 +10,7 @@
910
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
1011
using Rubberduck.VBEditor.SafeComWrappers.VBA;
1112
using System.Text;
13+
using Rubberduck.Parsing.Symbols;
1214

1315
namespace Rubberduck.UI.Command
1416
{
@@ -138,7 +140,11 @@ protected override bool EvaluateCanExecute(object parameter)
138140

139141
protected override void OnExecute(object parameter)
140142
{
141-
var project = parameter as IVBProject ?? GetProject();
143+
var parameterIsModuleDeclaration = parameter is ProceduralModuleDeclaration || parameter is ClassModuleDeclaration;
144+
145+
var project = parameter as IVBProject ??
146+
(parameterIsModuleDeclaration ? ((Declaration) parameter).Project : GetProject());
147+
142148
if (project.IsWrappingNullReference)
143149
{
144150
return;
@@ -164,14 +170,47 @@ protected override void OnExecute(object parameter)
164170
var options = string.Concat(hasOptionExplicit ? string.Empty : "Option Explicit\r\n",
165171
"Option Private Module\r\n\r\n");
166172

167-
var defaultTestMethod = string.Empty;
168-
if (settings.DefaultTestStubInNewModule)
173+
if (parameterIsModuleDeclaration)
174+
{
175+
var moduleCodeBuilder = new StringBuilder();
176+
var declarationsToStub = GetDeclarationsToStub((Declaration)parameter);
177+
178+
foreach (var declaration in declarationsToStub)
179+
{
180+
var name = string.Empty;
181+
182+
switch (declaration.DeclarationType)
183+
{
184+
case DeclarationType.Procedure:
185+
case DeclarationType.Function:
186+
name = declaration.IdentifierName;
187+
break;
188+
case DeclarationType.PropertyGet:
189+
name = $"Get{declaration.IdentifierName}";
190+
break;
191+
case DeclarationType.PropertyLet:
192+
name = $"Let{declaration.IdentifierName}";
193+
break;
194+
case DeclarationType.PropertySet:
195+
name = $"Set{declaration.IdentifierName}";
196+
break;
197+
}
198+
199+
var stub = AddTestMethodCommand.TestMethodTemplate.Replace(AddTestMethodCommand.NamePlaceholder, $"{name}_Test");
200+
moduleCodeBuilder.AppendLine(stub);
201+
}
202+
203+
module.AddFromString(options + GetTestModule(settings) + moduleCodeBuilder);
204+
}
205+
else
169206
{
170-
defaultTestMethod = AddTestMethodCommand.TestMethodTemplate.Replace(
171-
AddTestMethodCommand.NamePlaceholder, "TestMethod1");
207+
var defaultTestMethod = settings.DefaultTestStubInNewModule
208+
? AddTestMethodCommand.TestMethodTemplate.Replace(AddTestMethodCommand.NamePlaceholder, "TestMethod1")
209+
: string.Empty;
210+
211+
module.AddFromString(options + GetTestModule(settings) + defaultTestMethod);
172212
}
173213

174-
module.AddFromString(options + GetTestModule(settings) + defaultTestMethod);
175214
component.Activate();
176215
_state.OnParseRequested(this, component);
177216
}
@@ -183,5 +222,13 @@ private string GetNextTestModuleName(IVBProject project)
183222

184223
return string.Concat(TestModuleBaseName, index);
185224
}
225+
226+
private IEnumerable<Declaration> GetDeclarationsToStub(Declaration parentDeclaration)
227+
{
228+
return _state.AllUserDeclarations
229+
.Where(d => Equals(d.ParentDeclaration, parentDeclaration) && d.Accessibility == Accessibility.Public &&
230+
(d.DeclarationType == DeclarationType.Procedure || d.DeclarationType == DeclarationType.Function || d.DeclarationType.HasFlag(DeclarationType.Property)))
231+
.OrderBy(d => d.Context.Start.TokenIndex);
232+
}
186233
}
187234
}

RubberduckTests/CodeExplorer/CodeExplorerTests.cs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,99 @@ public void AddTestModuleWithStubs()
192192
components.Verify(c => c.Add(ComponentType.StandardModule), Times.Once);
193193
}
194194

195+
[TestCategory("Code Explorer")]
196+
[TestMethod]
197+
public void AddTestModuleWithStubs_DisabledWhenParameterIsProject()
198+
{
199+
var builder = new MockVbeBuilder();
200+
var project = builder.ProjectBuilder("TestProject1", ProjectProtection.Unprotected)
201+
.AddComponent("Module1", ComponentType.StandardModule, "");
202+
203+
var vbe = builder.AddProject(project.Build()).Build();
204+
205+
var configLoader = new Mock<ConfigurationLoader>(null, null, null, null, null, null, null);
206+
configLoader.Setup(c => c.LoadConfiguration()).Returns(GetDefaultUnitTestConfig());
207+
208+
var state = new RubberduckParserState(vbe.Object, new DeclarationFinderFactory());
209+
var vbeWrapper = vbe.Object;
210+
var commands = new List<CommandBase>
211+
{
212+
new AddTestModuleWithStubsCommand(vbeWrapper, new Rubberduck.UI.Command.AddTestModuleCommand(vbeWrapper, state, configLoader.Object))
213+
};
214+
215+
var vm = new CodeExplorerViewModel(new FolderHelper(state), state, commands, _generalSettingsProvider.Object, _windowSettingsProvider.Object);
216+
217+
var parser = MockParser.Create(vbe.Object, state);
218+
parser.Parse(new CancellationTokenSource());
219+
if (parser.State.Status >= ParserState.Error) { Assert.Inconclusive("Parser Error"); }
220+
221+
vm.SelectedItem = vm.Projects.First();
222+
223+
Assert.IsFalse(vm.AddTestModuleWithStubsCommand.CanExecute(vm.SelectedItem));
224+
}
225+
226+
[TestCategory("Code Explorer")]
227+
[TestMethod]
228+
public void AddTestModuleWithStubs_DisabledWhenParameterIsFolder()
229+
{
230+
var builder = new MockVbeBuilder();
231+
var project = builder.ProjectBuilder("TestProject1", ProjectProtection.Unprotected)
232+
.AddComponent("Module1", ComponentType.StandardModule, "");
233+
234+
var vbe = builder.AddProject(project.Build()).Build();
235+
236+
var configLoader = new Mock<ConfigurationLoader>(null, null, null, null, null, null, null);
237+
configLoader.Setup(c => c.LoadConfiguration()).Returns(GetDefaultUnitTestConfig());
238+
239+
var state = new RubberduckParserState(vbe.Object, new DeclarationFinderFactory());
240+
var vbeWrapper = vbe.Object;
241+
var commands = new List<CommandBase>
242+
{
243+
new AddTestModuleWithStubsCommand(vbeWrapper, new Rubberduck.UI.Command.AddTestModuleCommand(vbeWrapper, state, configLoader.Object))
244+
};
245+
246+
var vm = new CodeExplorerViewModel(new FolderHelper(state), state, commands, _generalSettingsProvider.Object, _windowSettingsProvider.Object);
247+
248+
var parser = MockParser.Create(vbe.Object, state);
249+
parser.Parse(new CancellationTokenSource());
250+
if (parser.State.Status >= ParserState.Error) { Assert.Inconclusive("Parser Error"); }
251+
252+
vm.SelectedItem = vm.Projects.First().Items.First();
253+
254+
Assert.IsFalse(vm.AddTestModuleWithStubsCommand.CanExecute(vm.SelectedItem));
255+
}
256+
257+
[TestCategory("Code Explorer")]
258+
[TestMethod]
259+
public void AddTestModuleWithStubs_DisabledWhenParameterIsModuleMember()
260+
{
261+
var builder = new MockVbeBuilder();
262+
var project = builder.ProjectBuilder("TestProject1", ProjectProtection.Unprotected)
263+
.AddComponent("Module1", ComponentType.StandardModule, "Public Sub S()\r\nEnd Sub");
264+
265+
var vbe = builder.AddProject(project.Build()).Build();
266+
267+
var configLoader = new Mock<ConfigurationLoader>(null, null, null, null, null, null, null);
268+
configLoader.Setup(c => c.LoadConfiguration()).Returns(GetDefaultUnitTestConfig());
269+
270+
var state = new RubberduckParserState(vbe.Object, new DeclarationFinderFactory());
271+
var vbeWrapper = vbe.Object;
272+
var commands = new List<CommandBase>
273+
{
274+
new AddTestModuleWithStubsCommand(vbeWrapper, new Rubberduck.UI.Command.AddTestModuleCommand(vbeWrapper, state, configLoader.Object))
275+
};
276+
277+
var vm = new CodeExplorerViewModel(new FolderHelper(state), state, commands, _generalSettingsProvider.Object, _windowSettingsProvider.Object);
278+
279+
var parser = MockParser.Create(vbe.Object, state);
280+
parser.Parse(new CancellationTokenSource());
281+
if (parser.State.Status >= ParserState.Error) { Assert.Inconclusive("Parser Error"); }
282+
283+
vm.SelectedItem = vm.Projects.First().Items.First().Items.First().Items.First();
284+
285+
Assert.IsFalse(vm.AddTestModuleWithStubsCommand.CanExecute(vm.SelectedItem));
286+
}
287+
195288
[TestCategory("Code Explorer")]
196289
[TestMethod]
197290
public void ImportModule()

RubberduckTests/Commands/UnitTestCommandTests.cs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,89 @@ public void AddsTestModule()
231231
Assert.IsTrue(module.Annotations.Any(a => a.AnnotationType == AnnotationType.TestModule));
232232
}
233233

234+
[TestCategory("Commands")]
235+
[TestMethod]
236+
public void AddsTestModuleWithStubs()
237+
{
238+
const string code =
239+
@"Public Type UserDefinedType
240+
UserDefinedTypeMember As String
241+
End Type
242+
243+
Public Declare PtrSafe Sub LibraryProcedure Lib ""lib.dll"" ()
244+
245+
Public Declare PtrSafe Function LibraryFunction Lib ""lib.dll"" ()
246+
247+
Public Variable As String
248+
249+
Public Const Constant As String = """"
250+
251+
Public Enum Enumeration
252+
EnumerationMember
253+
End Enum
254+
255+
Public Sub PublicProcedure(Parameter As String)
256+
Dim LocalVariable as String
257+
Const LocalConstant as String = """"
258+
LineLabel:
259+
End Sub
260+
261+
Public Function PublicFunction()
262+
End Function
263+
264+
Public Property Get PublicProperty()
265+
End Property
266+
267+
Public Property Let PublicProperty(v As Variant)
268+
End Property
269+
270+
Public Property Set PublicProperty(s As String)
271+
End Property
272+
273+
Private Sub PrivateProcedure(Parameter As String)
274+
End Sub
275+
276+
Private Function PrivateFunction()
277+
End Function
278+
279+
Private Property Get PrivateProperty()
280+
End Property
281+
282+
Private Property Let PrivateProperty(v As Variant)
283+
End Property
284+
285+
Private Property Set PrivateProperty(s As String)
286+
End Property";
287+
288+
IVBComponent component;
289+
var vbe = MockVbeBuilder.BuildFromSingleStandardModule(code, out component);
290+
var state = MockParser.CreateAndParse(vbe.Object);
291+
292+
var settings = new Mock<ConfigurationLoader>(null, null, null, null, null, null, null);
293+
var config = GetUnitTestConfig();
294+
settings.Setup(x => x.LoadConfiguration()).Returns(config);
295+
296+
var project = state.DeclarationFinder.FindProject("TestProject1");
297+
var module = state.DeclarationFinder.FindStdModule("TestModule1", project);
298+
299+
var addTestModuleCommand = new AddTestModuleCommand(vbe.Object, state, settings.Object);
300+
addTestModuleCommand.Execute(module);
301+
302+
var testModule = state.DeclarationFinder.FindStdModule("TestModule2", project);
303+
304+
var stubIdentifierNames = new[]
305+
{
306+
"PublicProcedure_Test", "PublicFunction_Test", "GetPublicProperty_Test", "LetPublicProperty_Test", "SetPublicProperty_Test"
307+
};
308+
309+
Assert.IsTrue(testModule.Annotations.Any(a => a.AnnotationType == AnnotationType.TestModule));
310+
311+
var stubs = state.DeclarationFinder.AllUserDeclarations.Where(d => d.IdentifierName.EndsWith("_Test")).ToList();
312+
313+
Assert.AreEqual(stubIdentifierNames.Length, stubs.Count);
314+
Assert.IsTrue(stubs.All(d => stubIdentifierNames.Contains(d.IdentifierName)));
315+
}
316+
234317
private Configuration GetUnitTestConfig()
235318
{
236319
var unitTestSettings = new UnitTestSettings

0 commit comments

Comments
 (0)