[sw, rom_ext_signer] Introduce unittests for `update_static_fields`

The test function:
- Manually initialises the config structure
- Uses the dev/test blank image file as an input
  - Makes sure that this file is actually blank
  - Uses the initialised config structure to update the fields
  - Makes sure that the correct fields have been updated, and
    no other portions of the image were modified

`Cargo test` is expected to be triggered via normal meason build,
otherwise the unittest will no knowledge of the environment
variables.

Signed-off-by: Silvestrs Timofejevs <silvestrst@lowrisc.org>
diff --git a/sw/host/rom_ext_image_tools/signer/dev/usage_constraints.bin b/sw/host/rom_ext_image_tools/signer/dev/usage_constraints.bin
index 7640dad..9648fd7 100644
--- a/sw/host/rom_ext_image_tools/signer/dev/usage_constraints.bin
+++ b/sw/host/rom_ext_image_tools/signer/dev/usage_constraints.bin
@@ -1 +1 @@
-¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
\ No newline at end of file
+¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
\ No newline at end of file
diff --git a/sw/host/rom_ext_image_tools/signer/image/src/image.rs b/sw/host/rom_ext_image_tools/signer/image/src/image.rs
index 50fcf33..ffec48c 100644
--- a/sw/host/rom_ext_image_tools/signer/image/src/image.rs
+++ b/sw/host/rom_ext_image_tools/signer/image/src/image.rs
@@ -189,19 +189,171 @@
     }
 }
 
+fn str_to_u64(val: &str) -> u64 {
+    match val.strip_prefix("0x") {
+        Some(s) => u64::from_str_radix(s, 16),
+        None => u64::from_str_radix(val, 10),
+    }
+    .expect("Failed to parse string to u64!")
+}
+
 /// Converts hex/decimal uint string into a little endian byte vector.
 ///
-/// Note: only understands unsigned u64 and u32 integers.
+/// Note: only understands values up to u64::MAX.
 fn str_to_vec_u8(s: &str) -> Vec<u8> {
-    let value = match s.starts_with("0x") {
-        true => u64::from_str_radix(s.trim_start_matches("0x"), 16)
-            .expect("Failed to parse string to u64!"),
-        false => s.parse::<u64>().expect("Failed to parse string to u64!"),
-    };
+    match str_to_u64(s).to_le_bytes() {
+        [a, b, c, d, 0, 0, 0, 0] => vec![a, b, c, d],
+        bytes => bytes.to_vec(),
+    }
+}
 
-    if value <= (u32::MAX as u64) {
-        (value as u32).to_le_bytes().to_vec()
-    } else {
-        value.to_le_bytes().to_vec()
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use std::collections::HashMap;
+    use std::env;
+
+    use rom_ext_config::parser::Extension;
+    use rom_ext_config::parser::InputFiles;
+
+    static DEV_RELATIVE_PATH: &str = "sw/host/rom_ext_image_tools/signer/dev";
+
+    #[test]
+    fn test_update_static_fields() {
+        let source_root = env::var("MESON_SOURCE_ROOT")
+            .expect("Failed, ENV variable not set!");
+
+        let dev_path = Path::new(&source_root).join(DEV_RELATIVE_PATH);
+        let full_path = |path| dev_path.join(path);
+
+        let config = ParsedConfig {
+            input_files: InputFiles {
+                image_path: full_path("rom_ext_blank_image.bin"),
+                private_key_der_path: PathBuf::from(""),
+                usage_constraints_path: full_path("usage_constraints.bin"),
+                system_state_value_path: PathBuf::from(""),
+            },
+            peripheral_lockdown_info: PeripheralLockdownInfo { value: 0 },
+            manifest_identifier: String::from("0x11111111"),
+            image_version: String::from("0x22222222"),
+            extensions: [
+                Extension {
+                    offset: String::from("0x33333333"),
+                    checksum: String::from("0x44444444"),
+                },
+                Extension {
+                    offset: String::from("0x55555555"),
+                    checksum: String::from("0x55555555"),
+                },
+                Extension {
+                    offset: String::from("0x66666666"),
+                    checksum: String::from("0x66666666"),
+                },
+                Extension {
+                    offset: String::from("0x77777777"),
+                    checksum: String::from("0x77777777"),
+                },
+            ],
+        };
+
+        let mut test_items: HashMap<usize, Vec<u8>> = HashMap::new();
+
+        let mut add_test_item = |key, val: Vec<u8>, expected_size| {
+            assert_eq!(val.len(), expected_size as usize);
+            test_items.insert(key as usize, val);
+        };
+
+        add_test_item(
+            manifest::ROM_EXT_MANIFEST_IDENTIFIER_OFFSET,
+            str_to_vec_u8(&config.manifest_identifier),
+            manifest::ROM_EXT_MANIFEST_IDENTIFIER_SIZE_BYTES,
+        );
+        add_test_item(
+            manifest::ROM_EXT_IMAGE_VERSION_OFFSET,
+            str_to_vec_u8(&config.image_version),
+            manifest::ROM_EXT_IMAGE_VERSION_SIZE_BYTES,
+        );
+        add_test_item(
+            manifest::ROM_EXT_EXTENSION0_OFFSET_OFFSET,
+            str_to_vec_u8(&config.extensions[0].offset),
+            manifest::ROM_EXT_EXTENSION0_OFFSET_SIZE_BYTES,
+        );
+        add_test_item(
+            manifest::ROM_EXT_EXTENSION1_OFFSET_OFFSET,
+            str_to_vec_u8(&config.extensions[1].offset),
+            manifest::ROM_EXT_EXTENSION1_OFFSET_SIZE_BYTES,
+        );
+        add_test_item(
+            manifest::ROM_EXT_EXTENSION2_OFFSET_OFFSET,
+            str_to_vec_u8(&config.extensions[2].offset),
+            manifest::ROM_EXT_EXTENSION2_OFFSET_SIZE_BYTES,
+        );
+        add_test_item(
+            manifest::ROM_EXT_EXTENSION3_OFFSET_OFFSET,
+            str_to_vec_u8(&config.extensions[3].offset),
+            manifest::ROM_EXT_EXTENSION3_OFFSET_SIZE_BYTES,
+        );
+        add_test_item(
+            manifest::ROM_EXT_EXTENSION0_CHECKSUM_OFFSET,
+            str_to_vec_u8(&config.extensions[0].checksum),
+            manifest::ROM_EXT_EXTENSION0_CHECKSUM_SIZE_BYTES,
+        );
+        add_test_item(
+            manifest::ROM_EXT_EXTENSION1_CHECKSUM_OFFSET,
+            str_to_vec_u8(&config.extensions[1].checksum),
+            manifest::ROM_EXT_EXTENSION1_CHECKSUM_SIZE_BYTES,
+        );
+        add_test_item(
+            manifest::ROM_EXT_EXTENSION2_CHECKSUM_OFFSET,
+            str_to_vec_u8(&config.extensions[2].checksum),
+            manifest::ROM_EXT_EXTENSION2_CHECKSUM_SIZE_BYTES,
+        );
+        add_test_item(
+            manifest::ROM_EXT_EXTENSION3_CHECKSUM_OFFSET,
+            str_to_vec_u8(&config.extensions[3].checksum),
+            manifest::ROM_EXT_EXTENSION3_CHECKSUM_SIZE_BYTES,
+        );
+        add_test_item(
+            manifest::ROM_EXT_USAGE_CONSTRAINTS_OFFSET,
+            fs::read(&config.input_files.usage_constraints_path)
+                .expect("Failed to read usage constraints!"),
+            manifest::ROM_EXT_USAGE_CONSTRAINTS_SIZE_BYTES,
+        );
+        add_test_item(
+            manifest::ROM_EXT_PERIPHERAL_LOCKDOWN_INFO_OFFSET,
+            [0xA5; 16].to_vec(),
+            manifest::ROM_EXT_PERIPHERAL_LOCKDOWN_INFO_SIZE_BYTES,
+        );
+
+        let mut image = RawImage::new(&config.input_files.image_path);
+
+        // Make sure that the image is blank to start with.
+        assert_eq!(image.data, vec![0; image.data.len()]);
+
+        image.update_static_fields(&config);
+
+        // Iterate through every single byte in the image, if it belongs to a
+        // field under test - compare with the respective `test_tuple` field,
+        // otherwise it should be zero.
+        let mut i = 0;
+        while i < image.data.len() {
+            // Check if the byte is part of the fields under test.
+            match test_items.get(&i) {
+                Some(x) => {
+                    // Check that field under test was successfully written
+                    // to the image.
+                    for byte in x {
+                        assert_eq!(*byte, image.data[i], "index = {}", i);
+                        i += 1;
+                    }
+                }
+                _ => {
+                    // Make sure that any other bytes are zero.
+                    assert_eq!(image.data[i], 0, "index = {}", i);
+                    i += 1;
+                }
+            }
+        }
     }
 }