Skip to content
This repository has been archived by the owner on Dec 19, 2018. It is now read-only.

Commit

Permalink
Added tests for extensible directives.
Browse files Browse the repository at this point in the history
- Also involved adding comparers for directive descriptors and their pieces.

#853
  • Loading branch information
NTaylorMullen committed Nov 24, 2016
1 parent b513709 commit 749866d
Show file tree
Hide file tree
Showing 9 changed files with 658 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ public class DirectiveDescriptor

public DirectiveDescriptorKind Kind { get; set; }

public IList<DirectiveTokenDescriptor> Tokens { get; set; }
public IReadOnlyList<DirectiveTokenDescriptor> Tokens { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Internal;

namespace Microsoft.AspNetCore.Razor.Evolution
{
internal class DirectiveDescriptorComparer : IEqualityComparer<DirectiveDescriptor>
{
public static readonly DirectiveDescriptorComparer Default = new DirectiveDescriptorComparer();

protected DirectiveDescriptorComparer()
{
}

public bool Equals(DirectiveDescriptor descriptorX, DirectiveDescriptor descriptorY)
{
if (descriptorX == descriptorY)
{
return true;
}

return descriptorX != null &&
string.Equals(descriptorX.Name, descriptorY.Name, StringComparison.Ordinal) &&
descriptorX.Kind == descriptorY.Kind &&
Enumerable.SequenceEqual(
descriptorX.Tokens,
descriptorY.Tokens,
DirectiveTokenDescriptorComparer.Default);
}

public int GetHashCode(DirectiveDescriptor descriptor)
{
if (descriptor == null)
{
throw new ArgumentNullException(nameof(descriptor));
}

var hashCodeCombiner = HashCodeCombiner.Start();
hashCodeCombiner.Add(descriptor.Name, StringComparer.Ordinal);
hashCodeCombiner.Add(descriptor.Kind);

return hashCodeCombiner.CombinedHash;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using Microsoft.Extensions.Internal;

namespace Microsoft.AspNetCore.Razor.Evolution
{
internal class DirectiveTokenDescriptorComparer : IEqualityComparer<DirectiveTokenDescriptor>
{
public static readonly DirectiveTokenDescriptorComparer Default = new DirectiveTokenDescriptorComparer();

protected DirectiveTokenDescriptorComparer()
{
}

public bool Equals(DirectiveTokenDescriptor descriptorX, DirectiveTokenDescriptor descriptorY)
{
if (descriptorX == descriptorY)
{
return true;
}

return descriptorX != null &&
string.Equals(descriptorX.Value, descriptorY.Value, StringComparison.Ordinal) &&
descriptorX.Kind == descriptorY.Kind;
}

public int GetHashCode(DirectiveTokenDescriptor descriptor)
{
if (descriptor == null)
{
throw new ArgumentNullException(nameof(descriptor));
}

var hashCodeCombiner = HashCodeCombiner.Start();
hashCodeCombiner.Add(descriptor.Value, StringComparer.Ordinal);
hashCodeCombiner.Add(descriptor.Kind);

return hashCodeCombiner.CombinedHash;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1440,10 +1440,12 @@ private void HandleDirective(DirectiveDescriptor descriptor)

if (tokenDescriptor.Kind == DirectiveTokenKind.Member || tokenDescriptor.Kind == DirectiveTokenKind.Type)
{
Span.ChunkGenerator = SpanChunkGenerator.Null;
Output(SpanKind.Code, AcceptedCharacters.WhiteSpace);
}
else
{
Span.ChunkGenerator = SpanChunkGenerator.Null;
Output(SpanKind.Markup, AcceptedCharacters.WhiteSpace);
}

Expand All @@ -1470,7 +1472,7 @@ private void HandleDirective(DirectiveDescriptor descriptor)
CurrentLocation,
LegacyResources.FormatDirectiveExpectsIdentifier(descriptor.Name),
CurrentSymbol.Content.Length);
continue;
return;
}

outputKind = SpanKind.Code;
Expand All @@ -1489,6 +1491,7 @@ private void HandleDirective(DirectiveDescriptor descriptor)
CurrentLocation,
LegacyResources.FormatUnexpectedDirectiveLiteral(descriptor.Name, tokenDescriptor.Value),
CurrentSymbol.Content.Length);
return;
}
break;
}
Expand All @@ -1498,6 +1501,7 @@ private void HandleDirective(DirectiveDescriptor descriptor)
}

AcceptWhile(IsSpacingToken(includeNewLines: false, includeComments: true));
Span.ChunkGenerator = SpanChunkGenerator.Null;

switch (descriptor.Kind)
{
Expand All @@ -1515,8 +1519,12 @@ private void HandleDirective(DirectiveDescriptor descriptor)
LegacyResources.FormatUnexpectedDirectiveLiteral(descriptor.Name, Environment.NewLine),
CurrentSymbol.Content.Length);
}

Output(SpanKind.Markup, AcceptedCharacters.AllWhiteSpace);
break;
case DirectiveDescriptorKind.RazorBlock:
Output(SpanKind.Markup, AcceptedCharacters.WhiteSpace);

ParseDirectiveBlock(descriptor, parseChildren: (startingBraceLocation) =>
{
// When transitioning to the HTML parser we no longer want to act as if we're in a nested C# state.
Expand All @@ -1534,8 +1542,11 @@ private void HandleDirective(DirectiveDescriptor descriptor)
});
break;
case DirectiveDescriptorKind.CodeBlock:
Output(SpanKind.Markup, AcceptedCharacters.WhiteSpace);

ParseDirectiveBlock(descriptor, parseChildren: (startingBraceLocation) =>
{
NextToken();
Balance(BalancingModes.NoErrorOnFailure, CSharpSymbolType.LeftBrace, CSharpSymbolType.RightBrace, startingBraceLocation);
Span.ChunkGenerator = new StatementChunkGenerator();
Output(SpanKind.Code);
Expand All @@ -1551,7 +1562,7 @@ private void ParseDirectiveBlock(DirectiveDescriptor descriptor, Action<SourceLo
Context.ErrorSink.OnError(
CurrentLocation,
LegacyResources.FormatUnexpectedEOFAfterDirective(descriptor.Name, "{"),
CurrentSymbol.Content.Length);
length: 1 /* { */);
}
else if (!At(CSharpSymbolType.LeftBrace))
{
Expand All @@ -1565,7 +1576,7 @@ private void ParseDirectiveBlock(DirectiveDescriptor descriptor, Action<SourceLo
var editHandler = new AutoCompleteEditHandler(Language.TokenizeString, autoCompleteAtEndOfSpan: true);
Span.EditHandler = editHandler;
var startingBraceLocation = CurrentLocation;
AcceptAndMoveNext();
Accept(CurrentSymbol);
Span.ChunkGenerator = SpanChunkGenerator.Null;
Output(SpanKind.MetaCode, AcceptedCharacters.None);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
// Copyright(c) .NET Foundation.All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using Microsoft.Extensions.Internal;

namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
{
internal class DirectiveChunkGenerator : ParentChunkGenerator
{
private static readonly Type Type = typeof(DirectiveChunkGenerator);

public DirectiveChunkGenerator(DirectiveDescriptor descriptor)
{
Descriptor = descriptor;
Expand All @@ -21,5 +26,20 @@ public override void AcceptEnd(ParserVisitor visitor, Block block)
{
visitor.VisitEndDirectiveBlock(this, block);
}
public override bool Equals(object obj)
{
var other = obj as DirectiveChunkGenerator;
return base.Equals(other) &&
DirectiveDescriptorComparer.Default.Equals(Descriptor, other.Descriptor);
}

public override int GetHashCode()
{
var combiner = HashCodeCombiner.Start();
combiner.Add(base.GetHashCode());
combiner.Add(Type);

return combiner.CombinedHash;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
// Copyright(c) .NET Foundation.All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using Microsoft.Extensions.Internal;

namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
{
internal class DirectiveTokenChunkGenerator : SpanChunkGenerator
{
private static readonly Type Type = typeof(DirectiveTokenChunkGenerator);

public DirectiveTokenChunkGenerator(DirectiveTokenDescriptor tokenDescriptor)
{
Descriptor = tokenDescriptor;
Expand All @@ -16,5 +21,21 @@ public override void Accept(ParserVisitor visitor, Span span)
{
visitor.VisitDirectiveToken(this, span);
}

public override bool Equals(object obj)
{
var other = obj as DirectiveTokenChunkGenerator;
return base.Equals(other) &&
DirectiveTokenDescriptorComparer.Default.Equals(Descriptor, other.Descriptor);
}

public override int GetHashCode()
{
var combiner = HashCodeCombiner.Start();
combiner.Add(base.GetHashCode());
combiner.Add(Type);

return combiner.CombinedHash;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright(c) .NET Foundation.All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Xunit;

namespace Microsoft.AspNetCore.Razor.Evolution
{
public class DirectiveDescriptorBuilderTest
{
[Fact]
public void Create_BuildsSingleLineDirectiveDescriptor()
{
// Act
var descriptor = DirectiveDescriptorBuilder.Create("custom").Build();

// Assert
Assert.Equal(DirectiveDescriptorKind.SingleLine, descriptor.Kind);
}

[Fact]
public void CreateRazorBlock_BuildsRazorBlockDirectiveDescriptor()
{
// Act
var descriptor = DirectiveDescriptorBuilder.CreateRazorBlock("custom").Build();

// Assert
Assert.Equal(DirectiveDescriptorKind.RazorBlock, descriptor.Kind);
}

[Fact]
public void CreateCodeBlock_BuildsCodeBlockDirectiveDescriptor()
{
// Act
var descriptor = DirectiveDescriptorBuilder.CreateCodeBlock("custom").Build();

// Assert
Assert.Equal(DirectiveDescriptorKind.CodeBlock, descriptor.Kind);
}

[Fact]
public void AddType_AddsToken()
{
// Arrange
var builder = DirectiveDescriptorBuilder.Create("custom");

// Act
var descriptor = builder.AddType().Build();

// Assert
var token = Assert.Single(descriptor.Tokens);
Assert.Equal(DirectiveTokenKind.Type, token.Kind);
}

[Fact]
public void AddMember_AddsToken()
{
// Arrange
var builder = DirectiveDescriptorBuilder.Create("custom");

// Act
var descriptor = builder.AddMember().Build();

// Assert
var token = Assert.Single(descriptor.Tokens);
Assert.Equal(DirectiveTokenKind.Member, token.Kind);
}

[Fact]
public void AddString_AddsToken()
{
// Arrange
var builder = DirectiveDescriptorBuilder.Create("custom");

// Act
var descriptor = builder.AddString().Build();

// Assert
var token = Assert.Single(descriptor.Tokens);
Assert.Equal(DirectiveTokenKind.String, token.Kind);
}

[Fact]
public void AddLiteral_AddsToken()
{
// Arrange
var builder = DirectiveDescriptorBuilder.Create("custom");

// Act
var descriptor = builder.AddLiteral(",").Build();

// Assert
var token = Assert.Single(descriptor.Tokens);
Assert.Equal(DirectiveTokenKind.Literal, token.Kind);
Assert.Equal(",", token.Value);
}

[Fact]
public void AddX_MaintainsMultipleTokens()
{
// Arrange
var builder = DirectiveDescriptorBuilder.Create("custom");

// Act
var descriptor = builder
.AddType()
.AddMember()
.AddString()
.AddLiteral(",")
.Build();

// Assert
Assert.Collection(descriptor.Tokens,
token => Assert.Equal(DirectiveTokenKind.Type, token.Kind),
token => Assert.Equal(DirectiveTokenKind.Member, token.Kind),
token => Assert.Equal(DirectiveTokenKind.String, token.Kind),
token =>
{
Assert.Equal(DirectiveTokenKind.Literal, token.Kind);
Assert.Equal(",", token.Value);
});
}
}
}
Loading

0 comments on commit 749866d

Please sign in to comment.