/ synthesizer / tests / test_process_execute.rs
test_process_execute.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the deltavm library.
  3  
  4  // Licensed under the Apache License, Version 2.0 (the "License");
  5  // you may not use this file except in compliance with the License.
  6  // You may obtain a copy of the License at:
  7  
  8  // http://www.apache.org/licenses/LICENSE-2.0
  9  
 10  // Unless required by applicable law or agreed to in writing, software
 11  // distributed under the License is distributed on an "AS IS" BASIS,
 12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  // See the License for the specific language governing permissions and
 14  // limitations under the License.
 15  
 16  mod utilities;
 17  
 18  use deltavm_console::{
 19      account::PrivateKey,
 20      network::prelude::*,
 21      program::{Identifier, Literal, ProgramID, Value},
 22      types::Boolean,
 23  };
 24  use deltavm_synthesizer_process::Process;
 25  use utilities::*;
 26  
 27  use rayon::prelude::*;
 28  use std::panic::AssertUnwindSafe;
 29  
 30  #[test]
 31  fn test_process_execute() {
 32      // Load the tests.
 33      let tests = load_tests::<_, ProgramTest>("./tests/process/execute", "./expectations/process/execute");
 34      // Initialize a process.
 35      let process = Process::<CurrentNetwork>::load().unwrap();
 36  
 37      // Run each test and compare it against its corresponding expectation.
 38      tests.par_iter().for_each(|test| {
 39          // Run the test.
 40          let output = run_test(process.clone(), test);
 41          // Check against the expected output.
 42          let res = test.check(&output);
 43          if let Err(err) = &res {
 44              println!("Error running test {:?}: {}", test.path(), err);
 45          }
 46          res.unwrap();
 47          // Save the output when valid.
 48          test.save(&output).unwrap();
 49      });
 50  }
 51  
 52  // A helper function to run the test and extract the outputs as YAML, to be compared against the expectation.
 53  fn run_test(process: Process<CurrentNetwork>, test: &ProgramTest) -> serde_yaml::Mapping {
 54      // Initialize the output.
 55      let mut output = serde_yaml::Mapping::new();
 56      output.insert(
 57          serde_yaml::Value::String("errors".to_string()),
 58          serde_yaml::Value::Sequence(serde_yaml::Sequence::new()),
 59      );
 60  
 61      // Add the programs into the process.
 62      let mut process = process.clone();
 63      for program in test.programs() {
 64          if let Err(err) = process.add_program(program) {
 65              output
 66                  .get_mut(serde_yaml::Value::String("errors".to_string()))
 67                  .unwrap()
 68                  .as_sequence_mut()
 69                  .unwrap()
 70                  .push(serde_yaml::Value::String(err.to_string()));
 71              output.insert(
 72                  serde_yaml::Value::String("outputs".to_string()),
 73                  serde_yaml::Value::Sequence(serde_yaml::Sequence::new()),
 74              );
 75              return output;
 76          }
 77      }
 78  
 79      // Initialize the RNG.
 80      let rng = &mut match test.randomness() {
 81          None => TestRng::default(),
 82          Some(randomness) => TestRng::fixed(randomness),
 83      };
 84  
 85      output.insert(
 86          serde_yaml::Value::String("outputs".to_string()),
 87          serde_yaml::Value::Sequence(
 88              test.cases()
 89                  .iter()
 90                  .map(|value| {
 91                      // Extract the function name, inputs, and optional private key.
 92                      let value = value.as_mapping().expect("expected mapping for test case");
 93                      let program_id = ProgramID::<CurrentNetwork>::from_str(
 94                          value
 95                              .get("program")
 96                              .expect("expected program name for test case")
 97                              .as_str()
 98                              .expect("expected string for program name"),
 99                      )
100                      .expect("unable to parse program name");
101                      let function_name = Identifier::<CurrentNetwork>::from_str(
102                          value
103                              .get("function")
104                              .expect("expected function name for test case")
105                              .as_str()
106                              .expect("expected string for function name"),
107                      )
108                      .expect("unable to parse function name");
109                      let inputs = value
110                          .get("inputs")
111                          .expect("expected inputs for test case")
112                          .as_sequence()
113                          .expect("expected sequence for inputs")
114                          .iter()
115                          .map(|input| match &input {
116                              serde_yaml::Value::Bool(bool) => {
117                                  Value::<CurrentNetwork>::from(Literal::Boolean(Boolean::new(*bool)))
118                              }
119                              _ => Value::<CurrentNetwork>::from_str(input.as_str().expect("expected string for input"))
120                                  .expect("unable to parse input"),
121                          })
122                          .collect_vec();
123                      let private_key = match value.get("private_key") {
124                          Some(private_key) => PrivateKey::<CurrentNetwork>::from_str(
125                              private_key.as_str().expect("expected string for private key"),
126                          )
127                          .expect("unable to parse private key"),
128                          None => PrivateKey::new(rng).unwrap(),
129                      };
130  
131                      let mut run_test = || -> serde_yaml::Value {
132                          // Authorize the execution.
133                          let authorization = match process.authorize::<CurrentAlpha, _>(
134                              &private_key,
135                              program_id,
136                              function_name,
137                              inputs.iter(),
138                              rng,
139                          ) {
140                              Ok(authorization) => authorization,
141                              Err(err) => return serde_yaml::Value::String(err.to_string()),
142                          };
143                          // Execute the authorization and extract the output as YAML.
144                          std::panic::catch_unwind(AssertUnwindSafe(|| {
145                              match process.execute::<CurrentAlpha, _>(authorization, rng) {
146                                  Ok((response, _)) => serde_yaml::Value::Sequence(
147                                      response
148                                          .outputs()
149                                          .iter()
150                                          .cloned()
151                                          .map(|output| serde_yaml::Value::String(output.to_string()))
152                                          .collect_vec(),
153                                  ),
154                                  Err(err) => serde_yaml::Value::String(err.to_string()),
155                              }
156                          }))
157                          .unwrap_or(serde_yaml::Value::String(
158                              "Compiler panicked when calling `Process::execute`".to_string(),
159                          ))
160                      };
161                      run_test()
162                  })
163                  .collect::<serde_yaml::Sequence>(),
164          ),
165      );
166  
167      output
168  }