mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-09-11 13:56:58 +03:00
adds integration tests to Leo CLI
- leo tests are now written as cli commands - leo libraries and binaries removed from package and cli - small code optimizations and removals
This commit is contained in:
parent
daa23b7311
commit
b8312ab4a4
724
Cargo.lock
generated
724
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -156,6 +156,12 @@ version = "0.12.1"
|
|||||||
[dev-dependencies.rusty-hook]
|
[dev-dependencies.rusty-hook]
|
||||||
version = "0.11.2"
|
version = "0.11.2"
|
||||||
|
|
||||||
|
[dev-dependencies.assert_cmd]
|
||||||
|
version = "1.0.3"
|
||||||
|
|
||||||
|
[dev-dependencies.testdir]
|
||||||
|
version = "0.4.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ ]
|
default = [ ]
|
||||||
ci_skip = [ "leo-compiler/ci_skip" ]
|
ci_skip = [ "leo-compiler/ci_skip" ]
|
||||||
|
14
examples/silly-sudoku/inputs/test_input.in
Normal file
14
examples/silly-sudoku/inputs/test_input.in
Normal 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;
|
@ -22,11 +22,11 @@ use leo_compiler::{
|
|||||||
use leo_package::{
|
use leo_package::{
|
||||||
inputs::*,
|
inputs::*,
|
||||||
outputs::{ChecksumFile, CircuitFile, OutputsDirectory, OUTPUTS_DIRECTORY_NAME},
|
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 leo_synthesizer::{CircuitSynthesizer, SerializedCircuit};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{anyhow, Result};
|
||||||
use snarkvm_curves::{bls12_377::Bls12_377, edwards_bls12::Fq};
|
use snarkvm_curves::{bls12_377::Bls12_377, edwards_bls12::Fq};
|
||||||
use snarkvm_r1cs::ConstraintSystem;
|
use snarkvm_r1cs::ConstraintSystem;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
@ -39,7 +39,7 @@ pub struct Build {}
|
|||||||
|
|
||||||
impl Command for Build {
|
impl Command for Build {
|
||||||
type Input = ();
|
type Input = ();
|
||||||
type Output = Option<(Compiler<'static, Fq, EdwardsGroupType>, bool)>;
|
type Output = (Compiler<'static, Fq, EdwardsGroupType>, bool);
|
||||||
|
|
||||||
fn log_span(&self) -> Span {
|
fn log_span(&self) -> Span {
|
||||||
tracing::span!(tracing::Level::INFO, "Build")
|
tracing::span!(tracing::Level::INFO, "Build")
|
||||||
@ -65,115 +65,95 @@ impl Command for Build {
|
|||||||
|
|
||||||
tracing::info!("Starting...");
|
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
|
// Compile the main.leo file along with constraints
|
||||||
if MainFile::exists_at(&package_path) {
|
if !MainFile::exists_at(&package_path) {
|
||||||
// Create the output directory
|
return Err(anyhow!("File main.leo not found in src/ 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)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,12 +55,12 @@ impl Command for Init {
|
|||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.to_string();
|
.to_string();
|
||||||
if !LeoPackage::is_package_name_valid(&package_name) {
|
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();
|
let username = read_username().ok();
|
||||||
|
|
||||||
LeoPackage::initialize(&package_name, false, &path, username)?;
|
LeoPackage::initialize(&package_name, &path, username)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ impl Command for New {
|
|||||||
// Create the package directory
|
// Create the package directory
|
||||||
fs::create_dir_all(&path).map_err(|err| anyhow!("Could not create directory {}", err))?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -58,8 +58,7 @@ impl Command for Setup {
|
|||||||
let package_name = context.manifest()?.get_package_name();
|
let package_name = context.manifest()?.get_package_name();
|
||||||
|
|
||||||
// Check if leo build failed
|
// Check if leo build failed
|
||||||
let (program, checksum_differs) =
|
let (program, checksum_differs) = input;
|
||||||
input.ok_or_else(|| anyhow!("Unable to build, check that main file exists"))?;
|
|
||||||
|
|
||||||
// Check if a proving key and verification key already exists
|
// Check if a proving key and verification key already exists
|
||||||
let keys_exist = ProvingKeyFile::new(&package_name).exists_at(&path)
|
let keys_exist = ProvingKeyFile::new(&package_name).exists_at(&path)
|
||||||
|
@ -65,13 +65,8 @@ impl Command for Watch {
|
|||||||
// See changes on the write event
|
// See changes on the write event
|
||||||
Ok(DebouncedEvent::Write(_write)) => {
|
Ok(DebouncedEvent::Write(_write)) => {
|
||||||
match (Build {}).execute(context.clone()) {
|
match (Build {}).execute(context.clone()) {
|
||||||
Ok(_output) => {
|
Ok(_output) => tracing::info!("Built successfully"),
|
||||||
tracing::info!("Built successfully");
|
Err(e) => tracing::error!("Error {:?}", e),
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
// Syntax error
|
|
||||||
tracing::error!("Error {:?}", e);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// Other events
|
// Other events
|
||||||
|
122
leo/tests/cmd.rs
Normal file
122
leo/tests/cmd.rs
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
use assert_cmd::Command;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use testdir::testdir;
|
||||||
|
|
||||||
|
/// Create Command from given arguments and CWD.
|
||||||
|
fn command(args: &str, cwd: Option<PathBuf>) -> Command {
|
||||||
|
let args = args.split(" ").collect::<Vec<&str>>();
|
||||||
|
let mut cmd = Command::cargo_bin("leo").unwrap();
|
||||||
|
|
||||||
|
if let Some(cwd) = cwd {
|
||||||
|
cmd.current_dir(cwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.args(args);
|
||||||
|
cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect_success(args: &str, cwd: Option<PathBuf>) {
|
||||||
|
command(args, cwd).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect_fail(args: &str, cwd: Option<PathBuf>) {
|
||||||
|
command(args, cwd).unwrap_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_global_options() {
|
||||||
|
expect_success("--path examples/pedersen-hash build", None);
|
||||||
|
expect_success("--path examples/pedersen-hash -q build", None);
|
||||||
|
expect_success("--path examples/pedersen-hash -d build", None);
|
||||||
|
|
||||||
|
expect_fail("--path examples/no-directory-there build", None);
|
||||||
|
expect_fail("-v build", None); // no such option
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn init() {
|
||||||
|
let dir = Some(testdir!());
|
||||||
|
|
||||||
|
expect_success("init", dir.clone());
|
||||||
|
expect_fail("init", dir); // can't do twice
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn init_fail() {
|
||||||
|
let dir = Some(testdir!()); // directory is named /init_fail - as test name
|
||||||
|
|
||||||
|
expect_fail("init", Some("directory-doesnt-exist".into()));
|
||||||
|
expect_fail("init", dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn new() {
|
||||||
|
let dir = Some(testdir!());
|
||||||
|
|
||||||
|
expect_success("new test", dir.clone());
|
||||||
|
expect_fail("new test", dir.clone()); // duplicate
|
||||||
|
expect_fail("new wrong_name123123", dir.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unimplemented() {
|
||||||
|
expect_fail("lint", None);
|
||||||
|
expect_fail("deploy", None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn clean() {
|
||||||
|
expect_success("--path examples/pedersen-hash build", None);
|
||||||
|
expect_success("--path examples/pedersen-hash clean", None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn setup_prove_run_clean() {
|
||||||
|
let dir = testdir!();
|
||||||
|
|
||||||
|
expect_success("new setup", Some(dir.clone()));
|
||||||
|
|
||||||
|
let dir = Some(dir.join("setup"));
|
||||||
|
|
||||||
|
expect_success("setup", dir.clone());
|
||||||
|
expect_success("setup", dir.clone());
|
||||||
|
expect_success("setup --skip-key-check", dir.clone());
|
||||||
|
expect_success("prove --skip-key-check", dir.clone());
|
||||||
|
expect_success("run --skip-key-check", dir.clone());
|
||||||
|
expect_success("clean", dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sudoku() {
|
||||||
|
let path = "examples/silly-sudoku";
|
||||||
|
|
||||||
|
expect_success("build", Some(path.into()));
|
||||||
|
expect_success("test", Some(path.into()));
|
||||||
|
expect_success("test -f src/lib.leo", Some(path.into()));
|
||||||
|
expect_success("test -f src/main.leo", Some(path.into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_missing_file() {
|
||||||
|
let path = testdir!();
|
||||||
|
|
||||||
|
expect_success("new missing-file-test", Some(path.clone()));
|
||||||
|
std::fs::remove_file(&path.clone().join("missing-file-test/src/main.leo")).unwrap();
|
||||||
|
expect_fail("test", Some(path.join("missing-file")));
|
||||||
|
}
|
@ -14,9 +14,10 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::path::PathBuf;
|
mod cmd;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
commands::{
|
commands::{
|
||||||
|
@ -33,13 +33,8 @@ pub struct LeoPackage;
|
|||||||
|
|
||||||
impl LeoPackage {
|
impl LeoPackage {
|
||||||
/// Initializes a Leo package at the given path.
|
/// Initializes a Leo package at the given path.
|
||||||
pub fn initialize(
|
pub fn initialize(package_name: &str, path: &Path, author: Option<String>) -> Result<(), PackageError> {
|
||||||
package_name: &str,
|
package::Package::initialize(package_name, path, author)
|
||||||
is_lib: bool,
|
|
||||||
path: &Path,
|
|
||||||
author: Option<String>,
|
|
||||||
) -> Result<(), PackageError> {
|
|
||||||
package::Package::initialize(package_name, is_lib, path, author)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the given Leo package name is valid.
|
/// Returns `true` if the given Leo package name is valid.
|
||||||
|
@ -19,7 +19,7 @@ use crate::{
|
|||||||
imports::ImportsDirectory,
|
imports::ImportsDirectory,
|
||||||
inputs::{InputFile, InputsDirectory, StateFile},
|
inputs::{InputFile, InputsDirectory, StateFile},
|
||||||
root::{Gitignore, Manifest, README},
|
root::{Gitignore, Manifest, README},
|
||||||
source::{LibraryFile, MainFile, SourceDirectory},
|
source::{MainFile, SourceDirectory},
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@ -107,7 +107,7 @@ impl Package {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if a package is can be initialized at a given path.
|
/// 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.
|
// Check that the package name is valid.
|
||||||
if !Self::is_package_name_valid(package_name) {
|
if !Self::is_package_name_valid(package_name) {
|
||||||
return false;
|
return false;
|
||||||
@ -122,32 +122,24 @@ impl Package {
|
|||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_lib {
|
// Check if the input file already exists.
|
||||||
// Check if the library file already exists.
|
let input_file = InputFile::new(&package_name);
|
||||||
if LibraryFile::exists_at(path) {
|
if input_file.exists_at(path) {
|
||||||
existing_files.push(LibraryFile::filename());
|
existing_files.push(input_file.filename());
|
||||||
result = false;
|
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 state file already exists.
|
// Check if the state file already exists.
|
||||||
let state_file = StateFile::new(&package_name);
|
let state_file = StateFile::new(&package_name);
|
||||||
if state_file.exists_at(path) {
|
if state_file.exists_at(path) {
|
||||||
existing_files.push(state_file.filename());
|
existing_files.push(state_file.filename());
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the main file already exists.
|
// Check if the main file already exists.
|
||||||
if MainFile::exists_at(path) {
|
if MainFile::exists_at(path) {
|
||||||
existing_files.push(MainFile::filename());
|
existing_files.push(MainFile::filename());
|
||||||
result = false;
|
result = false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !existing_files.is_empty() {
|
if !existing_files.is_empty() {
|
||||||
@ -158,7 +150,7 @@ impl Package {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if a package is initialized at the given path
|
/// 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.
|
// Check that the package name is valid.
|
||||||
if !Self::is_package_name_valid(package_name) {
|
if !Self::is_package_name_valid(package_name) {
|
||||||
return false;
|
return false;
|
||||||
@ -169,43 +161,31 @@ impl Package {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_lib {
|
// Check if the input file exists.
|
||||||
// Check if the library file exists.
|
let input_file = InputFile::new(&package_name);
|
||||||
if !LibraryFile::exists_at(&path) {
|
if !input_file.exists_at(&path) {
|
||||||
return false;
|
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 state file exists.
|
// Check if the state file exists.
|
||||||
let state_file = StateFile::new(&package_name);
|
let state_file = StateFile::new(&package_name);
|
||||||
if !state_file.exists_at(&path) {
|
if !state_file.exists_at(&path) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the main file exists.
|
// Check if the main file exists.
|
||||||
if !MainFile::exists_at(&path) {
|
if !MainFile::exists_at(&path) {
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a package at the given path
|
/// Creates a package at the given path
|
||||||
pub fn initialize(
|
pub fn initialize(package_name: &str, path: &Path, author: Option<String>) -> Result<(), PackageError> {
|
||||||
package_name: &str,
|
|
||||||
is_lib: bool,
|
|
||||||
path: &Path,
|
|
||||||
author: Option<String>,
|
|
||||||
) -> Result<(), PackageError> {
|
|
||||||
// First, verify that this directory is not already initialized as a Leo package.
|
// 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(
|
return Err(PackageError::FailedToInitialize(
|
||||||
package_name.to_owned(),
|
package_name.to_owned(),
|
||||||
path.as_os_str().to_owned(),
|
path.as_os_str().to_owned(),
|
||||||
@ -232,27 +212,21 @@ impl Package {
|
|||||||
// Create the source directory.
|
// Create the source directory.
|
||||||
SourceDirectory::create(&path)?;
|
SourceDirectory::create(&path)?;
|
||||||
|
|
||||||
// Create a new library or binary file.
|
// Create the input directory.
|
||||||
if is_lib {
|
InputsDirectory::create(&path)?;
|
||||||
// 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 file in the inputs directory.
|
// Create the input file in the inputs directory.
|
||||||
InputFile::new(&package_name).write_to(&path)?;
|
InputFile::new(&package_name).write_to(&path)?;
|
||||||
|
|
||||||
// Create the state file in the inputs directory.
|
// Create the state file in the inputs directory.
|
||||||
StateFile::new(&package_name).write_to(&path)?;
|
StateFile::new(&package_name).write_to(&path)?;
|
||||||
|
|
||||||
// Create the main file in the source directory.
|
// Create the main file in the source directory.
|
||||||
MainFile::new(&package_name).write_to(&path)?;
|
MainFile::new(&package_name).write_to(&path)?;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Next, verify that a valid Leo package has been initialized in this directory
|
// 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(
|
return Err(PackageError::FailedToInitialize(
|
||||||
package_name.to_owned(),
|
package_name.to_owned(),
|
||||||
path.as_os_str().to_owned(),
|
path.as_os_str().to_owned(),
|
||||||
|
@ -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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -17,8 +17,5 @@
|
|||||||
pub mod directory;
|
pub mod directory;
|
||||||
pub use directory::*;
|
pub use directory::*;
|
||||||
|
|
||||||
pub mod library;
|
|
||||||
pub use library::*;
|
|
||||||
|
|
||||||
pub mod main;
|
pub mod main;
|
||||||
pub use main::*;
|
pub use main::*;
|
||||||
|
@ -19,7 +19,7 @@ use leo_package::{
|
|||||||
inputs::{InputFile, InputsDirectory, StateFile},
|
inputs::{InputFile, InputsDirectory, StateFile},
|
||||||
package::Package,
|
package::Package,
|
||||||
root::Manifest,
|
root::Manifest,
|
||||||
source::{LibraryFile, MainFile, SourceDirectory},
|
source::{MainFile, SourceDirectory},
|
||||||
};
|
};
|
||||||
|
|
||||||
const TEST_PACKAGE_NAME: &str = "test-package";
|
const TEST_PACKAGE_NAME: &str = "test-package";
|
||||||
@ -29,13 +29,13 @@ fn initialize_valid_package() {
|
|||||||
let test_directory = test_dir();
|
let test_directory = test_dir();
|
||||||
|
|
||||||
// Ensure a package can be initialized at the `test_directory`
|
// 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`
|
// 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`
|
// 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]
|
#[test]
|
||||||
@ -43,21 +43,13 @@ fn initialize_valid_package_with_author() {
|
|||||||
let test_directory = test_dir();
|
let test_directory = test_dir();
|
||||||
|
|
||||||
// Ensure a package can be initialized at the `test_directory`
|
// 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`
|
// Initialize a package at the `test_directory`
|
||||||
assert!(
|
assert!(Package::initialize(TEST_PACKAGE_NAME, &test_directory, Some(String::from("test_user"))).is_ok());
|
||||||
Package::initialize(
|
|
||||||
TEST_PACKAGE_NAME,
|
|
||||||
false,
|
|
||||||
&test_directory,
|
|
||||||
Some(String::from("test_user"))
|
|
||||||
)
|
|
||||||
.is_ok()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ensure a package is initialized at the `test_directory`
|
// 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]
|
#[test]
|
||||||
@ -71,7 +63,7 @@ fn initialize_fails_with_existing_manifest() {
|
|||||||
let test_directory = test_dir();
|
let test_directory = test_dir();
|
||||||
|
|
||||||
// Ensure a package can be initialized at the `test_directory`
|
// 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`
|
// Manually add a manifest file to the `test_directory`
|
||||||
Manifest::new(TEST_PACKAGE_NAME, None)
|
Manifest::new(TEST_PACKAGE_NAME, None)
|
||||||
@ -80,28 +72,10 @@ fn initialize_fails_with_existing_manifest() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Attempt to initialize a package at the `test_directory`
|
// 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`
|
// 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]
|
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -109,25 +83,17 @@ fn initialize_fails_with_existing_input_file() {
|
|||||||
let test_directory = test_dir();
|
let test_directory = test_dir();
|
||||||
|
|
||||||
// Ensure a package can be initialized at the `test_directory`
|
// 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`
|
// Manually add an inputs directory and an input file to the `test_directory`
|
||||||
InputsDirectory::create(&test_directory).unwrap();
|
InputsDirectory::create(&test_directory).unwrap();
|
||||||
InputFile::new(TEST_PACKAGE_NAME).write_to(&test_directory).unwrap();
|
InputFile::new(TEST_PACKAGE_NAME).write_to(&test_directory).unwrap();
|
||||||
|
|
||||||
// Attempt to initialize a package at the `test_directory`
|
// Attempt to initialize a package at the `test_directory`
|
||||||
assert!(
|
assert!(Package::initialize(TEST_PACKAGE_NAME, &test_directory, Some(String::from("test_user"))).is_err());
|
||||||
Package::initialize(
|
|
||||||
TEST_PACKAGE_NAME,
|
|
||||||
false,
|
|
||||||
&test_directory,
|
|
||||||
Some(String::from("test_user"))
|
|
||||||
)
|
|
||||||
.is_err()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ensure package is not initialized at the `test_directory`
|
// 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]
|
#[test]
|
||||||
@ -135,17 +101,17 @@ fn initialize_fails_with_existing_state_file() {
|
|||||||
let test_directory = test_dir();
|
let test_directory = test_dir();
|
||||||
|
|
||||||
// Ensure a package can be initialized at the `test_directory`
|
// 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`
|
// Manually add an inputs directory and a state file to the `test_directory`
|
||||||
InputsDirectory::create(&test_directory).unwrap();
|
InputsDirectory::create(&test_directory).unwrap();
|
||||||
StateFile::new(TEST_PACKAGE_NAME).write_to(&test_directory).unwrap();
|
StateFile::new(TEST_PACKAGE_NAME).write_to(&test_directory).unwrap();
|
||||||
|
|
||||||
// Attempt to initialize a package at the `test_directory`
|
// 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`
|
// 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]
|
#[test]
|
||||||
@ -153,15 +119,15 @@ fn initialize_fails_with_existing_main_file() {
|
|||||||
let test_directory = test_dir();
|
let test_directory = test_dir();
|
||||||
|
|
||||||
// Ensure a package can be initialized at the `test_directory`
|
// 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`
|
// Manually add a source directory and a main file to the `test_directory`
|
||||||
SourceDirectory::create(&test_directory).unwrap();
|
SourceDirectory::create(&test_directory).unwrap();
|
||||||
MainFile::new(TEST_PACKAGE_NAME).write_to(&test_directory).unwrap();
|
MainFile::new(TEST_PACKAGE_NAME).write_to(&test_directory).unwrap();
|
||||||
|
|
||||||
// Attempt to initialize a package at the `test_directory`
|
// 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`
|
// 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));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user