Skip to content

Commit ecf8307

Browse files
committed
Add unit tests, address results.
1 parent 43d7092 commit ecf8307

File tree

15 files changed

+1148
-55
lines changed

15 files changed

+1148
-55
lines changed

Rubberduck.Core/AddRemoveReferences/ReferenceModel.cs

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -83,30 +83,26 @@ public ReferenceModel(IReference reference, int priority) : this()
8383
Type = reference.Type;
8484
}
8585

86-
public ReferenceModel(ITypeLib reference) : this()
86+
public ReferenceModel(string path, ITypeLib reference, IComLibraryProvider provider) : this()
8787
{
88-
var documentation = new ComDocumentation(reference, ComDocumentation.LibraryIndex);
88+
FullPath = path;
89+
90+
var documentation = provider.GetComDocumentation(reference);
8991
Name = documentation.Name;
9092
Description = documentation.DocString;
9193

92-
reference.GetLibAttr(out var attributes);
93-
using (DisposalActionContainer.Create(attributes, reference.ReleaseTLibAttr))
94-
{
95-
var typeAttr = Marshal.PtrToStructure<System.Runtime.InteropServices.ComTypes.TYPELIBATTR>(attributes);
96-
97-
Major = typeAttr.wMajorVerNum;
98-
Minor = typeAttr.wMinorVerNum;
99-
Flags = (TypeLibTypeFlags)typeAttr.wLibFlags;
100-
Guid = typeAttr.guid;
101-
}
94+
var info = provider.GetReferenceInfo(reference, Name, path);
95+
Guid = info.Guid;
96+
Major = info.Major;
97+
Minor = info.Minor;
10298
}
10399

104100
public ReferenceModel(string path, bool broken = false) : this()
105101
{
106102
FullPath = path;
107103
try
108104
{
109-
Name = Path.GetFileName(path);
105+
Name = Path.GetFileName(path) ?? path;
110106
Description = Name;
111107
}
112108
catch
@@ -139,10 +135,10 @@ public bool IsPinned
139135
public string Name { get; } = string.Empty;
140136
public Guid Guid { get; }
141137
public string Description { get; } = string.Empty;
142-
public string FullPath { get; } = string.Empty;
138+
public string FullPath { get; }
143139
public string LocaleName { get; } = string.Empty;
144140

145-
public bool IsBuiltIn { get; }
141+
public bool IsBuiltIn { get; set; }
146142
public bool IsBroken { get; }
147143
public TypeLibTypeFlags Flags { get; set; }
148144
public ReferenceKind Type { get; }

Rubberduck.Core/AddRemoveReferences/ReferenceReconciler.cs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,27 @@ public interface IReferenceReconciler
2424

2525
public class ReferenceReconciler : IReferenceReconciler
2626
{
27+
public static readonly List<string> TypeLibraryExtensions = new List<string> { ".olb", ".tlb", ".dll", ".ocx", ".exe" };
28+
2729
private readonly IMessageBox _messageBox;
2830
private readonly IConfigProvider<ReferenceSettings> _settings;
29-
private readonly IComLibraryProvider _tlbProvider;
31+
private readonly IComLibraryProvider _libraryProvider;
3032

31-
public ReferenceReconciler(IMessageBox messageBox, IConfigProvider<ReferenceSettings> settings, IComLibraryProvider tlbProvider)
33+
public ReferenceReconciler(
34+
IMessageBox messageBox,
35+
IConfigProvider<ReferenceSettings> settings,
36+
IComLibraryProvider libraryProvider)
3237
{
3338
_messageBox = messageBox;
3439
_settings = settings;
35-
_tlbProvider = tlbProvider;
40+
_libraryProvider = libraryProvider;
3641
}
3742

3843
public List<ReferenceModel> ReconcileReferences(IAddRemoveReferencesModel model)
3944
{
4045
if (model?.NewReferences is null || !model.NewReferences.Any())
4146
{
42-
return null;
47+
return new List<ReferenceModel>();
4348
}
4449

4550
return ReconcileReferences(model, model.NewReferences.ToList());
@@ -83,8 +88,6 @@ public List<ReferenceModel> ReconcileReferences(IAddRemoveReferencesModel model,
8388
return output;
8489
}
8590

86-
private static readonly List<string> InterestingExtensions = new List<string> { ".olb", ".tlb", ".dll", ".ocx", ".exe" };
87-
8891
public ReferenceModel GetLibraryInfoFromPath(string path)
8992
{
9093
try
@@ -96,9 +99,10 @@ public ReferenceModel GetLibraryInfoFromPath(string path)
9699
}
97100

98101
// LoadTypeLibrary will attempt to open files in the host, so only attempt on possible COM servers.
99-
if (InterestingExtensions.Contains(extension))
102+
if (TypeLibraryExtensions.Contains(extension))
100103
{
101-
return new ReferenceModel(_tlbProvider.LoadTypeLibrary(path));
104+
var type = _libraryProvider.LoadTypeLibrary(path);
105+
return new ReferenceModel(path, type, _libraryProvider);
102106
}
103107
return new ReferenceModel(path);
104108
}

Rubberduck.Core/AddRemoveReferences/RegisteredLibraryFinderService.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,6 @@
66

77
namespace Rubberduck.AddRemoveReferences
88
{
9-
public static class RegistryKeyExtensions
10-
{
11-
public static string GetKeyName(this RegistryKey key)
12-
{
13-
var name = key?.Name;
14-
return name?.Substring(name.LastIndexOf(@"\", StringComparison.InvariantCultureIgnoreCase) + 1) ?? string.Empty;
15-
}
16-
}
17-
189
public interface IRegisteredLibraryFinderService
1910
{
2011
IEnumerable<RegisteredLibraryInfo> FindRegisteredLibraries();
@@ -97,4 +88,13 @@ private IEnumerable<RegistryKey> EnumerateSubKeys(RegistryKey key)
9788
}
9889
}
9990
}
91+
92+
public static class RegistryKeyExtensions
93+
{
94+
public static string GetKeyName(this RegistryKey key)
95+
{
96+
var name = key?.Name;
97+
return name?.Substring(name.LastIndexOf(@"\", StringComparison.InvariantCultureIgnoreCase) + 1) ?? string.Empty;
98+
}
99+
}
100100
}

Rubberduck.Core/AddRemoveReferences/RegisteredLibraryInfo.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public class RegisteredLibraryInfo
2424
{
2525
private static readonly Dictionary<int, string> NativeLocaleNames = new Dictionary<int, string>
2626
{
27-
{ 0, "Standard" }
27+
{ 0, Resources.RubberduckUI.References_DefaultLocale }
2828
};
2929

3030
public RegisteredLibraryKey UniqueId { get; }
@@ -54,8 +54,8 @@ public string LocaleName
5454
}
5555
catch
5656
{
57-
NativeLocaleNames.Add(LocaleId, "Standard");
58-
return "Standard";
57+
NativeLocaleNames.Add(LocaleId, Resources.RubberduckUI.References_DefaultLocale);
58+
return Resources.RubberduckUI.References_DefaultLocale;
5959
}
6060
}
6161
}

Rubberduck.Core/Settings/ReferenceConfigProvider.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public ReferenceConfigProvider(IPersistanceService<ReferenceSettings> persister,
2929

3030
var settings = Create();
3131
_listening = settings.AddToRecentOnReferenceEvents;
32-
if (_listening)
32+
if (_listening && _events != null)
3333
{
3434
_events.ProjectReferenceAdded += ReferenceAddedHandler;
3535
}
@@ -52,13 +52,13 @@ public ReferenceSettings CreateDefaults()
5252
defaults.PinReference(new ReferenceInfo(new Guid(RubberduckGuid.RubberduckTypeLibGuid), string.Empty, string.Empty, version.Major, version.Minor));
5353
defaults.PinReference(new ReferenceInfo(new Guid(RubberduckGuid.RubberduckApiTypeLibGuid), string.Empty, string.Empty, version.Major, version.Minor));
5454

55-
var documents = _environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
55+
var documents = _environment?.GetFolderPath(Environment.SpecialFolder.MyDocuments);
5656
if (!string.IsNullOrEmpty(documents))
5757
{
5858
defaults.ProjectPaths.Add(documents);
5959
}
6060

61-
var appdata = _environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
61+
var appdata = _environment?.GetFolderPath(Environment.SpecialFolder.ApplicationData);
6262
if (!string.IsNullOrEmpty(documents))
6363
{
6464
var addins = Path.Combine(appdata, "Microsoft", "AddIns");
@@ -79,13 +79,13 @@ public ReferenceSettings CreateDefaults()
7979

8080
public void Save(ReferenceSettings settings)
8181
{
82-
if (_listening && !settings.AddToRecentOnReferenceEvents)
82+
if (_listening && _events != null && !settings.AddToRecentOnReferenceEvents)
8383
{
8484
_events.ProjectReferenceAdded -= ReferenceAddedHandler;
8585
_listening = false;
8686
}
8787

88-
if (_listening && !settings.AddToRecentOnReferenceEvents)
88+
if (_listening && _events != null && !settings.AddToRecentOnReferenceEvents)
8989
{
9090
_events.ProjectReferenceAdded += ReferenceAddedHandler;
9191
_listening = true;

Rubberduck.Core/Settings/ReferenceSettings.cs

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,21 @@ public ReferenceSettings(ReferenceSettings other)
6161
AddToRecentOnReferenceEvents = other.AddToRecentOnReferenceEvents;
6262
ProjectPaths = new List<string>(other.ProjectPaths);
6363
other.SerializationPrep(new StreamingContext(StreamingContextStates.All));
64-
_recent = other._recent;
65-
_pinned = other._pinned;
64+
_recent = other._recent.Select(use => new HostUsages(use)).ToList();
65+
RecentLibraryReferences = other.RecentLibraryReferences.ToList();
66+
_pinned = other._pinned.Select(pin => new HostPins(pin)).ToList();
67+
PinnedLibraryReferences = other.PinnedLibraryReferences.ToList();
6668
DeserializationLoad(new StreamingContext(StreamingContextStates.All));
6769
}
6870

71+
private int _tracked;
72+
6973
[DataMember(IsRequired = true)]
70-
public int RecentReferencesTracked { get; set; }
74+
public int RecentReferencesTracked
75+
{
76+
get => _tracked;
77+
set => _tracked = value < 0 ? 0 : Math.Min(value, RecentTrackingLimit);
78+
}
7179

7280
[DataMember(IsRequired = true)]
7381
public bool FixBrokenReferences { get; set; }
@@ -128,7 +136,8 @@ public void TrackUsage(ReferenceInfo reference, string host = null)
128136
{
129137
var use = new ReferenceUsage(reference);
130138
if (string.IsNullOrEmpty(host))
131-
{
139+
{
140+
RecentLibraryReferences.RemoveAll(usage => usage.Matches(reference));
132141
RecentLibraryReferences.Add(use);
133142
RecentLibraryReferences = RecentLibraryReferences
134143
.OrderByDescending(usage => usage.Timestamp)
@@ -154,20 +163,30 @@ public void TrackUsage(ReferenceInfo reference, string host = null)
154163
.Take(RecentReferencesTracked).ToList();
155164
}
156165

166+
// This is so close to damned near impossible that I was tempted to hard code it false, but it's useful for testing.
157167
public bool Equals(ReferenceSettings other)
158168
{
169+
if (ReferenceEquals(this, other))
170+
{
171+
return true;
172+
}
173+
159174
if (other is null ||
160-
RecentReferencesTracked != other.RecentReferencesTracked ||
161-
!PinnedLibraryReferences.OrderBy(_ => _).SequenceEqual(other.PinnedLibraryReferences.OrderBy(_ => _)) ||
162-
!RecentLibraryReferences.OrderBy(_ => _).SequenceEqual(other.RecentLibraryReferences.OrderBy(_ => _)))
175+
RecentReferencesTracked != other.RecentReferencesTracked ||
176+
PinnedLibraryReferences.Count != other.PinnedLibraryReferences.Count ||
177+
RecentLibraryReferences.Count != other.RecentLibraryReferences.Count ||
178+
PinnedLibraryReferences.Any(pin => !other.PinnedLibraryReferences.Any(lib => lib.Equals(pin))) ||
179+
RecentLibraryReferences.Any(recent => !other.RecentLibraryReferences.Any(lib => lib.Equals(recent))))
163180
{
164181
return false;
165182
}
166183

167184
foreach (var host in PinnedProjectReferences)
168185
{
169186
if (!other.PinnedProjectReferences.ContainsKey(host.Key) ||
170-
!host.Value.OrderBy(_ => _).SequenceEqual(other.PinnedProjectReferences[host.Key].OrderBy(_ => _)))
187+
!(other.PinnedProjectReferences[host.Key] is List<ReferenceInfo> otherHost) ||
188+
otherHost.Count != host.Value.Count ||
189+
host.Value.Any(pin => !otherHost.Any(lib => lib.Equals(pin))))
171190
{
172191
return false;
173192
}
@@ -176,8 +195,9 @@ public bool Equals(ReferenceSettings other)
176195
foreach (var host in RecentProjectReferences)
177196
{
178197
if (!other.RecentProjectReferences.ContainsKey(host.Key) ||
179-
!host.Value.OrderBy(usage => usage.Timestamp).Select(usage => usage.Reference)
180-
.SequenceEqual(other.RecentProjectReferences[host.Key].OrderBy(usage => usage.Timestamp).Select(usage => usage.Reference)))
198+
!(other.RecentProjectReferences[host.Key] is List<ReferenceUsage> otherHost) ||
199+
otherHost.Count != host.Value.Count ||
200+
host.Value.Any(pin => !otherHost.Any(lib => lib.Reference.Equals(pin.Reference) && lib.Timestamp.Equals(pin.Timestamp))))
181201
{
182202
return false;
183203
}
@@ -188,15 +208,15 @@ public bool Equals(ReferenceSettings other)
188208

189209
public List<ReferenceInfo> GetPinnedReferencesForHost(string host)
190210
{
191-
var key = host.ToUpperInvariant();
211+
var key = host?.ToUpperInvariant() ?? string.Empty;
192212
return PinnedLibraryReferences.Union(PinnedProjectReferences.ContainsKey(key)
193213
? PinnedProjectReferences[key].ToList()
194214
: new List<ReferenceInfo>()).ToList();
195215
}
196216

197217
public List<ReferenceInfo> GetRecentReferencesForHost(string host)
198218
{
199-
var key = host.ToUpperInvariant();
219+
var key = host?.ToUpperInvariant() ?? string.Empty;
200220
return RecentLibraryReferences
201221
.Concat(RecentProjectReferences.ContainsKey(key)
202222
? RecentProjectReferences[key]
@@ -207,6 +227,14 @@ public List<ReferenceInfo> GetRecentReferencesForHost(string host)
207227

208228
public void UpdatePinnedReferencesForHost(string host, List<ReferenceInfo> pinned)
209229
{
230+
var key = host?.ToUpperInvariant() ?? string.Empty;
231+
232+
PinnedLibraryReferences.Clear();
233+
if (PinnedProjectReferences.ContainsKey(key))
234+
{
235+
PinnedProjectReferences.Remove(key);
236+
}
237+
210238
foreach (var reference in pinned)
211239
{
212240
PinReference(reference, reference.Guid.Equals(Guid.Empty) ? host : string.Empty);
@@ -229,16 +257,19 @@ protected class ReferenceUsage
229257
public ReferenceInfo Reference { get; protected set; }
230258

231259
[DataMember(IsRequired = true)]
232-
public DateTime Timestamp { get; protected set; } = DateTime.Now;
260+
public DateTime Timestamp { get; protected set; }
233261

234262
public ReferenceUsage(ReferenceInfo reference)
235263
{
236264
Reference = reference;
265+
Timestamp = DateTime.Now;
237266
}
238267

239268
public bool Matches(ReferenceInfo other)
240269
{
241270
return Reference.FullPath.Equals(other.FullPath, StringComparison.OrdinalIgnoreCase) ||
271+
!Reference.Guid.Equals(Guid.Empty) &&
272+
!other.Guid.Equals(Guid.Empty) &&
242273
Reference.Guid.Equals(other.Guid) &&
243274
Reference.Major == other.Major &&
244275
Reference.Minor == other.Minor;
@@ -256,6 +287,12 @@ public HostUsages(string host, List<ReferenceUsage> usages)
256287
Host = host;
257288
Usages = usages;
258289
}
290+
291+
public HostUsages(HostUsages other)
292+
{
293+
Host = other.Host;
294+
Usages = other.Usages.ToList();
295+
}
259296
}
260297

261298
[DataContract]
@@ -269,6 +306,12 @@ public HostPins(string host, List<ReferenceInfo> usages)
269306
Host = host;
270307
Pins = usages;
271308
}
309+
310+
public HostPins(HostPins other)
311+
{
312+
Host = other.Host;
313+
Pins = other.Pins.ToList();
314+
}
272315
}
273316
}
274317
}

Rubberduck.Parsing/ComReflection/ComDocumentation.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,16 @@
33

44
namespace Rubberduck.Parsing.ComReflection
55
{
6+
public interface IComDocumentation
7+
{
8+
string Name { get; }
9+
string DocString { get; }
10+
string HelpFile { get; }
11+
int HelpContext { get; }
12+
}
13+
614
[DataContract]
7-
public class ComDocumentation
15+
public class ComDocumentation : IComDocumentation
816
{
917
public const int LibraryIndex = -1;
1018

0 commit comments

Comments
 (0)