onevcs_testing/lib.rs
1//! Test implementations of the two interfaces `onevcs` is built around.
2//!
3//! `onevcs` declares [`Vcs`](onevcs::Vcs) and [`RemoteHost`](onevcs::RemoteHost) so
4//! that a second implementation can be supplied, and
5//! [`Providers`](onevcs::Providers) is where one is. This crate is that second
6//! implementation: four providers, two flavours of each interface, so a consumer
7//! can drive a real `onevcs` through a real journey without a real GitHub — and
8//! without the scripted fake binary that substituting the whole CLI amounts to.
9//!
10//! # Why a separate crate rather than a feature
11//!
12//! Cargo features are additive across a dependency graph, so a feature that
13//! switched these on could be switched on by somebody else's dependency and end up
14//! inside a release binary. A crate a consumer puts in `dev-dependencies` cannot.
15//!
16//! # The two flavours
17//!
18//! | | State | Use it when |
19//! | --- | --- | --- |
20//! | [`MemoryVcs`] / [`MemoryHost`] | this process | one invocation, no filesystem, fastest |
21//! | [`FileVcs`] / [`FileHost`] | one JSON document | several invocations that must see one another |
22//!
23//! Both flavours are one implementation over a different [`Store`], so a behaviour
24//! cannot exist in one and not the other. Both are constructible empty and seeded
25//! from a [`VcsState`] or [`HostState`], and both hand their state back.
26//!
27//! # What they are honest about
28//!
29//! They emit the events the real implementations emit, into the same
30//! `$ONEVCS_HOME` stream the real ones write, so `onevcs events TOKEN` and
31//! `onevcs artifact cat ID` read a provider's run exactly as they read a real one.
32//! That is checked rather than asserted: `publication_events_match_across_backends`
33//! in the crate next door runs one publication twice — once on `Git` + `GitHub`,
34//! once on these — and holds the two event streams to each other.
35//!
36//! What they are *not* is git and GitHub. Nothing here clones, commits, pushes, or
37//! moves a ref; a merge records an outcome and no origin advances. A journey about
38//! git drives the real `Git`. A publication is the sharpest case of that: its host
39//! side really happens — a change request is opened, adopted, and merged on the
40//! [`Hosting`](onevcs::Hosting) it was handed — and its repository side does not,
41//! so nothing here emits a `fetch`, a gate verdict, a push, or a lock it did not
42//! take.
43//!
44//! ```no_run
45//! use onevcs::{Providers, cli::Cli, run_with};
46//! use onevcs_testing::{MemoryHost, MemoryVcs};
47//! use clap::Parser;
48//!
49//! let vcs = MemoryVcs::new();
50//! let host = MemoryHost::new();
51//! let cli = Cli::parse_from(["onevcs", "recoverable"]);
52//! let code = run_with(&cli, Providers { vcs: &vcs, hosting: &host });
53//!
54//! assert_eq!(code, 0);
55//! assert!(vcs.state().preserved.is_empty());
56//! ```
57
58#![warn(missing_docs)]
59
60mod events;
61mod remote;
62mod repository;
63mod state;
64mod store;
65
66pub use remote::{FileHost, Host, MemoryHost, DEFAULT_HOST, DEFAULT_SLUG};
67pub use repository::{FileVcs, MemoryVcs, Repository, DEFAULT_BASE, DEFAULT_PUBLICATION};
68pub use state::{HostState, VcsState, DEFAULT_AUTHENTICATED_USER, STATE_VERSION};
69pub use store::{Checked, FileStore, MemoryStore, Store};