use crate::codegen::{python, r};
use crate::{Argument, Deprecation, Function, TypeRecipe, Value};
use pretty_assertions::assert_eq;
use std::collections::HashMap;
fn make_argument() -> Argument {
Argument {
name: Some("fake_argument".to_string()),
c_type: Some("double".to_string()),
rust_type: Some(TypeRecipe::Name("f64".to_string())),
hint: None,
description: Some("fake description".to_string()),
default: Some(Value::Float(99.9)),
is_type: false,
do_not_convert: false,
example: None,
}
}
fn make_function(parameter_argument: Argument, return_argument: Argument) -> Function {
Function {
name: "fake_function".to_string(),
description: Some("fake description".to_string()),
features: vec!["fake_feature".to_string()],
args: vec![parameter_argument],
derived_types: vec![],
ret: return_argument,
supports_partial: false,
has_ffi: true,
deprecation: Some(Deprecation {
since: "1.2.3.4".to_string(),
note: "fake note".to_string(),
}),
}
}
#[test]
fn test_python_code_generation() {
let parameter_argument = make_argument();
let return_argument = make_argument();
let function = make_function(parameter_argument, return_argument);
let typemap: HashMap<String, String> =
serde_json::from_str(&include_str!("python_typemap.json")).unwrap();
let actual_code =
python::generate_function("fake_module", &function, &typemap, &HashMap::new());
let expected_code = "
@deprecated(version=\"1.2.3.4\", reason=\"fake note\")
def fake_function(
fake_argument = 99.9
):
r\"\"\"fake description
.. end-markdown
:param fake_argument: fake description
:return: fake description
:raises TypeError: if an argument's type differs from the expected type
:raises UnknownTypeException: if a type argument fails to parse
\"\"\"
assert_features(\"fake_feature\")
# No type arguments to standardize.
# Convert arguments to c types.
c_fake_argument = py_to_c(fake_argument, c_type=ctypes.c_double, type_name=\"f64\")
# Call library function.
lib_function = lib.opendp_fake_module__fake_function
lib_function.argtypes = [ctypes.c_double]
lib_function.restype = ctypes.c_double
output = c_to_py(lib_function(c_fake_argument))
try:
output.__opendp_dict__ = {
'__function__': 'fake_function',
'__module__': 'fake_module',
'__kwargs__': {
'fake_argument': fake_argument
},
}
except AttributeError: # pragma: no cover
pass
return output
";
assert_eq!(actual_code, expected_code);
}
#[test]
fn test_r_code_generation() {
let parameter_argument = make_argument();
let return_argument = make_argument();
let function = make_function(parameter_argument, return_argument);
let hierarchy: HashMap<String, Vec<String>> =
serde_json::from_str(&include_str!("type_hierarchy.json")).unwrap();
let actual_code = r::r::generate_r_function("fake_module", &function, &hierarchy);
let expected_code = "
#' fake description
#'
#' @concept fake_module
#' @param fake_argument fake description
#' @return fake description
#' @export
fake_function <- function(
fake_argument = 99.9
) {
.Deprecated(msg = \"fake note\")
assert_features(\"fake_feature\")
# No type arguments to standardize.
log_ <- new_constructor_log(\"fake_function\", \"fake_module\", new_hashtab(
list(\"fake_argument\"),
list(unbox2(fake_argument))
))
# Assert that arguments are correctly typed.
rt_assert_is_similar(expected = f64, inferred = rt_infer(fake_argument))
# Call wrapper function.
output <- .Call(
\"fake_module__fake_function\",
fake_argument,
log_, PACKAGE = \"opendp\")
output
}
";
assert_eq!(actual_code, expected_code);
}