1#include "test.h"
2
3#include <base/fs.h>
4#include <base/logger.h>
5#include <base/net.h>
6#include <base/os.h>
7#include <base/process.h>
8#include <base/str.h>
9
10#include <engine/storage.h>
11
12#include <gtest/gtest.h>
13
14#include <algorithm>
15
16CTestInfo::CTestInfo()
17{
18 const ::testing::TestInfo *pTestInfo =
19 ::testing::UnitTest::GetInstance()->current_test_info();
20
21 // Typed tests have test names like "TestName/0" and "TestName/1", which would result in invalid filenames.
22 // Replace the string after the first slash with the name of the typed test and use hyphen instead of slash.
23 char aTestCaseName[128];
24 str_copy(dst&: aTestCaseName, src: pTestInfo->test_case_name());
25 for(int i = 0; i < str_length(str: aTestCaseName); i++)
26 {
27 if(aTestCaseName[i] == '/')
28 {
29 aTestCaseName[i] = '-';
30 aTestCaseName[i + 1] = '\0';
31 str_append(dst&: aTestCaseName, src: pTestInfo->type_param());
32 break;
33 }
34 }
35 str_format(buffer: m_aFilenamePrefix, buffer_size: sizeof(m_aFilenamePrefix), format: "%s.%s-%d",
36 aTestCaseName, pTestInfo->name(), process_id());
37 Filename(pBuffer: m_aFilename, BufferLength: sizeof(m_aFilename), pSuffix: ".tmp");
38}
39
40void CTestInfo::Filename(char *pBuffer, size_t BufferLength, const char *pSuffix)
41{
42 str_format(buffer: pBuffer, buffer_size: BufferLength, format: "%s%s", m_aFilenamePrefix, pSuffix);
43}
44
45std::unique_ptr<IStorage> CTestInfo::CreateTestStorage()
46{
47 bool Error = fs_makedir(path: m_aFilename);
48 EXPECT_FALSE(Error);
49 if(Error)
50 {
51 return nullptr;
52 }
53 char aTestPath[IO_MAX_PATH_LENGTH];
54 str_copy(dst&: aTestPath, src: ::testing::internal::GetArgvs().front().c_str());
55 const char *apArgs[] = {aTestPath};
56 return CreateTempStorage(pDirectory: m_aFilename, NumArgs: std::size(apArgs), ppArguments: apArgs);
57}
58
59class CTestInfoPath
60{
61public:
62 bool m_IsDirectory;
63 char m_aData[IO_MAX_PATH_LENGTH];
64
65 bool operator<(const CTestInfoPath &Other) const
66 {
67 if(m_IsDirectory != Other.m_IsDirectory)
68 {
69 return m_IsDirectory < Other.m_IsDirectory;
70 }
71 return str_comp(a: m_aData, b: Other.m_aData) > 0;
72 }
73};
74
75class CTestCollectData
76{
77public:
78 char m_aCurrentDir[IO_MAX_PATH_LENGTH];
79 std::vector<CTestInfoPath> *m_pvEntries;
80};
81
82int TestCollect(const char *pName, int IsDir, int Unused, void *pUser)
83{
84 CTestCollectData *pData = (CTestCollectData *)pUser;
85
86 if(str_comp(a: pName, b: ".") == 0 || str_comp(a: pName, b: "..") == 0)
87 {
88 return 0;
89 }
90
91 CTestInfoPath Path;
92 Path.m_IsDirectory = IsDir;
93 str_format(buffer: Path.m_aData, buffer_size: sizeof(Path.m_aData), format: "%s/%s", pData->m_aCurrentDir, pName);
94 pData->m_pvEntries->push_back(x: Path);
95 if(Path.m_IsDirectory)
96 {
97 CTestCollectData DataRecursive;
98 str_copy(dst: DataRecursive.m_aCurrentDir, src: Path.m_aData, dst_size: sizeof(DataRecursive.m_aCurrentDir));
99 DataRecursive.m_pvEntries = pData->m_pvEntries;
100 fs_listdir(dir: DataRecursive.m_aCurrentDir, cb: TestCollect, type: 0, user: &DataRecursive);
101 }
102 return 0;
103}
104
105void TestDeleteTestStorageFiles(const char *pPath)
106{
107 std::vector<CTestInfoPath> vEntries;
108 CTestCollectData Data;
109 str_copy(dst: Data.m_aCurrentDir, src: pPath, dst_size: sizeof(Data.m_aCurrentDir));
110 Data.m_pvEntries = &vEntries;
111 fs_listdir(dir: Data.m_aCurrentDir, cb: TestCollect, type: 0, user: &Data);
112
113 CTestInfoPath Path;
114 Path.m_IsDirectory = true;
115 str_copy(dst: Path.m_aData, src: Data.m_aCurrentDir, dst_size: sizeof(Path.m_aData));
116 vEntries.push_back(x: Path);
117
118 // Sorts directories after files.
119 std::sort(first: vEntries.begin(), last: vEntries.end());
120
121 // Don't delete too many files.
122 ASSERT_LE(vEntries.size(), 10);
123 for(auto &Entry : vEntries)
124 {
125 if(Entry.m_IsDirectory)
126 {
127 ASSERT_FALSE(fs_removedir(Entry.m_aData));
128 }
129 else
130 {
131 ASSERT_FALSE(fs_remove(Entry.m_aData));
132 }
133 }
134}
135
136CTestInfo::~CTestInfo()
137{
138 if(!::testing::Test::HasFailure() && m_DeleteTestStorageFilesOnSuccess)
139 {
140 TestDeleteTestStorageFiles(pPath: m_aFilename);
141 }
142}
143
144int main(int argc, const char **argv)
145{
146 CCmdlineFix CmdlineFix(&argc, &argv);
147 log_set_global_logger_default();
148 ::testing::InitGoogleTest(argc: &argc, argv: const_cast<char **>(argv));
149 GTEST_FLAG_SET(death_test_style, "threadsafe");
150 net_init();
151 return RUN_ALL_TESTS();
152}
153
154TEST(TestInfo, Sort)
155{
156 std::vector<CTestInfoPath> vEntries;
157 vEntries.resize(new_size: 3);
158
159 const char aBasePath[] = "test_dir";
160 const char aSubPath[] = "test_dir/subdir";
161 const char aFilePath[] = "test_dir/subdir/file.txt";
162
163 vEntries[0].m_IsDirectory = true;
164 str_copy(dst&: vEntries[0].m_aData, src: aBasePath);
165
166 vEntries[1].m_IsDirectory = true;
167 str_copy(dst&: vEntries[1].m_aData, src: aSubPath);
168
169 vEntries[2].m_IsDirectory = false;
170 str_copy(dst&: vEntries[2].m_aData, src: aFilePath);
171
172 // Sorts directories after files.
173 std::sort(first: vEntries.begin(), last: vEntries.end());
174
175 EXPECT_FALSE(vEntries[0].m_IsDirectory);
176 EXPECT_EQ(str_comp(vEntries[0].m_aData, aFilePath), 0);
177 EXPECT_TRUE(vEntries[1].m_IsDirectory);
178 EXPECT_EQ(str_comp(vEntries[1].m_aData, aSubPath), 0);
179 EXPECT_TRUE(vEntries[2].m_IsDirectory);
180 EXPECT_EQ(str_comp(vEntries[2].m_aData, aBasePath), 0);
181}
182