Coverage Report

Created: 2024-02-20 21:15

/builds/xfbs/cindy/src/database/tests.rs
Line
Count
Source (jump to first uncovered line)
1
use super::*;
2
use crate::tag::{TagFilter, TagPredicate, TagValueInfo};
3
use cindy_common::{Point, Rectangle, Sequence};
4
use proptest::prelude::*;
5
6
1
#[test]
7
1
fn test_migrate() {
8
1
    let database = Database(Connection::open_in_memory().unwrap());
9
1
    database.migrate().unwrap();
10
1
}
11
12
1
#[test]
13
1
fn can_manage_files() {
14
1
    let database = Database(Connection::open_in_memory().unwrap());
15
1
    database.migrate().unwrap();
16
1
    let hash = Hash::new(&[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]);
17
1
    database.hash_add(&hash).unwrap();
18
1
    database.hash_remove(&hash).unwrap();
19
1
}
20
21
1
#[test]
22
1
fn tags_initially_empty() {
23
1
    let database = Database(Connection::open_in_memory().unwrap());
24
1
    database.migrate().unwrap();
25
1
26
1
    // no tags initially
27
1
    let list = database.tag_list(None, None).unwrap();
28
1
    assert_eq!(list, [].into());
29
1
}
30
31
1
#[test]
32
1
fn can_tags_list_all_one() {
33
1
    let database = Database(Connection::open_in_memory().unwrap());
34
1
    database.migrate().unwrap();
35
1
36
1
    // add tags
37
1
    database.tag_name_create("test", None).unwrap();
38
1
    database.tag_value_create("test", "label").unwrap();
39
1
40
1
    // get all tags
41
1
    let list = database.tag_list(None, None).unwrap();
42
1
    assert_eq!(
43
1
        list[&Tag::new("test".into(), "label".into())],
44
1
        TagValueInfo {
45
1
            files: 0,
46
1
            display: "label".into(),
47
1
            system: false,
48
1
        }
49
1
    );
50
1
}
51
52
1
#[test]
53
1
fn can_tags_value_set_display() {
54
1
    let database = Database(Connection::open_in_memory().unwrap());
55
1
    database.migrate().unwrap();
56
1
57
1
    // add tags
58
1
    database.tag_name_create("test", None).unwrap();
59
1
    database.tag_value_create("test", "label").unwrap();
60
1
    database
61
1
        .tag_value_display("test", "label", "Label Name")
62
1
        .unwrap();
63
1
64
1
    // get all tags
65
1
    let list = database.tag_list(None, None).unwrap();
66
1
    assert_eq!(
67
1
        list[&Tag::new("test".into(), "label".into())],
68
1
        TagValueInfo {
69
1
            files: 0,
70
1
            display: "Label Name".into(),
71
1
            system: false,
72
1
        }
73
1
    );
74
1
}
75
76
1
#[test]
77
1
fn can_tags_list_all_multiple() {
78
1
    let database = Database(Connection::open_in_memory().unwrap());
79
1
    database.migrate().unwrap();
80
1
81
1
    // add tag names
82
1
    database.tag_name_create("test", None).unwrap();
83
1
    database.tag_name_create("name", None).unwrap();
84
1
85
1
    // add tags
86
1
    database.tag_value_create("test", "label").unwrap();
87
1
    database.tag_value_create("test", "other").unwrap();
88
1
    database.tag_value_create("name", "zero").unwrap();
89
1
    database.tag_value_create("name", "other").unwrap();
90
1
91
1
    // get all tags
92
1
    let list = database.tag_list(None, None).unwrap();
93
1
    assert_eq!(list.len(), 4);
94
1
    assert_eq!(
95
1
        list[&Tag::new("test".into(), "label".into())],
96
1
        TagValueInfo {
97
1
            files: 0,
98
1
            display: "label".into(),
99
1
            system: false,
100
1
        }
101
1
    );
102
1
    assert_eq!(
103
1
        list[&Tag::new("test".into(), "other".into())],
104
1
        TagValueInfo {
105
1
            files: 0,
106
1
            display: "other".into(),
107
1
            system: false,
108
1
        }
109
1
    );
110
1
    assert_eq!(
111
1
        list[&Tag::new("name".into(), "zero".into())],
112
1
        TagValueInfo {
113
1
            files: 0,
114
1
            display: "zero".into(),
115
1
            system: false,
116
1
        }
117
1
    );
118
1
    assert_eq!(
119
1
        list[&Tag::new("name".into(), "other".into())],
120
1
        TagValueInfo {
121
1
            files: 0,
122
1
            display: "other".into(),
123
1
            system: false,
124
1
        }
125
1
    );
126
1
}
127
128
1
#[test]
129
1
fn can_tags_set_display_multiple() {
130
1
    let database = Database(Connection::open_in_memory().unwrap());
131
1
    database.migrate().unwrap();
132
1
133
1
    // add tag names
134
1
    database.tag_name_create("test", None).unwrap();
135
1
    database.tag_name_create("name", None).unwrap();
136
1
137
1
    // add tags
138
1
    database.tag_value_create("test", "label").unwrap();
139
1
    database.tag_value_create("test", "other").unwrap();
140
1
    database.tag_value_create("name", "zero").unwrap();
141
1
    database.tag_value_create("name", "other").unwrap();
142
1
143
1
    // set display
144
1
    database
145
1
        .tag_value_display("test", "label", "Test Label")
146
1
        .unwrap();
147
1
    database
148
1
        .tag_value_display("test", "other", "Test Other")
149
1
        .unwrap();
150
1
    database
151
1
        .tag_value_display("name", "zero", "Name Zero")
152
1
        .unwrap();
153
1
    database
154
1
        .tag_value_display("name", "other", "Name Other")
155
1
        .unwrap();
156
1
157
1
    // get all tags
158
1
    let list = database.tag_list(None, None).unwrap();
159
1
    assert_eq!(list.len(), 4);
160
1
    assert_eq!(
161
1
        list[&Tag::new("test".into(), "label".into())],
162
1
        TagValueInfo {
163
1
            files: 0,
164
1
            display: "Test Label".into(),
165
1
            system: false,
166
1
        }
167
1
    );
168
1
    assert_eq!(
169
1
        list[&Tag::new("test".into(), "other".into())],
170
1
        TagValueInfo {
171
1
            files: 0,
172
1
            display: "Test Other".into(),
173
1
            system: false,
174
1
        }
175
1
    );
176
1
    assert_eq!(
177
1
        list[&Tag::new("name".into(), "zero".into())],
178
1
        TagValueInfo {
179
1
            files: 0,
180
1
            display: "Name Zero".into(),
181
1
            system: false,
182
1
        }
183
1
    );
184
1
    assert_eq!(
185
1
        list[&Tag::new("name".into(), "other".into())],
186
1
        TagValueInfo {
187
1
            files: 0,
188
1
            display: "Name Other".into(),
189
1
            system: false,
190
1
        }
191
1
    );
192
1
}
193
194
1
#[test]
195
1
fn can_tags_list_by_name() {
196
1
    let database = Database(Connection::open_in_memory().unwrap());
197
1
    database.migrate().unwrap();
198
1
199
1
    // add tag names
200
1
    database.tag_name_create("test", None).unwrap();
201
1
    database.tag_name_create("foo", None).unwrap();
202
1
203
1
    // add tags
204
1
    database.tag_value_create("test", "label").unwrap();
205
1
    database.tag_value_create("test", "other").unwrap();
206
1
    database.tag_value_create("foo", "zero").unwrap();
207
1
    database.tag_value_create("foo", "other").unwrap();
208
1
209
1
    // list by name
210
1
    let list = database.tag_list(Some("test"), None).unwrap();
211
1
    assert_eq!(list.len(), 2);
212
1
    assert!(list.contains_key(&Tag::new("test".into(), "label".into())));
213
1
    assert!(list.contains_key(&Tag::new("test".into(), "other".into())));
214
1
}
215
216
1
#[test]
217
1
fn can_tags_list_by_value() {
218
1
    let database = Database(Connection::open_in_memory().unwrap());
219
1
    database.migrate().unwrap();
220
1
221
1
    // add tag names
222
1
    database.tag_name_create("test", None).unwrap();
223
1
    database.tag_name_create("foo", None).unwrap();
224
1
225
1
    // add tags
226
1
    database.tag_value_create("test", "label").unwrap();
227
1
    database.tag_value_create("test", "other").unwrap();
228
1
    database.tag_value_create("foo", "zero").unwrap();
229
1
    database.tag_value_create("foo", "other").unwrap();
230
1
231
1
    // list by value
232
1
    let list = database.tag_list(None, Some("other")).unwrap();
233
1
    assert_eq!(list.len(), 2);
234
1
    assert!(list.contains_key(&Tag::new("test".into(), "other".into())));
235
1
    assert!(list.contains_key(&Tag::new("foo".into(), "other".into())));
236
1
}
237
238
1
#[test]
239
1
fn can_tags_rename_by_name() {
240
1
    let database = Database(Connection::open_in_memory().unwrap());
241
1
    database.migrate().unwrap();
242
1
243
1
    // add tag names
244
1
    database.tag_name_create("test", None).unwrap();
245
1
    database.tag_name_create("bar", None).unwrap();
246
1
247
1
    // add tags
248
1
    database.tag_value_create("test", "label").unwrap();
249
1
    database.tag_value_create("test", "other").unwrap();
250
1
    database.tag_value_create("bar", "zero").unwrap();
251
1
    database.tag_value_create("bar", "other").unwrap();
252
1
253
1
    // rename test to foorbar
254
1
    database.tag_name_rename("test", "foo").unwrap();
255
1
256
1
    // get all tags
257
1
    let list = database.tag_list(None, None).unwrap();
258
1
    assert_eq!(list.len(), 4);
259
1
    assert!(list.contains_key(&Tag::new("foo".into(), "label".into())));
260
1
    assert!(list.contains_key(&Tag::new("foo".into(), "other".into())));
261
1
    assert!(list.contains_key(&Tag::new("bar".into(), "zero".into())));
262
1
    assert!(list.contains_key(&Tag::new("bar".into(), "other".into())));
263
1
}
264
265
1
#[test]
266
1
fn can_tags_rename_by_value() {
267
1
    let database = Database(Connection::open_in_memory().unwrap());
268
1
    database.migrate().unwrap();
269
1
270
1
    // add tag names
271
1
    database.tag_name_create("foo", None).unwrap();
272
1
    database.tag_name_create("bar", None).unwrap();
273
1
274
1
    // add tags
275
1
    database.tag_value_create("foo", "label").unwrap();
276
1
    database.tag_value_create("foo", "other").unwrap();
277
1
    database.tag_value_create("bar", "zero").unwrap();
278
1
    database.tag_value_create("bar", "other").unwrap();
279
1
280
1
    // rename test to foorbar
281
1
    database.tag_value_rename("bar", "other", "new").unwrap();
282
1
283
1
    // get all tags
284
1
    let list = database.tag_list(None, None).unwrap();
285
1
    assert_eq!(list.len(), 4);
286
1
    assert!(list.contains_key(&Tag::new("foo".into(), "label".into())));
287
1
    assert!(list.contains_key(&Tag::new("foo".into(), "other".into())));
288
1
    assert!(list.contains_key(&Tag::new("bar".into(), "zero".into())));
289
1
    assert!(list.contains_key(&Tag::new("bar".into(), "new".into())));
290
1
}
291
292
1
#[test]
293
1
fn can_tags_delete_all() {
294
1
    let database = Database(Connection::open_in_memory().unwrap());
295
1
    database.migrate().unwrap();
296
1
297
1
    // add tags
298
1
    database.tag_value_create("test", "label").unwrap();
299
1
    database.tag_value_create("test", "other").unwrap();
300
1
    database.tag_value_create("value", "zero").unwrap();
301
1
    database.tag_value_create("value", "other").unwrap();
302
1
303
1
    database.tag_delete(None, None).unwrap();
304
1
305
1
    // get all tags
306
1
    let list = database.tag_list(None, None).unwrap();
307
1
    assert_eq!(list, [].into());
308
1
}
309
310
1
#[test]
311
1
fn can_tags_delete_by_name() {
312
1
    let database = Database(Connection::open_in_memory().unwrap());
313
1
    database.migrate().unwrap();
314
1
315
1
    // add tag names
316
1
    database.tag_name_create("test", None).unwrap();
317
1
    database.tag_name_create("value", None).unwrap();
318
1
319
1
    // add tags values
320
1
    database.tag_value_create("test", "label").unwrap();
321
1
    database.tag_value_create("test", "other").unwrap();
322
1
    database.tag_value_create("value", "zero").unwrap();
323
1
    database.tag_value_create("value", "other").unwrap();
324
1
325
1
    // delete tag
326
1
    database.tag_delete(Some("test"), None).unwrap();
327
1
328
1
    // get all tags
329
1
    let list = database.tag_list(None, None).unwrap();
330
1
    assert_eq!(list.len(), 2);
331
1
    assert!(list.contains_key(&Tag::new("value".into(), "zero".into())));
332
1
    assert!(list.contains_key(&Tag::new("value".into(), "other".into())));
333
1
}
334
335
1
#[test]
336
1
fn can_tags_delete_by_value() {
337
1
    let database = Database(Connection::open_in_memory().unwrap());
338
1
    database.migrate().unwrap();
339
1
340
1
    // add tag names
341
1
    database.tag_name_create("test", None).unwrap();
342
1
    database.tag_name_create("value", None).unwrap();
343
1
344
1
    // add tags
345
1
    database.tag_value_create("test", "label").unwrap();
346
1
    database.tag_value_create("test", "other").unwrap();
347
1
    database.tag_value_create("value", "zero").unwrap();
348
1
    database.tag_value_create("value", "other").unwrap();
349
1
350
1
    // delete tags by value
351
1
    database.tag_delete(None, Some("other")).unwrap();
352
1
353
1
    // get all tags
354
1
    let list = database.tag_list(None, None).unwrap();
355
1
    assert_eq!(list.len(), 2);
356
1
    assert!(list.contains_key(&Tag::new("value".into(), "zero".into())));
357
1
    assert!(list.contains_key(&Tag::new("test".into(), "label".into())));
358
1
}
359
360
1
#[test]
361
1
fn can_manage_file_tags() {
362
1
    let database = Database(Connection::open_in_memory().unwrap());
363
1
    database.migrate().unwrap();
364
1
    let hash1 = Hash::new(&[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]);
365
1
    let hash2 = Hash::new(&[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0x01]);
366
1
    database.hash_add(&hash1).unwrap();
367
1
    database.hash_add(&hash2).unwrap();
368
1
    database.tag_name_create("name", None).unwrap();
369
1
    database.tag_value_create("name", "value").unwrap();
370
1
    database.tag_value_create("name", "other").unwrap();
371
1
    database.hash_tag_add(&hash1, "name", "value").unwrap();
372
1
    let tags = database.hash_tags(&hash1, None, None).unwrap();
373
1
    assert_eq!(tags, [Tag::new("name".into(), "value".into()),].into());
374
1
    assert_eq!(database.hash_tags(&hash2, None, None).unwrap(), [].into());
375
1
}
376
377
1
#[test]
378
1
fn can_delete_file_tags_all() {
379
1
    let database = Database(Connection::open_in_memory().unwrap());
380
1
    database.migrate().unwrap();
381
1
    let hash1 = Hash::new(&[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]);
382
1
    database.hash_add(&hash1).unwrap();
383
1
    database.tag_name_create("name", None).unwrap();
384
1
    database.tag_name_create("other", None).unwrap();
385
1
    database.tag_value_create("name", "value").unwrap();
386
1
    database.tag_value_create("name", "other").unwrap();
387
1
    database.tag_value_create("other", "value").unwrap();
388
1
    database.tag_value_create("other", "that").unwrap();
389
1
    database.hash_tag_add(&hash1, "name", "value").unwrap();
390
1
    database.hash_tag_add(&hash1, "other", "value").unwrap();
391
1
    database.hash_tag_add(&hash1, "other", "that").unwrap();
392
1
    database.hash_tag_remove(&hash1, None, None).unwrap();
393
1
    let tags = database.hash_tags(&hash1, None, None).unwrap();
394
1
    assert_eq!(tags, [].into());
395
1
}
396
397
1
#[test]
398
1
fn can_delete_file_tags_name() {
399
1
    let database = Database(Connection::open_in_memory().unwrap());
400
1
    database.migrate().unwrap();
401
1
    let hash1 = Hash::new(&[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]);
402
1
    database.hash_add(&hash1).unwrap();
403
1
    database.tag_name_create("name", None).unwrap();
404
1
    database.tag_name_create("other", None).unwrap();
405
1
    database.tag_value_create("name", "value").unwrap();
406
1
    database.tag_value_create("name", "other").unwrap();
407
1
    database.tag_value_create("other", "value").unwrap();
408
1
    database.tag_value_create("other", "that").unwrap();
409
1
    database.hash_tag_add(&hash1, "name", "value").unwrap();
410
1
    database.hash_tag_add(&hash1, "other", "value").unwrap();
411
1
    database.hash_tag_add(&hash1, "other", "that").unwrap();
412
1
    database
413
1
        .hash_tag_remove(&hash1, Some("name"), None)
414
1
        .unwrap();
415
1
    let list = database.hash_tags(&hash1, None, None).unwrap();
416
1
    assert_eq!(
417
1
        list,
418
1
        [
419
1
            Tag::new("other".into(), "value".into()),
420
1
            Tag::new("other".into(), "that".into()),
421
1
        ]
422
1
        .into()
423
1
    );
424
1
    database
425
1
        .hash_tag_remove(&hash1, Some("other"), None)
426
1
        .unwrap();
427
1
    assert_eq!(database.hash_tags(&hash1, None, None).unwrap(), [].into());
428
1
}
429
430
1
#[test]
431
1
fn can_delete_file_tags_individual() {
432
1
    let database = Database(Connection::open_in_memory().unwrap());
433
1
    database.migrate().unwrap();
434
1
    let hash1 = Hash::new(&[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]);
435
1
    database.hash_add(&hash1).unwrap();
436
1
    database.tag_name_create("name", None).unwrap();
437
1
    database.tag_name_create("other", None).unwrap();
438
1
    database.tag_value_create("name", "value").unwrap();
439
1
    database.tag_value_create("name", "other").unwrap();
440
1
    database.tag_value_create("other", "value").unwrap();
441
1
    database.tag_value_create("other", "that").unwrap();
442
1
    database.hash_tag_add(&hash1, "name", "value").unwrap();
443
1
    database.hash_tag_add(&hash1, "other", "value").unwrap();
444
1
    database.hash_tag_add(&hash1, "other", "that").unwrap();
445
1
    database
446
1
        .hash_tag_remove(&hash1, Some("other"), Some("value"))
447
1
        .unwrap();
448
1
    let list = database.hash_tags(&hash1, None, None).unwrap();
449
1
    assert_eq!(
450
1
        list,
451
1
        [
452
1
            Tag::new("name".into(), "value".into()),
453
1
            Tag::new("other".into(), "that".into())
454
1
        ]
455
1
        .into()
456
1
    );
457
1
    database
458
1
        .hash_tag_remove(&hash1, Some("name"), Some("value"))
459
1
        .unwrap();
460
1
    let list = database.hash_tags(&hash1, None, None).unwrap();
461
1
    assert_eq!(list, [Tag::new("other".into(), "that".into())].into());
462
1
    database
463
1
        .hash_tag_remove(&hash1, Some("other"), Some("that"))
464
1
        .unwrap();
465
1
    assert_eq!(database.hash_tags(&hash1, None, None).unwrap(), [].into());
466
1
}
467
468
1
#[test]
469
1
fn empty_query_list_returns_all() {
470
1
    let database = Database(Connection::open_in_memory().unwrap());
471
1
    database.migrate().unwrap();
472
1
    let hash1 = Hash::new(&[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]);
473
1
    let hash2 = Hash::new(&[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0x04]);
474
1
    database.hash_add(&hash1).unwrap();
475
1
    database.hash_add(&hash2).unwrap();
476
1
477
1
    let hashes = database.query_hashes(&mut [].iter()).unwrap();
478
1
    assert_eq!(hashes, [hash1.into(), hash2.into()].into());
479
1
}
480
481
1
#[test]
482
1
fn can_query_files_by_tag_name() {
483
1
    let database = Database(Connection::open_in_memory().unwrap());
484
1
    database.migrate().unwrap();
485
1
    let hash1 = Hash::new(&[0x01]);
486
1
    let hash2 = Hash::new(&[0x02]);
487
1
    let hash3 = Hash::new(&[0x03]);
488
1
    database.hash_add(&hash1).unwrap();
489
1
    database.hash_add(&hash2).unwrap();
490
1
    database.hash_add(&hash3).unwrap();
491
1
    database.tag_name_create("a", None).unwrap();
492
1
    database.tag_name_create("b", None).unwrap();
493
1
    database.tag_value_create("a", "value").unwrap();
494
1
    database.tag_value_create("b", "value").unwrap();
495
1
    database.hash_tag_add(&hash1, "a", "value").unwrap();
496
1
    database.hash_tag_add(&hash2, "b", "value").unwrap();
497
1
    database.hash_tag_add(&hash3, "a", "value").unwrap();
498
1
    database.hash_tag_add(&hash3, "b", "value").unwrap();
499
1
500
1
    let hashes = database
501
1
        .query_hashes(&mut [TagPredicate::Exists(TagFilter::new(Some("a"), None))].iter())
502
1
        .unwrap();
503
1
    assert_eq!(hashes, [hash1.into(), hash3.into()].into());
504
505
1
    let hashes = database
506
1
        .query_hashes(&mut [TagPredicate::Exists(TagFilter::new(Some("b"), None))].iter())
507
1
        .unwrap();
508
1
    assert_eq!(hashes, [hash2.into(), hash3.into()].into());
509
510
1
    let hashes = database
511
1
        .query_hashes(
512
1
            &mut [
513
1
                TagPredicate::Exists(TagFilter::new(Some("a"), None)),
514
1
                TagPredicate::Exists(TagFilter::new(Some("b"), None)),
515
1
            ]
516
1
            .iter(),
517
1
        )
518
1
        .unwrap();
519
1
    assert_eq!(hashes, [hash3.into()].into());
520
521
1
    let hashes = database
522
1
        .query_hashes(
523
1
            &mut [
524
1
                TagPredicate::Exists(TagFilter::new(Some("a"), None)),
525
1
                TagPredicate::Missing(TagFilter::new(Some("b"), None)),
526
1
            ]
527
1
            .iter(),
528
1
        )
529
1
        .unwrap();
530
1
    assert_eq!(hashes, [hash1.into()].into());
531
532
1
    let hashes = database
533
1
        .query_hashes(
534
1
            &mut [
535
1
                TagPredicate::Missing(TagFilter::new(Some("a"), None)),
536
1
                TagPredicate::Exists(TagFilter::new(Some("b"), None)),
537
1
            ]
538
1
            .iter(),
539
1
        )
540
1
        .unwrap();
541
1
    assert_eq!(hashes, [hash2.into()].into());
542
1
}
543
544
1
#[test]
545
1
fn can_query_files_by_tag_name_value() {
546
1
    let database = Database(Connection::open_in_memory().unwrap());
547
1
    database.migrate().unwrap();
548
1
    let hash1 = Hash::new(&[0x01]);
549
1
    let hash2 = Hash::new(&[0x02]);
550
1
    database.hash_add(&hash1).unwrap();
551
1
    database.hash_add(&hash2).unwrap();
552
1
    database.tag_name_create("name", None).unwrap();
553
1
    database.tag_value_create("name", "a").unwrap();
554
1
    database.tag_value_create("name", "b").unwrap();
555
1
    database.tag_value_create("name", "c").unwrap();
556
1
    database.hash_tag_add(&hash1, "name", "a").unwrap();
557
1
    database.hash_tag_add(&hash1, "name", "b").unwrap();
558
1
    database.hash_tag_add(&hash2, "name", "b").unwrap();
559
1
    database.hash_tag_add(&hash2, "name", "c").unwrap();
560
1
561
1
    let hashes = database
562
1
        .query_hashes(
563
1
            &mut [TagPredicate::Exists(TagFilter::new(
564
1
                Some("name"),
565
1
                Some("a"),
566
1
            ))]
567
1
            .iter(),
568
1
        )
569
1
        .unwrap();
570
1
    assert_eq!(hashes, [hash1.into()].into());
571
572
1
    let hashes = database
573
1
        .query_hashes(
574
1
            &mut [TagPredicate::Exists(TagFilter::new(
575
1
                Some("name"),
576
1
                Some("b"),
577
1
            ))]
578
1
            .iter(),
579
1
        )
580
1
        .unwrap();
581
1
    assert_eq!(hashes, [hash1.into(), hash2.into()].into());
582
583
1
    let hashes = database
584
1
        .query_hashes(
585
1
            &mut [TagPredicate::Exists(TagFilter::new(
586
1
                Some("name"),
587
1
                Some("c"),
588
1
            ))]
589
1
            .iter(),
590
1
        )
591
1
        .unwrap();
592
1
    assert_eq!(hashes, [hash2.into()].into());
593
594
1
    let hashes = database
595
1
        .query_hashes(
596
1
            &mut [
597
1
                TagPredicate::Exists(TagFilter::new(Some("name"), Some("a"))),
598
1
                TagPredicate::Exists(TagFilter::new(Some("name"), Some("b"))),
599
1
            ]
600
1
            .iter(),
601
1
        )
602
1
        .unwrap();
603
1
    assert_eq!(hashes, [hash1.into()].into());
604
605
1
    let hashes = database
606
1
        .query_hashes(
607
1
            &mut [
608
1
                TagPredicate::Exists(TagFilter::new(Some("name"), Some("b"))),
609
1
                TagPredicate::Exists(TagFilter::new(Some("name"), Some("c"))),
610
1
            ]
611
1
            .iter(),
612
1
        )
613
1
        .unwrap();
614
1
    assert_eq!(hashes, [hash2.into()].into());
615
616
1
    let hashes = database
617
1
        .query_hashes(
618
1
            &mut [
619
1
                TagPredicate::Exists(TagFilter::new(Some("name"), Some("a"))),
620
1
                TagPredicate::Exists(TagFilter::new(Some("name"), Some("b"))),
621
1
                TagPredicate::Exists(TagFilter::new(Some("name"), Some("c"))),
622
1
            ]
623
1
            .iter(),
624
1
        )
625
1
        .unwrap();
626
1
    assert_eq!(hashes, [].into());
627
628
1
    let hashes = database
629
1
        .query_hashes(
630
1
            &mut [TagPredicate::Missing(TagFilter::new(
631
1
                Some("name"),
632
1
                Some("b"),
633
1
            ))]
634
1
            .iter(),
635
1
        )
636
1
        .unwrap();
637
1
    assert_eq!(hashes, [].into());
638
639
1
    let hashes = database
640
1
        .query_hashes(
641
1
            &mut [TagPredicate::Missing(TagFilter::new(
642
1
                Some("name"),
643
1
                Some("a"),
644
1
            ))]
645
1
            .iter(),
646
1
        )
647
1
        .unwrap();
648
1
    assert_eq!(hashes, [hash2.into()].into());
649
1
}
650
651
1
#[test]
652
1
fn stress_test() {
653
1
    let database = Database(Connection::open_in_memory().unwrap());
654
1
    database.migrate().unwrap();
655
1
    //let transaction = database.transaction().unwrap();
656
1
    // create hashes
657
1
    let hash = (0..10000)
658
10.0k
        .map(|i| format!("{i}").into_bytes())
659
1
        .collect::<Vec<_>>();
660
10.0k
    for hash in hash.
iter()1
{
661
10.0k
        database.hash_add(Hash::new(&hash)).unwrap();
662
10.0k
    }
663
1
    let tags = [("a", 5), ("b", 7), ("c", 13)]
664
1
        .into_iter()
665
3
        .map(|(name, values)| {
666
3
            (
667
3
                name,
668
3
                (0..values)
669
25
                    .map(|v| format!("value-{v}"))
670
3
                    .collect::<Vec<_>>(),
671
3
            )
672
3
        })
673
1
        .collect::<Vec<_>>();
674
3
    for (name, values) in tags.
iter()1
{
675
3
        database.tag_name_create(name, None).unwrap();
676
25
        for value in values.
iter()3
{
677
25
            database.tag_value_create(name, &value).unwrap();
678
25
        }
679
30.0k
        for (hash, value) in 
hash.iter().zip(values.iter().cycle())3
{
680
30.0k
            database
681
30.0k
                .hash_tag_add(Hash::new(&hash), &name, &value)
682
30.0k
                .unwrap();
683
30.0k
        }
684
    }
685
1
    let hashes = database.query_hashes(&mut [].iter()).unwrap();
686
1
    assert_eq!(hashes.len(), hash.len());
687
688
3
    for (name, values) in tags.
iter()1
{
689
3
        let hashes = database
690
3
            .query_hashes(
691
3
                &mut [TagPredicate::Exists(TagFilter::new(
692
3
                    Some(*name),
693
3
                    Some(&values[0]),
694
3
                ))]
695
3
                .iter(),
696
3
            )
697
3
            .unwrap();
698
3
        assert_eq!(
699
3
            hashes,
700
3
            hash.iter()
701
3
                .step_by(values.len())
702
4.19k
                .map(|v| Box::<[u8]>::from(v[..].to_vec()))
703
3
                .map(BoxHash::from)
704
3
                .collect()
705
3
        );
706
    }
707
708
1
    let _hashes = database
709
1
        .query_hashes(&mut [TagPredicate::Exists(TagFilter::new(None, Some("value-3")))].iter())
710
1
        .unwrap();
711
1
}
712
713
1
#[test]
714
1
fn can_label_add_rect() {
715
1
    let database = Database(Connection::open_in_memory().unwrap());
716
1
    database.migrate().unwrap();
717
1
    let hash = Hash::new(&[0x01]);
718
1
    database.hash_add(&hash).unwrap();
719
1
    database.tag_name_create("name", None).unwrap();
720
1
    database.tag_value_create("name", "value").unwrap();
721
1
    database.hash_tag_add(&hash, "name", "value").unwrap();
722
1
    database
723
1
        .label_add(
724
1
            &hash,
725
1
            "name",
726
1
            "value",
727
1
            &Rectangle {
728
1
                start: Point::new(0, 0),
729
1
                end: Point::new(64, 64),
730
1
            }
731
1
            .into(),
732
1
        )
733
1
        .unwrap();
734
1
}
735
736
1
#[test]
737
1
fn can_label_add_seq() {
738
1
    let database = Database(Connection::open_in_memory().unwrap());
739
1
    database.migrate().unwrap();
740
1
    let hash = Hash::new(&[0x01]);
741
1
    database.hash_add(&hash).unwrap();
742
1
    database.tag_name_create("name", None).unwrap();
743
1
    database.tag_value_create("name", "value").unwrap();
744
1
    database.hash_tag_add(&hash, "name", "value").unwrap();
745
1
    database
746
1
        .label_add(
747
1
            &hash,
748
1
            "name",
749
1
            "value",
750
1
            &Sequence { start: 0, end: 55 }.into(),
751
1
        )
752
1
        .unwrap();
753
1
}
754
755
1
#[test]
756
1
fn can_label_remove_rect() {
757
1
    let database = Database(Connection::open_in_memory().unwrap());
758
1
    database.migrate().unwrap();
759
1
    let hash = Hash::new(&[0x01]);
760
1
    database.hash_add(&hash).unwrap();
761
1
    database.tag_value_create("name", "value").unwrap();
762
1
    database.hash_tag_add(&hash, "name", "value").unwrap();
763
1
    let label = Rectangle {
764
1
        start: Point::new(0, 0),
765
1
        end: Point::new(64, 64),
766
1
    }
767
1
    .into();
768
1
    database.label_add(&hash, "name", "value", &label).unwrap();
769
1
    database
770
1
        .label_remove(&hash, "name", "value", &label)
771
1
        .unwrap();
772
1
}
773
774
1
#[test]
775
1
fn can_label_remove_sequence() {
776
1
    let database = Database(Connection::open_in_memory().unwrap());
777
1
    database.migrate().unwrap();
778
1
    let hash = Hash::new(&[0x01]);
779
1
    database.hash_add(&hash).unwrap();
780
1
    database.tag_name_create("name", None).unwrap();
781
1
    database.tag_value_create("name", "value").unwrap();
782
1
    database.hash_tag_add(&hash, "name", "value").unwrap();
783
1
    let label = Sequence { start: 11, end: 99 }.into();
784
1
    database.label_add(&hash, "name", "value", &label).unwrap();
785
1
    database
786
1
        .label_remove(&hash, "name", "value", &label)
787
1
        .unwrap();
788
1
}
789
790
1
#[test]
791
1
fn can_label_query_empty() {
792
1
    let database = Database(Connection::open_in_memory().unwrap());
793
1
    database.migrate().unwrap();
794
1
    let labels = database.label_get(None, None, None, None).unwrap();
795
1
    assert_eq!(labels.len(), 0);
796
1
}
797
798
1
#[test]
799
1
fn can_label_get_rect() {
800
1
    let database = Database(Connection::open_in_memory().unwrap());
801
1
    database.migrate().unwrap();
802
1
    let hash = Hash::new(&[0x01]);
803
1
    database.hash_add(&hash).unwrap();
804
1
    database.tag_name_create("name", None).unwrap();
805
1
    database.tag_value_create("name", "value").unwrap();
806
1
    database.hash_tag_add(&hash, "name", "value").unwrap();
807
1
    let label = Rectangle {
808
1
        start: Point::new(0, 0),
809
1
        end: Point::new(64, 64),
810
1
    }
811
1
    .into();
812
1
    database.label_add(&hash, "name", "value", &label).unwrap();
813
1
    let labels = database.label_get(Some(&hash), None, None, None).unwrap();
814
1
    assert_eq!(
815
1
        labels,
816
1
        [(Tag::new("name".into(), "value".into()), label)].into()
817
1
    );
818
1
}
819
820
1
#[test]
821
1
fn can_label_get_seq() {
822
1
    let database = Database(Connection::open_in_memory().unwrap());
823
1
    database.migrate().unwrap();
824
1
    let hash = Hash::new(&[0x01]);
825
1
    database.hash_add(&hash).unwrap();
826
1
    database.tag_name_create("name", None).unwrap();
827
1
    database.tag_value_create("name", "value").unwrap();
828
1
    database.hash_tag_add(&hash, "name", "value").unwrap();
829
1
    let label = Sequence { start: 0, end: 15 }.into();
830
1
    database.label_add(&hash, "name", "value", &label).unwrap();
831
1
    let labels = database.label_get(Some(&hash), None, None, None).unwrap();
832
1
    assert_eq!(
833
1
        labels,
834
1
        [(Tag::new("name".into(), "value".into()), label)].into()
835
1
    );
836
1
}
837
838
// TODO: test label_get with more loaded data?
839
840
1
#[test]
841
1
fn can_get_tag_names_empty() {
842
1
    let database = Database(Connection::open_in_memory().unwrap());
843
1
    database.migrate().unwrap();
844
1
    database.tag_names().unwrap();
845
1
}
846
847
1
#[test]
848
1
fn can_get_tag_names_system() {
849
1
    let database = Database(Connection::open_in_memory().unwrap());
850
1
    database.migrate().unwrap();
851
1
    let names = database.tag_names().unwrap();
852
1
    assert_eq!(names["filesize"].system, true);
853
1
    assert_eq!(names["filename"].system, true);
854
1
    assert_eq!(names["directory"].system, true);
855
1
    assert_eq!(names["ancestor"].system, true);
856
1
    assert_eq!(names["media"].system, true);
857
1
    assert_eq!(names["format"].system, true);
858
1
    assert_eq!(names["duration"].system, true);
859
1
    assert_eq!(names["width"].system, true);
860
1
    assert_eq!(names["height"].system, true);
861
1
    assert_eq!(names["path"].system, true);
862
1
}
863
864
1
#[test]
865
1
fn can_get_tag_names_none() {
866
1
    let database = Database(Connection::open_in_memory().unwrap());
867
1
    database.migrate().unwrap();
868
1
    database.tag_name_create("name", None).unwrap();
869
1
    let names = database.tag_names().unwrap();
870
1
    assert_eq!(names["name"].values, 0);
871
1
    assert_eq!(names["name"].system, false);
872
1
    assert_eq!(names["name"].display, "name");
873
1
}
874
875
1
#[test]
876
1
fn can_get_tag_names_single() {
877
1
    let database = Database(Connection::open_in_memory().unwrap());
878
1
    database.migrate().unwrap();
879
1
    database.tag_name_create("name", None).unwrap();
880
1
    database.tag_value_create("name", "value").unwrap();
881
1
    let names = database.tag_names().unwrap();
882
1
    assert_eq!(names["name"].values, 1);
883
1
    assert_eq!(names["name"].system, false);
884
1
    assert_eq!(names["name"].display, "name");
885
1
}
886
887
1
#[test]
888
1
fn can_get_tag_names_multiple() {
889
1
    let database = Database(Connection::open_in_memory().unwrap());
890
1
    database.migrate().unwrap();
891
1
    database.tag_name_create("name", None).unwrap();
892
1
    database.tag_name_create("kind", None).unwrap();
893
1
    database.tag_value_create("name", "value").unwrap();
894
1
    database.tag_value_create("name", "other").unwrap();
895
1
    database.tag_value_create("kind", "car").unwrap();
896
1
    let names = database.tag_names().unwrap();
897
1
    assert_eq!(names["name"].values, 2);
898
1
    assert_eq!(names["name"].system, false);
899
1
    assert_eq!(names["name"].display, "name");
900
1
    assert_eq!(names["kind"].values, 1);
901
1
    assert_eq!(names["kind"].system, false);
902
1
    assert_eq!(names["kind"].display, "kind");
903
1
}
904
905
1
#[test]
906
1
fn can_get_tag_name_display_custom() {
907
1
    let database = Database(Connection::open_in_memory().unwrap());
908
1
    database.migrate().unwrap();
909
1
    database.tag_name_create("name", None).unwrap();
910
1
    database.tag_value_create("name", "value").unwrap();
911
1
    database.tag_name_display("name", "My Name").unwrap();
912
1
    let names = database.tag_names().unwrap();
913
1
    assert_eq!(names["name"].values, 1);
914
1
    assert_eq!(names["name"].system, false);
915
1
    assert_eq!(names["name"].display, "My Name");
916
1
}
917
918
6
fn arb_tag() -> impl Strategy<Value = Tag> {
919
28.2k
    ("[a-z]{4}", "[a-z]{4}").prop_map(|(name, value)| Tag::new(name, value))
920
6
}
921
922
0
fn arb_tag_filter() -> impl Strategy<Value = TagFilter<'static>> {
923
0
    prop_oneof![
924
0
        Just(TagFilter::new::<&str>(None, None)),
925
0
        "[a-z]{4}".prop_map(|string| TagFilter::new::<String>(Some(string), None)),
926
0
        "[a-z]{4}".prop_map(|string| TagFilter::new::<String>(None, Some(string))),
927
0
        ("[a-z]{4}", "[a-z]{4}")
928
0
            .prop_map(|(name, value)| TagFilter::new::<String>(Some(name), Some(value))),
929
0
    ]
930
0
    .boxed()
931
0
}
932
933
0
fn arb_tag_predicate() -> impl Strategy<Value = TagPredicate<'static>> {
934
0
    prop_oneof![
935
0
        arb_tag_filter().prop_map(TagPredicate::Exists),
936
0
        arb_tag_filter().prop_map(TagPredicate::Missing),
937
0
    ]
938
0
}
939
940
256
proptest! {
941
256
    #[test]
942
256
    fn query_tag_union_single(tags in proptest::collection::btree_set(arb_tag(), 0..20)) {
943
256
        let database = Database(Connection::open_in_memory().unwrap());
944
256
        database.migrate().unwrap();
945
256
        let hash = Hash::new(&[0x01]);
946
256
        database.hash_add(&hash).unwrap();
947
2.33k
        for tag in tags.
iter()256
{
948
2.33k
            database.tag_name_create(tag.name(), None).unwrap();
949
2.33k
            database.tag_value_create(tag.name(), tag.value()).unwrap();
950
2.33k
            database
951
2.33k
                .hash_tag_add(&hash, tag.name(), tag.value())
952
2.33k
                .unwrap();
953
2.33k
        }
954
256
        let result = database
955
256
            .query_tag_union(&mut [].iter(), None, None)
956
256
            .unwrap();
957
256
        assert_eq!(result, tags);
958
256
    }
959
256
960
256
    #[test]
961
256
    fn query_tag_union_two(
962
256
        tags1 in proptest::collection::btree_set(arb_tag(), 0..20),
963
256
        tags2 in proptest::collection::btree_set(arb_tag(), 0..20))
964
256
    {
965
256
        let database = Database(Connection::open_in_memory().unwrap());
966
256
        database.migrate().unwrap();
967
256
968
256
        // create tags
969
4.77k
        for tag in tags1.
union(&tags2)256
{
970
4.77k
            database.tag_name_create(tag.name(), None).unwrap();
971
4.77k
            database.tag_value_create(tag.name(), tag.value()).unwrap();
972
4.77k
        }
973
256
974
256
        // tag file1
975
256
        let hash1 = Hash::new(&[0x01]);
976
256
        database.hash_add(&hash1).unwrap();
977
2.36k
        for tag in tags1.
iter()256
{
978
2.36k
            database
979
2.36k
                .hash_tag_add(&hash1, tag.name(), tag.value())
980
2.36k
                .unwrap();
981
2.36k
        }
982
256
983
256
        // tag file2
984
256
        let hash2 = Hash::new(&[0x02]);
985
256
        database.hash_add(&hash2).unwrap();
986
2.41k
        for tag in tags2.
iter()256
{
987
2.41k
            database
988
2.41k
                .hash_tag_add(&hash2, tag.name(), tag.value())
989
2.41k
                .unwrap();
990
2.41k
        }
991
256
992
256
        // empty query returns all, so the union of both tags.
993
256
        let expected = tags1.union(&tags2).cloned().collect();
994
256
        let result = database
995
256
            .query_tag_union(&mut [].iter(), None, None)
996
256
            .unwrap();
997
256
        assert_eq!(result, expected);
998
256
999
256
        // any tag which is only present in file 1 only returns tags from file1.
1000
2.36k
        for tag in tags1.
difference(&tags2)256
{
1001
2.36k
            let result = database
1002
2.36k
                .query_tag_union(&mut [
1003
2.36k
                    tag.filter().exists()
1004
2.36k
                ].iter(), None, None)
1005
2.36k
                .unwrap();
1006
2.36k
            assert_eq!(result, tags1);
1007
256
        }
1008
256
1009
256
        // any tag which is only present in file 1 only returns tags from file1.
1010
2.41k
        for tag in tags2.
difference(&tags1)256
{
1011
2.41k
            let result = database
1012
2.41k
                .query_tag_union(&mut [
1013
2.41k
                    tag.filter().exists()
1014
2.41k
                ].iter(), None, None)
1015
2.41k
                .unwrap();
1016
2.41k
            assert_eq!(result, tags2);
1017
256
        }
1018
256
    }
1019
256
1020
256
    #[test]
1021
256
    fn query_tag_union_intersection(tags in proptest::collection::btree_set(arb_tag(), 0..20)) {
1022
256
        let database = Database(Connection::open_in_memory().unwrap());
1023
256
        database.migrate().unwrap();
1024
256
        let hash = Hash::new(&[0x01]);
1025
256
        database.hash_add(&hash).unwrap();
1026
2.28k
        for tag in tags.
iter()256
{
1027
2.28k
            database.tag_name_create(tag.name(), None).unwrap();
1028
2.28k
            database.tag_value_create(tag.name(), tag.value()).unwrap();
1029
2.28k
            database
1030
2.28k
                .hash_tag_add(&hash, tag.name(), tag.value())
1031
2.28k
                .unwrap();
1032
2.28k
        }
1033
256
        let result = database
1034
256
            .query_tag_intersection(&mut [].iter(), None, None)
1035
256
            .unwrap();
1036
256
        assert_eq!(result, tags);
1037
256
    }
1038
256
1039
256
    #[test]
1040
256
    fn query_tag_intersection_two(
1041
256
        tags1 in proptest::collection::btree_set(arb_tag(), 0..20),
1042
256
        tags2 in proptest::collection::btree_set(arb_tag(), 0..20))
1043
256
    {
1044
256
        let database = Database(Connection::open_in_memory().unwrap());
1045
256
        database.migrate().unwrap();
1046
1.02k
1047
1.02k
        // create tags
1048
4.70k
        for tag in tags1.
union(&tags2)256
{
1049
4.70k
            database.tag_name_create(tag.name(), None).unwrap();
1050
4.70k
            database.tag_value_create(tag.name(), tag.value()).unwrap();
1051
4.70k
        }
1052
1.02k
1053
1.02k
        // tag file1
1054
1.02k
        let hash1 = Hash::new(&[0x01]);
1055
256
        database.hash_add(&hash1).unwrap();
1056
2.43k
        for tag in tags1.
iter()256
{
1057
2.43k
            database
1058
2.43k
                .hash_tag_add(&hash1, tag.name(), tag.value())
1059
2.43k
                .unwrap();
1060
2.43k
        }
1061
1.02k
1062
1.02k
        // tag file2
1063
1.02k
        let hash2 = Hash::new(&[0x02]);
1064
256
        database.hash_add(&hash2).unwrap();
1065
2.27k
        for tag in tags2.
iter()256
{
1066
2.27k
            database
1067
2.27k
                .hash_tag_add(&hash2, tag.name(), tag.value())
1068
2.27k
                .unwrap();
1069
2.27k
        }
1070
1.02k
1071
1.02k
        // empty query returns all, so the union of both tags.
1072
1.02k
        let expected = tags1.intersection(&tags2).cloned().collect();
1073
256
        let result = database
1074
256
            .query_tag_intersection(&mut [].iter(), None, None)
1075
256
            .unwrap();
1076
256
        assert_eq!(result, expected);
1077
1.02k
    }
1078
1.02k
}