sim: add unsupported caps to device creation

Update `make_device` to return a slice of unsupported caps for a test.
This allows skipping tests in devices that are known to be non working
under some build configuration.

The device constructor was updated to return a `Result`, so that the
specific reason for skipping can be returned as a `String`.

Signed-off-by: Fabio Utzig <utzig@apache.org>
diff --git a/sim/src/image.rs b/sim/src/image.rs
index 035370f..8d6fb91 100644
--- a/sim/src/image.rs
+++ b/sim/src/image.rs
@@ -84,8 +84,14 @@
     /// Construct a new image builder for the given device.  Returns
     /// Some(builder) if is possible to test this configuration, or None if
     /// not possible (for example, if there aren't enough image slots).
-    pub fn new(device: DeviceName, align: usize, erased_val: u8) -> Option<Self> {
-        let (flash, areadesc) = Self::make_device(device, align, erased_val);
+    pub fn new(device: DeviceName, align: usize, erased_val: u8) -> Result<Self, String> {
+        let (flash, areadesc, unsupported_caps) = Self::make_device(device, align, erased_val);
+
+        for cap in unsupported_caps {
+            if cap.present() {
+                return Err(format!("unsupported {:?}", cap));
+            }
+        }
 
         let num_images = Caps::get_num_images();
 
@@ -100,7 +106,7 @@
             };
             let (primary_base, primary_len, primary_dev_id) = match areadesc.find(id0) {
                 Some(info) => info,
-                None => return None,
+                None => return Err("insufficient partitions".to_string()),
             };
             let id1 = match image {
                 0 => FlashId::Image1,
@@ -109,7 +115,7 @@
             };
             let (secondary_base, secondary_len, secondary_dev_id) = match areadesc.find(id1) {
                 Some(info) => info,
-                None => return None,
+                None => return Err("insufficient partitions".to_string()),
             };
 
             let offset_from_end = c::boot_magic_sz() + c::boot_max_align() * 4;
@@ -135,7 +141,7 @@
             slots.push([primary, secondary]);
         }
 
-        Some(ImagesBuilder {
+        Ok(ImagesBuilder {
             flash: flash,
             areadesc: areadesc,
             slots: slots,
@@ -149,8 +155,8 @@
             for &align in test_alignments() {
                 for &erased_val in &[0, 0xff] {
                     match Self::new(dev, align, erased_val) {
-                        Some(run) => f(run),
-                        None => warn!("Skipping {:?}, insufficient partitions", dev),
+                        Ok(run) => f(run),
+                        Err(msg) => warn!("Skipping {}: {}", dev, msg),
                     }
                 }
             }
@@ -227,7 +233,7 @@
     }
 
     /// Build the Flash and area descriptor for a given device.
-    pub fn make_device(device: DeviceName, align: usize, erased_val: u8) -> (SimMultiFlash, AreaDesc) {
+    pub fn make_device(device: DeviceName, align: usize, erased_val: u8) -> (SimMultiFlash, AreaDesc, &'static [Caps]) {
         match device {
             DeviceName::Stm32f4 => {
                 // STM style flash.  Large sectors, with a large scratch area.
@@ -244,7 +250,7 @@
 
                 let mut flash = SimMultiFlash::new();
                 flash.insert(dev_id, dev);
-                (flash, areadesc)
+                (flash, areadesc, &[Caps::SwapUsingMove])
             }
             DeviceName::K64f => {
                 // NXP style flash.  Small sectors, one small sector for scratch.
@@ -259,7 +265,7 @@
 
                 let mut flash = SimMultiFlash::new();
                 flash.insert(dev_id, dev);
-                (flash, areadesc)
+                (flash, areadesc, &[])
             }
             DeviceName::K64fBig => {
                 // Simulating an STM style flash on top of an NXP style flash.  Underlying flash device
@@ -275,7 +281,7 @@
 
                 let mut flash = SimMultiFlash::new();
                 flash.insert(dev_id, dev);
-                (flash, areadesc)
+                (flash, areadesc, &[Caps::SwapUsingMove])
             }
             DeviceName::Nrf52840 => {
                 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
@@ -291,7 +297,7 @@
 
                 let mut flash = SimMultiFlash::new();
                 flash.insert(dev_id, dev);
-                (flash, areadesc)
+                (flash, areadesc, &[])
             }
             DeviceName::Nrf52840SpiFlash => {
                 // Simulate nrf52840 with external SPI flash. The external SPI flash
@@ -310,7 +316,7 @@
                 let mut flash = SimMultiFlash::new();
                 flash.insert(0, dev0);
                 flash.insert(1, dev1);
-                (flash, areadesc)
+                (flash, areadesc, &[Caps::SwapUsingMove])
             }
             DeviceName::K64fMulti => {
                 // NXP style flash, but larger, to support multiple images.
@@ -327,7 +333,7 @@
 
                 let mut flash = SimMultiFlash::new();
                 flash.insert(dev_id, dev);
-                (flash, areadesc)
+                (flash, areadesc, &[])
             }
         }
     }
diff --git a/sim/src/lib.rs b/sim/src/lib.rs
index fda376a..dba7cb0 100644
--- a/sim/src/lib.rs
+++ b/sim/src/lib.rs
@@ -173,9 +173,9 @@
         warn!("Running on device {} with alignment {}", device, align);
 
         let run = match ImagesBuilder::new(device, align, erased_val) {
-            Some(builder) => builder,
-            None => {
-                warn!("Skipping device with insuffienct partitions");
+            Ok(builder) => builder,
+            Err(msg) => {
+                warn!("Skipping {}: {}", device, msg);
                 return;
             }
         };