docs / Suite de conformidadConformance suite
Suite de conformidad de .mini (especificación 1.0)#
Casos independientes del lenguaje para comprobar que una implementación de
.mini (Python, TypeScript u otra) se comporta como exige SPEC.md. Todas las
implementaciones deben ejecutar la misma lógica de runner descrita abajo.
python conformance/run_python.py # resumen por categoría (sale con 1 si algo falla)
python conformance/run_python.py -v # muestra el motivo de cada fallo
python conformance/run_python.py -k quotes
python conformance/generate.py # regenera cases/*.json
La suite también corre dentro de pytest (tests/test_conformance.py).
Archivos#
| Ruta | Contenido |
|---|---|
cases/<categoría>.json |
{"suite", "spec", "category", "cases": [caso, ...]} |
generate.py |
Fuente de los casos. Las expectativas salen de los fixtures publicados en forks/*/fixtures o están escritas a mano desde SPEC.md; nunca se calculan ejecutando la implementación. |
run_python.py |
Runner de referencia contra minifmt. |
Los casos que usan family leen forks/<family>/contract.json desde la raíz
del repositorio.
Formato de un caso#
{
"id": "quote-doubled",
"category": "quotes",
"description": "\"\" dentro de comillas es una comilla",
"mode": "strict",
"family": "a",
"contract": { "...": "contrato embebido, alternativa a family" },
"parent": "a",
"input": "mk|n=1\n\"dijo \"\"sí\"\"\"*,no|a*|a|1",
"expected": {
"canonical": { "prefix": "mk", "header": {"n": 1, "v": 1}, "rows": [ ... ] },
"errors": [ {"code": "E08", "line": 2} ],
"mini": "texto .mini esperado al serializar",
"rejected": true,
"diagnostics": { "invalid_lines": [3], "missing_records": 0 }
}
}
- Cada caso tiene exactamente uno de
family(nombre de familia oficial) ocontract(contrato embebido con el mismo esquema quecontract.json), salvo el modocontract, que no usa ninguno. inputes texto.mini(modosstrictylenient), un objeto canónico (mododumps), un contrato (modocontract) onull(modofork).- En
expectedsolo aparecen las claves que aplican al modo.
Semántica de los modos (lógica del runner)#
Comparaciones comunes:
- Errores: se comparan como conjunto de pares distintos
(code, line); el orden y las repeticiones no importan.linees la línea física (1-based, contando las líneas en blanco omitidas); los errores de documento (E01, E04) y los de contrato/fork (E20, E21) usan línea0. - Canónico: igualdad estructural; las claves de los objetos se comparan
como conjunto y los números numéricamente (
-1≡-1.0, tolerancia 1e-12). Los campos ausentes de un registro valennull; una lista marcada aparece como dos claves hermanas (elementos y selección).
| Modo | Acción | Pasa si |
|---|---|---|
strict |
parse(input, contract, strict) |
Si expected.errors existe: el documento se rechaza y los pares coinciden. Si no: se acepta, el canónico coincide con expected.canonical y, cuando hay expected.mini, dumps(canónico) == mini y parse(mini) vuelve a dar el mismo canónico (ida y vuelta). |
lenient |
parse(input, contract, lenient) |
Si hay expected.canonical: se devuelve un documento con esos registros válidos (y la cabecera leída), y sus errores coinciden con expected.errors (lista vacía = sin errores). Si no hay canonical: el documento no se puede construir (p. ej. E01) y los errores coinciden. Si hay expected.diagnostics: las líneas rechazadas (ascendentes, sin la cabecera) y los registros faltantes (n − líneas de registro, mínimo 0) coinciden. |
dumps |
dumps(input, contract) |
Si expected.rejected: el serializador lanza un error (el código no se compara). Si no: el texto es idéntico a expected.mini byte a byte y ese texto se acepta en modo estricto. |
contract |
cargar input como contrato |
Los errores (E20, línea 0) coinciden; [] significa contrato válido. |
fork |
comprobar contract/family contra parent (nombre de familia o contrato embebido) |
Los errores de invariantes (E21, línea 0) coinciden como conjunto; [] significa bifurcación válida. |
Un fallo inesperado de la implementación (excepción no prevista) cuenta como caso fallido.
Categorías#
| Categoría | Cubre |
|---|---|
fixtures |
valid.mini ↔ canonical.json y cada bad_*.mini de las 14 familias |
lenient |
cada bad_*.mini en modo tolerante: registros válidos conservados |
escapes |
\| \, \; \* \" \\ \n, escapes inválidos y colgantes (E09), CRLF, escaping.mini de cada familia |
quotes |
elementos entre comillas estilo CSV, "", marcador dentro o fuera, E09 |
lists |
aridad min/max/count_key (E07), tipos de elementos, separador propio |
mlist |
las cuatro reglas de marcador (E08) y la forma canónica de la selección |
tuples |
aridad (E07), componentes opcionales, marcador prohibido |
optionals |
campos vacíos, cola de extensiones, requeridos vacíos (E06) |
arity |
menos campos que el núcleo, o campos excedentes sin v posterior (E05) |
types |
int, float, bool, enum (E06, E10, E13) |
unique |
E11 y su interacción con el modo tolerante |
header |
E01, E02, E03, E04, E12, BOM, líneas en blanco, claves tipadas y desconocidas |
truncation |
último registro incompleto, líneas faltantes, diagnóstico de regeneración |
roundtrip |
serialización canónica y su rechazo de objetos inválidos |
contract |
contratos inválidos (E20) |
fork |
invariantes I3/I4 del protocolo de bifurcación (E21) |
Puntos no fijados por la suite#
La suite evita, a propósito, comportamientos que SPEC.md 1.0 no define con
precisión; quedan pendientes de decisión:
\,cuando el separador del contrato no es,(la gramática lo excluye; la implementación de referencia lo acepta).- Booleanos distintos de
true/false/1/0(la referencia acepta tambiényes/no/y/n/t/f), enteros con+y floats como.5o1.. - Código de un valor de cabecera con tipo incorrecto (
n=abcproduce E06 y E03 en la referencia; la tabla de §8 sugiere E12). - Claves de cabecera duplicadas (la referencia conserva la última).
- Elementos vacíos en listas (
a,,bo separador final): la referencia los acepta como cadena vacía, lo que rompe la ida y vuelta de[""]. - Lista opcional vacía: la referencia devuelve
[]y nonull. - Código de error del serializador ante objetos inválidos.
.mini conformance suite (specification 1.0)#
Language-independent cases to check that a .mini implementation (Python,
TypeScript or another) behaves as SPEC.md requires. Every implementation must
run the same runner logic described below.
python conformance/run_python.py # summary by category (exits 1 if anything fails)
python conformance/run_python.py -v # shows the reason for each failure
python conformance/run_python.py -k quotes
python conformance/generate.py # regenerates cases/*.json
The suite also runs inside pytest (tests/test_conformance.py).
Files#
| Path | Content |
|---|---|
cases/<category>.json |
{"suite", "spec", "category", "cases": [case, ...]} |
generate.py |
Source of the cases. Expectations come from the fixtures published in forks/*/fixtures or are handwritten from SPEC.md; they are never computed by running the implementation. |
run_python.py |
Reference runner against minifmt. |
Cases using family read forks/<family>/contract.json from the repository root.
Case format#
{
"id": "quote-doubled",
"category": "quotes",
"description": "\"\" inside quotes is one quote",
"mode": "strict",
"family": "a",
"contract": { "...": "embedded contract, alternative to family" },
"parent": "a",
"input": "mk|n=1\n\"dijo \"\"sí\"\"\"*,no|a*|a|1",
"expected": {
"canonical": { "prefix": "mk", "header": {"n": 1, "v": 1}, "rows": [ ... ] },
"errors": [ {"code": "E08", "line": 2} ],
"mini": "expected .mini text when serializing",
"rejected": true,
"diagnostics": { "invalid_lines": [3], "missing_records": 0 }
}
}
- Each case has exactly one of
family(official family name) orcontract(embedded contract with the same schema ascontract.json), exceptcontractmode, which uses neither. inputis.minitext (strictandlenientmodes), a canonical object (dumpsmode), a contract (contractmode) ornull(forkmode).expectedonly contains the keys that apply to the mode.
Mode semantics (runner logic)#
Common comparisons:
- Errors: compared as a set of distinct
(code, line)pairs; order and repetition do not matter.lineis the physical line (1-based, counting skipped blank lines); document errors (E01, E04) and contract/fork errors (E20, E21) use line0. - Canonical: structural equality; object keys are compared as a set and numbers
numerically (
-1≡-1.0, 1e-12 tolerance). A record's missing fields count asnull; a marked list appears as two sibling keys (elements and selection).
| Mode | Action | Passes if |
|---|---|---|
strict |
parse(input, contract, strict) |
If expected.errors exists: the document is rejected and the pairs match. If not: it is accepted, the canonical matches expected.canonical and, when expected.mini exists, dumps(canonical) == mini and parse(mini) yields the same canonical again (round-trip). |
lenient |
parse(input, contract, lenient) |
If expected.canonical exists: a document is returned with those valid records (and the header read), and its errors match expected.errors (empty list = no errors). If there is no canonical: the document cannot be built (e.g. E01) and the errors match. If expected.diagnostics exists: the rejected lines (ascending, without the header) and the missing records (n − record lines, minimum 0) match. |
dumps |
dumps(input, contract) |
If expected.rejected: the serializer throws an error (the code is not compared). If not: the text is byte-for-byte identical to expected.mini and that text is accepted in strict mode. |
contract |
load input as a contract |
The errors (E20, line 0) match; [] means valid contract. |
fork |
check contract/family against parent (family name or embedded contract) |
The invariant errors (E21, line 0) match as a set; [] means valid fork. |
An unexpected implementation failure (unforeseen exception) counts as a failed case.
Categories#
| Category | Covers |
|---|---|
fixtures |
valid.mini ↔ canonical.json and each bad_*.mini of the 14 families |
lenient |
each bad_*.mini in lenient mode: valid records kept |
escapes |
\| \, \; \* \" \\ \n, invalid and dangling escapes (E09), CRLF, each family's escaping.mini |
quotes |
CSV-style quoted elements, "", marker inside or outside, E09 |
lists |
min/max/count_key arity (E07), element types, custom separator |
mlist |
the four marker rules (E08) and the canonical form of the selection |
tuples |
arity (E07), optional components, marker forbidden |
optionals |
empty fields, extension tail, empty requireds (E06) |
arity |
fewer fields than the core, or excess fields without a later v (E05) |
types |
int, float, bool, enum (E06, E10, E13) |
unique |
E11 and its interaction with lenient mode |
header |
E01, E02, E03, E04, E12, BOM, blank lines, typed and unknown keys |
truncation |
incomplete last record, missing lines, regeneration diagnostics |
roundtrip |
canonical serialization and its rejection of invalid objects |
contract |
invalid contracts (E20) |
fork |
I3/I4 invariants of the forking protocol (E21) |
Points not pinned by the suite#
The suite deliberately avoids behavior that SPEC.md 1.0 does not define precisely;
it awaits a decision:
\,when the contract separator is not,(the grammar excludes it; the reference implementation accepts it).- Booleans other than
true/false/1/0(the reference also acceptsyes/no/y/n/t/f), integers with+and floats like.5or1.. - Error code of a mistyped header value (
n=abcproduces E06 and E03 in the reference; the §8 table suggests E12). - Duplicate header keys (the reference keeps the last).
- Empty list elements (
a,,bor trailing separator): the reference accepts them as the empty string, which breaks the round-trip of[""]. - Empty optional list: the reference returns
[], notnull. - Serializer error code for invalid objects.