Welcome to mirror list, hosted at ThFree Co, Russian Federation.

Interactive.fs « MonoDevelop.FSharp.Tests « fsharpbinding « external « main - github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 802a33a067895f968a246fa5870c70b6dc62b7bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
namespace MonoDevelopTests
open System.IO
open System.Reflection
open System.Runtime.CompilerServices
open System.Threading
open System.Threading.Tasks
open FsUnit
open NUnit.Framework
open MonoDevelop.Core
open MonoDevelop.Core.ProgressMonitoring
open MonoDevelop.Ide.Editor
open MonoDevelop.FSharp
open MonoDevelop.Projects
open Mono.TextEditor

[<TestFixture>]
module Interactive =
    let toTask computation : Task = Async.StartAsTask computation :> _

    let createSession() =
        async {
            let (/) a b = Path.Combine(a,b)
            let testDllFolder = Assembly.GetExecutingAssembly().Location |> Path.GetDirectoryName

            let pathToExe = "\"" + testDllFolder/"MonoDevelop.FSharpInteractive.Service.exe\""
            let ses = new InteractiveSession(pathToExe)
            ses.StartReceiving()
            do! ses.PromptReady |> Async.AwaitEvent
            return ses
        }

    [<Test;AsyncStateMachine(typeof<Task>)>]
    let ``Interactive receives completions``() =
        async {
            let! session = createSession()
            session.SendCompletionRequest "Lis" 3
            let! completions = session.CompletionsReceived |> Async.AwaitEvent
            let results = completions |> Array.map(fun c -> c.displayText)
            session.KillNow()
            results |> should contain "List"
        } |> toTask

    [<Test;AsyncStateMachine(typeof<Task>)>]
    let ``Interactive receives parameter hints``() =
        async {
            let! session = createSession()
            session.SendParameterHintRequest "System.DateTime.Now.AddDays(" 28
            let! parameters = session.ParameterHintReceived |> Async.AwaitEvent
            let results = parameters
                          |> Array.map
                               (function
                                | MonoDevelop.FSharp.Shared.ParameterTooltip.ToolTip (_signature, _doc, parameters) -> parameters
                                | MonoDevelop.FSharp.Shared.ParameterTooltip.EmptyTip -> [||])

            session.KillNow()
            results |> should equal [| [|"value"|] |]
        } |> toTask

    let sendInput (session:InteractiveSession) input =
        session.SendInput input None

    [<Test;AsyncStateMachine(typeof<Task>)>]
    let ``Interactive evaluates 1+1``() =
        async {
            let! session = createSession()
            sendInput session "1+1;;"
            let! results = session.TextReceived |> Async.AwaitEvent
            session.KillNow()
            results |> should equal "val it : int = 2\n"
        } |> toTask

    [<Test;AsyncStateMachine(typeof<Task>)>]
    let ``Interactive evaluates multiline expression``() =
        async {
            let! session = createSession()
            sendInput session "let myfun x="
            sendInput session "    if (x > 0) then 'a'"
            sendInput session "    else 'b'"
            sendInput session ";;"

            let! results = session.TextReceived |> Async.AwaitEvent
            session.KillNow()
            results |> should equal "val myfun : x:int -> char\n"
        } |> toTask

    [<Test;AsyncStateMachine(typeof<Task>)>]
    let ``Interactive evaluates complex type``() =
        async {
            let! session = createSession()
            sendInput session "type CmdResult = ErrorLevel of string * int;;"
            let! results = session.TextReceived |> Async.AwaitEvent
            session.KillNow()
            results |> should equal "type CmdResult = | ErrorLevel of string * int\n"
        } |> toTask

    [<Test;AsyncStateMachine(typeof<Task>)>]
    let ``Bug 56611``() =
        async {
            let! session = createSession()
            sendInput session "type O = { X:string };;"
            sendInput session "[| {X=\"\"} |];;"
            do! session.TextReceived |> Async.AwaitEvent |> Async.Ignore
            do! session.TextReceived |> Async.AwaitEvent |> Async.Ignore
            let! results = session.TextReceived |> Async.AwaitEvent
            session.KillNow()
            results |> should equal "val it : O [] = [|{X = \"\";}|]\n"
        } |> toTask

    [<Test;AsyncStateMachine(typeof<Task>)>]
    let ``Interactive send references uses real assemblies #43307``() =
        async {
            let! session = createSession()
            let sln = UnitTests.Util.GetSampleProject ("bug43307", "bug43307.sln")
            use monitor = UnitTests.Util.GetMonitor ()
            use! sol = Services.ProjectService.ReadWorkspaceItem (monitor, sln |> FilePath) |> Async.AwaitTask
            use project = sol.GetAllItems<FSharpProject> () |> Seq.head

            //workaround the fact that the project doesn't have a stable relative path
            //to newtonsoft.json under the test harness by removing and re-adding with known path
            let jsonAsmLoc = typeof<Newtonsoft.Json.JsonConvert>.Assembly.Location
            let jsonRef =
                project.References
                |> Seq.filter (fun r -> r.Include.Equals "Newtonsoft.Json")
                |> Seq.head
            do project.References.Remove (jsonRef) |> ignore
            project.References.Add (ProjectReference.CreateAssemblyFileReference (jsonAsmLoc |> FilePath))

            let! refs = project.GetOrderedReferences(CompilerArguments.getConfig())
            refs
            |> List.iter (fun a -> sendInput session (sprintf  @"#r ""%s"";;" a.Path))
            let finished = new AutoResetEvent(false)
            let input =
                """
                type Movie = {
                    Name : string
                    Year: int
                }
                let movies = [
                     { Name = "Bad Boys"; Year = 1995 }
                ]
                let jsonObj = Newtonsoft.Json.JsonConvert.SerializeObject(movies);;
                """
            sendInput session input

            let rec getOutput() =
                async {
                    let! output = session.TextReceived |> Async.AwaitEvent
                    if output.Contains "jsonObj" then
                        return output
                    else
                        return! getOutput()

                }
            let! results = getOutput()
            session.KillNow()
            results |> should equal "val jsonObj : string = \"[{\"Name\":\"Bad Boys\",\"Year\":1995}]\"\n"
        } |> toTask

    let getPadAndEditor() =
        FixtureSetup.initialiseMonoDevelop()
        let ctx = FsiDocumentContext()
        let doc = TextEditorFactory.CreateNewDocument()
        do
            doc.FileName <- FilePath ctx.Name

        let editor = TextEditorFactory.CreateNewEditor(ctx, doc, TextEditorType.Default)
        let pad = new FSharpInteractivePad(editor)

        let data = editor.GetContent<ITextEditorDataProvider>().GetTextEditorData()
        let textDocument = data.Document
        pad, editor, textDocument

    [<Test>]
    let ``Interactive doesn't remove prompt when text is added``() =
        let pad, editor, doc = getPadAndEditor()
        pad.SetPrompt()

        let line1 = doc.GetLine editor.CaretLine
        editor.CaretLine |> should equal 2
        doc.GetMarkers line1 |> Seq.length |> should equal 1
        pad.SetPrompt()

        let line2 = doc.GetLine editor.CaretLine
        editor.CaretLine |> should equal 3
        doc.GetMarkers line2 |> Seq.length |> should equal 1

    [<Test;AsyncStateMachine(typeof<Task>)>]
    let ``Interactive gets source file and directory``() =
        async {
            let sourceFile = Some "/SomeFolder/SomeFile.fsx"
            let! session = createSession()
            session.SendInput "printfn __SOURCE_FILE__;;" sourceFile
            let! output = session.TextReceived |> Async.AwaitEvent
            output |> should equal ("SomeFile.fsx\n")
            // ignore `val it: unit = ()`
            let! ignore = session.TextReceived |> Async.AwaitEvent
            session.SendInput "printfn __SOURCE_DIRECTORY__;;" sourceFile
            let! output = session.TextReceived |> Async.AwaitEvent
            session.KillNow()
            output |> should equal "/SomeFolder\n"
        } |> toTask

module ``Shell history`` =
    [<Test>]
    let ``Can go back``() =
        let hist = ShellHistory()
        hist.Push "1"
        hist.Up() |> should equal (Some "1")

    [<Test>]
    let ``Can go back twice``() =
        let hist = ShellHistory()
        hist.Push "1"
        hist.Push "2"
        hist.Up() |> should equal (Some "2")
        hist.Up() |> should equal (Some "1")
            
    [<Test>]
    let ``Can't go back three times``() =
        let hist = ShellHistory()
        hist.Push "1"
        hist.Push "2"
        hist.Up() |> should equal (Some "2")
        hist.Up() |> should equal (Some "1")
        hist.Up() |> should equal None

    [<Test>]
    let ``Down on empty list returns none``() =
        let hist = ShellHistory()
        hist.Down() |> should equal None

    [<Test>]
    let ``Up then down returns empty``() =
        let hist = ShellHistory()
        hist.Push "1"
        hist.Push "2"
        hist.Up() |> should equal (Some "2")
        hist.Down() |> should equal None

    [<Test>]
    let ``Up up down returns 2``() =
        let hist = ShellHistory()
        hist.Push "1"
        hist.Push "2"
        hist.Up() |> should equal (Some "2")
        hist.Up() |> should equal (Some "1")
        hist.Down() |> should equal (Some "2")
        hist.Down() |> should equal None

    [<Test>]
    let ``Up down up``() =
        let hist = ShellHistory()
        hist.Push "1"
        hist.Up() |> should equal (Some "1")
        hist.Down() |> should equal None
        hist.Up() |> should equal (Some "1")
      
    [<Test>]
    let ``Up down down down up``() =
        let hist = ShellHistory()
        hist.Push "1"
        hist.Up() |> should equal (Some "1")
        hist.Down() |> should equal None
        hist.Down() |> should equal None
        hist.Down() |> should equal None
        hist.Up() |> should equal (Some "1")