1use nonblocking::non_blocking_result as r;
9use tempfile::tempdir;
10pub use test_dag::TestDag;
11
12pub use self::drawdag::DrawDag;
13use crate::id::Group;
14use crate::id::Vertex;
15use crate::ops::DagAddHeads;
16use crate::ops::DagPersistent;
17use crate::ops::ImportAscii;
18#[cfg(feature = "render")]
19use crate::render::render_dag;
20use crate::set::SyncSetQuery;
21use crate::Dag;
22use crate::DagAlgorithm;
23use crate::IdMap;
24#[cfg(test)]
25use crate::IdSet;
26use crate::Result;
27use crate::Set;
28
29mod drawdag;
30mod test_dag;
31
32#[cfg(test)]
33mod test_add_heads;
34
35#[cfg(test)]
36mod test_bisect;
37
38#[cfg(test)]
39mod test_integrity;
40
41#[cfg(test)]
42mod test_sparse;
43
44#[cfg(test)]
45mod test_strip;
46
47#[cfg(test)]
48mod test_to_parents;
49
50#[cfg(test)]
51mod test_discontinuous;
52
53#[cfg(test)]
54mod test_server;
55
56#[cfg(test)]
57mod test_virtual;
58
59#[cfg(test)]
60pub mod dummy_dag;
61
62#[cfg(test)]
63pub(crate) use test_dag::ProtocolMonitor;
64
65use crate::dag::MemDag;
66#[cfg(test)]
67use crate::iddag::FirstAncestorConstraint;
68use crate::ops::IdConvert;
69#[cfg(test)]
70use crate::protocol::Process;
71#[cfg(test)]
72use crate::protocol::RequestLocationToName;
73#[cfg(test)]
74use crate::protocol::RequestNameToLocation;
75#[cfg(test)]
76use crate::render::render_segment_dag;
77#[cfg(test)]
78use crate::Id;
79#[cfg(test)]
80use crate::VertexListWithOptions;
81
82static ASCII_DAG1: &str = r#"
90 C-D-\ /--I--J--\
91 A-B------E-F-G-H--------K--L"#;
92
93static ASCII_DAG2: &str = r#"
94 T /---------------N--O---\ T
95 / / \ \
96 /----E-F-\ /-------L--M--------P--\ S--U---\
97 A-B-C-D------G--H--I--J--K---------------Q--R---------V--W
98 \--N"#;
99
100static ASCII_DAG3: &str = r#"
101 B---D---F--\
102 A---C---E-----G"#;
103
104static ASCII_DAG4: &str = r#"
105 D C B
106 \ \ \
107 A--E--F--G"#;
108
109static ASCII_DAG5: &str = r#"
110 B---D---F
111 \ \ \
112 A---C---E---G"#;
113
114fn test_dag_sort_version<T: DagAlgorithm + IdConvert>(dag: &T) -> Result<()> {
115 let sets = [
117 set(""),
118 set("A C B"),
119 r(from_ascii(MemDag::new(), ASCII_DAG3).sort(&set("C A B")))?,
120 ];
121 for set in sets {
122 let sorted = r(dag.sort(&set))?;
123 let hints = sorted.hints();
124 assert_eq!(hints.dag_version(), Some(dag.dag_version()));
125 assert_eq!(hints.id_map_version(), Some(dag.map_version()));
126 }
127
128 Ok(())
129}
130
131fn test_generic_dag1<T: DagAlgorithm + DagAddHeads + IdConvert>(dag: T) -> Result<T> {
132 let dag = from_ascii(dag, ASCII_DAG1);
133 assert_eq!(expand(r(dag.all())?), "A B C D E F G H I J K L");
134 assert_eq!(expand(r(dag.dirty())?), "A B C D E F G H I J K L");
135 assert_eq!(expand(r(dag.ancestors(set("H I")))?), "A B C D E F G H I");
136 assert_eq!(expand(r(dag.sort(&set("H E A")))?.skip(1).take(2)), "A E");
137 assert_eq!(expand(r(dag.first_ancestors(set("F")))?), "A B E F");
138 assert_eq!(expand(r(dag.parents(set("H I E")))?), "B D G");
139 assert_eq!(expand(r(dag.children(set("G D L")))?), "E H I");
140 assert_eq!(expand(r(dag.merges(r(dag.all())?))?), "E K");
141 assert_eq!(expand(r(dag.merges(set("E F J K")))?), "E K");
142 assert_eq!(expand(r(dag.merges(set("A B D F H J L")))?), "");
143 assert_eq!(expand(r(dag.roots(set("A B E F C D I J")))?), "A C I");
144 assert_eq!(expand(r(dag.heads(set("A B E F C D I J")))?), "F J");
145 assert_eq!(expand(r(dag.gca_all(set("J K H")))?), "G");
146
147 test_dag_sort_version(&dag)?;
148
149 Ok(dag)
150}
151
152fn test_generic_dag_beautify<D: DagAlgorithm + DagAddHeads>(
153 new_dag: &impl Fn() -> D,
154) -> Result<()> {
155 let ascii = r#"
156 A C
157 | |
158 B D
159 |/
160 E"#;
161 let order = ["B", "D", "A", "C"];
162 let dag = from_ascii_with_heads(new_dag(), ascii, Some(&order));
163 assert_eq!(expand(r(dag.all())?), "A B C D E");
164
165 let dag2 = r(dag.beautify(None))?;
166 assert_eq!(expand(r(dag2.all())?), "A B C D E");
167
168 let dag3 = r(dag.beautify(Some(set("A B E"))))?;
169 assert_eq!(expand(r(dag3.all())?), "A B C D E");
170
171 let dag4 = r(dag.beautify(Some(set("C D E"))))?;
172 assert_eq!(expand(r(dag4.all())?), "A B C D E");
173
174 let ascii = r#"
175 A G
176 |/
177 B F
178 |/
179 C E
180 |/
181 D"#;
182 let order = ["C", "E", "G", "F", "A"];
183 let dag = from_ascii_with_heads(new_dag(), ascii, Some(&order));
184 assert_eq!(expand(r(dag.all())?), "A B C D E F G");
185
186 let dag2 = r(dag.beautify(None))?;
187 assert_eq!(expand(r(dag2.all())?), "A B C D E F G");
188
189 let dag3 = r(dag.beautify(Some(r(dag.ancestors(set("A")))?)))?;
190 assert_eq!(expand(r(dag3.all())?), "A B C D E F G");
191
192 let ascii = r#"
193 A---B---C---D---E---F---G
194 \
195 H---I---J---K
196 \
197 L "#;
198 let order = ["D", "J", "L", "K", "G"];
199 let dag = from_ascii_with_heads(new_dag(), ascii, Some(&order));
200 assert_eq!(expand(r(dag.all())?), "A B C D E F G H I J K L");
201
202 let dag2 = r(dag.beautify(None))?;
203 assert_eq!(expand(r(dag2.all())?), "A B C D E F G H I J K L");
204
205 Ok(())
206}
207
208fn test_generic_dag_reachable_roots(dag: impl DagAlgorithm + DagAddHeads) -> Result<()> {
209 let ascii = r#"
210 Z
211 |\
212 D |
213 | F
214 C |
215 | E
216 B |
217 |/
218 A
219 "#;
220 let dag = from_ascii_with_heads(dag, ascii, Some(&["Z"][..]));
221
222 assert_eq!(
225 expand(r(dag.reachable_roots(set("A B C"), set("Z")))?),
226 "A C"
227 );
228
229 assert_eq!(
231 expand(r(dag.reachable_roots(set("A C E F"), set("Z")))?),
232 "C F"
233 );
234
235 assert_eq!(
237 expand(r(dag.reachable_roots(set("A B C D E F Z"), set("D F")))?),
238 "D F"
239 );
240
241 assert_eq!(
243 expand(r(dag.reachable_roots(set("A B E F"), set("D")))?),
244 "B"
245 );
246
247 assert_eq!(expand(r(dag.reachable_roots(set("A Z"), set("C")))?), "A");
249
250 Ok(())
251}
252
253fn test_specific_dag_import(dag: impl DagAlgorithm + DagAddHeads) -> Result<()> {
256 let ascii = r#"
257 J K
258 /|\|\
259 G H I H
260 |/|/|
261 E F |
262 /|/|\|
263 A B C D"#;
264 let dag1 = from_ascii_with_heads(dag, ascii, Some(&["J", "K"][..]));
265
266 let dir = tempdir().unwrap();
267 let mut dag2 = Dag::open(dir.path())?;
268 r(dag2.import_and_flush(&dag1, set("J")))?;
269 #[cfg(feature = "render")]
270 assert_eq!(
271 render(&dag2),
272 r#"
273 K
274 ├─╮
275 │ │ J
276 ╭─┬─┤
277 │ I │
278 │ ├───╮
279 H │ │ │
280 ├─────╮
281 │ │ │ F
282 │ ╭───┼─╮
283 │ D │ │ │
284 │ │ │ │
285 │ │ │ C
286 │ │ │
287 │ G │
288 ├───╯ │
289 E │
290 ├─────╮
291 │ B
292 │
293 A"#
294 );
295
296 let dag3 = Dag::open(dir.path())?;
298 #[cfg(feature = "render")]
299 assert_eq!(
300 render(&dag3),
301 r#"
302 K
303 ├─╮
304 │ │ J
305 ╭─┬─┤
306 │ I │
307 │ ├───╮
308 H │ │ │
309 ├─────╮
310 │ │ │ F
311 │ ╭───┼─╮
312 │ D │ │ │
313 │ │ │ │
314 │ │ │ C
315 │ │ │
316 │ G │
317 ├───╯ │
318 E │
319 ├─────╮
320 │ B
321 │
322 A"#
323 );
324 Ok(())
325}
326
327fn test_generic_dag2<T: DagAlgorithm + DagAddHeads>(dag: T) -> Result<T> {
328 let ascii = r#"
329 J K
330 / \|\
331 G H I H
332 |/|/|
333 E F |
334 /|/| |
335 A B C D"#;
336 let dag = from_ascii_with_heads(dag, ascii, Some(&["J", "K"][..]));
337
338 let v = |name: &str| -> Vertex { Vertex::copy_from(name.as_bytes()) };
339
340 assert_eq!(expand(r(dag.all())?), "A B C D E F G H I J K");
341 assert_eq!(expand(r(dag.ancestors(set("H I")))?), "A B C D E F H I");
342 assert_eq!(expand(r(dag.first_ancestors(set("H I")))?), "A D E H I");
343 assert_eq!(expand(r(dag.first_ancestors(set("J G D")))?), "A D E G J");
344 assert_eq!(expand(r(dag.parents(set("H I E")))?), "A B D E F");
345 assert_eq!(r(dag.first_ancestor_nth(v("H"), 2))?.unwrap(), v("A"));
346 assert!(r(dag.first_ancestor_nth(v("H"), 3))?.is_none());
347 assert_eq!(expand(r(dag.heads(set("E H F K I D")))?), "K");
348 assert_eq!(expand(r(dag.children(set("E F I")))?), "G H I J K");
349 assert_eq!(expand(r(dag.merges(r(dag.all())?))?), "E F H I J K");
350 assert_eq!(expand(r(dag.merges(set("E H G D I")))?), "E H I");
351 assert_eq!(expand(r(dag.roots(set("E G H J I K D")))?), "D E");
352 assert_eq!(r(dag.gca_one(set("J K")))?, Some(v("I")));
353 assert_eq!(expand(r(dag.gca_all(set("J K")))?), "E I");
354 assert_eq!(expand(r(dag.common_ancestors(set("G H")))?), "A B E");
355 assert!(r(dag.is_ancestor(v("B"), v("K")))?);
356 assert!(!r(dag.is_ancestor(v("K"), v("B")))?);
357 assert_eq!(expand(r(dag.heads_ancestors(set("A E F D G")))?), "D F G");
358 assert_eq!(expand(r(dag.range(set("A"), set("K")))?), "A E H K");
359 assert_eq!(expand(r(dag.only(set("I"), set("G")))?), "C D F I");
360 let (reachable, unreachable) = r(dag.only_both(set("I"), set("G")))?;
361 assert_eq!(expand(reachable), "C D F I");
362 assert_eq!(expand(unreachable), expand(r(dag.ancestors(set("G")))?));
363 assert_eq!(expand(r(dag.descendants(set("F E")))?), "E F G H I J K");
364
365 assert!(r(dag.is_ancestor(v("B"), v("J")))?);
366 assert!(r(dag.is_ancestor(v("F"), v("F")))?);
367 assert!(!r(dag.is_ancestor(v("K"), v("I")))?);
368
369 Ok(dag)
370}
371
372#[test]
373fn test_import_ascii_with_vertex_fn() {
374 let ascii = r#"
375 B C
376 |/
377 A
378 "#;
379 let mut dag = MemDag::new();
380 let vertex_fn = |s: &str| -> Vertex {
381 let mut bytes = s.as_bytes().to_vec();
382 bytes.push(b'0');
383 Vertex::copy_from(&bytes)
384 };
385 dag.import_ascii_with_vertex_fn(ascii, vertex_fn).unwrap();
386 assert_eq!(expand(r(dag.all()).unwrap()), "A0 B0 C0");
387}
388
389#[test]
390fn test_mem_dag() {
391 let new_dag = MemDag::new;
392 test_generic_dag(&new_dag);
393 test_specific_dag_import(new_dag()).unwrap();
394}
395
396#[test]
397fn test_dag() {
398 use std::sync::atomic::AtomicUsize;
399 use std::sync::atomic::Ordering;
400
401 let dir = tempdir().unwrap();
402 let counter = AtomicUsize::new(0);
403 let new_dag = move || {
404 let count = counter.fetch_add(1, Ordering::AcqRel);
405 Dag::open(dir.path().join(count.to_string())).unwrap()
406 };
407 test_generic_dag(&new_dag);
408 test_specific_dag_import(new_dag()).unwrap();
409}
410
411#[test]
412fn test_protocols() {
413 let mut built = build_segments(ASCII_DAG1, "A C E L", 3);
414 assert_eq!(
415 built.ascii[3],
416 r#"
417 1-2-\ /--7--8--\
418 0-3------4-5-6-9--------10-11
419Lv0: RH0-0[] R1-2[] 3-3[0] H4-8[3, 2] 9-9[6] H10-11[9, 8]
420Lv1: R0-0[] R1-8[0]"#
421 );
422
423 let replace = |mut s: String| -> String {
425 for ch in "ABCDEFGHIJKL".chars() {
426 s = s.replace(&format!("[{}]", ch as u8), &format!("{}", ch));
427 }
428 s
429 };
430
431 let ids: Vec<Id> = b"ABCEFGHI"
434 .iter()
435 .map(|&b| built.name_dag.map.find_id_by_name(&[b]).unwrap().unwrap())
436 .collect();
437 let ids = IdSet::from_spans(ids);
438 let request1: RequestLocationToName =
439 r((&built.name_dag.map, &built.name_dag.dag).process(ids)).unwrap();
440 assert_eq!(
441 replace(dbg(&request1)),
442 "RequestLocationToName { paths: [L~2, J~1(+5), D~1, B~1] }"
443 );
444
445 let names = b"ABCEFGHI"
447 .iter()
448 .map(|&b| Vertex::copy_from(&[b]))
449 .collect();
450 let request2: RequestNameToLocation =
451 r((&built.name_dag.map, &built.name_dag.dag).process(names)).unwrap();
452 assert_eq!(
453 replace(dbg(&request2)),
454 "RequestNameToLocation { names: [A, B, C, E, F, G, H, I], heads: [L] }"
455 );
456
457 let response1 = r((&built.name_dag.map, &built.name_dag.dag).process(request1)).unwrap();
459 assert_eq!(
460 replace(dbg(&response1)),
461 "ResponseIdNamePair { path_names: [(L~2, [H]), (J~1(+5), [I, G, F, E, B]), (D~1, [C]), (B~1, [A])] }"
462 );
463
464 let response2 = r((&built.name_dag.map, &built.name_dag.dag).process(request2)).unwrap();
467 assert_eq!(
468 replace(dbg(&response2)),
469 "ResponseIdNamePair { path_names: [(B~1, [A]), (H~4, [B]), (D~1, [C]), (H~3, [E]), (H~2, [F]), (H~1, [G]), (L~2, [H]), (J~1, [I])] }"
470 );
471
472 r((&mut built.name_dag.map, &built.name_dag.dag).process(response1)).unwrap();
474 r((&mut built.name_dag.map, &built.name_dag.dag).process(response2.clone())).unwrap();
475
476 let mut sparse_id_map = IdMap::open(built.dir.path().join("sparse-id")).unwrap();
479 r(built
480 .name_dag
481 .dag
482 .write_sparse_idmap(&built.name_dag.map, &mut sparse_id_map))
483 .unwrap();
484 assert_eq!(
485 dbg(&sparse_id_map),
486 "IdMap {\n D: 2,\n B: 3,\n J: 8,\n H: 9,\n L: 11,\n}\n"
487 );
488 r((&mut sparse_id_map, &built.name_dag.dag).process(response2)).unwrap();
490 assert_eq!(
491 dbg(&sparse_id_map),
492 r#"IdMap {
493 A: 0,
494 C: 1,
495 D: 2,
496 B: 3,
497 E: 4,
498 F: 5,
499 G: 6,
500 I: 7,
501 J: 8,
502 H: 9,
503 L: 11,
504}
505"#
506 );
507}
508
509#[test]
510fn test_segment_non_master() {
511 let ascii = r#"
512a----b----c----d----e----f----g----------h----i
513 \ \ /
514 h---i---j---k l---m---n---o
515 \ \
516 -----------------p---q"#;
517 let built = build_segments(ascii, "i q", 3);
518 assert_eq!(
519 built.ascii[0],
520 r#"
521N0---N1---N2---N3---N4---N5---N6---------N11--N12
522 \ \ /
523 N11-N12-j---k N7--N8--N9--N10
524 \ \
525 -----------------p---q
526Lv0: RN0-N6[] N7-N10[N5] N11-N12[N0, N6, N10]"#
527 );
528 assert_eq!(
529 built.ascii[1],
530 r#"
531N0---N1---N2---N3---N4---N5---N6---------N11--N12
532 \ \ /
533 N11-N12-N13-k N7--N8--N9--N10
534 \ \
535 -----------------N14-N15
536Lv0: RN0-N6[] N7-N10[N5] N11-N12[N0, N6, N10] N13-N13[N12] N14-N15[N13, N8]
537Lv1: RN0-N12[]"#
538 );
539}
540
541#[test]
542fn test_segment_examples() {
543 assert_eq!(
544 build_segments(ASCII_DAG1, "L", 3).ascii[0],
545 r#"
546 2-3-\ /--8--9--\
547 0-1------4-5-6-7--------10-11
548Lv0: RH0-1[] R2-3[] H4-7[1, 3] 8-9[6] H10-11[7, 9]
549Lv1: R0-7[]"#
550 );
551
552 assert_eq!(
553 build_segments(ASCII_DAG2, "W", 3).ascii[0],
554 r#"
555 19/---------------13-14--\ 19
556 / / \ \
557 /----4-5-\ /-------11-12-------15-\ 18-20--\
558 0-1-2-3------6--7--8--9--10--------------16-17--------21-22
559 \--13
560Lv0: RH0-3[] 4-5[1] H6-10[3, 5] 11-12[7] 13-14[5, 9] 15-15[12, 14] H16-17[10, 15] R18-18[] 19-19[4] 20-20[18, 19] H21-22[17, 20]
561Lv1: R0-10[] 11-15[7, 5, 9] 16-17[10, 15] R18-20[4]
562Lv2: R0-17[]"#
563 );
564
565 assert_eq!(
566 build_segments(ASCII_DAG3, "G", 3).ascii[0],
567 r#"
568 3---4---5--\
569 0---1---2-----6
570Lv0: RH0-2[] R3-5[] H6-6[2, 5]"#
571 );
572
573 assert_eq!(
574 build_segments(ASCII_DAG4, "G", 3).ascii[0],
575 r#"
576 3 1 0
577 \ \ \
578 2--4--5--6
579Lv0: RH0-0[] R1-1[] R2-2[] R3-3[] 4-4[2, 3] 5-5[1, 4] H6-6[0, 5]
580Lv1: R0-0[] R1-1[] R2-4[]"#
581 );
582
583 assert_eq!(
584 build_segments(ASCII_DAG5, "G", 3).ascii[0],
585 r#"
586 1---3---5
587 \ \ \
588 0---2---4---6
589Lv0: RH0-0[] R1-1[] H2-2[0, 1] 3-3[1] H4-4[2, 3] 5-5[3] H6-6[4, 5]
590Lv1: R0-2[] 3-4[1, 2]"#
591 );
592
593 let ascii_dag = r#"
597 Z---E--M--J--C
598 \ \ \ \
599 O--T--D--L
600 \ \ \ \
601 K--H--P--W
602 \ \ \ \
603 X--R--U--V
604 \ \ \ \
605 A--N--S--Y"#;
606 assert_eq!(
607 build_segments(ascii_dag, "Y", 3).ascii[0],
608 r#"
609 0---1--6--11-16
610 \ \ \ \
611 2--7--12-17
612 \ \ \ \
613 3--8--13-18
614 \ \ \ \
615 4--9--14-19
616 \ \ \ \
617 5--10-15-20
618Lv0: RH0-5[] 6-6[1] 7-7[6, 2] 8-8[3, 7] 9-9[8, 4] H10-10[5, 9] 11-11[6] 12-12[11, 7] 13-13[12, 8] 14-14[13, 9] H15-15[10, 14] 16-16[11] 17-17[16, 12] 18-18[17, 13] 19-19[14, 18] H20-20[15, 19]
619Lv1: R0-5[] 6-8[1, 2, 3] 9-10[8, 4, 5] 11-13[6, 7, 8] 14-15[13, 9, 10] 16-18[11, 12, 13]
620Lv2: R0-10[] 11-15[6, 7, 8, 9, 10]"#
621 );
622
623 let ascii_dag = r#"
625 Z---E--J--C--O--T
626 \ \ \
627 D L K
628 \ \ \
629 H--P--W--X--R
630 \ \ \
631 U V A
632 \ \ \
633 N--S--Y--B--G"#;
634 assert_eq!(
635 build_segments(ascii_dag, "G", 3).ascii[0],
636 r#"
637 0---1--2--3--4--5
638 \ \ \
639 8 7 6
640 \ \ \
641 9--10-11-12-13
642 \ \ \
643 15 18 14
644 \ \ \
645 16-17-19-20-21
646Lv0: RH0-6[] 7-7[3] 8-10[1] 11-12[7, 10] H13-14[6, 12] 15-17[9] 18-18[11] 19-20[17, 18] H21-21[14, 20]
647Lv1: R0-6[] 7-12[3, 1] 13-14[6, 12] 15-20[9, 11]
648Lv2: R0-14[]"#
649 );
650}
651
652#[test]
653fn test_segment_groups() {
654 let dag = r#"
655A---B---C---D---E---F---G--------H---I
656 \ \ /
657 h--i--j--k l--m--n--o
658 \ \
659 -------------p---q"#;
660
661 let built = build_segments(dag, "B D i k G q I", 3);
668 assert_eq!(
669 built.ascii.join("\n"),
670 r#"
6710---1---C---D---E---F---G--------H---I
672 \ \ /
673 h--i--j--k l--m--n--o
674 \ \
675 -------------p---q
676Lv0: RH0-1[]
677
6780---1---2---3---E---F---G--------H---I
679 \ \ /
680 h--i--j--k l--m--n--o
681 \ \
682 -------------p---q
683Lv0: RH0-3[]
684
6850---1---2---3---E---F---G--------H---I
686 \ \ /
687 N0-N1-j--k l--m--n--o
688 \ \
689 -------------p---q
690Lv0: RH0-3[] N0-N1[1]
691
6920---1---2---3---E---F---G--------H---I
693 \ \ /
694 N0-N1-N2-N3 l--m--n--o
695 \ \
696 -------------p---q
697Lv0: RH0-3[] N0-N1[1] N2-N3[N1]
698
6990---1---2---3---4---5---6--------H---I
700 \ \ /
701 N0-N1-N2-N3 l--m--n--o
702 \ \
703 -------------p---q
704Lv0: RH0-6[] N0-N3[1]
705
7060---1---2---3---4---5---6--------H---I
707 \ \ /
708 N0-N1-N2-N3 N4-N5-N6-o
709 \ \
710 -------------N7--N8
711Lv0: RH0-6[] N0-N3[1] N4-N6[5] N7-N8[N3, N6]
712
7130---1---2---3---4---5---6--------11--12
714 \ \ /
715 N0-N1-N2-N3 7--8--9--10
716 \ \
717 -------------N4--N5
718Lv0: RH0-6[] 7-10[5] H11-12[6, 10] N0-N3[1] N4-N5[N3, 9]"#
719 );
720
721 assert_eq!(
724 built.name_dag.map.find_id_by_name(b"m").unwrap().unwrap(),
725 Id(8)
726 );
727 assert_eq!(
728 built.name_dag.map.find_name_by_id(Id(8)).unwrap().unwrap(),
729 b"m"
730 );
731 let id = Group::NON_MASTER.min_id() + 5;
732 assert_eq!(
733 built.name_dag.map.find_name_by_id(id).unwrap().unwrap(),
734 b"q"
735 );
736
737 assert_eq!(dbg(built.name_dag.dag.children_id(Id(5)).unwrap(),), "6 7");
739}
740
741#[test]
742fn test_dag_reassign_master() -> crate::Result<()> {
743 let dir = tempdir().unwrap();
744 let mut dag = Dag::open(dir.path())?;
745 dag = from_ascii(dag, "A-B-C");
746
747 assert_eq!(dbg(r(dag.parent_names("A".into()))?), "[]");
749 assert_eq!(dbg(r(dag.parent_names("C".into()))?), "[B]");
750
751 r(dag.flush(&Default::default())).unwrap();
753
754 assert_eq!(dbg(r(dag.vertex_id("A".into()))?), "N0");
755 assert_eq!(dbg(r(dag.vertex_id("C".into()))?), "N2");
756
757 let heads =
759 VertexListWithOptions::from(vec![Vertex::from("B")]).with_desired_group(Group::MASTER);
760 r(dag.flush(&heads)).unwrap();
761 assert_eq!(dbg(r(dag.vertex_id("A".into()))?), "0");
762 assert_eq!(dbg(r(dag.vertex_id("B".into()))?), "1");
763 assert_eq!(dbg(r(dag.vertex_id("C".into()))?), "N0");
764
765 Ok(())
766}
767
768#[test]
769fn test_dag_reassign_non_master() {
770 let mut t = TestDag::new();
771
772 t.drawdag("A--B--Z", &["A"]);
774 t.drawdag("B--C--D--E", &[]);
776 t.drawdag("", &["C"]);
778
779 #[cfg(feature = "render")]
781 assert_eq!(
782 t.render_graph(),
783 r#"
784 Z N2
785 │
786 │ E N1
787 │ │
788 │ D N0
789 │ │
790 │ C 2
791 ├─╯
792 B 1
793 │
794 A 0"#
795 );
796
797 let z_id = r(t.dag.vertex_id("Z".into())).unwrap();
799 let z_vertex = r(t.dag.vertex_name(z_id)).unwrap();
800 assert_eq!(dbg(z_vertex), "Z");
801}
802
803#[test]
804fn test_segment_ancestors_example1() {
805 let ascii_dag = r#"
807 2-3-\ /--8--9--\
808 0-1------4-5-6-7--------10-11"#;
809 let result = build_segments(ascii_dag, "11", 3);
810 let dag = result.name_dag.dag;
811
812 for (id, count) in &[
813 (11, 12),
814 (10, 11),
815 (9, 9),
816 (8, 8),
817 (7, 8),
818 (6, 7),
819 (5, 6),
820 (4, 5),
821 (3, 2),
822 (2, 1),
823 (1, 2),
824 (0, 1),
825 ] {
826 assert_eq!(dag.ancestors((*id).into()).unwrap().count(), *count);
827 }
828
829 for (a, b, ancestor) in vec![
830 (10, 3, 3.into()),
831 (11, 0, 0.into()),
832 (11, 10, 10.into()),
833 (11, 9, 9.into()),
834 (3, 0, None),
835 (7, 1, 1.into()),
836 (9, 2, 2.into()),
837 (9, 7, 6.into()),
838 ] {
839 let ancestor = ancestor.map(Id);
840 let a = Id(a);
841 let b = Id(b);
842 assert_eq!(dag.gca_one((a, b).into()).unwrap(), ancestor);
843 assert_eq!(
844 dag.gca_all((a, b).into()).unwrap().iter_desc().nth(0),
845 ancestor
846 );
847 assert_eq!(dag.gca_all((a, b).into()).unwrap().iter_desc().nth(1), None);
848 assert_eq!(dag.is_ancestor(b, a).unwrap(), ancestor == Some(b));
849 assert_eq!(dag.is_ancestor(a, b).unwrap(), ancestor == Some(a));
850 }
851
852 for (spans, ancestors) in [
853 (vec![3..=8], vec![3]),
854 (vec![1..=1, 4..=9], vec![1]),
855 (vec![1..=4], vec![]),
856 ] {
857 assert_eq!(
858 dag.gca_all(IdSet::from_spans(spans))
859 .unwrap()
860 .iter_desc()
861 .collect::<Vec<Id>>(),
862 ancestors.into_iter().map(Id).collect::<Vec<Id>>(),
863 );
864 }
865}
866
867#[test]
868fn test_segment_multiple_gcas() {
869 let ascii_dag = r#"
870 B---C
871 \ /
872 A---D"#;
873 let result = build_segments(ascii_dag, "C D", 3);
874 assert_eq!(
875 result.ascii[1],
876 r#"
877 1---2
878 \ /
879 0---3
880Lv0: RH0-0[] R1-1[] H2-2[0, 1] 3-3[0, 1]
881Lv1: R0-2[]"#
882 );
883 let dag = result.name_dag.dag;
884 assert_eq!(dag.gca_one((2, 3).into()).unwrap(), Some(Id(1)));
886 assert_eq!(
887 dag.gca_all((2, 3).into())
888 .unwrap()
889 .iter_desc()
890 .collect::<Vec<_>>(),
891 vec![1, 0]
892 );
893}
894
895#[test]
896fn test_parents() {
897 let result = build_segments(ASCII_DAG1, "L", 3);
898 assert_eq!(
899 result.ascii[0],
900 r#"
901 2-3-\ /--8--9--\
902 0-1------4-5-6-7--------10-11
903Lv0: RH0-1[] R2-3[] H4-7[1, 3] 8-9[6] H10-11[7, 9]
904Lv1: R0-7[]"#
905 );
906
907 let dag = result.name_dag.dag;
908
909 let parents = |spans| -> String { dbg(dag.parents(IdSet::from_spans(spans)).unwrap()) };
910 let parent_ids = |id| -> String { dbg(dag.parent_ids(Id(id)).unwrap()) };
911 let first_ancestor_nth = |id, n| -> String { dbg(dag.first_ancestor_nth(Id(id), n).unwrap()) };
912 let to_first_ancestor_nth = |id| -> String {
913 let c = FirstAncestorConstraint::KnownUniversally {
914 heads: Id(11).into(),
915 };
916 let res = dag.to_first_ancestor_nth(Id(id), c);
917 match res {
918 Ok(s) => dbg(s),
919 Err(e) => e.to_string(),
920 }
921 };
922
923 assert_eq!(parents(vec![]), "");
924
925 assert_eq!(parents(vec![0..=0]), "");
926 assert_eq!(parents(vec![0..=1]), "0");
927 assert_eq!(parents(vec![0..=2]), "0");
928 assert_eq!(parents(vec![0..=3]), "0 2");
929 assert_eq!(parents(vec![0..=4]), "0..=3");
930 assert_eq!(parents(vec![0..=5]), "0..=4");
931 assert_eq!(parents(vec![0..=6]), "0..=5");
932 assert_eq!(parents(vec![0..=7]), "0..=6");
933 assert_eq!(parents(vec![0..=8]), "0..=6");
934 assert_eq!(parents(vec![0..=9]), "0..=6 8");
935 assert_eq!(parents(vec![0..=10]), "0..=9");
936 assert_eq!(parents(vec![0..=11]), "0..=10");
937
938 assert_eq!(parents(vec![0..=0, 2..=2]), "");
939 assert_eq!(parents(vec![0..=0, 3..=3, 5..=5, 9..=10]), "2 4 7 8 9");
940 assert_eq!(parents(vec![1..=1, 4..=4, 6..=6, 8..=11]), "0 1 3 5..=10");
941
942 assert_eq!(parent_ids(0), "[]");
943 assert_eq!(parent_ids(1), "[0]");
944 assert_eq!(parent_ids(4), "[1, 3]");
945 assert_eq!(parent_ids(10), "[7, 9]");
946 assert_eq!(parent_ids(11), "[10]");
947
948 assert_eq!(first_ancestor_nth(0, 0), "0");
949 assert_eq!(first_ancestor_nth(4, 2), "0");
950 assert_eq!(first_ancestor_nth(10, 2), "6");
951 assert_eq!(first_ancestor_nth(10, 3), "5");
952 assert_eq!(first_ancestor_nth(11, 0), "11");
953 assert_eq!(first_ancestor_nth(11, 1), "10");
954 assert_eq!(first_ancestor_nth(11, 2), "7");
955 assert_eq!(first_ancestor_nth(11, 3), "6");
956 assert_eq!(first_ancestor_nth(11, 4), "5");
957 assert_eq!(first_ancestor_nth(11, 6), "1");
958 assert_eq!(first_ancestor_nth(11, 7), "0");
959 assert!(dag.first_ancestor_nth(Id::MIN, 1).is_err());
960 assert!(dag.first_ancestor_nth(Id(11), 8).is_err());
961
962 assert_eq!(to_first_ancestor_nth(0), "Some((1, 1))");
963 assert_eq!(to_first_ancestor_nth(1), "Some((9, 5))");
964 assert_eq!(to_first_ancestor_nth(2), "Some((3, 1))");
965 assert_eq!(
966 to_first_ancestor_nth(3),
967 "ProgrammingError: cannot convert 3 to x~n form (x must be in `H + parents(ancestors(H) & merge())` where H = 11) (trace: in seg R2-3[], 3 has child seg (H4-7[1, 3]), child seg cannot be followed (3 is not p1))"
968 );
969 assert_eq!(to_first_ancestor_nth(4), "Some((9, 4))");
970 assert_eq!(to_first_ancestor_nth(5), "Some((9, 3))");
971 assert_eq!(to_first_ancestor_nth(6), "Some((9, 2))");
972 assert_eq!(to_first_ancestor_nth(7), "Some((11, 2))");
973 assert_eq!(to_first_ancestor_nth(8), "Some((9, 1))");
974 assert_eq!(
975 to_first_ancestor_nth(9),
976 "ProgrammingError: cannot convert 9 to x~n form (x must be in `H + parents(ancestors(H) & merge())` where H = 11) (trace: in seg 8-9[6], 9 has child seg (H10-11[7, 9]), child seg cannot be followed (9 is not p1))"
977 );
978 assert_eq!(to_first_ancestor_nth(10), "Some((11, 1))");
979 assert_eq!(to_first_ancestor_nth(11), "Some((11, 0))");
980}
981
982#[test]
983fn test_children() {
984 let result = build_segments(ASCII_DAG1, "L", 3);
985 let dag = result.name_dag.dag;
986 let children = |spans| -> String { dbg(dag.children(IdSet::from_spans(spans)).unwrap()) };
987
988 assert_eq!(children(vec![]), "");
991 assert_eq!(children(vec![0..=0]), "1");
992
993 assert_eq!(children(vec![0..=1]), "1 4");
994 assert_eq!(children(vec![0..=2]), "1 3 4");
995 assert_eq!(children(vec![0..=3]), "1 3 4");
996 assert_eq!(children(vec![0..=4]), "1 3 4 5");
997 assert_eq!(children(vec![0..=5]), "1 3..=6");
998 assert_eq!(children(vec![0..=6]), "1 3..=8");
999 assert_eq!(children(vec![0..=7]), "1 3..=8 10");
1000 assert_eq!(children(vec![0..=8]), "1 3..=10");
1001 assert_eq!(children(vec![0..=9]), "1 3..=10");
1002 assert_eq!(children(vec![0..=10]), "1 3..=11");
1003 assert_eq!(children(vec![0..=11]), "1 3..=11");
1004
1005 assert_eq!(children(vec![1..=10]), "3..=11");
1006 assert_eq!(children(vec![2..=10]), "3..=11");
1007 assert_eq!(children(vec![3..=10]), "4..=11");
1008 assert_eq!(children(vec![4..=10]), "5..=11");
1009 assert_eq!(children(vec![5..=10]), "6..=11");
1010 assert_eq!(children(vec![6..=10]), "7..=11");
1011 assert_eq!(children(vec![7..=10]), "9 10 11");
1012 assert_eq!(children(vec![8..=10]), "9 10 11");
1013 assert_eq!(children(vec![9..=10]), "10 11");
1014 assert_eq!(children(vec![10..=10]), "11");
1015
1016 assert_eq!(children(vec![0..=0, 2..=2]), "1 3");
1017 assert_eq!(children(vec![0..=0, 3..=3, 5..=5, 9..=10]), "1 4 6 10 11");
1018 assert_eq!(children(vec![1..=1, 4..=4, 6..=6, 10..=10]), "4 5 7 8 11");
1019}
1020
1021#[test]
1022fn test_heads() {
1023 let ascii = r#"
1024 C G K L
1025 | |\ |/
1026 B E F I J
1027 | |/ |/
1028 A D H"#;
1029
1030 let result = build_segments(ascii, "C G K L J", 2);
1031 assert_eq!(
1032 result.ascii[4],
1033 r#"
1034 2 6 9 10
1035 | |\ |/
1036 1 5 4 8 11
1037 | |/ |/
1038 0 3 7
1039Lv0: RH0-2[] R3-4[] 5-5[3] 6-6[5, 4] R7-9[] 10-10[8] 11-11[7]
1040Lv1: R0-2[] R3-4[] 5-6[3, 4] R7-9[] 10-10[8]
1041Lv2: R0-2[] R3-6[] R7-9[]"#
1042 );
1043
1044 let dag = result.name_dag.dag;
1045 let heads = |spans| -> String { dbg(dag.heads(IdSet::from_spans(spans)).unwrap()) };
1046
1047 assert_eq!(heads(vec![]), "");
1048 assert_eq!(heads(vec![0..=11]), "2 6 9 10 11");
1049 assert_eq!(heads(vec![0..=1, 3..=5, 7..=10]), "1 4 5 9 10");
1050 assert_eq!(heads(vec![0..=0, 2..=2]), "0 2");
1051 assert_eq!(heads(vec![1..=2, 4..=6, 7..=7, 11..=11, 9..=9]), "2 6 9 11");
1052}
1053
1054#[test]
1055fn test_roots() {
1056 let ascii = r#"
1057 C G J
1058 | |\ |\
1059 B E F I K
1060 | |/ |\
1061 A D H L"#;
1062
1063 let result = build_segments(ascii, "C G J", 2);
1064 assert_eq!(
1065 result.ascii[2],
1066 r#"
1067 2 6 11
1068 | |\ |\
1069 1 5 4 107
1070 | |/ |\
1071 0 3 9 8
1072Lv0: RH0-2[] R3-4[] 5-5[3] 6-6[5, 4] R7-7[] R8-8[] R9-9[] 10-10[9, 8] 11-11[10, 7]
1073Lv1: R0-2[] R3-4[] 5-6[3, 4] R7-7[] R8-8[] R9-10[8]
1074Lv2: R0-2[] R3-6[] R7-7[]"#
1075 );
1076
1077 let dag = result.name_dag.dag;
1078 let roots = |spans| -> String { dbg(dag.roots(IdSet::from_spans(spans)).unwrap()) };
1079
1080 assert_eq!(roots(vec![]), "");
1081 assert_eq!(roots(vec![0..=11]), "0 3 7 8 9");
1082 assert_eq!(roots(vec![1..=2, 4..=6, 8..=10]), "1 4 5 8 9");
1083 assert_eq!(roots(vec![0..=0, 2..=3, 5..=6, 9..=11]), "0 2 3 9");
1084 assert_eq!(roots(vec![1..=1, 3..=3, 6..=8, 11..=11]), "1 3 6 7 8");
1085}
1086
1087#[test]
1088fn test_range() {
1089 let ascii = r#"
1090 J
1091 /|\
1092 G H I
1093 |/|/
1094 E F
1095 /|/|\
1096 A B C D"#;
1097
1098 let result = build_segments(ascii, "J", 2);
1099 assert_eq!(
1100 result.ascii[0],
1101 r#"
1102 9
1103 /|\
1104 3 7 8
1105 |/|/
1106 2 6
1107 /|/|\
1108 0 1 4 5
1109Lv0: RH0-0[] R1-1[] H2-3[0, 1] R4-4[] R5-5[] 6-6[1, 4, 5] 7-7[2, 6] 8-8[6] H9-9[3, 7, 8]
1110Lv1: R0-0[] R1-3[0] R4-4[] R5-6[1, 4] 7-7[2, 6]
1111Lv2: R0-3[] R4-6[1]"#
1112 );
1113
1114 let dag = result.name_dag.dag;
1115 let range = |roots, heads| -> String {
1116 dbg(dag
1117 .range(IdSet::from_spans(roots), IdSet::from_spans(heads))
1118 .unwrap())
1119 };
1120
1121 assert_eq!(range(vec![6], vec![3]), "");
1122 assert_eq!(range(vec![1], vec![3, 8]), "1 2 3 6 8");
1123 assert_eq!(range(vec![4], vec![3, 8]), "4 6 8");
1124 assert_eq!(range(vec![0, 5], vec![7]), "0 2 5 6 7");
1125 assert_eq!(range(vec![0, 5], vec![3, 8]), "0 2 3 5 6 8");
1126 assert_eq!(range(vec![0, 1, 4, 5], vec![3, 7, 8]), "0..=8");
1127
1128 assert_eq!(range(vec![0], vec![0]), "0");
1129 assert_eq!(range(vec![0], vec![1]), "");
1130 assert_eq!(range(vec![0], vec![2]), "0 2");
1131 assert_eq!(range(vec![0], vec![3]), "0 2 3");
1132 assert_eq!(range(vec![0], vec![4]), "");
1133 assert_eq!(range(vec![0], vec![5]), "");
1134 assert_eq!(range(vec![0], vec![6]), "");
1135 assert_eq!(range(vec![0], vec![7]), "0 2 7");
1136 assert_eq!(range(vec![0], vec![8]), "");
1137 assert_eq!(range(vec![0], vec![9]), "0 2 3 7 9");
1138 assert_eq!(range(vec![1], vec![1]), "1");
1139 assert_eq!(range(vec![1], vec![2]), "1 2");
1140 assert_eq!(range(vec![1], vec![3]), "1 2 3");
1141 assert_eq!(range(vec![1], vec![4]), "");
1142 assert_eq!(range(vec![1], vec![5]), "");
1143 assert_eq!(range(vec![1], vec![6]), "1 6");
1144 assert_eq!(range(vec![1], vec![7]), "1 2 6 7");
1145 assert_eq!(range(vec![1], vec![8]), "1 6 8");
1146 assert_eq!(range(vec![1], vec![9]), "1 2 3 6..=9");
1147 assert_eq!(range(vec![2], vec![2]), "2");
1148 assert_eq!(range(vec![2], vec![3]), "2 3");
1149 assert_eq!(range(vec![2], vec![4]), "");
1150 assert_eq!(range(vec![2], vec![5]), "");
1151 assert_eq!(range(vec![2], vec![6]), "");
1152 assert_eq!(range(vec![2], vec![7]), "2 7");
1153 assert_eq!(range(vec![2], vec![8]), "");
1154 assert_eq!(range(vec![2], vec![9]), "2 3 7 9");
1155 assert_eq!(range(vec![3], vec![3]), "3");
1156 assert_eq!(range(vec![3], vec![4]), "");
1157 assert_eq!(range(vec![3], vec![5]), "");
1158 assert_eq!(range(vec![3], vec![6]), "");
1159 assert_eq!(range(vec![3], vec![7]), "");
1160 assert_eq!(range(vec![3], vec![8]), "");
1161 assert_eq!(range(vec![3], vec![9]), "3 9");
1162 assert_eq!(range(vec![4], vec![4]), "4");
1163 assert_eq!(range(vec![4], vec![5]), "");
1164 assert_eq!(range(vec![4], vec![6]), "4 6");
1165 assert_eq!(range(vec![4], vec![7]), "4 6 7");
1166 assert_eq!(range(vec![4], vec![8]), "4 6 8");
1167 assert_eq!(range(vec![4], vec![9]), "4 6..=9");
1168 assert_eq!(range(vec![5], vec![5]), "5");
1169 assert_eq!(range(vec![5], vec![6]), "5 6");
1170 assert_eq!(range(vec![5], vec![7]), "5 6 7");
1171 assert_eq!(range(vec![5], vec![8]), "5 6 8");
1172 assert_eq!(range(vec![5], vec![9]), "5..=9");
1173 assert_eq!(range(vec![6], vec![6]), "6");
1174 assert_eq!(range(vec![6], vec![7]), "6 7");
1175 assert_eq!(range(vec![6], vec![8]), "6 8");
1176 assert_eq!(range(vec![6], vec![9]), "6..=9");
1177 assert_eq!(range(vec![7], vec![7]), "7");
1178 assert_eq!(range(vec![7], vec![8]), "");
1179 assert_eq!(range(vec![7], vec![9]), "7 9");
1180 assert_eq!(range(vec![8], vec![8]), "8");
1181 assert_eq!(range(vec![8], vec![9]), "8 9");
1182 assert_eq!(range(vec![9], vec![9]), "9");
1183
1184 for bits in 0..(1 << 10) {
1186 let mut set = IdSet::empty();
1187 for i in (0..=9).rev() {
1188 if bits & (1 << i) != 0 {
1189 set.push_span(i.into());
1190 }
1191 }
1192
1193 let all = dag.all().unwrap();
1194 assert_eq!(
1195 dag.range(set.clone(), all.clone()).unwrap().as_spans(),
1196 dag.descendants(set.clone()).unwrap().as_spans(),
1197 );
1198
1199 assert_eq!(
1200 dag.range(all.clone(), set.clone()).unwrap().as_spans(),
1201 dag.ancestors(set.clone()).unwrap().as_spans(),
1202 );
1203 }
1204}
1205
1206#[test]
1207fn test_render_segment_dag() {
1208 assert_eq!(
1210 build_segments(ASCII_DAG2, "W", 3).ascii[0],
1211 r#"
1212 19/---------------13-14--\ 19
1213 / / \ \
1214 /----4-5-\ /-------11-12-------15-\ 18-20--\
1215 0-1-2-3------6--7--8--9--10--------------16-17--------21-22
1216 \--13
1217Lv0: RH0-3[] 4-5[1] H6-10[3, 5] 11-12[7] 13-14[5, 9] 15-15[12, 14] H16-17[10, 15] R18-18[] 19-19[4] 20-20[18, 19] H21-22[17, 20]
1218Lv1: R0-10[] 11-15[7, 5, 9] 16-17[10, 15] R18-20[4]
1219Lv2: R0-17[]"#
1220 );
1221
1222 let built = build_segments(ASCII_DAG2, "W", 3);
1223 let mut buf = Vec::new();
1224 buf.push(b'\n');
1225 render_segment_dag(&mut buf, &built.name_dag, 0, Group::MASTER).unwrap();
1226
1227 assert_eq!(
1228 String::from_utf8(buf).unwrap(),
1229 r#"
1230o V(21)-W(22)
1231├─╮
1232│ o U(20)-U(20)
1233│ ├─╮
1234│ │ o T(19)-T(19)
1235│ │ │
1236│ o │ S(18)-S(18)
1237│ │
1238o │ Q(16)-R(17)
1239├─╮ │
1240│ o │ P(15)-P(15)
1241│ ├───╮
1242│ │ │ o N(13)-O(14)
1243╭───┬─╯
1244│ o │ L(11)-M(12)
1245├─╯ │
1246o │ G(6)-K(10)
1247├───╮
1248│ o E(4)-F(5)
1249├───╯
1250o A(0)-D(3)
1251
1252"#
1253 );
1254
1255 let mut buf = Vec::new();
1256 buf.push(b'\n');
1257 render_segment_dag(&mut buf, &built.name_dag, 1, Group::MASTER).unwrap();
1258
1259 assert_eq!(
1260 String::from_utf8(buf).unwrap(),
1261 r#"
1262o S(18)-U(20)
1263│
1264│ o Q(16)-R(17)
1265╭─┤
1266│ o L(11)-P(15)
1267╭─╯
1268o A(0)-K(10)
1269
1270"#
1271 );
1272}
1273
1274#[test]
1275fn test_render_segment_dag_non_master() {
1276 let mut t = TestDag::new();
1277
1278 t.drawdag("A--B--Z", &["A"]);
1280
1281 let mut buf = Vec::new();
1282 buf.push(b'\n');
1283 render_segment_dag(&mut buf, &t.dag, 0, Group::NON_MASTER).unwrap();
1284
1285 assert_eq!(
1286 String::from_utf8(buf).unwrap(),
1287 r#"
1288o B(N0)-Z(N1)
1289│
1290~
1291"#
1292 );
1293}
1294
1295#[cfg_attr(test, tokio::test)]
1296async fn test_subdag() {
1297 let t = TestDag::draw("A..E");
1298 let s = t.dag.subdag(set("B D E")).await.unwrap();
1299 #[cfg(feature = "render")]
1300 assert_eq!(
1301 render(&s),
1302 r#"
1303 E
1304 │
1305 D
1306 │
1307 B"#
1308 );
1309
1310 let t = TestDag::draw("A-X B-X X-C X-D");
1312 let s1 = t.dag.subdag(set("D C B A")).await.unwrap();
1313 let s2 = t.dag.subdag(set("A B C D")).await.unwrap();
1314 #[cfg(feature = "render")]
1315 assert_eq!(
1316 render(&s1),
1317 r#"
1318 D
1319 ├─╮
1320 │ │ C
1321 ╭─┬─╯
1322 │ A
1323 │
1324 B"#
1325 );
1326 #[cfg(feature = "render")]
1327 assert_eq!(render(&s1), render(&s2));
1328}
1329
1330fn expand(set: Set) -> String {
1333 let mut names = set
1334 .iter()
1335 .unwrap()
1336 .map(|n| String::from_utf8_lossy(n.unwrap().as_ref()).to_string())
1337 .collect::<Vec<String>>();
1338 names.sort();
1339 names.join(" ")
1340}
1341
1342fn set(names: &str) -> Set {
1343 let names: Vec<Vertex> = names
1344 .split_whitespace()
1345 .map(|n| Vertex::copy_from(n.as_bytes()))
1346 .collect();
1347 Set::from_static_names(names)
1348}
1349
1350impl IdMap {
1351 fn replace(&self, text: &str) -> String {
1353 let mut result = text.to_string();
1354 for &group in Group::ALL.iter() {
1355 const MAX_ID_IN_ASCII_TEST: u64 = 30;
1356 for id in group.min_id().to(group.min_id() + MAX_ID_IN_ASCII_TEST) {
1357 if let Ok(Some(name)) = self.find_name_by_id(id) {
1358 let name = String::from_utf8(name.to_vec()).unwrap();
1359 let id_str = format!("{:01$}", id, name.len());
1360 if name.len() + 2 == id_str.len() {
1362 result = result
1363 .replace(&format!("{}--", name), &id_str)
1364 .replace(&format!("{} ", name), &id_str);
1365 } else if name.len() + 1 == id_str.len() {
1366 result = result
1367 .replace(&format!("{}-", name), &id_str)
1368 .replace(&format!("{} ", name), &id_str);
1369 }
1370 result = result.replace(&name.to_string(), &id_str);
1371 }
1372 }
1373 }
1374 result
1375 }
1376}
1377
1378fn get_parents_func_from_ascii(text: &str) -> impl Fn(Vertex) -> Result<Vec<Vertex>> {
1379 let parents = ::drawdag::parse(text);
1380 move |name: Vertex| -> Result<Vec<Vertex>> {
1381 Ok(parents[&String::from_utf8(name.as_ref().to_vec()).unwrap()]
1382 .iter()
1383 .map(|p| Vertex::copy_from(p.as_bytes()))
1384 .collect())
1385 }
1386}
1387
1388pub(crate) struct BuildSegmentResult {
1390 pub(crate) ascii: Vec<String>,
1391 pub(crate) name_dag: Dag,
1392 pub(crate) dir: tempfile::TempDir,
1393}
1394
1395pub(crate) fn build_segments(text: &str, heads: &str, segment_size: usize) -> BuildSegmentResult {
1398 let mut dag = TestDag::new_with_segment_size(segment_size);
1399
1400 let mut ascii = Vec::new();
1401 for head in heads.split(' ') {
1402 let master = if head.chars().nth(0).unwrap().is_lowercase() {
1404 vec![]
1405 } else {
1406 vec![head]
1407 };
1408 dag.drawdag_with_limited_heads(text, &master[..], Some(&[head]));
1409 let annotated = dag.annotate_ascii(text);
1410 let segments = dag.render_segments();
1411 ascii.push(format!("{}\n{}", annotated, segments));
1412 }
1413
1414 BuildSegmentResult {
1415 ascii,
1416 name_dag: dag.dag,
1417 dir: dag.dir,
1418 }
1419}
1420
1421fn from_ascii<D: DagAddHeads>(dag: D, text: &str) -> D {
1422 from_ascii_with_heads(dag, text, None)
1423}
1424
1425fn from_ascii_with_heads<D: DagAddHeads>(mut dag: D, text: &str, heads: Option<&[&str]>) -> D {
1426 dag.import_ascii_with_heads(text, heads).unwrap();
1427 dag
1428}
1429
1430pub fn test_generic_dag<D: DagAddHeads + DagAlgorithm + IdConvert + Send + Sync + 'static>(
1432 new_dag: &impl Fn() -> D,
1433) {
1434 test_generic_dag1(new_dag()).unwrap();
1435 test_generic_dag2(new_dag()).unwrap();
1436 test_generic_dag_reachable_roots(new_dag()).unwrap();
1437 test_generic_dag_beautify(new_dag).unwrap();
1438}
1439
1440#[cfg(feature = "render")]
1441fn render(dag: &(impl DagAlgorithm + ?Sized)) -> String {
1442 render_dag(dag, |_| None).unwrap()
1443}
1444
1445#[cfg(test)]
1446pub(crate) fn nid(i: u64) -> Id {
1447 Group::NON_MASTER.min_id() + i
1448}
1449
1450#[cfg(test)]
1451pub(crate) fn vid(i: u64) -> Id {
1452 Group::VIRTUAL.min_id() + i
1453}
1454
1455#[cfg(test)]
1456pub(crate) fn dbg_iter<'a, T: std::fmt::Debug>(
1457 iter: Box<dyn Iterator<Item = Result<T>> + 'a>,
1458) -> String {
1459 let v = iter.map(|s| s.unwrap()).collect::<Vec<_>>();
1460 dbg(v)
1461}
1462
1463#[cfg(test)]
1464pub(crate) fn dbg<T: std::fmt::Debug>(t: T) -> String {
1465 format!("{:?}", t)
1466}