Removing superfluous types and methods from Common.

This commit is contained in:
Pranav K 2015-05-07 14:27:52 -07:00
parent 61b76fd99f
commit 320507604a
50 changed files with 295 additions and 388 deletions

View File

@ -2,7 +2,6 @@
"version": "1.0.0-*",
"dependencies": {
"Microsoft.AspNet.Http.Extensions": "1.0.0-*",
"Microsoft.AspNet.Mvc.Common": { "version": "6.0.0-*", "type": "build" },
"Microsoft.Framework.NotNullAttribute.Sources": { "version": "1.0.0-*", "type": "build" },
"Microsoft.Framework.PropertyHelper.Sources": { "version": "1.0.0-*", "type": "build" },
"Newtonsoft.Json": "6.0.6"
@ -12,7 +11,6 @@
"dnxcore50": {
"dependencies": {
"Microsoft.CSharp": "4.0.0-beta-*",
"System.Collections": "4.0.10-beta-*",
"System.Collections.Concurrent": "4.0.10-beta-*",
"System.ComponentModel.TypeConverter": "4.0.0-beta-*",
"System.Globalization": "4.0.10-beta-*",

View File

@ -2,7 +2,10 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
using Microsoft.Framework.Internal;
@ -273,7 +276,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
/// <summary>
/// Gets a collection of metadata items for validators.
/// </summary>
public abstract IReadOnlyList<object> ValidatorMetadata { get;}
public abstract IReadOnlyList<object> ValidatorMetadata { get; }
/// <summary>
/// Gets a value indicating whether <see cref="ModelType"/> is a simple type.
@ -288,7 +291,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{
if (_isComplexType == null)
{
_isComplexType = !TypeHelper.HasStringConverter(ModelType);
_isComplexType = !TypeDescriptor.GetConverter(ModelType).CanConvertFrom(typeof(string));
}
return _isComplexType.Value;
@ -300,7 +303,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
/// </summary>
public bool IsNullableValueType
{
get { return ModelType.IsNullableValueType(); }
get { return TypeHelper.IsNullableValueType(ModelType); }
}
/// <summary>
@ -308,11 +311,22 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
/// </summary>
/// <remarks>
/// A collection type is defined as a <see cref="Type"/> which is assignable to
/// <see cref="System.Collections.IEnumerable"/>, and is not a <see cref="string"/>.
/// <see cref="IEnumerable"/>, and is not a <see cref="string"/>.
/// </remarks>
public bool IsCollectionType
{
get { return TypeHelper.IsCollectionType(ModelType); }
get
{
if (ModelType == typeof(string))
{
// Even though string implements IEnumerable, we don't really think of it
// as a collection for the purposes of model binding.
return false;
}
// We only need to look for IEnumerable, because IEnumerable<T> extends it.
return typeof(IEnumerable).IsAssignableFrom(ModelType);
}
}
/// <summary>
@ -338,4 +352,4 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
/// </summary>
public abstract Action<object, object> PropertySetter { get; }
}
}
}

View File

@ -70,12 +70,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
return UnwrapPossibleArrayType(cultureToUse, value, type);
}
public static bool CanConvertFromString(Type destinationType)
{
return TypeHelper.IsSimpleType(UnwrapNullableType(destinationType)) ||
TypeHelper.HasStringConverter(destinationType);
}
private object UnwrapPossibleArrayType(CultureInfo culture, object value, Type destinationType)
{
// array conversion results in four cases, as below
@ -148,7 +142,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
if (!(canConvertFrom || converter.CanConvertTo(destinationType)))
{
// EnumConverter cannot convert integer, so we verify manually
if (destinationType.IsEnum() && (value is int))
if (destinationType.GetTypeInfo().IsEnum && (value is int))
{
return Enum.ToObject(destinationType, (int)value);
}

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Routing;
@ -361,7 +362,7 @@ namespace Microsoft.AspNet.Mvc.ApiExplorer
// If the method is declared to return IActionResult or a derived class, that information
// isn't valuable to the formatter.
if (typeof(IActionResult).IsAssignableFrom(unwrappedType))
if (typeof(IActionResult).GetTypeInfo().IsAssignableFrom(unwrappedType.GetTypeInfo()))
{
return null;
}

View File

@ -1,20 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.AspNet.Mvc
{
internal static class PlatformHelper
{
private static readonly Lazy<bool> _isMono = new Lazy<bool>(() => Type.GetType("Mono.Runtime") != null);
public static bool IsMono
{
get
{
return _isMono.Value;
}
}
}
}

View File

@ -1,58 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
namespace Microsoft.AspNet.Mvc
{
internal static class StringHelper
{
public static string TrimSpacesAndChars(string value, params char[] chars)
{
if (string.IsNullOrWhiteSpace(value))
{
return string.Empty;
}
if (chars == null || chars.Length == 0)
{
return value.Trim();
}
var firstIndex = 0;
for (; firstIndex < value.Length; firstIndex++)
{
var currentChar = value[firstIndex];
if (!char.IsWhiteSpace(currentChar) && !chars.Any(compareChar => compareChar == currentChar))
{
break;
}
}
// We trimmed all the way
if (firstIndex == value.Length)
{
return string.Empty;
}
var lastIndex = value.Length - 1;
for (; lastIndex > firstIndex; lastIndex--)
{
var currentChar = value[lastIndex];
if (!char.IsWhiteSpace(currentChar) && !chars.Any(compareChar => compareChar == currentChar))
{
break;
}
}
if (firstIndex == 0 && lastIndex == value.Length - 1)
{
return value;
}
else
{
return value.Substring(firstIndex, lastIndex - firstIndex + 1);
}
}
}
}

View File

@ -1,113 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Reflection;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc
{
internal static class TypeExtensions
{
// NOTE: Do not make #105 worse! Do not add new extension methods that conflict w/ .NET 4.5 methods. The
// exising NETFX_CORE || DNXCORE50 methods should go away (soon).
#if NETFX_CORE || DNXCORE50
private static bool EqualTo([NotNull] this Type[] t1, [NotNull] Type[] t2)
{
if (t1.Length != t2.Length)
{
return false;
}
for (var idx = 0; idx < t1.Length; ++idx)
{
if (t1[idx] != t2[idx])
{
return false;
}
}
return true;
}
public static ConstructorInfo GetConstructor([NotNull] this Type type, Type[] types)
{
return type.GetTypeInfo().DeclaredConstructors
.Where(c => c.IsPublic)
.SingleOrDefault(c => c.GetParameters()
.Select(p => p.ParameterType).ToArray().EqualTo(types));
}
#endif
public static Type BaseType([NotNull] this Type type)
{
return type.GetTypeInfo().BaseType;
}
#if NETFX_CORE || DNXCORE50
public static Type[] GetGenericArguments([NotNull] this Type type)
{
return type.GetTypeInfo().GenericTypeArguments;
}
public static Type[] GetInterfaces([NotNull] this Type type)
{
return type.GetTypeInfo().ImplementedInterfaces.ToArray();
}
public static bool IsAssignableFrom([NotNull] this Type type, [NotNull] Type c)
{
return type.GetTypeInfo().IsAssignableFrom(c.GetTypeInfo());
}
#endif
public static bool IsEnum([NotNull] this Type type)
{
return type.GetTypeInfo().IsEnum;
}
public static bool IsGenericType([NotNull] this Type type)
{
return type.GetTypeInfo().IsGenericType;
}
public static bool IsInterface([NotNull] this Type type)
{
return type.GetTypeInfo().IsInterface;
}
public static bool IsValueType([NotNull] this Type type)
{
return type.GetTypeInfo().IsValueType;
}
public static bool IsCompatibleWith([NotNull] this Type type, object value)
{
return (value == null && AllowsNullValue(type)) ||
(value != null && type.GetTypeInfo().IsAssignableFrom(value.GetType().GetTypeInfo()));
}
public static bool IsNullableValueType([NotNull] this Type type)
{
return Nullable.GetUnderlyingType(type) != null;
}
public static bool AllowsNullValue([NotNull] this Type type)
{
return (!type.GetTypeInfo().IsValueType || IsNullableValueType(type));
}
public static Type[] GetTypeArgumentsIfMatch([NotNull] Type closedType, Type matchingOpenType)
{
var closedTypeInfo = closedType.GetTypeInfo();
if (!closedTypeInfo.IsGenericType)
{
return null;
}
var openType = closedType.GetGenericTypeDefinition();
return (matchingOpenType == openType) ? closedTypeInfo.GenericTypeArguments : null;
}
}
}

View File

@ -2,9 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Framework.Internal;
@ -15,12 +15,13 @@ namespace Microsoft.AspNet.Mvc
{
private static readonly Type TaskGenericType = typeof(Task<>);
public static Type GetTaskInnerTypeOrNull([NotNull]Type type)
public static Type GetTaskInnerTypeOrNull([NotNull] Type type)
{
if (type.GetTypeInfo().IsGenericType && !type.GetTypeInfo().IsGenericTypeDefinition)
var typeInfo = type.GetTypeInfo();
if (typeInfo.IsGenericType && !typeInfo.IsGenericTypeDefinition)
{
var genericTypeDefinition = type.GetGenericTypeDefinition();
var genericArguments = type.GetGenericArguments();
var genericTypeDefinition = typeInfo.GetGenericTypeDefinition();
var genericArguments = typeInfo.GenericTypeArguments;
if (genericArguments.Length == 1 && TaskGenericType == genericTypeDefinition)
{
// Only Return if there is a single argument.
@ -75,22 +76,39 @@ namespace Microsoft.AspNet.Mvc
type.Equals(typeof(Uri));
}
public static bool HasStringConverter(Type type)
public static bool IsCompatibleWith([NotNull] Type type, object value)
{
return TypeDescriptor.GetConverter(type).CanConvertFrom(typeof(string));
return (value == null && AllowsNullValue(type)) ||
(value != null && type.GetTypeInfo().IsAssignableFrom(value.GetType().GetTypeInfo()));
}
public static bool IsCollectionType(Type type)
public static bool IsNullableValueType([NotNull] Type type)
{
if (type == typeof(string))
{
// Even though string implements IEnumerable, we don't really think of it
// as a collection for the purposes of model binding.
return false;
}
return Nullable.GetUnderlyingType(type) != null;
}
// We only need to look for IEnumerable, because IEnumerable<T> extends it.
return typeof(IEnumerable).IsAssignableFrom(type);
public static bool AllowsNullValue([NotNull] Type type)
{
return !type.GetTypeInfo().IsValueType || IsNullableValueType(type);
}
public static TypeInfo ExtractGenericInterface([NotNull] Type queryType, Type interfaceType)
{
Func<TypeInfo, bool> matchesInterface =
typeInfo => typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == interfaceType;
var queryTypeInfo = queryType.GetTypeInfo();
if (matchesInterface(queryTypeInfo))
{
return queryTypeInfo;
}
else
{
return queryTypeInfo
.ImplementedInterfaces
.Select(type => type.GetTypeInfo())
.FirstOrDefault(matchesInterface);
}
}
}
}

View File

@ -3,6 +3,7 @@
using System;
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.Framework.DependencyInjection;
@ -40,7 +41,8 @@ namespace Microsoft.AspNet.Mvc
/// </param>
public BindAttribute([NotNull] Type predicateProviderType)
{
if (!typeof(IPropertyBindingPredicateProvider).IsAssignableFrom(predicateProviderType))
if (!typeof(IPropertyBindingPredicateProvider).GetTypeInfo()
.IsAssignableFrom(predicateProviderType.GetTypeInfo()))
{
var message = Resources.FormatPropertyBindingPredicateProvider_WrongType(
predicateProviderType.FullName,

View File

@ -125,7 +125,7 @@ namespace Microsoft.AspNet.Mvc
}
else
{
value = parameterInfo.ParameterType.IsValueType()
value = parameterInfo.ParameterType.GetTypeInfo().IsValueType
? Activator.CreateInstance(parameterInfo.ParameterType)
: null;
}

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
@ -39,8 +40,8 @@ namespace Microsoft.AspNet.Mvc.Core
filterProviders,
inputFormatters,
outputFormatters,
modelBinders,
modelValidatorProviders,
modelBinders,
modelValidatorProviders,
valueProviderFactories,
actionBindingContextAccessor,
loggerFactory,
@ -88,7 +89,7 @@ namespace Microsoft.AspNet.Mvc.Core
}
protected override Task<IDictionary<string, object>> BindActionArgumentsAsync(
ActionContext context,
ActionContext context,
ActionBindingContext bindingContext)
{
return _argumentBinder.BindActionArgumentsAsync(context, bindingContext, Instance);
@ -116,7 +117,8 @@ namespace Microsoft.AspNet.Mvc.Core
// Unwrap potential Task<T> types.
var actualReturnType = TypeHelper.GetTaskInnerTypeOrNull(declaredReturnType) ?? declaredReturnType;
if (actionReturnValue == null && typeof(IActionResult).IsAssignableFrom(actualReturnType))
if (actionReturnValue == null &&
typeof(IActionResult).GetTypeInfo().IsAssignableFrom(actualReturnType.GetTypeInfo()))
{
throw new InvalidOperationException(
Resources.FormatActionResult_ActionReturnValueCannotBeNull(actualReturnType));

View File

@ -128,7 +128,7 @@ namespace Microsoft.AspNet.Mvc
if (propertyHelper.Property.CanWrite && propertyHelper.Property.SetMethod?.IsPublic == true)
{
// Handle settable property. Do not set the property if the type is a non-nullable type.
if (source != null || propertyType.AllowsNullValue())
if (source != null || TypeHelper.AllowsNullValue(propertyType))
{
propertyHelper.SetValue(controller, source);
}

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.Framework.Internal;
@ -94,7 +95,7 @@ namespace Microsoft.AspNet.Mvc
[NotNull] Type filterType,
int order)
{
if (!typeof(IFilter).IsAssignableFrom(filterType))
if (!typeof(IFilter).GetTypeInfo().IsAssignableFrom(filterType.GetTypeInfo()))
{
var message = Resources.FormatTypeMustDeriveFromType(filterType.FullName, typeof(IFilter).FullName);
throw new ArgumentException(message, nameof(filterType));

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using Newtonsoft.Json;
@ -30,7 +31,7 @@ namespace Microsoft.AspNet.Mvc
// With the following settings here, if a value is not present on the wire for value types
// like primitive, struct etc., Json.net's serializer would throw exception which we catch
// and add it to model state.
if (propertyType.IsValueType() && !propertyType.IsNullableValueType())
if (propertyType.GetTypeInfo().IsValueType && !TypeHelper.IsNullableValueType(propertyType))
{
property.Required = Required.AllowNull;
}

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNet.JsonPatch;
using Microsoft.Framework.Internal;
@ -33,8 +34,9 @@ namespace Microsoft.AspNet.Mvc
/// <inheritdoc />
public override bool CanRead(InputFormatterContext context)
{
if (!typeof(IJsonPatchDocument).IsAssignableFrom(context.ModelType) ||
!context.ModelType.IsGenericType())
var modelTypeInfo = context.ModelType.GetTypeInfo();
if (!typeof(IJsonPatchDocument).GetTypeInfo().IsAssignableFrom(modelTypeInfo) ||
!modelTypeInfo.IsGenericType)
{
return false;
}

View File

@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Internal;
@ -29,7 +30,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
if (request.HasFormContentType)
{
var form = await request.ReadFormAsync();
if (bindingContext.ModelType.IsAssignableFrom(form.GetType()))
if (bindingContext.ModelType.GetTypeInfo().IsAssignableFrom(form.GetType().GetTypeInfo()))
{
model = form;
}

View File

@ -69,10 +69,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
private static Type GetKeyValuePairBinder(Type modelType)
{
return ModelBindingHelper.GetPossibleBinderInstanceType(
closedModelType: modelType,
openModelType: typeof(KeyValuePair<,>),
openBinderType: typeof(KeyValuePairModelBinder<,>));
var modelTypeInfo = modelType.GetTypeInfo();
if (modelTypeInfo.IsGenericType &&
modelTypeInfo.GetGenericTypeDefinition() == typeof(KeyValuePair<,>))
{
return typeof(KeyValuePairModelBinder<,>).MakeGenericType(modelTypeInfo.GenericTypeArguments);
}
return null;
}
/// <remarks>

View File

@ -94,13 +94,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
// IsEnum et cetera
var underlyingType = Nullable.GetUnderlyingType(context.Key.ModelType) ?? context.Key.ModelType;
if (underlyingType.IsEnum())
var underlyingTypeInfo = underlyingType.GetTypeInfo();
if (underlyingTypeInfo.IsEnum)
{
// IsEnum
displayMetadata.IsEnum = true;
// IsFlagsEnum
var underlyingTypeInfo = underlyingType.GetTypeInfo();
displayMetadata.IsFlagsEnum =
underlyingTypeInfo.GetCustomAttribute<FlagsAttribute>(inherit: false) != null;

View File

@ -343,7 +343,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
}
else
{
_isRequired = !ModelType.AllowsNullValue();
_isRequired = !TypeHelper.AllowsNullValue(ModelType);
}
}

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
@ -126,7 +127,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
if (propertyHelper.Property.CanWrite &&
propertyHelper.Property.SetMethod?.IsPublic == true &&
!key.ModelType.IsValueType())
!key.ModelType.GetTypeInfo().IsValueType)
{
propertyEntry.PropertySetter = propertyHelper.ValueSetter;
}

View File

@ -511,7 +511,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
return;
}
if (value != null || property.PropertyType.AllowsNullValue())
if (value != null || TypeHelper.AllowsNullValue(property.PropertyType))
{
try
{

View File

@ -12,7 +12,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{
ModelBindingHelper.ValidateBindingContext(bindingContext);
if (!TypeHelper.HasStringConverter(bindingContext.ModelType))
if (bindingContext.ModelMetadata.IsComplexType)
{
// this type cannot be converted
return null;

View File

@ -32,7 +32,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
return null; // the value doesn't exist
}
if (!context.ModelType.IsCompatibleWith(valueProviderResult.RawValue))
if (!TypeHelper.IsCompatibleWith(context.ModelType, valueProviderResult.RawValue))
{
return null; // value is of incompatible type
}

View File

@ -6,6 +6,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using Microsoft.Framework.Internal;
@ -313,7 +314,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
private static Type GetElementType(Type type)
{
Debug.Assert(typeof(IEnumerable).IsAssignableFrom(type));
Debug.Assert(typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()));
if (type.IsArray)
{
return type.GetElementType();
@ -321,7 +322,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
foreach (var implementedInterface in type.GetInterfaces())
{
if (implementedInterface.IsGenericType() &&
if (implementedInterface.GetTypeInfo().IsGenericType &&
implementedInterface.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
return implementedInterface.GetGenericArguments()[0];

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Reflection;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
@ -29,7 +30,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
/// <inheritdoc />
public bool IsTypeExcluded([NotNull] Type propertyType)
{
return ExcludedType.IsAssignableFrom(propertyType);
return ExcludedType.GetTypeInfo().IsAssignableFrom(propertyType.GetTypeInfo());
}
}
}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Reflection;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
@ -44,7 +45,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
return true;
}
return CheckIfTypeNameMatches(type.BaseType());
return CheckIfTypeNameMatches(type.GetTypeInfo().BaseType);
}
}
}

View File

@ -19,7 +19,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
{
Type[] actualTypes;
if (type.IsGenericType() &&
if (type.GetTypeInfo().IsGenericType &&
type.GetGenericTypeDefinition() == typeof(KeyValuePair<,>))
{
actualTypes = type.GenericTypeArguments;

View File

@ -413,7 +413,7 @@ namespace Microsoft.AspNet.Mvc
private static Type GetElementType(Type type)
{
Debug.Assert(typeof(IEnumerable).IsAssignableFrom(type));
Debug.Assert(typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()));
if (type.IsArray)
{
return type.GetElementType();
@ -421,7 +421,7 @@ namespace Microsoft.AspNet.Mvc
foreach (var implementedInterface in type.GetInterfaces())
{
if (implementedInterface.IsGenericType() &&
if (implementedInterface.GetTypeInfo().IsGenericType &&
implementedInterface.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
return implementedInterface.GetGenericArguments()[0];
@ -473,14 +473,6 @@ namespace Microsoft.AspNet.Mvc
return (model is TModel) ? (TModel)model : default(TModel);
}
internal static Type GetPossibleBinderInstanceType(Type closedModelType,
Type openModelType,
Type openBinderType)
{
var typeArguments = TypeExtensions.GetTypeArgumentsIfMatch(closedModelType, openModelType);
return (typeArguments != null) ? openBinderType.MakeGenericType(typeArguments) : null;
}
internal static void ReplaceEmptyStringWithNull(ModelMetadata modelMetadata, ref object model)
{
if (model is string &&

View File

@ -115,7 +115,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
typeInCollection = genericEnumerableType.GenericTypeArguments[0];
}
var typeInCollectionIsNullableValueType = typeInCollection.IsNullableValueType();
var typeInCollectionIsNullableValueType = TypeHelper.IsNullableValueType(typeInCollection);
var oldPrefix = htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix;

View File

@ -76,7 +76,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
typeInCollection = genericEnumerableType.GenericTypeArguments[0];
}
var typeInCollectionIsNullableValueType = typeInCollection.IsNullableValueType();
var typeInCollectionIsNullableValueType = TypeHelper.IsNullableValueType(typeInCollection);
var oldPrefix = viewData.TemplateInfo.HtmlFieldPrefix;
try

View File

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.ModelBinding;
@ -161,6 +162,8 @@ namespace Microsoft.AspNet.Mvc.Rendering.Internal
{
// Not returning type name here for IEnumerable<IFormFile> since we will be returning
// a more specific name, IEnumerableOfIFormFileName.
var fieldTypeInfo = fieldType.GetTypeInfo();
if (typeof(IEnumerable<IFormFile>) != fieldType)
{
yield return fieldType.Name;
@ -174,7 +177,7 @@ namespace Microsoft.AspNet.Mvc.Rendering.Internal
else if (!modelMetadata.IsComplexType)
{
// IsEnum is false for the Enum class itself
if (fieldType.IsEnum())
if (fieldTypeInfo.IsEnum)
{
// Same as fieldType.BaseType.Name in this case
yield return "Enum";
@ -187,12 +190,12 @@ namespace Microsoft.AspNet.Mvc.Rendering.Internal
yield return "String";
yield break;
}
else if (!fieldType.IsInterface())
else if (!fieldTypeInfo.IsInterface)
{
var type = fieldType;
while (true)
{
type = type.BaseType();
type = type.GetTypeInfo().BaseType;
if (type == null || type == typeof(object))
{
break;
@ -202,9 +205,9 @@ namespace Microsoft.AspNet.Mvc.Rendering.Internal
}
}
if (typeof(IEnumerable).IsAssignableFrom(fieldType))
if (typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(fieldTypeInfo))
{
if (typeof(IEnumerable<IFormFile>).IsAssignableFrom(fieldType))
if (typeof(IEnumerable<IFormFile>).GetTypeInfo().IsAssignableFrom(fieldTypeInfo))
{
yield return IEnumerableOfIFormFileName;
@ -217,7 +220,7 @@ namespace Microsoft.AspNet.Mvc.Rendering.Internal
yield return "Collection";
}
else if (typeof(IFormFile) != fieldType && typeof(IFormFile).IsAssignableFrom(fieldType))
else if (typeof(IFormFile) != fieldType && typeof(IFormFile).GetTypeInfo().IsAssignableFrom(fieldTypeInfo))
{
yield return nameof(IFormFile);
}

View File

@ -5,6 +5,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering.Expressions;
@ -372,7 +373,7 @@ namespace Microsoft.AspNet.Mvc
{
// IsCompatibleObject verifies if the value is either an instance of _declaredModelType or (if value is
// null) that _declaredModelType is a nullable type.
var castWillSucceed = _declaredModelType.IsCompatibleWith(value);
var castWillSucceed = TypeHelper.IsCompatibleWith(_declaredModelType, value);
if (!castWillSucceed)
{
string message;

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Reflection;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.Framework.Internal;
@ -19,7 +20,7 @@ namespace Microsoft.AspNet.Mvc
/// <param name="type">The <see cref="IViewEngine"/> type that the descriptor represents.</param>
public ViewEngineDescriptor([NotNull] Type type)
{
if (!typeof(IViewEngine).IsAssignableFrom(type))
if (!typeof(IViewEngine).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
{
var message = Resources.FormatTypeMustDeriveFromType(type.FullName, typeof(IViewEngine).FullName);
throw new ArgumentException(message, nameof(type));

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using Microsoft.AspNet.Mvc.Razor.Host;
using Microsoft.AspNet.Razor;
using Microsoft.AspNet.Razor.Generator;
@ -128,7 +129,7 @@ namespace Microsoft.AspNet.Mvc.Razor
.Substring(typeName.Length);
// ';' is optional
propertyName = StringHelper.TrimSpacesAndChars(propertyName, ';');
propertyName = TrimSpacesAndChars(propertyName, ';');
Span.CodeGenerator = new InjectParameterGenerator(typeName.Trim(), propertyName);
// Output the span and finish the block
@ -140,5 +141,54 @@ namespace Microsoft.AspNet.Mvc.Razor
{
return new ModelCodeGenerator(_baseType, model);
}
// Internal for unit testing
internal static string TrimSpacesAndChars(string value, params char[] chars)
{
if (string.IsNullOrWhiteSpace(value))
{
return string.Empty;
}
if (chars == null || chars.Length == 0)
{
return value.Trim();
}
var firstIndex = 0;
for (; firstIndex < value.Length; firstIndex++)
{
var currentChar = value[firstIndex];
if (!char.IsWhiteSpace(currentChar) && !chars.Any(compareChar => compareChar == currentChar))
{
break;
}
}
// We trimmed all the way
if (firstIndex == value.Length)
{
return string.Empty;
}
var lastIndex = value.Length - 1;
for (; lastIndex > firstIndex; lastIndex--)
{
var currentChar = value[lastIndex];
if (!char.IsWhiteSpace(currentChar) && !chars.Any(compareChar => compareChar == currentChar))
{
break;
}
}
if (firstIndex == 0 && lastIndex == value.Length - 1)
{
return value;
}
else
{
return value.Substring(firstIndex, lastIndex - firstIndex + 1);
}
}
}
}

View File

@ -6,7 +6,6 @@
},
"dependencies": {
"Microsoft.AspNet.FileProviders.Physical": "1.0.0-*",
"Microsoft.AspNet.Mvc.Common": { "version": "6.0.0-*", "type": "build" },
"Microsoft.AspNet.Razor.Runtime": "4.0.0-*",
"Microsoft.Framework.Caching.Memory": "1.0.0-*",
"Microsoft.Framework.PropertyHelper.Sources": { "version": "1.0.0-*", "type": "build" },

View File

@ -12,6 +12,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Internal
public class SymbolsUtility
{
private const string SymWriterGuid = "0AE2DEB0-F901-478b-BB9F-881EE8066788";
private static readonly Lazy<bool> _isMono = new Lazy<bool>(() => Type.GetType("Mono.Runtime") != null);
/// <summary>
/// Determines if the current platform supports symbols (pdb) generation.
@ -19,7 +20,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Internal
/// <returns><c>true</c> if pdb generation is supported; <c>false</c> otherwise.</returns>
public static bool SupportsSymbolsGeneration()
{
if (PlatformHelper.IsMono)
if (_isMono.Value)
{
return false;
}

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.Framework.Internal;
@ -88,7 +89,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
{
if (!context.AllAttributes.ContainsName(attribute) ||
context.AllAttributes[attribute] == null ||
(typeof(string).IsAssignableFrom(context.AllAttributes[attribute].Value.GetType()) &&
(context.AllAttributes[attribute].Value is string &&
string.IsNullOrWhiteSpace(context.AllAttributes[attribute].Value as string)))
{
// Missing attribute!

View File

@ -5,6 +5,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
@ -74,7 +75,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// "SelectExpressionNotEnumerable" InvalidOperationException during generation.
// Metadata.IsCollectionType() is similar but does not take runtime type into account.
var realModelType = For.ModelExplorer.ModelType;
var allowMultiple = typeof(string) != realModelType && typeof(IEnumerable).IsAssignableFrom(realModelType);
var allowMultiple = typeof(string) != realModelType &&
typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(realModelType.GetTypeInfo());
// Ensure GenerateSelect() _never_ looks anything up in ViewData.
var items = Items ?? Enumerable.Empty<SelectListItem>();

View File

@ -5,7 +5,6 @@
"warningsAsErrors": true
},
"dependencies": {
"Microsoft.AspNet.Mvc.Common": { "version": "6.0.0-*", "type": "build" },
"Microsoft.AspNet.Mvc.Razor": "6.0.0-*",
"Microsoft.Framework.Caching.Memory": "1.0.0-*",
"Microsoft.Framework.FileSystemGlobbing": "1.0.0-*",

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web.Http;
using Microsoft.AspNet.Mvc.ApplicationModels;
@ -27,7 +28,7 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
{
// This has a binding behavior configured, just leave it alone.
}
else if (ValueProviderResult.CanConvertFromString(parameter.ParameterInfo.ParameterType))
else if (CanConvertFromString(parameter.ParameterInfo.ParameterType))
{
// Simple types are by-default from the URI.
parameter.BindingInfo = parameter.BindingInfo ?? new BindingInfo();
@ -60,5 +61,12 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
{
return controller.Attributes.OfType<IUseWebApiParameterConventions>().Any();
}
private static bool CanConvertFromString(Type destinationType)
{
destinationType = Nullable.GetUnderlyingType(destinationType) ?? destinationType;
return TypeHelper.IsSimpleType(destinationType) ||
TypeDescriptor.GetConverter(destinationType).CanConvertFrom(typeof(string));
}
}
}

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net.Http.Formatting;
using Microsoft.AspNet.Mvc.ModelBinding;
@ -101,7 +102,7 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
if ((source.CanAcceptDataFrom(BindingSource.Path) ||
source.CanAcceptDataFrom(BindingSource.Query)) &&
ValueProviderResult.CanConvertFromString(parameter.ParameterType))
CanConvertFromString(parameter.ParameterType))
{
if (optionalParameters != null)
{
@ -155,6 +156,13 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
return keys;
}
private static bool CanConvertFromString(Type destinationType)
{
destinationType = Nullable.GetUnderlyingType(destinationType) ?? destinationType;
return TypeHelper.IsSimpleType(destinationType) ||
TypeDescriptor.GetConverter(destinationType).CanConvertFrom(typeof(string));
}
private class OverloadedParameter
{
public ParameterDescriptor ParameterDescriptor { get; set; }

View File

@ -5,7 +5,7 @@
"warningsAsErrors": false
},
"dependencies": {
"Microsoft.AspNet.Mvc.Common": { "version": "6.0.0-*", "type": "build" },
"Microsoft.AspNet.Mvc.Common": { "type": "build", "version": "6.0.0-*" },
"Microsoft.AspNet.Mvc.Core": "6.0.0-*",
"Microsoft.AspNet.WebApi.Client": "5.2.2",
"Microsoft.Framework.PropertyHelper.Sources": { "version": "1.0.0-*", "type": "build" },

View File

@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Mvc.Xml
var enumerableOfT = ClosedGenericMatcher.ExtractGenericInterface(
sourceEnumerableOfT,
typeof(IEnumerable<>));
if (!sourceEnumerableOfT.IsInterface() || enumerableOfT == null)
if (!sourceEnumerableOfT.GetTypeInfo().IsInterface || enumerableOfT == null)
{
throw new ArgumentException(
Resources.FormatEnumerableWrapperProvider_InvalidSourceEnumerableOfT(typeof(IEnumerable<>).Name),

View File

@ -1,8 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.Xml
@ -37,10 +37,11 @@ namespace Microsoft.AspNet.Mvc.Xml
{
// Example: IEnumerable<SerializableError>
var declaredType = context.DeclaredType;
var declaredTypeInfo = declaredType.GetTypeInfo();
// We only wrap interfaces types(ex: IEnumerable<T>, IQueryable<T>, IList<T> etc.) and not
// concrete types like List<T>, Collection<T> which implement IEnumerable<T>.
if (declaredType != null && declaredType.IsInterface() && declaredType.IsGenericType())
if (declaredType != null && declaredTypeInfo.IsInterface && declaredTypeInfo.IsGenericType)
{
var enumerableOfT = ClosedGenericMatcher.ExtractGenericInterface(
declaredType,

View File

@ -87,7 +87,7 @@ namespace Microsoft.AspNet.Mvc.Xml
// is Dictionary<,> which implements IEnumerable<KeyValuePair<TKey, TValue>>) as the model
// type here would be KeyValuePair<TKey, TValue> where Key and Value are public properties
// which would also be probed for Required attribute validation.
if (modelType.IsGenericType())
if (modelType.GetTypeInfo().IsGenericType)
{
var enumerableOfT = ClosedGenericMatcher.ExtractGenericInterface(modelType, typeof(IEnumerable<>));
if (enumerableOfT != null)
@ -125,7 +125,7 @@ namespace Microsoft.AspNet.Mvc.Xml
// Since DefaultObjectValidator can handle Required attribute validation for reference types,
// we only consider value types here.
if (propertyType.IsValueType() && !propertyType.IsNullableValueType())
if (propertyType.GetTypeInfo().IsValueType && !TypeHelper.IsNullableValueType(propertyType))
{
var validationError = GetValidationError(propertyInfo);
if (validationError != null)

View File

@ -8,7 +8,6 @@
"Microsoft.AspNet.Authorization": "1.0.0-*",
"Microsoft.AspNet.Cors": "1.0.0-*",
"Microsoft.AspNet.Mvc.ApiExplorer": "6.0.0-*",
"Microsoft.AspNet.Mvc.Common": { "version": "6.0.0-*", "type": "build" },
"Microsoft.AspNet.Mvc.Razor": "6.0.0-*",
"Microsoft.Framework.Caching.Memory": "1.0.0-*",
"Microsoft.Framework.DependencyInjection": "1.0.0-*",

View File

@ -1,97 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Xunit;
namespace Microsoft.AspNet.Mvc
{
public class StringHelperTest
{
public static TheoryData TrimSpacesAndCharsData
{
get
{
// input, trimCharacters, expectedOutput
return new TheoryData<string, char[], string>
{
{ "abcd", new char[] { }, "abcd" },
{ " /.", new char[] { '/', '.' }, string.Empty },
{ string.Empty, new char[] { }, string.Empty },
{ " ", new char[] { }, string.Empty },
{ " ", new char[] { }, string.Empty },
{ " / ", new char[] { '/' }, string.Empty },
{ " \t ", new char[] { '/' }, string.Empty },
{ " ", new char[] { '/' }, string.Empty },
{ " ", new char[] { '/' }, string.Empty },
{ "/", new char[] { '/' }, string.Empty },
{ "//", new char[] { '/' }, string.Empty },
{ "// ", new char[] { '/' }, string.Empty },
{ "/ ", new char[] { '/' }, string.Empty },
{ " a ", new char[] { }, "a" },
{ " a", new char[] { }, "a" },
{ "a ", new char[] { }, "a" },
{ " a ", new char[] { }, "a" },
{ " a \n\r", new char[] { }, "a" },
{ "\t\r a ", new char[] { }, "a" },
{ "\ta ", new char[] { }, "a" },
{ " a a ", new char[] { }, "a a" },
{ " a ", new char[] { '/' }, "a" },
{ " a", new char[] { '/' }, "a" },
{ "a ", new char[] { '/' }, "a" },
{ " a ", new char[] { '/' }, "a" },
{ " a \n\r", new char[] { '/' }, "a" },
{ "\t\r a ", new char[] { '/' }, "a" },
{ "\ta ", new char[] { '/' }, "a" },
{ " a a ", new char[] { '/' }, "a a" },
{ " a ", new char[] { '/', ' ' }, "a" },
{ " a", new char[] { '/', ' ' }, "a" },
{ "a ", new char[] { '/', ' ' }, "a" },
{ " a ", new char[] { '/', ' ' }, "a" },
{ " a \n\r", new char[] { '/', ' ' }, "a" },
{ "\t\r a ", new char[] { '/', ' ' }, "a" },
{ "\ta ", new char[] { '/', ' ' }, "a" },
{ " a a ", new char[] { '/', ' ' }, "a a" },
{ "/ a ", new char[] { '/' }, "a" },
{ " / a", new char[] { '/' }, "a" },
{ "a / /", new char[] { '/' }, "a" },
{ " a // //", new char[] { '/' }, "a" },
{ " a \n\r//", new char[] { '/' }, "a" },
{ "////\t\r a ", new char[] { '/' }, "a" },
{ "\ta /", new char[] { '/' }, "a" },
{ " a/ a ", new char[] { '/' }, "a/ a" },
{ "/ a ", new char[] { '/', ' ' }, "a" },
{ " / a", new char[] { '/', ' ' }, "a" },
{ "a / /", new char[] { '/', ' ' }, "a" },
{ " a // //", new char[] { '/', ' ' }, "a" },
{ " a \n\r//", new char[] { '/', ' ' }, "a" },
{ "////\t\r a ", new char[] { '/', ' ' }, "a" },
{ "\ta /", new char[] { '/', ' ' }, "a" },
{ " a/ a ", new char[] { '/', ' ' }, "a/ a" },
{ " a /.", new char[] { '/', '.' }, "a" },
{ " a", new char[] { '/', '.' }, "a" },
{ "/. ./a ", new char[] { '/', '.' }, "a" },
{ " a ", new char[] { '/', '.' }, "a" },
{ " a \n\r", new char[] { '/', '.' }, "a" },
{ "\t\r a ", new char[] { '/', '.' }, "a" },
{ "\ta ", new char[] { '/', '.' }, "a" },
{ "///..a/./a /. ./....", new char[] { '/', '.' }, "a/./a" },
};
}
}
[Theory]
[MemberData(nameof(TrimSpacesAndCharsData))]
public void TrimSpacesAndChars_GeneratesExpectedOutput(
string input,
char[] trimCharacters,
string expectedOutput)
{
// Arrange & Act
var output = StringHelper.TrimSpacesAndChars(input, trimCharacters);
// Assert
Assert.Equal(expectedOutput, output, StringComparer.Ordinal);
}
}
}

View File

@ -7,7 +7,7 @@ using Xunit;
namespace Microsoft.AspNet.Mvc
{
public class TypeExtensionsTest
public class TypeHelperTests
{
[Theory]
[InlineData(typeof(decimal))]
@ -15,7 +15,7 @@ namespace Microsoft.AspNet.Mvc
public void IsCompatibleWithReturnsFalse_IfValueTypeIsNull(Type type)
{
// Act
bool result = TypeExtensions.IsCompatibleWith(type, value: null);
bool result = TypeHelper.IsCompatibleWith(type, value: null);
// Assert
Assert.False(result);
@ -28,7 +28,7 @@ namespace Microsoft.AspNet.Mvc
public void IsCompatibleWithReturnsFalse_IfValueIsMismatched(Type type)
{
// Act
bool result = TypeExtensions.IsCompatibleWith(type, value: "Hello world");
bool result = TypeHelper.IsCompatibleWith(type, value: "Hello world");
// Assert
Assert.False(result);
@ -56,7 +56,7 @@ namespace Microsoft.AspNet.Mvc
public void IsCompatibleWithReturnsTrue_IfValueIsAssignable(Type type, object value)
{
// Act
bool result = TypeExtensions.IsCompatibleWith(type, value);
bool result = TypeHelper.IsCompatibleWith(type, value);
// Assert
Assert.True(result);

View File

@ -9,6 +9,7 @@ using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Testing;
using Microsoft.Net.Http.Headers;
using Moq;
using Xunit;
@ -90,7 +91,7 @@ namespace Microsoft.AspNet.Mvc
{
yield return new object[] { 30, 0 };
if (PlatformHelper.IsMono)
if (TestPlatformHelper.IsMono)
{
// The StreamWriter in Mono buffers 2x the buffer size before flushing.
yield return new object[] { ViewResultStreamWriterBufferSize * 2 + 30, ViewResultStreamWriterBufferSize };

View File

@ -177,6 +177,92 @@ namespace Microsoft.AspNet.Mvc.Razor
}
}
public static TheoryData TrimSpacesAndCharsData
{
get
{
// input, trimCharacters, expectedOutput
return new TheoryData<string, char[], string>
{
{ "abcd", new char[] { }, "abcd" },
{ " /.", new char[] { '/', '.' }, string.Empty },
{ string.Empty, new char[] { }, string.Empty },
{ " ", new char[] { }, string.Empty },
{ " ", new char[] { }, string.Empty },
{ " / ", new char[] { '/' }, string.Empty },
{ " \t ", new char[] { '/' }, string.Empty },
{ " ", new char[] { '/' }, string.Empty },
{ " ", new char[] { '/' }, string.Empty },
{ "/", new char[] { '/' }, string.Empty },
{ "//", new char[] { '/' }, string.Empty },
{ "// ", new char[] { '/' }, string.Empty },
{ "/ ", new char[] { '/' }, string.Empty },
{ " a ", new char[] { }, "a" },
{ " a", new char[] { }, "a" },
{ "a ", new char[] { }, "a" },
{ " a ", new char[] { }, "a" },
{ " a \n\r", new char[] { }, "a" },
{ "\t\r a ", new char[] { }, "a" },
{ "\ta ", new char[] { }, "a" },
{ " a a ", new char[] { }, "a a" },
{ " a ", new char[] { '/' }, "a" },
{ " a", new char[] { '/' }, "a" },
{ "a ", new char[] { '/' }, "a" },
{ " a ", new char[] { '/' }, "a" },
{ " a \n\r", new char[] { '/' }, "a" },
{ "\t\r a ", new char[] { '/' }, "a" },
{ "\ta ", new char[] { '/' }, "a" },
{ " a a ", new char[] { '/' }, "a a" },
{ " a ", new char[] { '/', ' ' }, "a" },
{ " a", new char[] { '/', ' ' }, "a" },
{ "a ", new char[] { '/', ' ' }, "a" },
{ " a ", new char[] { '/', ' ' }, "a" },
{ " a \n\r", new char[] { '/', ' ' }, "a" },
{ "\t\r a ", new char[] { '/', ' ' }, "a" },
{ "\ta ", new char[] { '/', ' ' }, "a" },
{ " a a ", new char[] { '/', ' ' }, "a a" },
{ "/ a ", new char[] { '/' }, "a" },
{ " / a", new char[] { '/' }, "a" },
{ "a / /", new char[] { '/' }, "a" },
{ " a // //", new char[] { '/' }, "a" },
{ " a \n\r//", new char[] { '/' }, "a" },
{ "////\t\r a ", new char[] { '/' }, "a" },
{ "\ta /", new char[] { '/' }, "a" },
{ " a/ a ", new char[] { '/' }, "a/ a" },
{ "/ a ", new char[] { '/', ' ' }, "a" },
{ " / a", new char[] { '/', ' ' }, "a" },
{ "a / /", new char[] { '/', ' ' }, "a" },
{ " a // //", new char[] { '/', ' ' }, "a" },
{ " a \n\r//", new char[] { '/', ' ' }, "a" },
{ "////\t\r a ", new char[] { '/', ' ' }, "a" },
{ "\ta /", new char[] { '/', ' ' }, "a" },
{ " a/ a ", new char[] { '/', ' ' }, "a/ a" },
{ " a /.", new char[] { '/', '.' }, "a" },
{ " a", new char[] { '/', '.' }, "a" },
{ "/. ./a ", new char[] { '/', '.' }, "a" },
{ " a ", new char[] { '/', '.' }, "a" },
{ " a \n\r", new char[] { '/', '.' }, "a" },
{ "\t\r a ", new char[] { '/', '.' }, "a" },
{ "\ta ", new char[] { '/', '.' }, "a" },
{ "///..a/./a /. ./....", new char[] { '/', '.' }, "a/./a" },
};
}
}
[Theory]
[MemberData(nameof(TrimSpacesAndCharsData))]
public void TrimSpacesAndChars_GeneratesExpectedOutput(
string input,
char[] trimCharacters,
string expectedOutput)
{
// Arrange & Act
var output = MvcRazorCodeParser.TrimSpacesAndChars(input, trimCharacters);
// Assert
Assert.Equal(expectedOutput, output, StringComparer.Ordinal);
}
private static CodeTree CreateCodeTree(params Chunk[] chunks)
{
return new CodeTree