Skip to content

Commit 917861f

Browse files
committed
Handle array redim external to declaring module
Separated Array related tests into dedicated test class/file. Some enum tests consolidation.
1 parent 091b637 commit 917861f

File tree

8 files changed

+267
-189
lines changed

8 files changed

+267
-189
lines changed

Rubberduck.Refactorings/EncapsulateField/EncapsulateFIeldResources.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,7 @@ public static string PrivateUDTPropertyText
4848
public static string Parameter => "Parameter";
4949

5050
public static string NameConflictDetected => "Name Conflict Detected";
51+
52+
public static string ArrayHasExternalRedimFormat => "Storage space for {0} is reallocated external to module '{1}'";
5153
}
5254
}

Rubberduck.Refactorings/EncapsulateField/FieldCandidates/ArrayCandidate.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ namespace Rubberduck.Refactorings.EncapsulateField
88
{
99
public interface IArrayCandidate : IEncapsulateFieldCandidate
1010
{
11-
1211
}
1312

1413
public class ArrayCandidate : EncapsulateFieldCandidate, IArrayCandidate
@@ -31,14 +30,25 @@ public ArrayCandidate(Declaration declaration, IValidateEncapsulateFieldNames va
3130
}
3231
}
3332

33+
private bool HasExternalRedimOperation
34+
=> Declaration.References.Any(rf => rf.QualifiedModuleName != QualifiedModuleName
35+
&& rf.Context.TryGetAncestor<VBAParser.RedimVariableDeclarationContext>(out _));
36+
37+
3438
public override string AsUDTMemberDeclaration
3539
=> $"{PropertyName}({_subscripts}) {Tokens.As} {AsTypeName_Field}";
3640

37-
public override bool TryValidateEncapsulationAttributes(out string errorMessage) //, bool isArray = false)
41+
public override bool TryValidateEncapsulationAttributes(out string errorMessage)
3842
{
3943
errorMessage = string.Empty;
4044
if (!EncapsulateFlag) { return true; }
4145

46+
if (HasExternalRedimOperation)
47+
{
48+
errorMessage = string.Format(EncapsulateFieldResources.ArrayHasExternalRedimFormat, Declaration.IdentifierName, Declaration.QualifiedModuleName.ComponentName);
49+
return false;
50+
}
51+
4252
if (ConvertFieldToUDTMember)
4353
{
4454
return TryValidateAsUDTMemberEncapsulationAttributes(out errorMessage, true);
@@ -60,6 +70,17 @@ public override void LoadFieldReferenceContextReplacements()
6070
{
6171
foreach (var idRef in Declaration.References)
6272
{
73+
//Locally, we do all operations using the backing field
74+
if (idRef.QualifiedModuleName == QualifiedModuleName)
75+
{
76+
var accessor = ConvertFieldToUDTMember
77+
? ReferenceForPreExistingReferences
78+
: FieldIdentifier;
79+
80+
SetReferenceRewriteContent(idRef, accessor);
81+
continue;
82+
}
83+
6384
var replacementText = RequiresAccessQualification(idRef)
6485
? $"{QualifiedModuleName.ComponentName}.{ReferenceForPreExistingReferences}"
6586
: ReferenceForPreExistingReferences;
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
using NUnit.Framework;
2+
using Rubberduck.Parsing.Rewriter;
3+
using Rubberduck.Parsing.Symbols;
4+
using Rubberduck.Parsing.VBA;
5+
using Rubberduck.Refactorings;
6+
using Rubberduck.Refactorings.EncapsulateField;
7+
using Rubberduck.VBEditor;
8+
using Rubberduck.VBEditor.Utility;
9+
using RubberduckTests.Mocks;
10+
using System;
11+
using System.Collections.Generic;
12+
using System.Linq;
13+
using System.Text;
14+
using System.Threading.Tasks;
15+
16+
namespace RubberduckTests.Refactoring.EncapsulateField
17+
{
18+
[TestFixture]
19+
public class EncapsulateArrayFieldTests : InteractiveRefactoringTestBase<IEncapsulateFieldPresenter, EncapsulateFieldModel>
20+
{
21+
private EncapsulateFieldTestSupport Support { get; } = new EncapsulateFieldTestSupport();
22+
23+
[TestCase("Private", "mArray(5) As String", "mArray(5) As String")]
24+
[TestCase("Public", "mArray(5) As String", "mArray(5) As String")]
25+
[TestCase("Private", "mArray(5,2,3) As String", "mArray(5,2,3) As String")]
26+
[TestCase("Public", "mArray(5,2,3) As String", "mArray(5,2,3) As String")]
27+
[TestCase("Private", "mArray(1 to 10) As String", "mArray(1 to 10) As String")]
28+
[TestCase("Public", "mArray(1 to 10) As String", "mArray(1 to 10) As String")]
29+
[TestCase("Private", "mArray() As String", "mArray() As String")]
30+
[TestCase("Public", "mArray() As String", "mArray() As String")]
31+
[TestCase("Private", "mArray(5)", "mArray(5) As Variant")]
32+
[TestCase("Public", "mArray(5)", "mArray(5) As Variant")]
33+
[Category("Refactorings")]
34+
[Category("Encapsulate Field")]
35+
public void EncapsulateArray(string visibility, string arrayDeclaration, string expectedArrayDeclaration)
36+
{
37+
string inputCode =
38+
$@"Option Explicit
39+
40+
{visibility} {arrayDeclaration}";
41+
42+
var selection = new Selection(3, 8, 3, 11);
43+
44+
string expectedCode =
45+
$@"Option Explicit
46+
47+
Private {expectedArrayDeclaration}
48+
49+
Public Property Get MyArray() As Variant
50+
MyArray = mArray
51+
End Property
52+
";
53+
var userInput = new UserInputDataObject()
54+
.UserSelectsField("mArray", "MyArray");
55+
56+
var presenterAction = Support.SetParameters(userInput);
57+
var actualCode = RefactoredCode(inputCode, selection, presenterAction);
58+
Assert.AreEqual(expectedCode.Trim(), actualCode);
59+
}
60+
61+
[TestCase("5")]
62+
[TestCase("5,2,3")]
63+
[TestCase("1 to 100")]
64+
[Category("Refactorings")]
65+
[Category("Encapsulate Field")]
66+
public void EncapsulateArray_DeclaredInList(string dimensions)
67+
{
68+
string inputCode =
69+
$@"Option Explicit
70+
71+
Public mArray({dimensions}) As String, anotherVar As Long, andOneMore As Variant";
72+
73+
var selection = new Selection(3, 8, 3, 11);
74+
75+
string expectedCode =
76+
$@"Option Explicit
77+
78+
Public anotherVar As Long, andOneMore As Variant
79+
Private mArray({dimensions}) As String
80+
81+
Public Property Get MyArray() As Variant
82+
MyArray = mArray
83+
End Property
84+
";
85+
var presenterAction = Support.SetParametersForSingleTarget("mArray", "MyArray");
86+
var actualCode = RefactoredCode(inputCode, selection, presenterAction);
87+
StringAssert.Contains("Public anotherVar As Long, andOneMore As Variant", actualCode);
88+
StringAssert.Contains($"Private mArray({dimensions}) As String", actualCode);
89+
StringAssert.Contains("Get MyArray() As Variant", actualCode);
90+
StringAssert.Contains("MyArray = mArray", actualCode);
91+
StringAssert.DoesNotContain("Let MyArray", actualCode);
92+
StringAssert.DoesNotContain("Set MyArray", actualCode);
93+
}
94+
95+
[TestCase("mArr|ay(5) As String, mNextVar As Long", "Private mArray(5) As String")]
96+
[TestCase("mNextVar As Long, mArr|ay(5) As String", "Private mArray(5) As String")]
97+
[TestCase("mArr|ay(5), mNextVar As Long", "Private mArray(5) As Variant")]
98+
[TestCase("mNextVar As Long, mAr|ray(5)", "Private mArray(5) As Variant")]
99+
[Category("Refactorings")]
100+
[Category("Encapsulate Field")]
101+
public void EncapsulateArray_newFieldNameForFieldInList(string declarationList, string expectedDeclaration)
102+
{
103+
string inputCode =
104+
$@"Option Explicit
105+
106+
Public {declarationList}";
107+
108+
string expectedCode =
109+
$@"Option Explicit
110+
111+
Public mNextVar As Long
112+
113+
{expectedDeclaration}
114+
115+
Public Property Get MyArray() As Variant
116+
MyArray = mArray
117+
End Property
118+
";
119+
var presenterAction = Support.SetParametersForSingleTarget("mArray", "MyArray");
120+
var actualCode = Support.RefactoredCode(inputCode.ToCodeString(), presenterAction);
121+
Assert.AreEqual(expectedCode.Trim(), actualCode);
122+
}
123+
124+
[Test]
125+
[Category("Refactorings")]
126+
[Category("Encapsulate Field")]
127+
public void RedimsBackingVariable()
128+
{
129+
string inputCode =
130+
$@"Option Explicit
131+
132+
Public myA|rray() As Integer
133+
134+
Private Sub InitializeArray(size As Long)
135+
Redim myArray(size)
136+
Dim idx As Long
137+
For idx = 1 To size
138+
myArray(idx) = idx
139+
Next idx
140+
End Sub
141+
";
142+
143+
var presenterAction = Support.UserAcceptsDefaults();
144+
var actualCode = Support.RefactoredCode(inputCode.ToCodeString(), presenterAction);
145+
StringAssert.Contains("Public Property Get MyArray() As Variant", actualCode);
146+
StringAssert.DoesNotContain("Public Property Let MyArray(", actualCode);
147+
StringAssert.Contains("Redim myArray_1(size)", actualCode);
148+
StringAssert.Contains("myArray_1(idx) = idx", actualCode);
149+
}
150+
151+
152+
[Test]
153+
[Category("Refactorings")]
154+
[Category("Encapsulate Field")]
155+
public void RedimsBackingVariableAsUDT()
156+
{
157+
string inputCode =
158+
$@"Option Explicit
159+
160+
Public myA|rray() As Integer
161+
162+
Private Sub InitializeArray(size As Long)
163+
Redim myArray(size)
164+
Dim idx As Long
165+
For idx = 1 To size
166+
myArray(idx) = idx
167+
Next idx
168+
End Sub
169+
";
170+
171+
var presenterAction = Support.UserAcceptsDefaults(convertFieldToUDTMember: true);
172+
var actualCode = Support.RefactoredCode(inputCode.ToCodeString(), presenterAction);
173+
StringAssert.Contains("Public Property Get MyArray() As Variant", actualCode);
174+
StringAssert.DoesNotContain("Public Property Let MyArray(", actualCode);
175+
StringAssert.Contains("Redim this.MyArray(size)", actualCode);
176+
StringAssert.Contains("this.MyArray(idx) = idx", actualCode);
177+
}
178+
179+
[TestCase(false)]
180+
[TestCase(true)]
181+
[Category("Refactorings")]
182+
[Category("Encapsulate Field")]
183+
public void RedimsBackingVariableExternally(bool convertField)
184+
{
185+
var fieldUT = "myArray";
186+
string inputCode =
187+
$@"Option Explicit
188+
189+
Public myArray() As Long
190+
";
191+
var redimCode =
192+
$@"Option Explicit
193+
194+
Private Sub InitializeArray(size As Long)
195+
Redim myArray(size)
196+
Dim idx As Long
197+
For idx = 1 To size
198+
myArray(idx) = idx
199+
Next idx
200+
End Sub
201+
";
202+
var presenterAction = Support.UserAcceptsDefaults(convertFieldToUDTMember: convertField);
203+
204+
var vbe = MockVbeBuilder.BuildFromStdModules(("SourceModule", inputCode), ("ClientModule", redimCode));
205+
var model = Support.RetrieveUserModifiedModelPriorToRefactoring(vbe.Object, fieldUT, DeclarationType.Variable, presenterAction);
206+
207+
model[fieldUT].TryValidateEncapsulationAttributes(out var errorMessage);
208+
209+
StringAssert.AreNotEqualIgnoringCase(EncapsulateFieldResources.ArrayHasExternalRedimFormat, errorMessage);
210+
}
211+
212+
protected override IRefactoring TestRefactoring(IRewritingManager rewritingManager, RubberduckParserState state, IRefactoringPresenterFactory factory, ISelectionService selectionService)
213+
=> Support.SupportTestRefactoring(rewritingManager, state, factory, selectionService);
214+
}
215+
}

0 commit comments

Comments
 (0)