use std::env;
use std::fs::File;
use std::io::{self, Read};
use std::io::Write;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use serde_json::Value;
use simpath::Simpath;
use tempdir::TempDir;
use url::Url;
use flowcore::{DONT_RUN_AGAIN, Implementation, RunAgain};
use flowcore::errors::Result;
use flowcore::meta_provider::MetaProvider;
use flowcore::model::flow_manifest::FlowManifest;
use flowcore::model::lib_manifest::{ImplementationLocator::Native, LibraryManifest};
use flowcore::model::metadata::MetaData;
use flowcore::model::runtime_function::RuntimeFunction;
use flowrlib::loader::Loader;
fn url_from_rel_path(path: &str) -> Url {
let cwd = cwd_as_url();
let source_file = cwd.join(file!()).expect("Could not join paths");
source_file.join(path).expect("Could not join paths")
}
fn cwd_as_url() -> Url {
Url::from_directory_path(env::current_dir().expect("Could not get CWD"))
.expect("Could not create Url from path")
}
fn create_manifest(functions: Vec<RuntimeFunction>) -> FlowManifest {
let metadata = MetaData {
name: "test manifest".into(),
description: "test manifest".into(),
version: "0.0".into(),
authors: vec!["me".into()],
};
let mut manifest = FlowManifest::new(metadata);
for function in functions {
let location_url = &Url::parse(function.implementation_location())
.expect("Could not create Url");
match location_url.scheme() {
"lib" => manifest.add_lib_reference(location_url),
"context" => manifest.add_context_reference(location_url),
_ => {}
}
manifest.add_function(function);
}
manifest
}
#[derive(Debug)]
struct Fake;
impl Implementation for Fake {
fn run(&self, mut _inputs: &[Value]) -> Result<(Option<Value>, RunAgain)> {
let mut value = None;
let mut buffer = String::new();
let stdin = io::stdin();
let mut handle = stdin.lock();
if let Ok(size) = handle.read_to_string(&mut buffer) {
if size > 0 {
let input = Value::String(buffer.trim().to_string());
value = Some(input);
}
}
Ok((value, DONT_RUN_AGAIN))
}
}
fn get_manifest() -> LibraryManifest {
let metadata = MetaData {
name: "context".to_string(),
description: "".into(),
version: "0.1.0".into(),
authors: vec!["".into()],
};
let lib_url = Url::parse("lib://context").expect("Couldn't create lib url");
let mut manifest = LibraryManifest::new(lib_url, metadata);
manifest.locators.insert(
Url::parse("context://args/get/get").expect("Could not create Url"),
Native(Arc::new(Fake {})),
);
manifest.locators.insert(
Url::parse("context://file/file_write/file_write").expect("Could not create Url"),
Native(Arc::new(Fake {})),
);
manifest.locators.insert(
Url::parse("context://stdio/readline/readline").expect("Could not create Url"),
Native(Arc::new(Fake {})),
);
manifest.locators.insert(
Url::parse("context://stdio/stdin/stdin").expect("Could not create Url"),
Native(Arc::new(Fake {})),
);
manifest.locators.insert(
Url::parse("context://stdio/stdout/stdout").expect("Could not create Url"),
Native(Arc::new(Fake {})),
);
manifest.locators.insert(
Url::parse("context://stdio/stderr/stderr").expect("Could not create Url"),
Native(Arc::new(Fake {})),
);
manifest
}
fn write_manifest(manifest: &FlowManifest, filename: &Path) -> Result<()> {
let mut manifest_file =
File::create(&filename).map_err(|_| "Could not create lib manifest file")?;
manifest_file
.write_all(
serde_json::to_string_pretty(manifest)
.map_err(|_| "Could not pretty format the manifest JSON contents")?
.as_bytes(),
)
.map_err(|_| "Could not write manifest data bytes to created manifest file")?;
Ok(())
}
fn set_lib_search_path() -> Simpath {
let mut lib_search_path = Simpath::new("lib_search_path");
let flowr_path_str = Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("Could not get project root dir")
.join("flowr/src/bin/flowr");
println!("flowr_path_str: {:?}", flowr_path_str);
lib_search_path.add_directory(
flowr_path_str
.to_str()
.expect("Could not get context parent directory path as string"),
);
lib_search_path
}
#[test]
fn load_manifest_from_file() {
let f_a = RuntimeFunction::new(
#[cfg(feature = "debugger")] "fA",
#[cfg(feature = "debugger")] "/fA",
"context://stdio/stdout/stdout",
vec![],
0,
0,
&[],
false,
);
let functions = vec![f_a];
let manifest = create_manifest(functions);
let temp_dir = TempDir::new("flow").expect("Could not get temp dir").into_path();
let manifest_file = temp_dir.join("manifest.json");
write_manifest(&manifest, &manifest_file).expect("Could not write manifest file");
let manifest_url = Url::from_directory_path(manifest_file).expect("Could not create url from directory path");
let provider = MetaProvider::new(set_lib_search_path(),
PathBuf::from("/"));
let mut loader = Loader::new();
loader
.add_lib(
&provider,
get_manifest(),
&Url::parse("lib://context").expect("Could not parse lib url"),
)
.expect("Could not add context library to loader");
let _ = loader
.load_flow(&provider, &manifest_url)
.expect("Loader could not load flow");
assert!(!loader.get_lib_implementations().is_empty());
}
#[test]
fn resolve_lib_implementation_test() {
let f_a = RuntimeFunction::new(
#[cfg(feature = "debugger")] "fA",
#[cfg(feature = "debugger")] "/fA",
"context://stdio/stdin/stdin",
vec![],
0,
0,
&[],
false,
);
let functions = vec![f_a];
let mut manifest = create_manifest(functions);
let provider = MetaProvider::new(set_lib_search_path(),
PathBuf::from("/"));
let mut loader = Loader::new();
let manifest_url = url_from_rel_path("manifest.json");
loader
.add_lib(&provider, get_manifest(), &cwd_as_url())
.expect("Could not add library");
loader
.resolve_implementations(&provider, &mut manifest, &manifest_url)
.expect("Could not add library");
}
#[test]
fn unresolved_lib_functions_test() {
let f_a = RuntimeFunction::new(
#[cfg(feature = "debugger")] "fA",
#[cfg(feature = "debugger")] "/fA",
"context://stdio/stdin/foo",
vec![],
0,
0,
&[],
false,
);
let functions = vec![f_a];
let mut manifest = create_manifest(functions);
let provider = MetaProvider::new(set_lib_search_path(),
PathBuf::from("/"));
let mut loader = Loader::new();
let manifest_url = url_from_rel_path("manifest.json");
loader
.add_lib(&provider, get_manifest(), &cwd_as_url())
.expect("Could not add context library to loader");
assert!(loader
.resolve_implementations(&provider, &mut manifest, &manifest_url)
.is_err());
}