]> git.proxmox.com Git - rustc.git/blame - vendor/cargo_metadata-0.11.2/tests/test_samples.rs
New upstream version 1.50.0+dfsg1
[rustc.git] / vendor / cargo_metadata-0.11.2 / tests / test_samples.rs
CommitLineData
ba9703b0
XL
1extern crate cargo_metadata;
2extern crate semver;
3#[macro_use]
4extern crate serde_json;
5
3dfed10e 6use cargo_metadata::{CargoOpt, DependencyKind, Metadata, MetadataCommand};
ba9703b0
XL
7use std::path::PathBuf;
8
9#[test]
10fn old_minimal() {
11 // Output from oldest supported version (1.24).
12 // This intentionally has as many null fields as possible.
13 // 1.8 is when metadata was introduced.
14 // Older versions not supported because the following are required:
15 // - `workspace_members` added in 1.13
16 // - `target_directory` added in 1.19
17 // - `workspace_root` added in 1.24
18 let json = r#"
19{
20 "packages": [
21 {
22 "name": "foo",
23 "version": "0.1.0",
24 "id": "foo 0.1.0 (path+file:///foo)",
25 "license": null,
26 "license_file": null,
27 "description": null,
28 "source": null,
29 "dependencies": [
30 {
31 "name": "somedep",
32 "source": null,
33 "req": "^1.0",
34 "kind": null,
35 "optional": false,
36 "uses_default_features": true,
37 "features": [],
38 "target": null
39 }
40 ],
41 "targets": [
42 {
43 "kind": [
44 "bin"
45 ],
46 "crate_types": [
47 "bin"
48 ],
49 "name": "foo",
50 "src_path": "/foo/src/main.rs"
51 }
52 ],
53 "features": {},
54 "manifest_path": "/foo/Cargo.toml"
55 }
56 ],
57 "workspace_members": [
58 "foo 0.1.0 (path+file:///foo)"
59 ],
60 "resolve": null,
61 "target_directory": "/foo/target",
62 "version": 1,
63 "workspace_root": "/foo"
64}
65"#;
66 let meta: Metadata = serde_json::from_str(json).unwrap();
67 assert_eq!(meta.packages.len(), 1);
68 let pkg = &meta.packages[0];
69 assert_eq!(pkg.name, "foo");
70 assert_eq!(pkg.version, semver::Version::parse("0.1.0").unwrap());
71 assert_eq!(pkg.authors.len(), 0);
72 assert_eq!(pkg.id.to_string(), "foo 0.1.0 (path+file:///foo)");
73 assert_eq!(pkg.description, None);
74 assert_eq!(pkg.license, None);
75 assert_eq!(pkg.license_file, None);
76 assert_eq!(pkg.dependencies.len(), 1);
77 let dep = &pkg.dependencies[0];
78 assert_eq!(dep.name, "somedep");
79 assert_eq!(dep.source, None);
80 assert_eq!(dep.req, semver::VersionReq::parse("^1.0").unwrap());
81 assert_eq!(dep.kind, DependencyKind::Normal);
82 assert_eq!(dep.optional, false);
83 assert_eq!(dep.uses_default_features, true);
84 assert_eq!(dep.features.len(), 0);
85 assert!(dep.target.is_none());
86 assert_eq!(dep.rename, None);
87 assert_eq!(dep.registry, None);
88 assert_eq!(pkg.targets.len(), 1);
89 let target = &pkg.targets[0];
90 assert_eq!(target.name, "foo");
91 assert_eq!(target.kind, vec!["bin"]);
92 assert_eq!(target.crate_types, vec!["bin"]);
93 assert_eq!(target.required_features.len(), 0);
94 assert_eq!(target.src_path, PathBuf::from("/foo/src/main.rs"));
95 assert_eq!(target.edition, "2015");
96 assert_eq!(target.doctest, true);
1b1a35ee 97 assert_eq!(target.test, true);
ba9703b0
XL
98 assert_eq!(pkg.features.len(), 0);
99 assert_eq!(pkg.manifest_path, PathBuf::from("/foo/Cargo.toml"));
100 assert_eq!(pkg.categories.len(), 0);
101 assert_eq!(pkg.keywords.len(), 0);
102 assert_eq!(pkg.readme, None);
103 assert_eq!(pkg.repository, None);
104 assert_eq!(pkg.edition, "2015");
105 assert_eq!(pkg.metadata, serde_json::Value::Null);
106 assert_eq!(pkg.links, None);
107 assert_eq!(pkg.publish, None);
108 assert_eq!(meta.workspace_members.len(), 1);
109 assert_eq!(
110 meta.workspace_members[0].to_string(),
111 "foo 0.1.0 (path+file:///foo)"
112 );
113 assert!(meta.resolve.is_none());
114 assert_eq!(meta.workspace_root, PathBuf::from("/foo"));
115 assert_eq!(meta.target_directory, PathBuf::from("/foo/target"));
116}
117
118macro_rules! sorted {
119 ($e:expr) => {{
120 let mut v = $e.clone();
121 v.sort();
122 v
123 }};
124}
125
126fn cargo_version() -> semver::Version {
127 let output = std::process::Command::new("cargo")
128 .arg("-V")
129 .output()
130 .expect("Failed to exec cargo.");
131 let out = std::str::from_utf8(&output.stdout)
132 .expect("invalid utf8")
133 .trim();
134 let split: Vec<&str> = out.split_whitespace().collect();
135 assert!(split.len() >= 2, "cargo -V output is unexpected: {}", out);
136 let mut ver = semver::Version::parse(split[1]).expect("cargo -V semver could not be parsed");
137 // Don't care about metadata, it is awkward to compare.
138 ver.pre = Vec::new();
139 ver.build = Vec::new();
140 ver
141}
142
143#[test]
144fn all_the_fields() {
1b1a35ee 145 // All the fields currently generated as of 1.47. This tries to exercise as
ba9703b0
XL
146 // much as possible.
147 let ver = cargo_version();
1b1a35ee 148 let minimum = semver::Version::parse("1.47.0").unwrap();
ba9703b0
XL
149 if ver < minimum {
150 // edition added in 1.30
151 // rename added in 1.31
152 // links added in 1.33
153 // doctest added in 1.37
154 // publish added in 1.39
155 // dep_kinds added in 1.41
1b1a35ee 156 // test added in 1.47
ba9703b0
XL
157 eprintln!("Skipping all_the_fields test, cargo {} is too old.", ver);
158 return;
159 }
160 let meta = MetadataCommand::new()
161 .manifest_path("tests/all/Cargo.toml")
162 .exec()
163 .unwrap();
164 assert_eq!(
165 meta.workspace_root.file_name().unwrap(),
166 PathBuf::from("all")
167 );
ba9703b0
XL
168 assert_eq!(meta.workspace_members.len(), 1);
169 assert!(meta.workspace_members[0].to_string().starts_with("all"));
170
171 assert_eq!(meta.packages.len(), 9);
172 let all = meta.packages.iter().find(|p| p.name == "all").unwrap();
173 assert_eq!(all.version, semver::Version::parse("0.1.0").unwrap());
174 assert_eq!(all.authors, vec!["Jane Doe <user@example.com>"]);
175 assert!(all.id.to_string().starts_with("all"));
176 assert_eq!(all.description, Some("Package description.".to_string()));
177 assert_eq!(all.license, Some("MIT/Apache-2.0".to_string()));
178 assert_eq!(all.license_file, Some(PathBuf::from("LICENSE")));
f035d41b 179 assert!(all.license_file().unwrap().ends_with("tests/all/LICENSE"));
ba9703b0
XL
180 assert_eq!(all.publish, Some(vec![]));
181 assert_eq!(all.links, Some("foo".to_string()));
182
183 assert_eq!(all.dependencies.len(), 8);
184 let bitflags = all
185 .dependencies
186 .iter()
187 .find(|d| d.name == "bitflags")
188 .unwrap();
189 assert_eq!(
190 bitflags.source,
191 Some("registry+https://github.com/rust-lang/crates.io-index".to_string())
192 );
193 assert_eq!(bitflags.optional, true);
194 assert_eq!(bitflags.req, semver::VersionReq::parse("^1.0").unwrap());
195
196 let path_dep = all
197 .dependencies
198 .iter()
199 .find(|d| d.name == "path-dep")
200 .unwrap();
201 assert_eq!(path_dep.source, None);
202 assert_eq!(path_dep.kind, DependencyKind::Normal);
203 assert_eq!(path_dep.req, semver::VersionReq::parse("*").unwrap());
204
205 all.dependencies
206 .iter()
207 .find(|d| d.name == "namedep")
208 .unwrap();
209
210 let featdep = all
211 .dependencies
212 .iter()
213 .find(|d| d.name == "featdep")
214 .unwrap();
215 assert_eq!(featdep.features, vec!["i128"]);
216 assert_eq!(featdep.uses_default_features, false);
217
218 let renamed = all
219 .dependencies
220 .iter()
221 .find(|d| d.name == "oldname")
222 .unwrap();
223 assert_eq!(renamed.rename, Some("newname".to_string()));
224
225 let devdep = all
226 .dependencies
227 .iter()
228 .find(|d| d.name == "devdep")
229 .unwrap();
230 assert_eq!(devdep.kind, DependencyKind::Development);
231
232 let bdep = all.dependencies.iter().find(|d| d.name == "bdep").unwrap();
233 assert_eq!(bdep.kind, DependencyKind::Build);
234
235 let windep = all
236 .dependencies
237 .iter()
238 .find(|d| d.name == "windep")
239 .unwrap();
240 assert_eq!(
241 windep.target.as_ref().map(|x| x.to_string()),
242 Some("cfg(windows)".to_string())
243 );
244
245 macro_rules! get_file_name {
246 ($v:expr) => {
247 all.targets
248 .iter()
249 .find(|t| t.src_path.file_name().unwrap() == $v)
250 .unwrap()
251 };
252 }
253 assert_eq!(all.targets.len(), 8);
254 let lib = get_file_name!("lib.rs");
255 assert_eq!(lib.name, "all");
256 assert_eq!(
257 sorted!(lib.kind),
258 vec!["cdylib", "dylib", "rlib", "staticlib"]
259 );
260 assert_eq!(
261 sorted!(lib.crate_types),
262 vec!["cdylib", "dylib", "rlib", "staticlib"]
263 );
264 assert_eq!(lib.required_features.len(), 0);
265 assert_eq!(lib.edition, "2018");
266 assert_eq!(lib.doctest, true);
1b1a35ee 267 assert_eq!(lib.test, true);
ba9703b0
XL
268
269 let main = get_file_name!("main.rs");
270 assert_eq!(main.crate_types, vec!["bin"]);
271 assert_eq!(main.kind, vec!["bin"]);
272 assert_eq!(main.doctest, false);
1b1a35ee 273 assert_eq!(main.test, true);
ba9703b0
XL
274
275 let otherbin = get_file_name!("otherbin.rs");
276 assert_eq!(otherbin.edition, "2015");
277
278 let reqfeat = get_file_name!("reqfeat.rs");
279 assert_eq!(reqfeat.required_features, vec!["feat2"]);
280
281 let ex1 = get_file_name!("ex1.rs");
282 assert_eq!(ex1.kind, vec!["example"]);
1b1a35ee 283 assert_eq!(ex1.test, false);
ba9703b0
XL
284
285 let t1 = get_file_name!("t1.rs");
286 assert_eq!(t1.kind, vec!["test"]);
287
288 let b1 = get_file_name!("b1.rs");
289 assert_eq!(b1.kind, vec!["bench"]);
290
291 let build = get_file_name!("build.rs");
292 assert_eq!(build.kind, vec!["custom-build"]);
293
294 assert_eq!(all.features.len(), 3);
295 assert_eq!(all.features["feat1"].len(), 0);
296 assert_eq!(all.features["feat2"].len(), 0);
297 assert_eq!(sorted!(all.features["default"]), vec!["bitflags", "feat1"]);
298
299 assert!(all.manifest_path.ends_with("all/Cargo.toml"));
300 assert_eq!(all.categories, vec!["command-line-utilities"]);
301 assert_eq!(all.keywords, vec!["cli"]);
302 assert_eq!(all.readme, Some(PathBuf::from("README.md")));
303 assert_eq!(
304 all.repository,
305 Some("https://github.com/oli-obk/cargo_metadata/".to_string())
306 );
307 assert_eq!(all.edition, "2018");
308 assert_eq!(
309 all.metadata,
310 json!({
311 "docs": {
312 "rs": {
313 "all-features": true,
314 "default-target": "x86_64-unknown-linux-gnu",
315 "rustc-args": ["--example-rustc-arg"]
316 }
317 }
318 })
319 );
320
321 let resolve = meta.resolve.as_ref().unwrap();
322 assert!(resolve
323 .root
324 .as_ref()
325 .unwrap()
326 .to_string()
327 .starts_with("all"));
328
329 assert_eq!(resolve.nodes.len(), 9);
330 let path_dep = resolve
331 .nodes
332 .iter()
333 .find(|n| n.id.to_string().starts_with("path-dep"))
334 .unwrap();
335 assert_eq!(path_dep.deps.len(), 0);
336 assert_eq!(path_dep.dependencies.len(), 0);
337 assert_eq!(path_dep.features.len(), 0);
338
339 let bitflags = resolve
340 .nodes
341 .iter()
342 .find(|n| n.id.to_string().starts_with("bitflags"))
343 .unwrap();
344 assert_eq!(bitflags.features, vec!["default"]);
345
346 let featdep = resolve
347 .nodes
348 .iter()
349 .find(|n| n.id.to_string().starts_with("featdep"))
350 .unwrap();
351 assert_eq!(featdep.features, vec!["i128"]);
352
353 let all = resolve
354 .nodes
355 .iter()
356 .find(|n| n.id.to_string().starts_with("all"))
357 .unwrap();
358 assert_eq!(all.dependencies.len(), 8);
359 assert_eq!(all.deps.len(), 8);
360 let newname = all.deps.iter().find(|d| d.name == "newname").unwrap();
361 assert!(newname.pkg.to_string().starts_with("oldname"));
362 // Note the underscore here.
363 let path_dep = all.deps.iter().find(|d| d.name == "path_dep").unwrap();
364 assert!(path_dep.pkg.to_string().starts_with("path-dep"));
365 assert_eq!(path_dep.dep_kinds.len(), 1);
366 let kind = &path_dep.dep_kinds[0];
367 assert_eq!(kind.kind, DependencyKind::Normal);
368 assert!(kind.target.is_none());
369
370 let namedep = all
371 .deps
372 .iter()
373 .find(|d| d.name == "different_name")
374 .unwrap();
375 assert!(namedep.pkg.to_string().starts_with("namedep"));
376 assert_eq!(sorted!(all.features), vec!["bitflags", "default", "feat1"]);
377
378 let bdep = all.deps.iter().find(|d| d.name == "bdep").unwrap();
379 assert_eq!(bdep.dep_kinds.len(), 1);
380 let kind = &bdep.dep_kinds[0];
381 assert_eq!(kind.kind, DependencyKind::Build);
382 assert!(kind.target.is_none());
383
384 let devdep = all.deps.iter().find(|d| d.name == "devdep").unwrap();
385 assert_eq!(devdep.dep_kinds.len(), 1);
386 let kind = &devdep.dep_kinds[0];
387 assert_eq!(kind.kind, DependencyKind::Development);
388 assert!(kind.target.is_none());
389
390 let windep = all.deps.iter().find(|d| d.name == "windep").unwrap();
391 assert_eq!(windep.dep_kinds.len(), 1);
392 let kind = &windep.dep_kinds[0];
393 assert_eq!(kind.kind, DependencyKind::Normal);
394 assert_eq!(
395 kind.target.as_ref().map(|x| x.to_string()),
396 Some("cfg(windows)".to_string())
397 );
398}
399
400#[test]
401fn alt_registry() {
402 // This is difficult to test (would need to set up a custom index).
403 // Just manually check the JSON is handled.
404 let json = r#"
405{
406 "packages": [
407 {
408 "name": "alt",
409 "version": "0.1.0",
410 "id": "alt 0.1.0 (path+file:///alt)",
411 "source": null,
412 "dependencies": [
413 {
414 "name": "alt2",
415 "source": "registry+https://example.com",
416 "req": "^0.1",
417 "kind": null,
418 "rename": null,
419 "optional": false,
420 "uses_default_features": true,
421 "features": [],
422 "target": null,
423 "registry": "https://example.com"
424 }
425 ],
426 "targets": [
427 {
428 "kind": [
429 "lib"
430 ],
431 "crate_types": [
432 "lib"
433 ],
434 "name": "alt",
435 "src_path": "/alt/src/lib.rs",
436 "edition": "2018"
437 }
438 ],
439 "features": {},
440 "manifest_path": "/alt/Cargo.toml",
441 "metadata": null,
442 "authors": [],
443 "categories": [],
444 "keywords": [],
445 "readme": null,
446 "repository": null,
447 "edition": "2018",
448 "links": null
449 }
450 ],
451 "workspace_members": [
452 "alt 0.1.0 (path+file:///alt)"
453 ],
454 "resolve": null,
455 "target_directory": "/alt/target",
456 "version": 1,
457 "workspace_root": "/alt"
458}
459"#;
460 let meta: Metadata = serde_json::from_str(json).unwrap();
461 assert_eq!(meta.packages.len(), 1);
462 let alt = &meta.packages[0];
463 let deps = &alt.dependencies;
464 assert_eq!(deps.len(), 1);
465 let dep = &deps[0];
466 assert_eq!(dep.registry, Some("https://example.com".to_string()));
467}
468
469#[test]
470fn current_dir() {
471 let meta = MetadataCommand::new()
472 .current_dir("tests/all/namedep")
473 .exec()
474 .unwrap();
475 let namedep = meta.packages.iter().find(|p| p.name == "namedep").unwrap();
476 assert!(namedep.name.starts_with("namedep"));
477}
f035d41b
XL
478
479#[test]
480fn parse_stream_is_robust() {
481 // Proc macros can print stuff to stdout, which naturally breaks JSON messages.
482 // Let's check that we don't die horribly in this case, and report an error.
483 let json_output = r##"{"reason":"compiler-artifact","package_id":"chatty 0.1.0 (path+file:///chatty-macro/chatty)","target":{"kind":["proc-macro"],"crate_types":["proc-macro"],"name":"chatty","src_path":"/chatty-macro/chatty/src/lib.rs","edition":"2018","doctest":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/chatty-macro/target/debug/deps/libchatty-f2adcff24cdf3bb2.so"],"executable":null,"fresh":false}
484Evil proc macro was here!
485{"reason":"compiler-artifact","package_id":"chatty-macro 0.1.0 (path+file:///chatty-macro)","target":{"kind":["lib"],"crate_types":["lib"],"name":"chatty-macro","src_path":"/chatty-macro/src/lib.rs","edition":"2018","doctest":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/chatty-macro/target/debug/libchatty_macro.rlib","/chatty-macro/target/debug/deps/libchatty_macro-cb5956ed52a11fb6.rmeta"],"executable":null,"fresh":false}
486"##;
487 let mut n_messages = 0;
488 let mut text = String::new();
489 for message in cargo_metadata::Message::parse_stream(json_output.as_bytes()) {
490 let message = message.unwrap();
491 match message {
492 cargo_metadata::Message::TextLine(line) => text = line,
493 _ => n_messages += 1,
494 }
495 }
496 assert_eq!(n_messages, 2);
497 assert_eq!(text, "Evil proc macro was here!");
498}
3dfed10e
XL
499
500#[test]
501fn advanced_feature_configuration() {
502 fn build_features<F: FnOnce(&mut MetadataCommand) -> &mut MetadataCommand>(
503 func: F,
504 ) -> Vec<String> {
505 let mut meta = MetadataCommand::new();
506 let meta = meta.manifest_path("tests/all/Cargo.toml");
507
508 let meta = func(meta);
509 let meta = meta.exec().unwrap();
510
511 let resolve = meta.resolve.as_ref().unwrap();
512
513 let all = resolve
514 .nodes
515 .iter()
516 .find(|n| n.id.to_string().starts_with("all"))
517 .unwrap();
518
519 all.features.clone()
520 }
521
522 // Default behavior; tested above
523 let default_features = build_features(|meta| meta);
524 assert_eq!(
525 sorted!(default_features),
526 vec!["bitflags", "default", "feat1"]
527 );
528
529 // Manually specify the same default features
530 let manual_features = build_features(|meta| {
531 meta.features(CargoOpt::NoDefaultFeatures)
532 .features(CargoOpt::SomeFeatures(vec![
533 "feat1".into(),
534 "bitflags".into(),
535 ]))
536 });
537 assert_eq!(sorted!(manual_features), vec!["bitflags", "feat1"]);
538
539 // Multiple SomeFeatures is same as one longer SomeFeatures
540 let manual_features = build_features(|meta| {
541 meta.features(CargoOpt::NoDefaultFeatures)
542 .features(CargoOpt::SomeFeatures(vec!["feat1".into()]))
543 .features(CargoOpt::SomeFeatures(vec!["feat2".into()]))
544 });
545 assert_eq!(sorted!(manual_features), vec!["feat1", "feat2"]);
546
547 // No features + All features == All features
548 let all_features = build_features(|meta| {
549 meta.features(CargoOpt::AllFeatures)
550 .features(CargoOpt::NoDefaultFeatures)
551 });
552 assert_eq!(
553 sorted!(all_features),
554 vec!["bitflags", "default", "feat1", "feat2"]
555 );
556
557 // The '--all-features' flag supersedes other feature flags
558 let all_flag_variants = build_features(|meta| {
559 meta.features(CargoOpt::SomeFeatures(vec!["feat2".into()]))
560 .features(CargoOpt::NoDefaultFeatures)
561 .features(CargoOpt::AllFeatures)
562 });
563 assert_eq!(sorted!(all_flag_variants), sorted!(all_features));
564}