]>
Commit | Line | Data |
---|---|---|
ba9703b0 XL |
1 | extern crate cargo_metadata; |
2 | extern crate semver; | |
3 | #[macro_use] | |
4 | extern crate serde_json; | |
5 | ||
3dfed10e | 6 | use cargo_metadata::{CargoOpt, DependencyKind, Metadata, MetadataCommand}; |
ba9703b0 XL |
7 | use std::path::PathBuf; |
8 | ||
9 | #[test] | |
10 | fn 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 | ||
118 | macro_rules! sorted { | |
119 | ($e:expr) => {{ | |
120 | let mut v = $e.clone(); | |
121 | v.sort(); | |
122 | v | |
123 | }}; | |
124 | } | |
125 | ||
126 | fn 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] | |
144 | fn 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] | |
401 | fn 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] | |
470 | fn 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] | |
480 | fn 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} | |
484 | Evil 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] | |
501 | fn 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 | } |