Skip to content

Commit

Permalink
Merge pull request #27848 from AleoHQ/tests/multi-program-tests
Browse files Browse the repository at this point in the history
[Testing] Support multi-program tests.
  • Loading branch information
d0cd authored Mar 29, 2024
2 parents 8c55ae4 + 2db1c91 commit dd7caa0
Show file tree
Hide file tree
Showing 678 changed files with 11,717 additions and 8,294 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion compiler/compiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,19 @@ version = "0.10"
version = "1.9"
features = []

[dev-dependencies.disassembler]
path = "../../utils/disassembler"

[dev-dependencies.leo-test-framework]
path = "../../tests/test-framework"

[dev-dependencies.leo-package]
path = "../../leo/package"

[dev-dependencies.aleo-std-storage]
version = "0.1.7"
default-features = false

[dev-dependencies.dotenvy]
version = "0.15.7"

Expand All @@ -76,4 +83,4 @@ version = "3.10"

[features]
default = [ ]
ci_skip = [ "leo-ast/ci_skip" ]
ci_skip = [ "leo-ast/ci_skip" ]
2 changes: 1 addition & 1 deletion compiler/compiler/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ impl<'a> Compiler<'a> {
}

/// Merges the dependencies defined in `program.json` with the dependencies imported in `.leo` file
fn add_import_stubs(&mut self) -> Result<()> {
pub fn add_import_stubs(&mut self) -> Result<()> {
// Create a list of both the explicit dependencies specified in the `.leo` file, as well as the implicit ones derived from those dependencies.
let (mut unexplored, mut explored): (IndexSet<Symbol>, IndexSet<Symbol>) =
(self.ast.ast.imports.keys().cloned().collect(), IndexSet::new());
Expand Down
147 changes: 90 additions & 57 deletions compiler/compiler/tests/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,28 @@ use utilities::{
hash_content,
hash_symbol_tables,
parse_program,
setup_build_directory,
BufferEmitter,
CompileOutput,
CurrentNetwork,
};

use disassembler::disassemble_from_str;
use leo_compiler::{CompilerOptions, OutputOptions};
use leo_errors::{emitter::Handler, LeoError};
use leo_span::symbol::create_session_if_not_set_then;
use leo_test_framework::{
runner::{Namespace, ParseType, Runner},
Test,
PROGRAM_DELIMITER,
};

use snarkvm::console::prelude::*;

use serde::{Deserialize, Serialize};
use indexmap::IndexMap;
use leo_span::Symbol;
use regex::Regex;
use serde_yaml::Value;
use snarkvm::{prelude::Process, synthesizer::program::ProgramCore};
use std::{fs, path::Path, rc::Rc};

struct CompileNamespace;
Expand All @@ -58,19 +64,8 @@ impl Namespace for CompileNamespace {
}

#[derive(Deserialize, PartialEq, Eq, Serialize)]
struct CompileOutput {
pub initial_symbol_table: String,
pub type_checked_symbol_table: String,
pub unrolled_symbol_table: String,
pub initial_ast: String,
pub unrolled_ast: String,
pub ssa_ast: String,
pub flattened_ast: String,
pub destructured_ast: String,
pub inlined_ast: String,
pub dce_ast: String,
pub bytecode: String,
pub warnings: String,
struct CompileOutputs {
pub compile: Vec<CompileOutput>,
}

fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value, ()> {
Expand All @@ -80,7 +75,10 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
// Extract the compiler build configurations from the config file.
let build_options = get_build_options(&test.config);

let mut outputs = Vec::with_capacity(build_options.len());
// Initialize a `Process`. This should always succeed.
let process = Process::<CurrentNetwork>::load().unwrap();

let mut all_outputs = Vec::with_capacity(build_options.len());

for build in build_options {
let compiler_options = CompilerOptions {
Expand All @@ -101,50 +99,85 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
},
};

// Parse the program.
let mut parsed =
handler.extend_if_error(parse_program(handler, &test.content, cwd.clone(), Some(compiler_options)))?;

// Compile the program to bytecode.
let program_name = format!("{}.{}", parsed.program_name, parsed.network);
let bytecode = handler.extend_if_error(compile_and_process(&mut parsed))?;

// Set up the build directory.
// Note that this function checks that the bytecode is well-formed.
let package = setup_build_directory(&program_name, &bytecode, handler)?;

// Get the program process and check all instructions.
handler.extend_if_error(package.get_process().map_err(LeoError::Anyhow))?;

// Hash the ast files.
let (initial_ast, unrolled_ast, ssa_ast, flattened_ast, destructured_ast, inlined_ast, dce_ast) = hash_asts();

// Hash the symbol tables.
let (initial_symbol_table, type_checked_symbol_table, unrolled_symbol_table) = hash_symbol_tables();

// Clean up the output directory.
if fs::read_dir("/tmp/output").is_ok() {
fs::remove_dir_all(Path::new("/tmp/output")).expect("Error failed to clean up output dir.");
// Split the test content into individual program strings based on the program delimiter.
let program_strings = test.content.split(PROGRAM_DELIMITER).collect::<Vec<&str>>();

// Initialize storage for the stubs.
let mut import_stubs = IndexMap::new();

// Clone the process.
let mut process = process.clone();

// Initialize storage for the compilation outputs.
let mut compile = Vec::with_capacity(program_strings.len());

// Compile each program string separately.
for program_string in program_strings {
// Parse the program name from the program string.
let re = Regex::new(r"program\s+([^\s.]+)\.aleo").unwrap();
let program_name = re.captures(program_string).unwrap().get(1).unwrap().as_str();
// Parse the program.
let mut parsed = handler.extend_if_error(parse_program(
program_name.to_string(),
handler,
program_string,
cwd.clone(),
Some(compiler_options.clone()),
import_stubs.clone(),
))?;

// Compile the program to bytecode.
let program_name = parsed.program_name.to_string();
let bytecode = handler.extend_if_error(compile_and_process(&mut parsed))?;

// Parse the bytecode as an Aleo program.
// Note that this function checks that the bytecode is well-formed.
let aleo_program = handler.extend_if_error(ProgramCore::from_str(&bytecode).map_err(LeoError::Anyhow))?;

// Add the program to the process.
// Note that this function performs an additional validity check on the bytecode.
handler.extend_if_error(process.add_program(&aleo_program).map_err(LeoError::Anyhow))?;

// Add the bytecode to the import stubs.
let stub = handler.extend_if_error(disassemble_from_str(&bytecode).map_err(|err| err.into()))?;
import_stubs.insert(Symbol::intern(&program_name), stub);

// Hash the ast files.
let (initial_ast, unrolled_ast, ssa_ast, flattened_ast, destructured_ast, inlined_ast, dce_ast) =
hash_asts(&program_name);

// Hash the symbol tables.
let (initial_symbol_table, type_checked_symbol_table, unrolled_symbol_table) =
hash_symbol_tables(&program_name);

// Clean up the output directory.
if fs::read_dir("/tmp/output").is_ok() {
fs::remove_dir_all(Path::new("/tmp/output")).expect("Error failed to clean up output dir.");
}

let output = CompileOutput {
initial_symbol_table,
type_checked_symbol_table,
unrolled_symbol_table,
initial_ast,
unrolled_ast,
ssa_ast,
flattened_ast,
destructured_ast,
inlined_ast,
dce_ast,
bytecode: hash_content(&bytecode),
errors: buf.0.take().to_string(),
warnings: buf.1.take().to_string(),
};
compile.push(output);
}

let final_output = CompileOutput {
initial_symbol_table,
type_checked_symbol_table,
unrolled_symbol_table,
initial_ast,
unrolled_ast,
ssa_ast,
flattened_ast,
destructured_ast,
inlined_ast,
dce_ast,
bytecode: hash_content(&bytecode),
warnings: buf.1.take().to_string(),
};

outputs.push(final_output);
// Combine all compilation outputs.
let compile_outputs = CompileOutputs { compile };
all_outputs.push(compile_outputs);
}
Ok(serde_yaml::to_value(outputs).expect("serialization failed"))
Ok(serde_yaml::to_value(all_outputs).expect("serialization failed"))
}

struct TestRunner;
Expand Down
Loading

0 comments on commit dd7caa0

Please sign in to comment.