-
Notifications
You must be signed in to change notification settings - Fork 226
/
tests.rs
142 lines (128 loc) · 4.52 KB
/
tests.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use serde_json::Value;
use crate::{
db::PlacesDb,
storage::bookmarks::get_raw_bookmark,
storage::bookmarks::json_tree::{fetch_tree, insert_tree, BookmarkTreeNode, FetchDepth},
types::BookmarkType,
};
use sql_support::ConnExt;
use sync_guid::Guid as SyncGuid;
use types::Timestamp;
use pretty_assertions::assert_eq;
pub fn insert_json_tree(conn: &PlacesDb, jtree: Value) {
let tree: BookmarkTreeNode = serde_json::from_value(jtree).expect("should be valid");
let folder_node = match tree {
BookmarkTreeNode::Folder { f: folder_node } => folder_node,
_ => panic!("must be a folder"),
};
insert_tree(conn, folder_node).expect("should insert");
}
pub struct InvalidBookmarkIds {
pub place_id: i64,
pub guid: SyncGuid,
}
// Append a bookmark with an invalid URL to the specified parent. Note that it's
// currently impossible to append a bookmark with NULL as there is a CHECK
// constraint in the schema.
pub fn append_invalid_bookmark(
db: &PlacesDb,
parent_guid: &SyncGuid,
title: &str,
url: &str,
) -> InvalidBookmarkIds {
let parent = get_raw_bookmark(db, parent_guid)
.expect("should work")
.expect("parent must exist");
assert_eq!(parent.bookmark_type, BookmarkType::Folder);
let position = parent.child_count;
let guid = SyncGuid::random();
// Assume the invalid URL isn't already there.
let place_sql = "
INSERT INTO moz_places (guid, url, url_hash)
VALUES (:guid, :url, hash(:url))";
db.execute_cached(
place_sql,
&[
(":guid", &guid as &dyn rusqlite::ToSql),
(":url", &url.to_string()),
],
)
.expect("should insert");
let place_id = db.conn().last_insert_rowid();
let bm_sql = format!(
"
INSERT INTO moz_bookmarks
(fk, type, parent, position,
title, dateAdded, lastModified, guid)
VALUES
({place_id}, {bm_type}, {parent_id}, {position},
:title, {timestamp}, {timestamp}, :guid)",
place_id = place_id,
bm_type = BookmarkType::Bookmark as u8,
timestamp = Timestamp::now(),
parent_id = parent.row_id.0,
position = position,
);
db.execute_cached(
&bm_sql,
&[
(":title", &title.to_string() as &dyn rusqlite::ToSql),
(":guid", &guid),
],
)
.expect("should insert bookmark");
InvalidBookmarkIds { place_id, guid }
}
pub fn assert_json_tree(conn: &PlacesDb, folder: &SyncGuid, expected: Value) {
assert_json_tree_with_depth(conn, folder, expected, &FetchDepth::Deepest)
}
pub fn assert_json_tree_with_depth(
conn: &PlacesDb,
folder: &SyncGuid,
expected: Value,
target_depth: &FetchDepth,
) {
let (fetched, _, _) = fetch_tree(conn, folder, target_depth)
.expect("error fetching tree")
.unwrap();
let deser_tree: BookmarkTreeNode = serde_json::from_value(expected).unwrap();
assert_eq!(fetched, deser_tree);
// and while checking the tree, check positions are correct.
check_positions(conn);
}
// check the positions for children in a folder are "correct" in that
// the first child has a value of zero, etc - ie, this will fail if there
// are holes or duplicates in the position values.
// Clever implementation stolen from desktop.
pub fn check_positions(conn: &PlacesDb) {
// Use triangular numbers to detect skipped position, then
// a subquery to select enough fields to help diagnose when it fails.
let sql = "
WITH bad_parents(pid) as (
SELECT parent
FROM moz_bookmarks
GROUP BY parent
HAVING (SUM(DISTINCT position + 1) - (count(*) * (count(*) + 1) / 2)) <> 0
)
SELECT parent, guid, title, position FROM moz_bookmarks
WHERE parent in bad_parents
ORDER BY parent, position
";
let mut stmt = conn.prepare(sql).expect("sql is ok");
let parents: Vec<_> = stmt
.query_and_then([], |row| -> rusqlite::Result<_> {
Ok((
row.get::<_, i64>(0)?,
row.get::<_, String>(1)?,
row.get::<_, Option<String>>(2)?,
row.get::<_, u32>(3)?,
))
})
.expect("should work")
.map(rusqlite::Result::unwrap)
.collect();
assert_eq!(parents, Vec::new());
}