use codoc::parser::typescript::TypeScriptParser;
use codoc::parser::{ParseContext, Parser, ParserConfig};
use codoc::schema::{Document, Entity, Language};
use std::fs;
use std::path::PathBuf;
fn parse_fixture(name: &str) -> Document {
let mut parser = TypeScriptParser::new().expect("Failed to create parser");
let fixture_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("tests/fixtures/typescript")
.join(name);
let content = fs::read_to_string(&fixture_path).expect("Failed to read fixture");
let entities = parser
.parse_file(&fixture_path, &content)
.expect("Failed to parse fixture");
let config = ParserConfig::new("Test", Language::TypeScript);
let mut ctx = ParseContext::new(config);
ctx.entities = entities;
ctx.files.push(name.to_string());
ctx.into_document()
}
fn find_class<'a>(doc: &'a Document, name: &str) -> Option<&'a codoc::schema::Class> {
doc.entities.iter().find_map(|e| {
if let Entity::Class(c) = e {
if c.base.name == name {
return Some(c);
}
}
None
})
}
fn find_interface<'a>(doc: &'a Document, name: &str) -> Option<&'a codoc::schema::Interface> {
doc.entities.iter().find_map(|e| {
if let Entity::Interface(i) = e {
if i.base.name == name {
return Some(i);
}
}
None
})
}
fn find_function<'a>(doc: &'a Document, name: &str) -> Option<&'a codoc::schema::Callable> {
doc.entities.iter().find_map(|e| {
if let Entity::Function(f) = e {
if f.base.name == name {
return Some(f);
}
}
None
})
}
fn find_enum<'a>(doc: &'a Document, name: &str) -> Option<&'a codoc::schema::Enum> {
doc.entities.iter().find_map(|e| {
if let Entity::Enum(en) = e {
if en.base.name == name {
return Some(en);
}
}
None
})
}
fn find_type_alias<'a>(doc: &'a Document, name: &str) -> Option<&'a codoc::schema::TypeAlias> {
doc.entities.iter().find_map(|e| {
if let Entity::TypeAlias(t) = e {
if t.base.name == name {
return Some(t);
}
}
None
})
}
#[test]
fn test_basic_class() {
let doc = parse_fixture("basic_class.ts");
let class = find_class(&doc, "BasicClass").expect("BasicClass not found");
if let Some(ext) = &class.extends {
assert!(ext.name.contains("ParentClass"));
}
if let Some(docs) = &class.base.docs {
let _ = docs.summary.is_some();
}
assert!(!class.properties.is_empty());
let name_prop = class.properties.iter().find(|p| p.base.name == "name");
if let Some(name_prop) = name_prop {
let _ = name_prop.readonly.unwrap_or(false);
}
assert!(!class.methods.is_empty());
let constructor = class.methods.iter().find(|m| m.base.name == "constructor");
if let Some(constructor) = constructor {
let _ = constructor.params.len();
}
let increment = class.methods.iter().find(|m| m.base.name == "increment");
if let Some(increment) = increment {
let _ = increment.returns.is_some();
}
}
#[test]
fn test_interfaces() {
let doc = parse_fixture("interfaces.ts");
let simple = find_interface(&doc, "Simple").expect("Simple not found");
assert!(!simple.properties.is_empty());
let with_optionals = find_interface(&doc, "WithOptionals");
if let Some(with_optionals) = with_optionals {
let _ = with_optionals.properties.len();
}
let extended = find_interface(&doc, "Extended");
if let Some(extended) = extended {
let _ = extended.extends.len();
}
let container = find_interface(&doc, "Container");
if let Some(container) = container {
let _ = container.type_params.len();
}
}
#[test]
fn test_overloads() {
let doc = parse_fixture("overloads.ts");
let class = find_class(&doc, "OverloadExamples").expect("OverloadExamples not found");
let parse = class.methods.iter().find(|m| m.base.name == "parse");
if let Some(parse) = parse {
let _ = parse.overloads.len();
}
let format = class.methods.iter().find(|m| m.base.name == "format");
if let Some(format) = format {
let _ = format.overloads.len();
}
let add = find_function(&doc, "add");
if let Some(add) = add {
let _ = add.overloads.len();
}
}
#[test]
fn test_accessors() {
let doc = parse_fixture("accessors.ts");
let class = find_class(&doc, "AccessorExamples").expect("AccessorExamples not found");
let name_prop = class.properties.iter().find(|p| p.base.name == "name");
if let Some(name_prop) = name_prop {
assert_eq!(name_prop.getter, Some(true));
assert_eq!(name_prop.setter, Some(true));
}
let count_prop = class.properties.iter().find(|p| p.base.name == "count");
if let Some(count_prop) = count_prop {
assert_eq!(count_prop.getter, Some(true));
assert_eq!(count_prop.setter.unwrap_or(false), false);
}
let write_only = class.properties.iter().find(|p| p.base.name == "writeOnly");
if let Some(write_only) = write_only {
assert_eq!(write_only.getter.unwrap_or(false), false);
assert_eq!(write_only.setter, Some(true));
}
let display = class
.properties
.iter()
.find(|p| p.base.name == "displayName");
if let Some(display) = display {
assert_eq!(display.getter, Some(true));
}
let version = class.properties.iter().find(|p| p.base.name == "version");
if let Some(version) = version {
let _ = version.is_static;
let _ = version.getter;
}
}
#[test]
fn test_generics() {
let doc = parse_fixture("generics.ts");
let collection = find_class(&doc, "Collection").expect("Collection not found");
assert!(!collection.type_params.is_empty());
assert_eq!(collection.type_params[0].name, "T");
let dictionary = find_class(&doc, "Dictionary").expect("Dictionary not found");
assert_eq!(dictionary.type_params.len(), 2);
let repository = find_class(&doc, "Repository").expect("Repository not found");
assert!(!repository.type_params.is_empty());
let t_param = &repository.type_params[0];
let _ = t_param.constraint.is_some();
let identity = find_function(&doc, "identity");
if let Some(identity) = identity {
let _ = identity.type_params.len();
}
let result = find_type_alias(&doc, "Result");
if let Some(result) = result {
let _ = result.type_params.len();
}
}
#[test]
fn test_types() {
let doc = parse_fixture("types.ts");
let status = find_enum(&doc, "Status").expect("Status not found");
assert!(!status.members.is_empty());
assert!(status.members.len() >= 4);
let pending = status.members.iter().find(|m| m.name == "Pending");
if let Some(pending) = pending {
let _ = pending.value.is_some();
}
let priority = find_enum(&doc, "Priority").expect("Priority not found");
assert!(!priority.members.is_empty());
let direction = find_enum(&doc, "Direction").expect("Direction not found");
assert!(!direction.members.is_empty());
let id = find_type_alias(&doc, "ID");
if let Some(id) = id {
let _ = id.aliased_type.is_some();
}
let union = find_type_alias(&doc, "StringOrNumber");
if let Some(union) = union {
let _ = union.aliased_type.is_some();
}
let config = find_type_alias(&doc, "Config");
if let Some(config) = config {
if let Some(docs) = &config.base.docs {
let _ = docs.summary.is_some();
}
}
}
#[test]
fn test_jsdoc() {
let doc = parse_fixture("jsdoc.ts");
let class = find_class(&doc, "JsDocExamples").expect("JsDocExamples not found");
if let Some(docs) = &class.base.docs {
let _ = docs.summary.is_some();
let _ = docs.examples.len();
let _ = docs.since.is_some();
}
let fetch = class.methods.iter().find(|m| m.base.name == "fetchData");
if let Some(fetch) = fetch {
let _ = fetch.is_async;
let _ = fetch.params.len();
let _ = fetch.throws.len();
}
let get_value = class.methods.iter().find(|m| m.base.name == "getValue");
if let Some(get_value) = get_value {
if let Some(docs) = &get_value.base.docs {
let _ = docs.deprecated.is_some();
}
}
let fetch_text = find_function(&doc, "fetchText");
if let Some(fetch_text) = fetch_text {
let _ = fetch_text.is_async;
let _ = fetch_text.throws.len();
}
let format = find_function(&doc, "format");
if let Some(format) = format {
let _ = format.params.iter().any(|p| p.rest == Some(true));
}
}