✨ feat(tsl-codegen): refine generation and metadata enrichment
This commit is contained in:
@@ -0,0 +1,778 @@
|
||||
import importlib.util
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
SCRIPT = Path(__file__).parents[1] / "scripts" / "enrich_metadata.py"
|
||||
|
||||
|
||||
def load_script():
|
||||
spec = importlib.util.spec_from_file_location("tsl_enrich_metadata", SCRIPT)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
sys.modules[spec.name] = module
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
class SourceCatalogTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.module = load_script()
|
||||
self.temp_dir = tempfile.TemporaryDirectory()
|
||||
self.docs = Path(self.temp_dir.name)
|
||||
|
||||
def tearDown(self):
|
||||
self.temp_dir.cleanup()
|
||||
|
||||
def write_corpus(self, corpus, rows, descriptions):
|
||||
root = self.docs / corpus
|
||||
pages = root / "pages"
|
||||
pages.mkdir(parents=True)
|
||||
manifest = [
|
||||
"id\ttitle\turl\tpath\tsource_bytes\tutf8_bytes\tsha256\tstatus"
|
||||
]
|
||||
for page_id, title in rows:
|
||||
manifest.append(
|
||||
f"{page_id}\t{title}\thttp://example/{page_id}\t"
|
||||
f"pages/{page_id}.html\t1\t1\tsha\tok"
|
||||
)
|
||||
description = descriptions[page_id]
|
||||
(pages / f"{page_id}.html").write_text(
|
||||
"<div id='help_content'><h3>"
|
||||
+ title
|
||||
+ "</h3><div><div class='DescriteTitle'>简述</div></div>"
|
||||
+ f"<div>{description}</div></div>",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(root / "manifest.tsv").write_text(
|
||||
"\n".join(manifest) + "\n", encoding="utf-8"
|
||||
)
|
||||
|
||||
def test_exact_matching_preserves_underscores_and_prefers_scope_corpus(self):
|
||||
self.write_corpus(
|
||||
"tsl_base",
|
||||
[("1", "alpha_test")],
|
||||
{"1": "基础解释器说明"},
|
||||
)
|
||||
self.write_corpus(
|
||||
"net_function",
|
||||
[("2", "alpha_test"), ("3", "alphaTest")],
|
||||
{"2": "NET 说明", "3": "无下划线的另一个函数"},
|
||||
)
|
||||
catalog = self.module.SourceCatalog.from_docs_root(self.docs)
|
||||
|
||||
builtin = self.module.EntryContext(
|
||||
name="alpha_test",
|
||||
signature="alpha_test()",
|
||||
kind="function",
|
||||
scope="builtin",
|
||||
page="builtin/demo.md",
|
||||
summary="原说明",
|
||||
)
|
||||
dotnet = self.module.EntryContext(
|
||||
name="alpha_test",
|
||||
signature="alpha_test()",
|
||||
kind="function",
|
||||
scope="dotnet",
|
||||
page="dotnet/demo.md",
|
||||
summary="原说明",
|
||||
)
|
||||
|
||||
self.assertEqual("tsl_base", catalog.match(builtin)[0].corpus)
|
||||
self.assertEqual("net_function", catalog.match(dotnet)[0].corpus)
|
||||
self.assertNotIn(
|
||||
"alphaTest", {record.title for record in catalog.match(dotnet)}
|
||||
)
|
||||
|
||||
def test_duplicate_titles_remain_visible_for_audit(self):
|
||||
self.write_corpus(
|
||||
"net_function",
|
||||
[("1", "same_name"), ("2", "same_name")],
|
||||
{"1": "说明一", "2": "说明二"},
|
||||
)
|
||||
catalog = self.module.SourceCatalog.from_docs_root(self.docs)
|
||||
entry = self.module.EntryContext(
|
||||
name="same_name",
|
||||
signature="same_name()",
|
||||
kind="function",
|
||||
scope="dotnet",
|
||||
page="dotnet/demo.md",
|
||||
summary="原说明",
|
||||
)
|
||||
|
||||
self.assertEqual(["1", "2"], [item.page_id for item in catalog.match(entry)])
|
||||
|
||||
|
||||
class DescriptionQualityTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.module = load_script()
|
||||
|
||||
def entry(self, **overrides):
|
||||
values = {
|
||||
"name": "profitRatio",
|
||||
"signature": "profitRatio(report_date)",
|
||||
"kind": "function",
|
||||
"scope": "dotnet",
|
||||
"page": "dotnet/financial/profitability.md",
|
||||
"summary": "总资产收益率(%)。",
|
||||
}
|
||||
values.update(overrides)
|
||||
return self.module.EntryContext(**values)
|
||||
|
||||
def test_removes_only_terminal_sentence_punctuation(self):
|
||||
entry = self.entry(summary="总资产收益率(%)。")
|
||||
|
||||
self.assertEqual(
|
||||
"返回总资产收益率(%)",
|
||||
self.module.improve_description(entry, []),
|
||||
)
|
||||
|
||||
def test_preserves_formula_and_identifiers(self):
|
||||
entry = self.entry(
|
||||
summary="总资产报酬率(%)=利润总额/平均资产总额*100。"
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
"计算总资产报酬率(%),公式为利润总额/平均资产总额*100",
|
||||
self.module.improve_description(entry, []),
|
||||
)
|
||||
|
||||
def test_rejects_source_process_prose(self):
|
||||
entry = self.entry(summary="返回指定值")
|
||||
source = self.module.SourceRecord(
|
||||
corpus="net_function",
|
||||
page_id="1",
|
||||
title="profitRatio",
|
||||
page=Path("1.html"),
|
||||
description="Windows 已验证通过,Linux 返回 not found",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
"返回指定值", self.module.improve_description(entry, [source])
|
||||
)
|
||||
|
||||
def test_current_environment_can_be_real_api_semantics(self):
|
||||
self.assertEqual(
|
||||
"获取当前环境时间系统参数",
|
||||
self.module.safe_source_description("获取当前环境时间系统参数。"),
|
||||
)
|
||||
|
||||
def test_property_access_is_stated_explicitly(self):
|
||||
entry = self.entry(
|
||||
name="Host",
|
||||
signature="Host",
|
||||
kind="property",
|
||||
scope="builtin",
|
||||
page="builtin/object/ftp.md",
|
||||
summary="远程服务器地址。",
|
||||
access="read/write",
|
||||
owner="FTP",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
"获取或设置远程服务器地址",
|
||||
self.module.improve_description(entry, []),
|
||||
)
|
||||
|
||||
def test_boolean_property_description_is_idempotent(self):
|
||||
entry = self.entry(
|
||||
name="UseTLS",
|
||||
signature="UseTLS",
|
||||
kind="property",
|
||||
scope="builtin",
|
||||
page="builtin/object/imap.md",
|
||||
summary="是否采用 SSL 连接",
|
||||
access="read/write",
|
||||
owner="IMAP",
|
||||
)
|
||||
|
||||
first = self.module.improve_description(entry, [])
|
||||
repeated = self.module.improve_description(
|
||||
self.module.EntryContext(
|
||||
**{**entry.__dict__, "summary": first}
|
||||
),
|
||||
[],
|
||||
)
|
||||
|
||||
self.assertEqual("控制是否采用 SSL 连接", first)
|
||||
self.assertEqual(first, repeated)
|
||||
|
||||
def test_low_confidence_sentence_is_kept_except_terminal_punctuation(self):
|
||||
entry = self.entry(
|
||||
name="opaqueApi",
|
||||
page="dotnet.md",
|
||||
summary="根据调用上下文处理结果,具体规则取决于输入。",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
"根据调用上下文处理结果,具体规则取决于输入",
|
||||
self.module.improve_description(entry, []),
|
||||
)
|
||||
|
||||
def test_short_description_is_not_replaced_by_ambiguous_source_text(self):
|
||||
entry = self.entry(
|
||||
name="clRed",
|
||||
page="builtin/color.md",
|
||||
summary="红色",
|
||||
)
|
||||
sources = [
|
||||
self.module.SourceRecord(
|
||||
corpus="net_function",
|
||||
page_id="1",
|
||||
title="clRed",
|
||||
page=Path("1.html"),
|
||||
description="定义",
|
||||
)
|
||||
]
|
||||
|
||||
self.assertEqual("红色", self.module.improve_description(entry, sources))
|
||||
|
||||
def test_existing_action_word_is_normalized_without_duplicate_verb(self):
|
||||
getter = self.entry(
|
||||
name="getCValue",
|
||||
page="builtin/color.md",
|
||||
summary="得到颜色的 CMYK 模式 C 值。",
|
||||
)
|
||||
writer = self.entry(
|
||||
name="write",
|
||||
page="builtin/cgi.md",
|
||||
summary="输出字符串。",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
"获取颜色的 CMYK 模式 C 值",
|
||||
self.module.improve_description(getter, []),
|
||||
)
|
||||
self.assertEqual("输出字符串", self.module.improve_description(writer, []))
|
||||
|
||||
def test_equation_inside_algorithm_sentence_is_not_rewritten_as_formula(self):
|
||||
entry = self.entry(
|
||||
name="se_Gauss",
|
||||
page="builtin/optimization.md",
|
||||
summary="用高斯消去法求解线性方程组 AX = B",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
"用高斯消去法求解线性方程组 AX = B",
|
||||
self.module.improve_description(entry, []),
|
||||
)
|
||||
|
||||
def test_builtin_class_gets_a_purpose_description(self):
|
||||
entry = self.entry(
|
||||
name="TStringList",
|
||||
signature="TStringList",
|
||||
kind="class",
|
||||
scope="builtin",
|
||||
page="builtin/object/tstringlist.md",
|
||||
summary="TStringList 内置对象",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
"提供字符串集合存储、查找、排序和名称值管理能力的内置对象",
|
||||
self.module.improve_description(entry, []),
|
||||
)
|
||||
|
||||
def test_long_property_explanation_is_not_wrapped_in_access_boilerplate(self):
|
||||
entry = self.entry(
|
||||
name="CommaTextW",
|
||||
signature="CommaTextW",
|
||||
kind="property",
|
||||
scope="builtin",
|
||||
page="builtin/object/tstringlist.md",
|
||||
summary=(
|
||||
"功能同 CommaText,区别是在读取时返回宽字节字符串,"
|
||||
"而 CommaText 返回多字节字符串"
|
||||
),
|
||||
access="read/write",
|
||||
owner="TStringList",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
entry.summary, self.module.improve_description(entry, [])
|
||||
)
|
||||
|
||||
def test_short_read_and_load_phrases_are_normalized(self):
|
||||
read_entry = self.entry(
|
||||
name="read",
|
||||
page="builtin/object/tstream.md",
|
||||
summary="读出内容",
|
||||
)
|
||||
load_entry = self.entry(
|
||||
name="loadFromFile",
|
||||
page="builtin/object/tstringlist.md",
|
||||
summary="从指定的文件中装载内容",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
"读取内容", self.module.improve_description(read_entry, [])
|
||||
)
|
||||
self.assertEqual(
|
||||
"从指定的文件中加载内容",
|
||||
self.module.improve_description(load_entry, []),
|
||||
)
|
||||
|
||||
def test_embedded_read_out_is_normalized_without_duplicate_prefix(self):
|
||||
entry = self.entry(
|
||||
name="readExcelSheets",
|
||||
page="dotnet.md",
|
||||
summary="从Excel文件中读出Sheets列表。",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
"从Excel文件中读取Sheets列表",
|
||||
self.module.improve_description(entry, []),
|
||||
)
|
||||
|
||||
def test_existing_decomposition_verb_is_not_prefixed(self):
|
||||
entry = self.entry(
|
||||
name="decodeGraphGroup",
|
||||
page="builtin/graph.md",
|
||||
summary="分解图形组合并写入输出参数",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
entry.summary, self.module.improve_description(entry, [])
|
||||
)
|
||||
|
||||
def test_comparison_expression_is_not_rewritten_as_formula(self):
|
||||
entry = self.entry(
|
||||
name="stockStepAmount",
|
||||
page="dotnet/financial/stock-capital-flow.md",
|
||||
summary="分档区间 V1<=Value<V2 的成交金额",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
entry.summary, self.module.improve_description(entry, [])
|
||||
)
|
||||
|
||||
def test_financial_action_sentence_is_not_prefixed_with_return(self):
|
||||
for summary in (
|
||||
"提取股票的财务比率,与系统证券相关",
|
||||
"根据报告期获取财务指标",
|
||||
"将日线数据转换为周线数据",
|
||||
"统计指定报告期的基金数量",
|
||||
"生成指定区间的分析结果",
|
||||
):
|
||||
with self.subTest(summary=summary):
|
||||
entry = self.entry(
|
||||
name="annualRatio",
|
||||
page="dotnet/financial/financial-analysis.md",
|
||||
summary=summary,
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
entry.summary, self.module.improve_description(entry, [])
|
||||
)
|
||||
|
||||
def test_financial_action_clauses_are_not_prefixed_with_return(self):
|
||||
for summary in (
|
||||
"用于生成投资组合结果名称",
|
||||
"如果存在对应记录则返回证券代码",
|
||||
"对矩阵进行正交处理",
|
||||
"从净值表中获取基金列表",
|
||||
"由交易价格倒推出隐含波动率",
|
||||
"按照周期读取数据",
|
||||
"与系统参数证券和日期相关",
|
||||
):
|
||||
with self.subTest(summary=summary):
|
||||
entry = self.entry(
|
||||
name="financialHelper",
|
||||
page="dotnet/financial/financial-analysis.md",
|
||||
summary=summary,
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
entry.summary, self.module.improve_description(entry, [])
|
||||
)
|
||||
|
||||
def test_financial_boolean_description_uses_judgment_wording(self):
|
||||
entry = self.entry(
|
||||
name="isBankBond",
|
||||
page="dotnet/financial/bond-basic-info.md",
|
||||
summary="是否银行间债券。如果是,返回1,否则返回0",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
"判断是否银行间债券。如果是,返回1,否则返回0",
|
||||
self.module.improve_description(entry, []),
|
||||
)
|
||||
|
||||
def test_function_boilerplate_is_removed_from_action_description(self):
|
||||
entry = self.entry(
|
||||
name="cb_ytm",
|
||||
page="dotnet/financial/convertible-bond.md",
|
||||
summary="该函数采用牛顿迭代法获取可转债的到期收益率",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
"采用牛顿迭代法获取可转债的到期收益率",
|
||||
self.module.improve_description(entry, []),
|
||||
)
|
||||
|
||||
def test_financial_numbered_explanation_is_not_prefixed_with_return(self):
|
||||
entry = self.entry(
|
||||
name="financialMode",
|
||||
page="dotnet/financial/financial-analysis.md",
|
||||
summary="1 表示合并报表,2 表示母公司报表",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
entry.summary, self.module.improve_description(entry, [])
|
||||
)
|
||||
|
||||
def test_related_data_placeholder_is_made_explicit(self):
|
||||
entry = self.entry(
|
||||
name="cb_downPeriodConversionPeriod",
|
||||
page="dotnet/financial/convertible-bond.md",
|
||||
summary="CB_DownPeriodConversionPeriod 相关函数",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
"返回 CB_DownPeriodConversionPeriod 对应的数据",
|
||||
self.module.improve_description(entry, []),
|
||||
)
|
||||
|
||||
def test_reviewed_generic_descriptions_use_precise_purpose_text(self):
|
||||
cases = (
|
||||
(
|
||||
"sf_Normal",
|
||||
"统计分布相关函数。",
|
||||
"计算正态分布函数值",
|
||||
),
|
||||
(
|
||||
"readFile",
|
||||
"文件访问函数相关函数。",
|
||||
"读取本地文件中的数据",
|
||||
),
|
||||
(
|
||||
"unicodeEsc2",
|
||||
"多语言支持函数相关函数。",
|
||||
"将字符串转换为 \\uxxxx 形式的 Unicode 编码串",
|
||||
),
|
||||
)
|
||||
for name, summary, expected in cases:
|
||||
with self.subTest(name=name):
|
||||
entry = self.entry(name=name, page="dotnet.md", summary=summary)
|
||||
self.assertEqual(
|
||||
expected, self.module.improve_description(entry, [])
|
||||
)
|
||||
|
||||
def test_reviewed_awkward_descriptions_are_rewritten_directly(self):
|
||||
cases = (
|
||||
(
|
||||
"encodeGraph",
|
||||
"返回根据指定的类型、名称、数据以及属性数组生成的图形。",
|
||||
"根据指定的类型、名称、数据和属性数组生成图形并返回",
|
||||
),
|
||||
(
|
||||
"dupeString",
|
||||
"返回将指定的字符串AText重复ACount次后的字符串",
|
||||
"将字符串 AText 重复 ACount 次并返回结果",
|
||||
),
|
||||
(
|
||||
"stockpjcj",
|
||||
"返回:区间平均成交,区间成交金额/区间成交量",
|
||||
"返回区间平均成交价,计算公式为区间成交金额 / 区间成交量",
|
||||
),
|
||||
)
|
||||
for name, summary, expected in cases:
|
||||
with self.subTest(name=name):
|
||||
entry = self.entry(
|
||||
name=name, page="builtin/string.md", summary=summary
|
||||
)
|
||||
self.assertEqual(
|
||||
expected, self.module.improve_description(entry, [])
|
||||
)
|
||||
|
||||
|
||||
class TagDerivationTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.module = load_script()
|
||||
|
||||
def test_array_deduplication_gets_controlled_chinese_and_english_aliases(self):
|
||||
entry = self.module.EntryContext(
|
||||
name="arrDropDuplicate",
|
||||
signature="arrDropDuplicate(data)",
|
||||
kind="function",
|
||||
scope="builtin",
|
||||
page="builtin/array.md",
|
||||
summary="删除数组中的重复元素",
|
||||
)
|
||||
page = self.module.PageContext(
|
||||
title="Builtin / 数组", path="builtin/array.md"
|
||||
)
|
||||
|
||||
tags = self.module.derive_tags(entry, page)
|
||||
|
||||
self.assertTrue(
|
||||
{"数组", "列表", "去重", "删除重复", "array", "deduplicate"}
|
||||
<= set(tags)
|
||||
)
|
||||
self.assertLessEqual(len(tags), 12)
|
||||
self.assertNotIn("函数", tags)
|
||||
self.assertNotIn("builtin", tags)
|
||||
|
||||
def test_file_digest_gets_digest_and_hash_aliases(self):
|
||||
entry = self.module.EntryContext(
|
||||
name="getMsgDigest",
|
||||
signature="getMsgDigest(s, mode)",
|
||||
kind="function",
|
||||
scope="builtin",
|
||||
page="builtin/string.md",
|
||||
summary="计算字符串摘要,支持 CRC32、MD5、SHA 和 SM3",
|
||||
)
|
||||
page = self.module.PageContext(
|
||||
title="Builtin / 字符串", path="builtin/string.md"
|
||||
)
|
||||
|
||||
tags = self.module.derive_tags(entry, page)
|
||||
|
||||
self.assertTrue(
|
||||
{"字符串", "摘要", "哈希", "散列", "digest", "hash"}
|
||||
<= set(tags)
|
||||
)
|
||||
|
||||
def test_existing_tags_are_preserved_first_and_output_is_idempotent(self):
|
||||
entry = self.module.EntryContext(
|
||||
name="readFile",
|
||||
signature="readFile(alias, file_name)",
|
||||
kind="function",
|
||||
scope="builtin",
|
||||
page="builtin/file.md",
|
||||
summary="读取文件内容",
|
||||
tags=("自定义", "读取"),
|
||||
)
|
||||
page = self.module.PageContext(
|
||||
title="Builtin / 文件", path="builtin/file.md"
|
||||
)
|
||||
|
||||
first = self.module.derive_tags(entry, page)
|
||||
second = self.module.derive_tags(
|
||||
self.module.EntryContext(**{**entry.__dict__, "tags": tuple(first)}),
|
||||
page,
|
||||
)
|
||||
|
||||
self.assertEqual(["自定义", "读取"], first[:2])
|
||||
self.assertEqual(first, second)
|
||||
|
||||
def test_substrings_do_not_create_digest_or_com_tags(self):
|
||||
reshape = self.module.EntryContext(
|
||||
name="reshape",
|
||||
signature="reshape(data, shape)",
|
||||
kind="function",
|
||||
scope="builtin",
|
||||
page="builtin/array.md",
|
||||
summary="重构数组形状",
|
||||
)
|
||||
uncompress = self.module.EntryContext(
|
||||
name="uniuncompress",
|
||||
signature="uniuncompress(data, type)",
|
||||
kind="function",
|
||||
scope="builtin",
|
||||
page="builtin/string.md",
|
||||
summary="统一解压缩数据",
|
||||
)
|
||||
|
||||
reshape_tags = self.module.derive_tags(
|
||||
reshape,
|
||||
self.module.PageContext("Builtin / 数组", reshape.page),
|
||||
)
|
||||
uncompress_tags = self.module.derive_tags(
|
||||
uncompress,
|
||||
self.module.PageContext("Builtin / 字符串", uncompress.page),
|
||||
)
|
||||
|
||||
self.assertNotIn("摘要", reshape_tags)
|
||||
self.assertNotIn("hash", reshape_tags)
|
||||
self.assertNotIn("COM", uncompress_tags)
|
||||
self.assertNotIn("OLE", uncompress_tags)
|
||||
|
||||
def test_runtime_and_character_names_do_not_create_time_or_graph_tags(self):
|
||||
random_entry = self.module.EntryContext(
|
||||
name="randomfrom",
|
||||
signature="randomfrom(values)",
|
||||
kind="function",
|
||||
scope="builtin",
|
||||
page="builtin/runtime.md",
|
||||
summary="返回随机数组元素",
|
||||
)
|
||||
char_entry = self.module.EntryContext(
|
||||
name="charToByteLen",
|
||||
signature="charToByteLen(s, max_len)",
|
||||
kind="function",
|
||||
scope="builtin",
|
||||
page="builtin/string.md",
|
||||
summary="计算字符串占用的字节数",
|
||||
)
|
||||
|
||||
random_tags = self.module.derive_tags(
|
||||
random_entry,
|
||||
self.module.PageContext("Builtin / 运行时", random_entry.page),
|
||||
)
|
||||
char_tags = self.module.derive_tags(
|
||||
char_entry,
|
||||
self.module.PageContext("Builtin / 字符串", char_entry.page),
|
||||
)
|
||||
|
||||
self.assertNotIn("日期时间", random_tags)
|
||||
self.assertNotIn("图形", char_tags)
|
||||
|
||||
def test_parameter_name_does_not_create_unrelated_time_domain(self):
|
||||
entry = self.module.EntryContext(
|
||||
name="futureValue",
|
||||
signature=(
|
||||
"futureValue(rate, n_periods, payment, present_value, payment_time)"
|
||||
),
|
||||
kind="function",
|
||||
scope="builtin",
|
||||
page="builtin/numeric.md",
|
||||
summary="返回一项投资的未来值",
|
||||
)
|
||||
tags = self.module.derive_tags(
|
||||
entry,
|
||||
self.module.PageContext("Builtin / 数值计算", entry.page),
|
||||
)
|
||||
|
||||
self.assertNotIn("日期时间", tags)
|
||||
|
||||
def test_hash_index_is_not_tagged_as_cryptographic_digest(self):
|
||||
entry = self.module.EntryContext(
|
||||
name="THashedStringList",
|
||||
signature="THashedStringList",
|
||||
kind="class",
|
||||
scope="builtin",
|
||||
page="builtin/object/thashedstringlist.md",
|
||||
summary="使用哈希索引加速查找的字符串列表内置对象",
|
||||
)
|
||||
tags = self.module.derive_tags(
|
||||
entry,
|
||||
self.module.PageContext(
|
||||
"Object / THashedStringList 字符串列表", entry.page
|
||||
),
|
||||
)
|
||||
|
||||
self.assertIn("哈希索引", tags)
|
||||
self.assertIn("hash", tags)
|
||||
self.assertNotIn("摘要", tags)
|
||||
self.assertNotIn("digest", tags)
|
||||
|
||||
def test_business_statistics_verb_does_not_add_probability_domain(self):
|
||||
entry = self.module.EntryContext(
|
||||
name="fundCount",
|
||||
signature="fundCount(report_date)",
|
||||
kind="function",
|
||||
scope="dotnet",
|
||||
page="dotnet/financial/fund-holdings.md",
|
||||
summary="统计指定报告期的基金数量",
|
||||
)
|
||||
tags = self.module.derive_tags(
|
||||
entry,
|
||||
self.module.PageContext("金融 / 基金 / 持仓", entry.page),
|
||||
)
|
||||
|
||||
self.assertNotIn("概率", tags)
|
||||
self.assertNotIn("statistics", tags)
|
||||
self.assertNotIn("统计指定报告期的基金数量", tags)
|
||||
self.assertNotIn("证券", tags)
|
||||
|
||||
def test_taxonomy_tags_remove_generic_suffixes(self):
|
||||
entry = self.module.EntryContext(
|
||||
name="weightedMedian",
|
||||
signature="weightedMedian(data, weights)",
|
||||
kind="function",
|
||||
scope="dotnet",
|
||||
page="dotnet/financial/weighted-statistics.md",
|
||||
summary="计算加权中位数",
|
||||
)
|
||||
tags = self.module.derive_tags(
|
||||
entry,
|
||||
self.module.PageContext(
|
||||
"基础算法常见加权统计量及其实现 / 时间相关函数",
|
||||
entry.page,
|
||||
),
|
||||
)
|
||||
|
||||
self.assertIn("基础算法常见加权统计量", tags)
|
||||
self.assertIn("时间", tags)
|
||||
self.assertNotIn("基础算法常见加权统计量及其实现", tags)
|
||||
self.assertNotIn("时间相关函数", tags)
|
||||
|
||||
def test_taxonomy_tags_drop_parenthetical_explanations_and_punctuation(self):
|
||||
entry = self.module.EntryContext(
|
||||
name="close",
|
||||
signature="close()",
|
||||
kind="function",
|
||||
scope="dotnet",
|
||||
page="dotnet/datawarehouse/after_market.md",
|
||||
summary="收盘价,与系统参数股票、时间、周期和复权相关",
|
||||
)
|
||||
tags = self.module.derive_tags(
|
||||
entry,
|
||||
self.module.PageContext(
|
||||
"数据仓库 / 盘后相关(在当日可用于盘中)", entry.page
|
||||
),
|
||||
)
|
||||
|
||||
self.assertIn("数据仓库", tags)
|
||||
self.assertIn("盘后", tags)
|
||||
self.assertNotIn("(", tags)
|
||||
self.assertNotIn(")", tags)
|
||||
self.assertNotIn("盘后相关在当日可用于盘中", tags)
|
||||
self.assertNotIn("关闭", tags)
|
||||
self.assertNotIn("close", tags)
|
||||
|
||||
def test_name_intent_does_not_override_an_explicit_action_clause(self):
|
||||
entry = self.module.EntryContext(
|
||||
name="openEndFundFilterByFundIndex",
|
||||
signature="openEndFundFilterByFundIndex(fund_inds)",
|
||||
kind="function",
|
||||
scope="dotnet",
|
||||
page="dotnet/financial/fund-pool.md",
|
||||
summary="根据基金指数获取成分基金,并对基金进行筛选",
|
||||
)
|
||||
tags = self.module.derive_tags(
|
||||
entry,
|
||||
self.module.PageContext("金融 / 基金 / 基金池", entry.page),
|
||||
)
|
||||
|
||||
self.assertNotIn("打开", tags)
|
||||
self.assertNotIn("open", tags)
|
||||
|
||||
|
||||
class MarkdownEnrichmentTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.module = load_script()
|
||||
|
||||
def test_inserts_tags_after_description_without_touching_code(self):
|
||||
text = (
|
||||
"# Builtin / 数组\n\n"
|
||||
"## `arrDropDuplicate(data)`\n\n"
|
||||
"声明:function\n\n"
|
||||
"删除数组中的重复元素。\n\n"
|
||||
"| 参数 | 类型 | 说明 |\n"
|
||||
"| --- | --- | --- |\n"
|
||||
"| `data` | array | 输入数组 |\n\n"
|
||||
"返回:array\n\n"
|
||||
"### 示例\n\n"
|
||||
"```tsl\nreturn arrDropDuplicate(array(1, 1));\n```\n"
|
||||
)
|
||||
|
||||
result, audit = self.module.enrich_markdown(
|
||||
text, "builtin/array.md", self.module.SourceCatalog.empty()
|
||||
)
|
||||
repeated, repeated_audit = self.module.enrich_markdown(
|
||||
result, "builtin/array.md", self.module.SourceCatalog.empty()
|
||||
)
|
||||
|
||||
self.assertIn("删除数组中的重复元素\n\n<!-- tags:", result)
|
||||
self.assertIn("return arrDropDuplicate(array(1, 1));", result)
|
||||
self.assertEqual(result, repeated)
|
||||
self.assertEqual(1, audit.changed_descriptions)
|
||||
self.assertEqual(1, audit.changed_tags)
|
||||
self.assertEqual(0, repeated_audit.changed_descriptions)
|
||||
self.assertEqual(0, repeated_audit.changed_tags)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user