DependencyManagerInteractiveTests.fs 33.2 KB
Newer Older
1 2
// Copyright (c) Microsoft Corporation.  All Rights Reserved.  See License.txt in the project root for license information.

K
Kevin Ransom (msft) 已提交
3
namespace FSharp.Compiler.Scripting.DependencyManager.UnitTests
4 5 6

open System
open System.IO
7
open System.Reflection
8
open System.Runtime.InteropServices
K
Kevin Ransom (msft) 已提交
9 10
open System.Threading

11
open FSharp.Compiler.Interactive.Shell
B
Brett V. Forsgren 已提交
12
open FSharp.Compiler.Scripting
13
open FSharp.Compiler.SourceCodeServices
K
Kevin Ransom (msft) 已提交
14
open FSharp.Compiler.Scripting.UnitTests
15
open FSharp.DependencyManager.Nuget
K
Kevin Ransom (msft) 已提交
16 17
open Microsoft.DotNet.DependencyManager

18 19
open Internal.Utilities

K
Kevin Ransom (msft) 已提交
20
open Xunit
21

22 23 24 25
module Native =
    [<DllImport("NoneExistentDll")>]
    extern int NoneSuch()

K
Kevin Ransom (msft) 已提交
26 27
type scriptHost (?langVersion: LangVersion) = inherit FSharpScript(langVersion=defaultArg langVersion LangVersion.Preview)

28 29 30 31 32 33 34 35 36
type DependencyManagerInteractiveTests() =

    let getValue ((value: Result<FsiValue option, exn>), (errors: FSharpErrorInfo[])) =
        if errors.Length > 0 then
            failwith <| sprintf "Evaluation returned %d errors:\r\n\t%s" errors.Length (String.Join("\r\n\t", errors))
        match value with
        | Ok(value) -> value
        | Error ex -> raise ex

K
Kevin Ransom (msft) 已提交
37 38
    let getErrors ((_value: Result<FsiValue option, exn>), (errors: FSharpErrorInfo[])) =
        errors
39

K
Kevin Ransom (msft) 已提交
40
    let ignoreValue = getValue >> ignore
B
Brett V. Forsgren 已提交
41

K
Kevin Ransom (msft) 已提交
42
    [<Fact>]
43 44
    member __.``SmokeTest - #r nuget``() =
        let text = """
45
#r @"nuget:Newtonsoft.Json, Version=9.0.1"
46
0"""
K
Kevin Ransom (msft) 已提交
47
        use script = new scriptHost()
48 49
        let opt = script.Eval(text) |> getValue
        let value = opt.Value
K
Kevin Ransom (msft) 已提交
50 51
        Assert.Equal(typeof<int>, value.ReflectionType)
        Assert.Equal(0, value.ReflectionValue :?> int)
52

K
Kevin Ransom (msft) 已提交
53
    [<Fact>]
54 55 56 57
    member __.``SmokeTest - #r nuget package not found``() =
        let text = """
#r @"nuget:System.Collections.Immutable.DoesNotExist, version=1.5.0"
0"""
K
Kevin Ransom (msft) 已提交
58
        use script = new scriptHost()
59 60
        let opt, errors = script.Eval(text)
        Assert.Equal(errors.Length, 1)
B
Brett V. Forsgren 已提交
61

K
Kevin Ransom (msft) 已提交
62 63 64 65 66 67 68 69
(*
    [<Theory>]
    [<InlineData("""#r "#i "unknown:Astring" """, """ """)>]
    member __.``syntax produces error messages in FSharp 4.7``(code:string, message: string) =
        use script = new scriptHost()
        let errors = script.Eval(code) |> getErrors
        Assert.Contains(message, errors |> Array.map(fun e -> e.Message))
*)
K
Kevin Ransom (msft) 已提交
70
    [<Fact>]
71
    member __.``Use Dependency Manager to resolve dependency FSharp.Data``() =
72 73 74 75 76 77 78 79 80 81

        let nativeProbingRoots () = Seq.empty<string>

        use dp = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))
        let reportError =
            let report errorType code message =
                match errorType with
                | ErrorReportType.Error -> printfn "PackageManagementError %d : %s" code message
                | ErrorReportType.Warning -> printfn "PackageManagementWarning %d : %s" code message
            ResolvingErrorReport (report)
82 83 84 85

        let idm = dp.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")

        if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
K
Kevin Ransom (msft) 已提交
86
            let result = dp.Resolve(idm, ".fsx", [|"r", "FSharp.Data"|], reportError, "net472")
K
Kevin Ransom (msft) 已提交
87 88 89 90
            Assert.Equal(true, result.Success)
            Assert.Equal(1, result.Resolutions |> Seq.length)
            Assert.Equal(1, result.SourceFiles |> Seq.length)
            Assert.Equal(1, result.Roots |> Seq.length)
91

K
Kevin Ransom (msft) 已提交
92
        let result = dp.Resolve(idm, ".fsx", [|"r", "FSharp.Data"|], reportError, "netcoreapp3.1")
K
Kevin Ransom (msft) 已提交
93 94 95 96
        Assert.Equal(true, result.Success)
        Assert.Equal(1, result.Resolutions |> Seq.length)
        Assert.Equal(1, result.SourceFiles |> Seq.length)
        Assert.Equal(1, result.Roots |> Seq.length)
97 98
        ()

B
Brett V. Forsgren 已提交
99

K
Kevin Ransom (msft) 已提交
100
    [<Fact>]
101
    member __.``Dependency add with nonexistent package should fail``() =
102 103 104 105 106 107 108 109 110 111

        let nativeProbingRoots () = Seq.empty<string>

        use dp = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))
        let reportError =
            let report errorType code message =
                match errorType with
                | ErrorReportType.Error -> printfn "PackageManagementError %d : %s" code message
                | ErrorReportType.Warning -> printfn "PackageManagementWarning %d : %s" code message
            ResolvingErrorReport (report)
112 113 114 115

        let idm = dp.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")

        if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
K
Kevin Ransom (msft) 已提交
116
            let result = dp.Resolve(idm, ".fsx", [|"r", "System.Collections.Immutable.DoesNotExist"|], reportError, "net472")
K
Kevin Ransom (msft) 已提交
117 118 119 120
            Assert.Equal(false, result.Success)
            Assert.Equal(0, result.Resolutions |> Seq.length)
            Assert.Equal(0, result.SourceFiles |> Seq.length)
            Assert.Equal(0, result.Roots |> Seq.length)
121

K
Kevin Ransom (msft) 已提交
122
        let result = dp.Resolve(idm, ".fsx", [|"r", "System.Collections.Immutable.DoesNotExist"|], reportError, "netcoreapp3.1")
K
Kevin Ransom (msft) 已提交
123 124 125 126
        Assert.Equal(false, result.Success)
        Assert.Equal(0, result.Resolutions |> Seq.length)
        Assert.Equal(0, result.SourceFiles |> Seq.length)
        Assert.Equal(0, result.Roots |> Seq.length)
127 128
        ()

B
Brett V. Forsgren 已提交
129

K
Kevin Ransom (msft) 已提交
130
    [<Fact>]
131 132
    member __.``Multiple Instances of DependencyProvider should be isolated``() =

133 134 135 136 137 138 139 140 141 142
        let assemblyProbingPaths () = Seq.empty<string>
        let nativeProbingRoots () = Seq.empty<string>

        use dp1 = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))
        let reportError =
            let report errorType code message =
                match errorType with
                | ErrorReportType.Error -> printfn "PackageManagementError %d : %s" code message
                | ErrorReportType.Warning -> printfn "PackageManagementWarning %d : %s" code message
            ResolvingErrorReport (report)
143 144 145

        let idm1 = dp1.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")
        if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
K
Kevin Ransom (msft) 已提交
146
            let result1 = dp1.Resolve(idm1, ".fsx", [|"r", "FSharp.Data"|], reportError, "net472")
K
Kevin Ransom (msft) 已提交
147 148 149 150 151 152
            Assert.Equal(true, result1.Success)
            Assert.Equal(1, result1.Resolutions |> Seq.length)
            Assert.True((result1.Resolutions |> Seq.head).Contains("\\net45\\"))
            Assert.Equal(1, result1.SourceFiles |> Seq.length)
            Assert.Equal(1, result1.Roots |> Seq.length)
            Assert.True((result1.Roots |> Seq.head).EndsWith("/fsharp.data/3.3.3/"))
153

K
Kevin Ransom (msft) 已提交
154
        let result2 = dp1.Resolve(idm1, ".fsx", [|"r", "FSharp.Data, 3.3.3"|], reportError, "netcoreapp3.1")
K
Kevin Ransom (msft) 已提交
155 156
        Assert.Equal(true, result2.Success)
        Assert.Equal(1, result2.Resolutions |> Seq.length)
157 158 159 160 161
        let expected2 =
            if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
                "\\netstandard2.0\\"
            else
                "/netstandard2.0/"
K
Kevin Ransom (msft) 已提交
162 163 164 165
        Assert.True((result2.Resolutions |> Seq.head).Contains(expected2))
        Assert.Equal(1, result2.SourceFiles |> Seq.length)
        Assert.Equal(1, result2.Roots |> Seq.length)
        Assert.True((result2.Roots |> Seq.head).EndsWith("/fsharp.data/3.3.3/"))
166

167
        use dp2 = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))
168 169 170
        let idm2 = dp2.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")

        if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
K
Kevin Ransom (msft) 已提交
171
            let result3 = dp2.Resolve(idm2, ".fsx", [|"r", "System.Json, Version=4.6.0"|], reportError, "net472")
K
Kevin Ransom (msft) 已提交
172 173 174 175 176 177
            Assert.Equal(true, result3.Success)
            Assert.Equal(1, result3.Resolutions |> Seq.length)
            Assert.True((result3.Resolutions |> Seq.head).Contains("\\netstandard2.0\\"))
            Assert.Equal(1, result3.SourceFiles |> Seq.length)
            Assert.Equal(1, result3.SourceFiles |> Seq.length)
            Assert.True((result3.Roots |> Seq.head).EndsWith("/system.json/4.6.0/"))
178

K
Kevin Ransom (msft) 已提交
179
        let result4 = dp2.Resolve(idm2, ".fsx", [|"r", "System.Json, Version=4.6.0"|], reportError, "netcoreapp3.1")
K
Kevin Ransom (msft) 已提交
180 181
        Assert.Equal(true, result4.Success)
        Assert.Equal(1, result4.Resolutions |> Seq.length)
182 183 184 185 186
        let expected4 =
            if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
                "\\netstandard2.0\\"
            else
                "/netstandard2.0/"
K
Kevin Ransom (msft) 已提交
187 188 189 190
        Assert.True((result4.Resolutions |> Seq.head).Contains(expected4))
        Assert.Equal(1, result4.SourceFiles |> Seq.length)
        Assert.Equal(1, result4.Roots |> Seq.length)
        Assert.True((result4.Roots |> Seq.head).EndsWith("/system.json/4.6.0/"))
191 192
        ()

K
Kevin Ransom (msft) 已提交
193
    [<Fact>]
194 195
    member __.``Nuget Reference package with dependencies we should get package roots and dependent references``() =

196 197 198 199 200 201 202 203 204
        let nativeProbingRoots () = Seq.empty<string>

        use dp1 = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))
        let reportError =
            let report errorType code message =
                match errorType with
                | ErrorReportType.Error -> printfn "PackageManagementError %d : %s" code message
                | ErrorReportType.Warning -> printfn "PackageManagementWarning %d : %s" code message
            ResolvingErrorReport (report)
205 206 207 208

        let idm1 = dp1.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")

        if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
K
Kevin Ransom (msft) 已提交
209
            let result1 = dp1.Resolve(idm1, ".fsx", [|"r", "Microsoft.Extensions.Configuration.Abstractions, 3.1.1"|], reportError, "net472")
K
Kevin Ransom (msft) 已提交
210 211 212 213 214 215
            Assert.Equal(true, result1.Success)
            Assert.Equal(6, result1.Resolutions |> Seq.length)
            Assert.True((result1.Resolutions |> Seq.head).Contains("\\netstandard2.0\\"))
            Assert.Equal(1, result1.SourceFiles |> Seq.length)
            Assert.Equal(6, result1.Roots |> Seq.length)
            Assert.True((result1.Roots |> Seq.head).EndsWith("/microsoft.extensions.configuration.abstractions/3.1.1/"))
216 217 218

        // Netstandard gets fewer dependencies than desktop, because desktop framework doesn't contain assemblies like System.Memory
        // Those assemblies must be delivered by nuget for desktop apps
K
Kevin Ransom (msft) 已提交
219
        let result2 = dp1.Resolve(idm1, ".fsx", [|"r", "Microsoft.Extensions.Configuration.Abstractions, 3.1.1"|], reportError, "netcoreapp3.1")
K
Kevin Ransom (msft) 已提交
220 221
        Assert.Equal(true, result2.Success)
        Assert.Equal(2, result2.Resolutions |> Seq.length)
222 223 224 225 226
        let expected =
            if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
                "\\netcoreapp3.1\\"
            else
                "/netcoreapp3.1/"
K
Kevin Ransom (msft) 已提交
227 228 229 230
        Assert.True((result2.Resolutions |> Seq.head).Contains(expected))
        Assert.Equal(1, result2.SourceFiles |> Seq.length)
        Assert.Equal(2, result2.Roots |> Seq.length)
        Assert.True((result2.Roots |> Seq.head).EndsWith("/microsoft.extensions.configuration.abstractions/3.1.1/"))
231 232 233
        ()

/// Native dll resolution is not implemented on desktop
234
#if NETCOREAPP
235
    [<Fact(Skip="downloads very large ephemeral packages"); >]
236 237 238 239 240 241 242 243 244 245
    member __.``Script using TorchSharp``() =
        let text = """
#r "nuget:RestoreSources=https://donsyme.pkgs.visualstudio.com/TorchSharp/_packaging/packages2/nuget/v3/index.json"
#r "nuget:libtorch-cpu,0.3.52118"
#r "nuget:TorchSharp,0.3.52118"

TorchSharp.Tensor.LongTensor.From([| 0L .. 100L |]).Device
"""

        if RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
K
Kevin Ransom (msft) 已提交
246
            use script = new scriptHost()
247 248
            let opt = script.Eval(text) |> getValue
            let value = opt.Value
K
Kevin Ransom (msft) 已提交
249 250
            Assert.Equal(typeof<string>, value.ReflectionType)
            Assert.Equal("cpu", value.ReflectionValue :?> string)
251 252 253
        ()


K
Kevin Ransom (msft) 已提交
254
    [<Fact>]
255 256
    member __.``Use Dependency Manager to restore packages with native dependencies, build and run script that depends on the results``() =
        let packagemanagerlines = [|
K
Kevin Ransom (msft) 已提交
257 258 259 260
            "r", "RestoreSources=https://dotnet.myget.org/F/dotnet-corefxlab/api/v3/index.json"
            "r", "Microsoft.ML,version=1.4.0-preview"
            "r", "Microsoft.ML.AutoML,version=0.16.0-preview"
            "r", "Microsoft.Data.DataFrame,version=0.1.1-e191008-1"
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
        |]

        let reportError =
            let report errorType code message =
                match errorType with
                | ErrorReportType.Error -> printfn "PackageManagementError %d : %s" code message
                | ErrorReportType.Warning -> printfn "PackageManagementWarning %d : %s" code message
            ResolvingErrorReport (report)

        let mutable resolverPackageRoots = Seq.empty<string>
        let mutable resolverPackageRoots = Seq.empty<string>
        let mutable resolverReferences = Seq.empty<string>

        let nativeProbingRoots () = resolverPackageRoots
        let assemblyProbingPaths () = resolverReferences

        // Restore packages, Get Reference dll paths and package roots
        let result =
            use dp = new DependencyProvider(AssemblyResolutionProbe(assemblyProbingPaths), NativeResolutionProbe(nativeProbingRoots))
            let idm = dp.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")
281
            dp.Resolve(idm, ".fsx", packagemanagerlines, reportError, "netcoreapp3.1")
282

K
Kevin Ransom (msft) 已提交
283
        Assert.True(result.Success, "resolve failed")
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348

        resolverPackageRoots <- result.Roots
        resolverReferences <- result.Resolutions

// Build and execute reference
        let referenceText =
#if DISABLED_DUE_TO_ISSUE_8588
//
// https://github.com/dotnet/fsharp/issues/8588
            // For this test case use Assembly Qualified References
            ("", result.Resolutions)
            ||> Seq.fold(fun acc r ->
                let assemblyName = AssemblyName.GetAssemblyName(r)
                acc + "#r @\"" + assemblyName.FullName + "\"" + Environment.NewLine)
#else
            // use standard #r for now
            ("", result.Resolutions)
            ||> Seq.fold(fun acc r ->
                acc + "#r @\"" + r + "\"" + Environment.NewLine)
#endif

        let code = @"
$(REFERENCES)

open System
open System.IO
open System.Linq
open Microsoft.Data

let Shuffle (arr:int[]) =
    let rnd = Random()
    for i in 0 .. arr.Length - 1 do
        let r = i + rnd.Next(arr.Length - i)
        let temp = arr.[r]
        arr.[r] <- arr.[i]
        arr.[i] <- temp
    arr

let housingPath = ""housing.csv""
let housingData = DataFrame.ReadCsv(housingPath)
let randomIndices = (Shuffle(Enumerable.Range(0, (int (housingData.RowCount) - 1)).ToArray()))
let testSize = int (float (housingData.RowCount) * 0.1)
let trainRows = randomIndices.[testSize..]
let testRows = randomIndices.[..testSize]
let housing_train = housingData.[trainRows]

open Microsoft.ML
open Microsoft.ML.Data
open Microsoft.ML.AutoML

let mlContext = MLContext()
let experiment = mlContext.Auto().CreateRegressionExperiment(maxExperimentTimeInSeconds = 15u)
let result = experiment.Execute(housing_train, labelColumnName = ""median_house_value"")
let details = result.RunDetails
printfn ""%A"" result
123
"
        let scriptText = code.Replace("$(REFERENCES)", referenceText)

        // Use the dependency manager to resolve assemblies and native paths
        use dp = new DependencyProvider(AssemblyResolutionProbe(assemblyProbingPaths), NativeResolutionProbe(nativeProbingRoots))

        use script = new FSharpScript()
        let opt = script.Eval(scriptText)  |> getValue
        let value = opt.Value
K
Kevin Ransom (msft) 已提交
349
        Assert.Equal(123, value.ReflectionValue :?> int32)
350

K
Kevin Ransom (msft) 已提交
351
    [<Fact>]
352 353
    member __.``Use NativeResolver to resolve native dlls.``() =
        let packagemanagerlines = [|
K
Kevin Ransom (msft) 已提交
354 355 356 357
            "r", "RestoreSources=https://dotnet.myget.org/F/dotnet-corefxlab/api/v3/index.json"
            "r", "Microsoft.ML,version=1.4.0-preview"
            "r", "Microsoft.ML.AutoML,version=0.16.0-preview"
            "r", "Microsoft.Data.DataFrame,version=0.1.1-e191008-1"
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
        |]

        let reportError =
            let report errorType code message =
                match errorType with
                | ErrorReportType.Error -> printfn "PackageManagementError %d : %s" code message
                | ErrorReportType.Warning -> printfn "PackageManagementWarning %d : %s" code message
            ResolvingErrorReport (report)

        let mutable resolverPackageRoots = Seq.empty<string>
        let mutable resolverPackageRoots = Seq.empty<string>

        let mutable resolverReferences = Seq.empty<string>
        let nativeProbingRoots () = resolverPackageRoots
        let assemblyPaths () = resolverReferences

        // Restore packages, Get Reference dll paths and package roots
        let result =
            use dp = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))
            let idm = dp.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")
378
            dp.Resolve(idm, ".fsx", packagemanagerlines, reportError, "netcoreapp3.1")
379

K
Kevin Ransom (msft) 已提交
380
        Assert.True(result.Success, "resolve failed")
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431

        resolverPackageRoots <- result.Roots
        resolverReferences <- result.Resolutions

        use _nativeDepencyResolver = new NativeDllResolveHandler(NativeResolutionProbe(nativeProbingRoots))

        // Build and execute script
        let referenceText =
            ("", result.Resolutions) ||> Seq.fold(fun acc r -> acc + @"#r @""" + r + "\"" + Environment.NewLine)

        let code = @"
$(REFERENCES)

open System
open System.IO
open System.Linq
open Microsoft.Data

let Shuffle (arr:int[]) =
    let rnd = Random()
    for i in 0 .. arr.Length - 1 do
        let r = i + rnd.Next(arr.Length - i)
        let temp = arr.[r]
        arr.[r] <- arr.[i]
        arr.[i] <- temp
    arr

let housingPath = ""housing.csv""
let housingData = DataFrame.ReadCsv(housingPath)
let randomIndices = (Shuffle(Enumerable.Range(0, (int (housingData.RowCount) - 1)).ToArray()))
let testSize = int (float (housingData.RowCount) * 0.1)
let trainRows = randomIndices.[testSize..]
let testRows = randomIndices.[..testSize]
let housing_train = housingData.[trainRows]

open Microsoft.ML
open Microsoft.ML.Data
open Microsoft.ML.AutoML

let mlContext = MLContext()
let experiment = mlContext.Auto().CreateRegressionExperiment(maxExperimentTimeInSeconds = 15u)
let result = experiment.Execute(housing_train, labelColumnName = ""median_house_value"")
let details = result.RunDetails
printfn ""%A"" result
123
"
        let scriptText = code.Replace("$(REFERENCES)", referenceText)

        use script = new FSharpScript()
        let opt = script.Eval(scriptText)  |> getValue
        let value = opt.Value
K
Kevin Ransom (msft) 已提交
432
        Assert.Equal(123, value.ReflectionValue :?> int32)
433

K
Kevin Ransom (msft) 已提交
434
    [<Fact>]
435 436
    member __.``Use AssemblyResolver to resolve assemblies``() =
        let packagemanagerlines = [|
K
Kevin Ransom (msft) 已提交
437 438 439 440
            "r", "RestoreSources=https://dotnet.myget.org/F/dotnet-corefxlab/api/v3/index.json"
            "r", "Microsoft.ML,version=1.4.0-preview"
            "r", "Microsoft.ML.AutoML,version=0.16.0-preview"
            "r", "Microsoft.Data.DataFrame,version=0.1.1-e191008-1"
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
        |]

        let reportError =
            let report errorType code message =
                match errorType with
                | ErrorReportType.Error -> printfn "PackageManagementError %d : %s" code message
                | ErrorReportType.Warning -> printfn "PackageManagementWarning %d : %s" code message
            ResolvingErrorReport (report)

        let mutable resolverPackageRoots = Seq.empty<string>
        let mutable resolverReferences = Seq.empty<string>

        let nativeProbingRoots () = resolverPackageRoots
        let assemblyProbingPaths () = resolverReferences

        // Restore packages, Get Reference dll paths and package roots
        let result =
            use dp = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))
            let idm = dp.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")
460
            dp.Resolve(idm, ".fsx", packagemanagerlines, reportError, "netcoreapp3.1")
461

K
Kevin Ransom (msft) 已提交
462
        Assert.True(result.Success, "resolve failed")
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493

        resolverPackageRoots <- result.Roots
        resolverReferences <- result.Resolutions

        use _assemblyResolver = new AssemblyResolveHandler(AssemblyResolutionProbe(assemblyProbingPaths))

        // Build and execute script
        let referenceText =
            ("", result.Resolutions)
            ||> Seq.fold(fun acc r ->
                acc + "    @\"" + r + "\";" + Environment.NewLine)

        let code = """
open System.Reflection

let x = [|
$(REFERENCES)
    |]

x |> Seq.iter(fun r ->
    let name = AssemblyName.GetAssemblyName(r)
    let asm = Assembly.Load(name)
    printfn "%A" (asm.FullName)
    )
123
"""
        let scriptText = code.Replace("$(REFERENCES)", referenceText)

        use script = new FSharpScript()
        let opt = script.Eval(scriptText)  |> getValue
        let value = opt.Value
K
Kevin Ransom (msft) 已提交
494
        Assert.Equal(123, value.ReflectionValue :?> int32)
495

K
Kevin Ransom (msft) 已提交
496
    [<Fact>]
K
Kevin Ransom (msft) 已提交
497
    member __.``Verify that referencing FSharp.Core fails with FSharp Scripts``() =
K
Kevin Ransom (msft) 已提交
498
        let packagemanagerlines = [| "r", "FSharp.Core,version=4.7.1" |]
K
Kevin Ransom (msft) 已提交
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516

        let reportError =
            let report errorType code message =
                match errorType with
                | ErrorReportType.Error -> printfn "PackageManagementError %d : %s" code message
                | ErrorReportType.Warning -> printfn "PackageManagementWarning %d : %s" code message
            ResolvingErrorReport (report)

        let mutable resolverPackageRoots = Seq.empty<string>
        let mutable resolverReferences = Seq.empty<string>

        let nativeProbingRoots () = resolverPackageRoots
        let assemblyProbingPaths () = resolverReferences

        // Restore packages, Get Reference dll paths and package roots
        let result =
            use dp = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))
            let idm = dp.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")
517
            dp.Resolve(idm, ".fsx", packagemanagerlines, reportError, "netcoreapp3.1")
K
Kevin Ransom (msft) 已提交
518 519

        // Expected: error FS3217: PackageManager can not reference the System Package 'FSharp.Core'
K
Kevin Ransom (msft) 已提交
520
        Assert.False(result.Success, "resolve succeeded but should have failed")
K
Kevin Ransom (msft) 已提交
521

K
Kevin Ransom (msft) 已提交
522
    [<Fact>]
K
Kevin Ransom (msft) 已提交
523
    member __.``Verify that referencing FSharp.Core succeeds with CSharp Scripts``() =
K
Kevin Ransom (msft) 已提交
524
        let packagemanagerlines = [| "r", "FSharp.Core,version=4.7.1" |]
K
Kevin Ransom (msft) 已提交
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542

        let reportError =
            let report errorType code message =
                match errorType with
                | ErrorReportType.Error -> printfn "PackageManagementError %d : %s" code message
                | ErrorReportType.Warning -> printfn "PackageManagementWarning %d : %s" code message
            ResolvingErrorReport (report)

        let mutable resolverPackageRoots = Seq.empty<string>
        let mutable resolverReferences = Seq.empty<string>

        let nativeProbingRoots () = resolverPackageRoots
        let assemblyProbingPaths () = resolverReferences

        // Restore packages, Get Reference dll paths and package roots
        let result =
            use dp = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))
            let idm = dp.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")
543
            dp.Resolve(idm, ".csx", packagemanagerlines, reportError, "netcoreapp3.1")
K
Kevin Ransom (msft) 已提交
544

K
Kevin Ransom (msft) 已提交
545
        Assert.True(result.Success, "resolve failed but should have succeeded")
K
Kevin Ransom (msft) 已提交
546

547

K
Kevin Ransom (msft) 已提交
548
    [<Fact>]
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
    member __.``Verify that Dispose on DependencyProvider unhooks ResolvingUnmanagedDll event handler``() =

        let mutable found = false
        let nativeProbingRoots () =
            found <- true
            Seq.empty<string>

        let reportError =
            let report errorType code message =
                match errorType with
                | ErrorReportType.Error -> printfn "PackageManagementError %d : %s" code message
                | ErrorReportType.Warning -> printfn "PackageManagementWarning %d : %s" code message
            ResolvingErrorReport (report)

        // Set up native resolver to resolve dll's
        do
            use dp = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))

            // Invoking a non-existent dll via pinvoke cause a probe. which should invoke the call back
            try Native.NoneSuch() |> ignore with _ -> ()
K
Kevin Ransom (msft) 已提交
569
            Assert.True (found, "Failed to invoke the nativeProbingRoots callback")
570 571 572 573

        // Here the dispose was invoked which should clear the ResolvingUnmanagedDll handler
        found <- false
        try Native.NoneSuch() |> ignore with _ -> ()
K
Kevin Ransom (msft) 已提交
574
        Assert.False (found, "Invoke the nativeProbingRoots callback -- Error the ResolvingUnmanagedDll still fired ")
575 576 577 578 579

        use dp = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))
        let idm = dp.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")

        if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
K
Kevin Ransom (msft) 已提交
580
            let result = dp.Resolve(idm, ".fsx", [|"r", "FSharp.Data"|], reportError, "net472")
K
Kevin Ransom (msft) 已提交
581 582 583 584
            Assert.Equal(true, result.Success)
            Assert.Equal(1, result.Resolutions |> Seq.length)
            Assert.Equal(1, result.SourceFiles |> Seq.length)
            Assert.Equal(1, result.Roots |> Seq.length)
585

K
Kevin Ransom (msft) 已提交
586
        let result = dp.Resolve(idm, ".fsx", [|"r", "FSharp.Data"|], reportError, "netcoreapp3.1")
K
Kevin Ransom (msft) 已提交
587 588 589 590
        Assert.Equal(true, result.Success)
        Assert.Equal(1, result.Resolutions |> Seq.length)
        Assert.Equal(1, result.SourceFiles |> Seq.length)
        Assert.Equal(1, result.Roots |> Seq.length)
591 592
        ()

593

K
Kevin Ransom (msft) 已提交
594
    [<Fact>]
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
    member __.``Verify that Dispose on DependencyProvider unhooks ResolvingUnmanagedDll and AssemblyResolver event handler``() =

        let mutable assemblyFound = false
        let assemblyProbingPaths () =
            assemblyFound <- true
            Seq.empty<string>

        let mutable nativeFound = false
        let nativeProbingRoots () =
            nativeFound <- true
            Seq.empty<string>

        // Set up native resolver to resolve dll's
        do
            use dp = new DependencyProvider(AssemblyResolutionProbe(assemblyProbingPaths), NativeResolutionProbe(nativeProbingRoots))

            // Invoking a non-existent dll via pinvoke cause a probe. which should invoke the call back
            try Native.NoneSuch() |> ignore with _ -> ()
K
Kevin Ransom (msft) 已提交
613
            Assert.True (nativeFound, "Failed to invoke the nativeProbingRoots callback")
614 615 616

            // Invoking a non-existent assembly causes a probe. which should invoke the call back
            try Assembly.Load("NoneSuchAssembly") |> ignore with _ -> ()
K
Kevin Ransom (msft) 已提交
617
            Assert.True (assemblyFound, "Failed to invoke the AssemblyResolve handler")
618 619 620 621 622 623

        // Here the dispose was invoked which should clear the ResolvingUnmanagedDll handler
        nativeFound <- false
        assemblyFound <- false

        try Native.NoneSuch() |> ignore with _ -> ()
K
Kevin Ransom (msft) 已提交
624
        Assert.False (nativeFound, "Invoke the nativeProbingRoots callback -- Error the ResolvingUnmanagedDll still fired ")
625 626

        try Assembly.Load("NoneSuchAssembly") |> ignore with _ -> ()
K
Kevin Ransom (msft) 已提交
627
        Assert.False (assemblyFound, "Invoke the assemblyProbingRoots callback -- Error the AssemblyResolve still fired ")
628 629
#endif

K
Kevin Ransom (msft) 已提交
630
    [<Fact>]
631 632 633 634 635 636 637 638 639 640 641 642 643
    member __.``Verify that Dispose on AssemblyResolveHandler unhooks AssemblyResolve event handler``() =

        let mutable assemblyFound = false
        let assemblyProbingPaths () =
            assemblyFound <- true
            Seq.empty<string>

        // Set up AssemblyResolver to resolve dll's
        do
            use dp = new AssemblyResolveHandler(AssemblyResolutionProbe(assemblyProbingPaths))

            // Invoking a non-existent assembly causes a probe. which should invoke the call back
            try Assembly.Load("NoneSuchAssembly") |> ignore with _ -> ()
K
Kevin Ransom (msft) 已提交
644
            Assert.True (assemblyFound, "Failed to invoke the AssemblyResolve handler")
645 646 647 648 649

        // Here the dispose was invoked which should clear the ResolvingUnmanagedDll handler
        assemblyFound <- false

        try Assembly.Load("NoneSuchAssembly") |> ignore with _ -> ()
K
Kevin Ransom (msft) 已提交
650
        Assert.False (assemblyFound, "Invoke the assemblyProbingRoots callback -- Error the AssemblyResolve still fired ")
K
Kevin Ransom (msft) 已提交
651 652


K
Kevin Ransom (msft) 已提交
653
    [<Fact>]
K
Kevin Ransom (msft) 已提交
654 655 656 657
    member __.``Verify that #help produces help text for fsi + dependency manager``() =
        let expected = [|
            """  F# Interactive directives:"""
            """"""
K
Kevin Ransom (msft) 已提交
658 659 660 661 662 663 664
            """    #r "file.dll";;                               // Reference (dynamically load) the given DLL"""
            """    #i "package source uri";;                     // Include package source uri when searching for packages"""
            """    #I "path";;                                   // Add the given search path for referenced DLLs"""
            """    #load "file.fs" ...;;                         // Load the given file(s) as if compiled and referenced"""
            """    #time ["on"|"off"];;                          // Toggle timing on/off"""
            """    #help;;                                       // Display help"""
            """    #quit;;                                       // Exit"""
K
Kevin Ransom (msft) 已提交
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
            """"""
            """  F# Interactive command line options:"""
            """"""

            // this is the end of the line each different platform has a different mechanism for starting fsi
            // Actual output looks similar to: """      See 'testhost --help' for options"""
            """--help' for options"""

            """"""
            """"""
        |]

        let mutable found = 0
        let lines = System.Collections.Generic.List()
        use sawExpectedOutput = new ManualResetEvent(false)
        let verifyOutput (line: string) =
            let compareLine (s: string) =
                if s = "" then line = ""
                else line.EndsWith(s)
            lines.Add(line)
            match expected |> Array.tryFind(compareLine) with
            | None -> ()
            | Some t ->
                found <- found + 1
                if found = expected.Length then sawExpectedOutput.Set() |> ignore

        let text = "#help"
        use output = new RedirectConsoleOutput()
        use script = new FSharpScript(quiet = false, langVersion = LangVersion.V47)
        let mutable found = 0
        output.OutputProduced.Add (fun line -> verifyOutput line)
        let opt = script.Eval(text) |> getValue
        Assert.True(sawExpectedOutput.WaitOne(TimeSpan.FromSeconds(5.0)), sprintf "Expected to see error sentinel value written\nexpected:%A\nactual:%A" expected lines)


K
Kevin Ransom (msft) 已提交
700
    [<Fact>]
K
Kevin Ransom (msft) 已提交
701 702 703 704
    member __.``Verify that #help produces help text for fsi + dependency manager language version preview``() =
        let expected = [|
            """  F# Interactive directives:"""
            """"""
K
Kevin Ransom (msft) 已提交
705 706 707 708 709 710 711 712 713
            """    #r "file.dll";;                               // Reference (dynamically load) the given DLL"""
            """    #i "package source uri";;                     // Include package source uri when searching for packages"""
            """    #I "path";;                                   // Add the given search path for referenced DLLs"""
            """    #load "file.fs" ...;;                         // Load the given file(s) as if compiled and referenced"""
            """    #time ["on"|"off"];;                          // Toggle timing on/off"""
            """    #help;;                                       // Display help"""
            """    #r "nuget:FSharp.Data, 3.1.2";;               // Load Nuget Package 'FSharp.Data' version '3.1.2'"""
            """    #r "nuget:FSharp.Data";;                      // Load Nuget Package 'FSharp.Data' with the highest version"""
            """    #quit;;                                       // Exit"""
K
Kevin Ransom (msft) 已提交
714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
            """"""
            """  F# Interactive command line options:"""
            """"""

            // this is the end of the line each different platform has a different mechanism for starting fsi
            // Actual output looks similar to: """      See 'testhost --help' for options"""
            """--help' for options"""

            """"""
            """"""
        |]

        let mutable found = 0
        let lines = System.Collections.Generic.List()
        use sawExpectedOutput = new ManualResetEvent(false)
        let verifyOutput (line: string) =
            let compareLine (s: string) =
                if s = "" then line = ""
                else line.EndsWith(s)
            lines.Add(line)
            match expected |> Array.tryFind(compareLine) with
            | None -> ()
            | Some t ->
                found <- found + 1
                if found = expected.Length then sawExpectedOutput.Set() |> ignore

        let text = "#help"
        use output = new RedirectConsoleOutput()
        use script = new FSharpScript(quiet = false, langVersion = LangVersion.Preview)
        let mutable found = 0
        output.OutputProduced.Add (fun line -> verifyOutput line)
        let opt = script.Eval(text) |> getValue
        Assert.True(sawExpectedOutput.WaitOne(TimeSpan.FromSeconds(5.0)), sprintf "Expected to see error sentinel value written\nexpected:%A\nactual:%A" expected lines)
K
Kevin Ransom (msft) 已提交
747

748 749 750 751 752 753 754 755 756 757 758 759 760
    [<Fact>]
    member __.``Ensure resolutions file doesn't contain lines with only empty values``() =
        use tempDir = getTempDir ()
        let dpm = new FSharpDependencyManager(Some(tempDir.ToString()))
        let resolutionResult = dpm.PrepareDependencyResolutionFiles(".fsx", [("r", "FParsec,Version=1.1.1")], "netcoreapp3.1", RidHelpers.platformRid)
        let resolutionLines =
            match resolutionResult.resolutionsFile with
            | Some path -> File.ReadAllLines(path)
            | None -> failwith "Expected resolutions file to be created."
        let improperResolutionLines =
            resolutionLines
            |> Array.filter (fun l -> l.StartsWith(","))
        Assert.Empty(improperResolutionLines)