aboutsummaryrefslogtreecommitdiff
path: root/test/unit/helpers.moon
blob: f533b9a1c6251495426159d134d5397a3538d928 (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
ffi = require 'ffi'
lpeg = require 'lpeg'
formatc = require 'test.unit.formatc'
Set = require 'test.unit.set'
Preprocess = require 'test.unit.preprocess'
Paths = require 'test.config.paths'

-- add some standard header locations
for i,p in ipairs(Paths.include_paths)
  Preprocess.add_to_include_path(p)

-- load neovim shared library
libnvim = ffi.load Paths.test_libnvim_path

trim = (s) ->
  s\match'^%s*(.*%S)' or ''

-- a Set that keeps around the lines we've already seen
export cdefs
if cdefs == nil
  cdefs = Set!

export imported
if imported == nil
  imported = Set!

-- some things are just too complex for the LuaJIT C parser to digest. We
-- usually don't need them anyway.
filter_complex_blocks = (body) ->
  result = {}
  for line in body\gmatch("[^\r\n]+")
    -- remove all lines that contain Objective-C block syntax, the LuaJIT ffi
    -- doesn't understand it.
    if string.find(line, "(^)", 1, true) ~= nil
      continue
    if string.find(line, "_ISwupper", 1, true) ~= nil
      continue
    result[#result + 1] = line
  table.concat(result, "\n")

-- use this helper to import C files, you can pass multiple paths at once,
-- this helper will return the C namespace of the nvim library.
-- cimport = (path) ->
cimport = (...) ->
  -- filter out paths we've already imported
  paths = [path for path in *{...} when not imported\contains(path)]
  for path in *paths
    imported\add(path)

  if #paths == 0
    return libnvim

  -- preprocess the header
  stream = Preprocess.preprocess_stream(unpack(paths))
  body = stream\read("*a")
  stream\close!

  -- format it (so that the lines are "unique" statements), also filter out
  -- Objective-C blocks
  body = formatc(body)
  body = filter_complex_blocks(body)

  -- add the formatted lines to a set
  new_cdefs = Set!
  for line in body\gmatch("[^\r\n]+")
    new_cdefs\add(trim(line))

  -- subtract the lines we've already imported from the new lines, then add
  -- the new unique lines to the old lines (so they won't be imported again)
  new_cdefs\diff(cdefs)
  cdefs\union(new_cdefs)

  if new_cdefs\size! == 0
    -- if there's no new lines, just return
    return libnvim

  -- request a sorted version of the new lines (same relative order as the
  -- original preprocessed file) and feed that to the LuaJIT ffi
  new_lines = new_cdefs\to_table!
  ffi.cdef(table.concat(new_lines, "\n"))

  return libnvim

cppimport = (path) ->
  return cimport Paths.test_include_path .. '/' .. path

cimport './src/nvim/types.h'

-- take a pointer to a C-allocated string and return an interned
-- version while also freeing the memory
internalize = (cdata, len) ->
  ffi.gc cdata, ffi.C.free
  return ffi.string cdata, len

cstr = ffi.typeof 'char[?]'

to_cstr = (string) ->
  cstr (string.len string) + 1, string

export vim_init_called
-- initialize some global variables, this is still necessary to unit test
-- functions that rely on global state.
vim_init = ->
  if vim_init_called ~= nil
    return
  -- import os_unix.h for mch_early_init(), which initializes some globals
  os = cimport './src/nvim/os_unix.h'
  os.mch_early_init!
  vim_init_called = true

-- C constants.
NULL = ffi.cast 'void*', 0

OK   = 1
FAIL = 0

return {
  cimport: cimport
  cppimport: cppimport
  internalize: internalize
  eq: (expected, actual) -> assert.are.same expected, actual
  neq: (expected, actual) -> assert.are_not.same expected, actual
  ffi: ffi
  lib: libnvim
  cstr: cstr
  to_cstr: to_cstr
  vim_init: vim_init
  NULL: NULL
  OK: OK
  FAIL: FAIL
}