aboutsummaryrefslogtreecommitdiffstats
path: root/tests/core/async/async_spec.lua
blob: c0e8992e709b42d1733ef761a36a27ddb61e7832 (plain) (blame)
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
local assert = require "luassert"
local spy = require "luassert.spy"
local match = require "luassert.match"
local a = require "nvim-lsp-installer.core.async"
local process = require "nvim-lsp-installer.process"

local function timestamp()
    local seconds, microseconds = vim.loop.gettimeofday()
    return (seconds * 1000) + math.floor(microseconds / 1000)
end

describe("async", function()
    it("should run in blocking mode", function()
        local start = timestamp()
        a.run_blocking(function()
            a.sleep(100)
        end)
        local stop = timestamp()
        local grace_ms = 25
        assert.is_true((stop - start) >= (100 - grace_ms))
    end)

    it(
        "should pass arguments to .run",
        async_test(function()
            local callback = spy.new()
            local start = timestamp()
            a.run(a.sleep, callback, 100)
            assert.wait_for(function()
                assert.spy(callback).was_called(1)
                local stop = timestamp()
                local grace_ms = 25
                assert.is_true((stop - start) >= (100 - grace_ms))
            end, 150)
        end)
    )

    it(
        "should wrap callback-style async functions",
        async_test(function()
            local stdio = process.in_memory_sink()
            local success, exit_code = a.promisify(process.spawn)("env", {
                args = {},
                env = { "FOO=BAR", "BAR=BAZ" },
                stdio_sink = stdio.sink,
            })
            assert.is_true(success)
            assert.equals(0, exit_code)
            assert.equals("FOO=BAR\nBAR=BAZ\n", table.concat(stdio.buffers.stdout, ""))
        end)
    )

    it(
        "should reject callback-style functions",
        async_test(function()
            local err = assert.has_error(function()
                a.promisify(function(arg1, cb)
                    cb(arg1, nil)
                end, true) "påskmust"
            end)
            assert.equals(err, "påskmust")
        end)
    )

    it(
        "should return all values",
        async_test(function()
            local val1, val2, val3 = a.wait(function(resolve)
                resolve(1, 2, 3)
            end)
            assert.equals(1, val1)
            assert.equals(2, val2)
            assert.equals(3, val3)
        end)
    )

    it(
        "should cancel coroutine",
        async_test(function()
            local james_bond = spy.new()
            local poutine = a.scope(function()
                a.sleep(100)
                james_bond()
            end)()
            poutine()
            a.sleep(200)
            assert.spy(james_bond).was_not.called()
        end)
    )

    it(
        "should raise error if async function raises error",
        async_test(function()
            local err = assert.has.errors(a.promisify(function()
                error "something went wrong"
            end))
            assert.is_true(match.has_match "something went wrong$"(err))
        end)
    )

    it(
        "should raise error if async function rejects",
        async_test(function()
            local err = assert.has.errors(function()
                a.wait(function(_, reject)
                    reject "This is an error"
                end)
            end)
            assert.equals("This is an error", err)
        end)
    )

    it(
        "should pass nil arguments to promisified functions",
        async_test(function()
            local fn = spy.new(function(_, _, _, _, _, _, _, cb)
                cb()
            end)
            a.promisify(fn)(nil, 2, nil, 4, nil, nil, 7)
            assert.spy(fn).was_called_with(nil, 2, nil, 4, nil, nil, 7, match.is_function())
        end)
    )

    it("should accept yielding non-promise values to parent coroutine context", function()
        local thread = coroutine.create(function(val)
            a.run_blocking(function()
                coroutine.yield(val)
            end)
        end)
        local ok, value = coroutine.resume(thread, 1337)
        assert.is_true(ok)
        assert.equals(1337, value)
    end)

    it(
        "should run all suspending functions concurrently",
        async_test(function()
            local start = timestamp()
            local function sleep(ms, ret_val)
                return function()
                    a.sleep(ms)
                    return ret_val
                end
            end
            local one, two, three, four, five = a.wait_all {
                sleep(100, 1),
                sleep(100, "two"),
                sleep(100, "three"),
                sleep(100, 4),
                sleep(100, 5),
            }
            local grace = 50
            local delta = timestamp() - start
            assert.is_true(delta <= (100 + grace))
            assert.is_true(delta >= (100 - grace))
            assert.equals(1, one)
            assert.equals("two", two)
            assert.equals("three", three)
            assert.equals(4, four)
            assert.equals(5, five)
        end)
    )
end)