Skip to content

Commit

Permalink
Add unit tests, address results.
Browse files Browse the repository at this point in the history
  • Loading branch information
comintern committed Dec 12, 2018
1 parent 43d7092 commit ecf8307
Show file tree
Hide file tree
Showing 15 changed files with 1,148 additions and 55 deletions.
26 changes: 11 additions & 15 deletions Rubberduck.Core/AddRemoveReferences/ReferenceModel.cs
Expand Up @@ -83,30 +83,26 @@ public ReferenceModel(IReference reference, int priority) : this()
Type = reference.Type;
}

public ReferenceModel(ITypeLib reference) : this()
public ReferenceModel(string path, ITypeLib reference, IComLibraryProvider provider) : this()
{
var documentation = new ComDocumentation(reference, ComDocumentation.LibraryIndex);
FullPath = path;

var documentation = provider.GetComDocumentation(reference);
Name = documentation.Name;
Description = documentation.DocString;

reference.GetLibAttr(out var attributes);
using (DisposalActionContainer.Create(attributes, reference.ReleaseTLibAttr))
{
var typeAttr = Marshal.PtrToStructure<System.Runtime.InteropServices.ComTypes.TYPELIBATTR>(attributes);

Major = typeAttr.wMajorVerNum;
Minor = typeAttr.wMinorVerNum;
Flags = (TypeLibTypeFlags)typeAttr.wLibFlags;
Guid = typeAttr.guid;
}
var info = provider.GetReferenceInfo(reference, Name, path);
Guid = info.Guid;
Major = info.Major;
Minor = info.Minor;
}

public ReferenceModel(string path, bool broken = false) : this()
{
FullPath = path;
try
{
Name = Path.GetFileName(path);
Name = Path.GetFileName(path) ?? path;
Description = Name;
}
catch
Expand Down Expand Up @@ -139,10 +135,10 @@ public bool IsPinned
public string Name { get; } = string.Empty;
public Guid Guid { get; }
public string Description { get; } = string.Empty;
public string FullPath { get; } = string.Empty;
public string FullPath { get; }
public string LocaleName { get; } = string.Empty;

public bool IsBuiltIn { get; }
public bool IsBuiltIn { get; set; }
public bool IsBroken { get; }
public TypeLibTypeFlags Flags { get; set; }
public ReferenceKind Type { get; }
Expand Down
20 changes: 12 additions & 8 deletions Rubberduck.Core/AddRemoveReferences/ReferenceReconciler.cs
Expand Up @@ -24,22 +24,27 @@ public interface IReferenceReconciler

public class ReferenceReconciler : IReferenceReconciler
{
public static readonly List<string> TypeLibraryExtensions = new List<string> { ".olb", ".tlb", ".dll", ".ocx", ".exe" };

private readonly IMessageBox _messageBox;
private readonly IConfigProvider<ReferenceSettings> _settings;
private readonly IComLibraryProvider _tlbProvider;
private readonly IComLibraryProvider _libraryProvider;

public ReferenceReconciler(IMessageBox messageBox, IConfigProvider<ReferenceSettings> settings, IComLibraryProvider tlbProvider)
public ReferenceReconciler(
IMessageBox messageBox,
IConfigProvider<ReferenceSettings> settings,
IComLibraryProvider libraryProvider)
{
_messageBox = messageBox;
_settings = settings;
_tlbProvider = tlbProvider;
_libraryProvider = libraryProvider;
}

public List<ReferenceModel> ReconcileReferences(IAddRemoveReferencesModel model)
{
if (model?.NewReferences is null || !model.NewReferences.Any())
{
return null;
return new List<ReferenceModel>();
}

return ReconcileReferences(model, model.NewReferences.ToList());
Expand Down Expand Up @@ -83,8 +88,6 @@ public List<ReferenceModel> ReconcileReferences(IAddRemoveReferencesModel model,
return output;
}

private static readonly List<string> InterestingExtensions = new List<string> { ".olb", ".tlb", ".dll", ".ocx", ".exe" };

public ReferenceModel GetLibraryInfoFromPath(string path)
{
try
Expand All @@ -96,9 +99,10 @@ public ReferenceModel GetLibraryInfoFromPath(string path)
}

// LoadTypeLibrary will attempt to open files in the host, so only attempt on possible COM servers.
if (InterestingExtensions.Contains(extension))
if (TypeLibraryExtensions.Contains(extension))
{
return new ReferenceModel(_tlbProvider.LoadTypeLibrary(path));
var type = _libraryProvider.LoadTypeLibrary(path);
return new ReferenceModel(path, type, _libraryProvider);
}
return new ReferenceModel(path);
}
Expand Down
Expand Up @@ -6,15 +6,6 @@

namespace Rubberduck.AddRemoveReferences
{
public static class RegistryKeyExtensions
{
public static string GetKeyName(this RegistryKey key)
{
var name = key?.Name;
return name?.Substring(name.LastIndexOf(@"\", StringComparison.InvariantCultureIgnoreCase) + 1) ?? string.Empty;
}
}

public interface IRegisteredLibraryFinderService
{
IEnumerable<RegisteredLibraryInfo> FindRegisteredLibraries();
Expand Down Expand Up @@ -97,4 +88,13 @@ private IEnumerable<RegistryKey> EnumerateSubKeys(RegistryKey key)
}
}
}

public static class RegistryKeyExtensions
{
public static string GetKeyName(this RegistryKey key)
{
var name = key?.Name;
return name?.Substring(name.LastIndexOf(@"\", StringComparison.InvariantCultureIgnoreCase) + 1) ?? string.Empty;
}
}
}
6 changes: 3 additions & 3 deletions Rubberduck.Core/AddRemoveReferences/RegisteredLibraryInfo.cs
Expand Up @@ -24,7 +24,7 @@ public class RegisteredLibraryInfo
{
private static readonly Dictionary<int, string> NativeLocaleNames = new Dictionary<int, string>
{
{ 0, "Standard" }
{ 0, Resources.RubberduckUI.References_DefaultLocale }
};

public RegisteredLibraryKey UniqueId { get; }
Expand Down Expand Up @@ -54,8 +54,8 @@ public string LocaleName
}
catch
{
NativeLocaleNames.Add(LocaleId, "Standard");
return "Standard";
NativeLocaleNames.Add(LocaleId, Resources.RubberduckUI.References_DefaultLocale);
return Resources.RubberduckUI.References_DefaultLocale;
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions Rubberduck.Core/Settings/ReferenceConfigProvider.cs
Expand Up @@ -29,7 +29,7 @@ public ReferenceConfigProvider(IPersistanceService<ReferenceSettings> persister,

var settings = Create();
_listening = settings.AddToRecentOnReferenceEvents;
if (_listening)
if (_listening && _events != null)
{
_events.ProjectReferenceAdded += ReferenceAddedHandler;
}
Expand All @@ -52,13 +52,13 @@ public ReferenceSettings CreateDefaults()
defaults.PinReference(new ReferenceInfo(new Guid(RubberduckGuid.RubberduckTypeLibGuid), string.Empty, string.Empty, version.Major, version.Minor));
defaults.PinReference(new ReferenceInfo(new Guid(RubberduckGuid.RubberduckApiTypeLibGuid), string.Empty, string.Empty, version.Major, version.Minor));

var documents = _environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var documents = _environment?.GetFolderPath(Environment.SpecialFolder.MyDocuments);
if (!string.IsNullOrEmpty(documents))
{
defaults.ProjectPaths.Add(documents);
}

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

public void Save(ReferenceSettings settings)
{
if (_listening && !settings.AddToRecentOnReferenceEvents)
if (_listening && _events != null && !settings.AddToRecentOnReferenceEvents)
{
_events.ProjectReferenceAdded -= ReferenceAddedHandler;
_listening = false;
}

if (_listening && !settings.AddToRecentOnReferenceEvents)
if (_listening && _events != null && !settings.AddToRecentOnReferenceEvents)
{
_events.ProjectReferenceAdded += ReferenceAddedHandler;
_listening = true;
Expand Down
69 changes: 56 additions & 13 deletions Rubberduck.Core/Settings/ReferenceSettings.cs
Expand Up @@ -61,13 +61,21 @@ public ReferenceSettings(ReferenceSettings other)
AddToRecentOnReferenceEvents = other.AddToRecentOnReferenceEvents;
ProjectPaths = new List<string>(other.ProjectPaths);
other.SerializationPrep(new StreamingContext(StreamingContextStates.All));
_recent = other._recent;
_pinned = other._pinned;
_recent = other._recent.Select(use => new HostUsages(use)).ToList();
RecentLibraryReferences = other.RecentLibraryReferences.ToList();
_pinned = other._pinned.Select(pin => new HostPins(pin)).ToList();
PinnedLibraryReferences = other.PinnedLibraryReferences.ToList();
DeserializationLoad(new StreamingContext(StreamingContextStates.All));
}

private int _tracked;

[DataMember(IsRequired = true)]
public int RecentReferencesTracked { get; set; }
public int RecentReferencesTracked
{
get => _tracked;
set => _tracked = value < 0 ? 0 : Math.Min(value, RecentTrackingLimit);
}

[DataMember(IsRequired = true)]
public bool FixBrokenReferences { get; set; }
Expand Down Expand Up @@ -128,7 +136,8 @@ public void TrackUsage(ReferenceInfo reference, string host = null)
{
var use = new ReferenceUsage(reference);
if (string.IsNullOrEmpty(host))
{
{
RecentLibraryReferences.RemoveAll(usage => usage.Matches(reference));
RecentLibraryReferences.Add(use);
RecentLibraryReferences = RecentLibraryReferences
.OrderByDescending(usage => usage.Timestamp)
Expand All @@ -154,20 +163,30 @@ public void TrackUsage(ReferenceInfo reference, string host = null)
.Take(RecentReferencesTracked).ToList();
}

// This is so close to damned near impossible that I was tempted to hard code it false, but it's useful for testing.
public bool Equals(ReferenceSettings other)
{
if (ReferenceEquals(this, other))
{
return true;
}

if (other is null ||
RecentReferencesTracked != other.RecentReferencesTracked ||
!PinnedLibraryReferences.OrderBy(_ => _).SequenceEqual(other.PinnedLibraryReferences.OrderBy(_ => _)) ||
!RecentLibraryReferences.OrderBy(_ => _).SequenceEqual(other.RecentLibraryReferences.OrderBy(_ => _)))
RecentReferencesTracked != other.RecentReferencesTracked ||
PinnedLibraryReferences.Count != other.PinnedLibraryReferences.Count ||
RecentLibraryReferences.Count != other.RecentLibraryReferences.Count ||
PinnedLibraryReferences.Any(pin => !other.PinnedLibraryReferences.Any(lib => lib.Equals(pin))) ||
RecentLibraryReferences.Any(recent => !other.RecentLibraryReferences.Any(lib => lib.Equals(recent))))
{
return false;
}

foreach (var host in PinnedProjectReferences)
{
if (!other.PinnedProjectReferences.ContainsKey(host.Key) ||
!host.Value.OrderBy(_ => _).SequenceEqual(other.PinnedProjectReferences[host.Key].OrderBy(_ => _)))
!(other.PinnedProjectReferences[host.Key] is List<ReferenceInfo> otherHost) ||
otherHost.Count != host.Value.Count ||
host.Value.Any(pin => !otherHost.Any(lib => lib.Equals(pin))))
{
return false;
}
Expand All @@ -176,8 +195,9 @@ public bool Equals(ReferenceSettings other)
foreach (var host in RecentProjectReferences)
{
if (!other.RecentProjectReferences.ContainsKey(host.Key) ||
!host.Value.OrderBy(usage => usage.Timestamp).Select(usage => usage.Reference)
.SequenceEqual(other.RecentProjectReferences[host.Key].OrderBy(usage => usage.Timestamp).Select(usage => usage.Reference)))
!(other.RecentProjectReferences[host.Key] is List<ReferenceUsage> otherHost) ||
otherHost.Count != host.Value.Count ||
host.Value.Any(pin => !otherHost.Any(lib => lib.Reference.Equals(pin.Reference) && lib.Timestamp.Equals(pin.Timestamp))))
{
return false;
}
Expand All @@ -188,15 +208,15 @@ public bool Equals(ReferenceSettings other)

public List<ReferenceInfo> GetPinnedReferencesForHost(string host)
{
var key = host.ToUpperInvariant();
var key = host?.ToUpperInvariant() ?? string.Empty;
return PinnedLibraryReferences.Union(PinnedProjectReferences.ContainsKey(key)
? PinnedProjectReferences[key].ToList()
: new List<ReferenceInfo>()).ToList();
}

public List<ReferenceInfo> GetRecentReferencesForHost(string host)
{
var key = host.ToUpperInvariant();
var key = host?.ToUpperInvariant() ?? string.Empty;
return RecentLibraryReferences
.Concat(RecentProjectReferences.ContainsKey(key)
? RecentProjectReferences[key]
Expand All @@ -207,6 +227,14 @@ public List<ReferenceInfo> GetRecentReferencesForHost(string host)

public void UpdatePinnedReferencesForHost(string host, List<ReferenceInfo> pinned)
{
var key = host?.ToUpperInvariant() ?? string.Empty;

PinnedLibraryReferences.Clear();
if (PinnedProjectReferences.ContainsKey(key))
{
PinnedProjectReferences.Remove(key);
}

foreach (var reference in pinned)
{
PinReference(reference, reference.Guid.Equals(Guid.Empty) ? host : string.Empty);
Expand All @@ -229,16 +257,19 @@ protected class ReferenceUsage
public ReferenceInfo Reference { get; protected set; }

[DataMember(IsRequired = true)]
public DateTime Timestamp { get; protected set; } = DateTime.Now;
public DateTime Timestamp { get; protected set; }

public ReferenceUsage(ReferenceInfo reference)
{
Reference = reference;
Timestamp = DateTime.Now;
}

public bool Matches(ReferenceInfo other)
{
return Reference.FullPath.Equals(other.FullPath, StringComparison.OrdinalIgnoreCase) ||
!Reference.Guid.Equals(Guid.Empty) &&
!other.Guid.Equals(Guid.Empty) &&
Reference.Guid.Equals(other.Guid) &&
Reference.Major == other.Major &&
Reference.Minor == other.Minor;
Expand All @@ -256,6 +287,12 @@ public HostUsages(string host, List<ReferenceUsage> usages)
Host = host;
Usages = usages;
}

public HostUsages(HostUsages other)
{
Host = other.Host;
Usages = other.Usages.ToList();
}
}

[DataContract]
Expand All @@ -269,6 +306,12 @@ public HostPins(string host, List<ReferenceInfo> usages)
Host = host;
Pins = usages;
}

public HostPins(HostPins other)
{
Host = other.Host;
Pins = other.Pins.ToList();
}
}
}
}
10 changes: 9 additions & 1 deletion Rubberduck.Parsing/ComReflection/ComDocumentation.cs
Expand Up @@ -3,8 +3,16 @@

namespace Rubberduck.Parsing.ComReflection
{
public interface IComDocumentation
{
string Name { get; }
string DocString { get; }
string HelpFile { get; }
int HelpContext { get; }
}

[DataContract]
public class ComDocumentation
public class ComDocumentation : IComDocumentation
{
public const int LibraryIndex = -1;

Expand Down

0 comments on commit ecf8307

Please sign in to comment.