Merge pull request #904 from war1025/dev/buffer_tests

Add unit tests for buffer.c and fileio.c
This commit is contained in:
Justin M. Keyes 2014-07-22 15:24:56 -04:00
commit ba04a1c306
11 changed files with 375 additions and 71 deletions

View File

@ -4,33 +4,43 @@
#include "nvim/pos.h" // for linenr_T
#include "nvim/ex_cmds_defs.h" // for exarg_T
/* Values for buflist_getfile() */
#define GETF_SETMARK 0x01 /* set pcmark before jumping */
#define GETF_ALT 0x02 /* jumping to alternate file (not buf num) */
#define GETF_SWITCH 0x04 /* respect 'switchbuf' settings when jumping */
// Values for buflist_getfile()
enum getf_values {
GETF_SETMARK = 0x01, // set pcmark before jumping
GETF_ALT = 0x02, // jumping to alternate file (not buf num)
GETF_SWITCH = 0x04, // respect 'switchbuf' settings when jumping
};
/* Values for buflist_new() flags */
#define BLN_CURBUF 1 /* May re-use curbuf for new buffer */
#define BLN_LISTED 2 /* Put new buffer in buffer list */
#define BLN_DUMMY 4 /* Allocating dummy buffer */
// Values for buflist_new() flags
enum bln_values {
BLN_CURBUF = 1, // May re-use curbuf for new buffer
BLN_LISTED = 2, // Put new buffer in buffer list
BLN_DUMMY = 4, // Allocating dummy buffer
};
/* Values for action argument for do_buffer() */
#define DOBUF_GOTO 0 /* go to specified buffer */
#define DOBUF_SPLIT 1 /* split window and go to specified buffer */
#define DOBUF_UNLOAD 2 /* unload specified buffer(s) */
#define DOBUF_DEL 3 /* delete specified buffer(s) from buflist */
#define DOBUF_WIPE 4 /* delete specified buffer(s) really */
// Values for action argument for do_buffer()
enum dobuf_action_values {
DOBUF_GOTO = 0, // go to specified buffer
DOBUF_SPLIT = 1, // split window and go to specified buffer
DOBUF_UNLOAD = 2, // unload specified buffer(s)
DOBUF_DEL = 3, // delete specified buffer(s) from buflist
DOBUF_WIPE = 4, // delete specified buffer(s) really
};
/* Values for start argument for do_buffer() */
#define DOBUF_CURRENT 0 /* "count" buffer from current buffer */
#define DOBUF_FIRST 1 /* "count" buffer from first buffer */
#define DOBUF_LAST 2 /* "count" buffer from last buffer */
#define DOBUF_MOD 3 /* "count" mod. buffer from current buffer */
// Values for start argument for do_buffer()
enum dobuf_start_values {
DOBUF_CURRENT = 0, // "count" buffer from current buffer
DOBUF_FIRST = 1, // "count" buffer from first buffer
DOBUF_LAST = 2, // "count" buffer from last buffer
DOBUF_MOD = 3, // "count" mod. buffer from current buffer
};
/* flags for buf_freeall() */
#define BFA_DEL 1 /* buffer is going to be deleted */
#define BFA_WIPE 2 /* buffer is going to be wiped out */
#define BFA_KEEP_UNDO 4 /* do not free undo information */
// flags for buf_freeall()
enum bfa_values {
BFA_DEL = 1, // buffer is going to be deleted
BFA_WIPE = 2, // buffer is going to be wiped out
BFA_KEEP_UNDO = 4, // do not free undo information
};
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "buffer.h.generated.h"

View File

@ -5156,7 +5156,11 @@ void fix_help_buffer(void)
/* Find all "doc/ *.txt" files in this directory. */
add_pathsep(NameBuff);
STRCAT(NameBuff, "doc/*.??[tx]");
if (gen_expand_wildcards(1, &NameBuff, &fcount,
// Note: We cannot just do `&NameBuff` because it is a statically sized array
// so `NameBuff == &NameBuff` according to C semantics.
char_u *buff_list[1] = {(char_u*) NameBuff};
if (gen_expand_wildcards(1, buff_list, &fcount,
&fnames, EW_FILE|EW_SILENT) == OK
&& fcount > 0) {
int i1;
@ -5324,7 +5328,11 @@ void ex_helptags(exarg_T *eap)
STRCPY(NameBuff, dirname);
add_pathsep(NameBuff);
STRCAT(NameBuff, "**");
if (gen_expand_wildcards(1, &NameBuff, &filecount, &files,
// Note: We cannot just do `&NameBuff` because it is a statically sized array
// so `NameBuff == &NameBuff` according to C semantics.
char_u *buff_list[1] = {(char_u*) NameBuff};
if (gen_expand_wildcards(1, buff_list, &filecount, &files,
EW_FILE|EW_SILENT) == FAIL
|| filecount == 0) {
EMSG2("E151: No match: %s", NameBuff);
@ -5422,7 +5430,11 @@ helptags_one (
STRCPY(NameBuff, dir);
STRCAT(NameBuff, "/**/*");
STRCAT(NameBuff, ext);
if (gen_expand_wildcards(1, &NameBuff, &filecount, &files,
// Note: We cannot just do `&NameBuff` because it is a statically sized array
// so `NameBuff == &NameBuff` according to C semantics.
char_u *buff_list[1] = {(char_u*) NameBuff};
if (gen_expand_wildcards(1, buff_list, &filecount, &files,
EW_FILE|EW_SILENT) == FAIL
|| filecount == 0) {
if (!got_int)

View File

@ -40,6 +40,20 @@
# define MSG_BUF_CLEN (MSG_BUF_LEN / 6) // cell length (worst case: utf-8
// takes 6 bytes for one cell)
/*
* Maximum length of a path (for non-unix systems) Make it a bit long, to stay
* on the safe side. But not too long to put on the stack.
* TODO(metrix78): Move this to os_defs.h
*/
#ifndef MAXPATHL
# ifdef MAXPATHLEN
# define MAXPATHL MAXPATHLEN
# else
# define MAXPATHL 256
# endif
#endif
/* Values for "starting" */
#define NO_SCREEN 2 /* no screen updating yet */
#define NO_BUFFERS 1 /* not all buffers loaded yet */
@ -841,11 +855,9 @@ EXTERN int swap_exists_action INIT(= SEA_NONE);
EXTERN int swap_exists_did_quit INIT(= FALSE);
/* Selected "quit" at the dialog. */
EXTERN char_u IObuff[IOSIZE]; /* sprintf's are done in this buffer,
size is IOSIZE */
EXTERN char_u *NameBuff; /* file names are expanded in this
* buffer, size is MAXPATHL */
EXTERN char_u msg_buf[MSG_BUF_LEN]; /* small buffer for messages */
EXTERN char_u IObuff[IOSIZE]; /* sprintf's are done in this buffer */
EXTERN char_u NameBuff[MAXPATHL]; /* buffer for expanding file names */
EXTERN char_u msg_buf[MSG_BUF_LEN]; /* small buffer for messages */
/* When non-zero, postpone redrawing. */
EXTERN int RedrawingDisabled INIT(= 0);

View File

@ -144,10 +144,6 @@ int main(int argc, char **argv)
char_u *fname = NULL; /* file name from command line */
mparm_T params; /* various parameters passed between
* main() and other functions. */
/*
* Do any system-specific initialisations. These can NOT use IObuff or
* NameBuff. Thus emsg2() cannot be called!
*/
mch_early_init();
/* Many variables are in "params" so that we can pass them to invoked
@ -167,12 +163,6 @@ int main(int argc, char **argv)
/* Init the table of Normal mode commands. */
init_normal_cmds();
/*
* Allocate space for the generic buffers (needed for set_init_1() and
* EMSG2()).
*/
allocate_generic_buffers();
#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
/*
* Setup to use the current locale (for ctype() and many other things).
@ -1476,16 +1466,6 @@ static void init_startuptime(mparm_T *paramp)
starttime = time(NULL);
}
/*
* Allocate space for the generic buffers (needed for set_init_1() and
* EMSG2()).
*/
static void allocate_generic_buffers(void)
{
NameBuff = xmalloc(MAXPATHL);
TIME_MSG("Allocated generic buffers");
}
/*
* Check if we have an interactive window.
* On the Amiga: If there is no window, we open one with a newcli command

View File

@ -510,8 +510,6 @@ void free_all_mem(void)
free_screenlines();
clear_hl_tables();
free(NameBuff);
}
#endif

View File

@ -3540,7 +3540,11 @@ void ex_helpgrep(exarg_T *eap)
/* Find all "*.txt" and "*.??x" files in the "doc" directory. */
add_pathsep(NameBuff);
STRCAT(NameBuff, "doc/*.\\(txt\\|??x\\)");
if (gen_expand_wildcards(1, &NameBuff, &fcount,
// Note: We cannot just do `&NameBuff` because it is a statically sized array
// so `NameBuff == &NameBuff` according to C semantics.
char_u *buff_list[1] = {(char_u*) NameBuff};
if (gen_expand_wildcards(1, buff_list, &fcount,
&fnames, EW_FILE|EW_SILENT) == OK
&& fcount > 0) {
for (fi = 0; fi < fcount && !got_int; ++fi) {

View File

@ -60,7 +60,11 @@ void vim_deltempdir(void)
char_u **files;
int file_count;
if (gen_expand_wildcards(1, &NameBuff, &file_count, &files,
// Note: We cannot just do `&NameBuff` because it is a statically
// sized array so `NameBuff == &NameBuff` according to C semantics.
char_u *buff_list[1] = {(char_u*) NameBuff};
if (gen_expand_wildcards(1, buff_list, &file_count, &files,
EW_DIR|EW_FILE|EW_SILENT) == OK) {
for (int i = 0; i < file_count; ++i) {
os_remove((char *)files[i]);

View File

@ -45,18 +45,6 @@ Error: configure did not run properly.Check auto/config.log.
#include "nvim/os_unix_defs.h" /* bring lots of system header files */
/*
* Maximum length of a path (for non-unix systems) Make it a bit long, to stay
* on the safe side. But not too long to put on the stack.
*/
#ifndef MAXPATHL
# ifdef MAXPATHLEN
# define MAXPATHL MAXPATHLEN
# else
# define MAXPATHL 256
# endif
#endif
#define NUMBUFLEN 30 /* length of a buffer to store a number in ASCII */
# define MAX_TYPENR 65535

216
test/unit/buffer_spec.lua Normal file
View File

@ -0,0 +1,216 @@
local helpers = require("test.unit.helpers")
local to_cstr = helpers.to_cstr
local eq = helpers.eq
helpers.vim_init()
local buffer = helpers.cimport("./src/nvim/buffer.h")
local window = helpers.cimport("./src/nvim/window.h")
local option = helpers.cimport("./src/nvim/option.h")
--{ Initialize the options needed for interacting with buffers
window.win_alloc_first()
option.set_init_1()
--}
describe('buffer functions', function()
local buflist_new = function(file, flags)
local c_file = to_cstr(file)
return buffer.buflist_new(c_file, c_file, 1, flags)
end
local close_buffer = function(win, buf, action, abort_if_last)
return buffer.close_buffer(win, buf, action, abort_if_last)
end
local path1 = 'test_file_path'
local path2 = 'file_path_test'
local path3 = 'path_test_file'
before_each(function()
-- create the files
io.open(path1, 'w').close()
io.open(path2, 'w').close()
io.open(path3, 'w').close()
end)
after_each(function()
os.remove(path1)
os.remove(path2)
os.remove(path3)
end)
describe('buf_valid', function()
it('should view NULL as an invalid buffer', function()
eq(0, buffer.buf_valid(NULL))
end)
it('should view an open buffer as valid', function()
local buf = buflist_new(path1, buffer.BLN_LISTED)
eq(1, buffer.buf_valid(buf))
end)
it('should view a closed and hidden buffer as valid', function()
local buf = buflist_new(path1, buffer.BLN_LISTED)
close_buffer(NULL, buf, 0, 0)
eq(1, buffer.buf_valid(buf))
end)
it('should view a closed and unloaded buffer as valid', function()
local buf = buflist_new(path1, buffer.BLN_LISTED)
close_buffer(NULL, buf, buffer.DOBUF_UNLOAD, 0)
eq(1, buffer.buf_valid(buf))
end)
it('should view a closed and wiped buffer as invalid', function()
local buf = buflist_new(path1, buffer.BLN_LISTED)
close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0)
eq(0, buffer.buf_valid(buf))
end)
end)
describe('buflist_findpat', function()
local ALLOW_UNLISTED = 1
local ONLY_LISTED = 0
local buflist_findpat = function(pat, allow_unlisted)
return buffer.buflist_findpat(to_cstr(pat), NULL, allow_unlisted, 0, 0)
end
it('should find exact matches', function()
local buf = buflist_new(path1, buffer.BLN_LISTED)
eq(buf.b_fnum, buflist_findpat(path1, ONLY_LISTED))
close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0)
end)
it('should prefer to match the start of a file path', function()
local buf1 = buflist_new(path1, buffer.BLN_LISTED)
local buf2 = buflist_new(path2, buffer.BLN_LISTED)
local buf3 = buflist_new(path3, buffer.BLN_LISTED)
eq(buf1.b_fnum, buflist_findpat("test", ONLY_LISTED))
eq(buf2.b_fnum, buflist_findpat("file", ONLY_LISTED))
eq(buf3.b_fnum, buflist_findpat("path", ONLY_LISTED))
close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0)
close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0)
close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0)
end)
it('should prefer to match the end of a file over the middle', function()
--{ Given: Two buffers, where 'test' appears in both
-- And: 'test' appears at the end of buf3 but in the middle of buf2
local buf2 = buflist_new(path2, buffer.BLN_LISTED)
local buf3 = buflist_new(path3, buffer.BLN_LISTED)
-- Then: buf2 is the buffer that is found
eq(buf2.b_fnum, buflist_findpat("test", ONLY_LISTED))
--}
--{ When: We close buf2
close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0)
-- And: Open buf1, which has 'file' in the middle of its name
local buf1 = buflist_new(path1, buffer.BLN_LISTED)
-- Then: buf3 is found since 'file' appears at the end of the name
eq(buf3.b_fnum, buflist_findpat("file", ONLY_LISTED))
--}
close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0)
close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0)
end)
it('should match a unique fragment of a file path', function()
local buf1 = buflist_new(path1, buffer.BLN_LISTED)
local buf2 = buflist_new(path2, buffer.BLN_LISTED)
local buf3 = buflist_new(path3, buffer.BLN_LISTED)
eq(buf3.b_fnum, buflist_findpat("_test_", ONLY_LISTED))
close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0)
close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0)
close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0)
end)
it('should include / ignore unlisted buffers based on the flag.', function()
--{ Given: A buffer
local buf3 = buflist_new(path3, buffer.BLN_LISTED)
-- Then: We should find the buffer when it is given a unique pattern
eq(buf3.b_fnum, buflist_findpat("_test_", ONLY_LISTED))
--}
--{ When: We unlist the buffer
close_buffer(NULL, buf3, buffer.DOBUF_DEL, 0)
-- Then: It should not find the buffer when searching only listed buffers
eq(-1, buflist_findpat("_test_", ONLY_LISTED))
-- And: It should find the buffer when including unlisted buffers
eq(buf3.b_fnum, buflist_findpat("_test_", ALLOW_UNLISTED))
--}
--{ When: We wipe the buffer
close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0)
-- Then: It should not find the buffer at all
eq(-1, buflist_findpat("_test_", ONLY_LISTED))
eq(-1, buflist_findpat("_test_", ALLOW_UNLISTED))
--}
end)
it('should prefer listed buffers to unlisted buffers.', function()
--{ Given: Two buffers that match a pattern
local buf1 = buflist_new(path1, buffer.BLN_LISTED)
local buf2 = buflist_new(path2, buffer.BLN_LISTED)
-- Then: The first buffer is preferred when both are listed
eq(buf1.b_fnum, buflist_findpat("test", ONLY_LISTED))
--}
--{ When: The first buffer is unlisted
close_buffer(NULL, buf1, buffer.DOBUF_DEL, 0)
-- Then: The second buffer is preferred because
-- unlisted buffers are not allowed
eq(buf2.b_fnum, buflist_findpat("test", ONLY_LISTED))
--}
--{ When: We allow unlisted buffers
-- Then: The second buffer is still preferred
-- because listed buffers are preferred to unlisted
eq(buf2.b_fnum, buflist_findpat("test", ALLOW_UNLISTED))
--}
--{ When: We unlist the second buffer
close_buffer(NULL, buf2, buffer.DOBUF_DEL, 0)
-- Then: The first buffer is preferred again
-- because buf1 matches better which takes precedence
-- when both buffers have the same listing status.
eq(buf1.b_fnum, buflist_findpat("test", ALLOW_UNLISTED))
-- And: Neither buffer is returned when ignoring unlisted
eq(-1, buflist_findpat("test", ONLY_LISTED))
--}
close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0)
close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0)
end)
end)
end)

83
test/unit/fileio_spec.lua Normal file
View File

@ -0,0 +1,83 @@
local helpers = require("test.unit.helpers")
--{:cimport, :internalize, :eq, :neq, :ffi, :lib, :cstr, :to_cstr} = require 'test.unit.helpers'
local eq = helpers.eq
local ffi = helpers.ffi
local to_cstr = helpers.to_cstr
local fileio = helpers.cimport("./src/nvim/fileio.h")
describe('file_pat functions', function()
describe('file_pat_to_reg_pat', function()
local file_pat_to_reg_pat = function(pat)
local res = fileio.file_pat_to_reg_pat(to_cstr(pat), NULL, NULL, 0)
return ffi.string(res)
end
it('returns ^path$ regex for literal path input', function()
eq( '^path$', file_pat_to_reg_pat('path'))
end)
it('does not prepend ^ when there is a starting glob (*)', function()
eq('path$', file_pat_to_reg_pat('*path'))
end)
it('does not append $ when there is an ending glob (*)', function()
eq('^path', file_pat_to_reg_pat('path*'))
end)
it('does not include ^ or $ when surrounded by globs (*)', function()
eq('path', file_pat_to_reg_pat('*path*'))
end)
it('replaces the bash any character (?) with the regex any character (.)', function()
eq('^foo.bar$', file_pat_to_reg_pat('foo?bar'))
end)
it('replaces a glob (*) in the middle of a path with regex multiple any character (.*)',
function()
eq('^foo.*bar$', file_pat_to_reg_pat('foo*bar'))
end)
it([[unescapes \? to ?]], function()
eq('^foo?bar$', file_pat_to_reg_pat([[foo\?bar]]))
end)
it([[unescapes \% to %]], function()
eq('^foo%bar$', file_pat_to_reg_pat([[foo\%bar]]))
end)
it([[unescapes \, to ,]], function()
eq('^foo,bar$', file_pat_to_reg_pat([[foo\,bar]]))
end)
it([[unescapes '\ ' to ' ']], function()
eq('^foo bar$', file_pat_to_reg_pat([[foo\ bar]]))
end)
it([[escapes . to \.]], function()
eq([[^foo\.bar$]], file_pat_to_reg_pat('foo.bar'))
end)
it('Converts bash brace expansion {a,b} to regex options (a|b)', function()
eq([[^foo\(bar\|baz\)$]], file_pat_to_reg_pat('foo{bar,baz}'))
end)
it('Collapses multiple consecutive * into a single character', function()
eq([[^foo.*bar$]], file_pat_to_reg_pat('foo*******bar'))
eq([[foobar$]], file_pat_to_reg_pat('********foobar'))
eq([[^foobar]], file_pat_to_reg_pat('foobar********'))
end)
it('Does not escape ^', function()
eq([[^^blah$]], file_pat_to_reg_pat('^blah'))
eq([[^foo^bar$]], file_pat_to_reg_pat('foo^bar'))
end)
it('Does not escape $', function()
eq([[^blah$$]], file_pat_to_reg_pat('blah$'))
eq([[^foo$bar$]], file_pat_to_reg_pat('foo$bar'))
end)
end)
end)

View File

@ -6,10 +6,7 @@ local tempfile = helpers.cimport './src/nvim/tempfile.h'
describe('tempfile related functions', function()
after_each(function()
-- This won't work because vim_deltempdir() uses global buffer
-- that is initialized in main() and main() is not called for unit tests.
-- But it is not a big problem: all tests can work with or without it.
-- tempfile.vim_deltempdir()
tempfile.vim_deltempdir()
end)
local vim_gettempdir = function()