• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

realm / realm-core / thomas.goyne_396

06 Jun 2024 03:48PM UTC coverage: 90.956% (+0.1%) from 90.858%
thomas.goyne_396

Pull #7698

Evergreen

tgoyne
Fix UB in Tokenizer
Pull Request #7698: RCORE-2141 RCORE-2142 Clean up a bunch of old encryption cruft

101814 of 180058 branches covered (56.55%)

1048 of 1098 new or added lines in 27 files covered. (95.45%)

132 existing lines in 20 files now uncovered.

214536 of 235869 relevant lines covered (90.96%)

6051586.73 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.4
/test/test_file.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2016 Realm Inc.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 * http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 **************************************************************************/
18

19
#include "testsettings.hpp"
20
#ifdef TEST_FILE
21

22
#include <map>
23
#include <ostream>
24
#include <sstream>
25

26
#include <realm/util/encrypted_file_mapping.hpp>
27
#include <realm/util/file.hpp>
28
#include <realm/util/file_mapper.hpp>
29

30
#include "test.hpp"
31

32
#if REALM_PLATFORM_APPLE
33
#include <fcntl.h>
34
#include <sys/stat.h>
35
#include <unistd.h>
36
#endif
37

38
using namespace realm;
39
using namespace realm::util;
40
using namespace realm::test_util;
41

42

43
// Test independence and thread-safety
44
// -----------------------------------
45
//
46
// All tests must be thread safe and independent of each other. This
47
// is required because it allows for both shuffling of the execution
48
// order and for parallelized testing.
49
//
50
// In particular, avoid using std::rand() since it is not guaranteed
51
// to be thread safe. Instead use the API offered in
52
// `test/util/random.hpp`.
53
//
54
// All files created in tests must use the TEST_PATH macro (or one of
55
// its friends) to obtain a suitable file system path. See
56
// `test/util/test_path.hpp`.
57
//
58
//
59
// Debugging and the ONLY() macro
60
// ------------------------------
61
//
62
// A simple way of disabling all tests except one called `Foo`, is to
63
// replace TEST(Foo) with ONLY(Foo) and then recompile and rerun the
64
// test suite. Note that you can also use filtering by setting the
65
// environment varible `UNITTEST_FILTER`. See `README.md` for more on
66
// this.
67
//
68
// Another way to debug a particular test, is to copy that test into
69
// `experiments/testcase.cpp` and then run `sh build.sh
70
// check-testcase` (or one of its friends) from the command line.
71

72

73
TEST(File_ExistsAndRemove)
74
{
2✔
75
    TEST_PATH(path);
2✔
76
    File(path, File::mode_Write);
2✔
77
    CHECK(File::exists(path));
2✔
78
    CHECK(File::try_remove(path));
2✔
79
    CHECK(!File::exists(path));
2✔
80
    CHECK(!File::try_remove(path));
2✔
81
}
2✔
82

83
TEST(File_IsSame)
84
{
2✔
85
    TEST_PATH(path_1);
2✔
86
    TEST_PATH(path_2);
2✔
87

88
    // exFAT does not allocate inode numbers until the file is first non-empty,
89
    // so all never-written-to files appear to be the same file
90
    File(path_1, File::mode_Write).resize(1);
2✔
91
    File(path_2, File::mode_Write).resize(1);
2✔
92

93
    File f1(path_1, File::mode_Append);
2✔
94
    File f2(path_1, File::mode_Read);
2✔
95
    File f3(path_2, File::mode_Append);
2✔
96

97
    CHECK(f1.is_same_file(f1));
2✔
98
    CHECK(f1.is_same_file(f2));
2✔
99
    CHECK(!f1.is_same_file(f3));
2✔
100
    CHECK(!f2.is_same_file(f3));
2✔
101
}
2✔
102

103

104
TEST(File_Streambuf)
105
{
2✔
106
    TEST_PATH(path);
2✔
107
    {
2✔
108
        File f(path, File::mode_Write);
2✔
109
        File::Streambuf b(&f);
2✔
110
        std::ostream out(&b);
2✔
111
        out << "Line " << 1 << std::endl;
2✔
112
        out << "Line " << 2 << std::endl;
2✔
113
    }
2✔
114
    {
2✔
115
        File f(path, File::mode_Read);
2✔
116
        char buffer[256];
2✔
117
        size_t n = f.read(0, buffer);
2✔
118
        std::string s_1(buffer, buffer + n);
2✔
119
        std::ostringstream out;
2✔
120
        out << "Line " << 1 << std::endl;
2✔
121
        out << "Line " << 2 << std::endl;
2✔
122
        std::string s_2 = out.str();
2✔
123
        CHECK(s_1 == s_2);
2✔
124
    }
2✔
125
}
2✔
126

127
TEST_TYPES(File_Map, std::true_type, std::false_type)
128
{
4✔
129
    TEST_PATH(path);
4✔
130
    const char data[4096] = "12345678901234567890";
4✔
131
    size_t len = strlen(data);
4✔
132
    {
4✔
133
        File f(path, File::mode_Write);
4✔
134
        f.set_encryption_key(crypt_key(TEST_TYPE::value));
4✔
135
        f.resize(len);
4✔
136

137
        File::Map<char> map(f, File::access_ReadWrite, len);
4✔
138
        util::encryption_read_barrier(map, 0, len);
4✔
139
        memcpy(map.get_addr(), data, len);
4✔
140
        realm::util::encryption_write_barrier(map, 0, len);
4✔
141
    }
4✔
142
    {
4✔
143
        File f(path, File::mode_Read);
4✔
144
        f.set_encryption_key(crypt_key(TEST_TYPE::value));
4✔
145
        File::Map<char> map(f, File::access_ReadOnly, len);
4✔
146
        util::encryption_read_barrier(map, 0, len);
4✔
147
        CHECK(memcmp(map.get_addr(), data, len) == 0);
4✔
148
    }
4✔
149
}
4✔
150

151

152
TEST_TYPES(File_MapMultiplePages, std::true_type, std::false_type)
153
{
4✔
154
    // two blocks of IV tables
155
    const size_t count = 4096 / sizeof(size_t) * 256 * 2;
4✔
156

157
    TEST_PATH(path);
4✔
158
    {
4✔
159
        File f(path, File::mode_Write);
4✔
160
        f.set_encryption_key(crypt_key(TEST_TYPE::value));
4✔
161
        f.resize(count * sizeof(size_t));
4✔
162

163
        File::Map<size_t> map(f, File::access_ReadWrite, count * sizeof(size_t));
4✔
164
        util::encryption_read_barrier(map, 0, count);
4✔
165
        for (size_t i = 0; i < count; ++i)
1,048,580✔
166
            map.get_addr()[i] = i;
1,048,576✔
167
        realm::util::encryption_write_barrier(map, 0, count);
4✔
168
    }
4✔
169
    {
4✔
170
        File f(path, File::mode_Read);
4✔
171
        f.set_encryption_key(crypt_key(TEST_TYPE::value));
4✔
172
        File::Map<size_t> map(f, File::access_ReadOnly, count * sizeof(size_t));
4✔
173
        util::encryption_read_barrier(map, 0, count);
4✔
174
        for (size_t i = 0; i < count; ++i) {
1,048,580✔
175
            CHECK_EQUAL(map.get_addr()[i], i);
1,048,576✔
176
            if (map.get_addr()[i] != i)
1,048,576✔
177
                return;
×
178
        }
1,048,576✔
179
    }
4✔
180
}
4✔
181

182
TEST_TYPES(File_ReaderAndWriter_SingleFile, std::true_type, std::false_type)
183
{
4✔
184
    const size_t count = 4096 / sizeof(size_t) * 256 * 2;
4✔
185

186
    TEST_PATH(path);
4✔
187

188
    File file(path, File::mode_Write);
4✔
189
    file.set_encryption_key(crypt_key(TEST_TYPE::value));
4✔
190
    file.resize(count * sizeof(size_t));
4✔
191

192
    File::Map<size_t> write(file, File::access_ReadWrite, count * sizeof(size_t));
4✔
193
    File::Map<size_t> read(file, File::access_ReadOnly, count * sizeof(size_t));
4✔
194

195
    for (size_t i = 0; i < count; i += 100) {
10,492✔
196
        util::encryption_read_barrier(write, i, 1);
10,488✔
197
        write.get_addr()[i] = i;
10,488✔
198
        realm::util::encryption_write_barrier(write, i);
10,488✔
199
        util::encryption_read_barrier(read, i);
10,488✔
200
        if (!CHECK_EQUAL(read.get_addr()[i], i))
10,488✔
NEW
201
            return;
×
202
    }
10,488✔
203
}
4✔
204

205
TEST_TYPES(File_ReaderAndWriter_MulitpleFiles, std::true_type, std::false_type)
206
{
4✔
207
    const size_t count = 4096 / sizeof(size_t) * 256 * 2;
4✔
208

209
    TEST_PATH(path);
4✔
210

211
    File writer(path, File::mode_Write);
4✔
212
    writer.set_encryption_key(crypt_key(TEST_TYPE::value));
4✔
213
    writer.resize(count * sizeof(size_t));
4✔
214

215
    File reader(path, File::mode_Read);
4✔
216
    reader.set_encryption_key(crypt_key(TEST_TYPE::value));
4✔
217
    CHECK_EQUAL(writer.get_size(), reader.get_size());
4✔
218

219
    File::Map<size_t> write(writer, File::access_ReadWrite, count * sizeof(size_t));
4✔
220
    File::Map<size_t> read(reader, File::access_ReadOnly, count * sizeof(size_t));
4✔
221

222
    for (size_t i = 0; i < count; i += 100) {
10,492✔
223
        util::encryption_read_barrier(write, i, 1);
10,488✔
224
        write.get_addr()[i] = i;
10,488✔
225
        realm::util::encryption_write_barrier(write, i);
10,488✔
226
        write.flush(true);
10,488✔
227
        if (auto encryption = reader.get_encryption())
10,488✔
228
            encryption->mark_data_as_possibly_stale();
5,244✔
229
        util::encryption_read_barrier(read, i);
10,488✔
230
        if (!CHECK_EQUAL(read.get_addr()[i], i))
10,488✔
UNCOV
231
            return;
×
232
    }
10,488✔
233
}
4✔
234

235
TEST_TYPES(File_Offset, std::true_type, std::false_type)
236
{
4✔
237
    const size_t size = page_size();
4✔
238
    const size_t count_per_page = size / sizeof(size_t);
4✔
239
    // two blocks of IV tables
240
    const size_t page_count = 256 * 2 / (size / 4096);
4✔
241

242
    TEST_PATH(path);
4✔
243
    {
4✔
244
        File f(path, File::mode_Write);
4✔
245
        f.set_encryption_key(crypt_key(TEST_TYPE::value));
4✔
246
        f.resize(page_count * size);
4✔
247

248
        for (size_t i = 0; i < page_count; ++i) {
1,284✔
249
            File::Map<size_t> map(f, i * size, File::access_ReadWrite, size);
1,280✔
250
            for (size_t j = 0; j < count_per_page; ++j) {
1,049,856✔
251
                util::encryption_read_barrier(map, j, 1);
1,048,576✔
252
                map.get_addr()[j] = i * size + j;
1,048,576✔
253
                realm::util::encryption_write_barrier(map, j);
1,048,576✔
254
            }
1,048,576✔
255
        }
1,280✔
256
    }
4✔
257
    {
4✔
258
        File f(path, File::mode_Read);
4✔
259
        f.set_encryption_key(crypt_key(TEST_TYPE::value));
4✔
260
        for (size_t i = 0; i < page_count; ++i) {
1,284✔
261
            File::Map<size_t> map(f, i * size, File::access_ReadOnly, size);
1,280✔
262
            for (size_t j = 0; j < count_per_page; ++j) {
1,049,856✔
263
                util::encryption_read_barrier(map, j);
1,048,576✔
264
                CHECK_EQUAL(map.get_addr()[j], i * size + j);
1,048,576✔
265
                if (map.get_addr()[j] != i * size + j)
1,048,576✔
266
                    return;
×
267
            }
1,048,576✔
268
        }
1,280✔
269
    }
4✔
270
}
4✔
271

272
TEST_TYPES(File_MultipleWriters_SingleFile, std::true_type, std::false_type)
273
{
4✔
274
    const size_t count = 4096 / sizeof(size_t) * 256 * 2;
4✔
275
    const size_t increments = 100;
4✔
276
    TEST_PATH(path);
4✔
277

278
    {
4✔
279
        File w(path, File::mode_Write);
4✔
280
        w.set_encryption_key(crypt_key(TEST_TYPE::value));
4✔
281
        w.resize(count * sizeof(size_t));
4✔
282
        File::Map<size_t> map1(w, File::access_ReadWrite, count * sizeof(size_t));
4✔
283
        File::Map<size_t> map2(w, File::access_ReadWrite, count * sizeof(size_t));
4✔
284

285
        // Place zeroes in selected places
286
        for (size_t i = 0; i < count; i += increments) {
10,492✔
287
            util::encryption_read_barrier(map1, i);
10,488✔
288
            map1.get_addr()[i] = 0;
10,488✔
289
            realm::util::encryption_write_barrier(map1, i);
10,488✔
290
        }
10,488✔
291

292
        for (size_t i = 0; i < count; i += increments) {
10,492✔
293
            util::encryption_read_barrier(map1, i, 1);
10,488✔
294
            ++map1.get_addr()[i];
10,488✔
295
            realm::util::encryption_write_barrier(map1, i);
10,488✔
296
            util::encryption_read_barrier(map2, i, 1);
10,488✔
297
            ++map2.get_addr()[i];
10,488✔
298
            realm::util::encryption_write_barrier(map2, i);
10,488✔
299
        }
10,488✔
300
    }
4✔
301

302
    File reader(path, File::mode_Read);
4✔
303
    reader.set_encryption_key(crypt_key(TEST_TYPE::value));
4✔
304

305
    File::Map<size_t> read(reader, File::access_ReadOnly, count * sizeof(size_t));
4✔
306
    util::encryption_read_barrier(read, 0, count);
4✔
307
    for (size_t i = 0; i < count; i += increments) {
10,492✔
308
        if (!CHECK_EQUAL(read.get_addr()[i], 2))
10,488✔
NEW
309
            return;
×
310
    }
10,488✔
311
}
4✔
312

313
TEST_TYPES(File_MultipleWriters_MultipleFiles, std::true_type, std::false_type)
314
{
4✔
315
    const size_t count = 4096 / sizeof(size_t) * 256 * 2;
4✔
316
    const size_t increments = 100;
4✔
317
    TEST_PATH(path);
4✔
318

319
    {
4✔
320
        File w1(path, File::mode_Write);
4✔
321
        w1.set_encryption_key(crypt_key(TEST_TYPE::value));
4✔
322
        w1.resize(count * sizeof(size_t));
4✔
323

324
        File w2(path, File::mode_Write);
4✔
325
        w2.set_encryption_key(crypt_key(TEST_TYPE::value));
4✔
326
        w2.resize(count * sizeof(size_t));
4✔
327

328
        File::Map<size_t> map1(w1, File::access_ReadWrite, count * sizeof(size_t));
4✔
329
        File::Map<size_t> map2(w2, File::access_ReadWrite, count * sizeof(size_t));
4✔
330

331
        // Place zeroes in selected places
332
        for (size_t i = 0; i < count; i += increments) {
10,492✔
333
            encryption_read_barrier(map1, i);
10,488✔
334
            map1.get_addr()[i] = 0;
10,488✔
335
            encryption_write_barrier(map1, i);
10,488✔
336
        }
10,488✔
337
        map1.flush();
4✔
338

339
        for (size_t i = 0; i < count; i += increments) {
10,492✔
340
            util::encryption_read_barrier(map1, i, 1);
10,488✔
341
            ++map1.get_addr()[i];
10,488✔
342
            encryption_write_barrier(map1, i);
10,488✔
343
            map1.flush(true);
10,488✔
344
            if (auto encryption = w2.get_encryption())
10,488✔
345
                encryption->mark_data_as_possibly_stale();
5,244✔
346

347
            util::encryption_read_barrier(map2, i, 1);
10,488✔
348
            ++map2.get_addr()[i];
10,488✔
349
            encryption_write_barrier(map2, i);
10,488✔
350
            map2.flush(true);
10,488✔
351
            if (auto encryption = w1.get_encryption())
10,488✔
352
                encryption->mark_data_as_possibly_stale();
5,244✔
353
        }
10,488✔
354
    }
4✔
355

356
    File reader(path, File::mode_Read);
4✔
357
    reader.set_encryption_key(crypt_key(TEST_TYPE::value));
4✔
358

359
    File::Map<size_t> read(reader, File::access_ReadOnly, count * sizeof(size_t));
4✔
360
    util::encryption_read_barrier(read, 0, count);
4✔
361
    for (size_t i = 0; i < count; i += increments) {
10,492✔
362
        if (!CHECK_EQUAL(read.get_addr()[i], 2))
10,488✔
UNCOV
363
            return;
×
364
    }
10,488✔
365
}
4✔
366

367
TEST(File_SetEncryptionKey)
368
{
2✔
369
    TEST_PATH(path);
2✔
370
    File f(path, File::mode_Write);
2✔
371
    const char key[64] = {0};
2✔
372

373
#if REALM_ENABLE_ENCRYPTION
2✔
374
    f.set_encryption_key(key); // should not throw
2✔
375
#else
376
    CHECK_THROW_EX(f.set_encryption_key(key), Exception, (e.code() == ErrorCodes::NotSupported));
377
#endif
378
}
2✔
379

380

381
TEST(File_ReadWrite)
382
{
2✔
383
    TEST_PATH(path);
2✔
384
    File f(path, File::mode_Write);
2✔
385
    f.set_encryption_key(crypt_key());
2✔
386
    f.resize(100);
2✔
387

388
    for (char i = 0; i < 100; ++i)
202✔
389
        f.write(i, &i, 1);
200✔
390
    for (char i = 0; i < 100; ++i) {
202✔
391
        char read;
200✔
392
        f.read(i, &read, 1);
200✔
393
        CHECK_EQUAL(i, read);
200✔
394
    }
200✔
395
}
2✔
396

397

398
TEST_TYPES(File_Resize, std::true_type, std::false_type)
399
{
4✔
400
    TEST_PATH(path);
4✔
401
    File f(path, File::mode_Write);
4✔
402
    f.set_encryption_key(crypt_key(TEST_TYPE::value));
4✔
403

404
    f.resize(page_size() * 2);
4✔
405
    CHECK_EQUAL(page_size() * 2, f.get_size());
4✔
406
    {
4✔
407
        File::Map<unsigned char> m(f, File::access_ReadWrite, page_size() * 2);
4✔
408
        for (unsigned int i = 0; i < page_size() * 2; ++i) {
81,924✔
409
            util::encryption_read_barrier(m, i, 1);
81,920✔
410
            m.get_addr()[i] = static_cast<unsigned char>(i);
81,920✔
411
            realm::util::encryption_write_barrier(m, i);
81,920✔
412
        }
81,920✔
413

414
        // Resizing away the first write is indistinguishable in encrypted files
415
        // from the process being interrupted before it does the first write,
416
        // but with subsequent writes it can tell that there was once valid
417
        // encrypted data there, so flush and write a second time
418
        m.sync();
4✔
419
        for (unsigned int i = 0; i < page_size() * 2; ++i) {
81,924✔
420
            util::encryption_read_barrier(m, i, 1);
81,920✔
421
            m.get_addr()[i] = static_cast<unsigned char>(i);
81,920✔
422
            realm::util::encryption_write_barrier(m, i);
81,920✔
423
        }
81,920✔
424
    }
4✔
425

426
    f.resize(page_size());
4✔
427
    CHECK_EQUAL(page_size(), f.get_size());
4✔
428
    {
4✔
429
        File::Map<unsigned char> m(f, File::access_ReadOnly, page_size());
4✔
430
        for (unsigned int i = 0; i < page_size(); ++i) {
40,964✔
431
            util::encryption_read_barrier(m, i);
40,960✔
432
            CHECK_EQUAL(static_cast<unsigned char>(i), m.get_addr()[i]);
40,960✔
433
            if (static_cast<unsigned char>(i) != m.get_addr()[i])
40,960✔
434
                return;
×
435
        }
40,960✔
436
    }
4✔
437

438
    f.resize(page_size() * 2);
4✔
439
    CHECK_EQUAL(page_size() * 2, f.get_size());
4✔
440
    {
4✔
441
        File::Map<unsigned char> m(f, File::access_ReadWrite, page_size() * 2);
4✔
442
        for (unsigned int i = 0; i < page_size() * 2; ++i) {
81,924✔
443
            util::encryption_read_barrier(m, i, 1);
81,920✔
444
            m.get_addr()[i] = static_cast<unsigned char>(i);
81,920✔
445
            realm::util::encryption_write_barrier(m, i);
81,920✔
446
        }
81,920✔
447
    }
4✔
448
    {
4✔
449
        File::Map<unsigned char> m(f, File::access_ReadOnly, page_size() * 2);
4✔
450
        for (unsigned int i = 0; i < page_size() * 2; ++i) {
81,924✔
451
            util::encryption_read_barrier(m, i);
81,920✔
452
            CHECK_EQUAL(static_cast<unsigned char>(i), m.get_addr()[i]);
81,920✔
453
            if (static_cast<unsigned char>(i) != m.get_addr()[i])
81,920✔
454
                return;
×
455
        }
81,920✔
456
    }
4✔
457
}
4✔
458

459

460
TEST(File_NotFound)
461
{
2✔
462
    TEST_PATH(path);
2✔
463
    File file;
2✔
464
    CHECK_THROW_EX(file.open(path), FileAccessError, e.get_path() == std::string(path));
2✔
465
}
2✔
466

467

468
TEST(File_PathNotFound)
469
{
2✔
470
    File file;
2✔
471
    CHECK_THROW_EX(file.open(""), FileAccessError, e.code() == ErrorCodes::FileNotFound);
2✔
472
}
2✔
473

474

475
TEST(File_Exists)
476
{
2✔
477
    TEST_PATH(path);
2✔
478
    File file;
2✔
479
    file.open(path, File::mode_Write); // Create the file
2✔
480
    file.close();
2✔
481
    CHECK_THROW_EX(file.open(path, File::access_ReadWrite, File::create_Must, File::flag_Trunc), FileAccessError,
2✔
482
                   e.get_path() == std::string(path) && e.code() == ErrorCodes::FileAlreadyExists);
2✔
483
}
2✔
484

485

486
TEST(File_Move)
487
{
2✔
488
    TEST_PATH(path);
2✔
489
    File file_1(path, File::mode_Write);
2✔
490
    CHECK(file_1.is_attached());
2✔
491
    File file_2(std::move(file_1));
2✔
492
    CHECK_NOT(file_1.is_attached());
2✔
493
    CHECK(file_2.is_attached());
2✔
494
    file_1 = std::move(file_2);
2✔
495
    CHECK(file_1.is_attached());
2✔
496
    CHECK_NOT(file_2.is_attached());
2✔
497
}
2✔
498

499
TEST(File_PreallocResizingAPFSBug)
500
{
2✔
501
    TEST_PATH(path);
2✔
502
    File file(path, File::mode_Write);
2✔
503
    CHECK(file.is_attached());
2✔
504
    file.write(0, "aaaaaaaaaaaaaaaaaaaa"); // 20 a's
2✔
505
    // calling prealloc on a newly created file would sometimes fail on APFS with EINVAL via fcntl(F_PREALLOCATE)
506
    // this may not be the only way to trigger the error, but it does seem to be timing dependant.
507
    file.prealloc(100);
2✔
508
    CHECK_EQUAL(file.get_size(), 100);
2✔
509

510
    // this will change the file size, but likely won't preallocate more space since the first call to prealloc
511
    // will probably have allocated a whole 4096 block.
512
    file.prealloc(200);
2✔
513
    CHECK_EQUAL(file.get_size(), 200);
2✔
514
    file.write(22, "aa");
2✔
515
    file.prealloc(5020); // expands to another 4096 block
2✔
516
    constexpr size_t insert_pos = 5000;
2✔
517
    const char* insert_str = "hello";
2✔
518
    file.write(insert_pos, insert_str);
2✔
519
    CHECK_EQUAL(file.get_size(), 5020);
2✔
520
    constexpr size_t input_size = 6;
2✔
521
    char input[input_size];
2✔
522
    file.read(insert_pos, input, input_size);
2✔
523
    CHECK_EQUAL(strncmp(input, insert_str, input_size), 0);
2✔
524
}
2✔
525

526
TEST(File_parent_dir)
527
{
2✔
528
    std::map<std::string, std::string> mappings = {{"Unicorn🦄/file.cpp", "Unicorn🦄"},
2✔
529
                                                   {"", ""},
2✔
530
                                                   {"asdf", ""},
2✔
531
                                                   {"file.cpp", ""},
2✔
532
                                                   {"Unicorn🦄", ""},
2✔
533
                                                   {"parent/file.cpp", "parent"},
2✔
534
                                                   {"parent//file.cpp", "parent"},
2✔
535
                                                   {"parent///file.cpp", "parent"},
2✔
536
                                                   {"parent////file.cpp", "parent"},
2✔
537
                                                   {"1/2/3/4.cpp", "1/2/3"},
2✔
538
                                                   {"/1/2/3/4", "/1/2/3"}};
2✔
539
    for (auto [input, expected] : mappings) {
22✔
540
        std::string actual = File::parent_dir(input);
22✔
541
        CHECK_EQUAL(actual, expected);
22✔
542
        if (actual != expected) {
22✔
543
            realm::util::format(std::cout, "unexpected result '%1' for input '%2'", actual, input);
×
544
        }
×
545
    }
22✔
546
}
2✔
547

548
TEST(File_Temp)
549
{
2✔
550
    auto tmp_file_name = make_temp_file("foo");
2✔
551
    {
2✔
552
        File file1;
2✔
553
        file1.open(tmp_file_name, File::mode_Write);
2✔
554
        CHECK(file1.is_attached());
2✔
555
    }
2✔
556
    remove(tmp_file_name.c_str());
2✔
557
}
2✔
558

559
#endif // TEST_FILE
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc