aboutsummaryrefslogtreecommitdiff
path: root/test/unit/helpers.moon
blob: 8064537d934a9346d5a9d9f670dcd4b54b9ca3fe (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
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

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
}