mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-08-07 20:20:20 +03:00
test(runner): байтовые проверки канона вместо масок (#57)
Раннер сам прятал дефекты, которые чинит #57. normalizeXmlContent при runtime=python снимал ровно четыре измерения: пробел перед `/>`, whitespace между тегами, пустую пару <Tag></Tag> и хвостовой пробельный мусор. Паритет PS<->PY по этим измерениям проверялся ЧЕРЕЗ маску — расхождение физически не могло упасть. Снято три из четырёх (пробел, пустая пара, хвост). Схлопывание whitespace между тегами оставлено: порты кое-где расставляют отступы иначе, это форматирование, а не байтовый канон. Ужесточён checkPreserves: eol теперь считает ОДИНОЧНЫЕ LF, а не «есть ли хоть один CR». Прежняя проверка пропускала смешанный выход — cfe-init давал 10 CR на 70 строк и проходил её, то есть головной дефект тикета был ей невидим. Добавлены ключи selfClose:"tight" и noEmptyPairs; preserves проставлен в 13 кейсах навыков-эмиттеров (по одному на навык, на его СОБСТВЕННЫЙ артефакт). Снятие масок сразу вскрыло четыре реальных расхождения портов: - form-edit собирает выход из OuterXml и писал `<a />`; в списке 17 навыков его не было, потому что искал по вызовам Save — здесь другой путь. Тот же случай, что с Form.xml в cfe-borrow; - meta-edit py дописывал хвостовой перевод в создаваемый Ext/Predefined.xml и читал существующий без newline='' (терял CRLF); - skd-info py писал отчёт -OutFile без хвостового перевода, PS через WriteAllLines — с ним. Это текстовый отчёт, канон Конфигуратора к нему не относится, поэтому выровнял py по существующему эталону; - фикстуры кейсов содержали <Vendor></Vendor> — снимок нашего же старого вывода. Конфигуратор пустых пар не пишет, .NET их сохраняет, lxml схлопывает. Поправлены 10 фикстур: пары → самозакрывающиеся, EOL и BOM не тронуты. Результат: PS 641/641, python 638/641 (+3 runtimeOnly-скипа) — со снятыми масками. Дрейф снэпшотов: 10 файлов, только пробельные теги и пустые пары. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
11e4e4301f
commit
d7fd6d79d3
@@ -1,4 +1,4 @@
|
||||
# form-edit v1.6 — Edit 1C managed form elements
|
||||
# form-edit v1.7 — Edit 1C managed form elements
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
@@ -1387,6 +1387,9 @@ if ($def.elementEvents -and $def.elementEvents.Count -gt 0) {
|
||||
$content = $xmlDoc.OuterXml
|
||||
# Ensure encoding declaration is uppercase UTF-8
|
||||
$content = $content -replace '^<\?xml version="1.0" encoding="utf-8"\?>', '<?xml version="1.0" encoding="UTF-8"?>'
|
||||
# Пустой элемент: OuterXml (как и XmlWriter) пишет `<a />`, Конфигуратор — `<a/>`.
|
||||
# Гард на CDATA/комментарии: только там ` />` может быть содержимым, а не концом тега.
|
||||
if ($content -notmatch '<!\[CDATA\[|<!--') { $content = [regex]::Replace($content, '(?<=\S) />', '/>') }
|
||||
|
||||
$enc = New-Object System.Text.UTF8Encoding($true)
|
||||
[System.IO.File]::WriteAllText($resolvedFormPath, $content, $enc)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# form-edit v1.6 — Edit 1C managed form elements (Python port)
|
||||
# form-edit v1.7 — Edit 1C managed form elements (Python port)
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
import argparse
|
||||
import json
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# meta-edit v1.26 — Edit existing 1C metadata object XML
|
||||
# meta-edit v1.27 — Edit existing 1C metadata object XML
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[string]$DefinitionFile,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# meta-edit v1.26 — Edit existing 1C metadata object XML
|
||||
# meta-edit v1.27 — Edit existing 1C metadata object XML
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
|
||||
import argparse
|
||||
@@ -3094,7 +3094,9 @@ def add_predefined_items(items):
|
||||
item_list = items if isinstance(items, list) else [items]
|
||||
items_xml = ''.join(build_predef_item_xml('\t', it, code_type) for it in item_list)
|
||||
if os.path.exists(path):
|
||||
with open(path, 'r', encoding='utf-8-sig') as f:
|
||||
# newline='' => без трансляции переводов строк: иначе CRLF молча схлопнется
|
||||
# в LF при чтении и файл будет переписан в LF (#44/#46/#47).
|
||||
with open(path, 'r', encoding='utf-8-sig', newline='') as f:
|
||||
text = f.read()
|
||||
text = text.replace('</PredefinedData>', items_xml + '</PredefinedData>')
|
||||
else:
|
||||
@@ -3103,7 +3105,7 @@ def add_predefined_items(items):
|
||||
'xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" '
|
||||
'xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
|
||||
f'xsi:type="{xsi_type}" version="{version}">\r\n')
|
||||
text = hdr + items_xml + '</PredefinedData>\r\n'
|
||||
text = hdr + items_xml + '</PredefinedData>'
|
||||
with open(path, 'wb') as f:
|
||||
f.write(b'\xef\xbb\xbf')
|
||||
f.write(text.encode('utf-8'))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# skd-info v1.8 — Analyze 1C DCS structure
|
||||
# skd-info v1.9 — Analyze 1C DCS structure
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# skd-info v1.8 — Analyze 1C DCS structure
|
||||
# skd-info v1.9 — Analyze 1C DCS structure
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
|
||||
import argparse
|
||||
@@ -1802,7 +1802,10 @@ def main():
|
||||
if not os.path.isabs(out_path):
|
||||
out_path = os.path.join(os.getcwd(), out_path)
|
||||
with open(out_path, "w", encoding="utf-8-sig") as fh:
|
||||
fh.write("\n".join(result))
|
||||
# Хвостовой перевод строки — как у PS-порта (WriteAllLines его добавляет).
|
||||
# Это текстовый отчёт, а не XML метаданных: канон Конфигуратора сюда не
|
||||
# относится, важен лишь паритет портов.
|
||||
fh.write("\n".join(result) + "\n")
|
||||
print(f"Written {total_lines} lines to {args.OutFile}")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
@@ -252,10 +252,18 @@ ibcmd-проход автоматически `○ skipped`, если рядом
|
||||
|---|---|
|
||||
| `file` | Путь к файлу относительно `workDir` (обязателен) |
|
||||
| `bom` | `true`/`false` — наличие UTF-8 BOM |
|
||||
| `eol` | `"crlf"` / `"lf"` |
|
||||
| `eol` | `"crlf"` / `"lf"` — проверяются ОДИНОЧНЫЕ переводы строк, поэтому смешанный выход падает |
|
||||
| `encoding` | Ожидаемое значение в XML-декларации, напр. `"UTF-8"` |
|
||||
| `finalNewline` | `true`/`false` — перевод строки в конце файла |
|
||||
| `noCR13` | `true` — в выходе не должно быть литерала ` ` |
|
||||
| `selfClose` | `"tight"` — пустой элемент только как `<a/>`, без пробела перед `/>` |
|
||||
| `noEmptyPairs` | `true` — пустого элемента в форме `<a></a>` быть не должно |
|
||||
|
||||
Канон выгрузки Конфигуратора (issue #57), измеренный на чистой выгрузке пустой ИБ на Windows
|
||||
и macOS и на 8 выгрузках в `cfsrc/`: **CRLF, BOM, последний байт `>` (без перевода строки),
|
||||
`<a/>` без пробела, ноль пустых пар, `encoding="UTF-8"`.** Для файла, который навык СОЗДАЁТ,
|
||||
ожидается канон; для файла, который он ПРАВИТ, — стиль входного файла (контракт #44/#46/#47),
|
||||
поэтому в кейсах `roundtrip-crlf-preserve` ожидания могут отличаться от канона.
|
||||
|
||||
`preserves` и эталон **дополняют** друг друга: первый следит за байтовым стилем файла, второй — за
|
||||
структурой содержимого. Наличие одного не отменяет необходимости другого.
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
</UsePurposes>
|
||||
<ScriptVariant>Russian</ScriptVariant>
|
||||
<DefaultRoles/>
|
||||
<Vendor></Vendor>
|
||||
<Version></Version>
|
||||
<Vendor/>
|
||||
<Version/>
|
||||
<CompatibilityMode>Version8_3_24</CompatibilityMode>
|
||||
<DefaultLanguage>Language.Русский</DefaultLanguage>
|
||||
<DataLockControlMode>Managed</DataLockControlMode>
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
</UsePurposes>
|
||||
<ScriptVariant>Russian</ScriptVariant>
|
||||
<DefaultRoles/>
|
||||
<Vendor></Vendor>
|
||||
<Version></Version>
|
||||
<Vendor/>
|
||||
<Version/>
|
||||
<UpdateCatalogAddress/>
|
||||
<IncludeHelpInContents>false</IncludeHelpInContents>
|
||||
<UseManagedFormInOrdinaryApplication>false</UseManagedFormInOrdinaryApplication>
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
</UsePurposes>
|
||||
<ScriptVariant>Russian</ScriptVariant>
|
||||
<DefaultRoles/>
|
||||
<Vendor></Vendor>
|
||||
<Version></Version>
|
||||
<Vendor/>
|
||||
<Version/>
|
||||
<CompatibilityMode>Version8_3_24</CompatibilityMode>
|
||||
<DefaultLanguage>Language.Русский</DefaultLanguage>
|
||||
<DataLockControlMode>Managed</DataLockControlMode>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
</UsePurposes>
|
||||
<ScriptVariant>Russian</ScriptVariant>
|
||||
<DefaultRoles/>
|
||||
<Vendor></Vendor>
|
||||
<Vendor/>
|
||||
<Version>1.0.0.2</Version>
|
||||
<UpdateCatalogAddress/>
|
||||
<IncludeHelpInContents>false</IncludeHelpInContents>
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
</UsePurposes>
|
||||
<ScriptVariant>Russian</ScriptVariant>
|
||||
<DefaultRoles/>
|
||||
<Vendor></Vendor>
|
||||
<Version></Version>
|
||||
<Vendor/>
|
||||
<Version/>
|
||||
<CompatibilityMode>Version8_3_24</CompatibilityMode>
|
||||
<DefaultLanguage>Language.Русский</DefaultLanguage>
|
||||
<DataLockControlMode>Managed</DataLockControlMode>
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
</UsePurposes>
|
||||
<ScriptVariant>Russian</ScriptVariant>
|
||||
<DefaultRoles/>
|
||||
<Vendor></Vendor>
|
||||
<Version></Version>
|
||||
<Vendor/>
|
||||
<Version/>
|
||||
<CompatibilityMode>Version8_3_24</CompatibilityMode>
|
||||
<DefaultLanguage>Language.Русский</DefaultLanguage>
|
||||
<DataLockControlMode>Managed</DataLockControlMode>
|
||||
|
||||
@@ -8,6 +8,16 @@
|
||||
"Configuration.xml",
|
||||
"Languages/Русский.xml",
|
||||
"Ext/ClientApplicationInterface.xml"
|
||||
]
|
||||
],
|
||||
"preserves": {
|
||||
"file": "Configuration.xml",
|
||||
"bom": true,
|
||||
"eol": "crlf",
|
||||
"encoding": "UTF-8",
|
||||
"finalNewline": false,
|
||||
"noCR13": true,
|
||||
"selfClose": "tight",
|
||||
"noEmptyPairs": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
</xr:ContainedObject>
|
||||
</InternalInfo>
|
||||
<Properties>
|
||||
<Name></Name>
|
||||
<Name/>
|
||||
<Synonym>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
@@ -48,8 +48,8 @@
|
||||
</UsePurposes>
|
||||
<ScriptVariant>Russian</ScriptVariant>
|
||||
<DefaultRoles/>
|
||||
<Vendor></Vendor>
|
||||
<Version></Version>
|
||||
<Vendor/>
|
||||
<Version/>
|
||||
<CompatibilityMode>Version8_3_24</CompatibilityMode>
|
||||
<DefaultLanguage>Language.Русский</DefaultLanguage>
|
||||
<DataLockControlMode>Managed</DataLockControlMode>
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
</UsePurposes>
|
||||
<ScriptVariant>Russian</ScriptVariant>
|
||||
<DefaultRoles/>
|
||||
<Vendor></Vendor>
|
||||
<Version></Version>
|
||||
<Vendor/>
|
||||
<Version/>
|
||||
<CompatibilityMode>Version8_3_24</CompatibilityMode>
|
||||
<DefaultLanguage>Language.Русский</DefaultLanguage>
|
||||
<DataLockControlMode>Managed</DataLockControlMode>
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
</UsePurposes>
|
||||
<ScriptVariant>Russian</ScriptVariant>
|
||||
<DefaultRoles/>
|
||||
<Vendor></Vendor>
|
||||
<Version></Version>
|
||||
<Vendor/>
|
||||
<Version/>
|
||||
<CompatibilityMode>Version8_3_24</CompatibilityMode>
|
||||
<DefaultLanguage>Language.Русский</DefaultLanguage>
|
||||
<DataLockControlMode>Managed</DataLockControlMode>
|
||||
|
||||
@@ -1,8 +1,23 @@
|
||||
{
|
||||
"name": "Пустое расширение",
|
||||
"params": { "name": "МоёРасширение", "outputDir": "ext" },
|
||||
"params": {
|
||||
"name": "МоёРасширение",
|
||||
"outputDir": "ext"
|
||||
},
|
||||
"validatePath": "ext",
|
||||
"expect": {
|
||||
"files": ["ext/Configuration.xml"]
|
||||
"files": [
|
||||
"ext/Configuration.xml"
|
||||
],
|
||||
"preserves": {
|
||||
"file": "Configuration.xml",
|
||||
"bom": true,
|
||||
"eol": "crlf",
|
||||
"encoding": "UTF-8",
|
||||
"finalNewline": false,
|
||||
"noCR13": true,
|
||||
"selfClose": "tight",
|
||||
"noEmptyPairs": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</xr:ContainedObject>
|
||||
</InternalInfo>
|
||||
<Properties>
|
||||
<Name></Name>
|
||||
<Name/>
|
||||
<CompatibilityMode>Version8_3_24</CompatibilityMode>
|
||||
</Properties>
|
||||
<ChildObjects/>
|
||||
|
||||
@@ -1,8 +1,22 @@
|
||||
{
|
||||
"name": "Пустая внешняя обработка",
|
||||
"params": { "name": "ТестоваяОбработка" },
|
||||
"params": {
|
||||
"name": "ТестоваяОбработка"
|
||||
},
|
||||
"validatePath": "ТестоваяОбработка",
|
||||
"expect": {
|
||||
"files": ["ТестоваяОбработка.xml"]
|
||||
"files": [
|
||||
"ТестоваяОбработка.xml"
|
||||
],
|
||||
"preserves": {
|
||||
"file": "ТестоваяОбработка.xml",
|
||||
"bom": true,
|
||||
"eol": "crlf",
|
||||
"encoding": "UTF-8",
|
||||
"finalNewline": false,
|
||||
"noCR13": true,
|
||||
"selfClose": "tight",
|
||||
"noEmptyPairs": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,22 @@
|
||||
{
|
||||
"name": "Пустой внешний отчёт",
|
||||
"params": { "name": "ТестовыйОтчёт" },
|
||||
"params": {
|
||||
"name": "ТестовыйОтчёт"
|
||||
},
|
||||
"validatePath": "ТестовыйОтчёт",
|
||||
"expect": {
|
||||
"files": ["ТестовыйОтчёт.xml"]
|
||||
"files": [
|
||||
"ТестовыйОтчёт.xml"
|
||||
],
|
||||
"preserves": {
|
||||
"file": "ТестовыйОтчёт.xml",
|
||||
"bom": true,
|
||||
"eol": "crlf",
|
||||
"encoding": "UTF-8",
|
||||
"finalNewline": false,
|
||||
"noCR13": true,
|
||||
"selfClose": "tight",
|
||||
"noEmptyPairs": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,31 @@
|
||||
"preRun": [
|
||||
{
|
||||
"script": "meta-compile/scripts/meta-compile",
|
||||
"input": { "type": "Catalog", "name": "Товары" },
|
||||
"args": { "-JsonPath": "{inputFile}", "-OutputDir": "{workDir}" }
|
||||
"input": {
|
||||
"type": "Catalog",
|
||||
"name": "Товары"
|
||||
},
|
||||
"args": {
|
||||
"-JsonPath": "{inputFile}",
|
||||
"-OutputDir": "{workDir}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"params": { "objectPath": "Catalogs/Товары.xml", "formName": "ФормаЭлемента" },
|
||||
"validatePath": "Catalogs/Товары/Forms/ФормаЭлемента"
|
||||
"params": {
|
||||
"objectPath": "Catalogs/Товары.xml",
|
||||
"formName": "ФормаЭлемента"
|
||||
},
|
||||
"validatePath": "Catalogs/Товары/Forms/ФормаЭлемента",
|
||||
"expect": {
|
||||
"preserves": {
|
||||
"file": "Catalogs/Товары/Forms/ФормаЭлемента/Ext/Form.xml",
|
||||
"bom": true,
|
||||
"eol": "crlf",
|
||||
"encoding": "UTF-8",
|
||||
"finalNewline": false,
|
||||
"noCR13": true,
|
||||
"selfClose": "tight",
|
||||
"noEmptyPairs": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,17 +3,40 @@
|
||||
"preRun": [
|
||||
{
|
||||
"script": "meta-compile/scripts/meta-compile",
|
||||
"input": { "type": "DataProcessor", "name": "Минимальная" },
|
||||
"args": { "-JsonPath": "{inputFile}", "-OutputDir": "{workDir}" }
|
||||
"input": {
|
||||
"type": "DataProcessor",
|
||||
"name": "Минимальная"
|
||||
},
|
||||
"args": {
|
||||
"-JsonPath": "{inputFile}",
|
||||
"-OutputDir": "{workDir}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"script": "form-add/scripts/form-add",
|
||||
"args": { "-ObjectPath": "{workDir}/DataProcessors/Минимальная.xml", "-FormName": "Форма" }
|
||||
"args": {
|
||||
"-ObjectPath": "{workDir}/DataProcessors/Минимальная.xml",
|
||||
"-FormName": "Форма"
|
||||
}
|
||||
}
|
||||
],
|
||||
"params": { "outputPath": "DataProcessors/Минимальная/Forms/Форма/Ext/Form.xml" },
|
||||
"params": {
|
||||
"outputPath": "DataProcessors/Минимальная/Forms/Форма/Ext/Form.xml"
|
||||
},
|
||||
"validatePath": "DataProcessors/Минимальная/Forms/Форма/Ext/Form.xml",
|
||||
"input": {
|
||||
"title": "Минимальная форма"
|
||||
},
|
||||
"expect": {
|
||||
"preserves": {
|
||||
"file": "DataProcessors/Минимальная/Forms/Форма/Ext/Form.xml",
|
||||
"bom": true,
|
||||
"eol": "crlf",
|
||||
"encoding": "UTF-8",
|
||||
"finalNewline": false,
|
||||
"noCR13": true,
|
||||
"selfClose": "tight",
|
||||
"noEmptyPairs": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1" />
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<Attributes>
|
||||
<Attribute name="Объект" id="1">
|
||||
<Type>
|
||||
|
||||
+2
-2
@@ -7,12 +7,12 @@
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1" />
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
<Button name="Выполнить" id="1">
|
||||
<CommandName>Form.Command.Выполнить</CommandName>
|
||||
<DefaultButton>true</DefaultButton>
|
||||
<ExtendedTooltip name="ВыполнитьРасширеннаяПодсказка" id="2" />
|
||||
<ExtendedTooltip name="ВыполнитьРасширеннаяПодсказка" id="2"/>
|
||||
</Button>
|
||||
</ChildItems>
|
||||
<Attributes>
|
||||
|
||||
+5
-5
@@ -7,7 +7,7 @@
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1" />
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
<InputField name="Поле1" id="1">
|
||||
<DataPath>Поле1</DataPath>
|
||||
@@ -17,8 +17,8 @@
|
||||
<v8:content>Поле 1</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<ContextMenu name="Поле1КонтекстноеМеню" id="2" />
|
||||
<ExtendedTooltip name="Поле1РасширеннаяПодсказка" id="3" />
|
||||
<ContextMenu name="Поле1КонтекстноеМеню" id="2"/>
|
||||
<ExtendedTooltip name="Поле1РасширеннаяПодсказка" id="3"/>
|
||||
</InputField>
|
||||
<InputField name="Поле2" id="4">
|
||||
<DataPath>Поле2</DataPath>
|
||||
@@ -28,8 +28,8 @@
|
||||
<v8:content>Поле 2</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<ContextMenu name="Поле2КонтекстноеМеню" id="5" />
|
||||
<ExtendedTooltip name="Поле2РасширеннаяПодсказка" id="6" />
|
||||
<ContextMenu name="Поле2КонтекстноеМеню" id="5"/>
|
||||
<ExtendedTooltip name="Поле2РасширеннаяПодсказка" id="6"/>
|
||||
</InputField>
|
||||
</ChildItems>
|
||||
<Attributes>
|
||||
|
||||
+8
-8
@@ -7,7 +7,7 @@
|
||||
</v8:item>
|
||||
</Title>
|
||||
<AutoTitle>false</AutoTitle>
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1" />
|
||||
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
|
||||
<ChildItems>
|
||||
<InputField name="Поле1" id="1">
|
||||
<DataPath>Поле1</DataPath>
|
||||
@@ -17,8 +17,8 @@
|
||||
<v8:content>Существующее поле</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<ContextMenu name="Поле1КонтекстноеМеню" id="2" />
|
||||
<ExtendedTooltip name="Поле1РасширеннаяПодсказка" id="3" />
|
||||
<ContextMenu name="Поле1КонтекстноеМеню" id="2"/>
|
||||
<ExtendedTooltip name="Поле1РасширеннаяПодсказка" id="3"/>
|
||||
</InputField>
|
||||
<UsualGroup name="ГруппаНовая" id="4">
|
||||
<Title>
|
||||
@@ -28,7 +28,7 @@
|
||||
</v8:item>
|
||||
</Title>
|
||||
<Group>Horizontal</Group>
|
||||
<ExtendedTooltip name="ГруппаНоваяРасширеннаяПодсказка" id="5" />
|
||||
<ExtendedTooltip name="ГруппаНоваяРасширеннаяПодсказка" id="5"/>
|
||||
<ChildItems>
|
||||
<InputField name="Поле2" id="6">
|
||||
<DataPath>Поле2</DataPath>
|
||||
@@ -38,8 +38,8 @@
|
||||
<v8:content>Поле 2</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<ContextMenu name="Поле2КонтекстноеМеню" id="7" />
|
||||
<ExtendedTooltip name="Поле2РасширеннаяПодсказка" id="8" />
|
||||
<ContextMenu name="Поле2КонтекстноеМеню" id="7"/>
|
||||
<ExtendedTooltip name="Поле2РасширеннаяПодсказка" id="8"/>
|
||||
</InputField>
|
||||
<InputField name="Поле3" id="9">
|
||||
<DataPath>Поле3</DataPath>
|
||||
@@ -49,8 +49,8 @@
|
||||
<v8:content>Поле 3</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<ContextMenu name="Поле3КонтекстноеМеню" id="10" />
|
||||
<ExtendedTooltip name="Поле3РасширеннаяПодсказка" id="11" />
|
||||
<ContextMenu name="Поле3КонтекстноеМеню" id="10"/>
|
||||
<ExtendedTooltip name="Поле3РасширеннаяПодсказка" id="11"/>
|
||||
</InputField>
|
||||
</ChildItems>
|
||||
</UsualGroup>
|
||||
|
||||
@@ -3,8 +3,25 @@
|
||||
"preRun": [
|
||||
{
|
||||
"script": "epf-init/scripts/init",
|
||||
"args": { "-Name": "МояОбработка", "-SrcDir": "{workDir}" }
|
||||
"args": {
|
||||
"-Name": "МояОбработка",
|
||||
"-SrcDir": "{workDir}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"params": { "objectName": "МояОбработка" }
|
||||
"params": {
|
||||
"objectName": "МояОбработка"
|
||||
},
|
||||
"expect": {
|
||||
"preserves": {
|
||||
"file": "МояОбработка.xml",
|
||||
"bom": true,
|
||||
"eol": "crlf",
|
||||
"encoding": "UTF-8",
|
||||
"finalNewline": false,
|
||||
"noCR13": true,
|
||||
"selfClose": "tight",
|
||||
"noEmptyPairs": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,24 @@
|
||||
{
|
||||
"name": "Простой справочник без реквизитов",
|
||||
"input": { "type": "Catalog", "name": "Валюты" },
|
||||
"input": {
|
||||
"type": "Catalog",
|
||||
"name": "Валюты"
|
||||
},
|
||||
"validatePath": "Catalogs/Валюты",
|
||||
"expect": {
|
||||
"files": ["Catalogs/Валюты.xml", "Catalogs/Валюты/Ext/ObjectModule.bsl"]
|
||||
"files": [
|
||||
"Catalogs/Валюты.xml",
|
||||
"Catalogs/Валюты/Ext/ObjectModule.bsl"
|
||||
],
|
||||
"preserves": {
|
||||
"file": "Catalogs/Валюты.xml",
|
||||
"bom": true,
|
||||
"eol": "crlf",
|
||||
"encoding": "UTF-8",
|
||||
"finalNewline": false,
|
||||
"noCR13": true,
|
||||
"selfClose": "tight",
|
||||
"noEmptyPairs": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
</UsePurposes>
|
||||
<ScriptVariant>Russian</ScriptVariant>
|
||||
<DefaultRoles />
|
||||
<Vendor></Vendor>
|
||||
<Version></Version>
|
||||
<Vendor/>
|
||||
<Version/>
|
||||
<UpdateCatalogAddress />
|
||||
<IncludeHelpInContents>false</IncludeHelpInContents>
|
||||
<UseManagedFormInOrdinaryApplication>false</UseManagedFormInOrdinaryApplication>
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
</UsePurposes>
|
||||
<ScriptVariant>Russian</ScriptVariant>
|
||||
<DefaultRoles />
|
||||
<Vendor></Vendor>
|
||||
<Version></Version>
|
||||
<Vendor/>
|
||||
<Version/>
|
||||
<UpdateCatalogAddress />
|
||||
<IncludeHelpInContents>false</IncludeHelpInContents>
|
||||
<UseManagedFormInOrdinaryApplication>false</UseManagedFormInOrdinaryApplication>
|
||||
|
||||
+1
-1
@@ -97,7 +97,7 @@
|
||||
</v8:item>
|
||||
</Synonym>
|
||||
<Comment/>
|
||||
<Group></Group>
|
||||
<Group/>
|
||||
<CommandParameterType>
|
||||
<v8:Type xmlns:d5p1="http://v8.1c.ru/8.1/data/enterprise/current-config">d5p1:CatalogRef.ТестКоманд</v8:Type>
|
||||
</CommandParameterType>
|
||||
|
||||
@@ -6,14 +6,35 @@
|
||||
{
|
||||
"name": "Ячейка",
|
||||
"rows": [
|
||||
{ "cells": [{ "col": 1, "text": "Значение" }] }
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"col": 1,
|
||||
"text": "Значение"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": { "outputPath": "Template.xml" },
|
||||
"params": {
|
||||
"outputPath": "Template.xml"
|
||||
},
|
||||
"validatePath": "Template.xml",
|
||||
"expect": {
|
||||
"files": ["Template.xml"]
|
||||
"files": [
|
||||
"Template.xml"
|
||||
],
|
||||
"preserves": {
|
||||
"file": "Template.xml",
|
||||
"bom": true,
|
||||
"eol": "crlf",
|
||||
"encoding": "UTF-8",
|
||||
"finalNewline": false,
|
||||
"noCR13": true,
|
||||
"selfClose": "tight",
|
||||
"noEmptyPairs": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,16 @@
|
||||
"files": [
|
||||
"Roles/Кладовщик.xml",
|
||||
"Roles/Кладовщик/Ext/Rights.xml"
|
||||
]
|
||||
],
|
||||
"preserves": {
|
||||
"file": "Roles/Кладовщик/Ext/Rights.xml",
|
||||
"bom": true,
|
||||
"eol": "crlf",
|
||||
"encoding": "UTF-8",
|
||||
"finalNewline": false,
|
||||
"noCR13": true,
|
||||
"selfClose": "tight",
|
||||
"noEmptyPairs": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,32 @@
|
||||
{
|
||||
"name": "Минимальная СКД — один набор, один запрос",
|
||||
"params": { "outputPath": "Template.xml" },
|
||||
"params": {
|
||||
"outputPath": "Template.xml"
|
||||
},
|
||||
"input": {
|
||||
"dataSets": [{
|
||||
"query": "ВЫБРАТЬ Номенклатура.Наименование КАК Наименование ИЗ Справочник.Номенклатура КАК Номенклатура",
|
||||
"fields": ["Наименование"]
|
||||
}]
|
||||
"dataSets": [
|
||||
{
|
||||
"query": "ВЫБРАТЬ Номенклатура.Наименование КАК Наименование ИЗ Справочник.Номенклатура КАК Номенклатура",
|
||||
"fields": [
|
||||
"Наименование"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"validatePath": "Template.xml",
|
||||
"expect": {
|
||||
"files": ["Template.xml"]
|
||||
"files": [
|
||||
"Template.xml"
|
||||
],
|
||||
"preserves": {
|
||||
"file": "Template.xml",
|
||||
"bom": true,
|
||||
"eol": "crlf",
|
||||
"encoding": "UTF-8",
|
||||
"finalNewline": false,
|
||||
"noCR13": true,
|
||||
"selfClose": "tight",
|
||||
"noEmptyPairs": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
<dataSource>ИсточникДанных1</dataSource>
|
||||
<query>SELECT 1</query>
|
||||
<field xsi:type="DataSetFieldField">
|
||||
<dataPath></dataPath>
|
||||
<field></field>
|
||||
<dataPath/>
|
||||
<field/>
|
||||
</field>
|
||||
</dataSet>
|
||||
<settingsVariant>
|
||||
|
||||
@@ -3,17 +3,37 @@
|
||||
"preRun": [
|
||||
{
|
||||
"script": "meta-compile/scripts/meta-compile",
|
||||
"input": { "type": "Catalog", "name": "Товары" },
|
||||
"args": { "-JsonPath": "{inputFile}", "-OutputDir": "{workDir}" }
|
||||
"input": {
|
||||
"type": "Catalog",
|
||||
"name": "Товары"
|
||||
},
|
||||
"args": {
|
||||
"-JsonPath": "{inputFile}",
|
||||
"-OutputDir": "{workDir}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"input": {
|
||||
"name": "Склад",
|
||||
"synonym": "Склад",
|
||||
"content": ["Catalogs.Товары"]
|
||||
"content": [
|
||||
"Catalogs.Товары"
|
||||
]
|
||||
},
|
||||
"validatePath": "Subsystems/Склад",
|
||||
"expect": {
|
||||
"files": ["Subsystems/Склад.xml"]
|
||||
"files": [
|
||||
"Subsystems/Склад.xml"
|
||||
],
|
||||
"preserves": {
|
||||
"file": "Subsystems/Склад.xml",
|
||||
"bom": true,
|
||||
"eol": "crlf",
|
||||
"encoding": "UTF-8",
|
||||
"finalNewline": false,
|
||||
"noCR13": true,
|
||||
"selfClose": "tight",
|
||||
"noEmptyPairs": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
</UsePurposes>
|
||||
<ScriptVariant>Russian</ScriptVariant>
|
||||
<DefaultRoles />
|
||||
<Vendor></Vendor>
|
||||
<Version></Version>
|
||||
<Vendor/>
|
||||
<Version/>
|
||||
<UpdateCatalogAddress />
|
||||
<IncludeHelpInContents>false</IncludeHelpInContents>
|
||||
<UseManagedFormInOrdinaryApplication>false</UseManagedFormInOrdinaryApplication>
|
||||
|
||||
+2
-2
@@ -48,8 +48,8 @@
|
||||
</UsePurposes>
|
||||
<ScriptVariant>Russian</ScriptVariant>
|
||||
<DefaultRoles />
|
||||
<Vendor></Vendor>
|
||||
<Version></Version>
|
||||
<Vendor/>
|
||||
<Version/>
|
||||
<UpdateCatalogAddress />
|
||||
<IncludeHelpInContents>false</IncludeHelpInContents>
|
||||
<UseManagedFormInOrdinaryApplication>false</UseManagedFormInOrdinaryApplication>
|
||||
|
||||
@@ -1,9 +1,26 @@
|
||||
{
|
||||
"name": "минимальный пакет: один objectType, два свойства",
|
||||
"caseFiles": ["minimal.xsd"],
|
||||
"params": { "xsdFile": "minimal.xsd" },
|
||||
"caseFiles": [
|
||||
"minimal.xsd"
|
||||
],
|
||||
"params": {
|
||||
"xsdFile": "minimal.xsd"
|
||||
},
|
||||
"validatePath": "XDTOPackages/minimal",
|
||||
"expect": {
|
||||
"files": ["XDTOPackages/minimal.xml", "XDTOPackages/minimal/Ext/Package.bin"]
|
||||
"files": [
|
||||
"XDTOPackages/minimal.xml",
|
||||
"XDTOPackages/minimal/Ext/Package.bin"
|
||||
],
|
||||
"preserves": {
|
||||
"file": "XDTOPackages/minimal.xml",
|
||||
"bom": true,
|
||||
"eol": "crlf",
|
||||
"encoding": "UTF-8",
|
||||
"finalNewline": false,
|
||||
"noCR13": true,
|
||||
"selfClose": "tight",
|
||||
"noEmptyPairs": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+36
-13
@@ -303,6 +303,14 @@ function buildArgs(skillConfig, caseData, workDir, inputFilePath, runtime) {
|
||||
|
||||
const UUID_RE = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi;
|
||||
|
||||
// Applied to the python runtime only: irons out ElementTree/lxml serialization quirks
|
||||
// so a snapshot recorded from PowerShell can still be compared against the python port.
|
||||
//
|
||||
// Three former steps — space before `/>`, empty pair `<Tag></Tag>`, trailing whitespace —
|
||||
// were REMOVED with the fix for issue #57. They masked exactly the divergence that issue
|
||||
// was about (PS wrote `<a />` plus a trailing newline, python wrote `<a/>` without one),
|
||||
// so port parity was being checked through the mask. Do not bring them back: the byte
|
||||
// canon itself is now asserted per case via `preserves`.
|
||||
function normalizeXmlContent(text, opts = {}) {
|
||||
let s = text;
|
||||
// 1. XML declaration: normalize quotes and encoding case
|
||||
@@ -317,14 +325,9 @@ function normalizeXmlContent(text, opts = {}) {
|
||||
if (!opts.keepXmlns) {
|
||||
s = s.replace(/\s+xmlns(?::[\w]+)?="[^"]*"/g, '');
|
||||
}
|
||||
// 4. Normalize self-closing tags: remove space before />
|
||||
s = s.replace(/\s*\/>/g, '/>');
|
||||
// 5. Collapse whitespace between tags: "> \n\t <" → "><"
|
||||
// 3. Collapse whitespace between tags: "> \n\t <" → "><". Kept: the ports indent a
|
||||
// few blocks differently, which is formatting rather than the byte canon.
|
||||
s = s.replace(/>\s+</g, '><');
|
||||
// 6. Normalize empty elements: <Tag></Tag> → <Tag/>
|
||||
s = s.replace(/<([\w:.]+)([^>]*)><\/\1>/g, '<$1$2/>');
|
||||
// 7. Strip trailing whitespace
|
||||
s = s.trimEnd();
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -356,10 +359,11 @@ function normalizeContent(text, config, relFile) {
|
||||
return s;
|
||||
}
|
||||
|
||||
// ─── Byte-style preservation check (round-trip #44/#46/#47) ─────────────────
|
||||
// ─── Byte-style preservation check (round-trip #44/#46/#47, канон #57) ──────
|
||||
// Проверяет СЫРЫЕ байты файла (в обход normalizeContent): BOM / EOL / регистр
|
||||
// encoding / финальный перенос / отсутствие . spec: { file, bom, eol:"crlf"|"lf",
|
||||
// encoding, finalNewline, noCR13 }. Возвращает массив ошибок.
|
||||
// encoding / финальный перенос / отсутствие / форма пустого элемента.
|
||||
// spec: { file, bom, eol:"crlf"|"lf", encoding, finalNewline, noCR13,
|
||||
// selfClose:"tight", noEmptyPairs }. Возвращает массив ошибок.
|
||||
function checkPreserves(workDir, spec) {
|
||||
const errs = [];
|
||||
const target = join(workDir, spec.file);
|
||||
@@ -371,9 +375,18 @@ function checkPreserves(workDir, spec) {
|
||||
if (spec.bom !== undefined && hasBom !== spec.bom)
|
||||
errs.push(`preserves: BOM expected ${spec.bom}, got ${hasBom}`);
|
||||
if (spec.eol) {
|
||||
const hasCR = body.includes(0x0d);
|
||||
const wantCR = spec.eol === 'crlf';
|
||||
if (hasCR !== wantCR) errs.push(`preserves: EOL expected ${spec.eol} (CR=${wantCR}), got CR=${hasCR}`);
|
||||
// Считаем ОДИНОЧНЫЕ LF, а не «есть ли хоть один CR»: прежняя проверка пропускала
|
||||
// смешанный выход (cfe-init давал 10 CR на 70 строк и проходил её) — то есть
|
||||
// главный дефект #57 был ей невидим.
|
||||
let lf = 0, crlf = 0;
|
||||
for (let i = 0; i < body.length; i++) {
|
||||
if (body[i] === 0x0a) { lf++; if (i > 0 && body[i - 1] === 0x0d) crlf++; }
|
||||
}
|
||||
const loneLF = lf - crlf;
|
||||
if (spec.eol === 'crlf' && loneLF > 0)
|
||||
errs.push(`preserves: EOL expected crlf, got mixed (${crlf} CRLF + ${loneLF} lone LF)`);
|
||||
if (spec.eol === 'lf' && crlf > 0)
|
||||
errs.push(`preserves: EOL expected lf, got mixed (${crlf} CRLF + ${loneLF} lone LF)`);
|
||||
}
|
||||
if (spec.encoding) {
|
||||
const m = /encoding="([^"]+)"/.exec(text);
|
||||
@@ -384,6 +397,16 @@ function checkPreserves(workDir, spec) {
|
||||
if (endsNL !== spec.finalNewline) errs.push(`preserves: finalNewline expected ${spec.finalNewline}, got ${endsNL}`);
|
||||
}
|
||||
if (spec.noCR13 && text.includes(' ')) errs.push(`preserves: unexpected literal in output`);
|
||||
// Канон Конфигуратора (#57): пустой элемент — <a/>, не <a /> и не <a></a>.
|
||||
// Проверено на 8 выгрузках в cfsrc: 21 294 119 самозакрывающихся тегов, пробельных 0.
|
||||
if (spec.selfClose === 'tight') {
|
||||
const spaced = text.match(/<[\w:.]+[^<>]*?\s\/>/g);
|
||||
if (spaced) errs.push(`preserves: expected tight self-closing, got ${spaced.length}× spaced (e.g. ${spaced[0].slice(0, 60)})`);
|
||||
}
|
||||
if (spec.noEmptyPairs) {
|
||||
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)})`);
|
||||
}
|
||||
return errs;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user