Tests/OrgAppTests/BabelSessionTests.swift
66 lines · 3838 bytes
6 symbols in this file
1import Foundation
2import Testing
3import OrgCore
4@testable import OrgApp
5
6struct BabelSessionStateTests {
7 func run(_ text: String, in folder: URL) async throws -> String {
8 let context = EditContext(revision: 0, text: text, tree: OrgParser.parse(text), selection: [2..<2])
9 guard case .success(let job) = Babel.plan(context) else { Issue.record("not planned: \(text)"); return "" }
10 let output = try await BabelRunner.run(job, fileDirectory: folder)
11 guard case .success(let edits) = Babel.finish(job, output: output, text: text) else { return "" }
12 let new = edits.sorted { $0.range.lowerBound > $1.range.lowerBound }.reduce(text) { $1.apply(to: $0) }
13 return String(new.dropFirst(text.count))
14 }
15
16 @Test func sessionsKeepState() async throws {
17 let folder = FileManager.default.temporaryDirectory.appendingPathComponent("orgstar-session-\(UUID().uuidString)")
18 try FileManager.default.createDirectory(at: folder, withIntermediateDirectories: true)
19 defer {
20 BabelSessions.shared.stopAll()
21 try? FileManager.default.removeItem(at: folder)
22 }
23 _ = try await run("#+begin_src sh :session s1\nx=5; cd /tmp\n#+end_src\n", in: folder)
24 #expect(try await run("#+begin_src sh :session s1 :results output\necho $x\n#+end_src\n", in: folder) == "\n#+RESULTS:\n: 5\n")
25 #expect(try await run("#+begin_src sh :session other :results output\necho \"[$x]\"\n#+end_src\n", in: folder) == "\n#+RESULTS:\n: []\n")
26 _ = try await run("#+begin_src python :session py :results output\na = 2\nprint('set')\n#+end_src\n", in: folder)
27 #expect(try await run("#+begin_src python :session py\na * 3\n#+end_src\n", in: folder) == "\n#+RESULTS:\n: 6\n")
28 #expect(try await run("#+begin_src python :session py :results output\nprint(a + 1)\n#+end_src\n", in: folder) == "\n#+RESULTS:\n: 3\n")
29 _ = try await run("#+begin_src python :session py :results output\nraise ValueError('x')\n#+end_src\n", in: folder)
30 #expect(try await run("#+begin_src python :session py\n[a, a]\n#+end_src\n", in: folder) == "\n#+RESULTS:\n| 2 | 2 |\n")
31 }
32}
33
34struct BabelRunnerTests {
35 @Test func refusesWithoutTheCompiler() async throws {
36 for (text, programs, message) in [
37 ("#+begin_src D\nwriteln(1);\n#+end_src\n", ["rdmd"], "rdmd isn't installed, so D blocks can't run."),
38 ("#+begin_src clojure\n1\n#+end_src\n", ["bb", "clojure"], "Neither bb nor clojure is installed, so clojure blocks can't run."),
39 ] where !programs.contains(where: BabelRunner.installed) {
40 let context = EditContext(revision: 0, text: text, tree: OrgParser.parse(text), selection: [2..<2])
41 guard case .success(let job) = Babel.plan(context) else {
42 Issue.record("not planned: \(text)")
43 continue
44 }
45 do {
46 _ = try await BabelRunner.run(job, fileDirectory: FileManager.default.temporaryDirectory)
47 Issue.record("ran: \(text)")
48 } catch let failure as BabelRunner.Failure {
49 #expect(failure.description == message)
50 }
51 }
52 }
53
54 @Test(.enabled(if: BabelRunner.installed("gcc")))
55 func compilesAndRunsC() async throws {
56 let text = "#+begin_src C :includes <stdio.h>\nprintf(\"%d\\n\", 6 * 7);\n#+end_src\n"
57 let context = EditContext(revision: 0, text: text, tree: OrgParser.parse(text), selection: [2..<2])
58 guard case .success(let job) = Babel.plan(context) else {
59 Issue.record("not planned")
60 return
61 }
62 let output = try await BabelRunner.run(job, fileDirectory: FileManager.default.temporaryDirectory)
63 #expect(output.stdout == "42\n")
64 #expect(output.problem == nil)
65 }
66}