use sigil_stitch::code_block::CodeBlock;
use sigil_stitch::lang::cpp_lang::CppLang;
use sigil_stitch::spec::annotation_spec::AnnotationSpec;
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::DeclarationContext;
use sigil_stitch::spec::parameter_spec::ParameterSpec;
use sigil_stitch::type_name::TypeName;
use super::golden;
fn emit_fun(fun: &FunSpec) -> CodeBlock {
let lang = CppLang::new();
fun.emit(&lang, DeclarationContext::Member).unwrap()
}
fn emit_field(field: &FieldSpec) -> CodeBlock {
let lang = CppLang::new();
field.emit(&lang, DeclarationContext::Member).unwrap()
}
#[test]
fn test_namespace_wrapping() {
let mut b = CodeBlock::builder();
b.add("int square(int x) {", ());
b.add_line();
b.add("%>", ());
b.add("return x * x;", ());
b.add_line();
b.add("%<", ());
b.add("}", ());
b.add_line();
let block = b.build().unwrap();
let file = FileSpec::builder_with("math.hpp", CppLang::header())
.header(CodeBlock::of("#pragma once", ()).unwrap())
.add_raw("namespace math {\n")
.add_code(block)
.add_raw("\n} // namespace math\n")
.build()
.unwrap();
let output = file.render(80).unwrap();
golden::assert_golden("cpp/namespace_wrapping.cpp", &output);
}
#[test]
fn test_full_header() {
let iostream = TypeName::importable("iostream", "std::cout");
let string_h = TypeName::importable("string", "std::string");
let tb = sigil_stitch::spec::type_spec::TypeSpec::builder(
"Logger",
sigil_stitch::spec::modifiers::TypeKind::Class,
)
.extends(TypeName::primitive("Base"))
.doc("Application logger.");
let mut priv_section = CodeBlock::builder();
priv_section.add("%<", ());
priv_section.add("private:", ());
priv_section.add_line();
priv_section.add("%>", ());
let field = FieldSpec::builder("name_", TypeName::primitive("std::string"))
.build()
.unwrap();
priv_section.add_code(emit_field(&field));
let tb = tb.extra_member(priv_section.build().unwrap());
let mut pub_section = CodeBlock::builder();
pub_section.add_line();
pub_section.add("%<", ());
pub_section.add("public:", ());
pub_section.add_line();
pub_section.add("%>", ());
let ctor_body = CodeBlock::of("name_ = name;", ()).unwrap();
pub_section.add_code(emit_fun(
&FunSpec::builder("Logger")
.add_param(
ParameterSpec::new("name", TypeName::primitive("const std::string&")).unwrap(),
)
.body(ctor_body)
.build()
.unwrap(),
));
pub_section.add_line();
let log_body = CodeBlock::of(
"%T << name_ << \": \" << %T(msg) << std::endl;",
(iostream, string_h),
)
.unwrap();
pub_section.add_code(emit_fun(
&FunSpec::builder("log")
.add_param(ParameterSpec::new("msg", TypeName::primitive("const char*")).unwrap())
.returns(TypeName::primitive("void"))
.body(log_body)
.build()
.unwrap(),
));
pub_section.add_line();
let name_body = CodeBlock::of("return name_;", ()).unwrap();
pub_section.add_code(emit_fun(
&FunSpec::builder("name")
.returns(TypeName::primitive("const std::string&"))
.suffix("const")
.body(name_body)
.build()
.unwrap(),
));
let ts = tb
.extra_member(pub_section.build().unwrap())
.build()
.unwrap();
let import_trigger =
CodeBlock::of("// Uses %T", (TypeName::importable("./base.hpp", "Base"),)).unwrap();
let file = FileSpec::builder_with("logger.hpp", CppLang::header())
.header(CodeBlock::of("#pragma once", ()).unwrap())
.add_code(import_trigger)
.add_type(ts)
.build()
.unwrap();
let output = file.render(80).unwrap();
golden::assert_golden("cpp/full_header.cpp", &output);
}
#[test]
fn test_annotation_attribute() {
let fun = FunSpec::builder("compute")
.annotate(AnnotationSpec::new("nodiscard"))
.returns(TypeName::primitive("int"))
.body(CodeBlock::of("return 42;", ()).unwrap())
.build()
.unwrap();
let rendered = emit_fun(&fun);
let file = FileSpec::builder_with("compute.hpp", CppLang::header())
.add_code(rendered)
.build()
.unwrap();
let output = file.render(80).unwrap();
golden::assert_golden("cpp/annotation_attribute.cpp", &output);
}