Skip to content

Commit

Permalink
Added the beginnings of View caching to minimize on disk reads
Browse files Browse the repository at this point in the history
  • Loading branch information
RobertTheGrey committed Aug 1, 2010
1 parent 0e84a97 commit 2b9d71f
Show file tree
Hide file tree
Showing 20 changed files with 382 additions and 148 deletions.
Binary file not shown.
44 changes: 44 additions & 0 deletions src/SparkSense.Tests/Parsing/CachingViewFolderTests.cs
@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using SparkSense.Parsing;
using System.IO;

namespace SparkSense.Tests.Parsing
{
[TestFixture]
public class CachingViewFolderTests
{
private const string ROOT_VIEW_PATH = "SparkSense.Tests.Views";

[Test]
public void ShouldLoadFromDiskIfPathNotInCache()
{
string contents = String.Empty;
var cache = new CachingViewFolder(ROOT_VIEW_PATH);
var content = cache.GetViewSource("Shared\\Application.spark");

using (TextReader reader = new StreamReader(content.OpenViewStream()))
contents = reader.ReadToEnd();

Assert.That(contents.Contains("no header by default"));
}

[Test]
public void ShouldLoadFromDiskIfPathInCacheWithNullData()
{
string path = "Shared\\Application.spark";
string contents = String.Empty;
var cache = new CachingViewFolder(ROOT_VIEW_PATH);
cache.Add(path);
var content = cache.GetViewSource(path);

using (TextReader reader = new StreamReader(content.OpenViewStream()))
contents = reader.ReadToEnd();

Assert.That(contents.Contains("no header by default"));
}
}
}
12 changes: 6 additions & 6 deletions src/SparkSense.Tests/Parsing/ProjectExplorerTests.cs
Expand Up @@ -5,6 +5,7 @@
using Spark.FileSystem;
using Spark.Parser;
using Spark.Parser.Syntax;
using SparkSense.Parsing;

namespace SparkSense.Tests.Parsing
{
Expand All @@ -26,20 +27,19 @@ public void Setup()
[ExpectedException(typeof(ArgumentNullException))]
public void ShouldThrowIfTheProjectEnvironmentIsNull()
{
new SparkSense.Parsing.ProjectExplorer(null);
new ProjectExplorer(null);
}

[Test] //TODO Rob G , Ignore("This test fails if run without an instance of VS running. It passes if it can attach to the DTE. Need to find a better way of testing this")]
public void ShouldBuildAMapOfAllViewsInTheSolution()
public void ShouldBuildAMapOfAllViewsInTheCurrentProject()
{
Console.WriteLine("This test fails if run without an instance of VS running. It passes if it can attach to the DTE. Need to find a better way of testing this");
var projectEnvironment = (DTE)Marshal.GetActiveObject("VisualStudio.DTE.10.0");

var projectExplorer = new SparkSense.Parsing.ProjectExplorer(projectEnvironment);
var viewMap = projectExplorer.ViewMap;
var projectExplorer = new ProjectExplorer(projectEnvironment);

Assert.Contains("Shared\\_SharedPartial.spark", viewMap);
Assert.Contains("Shared\\Application.spark", viewMap);
Assert.That(projectExplorer.HasView("Shared\\_SharedPartial.spark"));
Assert.That(projectExplorer.HasView("Shared\\Application.spark"));
}
}
}
14 changes: 7 additions & 7 deletions src/SparkSense.Tests/Parsing/ViewExplorerTests.cs
Expand Up @@ -35,7 +35,7 @@ public void ShouldRecogniseVariablesDeclaredInTheSameFile()
var viewFolder = new InMemoryViewFolder { { filePath, fileContent } };

_mockProjectExplorer.Expect(x => x.GetViewFolder()).Return(viewFolder);
_mockProjectExplorer.Expect(x => x.GetCurrentView()).Return(filePath);
_mockProjectExplorer.Expect(x => x.GetCurrentViewPath()).Return(filePath);

var viewExplorer = new ViewExplorer(_mockProjectExplorer);
IList<string> vars = viewExplorer.GetLocalVariables();
Expand All @@ -54,7 +54,7 @@ public void ShouldRecogniseMacrosDeclaredInTheSameFile()
var viewFolder = new InMemoryViewFolder { { filePath, fileContent } };

_mockProjectExplorer.Expect(x => x.GetViewFolder()).Return(viewFolder);
_mockProjectExplorer.Expect(x => x.GetCurrentView()).Return(filePath);
_mockProjectExplorer.Expect(x => x.GetCurrentViewPath()).Return(filePath);

var viewExplorer = new ViewExplorer(_mockProjectExplorer);
IList<string> macros = viewExplorer.GetLocalMacros();
Expand All @@ -72,7 +72,7 @@ public void ShouldRecogniseMacroParameters()
var viewFolder = new InMemoryViewFolder { { filePath, fileContent } };

_mockProjectExplorer.Expect(x => x.GetViewFolder()).Return(viewFolder);
_mockProjectExplorer.Expect(x => x.GetCurrentView()).Return(filePath);
_mockProjectExplorer.Expect(x => x.GetCurrentViewPath()).Return(filePath);

var viewExplorer = new ViewExplorer(_mockProjectExplorer);
IList<string> macroParams = viewExplorer.GetMacroParameters("Macro1");
Expand All @@ -97,13 +97,13 @@ public void ShouldReturnNameOfPartialsFound()
};

_mockProjectExplorer.Expect(x => x.GetViewFolder()).Return(viewFolder);
_mockProjectExplorer.Expect(x => x.GetCurrentView()).Return("Home\\index.spark");
_mockProjectExplorer.Expect(x => x.GetCurrentViewPath()).Return("Home\\index.spark");

var homeExplorer = new ViewExplorer(_mockProjectExplorer);
var homePartials = homeExplorer.GetRelatedPartials();

_mockProjectExplorer.Expect(x => x.GetViewFolder()).Return(viewFolder);
_mockProjectExplorer.Expect(x => x.GetCurrentView()).Return("Other\\index.spark");
_mockProjectExplorer.Expect(x => x.GetCurrentViewPath()).Return("Other\\index.spark");

var otherExplorer = new ViewExplorer(_mockProjectExplorer);
var otherPartials = otherExplorer.GetRelatedPartials();
Expand All @@ -128,7 +128,7 @@ public void ShouldReturnDefaultParametersOfPartial()
};

_mockProjectExplorer.Expect(x => x.GetViewFolder()).Return(viewFolder);
_mockProjectExplorer.Expect(x => x.GetCurrentView()).Return("Home\\index.spark");
_mockProjectExplorer.Expect(x => x.GetCurrentViewPath()).Return("Home\\index.spark");

var homeExplorer = new ViewExplorer(_mockProjectExplorer);
var homeParameters = homeExplorer.GetPossiblePartialDefaults("HomePartial");
Expand Down Expand Up @@ -156,7 +156,7 @@ public void ShouldReturnNameOfPossibleMasterLayoutsFound()
};

_mockProjectExplorer.Expect(x => x.GetViewFolder()).Return(viewFolder);
_mockProjectExplorer.Expect(x => x.GetCurrentView()).Return("Home\\index.spark");
_mockProjectExplorer.Expect(x => x.GetCurrentViewPath()).Return("Home\\index.spark");

var viewExplorer = new ViewExplorer(_mockProjectExplorer);
var possibleMasters = viewExplorer.GetPossibleMasterLayouts().ToList();
Expand Down
1 change: 1 addition & 0 deletions src/SparkSense.Tests/SparkSense.Tests.csproj
Expand Up @@ -95,6 +95,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Parsing\CachingViewFolderTests.cs" />
<Compile Include="Parsing\ParseContextChunkTests.cs" />
<Compile Include="Parsing\ParseContextNodeTests.cs" />
<Compile Include="Parsing\ParseMultipleNodeTests.cs" />
Expand Down
43 changes: 26 additions & 17 deletions src/SparkSense.Tests/StatementCompletion/CompletionSessionTests.cs
Expand Up @@ -3,9 +3,10 @@
using Microsoft.VisualStudio.Text.Editor;
using NUnit.Framework;
using Rhino.Mocks;
using SparkSense.Parsing;
using SparkSense.StatementCompletion;
using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.Text;
using NUnit.Framework.SyntaxHelpers;

namespace SparkSense.Tests.StatementCompletion
{
Expand All @@ -17,20 +18,7 @@ public class CompletionSessionTests
public void ShouldThrowIfConfigIsNull()
{
new CompletionSessionManager(
null,
MockRepository.GenerateStub<IProjectExplorer>(),
MockRepository.GenerateStub<IWpfTextView>(),
MockRepository.GenerateStub<ITextStructureNavigator>()
);
}

[Test]
[ExpectedException(typeof(ArgumentNullException))]
public void ShouldThrowIfProjectExplorerIsNull()
{
new CompletionSessionManager(
MockRepository.GenerateStub<ICompletionBroker>(),
null,
null,
MockRepository.GenerateStub<IWpfTextView>(),
MockRepository.GenerateStub<ITextStructureNavigator>()
);
Expand All @@ -42,7 +30,6 @@ public void ShouldThrowIfTextViewIsNull()
{
new CompletionSessionManager(
MockRepository.GenerateStub<ICompletionBroker>(),
MockRepository.GenerateStub<IProjectExplorer>(),
null,
MockRepository.GenerateStub<ITextStructureNavigator>()
);
Expand All @@ -54,10 +41,32 @@ public void ShouldThrowIfTextNavigatorIsNull()
{
new CompletionSessionManager(
MockRepository.GenerateStub<ICompletionBroker>(),
MockRepository.GenerateStub<IProjectExplorer>(),
MockRepository.GenerateStub<IWpfTextView>(),
null
);
}

[Test]
public void ListenerShouldAttemptToGetAnInstanceOfTheVisualStudioEnvironment()
{
IServiceProvider _mockServiceProvider;
_mockServiceProvider = new MockServiceProvider();

var _listener = new CompletionListener();
_listener.ServiceProvider = _mockServiceProvider;
var _mockTextBuffer = MockRepository.GenerateStub<ITextBuffer>();
_listener.TryCreateCompletionSource(_mockTextBuffer);
Assert.That(((MockServiceProvider)_mockServiceProvider).ServiceTypeName, Is.EqualTo("DTE"));
}
public class MockServiceProvider : IServiceProvider
{
public string ServiceTypeName { get; private set; }
public object GetService(Type serviceType)
{
ServiceTypeName = serviceType.Name;
return null;
}
}

}
}
56 changes: 21 additions & 35 deletions src/SparkSense.Tests/StatementCompletion/TextViewCreationTests.cs
Expand Up @@ -3,57 +3,43 @@
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.TextManager.Interop;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;
using Rhino.Mocks;
using SparkSense.StatementCompletion;
using Microsoft.VisualStudio.Utilities;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.Language.Intellisense;

namespace SparkSense.Tests.StatementCompletion
{
[TestFixture]
public class TextViewCreationTests
{
private ViewCreationListener _listener;
private IVsEditorAdaptersFactoryService _mockAdapterFactoryService;
private IServiceProvider _mockServiceProvider;
private IVsTextView _mockTextView;

[SetUp]
public void Setup()
{
_listener = new ViewCreationListener();
_mockAdapterFactoryService = MockRepository.GenerateMock<IVsEditorAdaptersFactoryService>();
_mockServiceProvider = new MockServiceProvider();
_mockTextView = MockRepository.GenerateMock<IVsTextView>();
_listener.AdaptersFactoryService = _mockAdapterFactoryService;
_listener.ServiceProvider = _mockServiceProvider;
}

[Test]
public void ListenerShouldAttemptToGetAnInstanceOfTheWpfTextView()
{
var listener = new ViewCreationListener();
var mockAdapterFactoryService = MockRepository.GenerateMock<IVsEditorAdaptersFactoryService>();
var mockTextView = MockRepository.GenerateMock<IVsTextView>();
var mockWpfTextView = MockRepository.GenerateMock<IWpfTextView>();
_mockAdapterFactoryService.Expect(x => x.GetWpfTextView(_mockTextView)).Return(mockWpfTextView);
var mockTextNav = MockRepository.GenerateStub<ITextStructureNavigatorSelectorService>();
var mockProperties = MockRepository.GenerateStub<PropertyCollection>();
var mockBuffer = MockRepository.GenerateStub<ITextBuffer>();
var mockBroker = MockRepository.GenerateStub<ICompletionBroker>();
var mockTextStructureNav = MockRepository.GenerateStub<ITextStructureNavigator>();

_listener.VsTextViewCreated(_mockTextView);
listener.AdaptersFactoryService = mockAdapterFactoryService;
listener.TextNavigator = mockTextNav;
listener.CompletionBroker = mockBroker;
mockAdapterFactoryService.Expect(x => x.GetWpfTextView(mockTextView)).Return(mockWpfTextView);
mockWpfTextView.Stub(x => x.Properties).Return(mockProperties);
mockWpfTextView.Stub(x => x.TextBuffer).Return(mockBuffer);
mockTextNav.Stub(x => x.GetTextStructureNavigator(mockBuffer)).Return(mockTextStructureNav);

_mockAdapterFactoryService.VerifyAllExpectations();
}
listener.VsTextViewCreated(mockTextView);

[Test]
public void ListenerShouldAttemptToGetAnInstanceOfTheVisualStudioEnvironment()
{
_listener.VsTextViewCreated(_mockTextView);
Assert.That(((MockServiceProvider)_mockServiceProvider).ServiceTypeName, Is.EqualTo("DTE"));
mockAdapterFactoryService.VerifyAllExpectations();
}

public class MockServiceProvider : IServiceProvider
{
public string ServiceTypeName { get; private set; }
public object GetService(Type serviceType)
{
ServiceTypeName = serviceType.Name;
return null;
}
}
}
}
52 changes: 52 additions & 0 deletions src/SparkSense/Parsing/CachingViewFolder.cs
@@ -0,0 +1,52 @@
using Spark.FileSystem;
using System.Collections.Generic;
using System.IO;

namespace SparkSense.Parsing
{
public class CachingViewFolder : IViewFolder
{
private FileSystemViewFolder _disk;
private InMemoryViewFolder _cache;

// TODO: Rob G evict cache entry when file on disk changes

public CachingViewFolder(string basePath)
{
_cache = new InMemoryViewFolder();
_disk = new FileSystemViewFolder(basePath);
}
public IViewFile GetViewSource(string path)
{
if (!_cache.HasView(path) || _cache[path].Length == 0)
{
LoadFromDisk(path);
}
return _cache.GetViewSource(path);
}

public IList<string> ListViews(string path)
{
return _cache.ListViews(path);
}

public bool HasView(string path)
{
return _cache.HasView(path) || _disk.HasView(path);
}

public void Add(string path)
{
_cache.Add(path, null);
}

private void LoadFromDisk(string path)
{
var fileContents = _disk.GetViewSource(path);
string contents;
using (TextReader reader = new StreamReader(fileContents.OpenViewStream()))
contents = reader.ReadToEnd();
_cache.Set(path, contents);
}
}
}
6 changes: 1 addition & 5 deletions src/SparkSense/Parsing/IProjectExplorer.cs
@@ -1,15 +1,11 @@
using System.Collections.Generic;
using Spark.FileSystem;

namespace SparkSense.Parsing
{
public interface IProjectExplorer
{
List<string> ViewMap { get; }
bool TryGetActiveDocumentPath(out string activeDocumentPath);
bool ViewFolderExists();
IViewFolder GetViewFolder();
string GetCurrentView();
bool IsCurrentDocumentASparkFile();
string GetCurrentViewPath();
}
}

0 comments on commit 2b9d71f

Please sign in to comment.