blob: 07a985037d23de26d4fee0fe467de36fa1913b2f [file] [log] [blame]
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define TESTLUCY_USE_SHORT_NAMES
#include "Lucy/Util/ToolSet.h"
#include "Lucy/Test.h"
#include "Lucy/Test/Store/TestFolderCommon.h"
#include "Clownfish/TestHarness/TestBatchRunner.h"
#include "Lucy/Store/Folder.h"
#include "Lucy/Store/DirHandle.h"
#include "Lucy/Store/FileHandle.h"
#include "Lucy/Store/InStream.h"
#include "Lucy/Store/OutStream.h"
#define set_up_t LUCY_TestFolderCommon_Set_Up_t
#define tear_down_t LUCY_TestFolderCommon_Tear_Down_t
static String *foo = NULL;
static String *bar = NULL;
static String *baz = NULL;
static String *boffo = NULL;
static String *banana = NULL;
static String *foo_bar = NULL;
static String *foo_bar_baz = NULL;
static String *foo_bar_boffo = NULL;
static String *foo_boffo = NULL;
static String *foo_foo = NULL;
static String *nope = NULL;
static String *nope_nyet = NULL;
static void
S_init_strings(void) {
foo = Str_newf("foo");
bar = Str_newf("bar");
baz = Str_newf("baz");
boffo = Str_newf("boffo");
banana = Str_newf("banana");
foo_bar = Str_newf("foo/bar");
foo_bar_baz = Str_newf("foo/bar/baz");
foo_bar_boffo = Str_newf("foo/bar/boffo");
foo_boffo = Str_newf("foo/boffo");
foo_foo = Str_newf("foo/foo");
nope = Str_newf("nope");
nope_nyet = Str_newf("nope/nyet");
}
static void
S_destroy_strings(void) {
DECREF(foo);
DECREF(bar);
DECREF(baz);
DECREF(boffo);
DECREF(banana);
DECREF(foo_bar);
DECREF(foo_bar_baz);
DECREF(foo_bar_boffo);
DECREF(foo_boffo);
DECREF(foo_foo);
DECREF(nope);
DECREF(nope_nyet);
}
static void
test_Local_Exists(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) {
Folder *folder = set_up();
OutStream *outstream = Folder_Open_Out(folder, boffo);
DECREF(outstream);
Folder_Local_MkDir(folder, foo);
outstream = Folder_Open_Out(folder, foo_boffo);
DECREF(outstream);
TEST_TRUE(runner, Folder_Local_Exists(folder, boffo),
"Local_Exists() returns true for file");
TEST_TRUE(runner, Folder_Local_Exists(folder, foo),
"Local_Exists() returns true for dir");
TEST_FALSE(runner, Folder_Local_Exists(folder, foo_boffo),
"Local_Exists() returns false for nested entry");
TEST_FALSE(runner, Folder_Local_Exists(folder, bar),
"Local_Exists() returns false for non-existent entry");
Folder_Delete(folder, foo_boffo);
Folder_Delete(folder, foo);
Folder_Delete(folder, boffo);
DECREF(folder);
tear_down();
}
static void
test_Local_Is_Directory(TestBatchRunner *runner, set_up_t set_up,
tear_down_t tear_down) {
Folder *folder = set_up();
OutStream *outstream = Folder_Open_Out(folder, boffo);
DECREF(outstream);
Folder_Local_MkDir(folder, foo);
TEST_FALSE(runner, Folder_Local_Is_Directory(folder, boffo),
"Local_Is_Directory() returns false for file");
TEST_TRUE(runner, Folder_Local_Is_Directory(folder, foo),
"Local_Is_Directory() returns true for dir");
TEST_FALSE(runner, Folder_Local_Is_Directory(folder, bar),
"Local_Is_Directory() returns false for non-existent entry");
Folder_Delete(folder, boffo);
Folder_Delete(folder, foo);
DECREF(folder);
tear_down();
}
static void
test_Local_Find_Folder(TestBatchRunner *runner, set_up_t set_up,
tear_down_t tear_down) {
Folder *folder = set_up();
Folder *local;
OutStream *outstream;
Folder_MkDir(folder, foo);
Folder_MkDir(folder, foo_bar);
outstream = Folder_Open_Out(folder, boffo);
DECREF(outstream);
outstream = Folder_Open_Out(folder, foo_boffo);
DECREF(outstream);
local = Folder_Local_Find_Folder(folder, nope);
TEST_TRUE(runner, local == NULL, "Non-existent entry yields NULL");
String *empty = SSTR_BLANK();
local = Folder_Local_Find_Folder(folder, empty);
TEST_TRUE(runner, local == NULL, "Empty string yields NULL");
local = Folder_Local_Find_Folder(folder, foo_bar);
TEST_TRUE(runner, local == NULL, "nested folder yields NULL");
local = Folder_Local_Find_Folder(folder, foo_boffo);
TEST_TRUE(runner, local == NULL, "nested file yields NULL");
local = Folder_Local_Find_Folder(folder, boffo);
TEST_TRUE(runner, local == NULL, "local file yields NULL");
local = Folder_Local_Find_Folder(folder, bar);
TEST_TRUE(runner, local == NULL, "name of nested folder yields NULL");
local = Folder_Local_Find_Folder(folder, foo);
TEST_TRUE(runner,
local
&& Folder_is_a(local, FOLDER)
&& Str_Ends_With(Folder_Get_Path(local), foo),
"Find local directory");
Folder_Delete(folder, foo_bar);
Folder_Delete(folder, foo_boffo);
Folder_Delete(folder, foo);
Folder_Delete(folder, boffo);
DECREF(folder);
tear_down();
}
static void
test_Local_MkDir(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) {
Folder *folder = set_up();
bool result;
result = Folder_Local_MkDir(folder, foo);
TEST_TRUE(runner, result, "Local_MkDir succeeds and returns true");
Err_set_error(NULL);
result = Folder_Local_MkDir(folder, foo);
TEST_FALSE(runner, result,
"Local_MkDir returns false when a dir already exists");
TEST_TRUE(runner, Err_get_error() != NULL,
"Local_MkDir sets global error when a dir already exists");
TEST_TRUE(runner, Folder_Exists(folder, foo),
"Existing dir untouched after failed Local_MkDir");
OutStream *outstream = Folder_Open_Out(folder, boffo);
DECREF(outstream);
Err_set_error(NULL);
result = Folder_Local_MkDir(folder, foo);
TEST_FALSE(runner, result,
"Local_MkDir returns false when a file already exists");
TEST_TRUE(runner, Err_get_error() != NULL,
"Local_MkDir sets global error when a file already exists");
TEST_TRUE(runner, Folder_Exists(folder, boffo) &&
!Folder_Local_Is_Directory(folder, boffo),
"Existing file untouched after failed Local_MkDir");
Folder_Delete(folder, foo);
Folder_Delete(folder, boffo);
DECREF(folder);
tear_down();
}
static void
test_Local_Open_Dir(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) {
Folder *folder = set_up();
DirHandle *dh = Folder_Local_Open_Dir(folder);
TEST_TRUE(runner, dh && DH_is_a(dh, DIRHANDLE),
"Local_Open_Dir returns an DirHandle");
DECREF(dh);
DECREF(folder);
tear_down();
}
static void
test_Local_Open_FileHandle(TestBatchRunner *runner, set_up_t set_up,
tear_down_t tear_down) {
Folder *folder = set_up();
FileHandle *fh;
fh = Folder_Local_Open_FileHandle(folder, boffo,
FH_CREATE | FH_WRITE_ONLY | FH_EXCLUSIVE);
TEST_TRUE(runner, fh && FH_is_a(fh, FILEHANDLE),
"opened FileHandle");
DECREF(fh);
fh = Folder_Local_Open_FileHandle(folder, boffo,
FH_CREATE | FH_WRITE_ONLY);
TEST_TRUE(runner, fh && FH_is_a(fh, FILEHANDLE),
"opened FileHandle for append");
DECREF(fh);
Err_set_error(NULL);
fh = Folder_Local_Open_FileHandle(folder, boffo,
FH_CREATE | FH_WRITE_ONLY | FH_EXCLUSIVE);
TEST_TRUE(runner, fh == NULL, "FH_EXLUSIVE flag prevents clobber");
TEST_TRUE(runner, Err_get_error() != NULL,
"failure due to FH_EXLUSIVE flag sets global error");
fh = Folder_Local_Open_FileHandle(folder, boffo, FH_READ_ONLY);
TEST_TRUE(runner, fh && FH_is_a(fh, FILEHANDLE),
"opened FileHandle for reading");
DECREF(fh);
Err_set_error(NULL);
fh = Folder_Local_Open_FileHandle(folder, nope, FH_READ_ONLY);
TEST_TRUE(runner, fh == NULL,
"Can't open non-existent file for reading");
TEST_TRUE(runner, Err_get_error() != NULL,
"Opening non-existent file for reading sets global error");
Folder_Delete(folder, boffo);
DECREF(folder);
tear_down();
}
static void
test_Local_Delete(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) {
Folder *folder = set_up();
OutStream *outstream;
outstream = Folder_Open_Out(folder, boffo);
DECREF(outstream);
TEST_TRUE(runner, Folder_Local_Delete(folder, boffo),
"Local_Delete on file succeeds");
TEST_FALSE(runner, Folder_Exists(folder, boffo),
"File is really gone");
Folder_Local_MkDir(folder, foo);
outstream = Folder_Open_Out(folder, foo_boffo);
DECREF(outstream);
Err_set_error(NULL);
TEST_FALSE(runner, Folder_Local_Delete(folder, foo),
"Local_Delete on non-empty dir fails");
Folder_Delete(folder, foo_boffo);
TEST_TRUE(runner, Folder_Local_Delete(folder, foo),
"Local_Delete on empty dir succeeds");
// FIXME: This test sometimes fails on Windows.
TEST_FALSE(runner, Folder_Exists(folder, foo),
"Dir is really gone");
DECREF(folder);
tear_down();
}
static void
test_Rename(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) {
Folder *folder = set_up();
OutStream *outstream;
bool result;
Folder_MkDir(folder, foo);
Folder_MkDir(folder, foo_bar);
outstream = Folder_Open_Out(folder, boffo);
OutStream_Close(outstream);
DECREF(outstream);
// Move files.
result = Folder_Rename(folder, boffo, banana);
TEST_TRUE(runner, result, "Rename succeeds and returns true");
TEST_TRUE(runner, Folder_Exists(folder, banana),
"File exists at new path");
TEST_FALSE(runner, Folder_Exists(folder, boffo),
"File no longer exists at old path");
result = Folder_Rename(folder, banana, foo_bar_boffo);
TEST_TRUE(runner, result, "Rename to file in nested dir");
TEST_TRUE(runner, Folder_Exists(folder, foo_bar_boffo),
"File exists at new path");
TEST_FALSE(runner, Folder_Exists(folder, banana),
"File no longer exists at old path");
result = Folder_Rename(folder, foo_bar_boffo, boffo);
TEST_TRUE(runner, result, "Rename from file in nested dir");
TEST_TRUE(runner, Folder_Exists(folder, boffo),
"File exists at new path");
TEST_FALSE(runner, Folder_Exists(folder, foo_bar_boffo),
"File no longer exists at old path");
outstream = Folder_Open_Out(folder, foo_boffo);
OutStream_Close(outstream);
DECREF(outstream);
result = Folder_Rename(folder, boffo, foo_boffo);
if (result) {
PASS(runner, "Rename clobbers on this system");
TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
"File exists at new path");
TEST_FALSE(runner, Folder_Exists(folder, boffo),
"File no longer exists at old path");
}
else {
PASS(runner, "Rename does not clobber on this system");
TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
"File exists at new path");
TEST_TRUE(runner, Folder_Exists(folder, boffo),
"File still exists at old path");
Folder_Delete(folder, boffo);
}
// Move Dirs.
Folder_MkDir(folder, baz);
result = Folder_Rename(folder, baz, boffo);
TEST_TRUE(runner, result, "Rename dir");
TEST_TRUE(runner, Folder_Exists(folder, boffo),
"Folder exists at new path");
TEST_FALSE(runner, Folder_Exists(folder, baz),
"Folder no longer exists at old path");
result = Folder_Rename(folder, boffo, foo_foo);
TEST_TRUE(runner, result, "Rename dir into nested subdir");
TEST_TRUE(runner, Folder_Exists(folder, foo_foo),
"Folder exists at new path");
TEST_FALSE(runner, Folder_Exists(folder, boffo),
"Folder no longer exists at old path");
result = Folder_Rename(folder, foo_foo, foo_bar_baz);
TEST_TRUE(runner, result, "Rename dir from nested subdir");
TEST_TRUE(runner, Folder_Exists(folder, foo_bar_baz),
"Folder exists at new path");
TEST_FALSE(runner, Folder_Exists(folder, foo_foo),
"Folder no longer exists at old path");
// Test failed clobbers.
Err_set_error(NULL);
result = Folder_Rename(folder, foo_boffo, foo_bar);
TEST_FALSE(runner, result, "Rename file clobbering dir fails");
TEST_TRUE(runner, Err_get_error() != NULL,
"Failed rename sets global error");
TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
"File still exists at old path");
TEST_TRUE(runner, Folder_Exists(folder, foo_bar),
"Dir still exists after failed clobber");
Err_set_error(NULL);
result = Folder_Rename(folder, foo_bar, foo_boffo);
TEST_FALSE(runner, result, "Rename dir clobbering file fails");
TEST_TRUE(runner, Err_get_error() != NULL,
"Failed rename sets global error");
TEST_TRUE(runner, Folder_Exists(folder, foo_bar),
"Dir still exists at old path");
TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
"File still exists after failed clobber");
// Test that "renaming" succeeds where to and from are the same.
result = Folder_Rename(folder, foo_boffo, foo_boffo);
TEST_TRUE(runner, result, "Renaming file to itself succeeds");
TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
"File still exists");
result = Folder_Rename(folder, foo_bar, foo_bar);
// FIXME: This test sometimes fails on Windows with "Permission denied".
TEST_TRUE(runner, result, "Renaming dir to itself succeeds");
TEST_TRUE(runner, Folder_Exists(folder, foo_bar),
"Dir still exists");
// Invalid filepaths.
Err_set_error(NULL);
result = Folder_Rename(folder, foo_boffo, nope_nyet);
TEST_FALSE(runner, result, "Rename into non-existent subdir fails");
TEST_TRUE(runner, Err_get_error() != NULL,
"Renaming into non-existent subdir sets global error");
TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
"Entry still exists at old path");
Err_set_error(NULL);
result = Folder_Rename(folder, nope_nyet, boffo);
TEST_FALSE(runner, result, "Rename non-existent file fails");
TEST_TRUE(runner, Err_get_error() != NULL,
"Renaming non-existent source file sets global error");
Folder_Delete(folder, foo_bar_baz);
Folder_Delete(folder, foo_bar);
Folder_Delete(folder, foo_boffo);
Folder_Delete(folder, foo);
DECREF(folder);
tear_down();
}
static void
test_Hard_Link(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) {
Folder *folder = set_up();
OutStream *outstream;
bool result;
Folder_MkDir(folder, foo);
Folder_MkDir(folder, foo_bar);
outstream = Folder_Open_Out(folder, boffo);
DECREF(outstream);
// Link files.
result = Folder_Hard_Link(folder, boffo, banana);
TEST_TRUE(runner, result, "Hard_Link succeeds and returns true");
TEST_TRUE(runner, Folder_Exists(folder, banana),
"File exists at new path");
TEST_TRUE(runner, Folder_Exists(folder, boffo),
"File still exists at old path");
Folder_Delete(folder, boffo);
result = Folder_Hard_Link(folder, banana, foo_bar_boffo);
TEST_TRUE(runner, result, "Hard_Link to target within nested dir");
TEST_TRUE(runner, Folder_Exists(folder, foo_bar_boffo),
"File exists at new path");
TEST_TRUE(runner, Folder_Exists(folder, banana),
"File still exists at old path");
Folder_Delete(folder, banana);
result = Folder_Hard_Link(folder, foo_bar_boffo, foo_boffo);
TEST_TRUE(runner, result, "Hard_Link from file in nested dir");
TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
"File exists at new path");
TEST_TRUE(runner, Folder_Exists(folder, foo_bar_boffo),
"File still exists at old path");
Folder_Delete(folder, foo_bar_boffo);
// Invalid clobbers.
outstream = Folder_Open_Out(folder, boffo);
DECREF(outstream);
result = Folder_Hard_Link(folder, foo_boffo, boffo);
TEST_FALSE(runner, result, "Clobber of file fails");
TEST_TRUE(runner, Folder_Exists(folder, boffo),
"File still exists at new path");
TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
"File still exists at old path");
Folder_Delete(folder, boffo);
Folder_MkDir(folder, baz);
result = Folder_Hard_Link(folder, foo_boffo, baz);
TEST_FALSE(runner, result, "Clobber of dir fails");
TEST_TRUE(runner, Folder_Exists(folder, baz),
"Dir still exists at new path");
TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
"File still exists at old path");
Folder_Delete(folder, baz);
// Invalid Hard_Link of dir.
Folder_MkDir(folder, baz);
result = Folder_Hard_Link(folder, baz, banana);
TEST_FALSE(runner, result, "Hard_Link dir fails");
TEST_FALSE(runner, Folder_Exists(folder, banana),
"Nothing at new path");
// FIXME: This test sometimes fails on Windows.
TEST_TRUE(runner, Folder_Exists(folder, baz),
"Folder still exists at old path");
Folder_Delete(folder, baz);
// Test that linking to yourself fails.
result = Folder_Hard_Link(folder, foo_boffo, foo_boffo);
TEST_FALSE(runner, result, "Hard_Link file to itself fails");
TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
"File still exists");
// Invalid filepaths.
Err_set_error(NULL);
result = Folder_Rename(folder, foo_boffo, nope_nyet);
TEST_FALSE(runner, result, "Hard_Link into non-existent subdir fails");
TEST_TRUE(runner, Err_get_error() != NULL,
"Hard_Link into non-existent subdir sets global error");
TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
"Entry still exists at old path");
Err_set_error(NULL);
result = Folder_Rename(folder, nope_nyet, boffo);
TEST_FALSE(runner, result, "Hard_Link non-existent source file fails");
TEST_TRUE(runner, Err_get_error() != NULL,
"Hard_Link non-existent source file sets global error");
Folder_Delete(folder, foo_bar);
Folder_Delete(folder, foo_boffo);
Folder_Delete(folder, foo);
DECREF(folder);
tear_down();
}
static void
test_Close(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) {
Folder *folder = set_up();
Folder_Close(folder);
PASS(runner, "Close() concludes without incident");
Folder_Close(folder);
Folder_Close(folder);
PASS(runner, "Calling Close() multiple times is safe");
DECREF(folder);
tear_down();
}
uint32_t
TestFolderCommon_num_tests() {
return 99;
}
void
TestFolderCommon_run_tests(TestBatchRunner *runner, set_up_t set_up,
tear_down_t tear_down) {
S_init_strings();
test_Local_Exists(runner, set_up, tear_down);
test_Local_Is_Directory(runner, set_up, tear_down);
test_Local_Find_Folder(runner, set_up, tear_down);
test_Local_MkDir(runner, set_up, tear_down);
test_Local_Open_Dir(runner, set_up, tear_down);
test_Local_Open_FileHandle(runner, set_up, tear_down);
test_Local_Delete(runner, set_up, tear_down);
test_Rename(runner, set_up, tear_down);
test_Hard_Link(runner, set_up, tear_down);
test_Close(runner, set_up, tear_down);
S_destroy_strings();
}