Conversation
Marge from dotnet/corert master
…ed one .il file with a simple test.
Reenabled System.CommandLine
|
Same for the other project (ILVerify.csproj). Is this maybe, because the .NET CLI under Tools\dotnetcli is an old version that does not understand the new .csproj format? I think this was already mentioned here: #3666 (comment) Just saw #3682. That would solve my problem, right? Could someone help out? How should we proceed? @jkotas ? |
src/ILVerify/src/ILVerify.csproj
Outdated
| <BaseNuGetRuntimeIdentifier>win7</BaseNuGetRuntimeIdentifier> | ||
| <!-- AutoGenerateBindingRedirects is not honoring the unification | ||
| table, and thus breaking unification by explicitly listing | ||
| bindingRedirects for assemblies that only differ by revision --> |
There was a problem hiding this comment.
You can delete FileAlignment and AutoGenerateBindingRedirects as well.
| <ItemGroup> | ||
| <Compile Include="Program.cs" /> | ||
| <Compile Include="ILImporter.Verify.cs" /> | ||
| <Compile Include="ILImporter.StackValue.cs" /> |
There was a problem hiding this comment.
I think it would look better to keep the explicit list of files here.
That's fine. |
Exclude ILVerify from the end-to-end build in https://github.com/dotnet/corert/blob/master/src/dirs.proj#L10 unconditionally. We will add it back once #3682 is fixed. |
I think the ILVerify tests should use the real System.Private.CoreLib.dll/System.Runtime.dll. |
| IL_0001: ldarg.1 | ||
| IL_0002: ldarg.2 | ||
| IL_0003: add | ||
| IL_0004: stloc.0 |
There was a problem hiding this comment.
This looks like cruft generated by the C# compiler in debug builds. It should not be here. This should have just what is needed:
{
.maxstack 2
ldarg.1
ldarg.2
add
ret
}
| public void SimpleAddTest() | ||
| { | ||
| ILImporter importer = TestDataLoader.GetMethodDesc(s_testModule, "[BasicArithmeticTests]BasicArithmeticTestsType.ValidSimpleAdd"); | ||
|
|
There was a problem hiding this comment.
I think this should be [Theory], the test data should be auto-generated by enumerating all methods in the test file, and filtering the ones for given theory based on the test name conventions - e.g. one theory should get all valid tests and other theory should get all invalid tests. For invalid tests, you can also have convention to encode the expected error in the test name.
src/ILVerify/tests/TestDataLoader.cs
Outdated
| /// <summary> | ||
| /// The folter with the binaries which are compiled from the test driver IL Code | ||
| /// </summary> | ||
| static string TESTASSEMBLYPATH = @"..\..\..\ILTests\"; |
There was a problem hiding this comment.
You should be able to get the test files dropped to the output by referencing the Project:
There was a problem hiding this comment.
Could you please share more about this? Currently there are only two projects: 1 ILVerify, 2 ILVerify.Tests, which contains the xunit code, and the .il file is just in a subfolder. (to get the dlls, which we test on I call ilasm manually). Should I move the .il files into a separate project and do the referencing trick with that project? I’m trying to do that, but I have problems with creating the .ilproj based project. I did not find that in VS, so I tried to do it manually (based on src\ILCompiler.TypeSystem\tests\ILTestAssembly\ILTestAssembly.ilproj), but VS cannot open the project I created manually (ILVerify.Tests.ILTests.ilproj : error : Project file is incomplete. Expected imports are missing.). So is this the way I should do it? If yes, is there a documentation on .ilproj? (google does not really help..).
There was a problem hiding this comment.
.ilproj is not supported by the .NET SDK out of the box, so there is no mainstream documentation for it. .NET SDK includes targets based on the project extension. For example, you can find code like this in Sdk.targets from the .NET SDK:
<LanguageTargets Condition="'$(MSBuildProjectExtension)' == '.csproj'">$(MSBuildToolsPath)\Microsoft.CSharp.targets</LanguageTargets>
<LanguageTargets Condition="'$(MSBuildProjectExtension)' == '.vbproj'">$(MSBuildToolsPath)\Microsoft.VisualBasic.targets</LanguageTargets>
Notice that there is no condition for .ilproj. You have to take of the msbuild targets for .ilproj yourself. I assume that it is what the VS is complaining about.
The .ilproj files work in the CoreRT build today because of our own buildtools extension that setups the targets for .ilproj: https://github.com/dotnet/buildtools/blob/03988127f489bcd1cf58d71131ac628620d53de9/src/Microsoft.DotNet.Build.Tasks/PackageFiles/FrameworkTargeting.targets#L106
I doubt that you would be able to include the buildtools ilproj targets into your project because of your have started using latest .NET CLI.
I think it should be ok to depend on manual building for now, and add the project file once #3682 is fixed.
There was a problem hiding this comment.
Ok, if I update the readme file I will document this, and then I will revisit this when #3682 is done. Thanks for the explanation though!
|
Thanks! ...still WIP, I pushed a change, which fixes some of the things, the last two are missing (theory + project reference to .il), i'm working on them. |
|
I pushed a new version with the ILMethodTester.cs file, which is a theory+memberdata based test scaffolding. With that writing new test basically means: just add the IL code, follow the naming conventions described in the comments for the ILReader.GetMethodsWithInvalidIL and ILReader. GetMethodsWithValidIL methods and that’s it, ILMethodTester.cs takes care of the rest. If this reaches a state where we are happy with it, I will add a short “how to add new tests” section to the readme file. |
src/ILVerify/tests/ILMethodTester.cs
Outdated
|
|
||
| if (newItem != null) | ||
| { | ||
| retVal.Add(new TestCase[] { newItem }); |
There was a problem hiding this comment.
Is there something better than this? According to what I found the method feeding MemberData must return IEnumerable<Object[]>, but what we need is just IEnumrable<TestCase>
There was a problem hiding this comment.
I think it is ok. An alternative would be to be just pass the individual elements as arguments to the test method.
If you keep the custom TestCase type, you may want to implemented IXunitSerializable on it to make it work well with XUnit - to get the test accounting right amount other things (https://stackoverflow.com/questions/30574322/xunit-memberdata-tests-show-up-as-one-test-instead-of-many).
| @@ -0,0 +1,3 @@ | |||
| using System.Runtime.CompilerServices; | |||
|
|
|||
| [assembly: InternalsVisibleTo("ILVerify.Tests")] | |||
There was a problem hiding this comment.
It would be nice if the tests are using just the public surface, no internals.
There was a problem hiding this comment.
Would it make sense for the test to generate the method tokens to verify and pass them to the verification method in the ILVerify?
It should avoid the need to have access to the CoreRT type system from the test driver; and it will work towards a .dll flavor of the verifier.
There was a problem hiding this comment.
Agree, that would be nice and I’m sure we want to have a .dll flavor of ILVerify. I wanted to test without InternalsVisibleTo, but currently there is no API surface, everything is internal. So I think, the first step is to define what we want to be public. I think we need VerifierError, VerificationErrorArgs, and most importantly some methods which are currently on ILImporter (or we create a façade class for that?).
Do we want to do that here? Or create an issue, define it there and I do it in another PR.
There was a problem hiding this comment.
The ILImporter (and everything from the CoreRT type system under Common) should stay internal. There should be a public façade for the few pieces that need to be public.
I am fine with creating an issue about defining what we want to be public, and switching tests to run against this surface later.
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| // See the LICENSE file in the project root for more information. | ||
|
|
||
| .assembly extern CoreTestAssembly |
There was a problem hiding this comment.
This should be System.Runtime given the other changes.
| ldarg.2 | ||
| add | ||
| ret | ||
| } // end of method Class1::Add |
There was a problem hiding this comment.
The comment does not match the method name - I do not think we need this comment.
| [2] int32 c) | ||
| ldc.i4.3 | ||
| stloc.0 | ||
| ldstr "sfdsf" |
There was a problem hiding this comment.
This can be just:
ldstr "sfdsf"
ldc.i4.3
add
ret
If you are generating the test cases by compiling C# and then running ildasm on it - compile the C# with /o+ to avoid the debug-only cruft.
src/ILVerify/tests/TestDataLoader.cs
Outdated
| @@ -0,0 +1,36 @@ | |||
| using System; | |||
There was a problem hiding this comment.
Could you please add the license header to this file
| ret | ||
| } // end of method Class1::Add | ||
|
|
||
| .method public hidebysig instance void SimpleAdd_Invalid_ExpectedNumericType_Internal.IL.LocalVerificationException() cil managed |
There was a problem hiding this comment.
Internal.IL.LocalVerificationException looks too verbose. Do we really need to differentiate the exception type here?
|
|
||
| .method public hidebysig instance void SimpleAdd_Invalid_ExpectedNumericType_Internal.IL.LocalVerificationException() cil managed | ||
| { | ||
| // Code size 16 (0x10) |
| add | ||
| stloc.3 | ||
| ret | ||
| } // end of method Program::Add |
src/ILVerify/tests/TestDataLoader.cs
Outdated
| var _typeSystemContext = new SimpleTypeSystemContext(); | ||
|
|
||
| var systemRuntime = System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromAssemblyName(new System.Reflection.AssemblyName("System.Runtime")); | ||
| var systemPrivateCoreLib = System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromAssemblyName(new System.Reflection.AssemblyName("System.Private.CoreLib")); |
There was a problem hiding this comment.
It may be better to use typeof(Object).Assembly here. It will make the tests work on both CoreCLR where the system module is System.Private.CoreLib, and desktop where the system module is mscorlib.
.gitignore
Outdated
| src/ILCompiler/reproNative/repro.s | ||
| src/ILCompiler/reproNative/reproNative.sln | ||
| src/ILCompiler/reproNative/reproNativeCpp.sln | ||
| /src/ILVerify/src/Properties/launchSettings.json |
There was a problem hiding this comment.
I think this can be launchSettings.json so that it applied globally.
src/ILVerify/tests/TestDataLoader.cs
Outdated
|
|
||
| public static EcmaModule GetModuleForTestAssembly(string assemblyName) | ||
| { | ||
| var _typeSystemContext = new SimpleTypeSystemContext(); |
There was a problem hiding this comment.
Nit: names of locals should not start with _
| } | ||
|
|
||
| .class public auto ansi beforefieldinit BasicArithmeticTestsType | ||
| extends [CoreTestAssembly]System.Object |
There was a problem hiding this comment.
CoreTestAssembly -> System.Runtime
src/ILVerify/tests/TestDataLoader.cs
Outdated
|
|
||
| _typeSystemContext.InputFilePaths = new Dictionary<string, string> | ||
| { | ||
| { coreAssembly.GetName().Name, coreAssembly.Location } |
There was a problem hiding this comment.
The System.Runtime should still be here like before (get it via Assembly.Load).
src/ILVerify/src/Program.cs
Outdated
|
|
||
| try | ||
| { | ||
| var sr = new System.Resources.ResourceManager("ILVerify.Resources.Strings", Assembly.GetExecutingAssembly()); |
There was a problem hiding this comment.
Constructing ResourceManager is expensive. It should be done only once.
src/ILVerify/src/Program.cs
Outdated
| var str = sr.GetString(args.Code.ToString(), CultureInfo.InvariantCulture); | ||
| message.Append(string.IsNullOrEmpty(str) ? args.Code.ToString() : str); | ||
| } | ||
| catch |
There was a problem hiding this comment.
This catch all should not be needed.
src/ILVerify/tests/ILMethodTester.cs
Outdated
| /// It loads all assemblies from the test folder defined in <code>TestDataLoader.TESTASSEMBLYPATH</code> | ||
| /// This class feeds the xunit Theories | ||
| /// </summary> | ||
| class ILReader |
There was a problem hiding this comment.
ILReader does not match what this type does - it does not read IL.
Would it make sense to merge it with TestDataLoader ?
src/ILVerify/tests/ILMethodTester.cs
Outdated
| /// </summary> | ||
| class ILReader | ||
| { | ||
| public enum TestMethodType |
src/ILVerify/tests/ILMethodTester.cs
Outdated
|
|
||
| if (newItem != null) | ||
| { | ||
| retVal.Add(new TestCase[] { newItem }); |
There was a problem hiding this comment.
I think it is ok. An alternative would be to be just pass the individual elements as arguments to the test method.
If you keep the custom TestCase type, you may want to implemented IXunitSerializable on it to make it work well with XUnit - to get the test accounting right amount other things (https://stackoverflow.com/questions/30574322/xunit-memberdata-tests-show-up-as-one-test-instead-of-many).
src/ILVerify/tests/ILMethodTester.cs
Outdated
| /// 1. part: a friendly name | ||
| /// 2. part: must be the word 'Invalid' | ||
| /// 3. part: the expected VerifierErrors as string separated by '.'. | ||
| /// 4. part: Either 'ExpectsException' or nothing. If 'ExpectsException' than ILVerify is expected to throw an exception during verification, otherwise not |
There was a problem hiding this comment.
The exceptions are kind of internal implementation detail. They are used to give up when things look too wrong to continue; and continuing would likely result in number of bogus errors to be generated. I am not sure whether it makes sense to test them directly.
It is related to the public surface discussion. I would expect that internal verifier exceptions would not be part of the public surface - they will be always caught internally.
There was a problem hiding this comment.
they will be always caught internally
That sounds good, but the current implementation crashes with exceptions in many cases (e.g. with my first simple add test) and we have to handle this somehow in the test code in order to be able to add and run tests as soon as possible.
My suggestion: I remove this 4. part (so we ignore this in the name of the test methods) and I simply add an empty catch block in the test code to make sure the test method does not fail when ILVerify crashes. Once the
I would expect that internal verifier exceptions would not be part of the public surface - they will be always caught internally. is implemented we can remove the empty catch block
src/ILVerify/tests/ILMethodTester.cs
Outdated
| if (mparams.Length == 4 && mparams[1].ToLower() == "invalid") | ||
| { | ||
| var expectedErrors = mparams[2].Split('.'); | ||
| List<VerifierError> verificationErros = new List<VerifierError>(); |
There was a problem hiding this comment.
Nit: var would be more appropriate here to fit with the rest
BTW: We try to follow https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/coding-style.md where possible. It says this about the var: We only use var when it's obvious what the variable type is (i.e. var stream = new FileStream(...) not var stream = OpenStandardInput()). I know that the ILVerify sources are not fully conformant with this style ... follow it when in doubts or for large chunks of new code.
src/ILVerify/tests/ILMethodTester.cs
Outdated
| return GetTestMethodsFromDll(methodSelector); | ||
| } | ||
|
|
||
| private static IEnumerable<Object[]> GetTestMethodsFromDll(Func<string[], EcmaMethod, EcmaMethodIL, TestCase> MethodSelector) |
There was a problem hiding this comment.
Argument names should start with lower case.
| } | ||
| catch | ||
| { | ||
| //in some cases ILVerify throws exceptions when things look too wrong to continue |
There was a problem hiding this comment.
Could you please open the issue on defining the public surface and add a link to it here?
|
LGTM otherwise. Thanks! @MichalStrehovsky Would you mind taking a look as well? |
|
I have a question: |
I think it has to do with TestCase being opaque type that xunit does not know how to deal with, related to my comment #3725 (comment). The output for The output for |
|
I see. I looked at edit: so this needs a serialization and then a deserialization, which somehow seems to be an overkill. Plus we have a |
| { systemRuntime.GetName().Name, systemRuntime.Location } | ||
| }; | ||
|
|
||
| typeSystemContext.SetSystemModule(typeSystemContext.GetModuleForSimpleName(coreAssembly.GetName().Name)); |
There was a problem hiding this comment.
This should be
typeSystemContext.SetSystemModule(typeSystemContext.GetModuleForSimpleName(systemRuntime.GetName().Name));
and not coreAssembly.GetName().Name.
right?
And System.Runtime forwards the "base" classes like System.Object both on full framework and on CoreCLR, so coreAssembly is either mscorlib or System.Private.CoreLib and we need that, because system.runtime depends on it. Is this assumption correct?
There was a problem hiding this comment.
Either one will work in current implementation, but coreAssembly.GetName().Name is more correct. The system module is meant to be the actual module where the wellknowtypes live, not a forwarder.
Is this assumption correct?
Right.
|
I revisited the part with IXunitSerializable:
So in sum if no one disagrees I would push a last change with:
|
MethodDefinitionHandle is just a wrapper around metadata token. You can convert it to int using |
That is what I needed! Thanks. So after all I implemented IXunitSerializable. |
| /// <summary> | ||
| /// The folder with the binaries which are compiled from the test driver IL Code | ||
| /// </summary> | ||
| public static string TESTASSEMBLYPATH = @"..\..\..\ILTests\"; |
There was a problem hiding this comment.
This looks very fragile. Is there any way this can be done in the build? The type system tests (\src\ILCompiler.TypeSystem\tests\TypeSystem.Tests.csproj) simply have a ProjectReference to the test data assemblies with a few flags set that get MSBuild to deploy the test artifacts right next to the test binary.
There was a problem hiding this comment.
This should be a temporary workaround. It should go away once this is added back to end-to-end build. Maybe add a comment about it?
There was a problem hiding this comment.
Ok, added more comment. The discussion we had with @jkotas is here: #3725 (comment)
src/ILVerify/tests/TestDataLoader.cs
Outdated
| { | ||
| if (mparams.Length == 2 && mparams[1].ToLower() == "valid") | ||
| { | ||
| return new ValidILTestCase { MetaDataToken = MetadataTokens.GetToken(methodHandle) }; |
There was a problem hiding this comment.
Nit: The CLR codebase tends to spell the word Metadata as MetaData for reasons unknown, but metadata is a legit word found in the dictionaries since the seventies or so. I've been avoiding importing that capitalization plague into CoreRT. We don't spell things like PlaceHolder, NotePad, UnderLine with this weird capitalization either.
There was a problem hiding this comment.
Interesting insight. Ok, changed it to Metadata.
src/ILVerify/tests/TestDataLoader.cs
Outdated
| { | ||
| var methodSelector = new Func<string[], MethodDefinitionHandle, TestCase>((mparams, methodHandle) => | ||
| { | ||
| if (mparams.Length == 2 && mparams[1].ToLower() == "valid") |
There was a problem hiding this comment.
Nit: I would just make this enforce the capitalization too, for consistency's sake. No need for ToLower().
#3569
-Added a .sln solution file
-Changed the main ILVerify project to the new .csproj format + ILVerify now targets netcoreapp2.0
-Added an xunit based project for testing - 1 Method for testing methods with valid IL, 1 Method for testing methods with invalid IL.
-This xunit based test project uses
TheoryandMemberDatato feed the test methods based on a naming convention defined in the comment inILMethodTester.cs(one it's finished they will be in the readme file)-Added the first .il file (with 2 small tests) as a test driver
One potential issue:
-netcoreapp2.0 won't work with VS2015 and the last RTM release of VS2017. I use the latest VS2017 preview, which supports netcoreapp2.0, plus of course command line tooling also works. Alternatives to netcoreapp2.0:
So my suggestion: let's go with netcoreapp2.0 and VS 2017 preview, or command line. (edit: -a few hours later- after seeing the failing builds I'm not so sure anymore...)
Further questions:
-How should we compile the .il files? I saw an .ilproj on the TypeSystem solution, but that also seems to be the old format. Currently I call ilasm manually. (so that step is definitely missing in this PR)
-What should be the output folder of the ilasm compilation? (currently the tests expect the dlls to be in the same folder (src\ILVerify\tests\ILTests), which I guess is not what we want).
-For the tests I think a base library is needed (with System.Object, etc.). I use the CoreTestAssembly from the TypeSystem tests as a "dummy mscorlib". This is how I reference it: https://github.com/dotnet/corert/compare/master...gregkalapos:Tests?expand=1#diff-099cd076d34a4cba24feb47d7aedd9fcR17. But I guess that's wrong.. How should I do that?
Thanks