52d94303bc
ci / test (push) Has been cancelled
Public demo snapshot of an in-house pyRevit extension for precast concrete shop-ticket QC (37 checks / 46 checklist rows) and a standalone panel handling solver (PCI Chapter 8). - No client, job, plant or product data: knowledge layers ship as structural templates only. - Ticket QC's model-read escalation targets a LAN model server endpoint (configurable), not a cloud provider. - Built from the private development repo via tools/make_dist.py.
108 lines
4.5 KiB
Python
108 lines
4.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Tests for the double itself -- because a kind double is a blindfold.
|
|
|
|
`pyrevit_yaml_fake` stands in for pyRevit's YAML reader, and every guard in
|
|
this repository that reads YAML is tested through it. Twice now the double
|
|
has been KINDER than the thing it doubles and the suite was green while the
|
|
button was broken:
|
|
|
|
* it TYPED its scalars while YamlDotNet returns every one as a string --
|
|
the master checklist reached the button with the word 'null' in 37 of 39
|
|
reason slots, on the owner's screen;
|
|
* it took the LAST of two duplicate keys while YamlDotNet raises
|
|
`Duplicate key` and returns nothing -- one nested duplicate discarded a
|
|
whole 255KB plant layer inside Revit on 2026-09-01, and nothing on the
|
|
host could reproduce it.
|
|
|
|
Both properties are the double's PRODUCT, so they are tested here rather than
|
|
assumed by the files that use it.
|
|
"""
|
|
import os
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
pytest.importorskip('yaml')
|
|
from pyrevit_yaml_fake import ( # noqa: E402
|
|
DuplicateKeyError, raise_on_duplicate_keys, stringify_like_yamldotnet,
|
|
strings_only_yaml_reader)
|
|
|
|
|
|
def _write(tmp_path, text):
|
|
path = tmp_path / 'layer.yaml'
|
|
path.write_text(text, encoding='utf-8')
|
|
return str(path)
|
|
|
|
|
|
# ------------------------------------------------------------- duplicate keys
|
|
|
|
def test_a_duplicate_key_at_the_top_level_raises(tmp_path):
|
|
path = _write(tmp_path, u'a: 1\nb: 2\na: 3\n')
|
|
with pytest.raises(DuplicateKeyError) as caught:
|
|
strings_only_yaml_reader()(path)
|
|
assert 'Duplicate key' in str(caught.value)
|
|
|
|
|
|
def test_a_duplicate_key_NESTED_raises_too(tmp_path):
|
|
"""The shape the incident actually had. A top-level-only check would have
|
|
read that file happily and thrown the layer away in production."""
|
|
path = _write(tmp_path, u'checks:\n'
|
|
u' rules:\n'
|
|
u' cap_label_mismatch_is_view_specific: true\n'
|
|
u' other: 1\n'
|
|
u' cap_label_mismatch_is_view_specific: false\n')
|
|
with pytest.raises(DuplicateKeyError) as caught:
|
|
strings_only_yaml_reader()(path)
|
|
said = str(caught.value)
|
|
assert 'cap_label_mismatch_is_view_specific' in said
|
|
assert 'line 5' in said # the SECOND statement: the one to delete
|
|
|
|
|
|
def test_a_duplicate_inside_a_list_item_raises(tmp_path):
|
|
path = _write(tmp_path, u'items:\n - name: a\n size: 1\n name: b\n')
|
|
with pytest.raises(DuplicateKeyError):
|
|
strings_only_yaml_reader()(path)
|
|
|
|
|
|
def test_the_same_key_in_two_different_mappings_is_fine(tmp_path):
|
|
"""Not a duplicate. A checker that called this one would be unusable --
|
|
every knowledge file names `note:` under a dozen different parents."""
|
|
path = _write(tmp_path, u'a:\n note: x\nb:\n note: y\n')
|
|
assert strings_only_yaml_reader()(path) == {'a': {'note': 'x'},
|
|
'b': {'note': 'y'}}
|
|
|
|
|
|
def test_a_clean_file_still_reads_and_still_comes_back_as_strings(tmp_path):
|
|
path = _write(tmp_path, u'n: 1.5\nflag: true\nempty: null\n')
|
|
assert strings_only_yaml_reader()(path) == {'n': '1.5', 'flag': 'true',
|
|
'empty': 'null'}
|
|
|
|
|
|
def test_a_document_pyyaml_cannot_parse_is_not_judged_for_duplicates():
|
|
"""Stated out loud rather than left to be discovered: this detector has
|
|
exactly one question, and it answers `no duplicate found` for a document
|
|
it could not read at all. `tools/knowledgelint.py` is the check that does
|
|
refuse those, and it is the one the landing agents run."""
|
|
raise_on_duplicate_keys(u'a:\n - [1, 2\n') # does not raise
|
|
|
|
|
|
def test_the_message_leads_with_the_words_pyrevit_uses():
|
|
"""The string in the message is what a person sees in Self Check and in
|
|
`config_problems()`, and what they will search for."""
|
|
with pytest.raises(DuplicateKeyError) as caught:
|
|
raise_on_duplicate_keys(u'a: 1\na: 2\n', path='C:/plant/k.yaml')
|
|
said = str(caught.value)
|
|
assert said.startswith('Duplicate key')
|
|
assert 'C:/plant/k.yaml' in said
|
|
|
|
|
|
# ---------------------------------------------------------------- the strings
|
|
|
|
def test_every_scalar_comes_back_as_text():
|
|
"""The other way this double was once kinder than production."""
|
|
assert stringify_like_yamldotnet(
|
|
{'a': 1.5, 'b': True, 'c': None, 'd': [1, {'e': False}]}) == \
|
|
{'a': '1.5', 'b': 'true', 'c': 'null', 'd': ['1', {'e': 'false'}]}
|