mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-08-08 04:30:19 +03:00
test(8 навыков): байтовые проверки канона там, где их не было (#57)
Из ~46 навыков-эмиттеров XML восемь не имели ни одной проверки `preserves`: form-edit, form-remove, meta-remove, skd-edit, template-remove, xdto-edit, support-edit, cfe-patch-method. Шесть из них правились в предыдущем коммите, и канон у них держался на том, что правка была механической, а не на проверке. Ожидания писались ПО КАНОНУ, а не по текущему поведению — и это сразу вскрыло три дефекта: 1. form-remove очищал слот формы через InnerText="" / text="" — получалась пустая пара <DefaultObjectForm></DefaultObjectForm>. Платформа пустых пар не пишет (0 на 476 942 XML). Теперь IsEmpty / text=None. 2. Опустевший <ChildObjects> оставался парой, разнесённой по строкам, — в PS-порту form-remove и template-remove. Корпус: 1394 самозакрывающихся <ChildObjects/> на acc+erp, пустых пар 0 в обеих формах. 3. template-add писал пустой макет парой <SpreadsheetDocument></...>. Во всей выгрузке acc_8.3.27 (65 040 XML) многострочных пустых пар нет ни для одного тега. Заодно усилена сама проверка noEmptyPairs: она ловила только СМЕЖНЫЕ теги, поэтому дефект №2 проходил мимо неё. Добавлен вариант с переводом строки внутри; дискриминатором служит сам перевод строки — значащий пробельный текст-узел (<xr:FillValue xsi:type="xs:string"> </xr:FillValue>) его не содержит и под проверку не попадает. support-edit покрыт частично (BOM у ParentConfigurations.bin — проверено, что платформа пишет его с BOM во всех трёх выгрузках), cfe-patch-method — BOM+EOL у .bsl: хвостовой перевод строки у модулей неканоничен (1235 с ним, 766 без), поэтому не утверждается. Регресс: 647/647 ps1, 644/647 py (3 skipped). Эталоны переснятые: три места, каждое — ровно ожидаемая пара строк. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a3f2a18dbf
commit
a7406d0982
@@ -1,4 +1,4 @@
|
|||||||
# form-remove v1.7 — Remove form from 1C object
|
# form-remove v1.8 — Remove form from 1C object
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -64,6 +64,10 @@ foreach ($node in $formNodes) {
|
|||||||
$parent.RemoveChild($prev) | Out-Null
|
$parent.RemoveChild($prev) | Out-Null
|
||||||
}
|
}
|
||||||
$parent.RemoveChild($node) | Out-Null
|
$parent.RemoveChild($node) | Out-Null
|
||||||
|
# Опустевший контейнер: остаётся отступ-whitespace, и XmlWriter пишет пару
|
||||||
|
# <ChildObjects>\n\t\t</ChildObjects>. Платформа пишет только <ChildObjects/>
|
||||||
|
# (1394 самозакрывающихся на acc+erp, пустых пар ни в одной форме — 0).
|
||||||
|
if ($parent.SelectNodes("*").Count -eq 0) { $parent.IsEmpty = $true }
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,7 +78,9 @@ foreach ($node in $formNodes) {
|
|||||||
$formRefRe = "Form\.$([regex]::Escape($FormName))$"
|
$formRefRe = "Form\.$([regex]::Escape($FormName))$"
|
||||||
foreach ($node in $xmlDoc.SelectNodes("//md:*", $nsMgr)) {
|
foreach ($node in $xmlDoc.SelectNodes("//md:*", $nsMgr)) {
|
||||||
if ($node.LocalName -like "*Form" -and $node.InnerText -and $node.InnerText -match $formRefRe) {
|
if ($node.LocalName -like "*Form" -and $node.InnerText -and $node.InnerText -match $formRefRe) {
|
||||||
$node.InnerText = ""
|
# IsEmpty, а не InnerText="": пустая строка сериализуется парой <Tag></Tag>, а
|
||||||
|
# Конфигуратор пустых пар не пишет (0 на 476 942 XML корпуса) — нужен <Tag/>.
|
||||||
|
$node.IsEmpty = $true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# form-remove v1.7 — Remove form from 1C object
|
# form-remove v1.8 — Remove form from 1C object
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -120,6 +120,10 @@ def main():
|
|||||||
if parent.text and parent.text.strip() == "":
|
if parent.text and parent.text.strip() == "":
|
||||||
parent.text = ""
|
parent.text = ""
|
||||||
parent.remove(node)
|
parent.remove(node)
|
||||||
|
# Опустевший контейнер: text="" сериализуется парой <ChildObjects></ChildObjects>,
|
||||||
|
# а нужен <ChildObjects/> — PS-порт через DOM даёт именно его.
|
||||||
|
if len(parent) == 0 and not (parent.text or "").strip():
|
||||||
|
parent.text = None
|
||||||
break
|
break
|
||||||
|
|
||||||
# Clear any Default*/Auxiliary* form slot that pointed to the removed form
|
# Clear any Default*/Auxiliary* form slot that pointed to the removed form
|
||||||
@@ -130,7 +134,9 @@ def main():
|
|||||||
if not isinstance(el.tag, str):
|
if not isinstance(el.tag, str):
|
||||||
continue
|
continue
|
||||||
if etree.QName(el).localname.endswith("Form") and el.text and ref_re.search(el.text):
|
if etree.QName(el).localname.endswith("Form") and el.text and ref_re.search(el.text):
|
||||||
el.text = ""
|
# text=None, а не "": пустая строка сериализуется парой <Tag></Tag>, а
|
||||||
|
# Конфигуратор пустых пар не пишет (0 на 476 942 XML корпуса) — нужен <Tag/>.
|
||||||
|
el.text = None
|
||||||
|
|
||||||
# Save with BOM
|
# Save with BOM
|
||||||
save_xml_with_bom(tree, root_xml_full)
|
save_xml_with_bom(tree, root_xml_full)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# template-add v1.17 — Add template to 1C object
|
# template-add v1.18 — Add template to 1C object
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -296,10 +296,12 @@ switch ($TemplateType) {
|
|||||||
[System.IO.File]::WriteAllText($templateFilePath, "", $encBom)
|
[System.IO.File]::WriteAllText($templateFilePath, "", $encBom)
|
||||||
}
|
}
|
||||||
"SpreadsheetDocument" {
|
"SpreadsheetDocument" {
|
||||||
|
# Пустой макет — самозакрывающимся корнем: пустых пар платформа не пишет
|
||||||
|
# ни в одной форме (0 на 65 040 XML выгрузки acc_8.3.27, включая разнесённые
|
||||||
|
# по строкам). Для XML `<A/>` и `<A></A>` тождественны по спецификации.
|
||||||
$content = @"
|
$content = @"
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<SpreadsheetDocument xmlns="http://v8.1c.ru/spreadsheet/document" xmlns:ss="http://v8.1c.ru/spreadsheet/document" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
<SpreadsheetDocument xmlns="http://v8.1c.ru/spreadsheet/document" xmlns:ss="http://v8.1c.ru/spreadsheet/document" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
|
||||||
</SpreadsheetDocument>
|
|
||||||
"@
|
"@
|
||||||
Write-XmlFile $templateFilePath $content $encBom
|
Write-XmlFile $templateFilePath $content $encBom
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# template-add v1.17 — Add template to 1C object
|
# template-add v1.18 — Add template to 1C object
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -418,13 +418,15 @@ def main():
|
|||||||
write_text_with_bom(template_file_path, "")
|
write_text_with_bom(template_file_path, "")
|
||||||
|
|
||||||
elif template_type == "SpreadsheetDocument":
|
elif template_type == "SpreadsheetDocument":
|
||||||
|
# Пустой макет — самозакрывающимся корнем: пустых пар платформа не пишет
|
||||||
|
# ни в одной форме (0 на 65 040 XML выгрузки acc_8.3.27, включая разнесённые
|
||||||
|
# по строкам). Для XML `<A/>` и `<A></A>` тождественны по спецификации.
|
||||||
content = (
|
content = (
|
||||||
'<?xml version="1.0" encoding="UTF-8"?>\n'
|
'<?xml version="1.0" encoding="UTF-8"?>\n'
|
||||||
'<SpreadsheetDocument xmlns="http://v8.1c.ru/spreadsheet/document"'
|
'<SpreadsheetDocument xmlns="http://v8.1c.ru/spreadsheet/document"'
|
||||||
' xmlns:ss="http://v8.1c.ru/spreadsheet/document"'
|
' xmlns:ss="http://v8.1c.ru/spreadsheet/document"'
|
||||||
' xmlns:v8="http://v8.1c.ru/8.1/data/core"'
|
' xmlns:v8="http://v8.1c.ru/8.1/data/core"'
|
||||||
' xmlns:xs="http://www.w3.org/2001/XMLSchema">\n'
|
' xmlns:xs="http://www.w3.org/2001/XMLSchema"/>'
|
||||||
'</SpreadsheetDocument>'
|
|
||||||
)
|
)
|
||||||
write_xml_file(template_file_path, content)
|
write_xml_file(template_file_path, content)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# template-remove v1.6 — Remove template from 1C object
|
# template-remove v1.7 — Remove template from 1C object
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -64,6 +64,10 @@ foreach ($node in $templateNodes) {
|
|||||||
$parent.RemoveChild($prev) | Out-Null
|
$parent.RemoveChild($prev) | Out-Null
|
||||||
}
|
}
|
||||||
$parent.RemoveChild($node) | Out-Null
|
$parent.RemoveChild($node) | Out-Null
|
||||||
|
# Опустевший контейнер: остаётся отступ-whitespace, и XmlWriter пишет пару
|
||||||
|
# <ChildObjects>\n\t\t</ChildObjects>. Платформа пишет только <ChildObjects/>
|
||||||
|
# (1394 самозакрывающихся на acc+erp, пустых пар ни в одной форме — 0).
|
||||||
|
if ($parent.SelectNodes("*").Count -eq 0) { $parent.IsEmpty = $true }
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# template-remove v1.6 — Remove template from 1C object
|
# template-remove v1.7 — Remove template from 1C object
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -120,6 +120,10 @@ def main():
|
|||||||
if parent.text and parent.text.strip() == "":
|
if parent.text and parent.text.strip() == "":
|
||||||
parent.text = ""
|
parent.text = ""
|
||||||
parent.remove(node)
|
parent.remove(node)
|
||||||
|
# Опустевший контейнер: text="" сериализуется парой <ChildObjects></ChildObjects>,
|
||||||
|
# а нужен <ChildObjects/> — PS-порт через DOM даёт именно его.
|
||||||
|
if len(parent) == 0 and not (parent.text or "").strip():
|
||||||
|
parent.text = None
|
||||||
break
|
break
|
||||||
|
|
||||||
# Clear MainDataCompositionSchema if it pointed to this template
|
# Clear MainDataCompositionSchema if it pointed to this template
|
||||||
|
|||||||
@@ -27,5 +27,12 @@
|
|||||||
"methodName": "ПриЗаписи",
|
"methodName": "ПриЗаписи",
|
||||||
"interceptorType": "Before"
|
"interceptorType": "Before"
|
||||||
},
|
},
|
||||||
"expect": { "stdoutContains": "&Перед(\"ПриЗаписи\")" }
|
"expect": {
|
||||||
|
"stdoutContains": "&Перед(\"ПриЗаписи\")",
|
||||||
|
"preserves": {
|
||||||
|
"file": "Ext/Catalogs/Товары/Ext/ObjectModule.bsl",
|
||||||
|
"bom": true,
|
||||||
|
"eol": "crlf"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -1,3 +1,2 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<SpreadsheetDocument xmlns="http://v8.1c.ru/spreadsheet/document" xmlns:ss="http://v8.1c.ru/spreadsheet/document" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
<SpreadsheetDocument xmlns="http://v8.1c.ru/spreadsheet/document" xmlns:ss="http://v8.1c.ru/spreadsheet/document" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
|
||||||
</SpreadsheetDocument>
|
|
||||||
@@ -25,5 +25,17 @@
|
|||||||
{ "name": "СуммаИтого", "type": "decimal(15,2)" },
|
{ "name": "СуммаИтого", "type": "decimal(15,2)" },
|
||||||
{ "name": "ДатаНачала", "type": "date" }
|
{ "name": "ДатаНачала", "type": "date" }
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"expect": {
|
||||||
|
"preserves": {
|
||||||
|
"file": "DataProcessors/Реквизиты/Forms/Форма/Ext/Form.xml",
|
||||||
|
"bom": true,
|
||||||
|
"eol": "crlf",
|
||||||
|
"encoding": "UTF-8",
|
||||||
|
"finalNewline": false,
|
||||||
|
"noCR13": true,
|
||||||
|
"selfClose": "tight",
|
||||||
|
"noEmptyPairs": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,16 @@
|
|||||||
"objectName": "Catalogs/Товары",
|
"objectName": "Catalogs/Товары",
|
||||||
"formName": "ФормаЭлемента",
|
"formName": "ФормаЭлемента",
|
||||||
"expect": {
|
"expect": {
|
||||||
"stdoutContains": "Форма ФормаЭлемента удалена"
|
"stdoutContains": "Форма ФормаЭлемента удалена",
|
||||||
|
"preserves": {
|
||||||
|
"file": "Catalogs/Товары.xml",
|
||||||
|
"bom": true,
|
||||||
|
"eol": "crlf",
|
||||||
|
"encoding": "UTF-8",
|
||||||
|
"finalNewline": false,
|
||||||
|
"noCR13": true,
|
||||||
|
"selfClose": "tight",
|
||||||
|
"noEmptyPairs": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
<SearchStringModeOnInputByString>Begin</SearchStringModeOnInputByString>
|
<SearchStringModeOnInputByString>Begin</SearchStringModeOnInputByString>
|
||||||
<FullTextSearchOnInputByString>DontUse</FullTextSearchOnInputByString>
|
<FullTextSearchOnInputByString>DontUse</FullTextSearchOnInputByString>
|
||||||
<ChoiceDataGetModeOnInputByString>Directly</ChoiceDataGetModeOnInputByString>
|
<ChoiceDataGetModeOnInputByString>Directly</ChoiceDataGetModeOnInputByString>
|
||||||
<DefaultObjectForm></DefaultObjectForm>
|
<DefaultObjectForm/>
|
||||||
<DefaultFolderForm/>
|
<DefaultFolderForm/>
|
||||||
<DefaultListForm/>
|
<DefaultListForm/>
|
||||||
<DefaultChoiceForm/>
|
<DefaultChoiceForm/>
|
||||||
@@ -86,7 +86,6 @@
|
|||||||
<UpdateDataHistoryImmediatelyAfterWrite>false</UpdateDataHistoryImmediatelyAfterWrite>
|
<UpdateDataHistoryImmediatelyAfterWrite>false</UpdateDataHistoryImmediatelyAfterWrite>
|
||||||
<ExecuteAfterWriteDataHistoryVersionProcessing>false</ExecuteAfterWriteDataHistoryVersionProcessing>
|
<ExecuteAfterWriteDataHistoryVersionProcessing>false</ExecuteAfterWriteDataHistoryVersionProcessing>
|
||||||
</Properties>
|
</Properties>
|
||||||
<ChildObjects>
|
<ChildObjects/>
|
||||||
</ChildObjects>
|
|
||||||
</Catalog>
|
</Catalog>
|
||||||
</MetaDataObject>
|
</MetaDataObject>
|
||||||
@@ -8,5 +8,17 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"params": { "object": "Catalog.Удалить" },
|
"params": { "object": "Catalog.Удалить" },
|
||||||
"args_extra": ["-Force"]
|
"args_extra": ["-Force"],
|
||||||
|
"expect": {
|
||||||
|
"preserves": {
|
||||||
|
"file": "Configuration.xml",
|
||||||
|
"bom": true,
|
||||||
|
"eol": "crlf",
|
||||||
|
"encoding": "UTF-8",
|
||||||
|
"finalNewline": false,
|
||||||
|
"noCR13": true,
|
||||||
|
"selfClose": "tight",
|
||||||
|
"noEmptyPairs": true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,5 +17,17 @@
|
|||||||
"templatePath": "Template.xml",
|
"templatePath": "Template.xml",
|
||||||
"operation": "add-field",
|
"operation": "add-field",
|
||||||
"value": "Цена: decimal(15,2)"
|
"value": "Цена: decimal(15,2)"
|
||||||
|
},
|
||||||
|
"expect": {
|
||||||
|
"preserves": {
|
||||||
|
"file": "Template.xml",
|
||||||
|
"bom": true,
|
||||||
|
"eol": "crlf",
|
||||||
|
"encoding": "UTF-8",
|
||||||
|
"finalNewline": false,
|
||||||
|
"noCR13": true,
|
||||||
|
"selfClose": "tight",
|
||||||
|
"noEmptyPairs": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,10 @@
|
|||||||
"editable"
|
"editable"
|
||||||
],
|
],
|
||||||
"expect": {
|
"expect": {
|
||||||
"stdoutContains": "редактируется с сохранением поддержки"
|
"stdoutContains": "редактируется с сохранением поддержки",
|
||||||
|
"preserves": {
|
||||||
|
"file": "Ext/ParentConfigurations.bin",
|
||||||
|
"bom": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -1,3 +1,2 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<SpreadsheetDocument xmlns="http://v8.1c.ru/spreadsheet/document" xmlns:ss="http://v8.1c.ru/spreadsheet/document" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
<SpreadsheetDocument xmlns="http://v8.1c.ru/spreadsheet/document" xmlns:ss="http://v8.1c.ru/spreadsheet/document" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
|
||||||
</SpreadsheetDocument>
|
|
||||||
@@ -10,5 +10,17 @@
|
|||||||
"args": { "-ObjectName": "МояОбработка", "-TemplateName": "Макет", "-TemplateType": "SpreadsheetDocument", "-SrcDir": "{workDir}" }
|
"args": { "-ObjectName": "МояОбработка", "-TemplateName": "Макет", "-TemplateType": "SpreadsheetDocument", "-SrcDir": "{workDir}" }
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"params": { "objectName": "МояОбработка", "templateName": "Макет" }
|
"params": { "objectName": "МояОбработка", "templateName": "Макет" },
|
||||||
|
"expect": {
|
||||||
|
"preserves": {
|
||||||
|
"file": "МояОбработка.xml",
|
||||||
|
"bom": true,
|
||||||
|
"eol": "crlf",
|
||||||
|
"encoding": "UTF-8",
|
||||||
|
"finalNewline": false,
|
||||||
|
"noCR13": true,
|
||||||
|
"selfClose": "tight",
|
||||||
|
"noEmptyPairs": true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
<DefaultForm/>
|
<DefaultForm/>
|
||||||
<AuxiliaryForm/>
|
<AuxiliaryForm/>
|
||||||
</Properties>
|
</Properties>
|
||||||
<ChildObjects>
|
<ChildObjects/>
|
||||||
</ChildObjects>
|
|
||||||
</ExternalDataProcessor>
|
</ExternalDataProcessor>
|
||||||
</MetaDataObject>
|
</MetaDataObject>
|
||||||
@@ -29,7 +29,6 @@
|
|||||||
<VariantsStorage/>
|
<VariantsStorage/>
|
||||||
<SettingsStorage/>
|
<SettingsStorage/>
|
||||||
</Properties>
|
</Properties>
|
||||||
<ChildObjects>
|
<ChildObjects/>
|
||||||
</ChildObjects>
|
|
||||||
</ExternalReport>
|
</ExternalReport>
|
||||||
</MetaDataObject>
|
</MetaDataObject>
|
||||||
@@ -25,6 +25,16 @@
|
|||||||
"expect": {
|
"expect": {
|
||||||
"files": [
|
"files": [
|
||||||
"XDTOPackages/types.xml"
|
"XDTOPackages/types.xml"
|
||||||
]
|
],
|
||||||
|
"preserves": {
|
||||||
|
"file": "XDTOPackages/types.xml",
|
||||||
|
"bom": true,
|
||||||
|
"eol": "crlf",
|
||||||
|
"encoding": "UTF-8",
|
||||||
|
"finalNewline": false,
|
||||||
|
"noCR13": true,
|
||||||
|
"selfClose": "tight",
|
||||||
|
"noEmptyPairs": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-2
@@ -404,8 +404,20 @@ function checkPreserves(workDir, spec) {
|
|||||||
if (spaced) errs.push(`preserves: expected tight self-closing, got ${spaced.length}× spaced (e.g. ${spaced[0].slice(0, 60)})`);
|
if (spaced) errs.push(`preserves: expected tight self-closing, got ${spaced.length}× spaced (e.g. ${spaced[0].slice(0, 60)})`);
|
||||||
}
|
}
|
||||||
if (spec.noEmptyPairs) {
|
if (spec.noEmptyPairs) {
|
||||||
const pairs = text.match(/<([\w:.]+)([^<>]*)><\/\1>/g);
|
const pairs = text.match(/<([\w:.]+)([^<>]*)><\/\1>/g) || [];
|
||||||
if (pairs) errs.push(`preserves: expected self-closing, got ${pairs.length}× empty pair (e.g. ${pairs[0].slice(0, 60)})`);
|
// Плюс пара, разнесённая по строкам: опустевший контейнер выглядит как
|
||||||
|
// `<ChildObjects>\n\t\t</ChildObjects>` и смежной проверкой НЕ ловился — так
|
||||||
|
// прошёл незамеченным дефект form-remove/template-remove. Платформа пишет
|
||||||
|
// только `<ChildObjects/>` (1394 на acc+erp, пустых пар 0 в обеих формах).
|
||||||
|
// Дискриминатор — перевод строки внутри: значащий пробельный текст-узел
|
||||||
|
// (`<xr:FillValue xsi:type="xs:string"> </xr:FillValue>`) его не содержит,
|
||||||
|
// поэтому под проверку не попадает.
|
||||||
|
const multiline = text.match(/<([\w:.]+)([^<>]*)>[ \t]*\r?\n\s*<\/\1>/g) || [];
|
||||||
|
const all = [...pairs, ...multiline];
|
||||||
|
if (all.length) {
|
||||||
|
const sample = all[0].replace(/\s+/g, ' ').slice(0, 60);
|
||||||
|
errs.push(`preserves: expected self-closing, got ${all.length}× empty pair (e.g. ${sample})`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return errs;
|
return errs;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user