use super::*;
use crate::docs::naming::func_name;
#[test]
fn test_render_method_signature_python_sync_with_params_and_return() {
let method = make_method(
"get_text",
vec![make_param("page", TypeRef::Primitive(PrimitiveType::U32), false)],
TypeRef::String,
false,
false,
None,
);
let sig = render_method_signature(&method, "Document", Language::Python, TEST_PREFIX);
assert_eq!(sig, "def get_text(self, page: int) -> str");
}
#[test]
fn test_render_method_signature_python_async() {
let method = make_method("process", vec![], TypeRef::String, true, false, None);
let sig = render_method_signature(&method, "Document", Language::Python, TEST_PREFIX);
assert_eq!(sig, "def process(self) -> str");
}
#[test]
fn test_render_method_signature_python_static() {
let method = make_method(
"create",
vec![make_param("name", TypeRef::String, false)],
TypeRef::Named("Document".to_string()),
false,
true,
None,
);
let sig = render_method_signature(&method, "Document", Language::Python, TEST_PREFIX);
assert_eq!(sig, "@staticmethod\ndef create(name: str) -> Document");
}
#[test]
fn test_render_method_signature_python_optional_return() {
let method = make_method(
"find",
vec![make_param("query", TypeRef::String, false)],
TypeRef::Optional(Box::new(TypeRef::String)),
false,
false,
None,
);
let sig = render_method_signature(&method, "Corpus", Language::Python, TEST_PREFIX);
assert_eq!(sig, "def find(self, query: str) -> str | None");
}
#[test]
fn test_render_method_signature_python_with_error_type() {
let method = make_method(
"parse",
vec![make_param("source", TypeRef::String, false)],
TypeRef::Named("Ast".to_string()),
false,
false,
Some("ParseError"),
);
let sig = render_method_signature(&method, "Parser", Language::Python, TEST_PREFIX);
assert_eq!(sig, "def parse(self, source: str) -> Ast");
}
#[test]
fn test_render_method_signature_node_sync_with_params_and_return() {
let method = make_method(
"get_text",
vec![make_param("page", TypeRef::Primitive(PrimitiveType::U32), false)],
TypeRef::String,
false,
false,
None,
);
let sig = render_method_signature(&method, "Document", Language::Node, TEST_PREFIX);
assert_eq!(sig, "getText(page: number): string");
}
#[test]
fn test_render_method_signature_node_async() {
let method = make_method("process", vec![], TypeRef::String, true, false, None);
let sig = render_method_signature(&method, "Document", Language::Node, TEST_PREFIX);
assert_eq!(sig, "process(): Promise<string>");
}
#[test]
fn test_render_method_signature_node_static() {
let method = make_method(
"create",
vec![make_param("name", TypeRef::String, false)],
TypeRef::Named("Document".to_string()),
false,
true,
None,
);
let sig = render_method_signature(&method, "Document", Language::Node, TEST_PREFIX);
assert_eq!(sig, "static create(name: string): Document");
}
#[test]
fn test_render_method_signature_node_optional_return() {
let method = make_method(
"find",
vec![],
TypeRef::Optional(Box::new(TypeRef::String)),
false,
false,
None,
);
let sig = render_method_signature(&method, "Corpus", Language::Node, TEST_PREFIX);
assert_eq!(sig, "find(): string | null");
}
#[test]
fn test_render_method_signature_node_with_error_type() {
let method = make_method(
"parse",
vec![make_param("source", TypeRef::String, false)],
TypeRef::Named("Ast".to_string()),
false,
false,
Some("ParseError"),
);
let sig = render_method_signature(&method, "Parser", Language::Node, TEST_PREFIX);
assert_eq!(sig, "parse(source: string): Ast");
}
#[test]
fn test_render_method_signature_rust_sync_with_params_and_return() {
let method = make_method(
"get_text",
vec![make_param("page", TypeRef::Primitive(PrimitiveType::U32), false)],
TypeRef::String,
false,
false,
None,
);
let sig = render_method_signature(&method, "Document", Language::Rust, TEST_PREFIX);
assert_eq!(sig, "pub fn get_text(&self, page: u32) -> String");
}
#[test]
fn test_render_method_signature_rust_async() {
let method = make_method("fetch", vec![], TypeRef::String, true, false, None);
let sig = render_method_signature(&method, "Client", Language::Rust, TEST_PREFIX);
assert_eq!(sig, "pub async fn fetch(&self) -> String");
}
#[test]
fn test_render_method_signature_rust_static() {
let method = make_method(
"new",
vec![make_ref_param("name", TypeRef::String, false)],
TypeRef::Named("Document".to_string()),
false,
true,
None,
);
let sig = render_method_signature(&method, "Document", Language::Rust, TEST_PREFIX);
assert_eq!(sig, "pub fn new(name: &str) -> Document");
}
#[test]
fn test_render_method_signature_rust_optional_return() {
let method = make_method(
"find",
vec![],
TypeRef::Optional(Box::new(TypeRef::Named("Node".to_string()))),
false,
false,
None,
);
let sig = render_method_signature(&method, "Tree", Language::Rust, TEST_PREFIX);
assert_eq!(sig, "pub fn find(&self) -> Option<Node>");
}
#[test]
fn test_render_method_signature_rust_with_error_type() {
let method = make_method(
"parse",
vec![make_ref_param("source", TypeRef::String, false)],
TypeRef::Named("Ast".to_string()),
false,
false,
Some("ParseError"),
);
let sig = render_method_signature(&method, "Parser", Language::Rust, TEST_PREFIX);
assert_eq!(sig, "pub fn parse(&self, source: &str) -> Result<Ast, ParseError>");
}
#[test]
fn test_render_method_signature_go_sync_with_params_and_return() {
let method = make_method(
"get_text",
vec![make_param("page", TypeRef::Primitive(PrimitiveType::U32), false)],
TypeRef::String,
false,
false,
None,
);
let sig = render_method_signature(&method, "Document", Language::Go, TEST_PREFIX);
assert_eq!(sig, "func (o *Document) GetText(page uint32) string");
}
#[test]
fn test_render_method_signature_go_async() {
let method = make_method("fetch", vec![], TypeRef::String, true, false, None);
let sig = render_method_signature(&method, "Client", Language::Go, TEST_PREFIX);
assert_eq!(sig, "func (o *Client) Fetch() string");
}
#[test]
fn test_render_method_signature_go_optional_return() {
let method = make_method(
"find",
vec![],
TypeRef::Optional(Box::new(TypeRef::String)),
false,
false,
None,
);
let sig = render_method_signature(&method, "Corpus", Language::Go, TEST_PREFIX);
assert_eq!(sig, "func (o *Corpus) Find() *string");
}
#[test]
fn test_render_method_signature_go_with_error_type() {
let method = make_method(
"parse",
vec![make_param("source", TypeRef::String, false)],
TypeRef::Named("Ast".to_string()),
false,
false,
Some("ParseError"),
);
let sig = render_method_signature(&method, "Parser", Language::Go, TEST_PREFIX);
assert_eq!(sig, "func (o *Parser) Parse(source string) (*Ast, error)");
}
#[test]
fn test_render_method_signature_go_static_method_has_no_receiver() {
let method = make_method(
"create",
vec![make_param("name", TypeRef::String, false)],
TypeRef::Named("Document".to_string()),
false,
true,
None,
);
let sig = render_method_signature(&method, "Document", Language::Go, TEST_PREFIX);
let receiver_type = type_name("Document", Language::Go, TEST_PREFIX);
let method_name = func_name("create", Language::Go, TEST_PREFIX);
let expected = format!("func {receiver_type}{method_name}(name string) *Document");
assert_eq!(sig, expected);
assert!(
!sig.contains("(o *"),
"a static Go method is a free function, not a method with a receiver: {sig}"
);
}
#[test]
fn test_render_method_signature_go_static_vs_instance_differ_only_in_receiver_clause() {
let instance_method = make_method(
"get_text",
vec![make_param("page", TypeRef::Primitive(PrimitiveType::U32), false)],
TypeRef::String,
false,
false,
None,
);
let mut static_method = instance_method.clone();
static_method.is_static = true;
let instance_sig = render_method_signature(&instance_method, "Document", Language::Go, TEST_PREFIX);
let static_sig = render_method_signature(&static_method, "Document", Language::Go, TEST_PREFIX);
assert_eq!(instance_sig, "func (o *Document) GetText(page uint32) string");
assert_eq!(static_sig, "func DocumentGetText(page uint32) string");
let call_tail = "GetText(page uint32) string";
assert!(instance_sig.ends_with(call_tail) && static_sig.ends_with(call_tail));
}
#[test]
fn test_render_method_signature_go_error_type_unit_return() {
let method = make_method("save", vec![], TypeRef::Unit, false, false, Some("IoError"));
let sig = render_method_signature(&method, "File", Language::Go, TEST_PREFIX);
assert_eq!(sig, "func (o *File) Save() error");
}
#[test]
fn test_render_method_signature_go_named_return_is_pointer_wrapped_even_when_infallible() {
let method = make_method(
"current",
vec![],
TypeRef::Named("Session".to_string()),
false,
false,
None,
);
let sig = render_method_signature(&method, "Client", Language::Go, TEST_PREFIX);
assert_eq!(sig, "func (o *Client) Current() *Session");
}
#[test]
fn test_render_method_signature_go_non_named_return_is_unaffected_by_pointer_wrapping() {
let method = make_method(
"find",
vec![],
TypeRef::Optional(Box::new(TypeRef::String)),
false,
false,
None,
);
let sig = render_method_signature(&method, "Corpus", Language::Go, TEST_PREFIX);
assert_eq!(sig, "func (o *Corpus) Find() *string");
}
#[test]
fn test_render_method_signature_ruby_sync_with_params() {
let method = make_method(
"get_text",
vec![make_param("page", TypeRef::Primitive(PrimitiveType::U32), false)],
TypeRef::String,
false,
false,
None,
);
let sig = render_method_signature(&method, "Document", Language::Ruby, TEST_PREFIX);
assert_eq!(sig, "def get_text(page)");
}
#[test]
fn test_render_method_signature_ruby_static() {
let method = make_method(
"create",
vec![make_param("name", TypeRef::String, false)],
TypeRef::Named("Document".to_string()),
false,
true,
None,
);
let sig = render_method_signature(&method, "Document", Language::Ruby, TEST_PREFIX);
assert_eq!(sig, "def self.create(name)");
}
#[test]
fn test_render_method_signature_ruby_async() {
let method = make_method("fetch", vec![], TypeRef::String, true, false, None);
let sig = render_method_signature(&method, "Client", Language::Ruby, TEST_PREFIX);
assert_eq!(sig, "def fetch()");
}
#[test]
fn test_render_method_signature_ruby_optional_return() {
let method = make_method(
"find",
vec![],
TypeRef::Optional(Box::new(TypeRef::String)),
false,
false,
None,
);
let sig = render_method_signature(&method, "Corpus", Language::Ruby, TEST_PREFIX);
assert_eq!(sig, "def find()");
}
#[test]
fn test_render_method_signature_ruby_with_error_type() {
let method = make_method("parse", vec![], TypeRef::String, false, false, Some("ParseError"));
let sig = render_method_signature(&method, "Parser", Language::Ruby, TEST_PREFIX);
assert_eq!(sig, "def parse()");
}
#[test]
fn test_render_method_signature_php_sync_with_params_and_return() {
let method = make_method(
"get_text",
vec![make_param("page", TypeRef::Primitive(PrimitiveType::U32), false)],
TypeRef::String,
false,
false,
None,
);
let sig = render_method_signature(&method, "Document", Language::Php, TEST_PREFIX);
assert_eq!(sig, "public function getText(int $page): string");
}
#[test]
fn test_render_method_signature_php_static() {
let method = make_method(
"create",
vec![make_param("name", TypeRef::String, false)],
TypeRef::Named("Document".to_string()),
false,
true,
None,
);
let sig = render_method_signature(&method, "Document", Language::Php, TEST_PREFIX);
assert_eq!(sig, "public static function create(string $name): Document");
}
#[test]
fn test_render_method_signature_php_optional_return() {
let method = make_method(
"find",
vec![],
TypeRef::Optional(Box::new(TypeRef::String)),
false,
false,
None,
);
let sig = render_method_signature(&method, "Corpus", Language::Php, TEST_PREFIX);
assert_eq!(sig, "public function find(): ?string");
}
#[test]
fn test_render_method_signature_php_async() {
let method = make_method("fetch", vec![], TypeRef::String, true, false, None);
let sig = render_method_signature(&method, "Client", Language::Php, TEST_PREFIX);
assert_eq!(sig, "public function fetch(): string");
}
#[test]
fn test_render_method_signature_php_with_error_type() {
let method = make_method("parse", vec![], TypeRef::String, false, false, Some("ParseError"));
let sig = render_method_signature(&method, "Parser", Language::Php, TEST_PREFIX);
assert_eq!(sig, "public function parse(): string");
}
#[test]
fn test_render_method_signature_java_sync_with_params_and_return() {
let method = make_method(
"get_text",
vec![make_param("page", TypeRef::Primitive(PrimitiveType::U32), false)],
TypeRef::String,
false,
false,
None,
);
let sig = render_method_signature(&method, "Document", Language::Java, TEST_PREFIX);
assert_eq!(sig, "public String getText(int page) throws HtmRsException");
}
#[test]
fn test_render_method_signature_java_static() {
let method = make_method(
"create",
vec![make_param("name", TypeRef::String, false)],
TypeRef::Named("Document".to_string()),
false,
true,
None,
);
let sig = render_method_signature(&method, "Document", Language::Java, TEST_PREFIX);
assert_eq!(sig, "public static Document create(String name) throws HtmRsException");
}
#[test]
fn test_render_method_signature_java_optional_return() {
let method = make_method(
"find",
vec![],
TypeRef::Optional(Box::new(TypeRef::String)),
false,
false,
None,
);
let sig = render_method_signature(&method, "Corpus", Language::Java, TEST_PREFIX);
assert_eq!(sig, "public @Nullable String find() throws HtmRsException");
}
#[test]
fn test_render_method_signature_java_async() {
let method = make_method("fetch", vec![], TypeRef::String, true, false, None);
let sig = render_method_signature(&method, "Client", Language::Java, TEST_PREFIX);
assert_eq!(sig, "public String fetch() throws HtmRsException");
}
#[test]
fn test_render_method_signature_java_with_error_type() {
let method = make_method(
"parse",
vec![make_param("source", TypeRef::String, false)],
TypeRef::Named("Ast".to_string()),
false,
false,
Some("ParseError"),
);
let sig = render_method_signature(&method, "Parser", Language::Java, TEST_PREFIX);
assert_eq!(sig, "public Ast parse(String source) throws HtmRsException");
}
#[test]
fn test_render_method_signature_java_clone_has_no_throws() {
let method = make_method(
"clone",
vec![],
TypeRef::Named("Document".to_string()),
false,
false,
None,
);
let sig = render_method_signature(&method, "Document", Language::Java, TEST_PREFIX);
assert_eq!(sig, "public Document clone()");
assert!(
!sig.contains("throws"),
"clone() never declares a checked exception: {sig}"
);
}
#[test]
fn test_render_method_signature_csharp_sync_with_params_and_return() {
let method = make_method(
"get_text",
vec![make_param("page", TypeRef::Primitive(PrimitiveType::U32), false)],
TypeRef::String,
false,
false,
None,
);
let sig = render_method_signature(&method, "Document", Language::Csharp, TEST_PREFIX);
assert_eq!(sig, "public string GetText(uint page)");
}
#[test]
fn test_render_method_signature_csharp_async() {
let method = make_method("fetch", vec![], TypeRef::String, true, false, None);
let sig = render_method_signature(&method, "Client", Language::Csharp, TEST_PREFIX);
assert_eq!(sig, "public async Task<string> FetchAsync()");
}
#[test]
fn test_render_method_signature_csharp_async_already_suffixed() {
let method = make_method("fetch_async", vec![], TypeRef::String, true, false, None);
let sig = render_method_signature(&method, "Client", Language::Csharp, TEST_PREFIX);
assert_eq!(sig, "public async Task<string> FetchAsync()");
}
#[test]
fn test_render_method_signature_csharp_optional_return() {
let method = make_method(
"find",
vec![],
TypeRef::Optional(Box::new(TypeRef::String)),
false,
false,
None,
);
let sig = render_method_signature(&method, "Corpus", Language::Csharp, TEST_PREFIX);
assert_eq!(sig, "public string? Find()");
}
#[test]
fn test_render_method_signature_csharp_with_error_type() {
let method = make_method("parse", vec![], TypeRef::String, false, false, Some("ParseError"));
let sig = render_method_signature(&method, "Parser", Language::Csharp, TEST_PREFIX);
assert_eq!(sig, "public string Parse()");
}
#[test]
fn test_render_method_signature_elixir_sync_with_params() {
let method = make_method(
"get_text",
vec![make_param("page", TypeRef::Primitive(PrimitiveType::U32), false)],
TypeRef::String,
false,
false,
None,
);
let sig = render_method_signature(&method, "Document", Language::Elixir, TEST_PREFIX);
assert_eq!(sig, "def get_text(obj, page)");
}
#[test]
fn test_render_method_signature_elixir_async() {
let method = make_method("fetch", vec![], TypeRef::String, true, false, None);
let sig = render_method_signature(&method, "Client", Language::Elixir, TEST_PREFIX);
assert_eq!(sig, "def fetch(obj)");
}
#[test]
fn test_render_method_signature_elixir_optional_return() {
let method = make_method(
"find",
vec![],
TypeRef::Optional(Box::new(TypeRef::String)),
false,
false,
None,
);
let sig = render_method_signature(&method, "Corpus", Language::Elixir, TEST_PREFIX);
assert_eq!(sig, "def find(obj)");
}
#[test]
fn test_render_method_signature_elixir_with_error_type() {
let method = make_method("parse", vec![], TypeRef::String, false, false, Some("ParseError"));
let sig = render_method_signature(&method, "Parser", Language::Elixir, TEST_PREFIX);
assert_eq!(sig, "def parse(obj)");
}
#[test]
fn test_render_method_signature_elixir_static_method_has_no_receiver() {
let method = make_method(
"create",
vec![make_param("name", TypeRef::String, false)],
TypeRef::Named("Document".to_string()),
false,
true,
None,
);
let sig = render_method_signature(&method, "Document", Language::Elixir, TEST_PREFIX);
assert_eq!(sig, "def create(name)");
assert!(
!sig.contains("obj"),
"a static Elixir function has no struct receiver: {sig}"
);
}
#[test]
fn test_render_method_signature_elixir_static_vs_instance_differ_only_in_receiver() {
let instance_method = make_method(
"get_text",
vec![make_param("page", TypeRef::Primitive(PrimitiveType::U32), false)],
TypeRef::String,
false,
false,
None,
);
let mut static_method = instance_method.clone();
static_method.is_static = true;
let instance_sig = render_method_signature(&instance_method, "Document", Language::Elixir, TEST_PREFIX);
let static_sig = render_method_signature(&static_method, "Document", Language::Elixir, TEST_PREFIX);
assert_eq!(instance_sig, "def get_text(obj, page)");
assert_eq!(static_sig, "def get_text(page)");
}
#[test]
fn test_render_method_signature_r_sync_with_params() {
let method = make_method(
"get_text",
vec![make_param("page", TypeRef::Primitive(PrimitiveType::U32), false)],
TypeRef::String,
false,
false,
None,
);
let sig = render_method_signature(&method, "Document", Language::R, TEST_PREFIX);
assert_eq!(sig, "get_text(page)");
}
#[test]
fn test_render_method_signature_r_async() {
let method = make_method("fetch", vec![], TypeRef::String, true, false, None);
let sig = render_method_signature(&method, "Client", Language::R, TEST_PREFIX);
assert_eq!(sig, "fetch()");
}
#[test]
fn test_render_method_signature_r_optional_return() {
let method = make_method(
"find",
vec![],
TypeRef::Optional(Box::new(TypeRef::String)),
false,
false,
None,
);
let sig = render_method_signature(&method, "Corpus", Language::R, TEST_PREFIX);
assert_eq!(sig, "find()");
}
#[test]
fn test_render_method_signature_r_with_error_type() {
let method = make_method("parse", vec![], TypeRef::String, false, false, Some("ParseError"));
let sig = render_method_signature(&method, "Parser", Language::R, TEST_PREFIX);
assert_eq!(sig, "parse()");
}
#[test]
fn test_render_method_signature_wasm_sync() {
let method = make_method(
"get_text",
vec![make_param("page", TypeRef::Primitive(PrimitiveType::U32), false)],
TypeRef::String,
false,
false,
None,
);
let sig = render_method_signature(&method, "Document", Language::Wasm, TEST_PREFIX);
assert_eq!(sig, "getText(page: number): string");
}
#[test]
fn test_render_method_signature_wasm_static() {
let method = make_method(
"create",
vec![],
TypeRef::Named("Document".to_string()),
false,
true,
None,
);
let sig = render_method_signature(&method, "Document", Language::Wasm, TEST_PREFIX);
assert_eq!(sig, "static create(): Document");
}
#[test]
fn test_render_method_signature_c_non_static_declares_this_receiver() {
let method = make_method(
"convert",
vec![make_param("options", TypeRef::Named("ParseOptions".to_string()), false)],
TypeRef::Named("ConversionResult".to_string()),
false,
false,
None,
);
let sig = render_method_signature(&method, "Converter", Language::C, TEST_PREFIX);
assert_eq!(
sig,
"HTMAlefHandle htm_converter_convert(HTMAlefHandle this, HTMAlefHandle options);"
);
}
#[test]
fn test_render_method_signature_c_static_method_has_no_this_receiver() {
let method = make_method(
"create",
vec![make_param("name", TypeRef::String, false)],
TypeRef::Named("Document".to_string()),
false,
true,
None,
);
let sig = render_method_signature(&method, "Document", Language::C, TEST_PREFIX);
assert_eq!(sig, "HTMAlefHandle htm_document_create(const char* name);");
assert!(
!sig.contains("this"),
"a static method has no instance to receive, so it must not declare `this`: {sig}"
);
}
#[test]
fn test_c_signature_and_example_agree_on_method_symbol() {
let method = make_method(
"convert",
vec![make_param("options", TypeRef::Named("ParseOptions".to_string()), false)],
TypeRef::Named("ConversionResult".to_string()),
false,
false,
None,
);
let expected_symbol = method_name("Converter", &method.name, Language::C, TEST_PREFIX);
assert_eq!(expected_symbol, "htm_converter_convert");
let signature = render_method_signature(&method, "Converter", Language::C, TEST_PREFIX);
assert!(
signature.starts_with(&format!("HTMAlefHandle {expected_symbol}(")),
"signature: {signature}"
);
let example = crate::docs::examples::render_method_example(&method, "Converter", Language::C, TEST_PREFIX);
assert!(
example.contains(&format!("{expected_symbol}(instance")),
"example must call the same symbol the signature declares: {example}"
);
}
#[test]
fn test_c_signature_and_example_agree_on_arity_for_non_static_method() {
let method = make_method(
"convert",
vec![make_param("options", TypeRef::Named("ParseOptions".to_string()), false)],
TypeRef::Named("ConversionResult".to_string()),
false,
false,
None,
);
let name = method_name("Converter", &method.name, Language::C, TEST_PREFIX);
let signature = render_method_signature(&method, "Converter", Language::C, TEST_PREFIX);
let example = crate::docs::examples::render_method_example(&method, "Converter", Language::C, TEST_PREFIX);
let sig_arity = c_paren_items(&signature, &format!("{name}("));
let call_arity = c_paren_items(&example, &format!("{name}("));
assert_eq!(sig_arity, 2, "expected `this` plus one declared param: {signature}");
assert_eq!(
sig_arity, call_arity,
"signature declares {sig_arity} param(s) but the example passes {call_arity} arg(s) -- \
signature: {signature}\nexample: {example}"
);
}
fn c_paren_items(text: &str, marker: &str) -> usize {
let start = text
.find(marker)
.unwrap_or_else(|| panic!("`{marker}` not found in: {text}"))
+ marker.len();
let rest = &text[start..];
let end = rest
.find(')')
.unwrap_or_else(|| panic!("no closing `)` after `{marker}` in: {text}"));
let items = rest[..end].trim();
if items.is_empty() { 0 } else { items.split(',').count() }
}