sim: Add dependency tests to simulator

Create a trait `Depender` which is passed down to the image create and
verification to check and test for various types of dependency
resolution.  Add a test that uses this to test the simple case of unmet
dependencies preventing an upgrade.

The actual test is disabled (with an `if false ...`) because the code
under test loops forever in this configuration.

Signed-off-by: David Brown <david.brown@linaro.org>
diff --git a/sim/tests/core.rs b/sim/tests/core.rs
index 883ed43..c536b0a 100644
--- a/sim/tests/core.rs
+++ b/sim/tests/core.rs
@@ -2,28 +2,75 @@
 //!
 //! Run the existing testsuite as a Rust unit test.
 
-use bootsim::{ImagesBuilder, testlog};
+use bootsim::{
+    DepTest, DepType, UpgradeInfo,
+    ImagesBuilder,
+    NO_DEPS,
+    testlog,
+};
 
-macro_rules! sim_test {
-    ($name:ident, $maker:ident($($margs:expr),*), $test:ident($($targs:expr),*)) => {
+/// A single test, after setting up logging and such.  Within the $body,
+/// $arg will be bound to each device.
+macro_rules! test_shell {
+    ($name:ident, $arg: ident, $body:expr) => {
         #[test]
         fn $name() {
             testlog::setup();
-
-            ImagesBuilder::each_device(|r| {
-                let image = r.$maker($($margs),*);
-                assert!(!image.$test($($targs),*));
+            ImagesBuilder::each_device(|$arg| {
+                $body;
             });
         }
+    }
+}
+
+/// A typical test calls a particular constructor, and runs a given test on
+/// that constructor.
+macro_rules! sim_test {
+    ($name:ident, $maker:ident($($margs:expr),*), $test:ident($($targs:expr),*)) => {
+        test_shell!($name, r, {
+            let image = r.$maker($($margs),*);
+            assert!(!image.$test($($targs),*));
+        });
     };
 }
 
 sim_test!(bad_secondary_slot, make_bad_secondary_slot_image(), run_signfail_upgrade());
-sim_test!(norevert_newimage, make_no_upgrade_image(), run_norevert_newimage());
-sim_test!(basic_revert, make_image(true), run_basic_revert());
-sim_test!(revert_with_fails, make_image(false), run_revert_with_fails());
-sim_test!(perm_with_fails, make_image(true), run_perm_with_fails());
-sim_test!(perm_with_random_fails, make_image(true), run_perm_with_random_fails(5));
-sim_test!(norevert, make_image(true), run_norevert());
-sim_test!(status_write_fails_complete, make_image(true), run_with_status_fails_complete());
-sim_test!(status_write_fails_with_reset, make_image(true), run_with_status_fails_with_reset());
+sim_test!(norevert_newimage, make_no_upgrade_image(&NO_DEPS), run_norevert_newimage());
+sim_test!(basic_revert, make_image(&NO_DEPS, true), run_basic_revert());
+sim_test!(revert_with_fails, make_image(&NO_DEPS, false), run_revert_with_fails());
+sim_test!(perm_with_fails, make_image(&NO_DEPS, true), run_perm_with_fails());
+sim_test!(perm_with_random_fails, make_image(&NO_DEPS, true), run_perm_with_random_fails(5));
+sim_test!(norevert, make_image(&NO_DEPS, true), run_norevert());
+sim_test!(status_write_fails_complete, make_image(&NO_DEPS, true), run_with_status_fails_complete());
+sim_test!(status_write_fails_with_reset, make_image(&NO_DEPS, true), run_with_status_fails_with_reset());
+
+// Test various combinations of incorrect dependencies.
+test_shell!(dependency_combos, r, {
+    // Only test setups with two images.
+    if r.num_images() != 2 {
+        return;
+    }
+
+    for dep in TEST_DEPS {
+        let image = r.clone().make_image(&dep, true);
+        assert!(!image.run_check_deps(&dep));
+    }
+});
+
+/// These are the variants of dependencies we will test.
+pub static TEST_DEPS: &[DepTest] = &[
+    // First is a sanity test, no dependencies should upgrade.
+    DepTest {
+        depends: [DepType::Nothing, DepType::Nothing],
+        upgrades: [UpgradeInfo::Upgraded, UpgradeInfo::Upgraded],
+    },
+
+    // If all of the dependencies are unmet, there should be no upgrades.
+    // TODO: Disabled because it fails.
+    /*
+    DepTest {
+        depends: [DepType::Newer, DepType::Newer],
+        upgrades: [UpgradeInfo::Held, UpgradeInfo::Held],
+    },
+    */
+];