use sigil_stitch::code_block::CodeBlock;
use sigil_stitch::lang::javascript::JavaScript;
use sigil_stitch::spec::enum_variant_spec::EnumVariantSpec;
use sigil_stitch::spec::field_spec::FieldSpec;
use sigil_stitch::spec::file_spec::FileSpec;
use sigil_stitch::spec::fun_spec::FunSpec;
use sigil_stitch::spec::modifiers::{TypeKind, Visibility};
use sigil_stitch::spec::parameter_spec::ParameterSpec;
use sigil_stitch::spec::type_spec::TypeSpec;
use sigil_stitch::type_name::TypeName;
use super::golden;
fn param(name: &str) -> ParameterSpec {
ParameterSpec::new(name, TypeName::primitive("")).unwrap()
}
fn field(name: &str) -> FieldSpec {
FieldSpec::builder(name, TypeName::primitive(""))
.build()
.unwrap()
}
#[test]
fn test_class_with_methods() {
let ctor_body = CodeBlock::of("this.count = 0;", ()).unwrap();
let inc_body = CodeBlock::of("this.count++;", ()).unwrap();
let get_body = CodeBlock::of("return this.count;", ()).unwrap();
let ts = TypeSpec::builder("Counter", TypeKind::Class)
.visibility(Visibility::Public)
.doc("A simple counter.")
.add_field(field("count"))
.add_method(
FunSpec::builder("constructor")
.body(ctor_body)
.build()
.unwrap(),
)
.add_method(
FunSpec::builder("increment")
.body(inc_body)
.build()
.unwrap(),
)
.add_method(FunSpec::builder("getCount").body(get_body).build().unwrap())
.build()
.unwrap();
let file = FileSpec::builder_with("counter.js", JavaScript::new())
.add_type(ts)
.build()
.unwrap();
let output = file.render(80).unwrap();
golden::assert_golden("javascript/class_with_methods.js", &output);
}
#[test]
fn test_class_with_constructor() {
let ctor_body = CodeBlock::of("this.name = name;\nthis.email = email;", ()).unwrap();
let ts = TypeSpec::builder("User", TypeKind::Class)
.visibility(Visibility::Public)
.add_field(field("name"))
.add_field(field("email"))
.add_method(
FunSpec::builder("constructor")
.add_param(param("name"))
.add_param(param("email"))
.body(ctor_body)
.build()
.unwrap(),
)
.build()
.unwrap();
let file = FileSpec::builder_with("user.js", JavaScript::new())
.add_type(ts)
.build()
.unwrap();
let output = file.render(80).unwrap();
golden::assert_golden("javascript/class_with_constructor.js", &output);
}
#[test]
fn test_class_extends() {
let animal_import = TypeName::importable("./animal", "Animal");
let ctor_body = CodeBlock::of("super(name);\nthis.breed = breed;", ()).unwrap();
let speak_body = CodeBlock::of("return 'Woof!';", ()).unwrap();
let ts = TypeSpec::builder("Dog", TypeKind::Class)
.visibility(Visibility::Public)
.extends(TypeName::primitive("Animal"))
.add_method(
FunSpec::builder("constructor")
.add_param(param("name"))
.add_param(param("breed"))
.body(ctor_body)
.build()
.unwrap(),
)
.add_method(FunSpec::builder("speak").body(speak_body).build().unwrap())
.build()
.unwrap();
let import_trigger = CodeBlock::of("// Uses %T", (animal_import,)).unwrap();
let file = FileSpec::builder_with("dog.js", JavaScript::new())
.add_code(import_trigger)
.add_type(ts)
.build()
.unwrap();
let output = file.render(80).unwrap();
golden::assert_golden("javascript/class_extends.js", &output);
}
#[test]
fn test_static_method() {
let body = CodeBlock::of("return a + b;", ()).unwrap();
let ts = TypeSpec::builder("MathUtils", TypeKind::Class)
.visibility(Visibility::Public)
.add_method(
FunSpec::builder("add")
.is_static()
.add_param(param("a"))
.add_param(param("b"))
.body(body)
.build()
.unwrap(),
)
.build()
.unwrap();
let file = FileSpec::builder_with("math.js", JavaScript::new())
.add_type(ts)
.build()
.unwrap();
let output = file.render(80).unwrap();
golden::assert_golden("javascript/static_method.js", &output);
}
#[test]
fn test_private_field() {
let ctor_body = CodeBlock::of("this.#balance = initialBalance;", ()).unwrap();
let get_body = CodeBlock::of("return this.#balance;", ()).unwrap();
let ts = TypeSpec::builder("BankAccount", TypeKind::Class)
.visibility(Visibility::Public)
.add_field(field("#balance"))
.add_method(
FunSpec::builder("constructor")
.add_param(param("initialBalance"))
.body(ctor_body)
.build()
.unwrap(),
)
.add_method(
FunSpec::builder("getBalance")
.body(get_body)
.build()
.unwrap(),
)
.build()
.unwrap();
let file = FileSpec::builder_with("account.js", JavaScript::new())
.add_type(ts)
.build()
.unwrap();
let output = file.render(80).unwrap();
golden::assert_golden("javascript/private_field.js", &output);
}
#[test]
fn test_enum() {
let file = FileSpec::builder_with("direction.js", JavaScript::new())
.add_type(
TypeSpec::builder("Direction", TypeKind::Enum)
.visibility(Visibility::Public)
.doc("Cardinal directions.")
.add_variant(
EnumVariantSpec::builder("Up")
.value(CodeBlock::of("'UP'", ()).unwrap())
.build()
.unwrap(),
)
.add_variant(
EnumVariantSpec::builder("Down")
.value(CodeBlock::of("'DOWN'", ()).unwrap())
.build()
.unwrap(),
)
.add_variant(
EnumVariantSpec::builder("Left")
.value(CodeBlock::of("'LEFT'", ()).unwrap())
.build()
.unwrap(),
)
.add_variant(
EnumVariantSpec::builder("Right")
.value(CodeBlock::of("'RIGHT'", ()).unwrap())
.build()
.unwrap(),
)
.build()
.unwrap(),
)
.build()
.unwrap();
let output = file.render(80).unwrap();
golden::assert_golden("javascript/enum.js", &output);
}