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

realm / realm-core / thomas.goyne_112

27 Oct 2023 10:49AM UTC coverage: 91.586% (+0.02%) from 91.571%
thomas.goyne_112

push

Evergreen

web-flow
Merge pull request #7085 from realm/release/13.23.2

Release/13.23.2

91754 of 168238 branches covered (0.0%)

230143 of 251285 relevant lines covered (91.59%)

7082763.83 hits per line

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

99.89
/test/test_table_view.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_TABLE_VIEW
21

22
#include <limits>
23
#include <string>
24
#include <sstream>
25
#include <ostream>
26
#include <cwchar>
27
#include <chrono>
28

29
#include <realm.hpp>
30

31
#include "util/misc.hpp"
32

33
#include "test.hpp"
34
#include "test_table_helper.hpp"
35

36
using namespace std::chrono;
37

38
using namespace realm;
39
using namespace test_util;
40

41
extern unsigned int unit_test_random_seed;
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
TEST(TableView_Json)
73
{
2✔
74
    Table table;
2✔
75
    auto col = table.add_column(type_Int, "first");
2✔
76

1✔
77
    table.create_object().set(col, 1);
2✔
78
    table.create_object().set(col, 2);
2✔
79
    table.create_object().set(col, 3);
2✔
80

1✔
81
    TableView v = table.where().find_all(2);
2✔
82
    std::stringstream ss;
2✔
83
    v.to_json(ss);
2✔
84
    const std::string json = ss.str();
2✔
85
    CHECK_EQUAL(true, json.length() > 0);
2✔
86
    CHECK_EQUAL("[{\"_key\":0,\"first\":1},{\"_key\":1,\"first\":2}]", json);
2✔
87
}
2✔
88

89

90
TEST(TableView_TimestampMaxMinCount)
91
{
2✔
92
    Table t;
2✔
93
    auto col = t.add_column(type_Timestamp, "ts", true);
2✔
94
    auto max_key = t.create_object().set_all(Timestamp(300, 300)).get_key();
2✔
95
    auto min_key = t.create_object().set_all(Timestamp(100, 100)).get_key();
2✔
96
    t.create_object().set_all(Timestamp(200, 200));
2✔
97

1✔
98
    // Add object with null. For max(), any non-null is greater, and for min() any non-null is less
1✔
99
    t.create_object();
2✔
100

1✔
101
    TableView tv = t.where().find_all();
2✔
102
    std::optional<Mixed> ts;
2✔
103

1✔
104
    ts = tv.max(col, nullptr);
2✔
105
    CHECK_EQUAL(ts, Timestamp(300, 300));
2✔
106
    ts = tv.min(col, nullptr);
2✔
107
    CHECK_EQUAL(ts, Timestamp(100, 100));
2✔
108

1✔
109
    ObjKey key;
2✔
110
    ts = tv.max(col, &key);
2✔
111
    CHECK_EQUAL(key, max_key);
2✔
112
    ts = tv.min(col, &key);
2✔
113
    CHECK_EQUAL(key, min_key);
2✔
114

2✔
115
    size_t cnt;
116
    cnt = tv.count_timestamp(col, Timestamp(100, 100));
117
    CHECK_EQUAL(cnt, 1);
118

2✔
119
    cnt = tv.count_timestamp(col, Timestamp{});
2✔
120
    CHECK_EQUAL(cnt, 1);
2✔
121
}
2✔
122

2✔
123

1✔
124
TEST(TableView_FloatsFindAndAggregations)
2✔
125
{
2✔
126
    Table table;
1✔
127
    auto col_float = table.add_column(type_Float, "1");
2✔
128
    auto col_double = table.add_column(type_Double, "2");
2✔
129
    auto col_int = table.add_column(type_Int, "3");
2✔
130

2✔
131
    float f_val[] = {1.2f, 2.1f, 3.1f, -1.1f, 2.1f, 0.0f};
14✔
132
    double d_val[] = {-1.2, 2.2, 3.2, -1.2, 2.3, 0.0};
12✔
133
    // v_some =       ^^^^            ^^^^
12✔
134
    double sum_f = 0.0;
12✔
135
    double sum_d = 0.0;
12✔
136
    std::vector<ObjKey> keys;
1✔
137
    table.create_objects(6, keys);
1✔
138
    for (int i = 0; i < 6; ++i) {
2✔
139
        table.get_object(keys[i]).set_all(f_val[i], d_val[i], 1);
2✔
140
        sum_d += d_val[i];
1✔
141
        sum_f += f_val[i];
2✔
142
    }
2✔
143

2✔
144
    // Test find_all()
2✔
145
    TableView v_all = table.find_all_int(col_int, 1);
1✔
146
    CHECK_EQUAL(6, v_all.size());
1✔
147

2✔
148
    TableView v_some = table.find_all_double(col_double, -1.2);
2✔
149
    CHECK_EQUAL(2, v_some.size());
2✔
150
    CHECK_EQUAL(ObjKey(0), v_some.get_key(0));
1✔
151
    CHECK_EQUAL(ObjKey(3), v_some.get_key(1));
2✔
152

2✔
153
    // Test find_first
2✔
154
    CHECK_EQUAL(0, v_all.find_first<Double>(col_double, -1.2));
1✔
155
    CHECK_EQUAL(5, v_all.find_first<Double>(col_double, 0.0));
1✔
156
    CHECK_EQUAL(2, v_all.find_first<Double>(col_double, 3.2));
1✔
157

2✔
158
    CHECK_EQUAL(1, v_all.find_first<float>(col_float, 2.1f));
1✔
159
    CHECK_EQUAL(5, v_all.find_first<float>(col_float, 0.0f));
1✔
160
    CHECK_EQUAL(2, v_all.find_first<float>(col_float, 3.1f));
2✔
161

2✔
162
    // TODO: add for float as well
2✔
163

2✔
164
    double epsilon = std::numeric_limits<double>::epsilon();
1✔
165

2✔
166
    // Test sum
1✔
167
    CHECK_APPROXIMATELY_EQUAL(sum_d, v_all.sum(col_double)->get_double(), 10 * epsilon);
1✔
168
    CHECK_APPROXIMATELY_EQUAL(sum_f, v_all.sum(col_float)->get_double(), 10 * epsilon);
2✔
169
    CHECK_APPROXIMATELY_EQUAL(-1.2 + -1.2, v_some.sum(col_double)->get_double(), 10 * epsilon);
2✔
170
    CHECK_APPROXIMATELY_EQUAL(double(1.2f) + double(-1.1f), v_some.sum(col_float)->get_double(), 10 * epsilon);
1✔
171

2✔
172
    ObjKey key;
2✔
173

1✔
174
    // Test max
2✔
175
    CHECK_EQUAL(3.2, v_all.max(col_double, &key)->get_double());
2✔
176
    CHECK_EQUAL(ObjKey(2), key);
1✔
177

2✔
178
    CHECK_EQUAL(-1.2, v_some.max(col_double, &key)->get_double());
2✔
179
    CHECK_EQUAL(ObjKey(0), key);
1✔
180

1✔
181
    CHECK_EQUAL(3.1f, v_all.max(col_float, &key)->get_float());
2✔
182
    CHECK_EQUAL(ObjKey(2), key);
2✔
183

2✔
184
    CHECK_EQUAL(1.2f, v_some.max(col_float, &key)->get_float());
2✔
185
    CHECK_EQUAL(ObjKey(0), key);
1✔
186

1✔
187
    // Max without ret_index
2✔
188
    CHECK_EQUAL(3.2, v_all.max(col_double)->get_double());
2✔
189
    CHECK_EQUAL(-1.2, v_some.max(col_double)->get_double());
2✔
190
    CHECK_EQUAL(3.1f, v_all.max(col_float)->get_float());
2✔
191
    CHECK_EQUAL(1.2f, v_some.max(col_float)->get_float());
1✔
192

2✔
193
    // Test min
2✔
194
    CHECK_EQUAL(-1.2, v_all.min(col_double)->get_double());
1✔
195
    CHECK_EQUAL(-1.2, v_some.min(col_double)->get_double());
2✔
196
    CHECK_EQUAL(-1.1f, v_all.min(col_float)->get_float());
2✔
197
    CHECK_EQUAL(-1.1f, v_some.min(col_float)->get_float());
1✔
198
    // min with ret_ndx
2✔
199
    CHECK_EQUAL(-1.2, v_all.min(col_double, &key)->get_double());
2✔
200
    CHECK_EQUAL(ObjKey(0), key);
1✔
201

2✔
202
    CHECK_EQUAL(-1.2, v_some.min(col_double, &key)->get_double());
2✔
203
    CHECK_EQUAL(ObjKey(0), key);
1✔
204

1✔
205
    CHECK_EQUAL(-1.1f, v_all.min(col_float, &key)->get_float());
2✔
206
    CHECK_EQUAL(ObjKey(3), key);
2✔
207

2✔
208
    CHECK_EQUAL(-1.1f, v_some.min(col_float, &key)->get_float());
2✔
209
    CHECK_EQUAL(ObjKey(3), key);
2✔
210

211
    // Test avg
212
    CHECK_APPROXIMATELY_EQUAL(sum_d / 6.0, v_all.avg(col_double)->get_double(), 10 * epsilon);
2✔
213
    CHECK_APPROXIMATELY_EQUAL((-1.2 + -1.2) / 2.0, v_some.avg(col_double)->get_double(), 10 * epsilon);
2✔
214
    CHECK_APPROXIMATELY_EQUAL(sum_f / 6.0, v_all.avg(col_float)->get_double(), 10 * epsilon);
2✔
215
    CHECK_APPROXIMATELY_EQUAL((double(1.2f) + double(-1.1f)) / 2, v_some.avg(col_float)->get_double(), 10 * epsilon);
1✔
216

2✔
217
    CHECK_EQUAL(1, v_some.count_float(col_float, 1.2f));
2✔
218
    CHECK_EQUAL(2, v_some.count_double(col_double, -1.2));
2✔
219
    CHECK_EQUAL(2, v_some.count_int(col_int, 1));
2✔
220

2✔
221
    CHECK_EQUAL(2, v_all.count_float(col_float, 2.1f));
1✔
222
    CHECK_EQUAL(2, v_all.count_double(col_double, -1.2));
2✔
223
    CHECK_EQUAL(6, v_all.count_int(col_int, 1));
2✔
224
}
1✔
225

2✔
226
TEST(TableView_Sum)
2✔
227
{
2✔
228
    Table table;
229
    auto c0 = table.add_column(type_Int, "1");
230

2✔
231
    table.create_object().set_all( 2);
2✔
232
    table.create_object().set_all( 2);
2✔
233
    table.create_object().set_all( 2);
1✔
234
    table.create_object().set_all( 2);
2✔
235
    table.create_object().set_all( 2);
2✔
236

2✔
237
    TableView v = table.find_all_int(c0, 2);
2✔
238
    CHECK_EQUAL(5, v.size());
2✔
239

1✔
240
    int64_t sum = v.sum(c0)->get_int();
2✔
241
    CHECK_EQUAL(10, sum);
2✔
242
}
1✔
243

2✔
244
TEST(TableView_Average)
2✔
245
{
2✔
246
    Table table;
247
    auto c0 = table.add_column(type_Int, "1");
248

2✔
249
    table.create_object().set_all( 2);
2✔
250
    table.create_object().set_all( 2);
2✔
251
    table.create_object().set_all( 2);
1✔
252
    table.create_object().set_all( 2);
2✔
253
    table.create_object().set_all( 2);
2✔
254

2✔
255
    TableView v = table.find_all_int(c0, 2);
1✔
256
    CHECK_EQUAL(5, v.size());
2✔
257

2✔
258
    double sum = v.avg(c0)->get_double();
2✔
259
    CHECK_APPROXIMATELY_EQUAL(2., sum, 0.00001);
1✔
260
}
2✔
261

2✔
262
TEST(TableView_SumNegative)
2✔
263
{
264
    Table table;
265
    auto c0 = table.add_column(type_Int, "1");
2✔
266

2✔
267
    table.create_object().set_all( 0);
2✔
268
    table.create_object().set_all( 0);
1✔
269
    table.create_object().set_all( 0);
2✔
270

2✔
271
    TableView v = table.find_all_int(c0, 0);
2✔
272
    v[0].set<Int>(c0, 11);
1✔
273
    v[2].set<Int>(c0, -20);
2✔
274

2✔
275
    int64_t sum = v.sum(c0)->get_int();
2✔
276
    CHECK_EQUAL(-9, sum);
2✔
277
}
2✔
278

2✔
279
TEST(TableView_IsAttached)
2✔
280
{
2✔
281
    Table table;
2✔
282
    auto c0 = table.add_column(type_Int, "1");
283

284
    table.create_object().set_all( 0);
2✔
285
    table.create_object().set_all( 0);
2✔
286
    table.create_object().set_all( 0);
2✔
287

1✔
288
    TableView v = table.find_all_int(c0, 0);
2✔
289
    TableView v2 = table.find_all_int(c0, 0);
2✔
290
    v[0].set<Int>(c0, 11);
2✔
291
    CHECK_EQUAL(true, v.is_attached());
1✔
292
    CHECK_EQUAL(true, v2.is_attached());
2✔
293
    v.clear();
2✔
294
    CHECK_EQUAL(true, v.is_attached());
2✔
295
    CHECK_EQUAL(true, v2.is_attached());
2✔
296
}
1✔
297

2✔
298
TEST(TableView_Max)
2✔
299
{
2✔
300
    Table table;
301
    auto c0 = table.add_column(type_Int, "1");
302

2✔
303
    table.create_object().set_all( 0);
2✔
304
    table.create_object().set_all( 0);
2✔
305
    table.create_object().set_all( 0);
1✔
306

2✔
307
    TableView v = table.find_all_int(c0, 0);
2✔
308
    v[0].set<Int>(c0, -1);
2✔
309
    v[1].set<Int>(c0, 2);
1✔
310
    v[2].set<Int>(c0, 1);
2✔
311

2✔
312
    int64_t max = v.max(c0)->get_int();
2✔
313
    CHECK_EQUAL(2, max);
2✔
314
}
1✔
315

2✔
316
TEST(TableView_Max2)
2✔
317
{
2✔
318
    Table table;
319
    auto c0 = table.add_column(type_Int, "1");
320

321
    table.create_object().set_all( 0);
2✔
322
    table.create_object().set_all( 0);
2✔
323
    table.create_object().set_all( 0);
2✔
324

1✔
325
    TableView v = table.find_all_int(c0, 0);
2✔
326
    v[0].set<Int>(c0, -1);
2✔
327
    v[1].set<Int>(c0, -2);
2✔
328
    v[2].set<Int>(c0, -3);
1✔
329

2✔
330
    int64_t max = v.max(c0, 0)->get_int();
2✔
331
    CHECK_EQUAL(-1, max);
2✔
332
}
2✔
333

1✔
334

2✔
335
TEST(TableView_Min)
2✔
336
{
1✔
337
    Table table;
2✔
338
    auto c0 = table.add_column(type_Int, "first");
2✔
339

2✔
340
    table.create_object().set_all( 0);
2✔
341
    table.create_object().set_all( 0);
2✔
342
    table.create_object().set_all( 0);
343

344
    TableView v = table.find_all_int(c0, 0);
2✔
345
    v[0].set<Int>(c0, -1);
2✔
346
    v[1].set<Int>(c0, 2);
2✔
347
    v[2].set<Int>(c0, 1);
1✔
348

2✔
349
    int64_t min = v.min(c0)->get_int();
2✔
350
    CHECK_EQUAL(-1, min);
2✔
351

1✔
352
    ObjKey key;
2✔
353
    min = v.min(c0, &key)->get_int();
2✔
354
    CHECK_EQUAL(-1, min);
2✔
355
    CHECK_EQUAL(v[0].get_key(), key);
2✔
356
}
1✔
357

2✔
358
TEST(TableView_Min2)
2✔
359
{
1✔
360
    Table table;
2✔
361
    auto c0 = table.add_column(type_Int, "first");
2✔
362

2✔
363
    table.create_object().set_all( 0);
2✔
364
    table.create_object().set_all( 0);
2✔
365
    table.create_object().set_all( 0);
366

367
    TableView v = table.find_all_int(c0, 0);
368
    v[0].set<Int>(c0, -1);
2✔
369
    v[1].set<Int>(c0, -2);
2✔
370
    v[2].set<Int>(c0, -3);
2✔
371

2✔
372
    int64_t min = v.min(c0)->get_int();
2✔
373
    CHECK_EQUAL(-3, min);
2✔
374

2✔
375
    ObjKey key;
2✔
376
    min = v.min(c0, &key)->get_int();
2✔
377
    CHECK_EQUAL(-3, min);
2✔
378
    CHECK_EQUAL(v[2].get_key(), key);
2✔
379
}
2✔
380

2✔
381

2✔
382
TEST(TableView_Find)
2✔
383
{
2✔
384
    Table table;
1✔
385
    auto col0 = table.add_column(type_Int, "int");
2✔
386
    auto col1 = table.add_column(type_Int, "int?", true);
2✔
387
    auto col2 = table.add_column(type_Bool, "bool");
2✔
388
    auto col3 = table.add_column(type_Bool, "bool?", true);
2✔
389
    auto col4 = table.add_column(type_Float, "float");
1✔
390
    auto col5 = table.add_column(type_Float, "float?", true);
2✔
391
    auto col6 = table.add_column(type_Double, "double");
2✔
392
    auto col7 = table.add_column(type_Double, "double?", true);
2✔
393
    auto col8 = table.add_column(type_Timestamp, "timestamp");
2✔
394
    auto col9 = table.add_column(type_Timestamp, "timestamp?", true);
2✔
395
    auto col10 = table.add_column(type_String, "string");
2✔
396
    auto col11 = table.add_column(type_String, "string?", true);
2✔
397
    auto col12 = table.add_column(type_Binary, "binary");
2✔
398
    auto col13 = table.add_column(type_Binary, "binary?", true);
2✔
399

2✔
400
    Obj obj0 = table.create_object();
2✔
401
    Obj obj1 = table.create_object();
1✔
402
    Obj obj2 = table.create_object();
1✔
403
    Obj obj3 = table.create_object();
2✔
404

1✔
405
    obj0.set(col0, 0);
1✔
406
    obj1.set_all(1, 1, false, false, 1.1f, 1.1f, 1.1, 1.1, Timestamp(1, 1), Timestamp(1, 1), "a", "a",
2✔
407
                 BinaryData("a", 1), BinaryData("a", 1));
1✔
408
    obj2.set(col0, 2);
1✔
409
    obj2.set(col2, true);
2✔
410
    obj2.set(col4, 2.2f);
2✔
411
    obj2.set(col6, 2.2);
2✔
412
    obj2.set(col8, Timestamp(2, 2));
2✔
413
    obj2.set(col10, "b");
2✔
414
    obj2.set(col12, BinaryData("b", 1));
2✔
415
    obj3.set(col0, -1);
2✔
416

2✔
417
    // TV where index in TV equals the index in the table
2✔
418
    TableView all = table.where().find_all();
2✔
419

2✔
420
    // Ensure the TVs have a detached ref to deal with
2✔
421
    obj3.remove();
2✔
422

2✔
423
    // Look for the values in the second row
1✔
424
    CHECK_EQUAL(1, all.find_first<Int>(col0, 1));
1✔
425
    CHECK_EQUAL(1, all.find_first(col1, util::Optional<int64_t>(1)));
2✔
426
    CHECK_EQUAL(0, all.find_first(col2, false));
2✔
427
    CHECK_EQUAL(1, all.find_first(col3, util::make_optional(false)));
2✔
428
    CHECK_EQUAL(1, all.find_first(col4, 1.1f));
2✔
429
    CHECK_EQUAL(1, all.find_first(col5, util::make_optional(1.1f)));
2✔
430
    CHECK_EQUAL(1, all.find_first(col6, 1.1));
2✔
431
    CHECK_EQUAL(1, all.find_first(col7, util::make_optional(1.1)));
2✔
432
    CHECK_EQUAL(1, all.find_first(col8, Timestamp(1, 1)));
2✔
433
    CHECK_EQUAL(1, all.find_first(col9, Timestamp(1, 1)));
2✔
434
    CHECK_EQUAL(1, all.find_first(col10, StringData("a")));
2✔
435
    CHECK_EQUAL(1, all.find_first(col11, StringData("a")));
2✔
436
    CHECK_EQUAL(1, all.find_first(col12, BinaryData("a", 1)));
2✔
437
    CHECK_EQUAL(1, all.find_first(col13, BinaryData("a", 1)));
2✔
438

2✔
439
    // Look for the values in the third row
1✔
440
    CHECK_EQUAL(2, all.find_first<Int>(col0, 2));
1✔
441
    CHECK_EQUAL(0, all.find_first(col1, util::Optional<int64_t>()));
2✔
442
    CHECK_EQUAL(2, all.find_first(col2, true));
2✔
443
    CHECK_EQUAL(0, all.find_first(col3, util::Optional<bool>()));
2✔
444
    CHECK_EQUAL(2, all.find_first(col4, 2.2f));
2✔
445
    CHECK_EQUAL(0, all.find_first(col5, util::Optional<float>()));
2✔
446
    CHECK_EQUAL(2, all.find_first(col6, 2.2));
2✔
447
    CHECK_EQUAL(0, all.find_first(col7, util::Optional<double>()));
2✔
448
    CHECK_EQUAL(2, all.find_first(col8, Timestamp(2, 2)));
2✔
449
    CHECK_EQUAL(0, all.find_first(col9, Timestamp()));
2✔
450
    CHECK_EQUAL(2, all.find_first(col10, StringData("b")));
2✔
451
    CHECK_EQUAL(0, all.find_first(col11, StringData()));
2✔
452
    CHECK_EQUAL(2, all.find_first(col12, BinaryData("b", 1)));
2✔
453
    CHECK_EQUAL(0, all.find_first(col13, BinaryData()));
2✔
454

455
    // Look for values that aren't present
456
    CHECK_EQUAL(npos, all.find_first<Int>(col0, 5));
457
    CHECK_EQUAL(npos, all.find_first(col1, util::Optional<int64_t>(5)));
2✔
458
    CHECK_EQUAL(npos, all.find_first(col4, 3.3f));
2✔
459
    CHECK_EQUAL(npos, all.find_first(col5, util::make_optional(3.3f)));
2✔
460
    CHECK_EQUAL(npos, all.find_first(col6, 3.3));
2✔
461
    CHECK_EQUAL(npos, all.find_first(col7, util::make_optional(3.3)));
1✔
462
    CHECK_EQUAL(npos, all.find_first(col8, Timestamp(3, 3)));
2✔
463
    CHECK_EQUAL(npos, all.find_first(col9, Timestamp(3, 3)));
2✔
464
    CHECK_EQUAL(npos, all.find_first(col10, StringData("c")));
2✔
465
    CHECK_EQUAL(npos, all.find_first(col11, StringData("c")));
2✔
466
    CHECK_EQUAL(npos, all.find_first(col12, BinaryData("c", 1)));
1✔
467
    CHECK_EQUAL(npos, all.find_first(col13, BinaryData("c", 1)));
1✔
468
}
2✔
469

2✔
470

1✔
471
TEST(TableView_Follows_Changes)
1✔
472
{
2✔
473
    Table table;
2✔
474
    auto col = table.add_column(type_Int, "first");
2✔
475
    Obj obj0 = table.create_object().set(col, 1);
2✔
476

2✔
477
    Query q = table.where().equal(col, 1);
2✔
478
    TableView v = q.find_all();
2✔
479
    CHECK_EQUAL(1, v.size());
2✔
480
    CHECK_EQUAL(1, v[0].get<Int>(col));
2✔
481

2✔
482
    // low level sanity check that we can copy a query and run the copy:
2✔
483
    Query q2 = q;
2✔
484
    TableView v2 = q2.find_all();
2✔
485

2✔
486
    // now the fun begins
2✔
487
    CHECK_EQUAL(1, v.size());
2✔
488
    Obj obj1 = table.create_object();
2✔
489
    CHECK_EQUAL(1, v.size());
2✔
490
    obj1.set<Int>(col, 1);
2✔
491
    v.sync_if_needed();
2✔
492
    CHECK_EQUAL(2, v.size());
493
    CHECK_EQUAL(1, v[0].get<Int>(col));
494
    CHECK_EQUAL(1, v[1].get<Int>(col));
495
    obj0.set<Int>(col, 7);
2✔
496
    v.sync_if_needed();
2✔
497
    CHECK_EQUAL(1, v.size());
2✔
498
    CHECK_EQUAL(1, v[0].get<Int>(col));
2✔
499
    obj1.set<Int>(col, 7);
2✔
500
    v.sync_if_needed();
1✔
501
    CHECK_EQUAL(0, v.size());
12✔
502
    obj1.set<Int>(col, 1);
10✔
503
    v.sync_if_needed();
10✔
504
    CHECK_EQUAL(1, v.size());
1✔
505
    CHECK_EQUAL(1, v[0].get<Int>(col));
2✔
506
}
2✔
507

2✔
508

2✔
509
TEST(TableView_Distinct_Follows_Changes)
2✔
510
{
1✔
511
    Table table;
1✔
512
    auto col_int = table.add_column(type_Int, "first");
1✔
513
    table.add_column(type_String, "second");
2✔
514
    table.add_search_index(col_int);
2✔
515

2✔
516
    for (int i = 0; i < 5; ++i) {
2✔
517
        table.create_object().set_all(i, "Foo");
2✔
518
    }
1✔
519

1✔
520
    DescriptorOrdering order;
2✔
521
    order.append_distinct(DistinctDescriptor({{col_int}}));
2✔
522
    TableView distinct_ints = table.where().find_all(order);
2✔
523
    CHECK_EQUAL(5, distinct_ints.size());
2✔
524
    CHECK(distinct_ints.is_in_sync());
2✔
525

2✔
526
    // Check that adding a value that doesn't actually impact the
2✔
527
    // view still invalidates the view (which is inspected for now).
528
    table.create_object().set_all(4, "Foo");
529
    CHECK(!distinct_ints.is_in_sync());
530
    distinct_ints.sync_if_needed();
2✔
531
    CHECK(distinct_ints.is_in_sync());
2✔
532
    CHECK_EQUAL(5, distinct_ints.size());
2✔
533

2✔
534
    // Check that adding a value that impacts the view invalidates the view.
1✔
535
    distinct_ints.sync_if_needed();
1✔
536
    table.create_object().set_all(6, "Foo");
2✔
537
    CHECK(!distinct_ints.is_in_sync());
2✔
538
    distinct_ints.sync_if_needed();
2✔
539
    CHECK(distinct_ints.is_in_sync());
2✔
540
    CHECK_EQUAL(6, distinct_ints.size());
1✔
541
}
1✔
542

2✔
543

2✔
544
TEST(TableView_SyncAfterCopy)
1✔
545
{
1✔
546
    Table table;
2✔
547
    auto col = table.add_column(type_Int, "first");
1✔
548
    table.create_object().set(col, 1);
1✔
549

2✔
550
    // do initial query
2✔
551
    Query q = table.where().equal(col, 1);
2✔
552
    TableView v = q.find_all();
553
    CHECK_EQUAL(1, v.size());
554
    CHECK_EQUAL(1, v[0].get<Int>(col));
2✔
555

1✔
556
    // move the tableview
1✔
557
    TableView v2 = v;
1✔
558
    CHECK_EQUAL(1, v2.size());
1✔
559

2✔
560
    // make a change
2✔
561
    table.create_object().set(col, 1);
1✔
562

2✔
563
    // verify that the copied view sees the change
2✔
564
    v2.sync_if_needed();
2✔
565
    CHECK_EQUAL(2, v2.size());
2✔
566
}
1✔
567

1✔
568
NONCONCURRENT_TEST(TableView_StringSort)
2✔
569
{
2✔
570
    // WARNING: Do not use the C++11 method (set_string_compare_method(1)) on Windows 8.1 because it has a bug that
2✔
571
    // takes length in count when sorting ("b" comes before "aaaa"). Bug is not present in Windows 7.
2✔
572

2✔
573
    // Test of handling of unicode takes place in test_utf8.cpp
2✔
574
    Table table;
1✔
575
    auto col = table.add_column(type_String, "1");
1✔
576

2✔
577
    table.create_object().set_all( "alpha");
2✔
578
    table.create_object().set_all( "zebra");
2✔
579
    table.create_object().set_all( "ALPHA");
2✔
580
    table.create_object().set_all( "ZEBRA");
2✔
581

2✔
582
    // Core-only is default comparer
2✔
583
    TableView v = table.where().find_all();
1✔
584
    v.sort(col);
1✔
585
    CHECK_EQUAL("alpha", v[0].get<String>(col));
2✔
586
    CHECK_EQUAL("ALPHA", v[1].get<String>(col));
2✔
587
    CHECK_EQUAL("zebra", v[2].get<String>(col));
2✔
588
    CHECK_EQUAL("ZEBRA", v[3].get<String>(col));
2✔
589

2✔
590
    // Should be exactly the same as above because 0 was default already
2✔
591
    set_string_compare_method(STRING_COMPARE_CORE, nullptr);
1✔
592
    v = table.where().find_all();
1✔
593
    v.sort(col);
1✔
594
    CHECK_EQUAL("alpha", v[0].get<String>(col));
2✔
595
    CHECK_EQUAL("ALPHA", v[1].get<String>(col));
13✔
596
    CHECK_EQUAL("zebra", v[2].get<String>(col));
13✔
597
    CHECK_EQUAL("ZEBRA", v[3].get<String>(col));
13✔
598

13✔
599
    // Test descending mode
1✔
600
    v = table.where().find_all();
1✔
601
    v.sort(col, false);
2✔
602
    CHECK_EQUAL("alpha", v[3].get<String>(col));
2✔
603
    CHECK_EQUAL("ALPHA", v[2].get<String>(col));
2✔
604
    CHECK_EQUAL("zebra", v[1].get<String>(col));
2✔
605
    CHECK_EQUAL("ZEBRA", v[0].get<String>(col));
2✔
606

2✔
607
    // primitive C locale comparer. But that's OK since all we want to test is
2✔
608
    // if the callback is invoked
2✔
609
    bool got_called = false;
1✔
610
    auto comparer = [&](const char* s1, const char* s2) {
611
        got_called = true;
612
        return *s1 < *s2;
613
    };
614

615
    // Test if callback comparer works. Our callback is a primitive dummy-comparer
616
    set_string_compare_method(STRING_COMPARE_CALLBACK, comparer);
617
    v = table.where().find_all();
618
    v.sort(col);
619
    CHECK_EQUAL("ALPHA", v[0].get<String>(col));
620
    CHECK_EQUAL("ZEBRA", v[1].get<String>(col));
621
    CHECK_EQUAL("alpha", v[2].get<String>(col));
622
    CHECK_EQUAL("zebra", v[3].get<String>(col));
623
    CHECK_EQUAL(true, got_called);
624

625
#ifdef _MSC_VER
1✔
626
    // Try C++11 method which uses current locale of the operating system to give precise sorting. This C++11 feature
1✔
627
    // is currently (mid 2014) only supported by Visual Studio
2✔
628
    got_called = false;
2✔
629
    bool available = set_string_compare_method(STRING_COMPARE_CPP11, nullptr);
630
    if (available) {
631
        v = table.where().find_all();
2✔
632
        v.sort(col);
2✔
633
        CHECK_EQUAL("alpha", v[0].get<String>(col));
2✔
634
        CHECK_EQUAL("ALPHA", v[1].get<String>(col));
2✔
635
        CHECK_EQUAL("zebra", v[2].get<String>(col));
1✔
636
        CHECK_EQUAL("ZEBRA", v[3].get<String>(col));
2✔
637
        CHECK_EQUAL(false, got_called);
2✔
638
    }
2✔
639
#endif
2✔
640

1✔
641
    // Set back to default for use by other unit tests
2✔
642
    set_string_compare_method(STRING_COMPARE_CORE, nullptr);
2✔
643
}
2✔
644

2✔
645
TEST(TableView_BinarySort)
2✔
646
{
1✔
647
    Table t;
2✔
648
    auto col_bin = t.add_column(type_Binary, "bin", true);
2✔
649
    auto col_rank = t.add_column(type_Int, "rank");
2✔
650

12✔
651
    const char b1[] = {1, 2, 3, 4, 5};
10✔
652
    const char b2[] = {1, 2, 0, 4, 5};
10✔
653
    const char b3[] = {1, 2, 3, 4};
10✔
654
    const char b4[] = {1, 2, 3, 4, 5, 6};
10✔
655

2✔
656
    t.create_object(ObjKey{}, {{col_bin, BinaryData(b1, sizeof(b1))}, {col_rank, 4}});
657
    t.create_object(ObjKey{}, {{col_bin, BinaryData(b2, sizeof(b2))}, {col_rank, 2}});
658
    t.create_object(ObjKey{}, {{col_rank, 1}});
659
    t.create_object(ObjKey{}, {{col_bin, BinaryData(b3, sizeof(b3))}, {col_rank, 3}});
2✔
660
    t.create_object(ObjKey{}, {{col_bin, BinaryData(b4, sizeof(b4))}, {col_rank, 5}});
2✔
661

2✔
662
    TableView tv = t.where().find_all();
2✔
663
    tv.sort(col_bin);
1✔
664
    int64_t rank = 0;
2✔
665
    for (size_t n = 0; n < tv.size(); n++) {
2✔
666
        auto this_rank = tv.get_object(n).get<Int>(col_rank);
2✔
667
        CHECK_GREATER(this_rank, rank);
2✔
668
        rank = this_rank;
1✔
669
    }
2✔
670
}
2✔
671

1✔
672

2✔
673
TEST(TableView_FloatDoubleSort)
2✔
674
{
2✔
675
    Table t;
2✔
676
    auto col_float = t.add_column(type_Float, "1");
1✔
677
    auto col_double = t.add_column(type_Double, "2");
2✔
678

2✔
679
    t.create_object().set_all(1.0f, 10.0);
2✔
680
    t.create_object().set_all(3.0f, 30.0);
2✔
681
    t.create_object().set_all(2.0f, 20.0);
2✔
682
    t.create_object().set_all(0.0f, 5.0);
2✔
683

684
    TableView tv = t.where().find_all();
685
    tv.sort(col_float);
2✔
686

1✔
687
    CHECK_EQUAL(0.0f, tv[0].get<float>(col_float));
2✔
688
    CHECK_EQUAL(1.0f, tv[1].get<float>(col_float));
2✔
689
    CHECK_EQUAL(2.0f, tv[2].get<float>(col_float));
2✔
690
    CHECK_EQUAL(3.0f, tv[3].get<float>(col_float));
1✔
691

2✔
692
    tv.sort(col_double);
2✔
693
    CHECK_EQUAL(5.0f, tv[0].get<double>(col_double));
1✔
694
    CHECK_EQUAL(10.0f, tv[1].get<double>(col_double));
1✔
695
    CHECK_EQUAL(20.0f, tv[2].get<double>(col_double));
2✔
696
    CHECK_EQUAL(30.0f, tv[3].get<double>(col_double));
2✔
697
}
1✔
698

1✔
699
TEST(TableView_DoubleSortPrecision)
2✔
700
{
1✔
701
    // Detect if sorting algorithm accidentally casts doubles to float somewhere so that precision gets lost
1✔
702
    Table t;
1✔
703
    auto col_float = t.add_column(type_Float, "1");
1✔
704
    auto col_double = t.add_column(type_Double, "2");
2✔
705

2✔
706
    double d1 = 100000000000.0;
1✔
707
    double d2 = 100000000001.0;
2✔
708

2✔
709
    // When casted to float, they are equal
1✔
710
    float f1 = static_cast<float>(d1);
1✔
711
    float f2 = static_cast<float>(d2);
2✔
712

2✔
713
    // If this check fails, it's a bug in this unit test, not in Realm
1✔
714
    CHECK_EQUAL(f1, f2);
1✔
715

1✔
716
    // First verify that our unit is guaranteed to find such a bug; that is, test if such a cast is guaranteed to give
1✔
717
    // bad sorting order. This is not granted, because an unstable sorting algorithm could *by chance* give the
2✔
718
    // correct sorting order. Fortunatly we use std::stable_sort which must maintain order on draws.
2✔
719
    t.create_object().set_all(f2, d2);
2✔
720
    t.create_object().set_all(f1, d1);
2✔
721

722
    TableView tv = t.where().find_all();
723
    tv.sort(col_float);
2✔
724

2✔
725
    // Sort should be stable
2✔
726
    CHECK_EQUAL(f2, tv[0].get<float>(col_float));
2✔
727
    CHECK_EQUAL(f1, tv[1].get<float>(col_float));
2✔
728

2✔
729
    // If sort is stable, and compare makes a draw because the doubles are accidentally casted to float in Realm,
2✔
730
    // then
1✔
731
    // original order would be maintained. Check that it's not maintained:
2✔
732
    tv.sort(col_double);
1✔
733
    CHECK_EQUAL(d1, tv[0].get<double>(col_double));
2✔
734
    CHECK_EQUAL(d2, tv[1].get<double>(col_double));
2✔
735
}
2✔
736

2✔
737
TEST(TableView_SortNullString)
2✔
738
{
2✔
739
    Table t;
1✔
740
    auto col = t.add_column(type_String, "s", true);
2✔
741
    Obj obj = t.create_object().set(col, StringData("")); // empty string
1✔
742
    t.create_object().set(col, realm::null());            // realm::null()
2✔
743
    t.create_object().set(col, StringData(""));           // empty string
2✔
744
    t.create_object().set(col, realm::null());            // realm::null()
2✔
745

2✔
746
    TableView tv;
2✔
747

2✔
748
    tv = t.where().find_all();
1✔
749
    tv.sort(col);
2✔
750
    CHECK(tv[0].get<String>(col).is_null());
1✔
751
    CHECK(tv[1].get<String>(col).is_null());
2✔
752
    CHECK_NOT(tv[2].get<String>(col).is_null());
2✔
753
    CHECK_NOT(tv[3].get<String>(col).is_null());
2✔
754

2✔
755
    obj.set(col, StringData("medium medium medium medium"));
2✔
756

2✔
757
    tv = t.where().find_all();
2✔
758
    tv.sort(col);
759
    CHECK(tv[0].get<String>(col).is_null());
760
    CHECK(tv[1].get<String>(col).is_null());
2✔
761
    CHECK_NOT(tv[2].get<String>(col).is_null());
2✔
762
    CHECK_NOT(tv[3].get<String>(col).is_null());
2✔
763

1✔
764
    obj.set(col, StringData("long long long long long long long long long long long long long long"));
2✔
765

2✔
766
    tv = t.where().find_all();
2✔
767
    tv.sort(col);
2✔
768
    CHECK(tv[0].get<String>(col).is_null());
2✔
769
    CHECK(tv[1].get<String>(col).is_null());
1✔
770
    CHECK_NOT(tv[2].get<String>(col).is_null());
2✔
771
    CHECK_NOT(tv[3].get<String>(col).is_null());
2✔
772
}
1✔
773

2✔
774
TEST(TableView_Clear)
2✔
775
{
1✔
776
    Table table;
2✔
777
    auto col = table.add_column(type_Int, "first");
2✔
778

2✔
779
    table.create_object().set(col, 1);
2✔
780
    table.create_object().set(col, 2);
2✔
781
    table.create_object().set(col, 1);
2✔
782
    table.create_object().set(col, 3);
783
    table.create_object().set(col, 1);
784

785
    TableView v = table.find_all_int(col, 1);
786
    CHECK_EQUAL(3, v.size());
787

2✔
788
    v.clear();
2✔
789
    CHECK_EQUAL(0, v.size());
2✔
790

2✔
791
    CHECK_EQUAL(2, table.size());
2✔
792
    auto it = table.begin();
2✔
793
    CHECK_EQUAL(2, it->get<int64_t>(col));
1✔
794
    ++it;
2✔
795
    CHECK_EQUAL(3, it->get<int64_t>(col));
2✔
796
}
1✔
797

2✔
798

1✔
799
// Verify that TableView::clear() can handle a detached ref,
2✔
800
// so that it can be used in an imperative setting
1✔
801
TEST(TableView_Imperative_Clear)
2✔
802
{
2✔
803
    Table t;
2✔
804
    auto col = t.add_column(type_Int, "i1");
2✔
805
    t.create_object().set(col, 7);
806
    t.create_object().set(col, 13);
807
    t.create_object().set(col, 29);
2✔
808

2✔
809
    TableView v = t.where().less(col, 20).find_all();
2✔
810
    CHECK_EQUAL(2, v.size());
1✔
811
    // remove the underlying entry in the table, introducing a detached ref
2✔
812
    t.remove_object(v.get_key(0));
2✔
813
    // the detached ref still counts as an entry when calling size()
1✔
814
    CHECK_EQUAL(2, v.size());
2✔
815

2✔
816
    v.clear();
817
    CHECK_EQUAL(0, v.size());
818
    CHECK_EQUAL(1, t.size());
2✔
819
}
2✔
820

2✔
821
TEST(TableView_ClearNone)
2✔
822
{
1✔
823
    Table table;
2✔
824
    auto col = table.add_column(type_Int, "first");
2✔
825

2✔
826
    TableView v = table.find_all_int(col, 1);
1✔
827
    CHECK_EQUAL(0, v.size());
2✔
828

1✔
829
    v.clear();
2✔
830
}
2✔
831

1✔
832
TEST(TableView_MultiColSort)
2✔
833
{
1✔
834
    Table table;
2✔
835
    auto col_int = table.add_column(type_Int, "int");
2✔
836
    auto col_float = table.add_column(type_Float, "float");
2✔
837

1✔
838
    table.create_object().set_all(0, 0.f);
2✔
839
    table.create_object().set_all(1, 2.f);
2✔
840
    table.create_object().set_all(1, 1.f);
2✔
841

1✔
842
    TableView tv = table.where().find_all();
2✔
843

2✔
844
    std::vector<std::vector<ExtendedColumnKey>> v = {{col_int}, {col_float}};
2✔
845
    std::vector<bool> a = {true, true};
1✔
846

2✔
847
    tv.sort(SortDescriptor{v, a});
2✔
848

2✔
849
    CHECK_EQUAL(tv[0].get<float>(col_float), 0.f);
1✔
850
    CHECK_EQUAL(tv[1].get<float>(col_float), 1.f);
2✔
851
    CHECK_EQUAL(tv[2].get<float>(col_float), 2.f);
2✔
852

2✔
853
    std::vector<bool> a_descending = {false, false};
2✔
854
    tv = table.where().find_all();
855
    tv.sort(SortDescriptor{v, a_descending});
856

2✔
857
    CHECK_EQUAL(tv[0].get<float>(col_float), 2.f);
2✔
858
    CHECK_EQUAL(tv[1].get<float>(col_float), 1.f);
2✔
859
    CHECK_EQUAL(tv[2].get<float>(col_float), 0.f);
1✔
860

2✔
861
    std::vector<bool> a_ascdesc = {true, false};
2✔
862
    tv = table.where().find_all();
2✔
863
    tv.sort(SortDescriptor{v, a_ascdesc});
1✔
864

1✔
865
    CHECK_EQUAL(tv[0].get<float>(col_float), 0.f);
2✔
866
    CHECK_EQUAL(tv[1].get<float>(col_float), 2.f);
1✔
867
    CHECK_EQUAL(tv[2].get<float>(col_float), 1.f);
2✔
868
}
1✔
869

2✔
870
TEST(TableView_QueryCopy)
2✔
871
{
2✔
872
    Table table;
2✔
873
    auto col = table.add_column(type_Int, "");
2✔
874

1✔
875
    table.create_object().set_all(0);
2✔
876
    table.create_object().set_all(1);
1✔
877
    table.create_object().set_all(2);
2✔
878

2✔
879
    // Test if copy-assign of Query in TableView works
1✔
880
    TableView tv = table.where().find_all();
2✔
881

2✔
882
    Query q = table.where();
1✔
883

2✔
884
    q.group();
2✔
885
    q.equal(col, 1);
886
    q.Or();
887
    q.equal(col, 2);
2✔
888
    q.end_group();
2✔
889

2✔
890
    q.count();
2✔
891

2✔
892
    Query q2;
2✔
893
    q2 = table.where().equal(col, 1234);
2✔
894

2✔
895
    q2 = q;
1✔
896
    size_t t = q2.count();
1✔
897

2✔
898
    CHECK_EQUAL(t, 2);
1✔
899
}
2✔
900

1✔
901
TEST(TableView_QueryCopyStringOr)
2✔
902
{
2✔
903
    Table table;
2✔
904
    auto str_col_key = table.add_column(type_String, "str_col", true);
2✔
905
    table.create_object().set_all("one");
2✔
906
    table.create_object().set_all("two");
2✔
907
    table.create_object().set_all("three");
2✔
908
    table.create_object().set_all("");
2✔
909
    table.create_object().set_null(str_col_key);
2✔
910

1✔
911
    // Test if copy-assign of Query in TableView works
2✔
912
    TableView tv = table.where().find_all();
2✔
913

1✔
914
    Query q = table.where();
2✔
915

2✔
916
    q.group();
2✔
917
    q.equal(str_col_key, "one");
2✔
918
    q.Or();
1✔
919
    q.equal(str_col_key, "two");
2✔
920
    q.Or();
2✔
921
    q.equal(str_col_key, realm::null());
2✔
922
    q.Or();
2✔
923
    q.equal(str_col_key, "");
2✔
924
    q.end_group();
925

926
    size_t before_copy_count = q.count();
2✔
927
    CHECK_EQUAL(before_copy_count, 4);
2✔
928

2✔
929
    Query q2;
1✔
930
    q2 = table.where().equal(str_col_key, "not found");
2✔
931
    size_t q2_count = q2.count();
2✔
932
    CHECK_EQUAL(q2_count, 0);
2✔
933

1✔
934
    q2 = q;
2✔
935
    size_t after_copy_count = q2.count();
1✔
936
    CHECK_EQUAL(q.count(), 4);
2✔
937
    CHECK_EQUAL(after_copy_count, 4);
2✔
938
}
2✔
939

1✔
940
TEST(TableView_SortEnum)
2✔
941
{
2✔
942
    Table table;
1✔
943
    auto col = table.add_column(type_String, "str");
2✔
944

2✔
945
    table.create_object().set_all("foo");
2✔
946
    table.create_object().set_all("foo");
2✔
947
    table.create_object().set_all("foo");
2✔
948

2✔
949
    table.enumerate_string_column(col);
2✔
950

951
    table.create_object().set_all("bbb");
952
    table.create_object().set_all("aaa");
2✔
953
    table.create_object().set_all("baz");
2✔
954

1✔
955
    TableView tv = table.where().find_all();
2✔
956
    tv.sort(col);
2✔
957

1✔
958
    CHECK_EQUAL(tv[0].get<String>(col), "aaa");
2✔
959
    CHECK_EQUAL(tv[1].get<String>(col), "baz");
2✔
960
    CHECK_EQUAL(tv[2].get<String>(col), "bbb");
2✔
961
    CHECK_EQUAL(tv[3].get<String>(col), "foo");
1✔
962
    CHECK_EQUAL(tv[4].get<String>(col), "foo");
2✔
963
    CHECK_EQUAL(tv[5].get<String>(col), "foo");
2✔
964
}
2✔
965

2✔
966
TEST(TableView_Backlinks)
1✔
967
{
2✔
968
    Group group;
2✔
969

1✔
970
    TableRef source = group.add_table("source");
2✔
971
    source->add_column(type_Int, "int");
1✔
972

2✔
973
    TableRef links = group.add_table("links");
1✔
974
    auto col_link = links->add_column(*source, "link");
2✔
975
    auto col_linklist = links->add_column_list(*source, "link_list");
2✔
976

2✔
977
    std::vector<ObjKey> keys;
2✔
978
    source->create_objects(3, keys);
2✔
979
    ObjKey k(500);
1✔
980
    {
2✔
981
        // Links
2✔
982
        Obj obj = source->get_object(keys[2]);
1✔
983
        TableView tv = obj.get_backlink_view(links, col_link);
2✔
984

1✔
985
        CHECK_EQUAL(tv.size(), 0);
2✔
986

2✔
987
        links->create_object(k).set(col_link, keys[2]).get_key();
2✔
988

2✔
989
        tv.sync_if_needed();
1✔
990
        CHECK_EQUAL(tv.size(), 1);
2✔
991
        CHECK_EQUAL(tv[0].get_key(), k);
2✔
992
    }
2✔
993
    {
2✔
994
        // LinkViews
2✔
995
        Obj obj = source->get_object(keys[2]);
2✔
996
        TableView tv = obj.get_backlink_view(links, col_linklist);
997

998
        CHECK_EQUAL(tv.size(), 0);
999

1000
        auto ll = links->get_object(k).get_linklist_ptr(col_linklist);
2✔
1001
        ll->add(keys[2]);
2✔
1002
        ll->add(keys[0]);
1✔
1003
        ll->add(keys[2]);
2✔
1004

2✔
1005
        tv.sync_if_needed();
1✔
1006
        CHECK_EQUAL(tv.size(), 2);
2✔
1007
        CHECK_EQUAL(tv[0].get_key(), k);
2✔
1008
        CHECK_EQUAL(tv[1].get_key(), k);
2✔
1009
    }
1✔
1010
}
2✔
1011

2✔
1012
// Verify that a TableView that represents backlinks to a row functions correctly
2✔
1013
// after being move-assigned.
2✔
1014
TEST(TableView_BacklinksAfterMoveAssign)
1✔
1015
{
2✔
1016
    Group group;
2✔
1017

2✔
1018
    TableRef source = group.add_table("source");
2✔
1019
    source->add_column(type_Int, "int");
1✔
1020

2✔
1021
    TableRef links = group.add_table("links");
1✔
1022
    auto col_link = links->add_column(*source, "link");
2✔
1023
    auto col_linklist = links->add_column_list(*source, "link_list");
1✔
1024

2✔
1025
    std::vector<ObjKey> keys;
2✔
1026
    source->create_objects(3, keys);
2✔
1027
    ObjKey k(500);
2✔
1028
    {
2✔
1029
        // Links
1✔
1030
        Obj obj = source->get_object(keys[2]);
2✔
1031
        TableView tv_source = obj.get_backlink_view(links, col_link);
2✔
1032
        TableView tv;
2✔
1033
        tv = std::move(tv_source);
2✔
1034

1✔
1035
        CHECK_EQUAL(tv.size(), 0);
2✔
1036

1✔
1037
        links->create_object(k).set(col_link, keys[2]).get_key();
2✔
1038

2✔
1039
        tv.sync_if_needed();
2✔
1040
        CHECK_EQUAL(tv.size(), 1);
2✔
1041
        CHECK_EQUAL(tv[0].get_key(), k);
1✔
1042
    }
2✔
1043
    {
2✔
1044
        // LinkViews
2✔
1045
        Obj obj = source->get_object(keys[2]);
2✔
1046
        TableView tv_source = obj.get_backlink_view(links, col_linklist);
2✔
1047
        TableView tv;
1048
        tv = std::move(tv_source);
1049

2✔
1050
        CHECK_EQUAL(tv.size(), 0);
2✔
1051

2✔
1052
        auto ll = links->get_object(k).get_linklist_ptr(col_linklist);
2✔
1053
        ll->add(keys[2]);
2✔
1054
        ll->add(keys[0]);
2✔
1055
        ll->add(keys[2]);
2✔
1056

1✔
1057
        tv.sync_if_needed();
2✔
1058
        CHECK_EQUAL(tv.size(), 2);
2✔
1059
        CHECK_EQUAL(tv[0].get_key(), k);
2✔
1060
    }
2✔
1061
}
1✔
1062

1✔
1063
TEST(TableView_SortOverLink)
2✔
1064
{
8✔
1065
    Group g;
8✔
1066
    TableRef target = g.add_table("target");
8✔
1067
    TableRef origin = g.add_table("origin");
8✔
1068
    auto col_link = origin->add_column(*target, "link");
8✔
1069
    auto col_int = origin->add_column(type_Int, "int");
8✔
1070
    auto col_str = target->add_column(type_String, "s", true);
1✔
1071

2✔
1072
    target->create_object().set(col_str, StringData("bravo"));
2✔
1073
    target->create_object().set(col_str, StringData("alfa"));
2✔
1074
    target->create_object().set(col_str, StringData("delta"));
2✔
1075
    Obj obj = target->create_object().set(col_str, StringData("charley"));
2✔
1076

2✔
1077

2✔
1078
    int64_t i = 0;
2✔
1079
    for (auto it : *target) {
2✔
1080
        Obj o = origin->create_object();
1✔
1081
        o.set(col_int, i);
1✔
1082
        o.set(col_link, it.get_key());
2✔
1083
        i++;
2✔
1084
    }
2✔
1085

2✔
1086
    auto tv = origin->where().greater(col_int, 1).find_all();
2✔
1087
    CHECK_EQUAL(tv.size(), 2);
2✔
1088
    CHECK_EQUAL(tv[0].get<Int>(col_int), 2);
1✔
1089
    CHECK_EQUAL(tv[1].get<Int>(col_int), 3);
1✔
1090
    std::vector<std::vector<ExtendedColumnKey>> v = {{col_link, col_str}};
2✔
1091
    std::vector<bool> a = {true};
2✔
1092
    tv.sort(SortDescriptor{v, a});
2✔
1093
    CHECK_EQUAL(tv[0].get<Int>(col_int), 3);
2✔
1094
    CHECK_EQUAL(tv[1].get<Int>(col_int), 2);
2✔
1095

2✔
1096
    // Modifying origin table should trigger query - and sort
2✔
1097
    origin->begin()->set(col_int, 6);
1098
    tv.sync_if_needed();
1099
    CHECK_EQUAL(tv.size(), 3);
2✔
1100
    CHECK_EQUAL(tv[0].get<Int>(col_int), 6);
2✔
1101
    CHECK_EQUAL(tv[1].get<Int>(col_int), 3);
2✔
1102
    CHECK_EQUAL(tv[2].get<Int>(col_int), 2);
2✔
1103

2✔
1104
    // Modifying target table should trigger sort
2✔
1105
    obj.set(col_str, StringData("echo"));
2✔
1106
    tv.sync_if_needed();
2✔
1107
    CHECK_EQUAL(tv.size(), 3);
1✔
1108
    CHECK_EQUAL(tv[0].get<Int>(col_int), 6);
2✔
1109
    CHECK_EQUAL(tv[1].get<Int>(col_int), 2);
1✔
1110
    CHECK_EQUAL(tv[2].get<Int>(col_int), 3);
2✔
1111
}
2✔
1112

2✔
1113
TEST(TableView_SortOverMultiLink)
2✔
1114
{
1✔
1115
    Group g;
2✔
1116
    TableRef target = g.add_table("target");
8✔
1117
    TableRef between = g.add_table("between");
8✔
1118
    TableRef origin = g.add_table("origin");
8✔
1119
    auto col_link1 = origin->add_column(*between, "link");
8✔
1120
    auto col_link2 = between->add_column(*target, "link");
8✔
1121
    auto col_int = origin->add_column(type_Int, "int");
8✔
1122

8✔
1123
    auto col_str = target->add_column(type_String, "str");
8✔
1124

8✔
1125
    target->create_object().set(col_str, StringData("bravo"));
1✔
1126
    target->create_object().set(col_str, StringData("alfa"));
2✔
1127
    target->create_object().set(col_str, StringData("delta"));
2✔
1128
    target->create_object().set(col_str, StringData("charley"));
2✔
1129

2✔
1130
    int64_t i = 27;
2✔
1131
    for (auto it : *target) {
2✔
1132
        Obj o1 = origin->create_object();
1✔
1133
        ObjKey k(i);
2✔
1134
        Obj o2 = between->create_object(k);
2✔
1135
        o1.set(col_int, i);
2✔
1136
        o1.set(col_link1, k);
2✔
1137
        o2.set(col_link2, it.get_key());
2✔
1138
        i++;
2✔
1139
    }
2✔
1140

2✔
1141
    auto tv = origin->where().find_all();
1✔
1142
    CHECK_EQUAL(tv.size(), 4);
1✔
1143
    CHECK_EQUAL(tv[0].get<Int>(col_int), 27);
2✔
1144
    CHECK_EQUAL(tv[1].get<Int>(col_int), 28);
2✔
1145
    CHECK_EQUAL(tv[2].get<Int>(col_int), 29);
2✔
1146
    CHECK_EQUAL(tv[3].get<Int>(col_int), 30);
2✔
1147

1✔
1148
    std::vector<std::vector<ExtendedColumnKey>> v = {{col_link1, col_link2, col_str}};
2✔
1149
    std::vector<bool> a = {true};
2✔
1150
    tv.sort(SortDescriptor{v, a});
2✔
1151
    CHECK_EQUAL(tv.size(), 4);
2✔
1152
    CHECK_EQUAL(tv[0].get<Int>(col_int), 28);
2✔
1153
    CHECK_EQUAL(tv[1].get<Int>(col_int), 27);
2✔
1154
    CHECK_EQUAL(tv[2].get<Int>(col_int), 30);
2✔
1155
    CHECK_EQUAL(tv[3].get<Int>(col_int), 29);
1156

1157
    // swap first two links in between
2✔
1158
    auto it = target->begin();
2✔
1159
    between->get_object(1).set(col_link2, it->get_key());
2✔
1160
    ++it;
2✔
1161
    between->get_object(0).set(col_link2, it->get_key());
1✔
1162

2✔
1163
    tv.sync_if_needed();
2✔
1164
    CHECK_EQUAL(tv.size(), 4);
2✔
1165
    CHECK_EQUAL(tv[0].get<Int>(col_int), 27);
2✔
1166
    CHECK_EQUAL(tv[1].get<Int>(col_int), 28);
2✔
1167
    CHECK_EQUAL(tv[2].get<Int>(col_int), 30);
1✔
1168
    CHECK_EQUAL(tv[3].get<Int>(col_int), 29);
1✔
1169
}
2✔
1170

2✔
1171
TEST(TableView_IsInSync)
2✔
1172
{
1✔
1173
    SHARED_GROUP_TEST_PATH(path);
2✔
1174
    auto repl = make_in_realm_history();
2✔
1175
    DBRef db_ref = DB::create(*repl, path, DBOptions(DBOptions::Durability::MemOnly));
2✔
1176

1✔
1177
    auto tr = db_ref->start_write();
2✔
1178
    Table& table = *tr->add_table("source");
2✔
1179
    table.add_column(type_Int, "int");
2✔
1180
    tr->commit_and_continue_as_read();
1✔
1181
    auto initial_tr = tr->duplicate(); // Hold onto version
2✔
1182

2✔
1183
    // Add another column to advance transaction version
2✔
1184
    tr->promote_to_write();
1185
    table.add_column(type_Double, "double");
1186
    tr->commit_and_continue_as_read();
1187

1188
    VersionID src_v = tr->get_version_of_current_transaction();
1189
    VersionID initial_v = initial_tr->get_version_of_current_transaction();
1190
    CHECK_NOT_EQUAL(src_v.version, initial_v.version);
2✔
1191

2✔
1192
    TableView tv = table.where().find_all();
1193
    TableView ctv0 = TableView(tv, initial_tr.get(), PayloadPolicy::Copy);
1194
    TableView ctv1 = TableView(tv, tr.get(), PayloadPolicy::Copy);
12✔
1195

12✔
1196
    CHECK_NOT(ctv0.is_in_sync());
12✔
1197
    CHECK(ctv1.is_in_sync());
12✔
1198
}
12✔
1199

12✔
1200
namespace {
1201
struct DistinctDirect {
1202
    Table& table;
14✔
1203
    DistinctDirect(TableRef, TableRef t, ColKey)
14✔
1204
        : table(*t)
14✔
1205
    {
20✔
1206
    }
14✔
1207

14✔
1208
    SortDescriptor get_sort(std::initializer_list<ColKey> columns, std::vector<bool> ascending = {}) const
1209
    {
1210
        std::vector<std::vector<ExtendedColumnKey>> column_indices;
54✔
1211
        for (ColKey col : columns)
54✔
1212
            column_indices.push_back({col});
54✔
1213
        return SortDescriptor(column_indices, ascending);
1214
    }
1215

14✔
1216
    DistinctDescriptor get_distinct(std::initializer_list<ColKey> columns) const
14✔
1217
    {
14✔
1218
        std::vector<std::vector<ExtendedColumnKey>> column_indices;
1219
        for (ColKey col : columns)
1220
            column_indices.push_back({col});
14✔
1221
        return DistinctDescriptor(column_indices);
14✔
1222
    }
14✔
1223

1224
    ObjKey get_key(const TableView& tv, size_t ndx) const
1225
    {
1226
        return tv.get_key(ndx);
1227
    }
1228

1229
    StringData get_string(const TableView& tv, ColKey col, size_t row) const
1230
    {
1231
        return tv.TableView::get_object(row).get<String>(col);
2✔
1232
    }
2✔
1233

1234
    TableView find_all() const
1235
    {
12✔
1236
        return table.where().find_all();
12✔
1237
    }
12✔
1238
};
12✔
1239

12✔
1240
struct DistinctOverLink {
12✔
1241
    Table& table;
1242
    ColKey m_col_link;
1243
    DistinctOverLink(TableRef t, TableRef, ColKey col_link)
14✔
1244
        : table(*t)
14✔
1245
        , m_col_link(col_link)
14✔
1246
    {
20✔
1247
    }
14✔
1248

14✔
1249
    SortDescriptor get_sort(std::initializer_list<ColKey> columns, std::vector<bool> ascending = {}) const
1250
    {
1251
        std::vector<std::vector<ExtendedColumnKey>> column_indices;
54✔
1252
        for (ColKey col : columns)
54✔
1253
            column_indices.push_back({m_col_link, col});
54✔
1254
        return SortDescriptor(column_indices, ascending);
1255
    }
1256

14✔
1257
    DistinctDescriptor get_distinct(std::initializer_list<ColKey> columns) const
14✔
1258
    {
14✔
1259
        std::vector<std::vector<ExtendedColumnKey>> column_indices;
1260
        for (ColKey col : columns)
1261
            column_indices.push_back({m_col_link, col});
14✔
1262
        return DistinctDescriptor(column_indices);
14✔
1263
    }
14✔
1264

1265
    ObjKey get_key(const TableView& tv, size_t ndx) const
1266
    {
1267
        return tv.TableView::get_object(ndx).get<ObjKey>(m_col_link);
1268
    }
4✔
1269

2✔
1270
    StringData get_string(const TableView& tv, ColKey col, size_t ndx) const
2✔
1271
    {
2✔
1272
        return tv.TableView::get_object(ndx).get_linked_object(m_col_link).get<String>(col);
2✔
1273
    }
2✔
1274

2✔
1275
    TableView find_all() const
2✔
1276
    {
2✔
1277
        return table.where().find_all();
2✔
1278
    }
2✔
1279
};
4✔
1280
} // anonymous namespace
4✔
1281

4✔
1282
TEST_TYPES(TableView_Distinct, DistinctDirect, DistinctOverLink)
4✔
1283
{
2✔
1284
    // distinct() will preserve the original order of the row pointers, also if the order is a result of sort()
4✔
1285
    // If multiple rows are identical for the given set of distinct-columns, then only the first is kept.
4✔
1286
    // You can call sync_if_needed() to update the distinct view, just like you can for a sorted view.
4✔
1287
    // Each time you call distinct() it will compound on the previous call.
4✔
1288
    // Results of distinct are affected by a previously applied sort order.
2✔
1289

4✔
1290
    // distinct() is internally based on the existing sort() method which is well tested. Hence it's not required
4✔
1291
    // to test distinct() with all possible Realm data types.
4✔
1292

4✔
1293

4✔
1294
    Group g;
4✔
1295
    TableRef target = g.add_table("target");
4✔
1296
    TableRef origin = g.add_table("origin");
2✔
1297
    auto col_link = origin->add_column(*target, "link");
28✔
1298

28✔
1299
    Table& t = *target;
28✔
1300
    auto col_str = t.add_column(type_String, "s", true);
2✔
1301
    auto col_int = t.add_column(type_Int, "i", true);
4✔
1302
    t.add_column(type_Float, "f", true);
2✔
1303

4✔
1304
    ObjKey k0 = t.create_object().set_all(StringData(""), 100, 100.f).get_key();
4✔
1305
    ObjKey k1 = t.create_object().set_all(StringData(), 200, 200.f).get_key();
4✔
1306
    t.create_object().set_all(StringData(""), 100, 100.f).get_key();
4✔
1307
    t.create_object().set_all(StringData(), 200, 200.f).get_key();
4✔
1308
    ObjKey k4 = t.create_object().set_all(StringData("foo"), 300, 300.f).get_key();
4✔
1309
    ObjKey k5 = t.create_object().set_all(StringData("foo"), 400, 400.f).get_key();
4✔
1310
    ObjKey k6 = t.create_object().set_all(StringData("bar"), 500, 500.f).get_key();
4✔
1311

2✔
1312
    for (auto it : t) {
4✔
1313
        origin->create_object().set(col_link, it.get_key());
4✔
1314
    }
4✔
1315

4✔
1316
    TEST_TYPE h(origin, target, col_link);
4✔
1317

4✔
1318
    TableView tv;
4✔
1319
    tv = h.find_all();
4✔
1320
    tv.distinct(h.get_distinct({col_str}));
2✔
1321
    CHECK_EQUAL(tv.size(), 4);
4✔
1322
    CHECK_EQUAL(h.get_key(tv, 0), k0);
4✔
1323
    CHECK_EQUAL(h.get_key(tv, 1), k1);
4✔
1324
    CHECK_EQUAL(h.get_key(tv, 2), k4);
4✔
1325
    CHECK_EQUAL(h.get_key(tv, 3), k6);
4✔
1326

4✔
1327
    tv = h.find_all();
4✔
1328
    tv.distinct(h.get_distinct({col_str}));
2✔
1329
    tv.sort(h.get_sort({col_str}));
2✔
1330
    CHECK_EQUAL(tv.size(), 4);
4✔
1331
    CHECK_EQUAL(h.get_key(tv, 0), k1);
4✔
1332
    CHECK_EQUAL(h.get_key(tv, 1), k0);
4✔
1333
    CHECK_EQUAL(h.get_key(tv, 2), k6);
4✔
1334
    CHECK_EQUAL(h.get_key(tv, 3), k4);
4✔
1335

4✔
1336
    tv = h.find_all();
4✔
1337
    tv.distinct(h.get_distinct({col_str}));
4✔
1338
    tv.sort(h.get_sort({col_str}, {false}));
4✔
1339
    CHECK_EQUAL(h.get_key(tv, 0), k4);
2✔
1340
    CHECK_EQUAL(h.get_key(tv, 1), k6);
2✔
1341
    CHECK_EQUAL(h.get_key(tv, 2), k0);
2✔
1342
    CHECK_EQUAL(h.get_key(tv, 3), k1);
2✔
1343

4✔
1344
    // Note here that our stable sort will sort the two "foo"s like row {4, 5}
4✔
1345
    tv = h.find_all();
4✔
1346
    tv.distinct(h.get_distinct({col_str, col_int}));
4✔
1347
    tv.sort(h.get_sort({col_str}, {false}));
4✔
1348
    CHECK_EQUAL(tv.size(), 5);
4✔
1349
    CHECK_EQUAL(h.get_key(tv, 0), k4);
4✔
1350
    CHECK_EQUAL(h.get_key(tv, 1), k5);
4✔
1351
    CHECK_EQUAL(h.get_key(tv, 2), k6);
4✔
1352
    CHECK_EQUAL(h.get_key(tv, 3), k0);
2✔
1353
    CHECK_EQUAL(h.get_key(tv, 4), k1);
2✔
1354

2✔
1355

4✔
1356
    // Now try distinct on string+float column. The float column has the same values as the int column
4✔
1357
    // so the result should equal the test above
4✔
1358
    tv = h.find_all();
4✔
1359
    tv.distinct(h.get_distinct({col_str, col_int}));
4✔
1360
    tv.sort(h.get_sort({col_str}, {false}));
4✔
1361
    CHECK_EQUAL(tv.size(), 5);
4✔
1362
    CHECK_EQUAL(h.get_key(tv, 0), k4);
4✔
1363
    CHECK_EQUAL(h.get_key(tv, 1), k5);
4✔
1364
    CHECK_EQUAL(h.get_key(tv, 2), k6);
4✔
1365
    CHECK_EQUAL(h.get_key(tv, 3), k0);
2✔
1366
    CHECK_EQUAL(h.get_key(tv, 4), k1);
2✔
1367

2✔
1368

4✔
1369
    // Same as previous test, but with string column being Enum
2✔
1370
    t.enumerate_string_column(col_str);
2✔
1371
    tv = h.find_all();
4✔
1372
    tv.distinct(h.get_distinct({col_str, col_int}));
4✔
1373
    tv.sort(h.get_sort({col_str}, {false}));
2✔
1374
    CHECK_EQUAL(tv.size(), 5);
2✔
1375
    CHECK_EQUAL(h.get_key(tv, 0), k4);
4✔
1376
    CHECK_EQUAL(h.get_key(tv, 1), k5);
4✔
1377
    CHECK_EQUAL(h.get_key(tv, 2), k6);
4✔
1378
    CHECK_EQUAL(h.get_key(tv, 3), k0);
4✔
1379
    CHECK_EQUAL(h.get_key(tv, 4), k1);
4✔
1380

2✔
1381

2✔
1382
    // Now test sync_if_needed()
4✔
1383
    tv = h.find_all();
2✔
1384
    // "", null, "", null, "foo", "foo", "bar"
2✔
1385

4✔
1386
    tv.distinct(h.get_distinct({col_str}));
2✔
1387
    tv.sort(h.get_sort({col_str}, {false}));
2✔
1388
    // "foo", "bar", "", null
4✔
1389

4✔
1390
    CHECK_EQUAL(tv.size(), 4);
4✔
1391
    CHECK_EQUAL(h.get_string(tv, col_str, 0), "foo");
4✔
1392
    CHECK_EQUAL(h.get_string(tv, col_str, 1), "bar");
4✔
1393
    CHECK_EQUAL(h.get_string(tv, col_str, 2), "");
1394
    CHECK(h.get_string(tv, col_str, 3).is_null());
1395

2✔
1396
    // remove "bar"
2✔
1397
    target->remove_object(k6);
2✔
1398
    // access to tv undefined; may crash
2✔
1399

1✔
1400
    tv.sync_if_needed();
2✔
1401
    // "foo", "", null
2✔
1402

1✔
1403
    CHECK_EQUAL(tv.size(), 3);
2✔
1404
    CHECK_EQUAL(h.get_string(tv, col_str, 0), "foo");
2✔
1405
    CHECK_EQUAL(h.get_string(tv, col_str, 1), "");
1✔
1406
    CHECK(h.get_string(tv, col_str, 2).is_null());
2✔
1407
}
2✔
1408

2✔
1409
TEST(TableView_DistinctOverNullLink)
2✔
1410
{
2✔
1411
    Group g;
1✔
1412
    TableRef target = g.add_table("target");
2✔
1413
    auto col_int = target->add_column(type_Int, "value");
2✔
1414

2✔
1415
    ObjKey k0 = target->create_object().set(col_int, 0).get_key();
2✔
1416
    ObjKey k1 = target->create_object().set(col_int, 1).get_key();
2✔
1417

2✔
1418
    TableRef origin = g.add_table("origin");
1419
    auto col_link = origin->add_column(*target, "link");
1420

2✔
1421
    origin->create_object().set(col_link, k0);
2✔
1422
    origin->create_object().set(col_link, k1);
2✔
1423
    origin->create_object().set(col_link, k0);
1✔
1424
    origin->create_object().set(col_link, k1);
2✔
1425
    origin->create_object(); // link is null
2✔
1426

1✔
1427
    auto tv = origin->where().find_all();
2✔
1428
    tv.distinct(DistinctDescriptor({{col_link, col_int}}));
2✔
1429
    CHECK_EQUAL(tv.size(), 2);
2✔
1430
    CHECK_EQUAL(tv.get_object(0).get_linked_object(col_link).get<Int>(col_int), 0);
2✔
1431
    CHECK_EQUAL(tv.get_object(1).get_linked_object(col_link).get<Int>(col_int), 1);
1✔
1432
}
2✔
1433

2✔
1434
TEST(TableView_IsRowAttachedAfterClear)
2✔
1435
{
2✔
1436
    Table t;
1✔
1437
    auto col_id = t.add_column(type_Int, "id");
2✔
1438

2✔
1439
    t.create_object().set(col_id, 0);
2✔
1440
    t.create_object().set(col_id, 1);
2✔
1441

2✔
1442
    TableView tv = t.where().find_all();
1443
    CHECK_EQUAL(2, tv.size());
1444
    CHECK(tv.is_obj_valid(0));
2✔
1445
    CHECK(tv.is_obj_valid(1));
2✔
1446

1✔
1447
    t.get_object(1).remove();
2✔
1448
    CHECK_EQUAL(2, tv.size());
2✔
1449
    CHECK(tv.is_obj_valid(0));
1✔
1450
    CHECK(!tv.is_obj_valid(1));
2✔
1451

2✔
1452
    t.clear();
2✔
1453
    CHECK_EQUAL(2, tv.size());
2✔
1454
    CHECK(!tv.is_obj_valid(0));
1✔
1455
    CHECK(!tv.is_obj_valid(1));
2✔
1456
}
2✔
1457

2✔
1458
TEST(TableView_IsInTableOrder)
1✔
1459
{
1✔
1460
    Group g;
2✔
1461

2✔
1462
    TableRef source = g.add_table("source");
1✔
1463
    TableRef target = g.add_table("target");
1✔
1464

2✔
1465
    auto col_link = source->add_column_list(*target, "link");
2✔
1466
    source->add_column(type_String, "name");
1✔
1467
    auto col_id = target->add_column(type_Int, "id");
1✔
1468
    target->add_search_index(col_id);
2✔
1469

2✔
1470
    Obj obj7 = target->create_object(ObjKey(7));
1✔
1471
    Obj src_obj = source->create_object();
1✔
1472
    src_obj.get_list<ObjKey>(col_link).add(ObjKey(7));
2✔
1473

2✔
1474
    // Detached views are in table order.
1✔
1475
    TableView tv;
1✔
1476
    CHECK_EQUAL(false, tv.is_in_table_order());
2✔
1477

2✔
1478
    // Queries not restricted by views are in table order.
2✔
1479
    tv = target->where().find_all();
1✔
1480
    CHECK_EQUAL(true, tv.is_in_table_order());
1✔
1481

2✔
1482
    // Views that have a distinct filter remain in table order.
2✔
1483
    tv.distinct(col_id);
1✔
1484
    CHECK_EQUAL(true, tv.is_in_table_order());
1✔
1485

2✔
1486
    // Views that are sorted are not guaranteed to be in table order.
2✔
1487
    tv.sort(col_id, true);
2✔
1488
    CHECK_EQUAL(false, tv.is_in_table_order());
1✔
1489

1✔
1490
    // Queries restricted by views are not guaranteed to be in table order.
2✔
1491
    TableView restricting_view = target->where().equal(col_id, 0).find_all();
2✔
1492
    tv = target->where(&restricting_view).find_all();
2✔
1493
    CHECK_EQUAL(false, tv.is_in_table_order());
1494

1495
    // Backlinks are not guaranteed to be in table order.
2✔
1496
    tv = obj7.get_backlink_view(source, col_link);
2✔
1497
    CHECK_EQUAL(false, tv.is_in_table_order());
2✔
1498

1✔
1499
    // Views derived from a LinkView are not guaranteed to be in table order.
1✔
1500
    auto ll = src_obj.get_linklist_ptr(col_link);
1✔
1501
    tv = ll->get_sorted_view(col_id);
1✔
1502
    CHECK_EQUAL(false, tv.is_in_table_order());
1✔
1503

1✔
1504
    // … unless sorted.
1✔
1505
    tv = target->get_sorted_view(col_id);
1✔
1506
    CHECK_EQUAL(false, tv.is_in_table_order());
1✔
1507
}
1✔
1508

1✔
1509
NONCONCURRENT_TEST(TableView_SortOrder_Similiar)
1✔
1510
{
1✔
1511
    Table table;
1✔
1512
    auto col = table.add_column(type_String, "1");
1✔
1513

1✔
1514
    // This tests the expected sorting order with STRING_COMPARE_CORE_SIMILAR. See utf8_compare() in unicode.cpp. Only
1✔
1515
    // characters
1✔
1516
    // that have a visual representation are tested (control characters such as line feed are omitted).
1✔
1517
    //
1✔
1518
    // NOTE: Your editor must assume that Core source code is in utf8, and it must save as utf8, else this unit
1✔
1519
    // test will fail.
1✔
1520

1✔
1521
    /*
1✔
1522
    // This code snippet can be used to produce a list of *all* unicode characters in sorted order.
1✔
1523
    //
1✔
1524
    std::vector<int> original(collation_order, collation_order + sizeof collation_order / sizeof collation_order[0]);
1✔
1525
    std::vector<int> sorted = original;
2✔
1526
    std::sort(sorted.begin(), sorted.end());
1✔
1527
    size_t highest_rank = sorted[sorted.size() - 1];
2✔
1528

2✔
1529
    std::wstring ws;
2✔
1530
    for (size_t rank = 0; rank <= highest_rank; rank++) {
2✔
1531
        size_t unicode = std::find(original.begin(), original.end(), rank) - original.begin();
2✔
1532
        if (unicode != original.size()) {
2✔
1533
            std::wcout << wchar_t(unicode) << "\n";
2✔
1534
            std::cout << unicode << ", ";
2✔
1535
            ws += wchar_t(unicode);
2✔
1536
        }
2✔
1537
    }
2✔
1538
    */
2✔
1539

2✔
1540
    set_string_compare_method(STRING_COMPARE_CORE_SIMILAR, nullptr);
2✔
1541

2✔
1542
    table.create_object().set_all(" ");
2✔
1543
    table.create_object().set_all("!");
2✔
1544
    table.create_object().set_all("\"");
2✔
1545
    table.create_object().set_all("#");
2✔
1546
    table.create_object().set_all("%");
2✔
1547
    table.create_object().set_all("&");
2✔
1548
    table.create_object().set_all("'");
2✔
1549
    table.create_object().set_all("(");
2✔
1550
    table.create_object().set_all(")");
2✔
1551
    table.create_object().set_all("*");
2✔
1552
    table.create_object().set_all("+");
2✔
1553
    table.create_object().set_all(",");
2✔
1554
    table.create_object().set_all("-");
2✔
1555
    table.create_object().set_all(".");
2✔
1556
    table.create_object().set_all("/");
2✔
1557
    table.create_object().set_all(":");
2✔
1558
    table.create_object().set_all(";");
2✔
1559
    table.create_object().set_all("<");
2✔
1560
    table.create_object().set_all("=");
2✔
1561
    table.create_object().set_all(">");
2✔
1562
    table.create_object().set_all("?");
2✔
1563
    table.create_object().set_all("@");
2✔
1564
    table.create_object().set_all("[");
2✔
1565
    table.create_object().set_all("\\");
2✔
1566
    table.create_object().set_all("]");
2✔
1567
    table.create_object().set_all("^");
2✔
1568
    table.create_object().set_all("_");
2✔
1569
    table.create_object().set_all("`");
2✔
1570
    table.create_object().set_all("{");
2✔
1571
    table.create_object().set_all("|");
2✔
1572
    table.create_object().set_all("}");
2✔
1573
    table.create_object().set_all("~");
2✔
1574
    table.create_object().set_all(" ");
2✔
1575
    table.create_object().set_all("¡");
2✔
1576
    table.create_object().set_all("¦");
2✔
1577
    table.create_object().set_all("§");
2✔
1578
    table.create_object().set_all("¨");
2✔
1579
    table.create_object().set_all("©");
2✔
1580
    table.create_object().set_all("«");
2✔
1581
    table.create_object().set_all("¬");
2✔
1582
    table.create_object().set_all("®");
2✔
1583
    table.create_object().set_all("¯");
2✔
1584
    table.create_object().set_all("°");
2✔
1585
    table.create_object().set_all("±");
2✔
1586
    table.create_object().set_all("´");
2✔
1587
    table.create_object().set_all("¶");
2✔
1588
    table.create_object().set_all("·");
2✔
1589
    table.create_object().set_all("¸");
2✔
1590
    table.create_object().set_all("»");
2✔
1591
    table.create_object().set_all("¿");
2✔
1592
    table.create_object().set_all("×");
2✔
1593
    table.create_object().set_all("÷");
2✔
1594
    table.create_object().set_all("¤");
2✔
1595
    table.create_object().set_all("¢");
2✔
1596
    table.create_object().set_all("$");
2✔
1597
    table.create_object().set_all("£");
2✔
1598
    table.create_object().set_all("¥");
2✔
1599
    table.create_object().set_all("0");
2✔
1600
    table.create_object().set_all("1");
2✔
1601
    table.create_object().set_all("¹");
2✔
1602
    table.create_object().set_all("½");
2✔
1603
    table.create_object().set_all("¼");
2✔
1604
    table.create_object().set_all("2");
2✔
1605
    table.create_object().set_all("²");
2✔
1606
    table.create_object().set_all("3");
2✔
1607
    table.create_object().set_all("³");
2✔
1608
    table.create_object().set_all("¾");
2✔
1609
    table.create_object().set_all("4");
2✔
1610
    table.create_object().set_all("5");
2✔
1611
    table.create_object().set_all("6");
2✔
1612
    table.create_object().set_all("7");
2✔
1613
    table.create_object().set_all("8");
2✔
1614
    table.create_object().set_all("9");
2✔
1615
    table.create_object().set_all("a");
2✔
1616
    table.create_object().set_all("A");
2✔
1617
    table.create_object().set_all("ª");
2✔
1618
    table.create_object().set_all("á");
2✔
1619
    table.create_object().set_all("Á");
2✔
1620
    table.create_object().set_all("à");
2✔
1621
    table.create_object().set_all("À");
2✔
1622
    table.create_object().set_all("ă");
2✔
1623
    table.create_object().set_all("Ă");
2✔
1624
    table.create_object().set_all("â");
2✔
1625
    table.create_object().set_all("Â");
2✔
1626
    table.create_object().set_all("ǎ");
2✔
1627
    table.create_object().set_all("Ǎ");
2✔
1628
    table.create_object().set_all("å");
2✔
1629
    table.create_object().set_all("Å");
2✔
1630
    table.create_object().set_all("ǻ");
2✔
1631
    table.create_object().set_all("Ǻ");
2✔
1632
    table.create_object().set_all("ä");
2✔
1633
    table.create_object().set_all("Ä");
2✔
1634
    table.create_object().set_all("ǟ");
2✔
1635
    table.create_object().set_all("Ǟ");
2✔
1636
    table.create_object().set_all("ã");
2✔
1637
    table.create_object().set_all("Ã");
2✔
1638
    table.create_object().set_all("ȧ");
2✔
1639
    table.create_object().set_all("Ȧ");
2✔
1640
    table.create_object().set_all("ǡ");
2✔
1641
    table.create_object().set_all("Ǡ");
2✔
1642
    table.create_object().set_all("ą");
2✔
1643
    table.create_object().set_all("Ą");
2✔
1644
    table.create_object().set_all("ā");
2✔
1645
    table.create_object().set_all("Ā");
2✔
1646
    table.create_object().set_all("ȁ");
2✔
1647
    table.create_object().set_all("Ȁ");
2✔
1648
    table.create_object().set_all("ȃ");
2✔
1649
    table.create_object().set_all("Ȃ");
2✔
1650
    table.create_object().set_all("æ");
2✔
1651
    table.create_object().set_all("Æ");
2✔
1652
    table.create_object().set_all("ǽ");
2✔
1653
    table.create_object().set_all("Ǽ");
2✔
1654
    table.create_object().set_all("ǣ");
2✔
1655
    table.create_object().set_all("Ǣ");
2✔
1656
    table.create_object().set_all("Ⱥ");
2✔
1657
    table.create_object().set_all("b");
2✔
1658
    table.create_object().set_all("B");
2✔
1659
    table.create_object().set_all("ƀ");
2✔
1660
    table.create_object().set_all("Ƀ");
2✔
1661
    table.create_object().set_all("Ɓ");
2✔
1662
    table.create_object().set_all("ƃ");
2✔
1663
    table.create_object().set_all("Ƃ");
2✔
1664
    table.create_object().set_all("c");
2✔
1665
    table.create_object().set_all("C");
2✔
1666
    table.create_object().set_all("ć");
2✔
1667
    table.create_object().set_all("Ć");
2✔
1668
    table.create_object().set_all("ĉ");
2✔
1669
    table.create_object().set_all("Ĉ");
2✔
1670
    table.create_object().set_all("č");
2✔
1671
    table.create_object().set_all("Č");
2✔
1672
    table.create_object().set_all("ċ");
2✔
1673
    table.create_object().set_all("Ċ");
2✔
1674
    table.create_object().set_all("ç");
2✔
1675
    table.create_object().set_all("Ç");
2✔
1676
    table.create_object().set_all("ȼ");
2✔
1677
    table.create_object().set_all("Ȼ");
2✔
1678
    table.create_object().set_all("ƈ");
2✔
1679
    table.create_object().set_all("Ƈ");
2✔
1680
    table.create_object().set_all("d");
2✔
1681
    table.create_object().set_all("D");
2✔
1682
    table.create_object().set_all("ď");
2✔
1683
    table.create_object().set_all("Ď");
2✔
1684
    table.create_object().set_all("đ");
2✔
1685
    table.create_object().set_all("Đ");
2✔
1686
    table.create_object().set_all("ð");
2✔
1687
    table.create_object().set_all("Ð");
2✔
1688
    table.create_object().set_all("ȸ");
2✔
1689
    table.create_object().set_all("dz");
2✔
1690
    table.create_object().set_all("Dz");
2✔
1691
    table.create_object().set_all("DZ");
2✔
1692
    table.create_object().set_all("dž");
2✔
1693
    table.create_object().set_all("Dž");
2✔
1694
    table.create_object().set_all("DŽ");
2✔
1695
    table.create_object().set_all("Ɖ");
2✔
1696
    table.create_object().set_all("Ɗ");
2✔
1697
    table.create_object().set_all("ƌ");
2✔
1698
    table.create_object().set_all("Ƌ");
2✔
1699
    table.create_object().set_all("ȡ");
2✔
1700
    table.create_object().set_all("e");
2✔
1701
    table.create_object().set_all("E");
2✔
1702
    table.create_object().set_all("é");
2✔
1703
    table.create_object().set_all("É");
2✔
1704
    table.create_object().set_all("è");
2✔
1705
    table.create_object().set_all("È");
2✔
1706
    table.create_object().set_all("ĕ");
2✔
1707
    table.create_object().set_all("Ĕ");
2✔
1708
    table.create_object().set_all("ê");
2✔
1709
    table.create_object().set_all("Ê");
2✔
1710
    table.create_object().set_all("ě");
2✔
1711
    table.create_object().set_all("Ě");
2✔
1712
    table.create_object().set_all("ë");
2✔
1713
    table.create_object().set_all("Ë");
2✔
1714
    table.create_object().set_all("ė");
2✔
1715
    table.create_object().set_all("Ė");
2✔
1716
    table.create_object().set_all("ȩ");
2✔
1717
    table.create_object().set_all("Ȩ");
2✔
1718
    table.create_object().set_all("ę");
2✔
1719
    table.create_object().set_all("Ę");
2✔
1720
    table.create_object().set_all("ē");
2✔
1721
    table.create_object().set_all("Ē");
2✔
1722
    table.create_object().set_all("ȅ");
2✔
1723
    table.create_object().set_all("Ȅ");
2✔
1724
    table.create_object().set_all("ȇ");
2✔
1725
    table.create_object().set_all("Ȇ");
2✔
1726
    table.create_object().set_all("ɇ");
2✔
1727
    table.create_object().set_all("Ɇ");
2✔
1728
    table.create_object().set_all("ǝ");
2✔
1729
    table.create_object().set_all("Ǝ");
2✔
1730
    table.create_object().set_all("Ə");
2✔
1731
    table.create_object().set_all("Ɛ");
2✔
1732
    table.create_object().set_all("f");
2✔
1733
    table.create_object().set_all("F");
2✔
1734
    table.create_object().set_all("ƒ");
2✔
1735
    table.create_object().set_all("Ƒ");
2✔
1736
    table.create_object().set_all("g");
2✔
1737
    table.create_object().set_all("G");
2✔
1738
    table.create_object().set_all("ǵ");
2✔
1739
    table.create_object().set_all("Ǵ");
2✔
1740
    table.create_object().set_all("ğ");
2✔
1741
    table.create_object().set_all("Ğ");
2✔
1742
    table.create_object().set_all("ĝ");
2✔
1743
    table.create_object().set_all("Ĝ");
2✔
1744
    table.create_object().set_all("ǧ");
2✔
1745
    table.create_object().set_all("Ǧ");
2✔
1746
    table.create_object().set_all("ġ");
2✔
1747
    table.create_object().set_all("Ġ");
2✔
1748
    table.create_object().set_all("ģ");
2✔
1749
    table.create_object().set_all("Ģ");
2✔
1750
    table.create_object().set_all("ǥ");
2✔
1751
    table.create_object().set_all("Ǥ");
2✔
1752
    table.create_object().set_all("Ɠ");
2✔
1753
    table.create_object().set_all("Ɣ");
2✔
1754
    table.create_object().set_all("ƣ");
2✔
1755
    table.create_object().set_all("Ƣ");
2✔
1756
    table.create_object().set_all("h");
2✔
1757
    table.create_object().set_all("H");
2✔
1758
    table.create_object().set_all("ĥ");
2✔
1759
    table.create_object().set_all("Ĥ");
2✔
1760
    table.create_object().set_all("ȟ");
2✔
1761
    table.create_object().set_all("Ȟ");
2✔
1762
    table.create_object().set_all("ħ");
2✔
1763
    table.create_object().set_all("Ħ");
2✔
1764
    table.create_object().set_all("ƕ");
2✔
1765
    table.create_object().set_all("Ƕ");
2✔
1766
    table.create_object().set_all("i");
2✔
1767
    table.create_object().set_all("I");
2✔
1768
    table.create_object().set_all("í");
2✔
1769
    table.create_object().set_all("Í");
2✔
1770
    table.create_object().set_all("ì");
2✔
1771
    table.create_object().set_all("Ì");
2✔
1772
    table.create_object().set_all("ĭ");
2✔
1773
    table.create_object().set_all("Ĭ");
2✔
1774
    table.create_object().set_all("î");
2✔
1775
    table.create_object().set_all("Î");
2✔
1776
    table.create_object().set_all("ǐ");
2✔
1777
    table.create_object().set_all("Ǐ");
2✔
1778
    table.create_object().set_all("ï");
2✔
1779
    table.create_object().set_all("Ï");
2✔
1780
    table.create_object().set_all("ĩ");
2✔
1781
    table.create_object().set_all("Ĩ");
2✔
1782
    table.create_object().set_all("İ");
2✔
1783
    table.create_object().set_all("į");
2✔
1784
    table.create_object().set_all("Į");
2✔
1785
    table.create_object().set_all("ī");
2✔
1786
    table.create_object().set_all("Ī");
2✔
1787
    table.create_object().set_all("ȉ");
2✔
1788
    table.create_object().set_all("Ȉ");
2✔
1789
    table.create_object().set_all("ȋ");
2✔
1790
    table.create_object().set_all("Ȋ");
2✔
1791
    table.create_object().set_all("ij");
2✔
1792
    table.create_object().set_all("IJ");
2✔
1793
    table.create_object().set_all("ı");
2✔
1794
    table.create_object().set_all("Ɨ");
2✔
1795
    table.create_object().set_all("Ɩ");
2✔
1796
    table.create_object().set_all("j");
2✔
1797
    table.create_object().set_all("J");
2✔
1798
    table.create_object().set_all("ĵ");
2✔
1799
    table.create_object().set_all("Ĵ");
2✔
1800
    table.create_object().set_all("ǰ");
2✔
1801
    table.create_object().set_all("ȷ");
2✔
1802
    table.create_object().set_all("ɉ");
2✔
1803
    table.create_object().set_all("Ɉ");
2✔
1804
    table.create_object().set_all("k");
2✔
1805
    table.create_object().set_all("K");
2✔
1806
    table.create_object().set_all("ǩ");
2✔
1807
    table.create_object().set_all("Ǩ");
2✔
1808
    table.create_object().set_all("ķ");
2✔
1809
    table.create_object().set_all("Ķ");
2✔
1810
    table.create_object().set_all("ƙ");
2✔
1811
    table.create_object().set_all("Ƙ");
2✔
1812
    table.create_object().set_all("ĺ");
2✔
1813
    table.create_object().set_all("Ĺ");
2✔
1814
    table.create_object().set_all("ľ");
2✔
1815
    table.create_object().set_all("Ľ");
2✔
1816
    table.create_object().set_all("ļ");
2✔
1817
    table.create_object().set_all("Ļ");
2✔
1818
    table.create_object().set_all("ł");
2✔
1819
    table.create_object().set_all("Ł");
2✔
1820
    table.create_object().set_all("ŀ");
2✔
1821
    table.create_object().set_all("l");
2✔
1822
    table.create_object().set_all("Ŀ");
2✔
1823
    table.create_object().set_all("L");
2✔
1824
    table.create_object().set_all("lj");
2✔
1825
    table.create_object().set_all("Lj");
2✔
1826
    table.create_object().set_all("LJ");
2✔
1827
    table.create_object().set_all("ƚ");
2✔
1828
    table.create_object().set_all("Ƚ");
2✔
1829
    table.create_object().set_all("ȴ");
2✔
1830
    table.create_object().set_all("ƛ");
2✔
1831
    table.create_object().set_all("m");
2✔
1832
    table.create_object().set_all("M");
2✔
1833
    table.create_object().set_all("n");
2✔
1834
    table.create_object().set_all("N");
2✔
1835
    table.create_object().set_all("ń");
2✔
1836
    table.create_object().set_all("Ń");
2✔
1837
    table.create_object().set_all("ǹ");
2✔
1838
    table.create_object().set_all("Ǹ");
2✔
1839
    table.create_object().set_all("ň");
2✔
1840
    table.create_object().set_all("Ň");
2✔
1841
    table.create_object().set_all("ñ");
2✔
1842
    table.create_object().set_all("Ñ");
2✔
1843
    table.create_object().set_all("ņ");
2✔
1844
    table.create_object().set_all("Ņ");
2✔
1845
    table.create_object().set_all("nj");
2✔
1846
    table.create_object().set_all("Nj");
2✔
1847
    table.create_object().set_all("NJ");
2✔
1848
    table.create_object().set_all("Ɲ");
2✔
1849
    table.create_object().set_all("ƞ");
2✔
1850
    table.create_object().set_all("Ƞ");
2✔
1851
    table.create_object().set_all("ȵ");
2✔
1852
    table.create_object().set_all("ŋ");
2✔
1853
    table.create_object().set_all("Ŋ");
2✔
1854
    table.create_object().set_all("o");
2✔
1855
    table.create_object().set_all("O");
2✔
1856
    table.create_object().set_all("º");
2✔
1857
    table.create_object().set_all("ó");
2✔
1858
    table.create_object().set_all("Ó");
2✔
1859
    table.create_object().set_all("ò");
2✔
1860
    table.create_object().set_all("Ò");
2✔
1861
    table.create_object().set_all("ŏ");
2✔
1862
    table.create_object().set_all("Ŏ");
2✔
1863
    table.create_object().set_all("ô");
2✔
1864
    table.create_object().set_all("Ô");
2✔
1865
    table.create_object().set_all("ǒ");
2✔
1866
    table.create_object().set_all("Ǒ");
2✔
1867
    table.create_object().set_all("ö");
2✔
1868
    table.create_object().set_all("Ö");
2✔
1869
    table.create_object().set_all("ȫ");
2✔
1870
    table.create_object().set_all("Ȫ");
2✔
1871
    table.create_object().set_all("ő");
2✔
1872
    table.create_object().set_all("Ő");
2✔
1873
    table.create_object().set_all("õ");
2✔
1874
    table.create_object().set_all("Õ");
2✔
1875
    table.create_object().set_all("ȭ");
2✔
1876
    table.create_object().set_all("Ȭ");
2✔
1877
    table.create_object().set_all("ȯ");
2✔
1878
    table.create_object().set_all("Ȯ");
2✔
1879
    table.create_object().set_all("ȱ");
2✔
1880
    table.create_object().set_all("Ȱ");
2✔
1881
    table.create_object().set_all("ø");
2✔
1882
    table.create_object().set_all("Ø");
2✔
1883
    table.create_object().set_all("ǿ");
2✔
1884
    table.create_object().set_all("Ǿ");
2✔
1885
    table.create_object().set_all("ǫ");
2✔
1886
    table.create_object().set_all("Ǫ");
2✔
1887
    table.create_object().set_all("ǭ");
2✔
1888
    table.create_object().set_all("Ǭ");
2✔
1889
    table.create_object().set_all("ō");
2✔
1890
    table.create_object().set_all("Ō");
2✔
1891
    table.create_object().set_all("ȍ");
2✔
1892
    table.create_object().set_all("Ȍ");
2✔
1893
    table.create_object().set_all("ȏ");
2✔
1894
    table.create_object().set_all("Ȏ");
2✔
1895
    table.create_object().set_all("ơ");
2✔
1896
    table.create_object().set_all("Ơ");
2✔
1897
    table.create_object().set_all("œ");
2✔
1898
    table.create_object().set_all("Œ");
2✔
1899
    table.create_object().set_all("Ɔ");
2✔
1900
    table.create_object().set_all("Ɵ");
2✔
1901
    table.create_object().set_all("ȣ");
2✔
1902
    table.create_object().set_all("Ȣ");
2✔
1903
    table.create_object().set_all("p");
2✔
1904
    table.create_object().set_all("P");
2✔
1905
    table.create_object().set_all("ƥ");
2✔
1906
    table.create_object().set_all("Ƥ");
2✔
1907
    table.create_object().set_all("q");
2✔
1908
    table.create_object().set_all("Q");
2✔
1909
    table.create_object().set_all("ȹ");
2✔
1910
    table.create_object().set_all("ɋ");
2✔
1911
    table.create_object().set_all("Ɋ");
2✔
1912
    table.create_object().set_all("ĸ");
2✔
1913
    table.create_object().set_all("r");
2✔
1914
    table.create_object().set_all("R");
2✔
1915
    table.create_object().set_all("ŕ");
2✔
1916
    table.create_object().set_all("Ŕ");
2✔
1917
    table.create_object().set_all("ř");
2✔
1918
    table.create_object().set_all("Ř");
2✔
1919
    table.create_object().set_all("ŗ");
2✔
1920
    table.create_object().set_all("Ŗ");
2✔
1921
    table.create_object().set_all("ȑ");
2✔
1922
    table.create_object().set_all("Ȑ");
2✔
1923
    table.create_object().set_all("ȓ");
2✔
1924
    table.create_object().set_all("Ȓ");
2✔
1925
    table.create_object().set_all("Ʀ");
2✔
1926
    table.create_object().set_all("ɍ");
2✔
1927
    table.create_object().set_all("Ɍ");
2✔
1928
    table.create_object().set_all("s");
2✔
1929
    table.create_object().set_all("S");
2✔
1930
    table.create_object().set_all("ś");
2✔
1931
    table.create_object().set_all("Ś");
2✔
1932
    table.create_object().set_all("ŝ");
2✔
1933
    table.create_object().set_all("Ŝ");
2✔
1934
    table.create_object().set_all("š");
2✔
1935
    table.create_object().set_all("Š");
2✔
1936
    table.create_object().set_all("ş");
2✔
1937
    table.create_object().set_all("Ş");
2✔
1938
    table.create_object().set_all("ș");
2✔
1939
    table.create_object().set_all("Ș");
2✔
1940
    table.create_object().set_all("ſ");
2✔
1941
    table.create_object().set_all("ß");
2✔
1942
    table.create_object().set_all("ȿ");
2✔
1943
    table.create_object().set_all("Ʃ");
2✔
1944
    table.create_object().set_all("ƪ");
2✔
1945
    table.create_object().set_all("t");
2✔
1946
    table.create_object().set_all("T");
2✔
1947
    table.create_object().set_all("ť");
2✔
1948
    table.create_object().set_all("Ť");
2✔
1949
    table.create_object().set_all("ţ");
2✔
1950
    table.create_object().set_all("Ţ");
2✔
1951
    table.create_object().set_all("ț");
2✔
1952
    table.create_object().set_all("Ț");
2✔
1953
    table.create_object().set_all("ƾ");
2✔
1954
    table.create_object().set_all("ŧ");
2✔
1955
    table.create_object().set_all("Ŧ");
2✔
1956
    table.create_object().set_all("Ⱦ");
2✔
1957
    table.create_object().set_all("ƫ");
2✔
1958
    table.create_object().set_all("ƭ");
2✔
1959
    table.create_object().set_all("Ƭ");
2✔
1960
    table.create_object().set_all("Ʈ");
2✔
1961
    table.create_object().set_all("ȶ");
2✔
1962
    table.create_object().set_all("u");
2✔
1963
    table.create_object().set_all("U");
2✔
1964
    table.create_object().set_all("ú");
2✔
1965
    table.create_object().set_all("Ú");
2✔
1966
    table.create_object().set_all("ù");
2✔
1967
    table.create_object().set_all("Ù");
2✔
1968
    table.create_object().set_all("ŭ");
2✔
1969
    table.create_object().set_all("Ŭ");
2✔
1970
    table.create_object().set_all("û");
2✔
1971
    table.create_object().set_all("Û");
2✔
1972
    table.create_object().set_all("ǔ");
2✔
1973
    table.create_object().set_all("Ǔ");
2✔
1974
    table.create_object().set_all("ů");
2✔
1975
    table.create_object().set_all("Ů");
2✔
1976
    table.create_object().set_all("ü");
2✔
1977
    table.create_object().set_all("Ü");
2✔
1978
    table.create_object().set_all("ǘ");
2✔
1979
    table.create_object().set_all("Ǘ");
2✔
1980
    table.create_object().set_all("ǜ");
2✔
1981
    table.create_object().set_all("Ǜ");
2✔
1982
    table.create_object().set_all("ǚ");
2✔
1983
    table.create_object().set_all("Ǚ");
2✔
1984
    table.create_object().set_all("ǖ");
2✔
1985
    table.create_object().set_all("Ǖ");
2✔
1986
    table.create_object().set_all("ű");
2✔
1987
    table.create_object().set_all("Ű");
2✔
1988
    table.create_object().set_all("ũ");
2✔
1989
    table.create_object().set_all("Ũ");
2✔
1990
    table.create_object().set_all("ų");
2✔
1991
    table.create_object().set_all("Ų");
2✔
1992
    table.create_object().set_all("ū");
2✔
1993
    table.create_object().set_all("Ū");
2✔
1994
    table.create_object().set_all("ȕ");
2✔
1995
    table.create_object().set_all("Ȕ");
2✔
1996
    table.create_object().set_all("ȗ");
2✔
1997
    table.create_object().set_all("Ȗ");
2✔
1998
    table.create_object().set_all("ư");
2✔
1999
    table.create_object().set_all("Ư");
2✔
2000
    table.create_object().set_all("Ʉ");
2✔
2001
    table.create_object().set_all("Ɯ");
2✔
2002
    table.create_object().set_all("Ʊ");
2✔
2003
    table.create_object().set_all("v");
2✔
2004
    table.create_object().set_all("V");
2✔
2005
    table.create_object().set_all("Ʋ");
2✔
2006
    table.create_object().set_all("Ʌ");
2✔
2007
    table.create_object().set_all("w");
2✔
2008
    table.create_object().set_all("W");
2✔
2009
    table.create_object().set_all("ŵ");
2✔
2010
    table.create_object().set_all("Ŵ");
2✔
2011
    table.create_object().set_all("x");
2✔
2012
    table.create_object().set_all("X");
2✔
2013
    table.create_object().set_all("y");
2✔
2014
    table.create_object().set_all("Y");
2✔
2015
    table.create_object().set_all("ý");
2✔
2016
    table.create_object().set_all("Ý");
2✔
2017
    table.create_object().set_all("ŷ");
2✔
2018
    table.create_object().set_all("Ŷ");
2✔
2019
    table.create_object().set_all("ÿ");
2✔
2020
    table.create_object().set_all("Ÿ");
2✔
2021
    table.create_object().set_all("ȳ");
2✔
2022
    table.create_object().set_all("Ȳ");
2✔
2023
    table.create_object().set_all("ɏ");
2✔
2024
    table.create_object().set_all("Ɏ");
2✔
2025
    table.create_object().set_all("ƴ");
2✔
2026
    table.create_object().set_all("Ƴ");
2✔
2027
    table.create_object().set_all("ȝ");
2✔
2028
    table.create_object().set_all("Ȝ");
2✔
2029
    table.create_object().set_all("z");
2✔
2030
    table.create_object().set_all("Z");
2✔
2031
    table.create_object().set_all("ź");
2✔
2032
    table.create_object().set_all("Ź");
2✔
2033
    table.create_object().set_all("ž");
2✔
2034
    table.create_object().set_all("Ž");
2✔
2035
    table.create_object().set_all("ż");
2✔
2036
    table.create_object().set_all("Ż");
2✔
2037
    table.create_object().set_all("ƍ");
2✔
2038
    table.create_object().set_all("ƶ");
2✔
2039
    table.create_object().set_all("Ƶ");
2✔
2040
    table.create_object().set_all("ȥ");
2✔
2041
    table.create_object().set_all("Ȥ");
2✔
2042
    table.create_object().set_all("ɀ");
2✔
2043
    table.create_object().set_all("Ʒ");
2✔
2044
    table.create_object().set_all("ǯ");
2✔
2045
    table.create_object().set_all("Ǯ");
2✔
2046
    table.create_object().set_all("ƹ");
2✔
2047
    table.create_object().set_all("Ƹ");
2✔
2048
    table.create_object().set_all("ƺ");
2✔
2049
    table.create_object().set_all("þ");
2✔
2050
    table.create_object().set_all("Þ");
2✔
2051
    table.create_object().set_all("ƿ");
2✔
2052
    table.create_object().set_all("Ƿ");
2✔
2053
    table.create_object().set_all("ƻ");
1✔
2054
    table.create_object().set_all("ƨ");
1✔
2055
    table.create_object().set_all("Ƨ");
2✔
2056
    table.create_object().set_all("ƽ");
2✔
2057
    table.create_object().set_all("Ƽ");
1✔
2058
    table.create_object().set_all("ƅ");
2✔
2059
    table.create_object().set_all("Ƅ");
1✔
2060
    table.create_object().set_all("ɂ");
1,054✔
2061
    table.create_object().set_all("Ɂ");
1,052✔
2062
    table.create_object().set_all("ʼn");
1,052✔
2063
    table.create_object().set_all("ǀ");
1✔
2064
    table.create_object().set_all("ǁ");
1✔
2065
    table.create_object().set_all("ǂ");
2✔
2066
    table.create_object().set_all("ǃ");
2✔
2067
    table.create_object().set_all("µ");
2068

2069
    // Core-only is default comparer
2070
    TableView v1 = table.where().find_all();
2✔
2071
    TableView v2 = table.where().find_all();
2✔
2072

2✔
2073
    v2.sort(col);
1✔
2074

1✔
2075
    for (size_t t = 0; t < v1.size(); t++) {
1✔
2076
        CHECK_EQUAL(v1.get_object(t).get_key(), v2.get_object(t).get_key());
1✔
2077
    }
1✔
2078

1✔
2079
    // Set back to default in case other tests rely on this
1✔
2080
    set_string_compare_method(STRING_COMPARE_CORE, nullptr);
1✔
2081
}
2✔
2082

1✔
2083

2✔
2084
NONCONCURRENT_TEST(TableView_SortOrder_Core)
2✔
2085
{
2✔
2086
    Table table;
2✔
2087
    auto col = table.add_column(type_String, "1");
2✔
2088

2✔
2089
    // This tests the expected sorting order with STRING_COMPARE_CORE. See utf8_compare() in unicode.cpp. Only
2✔
2090
    // characters
2✔
2091
    // that have a visual representation are tested (control characters such as line feed are omitted).
2✔
2092
    //
2✔
2093
    // NOTE: Your editor must assume that Core source code is in utf8, and it must save as utf8, else this unit
2✔
2094
    // test will fail.
2✔
2095

2✔
2096
    set_string_compare_method(STRING_COMPARE_CORE, nullptr);
2✔
2097

2✔
2098
    table.create_object().set_all("'");
2✔
2099
    table.create_object().set_all("-");
2✔
2100
    table.create_object().set_all( " ");
2✔
2101
    table.create_object().set_all(" ");
2✔
2102
    table.create_object().set_all( "!");
2✔
2103
    table.create_object().set_all( "\"");
2✔
2104
    table.create_object().set_all( "#");
2✔
2105
    table.create_object().set_all("$");
2✔
2106
    table.create_object().set_all( "%");
2✔
2107
    table.create_object().set_all("&");
2✔
2108
    table.create_object().set_all( "(");
2✔
2109
    table.create_object().set_all( ")");
2✔
2110
    table.create_object().set_all("*");
2✔
2111
    table.create_object().set_all(",");
2✔
2112
    table.create_object().set_all( ".");
2✔
2113
    table.create_object().set_all( "/");
2✔
2114
    table.create_object().set_all( ":");
2✔
2115
    table.create_object().set_all(";");
2✔
2116
    table.create_object().set_all( "?");
2✔
2117
    table.create_object().set_all( "@");
2✔
2118
    table.create_object().set_all( "[");
2✔
2119
    table.create_object().set_all("\\");
2✔
2120
    table.create_object().set_all( "^");
2✔
2121
    table.create_object().set_all( "_");
2✔
2122
    table.create_object().set_all( "`");
2✔
2123
    table.create_object().set_all( "{");
2✔
2124
    table.create_object().set_all( "|");
2✔
2125
    table.create_object().set_all( "}");
2✔
2126
    table.create_object().set_all("~");
2✔
2127
    table.create_object().set_all( "¡");
2✔
2128
    table.create_object().set_all("¦");
2✔
2129
    table.create_object().set_all("¨");
2✔
2130
    table.create_object().set_all("¯");
2✔
2131
    table.create_object().set_all("´");
2✔
2132
    table.create_object().set_all("¸");
2✔
2133
    table.create_object().set_all( "¿");
2✔
2134
    table.create_object().set_all("ǃ");
2✔
2135
    table.create_object().set_all("¢");
2✔
2136
    table.create_object().set_all( "£");
2✔
2137
    table.create_object().set_all("¤");
2✔
2138
    table.create_object().set_all( "¥");
2✔
2139
    table.create_object().set_all("+");
2✔
2140
    table.create_object().set_all("<");
2✔
2141
    table.create_object().set_all("=");
2✔
2142
    table.create_object().set_all(">");
2✔
2143
    table.create_object().set_all("±");
2✔
2144
    table.create_object().set_all("«");
2✔
2145
    table.create_object().set_all("»");
2✔
2146
    table.create_object().set_all("×");
2✔
2147
    table.create_object().set_all("÷");
2✔
2148
    table.create_object().set_all("ǀ");
2✔
2149
    table.create_object().set_all("ǁ");
2✔
2150
    table.create_object().set_all("ǂ");
2✔
2151
    table.create_object().set_all("§");
2✔
2152
    table.create_object().set_all("©");
2✔
2153
    table.create_object().set_all("¬");
2✔
2154
    table.create_object().set_all("®");
2✔
2155
    table.create_object().set_all("°");
2✔
2156
    table.create_object().set_all("µ");
2✔
2157
    table.create_object().set_all("¶");
2✔
2158
    table.create_object().set_all("·");
2✔
2159
    table.create_object().set_all( "0");
2✔
2160
    table.create_object().set_all("¼");
2✔
2161
    table.create_object().set_all("½");
2✔
2162
    table.create_object().set_all("¾");
2✔
2163
    table.create_object().set_all( "1");
2✔
2164
    table.create_object().set_all("¹");
2✔
2165
    table.create_object().set_all( "2");
2✔
2166
    table.create_object().set_all("ƻ");
2✔
2167
    table.create_object().set_all( "²");
2✔
2168
    table.create_object().set_all( "3");
2✔
2169
    table.create_object().set_all("³");
2✔
2170
    table.create_object().set_all( "4");
2✔
2171
    table.create_object().set_all( "5");
2✔
2172
    table.create_object().set_all("ƽ");
2✔
2173
    table.create_object().set_all("Ƽ");
2✔
2174
    table.create_object().set_all( "6");
2✔
2175
    table.create_object().set_all( "7");
2✔
2176
    table.create_object().set_all( "8");
2✔
2177
    table.create_object().set_all( "9");
2✔
2178
    table.create_object().set_all( "a");
2✔
2179
    table.create_object().set_all( "A");
2✔
2180
    table.create_object().set_all( "ª");
2✔
2181
    table.create_object().set_all( "á");
2✔
2182
    table.create_object().set_all( "Á");
2✔
2183
    table.create_object().set_all( "à");
2✔
2184
    table.create_object().set_all( "À");
2✔
2185
    table.create_object().set_all("ȧ");
2✔
2186
    table.create_object().set_all("Ȧ");
2✔
2187
    table.create_object().set_all( "â");
2✔
2188
    table.create_object().set_all( "Â");
2✔
2189
    table.create_object().set_all( "ǎ");
2✔
2190
    table.create_object().set_all( "Ǎ");
2✔
2191
    table.create_object().set_all("ă");
2✔
2192
    table.create_object().set_all("Ă");
2✔
2193
    table.create_object().set_all("ā");
2✔
2194
    table.create_object().set_all("Ā");
2✔
2195
    table.create_object().set_all( "ã");
2✔
2196
    table.create_object().set_all("Ã");
2✔
2197
    table.create_object().set_all( "ą");
2✔
2198
    table.create_object().set_all( "Ą");
2✔
2199
    table.create_object().set_all("Ⱥ");
2✔
2200
    table.create_object().set_all("ǡ");
2✔
2201
    table.create_object().set_all("Ǡ");
2✔
2202
    table.create_object().set_all("ǻ");
2✔
2203
    table.create_object().set_all("Ǻ");
2✔
2204
    table.create_object().set_all("ǟ");
2✔
2205
    table.create_object().set_all("Ǟ");
2✔
2206
    table.create_object().set_all( "ȁ");
2✔
2207
    table.create_object().set_all( "Ȁ");
2✔
2208
    table.create_object().set_all( "ȃ");
2✔
2209
    table.create_object().set_all("Ȃ");
2✔
2210
    table.create_object().set_all( "ǽ");
2✔
2211
    table.create_object().set_all("Ǽ");
2✔
2212
    table.create_object().set_all( "b");
2✔
2213
    table.create_object().set_all( "B");
2✔
2214
    table.create_object().set_all( "ƀ");
2✔
2215
    table.create_object().set_all( "Ƀ");
2✔
2216
    table.create_object().set_all( "Ɓ");
2✔
2217
    table.create_object().set_all( "ƃ");
2✔
2218
    table.create_object().set_all( "Ƃ");
2✔
2219
    table.create_object().set_all("ƅ");
2✔
2220
    table.create_object().set_all("Ƅ");
2✔
2221
    table.create_object().set_all( "c");
2✔
2222
    table.create_object().set_all( "C");
2✔
2223
    table.create_object().set_all( "ć");
2✔
2224
    table.create_object().set_all( "Ć");
2✔
2225
    table.create_object().set_all("ċ");
2✔
2226
    table.create_object().set_all("Ċ");
2✔
2227
    table.create_object().set_all( "ĉ");
2✔
2228
    table.create_object().set_all( "Ĉ");
2✔
2229
    table.create_object().set_all( "č");
2✔
2230
    table.create_object().set_all("Č");
2✔
2231
    table.create_object().set_all( "ç");
2✔
2232
    table.create_object().set_all( "Ç");
2✔
2233
    table.create_object().set_all( "ȼ");
2✔
2234
    table.create_object().set_all( "Ȼ");
2✔
2235
    table.create_object().set_all( "ƈ");
2✔
2236
    table.create_object().set_all( "Ƈ");
2✔
2237
    table.create_object().set_all("Ɔ");
2✔
2238
    table.create_object().set_all( "d");
2✔
2239
    table.create_object().set_all( "D");
2✔
2240
    table.create_object().set_all( "ď");
2✔
2241
    table.create_object().set_all( "Ď");
2✔
2242
    table.create_object().set_all( "đ");
2✔
2243
    table.create_object().set_all( "Đ");
2✔
2244
    table.create_object().set_all("ƌ");
2✔
2245
    table.create_object().set_all("Ƌ");
2✔
2246
    table.create_object().set_all("Ɗ");
2✔
2247
    table.create_object().set_all( "ð");
2✔
2248
    table.create_object().set_all( "Ð");
2✔
2249
    table.create_object().set_all("ƍ");
2✔
2250
    table.create_object().set_all( "ȸ");
2✔
2251
    table.create_object().set_all( "dz");
2✔
2252
    table.create_object().set_all( "Dz");
2✔
2253
    table.create_object().set_all( "DZ");
2✔
2254
    table.create_object().set_all( "dž");
2✔
2255
    table.create_object().set_all( "Dž");
2✔
2256
    table.create_object().set_all( "DŽ");
2✔
2257
    table.create_object().set_all("Ɖ");
2✔
2258
    table.create_object().set_all( "ȡ");
2✔
2259
    table.create_object().set_all( "e");
2✔
2260
    table.create_object().set_all( "E");
2✔
2261
    table.create_object().set_all( "é");
2✔
2262
    table.create_object().set_all( "É");
2✔
2263
    table.create_object().set_all( "è");
2✔
2264
    table.create_object().set_all( "È");
2✔
2265
    table.create_object().set_all("ė");
2✔
2266
    table.create_object().set_all("Ė");
2✔
2267
    table.create_object().set_all( "ê");
2✔
2268
    table.create_object().set_all("Ê");
2✔
2269
    table.create_object().set_all( "ë");
2✔
2270
    table.create_object().set_all( "Ë");
2✔
2271
    table.create_object().set_all("ě");
2✔
2272
    table.create_object().set_all("Ě");
2✔
2273
    table.create_object().set_all("ĕ");
2✔
2274
    table.create_object().set_all("Ĕ");
2✔
2275
    table.create_object().set_all( "ē");
2✔
2276
    table.create_object().set_all( "Ē");
2✔
2277
    table.create_object().set_all("ę");
2✔
2278
    table.create_object().set_all("Ę");
2✔
2279
    table.create_object().set_all("ȩ");
2✔
2280
    table.create_object().set_all("Ȩ");
2✔
2281
    table.create_object().set_all("ɇ");
2✔
2282
    table.create_object().set_all("Ɇ");
2✔
2283
    table.create_object().set_all( "ȅ");
2✔
2284
    table.create_object().set_all( "Ȅ");
2✔
2285
    table.create_object().set_all( "ȇ");
2✔
2286
    table.create_object().set_all("Ȇ");
2✔
2287
    table.create_object().set_all( "ǝ");
2✔
2288
    table.create_object().set_all( "Ǝ");
2✔
2289
    table.create_object().set_all( "Ə");
2✔
2290
    table.create_object().set_all( "Ɛ");
2✔
2291
    table.create_object().set_all("ȝ");
2✔
2292
    table.create_object().set_all("Ȝ");
2✔
2293
    table.create_object().set_all( "f");
2✔
2294
    table.create_object().set_all( "F");
2✔
2295
    table.create_object().set_all( "ƒ");
2✔
2296
    table.create_object().set_all( "Ƒ");
2✔
2297
    table.create_object().set_all( "g");
2✔
2298
    table.create_object().set_all( "G");
2✔
2299
    table.create_object().set_all( "ǵ");
2✔
2300
    table.create_object().set_all( "Ǵ");
2✔
2301
    table.create_object().set_all("ġ");
2✔
2302
    table.create_object().set_all("Ġ");
2✔
2303
    table.create_object().set_all( "ĝ");
2✔
2304
    table.create_object().set_all( "Ĝ");
2✔
2305
    table.create_object().set_all( "ǧ");
2✔
2306
    table.create_object().set_all( "Ǧ");
2✔
2307
    table.create_object().set_all("ğ");
2✔
2308
    table.create_object().set_all("Ğ");
2✔
2309
    table.create_object().set_all( "ģ");
2✔
2310
    table.create_object().set_all( "Ģ");
2✔
2311
    table.create_object().set_all( "ǥ");
2✔
2312
    table.create_object().set_all( "Ǥ");
2✔
2313
    table.create_object().set_all( "Ɠ");
2✔
2314
    table.create_object().set_all("Ɣ");
2✔
2315
    table.create_object().set_all( "h");
2✔
2316
    table.create_object().set_all( "H");
2✔
2317
    table.create_object().set_all( "ĥ");
2✔
2318
    table.create_object().set_all( "Ĥ");
2✔
2319
    table.create_object().set_all( "ȟ");
2✔
2320
    table.create_object().set_all( "Ȟ");
2✔
2321
    table.create_object().set_all( "ħ");
2✔
2322
    table.create_object().set_all( "Ħ");
2✔
2323
    table.create_object().set_all( "ƕ");
2✔
2324
    table.create_object().set_all( "Ƕ");
2✔
2325
    table.create_object().set_all( "i");
2✔
2326
    table.create_object().set_all( "I");
2✔
2327
    table.create_object().set_all("ı");
2✔
2328
    table.create_object().set_all( "í");
2✔
2329
    table.create_object().set_all( "Í");
2✔
2330
    table.create_object().set_all( "ì");
2✔
2331
    table.create_object().set_all( "Ì");
2✔
2332
    table.create_object().set_all("İ");
2✔
2333
    table.create_object().set_all( "î");
2✔
2334
    table.create_object().set_all("Î");
2✔
2335
    table.create_object().set_all( "ï");
2✔
2336
    table.create_object().set_all( "Ï");
2✔
2337
    table.create_object().set_all("ǐ");
2✔
2338
    table.create_object().set_all("Ǐ");
2✔
2339
    table.create_object().set_all("ĭ");
2✔
2340
    table.create_object().set_all("Ĭ");
2✔
2341
    table.create_object().set_all("ī");
2✔
2342
    table.create_object().set_all("Ī");
2✔
2343
    table.create_object().set_all( "ĩ");
2✔
2344
    table.create_object().set_all("Ĩ");
2✔
2345
    table.create_object().set_all( "į");
2✔
2346
    table.create_object().set_all( "Į");
2✔
2347
    table.create_object().set_all("Ɨ");
2✔
2348
    table.create_object().set_all( "ȉ");
2✔
2349
    table.create_object().set_all( "Ȉ");
2✔
2350
    table.create_object().set_all( "ȋ");
2✔
2351
    table.create_object().set_all( "Ȋ");
2✔
2352
    table.create_object().set_all("Ɩ");
2✔
2353
    table.create_object().set_all( "ij");
2✔
2354
    table.create_object().set_all("IJ");
2✔
2355
    table.create_object().set_all( "j");
2✔
2356
    table.create_object().set_all( "J");
2✔
2357
    table.create_object().set_all("ȷ");
2✔
2358
    table.create_object().set_all( "ĵ");
2✔
2359
    table.create_object().set_all( "Ĵ");
2✔
2360
    table.create_object().set_all("ǰ");
2✔
2361
    table.create_object().set_all( "ɉ");
2✔
2362
    table.create_object().set_all( "Ɉ");
2✔
2363
    table.create_object().set_all( "k");
2✔
2364
    table.create_object().set_all( "K");
2✔
2365
    table.create_object().set_all( "ǩ");
2✔
2366
    table.create_object().set_all( "Ǩ");
2✔
2367
    table.create_object().set_all( "ķ");
2✔
2368
    table.create_object().set_all( "Ķ");
2✔
2369
    table.create_object().set_all( "ƙ");
2✔
2370
    table.create_object().set_all( "Ƙ");
2✔
2371
    table.create_object().set_all("l");
2✔
2372
    table.create_object().set_all("L");
2✔
2373
    table.create_object().set_all( "ĺ");
2✔
2374
    table.create_object().set_all( "Ĺ");
2✔
2375
    table.create_object().set_all("ŀ");
2✔
2376
    table.create_object().set_all("Ŀ");
2✔
2377
    table.create_object().set_all( "ľ");
2✔
2378
    table.create_object().set_all( "Ľ");
2✔
2379
    table.create_object().set_all( "ļ");
2✔
2380
    table.create_object().set_all( "Ļ");
2✔
2381
    table.create_object().set_all("ƚ");
2✔
2382
    table.create_object().set_all("Ƚ");
2✔
2383
    table.create_object().set_all( "ł");
2✔
2384
    table.create_object().set_all( "Ł");
2✔
2385
    table.create_object().set_all("ƛ");
2✔
2386
    table.create_object().set_all( "lj");
2✔
2387
    table.create_object().set_all( "Lj");
2✔
2388
    table.create_object().set_all("LJ");
2✔
2389
    table.create_object().set_all("ȴ");
2✔
2390
    table.create_object().set_all( "m");
2✔
2391
    table.create_object().set_all( "M");
2✔
2392
    table.create_object().set_all("Ɯ");
2✔
2393
    table.create_object().set_all( "n");
2✔
2394
    table.create_object().set_all( "N");
2✔
2395
    table.create_object().set_all( "ń");
2✔
2396
    table.create_object().set_all( "Ń");
2✔
2397
    table.create_object().set_all( "ǹ");
2✔
2398
    table.create_object().set_all( "Ǹ");
2✔
2399
    table.create_object().set_all( "ň");
2✔
2400
    table.create_object().set_all( "Ň");
2✔
2401
    table.create_object().set_all( "ñ");
2✔
2402
    table.create_object().set_all( "Ñ");
2✔
2403
    table.create_object().set_all( "ņ");
2✔
2404
    table.create_object().set_all("Ņ");
2✔
2405
    table.create_object().set_all( "Ɲ");
2✔
2406
    table.create_object().set_all("ʼn");
2✔
2407
    table.create_object().set_all( "ƞ");
2✔
2408
    table.create_object().set_all( "Ƞ");
2✔
2409
    table.create_object().set_all("nj");
2✔
2410
    table.create_object().set_all("Nj");
2✔
2411
    table.create_object().set_all("NJ");
2✔
2412
    table.create_object().set_all( "ȵ");
2✔
2413
    table.create_object().set_all( "ŋ");
2✔
2414
    table.create_object().set_all( "Ŋ");
2✔
2415
    table.create_object().set_all( "o");
2✔
2416
    table.create_object().set_all( "O");
2✔
2417
    table.create_object().set_all( "º");
2✔
2418
    table.create_object().set_all( "ó");
2✔
2419
    table.create_object().set_all( "Ó");
2✔
2420
    table.create_object().set_all( "ò");
2✔
2421
    table.create_object().set_all( "Ò");
2✔
2422
    table.create_object().set_all("ȯ");
2✔
2423
    table.create_object().set_all("Ȯ");
2✔
2424
    table.create_object().set_all( "ô");
2✔
2425
    table.create_object().set_all( "Ô");
2✔
2426
    table.create_object().set_all( "ǒ");
2✔
2427
    table.create_object().set_all( "Ǒ");
2✔
2428
    table.create_object().set_all("ŏ");
2✔
2429
    table.create_object().set_all("Ŏ");
2✔
2430
    table.create_object().set_all("ō");
2✔
2431
    table.create_object().set_all("Ō");
2✔
2432
    table.create_object().set_all( "õ");
2✔
2433
    table.create_object().set_all( "Õ");
2✔
2434
    table.create_object().set_all("ǫ");
2✔
2435
    table.create_object().set_all("Ǫ");
2✔
2436
    table.create_object().set_all("Ɵ");
2✔
2437
    table.create_object().set_all( "ȱ");
2✔
2438
    table.create_object().set_all( "Ȱ");
2✔
2439
    table.create_object().set_all("ȫ");
2✔
2440
    table.create_object().set_all("Ȫ");
2✔
2441
    table.create_object().set_all( "ǿ");
2✔
2442
    table.create_object().set_all( "Ǿ");
2✔
2443
    table.create_object().set_all("ȭ");
2✔
2444
    table.create_object().set_all("Ȭ");
2✔
2445
    table.create_object().set_all( "ǭ");
2✔
2446
    table.create_object().set_all("Ǭ");
2✔
2447
    table.create_object().set_all( "ȍ");
2✔
2448
    table.create_object().set_all( "Ȍ");
2✔
2449
    table.create_object().set_all( "ȏ");
2✔
2450
    table.create_object().set_all( "Ȏ");
2✔
2451
    table.create_object().set_all( "ơ");
2✔
2452
    table.create_object().set_all( "Ơ");
2✔
2453
    table.create_object().set_all("ƣ");
2✔
2454
    table.create_object().set_all("Ƣ");
2✔
2455
    table.create_object().set_all( "œ");
2✔
2456
    table.create_object().set_all("Œ");
2✔
2457
    table.create_object().set_all( "ȣ");
2✔
2458
    table.create_object().set_all( "Ȣ");
2✔
2459
    table.create_object().set_all( "p");
2✔
2460
    table.create_object().set_all( "P");
2✔
2461
    table.create_object().set_all( "ƥ");
2✔
2462
    table.create_object().set_all( "Ƥ");
2✔
2463
    table.create_object().set_all( "q");
2✔
2464
    table.create_object().set_all( "Q");
2✔
2465
    table.create_object().set_all("ĸ");
2✔
2466
    table.create_object().set_all( "ɋ");
2✔
2467
    table.create_object().set_all( "Ɋ");
2✔
2468
    table.create_object().set_all("ȹ");
2✔
2469
    table.create_object().set_all( "r");
2✔
2470
    table.create_object().set_all( "R");
2✔
2471
    table.create_object().set_all("Ʀ");
2✔
2472
    table.create_object().set_all( "ŕ");
2✔
2473
    table.create_object().set_all( "Ŕ");
2✔
2474
    table.create_object().set_all( "ř");
2✔
2475
    table.create_object().set_all( "Ř");
2✔
2476
    table.create_object().set_all( "ŗ");
2✔
2477
    table.create_object().set_all( "Ŗ");
2✔
2478
    table.create_object().set_all("ɍ");
2✔
2479
    table.create_object().set_all("Ɍ");
2✔
2480
    table.create_object().set_all( "ȑ");
2✔
2481
    table.create_object().set_all( "Ȑ");
2✔
2482
    table.create_object().set_all( "ȓ");
2✔
2483
    table.create_object().set_all("Ȓ");
2✔
2484
    table.create_object().set_all( "s");
2✔
2485
    table.create_object().set_all( "S");
2✔
2486
    table.create_object().set_all( "ś");
2✔
2487
    table.create_object().set_all( "Ś");
2✔
2488
    table.create_object().set_all( "ŝ");
2✔
2489
    table.create_object().set_all( "Ŝ");
2✔
2490
    table.create_object().set_all( "š");
2✔
2491
    table.create_object().set_all( "Š");
2✔
2492
    table.create_object().set_all( "ş");
2✔
2493
    table.create_object().set_all( "Ş");
2✔
2494
    table.create_object().set_all( "ș");
2✔
2495
    table.create_object().set_all("Ș");
2✔
2496
    table.create_object().set_all( "ȿ");
2✔
2497
    table.create_object().set_all( "Ʃ");
2✔
2498
    table.create_object().set_all("ƨ");
2✔
2499
    table.create_object().set_all("Ƨ");
2✔
2500
    table.create_object().set_all( "ƪ");
2✔
2501
    table.create_object().set_all("ß");
2✔
2502
    table.create_object().set_all("ſ");
2✔
2503
    table.create_object().set_all( "t");
2✔
2504
    table.create_object().set_all( "T");
2✔
2505
    table.create_object().set_all( "ť");
2✔
2506
    table.create_object().set_all( "Ť");
2✔
2507
    table.create_object().set_all( "ţ");
2✔
2508
    table.create_object().set_all( "Ţ");
2✔
2509
    table.create_object().set_all( "ƭ");
2✔
2510
    table.create_object().set_all( "Ƭ");
2✔
2511
    table.create_object().set_all( "ƫ");
2✔
2512
    table.create_object().set_all( "Ʈ");
2✔
2513
    table.create_object().set_all( "ț");
2✔
2514
    table.create_object().set_all( "Ț");
2✔
2515
    table.create_object().set_all( "Ⱦ");
2✔
2516
    table.create_object().set_all( "ȶ");
2✔
2517
    table.create_object().set_all( "þ");
2✔
2518
    table.create_object().set_all( "Þ");
2✔
2519
    table.create_object().set_all( "ŧ");
2✔
2520
    table.create_object().set_all( "Ŧ");
2✔
2521
    table.create_object().set_all( "u");
2✔
2522
    table.create_object().set_all( "U");
2✔
2523
    table.create_object().set_all( "ú");
2✔
2524
    table.create_object().set_all( "Ú");
2✔
2525
    table.create_object().set_all( "ù");
2✔
2526
    table.create_object().set_all( "Ù");
2✔
2527
    table.create_object().set_all( "û");
2✔
2528
    table.create_object().set_all( "Û");
2✔
2529
    table.create_object().set_all( "ǔ");
2✔
2530
    table.create_object().set_all( "Ǔ");
2✔
2531
    table.create_object().set_all( "ŭ");
2✔
2532
    table.create_object().set_all( "Ŭ");
2✔
2533
    table.create_object().set_all( "ū");
2✔
2534
    table.create_object().set_all( "Ū");
2✔
2535
    table.create_object().set_all( "ũ");
2✔
2536
    table.create_object().set_all( "Ũ");
2✔
2537
    table.create_object().set_all( "ů");
2✔
2538
    table.create_object().set_all( "Ů");
2✔
2539
    table.create_object().set_all( "ų");
2✔
2540
    table.create_object().set_all( "Ų");
2✔
2541
    table.create_object().set_all( "Ʉ");
2✔
2542
    table.create_object().set_all( "ǘ");
2✔
2543
    table.create_object().set_all( "Ǘ");
2✔
2544
    table.create_object().set_all( "ǜ");
2✔
2545
    table.create_object().set_all( "Ǜ");
2✔
2546
    table.create_object().set_all( "ǚ");
2✔
2547
    table.create_object().set_all( "Ǚ");
2✔
2548
    table.create_object().set_all( "ǖ");
2✔
2549
    table.create_object().set_all( "Ǖ");
2✔
2550
    table.create_object().set_all( "ȕ");
2✔
2551
    table.create_object().set_all( "Ȕ");
2✔
2552
    table.create_object().set_all( "ȗ");
2✔
2553
    table.create_object().set_all( "Ȗ");
2✔
2554
    table.create_object().set_all( "ư");
2✔
2555
    table.create_object().set_all( "Ư");
2✔
2556
    table.create_object().set_all( "Ʊ");
2✔
2557
    table.create_object().set_all( "v");
2✔
2558
    table.create_object().set_all( "V");
2✔
2559
    table.create_object().set_all( "Ʋ");
2✔
2560
    table.create_object().set_all( "Ʌ");
2✔
2561
    table.create_object().set_all( "w");
2✔
2562
    table.create_object().set_all( "W");
2✔
2563
    table.create_object().set_all( "ŵ");
2✔
2564
    table.create_object().set_all( "Ŵ");
2✔
2565
    table.create_object().set_all( "ƿ");
2✔
2566
    table.create_object().set_all( "Ƿ");
2✔
2567
    table.create_object().set_all( "x");
2✔
2568
    table.create_object().set_all( "X");
2✔
2569
    table.create_object().set_all( "y");
2✔
2570
    table.create_object().set_all( "Y");
2✔
2571
    table.create_object().set_all( "ý");
2✔
2572
    table.create_object().set_all( "Ý");
2✔
2573
    table.create_object().set_all( "ŷ");
2✔
2574
    table.create_object().set_all( "Ŷ");
2✔
2575
    table.create_object().set_all( "ÿ");
2✔
2576
    table.create_object().set_all( "Ÿ");
2✔
2577
    table.create_object().set_all( "ȳ");
2✔
2578
    table.create_object().set_all( "Ȳ");
2✔
2579
    table.create_object().set_all( "ű");
2✔
2580
    table.create_object().set_all( "Ű");
2✔
2581
    table.create_object().set_all( "ɏ");
2✔
2582
    table.create_object().set_all( "Ɏ");
2✔
2583
    table.create_object().set_all( "ƴ");
2✔
2584
    table.create_object().set_all( "Ƴ");
2✔
2585
    table.create_object().set_all( "ü");
2✔
2586
    table.create_object().set_all( "Ü");
2✔
2587
    table.create_object().set_all( "z");
2✔
2588
    table.create_object().set_all( "Z");
2✔
2589
    table.create_object().set_all( "ź");
2✔
2590
    table.create_object().set_all( "Ź");
2✔
2591
    table.create_object().set_all( "ż");
2✔
2592
    table.create_object().set_all( "Ż");
2✔
2593
    table.create_object().set_all( "ž");
2✔
2594
    table.create_object().set_all( "Ž");
2✔
2595
    table.create_object().set_all( "ƶ");
2✔
2596
    table.create_object().set_all( "Ƶ");
2✔
2597
    table.create_object().set_all( "ȥ");
2✔
2598
    table.create_object().set_all( "Ȥ");
2✔
2599
    table.create_object().set_all( "ɀ");
2✔
2600
    table.create_object().set_all( "æ");
2✔
2601
    table.create_object().set_all( "Æ");
2✔
2602
    table.create_object().set_all( "Ʒ");
2✔
2603
    table.create_object().set_all( "ǣ");
2✔
2604
    table.create_object().set_all( "Ǣ");
2✔
2605
    table.create_object().set_all( "ä");
2✔
2606
    table.create_object().set_all( "Ä");
2✔
2607
    table.create_object().set_all( "ǯ");
2✔
2608
    table.create_object().set_all( "Ǯ");
1✔
2609
    table.create_object().set_all( "ƹ");
1✔
2610
    table.create_object().set_all( "Ƹ");
2✔
2611
    table.create_object().set_all( "ƺ");
2✔
2612
    table.create_object().set_all( "ø");
1✔
2613
    table.create_object().set_all( "Ø");
2✔
2614
    table.create_object().set_all( "ö");
1✔
2615
    table.create_object().set_all( "Ö");
1,052✔
2616
    table.create_object().set_all( "ő");
1,050✔
2617
    table.create_object().set_all( "Ő");
1,050✔
2618
    table.create_object().set_all( "å");
1✔
2619
    table.create_object().set_all( "Å");
1✔
2620
    table.create_object().set_all( "ƾ");
2✔
2621
    table.create_object().set_all( "ɂ");
2✔
2622
    table.create_object().set_all( "Ɂ");
2623

2624
    // Core-only is default comparer
2625
    TableView v1 = table.where().find_all();
2✔
2626
    TableView v2 = table.where().find_all();
1✔
2627

2✔
2628
    v2.sort(col);
2✔
2629

2✔
2630
    for (size_t t = 0; t < v1.size(); t++) {
2✔
2631
        CHECK_EQUAL(v1.get_object(t).get_key(), v2.get_object(t).get_key());
2✔
2632
    }
2✔
2633

2✔
2634
    // Set back to default in case other tests rely on this
2✔
2635
    set_string_compare_method(STRING_COMPARE_CORE, nullptr);
2✔
2636
}
2✔
2637

1✔
2638

2✔
2639
TEST(TableView_SortNull)
2✔
2640
{
2✔
2641
    // Verifies that NULL values will come first when sorting
2✔
2642
    Table table;
2✔
2643
    auto col_int = table.add_column(type_Int, "int", true);
2✔
2644
    auto col_bool = table.add_column(type_Bool, "bool", true);
2✔
2645
    auto col_float = table.add_column(type_Float, "float", true);
2✔
2646
    auto col_double = table.add_column(type_Double, "double", true);
18✔
2647
    auto col_str = table.add_column(type_String, "string", true);
18✔
2648
    auto col_date = table.add_column(type_Timestamp, "date", true);
18✔
2649
    auto col_oid = table.add_column(type_ObjectId, "oid", true);
18✔
2650
    auto col_decimal = table.add_column(type_Decimal, "decimal", true);
18✔
2651
    auto col_int2 = table.add_column(type_Int, "int2", true);
9✔
2652

18✔
2653
    std::vector<ObjKey> keys;
18✔
2654
    auto k = table.create_object()
18✔
2655
                 .set_all(1, false, 1.0f, 1.0, "1", Timestamp(1, 1), ObjectId("000000000000000000000001"),
18✔
2656
                          Decimal128("1"), 1)
1✔
2657
                 .get_key();
2✔
2658
    keys.push_back(k);
1✔
2659
    auto all_cols = table.get_column_keys();
2✔
2660
    int i = 0;
2✔
2661
    for (auto col : all_cols) {
1✔
2662
        Obj o = table.create_object();
2✔
2663
        std::string oid_init = "00000000000000000000000" + util::to_string(i);
2✔
2664
        o.set_all(int64_t(i), false, float(i), double(i), util::to_string(i), Timestamp(i, i),
1✔
2665
                  ObjectId(oid_init.c_str()), Decimal128(i), 1);
2✔
2666
        // Set one field to Null. This element must come first when sorting by this column
2✔
2667
        o.set_null(col);
1✔
2668
        keys.push_back(o.get_key());
2✔
2669
        i++;
2✔
2670
    }
2✔
2671

2✔
2672
    auto tv = table.where().find_all();
2✔
2673
    // Without sorting first object comes first
2✔
2674
    CHECK_EQUAL(tv.get_object(0).get_key(), keys[0]);
2✔
2675
    tv.sort(col_int);
2✔
2676
    // Now second element should come first
2✔
2677
    CHECK_EQUAL(tv.get_object(0).get_key(), keys[1]);
2✔
2678
    tv.sort(col_bool);
2✔
2679
    // Now third element should come first
2✔
2680
    CHECK_EQUAL(tv.get_object(0).get_key(), keys[2]);
2✔
2681
    tv.sort(col_float);
2✔
2682
    // etc.
2683
    CHECK_EQUAL(tv.get_object(0).get_key(), keys[3]);
2684
    tv.sort(col_double);
2685
    CHECK_EQUAL(tv.get_object(0).get_key(), keys[4]);
2✔
2686
    tv.sort(col_str);
2✔
2687
    CHECK_EQUAL(tv.get_object(0).get_key(), keys[5]);
2✔
2688
    tv.sort(col_date);
1✔
2689
    CHECK_EQUAL(tv.get_object(0).get_key(), keys[6]);
2✔
2690
    tv.sort(col_oid);
2✔
2691
    CHECK_EQUAL(tv.get_object(0).get_key(), keys[7]);
2✔
2692
    tv.sort(col_decimal);
1✔
2693
    CHECK_EQUAL(tv.get_object(0).get_key(), keys[8]);
2✔
2694
    tv.sort(col_int2);
2✔
2695
    CHECK_EQUAL(tv.get_object(0).get_key(), keys[9]);
1✔
2696
}
2✔
2697

2✔
2698
// Verify that copy-constructed and copy-assigned TableViews work normally.
2✔
2699
TEST(TableView_Copy)
1✔
2700
{
2✔
2701
    Table table;
2✔
2702
    auto col_id = table.add_column(type_Int, "id");
2✔
2703

1✔
2704
    table.create_object().set(col_id, -1);
2✔
2705
    ObjKey k1 = table.create_object().set(col_id, 1).get_key();
2✔
2706
    ObjKey k2 = table.create_object().set(col_id, 2).get_key();
2✔
2707

1✔
2708
    TableView tv = (table.column<Int>(col_id) > 0).find_all();
2✔
2709
    CHECK_EQUAL(2, tv.size());
1✔
2710

2✔
2711
    TableView copy_1(tv);
2✔
2712
    TableView copy_2;
1✔
2713
    copy_2 = tv;
2✔
2714

2✔
2715
    CHECK_EQUAL(2, copy_1.size());
2✔
2716
    CHECK_EQUAL(k1, copy_1.get_key(0));
1✔
2717
    CHECK_EQUAL(k2, copy_1.get_key(1));
2✔
2718

2✔
2719
    CHECK_EQUAL(2, copy_2.size());
2✔
2720
    CHECK_EQUAL(k1, copy_2.get_key(0));
2✔
2721
    CHECK_EQUAL(k2, copy_2.get_key(1));
2722

2723
    table.remove_object(k1);
2✔
2724

2✔
2725
    CHECK(!copy_1.is_in_sync());
2✔
2726
    CHECK(!copy_2.is_in_sync());
2✔
2727

2✔
2728
    copy_1.sync_if_needed();
22✔
2729
    CHECK_EQUAL(1, copy_1.size());
20✔
2730
    CHECK_EQUAL(k2, copy_1.get_key(0));
20✔
2731

1✔
2732
    copy_2.sync_if_needed();
2✔
2733
    CHECK_EQUAL(1, copy_2.size());
2✔
2734
    CHECK_EQUAL(k2, copy_2.get_key(0));
2✔
2735
}
2✔
2736

2✔
2737
TEST(TableView_RemoveColumnsAfterSort)
2✔
2738
{
1✔
2739
    Table table;
2✔
2740
    auto col_str0 = table.add_column(type_String, "0");
2✔
2741
    auto col_str1 = table.add_column(type_String, "1");
2✔
2742
    auto col_int = table.add_column(type_Int, "value");
2✔
2743
    for (int i = 0; i < 10; ++i) {
2✔
2744
        table.create_object().set(col_int, i);
2✔
2745
    }
2746

2747
    SortDescriptor desc({{col_int}}, {false}); // sort by the one column in descending order
2✔
2748
    table.create_object();
2✔
2749
    table.remove_column(col_str0);
2✔
2750
    auto tv = table.get_sorted_view(desc);
22✔
2751
    CHECK_EQUAL(tv.get_object(0).get<Int>(col_int), 9);
20✔
2752
    CHECK_EQUAL(tv.get_object(9).get<Int>(col_int), 0);
20✔
2753

1✔
2754
    table.remove_column(col_str1);
2✔
2755
    table.create_object();
2✔
2756
    tv.sync_if_needed();
2✔
2757
    CHECK_EQUAL(tv.get_object(0).get<Int>(col_int), 9);
1✔
2758
    CHECK_EQUAL(tv.get_object(10).get<Int>(col_int), 0);
2✔
2759
}
2✔
2760

2✔
2761
TEST(TableView_TimestampMaxRemoveRow)
1✔
2762
{
2✔
2763
    Table table;
2✔
2764
    auto col_date = table.add_column(type_Timestamp, "time");
2✔
2765
    for (size_t i = 0; i < 10; ++i) {
2✔
2766
        table.create_object().set(col_date, Timestamp(i, 0));
2767
    }
2768

2✔
2769
    TableView tv = table.where().find_all();
2✔
2770
    CHECK_EQUAL(tv.size(), 10);
2✔
2771
    CHECK_EQUAL(tv.max(col_date)->get_timestamp(), Timestamp(9, 0));
2✔
2772

2✔
2773
    table.remove_object(ObjKey(9));
2✔
2774
    CHECK_EQUAL(tv.size(), 10);                            // not changed since sync_if_needed hasn't been called
2✔
2775
    CHECK_EQUAL(tv.max(col_date)->get_timestamp(), Timestamp(8, 0)); // but aggregate functions skip removed rows
1✔
2776

2✔
2777
    tv.sync_if_needed();
2✔
2778
    CHECK_EQUAL(tv.size(), 9);
2✔
2779
    CHECK_EQUAL(tv.max(col_date)->get_timestamp(), Timestamp(8, 0));
2✔
2780
}
1✔
2781

1✔
2782
TEST(TableView_UpdateQuery)
2✔
2783
{
2✔
2784
    Table table;
2✔
2785
    auto col = table.add_column(type_Int, "first");
2✔
2786
    table.create_object().set(col, 1);
2✔
2787
    table.create_object().set(col, 2);
2✔
2788
    table.create_object().set(col, 3);
2789
    table.create_object().set(col, 3);
2790

2791
    Query q = table.where().equal(col, 1);
2792
    TableView v = q.find_all();
2793
    CHECK_EQUAL(1, v.size());
2794
    CHECK_EQUAL(1, v[0].get<Int>(col));
×
2795

×
2796
    // Create new query and update tableview to show this instead
×
2797
    Query q2 = table.where().equal(col, 3);
2798
    v.update_query(q2);
2✔
2799
    CHECK_EQUAL(2, v.size());
2✔
2800
    CHECK_EQUAL(3, v[0].get<Int>(col));
22✔
2801
    CHECK_EQUAL(3, v[1].get<Int>(col));
20✔
2802
}
20✔
2803

2✔
2804
class TestTableView : public TableView {
2805
public:
2806
    using TableView::TableView;
2807

2✔
2808
    KeyValues& get_keys()
2✔
2809
    {
2✔
2810
        return this->m_key_values;
2811
    }
2812
    void add_values()
2✔
2813
    {
2✔
2814
        m_key_values.create();
1✔
2815
        for (int i = 0; i < 10; i++) {
2✔
2816
            m_key_values.add(ObjKey(i));
1✔
2817
        }
2✔
2818
    }
2✔
2819
};
2✔
2820

1✔
2821
static TestTableView get_table_view(TestTableView val)
2✔
2822
{
2✔
2823
    return val;
2✔
2824
}
2✔
2825

2826
TEST(TableView_CopyKeyValues)
2827
{
2✔
2828
    TestTableView view;
2✔
2829

2✔
2830
    view.add_values();
2✔
2831

2✔
2832
    TestTableView another_view(view);
2✔
2833
    CHECK_EQUAL(another_view.size(), 10);
2✔
2834
    CHECK_EQUAL(another_view.get_key(0), ObjKey(0));
1✔
2835

20,000✔
2836
    TestTableView yet_another_view(get_table_view(view)); // Using move constructor
20,000✔
2837
    CHECK_EQUAL(yet_another_view.size(), 10);
20,000✔
2838
    CHECK_EQUAL(yet_another_view.get_key(0), ObjKey(0));
1✔
2839
}
2✔
2840

2✔
2841
TEST(TableView_SortFollowedByLimit)
2✔
2842
{
2✔
2843
    constexpr int limit = 100;
1✔
2844
    Table table;
2✔
2845
    auto col = table.add_column(type_Int, "first");
2✔
2846
    std::vector<int> values(10000);
2✔
2847
    std::iota(values.begin(), values.end(), 0);
1✔
2848
    std::shuffle(values.begin(), values.end(), std::mt19937(unit_test_random_seed));
2✔
2849

1✔
2850
    for (auto i : values) {
1✔
2851
        table.create_object().set(col, i);
2✔
2852
    }
202✔
2853

200✔
2854
    auto tv = table.where().find_all();
200✔
2855
    DescriptorOrdering ordering;
2✔
2856
    ordering.append_sort(SortDescriptor({{col}}));
2857
    ordering.append_limit(limit);
2858

2✔
2859
    auto t1 = steady_clock::now();
2✔
2860
    tv.apply_descriptor_ordering(ordering);
2✔
2861
    auto t2 = steady_clock::now();
1✔
2862

2✔
2863
    CHECK(t2 > t1);
2✔
2864
    // std::cout << duration_cast<microseconds>(t2 - t1).count() << " us" << std::endl;
2,002✔
2865

2,000✔
2866
    CHECK_EQUAL(tv.size(), limit);
2,000✔
2867
    for (int i = 0; i < limit; i++) {
20✔
2868
        CHECK_EQUAL(tv.get_object(i).get<Int>(col), i);
2,000✔
2869
    }
2✔
2870
}
1✔
2871

1✔
2872
TEST(TableView_Filter)
4,010✔
2873
{
4,010✔
2874
    Table table;
4,010✔
2875
    ColKey col = table.add_column(type_Int, "id");
1✔
2876

2✔
2877
    std::set<Int> keys;
2✔
2878
    {
2✔
2879
        for (int i = 1; i <= 1000; ++i) {
2✔
2880
            table.create_object().set(col, i);
22✔
2881
            if (i % 100 == 0)
20✔
2882
                keys.insert(i);
2✔
2883
        }
2✔
2884
    }
2✔
2885

2✔
2886
    // filtered by column 'val': 100, 200, 300... 1000
2✔
2887
    auto predicate = [&](const Obj& o) {
12✔
2888
        return keys.find(o.get<Int>(col)) != keys.end();
10✔
2889
    };
1✔
2890

1✔
2891
    { // Test single querty for multiple values
2✔
2892
        TableView v = table.where().find_all();
2✔
2893
        v.filter(FilterDescriptor(predicate));
12✔
2894
        CHECK_EQUAL(10, v.size());
10✔
2895
        for (size_t i = 0; i < 10; ++i)
1✔
2896
            CHECK_EQUAL((i + 1) * 100, v[i].get<Int>(col));
1✔
2897
    }
2✔
2898
    { // Combined with regular query and sort
2✔
2899
        TableView v = table.where().greater(col, 500).find_all();
12✔
2900
        v.filter(FilterDescriptor(predicate));
10✔
2901
        CHECK_EQUAL(5, v.size());
2✔
2902
        for (size_t i = 0; i < 5; ++i)
2✔
2903
            CHECK_EQUAL(600 + i * 100, v[i].get<Int>(col));
2✔
2904

2✔
2905
        // reverse the order: 1000, 900... 600
2✔
2906
        v.sort(col, false);
2✔
2907
        CHECK_EQUAL(5, v.size());
1✔
2908
        for (size_t i = 0; i < 5; ++i)
20,000✔
2909
            CHECK_EQUAL(1000 - i * 100, v[i].get<Int>(col));
20,000✔
2910

20,000✔
2911
        // update query: 500, 400... 100
1✔
2912
        v.update_query(table.where().less_equal(col, 500));
2✔
2913
        CHECK_EQUAL(5, v.size());
2✔
2914
        for (size_t i = 0; i < 5; ++i)
40,000✔
2915
            CHECK_EQUAL(500 - i * 100, v[i].get<Int>(col));
40,000✔
2916
    }
40,000✔
2917
    { // apply filter through DescriptorOrdering
2✔
2918
        table.clear();
2✔
2919
        std::vector<int> values(10000);
1✔
2920
        std::iota(values.begin(), values.end(), 0);
2✔
2921
        std::shuffle(values.begin(), values.end(), std::mt19937(unit_test_random_seed));
2✔
2922

2✔
2923
        for (auto i : values) {
2✔
2924
            table.create_object().set(col, i);
2✔
2925
        }
2926

2927
        TableView tv(table.where(), size_t(-1));
2928
        DescriptorOrdering ordering;
2929
        ordering.append_filter(FilterDescriptor([&](const Obj& obj) {
2930
            return obj.get<Int>(col) < 100;
2931
        }));
2932
        tv.apply_descriptor_ordering(ordering);
2933
        CHECK_EQUAL(tv.size(), 100);
2934

2935
        ordering.append_limit(LimitDescriptor(50));
2936
        tv.apply_descriptor_ordering(ordering);
2937
        CHECK_EQUAL(tv.size(), 50);
2938
    }
2939
}
2940

2941
#endif // TEST_TABLE_VIEW
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