-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Add tests for reflection based serialization of coretypes #20247
Conversation
| public void ValidateAgainstFile(object original, string coreBase64, string netfxBase64) | ||
| { | ||
| CheckForAnyEquals(original, LoadFromFile(coreBase64)); | ||
| //CheckForAnyEquals(originalType, LoadFromFile(netfxBase64)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
intentional for this PR. I rushed to finish core <--> core serialization and also moved test data to code as @stephentoub suggested.
| } | ||
| else | ||
| { | ||
| // Check if object.Equals(object) is overriden and if not check if there is a more concrete equality check implementation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo, 'overridden'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and below
|
I added all necessary equality checks as extension methods. Some of them could be ported directly into the respective types. Let's discuss that after everything else. |
| T[] sub1 = array1[i], sub2 = array2[i]; | ||
| if (sub1 == null || sub2 == null && (sub1 != sub2)) return false; | ||
| if (sub1.Length != sub2.Length) return false; | ||
| if (sub1 == null || sub2 == null && (sub1 != sub2)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use parentheses when mixing || and && so I don't have to remember precedence order.
Also, if sub1 == sub2 == null then this will fail on the length check. Should it be
if (sub1 == null || sub2 == null)
return sub1 == sub2;| [Serializable] | ||
| internal sealed class PointEqualityComparer : IEqualityComparer<Point> | ||
| { | ||
| public bool Equals(Point x, Point y) => x.X == y.X && x.Y == y.Y; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, parens would be good
| /// <summary> | ||
| /// First: Object | ||
| /// Second: Core Base64 serialized string | ||
| /// Third: Netfx Base64 serialized string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At some point in the future we'll have to update these base64 values. Eg we added a field in hopefully a non breaking way. At that point we will need to have blobs for both old and new and test both directions. I guess that is a problem to solve at that time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought a lot about what the best data structure could be for this case. Putting the base64 strings into a different container for every configuration brings the hassle of references to the objects. The base64 hash of e.g. byte.MaxValue must reference the value byte.MaxValue. Therefore I decided to put them together in one place.
If we e.g. need a dedicated hash for net471 we could just add another object to the array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fine
|
EDIT @ViktorHofer: Updated list as it contained too many types. Moved list to top. |
| private static int Identity(int i) => i; | ||
|
|
||
| [Fact] | ||
| public void Roundtrip_Delegates_NoTarget() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Delegates aren't supposed to be serializable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I seem to recall deleting these. You might need to rebase.
| { | ||
| if (extendedType.IsGenericType) | ||
| { | ||
| return typeof(EqualityExtensions).GetMethods() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using reflection this complex would probably require writing rd.xml for aot. If you don't want to figure that out, a switch statement or dictionary of delegates might be easiest.
| { | ||
| public partial class BinaryFormatterTests | ||
| { | ||
| /// <summary> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a comment on how to generate these strings.
| //yield return ValueTuple.Create(1, "2", 3u, 4L, 5.6, 7.8f, 9m }; | ||
| //yield return ValueTuple.Create(1, "2", 3u, 4L, 5.6, 7.8f, 9m, Tuple.Create(10) }; | ||
| yield return new object[] { new BigInteger(), "AAEAAAD/////AQAAAAAAAAAMAgAAAFpTeXN0ZW0uUnVudGltZS5OdW1lcmljcywgVmVyc2lvbj00LjEuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABpTeXN0ZW0uTnVtZXJpY3MuQmlnSW50ZWdlcgIAAAAFX3NpZ24FX2JpdHMABwgPAgAAAAAAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAFJTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAaU3lzdGVtLk51bWVyaWNzLkJpZ0ludGVnZXICAAAABV9zaWduBV9iaXRzAAcIDwIAAAAAAAAACgs=" }; | ||
| yield return new object[] { new BigInteger(10324176), "AAEAAAD/////AQAAAAAAAAAMAgAAAFpTeXN0ZW0uUnVudGltZS5OdW1lcmljcywgVmVyc2lvbj00LjEuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABpTeXN0ZW0uTnVtZXJpY3MuQmlnSW50ZWdlcgIAAAAFX3NpZ24FX2JpdHMABwgPAgAAANCInQAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAFJTeXN0ZW0uTnVtZXJpY |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to also add System.Collections.Specialized.NameObjectCollectionBase
|
@karelz This is 2.0 work and must be finished by tomorrow... |
1d58e56 to
e520c99
Compare
The MemberData is enumerated promptly, such that even though we're yielding the graph object, subsequent modifications to that same object are manifested prior to that object being tested, and it doesn't match the serialized version.
| dict["Bar"] = 2; | ||
| ReadOnlyDictionary<string, int> value = new ReadOnlyDictionary<string, int>(dict); | ||
| var deserializedValue = SerializeAndDeserialize(value, @"<ReadOnlyDictionaryOfstringint xmlns=""http://schemas.datacontract.org/2004/07/System.Collections.ObjectModel"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><_dictionary xmlns:a=""http://schemas.microsoft.com/2003/10/Serialization/Arrays""><a:KeyValueOfstringint><a:Key>Foo</a:Key><a:Value>1</a:Value></a:KeyValueOfstringint><a:KeyValueOfstringint><a:Key>Bar</a:Key><a:Value>2</a:Value></a:KeyValueOfstringint></_dictionary></ReadOnlyDictionaryOfstringint>"); | ||
| var deserializedValue = SerializeAndDeserialize(value, @"<ReadOnlyDictionaryOfstringint xmlns=""http://schemas.datacontract.org/2004/07/System.Collections.ObjectModel"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><m_dictionary xmlns:a=""http://schemas.microsoft.com/2003/10/Serialization/Arrays""><a:KeyValueOfstringint><a:Key>Foo</a:Key><a:Value>1</a:Value></a:KeyValueOfstringint><a:KeyValueOfstringint><a:Key>Bar</a:Key><a:Value>2</a:Value></a:KeyValueOfstringint></m_dictionary></ReadOnlyDictionaryOfstringint>"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please remove the [SkipOnTargetFramework] on the test? The test is being skipped on netfx. Removing the attribute would enable the test on netfx so that we get desktop<-->core coverage..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason for the attribute is already gone?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test failed on netfx because of the naming difference between core and desktop. It should pass after your fix.
Besides, you just closed #18312, which is the issue being tracked by the attribute. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| dict["Bar"] = 2; | ||
| ReadOnlyDictionary<string, int> value = new ReadOnlyDictionary<string, int>(dict); | ||
| var deserializedValue = SerializeAndDeserialize(value, @"{""_dictionary"":[{""Key"":""Foo"",""Value"":1},{""Key"":""Bar"",""Value"":2}]}"); | ||
| var deserializedValue = SerializeAndDeserialize(value, @"{""m_dictionary"":[{""Key"":""Foo"",""Value"":1},{""Key"":""Bar"",""Value"":2}]}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please remove the [SkipOnTargetFramework] on the test? The test is being skipped on netfx. Removing the attribute would enable the test on netfx so that we get desktop<-->core coverage..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| public int X; | ||
| public int Y; | ||
|
|
||
| public Point() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: why adding this public default ctor? This may have changed the test scenario. Before the change, the test was for type without public default ctor; after the fix, the test is for type having public constructor. DCS deal with these two cases differently. I'm not sure how BinaryFormatter would deal with this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@krwq is following up on your question and testing locally without the default constructor. I think there was a reason why I had to add it.
|
@dotnet-bot test OSX x64 Debug Build please |
|
@morganbr @ViktorHofer I've changed culture inside the test and also saw two other test cases failing and have fixed them with setting Locale in one of their fields: new DataSet("Dataset") { Locale = CultureInfo.InvariantCulture }
new DataTable("Datatable", "corens") { Locale = CultureInfo.InvariantCulture }I couldn't repro the issue from the CI but the hashes were likely not updated due to RegEx replacing only lines which had |
|
@dotnet-bot test Linux x64 Tests - Release - Ubuntu.1404.Amd64.Open |
|
@dotnet-bot test Linux x64 Tests - Release - Ubuntu.1404.Amd64.Open please |
|
The remaining failure is https://github.com/dotnet/corefx/issues/20245. It is not worth rerunning again int this case.Merging. |
Add tests for reflection based serialization of coretypes
Add tests for reflection based serialization of coretypes
Relates to https://github.com/dotnet/corefx/issues/19119
Follow up work