tests.rs (61437B)
1 use super::{ 2 DependenciesErr, FeatureDependenciesErr, Features, FeaturesErr, ImpliedFeaturesErr, Manifest, 3 ManifestErr, Msrv, NonZeroUsizePlus1, Package, PackageErr, Path, PathBuf, PowerSet, 4 TooManyFeaturesErr, TryLockError, WorkspaceErr, 5 }; 6 impl PartialEq for PackageErr { 7 #[expect(clippy::cognitive_complexity, reason = "long match expression")] 8 fn eq(&self, other: &Self) -> bool { 9 match *self { 10 Self::Missing => matches!(*other, Self::Missing), 11 Self::InvalidType => matches!(*other, Self::InvalidType), 12 Self::MissingName => matches!(*other, Self::MissingName), 13 Self::InvalidNameType => matches!(*other, Self::InvalidNameType), 14 Self::InvalidMsrvType => matches!(*other, Self::InvalidMsrvType), 15 Self::Msrv => matches!(*other, Self::Msrv), 16 Self::MsrvWorkspaceMissing => matches!(*other, Self::MsrvWorkspaceMissing), 17 Self::MsrvWorkspaceVal => matches!(*other, Self::MsrvWorkspaceVal), 18 Self::InvalidWorkspaceType => matches!(*other, Self::InvalidWorkspaceType), 19 Self::WorkspaceIo(ref e) => { 20 matches!(*other, Self::WorkspaceIo(ref e2) if e.kind() == e2.kind()) 21 } 22 Self::WorkspaceLock(ref e) => { 23 matches!(*other, Self::WorkspaceLock(ref e2) if match *e { 24 TryLockError::Error(ref inner_e) => matches!(*e2, TryLockError::Error(ref inner_e2) if inner_e.kind() == inner_e2.kind()), 25 TryLockError::WouldBlock => matches!(*e2, TryLockError::WouldBlock), 26 }) 27 } 28 Self::WorkspaceLenMismatch => matches!(*other, Self::WorkspaceLenMismatch), 29 Self::WorkspaceDoesNotExist => matches!(*other, Self::WorkspaceDoesNotExist), 30 Self::WorkspaceRead(ref e, ref p) => { 31 matches!(*other, Self::WorkspaceRead(ref e2, ref p2) if e.kind() == e2.kind() && p == p2) 32 } 33 Self::WorkspaceReadLock(ref e, ref p) => { 34 matches!(*other, Self::WorkspaceReadLock(ref e2, ref p2) if p == p2 && match *e { 35 TryLockError::Error(ref inner_e) => matches!(*e2, TryLockError::Error(ref inner_e2) if inner_e.kind() == inner_e2.kind()), 36 TryLockError::WouldBlock => matches!(*e2, TryLockError::WouldBlock), 37 }) 38 } 39 Self::WorkspaceReadLenMismatch(ref p) => { 40 matches!(*other, Self::WorkspaceReadLenMismatch(ref p2) if p == p2) 41 } 42 Self::WorkspaceToml(ref e, ref p) => { 43 matches!(*other, Self::WorkspaceToml(ref e2, ref p2) if e == e2 && p == p2) 44 } 45 Self::Workspace(e, ref p) => { 46 matches!(*other, Self::Workspace(e2, ref p2) if e == e2 && p == p2) 47 } 48 } 49 } 50 } 51 #[expect( 52 clippy::cognitive_complexity, 53 clippy::too_many_lines, 54 reason = "want to test a lot of things" 55 )] 56 #[test] 57 fn cargo_toml() { 58 assert!( 59 Manifest::from_toml("a".to_owned(), false, Path::new(""), &[]) 60 .map_or_else(|e| matches!(*e, ManifestErr::Toml(_, _)), |_| false) 61 ); 62 assert_eq!( 63 Manifest::from_toml(String::new(), false, Path::new(""), &[]), 64 Err(Box::new(ManifestErr::Package( 65 PackageErr::Missing, 66 PathBuf::new() 67 ))) 68 ); 69 assert_eq!( 70 Manifest::from_toml("[' package']".to_owned(), false, Path::new(""), &[]), 71 Err(Box::new(ManifestErr::Package( 72 PackageErr::Missing, 73 PathBuf::new() 74 ))) 75 ); 76 assert_eq!( 77 Manifest::from_toml("['package ']".to_owned(), false, Path::new(""), &[]), 78 Err(Box::new(ManifestErr::Package( 79 PackageErr::Missing, 80 PathBuf::new() 81 ))) 82 ); 83 assert_eq!( 84 Manifest::from_toml("package=2".to_owned(), false, Path::new(""), &[]), 85 Err(Box::new(ManifestErr::Package( 86 PackageErr::InvalidType, 87 PathBuf::new() 88 ))) 89 ); 90 assert_eq!( 91 Manifest::from_toml("[package]".to_owned(), false, Path::new(""), &[]), 92 Err(Box::new(ManifestErr::Package( 93 PackageErr::MissingName, 94 PathBuf::new() 95 ))) 96 ); 97 assert_eq!( 98 Manifest::from_toml("[package]\nname=true".to_owned(), false, Path::new(""), &[]), 99 Err(Box::new(ManifestErr::Package( 100 PackageErr::InvalidNameType, 101 PathBuf::new() 102 ))) 103 ); 104 assert_eq!( 105 Manifest::from_toml( 106 "[package]\nname=\"\"\n\nrust-version=2".to_owned(), 107 false, 108 Path::new(""), 109 &[] 110 ), 111 Err(Box::new(ManifestErr::Package( 112 PackageErr::InvalidMsrvType, 113 PathBuf::new() 114 ))) 115 ); 116 assert_eq!( 117 Manifest::from_toml( 118 "[package]\nname=\"\"\nrust-version=\"\"".to_owned(), 119 false, 120 Path::new(""), 121 &[] 122 ), 123 Err(Box::new(ManifestErr::Package( 124 PackageErr::Msrv, 125 PathBuf::new() 126 ))) 127 ); 128 assert_eq!( 129 Manifest::from_toml( 130 "[package]\nname=\"\"\nrust-version=\"a\"".to_owned(), 131 false, 132 Path::new(""), 133 &[] 134 ), 135 Err(Box::new(ManifestErr::Package( 136 PackageErr::Msrv, 137 PathBuf::new() 138 ))) 139 ); 140 assert_eq!( 141 Manifest::from_toml( 142 "[package]\nname=\"\"\nrust-version=\"1.00.0\"".to_owned(), 143 false, 144 Path::new(""), 145 &[] 146 ), 147 Err(Box::new(ManifestErr::Package( 148 PackageErr::Msrv, 149 PathBuf::new() 150 ))) 151 ); 152 assert_eq!( 153 Manifest::from_toml( 154 "[package]\nname=\"\"\nrust-version=\"1..0\"".to_owned(), 155 false, 156 Path::new(""), 157 &[] 158 ), 159 Err(Box::new(ManifestErr::Package( 160 PackageErr::Msrv, 161 PathBuf::new() 162 ))) 163 ); 164 assert_eq!( 165 Manifest::from_toml( 166 "[package]\nname=\"\"\nrust-version=\"1.\"".to_owned(), 167 false, 168 Path::new(""), 169 &[] 170 ), 171 Err(Box::new(ManifestErr::Package( 172 PackageErr::Msrv, 173 PathBuf::new() 174 ))) 175 ); 176 assert_eq!( 177 Manifest::from_toml( 178 "[package]\nname=\"\"\nrust-version=\"01.0.0\"".to_owned(), 179 false, 180 Path::new(""), 181 &[] 182 ), 183 Err(Box::new(ManifestErr::Package( 184 PackageErr::Msrv, 185 PathBuf::new() 186 ))) 187 ); 188 assert_eq!( 189 Manifest::from_toml( 190 "[package]\nname=\"\"\nrust-version=\"1.0.0.1\"".to_owned(), 191 false, 192 Path::new(""), 193 &[] 194 ), 195 Err(Box::new(ManifestErr::Package( 196 PackageErr::Msrv, 197 PathBuf::new() 198 ))) 199 ); 200 assert_eq!( 201 Manifest::from_toml( 202 "[package]\nname=\"\"\nrust-version=\"111111111111111111111111.2.3\"".to_owned(), 203 false, 204 Path::new(""), 205 &[] 206 ), 207 Err(Box::new(ManifestErr::Package( 208 PackageErr::Msrv, 209 PathBuf::new() 210 ))) 211 ); 212 assert_eq!( 213 Manifest::from_toml( 214 "[package]\nname=\"\"\nrust-version=\"1.0.0-nightly\"".to_owned(), 215 false, 216 Path::new(""), 217 &[] 218 ), 219 Err(Box::new(ManifestErr::Package( 220 PackageErr::Msrv, 221 PathBuf::new() 222 ))) 223 ); 224 assert_eq!( 225 Manifest::from_toml( 226 "[package]\nname=\"\"\nrust-version=\"-1.0.0\"".to_owned(), 227 false, 228 Path::new(""), 229 &[] 230 ), 231 Err(Box::new(ManifestErr::Package( 232 PackageErr::Msrv, 233 PathBuf::new() 234 ))) 235 ); 236 assert_eq!( 237 Manifest::from_toml( 238 "[package]\nname=\"\"\nrust-version=\" 1.0.0\"".to_owned(), 239 false, 240 Path::new(""), 241 &[] 242 ), 243 Err(Box::new(ManifestErr::Package( 244 PackageErr::Msrv, 245 PathBuf::new() 246 ))) 247 ); 248 assert_eq!( 249 Manifest::from_toml( 250 "[package]\nname=\"\"\nrust-version=\"1.0.0 \"".to_owned(), 251 false, 252 Path::new(""), 253 &[] 254 ), 255 Err(Box::new(ManifestErr::Package( 256 PackageErr::Msrv, 257 PathBuf::new() 258 ))) 259 ); 260 assert_eq!( 261 Manifest::from_toml( 262 "[package]\nname=\"\"\nrust-version={}".to_owned(), 263 false, 264 Path::new(""), 265 &[] 266 ), 267 Err(Box::new(ManifestErr::Package( 268 PackageErr::MsrvWorkspaceMissing, 269 PathBuf::new() 270 ))) 271 ); 272 assert_eq!( 273 Manifest::from_toml( 274 "[package]\nname=\"\"\nrust-version={workspace=2}".to_owned(), 275 false, 276 Path::new(""), 277 &[] 278 ), 279 Err(Box::new(ManifestErr::Package( 280 PackageErr::MsrvWorkspaceVal, 281 PathBuf::new() 282 ))) 283 ); 284 assert_eq!( 285 Manifest::from_toml( 286 "[package]\nname=\"\"\nrust-version={workspace=false}".to_owned(), 287 false, 288 Path::new(""), 289 &[] 290 ), 291 Err(Box::new(ManifestErr::Package( 292 PackageErr::MsrvWorkspaceVal, 293 PathBuf::new() 294 ))) 295 ); 296 assert_eq!( 297 Manifest::from_toml( 298 "[package]\nname=\"\"\nrust-version={workspace=true}\nworkspace=2".to_owned(), 299 false, 300 Path::new(""), 301 &[] 302 ), 303 Err(Box::new(ManifestErr::Package( 304 PackageErr::InvalidWorkspaceType, 305 PathBuf::new() 306 ))) 307 ); 308 assert_eq!( 309 Manifest::from_toml( 310 "workspace=2\n[package]\nname=\"\"\nrust-version={workspace=true}".to_owned(), 311 false, 312 Path::new(""), 313 &[] 314 ), 315 Err(Box::new(ManifestErr::Package( 316 PackageErr::Workspace(WorkspaceErr::InvalidType, PathBuf::new()), 317 PathBuf::new() 318 ))) 319 ); 320 assert_eq!( 321 Manifest::from_toml( 322 "[workspace]\n[package]\nname=\"\"\nrust-version={workspace=true}".to_owned(), 323 false, 324 Path::new(""), 325 &[] 326 ), 327 Err(Box::new(ManifestErr::Package( 328 PackageErr::Workspace(WorkspaceErr::MissingPackage, PathBuf::new()), 329 PathBuf::new() 330 ))) 331 ); 332 assert_eq!( 333 Manifest::from_toml( 334 "[workspace]\npackage=2\n[package]\nname=\"\"\nrust-version={workspace=true}" 335 .to_owned(), 336 false, 337 Path::new(""), 338 &[] 339 ), 340 Err(Box::new(ManifestErr::Package( 341 PackageErr::Workspace(WorkspaceErr::InvalidPackageType, PathBuf::new()), 342 PathBuf::new() 343 ))) 344 ); 345 assert_eq!( 346 Manifest::from_toml( 347 "[workspace.package]\n[package]\nname=\"\"\nrust-version={workspace=true}".to_owned(), 348 false, 349 Path::new(""), 350 &[] 351 ), 352 Err(Box::new(ManifestErr::Package( 353 PackageErr::Workspace(WorkspaceErr::MissingPackageMsrv, PathBuf::new()), 354 PathBuf::new() 355 ))) 356 ); 357 assert_eq!( 358 Manifest::from_toml( 359 "[workspace.package]\nrust-version={}\n[package]\nname=\"\"\nrust-version={workspace=true}" 360 .to_owned(), 361 false, 362 Path::new(""), 363 &[] 364 ), 365 Err(Box::new(ManifestErr::Package( 366 PackageErr::Workspace(WorkspaceErr::InvalidPackageMsrvType, PathBuf::new()), 367 PathBuf::new() 368 ))) 369 ); 370 assert_eq!( 371 Manifest::from_toml( 372 "[workspace.package]\nrust-version=\"\"\n[package]\nname=\"\"\nrust-version={workspace=true}" 373 .to_owned(), 374 false, 375 Path::new(""), 376 &[] 377 ), 378 Err(Box::new(ManifestErr::Package( 379 PackageErr::Workspace(WorkspaceErr::Msrv, PathBuf::new()), 380 PathBuf::new() 381 ))) 382 ); 383 assert_eq!( 384 Manifest::from_toml( 385 "features=2\n[package]\nname=\"\"".to_owned(), 386 false, 387 Path::new(""), 388 &[] 389 ), 390 Err(Box::new(ManifestErr::Features( 391 FeaturesErr::InvalidType, 392 PathBuf::new() 393 ))) 394 ); 395 assert_eq!( 396 Manifest::from_toml( 397 "[features]\n\"/\"=[]\n[package]\nname=\"\"".to_owned(), 398 false, 399 Path::new(""), 400 &[] 401 ), 402 Err(Box::new(ManifestErr::Features( 403 FeaturesErr::InvalidName("/".to_owned()), 404 PathBuf::new() 405 ))) 406 ); 407 assert_eq!( 408 Manifest::from_toml( 409 "[features]\n\"dep:\"=[]\n[package]\nname=\"\"".to_owned(), 410 false, 411 Path::new(""), 412 &[] 413 ), 414 Err(Box::new(ManifestErr::Features( 415 FeaturesErr::InvalidName("dep:".to_owned()), 416 PathBuf::new() 417 ))) 418 ); 419 assert_eq!( 420 Manifest::from_toml( 421 "[features]\n\"\"=2\n[package]\nname=\"\"".to_owned(), 422 false, 423 Path::new(""), 424 &[] 425 ), 426 Err(Box::new(ManifestErr::Features( 427 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::InvalidFeatureType( 428 String::new() 429 )), 430 PathBuf::new() 431 ))) 432 ); 433 assert_eq!( 434 Manifest::from_toml( 435 "[features]\n\"\"=[true]\n[package]\nname=\"\"".to_owned(), 436 false, 437 Path::new(""), 438 &[] 439 ), 440 Err(Box::new(ManifestErr::Features( 441 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::InvalidDependencyType( 442 String::new() 443 )), 444 PathBuf::new() 445 ))) 446 ); 447 assert_eq!( 448 Manifest::from_toml( 449 "[features]\n\"\"=[\"foo\"]\n[package]\nname=\"\"".to_owned(), 450 false, 451 Path::new(""), 452 &[] 453 ), 454 Err(Box::new(ManifestErr::Features( 455 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::InvalidDependency( 456 String::new(), 457 "foo".to_owned() 458 )), 459 PathBuf::new() 460 ))) 461 ); 462 // Feature dependencies can't be implied features when implied features are forbidden. 463 assert_eq!( 464 Manifest::from_toml( 465 "[dependencies]\nfoo={optional=true}\n[features]\n\"\"=[\"foo\"]\n[package]\nname=\"\"" 466 .to_owned(), 467 false, 468 Path::new(""), 469 &[] 470 ), 471 Err(Box::new(ManifestErr::Features( 472 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::InvalidDependency( 473 String::new(), 474 "foo".to_owned() 475 )), 476 PathBuf::new() 477 ))) 478 ); 479 assert_eq!( 480 Manifest::from_toml( 481 "[features]\n\"\"=[\"\"]\n[package]\nname=\"\"".to_owned(), 482 false, 483 Path::new(""), 484 &[] 485 ), 486 Err(Box::new(ManifestErr::Features( 487 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::CyclicFeature(String::new())), 488 PathBuf::new() 489 ))) 490 ); 491 assert_eq!( 492 Manifest::from_toml( 493 "[features]\n\"\"=[\"a\"]\na=[\"\"]\n[package]\nname=\"\"".to_owned(), 494 false, 495 Path::new(""), 496 &[] 497 ), 498 Err(Box::new(ManifestErr::Features( 499 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::CyclicFeature(String::new())), 500 PathBuf::new() 501 ))) 502 ); 503 assert_eq!( 504 Manifest::from_toml( 505 "[features]\n\"\"=[\"a\"]\na=[\"b\"]\nb=[\"a\"]\n[package]\nname=\"\"".to_owned(), 506 false, 507 Path::new(""), 508 &[] 509 ), 510 Err(Box::new(ManifestErr::Features( 511 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::CyclicFeature("a".to_owned())), 512 PathBuf::new() 513 ))) 514 ); 515 assert_eq!( 516 Manifest::from_toml( 517 "[features]\n\"\"=[\"a\"]\na=[\"c\",\"b\"]\nb=[\"a\"]\nc=[]\n[package]\nname=\"\"" 518 .to_owned(), 519 false, 520 Path::new(""), 521 &[] 522 ), 523 Err(Box::new(ManifestErr::Features( 524 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::CyclicFeature("a".to_owned())), 525 PathBuf::new() 526 ))) 527 ); 528 assert_eq!( 529 Manifest::from_toml( 530 "[features]\n\"\"=[]\na=[\"c\",\"b\"]\nb=[\"a\"]\nc=[]\n[package]\nname=\"\"" 531 .to_owned(), 532 false, 533 Path::new(""), 534 &[] 535 ), 536 Err(Box::new(ManifestErr::Features( 537 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::CyclicFeature("a".to_owned())), 538 PathBuf::new() 539 ))) 540 ); 541 assert_eq!( 542 Manifest::from_toml( 543 "[features]\n\"\"=[\"a\",\"b\"]\na=[\"b\"]\nb=[]\n[package]\nname=\"\"".to_owned(), 544 false, 545 Path::new(""), 546 &[] 547 ), 548 Err(Box::new(ManifestErr::Features( 549 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::RedundantDependency( 550 String::new(), 551 "b".to_owned() 552 )), 553 PathBuf::new() 554 ))) 555 ); 556 assert_eq!( 557 Manifest::from_toml( 558 "[features]\n\"\"=[\"a\",\"a\"]\na=[]\n[package]\nname=\"\"".to_owned(), 559 false, 560 Path::new(""), 561 &[] 562 ), 563 Err(Box::new(ManifestErr::Features( 564 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::RedundantDependency( 565 String::new(), 566 "a".to_owned() 567 )), 568 PathBuf::new() 569 ))) 570 ); 571 // Duplicate `"dep:"` feature dependencies error. 572 assert_eq!( 573 Manifest::from_toml( 574 "[features]\n\"\"=[\"dep:\",\"dep:\"]\na=[]\n[package]\nname=\"\"".to_owned(), 575 false, 576 Path::new(""), 577 &[] 578 ), 579 Err(Box::new(ManifestErr::Features( 580 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::RedundantDependency( 581 String::new(), 582 "dep:".to_owned() 583 )), 584 PathBuf::new() 585 ))) 586 ); 587 assert_eq!( 588 Manifest::from_toml( 589 "target=2\n[package]\nname=\"\"".to_owned(), 590 false, 591 Path::new(""), 592 &[] 593 ), 594 Err(Box::new(ManifestErr::ImpliedFeatures( 595 ImpliedFeaturesErr::TargetType, 596 PathBuf::new() 597 ))) 598 ); 599 assert_eq!( 600 Manifest::from_toml( 601 "dependencies=2\n[package]\nname=\"\"".to_owned(), 602 false, 603 Path::new(""), 604 &[] 605 ), 606 Err(Box::new(ManifestErr::ImpliedFeatures( 607 ImpliedFeaturesErr::Dependencies(DependenciesErr::Type("dependencies")), 608 PathBuf::new() 609 ))) 610 ); 611 assert_eq!( 612 Manifest::from_toml( 613 "build-dependencies=2\n[package]\nname=\"\"".to_owned(), 614 false, 615 Path::new(""), 616 &[] 617 ), 618 Err(Box::new(ManifestErr::ImpliedFeatures( 619 ImpliedFeaturesErr::Dependencies(DependenciesErr::Type("build-dependencies")), 620 PathBuf::new(), 621 ))) 622 ); 623 assert_eq!( 624 Manifest::from_toml( 625 "[dependencies]\n\"dep:\"=\"\"\n[package]\nname=\"\"".to_owned(), 626 false, 627 Path::new(""), 628 &[] 629 ), 630 Err(Box::new(ManifestErr::ImpliedFeatures( 631 ImpliedFeaturesErr::Dependencies(DependenciesErr::Name( 632 "dependencies", 633 "dep:".to_owned() 634 )), 635 PathBuf::new(), 636 ))) 637 ); 638 assert_eq!( 639 Manifest::from_toml( 640 "[dependencies]\n\"/\"=\"\"\n[package]\nname=\"\"".to_owned(), 641 false, 642 Path::new(""), 643 &[] 644 ), 645 Err(Box::new(ManifestErr::ImpliedFeatures( 646 ImpliedFeaturesErr::Dependencies(DependenciesErr::Name("dependencies", "/".to_owned())), 647 PathBuf::new(), 648 ))) 649 ); 650 assert_eq!( 651 Manifest::from_toml( 652 "[build-dependencies]\n\"dep:\"=\"\"\n[package]\nname=\"\"".to_owned(), 653 false, 654 Path::new(""), 655 &[] 656 ), 657 Err(Box::new(ManifestErr::ImpliedFeatures( 658 ImpliedFeaturesErr::Dependencies(DependenciesErr::Name( 659 "build-dependencies", 660 "dep:".to_owned() 661 )), 662 PathBuf::new(), 663 ))) 664 ); 665 assert_eq!( 666 Manifest::from_toml( 667 "[build-dependencies]\n\"/\"=\"\"\n[package]\nname=\"\"".to_owned(), 668 false, 669 Path::new(""), 670 &[] 671 ), 672 Err(Box::new(ManifestErr::ImpliedFeatures( 673 ImpliedFeaturesErr::Dependencies(DependenciesErr::Name( 674 "build-dependencies", 675 "/".to_owned() 676 )), 677 PathBuf::new(), 678 ))) 679 ); 680 assert_eq!( 681 Manifest::from_toml( 682 "[dependencies]\n\"\"=2\n[package]\nname=\"\"".to_owned(), 683 false, 684 Path::new(""), 685 &[] 686 ), 687 Err(Box::new(ManifestErr::ImpliedFeatures( 688 ImpliedFeaturesErr::Dependencies(DependenciesErr::DependencyType( 689 "dependencies", 690 String::new() 691 )), 692 PathBuf::new(), 693 ))) 694 ); 695 assert_eq!( 696 Manifest::from_toml( 697 "[build-dependencies]\n\"\"=2\n[package]\nname=\"\"".to_owned(), 698 false, 699 Path::new(""), 700 &[] 701 ), 702 Err(Box::new(ManifestErr::ImpliedFeatures( 703 ImpliedFeaturesErr::Dependencies(DependenciesErr::DependencyType( 704 "build-dependencies", 705 String::new() 706 )), 707 PathBuf::new(), 708 ))) 709 ); 710 assert_eq!( 711 Manifest::from_toml( 712 "[dependencies]\n\"\"={optional=2}\n[package]\nname=\"\"".to_owned(), 713 false, 714 Path::new(""), 715 &[] 716 ), 717 Err(Box::new(ManifestErr::ImpliedFeatures( 718 ImpliedFeaturesErr::Dependencies(DependenciesErr::OptionalType( 719 "dependencies", 720 String::new() 721 )), 722 PathBuf::new(), 723 ))) 724 ); 725 assert_eq!( 726 Manifest::from_toml( 727 "[build-dependencies]\n\"\"={optional=2}\n[package]\nname=\"\"".to_owned(), 728 false, 729 Path::new(""), 730 &[] 731 ), 732 Err(Box::new(ManifestErr::ImpliedFeatures( 733 ImpliedFeaturesErr::Dependencies(DependenciesErr::OptionalType( 734 "build-dependencies", 735 String::new() 736 )), 737 PathBuf::new(), 738 ))) 739 ); 740 // Implied features are disallowed iff `!allow_implied_features`. 741 assert_eq!( 742 Manifest::from_toml( 743 "[dependencies]\nfoo={optional=true}\n[package]\nname=\"\"".to_owned(), 744 false, 745 Path::new(""), 746 &[] 747 ), 748 Err(Box::new(ManifestErr::ImpliedFeatures( 749 ImpliedFeaturesErr::Dependencies(DependenciesErr::ImpliedFeature( 750 "dependencies", 751 "foo".to_owned() 752 )), 753 PathBuf::new(), 754 ))) 755 ); 756 assert_eq!( 757 Manifest::from_toml( 758 "[target]\n\"\"=2\n[package]\nname=\"\"".to_owned(), 759 false, 760 Path::new(""), 761 &[] 762 ), 763 Err(Box::new(ManifestErr::ImpliedFeatures( 764 ImpliedFeaturesErr::TargetPlatformType(String::new()), 765 PathBuf::new(), 766 ))) 767 ); 768 assert_eq!( 769 Manifest::from_toml( 770 "[target.\"\"]\ndependencies=2\n[package]\nname=\"\"".to_owned(), 771 false, 772 Path::new(""), 773 &[] 774 ), 775 Err(Box::new(ManifestErr::ImpliedFeatures( 776 ImpliedFeaturesErr::TagetPlatformDependencies( 777 String::new(), 778 DependenciesErr::Type("dependencies") 779 ), 780 PathBuf::new(), 781 ))) 782 ); 783 assert_eq!( 784 Manifest::from_toml( 785 "[target.\"\"]\nbuild-dependencies=2\n[package]\nname=\"\"".to_owned(), 786 false, 787 Path::new(""), 788 &[] 789 ), 790 Err(Box::new(ManifestErr::ImpliedFeatures( 791 ImpliedFeaturesErr::TagetPlatformDependencies( 792 String::new(), 793 DependenciesErr::Type("build-dependencies") 794 ), 795 PathBuf::new(), 796 ))) 797 ); 798 assert_eq!( 799 Manifest::from_toml( 800 "[target.\"\".dependencies]\n\"/\"=\"\"\n[package]\nname=\"\"".to_owned(), 801 false, 802 Path::new(""), 803 &[] 804 ), 805 Err(Box::new(ManifestErr::ImpliedFeatures( 806 ImpliedFeaturesErr::TagetPlatformDependencies( 807 String::new(), 808 DependenciesErr::Name("dependencies", "/".to_owned()) 809 ), 810 PathBuf::new(), 811 ))) 812 ); 813 assert_eq!( 814 Manifest::from_toml( 815 "[target.\"\".dependencies]\n\"dep:\"=\"\"\n[package]\nname=\"\"".to_owned(), 816 false, 817 Path::new(""), 818 &[] 819 ), 820 Err(Box::new(ManifestErr::ImpliedFeatures( 821 ImpliedFeaturesErr::TagetPlatformDependencies( 822 String::new(), 823 DependenciesErr::Name("dependencies", "dep:".to_owned()) 824 ), 825 PathBuf::new(), 826 ))) 827 ); 828 assert_eq!( 829 Manifest::from_toml( 830 "[target.\"\".build-dependencies]\n\"/\"=\"\"\n[package]\nname=\"\"".to_owned(), 831 false, 832 Path::new(""), 833 &[] 834 ), 835 Err(Box::new(ManifestErr::ImpliedFeatures( 836 ImpliedFeaturesErr::TagetPlatformDependencies( 837 String::new(), 838 DependenciesErr::Name("build-dependencies", "/".to_owned()) 839 ), 840 PathBuf::new(), 841 ))) 842 ); 843 assert_eq!( 844 Manifest::from_toml( 845 "[target.\"\".build-dependencies]\n\"dep:\"=\"\"\n[package]\nname=\"\"".to_owned(), 846 false, 847 Path::new(""), 848 &[] 849 ), 850 Err(Box::new(ManifestErr::ImpliedFeatures( 851 ImpliedFeaturesErr::TagetPlatformDependencies( 852 String::new(), 853 DependenciesErr::Name("build-dependencies", "dep:".to_owned()) 854 ), 855 PathBuf::new(), 856 ))) 857 ); 858 assert_eq!( 859 Manifest::from_toml( 860 "[target.\"\".dependencies]\n\"\"=false\n[package]\nname=\"\"".to_owned(), 861 false, 862 Path::new(""), 863 &[] 864 ), 865 Err(Box::new(ManifestErr::ImpliedFeatures( 866 ImpliedFeaturesErr::TagetPlatformDependencies( 867 String::new(), 868 DependenciesErr::DependencyType("dependencies", String::new()) 869 ), 870 PathBuf::new(), 871 ))) 872 ); 873 assert_eq!( 874 Manifest::from_toml( 875 "[target.\"\".build-dependencies]\n\"\"=false\n[package]\nname=\"\"".to_owned(), 876 false, 877 Path::new(""), 878 &[] 879 ), 880 Err(Box::new(ManifestErr::ImpliedFeatures( 881 ImpliedFeaturesErr::TagetPlatformDependencies( 882 String::new(), 883 DependenciesErr::DependencyType("build-dependencies", String::new()) 884 ), 885 PathBuf::new(), 886 ))) 887 ); 888 assert_eq!( 889 Manifest::from_toml( 890 "[target.\"\".dependencies]\n\"\"={optional=2}\n[package]\nname=\"\"".to_owned(), 891 false, 892 Path::new(""), 893 &[] 894 ), 895 Err(Box::new(ManifestErr::ImpliedFeatures( 896 ImpliedFeaturesErr::TagetPlatformDependencies( 897 String::new(), 898 DependenciesErr::OptionalType("dependencies", String::new()) 899 ), 900 PathBuf::new(), 901 ))) 902 ); 903 assert_eq!( 904 Manifest::from_toml( 905 "[target.\"\".build-dependencies]\n\"\"={optional=2}\n[package]\nname=\"\"".to_owned(), 906 false, 907 Path::new(""), 908 &[] 909 ), 910 Err(Box::new(ManifestErr::ImpliedFeatures( 911 ImpliedFeaturesErr::TagetPlatformDependencies( 912 String::new(), 913 DependenciesErr::OptionalType("build-dependencies", String::new()) 914 ), 915 PathBuf::new(), 916 ))) 917 ); 918 // An invalid dependency error occurs later when we `allow_implied_features` since 919 // implied features aren't added until after feature extraction. 920 assert_eq!( 921 Manifest::from_toml( 922 "[features]\n\"\"=[\"foo\"]\n[package]\nname=\"\"".to_owned(), 923 true, 924 Path::new(""), 925 &[] 926 ), 927 Err(Box::new(ManifestErr::ImpliedFeatures( 928 ImpliedFeaturesErr::InvalidDependency(String::new(), "foo".to_owned()), 929 PathBuf::new(), 930 ))) 931 ); 932 // In contrast, above would have erred sooner if `!allow_implied_features`. 933 assert_eq!( 934 Manifest::from_toml( 935 "[features]\n\"\"=[\"foo\"]\n[package]\nname=\"\"".to_owned(), 936 false, 937 Path::new(""), 938 &[] 939 ), 940 Err(Box::new(ManifestErr::Features( 941 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::InvalidDependency( 942 String::new(), 943 "foo".to_owned() 944 )), 945 PathBuf::new() 946 ))) 947 ); 948 assert_eq!( 949 Manifest::from_toml( 950 "[package]\nname=\"\"".to_owned(), 951 false, 952 Path::new(""), 953 &["a".to_owned()] 954 ), 955 Err(Box::new(ManifestErr::UndefinedIgnoreFeature( 956 "a".to_owned(), 957 PathBuf::new() 958 ))) 959 ); 960 // Even if we forbid implied features, we don't error when a feature is defined 961 // with the same name of an implied feature. This is due to simplicity in code 962 // and the fact that `cargo` will error anyway. 963 // 964 // For example once `cargo` is invoked, an error will occur due to duplicate features: 965 // the explict feature `foo` and the implied feature from the dependency `foo`. 966 assert_eq!( 967 Manifest::from_toml( 968 "[dependencies]\nfoo={optional=true}\n[features]\nfoo=[]\n[package]\nname=\"\"" 969 .to_owned(), 970 false, 971 Path::new(""), 972 &[] 973 ), 974 Ok(Manifest { 975 package: Package { 976 msrv: None, 977 name: String::new(), 978 }, 979 features: Features(vec![("foo".to_owned(), Vec::new())]), 980 }) 981 ); 982 // Allow major-only MSRV. 983 assert_eq!( 984 Manifest::from_toml( 985 "[package]\nname=\"foo\"\nrust-version=\"0\"".to_owned(), 986 false, 987 Path::new(""), 988 &[] 989 ), 990 Ok(Manifest { 991 package: Package { 992 msrv: Some(Msrv { 993 major: 0, 994 minor: None, 995 patch: None, 996 }), 997 name: "foo".to_owned(), 998 }, 999 features: Features(Vec::new()), 1000 }) 1001 ); 1002 // Allow escapes. 1003 assert_eq!( 1004 Manifest::from_toml( 1005 "[\"\\u0070ackage\"]\n\"n\\u0061me\"=\"\\u0066oo\"\n\"\\u0072ust-version\"=\"0\\u002E\\u0031\"".to_owned(), 1006 false, 1007 Path::new(""), 1008 &[] 1009 ), 1010 Ok(Manifest { 1011 package: Package { 1012 msrv: Some(Msrv { 1013 major: 0, 1014 minor: Some(1), 1015 patch: None, 1016 }), 1017 name: "foo".to_owned(), 1018 }, 1019 features: Features(Vec::new()), 1020 }) 1021 ); 1022 assert_eq!( 1023 Manifest::from_toml( 1024 "[package]\nname=\"\"\nrust-version=\"0.0.0\"".to_owned(), 1025 false, 1026 Path::new(""), 1027 &[] 1028 ), 1029 Ok(Manifest { 1030 package: Package { 1031 msrv: Some(Msrv { 1032 major: 0, 1033 minor: Some(0), 1034 patch: Some(0), 1035 }), 1036 name: String::new(), 1037 }, 1038 features: Features(Vec::new()), 1039 }) 1040 ); 1041 // Ignore non `rust-version` keys in `package`. Ignore keys in the root document except `package`, 1042 // `features`, `dependencies`, `build-dependencies`, and `target`. Ignore keys in 1043 // `target.<something>` unless the key is `dependencies` or `build-dependencies`. Don't treat 1044 // `<something>` special in `target.<something>` other than its being a table. 1045 assert_eq!( 1046 Manifest::from_toml("dev-dependencies=2\n[package]\nname=\"\"\n\nfoo=2\nrust-version=\"18446744073709551615.18446744073709551615.18446744073709551615\"\n[foo]\nbar=false\n[target.\"\".foo]\nbar=2\n[target.foo]\nbar=false\n[target.dependencies]\nfoo=2\n[target.build-dependencies]\nfoo=false\n[target.dev-dependencies]\nfoo=true\n".to_owned(), false, Path::new(""), &[]), 1047 Ok(Manifest { 1048 package: Package { 1049 msrv: Some(Msrv { 1050 major: u64::MAX, 1051 minor: Some(u64::MAX), 1052 patch: Some(u64::MAX), 1053 }), 1054 name: String::new(), 1055 }, 1056 features: Features(Vec::new()), 1057 }) 1058 ); 1059 // [package] 1060 // name = "" 1061 // 1062 // ["\u0064ependencies"] 1063 // "\u0000" = "\u0000" 1064 // a = { optional = true } 1065 // 1066 // ["build-\u0064ependencies"] 1067 // "\u0000" = { optional = true } 1068 // 1069 // [dev-dependencies] 1070 // buzz = { optional = true } 1071 // 1072 // [target."".dependencies] 1073 // b = { optional = false, foo = 2 } 1074 // fizz = { optional = true, foo = 3 } 1075 // 1076 // [target.a.dependencies] 1077 // c = { optional = true } 1078 // wuzz = { optional = true } 1079 // 1080 // [features] 1081 // default = ["bar","dep:lk","a/ak", "a/ak"] 1082 // bar = ["dep\u003Awuzz"] 1083 // 1084 // We allow any and all key names unless it's the features table or a dependency table; in which case 1085 // key names must not contain `'/'` nor begin with `"dep:"`. 1086 // 1087 // The order of features is based on the following hierarchy: 1088 // * Explict features: lexicographically sorted 1089 // * dependencies: optional only, lexicographically sorted, only if an explicit feature doesn't exist with 1090 // the same name nor any explicit feature contains a dependency named `"dep:<dependecy>"` and we allow 1091 // implied features. If such feature exists, we don't error but simply don't add. 1092 // * build-dependencies: read above. 1093 // * target.<something>: lexicographically sorted by something, within `something`, `dependencies` 1094 // is first using the same methodology as item 2, last `build-dependencies`. 1095 // 1096 // Once the order of features is determined, the only feature dependencies that are retained are those 1097 // that don't contain `'/'` nor begin with `"dep:"`. We don't require dependencies to be defined for 1098 // feature dependencies that contain `'/'` or begin with `"dep:"`. We don't care about duplicate feature 1099 // dependencies that contain `'/'`. 1100 // 1101 // Based on above, `Features` looks like the following: 1102 // 1. (bar, []) 1103 // 2. (default, ["bar"]) 1104 // 3. (a, []) 1105 // 4. (\x00, []) 1106 // 5. (fizz, []) 1107 // 6. (c, []) 1108 assert_eq!( 1109 Manifest::from_toml( 1110 "[\"\\u0064ependencies\"]\n\"\\u0000\"=\"\\u0000\"\na={optional=true}\n[\"build-\\u0064ependencies\"]\n\"\\u0000\"={optional=true}\n[target.\"\".dependencies]\nb={optional=false,foo=2}\nfizz={optional=true,foo=3}\n[features]\ndefault=[\"bar\",\"dep:lk\",\"a/ak\",\"a/ak\"]\nbar=[\"dep\\u003Awuzz\"]\n[dev-dependencies]\nbuzz={optional=true}\n[target.a.dependencies]\nc={optional=true}\nwuzz={optional=true}\n[package]\nname=\"\"".to_owned(), 1111 true, 1112 Path::new(""), 1113 &[] 1114 ), 1115 Ok(Manifest { 1116 package: Package { 1117 msrv: None, 1118 name: String::new(), 1119 }, 1120 features: Features(vec![("bar".to_owned(), Vec::new()), ("default".to_owned(), vec!["bar".to_owned()]), ("a".to_owned(), Vec::new()), ("\0".to_owned(), Vec::new()), ("fizz".to_owned(), Vec::new()), ("c".to_owned(), Vec::new())]), 1121 }) 1122 ); 1123 // [package] 1124 // name = "" 1125 // 1126 // [dependencies] 1127 // foo = { "optional" = true } 1128 // fizz = { "optional" = true } 1129 // 1130 // [features] 1131 // fizz = ["dep:fizz"] 1132 // bar = ["dep:foo"] 1133 assert_eq!( 1134 Manifest::from_toml( 1135 "[package]\nname=\"\"\n[dependencies]\nfoo={optional=true}\nfizz={optional=true}\n[features]\nfizz=[\"dep:fizz\"]\nbar=[\"dep:foo\"]".to_owned(), 1136 false, 1137 Path::new(""), 1138 &[] 1139 ), 1140 Ok(Manifest { 1141 package: Package { 1142 msrv: None, 1143 name: String::new(), 1144 }, 1145 features: Features(vec![ 1146 ("bar".to_owned(), Vec::new()), 1147 ("fizz".to_owned(), Vec::new()) 1148 ]), 1149 }) 1150 ); 1151 // [package] 1152 // name = "" 1153 // 1154 // [dependencies] 1155 // bar = { "optional" = true } 1156 // 1157 // [features] 1158 // foo = ["bar"] 1159 assert_eq!( 1160 Manifest::from_toml( 1161 "[package]\nname=\"\"\n[dependencies]\nbar={optional=true}\n[features]\nfoo=[\"bar\"]" 1162 .to_owned(), 1163 true, 1164 Path::new(""), 1165 &[] 1166 ), 1167 Ok(Manifest { 1168 package: Package { 1169 msrv: None, 1170 name: String::new(), 1171 }, 1172 features: Features(vec![ 1173 ("foo".to_owned(), vec!["bar".to_owned()]), 1174 ("bar".to_owned(), Vec::new()), 1175 ]), 1176 }) 1177 ); 1178 assert_eq!( 1179 Manifest::from_toml( 1180 "[package]\nname=\"\"\n[features]\na=[]\nb=[\"a\"]".to_owned(), 1181 false, 1182 Path::new(""), 1183 &["a".to_owned()] 1184 ), 1185 Ok(Manifest { 1186 package: Package { 1187 msrv: None, 1188 name: String::new(), 1189 }, 1190 features: Features(vec![]), 1191 }) 1192 ); 1193 assert_eq!( 1194 Manifest::from_toml( 1195 "[package]\nname=\"\"\n[features]\na=[]\nb=[\"a\"]".to_owned(), 1196 false, 1197 Path::new(""), 1198 &["b".to_owned()] 1199 ), 1200 Ok(Manifest { 1201 package: Package { 1202 msrv: None, 1203 name: String::new(), 1204 }, 1205 features: Features(vec![("a".to_owned(), Vec::new())]), 1206 }) 1207 ); 1208 assert_eq!( 1209 Manifest::from_toml( 1210 "[package]\nname=\"\"\n[dependencies]\nc={optional=true}\n[features]\nb=[\"c\"]" 1211 .to_owned(), 1212 true, 1213 Path::new(""), 1214 &["c".to_owned()] 1215 ), 1216 Ok(Manifest { 1217 package: Package { 1218 msrv: None, 1219 name: String::new(), 1220 }, 1221 features: Features(vec![]), 1222 }) 1223 ); 1224 assert_eq!( 1225 Manifest::from_toml( 1226 "[package]\nname=\"\"\n[dependencies]\nc={optional=true}\n[features]\nb=[\"c\"]" 1227 .to_owned(), 1228 true, 1229 Path::new(""), 1230 &["b".to_owned()] 1231 ), 1232 Ok(Manifest { 1233 package: Package { 1234 msrv: None, 1235 name: String::new(), 1236 }, 1237 features: Features(vec![("c".to_owned(), Vec::new())]), 1238 }) 1239 ); 1240 } 1241 #[expect(clippy::unreachable, reason = "want to crash when there is a bug")] 1242 #[expect( 1243 clippy::cognitive_complexity, 1244 clippy::too_many_lines, 1245 reason = "want to test for a lot of things" 1246 )] 1247 #[test] 1248 fn power_set() { 1249 #[cfg(target_pointer_width = "16")] 1250 let feat_len_one_too_large = 17; 1251 #[cfg(target_pointer_width = "32")] 1252 let feat_len_one_too_large = 33; 1253 #[cfg(target_pointer_width = "64")] 1254 let feat_len_one_too_large = 65; 1255 let mut feats = Features(vec![(String::new(), Vec::new()); feat_len_one_too_large]); 1256 assert_eq!(PowerSet::new(&feats, false), Err(TooManyFeaturesErr)); 1257 #[cfg(target_pointer_width = "16")] 1258 let max_feat_len = 16; 1259 #[cfg(target_pointer_width = "32")] 1260 let max_feat_len = 32; 1261 #[cfg(target_pointer_width = "64")] 1262 let max_feat_len = 64; 1263 feats.0 = vec![(String::new(), Vec::new()); max_feat_len]; 1264 #[cfg(any( 1265 target_pointer_width = "16", 1266 target_pointer_width = "32", 1267 target_pointer_width = "64" 1268 ))] 1269 assert_eq!( 1270 PowerSet::new(&feats, false), 1271 Ok(Some(PowerSet { 1272 feats: feats.0.as_slice(), 1273 has_remaining: true, 1274 check_overlap: false, 1275 idx: usize::MAX, 1276 buffer: vec![""; max_feat_len], 1277 set: String::new(), 1278 skipped_sets_counter: 0, 1279 skip_empty_set: false, 1280 })) 1281 ); 1282 feats.0 = Vec::new(); 1283 assert_eq!( 1284 PowerSet::new(&feats, false), 1285 Ok(Some(PowerSet { 1286 feats: feats.0.as_slice(), 1287 has_remaining: true, 1288 check_overlap: false, 1289 idx: 0, 1290 buffer: Vec::new(), 1291 set: String::new(), 1292 skipped_sets_counter: 0, 1293 skip_empty_set: false, 1294 })) 1295 ); 1296 assert_eq!(PowerSet::new(&feats, true), Ok(None)); 1297 let mut power_set = PowerSet::new(&feats, false) 1298 .unwrap_or_else(|_e| { 1299 unreachable!("not possible since we just verified PowerSet::new returned Ok") 1300 }) 1301 .unwrap_or_else(|| { 1302 unreachable!("not possible since we just verified PowerSet::new returned Ok(Some)") 1303 }); 1304 assert_eq!(power_set.len(), NonZeroUsizePlus1::new(1)); 1305 assert_eq!(power_set.next_set(), Some("")); 1306 assert_eq!( 1307 power_set, 1308 PowerSet { 1309 feats: feats.0.as_slice(), 1310 has_remaining: false, 1311 check_overlap: false, 1312 idx: 0, 1313 buffer: Vec::new(), 1314 set: String::new(), 1315 skipped_sets_counter: 0, 1316 skip_empty_set: false 1317 } 1318 ); 1319 assert_eq!(power_set.next_set(), None); 1320 assert_eq!(power_set.len(), NonZeroUsizePlus1::new(1)); 1321 assert_eq!( 1322 power_set, 1323 PowerSet { 1324 feats: feats.0.as_slice(), 1325 has_remaining: false, 1326 check_overlap: false, 1327 idx: 0, 1328 buffer: Vec::new(), 1329 set: String::new(), 1330 skipped_sets_counter: 0, 1331 skip_empty_set: false 1332 } 1333 ); 1334 assert_eq!(power_set.next_set(), None); 1335 power_set.reset(); 1336 assert_eq!( 1337 power_set, 1338 PowerSet { 1339 feats: feats.0.as_slice(), 1340 has_remaining: true, 1341 check_overlap: false, 1342 idx: 0, 1343 buffer: Vec::new(), 1344 set: String::new(), 1345 skipped_sets_counter: 0, 1346 skip_empty_set: false 1347 } 1348 ); 1349 assert_eq!(power_set.next_set(), Some("")); 1350 assert_eq!( 1351 power_set, 1352 PowerSet { 1353 feats: feats.0.as_slice(), 1354 has_remaining: false, 1355 check_overlap: false, 1356 idx: 0, 1357 buffer: Vec::new(), 1358 set: String::new(), 1359 skipped_sets_counter: 0, 1360 skip_empty_set: false 1361 } 1362 ); 1363 assert_eq!(power_set.next_set(), None); 1364 assert_eq!( 1365 power_set, 1366 PowerSet { 1367 feats: feats.0.as_slice(), 1368 has_remaining: false, 1369 check_overlap: false, 1370 idx: 0, 1371 buffer: Vec::new(), 1372 set: String::new(), 1373 skipped_sets_counter: 0, 1374 skip_empty_set: false 1375 } 1376 ); 1377 assert_eq!(power_set.next_set(), None); 1378 // [features] 1379 // a = ["b"] 1380 // b = ["c", "d"] 1381 // c = [] 1382 // d = [] 1383 feats.0 = vec![ 1384 ("a".to_owned(), vec!["b".to_owned()]), 1385 ("b".to_owned(), vec!["c".to_owned(), "d".to_owned()]), 1386 ("c".to_owned(), Vec::new()), 1387 ("d".to_owned(), Vec::new()), 1388 ]; 1389 assert_eq!( 1390 PowerSet::new(&feats, false), 1391 Ok(Some(PowerSet { 1392 feats: feats.0.as_slice(), 1393 has_remaining: true, 1394 // At least one feature depends on another, so this will be set to `true`. 1395 check_overlap: true, 1396 idx: 15, 1397 buffer: vec!["a", "b", "c", "d"], 1398 set: String::new(), 1399 skipped_sets_counter: 0, 1400 skip_empty_set: false 1401 })) 1402 ); 1403 power_set = PowerSet::new(&feats, false) 1404 .unwrap_or_else(|_e| { 1405 unreachable!("not possible since we just verified PowerSet::new returned Ok") 1406 }) 1407 .unwrap_or_else(|| { 1408 unreachable!("not possible since we just verified PowerSet::new returned Ok(Some)") 1409 }); 1410 assert_eq!(power_set.len(), NonZeroUsizePlus1::new(16)); 1411 // Order is the following: 1412 // 1. a,b,c,d: skipped since a depends on b. 1413 // 2. b,c,d: skipped since b depends on c. 1414 // 3. a,c,d: skipped since a depends on c (via b). 1415 // 4. c,d 1416 // 5. a,b,d: skipped since a depends on b. 1417 // 6. b,d: skipped since b depends on d. 1418 // 7. a,d: skipped since a depends on d (via b). 1419 // 8. d 1420 // 9. a,b,c: skipped since a depends on b. 1421 // 10. b,c: skipped since b depends on c. 1422 // 11. a,c: skipped since a depends on c (via b). 1423 // 12. c 1424 // 13. a,b: skipped since a depends on b. 1425 // 14. b 1426 // 15. a 1427 // 16. 1428 assert_eq!(power_set.next_set(), Some("c,d")); 1429 assert_eq!( 1430 power_set, 1431 PowerSet { 1432 feats: feats.0.as_slice(), 1433 has_remaining: true, 1434 check_overlap: true, 1435 // We started at 15, and we iterated 4 items (skipping 3). 1436 idx: 11, 1437 buffer: vec!["c", "d"], 1438 set: "c,d".to_owned(), 1439 skipped_sets_counter: 3, 1440 skip_empty_set: false 1441 } 1442 ); 1443 assert_eq!(power_set.next_set(), Some("d")); 1444 assert_eq!( 1445 power_set, 1446 PowerSet { 1447 feats: feats.0.as_slice(), 1448 has_remaining: true, 1449 check_overlap: true, 1450 // We started at 11, and we iterated 4 items (skipping 3). 1451 idx: 7, 1452 buffer: vec!["d"], 1453 set: "d".to_owned(), 1454 skipped_sets_counter: 6, 1455 skip_empty_set: false 1456 } 1457 ); 1458 assert_eq!(power_set.next_set(), Some("c")); 1459 assert_eq!( 1460 power_set, 1461 PowerSet { 1462 feats: feats.0.as_slice(), 1463 has_remaining: true, 1464 check_overlap: true, 1465 // We started at 7, and we iterated 4 items (skipping 3). 1466 idx: 3, 1467 buffer: vec!["c"], 1468 set: "c".to_owned(), 1469 skipped_sets_counter: 9, 1470 skip_empty_set: false 1471 } 1472 ); 1473 assert_eq!(power_set.next_set(), Some("b")); 1474 assert_eq!( 1475 power_set, 1476 PowerSet { 1477 feats: feats.0.as_slice(), 1478 has_remaining: true, 1479 check_overlap: true, 1480 // We started at 3, and we iterated 2 items (skipping 1). 1481 idx: 1, 1482 buffer: vec!["b"], 1483 set: "b".to_owned(), 1484 skipped_sets_counter: 10, 1485 skip_empty_set: false 1486 } 1487 ); 1488 assert_eq!(power_set.next_set(), Some("a")); 1489 assert_eq!( 1490 power_set, 1491 PowerSet { 1492 feats: feats.0.as_slice(), 1493 has_remaining: true, 1494 check_overlap: true, 1495 // We started at 1, and we iterated 1 item. 1496 idx: 0, 1497 buffer: vec!["a"], 1498 set: "a".to_owned(), 1499 skipped_sets_counter: 10, 1500 skip_empty_set: false 1501 } 1502 ); 1503 assert_eq!(power_set.next_set(), Some("")); 1504 assert_eq!( 1505 power_set, 1506 PowerSet { 1507 feats: feats.0.as_slice(), 1508 has_remaining: false, 1509 check_overlap: true, 1510 // We started at 0, and we iterated 1 item but we don't underflow instead `has_remaining` is set 1511 // to `false`. 1512 idx: 0, 1513 buffer: Vec::new(), 1514 set: String::new(), 1515 skipped_sets_counter: 10, 1516 skip_empty_set: false 1517 } 1518 ); 1519 assert_eq!(power_set.next_set(), None); 1520 // Internal state is left unchanged. 1521 assert_eq!( 1522 power_set, 1523 PowerSet { 1524 feats: feats.0.as_slice(), 1525 has_remaining: false, 1526 check_overlap: true, 1527 idx: 0, 1528 buffer: Vec::new(), 1529 set: String::new(), 1530 skipped_sets_counter: 10, 1531 skip_empty_set: false 1532 } 1533 ); 1534 assert_eq!(power_set.next_set(), None); 1535 // Internal state is left unchanged. 1536 assert_eq!( 1537 power_set, 1538 PowerSet { 1539 feats: feats.0.as_slice(), 1540 has_remaining: false, 1541 check_overlap: true, 1542 idx: 0, 1543 buffer: Vec::new(), 1544 set: String::new(), 1545 skipped_sets_counter: 10, 1546 skip_empty_set: false 1547 } 1548 ); 1549 assert_eq!(power_set.len(), NonZeroUsizePlus1::new(16)); 1550 power_set.reset(); 1551 // `PowerSet::reset` only resets what is necessary nothing more; in particular, `buffer` and `set` are 1552 // left alone. 1553 assert_eq!( 1554 power_set, 1555 PowerSet { 1556 feats: feats.0.as_slice(), 1557 has_remaining: true, 1558 check_overlap: true, 1559 idx: 15, 1560 buffer: Vec::new(), 1561 set: String::new(), 1562 skipped_sets_counter: 0, 1563 skip_empty_set: false 1564 } 1565 ); 1566 assert_eq!(power_set.len(), NonZeroUsizePlus1::new(16)); 1567 // Same as above except no feature depends on any other. 1568 // [features] 1569 // a = [] 1570 // b = [] 1571 // c = [] 1572 // d = [] 1573 feats.0 = vec![ 1574 ("a".to_owned(), Vec::new()), 1575 ("b".to_owned(), Vec::new()), 1576 ("c".to_owned(), Vec::new()), 1577 ("d".to_owned(), Vec::new()), 1578 ]; 1579 assert_eq!( 1580 PowerSet::new(&feats, false), 1581 Ok(Some(PowerSet { 1582 feats: feats.0.as_slice(), 1583 has_remaining: true, 1584 check_overlap: false, 1585 idx: 15, 1586 buffer: vec!["a", "b", "c", "d"], 1587 set: String::new(), 1588 skipped_sets_counter: 0, 1589 skip_empty_set: false 1590 })) 1591 ); 1592 power_set = PowerSet::new(&feats, false) 1593 .unwrap_or_else(|_e| { 1594 unreachable!("not possible since we just verified PowerSet::new returned Ok") 1595 }) 1596 .unwrap_or_else(|| { 1597 unreachable!("not possible since we just verified PowerSet::new returned Ok(Some)") 1598 }); 1599 assert_eq!(power_set.len(), NonZeroUsizePlus1::new(16)); 1600 // Order is the same as above except nothing is skipped: 1601 // 1. a,b,c,d 1602 // 2. b,c,d 1603 // 3. a,c,d 1604 // 4. c,d 1605 // 5. a,b,d 1606 // 6. b,d 1607 // 7. a,d 1608 // 8. d 1609 // 9. a,b,c 1610 // 10. b,c 1611 // 11. a,c 1612 // 12. c 1613 // 13. a,b 1614 // 14. b 1615 // 15. a 1616 // 16. 1617 assert_eq!(power_set.next_set(), Some("a,b,c,d")); 1618 assert_eq!( 1619 power_set, 1620 PowerSet { 1621 feats: feats.0.as_slice(), 1622 has_remaining: true, 1623 check_overlap: false, 1624 idx: 14, 1625 buffer: vec!["a", "b", "c", "d"], 1626 set: "a,b,c,d".to_owned(), 1627 skipped_sets_counter: 0, 1628 skip_empty_set: false 1629 } 1630 ); 1631 assert_eq!(power_set.next_set(), Some("b,c,d")); 1632 assert_eq!( 1633 power_set, 1634 PowerSet { 1635 feats: feats.0.as_slice(), 1636 has_remaining: true, 1637 check_overlap: false, 1638 idx: 13, 1639 buffer: vec!["b", "c", "d"], 1640 set: "b,c,d".to_owned(), 1641 skipped_sets_counter: 0, 1642 skip_empty_set: false 1643 } 1644 ); 1645 assert_eq!(power_set.next_set(), Some("a,c,d")); 1646 assert_eq!( 1647 power_set, 1648 PowerSet { 1649 feats: feats.0.as_slice(), 1650 has_remaining: true, 1651 check_overlap: false, 1652 idx: 12, 1653 buffer: vec!["a", "c", "d"], 1654 set: "a,c,d".to_owned(), 1655 skipped_sets_counter: 0, 1656 skip_empty_set: false 1657 } 1658 ); 1659 assert_eq!(power_set.next_set(), Some("c,d")); 1660 assert_eq!( 1661 power_set, 1662 PowerSet { 1663 feats: feats.0.as_slice(), 1664 has_remaining: true, 1665 check_overlap: false, 1666 idx: 11, 1667 buffer: vec!["c", "d"], 1668 set: "c,d".to_owned(), 1669 skipped_sets_counter: 0, 1670 skip_empty_set: false 1671 } 1672 ); 1673 assert_eq!(power_set.next_set(), Some("a,b,d")); 1674 assert_eq!( 1675 power_set, 1676 PowerSet { 1677 feats: feats.0.as_slice(), 1678 has_remaining: true, 1679 check_overlap: false, 1680 idx: 10, 1681 buffer: vec!["a", "b", "d"], 1682 set: "a,b,d".to_owned(), 1683 skipped_sets_counter: 0, 1684 skip_empty_set: false 1685 } 1686 ); 1687 assert_eq!(power_set.next_set(), Some("b,d")); 1688 assert_eq!( 1689 power_set, 1690 PowerSet { 1691 feats: feats.0.as_slice(), 1692 has_remaining: true, 1693 check_overlap: false, 1694 idx: 9, 1695 buffer: vec!["b", "d"], 1696 set: "b,d".to_owned(), 1697 skipped_sets_counter: 0, 1698 skip_empty_set: false 1699 } 1700 ); 1701 assert_eq!(power_set.next_set(), Some("a,d")); 1702 assert_eq!( 1703 power_set, 1704 PowerSet { 1705 feats: feats.0.as_slice(), 1706 has_remaining: true, 1707 check_overlap: false, 1708 idx: 8, 1709 buffer: vec!["a", "d"], 1710 set: "a,d".to_owned(), 1711 skipped_sets_counter: 0, 1712 skip_empty_set: false 1713 } 1714 ); 1715 assert_eq!(power_set.next_set(), Some("d")); 1716 assert_eq!( 1717 power_set, 1718 PowerSet { 1719 feats: feats.0.as_slice(), 1720 has_remaining: true, 1721 check_overlap: false, 1722 idx: 7, 1723 buffer: vec!["d"], 1724 set: "d".to_owned(), 1725 skipped_sets_counter: 0, 1726 skip_empty_set: false 1727 } 1728 ); 1729 assert_eq!(power_set.next_set(), Some("a,b,c")); 1730 assert_eq!( 1731 power_set, 1732 PowerSet { 1733 feats: feats.0.as_slice(), 1734 has_remaining: true, 1735 check_overlap: false, 1736 idx: 6, 1737 buffer: vec!["a", "b", "c"], 1738 set: "a,b,c".to_owned(), 1739 skipped_sets_counter: 0, 1740 skip_empty_set: false 1741 } 1742 ); 1743 assert_eq!(power_set.next_set(), Some("b,c")); 1744 assert_eq!( 1745 power_set, 1746 PowerSet { 1747 feats: feats.0.as_slice(), 1748 has_remaining: true, 1749 check_overlap: false, 1750 idx: 5, 1751 buffer: vec!["b", "c"], 1752 set: "b,c".to_owned(), 1753 skipped_sets_counter: 0, 1754 skip_empty_set: false 1755 } 1756 ); 1757 assert_eq!(power_set.next_set(), Some("a,c")); 1758 assert_eq!( 1759 power_set, 1760 PowerSet { 1761 feats: feats.0.as_slice(), 1762 has_remaining: true, 1763 check_overlap: false, 1764 idx: 4, 1765 buffer: vec!["a", "c"], 1766 set: "a,c".to_owned(), 1767 skipped_sets_counter: 0, 1768 skip_empty_set: false 1769 } 1770 ); 1771 assert_eq!(power_set.next_set(), Some("c")); 1772 assert_eq!( 1773 power_set, 1774 PowerSet { 1775 feats: feats.0.as_slice(), 1776 has_remaining: true, 1777 check_overlap: false, 1778 idx: 3, 1779 buffer: vec!["c"], 1780 set: "c".to_owned(), 1781 skipped_sets_counter: 0, 1782 skip_empty_set: false 1783 } 1784 ); 1785 assert_eq!(power_set.next_set(), Some("a,b")); 1786 assert_eq!( 1787 power_set, 1788 PowerSet { 1789 feats: feats.0.as_slice(), 1790 has_remaining: true, 1791 check_overlap: false, 1792 idx: 2, 1793 buffer: vec!["a", "b"], 1794 set: "a,b".to_owned(), 1795 skipped_sets_counter: 0, 1796 skip_empty_set: false 1797 } 1798 ); 1799 assert_eq!(power_set.next_set(), Some("b")); 1800 assert_eq!( 1801 power_set, 1802 PowerSet { 1803 feats: feats.0.as_slice(), 1804 has_remaining: true, 1805 check_overlap: false, 1806 idx: 1, 1807 buffer: vec!["b"], 1808 set: "b".to_owned(), 1809 skipped_sets_counter: 0, 1810 skip_empty_set: false 1811 } 1812 ); 1813 assert_eq!(power_set.next_set(), Some("a")); 1814 assert_eq!( 1815 power_set, 1816 PowerSet { 1817 feats: feats.0.as_slice(), 1818 has_remaining: true, 1819 check_overlap: false, 1820 idx: 0, 1821 buffer: vec!["a"], 1822 set: "a".to_owned(), 1823 skipped_sets_counter: 0, 1824 skip_empty_set: false 1825 } 1826 ); 1827 assert_eq!(power_set.next_set(), Some("")); 1828 assert_eq!( 1829 power_set, 1830 PowerSet { 1831 feats: feats.0.as_slice(), 1832 has_remaining: false, 1833 check_overlap: false, 1834 idx: 0, 1835 buffer: Vec::new(), 1836 set: String::new(), 1837 skipped_sets_counter: 0, 1838 skip_empty_set: false 1839 } 1840 ); 1841 assert_eq!(power_set.next_set(), None); 1842 assert_eq!( 1843 power_set, 1844 PowerSet { 1845 feats: feats.0.as_slice(), 1846 has_remaining: false, 1847 check_overlap: false, 1848 idx: 0, 1849 buffer: Vec::new(), 1850 set: String::new(), 1851 skipped_sets_counter: 0, 1852 skip_empty_set: false 1853 } 1854 ); 1855 assert_eq!(power_set.len(), NonZeroUsizePlus1::new(16)); 1856 feats.0 = vec![("a".to_owned(), Vec::new())]; 1857 assert_eq!( 1858 PowerSet::new(&feats, true), 1859 Ok(Some(PowerSet { 1860 feats: feats.0.as_slice(), 1861 has_remaining: true, 1862 check_overlap: false, 1863 idx: 1, 1864 buffer: vec!["a"], 1865 set: String::new(), 1866 skipped_sets_counter: 0, 1867 skip_empty_set: true 1868 })) 1869 ); 1870 power_set = PowerSet::new(&feats, true) 1871 .unwrap_or_else(|_e| { 1872 unreachable!("not possible since we just verified PowerSet::new returned Ok") 1873 }) 1874 .unwrap_or_else(|| { 1875 unreachable!("not possible since we just verified PowerSet::new returned Ok(Some)") 1876 }); 1877 assert_eq!(power_set.len(), NonZeroUsizePlus1::new(1)); 1878 assert_eq!(power_set.next_set(), Some("a")); 1879 assert_eq!( 1880 power_set, 1881 PowerSet { 1882 feats: feats.0.as_slice(), 1883 has_remaining: false, 1884 check_overlap: false, 1885 idx: 0, 1886 buffer: vec!["a"], 1887 set: "a".to_owned(), 1888 skipped_sets_counter: 0, 1889 skip_empty_set: true, 1890 } 1891 ); 1892 assert_eq!(power_set.next_set(), None); 1893 assert_eq!( 1894 power_set, 1895 PowerSet { 1896 feats: feats.0.as_slice(), 1897 has_remaining: false, 1898 check_overlap: false, 1899 idx: 0, 1900 buffer: vec!["a"], 1901 set: "a".to_owned(), 1902 skipped_sets_counter: 0, 1903 skip_empty_set: true, 1904 } 1905 ); 1906 assert_eq!(power_set.next_set(), None); 1907 assert_eq!( 1908 power_set, 1909 PowerSet { 1910 feats: feats.0.as_slice(), 1911 has_remaining: false, 1912 check_overlap: false, 1913 idx: 0, 1914 buffer: vec!["a"], 1915 set: "a".to_owned(), 1916 skipped_sets_counter: 0, 1917 skip_empty_set: true, 1918 } 1919 ); 1920 power_set.reset(); 1921 assert_eq!( 1922 power_set, 1923 PowerSet { 1924 feats: feats.0.as_slice(), 1925 has_remaining: true, 1926 check_overlap: false, 1927 idx: 1, 1928 buffer: vec!["a"], 1929 set: "a".to_owned(), 1930 skipped_sets_counter: 0, 1931 skip_empty_set: true, 1932 } 1933 ); 1934 assert_eq!(power_set.next_set(), Some("a")); 1935 assert_eq!(power_set.next_set(), None); 1936 assert_eq!( 1937 power_set, 1938 PowerSet { 1939 feats: feats.0.as_slice(), 1940 has_remaining: false, 1941 check_overlap: false, 1942 idx: 0, 1943 buffer: vec!["a"], 1944 set: "a".to_owned(), 1945 skipped_sets_counter: 0, 1946 skip_empty_set: true, 1947 } 1948 ); 1949 assert_eq!(power_set.len(), NonZeroUsizePlus1::new(1)); 1950 }