aboutsummaryrefslogtreecommitdiff
path: root/src/zen-test/utility-cmd-tests.cpp
blob: aa49d7299cbcf912f5e4b0d8cbe71f490c46a8da (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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Copyright Epic Games, Inc. All Rights Reserved.

#include <zencore/zencore.h>

#if ZEN_WITH_TESTS

#	include "zen-test.h"

#	include <zencore/compactbinarybuilder.h>
#	include <zencore/filesystem.h>
#	include <zencore/iobuffer.h>
#	include <zencore/testing.h>
#	include <zencore/testutils.h>

namespace zen::tests {

TEST_SUITE_BEGIN("zen.utility-cmd");

TEST_CASE("print.cbo_to_json")
{
	ScopedTemporaryDirectory TempDir;

	// Build a small compact binary object covering a few primitive field types.
	CbObjectWriter Writer;
	Writer << "Name"
		   << "ZenPrintTest";
	Writer << "Count" << int32_t(42);
	Writer << "Enabled" << true;

	IoBuffer Payload = Writer.Save().GetBuffer().AsIoBuffer();
	REQUIRE(Payload.GetSize() > 0);

	const std::filesystem::path CboPath = TempDir.Path() / "object.cbo";
	WriteFile(CboPath, Payload);

	const ZenCommandResult Result = RunZen(fmt::format(R"(print --source "{}")", CboPath.string()));

	REQUIRE_MESSAGE(Result.ExitCode == 0, fmt::format("zen print exited with code {}", Result.ExitCode));

	// CompactBinaryToJson emits a JSON object; field names are quoted and values appear verbatim.
	CHECK(Result.Output.find("\"Name\"") != std::string::npos);
	CHECK(Result.Output.find("\"ZenPrintTest\"") != std::string::npos);
	CHECK(Result.Output.find("\"Count\"") != std::string::npos);
	CHECK(Result.Output.find("42") != std::string::npos);
	CHECK(Result.Output.find("\"Enabled\"") != std::string::npos);
	CHECK(Result.Output.find("true") != std::string::npos);
}

TEST_CASE("print.show_type_info_annotates_output")
{
	ScopedTemporaryDirectory TempDir;

	CbObjectWriter Writer;
	Writer << "Count" << int32_t(7);

	IoBuffer					Payload = Writer.Save().GetBuffer().AsIoBuffer();
	const std::filesystem::path CboPath = TempDir.Path() / "object.cbo";
	WriteFile(CboPath, Payload);

	const ZenCommandResult Plain = RunZen(fmt::format(R"(print --source "{}")", CboPath.string()));
	const ZenCommandResult Typed = RunZen(fmt::format(R"(print --show-type-info --source "{}")", CboPath.string()));

	REQUIRE(Plain.ExitCode == 0);
	REQUIRE(Typed.ExitCode == 0);

	// --show-type-info prefixes values with type annotations like [IntegerPositive] that the plain variant omits.
	CHECK(Typed.Output.size() > Plain.Output.size());
	CHECK(Typed.Output.find("[IntegerPositive]") != std::string::npos);
	CHECK(Plain.Output.find("[IntegerPositive]") == std::string::npos);
}

TEST_CASE("print.missing_source_fails")
{
	const ZenCommandResult Result = RunZen(R"(print)");

	CHECK(Result.ExitCode != 0);
}

TEST_CASE("print.non_cbo_file_fails")
{
	ScopedTemporaryDirectory TempDir;

	const std::filesystem::path GarbagePath = TempDir.Path() / "garbage.cbo";
	const std::string_view		Garbage		= "this is not compact binary data";
	WriteFile(GarbagePath, IoBuffer(IoBuffer::Wrap, Garbage.data(), Garbage.size()));

	const ZenCommandResult Result = RunZen(fmt::format(R"(print --source "{}")", GarbagePath.string()));

	CHECK(Result.ExitCode != 0);
}

////////////////////////////////////////////////////////////////////////////////
// wipe

namespace {

	// Drop a small fixture tree of files and nested directories inside Root so wipe has
	// something non-trivial to recurse over.
	void PopulateWipeFixture(const std::filesystem::path& Root)
	{
		std::filesystem::create_directories(Root / "nested" / "deep");
		const std::string_view Contents = "hello";
		const IoBuffer		   Payload(IoBuffer::Wrap, Contents.data(), Contents.size());
		WriteFile(Root / "top.txt", Payload);
		WriteFile(Root / "nested" / "mid.txt", Payload);
		WriteFile(Root / "nested" / "deep" / "leaf.txt", Payload);
	}

	bool DirectoryIsEmpty(const std::filesystem::path& Path)
	{
		std::error_code Ec;
		return std::filesystem::is_empty(Path, Ec) && !Ec;
	}

}  // namespace

TEST_CASE("wipe.removes_directory_contents")
{
	ScopedTemporaryDirectory	TempDir;
	const std::filesystem::path Target = TempDir.Path() / "to-wipe";
	PopulateWipeFixture(Target);

	REQUIRE(std::filesystem::exists(Target / "top.txt"));
	REQUIRE(std::filesystem::exists(Target / "nested" / "deep" / "leaf.txt"));

	const ZenCommandResult Result = RunZen(fmt::format(R"(wipe --yes --quiet --directory "{}")", Target.string()));

	REQUIRE_MESSAGE(Result.ExitCode == 0, fmt::format("zen wipe exited with code {}", Result.ExitCode));

	CHECK_FALSE(std::filesystem::exists(Target / "top.txt"));
	CHECK_FALSE(std::filesystem::exists(Target / "nested"));
}

TEST_CASE("wipe.dryrun_keeps_files")
{
	ScopedTemporaryDirectory	TempDir;
	const std::filesystem::path Target = TempDir.Path() / "to-wipe";
	PopulateWipeFixture(Target);

	const ZenCommandResult Result = RunZen(fmt::format(R"(wipe --yes --quiet --dryrun --directory "{}")", Target.string()));

	REQUIRE_MESSAGE(Result.ExitCode == 0, fmt::format("zen wipe --dryrun exited with code {}", Result.ExitCode));

	// --dryrun must leave the tree untouched.
	CHECK(std::filesystem::exists(Target / "top.txt"));
	CHECK(std::filesystem::exists(Target / "nested" / "mid.txt"));
	CHECK(std::filesystem::exists(Target / "nested" / "deep" / "leaf.txt"));
}

TEST_CASE("wipe.nonexistent_directory_is_noop")
{
	ScopedTemporaryDirectory	TempDir;
	const std::filesystem::path Missing = TempDir.Path() / "does-not-exist";
	REQUIRE_FALSE(std::filesystem::exists(Missing));

	const ZenCommandResult Result = RunZen(fmt::format(R"(wipe --yes --quiet --directory "{}")", Missing.string()));

	// A missing directory should be silently skipped without failing.
	CHECK(Result.ExitCode == 0);
	CHECK_FALSE(std::filesystem::exists(Missing));
}

TEST_CASE("wipe.empty_directory")
{
	ScopedTemporaryDirectory	TempDir;
	const std::filesystem::path Target = TempDir.Path() / "empty";
	std::filesystem::create_directories(Target);
	REQUIRE(DirectoryIsEmpty(Target));

	const ZenCommandResult Result = RunZen(fmt::format(R"(wipe --yes --quiet --directory "{}")", Target.string()));

	CHECK(Result.ExitCode == 0);
}

TEST_SUITE_END();

}  // namespace zen::tests

#endif