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
use super::*;
/// When the user is sandwiched between two `[workspace]`
/// roots - and the outer does NOT list the nested directory
/// as a member - discovery still errors rather than silently
/// picking one. The strict rule names both roots, so the
/// user can disambiguate by passing `--manifest-path`
/// explicitly; an earlier rule only rejected the nested case
/// via the loader and only when the outer claimed the nested
/// as a member.
#[test]
fn metadata_inside_nested_workspace_with_unrelated_outer_errors() {
let dir = TempDir::new().unwrap();
dir.child("cabin.toml")
.write_str(
r#"[workspace]
members = []
"#,
)
.unwrap();
dir.child("nested/cabin.toml")
.write_str(
r#"[workspace]
members = []
"#,
)
.unwrap();
cabin()
.current_dir(dir.path().join("nested"))
.args(["metadata"])
.assert()
.failure()
.stderr(predicate::str::contains("nested workspace detected"));
}
/// Selection-aware materialization. With workspace
/// `app + b`, where `b` (unrelated to `app`) declares a
/// versioned dep `spdlog` that is *not* in the registry, and
/// the registry only carries `fmt` (which `app` uses),
/// `cabin resolve -p app` must not error on the missing
/// `spdlog` because `b` is outside the selected closure.
#[test]
fn resolve_p_app_does_not_require_unrelated_dep_in_registry() {
let dir = TempDir::new().unwrap();
dir.child("cabin.toml")
.write_str(
r#"[workspace]
members = ["packages/*"]
"#,
)
.unwrap();
dir.child("packages/app/cabin.toml")
.write_str(
r#"[package]
name = "app"
version = "0.1.0"
[dependencies]
fmt = ">=10.0.0 <11.0.0"
"#,
)
.unwrap();
// `b` declares a dep on `spdlog` that the registry does
// not carry. Selection-aware materialization must skip it.
dir.child("packages/b/cabin.toml")
.write_str(
r#"[package]
name = "b"
version = "0.1.0"
[dependencies]
spdlog = "^1"
"#,
)
.unwrap();
dir.child("index/fmt.json")
.write_str(r#"{
"schema": 1,
"name": "fmt",
"versions": {
"10.2.1": { "dependencies": {}, "yanked": false, "checksum": "sha256:0000000000000000000000000000000000000000000000000000000000000000" }
}
}"#)
.unwrap();
cabin()
.args(["resolve", "--manifest-path"])
.arg(dir.path().join("cabin.toml"))
.args(["--package", "app", "--index-path"])
.arg(dir.path().join("index"))
.assert()
.success();
}
/// `cabin update --package <name>` only refreshes direct
/// versioned deps. Even if a transitive locked package would
/// otherwise be reachable via the lockfile, the CLI rejects
/// it explicitly.
#[test]
fn update_package_rejects_transitive() {
let dir = TempDir::new().unwrap();
dir.child("cabin.toml")
.write_str(
r#"[package]
name = "demo"
version = "0.1.0"
[dependencies]
fmt = ">=10.0.0 <11.0.0"
"#,
)
.unwrap();
dir.child("index/fmt.json")
.write_str(r#"{
"schema": 1,
"name": "fmt",
"versions": {
"10.2.1": { "dependencies": {}, "yanked": false, "checksum": "sha256:0000000000000000000000000000000000000000000000000000000000000000" }
}
}"#)
.unwrap();
cabin()
.args(["update", "--manifest-path"])
.arg(dir.path().join("cabin.toml"))
.args(["--package", "spdlog", "--index-path"])
.arg(dir.path().join("index"))
.assert()
.failure()
.stderr(predicate::str::contains(
"only refreshes direct dependencies",
));
}