Skip to content

Commit ae49e6d

Browse files
committed
test: Add support for the -s option
1 parent 05dcf6d commit ae49e6d

File tree

3 files changed

+59
-1
lines changed

3 files changed

+59
-1
lines changed

Tests/Utilities/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
set(TEST_SOURCES
22
TestPatch.cpp
33
TestSed.cpp
4+
TestTest.cpp
45
TestUniq.cpp
56
)
67

Tests/Utilities/TestTest.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (c) 2026, Lucas Chollet <lucas.chollet@serenityos.org>
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
7+
#include <AK/StringView.h>
8+
#include <LibCore/File.h>
9+
#include <LibCore/Process.h>
10+
#include <LibFileSystem/TempFile.h>
11+
#include <LibTest/TestCase.h>
12+
13+
static void run_test(Vector<ByteString>&& arguments, int expected_exit_status)
14+
{
15+
auto test = TRY_OR_FAIL(Core::Process::spawn(
16+
Core::ProcessSpawnOptions { .executable = "test"sv,
17+
.search_for_executable_in_path = true,
18+
.arguments = arguments }));
19+
auto exited_with_code_0 = TRY_OR_FAIL(test.wait_for_termination());
20+
EXPECT_EQ(expected_exit_status, exited_with_code_0 ? 0 : 1);
21+
}
22+
23+
TEST_CASE(option_s)
24+
{
25+
run_test({ "-s", "file_that_do_not_exist" }, 1);
26+
27+
// empty file
28+
auto temp_file = TRY_OR_FAIL(FileSystem::TempFile::create_temp_file());
29+
run_test({ "-s", MUST(ByteString::from_utf8(temp_file->path())) }, 1);
30+
31+
auto file = TRY_OR_FAIL(Core::File::open(temp_file->path(), Core::File::OpenMode::Write));
32+
TRY_OR_FAIL(file->write_until_depleted("file content\n"sv));
33+
run_test({ "-s", MUST(ByteString::from_utf8(temp_file->path())) }, 0);
34+
}

Userland/Utilities/test.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,28 @@ class FileIsOwnedBy : public Condition {
265265
Owner m_kind { EffectiveGID };
266266
};
267267

268+
class FileExists : public Condition {
269+
public:
270+
FileExists(StringView path)
271+
: m_path(path)
272+
{
273+
}
274+
275+
private:
276+
virtual bool check() const override
277+
{
278+
// "True if pathname resolves to an existing directory entry for a file that
279+
// has a size greater than zero. False if pathname cannot be resolved, or if
280+
// pathname resolves to an existing directory entry for a file that does not
281+
// have a size greater than zero."
282+
283+
auto result = Core::System::stat(m_path);
284+
return !result.is_error() && result.value().st_size > 0;
285+
}
286+
287+
ByteString m_path;
288+
};
289+
268290
class StringCompare : public Condition {
269291
public:
270292
enum Mode {
@@ -478,8 +500,9 @@ static OwnPtr<Condition> parse_simple_expression(char* argv[])
478500
return make<FileIsOwnedBy>(value, FileIsOwnedBy::EffectiveGID);
479501
case 'O':
480502
return make<FileIsOwnedBy>(value, FileIsOwnedBy::EffectiveUID);
481-
case 'N':
482503
case 's':
504+
return make<FileExists>(value);
505+
case 'N':
483506
// 'optind' has been incremented to refer to the argument after the
484507
// operator, while we want to print the operator itself.
485508
fatal_error("Unsupported operator \033[1m%s", argv[optind - 1]);

0 commit comments

Comments
 (0)