File: PDB\VisualBasicDeterministicBuildCompilationTests.vb
Web Access
Project: src\src\Compilers\VisualBasic\Test\Emit\Microsoft.CodeAnalysis.VisualBasic.Emit.UnitTests.vbproj (Microsoft.CodeAnalysis.VisualBasic.Emit.UnitTests)
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
 
Imports System.Reflection.Metadata
Imports System.Reflection.PortableExecutable
Imports System.Text
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Debugging
Imports Microsoft.CodeAnalysis.Emit
Imports Microsoft.CodeAnalysis.Test.Utilities
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests
Imports Roslyn.Test.Utilities
Imports Roslyn.Test.Utilities.PDB
 
Public Class VisualBasicDeterministicBuildCompilationTests
    Inherits BasicTestBase
    Implements IEnumerable(Of Object())
 
    Private Sub VerifyCompilationOptions(originalOptions As VisualBasicCompilationOptions, compilationOptionsBlobReader As BlobReader, emitOptions As EmitOptions, compilation As VisualBasicCompilation)
        Dim pdbOptions = DeterministicBuildCompilationTestHelpers.ParseCompilationOptions(compilationOptionsBlobReader)
 
        DeterministicBuildCompilationTestHelpers.AssertCommonOptions(emitOptions, originalOptions, compilation, pdbOptions)
 
        ' See VisualBasicCompilation.SerializeForPdb for options that are added
        pdbOptions.VerifyPdbOption("checked", originalOptions.CheckOverflow)
        pdbOptions.VerifyPdbOption("strict", originalOptions.OptionStrict)
 
        Assert.Equal(originalOptions.ParseOptions.LanguageVersion.MapSpecifiedToEffectiveVersion().ToDisplayString(), pdbOptions("language-version"))
 
        pdbOptions.VerifyPdbOption(
            "define",
            originalOptions.ParseOptions.PreprocessorSymbols,
            isDefault:=Function(v) v.IsEmpty,
            toString:=Function(v) String.Join(",", v.Select(Function(p) If(p.Value IsNot Nothing, $"{p.Key}=""{p.Value}""", p.Key))))
    End Sub
 
    Private Sub TestDeterministicCompilationVB(syntaxTrees As SyntaxTree(), compilationOptions As VisualBasicCompilationOptions, emitOptions As EmitOptions, ParamArray metadataReferences() As TestMetadataReferenceInfo)
 
        Dim tf = TargetFramework.NetStandard20
        Dim originalCompilation = CreateCompilation(
                syntaxTrees,
                references:=metadataReferences.SelectAsArray(Of MetadataReference)(Function(r) r.MetadataReference),
                options:=compilationOptions,
                targetFramework:=tf)
 
        Dim peBlob = originalCompilation.EmitToArray(emitOptions)
 
        Using peReader As PEReader = New PEReader(peBlob)
            Dim entries = peReader.ReadDebugDirectory()
 
            AssertEx.Equal({DebugDirectoryEntryType.CodeView, DebugDirectoryEntryType.PdbChecksum, DebugDirectoryEntryType.Reproducible, DebugDirectoryEntryType.EmbeddedPortablePdb}, entries.Select(Of DebugDirectoryEntryType)(Function(e) e.Type))
 
            Dim codeView = entries(0)
            Dim checksum = entries(1)
            Dim reproducible = entries(2)
            Dim embedded = entries(3)
 
            Using embeddedPdb As MetadataReaderProvider = peReader.ReadEmbeddedPortablePdbDebugDirectoryData(embedded)
                Dim pdbReader = embeddedPdb.GetMetadataReader()
 
                Dim metadataReferenceReader = DeterministicBuildCompilationTestHelpers.GetSingleBlob(PortableCustomDebugInfoKinds.CompilationMetadataReferences, pdbReader)
                Dim compilationOptionsReader = DeterministicBuildCompilationTestHelpers.GetSingleBlob(PortableCustomDebugInfoKinds.CompilationOptions, pdbReader)
 
                VerifyCompilationOptions(compilationOptions, compilationOptionsReader, emitOptions, originalCompilation)
                DeterministicBuildCompilationTestHelpers.VerifyReferenceInfo(metadataReferences, tf, metadataReferenceReader)
            End Using
        End Using
    End Sub
 
    <Theory>
    <ClassData(GetType(VisualBasicDeterministicBuildCompilationTests))>
    Public Sub PortablePdb_DeterministicCompilation(compilationOptions As VisualBasicCompilationOptions, emitOptions As EmitOptions)
        Dim sourceOne = Parse("
Class C1
End Class", fileName:="one.vb", options:=compilationOptions.ParseOptions, encoding:=Encoding.UTF8)
 
        Dim sourceTwo = Parse("
Class C2
End Class", fileName:="two.vb", options:=compilationOptions.ParseOptions, encoding:=New UTF8Encoding(encoderShouldEmitUTF8Identifier:=False))
 
        Dim referenceSourceOne =
            <compilation>
                <file name="b.vb">
                    Public Class SomeClass
                    End Class
 
                    Public Class SomeOtherClass
                    End Class
                </file>
            </compilation>
 
        Dim referenceSourceTwo =
    <compilation>
        <file name="b.vb">
                    Public Class SomeClass
                    End Class
 
                    Public Class SomeOtherClass
                    End Class
                </file>
    </compilation>
 
        Dim referenceOneCompilation = CreateCompilation(referenceSourceOne, options:=TestOptions.DebugDll)
        Dim referenceTwoCompilation = CreateCompilation(referenceSourceTwo, options:=TestOptions.DebugDll)
 
        Using referenceOne As TestMetadataReferenceInfo = TestMetadataReferenceInfo.Create(referenceOneCompilation, "abcd.dll", EmitOptions.Default)
            Using referenceTwo As TestMetadataReferenceInfo = TestMetadataReferenceInfo.Create(referenceTwoCompilation, "efgh.dll", EmitOptions.Default)
                TestDeterministicCompilationVB({sourceOne, sourceTwo}, compilationOptions, emitOptions, referenceOne, referenceTwo)
            End Using
        End Using
    End Sub
 
    <ConditionalTheory(GetType(DesktopOnly))>
    <ClassData(GetType(VisualBasicDeterministicBuildCompilationTests))>
    Public Sub PortablePdb_DeterministicCompilationWithSJIS(compilationOptions As VisualBasicCompilationOptions, emitOptions As EmitOptions)
        Dim sourceOne = Parse("
Class C1
End Class", fileName:="one.vb", options:=compilationOptions.ParseOptions, encoding:=Encoding.UTF8)
 
        Dim sourceTwo = Parse("
Class C2
End Class", fileName:="two.vb", options:=compilationOptions.ParseOptions, encoding:=New UTF8Encoding(encoderShouldEmitUTF8Identifier:=False))
 
        Dim sourceThree = Parse("
Class C3
End Class", fileName:="three.vb", options:=compilationOptions.ParseOptions, encoding:=Encoding.GetEncoding(932)) ' SJIS encoding
 
        Dim referenceSourceOne =
            <compilation>
                <file name="b.vb">
                    Public Class SomeClass
                    End Class
 
                    Public Class SomeOtherClass
                    End Class
                </file>
            </compilation>
 
        Dim referenceSourceTwo =
    <compilation>
        <file name="b.vb">
                    Public Class SomeClass
                    End Class
 
                    Public Class SomeOtherClass
                    End Class
                </file>
    </compilation>
 
        Dim referenceOneCompilation = CreateCompilation(referenceSourceOne, options:=TestOptions.DebugDll)
        Dim referenceTwoCompilation = CreateCompilation(referenceSourceTwo, options:=TestOptions.DebugDll)
 
        Using referenceOne As TestMetadataReferenceInfo = TestMetadataReferenceInfo.Create(referenceOneCompilation, "abcd.dll", EmitOptions.Default)
            Using referenceTwo As TestMetadataReferenceInfo = TestMetadataReferenceInfo.Create(referenceTwoCompilation, "efgh.dll", EmitOptions.Default)
                TestDeterministicCompilationVB({sourceOne, sourceTwo, sourceThree}, compilationOptions, emitOptions, referenceOne, referenceTwo)
            End Using
        End Using
    End Sub
 
    Public Iterator Function GetEnumerator() As IEnumerator(Of Object()) Implements IEnumerable(Of Object()).GetEnumerator
        For Each compilationOptions As VisualBasicCompilationOptions In GetCompilationOptions()
            For Each emitOptions As EmitOptions In GetEmitOptions()
                Yield {compilationOptions, emitOptions}
            Next
        Next
    End Function
 
    Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
        Return GetEnumerator()
    End Function
 
    Private Iterator Function GetEmitOptions() As IEnumerable(Of EmitOptions)
        Dim emitOptions = New EmitOptions(debugInformationFormat:=DebugInformationFormat.Embedded)
        Yield emitOptions
        Yield emitOptions.WithDefaultSourceFileEncoding(Encoding.UTF8)
    End Function
 
    Private Iterator Function GetCompilationOptions() As IEnumerable(Of VisualBasicCompilationOptions)
        For Each parseOption As VisualBasicParseOptions In GetParseOptions()
            ' Provide non default options for to test that they are being serialized
            ' to the pdb correctly. It needs to produce a compilation to be emitted, but otherwise
            ' everything should be non-default if possible. Diagnostic settings are ignored
            ' because they won't be serialized. 
 
            ' Use constructor that requires all arguments. If New arguments are added, it's possible they need to be
            ' included in the pdb serialization And added to tests here
            Dim defaultOptions = New VisualBasicCompilationOptions(
                OutputKind.DynamicallyLinkedLibrary,
                moduleName:=Nothing,
                mainTypeName:=Nothing,
                scriptClassName:=WellKnownMemberNames.DefaultScriptClassName,
                globalImports:={GlobalImport.Parse("System")},
                rootNamespace:=Nothing,
                optionStrict:=OptionStrict.Off,
                optionInfer:=True,
                optionExplicit:=True,
                optionCompareText:=False,
                parseOptions:=parseOption,
                embedVbCoreRuntime:=False,
                optimizationLevel:=OptimizationLevel.Debug,
                checkOverflow:=True,
                cryptoKeyContainer:=Nothing,
                cryptoKeyFile:=Nothing,
                cryptoPublicKey:=Nothing,
                delaySign:=Nothing,
                platform:=Platform.AnyCpu,
                generalDiagnosticOption:=ReportDiagnostic.Default,
                specificDiagnosticOptions:=Nothing,
                concurrentBuild:=True,
                deterministic:=True,
                xmlReferenceResolver:=Nothing,
                sourceReferenceResolver:=Nothing,
                metadataReferenceResolver:=Nothing,
                assemblyIdentityComparer:=Nothing,
                strongNameProvider:=Nothing,
                publicSign:=False,
                reportSuppressedDiagnostics:=False,
                metadataImportOptions:=MetadataImportOptions.Public)
 
            Yield defaultOptions
            Yield defaultOptions.WithOptimizationLevel(OptimizationLevel.Release)
            Yield defaultOptions.WithDebugPlusMode(True)
            Yield defaultOptions.WithOptimizationLevel(OptimizationLevel.Release).WithDebugPlusMode(True)
        Next
    End Function
 
    Private Iterator Function GetParseOptions() As IEnumerable(Of VisualBasicParseOptions)
        Dim parseOptions As New VisualBasicParseOptions()
 
        Yield parseOptions
        Yield parseOptions.WithLanguageVersion(LanguageVersion.VisualBasic15_3)
        ' https://github.com/dotnet/roslyn/issues/44802 tracks
        ' enabling preprocessor symbol validation for VB
        ' Yield parseOptions.WithPreprocessorSymbols({New KeyValuePair(Of String, Object)("TestPre", True), New KeyValuePair(Of String, Object)("TestPreTwo", True)})
    End Function
End Class