Merge pull request #883 from AleoHQ/feature-cli-coverage

[CLI] Adds integration tests to Leo CLI + removes --lib legacy
This commit is contained in:
Collin Chin 2021-04-26 10:54:23 -07:00 committed by GitHub
commit 35619c99b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 477 additions and 366 deletions

161
Cargo.lock generated
View File

@ -87,6 +87,20 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "assert_cmd"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2475b58cd94eb4f70159f4fd8844ba3b807532fe3131b3373fae060bbe30396"
dependencies = [
"bstr",
"doc-comment",
"predicates",
"predicates-core",
"predicates-tree",
"wait-timeout",
]
[[package]]
name = "atty"
version = "0.2.14"
@ -601,6 +615,12 @@ dependencies = [
"syn 1.0.64",
]
[[package]]
name = "difference"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
[[package]]
name = "digest"
version = "0.8.1"
@ -639,6 +659,12 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "doc-comment"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "dtoa"
version = "0.4.8"
@ -1307,8 +1333,8 @@ dependencies = [
"leo-state",
"num-bigint",
"pest",
"rand",
"rand_core",
"rand 0.8.3",
"rand_core 0.6.2",
"rand_xorshift",
"serde",
"sha2",
@ -1355,6 +1381,7 @@ version = "1.4.0"
dependencies = [
"ansi_term 0.12.1",
"anyhow",
"assert_cmd",
"clap",
"colored",
"console",
@ -1369,8 +1396,8 @@ dependencies = [
"leo-state",
"leo-synthesizer",
"notify",
"rand",
"rand_core",
"rand 0.8.3",
"rand_core 0.6.2",
"reqwest",
"rusty-hook",
"self_update",
@ -1382,6 +1409,7 @@ dependencies = [
"snarkvm-r1cs",
"snarkvm-utilities",
"structopt",
"test_dir",
"thiserror",
"toml",
"tracing",
@ -1430,8 +1458,8 @@ dependencies = [
"indexmap",
"leo-ast",
"leo-input",
"rand",
"rand_core",
"rand 0.8.3",
"rand_core 0.6.2",
"rand_xorshift",
"snarkvm-algorithms",
"snarkvm-curves",
@ -2048,6 +2076,32 @@ version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "predicates"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eeb433456c1a57cc93554dea3ce40b4c19c4057e41c55d4a0f3d84ea71c325aa"
dependencies = [
"difference",
"predicates-core",
]
[[package]]
name = "predicates-core"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451"
[[package]]
name = "predicates-tree"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15f553275e5721409451eb85e15fd9a860a6e5ab4496eb215987502b5f5391f2"
dependencies = [
"predicates-core",
"treeline",
]
[[package]]
name = "proc-macro-crate"
version = "0.1.5"
@ -2138,6 +2192,19 @@ version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom 0.1.16",
"libc",
"rand_chacha 0.2.2",
"rand_core 0.5.1",
"rand_hc 0.2.0",
]
[[package]]
name = "rand"
version = "0.8.3"
@ -2145,9 +2212,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
"rand_chacha 0.3.0",
"rand_core 0.6.2",
"rand_hc 0.3.0",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
"ppv-lite86",
"rand_core 0.5.1",
]
[[package]]
@ -2157,7 +2234,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
dependencies = [
"ppv-lite86",
"rand_core",
"rand_core 0.6.2",
]
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom 0.1.16",
]
[[package]]
@ -2169,13 +2255,22 @@ dependencies = [
"getrandom 0.2.2",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "rand_hc"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
dependencies = [
"rand_core",
"rand_core 0.6.2",
]
[[package]]
@ -2184,7 +2279,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
dependencies = [
"rand_core",
"rand_core 0.6.2",
]
[[package]]
@ -2615,8 +2710,8 @@ dependencies = [
"derivative",
"digest 0.9.0",
"itertools 0.10.0",
"rand",
"rand_chacha",
"rand 0.8.3",
"rand_chacha 0.3.0",
"rayon",
"sha2",
"smallvec",
@ -2635,7 +2730,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64610b135b8b1152439d5dfa4f745515933366082f08651961344aa0bb5abfca"
dependencies = [
"derivative",
"rand",
"rand 0.8.3",
"rand_xorshift",
"rustc_version 0.3.3",
"serde",
@ -2670,7 +2765,7 @@ dependencies = [
"derivative",
"hex",
"itertools 0.10.0",
"rand",
"rand 0.8.3",
"snarkvm-algorithms",
"snarkvm-curves",
"snarkvm-fields",
@ -2691,7 +2786,7 @@ checksum = "8c49c69d02df11be58e07f626c9d6f5804c6dd4ccf42e425f2be8d79fe6e5bb7"
dependencies = [
"bincode",
"derivative",
"rand",
"rand 0.8.3",
"rand_xorshift",
"serde",
"snarkvm-utilities",
@ -2726,7 +2821,7 @@ dependencies = [
"chrono",
"hex",
"once_cell",
"rand",
"rand 0.8.3",
"serde",
"sha2",
"snarkvm-algorithms",
@ -2780,7 +2875,7 @@ dependencies = [
"bincode",
"hex",
"parking_lot",
"rand",
"rand 0.8.3",
"rocksdb",
"serde",
"snarkvm-algorithms",
@ -2798,7 +2893,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c763843fa67a3aa4ce68173c8cd96b4f04aaa135a5792bc051c36eec0fe1cd73"
dependencies = [
"bincode",
"rand",
"rand 0.8.3",
"snarkvm-derives",
"thiserror",
]
@ -2904,7 +2999,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
dependencies = [
"cfg-if 1.0.0",
"libc",
"rand",
"rand 0.8.3",
"redox_syscall 0.2.5",
"remove_dir_all",
"winapi 0.3.9",
@ -2940,6 +3035,15 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "test_dir"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e571ebf9127a9da821890a9fa8a8ef777fce3e0f959ff6949cf06ca8b736381d"
dependencies = [
"rand 0.7.3",
]
[[package]]
name = "textwrap"
version = "0.11.0"
@ -3152,6 +3256,12 @@ dependencies = [
"tracing-serde",
]
[[package]]
name = "treeline"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
[[package]]
name = "try-lock"
version = "0.2.3"
@ -3269,6 +3379,15 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "wait-timeout"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
dependencies = [
"libc",
]
[[package]]
name = "walkdir"
version = "2.3.2"

View File

@ -157,6 +157,12 @@ version = "0.12.1"
[dev-dependencies.rusty-hook]
version = "0.11.2"
[dev-dependencies.assert_cmd]
version = "1.0.3"
[dev-dependencies.test_dir]
version = "0.1.0"
[features]
default = [ ]
ci_skip = [ "leo-compiler/ci_skip" ]

View File

@ -0,0 +1,14 @@
// The program input for tmp-test/src/main.leo
[main]
puzzle: [u8; (3, 3)] = [[1, 0, 5],
[0, 2, 0],
[7, 0, 0]];
answer: [u8; (3, 3)] = [[1, 4, 5],
[3, 2, 6],
[7, 8, 9]];
expected: bool = true;
[registers]
r: bool = false;

View File

@ -22,11 +22,11 @@ use leo_compiler::{
use leo_package::{
inputs::*,
outputs::{ChecksumFile, CircuitFile, OutputsDirectory, OUTPUTS_DIRECTORY_NAME},
source::{LibraryFile, MainFile, LIBRARY_FILENAME, MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
source::{MainFile, MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
};
use leo_synthesizer::{CircuitSynthesizer, SerializedCircuit};
use anyhow::Result;
use anyhow::{anyhow, Result};
use snarkvm_curves::{bls12_377::Bls12_377, edwards_bls12::Fq};
use snarkvm_r1cs::ConstraintSystem;
use structopt::StructOpt;
@ -39,7 +39,7 @@ pub struct Build {}
impl Command for Build {
type Input = ();
type Output = Option<(Compiler<'static, Fq, EdwardsGroupType>, bool)>;
type Output = (Compiler<'static, Fq, EdwardsGroupType>, bool);
fn log_span(&self) -> Span {
tracing::span!(tracing::Level::INFO, "Build")
@ -65,115 +65,95 @@ impl Command for Build {
tracing::info!("Starting...");
// Compile the package starting with the lib.leo file
if LibraryFile::exists_at(&package_path) {
// Construct the path to the library file in the source directory
let mut lib_file_path = package_path.clone();
lib_file_path.push(SOURCE_DIRECTORY_NAME);
lib_file_path.push(LIBRARY_FILENAME);
// Log compilation of library file to console
tracing::info!("Compiling library... ({:?})", lib_file_path);
// Compile the library file but do not output
let _program = Compiler::<Fq, EdwardsGroupType>::parse_program_without_input(
package_name.clone(),
lib_file_path,
output_directory.clone(),
thread_leaked_context(),
)?;
tracing::info!("Complete");
};
// Compile the main.leo file along with constraints
if MainFile::exists_at(&package_path) {
// Create the output directory
OutputsDirectory::create(&package_path)?;
// Construct the path to the main file in the source directory
let mut main_file_path = package_path.clone();
main_file_path.push(SOURCE_DIRECTORY_NAME);
main_file_path.push(MAIN_FILENAME);
// Load the input file at `package_name.in`
let (input_string, input_path) = InputFile::new(&package_name).read_from(&path)?;
// Load the state file at `package_name.in`
let (state_string, state_path) = StateFile::new(&package_name).read_from(&path)?;
// Log compilation of files to console
tracing::info!("Compiling main program... ({:?})", main_file_path);
// Load the program at `main_file_path`
let program = Compiler::<Fq, EdwardsGroupType>::parse_program_with_input(
package_name.clone(),
main_file_path,
output_directory,
&input_string,
&input_path,
&state_string,
&state_path,
thread_leaked_context(),
)?;
// Compute the current program checksum
let program_checksum = program.checksum()?;
// Generate the program on the constraint system and verify correctness
{
let mut cs = CircuitSynthesizer::<Bls12_377> {
constraints: Default::default(),
public_variables: Default::default(),
private_variables: Default::default(),
namespaces: Default::default(),
};
let temporary_program = program.clone();
let output = temporary_program.compile_constraints(&mut cs)?;
tracing::debug!("Compiled output - {:#?}", output);
tracing::info!("Number of constraints - {:#?}", cs.num_constraints());
// Serialize the circuit
let circuit_object = SerializedCircuit::from(cs);
let json = circuit_object.to_json_string().unwrap();
// println!("json: {}", json);
// Write serialized circuit to circuit `.json` file.
let circuit_file = CircuitFile::new(&package_name);
circuit_file.write_to(&path, json)?;
// Check that we can read the serialized circuit file
// let serialized = circuit_file.read_from(&package_path)?;
// Deserialize the circuit
// let deserialized = SerializedCircuit::from_json_string(&serialized).unwrap();
// let _circuit_synthesizer = CircuitSynthesizer::<Bls12_377>::try_from(deserialized).unwrap();
// println!("deserialized {:?}", circuit_synthesizer.num_constraints());
}
// If a checksum file exists, check if it differs from the new checksum
let checksum_file = ChecksumFile::new(&package_name);
let checksum_differs = if checksum_file.exists_at(&package_path) {
let previous_checksum = checksum_file.read_from(&package_path)?;
program_checksum != previous_checksum
} else {
// By default, the checksum differs if there is no checksum to compare against
true
};
// If checksum differs, compile the program
if checksum_differs {
// Write the new checksum to the output directory
checksum_file.write_to(&path, program_checksum)?;
tracing::debug!("Checksum saved ({:?})", path);
}
tracing::info!("Complete");
return Ok(Some((program, checksum_differs)));
if !MainFile::exists_at(&package_path) {
return Err(anyhow!("File main.leo not found in src/ directory"));
}
Ok(None)
// Create the output directory
OutputsDirectory::create(&package_path)?;
// Construct the path to the main file in the source directory
let mut main_file_path = package_path.clone();
main_file_path.push(SOURCE_DIRECTORY_NAME);
main_file_path.push(MAIN_FILENAME);
// Load the input file at `package_name.in`
let (input_string, input_path) = InputFile::new(&package_name).read_from(&path)?;
// Load the state file at `package_name.in`
let (state_string, state_path) = StateFile::new(&package_name).read_from(&path)?;
// Log compilation of files to console
tracing::info!("Compiling main program... ({:?})", main_file_path);
// Load the program at `main_file_path`
let program = Compiler::<Fq, EdwardsGroupType>::parse_program_with_input(
package_name.clone(),
main_file_path,
output_directory,
&input_string,
&input_path,
&state_string,
&state_path,
thread_leaked_context(),
)?;
// Compute the current program checksum
let program_checksum = program.checksum()?;
// Generate the program on the constraint system and verify correctness
{
let mut cs = CircuitSynthesizer::<Bls12_377> {
constraints: Default::default(),
public_variables: Default::default(),
private_variables: Default::default(),
namespaces: Default::default(),
};
let temporary_program = program.clone();
let output = temporary_program.compile_constraints(&mut cs)?;
tracing::debug!("Compiled output - {:#?}", output);
tracing::info!("Number of constraints - {:#?}", cs.num_constraints());
// Serialize the circuit
let circuit_object = SerializedCircuit::from(cs);
let json = circuit_object.to_json_string().unwrap();
// println!("json: {}", json);
// Write serialized circuit to circuit `.json` file.
let circuit_file = CircuitFile::new(&package_name);
circuit_file.write_to(&path, json)?;
// Check that we can read the serialized circuit file
// let serialized = circuit_file.read_from(&package_path)?;
// Deserialize the circuit
// let deserialized = SerializedCircuit::from_json_string(&serialized).unwrap();
// let _circuit_synthesizer = CircuitSynthesizer::<Bls12_377>::try_from(deserialized).unwrap();
// println!("deserialized {:?}", circuit_synthesizer.num_constraints());
}
// If a checksum file exists, check if it differs from the new checksum
let checksum_file = ChecksumFile::new(&package_name);
let checksum_differs = if checksum_file.exists_at(&package_path) {
let previous_checksum = checksum_file.read_from(&package_path)?;
program_checksum != previous_checksum
} else {
// By default, the checksum differs if there is no checksum to compare against
true
};
// If checksum differs, compile the program
if checksum_differs {
// Write the new checksum to the output directory
checksum_file.write_to(&path, program_checksum)?;
tracing::debug!("Checksum saved ({:?})", path);
}
tracing::info!("Complete");
Ok((program, checksum_differs))
}
}

View File

@ -18,7 +18,6 @@ use crate::{commands::Command, config::*, context::Context};
use leo_package::LeoPackage;
use anyhow::{anyhow, Result};
use std::env::current_dir;
use structopt::StructOpt;
use tracing::span::Span;
@ -39,9 +38,9 @@ impl Command for Init {
Ok(())
}
fn apply(self, _: Context, _: Self::Input) -> Result<Self::Output> {
fn apply(self, context: Context, _: Self::Input) -> Result<Self::Output> {
// Derive the package directory path.
let path = current_dir()?;
let path = context.dir()?;
// Check that the current package directory path exists.
if !path.exists() {
@ -55,12 +54,12 @@ impl Command for Init {
.to_string_lossy()
.to_string();
if !LeoPackage::is_package_name_valid(&package_name) {
return Err(anyhow!("Invalid Leo project name"));
return Err(anyhow!("Invalid Leo project name: {}", package_name));
}
let username = read_username().ok();
LeoPackage::initialize(&package_name, false, &path, username)?;
LeoPackage::initialize(&package_name, &path, username)?;
Ok(())
}

View File

@ -18,7 +18,7 @@ use crate::{commands::Command, config::*, context::Context};
use leo_package::LeoPackage;
use anyhow::{anyhow, Result};
use std::{env::current_dir, fs};
use std::fs;
use structopt::StructOpt;
use tracing::span::Span;
@ -42,7 +42,7 @@ impl Command for New {
Ok(())
}
fn apply(self, _: Context, _: Self::Input) -> Result<Self::Output> {
fn apply(self, context: Context, _: Self::Input) -> Result<Self::Output> {
// Check that the given package name is valid.
let package_name = self.name;
if !LeoPackage::is_package_name_valid(&package_name) {
@ -52,7 +52,7 @@ impl Command for New {
let username = read_username().ok();
// Derive the package directory path.
let mut path = current_dir()?;
let mut path = context.dir()?;
path.push(&package_name);
// Verify the package directory path does not exist yet.
@ -63,7 +63,7 @@ impl Command for New {
// Create the package directory
fs::create_dir_all(&path).map_err(|err| anyhow!("Could not create directory {}", err))?;
LeoPackage::initialize(&package_name, false, &path, username)?;
LeoPackage::initialize(&package_name, &path, username)?;
Ok(())
}

View File

@ -58,8 +58,7 @@ impl Command for Setup {
let package_name = context.manifest()?.get_package_name();
// Check if leo build failed
let (program, checksum_differs) =
input.ok_or_else(|| anyhow!("Unable to build, check that main file exists"))?;
let (program, checksum_differs) = input;
// Check if a proving key and verification key already exists
let keys_exist = ProvingKeyFile::new(&package_name).exists_at(&path)

View File

@ -21,7 +21,7 @@ use structopt::StructOpt;
use tracing::span::Span;
/// Setting for automatic updates of Leo
#[derive(Debug, StructOpt, PartialEq)]
#[derive(Debug, StructOpt)]
pub enum Automatic {
Automatic {
#[structopt(name = "bool", help = "Boolean value: true or false", parse(try_from_str))]

View File

@ -65,13 +65,8 @@ impl Command for Watch {
// See changes on the write event
Ok(DebouncedEvent::Write(_write)) => {
match (Build {}).execute(context.clone()) {
Ok(_output) => {
tracing::info!("Built successfully");
}
Err(e) => {
// Syntax error
tracing::error!("Error {:?}", e);
}
Ok(_output) => tracing::info!("Built successfully"),
Err(e) => tracing::error!("Error {:?}", e),
};
}
// Other events

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use std::fmt;
use std::{fmt, sync::Once};
use colored::Colorize;
use tracing::{event::Event, subscriber::Subscriber};
@ -24,6 +24,8 @@ use tracing_subscriber::{
FmtSubscriber,
};
static START: Once = Once::new();
#[derive(Debug, Clone)]
pub struct Format<F = Full, T = SystemTime> {
format: F,
@ -220,5 +222,8 @@ pub fn init_logger(_app_name: &'static str, verbosity: usize) {
.event_format(Format::default())
.finish();
tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
// call this line only once per process. needed for tests using same thread
START.call_once(|| {
tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
});
}

View File

@ -181,9 +181,11 @@ enum CommandOpts {
}
fn main() {
// Read command line arguments.
let opt = Opt::from_args();
handle_error(run_with_args(Opt::from_args()))
}
/// Run command with custom build arguments.
fn run_with_args(opt: Opt) -> Result<(), Error> {
if !opt.quiet {
// Init logger with optional debug flag.
logger::init_logger("leo", match opt.debug {
@ -199,7 +201,7 @@ fn main() {
None => context::get_context(opt.api),
});
handle_error(match opt.command {
match opt.command {
CommandOpts::Init { command } => command.try_execute(context),
CommandOpts::New { command } => command.try_execute(context),
CommandOpts::Build { command } => command.try_execute(context),
@ -220,7 +222,7 @@ fn main() {
CommandOpts::Lint { command } => command.try_execute(context),
CommandOpts::Deploy { command } => command.try_execute(context),
});
}
}
fn handle_error<T>(res: Result<T, Error>) -> T {
@ -232,3 +234,140 @@ fn handle_error<T>(res: Result<T, Error>) -> T {
}
}
}
#[cfg(test)]
mod cli_tests {
use crate::{run_with_args, Opt};
use anyhow::Error;
use std::path::PathBuf;
use structopt::StructOpt;
use test_dir::{DirBuilder, FileType, TestDir};
// Runs Command from cmd-like argument "leo run --arg1 --arg2".
fn run_cmd(args: &str, path: &Option<PathBuf>) -> Result<(), Error> {
let args = args.split(' ').collect::<Vec<&str>>();
let mut opts = Opt::from_iter_safe(args)?;
if path.is_some() {
opts.path = path.clone();
}
if !opts.debug {
// turn off tracing for all tests
opts.quiet = true;
}
run_with_args(opts)
}
// Create a test directory with name.
fn testdir(name: &str) -> TestDir {
TestDir::temp().create(name, FileType::Dir)
}
#[test]
fn global_options() {
let path = Some(PathBuf::from("examples/pedersen-hash"));
assert!(run_cmd("leo build", &path).is_ok());
assert!(run_cmd("leo -q build", &path).is_ok());
assert!(run_cmd("leo --path ../../examples/no-directory-there build", &None).is_err());
assert!(run_cmd("leo -v build", &None).is_err());
}
#[test]
fn global_options_fail() {
assert!(run_cmd("leo --path ../../examples/no-directory-there build", &None).is_err());
assert!(run_cmd("leo -v build", &None).is_err());
}
#[test]
fn init() {
let dir = testdir("test");
let path = Some(dir.path("test"));
assert!(run_cmd("leo init", &path).is_ok());
assert!(run_cmd("leo init", &path).is_err()); // 2nd time
}
#[test]
fn init_fail() {
let dir = testdir("incorrect_name");
let path = Some(dir.path("incorrect_name"));
let fake = Some(PathBuf::from("no_such_directory"));
assert!(run_cmd("leo init", &fake).is_err());
assert!(run_cmd("leo init", &path).is_err());
}
#[test]
fn new() {
let dir = testdir("new");
let path = Some(dir.path("new"));
assert!(run_cmd("leo new test", &path).is_ok());
assert!(run_cmd("leo new test", &path).is_err()); // 2nd time
assert!(run_cmd("leo new wrong_name", &path).is_err());
}
#[test]
#[should_panic]
fn unimplemented() {
assert!(run_cmd("leo lint", &None).is_err());
assert!(run_cmd("leo deploy", &None).is_err());
}
#[test]
fn clean() {
let path = &Some(PathBuf::from("examples/pedersen-hash"));
assert!(run_cmd("leo build", path).is_ok());
assert!(run_cmd("leo clean", path).is_ok());
}
#[test]
fn setup_prove_run_clean() {
let dir = testdir("test");
let path = dir.path("test");
assert!(run_cmd("leo new setup-test", &Some(path.clone())).is_ok());
let setup_path = &Some(path.join("setup-test"));
assert!(run_cmd("leo setup", setup_path).is_ok());
assert!(run_cmd("leo setup", setup_path).is_ok());
assert!(run_cmd("leo setup --skip-key-check", setup_path).is_ok());
assert!(run_cmd("leo prove --skip-key-check", setup_path).is_ok());
assert!(run_cmd("leo run --skip-key-check", setup_path).is_ok());
assert!(run_cmd("leo clean", setup_path).is_ok());
}
#[test]
fn test_missing_file() {
let dir = testdir("test");
let path = dir.path("test");
assert!(run_cmd("leo new test-file-missing", &Some(path.clone())).is_ok());
let path = path.join("test-file-missing");
let file = path.join("src/main.leo");
let path = Some(path);
assert!(run_cmd("leo test", &path).is_ok());
std::fs::remove_file(&file).unwrap();
assert!(run_cmd("leo test", &path).is_err());
}
#[test]
#[ignore] // ignore until imports path is fixed #875
fn test_sudoku() {
let path = &Some(PathBuf::from("examples/silly-sudoku"));
assert!(run_cmd("leo build", path).is_ok());
assert!(run_cmd("leo test", path).is_ok());
assert!(run_cmd("leo test -f src/lib.leo", path).is_ok());
assert!(run_cmd("leo test -f src/main.leo", path).is_ok());
}
}

View File

@ -14,9 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use std::path::PathBuf;
use anyhow::Result;
use std::path::PathBuf;
use crate::{
commands::{

View File

@ -33,13 +33,8 @@ pub struct LeoPackage;
impl LeoPackage {
/// Initializes a Leo package at the given path.
pub fn initialize(
package_name: &str,
is_lib: bool,
path: &Path,
author: Option<String>,
) -> Result<(), PackageError> {
package::Package::initialize(package_name, is_lib, path, author)
pub fn initialize(package_name: &str, path: &Path, author: Option<String>) -> Result<(), PackageError> {
package::Package::initialize(package_name, path, author)
}
/// Returns `true` if the given Leo package name is valid.

View File

@ -19,7 +19,7 @@ use crate::{
imports::ImportsDirectory,
inputs::{InputFile, InputsDirectory, StateFile},
root::{Gitignore, Manifest, README},
source::{LibraryFile, MainFile, SourceDirectory},
source::{MainFile, SourceDirectory},
};
use serde::Deserialize;
@ -107,7 +107,7 @@ impl Package {
}
/// Returns `true` if a package is can be initialized at a given path.
pub fn can_initialize(package_name: &str, is_lib: bool, path: &Path) -> bool {
pub fn can_initialize(package_name: &str, path: &Path) -> bool {
// Check that the package name is valid.
if !Self::is_package_name_valid(package_name) {
return false;
@ -122,32 +122,24 @@ impl Package {
result = false;
}
if is_lib {
// Check if the library file already exists.
if LibraryFile::exists_at(path) {
existing_files.push(LibraryFile::filename());
result = false;
}
} else {
// Check if the input file already exists.
let input_file = InputFile::new(&package_name);
if input_file.exists_at(path) {
existing_files.push(input_file.filename());
result = false;
}
// Check if the input file already exists.
let input_file = InputFile::new(&package_name);
if input_file.exists_at(path) {
existing_files.push(input_file.filename());
result = false;
}
// Check if the state file already exists.
let state_file = StateFile::new(&package_name);
if state_file.exists_at(path) {
existing_files.push(state_file.filename());
result = false;
}
// Check if the state file already exists.
let state_file = StateFile::new(&package_name);
if state_file.exists_at(path) {
existing_files.push(state_file.filename());
result = false;
}
// Check if the main file already exists.
if MainFile::exists_at(path) {
existing_files.push(MainFile::filename());
result = false;
}
// Check if the main file already exists.
if MainFile::exists_at(path) {
existing_files.push(MainFile::filename());
result = false;
}
if !existing_files.is_empty() {
@ -158,7 +150,7 @@ impl Package {
}
/// Returns `true` if a package is initialized at the given path
pub fn is_initialized(package_name: &str, is_lib: bool, path: &Path) -> bool {
pub fn is_initialized(package_name: &str, path: &Path) -> bool {
// Check that the package name is valid.
if !Self::is_package_name_valid(package_name) {
return false;
@ -169,43 +161,31 @@ impl Package {
return false;
}
if is_lib {
// Check if the library file exists.
if !LibraryFile::exists_at(&path) {
return false;
}
} else {
// Check if the input file exists.
let input_file = InputFile::new(&package_name);
if !input_file.exists_at(&path) {
return false;
}
// Check if the input file exists.
let input_file = InputFile::new(&package_name);
if !input_file.exists_at(&path) {
return false;
}
// Check if the state file exists.
let state_file = StateFile::new(&package_name);
if !state_file.exists_at(&path) {
return false;
}
// Check if the state file exists.
let state_file = StateFile::new(&package_name);
if !state_file.exists_at(&path) {
return false;
}
// Check if the main file exists.
if !MainFile::exists_at(&path) {
return false;
}
// Check if the main file exists.
if !MainFile::exists_at(&path) {
return false;
}
true
}
/// Creates a package at the given path
pub fn initialize(
package_name: &str,
is_lib: bool,
path: &Path,
author: Option<String>,
) -> Result<(), PackageError> {
pub fn initialize(package_name: &str, path: &Path, author: Option<String>) -> Result<(), PackageError> {
// First, verify that this directory is not already initialized as a Leo package.
{
if !Self::can_initialize(package_name, is_lib, path) {
if !Self::can_initialize(package_name, path) {
return Err(PackageError::FailedToInitialize(
package_name.to_owned(),
path.as_os_str().to_owned(),
@ -232,27 +212,21 @@ impl Package {
// Create the source directory.
SourceDirectory::create(&path)?;
// Create a new library or binary file.
if is_lib {
// Create the library file in the source directory.
LibraryFile::new(&package_name).write_to(&path)?;
} else {
// Create the input directory.
InputsDirectory::create(&path)?;
// Create the input directory.
InputsDirectory::create(&path)?;
// Create the input file in the inputs directory.
InputFile::new(&package_name).write_to(&path)?;
// Create the input file in the inputs directory.
InputFile::new(&package_name).write_to(&path)?;
// Create the state file in the inputs directory.
StateFile::new(&package_name).write_to(&path)?;
// Create the state file in the inputs directory.
StateFile::new(&package_name).write_to(&path)?;
// Create the main file in the source directory.
MainFile::new(&package_name).write_to(&path)?;
}
// Create the main file in the source directory.
MainFile::new(&package_name).write_to(&path)?;
}
// Next, verify that a valid Leo package has been initialized in this directory
{
if !Self::is_initialized(package_name, is_lib, path) {
if !Self::is_initialized(package_name, path) {
return Err(PackageError::FailedToInitialize(
package_name.to_owned(),
path.as_os_str().to_owned(),

View File

@ -1,76 +0,0 @@
// Copyright (C) 2019-2021 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
//! The `lib.leo` file.
use crate::{errors::LibraryFileError, source::directory::SOURCE_DIRECTORY_NAME};
use serde::Deserialize;
use std::{borrow::Cow, fs::File, io::Write, path::Path};
pub static LIBRARY_FILENAME: &str = "lib.leo";
#[derive(Deserialize)]
pub struct LibraryFile {
pub package_name: String,
}
impl LibraryFile {
pub fn new(package_name: &str) -> Self {
Self {
package_name: package_name.to_string(),
}
}
pub fn filename() -> String {
format!("{}{}", SOURCE_DIRECTORY_NAME, LIBRARY_FILENAME)
}
pub fn exists_at(path: &Path) -> bool {
let mut path = Cow::from(path);
if path.is_dir() {
if !path.ends_with(SOURCE_DIRECTORY_NAME) {
path.to_mut().push(SOURCE_DIRECTORY_NAME);
}
path.to_mut().push(LIBRARY_FILENAME);
}
path.exists()
}
pub fn write_to(self, path: &Path) -> Result<(), LibraryFileError> {
let mut path = Cow::from(path);
if path.is_dir() {
if !path.ends_with(SOURCE_DIRECTORY_NAME) {
path.to_mut().push(SOURCE_DIRECTORY_NAME);
}
path.to_mut().push(LIBRARY_FILENAME);
}
let mut file = File::create(&path)?;
Ok(file.write_all(self.template().as_bytes())?)
}
fn template(&self) -> String {
format!(
r#"// The '{}' library circuit.
circuit Foo {{
a: field
}}
"#,
self.package_name
)
}
}

View File

@ -17,8 +17,5 @@
pub mod directory;
pub use directory::*;
pub mod library;
pub use library::*;
pub mod main;
pub use main::*;

View File

@ -19,7 +19,7 @@ use leo_package::{
inputs::{InputFile, InputsDirectory, StateFile},
package::Package,
root::Manifest,
source::{LibraryFile, MainFile, SourceDirectory},
source::{MainFile, SourceDirectory},
};
const TEST_PACKAGE_NAME: &str = "test-package";
@ -29,13 +29,13 @@ fn initialize_valid_package() {
let test_directory = test_dir();
// Ensure a package can be initialized at the `test_directory`
assert!(Package::can_initialize(TEST_PACKAGE_NAME, false, &test_directory));
assert!(Package::can_initialize(TEST_PACKAGE_NAME, &test_directory));
// Initialize a package at the `test_directory`
assert!(Package::initialize(TEST_PACKAGE_NAME, false, &test_directory, None).is_ok());
assert!(Package::initialize(TEST_PACKAGE_NAME, &test_directory, None).is_ok());
// Ensure a package is initialized at the `test_directory`
assert!(Package::is_initialized(TEST_PACKAGE_NAME, false, &test_directory));
assert!(Package::is_initialized(TEST_PACKAGE_NAME, &test_directory));
}
#[test]
@ -43,21 +43,13 @@ fn initialize_valid_package_with_author() {
let test_directory = test_dir();
// Ensure a package can be initialized at the `test_directory`
assert!(Package::can_initialize(TEST_PACKAGE_NAME, false, &test_directory));
assert!(Package::can_initialize(TEST_PACKAGE_NAME, &test_directory));
// Initialize a package at the `test_directory`
assert!(
Package::initialize(
TEST_PACKAGE_NAME,
false,
&test_directory,
Some(String::from("test_user"))
)
.is_ok()
);
assert!(Package::initialize(TEST_PACKAGE_NAME, &test_directory, Some(String::from("test_user"))).is_ok());
// Ensure a package is initialized at the `test_directory`
assert!(Package::is_initialized(TEST_PACKAGE_NAME, false, &test_directory));
assert!(Package::is_initialized(TEST_PACKAGE_NAME, &test_directory));
}
#[test]
@ -71,7 +63,7 @@ fn initialize_fails_with_existing_manifest() {
let test_directory = test_dir();
// Ensure a package can be initialized at the `test_directory`
assert!(Package::can_initialize(TEST_PACKAGE_NAME, false, &test_directory));
assert!(Package::can_initialize(TEST_PACKAGE_NAME, &test_directory));
// Manually add a manifest file to the `test_directory`
Manifest::new(TEST_PACKAGE_NAME, None)
@ -80,28 +72,10 @@ fn initialize_fails_with_existing_manifest() {
.unwrap();
// Attempt to initialize a package at the `test_directory`
assert!(Package::initialize(TEST_PACKAGE_NAME, false, &test_directory, None).is_err());
assert!(Package::initialize(TEST_PACKAGE_NAME, &test_directory, None).is_err());
// Ensure package is not initialized at the `test_directory`
assert!(!Package::is_initialized(TEST_PACKAGE_NAME, false, &test_directory));
}
#[test]
fn initialize_fails_with_existing_library_file() {
let test_directory = test_dir();
// Ensure a package can be initialized at the `test_directory`
assert!(Package::can_initialize(TEST_PACKAGE_NAME, true, &test_directory));
// Manually add a source directory and a library file to the `test_directory`
SourceDirectory::create(&test_directory).unwrap();
LibraryFile::new(TEST_PACKAGE_NAME).write_to(&test_directory).unwrap();
// Attempt to initialize a package at the `test_directory`
assert!(Package::initialize(TEST_PACKAGE_NAME, true, &test_directory, None).is_err());
// Ensure package is not initialized at the `test_directory`
assert!(!Package::is_initialized(TEST_PACKAGE_NAME, true, &test_directory));
assert!(!Package::is_initialized(TEST_PACKAGE_NAME, &test_directory));
}
#[test]
@ -109,25 +83,17 @@ fn initialize_fails_with_existing_input_file() {
let test_directory = test_dir();
// Ensure a package can be initialized at the `test_directory`
assert!(Package::can_initialize(TEST_PACKAGE_NAME, false, &test_directory));
assert!(Package::can_initialize(TEST_PACKAGE_NAME, &test_directory));
// Manually add an inputs directory and an input file to the `test_directory`
InputsDirectory::create(&test_directory).unwrap();
InputFile::new(TEST_PACKAGE_NAME).write_to(&test_directory).unwrap();
// Attempt to initialize a package at the `test_directory`
assert!(
Package::initialize(
TEST_PACKAGE_NAME,
false,
&test_directory,
Some(String::from("test_user"))
)
.is_err()
);
assert!(Package::initialize(TEST_PACKAGE_NAME, &test_directory, Some(String::from("test_user"))).is_err());
// Ensure package is not initialized at the `test_directory`
assert!(!Package::is_initialized(TEST_PACKAGE_NAME, false, &test_directory));
assert!(!Package::is_initialized(TEST_PACKAGE_NAME, &test_directory));
}
#[test]
@ -135,17 +101,17 @@ fn initialize_fails_with_existing_state_file() {
let test_directory = test_dir();
// Ensure a package can be initialized at the `test_directory`
assert!(Package::can_initialize(TEST_PACKAGE_NAME, false, &test_directory));
assert!(Package::can_initialize(TEST_PACKAGE_NAME, &test_directory));
// Manually add an inputs directory and a state file to the `test_directory`
InputsDirectory::create(&test_directory).unwrap();
StateFile::new(TEST_PACKAGE_NAME).write_to(&test_directory).unwrap();
// Attempt to initialize a package at the `test_directory`
assert!(Package::initialize(TEST_PACKAGE_NAME, false, &test_directory, None).is_err());
assert!(Package::initialize(TEST_PACKAGE_NAME, &test_directory, None).is_err());
// Ensure package is not initialized at the `test_directory`
assert!(!Package::is_initialized(TEST_PACKAGE_NAME, false, &test_directory));
assert!(!Package::is_initialized(TEST_PACKAGE_NAME, &test_directory));
}
#[test]
@ -153,15 +119,15 @@ fn initialize_fails_with_existing_main_file() {
let test_directory = test_dir();
// Ensure a package can be initialized at the `test_directory`
assert!(Package::can_initialize(TEST_PACKAGE_NAME, false, &test_directory));
assert!(Package::can_initialize(TEST_PACKAGE_NAME, &test_directory));
// Manually add a source directory and a main file to the `test_directory`
SourceDirectory::create(&test_directory).unwrap();
MainFile::new(TEST_PACKAGE_NAME).write_to(&test_directory).unwrap();
// Attempt to initialize a package at the `test_directory`
assert!(Package::initialize(TEST_PACKAGE_NAME, false, &test_directory, None).is_err());
assert!(Package::initialize(TEST_PACKAGE_NAME, &test_directory, None).is_err());
// Ensure package is not initialized at the `test_directory`
assert!(!Package::is_initialized(TEST_PACKAGE_NAME, false, &test_directory));
assert!(!Package::is_initialized(TEST_PACKAGE_NAME, &test_directory));
}