Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ string GenerateTableAlias(SqlExpression sqlExpression)
{
ColumnExpression c => c.Name,
JsonScalarExpression jsonScalar
=> jsonScalar.Path.LastOrDefault(s => s.PropertyName is not null).PropertyName
=> jsonScalar.Path.Select(s => s.PropertyName).LastOrDefault()
?? GenerateTableAlias(jsonScalar.Json),
ScalarSubqueryExpression scalarSubquery => scalarSubquery.Subquery.Projection[0].Alias,

Expand Down Expand Up @@ -924,30 +924,30 @@ private SqlExpression CreateJoinPredicate(
var outerKey = RemapLambdaBody(outer, outerKeySelector);
var innerKey = RemapLambdaBody(inner, innerKeySelector);

if (outerKey is NewExpression { Arguments.Count: > 0 } outerNew)
if (outerKey is not NewExpression { Arguments.Count: > 0 } outerNew)
{
var innerNew = (NewExpression)innerKey;
return CreateJoinPredicate(outerKey, innerKey);
}

SqlExpression? result = null;
for (var i = 0; i < outerNew.Arguments.Count; i++)
{
var joinPredicate = CreateJoinPredicate(outerNew.Arguments[i], innerNew.Arguments[i]);
result = result == null
? joinPredicate
: _sqlExpressionFactory.AndAlso(result, joinPredicate);
}
var innerNew = (NewExpression)innerKey;

if (outerNew.Arguments.Count == 1)
{
result = _sqlExpressionFactory.AndAlso(
result!,
CreateJoinPredicate(Expression.Constant(true), Expression.Constant(true)));
}
SqlExpression? result = null;
for (var i = 0; i < outerNew.Arguments.Count; i++)
{
var joinPredicate = CreateJoinPredicate(outerNew.Arguments[i], innerNew.Arguments[i]);
result = result == null
? joinPredicate
: _sqlExpressionFactory.AndAlso(result, joinPredicate);
}

return result!;
if (outerNew.Arguments.Count == 1)
{
result = _sqlExpressionFactory.AndAlso(
result!,
CreateJoinPredicate(Expression.Constant(true), Expression.Constant(true)));
}

return CreateJoinPredicate(outerKey, innerKey);
return result!;
}

private SqlExpression CreateJoinPredicate(Expression outerKey, Expression innerKey)
Expand Down
104 changes: 50 additions & 54 deletions test/EFCore.Specification.Tests/ApiConsistencyTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,10 @@ public virtual void Generic_fluent_api_methods_should_return_generic_types()
|| hidingMethod.ReturnType != type
|| !hidingMethod.GetParameters().Select(p => p.ParameterType)
.SequenceEqual(
method.GetParameters().Select(
p => GetEquivalentGenericType(
p.ParameterType,
hidingMethod.GetGenericArguments(),
method.IsGenericMethod ? method.GetGenericArguments() : []))))
method.GetParameters().Select(p => GetEquivalentGenericType(
p.ParameterType,
hidingMethod.GetGenericArguments(),
method.IsGenericMethod ? method.GetGenericArguments() : []))))
{
continue;
}
Expand Down Expand Up @@ -135,8 +134,8 @@ public virtual void Generic_fluent_api_methods_should_return_generic_types()
|| hidingMethod.ReturnType.GetGenericTypeDefinition() != genericType
|| !hidingMethod.GetParameters().Skip(1).Select(p => p.ParameterType)
.SequenceEqual(
method.GetParameters().Skip(1).Select(
p => GetEquivalentGenericType(p.ParameterType,
method.GetParameters().Skip(1).Select(p => GetEquivalentGenericType(
p.ParameterType,
hidingMethod.GetGenericArguments(),
method.IsGenericMethod ? method.GetGenericArguments() : []))))
{
Expand All @@ -159,8 +158,9 @@ public virtual void Generic_fluent_api_methods_should_return_generic_types()
nonGenericMethods.Count > 0,
"\r\n-- Non-generic fluent returns that aren't hidden --\r\n"
+ string.Join(
Environment.NewLine, nonGenericMethods.Select(
m => $"{m.Method.ReturnType.ShortDisplayName()} {m.Type.Name}.{m.Method.Name}{FormatGenericArguments(m.Method)}({Format(m.Method.GetParameters())})")));
Environment.NewLine,
nonGenericMethods.Select(m
=> $"{m.Method.ReturnType.ShortDisplayName()} {m.Type.Name}.{m.Method.Name}{FormatGenericArguments(m.Method)}({Format(m.Method.GetParameters())})")));
}

public static string FormatGenericArguments(MethodInfo methodInfo)
Expand All @@ -183,7 +183,8 @@ protected Type GetEquivalentGenericType(Type parameterType, Type[] hidingGeneric
{
return typeof(Action<>).MakeGenericType(builderDefinition.MakeGenericType(hidingGenericArguments));
}
else if (builderArguments.Length == 1

if (builderArguments.Length == 1
&& baseGenericArguments.Length == hidingGenericArguments.Length)
{
for (var i = 0; i < baseGenericArguments.Length; i++)
Expand Down Expand Up @@ -372,15 +373,14 @@ protected virtual string ValidateMetadata(KeyValuePair<Type, (Type, Type, Type,
public virtual void Mutable_metadata_types_have_matching_methods()
{
var errors =
Fixture.MetadataMethods.Select(
typeTuple =>
from readonlyMethod in typeTuple.ReadOnly
where !Fixture.UnmatchedMetadataMethods.Contains(readonlyMethod)
where typeTuple.Mutable != null
join mutableMethod in typeTuple.Mutable
on readonlyMethod.Name equals mutableMethod.Name into mutableGroup
from mutableMethod in mutableGroup.DefaultIfEmpty()
select (readonlyMethod, mutableMethod))
Fixture.MetadataMethods.Select(typeTuple =>
from readonlyMethod in typeTuple.ReadOnly
where !Fixture.UnmatchedMetadataMethods.Contains(readonlyMethod)
where typeTuple.Mutable != null
join mutableMethod in typeTuple.Mutable
on readonlyMethod.Name equals mutableMethod.Name into mutableGroup
from mutableMethod in mutableGroup.DefaultIfEmpty()
select (readonlyMethod, mutableMethod))
.SelectMany(m => m.Select(MatchMutable))
.Where(e => e != null)
.ToList();
Expand Down Expand Up @@ -435,14 +435,13 @@ protected virtual string MatchMutable((MethodInfo Readonly, MethodInfo Mutable)
public virtual void Convention_metadata_types_have_matching_methods()
{
var errors =
Fixture.MetadataMethods.Select(
typeTuple =>
from mutableMethod in typeTuple.Mutable
where !Fixture.UnmatchedMetadataMethods.Contains(mutableMethod)
join conventionMethod in typeTuple.Convention
on GetConventionName(mutableMethod) equals conventionMethod.Name into conventionGroup
from conventionMethod in conventionGroup.DefaultIfEmpty()
select (mutableMethod, conventionMethod))
Fixture.MetadataMethods.Select(typeTuple =>
from mutableMethod in typeTuple.Mutable
where !Fixture.UnmatchedMetadataMethods.Contains(mutableMethod)
join conventionMethod in typeTuple.Convention
on GetConventionName(mutableMethod) equals conventionMethod.Name into conventionGroup
from conventionMethod in conventionGroup.DefaultIfEmpty()
select (mutableMethod, conventionMethod))
.SelectMany(m => m.Select(MatchConvention))
.Where(e => e != null)
.ToList();
Expand Down Expand Up @@ -671,9 +670,8 @@ protected virtual string ValidateConventionBuilderMethods(IReadOnlyList<MethodIn
public virtual void Convention_builder_methods_have_matching_returns()
{
var errors =
Fixture.MetadataTypes.Select(
t =>
ValidateConventionBuilderMethodReturns(t.Value.ConventionBuilder, t.Value.Convention))
Fixture.MetadataTypes.Select(t =>
ValidateConventionBuilderMethodReturns(t.Value.ConventionBuilder, t.Value.Convention))
.Where(e => e != null)
.ToList();

Expand Down Expand Up @@ -788,7 +786,8 @@ protected virtual string ValidateConventionBuilderMethodReturns(Type builderType
parameters
.Skip(1)
.Select(p => GetEquivalentGenericType(
p.ParameterType, builderType.GetGenericArguments(), method.IsGenericMethod ? method.GetGenericArguments() : [])))
p.ParameterType, builderType.GetGenericArguments(),
method.IsGenericMethod ? method.GetGenericArguments() : [])))
.ToArray();
var hidingMethod = extensionType.GetMethod(
method.Name,
Expand All @@ -813,22 +812,22 @@ protected virtual string ValidateConventionBuilderMethodReturns(Type builderType
}

return string.Join(
Environment.NewLine, unmatchedMethods.Select(
m => $"{m.ReturnType.ShortDisplayName()} {m.Type.Name}.{m.Method.Name}{FormatGenericArguments(m.Method)}({Format(m.Method.GetParameters())})"));
Environment.NewLine,
unmatchedMethods.Select(m
=> $"{m.ReturnType.ShortDisplayName()} {m.Type.Name}.{m.Method.Name}{FormatGenericArguments(m.Method)}({Format(m.Method.GetParameters())})"));
}

[ConditionalFact]
public virtual void Runtime_metadata_types_have_matching_methods()
{
var errors =
Fixture.MetadataMethods.Select(
typeTuple =>
from readOnlyMethod in typeTuple.ReadOnly
where !Fixture.UnmatchedMetadataMethods.Contains(readOnlyMethod)
join runtimeMethod in typeTuple.Runtime
on readOnlyMethod.Name equals runtimeMethod?.Name into runtimeGroup
from runtimeMethod in runtimeGroup.DefaultIfEmpty()
select (readOnlyMethod, runtimeMethod))
Fixture.MetadataMethods.Select(typeTuple =>
from readOnlyMethod in typeTuple.ReadOnly
where !Fixture.UnmatchedMetadataMethods.Contains(readOnlyMethod)
join runtimeMethod in typeTuple.Runtime
on readOnlyMethod.Name equals runtimeMethod?.Name into runtimeGroup
from runtimeMethod in runtimeGroup.DefaultIfEmpty()
select (readOnlyMethod, runtimeMethod))
.SelectMany(m => m.Select(MatchRuntime))
.Where(e => e != null)
.ToList();
Expand Down Expand Up @@ -1062,10 +1061,9 @@ where ns.StartsWith("Microsoft.Entity", StringComparison.Ordinal)
// Check that the parameter has a non-public copy constructor, identifying C# 9 records
|| !it.GetConstructors()[0].GetParameters()[0].ParameterType
.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)
.Any(
c => c.GetParameters() is var parameters
&& parameters.Length == 1
&& parameters[0].Name == "original"))
.Any(c => c.GetParameters() is var parameters
&& parameters.Length == 1
&& parameters[0].Name == "original"))
select it)
.ToList();

Expand Down Expand Up @@ -1107,7 +1105,7 @@ where type.IsVisible
&& !type.IsSealed
&& !type.GetCustomAttributes<GeneratedCodeAttribute>().Any()
&& type.GetMethod("<Clone>$") == null // Exclude records
from method in type.GetMethods(AnyInstance)
from method in type.GetMethods(AnyInstance)
where method.DeclaringType == type
&& !Fixture.VirtualMethodExceptions.Contains(method)
&& !Fixture.VirtualMethodExceptions.Contains(method)
Expand Down Expand Up @@ -1150,9 +1148,8 @@ var asyncMethodsWithoutToken
var missingOverloads
= (from methodWithoutToken in asyncMethodsWithoutToken
where !asyncMethodsWithToken
.Any(
methodWithToken => methodWithoutToken.Name == methodWithToken.Name
&& methodWithoutToken.DeclaringType == methodWithToken.DeclaringType)
.Any(methodWithToken => methodWithoutToken.Name == methodWithToken.Name
&& methodWithoutToken.DeclaringType == methodWithToken.DeclaringType)
&& !Fixture.AsyncMethodExceptions.Contains(methodWithoutToken)
// ReSharper disable once PossibleNullReferenceException
select methodWithoutToken.DeclaringType.Name + "." + methodWithoutToken.Name)
Expand All @@ -1164,10 +1161,9 @@ var missingOverloads

var missingSuffixMethods
= asyncMethods
.Where(
method => !method.Name.EndsWith("Async", StringComparison.Ordinal)
&& method.DeclaringType != null
&& !Fixture.AsyncMethodExceptions.Contains(method))
.Where(method => !method.Name.EndsWith("Async", StringComparison.Ordinal)
&& method.DeclaringType != null
&& !Fixture.AsyncMethodExceptions.Contains(method))
.Select(method => method.DeclaringType.Name + "." + method.Name)
.ToList();

Expand Down Expand Up @@ -1443,7 +1439,7 @@ protected ApiConsistencyFixtureBase()

public Dictionary<Type, Type> MutableMetadataTypes { get; } = new();
public Dictionary<Type, Type> ConventionMetadataTypes { get; } = new();
public virtual HashSet<MethodInfo> NonCancellableAsyncMethods { get; } = new();
public virtual HashSet<MethodInfo> NonCancellableAsyncMethods { get; } = [];

public virtual
Dictionary<Type, (Type ReadonlyExtensions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,8 @@ namespace Microsoft.EntityFrameworkCore;

public abstract class BadDataJsonDeserializationTestBase
{
[ConditionalTheory]
[InlineData("""{"Prop"}""")]
[InlineData("""{"Prop"}:127}""")]
[InlineData("""{"Prop":"X"}""")]
[InlineData("""{"Prop":}""")]
[ConditionalTheory, InlineData("""{"Prop"}"""), InlineData("""{"Prop"}:127}"""), InlineData("""{"Prop":"X"}"""),
InlineData("""{"Prop":}""")]
public virtual void Throws_for_bad_sbyte_JSON_values(string json)
=> Throws_for_bad_JSON_value<Int8Type, sbyte>(nameof(Int8Type.Int8), json);

Expand All @@ -22,11 +19,8 @@ protected class Int8Type
public sbyte Int8 { get; set; }
}

[ConditionalTheory]
[InlineData("""{"Prop"}""")]
[InlineData("""{"Prop"}:127}""")]
[InlineData("""{"Prop":"X"}""")]
[InlineData("""{"Prop":}""")]
[ConditionalTheory, InlineData("""{"Prop"}"""), InlineData("""{"Prop"}:127}"""), InlineData("""{"Prop":"X"}"""),
InlineData("""{"Prop":}""")]
public virtual void Throws_for_bad_nullable_long_JSON_values(string json)
=> Throws_for_bad_JSON_value<NullableInt64Type, long?>(nameof(NullableInt64Type.Int64), json);

Expand All @@ -35,15 +29,11 @@ protected class NullableInt64Type
public long? Int64 { get; set; }
}

[ConditionalTheory]
[InlineData("""{"Prop":{"type""Point","coordinates":[2.0,4.0]}}""")]
[InlineData("""{"Prop":{"type":["Point","coordinates":[2.0,4.0]}}""")]
[InlineData("""{"Prop":{"type":"Point","coordinates":[2.0,,4.0]}}""")]
[InlineData("""{"Prop":[{"type":"Point","coordinates":[2.0,4.0]}]}""")]
[InlineData("""{"Prop":1}""")]
[InlineData("""{"Prop":true}""")]
[InlineData("""{"Prop":false}""")]
[InlineData("""{"Prop":"X"}""")]
[ConditionalTheory, InlineData("""{"Prop":{"type""Point","coordinates":[2.0,4.0]}}"""),
InlineData("""{"Prop":{"type":["Point","coordinates":[2.0,4.0]}}"""),
InlineData("""{"Prop":{"type":"Point","coordinates":[2.0,,4.0]}}"""),
InlineData("""{"Prop":[{"type":"Point","coordinates":[2.0,4.0]}]}"""), InlineData("""{"Prop":1}"""), InlineData("""{"Prop":true}"""),
InlineData("""{"Prop":false}"""), InlineData("""{"Prop":"X"}""")]
public virtual void Throws_for_bad_point_as_GeoJson(string json)
=> Throws_for_bad_JSON_property_value<PointType, Point>(
b => b.Metadata.SetJsonValueReaderWriterType(typeof(JsonTypesTestBase.JsonGeoJsonReaderWriter)),
Expand All @@ -55,12 +45,8 @@ public class PointType
public Point? Point { get; set; }
}

[ConditionalTheory]
[InlineData("""{"Prop":[-128,[0,127]]}""")]
[InlineData("""{"Prop":[-128,{"P":127}]}""")]
[InlineData("""{"Prop":[-128,],23]}""")]
[InlineData("""{"Prop":[-128,},23]}""")]
[InlineData("""{"Prop":[-128,,23]}""")]
[ConditionalTheory, InlineData("""{"Prop":[-128,[0,127]]}"""), InlineData("""{"Prop":[-128,{"P":127}]}"""),
InlineData("""{"Prop":[-128,],23]}"""), InlineData("""{"Prop":[-128,},23]}"""), InlineData("""{"Prop":[-128,,23]}""")]
public virtual void Throws_for_bad_collection_of_sbyte_JSON_values(string json)
=> Throws_for_bad_JSON_value<Int8CollectionType, List<sbyte>>(
nameof(Int8CollectionType.Int8),
Expand All @@ -72,12 +58,8 @@ protected class Int8CollectionType
public sbyte[] Int8 { get; set; } = null!;
}

[ConditionalTheory]
[InlineData("""{"Prop":[-128,[0,127]]}""")]
[InlineData("""{"Prop":[-128,{"P":127}]}""")]
[InlineData("""{"Prop":[-128,],23]}""")]
[InlineData("""{"Prop":[-128,},23]}""")]
[InlineData("""{"Prop":[-128,,23]}""")]
[ConditionalTheory, InlineData("""{"Prop":[-128,[0,127]]}"""), InlineData("""{"Prop":[-128,{"P":127}]}"""),
InlineData("""{"Prop":[-128,],23]}"""), InlineData("""{"Prop":[-128,},23]}"""), InlineData("""{"Prop":[-128,,23]}""")]
public virtual void Throws_for_bad_collection_of_nullable_long_JSON_values(string json)
=> Throws_for_bad_JSON_value<NullableInt64CollectionType, List<long?>>(
nameof(NullableInt64CollectionType.Int64),
Expand Down Expand Up @@ -189,9 +171,8 @@ public object Create(DbContext context, bool designTime)
}

protected virtual void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.ConfigureWarnings(
w => w.Ignore(
CoreEventId.MappedEntityTypeIgnoredWarning,
CoreEventId.MappedPropertyIgnoredWarning,
CoreEventId.MappedNavigationIgnoredWarning));
=> optionsBuilder.ConfigureWarnings(w => w.Ignore(
CoreEventId.MappedEntityTypeIgnoredWarning,
CoreEventId.MappedPropertyIgnoredWarning,
CoreEventId.MappedNavigationIgnoredWarning));
}
Loading
Loading