Tests/OrgCoreTests/CompletionTests.swift
64 lines · 3732 bytes
1import Foundation
2import Testing
3@testable import OrgCore
4
5struct CompletionTests {
6 static let oracle = ProcessInfo.processInfo.environment["ORGSTAR_SKIP_ORACLE"] == nil
7
8 func complete(_ text: String, _ caret: Int? = nil, knownTags: [String] = []) -> Completion? {
9 let caret = caret ?? text.utf16.count
10 let context = EditContext(revision: 0, text: text, tree: OrgParser.parse(text), selection: [caret..<caret], knownTags: { knownTags })
11 return OrgCompletion.at(context)
12 }
13
14 static let cases: [(String, Int?)] = [
15 ("#+TI", nil), ("#+", nil), ("#+ti", nil), ("#+BEGIN_S", nil),
16 ("* T", nil), ("* ", nil), ("* D x", 3),
17 ("* H :work:\n* I :", nil), ("* H :work:\n* I :w", nil), ("* H :a:b:\n* I :x:", nil), ("* H :a:b:\n* I :a:", nil),
18 ("#+TAGS: work home(h)\n* H :", nil),
19 ("* H\n:PROPERTIES:\n:A: 1\n:\n:END:\n", 24), ("* H\n:PROPERTIES:\n:A: 1\n:CU\n:END:\n", 26),
20 ("* H\n:PROPERTIES:\n:A: 1\n:END:\n* I\n:PROPERTIES:\n:\n:END:\n", 46),
21 ("x \\alp", nil), ("x \\Alp", nil),
22 ("* Foo bar\n* TODO [#A] Baz [1/2] :t:\n[[*", nil), ("* Foo bar\n[[*Fo", nil),
23 ("#+STARTUP: in", nil), ("#+STARTUP: hidestars s", nil), ("#+OPTIONS: to", nil), ("#+PRIORITIES: ", nil),
24 ("#+begin_src py", nil), ("#+begin_src python :ses", nil),
25 ("#+BEGIN: clocktable :max", nil),
26 ("#+LINK: gh https://github.com/%s\n[[g", nil),
27 ("text\n:LO", nil), ("text\n:LOGBOOK:\n- x\n:END:\n:L", nil), ("* H\ntext\n:", nil),
28 ("plain text", nil),
29 ]
30
31 @Test(.enabled(if: oracle))
32 func matchesPcomplete() throws {
33 let form = """
34 (let ((r (progn (require 'ox) (org-load-export-backends) (pcomplete-completions-at-point))) out)
35 (setq out (if (null r) "none"
36 (let* ((beg (nth 0 r))
37 (all (delete-dups (all-completions (buffer-substring-no-properties beg (point)) (nth 2 r)))))
38 (mapconcat #'identity (cons (number-to-string (1- beg)) (sort all #'string<)) "\\n"))))
39 (erase-buffer)
40 (insert out))
41 """
42 let results = try EmacsOracle.run(Self.cases.map { EmacsOracle.Case(text: $0.0, point: ($0.1 ?? $0.0.count) + 1, form: form) })
43 for ((text, caret), result) in zip(Self.cases, results) {
44 let completion = complete(text, caret)
45 let ours = completion.map { c in ([String(c.range.lowerBound)] + c.candidates.sorted()).joined(separator: "\n") } ?? "none"
46 let emacs = result.text
47 let a = Set(ours.split(separator: "\n")), b = Set(emacs.split(separator: "\n"))
48 #expect(ours == emacs, "\(text.debugDescription) @\(caret ?? text.count)\nonly ours: \(a.subtracting(b).sorted())\nonly emacs: \(b.subtracting(a).sorted()) \(result.error)")
49 }
50 }
51
52 @Test func addsLinkTypesWorkspaceTagsAndTemplates() {
53 #expect(complete("[[ht")?.candidates == ["http:", "https:"])
54 #expect(complete("* H :", knownTags: ["home", "work"])?.candidates == ["home:", "work:"])
55 #expect(complete("#+TAGS: a\n* H :", knownTags: ["home"])?.candidates == ["a:"])
56 let template = complete(" <s")!
57 #expect(template.kind == .template && template.range == 0..<4 && template.candidates == ["<s"])
58 #expect(template.insertion("<s") == ("#+begin_src \n#+end_src", 12))
59 #expect(complete("<q")!.insertion("<q") == ("#+begin_quote\n#+end_quote", 13))
60 #expect(complete("<h")!.insertion("<h") == ("#+begin_export html\n#+end_export", 19))
61 #expect(complete("<L")!.insertion("<L") == ("#+latex: ", 9))
62 #expect(complete("text <s") == nil)
63 }
64}