Improve `GetHashCode()` implementations and their consistency with `Equals()`

- #362 and more
- make a few more properties immutable
 - in a few cases, just remove `private` setters
 - in others, adjust consuming code to handle the changes
- make `Equals()` commutative
 - use `GetType() == obj.GetType()` if necessary
- use only immutable values in `GetHashCode()` calculations
 - avoid `object.GetHashCode()`; that calculates hash of reference
 - add warnings about `RazorError` property setters but use properties
 - BUT lack of immutable values leads to some static `GetHashCode()` calculations
- correct important typo in `TagHelperDescriptorComparer`
- ensure `Equals()` does not `throw` an NRE e.g. in `LineMapping`
- add `SyntaxTreeNode.GetEquivalenceHash()`
- make `SourceLocation.Equals()` and `SourceLocation.CompareTo()` consistent

Update affected tests
- code generators and edit handlers less likely to be equal; adjust expectations

Add lots of tests
- not for all updated classes but enough to see impact of odd choices

nits:
- remove some `Equals()` and `GetHashCode()` overrides in `SpanCodeGenerator` subclasses
 - no longer unique
- remove redundant null checks e.g. when also done in `base.Equals()`
- add `StringComparer.Ordinal` if `StringComparison.Ordinal` used in `Equals()`
- make some `CSharpLineMappingWriter` fields `readonly`
- remove unused `LineMapping` constructor
This commit is contained in:
Doug Bunting 2015-04-26 22:45:40 -07:00
parent 1111405786
commit 6384977e96
62 changed files with 1837 additions and 405 deletions

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{

View File

@ -13,19 +13,28 @@ namespace Microsoft.AspNet.Razor.Parser.SyntaxTree
{
public class AutoCompleteEditHandler : SpanEditHandler
{
private static readonly int TypeHashCode = typeof(AutoCompleteEditHandler).GetHashCode();
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "Func<T> is the recommended delegate type and requires this level of nesting.")]
public AutoCompleteEditHandler(Func<string, IEnumerable<ISymbol>> tokenizer)
: base(tokenizer)
{
}
public AutoCompleteEditHandler(Func<string, IEnumerable<ISymbol>> tokenizer, bool autoCompleteAtEndOfSpan)
: this(tokenizer)
{
AutoCompleteAtEndOfSpan = autoCompleteAtEndOfSpan;
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "Func<T> is the recommended delegate type and requires this level of nesting.")]
public AutoCompleteEditHandler(Func<string, IEnumerable<ISymbol>> tokenizer, AcceptedCharacters accepted)
: base(tokenizer, accepted)
{
}
public bool AutoCompleteAtEndOfSpan { get; set; }
public bool AutoCompleteAtEndOfSpan { get; }
public string AutoCompleteString { get; set; }
protected override PartialParseResult CanAcceptChange(Span target, TextChange normalizedChange)
@ -48,17 +57,17 @@ namespace Microsoft.AspNet.Razor.Parser.SyntaxTree
public override bool Equals(object obj)
{
var other = obj as AutoCompleteEditHandler;
return base.Equals(obj) &&
other != null &&
string.Equals(other.AutoCompleteString, AutoCompleteString, StringComparison.Ordinal) &&
AutoCompleteAtEndOfSpan == other.AutoCompleteAtEndOfSpan;
return base.Equals(other) &&
string.Equals(other.AutoCompleteString, AutoCompleteString, StringComparison.Ordinal) &&
AutoCompleteAtEndOfSpan == other.AutoCompleteAtEndOfSpan;
}
public override int GetHashCode()
{
// Hash code should include only immutable properties but Equals also checks the type.
return HashCodeCombiner.Start()
.Add(base.GetHashCode())
.Add(AutoCompleteString)
.Add(TypeHashCode)
.Add(AutoCompleteAtEndOfSpan)
.CombinedHash;
}
}

View File

@ -18,15 +18,31 @@ namespace Microsoft.AspNet.Razor.Editor
{
public class ImplicitExpressionEditHandler : SpanEditHandler
{
private readonly ISet<string> _keywords;
private readonly IReadOnlyCollection<string> _readOnlyKeywords;
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "Func<T> is the recommended delegate type and requires this level of nesting.")]
public ImplicitExpressionEditHandler(Func<string, IEnumerable<ISymbol>> tokenizer, ISet<string> keywords, bool acceptTrailingDot)
: base(tokenizer)
{
Initialize(keywords, acceptTrailingDot);
_keywords = keywords ?? new HashSet<string>();
// HashSet<T> implements IReadOnlyCollection<T> as of 4.6, but does not for 4.5.1. If the runtime cast
// succeeds, avoid creating a new collection.
_readOnlyKeywords = (_keywords as IReadOnlyCollection<string>) ?? _keywords.ToArray();
AcceptTrailingDot = acceptTrailingDot;
}
public bool AcceptTrailingDot { get; private set; }
public ISet<string> Keywords { get; private set; }
public bool AcceptTrailingDot { get; }
public IReadOnlyCollection<string> Keywords
{
get
{
return _readOnlyKeywords;
}
}
public override string ToString()
{
@ -36,18 +52,17 @@ namespace Microsoft.AspNet.Razor.Editor
public override bool Equals(object obj)
{
var other = obj as ImplicitExpressionEditHandler;
return other != null &&
base.Equals(other) &&
Keywords.SetEquals(other.Keywords) &&
AcceptTrailingDot == other.AcceptTrailingDot;
return base.Equals(other) &&
_keywords.SetEquals(other._keywords) &&
AcceptTrailingDot == other.AcceptTrailingDot;
}
public override int GetHashCode()
{
// Hash code should include only immutable properties and base has none.
return HashCodeCombiner.Start()
.Add(base.GetHashCode())
.Add(AcceptTrailingDot)
.Add(Keywords)
.Add(AcceptTrailingDot)
.CombinedHash;
}
@ -104,12 +119,6 @@ namespace Microsoft.AspNet.Razor.Editor
return PartialParseResult.Rejected;
}
private void Initialize(ISet<string> keywords, bool acceptTrailingDot)
{
Keywords = keywords ?? new HashSet<string>();
AcceptTrailingDot = acceptTrailingDot;
}
// A dotless commit is the process of inserting a '.' with an intellisense selection.
private static bool IsDotlessCommitInsertion(Span target, TextChange change)
{
@ -310,7 +319,7 @@ namespace Microsoft.AspNet.Razor.Editor
{
using (var reader = new StringReader(newContent))
{
return Keywords.Contains(reader.ReadWhile(ParserHelpers.IsIdentifierPart));
return _keywords.Contains(reader.ReadWhile(ParserHelpers.IsIdentifierPart));
}
}
}

View File

@ -8,13 +8,14 @@ using System.Linq;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Text;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor.Editor
{
// Manages edits to a span
public class SpanEditHandler
{
private static readonly int TypeHashCode = typeof(SpanEditHandler).GetHashCode();
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "Func<T> is the recommended delegate type and requires this level of nesting.")]
public SpanEditHandler(Func<string, IEnumerable<ISymbol>> tokenizer)
: this(tokenizer, AcceptedCharacters.Any)
@ -170,16 +171,15 @@ namespace Microsoft.AspNet.Razor.Editor
{
var other = obj as SpanEditHandler;
return other != null &&
AcceptedCharacters == other.AcceptedCharacters &&
EditorHints == other.EditorHints;
GetType() == other.GetType() &&
AcceptedCharacters == other.AcceptedCharacters &&
EditorHints == other.EditorHints;
}
public override int GetHashCode()
{
return HashCodeCombiner.Start()
.Add(AcceptedCharacters)
.Add(EditorHints)
.CombinedHash;
// Hash code should include only immutable properties but Equals also checks the type.
return TypeHashCode;
}
}
}

View File

@ -3,7 +3,6 @@
using System;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor.Generator
{
@ -15,7 +14,8 @@ namespace Microsoft.AspNet.Razor.Generator
NamespaceKeywordLength = namespaceKeywordLength;
}
public string Namespace { get; private set; }
public string Namespace { get; }
public int NamespaceKeywordLength { get; set; }
public override void GenerateCode(Span target, CodeGeneratorContext context)
@ -39,16 +39,14 @@ namespace Microsoft.AspNet.Razor.Generator
{
var other = obj as AddImportCodeGenerator;
return other != null &&
string.Equals(Namespace, other.Namespace, StringComparison.Ordinal) &&
NamespaceKeywordLength == other.NamespaceKeywordLength;
string.Equals(Namespace, other.Namespace, StringComparison.Ordinal) &&
NamespaceKeywordLength == other.NamespaceKeywordLength;
}
public override int GetHashCode()
{
return HashCodeCombiner.Start()
.Add(Namespace)
.Add(NamespaceKeywordLength)
.CombinedHash;
// Hash code should include only immutable properties.
return Namespace == null ? 0 : StringComparer.Ordinal.GetHashCode(Namespace);
}
}
}

View File

@ -19,9 +19,11 @@ namespace Microsoft.AspNet.Razor.Generator
Suffix = suffix;
}
public string Name { get; private set; }
public LocationTagged<string> Prefix { get; private set; }
public LocationTagged<string> Suffix { get; private set; }
public string Name { get; }
public LocationTagged<string> Prefix { get; }
public LocationTagged<string> Suffix { get; }
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
@ -46,15 +48,15 @@ namespace Microsoft.AspNet.Razor.Generator
{
var other = obj as AttributeBlockCodeGenerator;
return other != null &&
string.Equals(other.Name, Name, StringComparison.Ordinal) &&
Equals(other.Prefix, Prefix) &&
Equals(other.Suffix, Suffix);
string.Equals(other.Name, Name, StringComparison.Ordinal) &&
Equals(other.Prefix, Prefix) &&
Equals(other.Suffix, Suffix);
}
public override int GetHashCode()
{
return HashCodeCombiner.Start()
.Add(Name)
.Add(Name, StringComparer.Ordinal)
.Add(Prefix)
.Add(Suffix)
.CombinedHash;

View File

@ -8,6 +8,8 @@ namespace Microsoft.AspNet.Razor.Generator
{
public abstract class BlockCodeGenerator : IBlockCodeGenerator
{
private static readonly int TypeHashCode = typeof(BlockCodeGenerator).GetHashCode();
[SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "This class has no instance state")]
public static readonly IBlockCodeGenerator Null = new NullBlockCodeGenerator();
@ -21,12 +23,13 @@ namespace Microsoft.AspNet.Razor.Generator
public override bool Equals(object obj)
{
return (obj as IBlockCodeGenerator) != null;
return obj != null &&
GetType() == obj.GetType();
}
public override int GetHashCode()
{
return base.GetHashCode();
return TypeHashCode;
}
private class NullBlockCodeGenerator : IBlockCodeGenerator

View File

@ -8,16 +8,16 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{
public class CSharpLineMappingWriter : IDisposable
{
private CSharpCodeWriter _writer;
private MappingLocation _documentMapping;
private SourceLocation _generatedLocation;
private int _startIndent;
private int _generatedContentLength;
private bool _writePragmas;
private bool _addLineMapping;
private readonly CSharpCodeWriter _writer;
private readonly MappingLocation _documentMapping;
private readonly int _startIndent;
private readonly bool _writePragmas;
private readonly bool _addLineMapping;
private CSharpLineMappingWriter([NotNull] CSharpCodeWriter writer,
bool addLineMappings)
private SourceLocation _generatedLocation;
private int _generatedContentLength;
private CSharpLineMappingWriter([NotNull] CSharpCodeWriter writer, bool addLineMappings)
{
_writer = writer;
_addLineMapping = addLineMappings;
@ -32,7 +32,11 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
_generatedLocation = _writer.GetCurrentSourceLocation();
}
public CSharpLineMappingWriter(CSharpCodeWriter writer, SourceLocation documentLocation, int contentLength, string sourceFilename)
public CSharpLineMappingWriter(
CSharpCodeWriter writer,
SourceLocation documentLocation,
int contentLength,
string sourceFilename)
: this(writer, documentLocation, contentLength)
{
_writePragmas = true;
@ -49,9 +53,10 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
/// <param name="writer">The <see cref="CSharpCodeWriter"/> to write output to.</param>
/// <param name="documentLocation">The <see cref="SourceLocation"/> of the Razor content being mapping.</param>
/// <param name="sourceFileName">The input file path.</param>
public CSharpLineMappingWriter([NotNull] CSharpCodeWriter writer,
[NotNull] SourceLocation documentLocation,
[NotNull] string sourceFileName)
public CSharpLineMappingWriter(
[NotNull] CSharpCodeWriter writer,
[NotNull] SourceLocation documentLocation,
[NotNull] string sourceFileName)
: this(writer, addLineMappings: false)
{
_writePragmas = true;
@ -79,14 +84,20 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
}
var generatedLocation = new MappingLocation(_generatedLocation, _generatedContentLength);
if (_documentMapping.ContentLength == -1)
var documentMapping = _documentMapping;
if (documentMapping.ContentLength == -1)
{
_documentMapping.ContentLength = generatedLocation.ContentLength;
documentMapping = new MappingLocation(
location: new SourceLocation(
_documentMapping.AbsoluteIndex,
_documentMapping.LineIndex,
_documentMapping.CharacterIndex),
contentLength: _generatedContentLength);
}
_writer.LineMappingManager.AddMapping(
documentLocation: _documentMapping,
generatedLocation: new MappingLocation(_generatedLocation, _generatedContentLength));
documentLocation: documentMapping,
generatedLocation: generatedLocation);
}
if (_writePragmas)
@ -105,7 +116,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
}
_writer.WriteLineDefaultDirective()
.WriteLineHiddenDirective();
.WriteLineHiddenDirective();
}
// Reset indent back to when it was started

View File

@ -2,44 +2,71 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Globalization;
using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class LineMapping
{
public LineMapping()
: this(documentLocation: null, generatedLocation: null)
{
}
public LineMapping(MappingLocation documentLocation, MappingLocation generatedLocation)
{
DocumentLocation = documentLocation;
GeneratedLocation = generatedLocation;
}
public MappingLocation DocumentLocation { get; set; }
public MappingLocation GeneratedLocation { get; set; }
public MappingLocation DocumentLocation { get; }
public MappingLocation GeneratedLocation { get; }
public override bool Equals(object obj)
{
var other = obj as LineMapping;
if (ReferenceEquals(other, null))
{
return false;
}
return DocumentLocation.Equals(other.DocumentLocation) &&
GeneratedLocation.Equals(other.GeneratedLocation);
GeneratedLocation.Equals(other.GeneratedLocation);
}
public override int GetHashCode()
{
return base.GetHashCode();
return HashCodeCombiner.Start()
.Add(DocumentLocation)
.Add(GeneratedLocation)
.CombinedHash;
}
public static bool operator ==(LineMapping left, LineMapping right)
{
if (ReferenceEquals(left, right))
{
// Exact equality e.g. both objects are null.
return true;
}
if (ReferenceEquals(left, null))
{
return false;
}
return left.Equals(right);
}
public static bool operator !=(LineMapping left, LineMapping right)
{
if (ReferenceEquals(left, right))
{
// Exact equality e.g. both objects are null.
return false;
}
if (ReferenceEquals(left, null))
{
return true;
}
return !left.Equals(right);
}

View File

@ -12,15 +12,11 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler
Mappings = new List<LineMapping>();
}
public List<LineMapping> Mappings { get; private set; }
public List<LineMapping> Mappings { get; }
public void AddMapping(MappingLocation documentLocation, MappingLocation generatedLocation)
{
Mappings.Add(new LineMapping
{
DocumentLocation = documentLocation,
GeneratedLocation = generatedLocation
});
Mappings.Add(new LineMapping(documentLocation, generatedLocation));
}
}
}

View File

@ -2,12 +2,15 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Globalization;
using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class MappingLocation
{
public MappingLocation() : base() { }
public MappingLocation()
{
}
public MappingLocation(SourceLocation location, int contentLength)
{
@ -17,24 +20,36 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler
CharacterIndex = location.CharacterIndex;
}
public int ContentLength { get; set; }
public int AbsoluteIndex { get; set; }
public int LineIndex { get; set; }
public int CharacterIndex { get; set; }
public int ContentLength { get; }
public int AbsoluteIndex { get; }
public int LineIndex { get; }
public int CharacterIndex { get; }
public override bool Equals(object obj)
{
var other = obj as MappingLocation;
if (ReferenceEquals(other, null))
{
return false;
}
return AbsoluteIndex == other.AbsoluteIndex &&
ContentLength == other.ContentLength &&
LineIndex == other.LineIndex &&
CharacterIndex == other.CharacterIndex;
ContentLength == other.ContentLength &&
LineIndex == other.LineIndex &&
CharacterIndex == other.CharacterIndex;
}
public override int GetHashCode()
{
return base.GetHashCode();
return HashCodeCombiner.Start()
.Add(AbsoluteIndex)
.Add(ContentLength)
.Add(LineIndex)
.Add(CharacterIndex)
.CombinedHash;
}
public override string ToString()
@ -49,11 +64,33 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler
public static bool operator ==(MappingLocation left, MappingLocation right)
{
if (ReferenceEquals(left, right))
{
// Exact equality e.g. both objects are null.
return true;
}
if (ReferenceEquals(left, null))
{
return false;
}
return left.Equals(right);
}
public static bool operator !=(MappingLocation left, MappingLocation right)
{
if (ReferenceEquals(left, right))
{
// Exact equality e.g. both objects are null.
return false;
}
if (ReferenceEquals(left, null))
{
return true;
}
return !left.Equals(right);
}
}

View File

@ -1,12 +1,10 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.Globalization;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Text;
using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor.Generator
{
@ -23,8 +21,9 @@ namespace Microsoft.AspNet.Razor.Generator
ValueStart = valueStart;
}
public LocationTagged<string> Prefix { get; private set; }
public SourceLocation ValueStart { get; private set; }
public LocationTagged<string> Prefix { get; }
public SourceLocation ValueStart { get; }
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
@ -47,14 +46,12 @@ namespace Microsoft.AspNet.Razor.Generator
{
var other = obj as DynamicAttributeBlockCodeGenerator;
return other != null &&
Equals(other.Prefix, Prefix);
Equals(other.Prefix, Prefix);
}
public override int GetHashCode()
{
return HashCodeCombiner.Start()
.Add(Prefix)
.CombinedHash;
return Prefix == null ? 0 : Prefix.GetHashCode();
}
}
}

View File

@ -8,6 +8,8 @@ namespace Microsoft.AspNet.Razor.Generator
{
public class ExpressionCodeGenerator : HybridCodeGenerator
{
private static readonly int TypeHashCode = typeof(ExpressionCodeGenerator).GetHashCode();
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
context.CodeTreeBuilder.StartChunkBlock<ExpressionBlockChunk>(target);
@ -30,12 +32,13 @@ namespace Microsoft.AspNet.Razor.Generator
public override bool Equals(object obj)
{
return obj is ExpressionCodeGenerator;
return obj != null &&
GetType() == obj.GetType();
}
public override int GetHashCode()
{
return base.GetHashCode();
return TypeHashCode;
}
}
}

View File

@ -4,6 +4,7 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Framework.Internal;
using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor.Generator
{
@ -121,12 +122,12 @@ namespace Microsoft.AspNet.Razor.Generator
}
// Required Items
public string WriteMethodName { get; private set; }
public string WriteLiteralMethodName { get; private set; }
public string WriteToMethodName { get; private set; }
public string WriteLiteralToMethodName { get; private set; }
public string ExecuteMethodName { get; private set; }
public GeneratedTagHelperContext GeneratedTagHelperContext { get; private set; }
public string WriteMethodName { get; }
public string WriteLiteralMethodName { get; }
public string WriteToMethodName { get; }
public string WriteLiteralToMethodName { get; }
public string ExecuteMethodName { get; }
public GeneratedTagHelperContext GeneratedTagHelperContext { get; }
// Optional Items
public string BeginContextMethodName { get; set; }
@ -160,30 +161,29 @@ namespace Microsoft.AspNet.Razor.Generator
{
return false;
}
var other = (GeneratedClassContext)obj;
return string.Equals(DefineSectionMethodName, other.DefineSectionMethodName, StringComparison.Ordinal) &&
string.Equals(WriteMethodName, other.WriteMethodName, StringComparison.Ordinal) &&
string.Equals(WriteLiteralMethodName, other.WriteLiteralMethodName, StringComparison.Ordinal) &&
string.Equals(WriteToMethodName, other.WriteToMethodName, StringComparison.Ordinal) &&
string.Equals(WriteLiteralToMethodName, other.WriteLiteralToMethodName, StringComparison.Ordinal) &&
string.Equals(ExecuteMethodName, other.ExecuteMethodName, StringComparison.Ordinal) &&
string.Equals(TemplateTypeName, other.TemplateTypeName, StringComparison.Ordinal) &&
string.Equals(BeginContextMethodName, other.BeginContextMethodName, StringComparison.Ordinal) &&
string.Equals(EndContextMethodName, other.EndContextMethodName, StringComparison.Ordinal);
string.Equals(WriteMethodName, other.WriteMethodName, StringComparison.Ordinal) &&
string.Equals(WriteLiteralMethodName, other.WriteLiteralMethodName, StringComparison.Ordinal) &&
string.Equals(WriteToMethodName, other.WriteToMethodName, StringComparison.Ordinal) &&
string.Equals(WriteLiteralToMethodName, other.WriteLiteralToMethodName, StringComparison.Ordinal) &&
string.Equals(ExecuteMethodName, other.ExecuteMethodName, StringComparison.Ordinal) &&
string.Equals(TemplateTypeName, other.TemplateTypeName, StringComparison.Ordinal) &&
string.Equals(BeginContextMethodName, other.BeginContextMethodName, StringComparison.Ordinal) &&
string.Equals(EndContextMethodName, other.EndContextMethodName, StringComparison.Ordinal);
}
public override int GetHashCode()
{
// TODO: Use HashCodeCombiner
return DefineSectionMethodName.GetHashCode() ^
WriteMethodName.GetHashCode() ^
WriteLiteralMethodName.GetHashCode() ^
WriteToMethodName.GetHashCode() ^
WriteLiteralToMethodName.GetHashCode() ^
ExecuteMethodName.GetHashCode() ^
TemplateTypeName.GetHashCode() ^
BeginContextMethodName.GetHashCode() ^
EndContextMethodName.GetHashCode();
// Hash code should include only immutable properties.
return HashCodeCombiner.Start()
.Add(WriteMethodName, StringComparer.Ordinal)
.Add(WriteLiteralMethodName, StringComparer.Ordinal)
.Add(WriteToMethodName, StringComparer.Ordinal)
.Add(WriteLiteralToMethodName, StringComparer.Ordinal)
.Add(ExecuteMethodName, StringComparer.Ordinal)
.CombinedHash;
}
public static bool operator ==(GeneratedClassContext left, GeneratedClassContext right)

View File

@ -1,7 +1,6 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.Globalization;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
@ -24,9 +23,11 @@ namespace Microsoft.AspNet.Razor.Generator
Value = value;
}
public LocationTagged<string> Prefix { get; private set; }
public LocationTagged<string> Value { get; private set; }
public LocationTagged<SpanCodeGenerator> ValueGenerator { get; private set; }
public LocationTagged<string> Prefix { get; }
public LocationTagged<string> Value { get; }
public LocationTagged<SpanCodeGenerator> ValueGenerator { get; }
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
@ -62,9 +63,9 @@ namespace Microsoft.AspNet.Razor.Generator
{
var other = obj as LiteralAttributeCodeGenerator;
return other != null &&
Equals(other.Prefix, Prefix) &&
Equals(other.Value, Value) &&
Equals(other.ValueGenerator, ValueGenerator);
Equals(other.Prefix, Prefix) &&
Equals(other.Value, Value) &&
Equals(other.ValueGenerator, ValueGenerator);
}
public override int GetHashCode()

View File

@ -16,15 +16,5 @@ namespace Microsoft.AspNet.Razor.Generator
{
return "Markup";
}
public override bool Equals(object obj)
{
return obj is MarkupCodeGenerator;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
}

View File

@ -1,7 +1,6 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
@ -25,15 +24,5 @@ namespace Microsoft.AspNet.Razor.Generator
{
return "VirtualPath";
}
public override bool Equals(object obj)
{
return obj is ResolveUrlCodeGenerator;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
}

View File

@ -4,7 +4,6 @@
using System;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor.Generator
{
@ -15,7 +14,7 @@ namespace Microsoft.AspNet.Razor.Generator
SectionName = sectionName;
}
public string SectionName { get; private set; }
public string SectionName { get; }
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
@ -32,17 +31,13 @@ namespace Microsoft.AspNet.Razor.Generator
public override bool Equals(object obj)
{
var other = obj as SectionCodeGenerator;
return other != null &&
base.Equals(other) &&
string.Equals(SectionName, other.SectionName, StringComparison.Ordinal);
return base.Equals(other) &&
string.Equals(SectionName, other.SectionName, StringComparison.Ordinal);
}
public override int GetHashCode()
{
return HashCodeCombiner.Start()
.Add(base.GetHashCode())
.Add(SectionName)
.CombinedHash;
return SectionName == null ? 0 : StringComparer.Ordinal.GetHashCode(SectionName);
}
public override string ToString()

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Razor.Generator
BaseType = baseType;
}
public string BaseType { get; private set; }
public string BaseType { get; }
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
@ -29,7 +29,7 @@ namespace Microsoft.AspNet.Razor.Generator
{
var other = obj as SetBaseTypeCodeGenerator;
return other != null &&
string.Equals(BaseType, other.BaseType, StringComparison.Ordinal);
string.Equals(BaseType, other.BaseType, StringComparison.Ordinal);
}
public override int GetHashCode()

View File

@ -8,6 +8,8 @@ namespace Microsoft.AspNet.Razor.Generator
{
public abstract class SpanCodeGenerator : ISpanCodeGenerator
{
private static readonly int TypeHashCode = typeof(SpanCodeGenerator).GetHashCode();
[SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "This class has no instance state")]
public static readonly ISpanCodeGenerator Null = new NullSpanCodeGenerator();
@ -17,12 +19,13 @@ namespace Microsoft.AspNet.Razor.Generator
public override bool Equals(object obj)
{
return (obj as ISpanCodeGenerator) != null;
return obj != null &&
GetType() == obj.GetType();
}
public override int GetHashCode()
{
return base.GetHashCode();
return TypeHashCode;
}
private class NullSpanCodeGenerator : ISpanCodeGenerator

View File

@ -16,15 +16,5 @@ namespace Microsoft.AspNet.Razor.Generator
{
return "Stmt";
}
public override bool Equals(object obj)
{
return obj is StatementCodeGenerator;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
}

View File

@ -6,7 +6,7 @@ using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
{
/// <summary>
/// A <see cref="SpanCodeGenerator"/> responsible for generating
/// A <see cref="SpanCodeGenerator"/> responsible for generating
/// <see cref="Compiler.TagHelperPrefixDirectiveChunk"/>s.
/// </summary>
public class TagHelperPrefixDirectiveCodeGenerator : SpanCodeGenerator

View File

@ -16,16 +16,5 @@ namespace Microsoft.AspNet.Razor.Generator
{
return "TypeMember";
}
public override bool Equals(object obj)
{
return obj is TypeMemberCodeGenerator;
}
// C# complains at us if we don't provide an implementation, even one like this
public override int GetHashCode()
{
return base.GetHashCode();
}
}
}

View File

@ -117,7 +117,7 @@ namespace Microsoft.AspNet.Razor.Parser
}
// Set up edit handler
var editHandler = new AutoCompleteEditHandler(Language.TokenizeString) { AutoCompleteAtEndOfSpan = true };
var editHandler = new AutoCompleteEditHandler(Language.TokenizeString, autoCompleteAtEndOfSpan: true);
Span.EditHandler = editHandler;
Span.Accept(CurrentSymbol);

View File

@ -8,6 +8,7 @@ using System.Globalization;
using System.Linq;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Text;
using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor.Parser.SyntaxTree
{
@ -45,11 +46,11 @@ namespace Microsoft.AspNet.Razor.Parser.SyntaxTree
}
[SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "Type is the most appropriate name for this property and there is little chance of confusion with GetType")]
public BlockType Type { get; private set; }
public BlockType Type { get; }
public IEnumerable<SyntaxTreeNode> Children { get; private set; }
public IEnumerable<SyntaxTreeNode> Children { get; }
public IBlockCodeGenerator CodeGenerator { get; private set; }
public IBlockCodeGenerator CodeGenerator { get; }
public override bool IsBlock
{
@ -111,14 +112,18 @@ namespace Microsoft.AspNet.Razor.Parser.SyntaxTree
{
var other = obj as Block;
return other != null &&
Type == other.Type &&
Equals(CodeGenerator, other.CodeGenerator) &&
ChildrenEqual(Children, other.Children);
Type == other.Type &&
Equals(CodeGenerator, other.CodeGenerator) &&
ChildrenEqual(Children, other.Children);
}
public override int GetHashCode()
{
return (int)Type;
return HashCodeCombiner.Start()
.Add(Type)
.Add(CodeGenerator)
.Add(Children)
.CombinedHash;
}
public IEnumerable<Span> Flatten()
@ -201,7 +206,19 @@ namespace Microsoft.AspNet.Razor.Parser.SyntaxTree
{
return false;
}
return Enumerable.SequenceEqual(Children, other.Children, new EquivalenceComparer());
}
public override int GetEquivalenceHash()
{
var combiner = HashCodeCombiner.Start().Add(Type);
foreach (var child in Children)
{
combiner.Add(child.GetEquivalenceHash());
}
return combiner.CombinedHash;
}
}
}

View File

@ -14,7 +14,7 @@ namespace Microsoft.AspNet.Razor.Parser.SyntaxTree
public int GetHashCode(SyntaxTreeNode obj)
{
return obj.GetHashCode();
return obj.GetEquivalenceHash();
}
}
}

View File

@ -10,12 +10,12 @@ using Microsoft.AspNet.Razor.Editor;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Text;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor.Parser.SyntaxTree
{
public class Span : SyntaxTreeNode
{
private static readonly int TypeHashCode = typeof(Span).GetHashCode();
private SourceLocation _start;
public Span(SpanBuilder builder)
@ -126,29 +126,32 @@ namespace Microsoft.AspNet.Razor.Parser.SyntaxTree
{
var other = node as Span;
return other != null &&
Kind.Equals(other.Kind) &&
Start.Equals(other.Start) &&
EditHandler.Equals(other.EditHandler) &&
string.Equals(other.Content, Content, StringComparison.Ordinal);
Kind.Equals(other.Kind) &&
Start.Equals(other.Start) &&
EditHandler.Equals(other.EditHandler) &&
string.Equals(other.Content, Content, StringComparison.Ordinal);
}
public override int GetEquivalenceHash()
{
// Hash code should include only immutable properties but EquivalentTo also checks the type.
return TypeHashCode;
}
public override bool Equals(object obj)
{
var other = obj as Span;
return other != null &&
Kind.Equals(other.Kind) &&
EditHandler.Equals(other.EditHandler) &&
CodeGenerator.Equals(other.CodeGenerator) &&
Symbols.SequenceEqual(other.Symbols);
Kind.Equals(other.Kind) &&
EditHandler.Equals(other.EditHandler) &&
CodeGenerator.Equals(other.CodeGenerator) &&
Symbols.SequenceEqual(other.Symbols);
}
public override int GetHashCode()
{
return HashCodeCombiner.Start()
.Add((int)Kind)
.Add(Start)
.Add(Content)
.CombinedHash;
// Hash code should include only immutable properties but Equals also checks the type.
return TypeHashCode;
}
}
}

View File

@ -37,5 +37,15 @@ namespace Microsoft.AspNet.Razor.Parser.SyntaxTree
/// symbols may be different.
/// </returns>
public abstract bool EquivalentTo(SyntaxTreeNode node);
/// <summary>
/// Determines a hash code for the <see cref="SyntaxTreeNode"/> using only information relevant in
/// <see cref="EquivalentTo"/> comparisons.
/// </summary>
/// <returns>
/// A hash code for the <see cref="SyntaxTreeNode"/> using only information relevant in
/// <see cref="EquivalentTo"/> comparisons.
/// </returns>
public abstract int GetEquivalenceHash();
}
}

View File

@ -81,7 +81,7 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
/// <summary>
/// The HTML tag name.
/// </summary>
public string TagName { get; private set; }
public string TagName { get; }
public override int Length
{
@ -115,20 +115,18 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
/// </returns>
public bool Equals(TagHelperBlock other)
{
return other != null &&
TagName == other.TagName &&
Attributes.SequenceEqual(other.Attributes) &&
base.Equals(other);
return base.Equals(other) &&
string.Equals(TagName, other.TagName, StringComparison.OrdinalIgnoreCase) &&
Attributes.SequenceEqual(other.Attributes);
}
/// <inheritdoc />
public override int GetHashCode()
{
return HashCodeCombiner
.Start()
.Add(TagName)
.Add(Attributes)
return HashCodeCombiner.Start()
.Add(base.GetHashCode())
.Add(TagName, StringComparer.OrdinalIgnoreCase)
.Add(Attributes)
.CombinedHash;
}
}

View File

@ -3,6 +3,7 @@
using System;
using System.Globalization;
using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor
{
@ -35,8 +36,22 @@ namespace Microsoft.AspNet.Razor
{
}
/// <summary>
/// Gets (or sets) the message describing the error.
/// </summary>
/// <remarks>Set property is only accessible for deserialization purposes.</remarks>
public string Message { get; set; }
/// <summary>
/// Gets (or sets) the start position of the erroneous text.
/// </summary>
/// <remarks>Set property is only accessible for deserialization purposes.</remarks>
public SourceLocation Location { get; set; }
/// <summary>
/// Gets or sets the length of the erroneous text.
/// </summary>
/// <remarks>Set property is only accessible for deserialization purposes.</remarks>
public int Length { get; set; }
public override string ToString()
@ -46,19 +61,23 @@ namespace Microsoft.AspNet.Razor
public override bool Equals(object obj)
{
var err = obj as RazorError;
return (err != null) && Equals(err);
var error = obj as RazorError;
return Equals(error);
}
public override int GetHashCode()
{
return base.GetHashCode();
return HashCodeCombiner.Start()
.Add(Message, StringComparer.Ordinal)
.Add(Location)
.CombinedHash;
}
public bool Equals(RazorError other)
{
return string.Equals(other.Message, Message, StringComparison.Ordinal) &&
Location.Equals(other.Location);
return other != null &&
string.Equals(other.Message, Message, StringComparison.Ordinal) &&
Location.Equals(other.Location);
}
}
}

View File

@ -90,13 +90,13 @@ namespace Microsoft.AspNet.Razor
/// <inheritdoc />
public override bool Equals(object obj)
{
return (obj is SourceLocation) && Equals((SourceLocation)obj);
return obj is SourceLocation &&
Equals((SourceLocation)obj);
}
/// <inheritdoc />
public override int GetHashCode()
{
// LineIndex and CharacterIndex can be calculated from AbsoluteIndex and the document content.
return HashCodeCombiner.Start()
.Add(FilePath, StringComparer.Ordinal)
.Add(AbsoluteIndex)
@ -106,10 +106,8 @@ namespace Microsoft.AspNet.Razor
/// <inheritdoc />
public bool Equals(SourceLocation other)
{
return string.Equals(FilePath, other.FilePath, StringComparison.Ordinal) &&
AbsoluteIndex == other.AbsoluteIndex &&
LineIndex == other.LineIndex &&
CharacterIndex == other.CharacterIndex;
// LineIndex and CharacterIndex can be calculated from AbsoluteIndex and the document content.
return CompareTo(other) == 0;
}
/// <inheritdoc />

View File

@ -68,7 +68,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers
/// <paramref name="attributes"/>.
/// </summary>
/// <param name="prefix">
/// Text used as a required prefix when matching HTML start and end tags in the Razor source to available
/// Text used as a required prefix when matching HTML start and end tags in the Razor source to available
/// tag helpers.
/// </param>
/// <param name="tagName">The tag name that the tag helper targets. '*' indicates a catch-all
@ -99,7 +99,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers
}
/// <summary>
/// Text used as a required prefix when matching HTML start and end tags in the Razor source to available
/// Text used as a required prefix when matching HTML start and end tags in the Razor source to available
/// tag helpers.
/// </summary>
public string Prefix { get; private set; }
@ -128,11 +128,11 @@ namespace Microsoft.AspNet.Razor.TagHelpers
/// <summary>
/// The list of attributes the tag helper expects.
/// </summary>
public IList<TagHelperAttributeDescriptor> Attributes { get; private set; }
public IReadOnlyList<TagHelperAttributeDescriptor> Attributes { get; private set; }
/// <summary>
/// The list of required attribute names the tag helper expects to target an element.
/// </summary>
public IList<string> RequiredAttributes { get; private set; }
public IReadOnlyList<string> RequiredAttributes { get; private set; }
}
}

View File

@ -40,10 +40,10 @@ namespace Microsoft.AspNet.Razor.TagHelpers
string.Equals(descriptorX.AssemblyName, descriptorY.AssemblyName, StringComparison.Ordinal) &&
Enumerable.SequenceEqual(
descriptorX.RequiredAttributes.OrderBy(
attribute => attribute,
attribute => attribute,
StringComparer.OrdinalIgnoreCase),
descriptorY.RequiredAttributes.OrderBy(
attribute => attribute,
attribute => attribute,
StringComparer.OrdinalIgnoreCase),
StringComparer.OrdinalIgnoreCase);
}
@ -62,12 +62,11 @@ namespace Microsoft.AspNet.Razor.TagHelpers
.Add(descriptor.AssemblyName, StringComparer.Ordinal);
var attributes = descriptor.RequiredAttributes.OrderBy(
attribute => attribute,
attribute => attribute,
StringComparer.OrdinalIgnoreCase);
foreach (var attribute in attributes)
{
hashCodeCombiner.Add(attributes);
hashCodeCombiner.Add(attribute, StringComparer.OrdinalIgnoreCase);
}
return hashCodeCombiner.CombinedHash;

View File

@ -36,16 +36,16 @@ namespace Microsoft.AspNet.Razor.TagHelpers
/// <summary>
/// A <see cref="string"/> used to find tag helper <see cref="System.Type"/>s.
/// </summary>
public string DirectiveText { get; private set; }
public string DirectiveText { get; }
/// <summary>
/// The <see cref="TagHelperDirectiveType"/> of this directive.
/// </summary>
public TagHelperDirectiveType DirectiveType { get; private set; }
public TagHelperDirectiveType DirectiveType { get; }
/// <summary>
/// The <see cref="SourceLocation"/> of the directive.
/// </summary>
public SourceLocation Location { get; private set; }
public SourceLocation Location { get; }
}
}

View File

@ -33,15 +33,20 @@ namespace Microsoft.AspNet.Razor.Text
Value = value;
}
public SourceLocation Location { get; private set; }
public T Value { get; private set; }
public SourceLocation Location { get; }
public T Value { get; }
public override bool Equals(object obj)
{
LocationTagged<T> other = obj as LocationTagged<T>;
return other != null &&
Equals(other.Location, Location) &&
Equals(other.Value, Value);
if (ReferenceEquals(other, null))
{
return false;
}
return Equals(other.Location, Location) &&
Equals(other.Value, Value);
}
public override int GetHashCode()

View File

@ -6,6 +6,7 @@ using System.Diagnostics;
using System.Globalization;
using System.Text;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor.Text
{
@ -58,12 +59,17 @@ namespace Microsoft.AspNet.Razor.Text
OldBuffer = oldBuffer;
}
public int OldPosition { get; private set; }
public int NewPosition { get; private set; }
public int OldLength { get; private set; }
public int NewLength { get; private set; }
public ITextBuffer NewBuffer { get; private set; }
public ITextBuffer OldBuffer { get; private set; }
public int OldPosition { get; }
public int NewPosition { get; }
public int OldLength { get; }
public int NewLength { get; }
public ITextBuffer NewBuffer { get; }
public ITextBuffer OldBuffer { get; }
/// <remark>
/// Note: This property is not thread safe, and will move position on the textbuffer while being read.
@ -120,13 +126,26 @@ namespace Microsoft.AspNet.Razor.Text
{
return false;
}
var change = (TextChange)obj;
return (change.OldPosition == OldPosition) &&
(change.NewPosition == NewPosition) &&
(change.OldLength == OldLength) &&
(change.NewLength == NewLength) &&
OldBuffer.Equals(change.OldBuffer) &&
NewBuffer.Equals(change.NewBuffer);
return change.OldPosition == OldPosition &&
change.NewPosition == NewPosition &&
change.OldLength == OldLength &&
change.NewLength == NewLength &&
OldBuffer.Equals(change.OldBuffer) &&
NewBuffer.Equals(change.NewBuffer);
}
public override int GetHashCode()
{
return HashCodeCombiner.Start()
.Add(OldPosition)
.Add(NewPosition)
.Add(OldLength)
.Add(NewLength)
.Add(OldBuffer)
.Add(NewBuffer)
.CombinedHash;
}
public string ApplyChange(string content, int changeOffset)
@ -147,11 +166,6 @@ namespace Microsoft.AspNet.Razor.Text
return ApplyChange(span.Content, span.Start.AbsoluteIndex);
}
public override int GetHashCode()
{
return OldPosition ^ NewPosition ^ OldLength ^ NewLength ^ NewBuffer.GetHashCode() ^ OldBuffer.GetHashCode();
}
public override string ToString()
{
return string.Format(CultureInfo.CurrentCulture, "({0}:{1}) \"{3}\" -> ({0}:{2}) \"{4}\"", OldPosition, OldLength, NewLength, OldText, NewText);

View File

@ -35,12 +35,13 @@ namespace Microsoft.AspNet.Razor.Tokenizer.Symbols
public override bool Equals(object obj)
{
var other = obj as CSharpSymbol;
return base.Equals(obj) && other.Keyword == Keyword;
return base.Equals(other) && other.Keyword == Keyword;
}
public override int GetHashCode()
{
return base.GetHashCode() ^ Keyword.GetHashCode();
// Hash code should include only immutable properties.
return base.GetHashCode();
}
}
}

View File

@ -29,26 +29,28 @@ namespace Microsoft.AspNet.Razor.Tokenizer.Symbols
}
public SourceLocation Start { get; private set; }
public string Content { get; private set; }
public IEnumerable<RazorError> Errors { get; private set; }
public string Content { get; }
public IEnumerable<RazorError> Errors { get; }
[SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "This is the most appropriate name for this property and conflicts are unlikely")]
public TType Type { get; private set; }
public TType Type { get; }
public override bool Equals(object obj)
{
SymbolBase<TType> other = obj as SymbolBase<TType>;
return other != null &&
Start.Equals(other.Start) &&
string.Equals(Content, other.Content, StringComparison.Ordinal) &&
Type.Equals(other.Type);
Start.Equals(other.Start) &&
string.Equals(Content, other.Content, StringComparison.Ordinal) &&
Type.Equals(other.Type);
}
public override int GetHashCode()
{
// Hash code should include only immutable properties.
return HashCodeCombiner.Start()
.Add(Start)
.Add(Content)
.Add(Content, StringComparer.Ordinal)
.Add(Type)
.CombinedHash;
}

View File

@ -40,7 +40,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
var hashCodeCombiner = HashCodeCombiner
.Start()
.Add(base.GetHashCode())
.Add(base.GetHashCode(descriptor))
.Add(descriptor.TagName, StringComparer.Ordinal)
.Add(descriptor.Prefix);

View File

@ -0,0 +1,220 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using Microsoft.AspNet.Razor.Editor;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Xunit;
namespace Microsoft.AspNet.Razor.Parser.SyntaxTree
{
public class AutoCompleteEditHandlerTest
{
public static TheoryData<AutoCompleteEditHandler, AutoCompleteEditHandler> MatchingTestDataSet
{
get
{
return new TheoryData<AutoCompleteEditHandler, AutoCompleteEditHandler>
{
{
new AutoCompleteEditHandler(tokenizer: null, autoCompleteAtEndOfSpan: false)
{
AcceptedCharacters = AcceptedCharacters.AllWhiteSpace,
AutoCompleteString = "one string",
EditorHints = EditorHints.VirtualPath,
},
new AutoCompleteEditHandler(tokenizer: null, autoCompleteAtEndOfSpan: false)
{
AcceptedCharacters = AcceptedCharacters.AllWhiteSpace,
AutoCompleteString = "one string",
EditorHints = EditorHints.VirtualPath,
}
},
{
// Tokenizer not involved in equality check or hash code calculation.
new AutoCompleteEditHandler(tokenizer: null, autoCompleteAtEndOfSpan: true)
{
AcceptedCharacters = AcceptedCharacters.Any,
AutoCompleteString = "two string",
EditorHints = EditorHints.None,
},
new AutoCompleteEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
autoCompleteAtEndOfSpan: true)
{
AcceptedCharacters = AcceptedCharacters.Any,
AutoCompleteString = "two string",
EditorHints = EditorHints.None,
}
},
};
}
}
public static TheoryData<AutoCompleteEditHandler, object> NonMatchingTestDataSet
{
get
{
return new TheoryData<AutoCompleteEditHandler, object>
{
{
new AutoCompleteEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
autoCompleteAtEndOfSpan: false)
{
AcceptedCharacters = AcceptedCharacters.AllWhiteSpace,
AutoCompleteString = "three string",
EditorHints = EditorHints.VirtualPath,
},
null
},
{
new AutoCompleteEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
autoCompleteAtEndOfSpan: false)
{
AcceptedCharacters = AcceptedCharacters.AllWhiteSpace,
AutoCompleteString = "three string",
EditorHints = EditorHints.VirtualPath,
},
new object()
},
{
new AutoCompleteEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
autoCompleteAtEndOfSpan: false)
{
AcceptedCharacters = AcceptedCharacters.AllWhiteSpace,
AutoCompleteString = "three string",
EditorHints = EditorHints.VirtualPath,
},
new SpanEditHandler(tokenizer: _ => Enumerable.Empty<ISymbol>())
},
{
// Different AcceptedCharacters.
new AutoCompleteEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
autoCompleteAtEndOfSpan: true)
{
AcceptedCharacters = AcceptedCharacters.AllWhiteSpace,
AutoCompleteString = "three string",
EditorHints = EditorHints.VirtualPath,
},
new AutoCompleteEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
autoCompleteAtEndOfSpan: true)
{
AcceptedCharacters = AcceptedCharacters.AnyExceptNewline,
AutoCompleteString = "three string",
EditorHints = EditorHints.VirtualPath,
}
},
{
// Different AutoCompleteAtEndOfSpan.
new AutoCompleteEditHandler(tokenizer: null, autoCompleteAtEndOfSpan: false)
{
AcceptedCharacters = AcceptedCharacters.AnyExceptNewline,
AutoCompleteString = "four string",
EditorHints = EditorHints.None,
},
new AutoCompleteEditHandler(tokenizer: null, autoCompleteAtEndOfSpan: true)
{
AcceptedCharacters = AcceptedCharacters.AnyExceptNewline,
AutoCompleteString = "four string",
EditorHints = EditorHints.None,
}
},
{
// Different AutoCompleteString.
new AutoCompleteEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
autoCompleteAtEndOfSpan: true)
{
AcceptedCharacters = AcceptedCharacters.NewLine,
AutoCompleteString = "some string",
EditorHints = EditorHints.None,
},
new AutoCompleteEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
autoCompleteAtEndOfSpan: true)
{
AcceptedCharacters = AcceptedCharacters.NewLine,
AutoCompleteString = "different string",
EditorHints = EditorHints.None,
}
},
{
// Different AutoCompleteString (case sensitive).
new AutoCompleteEditHandler(tokenizer: null, autoCompleteAtEndOfSpan: false)
{
AcceptedCharacters = AcceptedCharacters.None,
AutoCompleteString = "some string",
EditorHints = EditorHints.VirtualPath,
},
new AutoCompleteEditHandler(tokenizer: null, autoCompleteAtEndOfSpan: false)
{
AcceptedCharacters = AcceptedCharacters.None,
AutoCompleteString = "Some String",
EditorHints = EditorHints.VirtualPath,
}
},
{
// Different EditorHints.
new AutoCompleteEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
autoCompleteAtEndOfSpan: true)
{
AcceptedCharacters = AcceptedCharacters.NonWhiteSpace,
AutoCompleteString = "five string",
EditorHints = EditorHints.VirtualPath,
},
new AutoCompleteEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
autoCompleteAtEndOfSpan: true)
{
AcceptedCharacters = AcceptedCharacters.NonWhiteSpace,
AutoCompleteString = "five string",
EditorHints = EditorHints.None,
}
},
};
}
}
[Theory]
[MemberData(nameof(MatchingTestDataSet))]
public void Equals_True_WhenExpected(AutoCompleteEditHandler leftObject, AutoCompleteEditHandler rightObject)
{
// Arrange & Act
var result = leftObject.Equals(rightObject);
// Assert
Assert.True(result);
}
[Theory]
[MemberData(nameof(NonMatchingTestDataSet))]
public void Equals_False_WhenExpected(AutoCompleteEditHandler leftObject, object rightObject)
{
// Arrange & Act
var result = leftObject.Equals(rightObject);
// Assert
Assert.False(result);
}
[Theory]
[MemberData(nameof(MatchingTestDataSet))]
public void GetHashCode_ReturnsSameValue_WhenEqual(
AutoCompleteEditHandler leftObject,
AutoCompleteEditHandler rightObject)
{
// Arrange & Act
var leftResult = leftObject.GetHashCode();
var rightResult = rightObject.GetHashCode();
// Assert
Assert.Equal(leftResult, rightResult);
}
}
}

View File

@ -0,0 +1,295 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.AspNet.Razor.Editor;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Xunit;
namespace Microsoft.AspNet.Razor.Parser.SyntaxTree
{
public class ImplicitExpressionEditHandlerTest
{
public static TheoryData<ImplicitExpressionEditHandler, ImplicitExpressionEditHandler> MatchingTestDataSet
{
get
{
return new TheoryData<ImplicitExpressionEditHandler, ImplicitExpressionEditHandler>
{
{
new ImplicitExpressionEditHandler(
tokenizer: null,
keywords: new HashSet<string>(),
acceptTrailingDot: false)
{
AcceptedCharacters = AcceptedCharacters.AllWhiteSpace,
EditorHints = EditorHints.VirtualPath,
},
new ImplicitExpressionEditHandler(
tokenizer: null,
keywords: new HashSet<string>(),
acceptTrailingDot: false)
{
AcceptedCharacters = AcceptedCharacters.AllWhiteSpace,
EditorHints = EditorHints.VirtualPath,
}
},
{
// Tokenizer not involved in equality check or hash code calculation.
new ImplicitExpressionEditHandler(
tokenizer: null,
keywords: new HashSet<string> { "keyword 1" },
acceptTrailingDot: true)
{
AcceptedCharacters = AcceptedCharacters.Any,
EditorHints = EditorHints.None,
},
new ImplicitExpressionEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
keywords: new HashSet<string> { "keyword 1" },
acceptTrailingDot: true)
{
AcceptedCharacters = AcceptedCharacters.Any,
EditorHints = EditorHints.None,
}
},
{
// Only comparers are different (HashSet's comparer does not affect GetHashCode of entries).
new ImplicitExpressionEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
keywords: new HashSet<string> { "keyword 2", "keyword 3" },
acceptTrailingDot: true)
{
AcceptedCharacters = AcceptedCharacters.Any,
EditorHints = EditorHints.None,
},
new ImplicitExpressionEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
keywords: new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "keyword 2", "keyword 3" },
acceptTrailingDot: true)
{
AcceptedCharacters = AcceptedCharacters.Any,
EditorHints = EditorHints.None,
}
},
};
}
}
public static TheoryData<ImplicitExpressionEditHandler, object> NonMatchingTestDataSet
{
get
{
return new TheoryData<ImplicitExpressionEditHandler, object>
{
{
new ImplicitExpressionEditHandler(
tokenizer: _ => null,
keywords: new HashSet<string> { "keyword 4" },
acceptTrailingDot: false)
{
AcceptedCharacters = AcceptedCharacters.WhiteSpace,
EditorHints = EditorHints.VirtualPath,
},
null
},
{
new ImplicitExpressionEditHandler(
tokenizer: _ => null,
keywords: new HashSet<string> { "keyword 4" },
acceptTrailingDot: false)
{
AcceptedCharacters = AcceptedCharacters.WhiteSpace,
EditorHints = EditorHints.VirtualPath,
},
new object()
},
{
new ImplicitExpressionEditHandler(
tokenizer: _ => null,
keywords: new HashSet<string> { "keyword 4" },
acceptTrailingDot: false)
{
AcceptedCharacters = AcceptedCharacters.WhiteSpace,
EditorHints = EditorHints.None,
},
new SpanEditHandler( tokenizer: _ => null)
},
{
// Different AcceptedCharacters.
new ImplicitExpressionEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
keywords: new HashSet<string> { "keyword 5" },
acceptTrailingDot: true)
{
AcceptedCharacters = AcceptedCharacters.AllWhiteSpace,
EditorHints = EditorHints.VirtualPath,
},
new ImplicitExpressionEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
keywords: new HashSet<string> { "keyword 5" },
acceptTrailingDot: true)
{
AcceptedCharacters = AcceptedCharacters.AnyExceptNewline,
EditorHints = EditorHints.VirtualPath,
}
},
{
// Different AcceptTrailingDot.
new ImplicitExpressionEditHandler(
tokenizer: _ => null,
keywords: new HashSet<string> { "keyword 6" },
acceptTrailingDot: false)
{
AcceptedCharacters = AcceptedCharacters.AnyExceptNewline,
EditorHints = EditorHints.VirtualPath,
},
new ImplicitExpressionEditHandler(
tokenizer: _ => null,
keywords: new HashSet<string> { "keyword 6" },
acceptTrailingDot: true)
{
AcceptedCharacters = AcceptedCharacters.AnyExceptNewline,
EditorHints = EditorHints.VirtualPath,
}
},
{
// Different Keywords.
new ImplicitExpressionEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
keywords: new HashSet<string> { "keyword 7" },
acceptTrailingDot: true)
{
AcceptedCharacters = AcceptedCharacters.NewLine,
EditorHints = EditorHints.None,
},
new ImplicitExpressionEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
keywords: new HashSet<string> { "keyword 8" },
acceptTrailingDot: true)
{
AcceptedCharacters = AcceptedCharacters.NewLine,
EditorHints = EditorHints.None,
}
},
{
// Different Keywords comparers (Equals uses left comparer).
new ImplicitExpressionEditHandler(
tokenizer: _ => null,
keywords: new HashSet<string> { "keyword 9" },
acceptTrailingDot: false)
{
AcceptedCharacters = AcceptedCharacters.None,
EditorHints = EditorHints.VirtualPath,
},
new ImplicitExpressionEditHandler(
tokenizer: _ => null,
keywords: new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "KEYWORD 9" },
acceptTrailingDot: false)
{
AcceptedCharacters = AcceptedCharacters.None,
EditorHints = EditorHints.VirtualPath,
}
},
{
// Different Keywords (count).
new ImplicitExpressionEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
keywords: new HashSet<string> { "keyword 10" },
acceptTrailingDot: true)
{
AcceptedCharacters = AcceptedCharacters.NonWhiteSpace,
EditorHints = EditorHints.None,
},
new ImplicitExpressionEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
keywords: new HashSet<string> { "keyword 10", "keyword 11" },
acceptTrailingDot: true)
{
AcceptedCharacters = AcceptedCharacters.NonWhiteSpace,
EditorHints = EditorHints.None,
}
},
{
// Different Keywords (count).
new ImplicitExpressionEditHandler(
tokenizer: null,
keywords: new HashSet<string> { "keyword 12" },
acceptTrailingDot: false)
{
AcceptedCharacters = AcceptedCharacters.WhiteSpace,
EditorHints = EditorHints.None,
},
new ImplicitExpressionEditHandler(
tokenizer: null,
keywords: new HashSet<string>(),
acceptTrailingDot: false)
{
AcceptedCharacters = AcceptedCharacters.WhiteSpace,
EditorHints = EditorHints.None,
}
},
{
// Different EditorHints.
new ImplicitExpressionEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
keywords: new HashSet<string> { "keyword 13" },
acceptTrailingDot: true)
{
AcceptedCharacters = AcceptedCharacters.AllWhiteSpace,
EditorHints = EditorHints.VirtualPath,
},
new ImplicitExpressionEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
keywords: new HashSet<string> { "keyword 13" },
acceptTrailingDot: true)
{
AcceptedCharacters = AcceptedCharacters.AllWhiteSpace,
EditorHints = EditorHints.None,
}
},
};
}
}
[Theory]
[MemberData(nameof(MatchingTestDataSet))]
public void Equals_True_WhenExpected(
ImplicitExpressionEditHandler leftObject,
ImplicitExpressionEditHandler rightObject)
{
// Arrange & Act
var result = leftObject.Equals(rightObject);
// Assert
Assert.True(result);
}
[Theory]
[MemberData(nameof(NonMatchingTestDataSet))]
public void Equals_False_WhenExpected(ImplicitExpressionEditHandler leftObject, object rightObject)
{
// Arrange & Act
var result = leftObject.Equals(rightObject);
// Assert
Assert.False(result);
}
[Theory]
[MemberData(nameof(MatchingTestDataSet))]
public void GetHashCode_ReturnsSameValue_WhenEqual(
ImplicitExpressionEditHandler leftObject,
ImplicitExpressionEditHandler rightObject)
{
// Arrange & Act
var leftResult = leftObject.GetHashCode();
var rightResult = rightObject.GetHashCode();
// Assert
Assert.Equal(leftResult, rightResult);
}
}
}

View File

@ -0,0 +1,165 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Razor.Editor;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Xunit;
namespace Microsoft.AspNet.Razor.Parser.SyntaxTree
{
public class SpanEditHandlerTest
{
public static TheoryData<SpanEditHandler, SpanEditHandler> MatchingTestDataSet
{
get
{
return new TheoryData<SpanEditHandler, SpanEditHandler>
{
{
new SpanEditHandler(tokenizer: null)
{
AcceptedCharacters = AcceptedCharacters.AllWhiteSpace,
EditorHints = EditorHints.VirtualPath,
},
new SpanEditHandler(tokenizer: null)
{
AcceptedCharacters = AcceptedCharacters.AllWhiteSpace,
EditorHints = EditorHints.VirtualPath,
}
},
{
// Tokenizer not involved in equality check or hash code calculation.
new SpanEditHandler(tokenizer: null)
{
AcceptedCharacters = AcceptedCharacters.Any,
EditorHints = EditorHints.None,
},
new SpanEditHandler(tokenizer: _ => Enumerable.Empty<ISymbol>())
{
AcceptedCharacters = AcceptedCharacters.Any,
EditorHints = EditorHints.None,
}
},
};
}
}
public static TheoryData<SpanEditHandler, object> NonMatchingTestDataSet
{
get
{
return new TheoryData<SpanEditHandler, object>
{
{
new SpanEditHandler(tokenizer: _ => Enumerable.Empty<ISymbol>())
{
AcceptedCharacters = AcceptedCharacters.AllWhiteSpace,
EditorHints = EditorHints.VirtualPath,
},
null
},
{
new SpanEditHandler(tokenizer: _ => Enumerable.Empty<ISymbol>())
{
AcceptedCharacters = AcceptedCharacters.AllWhiteSpace,
EditorHints = EditorHints.VirtualPath,
},
new object()
},
{
new SpanEditHandler(tokenizer: _ => Enumerable.Empty<ISymbol>())
{
AcceptedCharacters = AcceptedCharacters.Any,
EditorHints = EditorHints.None,
},
new AutoCompleteEditHandler(
tokenizer: _ => Enumerable.Empty<ISymbol>(),
autoCompleteAtEndOfSpan: true)
{
AcceptedCharacters = AcceptedCharacters.Any,
AutoCompleteString = "two string",
EditorHints = EditorHints.None,
}
},
{
new SpanEditHandler(tokenizer: null)
{
AcceptedCharacters = AcceptedCharacters.AnyExceptNewline,
EditorHints = EditorHints.VirtualPath,
},
new ImplicitExpressionEditHandler(
tokenizer: null,
keywords: new HashSet<string>(),
acceptTrailingDot: false)
{
AcceptedCharacters = AcceptedCharacters.AnyExceptNewline,
EditorHints = EditorHints.VirtualPath,
}
},
{
// Different AcceptedCharacters.
new SpanEditHandler(tokenizer: _ => Enumerable.Empty<ISymbol>())
{
AcceptedCharacters = AcceptedCharacters.AllWhiteSpace,
EditorHints = EditorHints.VirtualPath,
},
new SpanEditHandler(tokenizer: _ => Enumerable.Empty<ISymbol>())
{
AcceptedCharacters = AcceptedCharacters.AnyExceptNewline,
EditorHints = EditorHints.VirtualPath,
}
},
{
// Different EditorHints.
new SpanEditHandler(tokenizer: _ => Enumerable.Empty<ISymbol>())
{
AcceptedCharacters = AcceptedCharacters.NonWhiteSpace,
EditorHints = EditorHints.VirtualPath,
},
new SpanEditHandler(tokenizer: _ => Enumerable.Empty<ISymbol>())
{
AcceptedCharacters = AcceptedCharacters.NonWhiteSpace,
EditorHints = EditorHints.None,
}
},
};
}
}
[Theory]
[MemberData(nameof(MatchingTestDataSet))]
public void Equals_True_WhenExpected(SpanEditHandler leftObject, SpanEditHandler rightObject)
{
// Arrange & Act
var result = leftObject.Equals(rightObject);
// Assert
Assert.True(result);
}
[Theory]
[MemberData(nameof(NonMatchingTestDataSet))]
public void Equals_False_WhenExpected(SpanEditHandler leftObject, object rightObject)
{
// Arrange & Act
var result = leftObject.Equals(rightObject);
// Assert
Assert.False(result);
}
[Theory]
[MemberData(nameof(MatchingTestDataSet))]
public void GetHashCode_ReturnsSameValue_WhenEqual(SpanEditHandler leftObject, SpanEditHandler rightObject)
{
// Arrange & Act
var leftResult = leftObject.GetHashCode();
var rightResult = rightObject.GetHashCode();
// Assert
Assert.Equal(leftResult, rightResult);
}
}
}

View File

@ -6,14 +6,13 @@ using System.Globalization;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Text;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor.Test.Framework
{
internal class RawTextSymbol : ISymbol
{
public SourceLocation Start { get; private set; }
public string Content { get; private set; }
public string Content { get; }
public RawTextSymbol(SourceLocation start, string content)
{
@ -39,10 +38,8 @@ namespace Microsoft.AspNet.Razor.Test.Framework
public override int GetHashCode()
{
return HashCodeCombiner.Start()
.Add(Start)
.Add(Content)
.CombinedHash;
// Hash code should include only immutable properties.
return Content == null ? 0 : Content.GetHashCode();
}
public void OffsetStart(SourceLocation documentStart)

View File

@ -243,7 +243,12 @@ namespace Microsoft.AspNet.Razor.Test.Framework
public static SpanConstructor AutoCompleteWith(this SpanConstructor self, string autoCompleteString, bool atEndOfSpan)
{
return self.With(new AutoCompleteEditHandler(SpanConstructor.TestTokenizer) { AutoCompleteString = autoCompleteString, AutoCompleteAtEndOfSpan = atEndOfSpan });
return self.With(new AutoCompleteEditHandler(
SpanConstructor.TestTokenizer,
autoCompleteAtEndOfSpan: atEndOfSpan)
{
AutoCompleteString = autoCompleteString
});
}
public static SpanConstructor WithEditorHints(this SpanConstructor self, EditorHints hints)

View File

@ -0,0 +1,109 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.AspNet.Razor.Generator
{
public class AddImportCodeGeneratorTest
{
public static TheoryData<AddImportCodeGenerator, AddImportCodeGenerator> MatchingTestDataSet
{
get
{
return new TheoryData<AddImportCodeGenerator, AddImportCodeGenerator>
{
{
new AddImportCodeGenerator(ns: null, namespaceKeywordLength: 3),
new AddImportCodeGenerator(ns: null, namespaceKeywordLength: 3)
},
{
new AddImportCodeGenerator(ns: "Fred", namespaceKeywordLength: 23),
new AddImportCodeGenerator(ns: "Fred", namespaceKeywordLength: 23)
},
};
}
}
public static TheoryData<AddImportCodeGenerator, object> NonMatchingTestDataSet
{
get
{
return new TheoryData<AddImportCodeGenerator, object>
{
{
new AddImportCodeGenerator(ns: null, namespaceKeywordLength: 0),
null
},
{
new AddImportCodeGenerator(ns: "Fred", namespaceKeywordLength: 23),
null
},
{
new AddImportCodeGenerator(ns: "Fred", namespaceKeywordLength: 23),
new object()
},
{
new AddImportCodeGenerator(ns: "Fred", namespaceKeywordLength: 23),
SpanCodeGenerator.Null
},
{
new AddImportCodeGenerator(ns: "Fred", namespaceKeywordLength: 23),
new StatementCodeGenerator()
},
{
// Different Namespace.
new AddImportCodeGenerator(ns: "Fred", namespaceKeywordLength: 3),
new AddImportCodeGenerator(ns: "Ginger", namespaceKeywordLength: 3)
},
{
// Different Namespace (case sensitive).
new AddImportCodeGenerator(ns: "fred", namespaceKeywordLength: 9),
new AddImportCodeGenerator(ns: "FRED", namespaceKeywordLength: 9)
},
{
// Different NamespaceKeywordLength.
new AddImportCodeGenerator(ns: null, namespaceKeywordLength: 0),
new AddImportCodeGenerator(ns: null, namespaceKeywordLength: 23)
},
};
}
}
[Theory]
[MemberData(nameof(MatchingTestDataSet))]
public void Equals_True_WhenExpected(AddImportCodeGenerator leftObject, AddImportCodeGenerator rightObject)
{
// Arrange & Act
var result = leftObject.Equals(rightObject);
// Assert
Assert.True(result);
}
[Theory]
[MemberData(nameof(NonMatchingTestDataSet))]
public void Equals_False_WhenExpected(AddImportCodeGenerator leftObject, object rightObject)
{
// Arrange & Act
var result = leftObject.Equals(rightObject);
// Assert
Assert.False(result);
}
[Theory]
[MemberData(nameof(MatchingTestDataSet))]
public void GetHashCode_ReturnsSameValue_WhenEqual(
AddImportCodeGenerator leftObject,
AddImportCodeGenerator rightObject)
{
// Arrange & Act
var leftResult = leftObject.GetHashCode();
var rightResult = rightObject.GetHashCode();
// Assert
Assert.Equal(leftResult, rightResult);
}
}
}

View File

@ -0,0 +1,157 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Text;
using Xunit;
namespace Microsoft.AspNet.Razor.Generator
{
public class AttributeBlockCodeGeneratorTest
{
public static TheoryData<AttributeBlockCodeGenerator, AttributeBlockCodeGenerator> MatchingTestDataSet
{
get
{
return new TheoryData<AttributeBlockCodeGenerator, AttributeBlockCodeGenerator>
{
{
new AttributeBlockCodeGenerator(name: null, prefix: null, suffix: null),
new AttributeBlockCodeGenerator(name: null, prefix: null, suffix: null)
},
{
new AttributeBlockCodeGenerator(
name: "Fred",
prefix: new LocationTagged<string>(value: "Ginger", offset: 0, line: 0, col: 0),
suffix: new LocationTagged<string>(value: "George", offset: 0, line: 0, col: 0)),
new AttributeBlockCodeGenerator(
name: "Fred",
prefix: new LocationTagged<string>(value: "Ginger", offset: 0, line: 0, col: 0),
suffix: new LocationTagged<string>(value: "George", offset: 0, line: 0, col: 0))
},
{
new AttributeBlockCodeGenerator(
name: "Fred",
prefix: new LocationTagged<string>(value: "Ginger", offset: 10, line: 11, col: 12),
suffix: new LocationTagged<string>(value: "George", offset: 13, line: 14, col: 15)),
new AttributeBlockCodeGenerator(
name: "Fred",
prefix: new LocationTagged<string>(value: "Ginger", offset: 10, line: 11, col: 12),
suffix: new LocationTagged<string>(value: "George", offset: 13, line: 14, col: 15))
},
};
}
}
public static TheoryData<AttributeBlockCodeGenerator, object> NonMatchingTestDataSet
{
get
{
return new TheoryData<AttributeBlockCodeGenerator, object>
{
{
new AttributeBlockCodeGenerator(name: null, prefix: null, suffix: null),
null
},
{
new AttributeBlockCodeGenerator(
name: "Fred",
prefix: new LocationTagged<string>(value: "Ginger", offset: 0, line: 0, col: 0),
suffix: new LocationTagged<string>(value: "George", offset: 0, line: 0, col: 0)),
null
},
{
new AttributeBlockCodeGenerator(
name: "Fred",
prefix: new LocationTagged<string>(value: "Ginger", offset: 10, line: 11, col: 12),
suffix: new LocationTagged<string>(value: "George", offset: 13, line: 14, col: 15)),
null
},
{
new AttributeBlockCodeGenerator(
name: "Fred",
prefix: new LocationTagged<string>(value: "Ginger", offset: 10, line: 11, col: 12),
suffix: new LocationTagged<string>(value: "George", offset: 13, line: 14, col: 15)),
new object()
},
{
new AttributeBlockCodeGenerator(
name: "Fred",
prefix: new LocationTagged<string>(value: "Ginger", offset: 10, line: 11, col: 12),
suffix: new LocationTagged<string>(value: "George", offset: 13, line: 14, col: 15)),
new RazorCommentCodeGenerator()
},
{
// Different Name.
new AttributeBlockCodeGenerator(name: "Fred", prefix: null, suffix: null),
new AttributeBlockCodeGenerator(name: "Ginger", prefix: null, suffix: null)
},
{
// Different Name (case sensitive).
new AttributeBlockCodeGenerator(name: "fred", prefix: null, suffix: null),
new AttributeBlockCodeGenerator(name: "FRED", prefix: null, suffix: null)
},
{
// Different Prefix.
new AttributeBlockCodeGenerator(
name: null,
prefix: new LocationTagged<string>(value: "Ginger", offset: 10, line: 11, col: 12),
suffix: null),
new AttributeBlockCodeGenerator(
name: null,
prefix: new LocationTagged<string>(value: "George", offset: 10, line: 11, col: 12),
suffix: null)
},
{
// Different Suffix.
new AttributeBlockCodeGenerator(
name: null,
prefix: null,
suffix: new LocationTagged<string>(value: "Ginger", offset: 10, line: 11, col: 12)),
new AttributeBlockCodeGenerator(
name: null,
prefix: null,
suffix: new LocationTagged<string>(value: "George", offset: 10, line: 11, col: 12))
},
};
}
}
[Theory]
[MemberData(nameof(MatchingTestDataSet))]
public void Equals_True_WhenExpected(
AttributeBlockCodeGenerator leftObject,
AttributeBlockCodeGenerator rightObject)
{
// Arrange & Act
var result = leftObject.Equals(rightObject);
// Assert
Assert.True(result);
}
[Theory]
[MemberData(nameof(NonMatchingTestDataSet))]
public void Equals_False_WhenExpected(AttributeBlockCodeGenerator leftObject, object rightObject)
{
// Arrange & Act
var result = leftObject.Equals(rightObject);
// Assert
Assert.False(result);
}
[Theory]
[MemberData(nameof(MatchingTestDataSet))]
public void GetHashCode_ReturnsSameValue_WhenEqual(
AttributeBlockCodeGenerator leftObject,
AttributeBlockCodeGenerator rightObject)
{
// Arrange & Act
var leftResult = leftObject.GetHashCode();
var rightResult = rightObject.GetHashCode();
// Assert
Assert.Equal(leftResult, rightResult);
}
}
}

View File

@ -0,0 +1,166 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Text;
using Xunit;
namespace Microsoft.AspNet.Razor.Generator
{
public class DynamicAttributeBlockCodeGeneratorTest
{
public static TheoryData<DynamicAttributeBlockCodeGenerator, DynamicAttributeBlockCodeGenerator> MatchingTestDataSet
{
get
{
return new TheoryData<DynamicAttributeBlockCodeGenerator, DynamicAttributeBlockCodeGenerator>
{
{
new DynamicAttributeBlockCodeGenerator(prefix: null, offset: 0, line: 0, col: 0),
new DynamicAttributeBlockCodeGenerator(prefix: null, offset: 0, line: 0, col: 0)
},
{
new DynamicAttributeBlockCodeGenerator(
prefix: new LocationTagged<string>(value: "Fred", offset: 0, line: 0, col: 0),
offset: 10,
line: 11,
col: 12),
new DynamicAttributeBlockCodeGenerator(
prefix: new LocationTagged<string>(value: "Fred", offset: 0, line: 0, col: 0),
offset: 10,
line: 11,
col: 12)
},
// ValueStart not involved in equality check or hash code calculation.
{
new DynamicAttributeBlockCodeGenerator(
prefix: new LocationTagged<string>(value: "Ginger", offset: 10, line: 11, col: 12),
offset: 10,
line: 11,
col: 12),
new DynamicAttributeBlockCodeGenerator(
prefix: new LocationTagged<string>(value: "Ginger", offset: 10, line: 11, col: 12),
offset: 100,
line: 11,
col: 12)
},
{
new DynamicAttributeBlockCodeGenerator(
prefix: new LocationTagged<string>(value: "George", offset: 10, line: 11, col: 12),
offset: 10,
line: 11,
col: 12),
new DynamicAttributeBlockCodeGenerator(
prefix: new LocationTagged<string>(value: "George", offset: 10, line: 11, col: 12),
offset: 10,
line: 110,
col: 12)
},
{
new DynamicAttributeBlockCodeGenerator(
prefix: new LocationTagged<string>(value: "Dean", offset: 10, line: 11, col: 12),
offset: 10,
line: 11,
col: 12),
new DynamicAttributeBlockCodeGenerator(
prefix: new LocationTagged<string>(value: "Dean", offset: 10, line: 11, col: 12),
offset: 10,
line: 11,
col: 120)
},
};
}
}
public static TheoryData<DynamicAttributeBlockCodeGenerator, object> NonMatchingTestDataSet
{
get
{
return new TheoryData<DynamicAttributeBlockCodeGenerator, object>
{
{
new DynamicAttributeBlockCodeGenerator(prefix: null, offset: 0, line: 0, col: 0),
null
},
{
new DynamicAttributeBlockCodeGenerator(
prefix: new LocationTagged<string>(value: "Ginger", offset: 0, line: 0, col: 0),
offset: 10,
line: 11,
col: 12),
null
},
{
new DynamicAttributeBlockCodeGenerator(
prefix: new LocationTagged<string>(value: "Ginger", offset: 10, line: 11, col: 12),
offset: 10,
line: 11,
col: 12),
new object()
},
{
new DynamicAttributeBlockCodeGenerator(
prefix: new LocationTagged<string>(value: "George", offset: 10, line: 11, col: 12),
offset: 10,
line: 11,
col: 12),
new AttributeBlockCodeGenerator(
name: "Fred",
prefix: new LocationTagged<string>(value: "Ginger", offset: 10, line: 11, col: 12),
suffix: new LocationTagged<string>(value: "George", offset: 13, line: 14, col: 15))
},
{
// Different Prefix.
new DynamicAttributeBlockCodeGenerator(
prefix: new LocationTagged<string>(value: "Ginger", offset: 10, line: 11, col: 12),
offset: 10,
line: 11,
col: 12),
new DynamicAttributeBlockCodeGenerator(
prefix: new LocationTagged<string>(value: "George", offset: 10, line: 11, col: 12),
offset: 10,
line: 11,
col: 12)
},
};
}
}
[Theory]
[MemberData(nameof(MatchingTestDataSet))]
public void Equals_True_WhenExpected(
DynamicAttributeBlockCodeGenerator leftObject,
DynamicAttributeBlockCodeGenerator rightObject)
{
// Arrange & Act
var result = leftObject.Equals(rightObject);
// Assert
Assert.True(result);
}
[Theory]
[MemberData(nameof(NonMatchingTestDataSet))]
public void Equals_False_WhenExpected(DynamicAttributeBlockCodeGenerator leftObject, object rightObject)
{
// Arrange & Act
var result = leftObject.Equals(rightObject);
// Assert
Assert.False(result);
}
[Theory]
[MemberData(nameof(MatchingTestDataSet))]
public void GetHashCode_ReturnsSameValue_WhenEqual(
DynamicAttributeBlockCodeGenerator leftObject,
DynamicAttributeBlockCodeGenerator rightObject)
{
// Arrange & Act
var leftResult = leftObject.GetHashCode();
var rightResult = rightObject.GetHashCode();
// Assert
Assert.Equal(leftResult, rightResult);
}
}
}

View File

@ -0,0 +1,92 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using Microsoft.AspNet.Razor.TagHelpers;
using Xunit;
namespace Microsoft.AspNet.Razor.Generator
{
// Really tests underlying BlockCodeGenerator
public class RazorCommentCodeGeneratorTest
{
public static TheoryData<RazorCommentCodeGenerator, IBlockCodeGenerator> MatchingTestDataSet
{
get
{
return new TheoryData<RazorCommentCodeGenerator, IBlockCodeGenerator>
{
{ new RazorCommentCodeGenerator(), new RazorCommentCodeGenerator() },
};
}
}
public static TheoryData<IBlockCodeGenerator, object> NonMatchingTestDataSet
{
get
{
return new TheoryData<IBlockCodeGenerator, object>
{
{ new RazorCommentCodeGenerator(), null },
{ new RazorCommentCodeGenerator(), new object() },
{ new RazorCommentCodeGenerator(), BlockCodeGenerator.Null },
{
new RazorCommentCodeGenerator(),
new AttributeBlockCodeGenerator(name: null, prefix: null, suffix: null)
},
{
new RazorCommentCodeGenerator(),
new DynamicAttributeBlockCodeGenerator(prefix: null, offset: 0, line: 0, col: 0)
},
{ new RazorCommentCodeGenerator(), new ExpressionCodeGenerator() },
{ new RazorCommentCodeGenerator(), new SectionCodeGenerator(sectionName: null) },
{
new RazorCommentCodeGenerator(),
new TagHelperCodeGenerator(Enumerable.Empty<TagHelperDescriptor>())
},
{ new RazorCommentCodeGenerator(), new TemplateBlockCodeGenerator() },
{
new RazorCommentCodeGenerator(),
new AddImportCodeGenerator(ns: "Fred", namespaceKeywordLength: 0)
},
};
}
}
[Theory]
[MemberData(nameof(MatchingTestDataSet))]
public void Equals_True_WhenExpected(RazorCommentCodeGenerator leftObject, IBlockCodeGenerator rightObject)
{
// Arrange & Act
var result = leftObject.Equals(rightObject);
// Assert
Assert.True(result);
}
[Theory]
[MemberData(nameof(NonMatchingTestDataSet))]
public void Equals_False_WhenExpected(IBlockCodeGenerator leftObject, object rightObject)
{
// Arrange & Act
var result = leftObject.Equals(rightObject);
// Assert
Assert.False(result);
}
[Theory]
[MemberData(nameof(MatchingTestDataSet))]
public void GetHashCode_ReturnsSameValue_WhenEqual(
RazorCommentCodeGenerator leftObject,
IBlockCodeGenerator rightObject)
{
// Arrange & Act
var leftResult = leftObject.GetHashCode();
var rightResult = rightObject.GetHashCode();
// Assert
Assert.Equal(leftResult, rightResult);
}
}
}

View File

@ -1,8 +1,8 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor.Test.Generator
{
@ -28,9 +28,11 @@ namespace Microsoft.AspNet.Razor.Test.Generator
{
}
public SpanKind Kind { get; private set; }
public int Start { get; private set; }
public int End { get; private set; }
public SpanKind Kind { get; }
public int Start { get; }
public int End { get; }
public override string ToString()
{
@ -40,20 +42,19 @@ namespace Microsoft.AspNet.Razor.Test.Generator
public override bool Equals(object obj)
{
var other = obj as TestSpan;
if (other != null)
{
return (Kind == other.Kind) &&
(Start == other.Start) &&
(End == other.End);
}
return false;
return other != null &&
Kind == other.Kind &&
Start == other.Start &&
End == other.End;
}
public override int GetHashCode()
{
return base.GetHashCode();
return HashCodeCombiner.Start()
.Add(Kind)
.Add(Start)
.Add(End)
.CombinedHash;
}
}
}

View File

@ -20,7 +20,8 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory
.MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\"\"").AsTagHelperPrefixDirective("")));
Factory.Code("\"\"")
.AsTagHelperPrefixDirective(string.Empty)));
}
[Fact]
@ -32,7 +33,8 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory
.MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\"Foo\"").AsTagHelperPrefixDirective("Foo")));
Factory.Code("\"Foo\"")
.AsTagHelperPrefixDirective("Foo")));
}
[Fact]
@ -44,7 +46,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory
.MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().AsTagHelperPrefixDirective(string.Empty)),
Factory.EmptyCSharp()
.AsStatement()
.Accepts(AcceptedCharacters.AnyExceptNewline)),
new RazorError(
RazorResources.FormatParseError_DirectiveMustHaveValue(
SyntaxConstants.CSharp.TagHelperPrefixKeyword),
@ -60,12 +64,13 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory
.MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\"Foo").AsTagHelperPrefixDirective("Foo")),
new RazorError(
RazorResources.ParseError_Unterminated_String_Literal,
absoluteIndex: 17, lineIndex: 0, columnIndex: 17),
new RazorError(
RazorResources.FormatParseError_DirectiveMustBeSurroundedByQuotes(
Factory.Code("\"Foo")
.AsTagHelperPrefixDirective("Foo")),
new RazorError(
RazorResources.ParseError_Unterminated_String_Literal,
absoluteIndex: 17, lineIndex: 0, columnIndex: 17),
new RazorError(
RazorResources.FormatParseError_DirectiveMustBeSurroundedByQuotes(
SyntaxConstants.CSharp.TagHelperPrefixKeyword),
absoluteIndex: 17, lineIndex: 0, columnIndex: 17));
}
@ -79,7 +84,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory
.MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Foo\"").AsTagHelperPrefixDirective("Foo")),
Factory.Code("Foo\"")
.AsStatement()
.Accepts(AcceptedCharacters.AnyExceptNewline)),
new RazorError(
RazorResources.ParseError_Unterminated_String_Literal,
absoluteIndex: 20, lineIndex: 0, columnIndex: 20),
@ -98,7 +105,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory
.MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Foo").AsTagHelperPrefixDirective("Foo")),
Factory.Code("Foo")
.AsStatement()
.Accepts(AcceptedCharacters.AnyExceptNewline)),
new RazorError(
RazorResources.FormatParseError_DirectiveMustBeSurroundedByQuotes(
SyntaxConstants.CSharp.TagHelperPrefixKeyword),
@ -113,7 +122,8 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\"Foo\"").AsRemoveTagHelper("Foo")));
Factory.Code("\"Foo\"")
.AsRemoveTagHelper("Foo")));
}
[Fact]
@ -124,7 +134,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\" Foo, Bar \" ").AsRemoveTagHelper(" Foo, Bar ")));
Factory.Code("\" Foo, Bar \" ")
.AsRemoveTagHelper("Foo, Bar")
.Accepts(AcceptedCharacters.AnyExceptNewline)));
}
[Fact]
@ -135,7 +147,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().AsRemoveTagHelper(string.Empty)),
Factory.EmptyCSharp()
.AsStatement()
.Accepts(AcceptedCharacters.AnyExceptNewline)),
new RazorError(
RazorResources.FormatParseError_DirectiveMustHaveValue(
SyntaxConstants.CSharp.RemoveTagHelperKeyword),
@ -150,7 +164,8 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\"Foo").AsRemoveTagHelper("Foo")),
Factory.Code("\"Foo")
.AsRemoveTagHelper("Foo")),
new RazorError(
RazorResources.ParseError_Unterminated_String_Literal,
absoluteIndex: 17, lineIndex: 0, columnIndex: 17),
@ -168,7 +183,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Foo\"").AsRemoveTagHelper("Foo")),
Factory.Code("Foo\"")
.AsStatement()
.Accepts(AcceptedCharacters.AnyExceptNewline)),
new RazorError(
RazorResources.ParseError_Unterminated_String_Literal,
absoluteIndex: 20, lineIndex: 0, columnIndex: 20),
@ -186,7 +203,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Foo").AsRemoveTagHelper("Foo")),
Factory.Code("Foo")
.AsStatement()
.Accepts(AcceptedCharacters.AnyExceptNewline)),
new RazorError(
RazorResources.FormatParseError_DirectiveMustBeSurroundedByQuotes(
SyntaxConstants.CSharp.RemoveTagHelperKeyword),
@ -201,7 +220,8 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\"Foo\"").AsAddTagHelper("Foo")));
Factory.Code("\"Foo\"")
.AsAddTagHelper("Foo")));
}
[Fact]
@ -212,7 +232,8 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\" Foo, Bar \" ").AsAddTagHelper(" Foo, Bar ")));
Factory.Code("\" Foo, Bar \" ")
.AsAddTagHelper("Foo, Bar")));
}
[Fact]
@ -223,7 +244,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().AsAddTagHelper(string.Empty)),
Factory.EmptyCSharp()
.AsStatement()
.Accepts(AcceptedCharacters.AnyExceptNewline)),
new RazorError(
RazorResources.FormatParseError_DirectiveMustHaveValue(SyntaxConstants.CSharp.AddTagHelperKeyword),
absoluteIndex: 14, lineIndex: 0, columnIndex: 14));
@ -237,7 +260,8 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\"Foo").AsAddTagHelper("Foo")),
Factory.Code("\"Foo")
.AsAddTagHelper("Foo")),
new RazorError(
RazorResources.ParseError_Unterminated_String_Literal,
absoluteIndex: 14, lineIndex: 0, columnIndex: 14),
@ -255,7 +279,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Foo\"").AsAddTagHelper("Foo")),
Factory.Code("Foo\"")
.AsStatement()
.Accepts(AcceptedCharacters.AnyExceptNewline)),
new RazorError(
RazorResources.ParseError_Unterminated_String_Literal,
absoluteIndex: 17, lineIndex: 0, columnIndex: 17),
@ -273,7 +299,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Foo").AsAddTagHelper("Foo")),
Factory.Code("Foo")
.AsStatement()
.Accepts(AcceptedCharacters.AnyExceptNewline)),
new RazorError(
RazorResources.FormatParseError_DirectiveMustBeSurroundedByQuotes(
SyntaxConstants.CSharp.AddTagHelperKeyword),
@ -349,7 +377,8 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.MetaCode(SyntaxConstants.CSharp.FunctionsKeyword + " {")
.Accepts(AcceptedCharacters.None),
Factory.Code(" foo(); bar(); ")
.AsFunctionsBody(),
.AsFunctionsBody()
.AutoCompleteWith(autoCompleteString: null),
Factory.MetaCode("}")
.Accepts(AcceptedCharacters.None)));
}
@ -363,7 +392,8 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.MetaCode(SyntaxConstants.CSharp.FunctionsKeyword + " {")
.Accepts(AcceptedCharacters.None),
Factory.Code(" ")
.AsFunctionsBody(),
.AsFunctionsBody()
.AutoCompleteWith(autoCompleteString: null),
Factory.MetaCode("}")
.Accepts(AcceptedCharacters.None)));
}

View File

@ -57,7 +57,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
ParseBlockTest("{}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().AsStatement(),
Factory.EmptyCSharp()
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
));
}
@ -82,7 +84,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(Environment.NewLine + " ").AsStatement(),
Factory.Code(Environment.NewLine + " ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.EmptyCSharp()
@ -101,7 +105,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
+ " @",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(Environment.NewLine + " ").AsStatement(),
Factory.Code(Environment.NewLine + " ")
.AsStatement()
.AutoCompleteWith("}"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.EmptyCSharp()
@ -247,8 +253,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
ParseBlockTest("{ var foo = bar; if(foo != null) { bar(); } ",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" var foo = bar; if(foo != null) { bar(); } ").AsStatement()
),
Factory.Code(" var foo = bar; if(foo != null) { bar(); } ")
.AsStatement()
.AutoCompleteWith("}")),
new RazorError(
RazorResources.FormatParseError_Expected_EndOfBlock_Before_EOF(RazorResources.BlockName_Code, '}', '{'),
SourceLocation.Zero));
@ -260,8 +267,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
ParseBlockTest("functions { var foo = bar; if(foo != null) { bar(); } ",
new FunctionsBlock(
Factory.MetaCode("functions {").Accepts(AcceptedCharacters.None),
Factory.Code(" var foo = bar; if(foo != null) { bar(); } ").AsFunctionsBody()
),
Factory.Code(" var foo = bar; if(foo != null) { bar(); } ")
.AsFunctionsBody()
.AutoCompleteWith("}")),
new RazorError(
RazorResources.FormatParseError_Expected_EndOfBlock_Before_EOF("functions", '}', '{'),
SourceLocation.Zero));
@ -592,7 +600,8 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code("string.Format(")
.AsStatement(),
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new MarkupBlock(
BlockFactory.MarkupTagBlock("<html>", AcceptedCharacters.None),
BlockFactory.MarkupTagBlock("</html>", AcceptedCharacters.None)),

View File

@ -122,7 +122,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
new StatementBlock(
Factory.CodeTransition(),
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(Environment.NewLine).AsStatement(),
Factory.Code(Environment.NewLine)
.AsStatement()
.AutoCompleteWith("}"),
new MarkupBlock(
Factory.Markup(" "),
new MarkupTagBlock(
@ -158,7 +160,8 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.CodeTransition(),
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp()
.AsStatement(),
.AsStatement()
.AutoCompleteWith("}"),
new CommentBlock(
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None),

View File

@ -53,7 +53,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
ParseBlockTest("{ using Foo.Bar.Baz; var foo = bar; }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" using Foo.Bar.Baz; var foo = bar; ").AsStatement(),
Factory.Code(" using Foo.Bar.Baz; var foo = bar; ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
),
new RazorError(
@ -67,7 +69,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
ParseBlockTest("{ using Foo = Bar.Baz; var foo = bar; }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" using Foo = Bar.Baz; var foo = bar; ").AsStatement(),
Factory.Code(" using Foo = Bar.Baz; var foo = bar; ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
),
new RazorError(
@ -81,7 +85,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
ParseBlockTest("{ functions Foo; }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" functions Foo; ").AsStatement(),
Factory.Code(" functions Foo; ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
));
}
@ -94,7 +100,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code($"{Environment.NewLine} List<dynamic> photos = gallery.Photo.ToList();{Environment.NewLine}").AsStatement(),
Factory.Code($"{Environment.NewLine} List<dynamic> photos = gallery.Photo.ToList();{Environment.NewLine}")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
));
}
@ -109,7 +117,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
ParseBlockTest("{" + code + "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(code).AsStatement(),
Factory.Code(code)
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
));
}
@ -136,7 +146,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
ParseBlockTest("functions {" + code + "} zoop",
new FunctionsBlock(
Factory.MetaCode("functions {").Accepts(AcceptedCharacters.None),
Factory.Code(code).AsFunctionsBody(),
Factory.Code(code)
.AsFunctionsBody()
.AutoCompleteWith(autoCompleteString: null),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
));
}
@ -147,7 +159,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
ParseBlockTest("functions { { { { { } zoop",
new FunctionsBlock(
Factory.MetaCode("functions {").Accepts(AcceptedCharacters.None),
Factory.Code(" { { { { } zoop").AsFunctionsBody()
Factory.Code(" { { { { } zoop")
.AsFunctionsBody()
.AutoCompleteWith("}")
),
new RazorError(
RazorResources.FormatParseError_Expected_EndOfBlock_Before_EOF("functions", "}", "{"),

View File

@ -82,7 +82,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
+ "; }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" var foo = ").AsStatement(),
Factory.Code(" var foo = ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new TemplateBlock(
new MarkupBlock(
Factory.MarkupTransition(),
@ -104,7 +106,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code("i").AsStatement(),
Factory.Code("i")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new TemplateBlock(
new MarkupBlock(
Factory.MarkupTransition(),
@ -210,7 +214,8 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
ParseBlockTest("foreach(foo in Bar) { Html.ExecuteTemplate(foo," + TestNestedTemplateCode + "); }",
new StatementBlock(
Factory.Code("foreach(foo in Bar) { Html.ExecuteTemplate(foo, ").AsStatement(),
Factory.Code("foreach(foo in Bar) { Html.ExecuteTemplate(foo, ")
.AsStatement(),
TestNestedTemplate(),
Factory.Code("); }")
.AsStatement()
@ -225,7 +230,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
ParseBlockTest("{ var foo = bar; Html.ExecuteTemplate(foo," + TestTemplateCode + "); }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" var foo = bar; Html.ExecuteTemplate(foo, ").AsStatement(),
Factory.Code(" var foo = bar; Html.ExecuteTemplate(foo, ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
TestTemplate(),
Factory.Code("); ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
@ -238,7 +245,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
ParseBlockTest("{ var foo = bar; Html.ExecuteTemplate(foo," + TestTemplateCode + "," + TestTemplateCode + "); }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" var foo = bar; Html.ExecuteTemplate(foo, ").AsStatement(),
Factory.Code(" var foo = bar; Html.ExecuteTemplate(foo, ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
TestTemplate(),
Factory.Code(", ").AsStatement(),
TestTemplate(),
@ -253,7 +262,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
ParseBlockTest("{ var foo = bar; Html.ExecuteTemplate(foo," + TestNestedTemplateCode + "); }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" var foo = bar; Html.ExecuteTemplate(foo, ").AsStatement(),
Factory.Code(" var foo = bar; Html.ExecuteTemplate(foo, ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
TestNestedTemplate(),
Factory.Code("); ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)

View File

@ -19,7 +19,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
ParseBlockTest("{ List< }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" List< ").AsStatement(),
Factory.Code(" List< ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)));
}
@ -77,7 +79,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(Environment.NewLine + " ").AsStatement(),
Factory.Code(Environment.NewLine + " ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new MarkupBlock(
new MarkupTagBlock(
Factory.Markup("<p>").Accepts(AcceptedCharacters.None)),
@ -98,7 +102,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(Environment.NewLine + " ").AsStatement(),
Factory.Code(Environment.NewLine + " ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new MarkupBlock(
Factory.MarkupTransition(),
new MarkupTagBlock(
@ -122,7 +128,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(Environment.NewLine + " ").AsStatement(),
Factory.Code(Environment.NewLine + " ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new MarkupBlock(
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
@ -152,13 +160,15 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
new StatementBlock(
Factory.CodeTransition(),
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().AsStatement(),
Factory.EmptyCSharp()
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
),
Factory.Markup(Environment.NewLine)
.With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString, AcceptedCharacters.None))
)
),
.Accepts(AcceptedCharacters.None)
)
),
Factory.Code(")")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)
@ -291,7 +301,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
ParseBlockTest("{ if(foo) { <p>Bar</p> } else if(bar) { <p>Baz</p> } else { <p>Boz</p> } }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" if(foo) {").AsStatement(),
Factory.Code(" if(foo) {")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new MarkupBlock(
Factory.Markup(" "),
new MarkupTagBlock(
@ -421,7 +433,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
+ "} }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code($" switch(foo) {{{Environment.NewLine} case 0:{Environment.NewLine}").AsStatement(),
Factory.Code($" switch(foo) {{{Environment.NewLine} case 0:{Environment.NewLine}")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new MarkupBlock(
Factory.Markup(" "),
new MarkupTagBlock(
@ -501,7 +515,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
ParseBlockTest("{ for(int i = 0; i < 10; i++) { <p>Foo</p> } }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" for(int i = 0; i < 10; i++) {").AsStatement(),
Factory.Code(" for(int i = 0; i < 10; i++) {")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new MarkupBlock(
Factory.Markup(" "),
new MarkupTagBlock(
@ -541,12 +557,15 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
+ "} } zoop",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" if(foo) {").AsStatement(),
Factory.Code(" if(foo) {")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup("Bar" + Environment.NewLine).Accepts(AcceptedCharacters.None)
.With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString, AcceptedCharacters.None))
),
Factory.Code("} ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)));
@ -576,7 +595,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
ParseBlockTest("{ if (i > 0) { <text>;</text> } }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" if (i > 0) {").AsStatement(),
Factory.Code(" if (i > 0) {")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new MarkupBlock(
Factory.Markup(" "),
new MarkupTagBlock(
@ -606,7 +627,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code($"{Environment.NewLine} if(true) {{{Environment.NewLine}").AsStatement(),
Factory.Code($"{Environment.NewLine} if(true) {{{Environment.NewLine}")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition(),

View File

@ -21,7 +21,8 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.MetaCode("{")
.Accepts(AcceptedCharacters.None),
Factory.Code(" foo(); ")
.AsStatement(),
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
Factory.MetaCode("}")
.Accepts(AcceptedCharacters.None)
));
@ -33,7 +34,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
ParseBlockTest("{@}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().AsStatement(),
Factory.EmptyCSharp()
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.EmptyCSharp().AsImplicitExpression(KeywordSet, acceptTrailingDot: true).Accepts(AcceptedCharacters.NonWhiteSpace)
@ -53,7 +56,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
ParseBlockTest("{@.}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().AsStatement(),
Factory.EmptyCSharp()
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.EmptyCSharp().AsImplicitExpression(KeywordSet, acceptTrailingDot: true).Accepts(AcceptedCharacters.NonWhiteSpace)
@ -75,7 +80,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(Environment.NewLine + " ").AsStatement(),
Factory.Code(Environment.NewLine + " ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.EmptyCSharp().AsImplicitExpression(KeywordSet, acceptTrailingDot: true).Accepts(AcceptedCharacters.NonWhiteSpace)
@ -94,7 +101,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().AsStatement(),
Factory.EmptyCSharp()
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo.").AsImplicitExpression(KeywordSet, acceptTrailingDot: true).Accepts(AcceptedCharacters.NonWhiteSpace)),
@ -109,7 +118,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().AsStatement(),
Factory.EmptyCSharp()
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo.").AsImplicitExpression(KeywordSet, acceptTrailingDot: true).Accepts(AcceptedCharacters.NonWhiteSpace)),

View File

@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Editor;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
@ -20,7 +22,10 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.MarkupTransition()
.Accepts(AcceptedCharacters.None),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup(" "),
Factory.Markup(" ")
.With(new SingleLineMarkupEditHandler(
CSharpLanguageCharacteristics.Instance.TokenizeString,
AcceptedCharacters.Any)),
new StatementBlock(
Factory.CodeTransition()
.Accepts(AcceptedCharacters.None),

View File

@ -36,7 +36,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.Html
new StatementBlock(
Factory.CodeTransition(),
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(Environment.NewLine).AsStatement(),
Factory.Code(Environment.NewLine)
.AsStatement()
.AutoCompleteWith("}"),
new MarkupBlock(
new MarkupTagBlock(
Factory.Markup("<"))))),
@ -56,7 +58,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.Html
new StatementBlock(
Factory.CodeTransition(),
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(Environment.NewLine).AsStatement(),
Factory.Code(Environment.NewLine)
.AsStatement()
.AutoCompleteWith("}"),
new MarkupBlock(
new MarkupTagBlock(
Factory.Markup("<" + Environment.NewLine))

View File

@ -257,7 +257,8 @@ namespace Microsoft.AspNet.Razor.Test.Parser.Html
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("Foo"),
Factory.CodeTransition(),
Factory.MetaCode("section Foo {"),
Factory.MetaCode("section Foo {")
.AutoCompleteWith(autoCompleteString: null, atEndOfSpan: true),
new MarkupBlock(
Factory.Markup(" "),
BlockFactory.MarkupTagBlock("<script>"),

View File

@ -107,7 +107,7 @@ namespace Microsoft.AspNet.Razor.Test.Parser.Html
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup(" Baz" + Environment.NewLine)
.With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString, AcceptedCharacters.None))));
.Accepts(AcceptedCharacters.None)));
}
[Fact]

View File

@ -50,7 +50,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.PartialParsing
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("{").Accepts(AcceptedCharacters.None),
factory.Code(Environment.NewLine + " ").AsStatement(),
factory.Code(Environment.NewLine + " ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("DateTime..Now")
@ -106,7 +108,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.PartialParsing
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("{").Accepts(AcceptedCharacters.None),
factory.Code(Environment.NewLine + " ").AsStatement(),
factory.Code(Environment.NewLine + " ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code(expectedCode)
@ -166,7 +170,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.PartialParsing
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("{").Accepts(AcceptedCharacters.None),
factory.Code(Environment.NewLine + " ").AsStatement(),
factory.Code(Environment.NewLine + " ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code(expectedCode)
@ -352,7 +358,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.PartialParsing
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("{").Accepts(AcceptedCharacters.None),
factory.Code(Environment.NewLine + " ").AsStatement(),
factory.Code(Environment.NewLine + " ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("food")
@ -379,7 +387,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.PartialParsing
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("{").Accepts(AcceptedCharacters.None),
factory.Code(Environment.NewLine + " ").AsStatement(),
factory.Code(Environment.NewLine + " ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("foo.d")
@ -406,7 +416,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.PartialParsing
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("{").Accepts(AcceptedCharacters.None),
factory.Code(Environment.NewLine + " ").AsStatement(),
factory.Code(Environment.NewLine + " ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code(@"foo.")
@ -536,7 +548,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.PartialParsing
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("{").Accepts(AcceptedCharacters.None),
factory.EmptyCSharp().AsStatement(),
factory.EmptyCSharp()
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("foo.b")
@ -559,7 +573,9 @@ namespace Microsoft.AspNet.Razor.Test.Parser.PartialParsing
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("{").Accepts(AcceptedCharacters.None),
factory.EmptyCSharp().AsStatement(),
factory.EmptyCSharp()
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("foo.")

View File

@ -41,13 +41,15 @@ namespace Microsoft.AspNet.Razor
Assert.Equal(characterIndex, sourceLocation.CharacterIndex);
}
[Fact]
public void GetHashCode_ReturnsHashCode_UsingAbsoluteIndex()
[Theory]
[InlineData(null)]
[InlineData("some-file")]
public void GetHashCode_ReturnsSameValue_WhenEqual(string path)
{
// Arrange
var sourceLocationA = new SourceLocation(10, 3, 4);
var sourceLocationB = new SourceLocation(10, 45, 8754);
var sourceLocationC = new SourceLocation(12, 45, 8754);
var sourceLocationA = new SourceLocation(path, 10, 3, 4);
var sourceLocationB = new SourceLocation(path, 10, 3, 4);
var sourceLocationC = new SourceLocation(path, 10, 45, 8754);
// Act
var hashCodeA = sourceLocationA.GetHashCode();
@ -56,29 +58,11 @@ namespace Microsoft.AspNet.Razor
// Assert
Assert.Equal(hashCodeA, hashCodeB);
Assert.NotEqual(hashCodeA, hashCodeC);
Assert.Equal(hashCodeA, hashCodeC);
}
[Fact]
public void GetHashCode_ReturnsHashCode_UsingFilePathAndAbsoluteIndex_WhenFilePathIsNonNull()
{
// Arrange
var sourceLocationA = new SourceLocation("some-path", 3, 53, 94);
var sourceLocationB = new SourceLocation("some-path", 3, 43, 87);
var sourceLocationC = new SourceLocation(3, 53, 94);
// Act
var hashCodeA = sourceLocationA.GetHashCode();
var hashCodeB = sourceLocationB.GetHashCode();
var hashCodeC = sourceLocationC.GetHashCode();
// Assert
Assert.Equal(hashCodeA, hashCodeB);
Assert.NotEqual(hashCodeA, hashCodeC);
}
[Fact]
public void Equal_ReturnsFalse_IfIndexesDiffer()
public void Equals_ReturnsTrue_FilePathsNullAndAbsoluteIndicesMatch()
{
// Arrange
var sourceLocationA = new SourceLocation(10, 3, 4);
@ -88,11 +72,11 @@ namespace Microsoft.AspNet.Razor
var result = sourceLocationA.Equals(sourceLocationB);
// Assert
Assert.False(result);
Assert.True(result);
}
[Fact]
public void Equal_ReturnsFalse_IfFilePathIsDifferent()
public void Equals_ReturnsFalse_IfFilePathIsDifferent()
{
// Arrange
var sourceLocationA = new SourceLocation(10, 3, 4);
@ -108,7 +92,7 @@ namespace Microsoft.AspNet.Razor
[Theory]
[InlineData(null)]
[InlineData("some-file")]
public void Equal_ReturnsTrue_IfFilePathAndIndexesAreSame(string path)
public void Equals_ReturnsTrue_IfFilePathAndIndexesAreSame(string path)
{
// Arrange
var sourceLocationA = new SourceLocation(path, 10, 3, 4);