mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-08-16 09:10:32 +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]
|
||||
version = "0.11.2"
|
||||
|
||||
[dev-dependencies.assert_cmd]
|
||||
version = "1.0.3"
|
||||
|
||||
[dev-dependencies.testdir]
|
||||
version = "0.4.0"
|
||||
|
||||
[features]
|
||||
default = [ ]
|
||||
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::{
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
@ -55,12 +55,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(())
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
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
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use std::path::PathBuf;
|
||||
mod cmd;
|
||||
|
||||
use anyhow::Result;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::{
|
||||
commands::{
|
||||
|
@ -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.
|
||||
|
@ -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(),
|
||||
|
@ -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 use directory::*;
|
||||
|
||||
pub mod library;
|
||||
pub use library::*;
|
||||
|
||||
pub mod main;
|
||||
pub use main::*;
|
||||
|
@ -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));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user