mirror of
https://github.com/neovim/neovim.git
synced 2025-09-25 12:38:33 +00:00
Move functions from os/fs.c into path.c
Move unit tests from os/fs.moon to path.moon
This commit is contained in:

committed by
Thiago de Arruda

parent
49f5e5d0b1
commit
4348d1e6f7
191
src/os/fs.c
191
src/os/fs.c
@@ -5,6 +5,7 @@
|
||||
#include "message.h"
|
||||
#include "misc1.h"
|
||||
#include "misc2.h"
|
||||
#include "path.h"
|
||||
|
||||
// Many fs functions from libuv return that value on success.
|
||||
static const int kLibuvSuccess = 0;
|
||||
@@ -30,117 +31,6 @@ int os_dirname(char_u *buf, size_t len)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// Get the absolute name of the given relative directory.
|
||||
///
|
||||
/// @param directory Directory name, relative to current directory.
|
||||
/// @return `FAIL` for failure, `OK` for success.
|
||||
int os_full_dir_name(char *directory, char *buffer, int len)
|
||||
{
|
||||
int retval = OK;
|
||||
|
||||
if (STRLEN(directory) == 0) {
|
||||
return os_dirname((char_u *) buffer, len);
|
||||
}
|
||||
|
||||
char old_dir[MAXPATHL];
|
||||
|
||||
// Get current directory name.
|
||||
if (os_dirname((char_u *) old_dir, MAXPATHL) == FAIL) {
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
// We have to get back to the current dir at the end, check if that works.
|
||||
if (os_chdir(old_dir) != kLibuvSuccess) {
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if (os_chdir(directory) != kLibuvSuccess) {
|
||||
// Do not return immediatly since we may be in the wrong directory.
|
||||
retval = FAIL;
|
||||
}
|
||||
|
||||
if (retval == FAIL || os_dirname((char_u *) buffer, len) == FAIL) {
|
||||
// Do not return immediatly since we are in the wrong directory.
|
||||
retval = FAIL;
|
||||
}
|
||||
|
||||
if (os_chdir(old_dir) != kLibuvSuccess) {
|
||||
// That shouldn't happen, since we've tested if it works.
|
||||
retval = FAIL;
|
||||
EMSG(_(e_prev_dir));
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Append to_append to path with a slash in between.
|
||||
int append_path(char *path, const char *to_append, int max_len)
|
||||
{
|
||||
int current_length = STRLEN(path);
|
||||
int to_append_length = STRLEN(to_append);
|
||||
|
||||
// Do not append empty strings.
|
||||
if (to_append_length == 0) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
// Do not append a dot.
|
||||
if (STRCMP(to_append, ".") == 0) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
// Glue both paths with a slash.
|
||||
if (current_length > 0 && path[current_length-1] != '/') {
|
||||
current_length += 1; // Count the trailing slash.
|
||||
|
||||
// +1 for the NUL at the end.
|
||||
if (current_length + 1 > max_len) {
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
STRCAT(path, "/");
|
||||
}
|
||||
|
||||
// +1 for the NUL at the end.
|
||||
if (current_length + to_append_length + 1 > max_len) {
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
STRCAT(path, to_append);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int os_get_absolute_path(char_u *fname, char_u *buf, int len, int force)
|
||||
{
|
||||
char_u *p;
|
||||
*buf = NUL;
|
||||
|
||||
char relative_directory[len];
|
||||
char *end_of_path = (char *) fname;
|
||||
|
||||
// expand it if forced or not an absolute path
|
||||
if (force || !os_is_absolute_path(fname)) {
|
||||
if ((p = vim_strrchr(fname, '/')) != NULL) {
|
||||
STRNCPY(relative_directory, fname, p-fname);
|
||||
relative_directory[p-fname] = NUL;
|
||||
end_of_path = (char *) (p + 1);
|
||||
} else {
|
||||
relative_directory[0] = NUL;
|
||||
end_of_path = (char *) fname;
|
||||
}
|
||||
|
||||
if (FAIL == os_full_dir_name(relative_directory, (char *) buf, len)) {
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
return append_path((char *) buf, (char *) end_of_path, len);
|
||||
}
|
||||
|
||||
int os_is_absolute_path(const char_u *fname)
|
||||
{
|
||||
return *fname == '/' || *fname == '~';
|
||||
}
|
||||
|
||||
bool os_isdir(const char_u *name)
|
||||
{
|
||||
int32_t mode = os_getperm(name);
|
||||
@@ -155,85 +45,6 @@ bool os_isdir(const char_u *name)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_executable(const char_u *name);
|
||||
static bool is_executable_in_path(const char_u *name);
|
||||
|
||||
bool os_can_exe(const char_u *name)
|
||||
{
|
||||
// If it's an absolute or relative path don't need to use $PATH.
|
||||
if (os_is_absolute_path(name) ||
|
||||
(name[0] == '.' && (name[1] == '/' ||
|
||||
(name[1] == '.' && name[2] == '/')))) {
|
||||
return is_executable(name);
|
||||
}
|
||||
|
||||
return is_executable_in_path(name);
|
||||
}
|
||||
|
||||
// Return true if "name" is an executable file, false if not or it doesn't
|
||||
// exist.
|
||||
static bool is_executable(const char_u *name)
|
||||
{
|
||||
int32_t mode = os_getperm(name);
|
||||
|
||||
if (mode < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (S_ISREG(mode) && (S_IEXEC & mode)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Check if a file is inside the $PATH and is executable.
|
||||
///
|
||||
/// @return `true` if `name` is an executable inside $PATH.
|
||||
static bool is_executable_in_path(const char_u *name)
|
||||
{
|
||||
const char *path = getenv("PATH");
|
||||
// PATH environment variable does not exist or is empty.
|
||||
if (path == NULL || *path == NUL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int buf_len = STRLEN(name) + STRLEN(path) + 2;
|
||||
char_u *buf = alloc((unsigned)(buf_len));
|
||||
|
||||
// Walk through all entries in $PATH to check if "name" exists there and
|
||||
// is an executable file.
|
||||
for (;; ) {
|
||||
const char *e = strchr(path, ':');
|
||||
if (e == NULL) {
|
||||
e = path + STRLEN(path);
|
||||
}
|
||||
|
||||
// Glue together the given directory from $PATH with name and save into
|
||||
// buf.
|
||||
vim_strncpy(buf, (char_u *) path, e - path);
|
||||
append_path((char *) buf, (const char *) name, buf_len);
|
||||
|
||||
if (is_executable(buf)) {
|
||||
// Found our executable. Free buf and return.
|
||||
vim_free(buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (*e != ':') {
|
||||
// End of $PATH without finding any executable called name.
|
||||
vim_free(buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
path = e + 1;
|
||||
}
|
||||
|
||||
// We should never get to this point.
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
int os_stat(const char_u *name, uv_stat_t *statbuf)
|
||||
{
|
||||
uv_fs_t request;
|
||||
|
25
src/os/os.h
25
src/os/os.h
@@ -16,36 +16,11 @@ int os_chdir(const char *path);
|
||||
/// @return `OK` for success, `FAIL` for failure.
|
||||
int os_dirname(char_u *buf, size_t len);
|
||||
|
||||
/// Expand a given file to its absolute path.
|
||||
///
|
||||
/// @param fname The filename which should be expanded.
|
||||
/// @param buf Buffer to store the absolute path of `fname`.
|
||||
/// @param len Length of `buf`.
|
||||
/// @param force Also expand when `fname` is already absolute.
|
||||
/// @return `FAIL` for failure, `OK` for success.
|
||||
int os_get_absolute_path(char_u *fname, char_u *buf, int len, int force);
|
||||
|
||||
/// Check if the given file is absolute.
|
||||
///
|
||||
/// This just checks if the file name starts with '/' or '~'.
|
||||
/// @return `true` if "fname" is absolute.
|
||||
int os_is_absolute_path(const char_u *fname);
|
||||
|
||||
/// Check if the given path is a directory or not.
|
||||
///
|
||||
/// @return `true` if `fname` is a directory.
|
||||
bool os_isdir(const char_u *name);
|
||||
|
||||
/// Check if the given path represents an executable file.
|
||||
///
|
||||
/// @return `true` if `name` is executable and
|
||||
/// - can be found in $PATH,
|
||||
/// - is relative to current dir or
|
||||
/// - is absolute.
|
||||
///
|
||||
/// @return `false` otherwise.
|
||||
bool os_can_exe(const char_u *name);
|
||||
|
||||
/// Get the file permissions for a given file.
|
||||
///
|
||||
/// @return `-1` when `name` doesn't exist.
|
||||
|
192
src/path.c
192
src/path.c
@@ -30,6 +30,9 @@
|
||||
#define URL_SLASH 1 /* path_is_url() has found "://" */
|
||||
#define URL_BACKSLASH 2 /* path_is_url() has found ":\\" */
|
||||
|
||||
static bool is_executable(const char_u *name);
|
||||
static bool is_executable_in_path(const char_u *name);
|
||||
|
||||
FileComparison path_full_compare(char_u *s1, char_u *s2, int checkname)
|
||||
{
|
||||
assert(s1 && s2);
|
||||
@@ -1938,3 +1941,192 @@ int match_suffix(char_u *fname)
|
||||
}
|
||||
return setsuflen != 0;
|
||||
}
|
||||
|
||||
/// Get the absolute name of the given relative directory.
|
||||
///
|
||||
/// @param directory Directory name, relative to current directory.
|
||||
/// @return `FAIL` for failure, `OK` for success.
|
||||
int os_full_dir_name(char *directory, char *buffer, int len)
|
||||
{
|
||||
int SUCCESS = 0;
|
||||
int retval = OK;
|
||||
|
||||
if (STRLEN(directory) == 0) {
|
||||
return os_dirname((char_u *) buffer, len);
|
||||
}
|
||||
|
||||
char old_dir[MAXPATHL];
|
||||
|
||||
// Get current directory name.
|
||||
if (os_dirname((char_u *) old_dir, MAXPATHL) == FAIL) {
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
// We have to get back to the current dir at the end, check if that works.
|
||||
if (os_chdir(old_dir) != SUCCESS) {
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if (os_chdir(directory) != SUCCESS) {
|
||||
// Do not return immediatly since we may be in the wrong directory.
|
||||
retval = FAIL;
|
||||
}
|
||||
|
||||
if (retval == FAIL || os_dirname((char_u *) buffer, len) == FAIL) {
|
||||
// Do not return immediatly since we are in the wrong directory.
|
||||
retval = FAIL;
|
||||
}
|
||||
|
||||
if (os_chdir(old_dir) != SUCCESS) {
|
||||
// That shouldn't happen, since we've tested if it works.
|
||||
retval = FAIL;
|
||||
EMSG(_(e_prev_dir));
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Append to_append to path with a slash in between.
|
||||
int append_path(char *path, const char *to_append, int max_len)
|
||||
{
|
||||
int current_length = STRLEN(path);
|
||||
int to_append_length = STRLEN(to_append);
|
||||
|
||||
// Do not append empty strings.
|
||||
if (to_append_length == 0) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
// Do not append a dot.
|
||||
if (STRCMP(to_append, ".") == 0) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
// Glue both paths with a slash.
|
||||
if (current_length > 0 && path[current_length-1] != '/') {
|
||||
current_length += 1; // Count the trailing slash.
|
||||
|
||||
// +1 for the NUL at the end.
|
||||
if (current_length + 1 > max_len) {
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
STRCAT(path, "/");
|
||||
}
|
||||
|
||||
// +1 for the NUL at the end.
|
||||
if (current_length + to_append_length + 1 > max_len) {
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
STRCAT(path, to_append);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int os_get_absolute_path(char_u *fname, char_u *buf, int len, int force)
|
||||
{
|
||||
char_u *p;
|
||||
*buf = NUL;
|
||||
|
||||
char relative_directory[len];
|
||||
char *end_of_path = (char *) fname;
|
||||
|
||||
// expand it if forced or not an absolute path
|
||||
if (force || !os_is_absolute_path(fname)) {
|
||||
if ((p = vim_strrchr(fname, '/')) != NULL) {
|
||||
STRNCPY(relative_directory, fname, p-fname);
|
||||
relative_directory[p-fname] = NUL;
|
||||
end_of_path = (char *) (p + 1);
|
||||
} else {
|
||||
relative_directory[0] = NUL;
|
||||
end_of_path = (char *) fname;
|
||||
}
|
||||
|
||||
if (FAIL == os_full_dir_name(relative_directory, (char *) buf, len)) {
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
return append_path((char *) buf, (char *) end_of_path, len);
|
||||
}
|
||||
|
||||
int os_is_absolute_path(const char_u *fname)
|
||||
{
|
||||
return *fname == '/' || *fname == '~';
|
||||
}
|
||||
|
||||
bool os_can_exe(const char_u *name)
|
||||
{
|
||||
// If it's an absolute or relative path don't need to use $PATH.
|
||||
if (os_is_absolute_path(name) ||
|
||||
(name[0] == '.' && (name[1] == '/' ||
|
||||
(name[1] == '.' && name[2] == '/')))) {
|
||||
return is_executable(name);
|
||||
}
|
||||
|
||||
return is_executable_in_path(name);
|
||||
}
|
||||
|
||||
// Return true if "name" is an executable file, false if not or it doesn't
|
||||
// exist.
|
||||
static bool is_executable(const char_u *name)
|
||||
{
|
||||
int32_t mode = os_getperm(name);
|
||||
|
||||
if (mode < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (S_ISREG(mode) && (S_IEXEC & mode)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Check if a file is inside the $PATH and is executable.
|
||||
///
|
||||
/// @return `true` if `name` is an executable inside $PATH.
|
||||
static bool is_executable_in_path(const char_u *name)
|
||||
{
|
||||
const char *path = getenv("PATH");
|
||||
// PATH environment variable does not exist or is empty.
|
||||
if (path == NULL || *path == NUL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int buf_len = STRLEN(name) + STRLEN(path) + 2;
|
||||
char_u *buf = alloc((unsigned)(buf_len));
|
||||
|
||||
// Walk through all entries in $PATH to check if "name" exists there and
|
||||
// is an executable file.
|
||||
for (;; ) {
|
||||
const char *e = strchr(path, ':');
|
||||
if (e == NULL) {
|
||||
e = path + STRLEN(path);
|
||||
}
|
||||
|
||||
// Glue together the given directory from $PATH with name and save into
|
||||
// buf.
|
||||
vim_strncpy(buf, (char_u *) path, e - path);
|
||||
append_path((char *) buf, (const char *) name, buf_len);
|
||||
|
||||
if (is_executable(buf)) {
|
||||
// Found our executable. Free buf and return.
|
||||
vim_free(buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (*e != ':') {
|
||||
// End of $PATH without finding any executable called name.
|
||||
vim_free(buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
path = e + 1;
|
||||
}
|
||||
|
||||
// We should never get to this point.
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
35
src/path.h
35
src/path.h
@@ -87,4 +87,39 @@ int expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u *
|
||||
**file,
|
||||
int flags);
|
||||
int match_suffix(char_u *fname);
|
||||
|
||||
/// Get the absolute name of the given relative directory.
|
||||
///
|
||||
/// @param directory Directory name, relative to current directory.
|
||||
/// @return `FAIL` for failure, `OK` for success.
|
||||
int os_full_dir_name(char *directory, char *buffer, int len);
|
||||
|
||||
// Append to_append to path with a slash in between.
|
||||
int append_path(char *path, const char *to_append, int max_len);
|
||||
|
||||
/// Expand a given file to its absolute path.
|
||||
///
|
||||
/// @param fname The filename which should be expanded.
|
||||
/// @param buf Buffer to store the absolute path of `fname`.
|
||||
/// @param len Length of `buf`.
|
||||
/// @param force Also expand when `fname` is already absolute.
|
||||
/// @return `FAIL` for failure, `OK` for success.
|
||||
int os_get_absolute_path(char_u *fname, char_u *buf, int len, int force);
|
||||
|
||||
/// Check if the given file is absolute.
|
||||
///
|
||||
/// This just checks if the file name starts with '/' or '~'.
|
||||
/// @return `TRUE` if "fname" is absolute.
|
||||
int os_is_absolute_path(const char_u *fname);
|
||||
|
||||
/// Check if the given path represents an executable file.
|
||||
///
|
||||
/// @return `TRUE` if `name` is executable and
|
||||
/// - can be found in $PATH,
|
||||
/// - is relative to current dir or
|
||||
/// - is absolute.
|
||||
///
|
||||
/// @return `FALSE` otherwise.
|
||||
int os_can_exe(const char_u *name);
|
||||
|
||||
#endif
|
||||
|
@@ -34,6 +34,7 @@
|
||||
#include "garray.h"
|
||||
#include "option.h"
|
||||
#include "os_unix.h"
|
||||
#include "path.h"
|
||||
#include "regexp.h"
|
||||
#include "screen.h"
|
||||
#include "term.h"
|
||||
|
@@ -94,134 +94,6 @@ describe 'fs function', ->
|
||||
eq lfs.currentdir! .. '/unit-test-directory', (ffi.string buffer)
|
||||
eq OK, result
|
||||
|
||||
describe 'os_get_absolute_path', ->
|
||||
ffi.cdef 'int os_get_absolute_path(char *fname, char *buf, int len, int force);'
|
||||
|
||||
os_get_absolute_path = (filename, buffer, length, force) ->
|
||||
filename = to_cstr filename
|
||||
fs.os_get_absolute_path filename, buffer, length, force
|
||||
|
||||
before_each ->
|
||||
-- Create empty string buffer which will contain the resulting path.
|
||||
export len = (string.len lfs.currentdir!) + 33
|
||||
export buffer = cstr len, ''
|
||||
|
||||
it 'fails if given filename contains non-existing directory', ->
|
||||
force_expansion = 1
|
||||
result = os_get_absolute_path 'non_existing_dir/test.file', buffer, len, force_expansion
|
||||
eq FAIL, result
|
||||
|
||||
it 'concatenates given filename if it does not contain a slash', ->
|
||||
force_expansion = 1
|
||||
result = os_get_absolute_path 'test.file', buffer, len, force_expansion
|
||||
expected = lfs.currentdir! .. '/test.file'
|
||||
eq expected, (ffi.string buffer)
|
||||
eq OK, result
|
||||
|
||||
it 'concatenates given filename if it is a directory but does not contain a
|
||||
slash', ->
|
||||
force_expansion = 1
|
||||
result = os_get_absolute_path '..', buffer, len, force_expansion
|
||||
expected = lfs.currentdir! .. '/..'
|
||||
eq expected, (ffi.string buffer)
|
||||
eq OK, result
|
||||
|
||||
-- Is it possible for every developer to enter '..' directory while running
|
||||
-- the unit tests? Which other directory would be better?
|
||||
it 'enters given directory (instead of just concatenating the strings) if
|
||||
possible and if path contains a slash', ->
|
||||
force_expansion = 1
|
||||
result = os_get_absolute_path '../test.file', buffer, len, force_expansion
|
||||
old_dir = lfs.currentdir!
|
||||
lfs.chdir '..'
|
||||
expected = lfs.currentdir! .. '/test.file'
|
||||
lfs.chdir old_dir
|
||||
eq expected, (ffi.string buffer)
|
||||
eq OK, result
|
||||
|
||||
it 'just copies the path if it is already absolute and force=0', ->
|
||||
force_expansion = 0
|
||||
absolute_path = '/absolute/path'
|
||||
result = os_get_absolute_path absolute_path, buffer, len, force_expansion
|
||||
eq absolute_path, (ffi.string buffer)
|
||||
eq OK, result
|
||||
|
||||
it 'fails when the path is relative to HOME', ->
|
||||
force_expansion = 1
|
||||
absolute_path = '~/home.file'
|
||||
result = os_get_absolute_path absolute_path, buffer, len, force_expansion
|
||||
eq FAIL, result
|
||||
|
||||
it 'works with some "normal" relative path with directories', ->
|
||||
force_expansion = 1
|
||||
result = os_get_absolute_path 'unit-test-directory/test.file', buffer, len, force_expansion
|
||||
eq OK, result
|
||||
eq lfs.currentdir! .. '/unit-test-directory/test.file', (ffi.string buffer)
|
||||
|
||||
it 'does not modify the given filename', ->
|
||||
force_expansion = 1
|
||||
filename = to_cstr 'unit-test-directory/test.file'
|
||||
-- Don't use the wrapper here but pass a cstring directly to the c
|
||||
-- function.
|
||||
result = fs.os_get_absolute_path filename, buffer, len, force_expansion
|
||||
eq lfs.currentdir! .. '/unit-test-directory/test.file', (ffi.string buffer)
|
||||
eq 'unit-test-directory/test.file', (ffi.string filename)
|
||||
eq OK, result
|
||||
|
||||
describe 'append_path', ->
|
||||
ffi.cdef 'int append_path(char *path, char *to_append, int max_len);'
|
||||
|
||||
it 'joins given paths with a slash', ->
|
||||
path = cstr 100, 'path1'
|
||||
to_append = to_cstr 'path2'
|
||||
eq OK, (fs.append_path path, to_append, 100)
|
||||
eq "path1/path2", (ffi.string path)
|
||||
|
||||
it 'joins given paths without adding an unnecessary slash', ->
|
||||
path = cstr 100, 'path1/'
|
||||
to_append = to_cstr 'path2'
|
||||
eq OK, fs.append_path path, to_append, 100
|
||||
eq "path1/path2", (ffi.string path)
|
||||
|
||||
it 'fails if there is not enough space left for to_append', ->
|
||||
path = cstr 11, 'path1/'
|
||||
to_append = to_cstr 'path2'
|
||||
eq FAIL, (fs.append_path path, to_append, 11)
|
||||
|
||||
it 'does not append a slash if to_append is empty', ->
|
||||
path = cstr 6, 'path1'
|
||||
to_append = to_cstr ''
|
||||
eq OK, (fs.append_path path, to_append, 6)
|
||||
eq 'path1', (ffi.string path)
|
||||
|
||||
it 'does not append unnecessary dots', ->
|
||||
path = cstr 6, 'path1'
|
||||
to_append = to_cstr '.'
|
||||
eq OK, (fs.append_path path, to_append, 6)
|
||||
eq 'path1', (ffi.string path)
|
||||
|
||||
it 'copies to_append to path, if path is empty', ->
|
||||
path = cstr 7, ''
|
||||
to_append = to_cstr '/path2'
|
||||
eq OK, (fs.append_path path, to_append, 7)
|
||||
eq '/path2', (ffi.string path)
|
||||
|
||||
describe 'os_is_absolute_path', ->
|
||||
ffi.cdef 'int os_is_absolute_path(char *fname);'
|
||||
|
||||
os_is_absolute_path = (filename) ->
|
||||
filename = to_cstr filename
|
||||
fs.os_is_absolute_path filename
|
||||
|
||||
it 'returns true if filename starts with a slash', ->
|
||||
eq OK, os_is_absolute_path '/some/directory/'
|
||||
|
||||
it 'returns true if filename starts with a tilde', ->
|
||||
eq OK, os_is_absolute_path '~/in/my/home~/directory'
|
||||
|
||||
it 'returns false if filename starts not with slash nor tilde', ->
|
||||
eq FAIL, os_is_absolute_path 'not/in/my/home~/directory'
|
||||
|
||||
describe 'os_isdir', ->
|
||||
os_isdir = (name) ->
|
||||
fs.os_isdir (to_cstr name)
|
||||
|
@@ -1,4 +1,5 @@
|
||||
{:cimport, :internalize, :eq, :neq, :ffi, :lib, :cstr, :to_cstr} = require 'test.unit.helpers'
|
||||
require 'lfs'
|
||||
|
||||
path = lib
|
||||
|
||||
@@ -10,11 +11,16 @@ FileComparison path_full_compare(char_u *s1, char_u *s2, int checkname);
|
||||
char_u *path_tail(char_u *fname);
|
||||
char_u *path_tail_with_sep(char_u *fname);
|
||||
char_u *path_next_component(char_u *fname);
|
||||
int is_executable(char_u *name);
|
||||
int os_can_exe(char_u *name);
|
||||
]]
|
||||
|
||||
|
||||
-- import constants parsed by ffi
|
||||
{:kEqualFiles, :kDifferentFiles, :kBothFilesMissing, :kOneFileMissing, :kEqualFileNames} = path
|
||||
NULL = ffi.cast 'void*', 0
|
||||
{:OK, :FAIL} = path
|
||||
{:TRUE, :FALSE} = path
|
||||
|
||||
describe 'path function', ->
|
||||
describe 'path_full_compare', ->
|
||||
@@ -98,3 +104,171 @@ describe 'path function', ->
|
||||
|
||||
it 'returns empty string if given file contains no seperator', ->
|
||||
eq '', path_next_component 'file.txt'
|
||||
|
||||
describe 'former os function', ->
|
||||
setup ->
|
||||
lfs.mkdir 'unit-test-directory'
|
||||
(io.open 'unit-test-directory/test.file', 'w').close!
|
||||
|
||||
-- Since the tests are executed, they are called by an executable. We use
|
||||
-- that executable for several asserts.
|
||||
export absolute_executable = arg[0]
|
||||
|
||||
-- Split absolute_executable into a directory and the actual file name for
|
||||
-- later usage.
|
||||
export directory, executable_name = string.match(absolute_executable, '^(.*)/(.*)$')
|
||||
|
||||
teardown ->
|
||||
os.remove 'unit-test-directory/test.file'
|
||||
lfs.rmdir 'unit-test-directory'
|
||||
|
||||
describe 'os_get_absolute_path', ->
|
||||
ffi.cdef 'int os_get_absolute_path(char *fname, char *buf, int len, int force);'
|
||||
|
||||
os_get_absolute_path = (filename, buffer, length, force) ->
|
||||
filename = to_cstr filename
|
||||
path.os_get_absolute_path filename, buffer, length, force
|
||||
|
||||
before_each ->
|
||||
-- Create empty string buffer which will contain the resulting path.
|
||||
export len = (string.len lfs.currentdir!) + 33
|
||||
export buffer = cstr len, ''
|
||||
|
||||
it 'fails if given filename contains non-existing directory', ->
|
||||
force_expansion = 1
|
||||
result = os_get_absolute_path 'non_existing_dir/test.file', buffer, len, force_expansion
|
||||
eq FAIL, result
|
||||
|
||||
it 'concatenates given filename if it does not contain a slash', ->
|
||||
force_expansion = 1
|
||||
result = os_get_absolute_path 'test.file', buffer, len, force_expansion
|
||||
expected = lfs.currentdir! .. '/test.file'
|
||||
eq expected, (ffi.string buffer)
|
||||
eq OK, result
|
||||
|
||||
it 'concatenates given filename if it is a directory but does not contain a
|
||||
slash', ->
|
||||
force_expansion = 1
|
||||
result = os_get_absolute_path '..', buffer, len, force_expansion
|
||||
expected = lfs.currentdir! .. '/..'
|
||||
eq expected, (ffi.string buffer)
|
||||
eq OK, result
|
||||
|
||||
-- Is it possible for every developer to enter '..' directory while running
|
||||
-- the unit tests? Which other directory would be better?
|
||||
it 'enters given directory (instead of just concatenating the strings) if
|
||||
possible and if path contains a slash', ->
|
||||
force_expansion = 1
|
||||
result = os_get_absolute_path '../test.file', buffer, len, force_expansion
|
||||
old_dir = lfs.currentdir!
|
||||
lfs.chdir '..'
|
||||
expected = lfs.currentdir! .. '/test.file'
|
||||
lfs.chdir old_dir
|
||||
eq expected, (ffi.string buffer)
|
||||
eq OK, result
|
||||
|
||||
it 'just copies the path if it is already absolute and force=0', ->
|
||||
force_expansion = 0
|
||||
absolute_path = '/absolute/path'
|
||||
result = os_get_absolute_path absolute_path, buffer, len, force_expansion
|
||||
eq absolute_path, (ffi.string buffer)
|
||||
eq OK, result
|
||||
|
||||
it 'fails when the path is relative to HOME', ->
|
||||
force_expansion = 1
|
||||
absolute_path = '~/home.file'
|
||||
result = os_get_absolute_path absolute_path, buffer, len, force_expansion
|
||||
eq FAIL, result
|
||||
|
||||
it 'works with some "normal" relative path with directories', ->
|
||||
force_expansion = 1
|
||||
result = os_get_absolute_path 'unit-test-directory/test.file', buffer, len, force_expansion
|
||||
eq OK, result
|
||||
eq lfs.currentdir! .. '/unit-test-directory/test.file', (ffi.string buffer)
|
||||
|
||||
it 'does not modify the given filename', ->
|
||||
force_expansion = 1
|
||||
filename = to_cstr 'unit-test-directory/test.file'
|
||||
-- Don't use the wrapper here but pass a cstring directly to the c
|
||||
-- function.
|
||||
result = path.os_get_absolute_path filename, buffer, len, force_expansion
|
||||
eq lfs.currentdir! .. '/unit-test-directory/test.file', (ffi.string buffer)
|
||||
eq 'unit-test-directory/test.file', (ffi.string filename)
|
||||
eq OK, result
|
||||
|
||||
describe 'append_path', ->
|
||||
ffi.cdef 'int append_path(char *path, char *to_append, int max_len);'
|
||||
|
||||
it 'joins given paths with a slash', ->
|
||||
path1 = cstr 100, 'path1'
|
||||
to_append = to_cstr 'path2'
|
||||
eq OK, (path.append_path path1, to_append, 100)
|
||||
eq "path1/path2", (ffi.string path1)
|
||||
|
||||
it 'joins given paths without adding an unnecessary slash', ->
|
||||
path1 = cstr 100, 'path1/'
|
||||
to_append = to_cstr 'path2'
|
||||
eq OK, path.append_path path1, to_append, 100
|
||||
eq "path1/path2", (ffi.string path1)
|
||||
|
||||
it 'fails if there is not enough space left for to_append', ->
|
||||
path1 = cstr 11, 'path1/'
|
||||
to_append = to_cstr 'path2'
|
||||
eq FAIL, (path.append_path path1, to_append, 11)
|
||||
|
||||
it 'does not append a slash if to_append is empty', ->
|
||||
path1 = cstr 6, 'path1'
|
||||
to_append = to_cstr ''
|
||||
eq OK, (path.append_path path1, to_append, 6)
|
||||
eq 'path1', (ffi.string path1)
|
||||
|
||||
it 'does not append unnecessary dots', ->
|
||||
path1 = cstr 6, 'path1'
|
||||
to_append = to_cstr '.'
|
||||
eq OK, (path.append_path path1, to_append, 6)
|
||||
eq 'path1', (ffi.string path1)
|
||||
|
||||
it 'copies to_append to path, if path is empty', ->
|
||||
path1 = cstr 7, ''
|
||||
to_append = to_cstr '/path2'
|
||||
eq OK, (path.append_path path1, to_append, 7)
|
||||
eq '/path2', (ffi.string path1)
|
||||
|
||||
describe 'os_is_absolute_path', ->
|
||||
ffi.cdef 'int os_is_absolute_path(char *fname);'
|
||||
|
||||
os_is_absolute_path = (filename) ->
|
||||
filename = to_cstr filename
|
||||
path.os_is_absolute_path filename
|
||||
|
||||
it 'returns true if filename starts with a slash', ->
|
||||
eq OK, os_is_absolute_path '/some/directory/'
|
||||
|
||||
it 'returns true if filename starts with a tilde', ->
|
||||
eq OK, os_is_absolute_path '~/in/my/home~/directory'
|
||||
|
||||
it 'returns false if filename starts not with slash nor tilde', ->
|
||||
eq FAIL, os_is_absolute_path 'not/in/my/home~/directory'
|
||||
|
||||
describe 'os_can_exe', ->
|
||||
os_can_exe = (name) ->
|
||||
path.os_can_exe (to_cstr name)
|
||||
|
||||
it 'returns false when given a directory', ->
|
||||
eq FALSE, (os_can_exe './unit-test-directory')
|
||||
|
||||
it 'returns false when given a regular file without executable bit set', ->
|
||||
eq FALSE, (os_can_exe 'unit-test-directory/test.file')
|
||||
|
||||
it 'returns false when the given file does not exists', ->
|
||||
eq FALSE, (os_can_exe 'does-not-exist.file')
|
||||
|
||||
it 'returns true when given an executable inside $PATH', ->
|
||||
eq TRUE, (os_can_exe executable_name)
|
||||
|
||||
it 'returns true when given an executable relative to the current dir', ->
|
||||
old_dir = lfs.currentdir!
|
||||
lfs.chdir directory
|
||||
relative_executable = './' .. executable_name
|
||||
eq TRUE, (os_can_exe relative_executable)
|
||||
lfs.chdir old_dir
|
||||
|
Reference in New Issue
Block a user