Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package mdevctl for openSUSE:Factory checked 
in at 2022-12-13 18:54:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/mdevctl (Old)
 and      /work/SRC/openSUSE:Factory/.mdevctl.new.1835 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "mdevctl"

Tue Dec 13 18:54:32 2022 rev:6 rq:1042231 version:1.2.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/mdevctl/mdevctl.changes  2022-03-24 
22:56:51.668183938 +0100
+++ /work/SRC/openSUSE:Factory/.mdevctl.new.1835/mdevctl.changes        
2022-12-13 18:54:34.610918125 +0100
@@ -1,0 +2,11 @@
+Sun Dec 11 18:19:52 UTC 2022 - [email protected]
+
+- Update to version 1.2.0:
+  * Port CLI to clap v3
+  * start: provide useful hint for parent with wrong case
+  * tests: Add ability to test error messages
+  * tests: extract function for checking pass/fail expectations
+  * MDev::create() does not need to be public
+  * Fix new clippy warning
+
+-------------------------------------------------------------------

Old:
----
  mdevctl-1.1.0.tar.xz
  vendor.tar.xz

New:
----
  _servicedata
  cargo_config
  mdevctl-1.2.0.tar.xz
  vendor.tar.zst

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ mdevctl.spec ++++++
--- /var/tmp/diff_new_pack.BdDHoT/_old  2022-12-13 18:54:35.390922288 +0100
+++ /var/tmp/diff_new_pack.BdDHoT/_new  2022-12-13 18:54:35.398922330 +0100
@@ -17,16 +17,18 @@
 
 
 Name:           mdevctl
-Version:        1.1.0
+Version:        1.2.0
 Release:        0
 Summary:        Mediated device management and persistence utility
 License:        LGPL-2.1-or-later
 URL:            https://github.com/mdevctl/mdevctl
 Source0:        %{name}-%{version}.tar.xz
-Source1:        vendor.tar.xz
+Source1:        vendor.tar.zst
+Source2:        cargo_config
 BuildRequires:  cargo
 BuildRequires:  python3-docutils
 BuildRequires:  rust
+BuildRequires:  zstd
 BuildRequires:  pkgconfig(udev)
 
 %description

++++++ _service ++++++
--- /var/tmp/diff_new_pack.BdDHoT/_old  2022-12-13 18:54:35.474922736 +0100
+++ /var/tmp/diff_new_pack.BdDHoT/_new  2022-12-13 18:54:35.478922758 +0100
@@ -1,7 +1,7 @@
 <services>
   <service name="tar_scm" mode="disabled">
     <param name="filename">mdevctl</param>
-    <param name="revision">13084d837490f6c0671e2ab9a275cbe3611750c5</param>
+    <param name="revision">v1.2.0</param>
     <param name="scm">git</param>
     <param name="submodules">disable</param>
     <param name="url">https://github.com/mdevctl/mdevctl</param>
@@ -14,5 +14,13 @@
     <param name="compression">xz</param>
   </service>
   <service name="set_version" mode="disabled"/>
+  <service name="cargo_vendor" mode="disabled">
+     <param name="srcdir">mdevctl-1.2.0</param>
+     <param name="compression">zst</param>
+     <param name="update">true</param>
+  </service>
+  <service name="cargo_audit" mode="disabled">
+     <param name="srcdir">mdevctl-1.2.0</param>
+  </service>
 </services>
 

++++++ _servicedata ++++++
<servicedata>
<service name="tar_scm">
                <param name="url">https://github.com/mdevctl/mdevctl</param>
              <param 
name="changesrevision">ec4b9a04ce15ad7dccef2dc99b20a53987eb16bc</param></service></servicedata>
(No newline at EOF)

++++++ cargo_config ++++++
[source.crates-io]
replace-with = "vendored-sources"

[source.vendored-sources]
directory = "vendor"
(No newline at EOF)

++++++ mdevctl-1.1.0.tar.xz -> mdevctl-1.2.0.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mdevctl-1.1.0/.gitignore new/mdevctl-1.2.0/.gitignore
--- old/mdevctl-1.1.0/.gitignore        1970-01-01 01:00:00.000000000 +0100
+++ new/mdevctl-1.2.0/.gitignore        2022-08-05 18:01:16.000000000 +0200
@@ -0,0 +1,7 @@
+/target
+*.sw?
+Cargo.lock
+Makefile
+mdevctl.spec
+/vendor/
+/*.rpm
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mdevctl-1.1.0/Cargo.toml new/mdevctl-1.2.0/Cargo.toml
--- old/mdevctl-1.1.0/Cargo.toml        2022-02-28 18:10:22.000000000 +0100
+++ new/mdevctl-1.2.0/Cargo.toml        2022-08-05 18:01:16.000000000 +0200
@@ -1,7 +1,7 @@
 [package]
 name = "mdevctl"
 # For now, just bump the y version on release (x.y.z)
-version = "1.1.0"
+version = "1.2.0"
 authors = ["Jonathon Jongsma <[email protected]>"]
 edition = "2018"
 license = "LGPL-2.1"
@@ -13,13 +13,14 @@
 
 [dependencies]
 anyhow = "1.0"
+clap = { version = "3.1.18", features = ["derive"]}
 env_logger = "0.8.3"
 log = "0.4"
 serde_json = {version = "1.0", features = ["preserve_order"]}
-structopt = "0.3.13"
 uuid = {version = "0.8.2", features = ["v4"]}
 tempfile = "3"
 
 [build-dependencies]
-structopt = "0.3.13"
+clap = { version = "3.1.18", features = ["derive"]}
+clap_complete = "3.0.6"
 uuid = "0.8.2"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mdevctl-1.1.0/build.rs new/mdevctl-1.2.0/build.rs
--- old/mdevctl-1.1.0/build.rs  2022-02-28 18:10:22.000000000 +0100
+++ new/mdevctl-1.2.0/build.rs  2022-08-05 18:01:16.000000000 +0200
@@ -1,9 +1,9 @@
+use clap::CommandFactory;
+use clap_complete::{generate_to, Shell};
 use std::env;
 use std::fs;
 use std::path::{Path, PathBuf};
 use std::process::Command;
-use structopt::clap::Shell;
-use structopt::StructOpt;
 
 #[path = "src/cli.rs"]
 mod cli;
@@ -44,13 +44,18 @@
         .expect("Unable to generate manpage. Is 'rst2man' installed? You can 
specify a custom 'rst2man' executable by setting the RST2MAN environment 
variable.");
 }
 
+fn generate_completion(cmd: &mut clap::Command, outdir: &PathBuf) {
+    let name = cmd.get_name().to_string();
+    generate_to(Shell::Bash, cmd, name, outdir).expect("Unable to generate 
shell completion files");
+}
+
 fn main() {
     let outdir =
         PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR environment 
variable not defined"));
 
     // generate bash completions for both executables
-    cli::MdevctlCommands::clap().gen_completions("mdevctl", Shell::Bash, 
&outdir);
-    cli::LsmdevOptions::clap().gen_completions("lsmdev", Shell::Bash, &outdir);
+    generate_completion(&mut cli::MdevctlCommands::command(), &outdir);
+    generate_completion(&mut cli::LsmdevOptions::command(), &outdir);
 
     // generate manpage
     generate_manpage(outdir);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mdevctl-1.1.0/mdevctl.rst 
new/mdevctl-1.2.0/mdevctl.rst
--- old/mdevctl-1.1.0/mdevctl.rst       2022-02-28 18:10:22.000000000 +0100
+++ new/mdevctl-1.2.0/mdevctl.rst       2022-08-05 18:01:16.000000000 +0200
@@ -63,7 +63,8 @@
     for the ``modify`` command.
 
 ``-p|--parent=PARENT``
-    Specify or identify the device by its parent device.
+    Specify or identify the device by its parent device. Note that the parent
+    device is specified by its kernel sysfs name and is case-sensitive.
 
 ``-t|--type=TYPE``
     Specify or identify the device by its type.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mdevctl-1.1.0/src/cli.rs new/mdevctl-1.2.0/src/cli.rs
--- old/mdevctl-1.1.0/src/cli.rs        2022-02-28 18:10:22.000000000 +0100
+++ new/mdevctl-1.2.0/src/cli.rs        2022-08-05 18:01:16.000000000 +0200
@@ -1,21 +1,21 @@
 //! Command line options for mdevctl
 
+pub use clap::Parser;
 use std::path::PathBuf;
-pub use structopt::StructOpt;
 use uuid::Uuid;
 
-#[derive(StructOpt, Debug)]
-#[structopt(about = "List mediated devices")]
+#[derive(Parser, Debug)]
+#[clap(version, about = "List mediated devices", name = "lsmdev")]
 pub struct LsmdevOptions {
-    #[structopt(short, long, help = "Show defined devices")]
+    #[clap(short, long, help = "Show defined devices")]
     pub defined: bool,
-    #[structopt(long, help = "Output device list in json format")]
+    #[clap(long, help = "Output device list in json format")]
     pub dumpjson: bool,
-    #[structopt(short, long, help = "Print additional information about the 
devices")]
+    #[clap(short, long, help = "Print additional information about the 
devices")]
     pub verbose: bool,
-    #[structopt(short, long, help = "List devices matching the specified 
UUID")]
+    #[clap(short, long, help = "List devices matching the specified UUID")]
     pub uuid: Option<Uuid>,
-    #[structopt(
+    #[clap(
         short,
         long,
         help = "List devices associated with the specified Parent device"
@@ -24,16 +24,10 @@
 }
 
 // command-line argument definitions.
-#[derive(StructOpt)]
-#[structopt(
-    about = "A mediated device management utility for Linux",
-    global_settings = &[
-        structopt::clap::AppSettings::VersionlessSubcommands,
-        structopt::clap::AppSettings::UnifiedHelpMessage,
-    ]
-)]
+#[derive(Parser)]
+#[clap(version, about = "A mediated device management utility for Linux")]
 pub enum MdevctlCommands {
-    #[structopt(
+    #[clap(
         about = "Define a persistent mediated device",
         long_about = "Define a persistent mediated device\n\n\
                 If the device specified by the UUID currently exists, 'parent' 
and 'type' may be \
@@ -43,34 +37,34 @@
                 Running devices are unaffected by this command."
     )]
     Define {
-        #[structopt(
+        #[clap(
             short,
             long,
-            required_unless("parent"),
+            required_unless_present("parent"),
             help = "Assign UUID to the device"
         )]
         uuid: Option<Uuid>,
-        #[structopt(
+        #[clap(
             short,
             long,
             help = "Automatically start device on parent availability"
         )]
         auto: bool,
-        #[structopt(
+        #[clap(
             short,
             long,
-            required_unless("uuid"),
+            required_unless_present("uuid"),
             help = "Specify the parent of the device"
         )]
         parent: Option<String>,
-        #[structopt(
+        #[clap(
             name = "type",
             short,
             long,
             help = "Specify the mdev type of the device"
         )]
         mdev_type: Option<String>,
-        #[structopt(
+        #[clap(
             long, parse(from_os_str),
             conflicts_with_all(&["type", "auto"]),
             help = "Specify device details in JSON format"
@@ -78,7 +72,7 @@
         jsonfile: Option<PathBuf>,
     },
 
-    #[structopt(
+    #[clap(
         about = "Undefine a persistent mediated device",
         long_about = "Undefine, or remove a config for an mdev device\n\n\
                 If a UUID exists for multiple parents, all will be removed 
unless a parent is
@@ -86,13 +80,13 @@
                 Running devices are unaffected by this command."
     )]
     Undefine {
-        #[structopt(short, long, help = "UUID of the device to be undefined")]
+        #[clap(short, long, help = "UUID of the device to be undefined")]
         uuid: Uuid,
-        #[structopt(short, long, help = "Parent of the device to be 
undefined")]
+        #[clap(short, long, help = "Parent of the device to be undefined")]
         parent: Option<String>,
     },
 
-    #[structopt(
+    #[clap(
         about = "Modify the definition of a mediated device",
         long_about = "Modify the definition of a mediated device\n\n\
                 The 'parent' option further identifies a UUID if it is not 
unique. The parent for a \
@@ -107,18 +101,18 @@
                 Running devices are unaffected by this command."
     )]
     Modify {
-        #[structopt(short, long, help = "UUID of the mdev to modify")]
+        #[clap(short, long, help = "UUID of the mdev to modify")]
         uuid: Uuid,
-        #[structopt(short, long, help = "Parent of the mdev to modify")]
+        #[clap(short, long, help = "Parent of the mdev to modify")]
         parent: Option<String>,
-        #[structopt(
+        #[clap(
             name = "type",
             short,
             long,
             help = "Modify the mdev type for this device"
         )]
         mdev_type: Option<String>,
-        #[structopt(
+        #[clap(
             long,
             conflicts_with("delattr"),
             requires("value"),
@@ -126,19 +120,19 @@
             value_name = "attr_name"
         )]
         addattr: Option<String>,
-        #[structopt(long, help = "Delete an attribute")]
+        #[clap(long, help = "Delete an attribute")]
         delattr: bool,
-        #[structopt(long, short, help = "Index of the attribute to modify")]
+        #[clap(long, short, help = "Index of the attribute to modify")]
         index: Option<u32>,
-        #[structopt(
+        #[clap(
             long,
             help = "Value for the attribute specified by --addattr",
             value_name = "attr_value"
         )]
         value: Option<String>,
-        #[structopt(short, long, help = "Device will be started 
automatically")]
+        #[clap(short, long, help = "Device will be started automatically")]
         auto: bool,
-        #[structopt(
+        #[clap(
             short,
             long,
             conflicts_with("auto"),
@@ -146,7 +140,7 @@
         )]
         manual: bool,
     },
-    #[structopt(
+    #[clap(
         about = "Start a mediated device",
         long_about = "Start a mediated device\n\n\
                 If the UUID is previously defined and unique, the UUID is 
sufficient to start the \
@@ -159,23 +153,23 @@
                 attributes to be applied to the started device."
     )]
     Start {
-        #[structopt(
+        #[clap(
             short,
             long,
-            required_unless("parent"),
+            required_unless_present("parent"),
             help = "UUID of the device to start"
         )]
         uuid: Option<Uuid>,
-        #[structopt(
+        #[clap(
             short,
             long,
-            required_unless("uuid"),
+            required_unless_present("uuid"),
             help = "Parent of the device to start"
         )]
         parent: Option<String>,
-        #[structopt(name = "type", short, long, help = "Mdev type of the 
device to start")]
+        #[clap(name = "type", short, long, help = "Mdev type of the device to 
start")]
         mdev_type: Option<String>,
-        #[structopt(
+        #[clap(
             long,
             parse(from_os_str),
             conflicts_with("type"),
@@ -183,12 +177,12 @@
         )]
         jsonfile: Option<PathBuf>,
     },
-    #[structopt(about = "Stop a mediated device")]
+    #[clap(about = "Stop a mediated device")]
     Stop {
-        #[structopt(short, long, help = "UUID of the device to stop")]
+        #[clap(short, long, help = "UUID of the device to stop")]
         uuid: Uuid,
     },
-    #[structopt(
+    #[clap(
         about = "List mediated devices",
         long_about = "List mediated devices\n\n\
                 With no options, information about the currently running 
mediated devices is \
@@ -202,18 +196,18 @@
                 include attributes for the device(s)."
     )]
     List(LsmdevOptions),
-    #[structopt(
+    #[clap(
         about = "List available mediated device types",
         long_about = "List available mediated device types\n\n\
                 Specifying a 'parent' lists only the types provided by the 
given parent device. \
                 The 'dumpjson' option provides output in machine readable JSON 
format."
     )]
     Types {
-        #[structopt(short, long, help = "Show supported types for the 
specified parent")]
+        #[clap(short, long, help = "Show supported types for the specified 
parent")]
         parent: Option<String>,
-        #[structopt(long, help = "Output mdev types list in JSON format")]
+        #[clap(long, help = "Output mdev types list in JSON format")]
         dumpjson: bool,
     },
-    #[structopt(setting = structopt::clap::AppSettings::Hidden)]
+    #[clap(hide = true)]
     StartParentMdevs { parent: String },
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mdevctl-1.1.0/src/main.rs 
new/mdevctl-1.2.0/src/main.rs
--- old/mdevctl-1.1.0/src/main.rs       2022-02-28 18:10:22.000000000 +0100
+++ new/mdevctl-1.2.0/src/main.rs       2022-08-05 18:01:16.000000000 +0200
@@ -6,6 +6,7 @@
 //! See `mdevctl help` or the manpage for more information.
 
 use anyhow::{anyhow, ensure, Context, Result};
+use clap::Parser;
 use log::{debug, warn};
 use std::cmp::Ordering;
 use std::collections::BTreeMap;
@@ -13,7 +14,6 @@
 use std::io::Read;
 use std::path::PathBuf;
 use std::vec::Vec;
-use structopt::StructOpt;
 use uuid::Uuid;
 
 use crate::callouts::*;
@@ -625,7 +625,7 @@
                 if path.exists() {
                     t.description = fs::read_to_string(&path)?
                         .trim()
-                        .replace("\n", ", ")
+                        .replace('\n', ", ")
                         .to_string();
                 }
 
@@ -737,7 +737,7 @@
     match exe.to_str() {
         Some(val) if val.ends_with("lsmdev") => {
             debug!("running as 'lsmdev'");
-            let opts = LsmdevOptions::from_args();
+            let opts = LsmdevOptions::parse();
             list_command(
                 &env,
                 opts.defined,
@@ -747,7 +747,7 @@
                 opts.parent,
             )
         }
-        _ => match MdevctlCommands::from_args() {
+        _ => match MdevctlCommands::parse() {
             MdevctlCommands::Define {
                 uuid,
                 auto,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mdevctl-1.1.0/src/mdev.rs 
new/mdevctl-1.2.0/src/mdev.rs
--- old/mdevctl-1.1.0/src/mdev.rs       2022-02-28 18:10:22.000000000 +0100
+++ new/mdevctl-1.2.0/src/mdev.rs       2022-08-05 18:01:16.000000000 +0200
@@ -287,7 +287,31 @@
         }
     }
 
-    pub fn create(&mut self) -> Result<()> {
+    fn find_parent_dir(&self) -> Result<PathBuf> {
+        let parent = self.parent()?;
+        let path: PathBuf = self.env.parent_base().join(&parent);
+
+        if path.is_dir() {
+            return Ok(path);
+        }
+
+        // check if there's a similar parent dir with different capitalization
+        let parentsdir = self.env.parent_base().read_dir()?;
+        for subdir in parentsdir {
+            let dir = subdir?;
+            let parentname = dir.file_name();
+            if parentname.to_string_lossy().to_lowercase() == 
parent.to_lowercase() {
+                return Err(anyhow!(
+                    "Unable to find parent device '{}'. Did you mean '{}'?",
+                    parent,
+                    parentname.to_string_lossy()
+                ));
+            }
+        }
+        Err(anyhow!("Unable to find parent device '{}'", parent))
+    }
+
+    fn create(&mut self) -> Result<()> {
         debug!("Creating mdev {:?}", self.uuid);
         let parent = self.parent()?;
         let mdev_type = self.mdev_type()?;
@@ -303,11 +327,8 @@
             return Err(anyhow!("Device already exists"));
         }
 
-        let mut path: PathBuf = self
-            .env
-            .parent_base()
-            .join(&parent)
-            .join("mdev_supported_types");
+        let mut path = self.find_parent_dir()?;
+        path.push("mdev_supported_types");
         debug!("Checking parent for mdev support: {:?}", path);
         if !path.is_dir() {
             return Err(anyhow!(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mdevctl-1.1.0/src/tests.rs 
new/mdevctl-1.2.0/src/tests.rs
--- old/mdevctl-1.1.0/src/tests.rs      2022-02-28 18:10:22.000000000 +0100
+++ new/mdevctl-1.2.0/src/tests.rs      2022-08-05 18:01:16.000000000 +0200
@@ -1,4 +1,4 @@
-use anyhow::Result;
+use anyhow::{anyhow, Result};
 use log::info;
 use std::collections::BTreeMap;
 use std::env;
@@ -19,10 +19,23 @@
     let _ = logger().is_test(true).try_init();
 }
 
-#[derive(PartialEq)]
-enum Expect {
+fn assert_result<T: std::fmt::Debug>(res: Result<T>, expect: Expect, testname: 
&str) -> Result<T> {
+    match expect {
+        Expect::Fail(msg) => {
+            let e = res.expect_err(format!("Expected {} to fail", 
testname).as_str());
+            if let Some(msg) = msg {
+                assert_eq!(msg, e.to_string());
+            }
+            Err(anyhow!(e))
+        }
+        Expect::Pass => Ok(res.expect(format!("Expected {} to pass", 
testname).as_str())),
+    }
+}
+
+#[derive(PartialEq, Clone, Copy)]
+enum Expect<'a> {
     Pass,
-    Fail,
+    Fail(Option<&'a str>),
 }
 
 #[derive(Debug)]
@@ -192,19 +205,14 @@
     let test = TestEnvironment::new("load-json", uuid);
 
     let res = test.load_from_json(uuid, parent, &format!("{}.in", uuid));
-    if expect == Expect::Fail {
-        info!("{:?}", res);
-        res.expect_err("Expected command to fail");
-        return;
+    if let Ok(dev) = assert_result(res, expect, "load-json") {
+        let jsonval = dev.to_json(false).unwrap();
+        let jsonstr = serde_json::to_string_pretty(&jsonval).unwrap();
+
+        test.compare_to_file(&format!("{}.out", uuid), &jsonstr);
+        assert_eq!(uuid, dev.uuid.to_hyphenated().to_string());
+        assert_eq!(Some(parent.to_string()), dev.parent);
     }
-
-    let dev = res.expect("Command failed unexpectedly");
-    let jsonval = dev.to_json(false).unwrap();
-    let jsonstr = serde_json::to_string_pretty(&jsonval).unwrap();
-
-    test.compare_to_file(&format!("{}.out", uuid), &jsonstr);
-    assert_eq!(uuid, dev.uuid.to_hyphenated().to_string());
-    assert_eq!(Some(parent.to_string()), dev.parent);
 }
 
 #[test]
@@ -235,19 +243,19 @@
     test_load_json_helper(
         "b6f7e33f-ea28-4f9d-8c42-797ff0ec2888",
         "0000:00:03.0",
-        Expect::Fail,
+        Expect::Fail(None),
     );
     // json file has malformed attributes - an array of strings
     test_load_json_helper(
         "fe7a39db-973b-47b4-9b77-1d7b97267d59",
         "0000:00:03.0",
-        Expect::Fail,
+        Expect::Fail(None),
     );
     // json file has malformed attributes - no array
     test_load_json_helper(
         "37ccb149-a0ce-49e3-8391-a952ef07bdc2",
         "0000:00:03.0",
-        Expect::Fail,
+        Expect::Fail(None),
     );
 }
 
@@ -267,12 +275,7 @@
     use crate::define_command;
     let res = define_command(&test, uuid, false, parent, mdev_type, None);
 
-    if expect == Expect::Fail {
-        res.expect_err("expected callout to fail");
-        return;
-    }
-
-    assert!(res.is_ok());
+    let _ = assert_result(res, expect, "define callout");
 }
 
 fn test_define_helper<F>(
@@ -298,20 +301,16 @@
 
     setupfn(&test);
 
-    let def = define_command_helper(&test, uuid, auto, parent, mdev_type, 
jsonfile);
-    if expect == Expect::Fail {
-        def.expect_err("expected define command to fail");
-        return;
+    let res = define_command_helper(&test, uuid, auto, parent, mdev_type, 
jsonfile);
+    if let Ok(def) = assert_result(res, expect, "define command") {
+        let path = def.persist_path().unwrap();
+        assert!(!path.exists());
+        def.define().expect("Failed to define device");
+        assert!(path.exists());
+        assert!(def.is_defined());
+        let filecontents = fs::read_to_string(&path).unwrap();
+        test.compare_to_file(&format!("{}.expected", testname), &filecontents);
     }
-
-    let def = def.expect("define command failed unexpectedly");
-    let path = def.persist_path().unwrap();
-    assert!(!path.exists());
-    def.define().expect("Failed to define device");
-    assert!(path.exists());
-    assert!(def.is_defined());
-    let filecontents = fs::read_to_string(&path).unwrap();
-    test.compare_to_file(&format!("{}.expected", testname), &filecontents);
 }
 
 #[test]
@@ -322,7 +321,7 @@
     const DEFAULT_PARENT: &str = "0000:00:03.0";
     test_define_helper(
         "no-uuid-no-type",
-        Expect::Fail,
+        Expect::Fail(None),
         None,
         true,
         Some(DEFAULT_PARENT.to_string()),
@@ -366,7 +365,7 @@
     // invalid to specify an separate mdev_type if defining via jsonfile
     test_define_helper(
         "jsonfile-type",
-        Expect::Fail,
+        Expect::Fail(None),
         Uuid::parse_str(DEFAULT_UUID).ok(),
         false,
         Some(DEFAULT_PARENT.to_string()),
@@ -388,7 +387,7 @@
     // If uuid is already active, specifying mdev_type will result in an error
     test_define_helper(
         "uuid-running-no-parent",
-        Expect::Fail,
+        Expect::Fail(None),
         Uuid::parse_str(DEFAULT_UUID).ok(),
         false,
         None,
@@ -442,7 +441,7 @@
     // defining a device that is already defined should result in an error
     test_define_helper(
         "uuid-already-defined",
-        Expect::Fail,
+        Expect::Fail(None),
         Uuid::parse_str(DEFAULT_UUID).ok(),
         false,
         Some(DEFAULT_PARENT.to_string()),
@@ -466,7 +465,7 @@
     );
     test_define_command_callout(
         "define-with-callout-all-fail",
-        Expect::Fail,
+        Expect::Fail(None),
         Uuid::parse_str(DEFAULT_UUID).ok(),
         Some(DEFAULT_PARENT.to_string()),
         Some("i915-GVTg_V5_4".to_string()),
@@ -488,7 +487,7 @@
     );
     test_define_command_callout(
         "define-with-callout-all-bad-json",
-        Expect::Fail,
+        Expect::Fail(None),
         Uuid::parse_str(DEFAULT_UUID).ok(),
         Some(DEFAULT_PARENT.to_string()),
         Some("i915-GVTg_V5_4".to_string()),
@@ -531,13 +530,10 @@
         auto,
         manual,
     );
-    if expect == Expect::Fail {
-        assert!(result.is_err());
+    if assert_result(result, expect, "modify command").is_err() {
         return;
     }
 
-    result.expect("Modify command failed unexpectedly");
-
     let def = crate::get_defined_device(&test, uuid, parent.as_ref())
         .expect("Couldn't find defined device");
     let path = def.persist_path().unwrap();
@@ -555,7 +551,7 @@
     const PARENT: &str = "0000:00:03.0";
     test_modify_helper(
         "device-not-defined",
-        Expect::Fail,
+        Expect::Fail(None),
         UUID,
         None,
         None,
@@ -681,7 +677,7 @@
     );
     test_modify_helper(
         "multiple-noparent",
-        Expect::Fail,
+        Expect::Fail(None),
         UUID,
         None,
         None,
@@ -715,7 +711,7 @@
     );
     test_modify_helper(
         "auto-manual",
-        Expect::Fail,
+        Expect::Fail(None),
         UUID,
         Some(PARENT.to_string()),
         None,
@@ -744,13 +740,10 @@
 
     let result = crate::undefine_command(&test, uuid, parent.clone());
 
-    if expect == Expect::Fail {
-        result.expect_err("undefine command should have failed");
+    if assert_result(result, expect, "undefine command").is_err() {
         return;
     }
 
-    result.expect("undefine command should have succeeded");
-
     let devs = crate::defined_devices(&test, Some(&uuid), parent.as_ref())
         .expect("failed to query defined devices");
     assert!(devs.is_empty());
@@ -793,7 +786,7 @@
     });
     test_undefine_helper(
         "nonexistent",
-        Expect::Fail,
+        Expect::Fail(None),
         UUID,
         Some(PARENT.to_string()),
         |_| {},
@@ -815,13 +808,7 @@
 
     use crate::start_command;
     let res = start_command(&test, uuid, parent, mdev_type, None);
-
-    if expect == Expect::Fail {
-        res.expect_err("expected callout to fail");
-        return;
-    }
-
-    assert!(res.is_ok());
+    let _ = assert_result(res, expect, "start callout");
 }
 
 fn test_start_helper<F>(
@@ -840,33 +827,27 @@
     setupfn(&test);
     let uuid = uuid.map(|s| Uuid::parse_str(s.as_ref()).unwrap());
 
-    let dev = crate::start_command_helper(&test, uuid, parent, mdev_type, 
jsonfile);
+    let result = crate::start_command_helper(&test, uuid, parent, mdev_type, 
jsonfile);
 
-    if expect_setup == Expect::Fail {
-        dev.expect_err("start command should have failed");
-        return;
-    }
-    let mut dev = dev.expect("Couldn't run start command");
-
-    let result = dev.start();
-    if expect_execute == Expect::Fail {
-        result.expect_err("start command should have failed");
-        return;
-    }
-    result.expect("Couldn't start the device");
+    if let Ok(mut dev) = assert_result(result, expect_setup, "start command 
setup") {
+        let result = dev.start();
+        if assert_result(result, expect_execute, "start command").is_err() {
+            return;
+        }
 
-    let create_path = test
-        .parent_base()
-        .join(dev.parent.unwrap())
-        .join("mdev_supported_types")
-        .join(dev.mdev_type.unwrap())
-        .join("create");
-    assert!(create_path.exists());
-    if uuid.is_some() {
-        assert_eq!(uuid.unwrap(), dev.uuid);
+        let create_path = test
+            .parent_base()
+            .join(dev.parent.unwrap())
+            .join("mdev_supported_types")
+            .join(dev.mdev_type.unwrap())
+            .join("create");
+        assert!(create_path.exists());
+        if uuid.is_some() {
+            assert_eq!(uuid.unwrap(), dev.uuid);
+        }
+        let contents = fs::read_to_string(create_path).expect("Unable to read 
'create' file");
+        assert_eq!(dev.uuid.to_hyphenated().to_string(), contents);
     }
-    let contents = fs::read_to_string(create_path).expect("Unable to read 
'create' file");
-    assert_eq!(dev.uuid.to_hyphenated().to_string(), contents);
 }
 
 #[test]
@@ -876,6 +857,7 @@
     const UUID: &str = "976d8cc2-4bfc-43b9-b9f9-f4af2de91ab9";
     const PARENT: &str = "0000:00:03.0";
     const PARENT2: &str = "0000:00:02.0";
+    const PARENT3: &str = "0000:2b:00.0";
     const MDEV_TYPE: &str = "arbitrary_type";
 
     test_start_helper(
@@ -904,8 +886,8 @@
     );
     test_start_helper(
         "no-uuid-no-parent",
-        Expect::Fail,
-        Expect::Fail,
+        Expect::Fail(None),
+        Expect::Fail(None),
         None,
         None,
         Some(MDEV_TYPE.to_string()),
@@ -916,8 +898,8 @@
     );
     test_start_helper(
         "no-uuid-no-type",
-        Expect::Fail,
-        Expect::Fail,
+        Expect::Fail(None),
+        Expect::Fail(None),
         None,
         Some(PARENT.to_string()),
         None,
@@ -928,8 +910,8 @@
     );
     test_start_helper(
         "no-parent",
-        Expect::Fail,
-        Expect::Fail,
+        Expect::Fail(None),
+        Expect::Fail(None),
         Some(UUID.to_string()),
         None,
         Some(MDEV_TYPE.to_string()),
@@ -939,8 +921,8 @@
     // should fail if there is no defined device with the given uuid
     test_start_helper(
         "no-type",
-        Expect::Fail,
-        Expect::Fail,
+        Expect::Fail(None),
+        Expect::Fail(None),
         Some(UUID.to_string()),
         Some(PARENT.to_string()),
         None,
@@ -992,8 +974,8 @@
     // if there are multiple defined devices with the same UUID, must 
disambiguate with parent
     test_start_helper(
         "defined-multiple-underspecified",
-        Expect::Fail,
-        Expect::Fail,
+        Expect::Fail(None),
+        Expect::Fail(None),
         Some(UUID.to_string()),
         None,
         None,
@@ -1024,8 +1006,8 @@
     // type. See https://github.com/mdevctl/mdevctl/issues/38
     test_start_helper(
         "defined-diff-type",
-        Expect::Fail,
-        Expect::Fail,
+        Expect::Fail(None),
+        Expect::Fail(None),
         Some(UUID.to_string()),
         Some(PARENT.to_string()),
         Some("wrong-type".to_string()),
@@ -1038,7 +1020,7 @@
     test_start_helper(
         "already-running",
         Expect::Pass,
-        Expect::Fail,
+        Expect::Fail(None),
         Some(UUID.to_string()),
         Some(PARENT.to_string()),
         Some(MDEV_TYPE.to_string()),
@@ -1051,7 +1033,7 @@
     test_start_helper(
         "no-instances",
         Expect::Pass,
-        Expect::Fail,
+        Expect::Fail(None),
         Some(UUID.to_string()),
         Some(PARENT.to_string()),
         Some(MDEV_TYPE.to_string()),
@@ -1090,7 +1072,7 @@
     );
     test_start_command_callout(
         "defined-multiple",
-        Expect::Fail,
+        Expect::Fail(None),
         Uuid::parse_str(UUID).ok(),
         Some(PARENT.to_string()),
         Some(MDEV_TYPE.to_string()),
@@ -1102,6 +1084,37 @@
             test.populate_callout_script("rc1.sh");
         },
     );
+    test_start_helper(
+        "missing-parent",
+        Expect::Pass,
+        Expect::Fail(Some(
+            format!("Unable to find parent device '{}'", PARENT).as_str(),
+        )),
+        Some(UUID.to_string()),
+        Some(PARENT.to_string()),
+        Some(MDEV_TYPE.to_string()),
+        None,
+        |_| {},
+    );
+    test_start_helper(
+        "parent-case",
+        Expect::Pass,
+        Expect::Fail(Some(
+            format!(
+                "Unable to find parent device '{}'. Did you mean '{}'?",
+                PARENT3.to_string().to_uppercase(),
+                PARENT3.to_string()
+            )
+            .as_str(),
+        )),
+        Some(UUID.to_string()),
+        Some(PARENT3.to_string().to_uppercase()),
+        Some(MDEV_TYPE.to_string()),
+        None,
+        |test| {
+            test.populate_parent_device(PARENT3, MDEV_TYPE, 1, "vfio-pci", 
"test device", None);
+        },
+    );
 
     // TODO: test attributes -- difficult because executing the 'start' 
command by writing to
     // the 'create' file in sysfs does not automatically create the device 
file structure in
@@ -1165,22 +1178,14 @@
     setupfn(&test);
 
     let res = list_command_helper(&test, defined, false, verbose, uuid, 
parent.clone());
-    if expect == Expect::Fail {
-        res.expect_err("expected list command to fail");
-        return;
+    if let Ok(output) = assert_result(res, expect, "list json command") {
+        test.compare_to_file(&format!("{}.text", subtest), &output);
     }
 
-    let output = res.expect("list command failed unexpectedly");
-    test.compare_to_file(&format!("{}.text", subtest), &output);
-
     let res = list_command_helper(&test, defined, true, verbose, uuid, 
parent.clone());
-    if expect == Expect::Fail {
-        res.expect_err("expected list command to fail");
-        return;
+    if let Ok(output) = assert_result(res, expect, "list command") {
+        test.compare_to_file(&format!("{}.json", subtest), &output);
     }
-
-    let output = res.expect("list command failed unexpectedly");
-    test.compare_to_file(&format!("{}.json", subtest), &output);
 }
 
 #[test]
@@ -1413,23 +1418,15 @@
 
     // test text output
     let res = types_command_helper(test, parent.clone(), false);
-    if expect == Expect::Fail {
-        res.expect_err("expected types command to fail");
-        return;
+    if let Ok(output) = assert_result(res, expect, "types command") {
+        test.compare_to_file(&format!("{}.text", subtest), &output);
     }
 
-    let output = res.expect("types command failed unexpectedly");
-    test.compare_to_file(&format!("{}.text", subtest), &output);
-
     // test JSON output
     let res = types_command_helper(test, parent.clone(), true);
-    if expect == Expect::Fail {
-        res.expect_err("expected types command to fail");
-        return;
+    if let Ok(output) = assert_result(res, expect, "types json command") {
+        test.compare_to_file(&format!("{}.json", subtest), &output);
     }
-
-    let output = res.expect("types command failed unexpectedly");
-    test.compare_to_file(&format!("{}.json", subtest), &output);
 }
 
 #[test]
@@ -1515,13 +1512,7 @@
     empty_mdev.parent = Some(parent.to_string());
 
     let res = Callout::invoke(&mut empty_mdev, action, |_empty_mdev| Ok(()));
-
-    if expect == Expect::Fail {
-        res.expect_err("expected callout to fail");
-        return;
-    }
-
-    assert!(res.is_ok());
+    let _ = assert_result(res, expect, "invoke callout");
 }
 
 fn test_get_callout<F>(
@@ -1542,13 +1533,7 @@
     empty_mdev.parent = Some(parent.to_string());
 
     let res = Callout::get_attributes(&mut empty_mdev);
-
-    if expect == Expect::Fail {
-        res.expect_err("expected callout to fail");
-        return;
-    }
-
-    assert!(res.is_ok());
+    let _ = assert_result(res, expect, "get callout");
 }
 
 #[test]
@@ -1571,7 +1556,7 @@
     );
     test_invoke_callout(
         "test_callout_all_fail",
-        Expect::Fail,
+        Expect::Fail(None),
         Action::Test,
         Uuid::parse_str(DEFAULT_UUID).unwrap(),
         DEFAULT_PARENT,
@@ -1597,7 +1582,7 @@
     // return error code 1.
     test_invoke_callout(
         "test_callout_type_c",
-        Expect::Fail,
+        Expect::Fail(None),
         Action::Test,
         Uuid::parse_str(DEFAULT_UUID).unwrap(),
         "parent_c",
@@ -1692,7 +1677,7 @@
     );
     test_get_callout(
         "test_callout_bad_json",
-        Expect::Fail,
+        Expect::Fail(None),
         Uuid::parse_str(DEFAULT_UUID).unwrap(),
         DEFAULT_PARENT,
         DEFAULT_TYPE,

Reply via email to