168e4fda59
Change-Id: I3c94ecb5958294b5973c6fcdf5ee9c0d37fa54ad Reviewed-on: https://cl.tvl.fyi/c/depot/+/11976 Reviewed-by: flokli <flokli@flokli.de> Tested-by: BuildkiteCI Autosubmit: yuka <yuka@yuka.dev>
244 lines
5.4 KiB
Rust
244 lines
5.4 KiB
Rust
use serde::Deserialize;
|
|
use std::collections::HashMap;
|
|
use tvix_eval::builtin_macros::builtins;
|
|
|
|
use crate::de::{from_str, from_str_with_config};
|
|
|
|
#[test]
|
|
fn deserialize_none() {
|
|
let result: Option<usize> = from_str("null").expect("should deserialize");
|
|
assert_eq!(None, result);
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_some() {
|
|
let result: Option<usize> = from_str("40 + 2").expect("should deserialize");
|
|
assert_eq!(Some(42), result);
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_string() {
|
|
let result: String = from_str(
|
|
r#"
|
|
let greeter = name: "Hello ${name}!";
|
|
in greeter "Slartibartfast"
|
|
"#,
|
|
)
|
|
.expect("should deserialize");
|
|
|
|
assert_eq!(result, "Hello Slartibartfast!");
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_empty_list() {
|
|
let result: Vec<usize> = from_str("[ ]").expect("should deserialize");
|
|
assert!(result.is_empty())
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_integer_list() {
|
|
let result: Vec<usize> =
|
|
from_str("builtins.map (n: n + 2) [ 21 40 67 ]").expect("should deserialize");
|
|
assert_eq!(result, vec![23, 42, 69]);
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_empty_map() {
|
|
let result: HashMap<String, usize> = from_str("{ }").expect("should deserialize");
|
|
assert!(result.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_integer_map() {
|
|
let result: HashMap<String, usize> = from_str("{ age = 40 + 2; }").expect("should deserialize");
|
|
assert_eq!(result.len(), 1);
|
|
assert_eq!(*result.get("age").unwrap(), 42);
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_struct() {
|
|
#[derive(Debug, Deserialize, PartialEq)]
|
|
struct Person {
|
|
name: String,
|
|
age: usize,
|
|
}
|
|
|
|
let result: Person = from_str(
|
|
r#"
|
|
{
|
|
name = "Slartibartfast";
|
|
age = 42;
|
|
}
|
|
"#,
|
|
)
|
|
.expect("should deserialize");
|
|
|
|
assert_eq!(
|
|
result,
|
|
Person {
|
|
name: "Slartibartfast".into(),
|
|
age: 42,
|
|
}
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_newtype() {
|
|
#[derive(Debug, Deserialize, PartialEq)]
|
|
struct Number(usize);
|
|
|
|
let result: Number = from_str("42").expect("should deserialize");
|
|
assert_eq!(result, Number(42));
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_tuple() {
|
|
let result: (String, usize) = from_str(r#" [ "foo" 42 ] "#).expect("should deserialize");
|
|
assert_eq!(result, ("foo".into(), 42));
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_unit_enum() {
|
|
#[derive(Debug, Deserialize, PartialEq)]
|
|
enum Foo {
|
|
Bar,
|
|
Baz,
|
|
}
|
|
|
|
let result: Foo = from_str("\"Baz\"").expect("should deserialize");
|
|
assert_eq!(result, Foo::Baz);
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_tuple_enum() {
|
|
#[derive(Debug, Deserialize, PartialEq)]
|
|
enum Foo {
|
|
Bar,
|
|
Baz(String, usize),
|
|
}
|
|
|
|
let result: Foo = from_str(
|
|
r#"
|
|
{
|
|
Baz = [ "Slartibartfast" 42 ];
|
|
}
|
|
"#,
|
|
)
|
|
.expect("should deserialize");
|
|
|
|
assert_eq!(result, Foo::Baz("Slartibartfast".into(), 42));
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_struct_enum() {
|
|
#[derive(Debug, Deserialize, PartialEq)]
|
|
enum Foo {
|
|
Bar,
|
|
Baz { name: String, age: usize },
|
|
}
|
|
|
|
let result: Foo = from_str(
|
|
r#"
|
|
{
|
|
Baz.name = "Slartibartfast";
|
|
Baz.age = 42;
|
|
}
|
|
"#,
|
|
)
|
|
.expect("should deserialize");
|
|
|
|
assert_eq!(
|
|
result,
|
|
Foo::Baz {
|
|
name: "Slartibartfast".into(),
|
|
age: 42
|
|
}
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_enum_all() {
|
|
#[derive(Debug, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "snake_case")]
|
|
enum TestEnum {
|
|
Unit,
|
|
Tuple(String, String),
|
|
Struct { name: String, age: usize },
|
|
}
|
|
|
|
let result: Vec<TestEnum> = from_str(
|
|
r#"
|
|
let
|
|
mkTuple = country: drink: { tuple = [ country drink ]; };
|
|
in
|
|
[
|
|
(mkTuple "UK" "cask ale")
|
|
|
|
"unit"
|
|
|
|
{
|
|
struct.name = "Slartibartfast";
|
|
struct.age = 42;
|
|
}
|
|
|
|
(mkTuple "Russia" "квас")
|
|
]
|
|
"#,
|
|
)
|
|
.expect("should deserialize");
|
|
|
|
let expected = vec![
|
|
TestEnum::Tuple("UK".into(), "cask ale".into()),
|
|
TestEnum::Unit,
|
|
TestEnum::Struct {
|
|
name: "Slartibartfast".into(),
|
|
age: 42,
|
|
},
|
|
TestEnum::Tuple("Russia".into(), "квас".into()),
|
|
];
|
|
|
|
assert_eq!(result, expected);
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_with_config() {
|
|
let result: String = from_str_with_config("builtins.testWithConfig", |eval| {
|
|
// Add a literal string builtin that just returns `"ok"`.
|
|
eval.add_src_builtin("testWithConfig", "\"ok\"")
|
|
})
|
|
.expect("should deserialize");
|
|
|
|
assert_eq!(result, "ok");
|
|
}
|
|
|
|
#[builtins]
|
|
mod test_builtins {
|
|
use bstr::ByteSlice;
|
|
use tvix_eval::generators::{Gen, GenCo};
|
|
use tvix_eval::{ErrorKind, NixString, Value};
|
|
|
|
#[builtin("prependHello")]
|
|
pub async fn builtin_prepend_hello(co: GenCo, x: Value) -> Result<Value, ErrorKind> {
|
|
match x {
|
|
Value::String(s) => {
|
|
let new_string = NixString::from(format!("hello {}", s.to_str().unwrap()));
|
|
Ok(Value::from(new_string))
|
|
}
|
|
_ => Err(ErrorKind::TypeError {
|
|
expected: "string",
|
|
actual: "not string",
|
|
}),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_with_extra_builtin() {
|
|
let code = "builtins.prependHello \"world\"";
|
|
|
|
let result: String =
|
|
from_str_with_config(code, |eval| eval.add_builtins(test_builtins::builtins()))
|
|
.expect("should deserialize");
|
|
|
|
assert_eq!(result, "hello world");
|
|
}
|