diff --git a/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml b/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml index e77304762..dd4e87789 100644 --- a/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml +++ b/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml @@ -7668,7 +7668,7 @@ - Looks up a localized string similar to The template string '{0}' of '{1}' is not a valid template literal. And a template literal should wrapper with '{' and '}'.. + Looks up a localized string similar to The template string '{0}' of '{1}' is not a valid template literal. And a template literal should wrapper with '{{' and '}}'.. diff --git a/src/Microsoft.AspNetCore.OData/Properties/SRResources.Designer.cs b/src/Microsoft.AspNetCore.OData/Properties/SRResources.Designer.cs index 822469127..c7474590a 100644 --- a/src/Microsoft.AspNetCore.OData/Properties/SRResources.Designer.cs +++ b/src/Microsoft.AspNetCore.OData/Properties/SRResources.Designer.cs @@ -889,7 +889,7 @@ internal static string InvalidSegmentInSelectExpandPath { } /// - /// Looks up a localized string similar to The template string '{0}' of '{1}' is not a valid template literal. And a template literal should wrapper with '{' and '}'.. + /// Looks up a localized string similar to The template string '{0}' of '{1}' is not a valid template literal. And a template literal should wrapper with '{{' and '}}'.. /// internal static string InvalidTemplateLiteral { get { @@ -1841,7 +1841,7 @@ internal static string TypeMustBeRelated { return ResourceManager.GetString("TypeMustBeRelated", resourceCulture); } } - + /// /// Looks up a localized string similar to '{0}' is not a resource set type. Only resource set are supported.. /// @@ -1850,7 +1850,7 @@ internal static string TypeMustBeResourceSet { return ResourceManager.GetString("TypeMustBeResourceSet", resourceCulture); } } - + /// /// Looks up a localized string similar to The type '{0}' does not implement '{1}' interface.. /// @@ -1859,7 +1859,7 @@ internal static string TypeMustImplementInterface { return ResourceManager.GetString("TypeMustImplementInterface", resourceCulture); } } - + /// /// Looks up a localized string similar to The type '{0}' does not inherit from '{1}'.. /// @@ -1868,7 +1868,7 @@ internal static string TypeMustInheritFromType { return ResourceManager.GetString("TypeMustInheritFromType", resourceCulture); } } - + /// /// Looks up a localized string similar to The type '{0}' of dynamic property '{1}' is not supported.. /// diff --git a/src/Microsoft.AspNetCore.OData/Properties/SRResources.resx b/src/Microsoft.AspNetCore.OData/Properties/SRResources.resx index e41cf3321..df3e78414 100644 --- a/src/Microsoft.AspNetCore.OData/Properties/SRResources.resx +++ b/src/Microsoft.AspNetCore.OData/Properties/SRResources.resx @@ -667,7 +667,7 @@ Cannot Get the Enum Clr member using '{0}'. - The template string '{0}' of '{1}' is not a valid template literal. And a template literal should wrapper with '{' and '}'. + The template string '{0}' of '{1}' is not a valid template literal. And a template literal should wrapper with '{{' and '}}'. Missing the parameter alias '{0}' in the request query string. diff --git a/test/Microsoft.AspNetCore.OData.Tests/Resources/SRResourcesTests.cs b/test/Microsoft.AspNetCore.OData.Tests/Resources/SRResourcesTests.cs new file mode 100644 index 000000000..9af61d278 --- /dev/null +++ b/test/Microsoft.AspNetCore.OData.Tests/Resources/SRResourcesTests.cs @@ -0,0 +1,251 @@ +//----------------------------------------------------------------------------- +// +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// See License.txt in the project root for license information. +// +//------------------------------------------------------------------------------ + +using System.Linq; +using System.Text.RegularExpressions; +using Xunit; + +namespace Microsoft.AspNetCore.OData.Tests.Resources; + +public class SRResourcesTests +{ + [Theory] + [InlineData("ActionContextMustHaveDescriptor", new object[] { })] + [InlineData("ActionDescriptorNotControllerActionDescriptor", new object[] { })] + [InlineData("ActionExecutedContextMustHaveRequest", new object[] { })] + [InlineData("ActionNotBoundToCollectionOfEntity", new object[] { "arg1" })] + [InlineData("ActionNotBoundToEntity", new object[] { "arg1" })] + [InlineData("AggregateKindNotSupported", new object[] { "arg1" })] + [InlineData("AggregationMethodNotSupported", new object[] { "arg1" })] + [InlineData("AggregationNotSupportedForType", new object[] { "arg1", "arg2", "arg3" })] + [InlineData("AmbiguousNavigationSourceNameFound", new object[] { "arg1" })] + [InlineData("AmbiguousPropertyNameFound", new object[] { "arg1" })] + [InlineData("AmbiguousTypeNameFound", new object[] { "arg1" })] + [InlineData("ApplyQueryOptionNotSupportedForLinq2SQL", new object[] { })] + [InlineData("ApplyToOnUntypedQueryOption", new object[] { "arg1" })] + [InlineData("ArgumentMustBeGreaterThanOrEqualTo", new object[] { "arg1" })] + [InlineData("ArgumentMustBeLessThanOrEqualTo", new object[] { "arg1" })] + [InlineData("ArgumentMustBeOfType", new object[] { "arg1" })] + [InlineData("ArgumentNullOrEmpty", new object[] { "arg1" })] + [InlineData("BatchRequestInvalidMediaType", new object[] { "arg1", "arg2" })] + [InlineData("BatchRequestMissingBody", new object[] { })] + [InlineData("BatchRequestMissingBoundary", new object[] { })] + [InlineData("BatchRequestMissingContentType", new object[] { })] + [InlineData("BinaryOperatorNotSupported", new object[] { "arg1", "arg2", "arg3" })] + [InlineData("CannotAddToNullCollection", new object[] { "arg1", "arg2" })] + [InlineData("CannotApplyETagOfT", new object[] { "arg1", "arg2", "arg3", "arg4" })] + [InlineData("CannotApplyODataQueryOptionsOfT", new object[] { "arg1", "arg2", "arg3", "arg4" })] + [InlineData("CannotCastFilter", new object[] { "arg1", "arg2" })] + [InlineData("CannotDeserializeUnknownProperty", new object[] { "arg1", "arg2" })] + [InlineData("CannotFindKeyInEntityType", new object[] { "arg1", "arg2" })] + [InlineData("CannotFindParameterInOperation", new object[] { "arg1", "arg2" })] + [InlineData("CannotGetEnumClrMember", new object[] { "arg1" })] + [InlineData("CannotInstantiateAbstractResourceType", new object[] { "arg1" })] + [InlineData("CannotParseQueryRequestPayload", new object[] { })] + [InlineData("CannotPatchNavigationProperties", new object[] { "arg1", "arg2" })] + [InlineData("CannotProcessPrefixTemplate", new object[] { "arg1" })] + [InlineData("CannotSerializerNull", new object[] { "arg1" })] + [InlineData("CannotSetDynamicPropertyDictionary", new object[] { "arg1", "arg2" })] + [InlineData("CannotWriteType", new object[] { "arg1", "arg2" })] + [InlineData("ClrTypeNotInModel", new object[] { "arg1" })] + [InlineData("CollectionParameterShouldHaveAddMethod", new object[] { "arg1", "arg2" })] + [InlineData("CollectionShouldHaveAddMethod", new object[] { "arg1", "arg2", "arg3" })] + [InlineData("CollectionShouldHaveClearMethod", new object[] { "arg1", "arg2", "arg3" })] + [InlineData("ConvertToEnumFailed", new object[] { "arg1", "arg2" })] + [InlineData("CreateODataValueNotSupported", new object[] { "arg1" })] + [InlineData("CustomQueryOptionNotSupportedWithDollarSign", new object[] { "arg1" })] + [InlineData("DeltaEntityTypeNotAssignable", new object[] { "arg1", "arg2" })] + [InlineData("DeltaNestedResourceNameNotFound", new object[] { "arg1", "arg2" })] + [InlineData("DeltaTypeMismatch", new object[] { "arg1", "arg2" })] + [InlineData("DeserializerDoesNotSupportRead", new object[] { "arg1" })] + [InlineData("DoesNotSupportReadInLine", new object[] { "arg1" })] + [InlineData("DuplicateDynamicPropertyNameFound", new object[] { "arg1", "arg2" })] + [InlineData("DynamicPropertyCannotBeSerialized", new object[] { "arg1", "arg2" })] + [InlineData("DynamicPropertyNameAlreadyUsedAsDeclaredPropertyName", new object[] { "arg1", "arg2" })] + [InlineData("DynamicResourceSetTypeNameIsRequired", new object[] { "arg1" })] + [InlineData("EditLinkNullForLocationHeader", new object[] { "arg1" })] + [InlineData("EdmComplexObjectNullRef", new object[] { "arg1", "arg2" })] + [InlineData("EdmObjectNull", new object[] { "arg1" })] + [InlineData("EdmTypeCannotBeNull", new object[] { "arg1", "arg2" })] + [InlineData("EdmTypeNotSupported", new object[] { "arg1" })] + [InlineData("ElementClrTypeNull", new object[] { "arg1" })] + [InlineData("EmptyKeyTemplate", new object[] { "arg1", "arg2" })] + [InlineData("EmptyParameterAlias", new object[] { "arg1", "arg2" })] + [InlineData("EmptyPathTemplate", new object[] { "arg1" })] + [InlineData("EntityReferenceMustHasKeySegment", new object[] { "arg1" })] + [InlineData("EntityTypeMismatch", new object[] { "arg1", "arg2" })] + [InlineData("ErrorTypeMustBeODataErrorOrHttpError", new object[] { "arg1" })] + [InlineData("ETagNotWellFormed", new object[] { })] + [InlineData("ExpandFilterExpressionNotLambdaExpression", new object[] { "arg1", "arg2" })] + [InlineData("ExpressionLexer_UnbalancedBracketExpression", new object[] { "arg1", "arg2" })] + [InlineData("ExpressionLexerSyntaxError", new object[] { "arg1", "arg2" })] + [InlineData("ExpressionLexerUnterminatedStringLiteral", new object[] { "arg1", "arg2" })] + [InlineData("FailedToBuildEdmModelBecauseReturnTypeIsNull", new object[] { "arg1", "arg2" })] + [InlineData("FailedToRetrieveTypeToBuildEdmModel", new object[] { "arg1", "arg2", "arg3" })] + [InlineData("FormatterReadIsNotSupportedForType", new object[] { "arg1", "arg2" })] + [InlineData("FunctionNotBoundToCollectionOfEntity", new object[] { "arg1" })] + [InlineData("FunctionNotBoundToEntity", new object[] { "arg1" })] + [InlineData("FunctionNotSupportedOnEnum", new object[] { "arg1" })] + [InlineData("GetOnlyCollectionCannotBeArray", new object[] { "arg1", "arg2" })] + [InlineData("IdLinkNullForEntityIdHeader", new object[] { "arg1" })] + [InlineData("InfiniteParameterAlias", new object[] { "arg1" })] + [InlineData("InputCastTypeKindNotMatch", new object[] { "arg1", "arg2" })] + [InlineData("InputKeyNotMatchEntityTypeKey", new object[] { "arg1", "arg2", "arg3" })] + [InlineData("InvalidAttributeRoutingTemplateSegment", new object[] { "arg1" })] + [InlineData("InvalidBatchReaderState", new object[] { "arg1", "arg2" })] + [InlineData("InvalidExpansionDepthValue", new object[] { "arg1", "arg2" })] + [InlineData("InvalidKeyInUriFound", new object[] { "arg1", "arg2" })] + [InlineData("InvalidLastSegmentInSelectExpandPath", new object[] { "arg1" })] + [InlineData("InvalidODataRouteOnAction", new object[] { "arg1", "arg2", "arg3", "arg4" })] + [InlineData("InvalidODataUntypedValue", new object[] { "arg1" })] + [InlineData("InvalidParameterValueInUriFound", new object[] { "arg1", "arg2" })] + [InlineData("InvalidPropertyMapper", new object[] { "arg1", "arg2" })] + [InlineData("InvalidPropertyMapping", new object[] { "arg1" })] + [InlineData("InvalidSegmentInSelectExpandPath", new object[] { "arg1" })] + [InlineData("InvalidTemplateLiteral", new object[] { "arg1", "arg2" })] + [InlineData("JsonConverterDoesnotSupportRead", new object[] { "arg1" })] + [InlineData("KeyTemplateMustBeInCurlyBraces", new object[] { "arg1", "arg2" })] + [InlineData("KeyValueCannotBeNull", new object[] { "arg1", "arg2" })] + [InlineData("MappingDoesNotContainResourceType", new object[] { "arg1" })] + [InlineData("MaxAnyAllExpressionLimitExceeded", new object[] { "arg1", "arg2" })] + [InlineData("MaxExpandDepthExceeded", new object[] { "arg1", "arg2" })] + [InlineData("MaxNodeLimitExceeded", new object[] { "arg1", "arg2" })] + [InlineData("MissingNonODataContainer", new object[] { })] + [InlineData("MissingNonStandardTypeSupportFor", new object[] { "arg1" })] + [InlineData("MissingODataContainer", new object[] { "arg1" })] + [InlineData("MissingODataServices", new object[] { "arg1" })] + [InlineData("MissingParameterAlias", new object[] { "arg1" })] + [InlineData("MissingRequiredParameterInOperation", new object[] { "arg1", "arg2" })] + [InlineData("ModelBinderUtil_ModelMetadataCannotBeNull", new object[] { })] + [InlineData("ModelBinderUtil_ValueCannotBeEnum", new object[] { "arg1", "arg2" })] + [InlineData("ModelBindingContextMustHaveRequest", new object[] { })] + [InlineData("ModelMissingFromReadContext", new object[] { })] + [InlineData("ModelPrefixAlreadyUsed", new object[] { "arg1" })] + [InlineData("MultipleActionImportFound", new object[] { "arg1" })] + [InlineData("MultipleMatchingClrTypesForEdmType", new object[] { "arg1", "arg2" })] + [InlineData("MultipleSingleLiteralNotAllowed", new object[] { "arg1" })] + [InlineData("NavigationSourceMissingDuringDeserialization", new object[] { })] + [InlineData("NavigationSourceMissingDuringSerialization", new object[] { })] + [InlineData("NestedCollectionsNotSupported", new object[] { "arg1" })] + [InlineData("NestedPropertyNotfound", new object[] { "arg1", "arg2" })] + [InlineData("NonSelectExpandOnSingleEntity", new object[] { })] + [InlineData("NotAllowedArithmeticOperator", new object[] { "arg1", "arg2" })] + [InlineData("NotAllowedFunction", new object[] { "arg1", "arg2" })] + [InlineData("NotAllowedLogicalOperator", new object[] { "arg1", "arg2" })] + [InlineData("NotAllowedOrderByProperty", new object[] { "arg1", "arg2" })] + [InlineData("NotAllowedQueryOption", new object[] { "arg1", "arg2" })] + [InlineData("NotCountableEntitySetUsedForCount", new object[] { "arg1" })] + [InlineData("NotCountablePropertyUsedForCount", new object[] { "arg1" })] + [InlineData("NotExpandablePropertyUsedInExpand", new object[] { "arg1" })] + [InlineData("NotFilterablePropertyUsedInFilter", new object[] { "arg1" })] + [InlineData("NotNavigablePropertyUsedInNavigation", new object[] { "arg1" })] + [InlineData("NotSelectablePropertyUsedInSelect", new object[] { "arg1" })] + [InlineData("NotSortablePropertyUsedInOrderBy", new object[] { "arg1" })] + [InlineData("NotSupportedChildTransformationKind", new object[] { "arg1", "arg2" })] + [InlineData("NotSupportedTransformationKind", new object[] { "arg1" })] + [InlineData("NullContainer", new object[] { })] + [InlineData("NullContainerBuilder", new object[] { })] + [InlineData("NullElementInCollection", new object[] { })] + [InlineData("ODataFunctionNotSupported", new object[] { "arg1" })] + [InlineData("ODataPathMissing", new object[] { })] + [InlineData("OnlySingleValueNodeSupported", new object[] { })] + [InlineData("OperationIsNotBound", new object[] { "arg1", "arg2" })] + [InlineData("OperationMustBeUniqueInEntitySetContainer", new object[] { "arg1" })] + [InlineData("OrderByClauseInvalid", new object[] { "arg1", "arg2" })] + [InlineData("OrderByClauseNotSupported", new object[] { })] + [InlineData("OrderByDuplicateIt", new object[] { })] + [InlineData("OrderByDuplicateProperty", new object[] { "arg1" })] + [InlineData("OrderByNodeCountExceeded", new object[] { "arg1" })] + [InlineData("ParameterTemplateMustBeInCurlyBraces", new object[] { "arg1", "arg2" })] + [InlineData("ParameterTypeIsNotCollection", new object[] { "arg1", "arg2" })] + [InlineData("PropertyCannotBeConverted", new object[] { "arg1" })] + [InlineData("PropertyIsNotCollection", new object[] { "arg1", "arg2", "arg3" })] + [InlineData("PropertyMustBeBoolean", new object[] { })] + [InlineData("PropertyMustBeDateTimeOffsetOrDate", new object[] { })] + [InlineData("PropertyMustBeEnum", new object[] { "arg1", "arg2" })] + [InlineData("PropertyMustBeSet", new object[] { "arg1" })] + [InlineData("PropertyMustBeSetWhenAnotherPropertyIsSet", new object[] { "arg1", "arg2" })] + [InlineData("PropertyMustBeString", new object[] { })] + [InlineData("PropertyMustBeStringLengthOne", new object[] { })] + [InlineData("PropertyMustBeStringMaxLengthOne", new object[] { })] + [InlineData("PropertyMustBeTimeOfDay", new object[] { })] + [InlineData("PropertyMustHavePublicGetterAndSetter", new object[] { })] + [InlineData("PropertyNotFound", new object[] { "arg1", "arg2" })] + [InlineData("PropertyNotFoundOnPathExpression", new object[] { "arg1", "arg2" })] + [InlineData("PropertyOrPathWasRemovedFromContext", new object[] { "arg1" })] + [InlineData("PropertyTypeOverflow", new object[] { "arg1" })] + [InlineData("PropertyUnrecognizedFormat", new object[] { "arg1" })] + [InlineData("QueryCannotBeEmpty", new object[] { "arg1" })] + [InlineData("QueryGetModelMustNotReturnNull", new object[] { })] + [InlineData("QueryNodeBindingNotSupported", new object[] { "arg1", "arg2" })] + [InlineData("QueryNodeValidationNotSupported", new object[] { "arg1", "arg2" })] + [InlineData("QueryParameterNotSupported", new object[] { "arg1" })] + [InlineData("ReadFromStreamAsyncMustHaveRequest", new object[] { })] + [InlineData("ReferenceNavigationPropertyExpandFilterVisitorUnexpectedParameter", new object[] { "arg1" })] + [InlineData("RequestMustHaveModel", new object[] { })] + [InlineData("RequestNotActionInvocation", new object[] { "arg1" })] + [InlineData("RequiredParametersNotSubsetOfFunctionParameters", new object[] { "arg1", "arg2" })] + [InlineData("ResourceTypeNotInModel", new object[] { "arg1" })] + [InlineData("RootElementNameMissing", new object[] { "arg1" })] + [InlineData("RouteOptionDisabledKeySegment", new object[] { })] + [InlineData("RouteOptionDisabledOperationSegment", new object[] { })] + [InlineData("RouteServicesAlreadyExist", new object[] { })] + [InlineData("SegmentShouldBeKind", new object[] { "arg1", "arg2" })] + [InlineData("SelectExpandEmptyOrNull", new object[] { })] + [InlineData("SelectExpandEmptyOrWhitespace", new object[] { })] + [InlineData("SelectionTypeNotSupported", new object[] { "arg1" })] + [InlineData("SelectNonStructured", new object[] { "arg1" })] + [InlineData("ShouldHaveNavigationPropertyInNavigationExpandPath", new object[] { })] + [InlineData("SingleResultHasMoreThanOneEntity", new object[] { "arg1", "arg2", "arg3" })] + [InlineData("SkipTokenNotSupportedOrderByExpression", new object[] { "arg1" })] + [InlineData("SkipTokenParseError", new object[] { "arg1" })] + [InlineData("SkipTokenProcessingError", new object[] { })] + [InlineData("SkipTopLimitExceeded", new object[] { "arg1", "arg2", "arg3" })] + [InlineData("TargetKindNotImplemented", new object[] { "arg1", "arg2" })] + [InlineData("TypeCannotBeDeserialized", new object[] { "arg1" })] + [InlineData("TypeCannotBeSerialized", new object[] { "arg1" })] + [InlineData("TypeMustBeEntity", new object[] { "arg1" })] + [InlineData("TypeMustBeEnumOrNullableEnum", new object[] { "arg1" })] + [InlineData("TypeMustBeOpenType", new object[] { "arg1" })] + [InlineData("TypeMustBeRelated", new object[] { "arg1", "arg2" })] + [InlineData("TypeMustBeResourceSet", new object[] { "arg1" })] + [InlineData("TypeMustImplementInterface", new object[] { "arg1", "arg2" })] + [InlineData("TypeMustInheritFromType", new object[] { "arg1", "arg2" })] + [InlineData("TypeOfDynamicPropertyNotSupported", new object[] { "arg1", "arg2" })] + [InlineData("UnableToDetermineBaseUrl", new object[] { })] + [InlineData("UnableToDetermineMetadataUrl", new object[] { })] + [InlineData("UnableToIdentifyUniqueProperty", new object[] { "arg1" })] + [InlineData("UnaryNodeValidationNotSupported", new object[] { "arg1", "arg2" })] + [InlineData("UnexpectedElementType", new object[] { "arg1", "arg2", "arg3" })] + [InlineData("UnsupportedEdmType", new object[] { "arg1", "arg2" })] + [InlineData("UnsupportedEdmTypeKind", new object[] { "arg1" })] + [InlineData("UriFunctionClrBinderAlreadyBound", new object[] { "arg1" })] + [InlineData("UriQueryStringInvalid", new object[] { "arg1" })] + [InlineData("ValueIsInvalid", new object[] { "arg1", "arg2" })] + [InlineData("WriteObjectInlineNotSupported", new object[] { "arg1" })] + [InlineData("WriteObjectNotSupported", new object[] { "arg1" })] + [InlineData("WriteToResponseAsyncMustHaveRequest", new object[] { })] + public void ResourceKey_ShouldFormatWithoutException(string resourceKey, object[] formatArgs) + { + // Arrange + var resourceValue = SRResources.ResourceManager.GetString(resourceKey, SRResources.Culture); + Assert.NotNull(resourceValue); // Ensure the resource exists + + // Act & Assert + var exception = Record.Exception(() => Error.Format(resourceValue, formatArgs)); + Assert.Null(exception); // Ensure no Exception is thrown + + // Match numbers of arguments required in the resource string and validate against formatArgs + var matches = Regex.Matches(resourceValue, @"\{\d+\}").Select(m => m.Value).Distinct(); + Assert.Equal(matches.Count(), formatArgs.Length); + + var formattedValue = Error.Format(resourceValue, formatArgs); + Assert.NotNull(formattedValue); + + Assert.Equal(formattedValue, string.Format(resourceValue, formatArgs)); + } +}