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