DependencyManagerInteractiveTests.fs 39.0 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
12
open FSharp.Compiler.DependencyManager
D
Don Syme 已提交
13
open FSharp.Compiler.Diagnostics
14
open FSharp.Test.ScriptHelpers
15
open FSharp.DependencyManager.Nuget
K
Kevin Ransom (msft) 已提交
16

17 18
open Internal.Utilities

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

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

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

27 28
type DependencyManagerInteractiveTests() =

D
Don Syme 已提交
29
    let getValue ((value: Result<FsiValue option, exn>), (errors: FSharpDiagnostic[])) =
30 31 32 33 34 35
        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

D
Don Syme 已提交
36
    let getErrors ((_value: Result<FsiValue option, exn>), (errors: FSharpDiagnostic[])) =
K
Kevin Ransom (msft) 已提交
37
        errors
38

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

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

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

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

        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)
81 82 83 84

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

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

K
Kevin Ransom (msft) 已提交
91
        let result = dp.Resolve(idm, ".fsx", [|"r", "FSharp.Data,3.3.3"|], reportError, "net6.0")
K
Kevin Ransom (msft) 已提交
92 93 94 95
        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)
96 97
        ()

98
    [<Fact>]
D
Don Syme 已提交
99
    member _.``Dependency Manager Reports package root for nuget package with no build artifacts``() =
100 101 102 103 104 105 106 107 108 109 110 111 112

        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)

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

K
Kevin Ransom (msft) 已提交
113
        let result = dp.Resolve(idm, ".fsx", [|"r", "Microsoft.Data.Sqlite, 3.1.8"|], reportError, "net6.0")
114 115 116 117 118 119
        Assert.Equal(true, result.Success)
        Assert.True((result.Resolutions |> Seq.length) > 1)
        Assert.Equal(1, result.SourceFiles |> Seq.length)
        Assert.True(Option.isSome(result.Roots |> Seq.tryFind(fun root -> root.EndsWith("microsoft.data.sqlite/3.1.8/"))))
        ()

B
Brett V. Forsgren 已提交
120

K
Kevin Ransom (msft) 已提交
121
    [<Fact>]
D
Don Syme 已提交
122
    member _.``Dependency add with nonexistent package should fail``() =
123 124 125 126 127 128 129 130 131 132

        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)
133 134 135 136

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

        if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
K
Kevin Ransom (msft) 已提交
137
            let result = dp.Resolve(idm, ".fsx", [|"r", "System.Collections.Immutable.DoesNotExist"|], reportError, "net472")
K
Kevin Ransom (msft) 已提交
138 139 140 141
            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)
142

K
Kevin Ransom (msft) 已提交
143
        let result = dp.Resolve(idm, ".fsx", [|"r", "System.Collections.Immutable.DoesNotExist"|], reportError, "net6.0")
K
Kevin Ransom (msft) 已提交
144 145 146 147
        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)
148 149
        ()

B
Brett V. Forsgren 已提交
150

D
Don Syme 已提交
151
    [<Fact(Skip="failing on main")>]
D
Don Syme 已提交
152
    member _.``Multiple Instances of DependencyProvider should be isolated``() =
153

154 155 156 157 158 159 160 161 162 163
        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)
164 165 166

        let idm1 = dp1.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")
        if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
K
Kevin Ransom (msft) 已提交
167
            let result1 = dp1.Resolve(idm1, ".fsx", [|"r", "FSharp.Data,3.3.3"|], reportError, "net472")
K
Kevin Ransom (msft) 已提交
168 169
            Assert.Equal(true, result1.Success)
            Assert.Equal(1, result1.Resolutions |> Seq.length)
170
            Assert.True((result1.Resolutions |> Seq.head).Contains("/net45/"))
K
Kevin Ransom (msft) 已提交
171
            Assert.Equal(1, result1.SourceFiles |> Seq.length)
172
            Assert.Equal(2, result1.Roots |> Seq.length)
K
Kevin Ransom (msft) 已提交
173
            Assert.True((result1.Roots |> Seq.head).EndsWith("/fsharp.data/3.3.3/"))
174
            Assert.True((result1.Roots |> Seq.last).EndsWith("/microsoft.netframework.referenceassemblies/1.0.0/"))
175

K
Kevin Ransom (msft) 已提交
176
        let result2 = dp1.Resolve(idm1, ".fsx", [|"r", "FSharp.Data,3.3.3"|], reportError, "net6.0")
K
Kevin Ransom (msft) 已提交
177 178
        Assert.Equal(true, result2.Success)
        Assert.Equal(1, result2.Resolutions |> Seq.length)
179
        let expected2 = "/netstandard2.0/"
K
Kevin Ransom (msft) 已提交
180 181 182 183
        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/"))
184

185
        use dp2 = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))
186 187 188
        let idm2 = dp2.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")

        if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
K
Kevin Ransom (msft) 已提交
189
            let result3 = dp2.Resolve(idm2, ".fsx", [|"r", "System.Json, Version=4.6.0"|], reportError, "net472")
K
Kevin Ransom (msft) 已提交
190 191
            Assert.Equal(true, result3.Success)
            Assert.Equal(1, result3.Resolutions |> Seq.length)
192
            Assert.True((result3.Resolutions |> Seq.head).Contains("/netstandard2.0/"))
K
Kevin Ransom (msft) 已提交
193 194 195
            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/"))
196

K
Kevin Ransom (msft) 已提交
197
        let result4 = dp2.Resolve(idm2, ".fsx", [|"r", "System.Json, Version=4.6.0"|], reportError, "net6.0")
K
Kevin Ransom (msft) 已提交
198 199
        Assert.Equal(true, result4.Success)
        Assert.Equal(1, result4.Resolutions |> Seq.length)
200
        let expected4 = "/netstandard2.0/"
K
Kevin Ransom (msft) 已提交
201 202 203 204
        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/"))
205 206
        ()

K
Kevin Ransom (msft) 已提交
207
    [<Fact>]
D
Don Syme 已提交
208
    member _.``Nuget Reference package with dependencies we should get package roots and dependent references``() =
209

210 211 212 213 214 215 216 217 218
        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)
219 220 221 222

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

        if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
K
Kevin Ransom (msft) 已提交
223
            let result1 = dp1.Resolve(idm1, ".fsx", [|"r", "Microsoft.Extensions.Configuration.Abstractions, 3.1.1"|], reportError, "net472")
K
Kevin Ransom (msft) 已提交
224 225
            Assert.Equal(true, result1.Success)
            Assert.Equal(6, result1.Resolutions |> Seq.length)
226
            Assert.True((result1.Resolutions |> Seq.head).Contains("/netstandard2.0/"))
K
Kevin Ransom (msft) 已提交
227
            Assert.Equal(1, result1.SourceFiles |> Seq.length)
228
            Assert.Equal(7, result1.Roots |> Seq.length)
K
Kevin Ransom (msft) 已提交
229
            Assert.True((result1.Roots |> Seq.head).EndsWith("/microsoft.extensions.configuration.abstractions/3.1.1/"))
230 231 232

        // 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) 已提交
233
        let result2 = dp1.Resolve(idm1, ".fsx", [|"r", "Microsoft.Extensions.Configuration.Abstractions, 3.1.1"|], reportError, "net6.0")
K
Kevin Ransom (msft) 已提交
234 235
        Assert.Equal(true, result2.Success)
        Assert.Equal(2, result2.Resolutions |> Seq.length)
236
        let expected = "/netcoreapp3.1/"
K
Kevin Ransom (msft) 已提交
237 238 239 240
        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/"))
241 242 243
        ()

/// Native dll resolution is not implemented on desktop
244
#if NETCOREAPP
245
    [<Fact(Skip="downloads very large ephemeral packages"); >]
D
Don Syme 已提交
246
    member _.``Script using TorchSharp``() =
247 248 249 250 251 252 253 254 255
        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) 已提交
256
            use script = new scriptHost()
257 258
            let opt = script.Eval(text) |> getValue
            let value = opt.Value
K
Kevin Ransom (msft) 已提交
259 260
            Assert.Equal(typeof<string>, value.ReflectionType)
            Assert.Equal("cpu", value.ReflectionValue :?> string)
261 262 263
        ()


K
Kevin Ransom (msft) 已提交
264
    [<Fact>]
D
Don Syme 已提交
265
    member _.``Use Dependency Manager to restore packages with native dependencies, build and run script that depends on the results``() =
266
        let packagemanagerlines = [|
K
Kevin Ransom (msft) 已提交
267 268
            "r", "Microsoft.ML,version=1.4.0-preview"
            "r", "Microsoft.ML.AutoML,version=0.16.0-preview"
269
            "r", "Microsoft.Data.Analysis,version=0.4.0"
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
        |]

        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")
K
Kevin Ransom (msft) 已提交
290
            dp.Resolve(idm, ".fsx", packagemanagerlines, reportError, "net6.0")
291

K
Kevin Ransom (msft) 已提交
292
        Assert.True(result.Success, "resolve failed")
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

        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
320
open Microsoft.Data.Analysis
321 322 323 324 325 326 327 328 329 330 331

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""
332 333 334
let housingData = DataFrame.LoadCsv(housingPath)
let randomIndices = (Shuffle(Enumerable.Range(0, (int (housingData.Rows.Count) - 1)).ToArray()))
let testSize = int (float (housingData.Rows.Count) * 0.1)
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
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) 已提交
358
        Assert.Equal(123, value.ReflectionValue :?> int32)
359

K
Kevin Ransom (msft) 已提交
360
    [<Fact>]
D
Don Syme 已提交
361
    member _.``Use NativeResolver to resolve native dlls.``() =
362
        let packagemanagerlines = [|
K
Kevin Ransom (msft) 已提交
363 364
            "r", "Microsoft.ML,version=1.4.0-preview"
            "r", "Microsoft.ML.AutoML,version=0.16.0-preview"
365
            "r", "Microsoft.Data.Analysis,version=0.4.0"
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
        |]

        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")
K
Kevin Ransom (msft) 已提交
386
            dp.Resolve(idm, ".fsx", packagemanagerlines, reportError, "net6.0")
387

K
Kevin Ransom (msft) 已提交
388
        Assert.True(result.Success, "resolve failed")
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404

        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
405
open Microsoft.Data.Analysis
406 407 408 409 410 411 412 413 414 415 416

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""
417 418 419
let housingData = DataFrame.LoadCsv(housingPath)
let randomIndices = (Shuffle(Enumerable.Range(0, (int (housingData.Rows.Count) - 1)).ToArray()))
let testSize = int (float (housingData.Rows.Count) * 0.1)
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
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) 已提交
440
        Assert.Equal(123, value.ReflectionValue :?> int32)
441

K
Kevin Ransom (msft) 已提交
442
    [<Fact>]
D
Don Syme 已提交
443
    member _.``Use AssemblyResolver to resolve assemblies``() =
444
        let packagemanagerlines = [|
K
Kevin Ransom (msft) 已提交
445 446
            "r", "Microsoft.ML,version=1.4.0-preview"
            "r", "Microsoft.ML.AutoML,version=0.16.0-preview"
447
            "r", "Microsoft.Data.Analysis,version=0.4.0"
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
        |]

        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")
K
Kevin Ransom (msft) 已提交
467
            dp.Resolve(idm, ".fsx", packagemanagerlines, reportError, "net6.0")
468

K
Kevin Ransom (msft) 已提交
469
        Assert.True(result.Success, "resolve failed")
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500

        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) 已提交
501
        Assert.Equal(123, value.ReflectionValue :?> int32)
502

K
Kevin Ransom (msft) 已提交
503
    [<Fact>]
D
Don Syme 已提交
504
    member _.``Verify that referencing FSharp.Core fails with FSharp Scripts``() =
K
Kevin Ransom (msft) 已提交
505
        let packagemanagerlines = [| "r", "FSharp.Core,version=4.7.1" |]
K
Kevin Ransom (msft) 已提交
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523

        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")
K
Kevin Ransom (msft) 已提交
524
            dp.Resolve(idm, ".fsx", packagemanagerlines, reportError, "net6.0")
K
Kevin Ransom (msft) 已提交
525 526

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

K
Kevin Ransom (msft) 已提交
529
    [<Fact>]
D
Don Syme 已提交
530
    member _.``Verify that referencing FSharp.Core succeeds with CSharp Scripts``() =
K
Kevin Ransom (msft) 已提交
531
        let packagemanagerlines = [| "r", "FSharp.Core,version=4.7.1" |]
K
Kevin Ransom (msft) 已提交
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549

        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")
K
Kevin Ransom (msft) 已提交
550
            dp.Resolve(idm, ".csx", packagemanagerlines, reportError, "net6.0")
K
Kevin Ransom (msft) 已提交
551

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

554

K
Kevin Ransom (msft) 已提交
555
    [<Fact>]
D
Don Syme 已提交
556
    member _.``Verify that Dispose on DependencyProvider unhooks ResolvingUnmanagedDll event handler``() =
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575

        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) 已提交
576
            Assert.True (found, "Failed to invoke the nativeProbingRoots callback")
577 578 579 580

        // Here the dispose was invoked which should clear the ResolvingUnmanagedDll handler
        found <- false
        try Native.NoneSuch() |> ignore with _ -> ()
K
Kevin Ransom (msft) 已提交
581
        Assert.False (found, "Invoke the nativeProbingRoots callback -- Error the ResolvingUnmanagedDll still fired ")
582 583 584 585 586

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

        if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
K
Kevin Ransom (msft) 已提交
587
            let result = dp.Resolve(idm, ".fsx", [|"r", "FSharp.Data,3.3.3"|], reportError, "net472")
K
Kevin Ransom (msft) 已提交
588 589 590
            Assert.Equal(true, result.Success)
            Assert.Equal(1, result.Resolutions |> Seq.length)
            Assert.Equal(1, result.SourceFiles |> Seq.length)
591
            Assert.Equal(2, result.Roots |> Seq.length)
592

K
Kevin Ransom (msft) 已提交
593
        let result = dp.Resolve(idm, ".fsx", [|"r", "FSharp.Data,3.3.3"|], reportError, "net6.0")
K
Kevin Ransom (msft) 已提交
594 595 596 597
        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)
598 599
        ()

600

K
Kevin Ransom (msft) 已提交
601
    [<Fact>]
D
Don Syme 已提交
602
    member _.``Verify that Dispose on DependencyProvider unhooks ResolvingUnmanagedDll and AssemblyResolver event handler``() =
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619

        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) 已提交
620
            Assert.True (nativeFound, "Failed to invoke the nativeProbingRoots callback")
621 622 623

            // Invoking a non-existent assembly causes a probe. which should invoke the call back
            try Assembly.Load("NoneSuchAssembly") |> ignore with _ -> ()
K
Kevin Ransom (msft) 已提交
624
            Assert.True (assemblyFound, "Failed to invoke the AssemblyResolve handler")
625 626 627 628 629 630

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

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

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

K
Kevin Ransom (msft) 已提交
637
    [<Fact>]
D
Don Syme 已提交
638
    member _.``Verify that Dispose on AssemblyResolveHandler unhooks AssemblyResolve event handler``() =
639 640 641 642 643 644 645 646 647 648 649 650

        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) 已提交
651
            Assert.True (assemblyFound, "Failed to invoke the AssemblyResolve handler")
652 653 654 655 656

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

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

659
    [<Fact>]
D
Don Syme 已提交
660
    member _.``Verify that Dispose cleans up the native paths added``() =
661 662 663 664 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
        let nativeProbingRoots () = Seq.empty<string>

        let appendSemiColon (p:string) =
            if not(p.EndsWith(";", StringComparison.OrdinalIgnoreCase)) then
                p + ";"
            else
                p

        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 initialPath:string = null
        let mutable currentPath:string = null
        let mutable finalPath:string =  null
        do
            initialPath <- appendSemiColon (Environment.GetEnvironmentVariable("PATH"))
            use dp = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))
            let idm = dp.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")
            let mutable currentPath:string = null
            if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
                let result = dp.Resolve(idm, ".fsx", [|"r", "Microsoft.Data.Sqlite,3.1.7"|], reportError, "netstandard2.0")
                Assert.Equal(true, result.Success)
                currentPath <-  appendSemiColon (Environment.GetEnvironmentVariable("PATH"))
        finalPath <- appendSemiColon (Environment.GetEnvironmentVariable("PATH"))
        Assert.True(currentPath <> initialPath)     // The path was modified by #r "nuget: ..."
        Assert.Equal(finalPath, initialPath)        // IDispose correctly cleaned up the path

        initialPath <- null
        currentPath <- null
        finalPath <-  null
        do
            initialPath <- appendSemiColon (Environment.GetEnvironmentVariable("PATH"))
            let mutable currentPath:string = null
            use dp = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))
            let idm = dp.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")
K
Kevin Ransom (msft) 已提交
700
            let result = dp.Resolve(idm, ".fsx", [|"r", "Microsoft.Data.Sqlite,3.1.7"|], reportError, "net6.0")
701 702 703 704 705 706 707
            Assert.Equal(true, result.Success)
            currentPath <-  appendSemiColon (Environment.GetEnvironmentVariable("PATH"))
        finalPath <- appendSemiColon (Environment.GetEnvironmentVariable("PATH"))
        Assert.True(currentPath <> initialPath)      // The path was modified by #r "nuget: ..."
        Assert.Equal(finalPath, initialPath)        // IDispose correctly cleaned up the path

        ()
K
Kevin Ransom (msft) 已提交
708

K
Kevin Ransom (msft) 已提交
709
    [<Fact>]
D
Don Syme 已提交
710
    member _.``Verify that #help produces help text for fsi + dependency manager``() =
K
Kevin Ransom (msft) 已提交
711 712 713
        let expected = [|
            """  F# Interactive directives:"""
            """"""
K
Kevin Ransom (msft) 已提交
714 715 716 717 718
            """    #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"""
J
jkone27 已提交
719
            """    #clear;;                                      // Clear screen"""
K
Kevin Ransom (msft) 已提交
720 721
            """    #help;;                                       // Display help"""
            """    #quit;;                                       // Exit"""
K
Kevin Ransom (msft) 已提交
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 747 748 749 750 751 752 753 754 755 756
            """"""
            """  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) 已提交
757
    [<Fact>]
D
Don Syme 已提交
758
    member _.``Verify that #help produces help text for fsi + dependency manager language version preview``() =
K
Kevin Ransom (msft) 已提交
759 760 761
        let expected = [|
            """  F# Interactive directives:"""
            """"""
K
Kevin Ransom (msft) 已提交
762 763 764 765 766 767 768 769
            """    #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"""
J
jkone27 已提交
770
            """    #clear;;                                      // Clear screen"""
K
Kevin Ransom (msft) 已提交
771
            """    #quit;;                                       // Exit"""
K
Kevin Ransom (msft) 已提交
772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
            """"""
            """  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)
805 806 807


    [<Fact>]
D
Don Syme 已提交
808
    member _.``Verify that timeout --- times out and fails``() =
809 810 811 812 813 814 815 816 817
        let nativeProbingRoots () = Seq.empty<string>
        let mutable foundCorrectError = false
        let mutable foundWrongError = false

        use dp = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))
        let reportError =
            let report errorType code message =
                match errorType with
                | ErrorReportType.Error ->
818
                    if code = 3217 then foundCorrectError <- true
819 820 821 822 823
                    else foundWrongError <- true
                | ErrorReportType.Warning -> printfn "PackageManagementWarning %d : %s" code message
            ResolvingErrorReport (report)

        let idm = dp.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")
K
Kevin Ransom (msft) 已提交
824
        let result = dp.Resolve(idm, ".fsx", [|"r", "FSharp.Data,3.3.3"|], reportError, "net6.0", timeout=0)           // Fail in 0 milliseconds
825 826 827 828 829 830
        Assert.Equal(false, result.Success)
        Assert.Equal(foundCorrectError, true)
        Assert.Equal(foundWrongError, false)
        ()

    [<Fact>]
D
Don Syme 已提交
831
    member _.``Verify that script based timeout overrides api based - timeout on script``() =
832 833 834 835 836 837 838 839 840
        let nativeProbingRoots () = Seq.empty<string>
        let mutable foundCorrectError = false
        let mutable foundWrongError = false

        use dp = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))
        let reportError =
            let report errorType code message =
                match errorType with
                | ErrorReportType.Error ->
841
                    if code = 3217 then foundCorrectError <- true
842 843 844 845 846
                    else foundWrongError <- true
                | ErrorReportType.Warning -> printfn "PackageManagementWarning %d : %s" code message
            ResolvingErrorReport (report)

        let idm = dp.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")
K
Kevin Ransom (msft) 已提交
847
        let result = dp.Resolve(idm, ".fsx", [|"r", "FSharp.Data,3.3.3"; "r", "timeout=0"|], reportError, "net6.0", null, "", "", "", -1)           // Wait forever
848 849 850 851 852 853
        Assert.Equal(false, result.Success)
        Assert.Equal(foundCorrectError, true)
        Assert.Equal(foundWrongError, false)
        ()

    [<Fact>]
D
Don Syme 已提交
854
    member _.``Verify that script based timeout overrides api based - timeout on api , forever on script``() =
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
        let nativeProbingRoots () = Seq.empty<string>
        let mutable foundCorrectError = false
        let mutable foundWrongError = false

        use dp = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))
        let reportError =
            let report errorType code message =
                match errorType with
                | ErrorReportType.Error ->
                    if code = 3401 then foundCorrectError <- true
                    else foundWrongError <- true
                | ErrorReportType.Warning -> printfn "PackageManagementWarning %d : %s" code message
            ResolvingErrorReport (report)

        let idm = dp.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")
K
Kevin Ransom (msft) 已提交
870
        let result = dp.Resolve(idm, ".fsx", [|"r", "FSharp.Data,3.3.3"; "r", "timeout=none"|], reportError, "net6.0", null, "", "", "", -1)           // Wait forever
871 872 873 874 875 876
        Assert.Equal(true, result.Success)
        Assert.Equal(foundCorrectError, false)
        Assert.Equal(foundWrongError, false)
        ()