Skip to content

Commit eb8dd7b

Browse files
committed
Add MoveToFolderBaseRefactoring
Also adds BaseRefactoringTestBase to support testing the base refactorings in separation from the full implementations of IRefactoring.
1 parent 6f9e347 commit eb8dd7b

File tree

5 files changed

+216
-6
lines changed

5 files changed

+216
-6
lines changed

Rubberduck.Parsing/Annotations/Concrete/FolderAnnotation.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
using Rubberduck.VBEditor;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using Rubberduck.Parsing.Grammar;
5-
6-
namespace Rubberduck.Parsing.Annotations
1+
namespace Rubberduck.Parsing.Annotations
72
{
83
/// <summary>
94
/// Used for specifying the Code Explorer folder a appears under.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using Rubberduck.Common;
4+
using Rubberduck.Parsing.Annotations;
5+
using Rubberduck.Parsing.Rewriter;
6+
using Rubberduck.Parsing.VBA;
7+
8+
namespace Rubberduck.Refactorings.MoveToFolder
9+
{
10+
public class MoveToFolderBaseRefactoring : CodeOnlyBaseRefactoringBase<MoveToFolderModel>
11+
{
12+
private readonly IAnnotationUpdater _annotationUpdater;
13+
14+
public MoveToFolderBaseRefactoring(
15+
IRewritingManager rewritingManager,
16+
IAnnotationUpdater annotationUpdater)
17+
: base(rewritingManager)
18+
{
19+
_annotationUpdater = annotationUpdater;
20+
}
21+
22+
public override void Refactor(MoveToFolderModel model, IRewriteSession rewriteSession)
23+
{
24+
var oldFolderAnnotation = model.Target.Annotations.FirstOrDefault(pta => pta.Annotation is FolderAnnotation);
25+
if (oldFolderAnnotation != null)
26+
{
27+
UpdateFolderAnnotation(model, oldFolderAnnotation, rewriteSession);
28+
}
29+
else
30+
{
31+
AddFolderAnnotation(model, rewriteSession);
32+
}
33+
}
34+
35+
private void UpdateFolderAnnotation(MoveToFolderModel model, IParseTreeAnnotation oldPta, IRewriteSession rewriteSession)
36+
{
37+
var oldFolderName = oldPta.AnnotationArguments.FirstOrDefault();
38+
if (oldFolderName == null || oldFolderName.Equals(model.TargetFolder))
39+
{
40+
return;
41+
}
42+
43+
var (annotation, annotationValues) = NewAnnotation(model.TargetFolder);
44+
45+
_annotationUpdater.UpdateAnnotation(rewriteSession, oldPta, annotation, annotationValues);
46+
}
47+
48+
private static (IAnnotation annotation, IReadOnlyList<string> annotationArguments) NewAnnotation(string targetFolder)
49+
{
50+
var annotation = new FolderAnnotation();
51+
var annotationValues = new List<string> { targetFolder.EnQuote() };
52+
53+
return (annotation, annotationValues);
54+
}
55+
56+
private void AddFolderAnnotation(MoveToFolderModel model, IRewriteSession rewriteSession)
57+
{
58+
var (annotation, annotationValues) = NewAnnotation(model.TargetFolder);
59+
60+
_annotationUpdater.AddAnnotation(rewriteSession, model.Target, annotation, annotationValues);
61+
}
62+
}
63+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using Rubberduck.Parsing.Symbols;
2+
3+
namespace Rubberduck.Refactorings.MoveToFolder
4+
{
5+
public class MoveToFolderModel : IRefactoringModel
6+
{
7+
public ModuleDeclaration Target { get; }
8+
public string TargetFolder { get; }
9+
10+
public MoveToFolderModel(ModuleDeclaration target, string targetFolder)
11+
{
12+
Target = target;
13+
TargetFolder = targetFolder;
14+
}
15+
}
16+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Rubberduck.Parsing.Rewriter;
5+
using Rubberduck.Parsing.VBA;
6+
using Rubberduck.Refactorings;
7+
using Rubberduck.VBEditor;
8+
using Rubberduck.VBEditor.SafeComWrappers;
9+
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
10+
using RubberduckTests.Mocks;
11+
12+
namespace RubberduckTests.Refactoring
13+
{
14+
public abstract class BaseRefactoringTestBase<TModel>
15+
where TModel : class, IRefactoringModel
16+
{
17+
18+
protected string RefactoredCode(string code, Func<RubberduckParserState, TModel> modelBuilder)
19+
{
20+
var vbe = TestVbe(code, out _);
21+
var componentName = vbe.SelectedVBComponent.Name;
22+
var refactored = RefactoredCode(vbe, modelBuilder);
23+
return refactored[componentName];
24+
}
25+
26+
protected IDictionary<string, string> RefactoredCode(Func<RubberduckParserState, TModel> modelBuilder, params (string componentName, string content, ComponentType componentType)[] modules)
27+
{
28+
var vbe = TestVbe(modules);
29+
return RefactoredCode(vbe, modelBuilder);
30+
}
31+
32+
protected IDictionary<string, string> RefactoredCode(IVBE vbe, Func<RubberduckParserState, TModel> modelBuilder)
33+
{
34+
var (state, rewritingManager) = MockParser.CreateAndParseWithRewritingManager(vbe);
35+
using (state)
36+
{
37+
var baseRefactoring = TestBaseRefactoring(state, rewritingManager);
38+
var model = modelBuilder(state);
39+
40+
baseRefactoring.Refactor(model);
41+
42+
return vbe.ActiveVBProject.VBComponents
43+
.ToDictionary(component => component.Name, component => component.CodeModule.Content());
44+
}
45+
}
46+
47+
protected abstract IBaseRefactoring<TModel> TestBaseRefactoring(
48+
RubberduckParserState state,
49+
IRewritingManager rewritingManager
50+
);
51+
52+
protected virtual IVBE TestVbe(string content, out IVBComponent component, Selection? selection = null)
53+
{
54+
return MockVbeBuilder.BuildFromSingleStandardModule(content, out component, selection ?? default).Object;
55+
}
56+
57+
protected virtual IVBE TestVbe(params (string componentName, string content, ComponentType componentType)[] modules)
58+
{
59+
return MockVbeBuilder.BuildFromModules(modules).Object;
60+
}
61+
}
62+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
using System;
2+
using System.Linq;
3+
using NUnit.Framework;
4+
using Rubberduck.Parsing.Rewriter;
5+
using Rubberduck.Parsing.Symbols;
6+
using Rubberduck.Parsing.VBA;
7+
using Rubberduck.Refactorings;
8+
using Rubberduck.Refactorings.MoveToFolder;
9+
10+
namespace RubberduckTests.Refactoring
11+
{
12+
[TestFixture]
13+
public class MoveToFolderTests : BaseRefactoringTestBase<MoveToFolderModel>
14+
{
15+
[Test]
16+
[Category("Refactorings")]
17+
public void MoveToFolderBaseRefactoring_NoAnnotation()
18+
{
19+
const string code = @"
20+
Public Sub Foo()
21+
End Sub
22+
";
23+
const string expectedCode = @"'@Folder ""MyNewFolder.MySubFolder""
24+
25+
Public Sub Foo()
26+
End Sub
27+
";
28+
Func<RubberduckParserState, MoveToFolderModel> modelBuilder = (state) =>
29+
{
30+
var module = state.DeclarationFinder
31+
.UserDeclarations(DeclarationType.ProceduralModule)
32+
.Single() as ModuleDeclaration;
33+
return new MoveToFolderModel(module, "MyNewFolder.MySubFolder");
34+
};
35+
36+
var refactoredCode = RefactoredCode(code, modelBuilder);
37+
38+
Assert.AreEqual(expectedCode, refactoredCode);
39+
}
40+
41+
[Test]
42+
[Category("Refactorings")]
43+
public void MoveToFolderBaseRefactoring_UpdateAnnotation()
44+
{
45+
const string code = @"
46+
'@Folder(""MyOldFolder.MyOldSubfolder.SubSub"")
47+
Public Sub Foo()
48+
End Sub
49+
";
50+
const string expectedCode = @"
51+
'@Folder ""MyNewFolder.MySubFolder""
52+
Public Sub Foo()
53+
End Sub
54+
";
55+
Func<RubberduckParserState, MoveToFolderModel> modelBuilder = (state) =>
56+
{
57+
var module = state.DeclarationFinder
58+
.UserDeclarations(DeclarationType.ProceduralModule)
59+
.Single() as ModuleDeclaration;
60+
return new MoveToFolderModel(module, "MyNewFolder.MySubFolder");
61+
};
62+
63+
var refactoredCode = RefactoredCode(code, modelBuilder);
64+
65+
Assert.AreEqual(expectedCode, refactoredCode);
66+
}
67+
68+
protected override IBaseRefactoring<MoveToFolderModel> TestBaseRefactoring(RubberduckParserState state, IRewritingManager rewritingManager)
69+
{
70+
var annotationUpdater = new AnnotationUpdater();
71+
return new MoveToFolderBaseRefactoring(rewritingManager, annotationUpdater);
72+
}
73+
}
74+
}

0 commit comments

Comments
 (0)