leptris 1.9.390.3-ppc64le-linux → 1.9.394.0-ppc64le-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c2ce6913148ab354fb289a8384956048725fbeeb5d6d9becd6a5de080377b4c8
4
- data.tar.gz: a2feecb8fe74b051f8577e9234dd31fb0b0ffd2d26de9f769e877d67327ddebf
3
+ metadata.gz: 7e3208fdd19dc20eb05cdeaff72a587f053ec9e9b338b863afcc18065f12ba50
4
+ data.tar.gz: cbb3a90c5c594faee31b9fd845b127edb7dadf2d3952f9e6f02cc1c8718de675
5
5
  SHA512:
6
- metadata.gz: 3e1cbe14ad5914f9d4ac797fd257ce558931a8c58a547c9a8ce478070828f6c59251c1710b576582aa1bb1e4eecc88acf6bede24a378a94733d7551ca2de127b
7
- data.tar.gz: 70f3c83560237ab67d8e378cc6527741d6be5f9159e37a099a537834d6ab2ba701ad325d3bc1d83ebc3c95a0cbe1f00913e55365680df7555875cdab1a251c85
6
+ metadata.gz: f4d47ec0dd4ca188ffd7e04048b7c4efbdc708d60ce2a93a546a6eeba020c28f9fe8a22ca0cc7821729200357d0fece1c1ab4667fa95c4ad8ede11aeb5ce161b
7
+ data.tar.gz: c3f0b734f40bcda5aa98df85fd2b0a0c93239f986c23d4035b58ec205183082b07594bf5b3baff1dc9655a7649fbf6ebb19e9d9facdc1014a378b03a83e309f7
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ RSpec::Core::RakeTask.new(:spec)
8
8
  # Pin for `rake compile` and the platform-gem builds. Keep in lockstep
9
9
  # with .github/workflows/build.yml (which calls `rake compile`) and the
10
10
  # CHANGELOG when libleptris releases.
11
- LIBLEPTRIS_VERSION = "1.9.390"
11
+ LIBLEPTRIS_VERSION = "1.9.394"
12
12
  # Vendored alongside libleptris for fn:normalize-unicode (TODO
13
13
  # .restructure/20): built per platform with a RELOCATABLE @rpath
14
14
  # install name, loaded by ffi.rb before libleptris so the
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.390.3"
4
+ VERSION = "1.9.394.0"
5
5
  end
data/lib/libleptris.so CHANGED
Binary file
data/vendor-src/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  Sources vendored in this gem (recompile rights; the ruby
2
2
  variant builds them at install via extconf.rb):
3
3
 
4
- - libleptris v1.9.390
4
+ - libleptris v1.9.394
5
5
  - utf8proc v2.11.0
6
6
 
7
7
  Rebuild by hand:
@@ -1,5 +1,106 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.9.394] - 2026-10-30
4
+
5
+ ### Fixed
6
+
7
+ - **xs:override loads its base and replaces the overridden components
8
+ (leptris#1913, PR #1917).** `override` was absent from the
9
+ declaration gate and the include-family chase, so the base document
10
+ never loaded and the override body's nested declarations were never
11
+ captured — the compiled schema had an empty symbol space (decls=0,
12
+ every instance element "not declared"). Override now chases its
13
+ schemaLocation like include (same targetNamespace), then captures
14
+ its own declaration children as a pseudo-root AFTER the base so the
15
+ head-first lookup ladder sees the replacements; the attributeGroup
16
+ pre-pass honors a capture-force flag in that body, and the ref-check
17
+ declaration collector walks the override body too. Witness: base
18
+ `Doc` replaced by the override's `Doc` — `<doc><b>1</b></doc>`
19
+ validates, `<doc><a>x</a></doc>` is rejected.
20
+
21
+
22
+
23
+ ## [1.9.393] - 2026-10-30
24
+
25
+ ### Added
26
+
27
+ - **Capability bit for entity-reference nodes (leptris#1904, PR #1915).**
28
+ `LEPTRIS_PARSE_KEEP_ENTITY_REFS` already parses references as
29
+ first-class `LEPTRIS_NODE_TYPE_ENTITY_REF` nodes — text segments
30
+ split around the five built-ins and custom named references
31
+ (numeric character references stay text, XML 1.0 §4.1) — but
32
+ nothing advertised it. `LEPTRIS_CAP_ENTITY_REF_NODES` lets a
33
+ binding probe once and parse with the flag instead of re-scanning
34
+ expanded text; a spec pins the DOM shape and the
35
+ string-value / serialization / XPath agreement.
36
+
37
+ ### Fixed
38
+
39
+ - **XSD 1.1 was inert for every `vc:minVersion`-marked schema
40
+ (leptris#1910, leptris#1911, PR #1914).** The version detector
41
+ read only the root's plain `version` attribute; the W3C suite and
42
+ the binding ecosystem mark 1.1 with `vc:minVersion` in the
43
+ versioning namespace. With the capture gates off,
44
+ `xs:alternative` and `xs:assert` compiled to nothing —
45
+ conditional type assignment applied the declared base type's
46
+ model in both directions (false rejects and false accepts), and
47
+ asserts never attached to their types. The detector now honors
48
+ `version`, `vc:minVersion`, and a `vc:maxVersion="1.0"` pin, and
49
+ `xs:openContent` interleave/suffix semantics engage with it
50
+ (leptris#1912's repro validates clean).
51
+ - **Value-comparison keywords accept name-test operands
52
+ (`w le h`).** The XPath `eq/ne/lt/le/gt/ge` operators only read
53
+ as operators when the right operand opened with a scalar, paren,
54
+ variable, or function call — an `xs:assert test="w le h"` failed
55
+ to compile. Adjacent name tokens are never a valid path
56
+ continuation, so a bare name-test follower is unambiguously an
57
+ operand; every path start is now admitted.
58
+
59
+
60
+
61
+ ## [1.9.392] - 2026-10-30
62
+
63
+ ### Added
64
+
65
+ - **Capability descriptor face (leptris#1905, PR #1908).**
66
+ `leptris_capabilities()` returns a versioned bitset of every face
67
+ this installed engine serves — the engine-side half of the
68
+ moxml#504 capability report. Bindings OR it with their own wrapper
69
+ knowledge instead of maintaining scattered version-gate
70
+ constants; build-conditional faces (DUCET collation, utf8proc,
71
+ iconv, AVX2) follow the same `LEPTRIS_HAS_*` macros that gate the
72
+ sources, so the descriptor cannot drift from the binary it ships
73
+ in. Contract: bits append, never reorder; the descriptor version
74
+ gates shape changes. The spec anchors every unconditional bit to
75
+ its real face symbol — a bit without a linked face fails the
76
+ build, not the assertion.
77
+
78
+
79
+
80
+ ## [1.9.391] - 2026-10-30
81
+
82
+ ### Fixed
83
+
84
+ - **XSD: resolve attributeGroup ref rows the pre-pass captured
85
+ before its imports (leptris-ruby#569, PR #1906).** The #1880
86
+ attributeGroup pre-pass captures each unit's group defs *before*
87
+ that unit's imports are chased, so an `<xs:attribute ref="r:embed"/>`
88
+ row whose declaration lives in a later-imported unit found no
89
+ global attribute and was silently dropped. Types were left
90
+ hole-punched (whole-instance validation then rejected `a:blip
91
+ @r:embed` with "not declared (strict)" on the OOXML `wml.xsd`
92
+ chain — clean on 1.9.368.1, regressed by the 386-390 wave) or
93
+ attribute-less, which skipped the strict attribute walk entirely
94
+ and false-validated foreign attributes. Unresolved ref rows are
95
+ now kept pending — with the ref's own `use=` override recorded —
96
+ and re-resolved against the merged top-level attribute table once
97
+ the whole capture has run; row copies carry the flag so referencing
98
+ types heal too. Witness: the real uniword `wml.xsd` (1826
99
+ declarations) compiles clean and a docx-style document with
100
+ `a:blip r:embed` validates 1.
101
+
102
+
103
+
3
104
  ## [1.9.390] - 2026-10-29
4
105
 
5
106
  ### Fixed
@@ -3,7 +3,7 @@
3
3
  cmake_minimum_required(VERSION 3.20)
4
4
 
5
5
  project(leptris
6
- VERSION 1.9.390
6
+ VERSION 1.9.394
7
7
  DESCRIPTION "Fast XML parser and XPath evaluator in pure C"
8
8
  LANGUAGES C CXX
9
9
  )
@@ -744,6 +744,43 @@ To pin enum values (bindings hard-code these):
744
744
  ctest --test-dir build -R HeaderHygiene
745
745
  ----
746
746
 
747
+ === Capability descriptor (one call: what does this engine serve?)
748
+
749
+ Bindings and embedders stop maintaining scattered version-gate
750
+ constants: one call returns a versioned bitset of every face this
751
+ installed engine serves. Build-conditional faces (Unicode
752
+ normalization, iconv, DUCET collation, AVX2) answer honestly for the
753
+ exact library you linked. New capabilities APPEND bits — the
754
+ descriptor version gates shape changes.
755
+
756
+ [source,c]
757
+ ----
758
+ LeptrisCapabilities c = leptris_capabilities();
759
+ if (c.descriptor_version >= 1 && (c.caps & LEPTRIS_CAP_XSD)) {
760
+ /* xsd compile/validate faces are present */
761
+ }
762
+ ----
763
+
764
+ Entity references: parsing with `LEPTRIS_PARSE_KEEP_ENTITY_REFS`
765
+ yields `LEPTRIS_NODE_TYPE_ENTITY_REF` nodes instead of pre-expanded
766
+ text — segments split around the five built-ins and custom named
767
+ references (numeric character references stay text, per XML 1.0
768
+ §4.1). String-value, serialization, and XPath all see the expanded
769
+ value. Probe `LEPTRIS_CAP_ENTITY_REF_NODES` before relying on the
770
+ mode.
771
+
772
+ The bits: `LEPTRIS_CAP_PARSE`, `LEPTRIS_CAP_DOM`, `LEPTRIS_CAP_XPATH`,
773
+ `LEPTRIS_CAP_XQUERY`, `LEPTRIS_CAP_DTD`, `LEPTRIS_CAP_SAX`,
774
+ `LEPTRIS_CAP_HTML`, `LEPTRIS_CAP_XINCLUDE`, `LEPTRIS_CAP_DIFF`,
775
+ `LEPTRIS_CAP_DIGEST`, `LEPTRIS_CAP_XSD`, `LEPTRIS_CAP_XSD_SET`,
776
+ `LEPTRIS_CAP_RELAXNG`, `LEPTRIS_CAP_SCHEMATRON`, `LEPTRIS_CAP_XSLT`,
777
+ `LEPTRIS_CAP_DESCRIPTOR`, `LEPTRIS_CAP_NS_SNAPSHOT_BULK`,
778
+ `LEPTRIS_CAP_CHILDREN_BATCH`, `LEPTRIS_CAP_NAME_COMPARE`,
779
+ `LEPTRIS_CAP_VERSION`, and the build-conditional
780
+ `LEPTRIS_CAP_COLLATION_DUCET`, `LEPTRIS_CAP_UNICODE_UTF8PROC`,
781
+ `LEPTRIS_CAP_ENCODING_ICONV`, `LEPTRIS_CAP_SIMD_AVX2`,
782
+ `LEPTRIS_CAP_ENTITY_REF_NODES`.
783
+
747
784
  [#FFI]
748
785
  == FFI design
749
786
 
@@ -447,6 +447,58 @@ typedef struct leptris_xpath_compiled* LeptrisXPathCompiled;
447
447
  * compiled — apply it to any number of documents, from any threads. */
448
448
  typedef struct leptris_xslt* LeptrisXslt;
449
449
 
450
+ /* ============================================================================
451
+ * Capability Descriptor (leptris#1905)
452
+ * ============================================================================ */
453
+
454
+ /* What this INSTALLED engine serves — one call, one versioned
455
+ * bitset. Contract: new capabilities APPEND bits; a bit is never
456
+ * removed, repurposed, or reordered — that is a descriptor-version
457
+ * bump. Build-conditional faces (utf8proc/iconv/DUCET/AVX2) answer
458
+ * honestly for the exact library a consumer linked. Bindings OR
459
+ * this with their own wrapper knowledge; consumers stop maintaining
460
+ * scattered version-gate constants. */
461
+ enum {
462
+ LEPTRIS_CAP_PARSE = 1ULL << 0,
463
+ LEPTRIS_CAP_DOM = 1ULL << 1,
464
+ LEPTRIS_CAP_XPATH = 1ULL << 2,
465
+ LEPTRIS_CAP_XQUERY = 1ULL << 3,
466
+ LEPTRIS_CAP_DTD = 1ULL << 4,
467
+ LEPTRIS_CAP_SAX = 1ULL << 5,
468
+ LEPTRIS_CAP_HTML = 1ULL << 6,
469
+ LEPTRIS_CAP_XINCLUDE = 1ULL << 7,
470
+ LEPTRIS_CAP_DIFF = 1ULL << 8,
471
+ LEPTRIS_CAP_DIGEST = 1ULL << 9,
472
+ LEPTRIS_CAP_XSD = 1ULL << 10,
473
+ LEPTRIS_CAP_XSD_SET = 1ULL << 11,
474
+ LEPTRIS_CAP_RELAXNG = 1ULL << 12,
475
+ LEPTRIS_CAP_SCHEMATRON = 1ULL << 13,
476
+ LEPTRIS_CAP_XSLT = 1ULL << 14,
477
+ LEPTRIS_CAP_DESCRIPTOR = 1ULL << 15,
478
+ LEPTRIS_CAP_NS_SNAPSHOT_BULK = 1ULL << 16,
479
+ LEPTRIS_CAP_CHILDREN_BATCH = 1ULL << 17,
480
+ LEPTRIS_CAP_NAME_COMPARE = 1ULL << 18,
481
+ LEPTRIS_CAP_VERSION = 1ULL << 19,
482
+ /* build-conditional */
483
+ LEPTRIS_CAP_COLLATION_DUCET = 1ULL << 20,
484
+ LEPTRIS_CAP_UNICODE_UTF8PROC = 1ULL << 21,
485
+ LEPTRIS_CAP_ENCODING_ICONV = 1ULL << 22,
486
+ LEPTRIS_CAP_SIMD_AVX2 = 1ULL << 23,
487
+ /* LEPTRIS_PARSE_KEEP_ENTITY_REFS yields entity references as
488
+ * first-class ENTITY_REF nodes (segments split around the five
489
+ * built-ins and custom named references; leptris#1904). */
490
+ LEPTRIS_CAP_ENTITY_REF_NODES = 1ULL << 24
491
+ };
492
+
493
+ /* Descriptor shape version: 1. Bump when the STRUCT changes or a
494
+ * bit is retired (never expected — bits append). */
495
+ #define LEPTRIS_CAPS_DESCRIPTOR_VERSION 1u
496
+
497
+ typedef struct leptris_capabilities {
498
+ unsigned long long caps;
499
+ unsigned descriptor_version;
500
+ } LeptrisCapabilities;
501
+
450
502
  /* ============================================================================
451
503
  * Memory Allocation Function Types
452
504
  * ============================================================================ */
@@ -4230,6 +4230,12 @@ LEPTRIS_API const char* leptris_version(void);
4230
4230
  */
4231
4231
  LEPTRIS_API void leptris_version_components(int* major, int* minor, int* patch);
4232
4232
 
4233
+ /* leptris#1905: the capability descriptor — what this installed
4234
+ * engine serves, as a versioned bitset (LEPTRIS_CAP_*). Query once
4235
+ * at attach; new capabilities append bits (the descriptor version
4236
+ * gates shape changes). Thread-safe: pure, allocation-free. */
4237
+ LEPTRIS_API LeptrisCapabilities leptris_capabilities(void);
4238
+
4233
4239
  /**
4234
4240
  * Release this thread's libleptris caches
4235
4241
  *
@@ -72,6 +72,37 @@ LEPTRIS_API void leptris_version_components(int* major, int* minor, int* patch)
72
72
  if (patch) *patch = LEPTRIS_VERSION_PATCH;
73
73
  }
74
74
 
75
+ /* leptris#1905: the capability descriptor. Unconditional faces are
76
+ * always compiled into this library; the build-conditional bits
77
+ * follow the same macros the build system defines for the sources
78
+ * — the descriptor cannot drift from the binary it ships in. */
79
+ LEPTRIS_API LeptrisCapabilities leptris_capabilities(void) {
80
+ LeptrisCapabilities c;
81
+ c.caps = LEPTRIS_CAP_PARSE | LEPTRIS_CAP_DOM | LEPTRIS_CAP_XPATH |
82
+ LEPTRIS_CAP_XQUERY | LEPTRIS_CAP_DTD | LEPTRIS_CAP_SAX |
83
+ LEPTRIS_CAP_HTML | LEPTRIS_CAP_XINCLUDE | LEPTRIS_CAP_DIFF |
84
+ LEPTRIS_CAP_DIGEST | LEPTRIS_CAP_XSD | LEPTRIS_CAP_XSD_SET |
85
+ LEPTRIS_CAP_RELAXNG | LEPTRIS_CAP_SCHEMATRON |
86
+ LEPTRIS_CAP_XSLT | LEPTRIS_CAP_DESCRIPTOR |
87
+ LEPTRIS_CAP_NS_SNAPSHOT_BULK | LEPTRIS_CAP_CHILDREN_BATCH |
88
+ LEPTRIS_CAP_NAME_COMPARE | LEPTRIS_CAP_VERSION |
89
+ LEPTRIS_CAP_ENTITY_REF_NODES;
90
+ #if defined(LEPTRIS_HAS_DUCET)
91
+ c.caps |= LEPTRIS_CAP_COLLATION_DUCET;
92
+ #endif
93
+ #if defined(LEPTRIS_HAS_UTF8PROC)
94
+ c.caps |= LEPTRIS_CAP_UNICODE_UTF8PROC;
95
+ #endif
96
+ #if defined(LEPTRIS_HAS_ICONV)
97
+ c.caps |= LEPTRIS_CAP_ENCODING_ICONV;
98
+ #endif
99
+ #if defined(LEPTRIS_HAS_AVX2_BUILD)
100
+ c.caps |= LEPTRIS_CAP_SIMD_AVX2;
101
+ #endif
102
+ c.descriptor_version = LEPTRIS_CAPS_DESCRIPTOR_VERSION;
103
+ return c;
104
+ }
105
+
75
106
  LEPTRIS_API void leptris_thread_cleanup(void) {
76
107
  leptris_xpath_drain_thread_caches();
77
108
  leptris_root_doc_drain_thread_caches();
@@ -643,44 +643,26 @@ static XPathASTNode* parse_string_concat_expr(XPathParser* parser) {
643
643
  }
644
644
 
645
645
  /* True when the token AFTER a bare value-comparison keyword may
646
- * START an operand. The base list covers scalars/parens; an NCName
647
- * qualifies ONLY when it opens a function call — a bare NCName
648
- * follower stays a path step (XPath 1.0 name-test precedence). */
646
+ * START an operand. Scalars, parens, variables, and (leptris#1910)
647
+ * every path start: a bare NCName/QName is an element name test in
648
+ * operand position, and adjacent name tokens are never a valid
649
+ * path continuation, so the keyword reading is unambiguous
650
+ * (`w le h` in xs:assert/xs:alternative tests). */
649
651
  static int kw_operand_boundary(XPathParser* parser, XPathToken* nx) {
652
+ (void)parser;
650
653
  if (!nx) return 1;
651
654
  switch (nx->type) {
652
655
  case TOK_EOF: case TOK_RPAREN: case TOK_COMMA:
653
656
  case TOK_RBRACE: case TOK_LBRACE: case TOK_NUMBER:
654
657
  case TOK_STRING: case TOK_DOLLAR: case TOK_LPAREN:
655
658
  case TOK_MINUS: case TOK_PLUS:
659
+ case TOK_SLASH: case TOK_DOUBLE_SLASH: case TOK_AT:
660
+ case TOK_DOT: case TOK_DOUBLE_DOT: case TOK_STAR:
656
661
  return 1;
657
662
  case TOK_QNAME:
658
- /* prefixed call: QName '(' — a lone QName stays a path
659
- * step (name-test precedence, like NCName). */
660
- case TOK_NCNAME: {
661
- /* unprefixed call: name '(' ... prefixed call:
662
- * name ':' name '(' (the QT3 corpus writes fn:year-...). */
663
- XPathToken* nnx =
664
- parser->token_pos + 2 < parser->token_count
665
- ? &parser->tokens[parser->token_pos + 2]
666
- : NULL;
667
- if (nnx && nnx->type == TOK_LPAREN) return 1;
668
- XPathToken* t3 =
669
- parser->token_pos + 3 < parser->token_count
670
- ? &parser->tokens[parser->token_pos + 3]
671
- : NULL;
672
- XPathToken* t4 =
673
- parser->token_pos + 4 < parser->token_count
674
- ? &parser->tokens[parser->token_pos + 4]
675
- : NULL;
676
- XPathToken* t5 =
677
- parser->token_pos + 5 < parser->token_count
678
- ? &parser->tokens[parser->token_pos + 5]
679
- : NULL;
680
- return nnx && nnx->type == TOK_COLON && t3 &&
681
- t3->type == TOK_NCNAME && t4 &&
682
- t4->type == TOK_LPAREN && t5;
683
- }
663
+ case TOK_NCNAME:
664
+ /* name test, function call, or prefixed call */
665
+ return 1;
684
666
  default:
685
667
  return 0;
686
668
  }
@@ -51,7 +51,11 @@ struct leptris_xsd_schema {
51
51
  char* target_ns;
52
52
  int version_11; /* xs:schema @version = "1.1" */
53
53
  char* base_dir; /* schemaLocation resolution (file compile) */
54
- int include_depth; /* include/import recursion guard */
54
+ int include_depth;
55
+ /* xs:override body capture replaces same-named components: the
56
+ * attributeGroup pre-pass must re-register defs the base
57
+ * already captured (leptris#1913). */
58
+ int capture_force; /* include/import recursion guard */
55
59
  /* leptris#1644: already-captured schema units (canonical
56
60
  * location per entry) — the include/import DAG is dense and
57
61
  * cyclic; without this set every DAG path re-parses and
@@ -100,6 +104,7 @@ static void xsd_capture_root(struct leptris_xsd_schema* s,
100
104
  LeptrisElement root);
101
105
  static char* xsd_read_file(const char* path, size_t* out_len);
102
106
  static XsdAttrDecl* xsd_copy_attr_rows(const XsdAttrDecl* src);
107
+ static void xsd_resolve_pending_attr_refs(struct leptris_xsd_schema* s);
103
108
  static void xsd_register_complex(struct leptris_xsd_schema* s,
104
109
  XsdCm* root, XsdAttrDecl* attrs,
105
110
  const char* name, char* any_attr_ns,
@@ -678,7 +683,7 @@ static int xsd_is_declaration(const char* local, const char* uri) {
678
683
  "element", "attribute", "simpleType", "complexType",
679
684
  "group", "attributeGroup", "notation", "include",
680
685
  "defaultOpenContent",
681
- "import", "redefine", NULL
686
+ "import", "redefine", "override", NULL
682
687
  };
683
688
  for (int i = 0; names[i]; i++)
684
689
  if (strcmp(local, names[i]) == 0) return 1;
@@ -1809,7 +1814,8 @@ static void xsd_collect_decls_doc(LeptrisElement root, const char* eff_tns,
1809
1814
  if (!l || !u || strcmp(u, XSD_NS) != 0)
1810
1815
  continue;
1811
1816
  int is_inc = (strcmp(l, "include") == 0 ||
1812
- strcmp(l, "redefine") == 0);
1817
+ strcmp(l, "redefine") == 0 ||
1818
+ strcmp(l, "override") == 0);
1813
1819
  int is_imp = (strcmp(l, "import") == 0);
1814
1820
  if (!is_inc && !is_imp) continue;
1815
1821
  const char* loc = leptris_element_attribute(c, "schemaLocation");
@@ -1852,6 +1858,13 @@ static void xsd_collect_decls_doc(LeptrisElement root, const char* eff_tns,
1852
1858
  xsd_collect_decls_doc(subroot, eff, sub_base, decls, n, max,
1853
1859
  claimed, nclaimed, cmax, depth + 1);
1854
1860
  }
1861
+ /* leptris#1913: an xs:override body's declarations belong
1862
+ * to the symbol space too — walk the override element as a
1863
+ * pseudo-root (it has no include/import children of its
1864
+ * own). */
1865
+ if (strcmp(l, "override") == 0)
1866
+ xsd_collect_decls_doc(c, eff_tns, base_dir, decls, n, max,
1867
+ claimed, nclaimed, cmax, depth + 1);
1855
1868
  leptris_document_free(sub);
1856
1869
  }
1857
1870
  }
@@ -1959,8 +1972,24 @@ static LeptrisXsdSchema xsd_compile_impl(const char* xsd_text,
1959
1972
  s->target_ns = xsd_strdup(
1960
1973
  leptris_element_attribute(root, "targetNamespace"));
1961
1974
  {
1975
+ /* XSD 1.1 §4.3 schema versioning: the W3C suite and the
1976
+ * binding ecosystem mark 1.1 with vc:minVersion (the
1977
+ * versioning namespace); the plain version attribute is
1978
+ * the other legal spelling. vc:maxVersion below 1.1 pins
1979
+ * a 1.0 processor target regardless. leptris#1910/#1911:
1980
+ * reading only @version silently compiled asserts and
1981
+ * alternatives away for every vc-marked schema. */
1962
1982
  const char* ver = leptris_element_attribute(root, "version");
1963
- s->version_11 = (ver && strcmp(ver, "1.1") == 0);
1983
+ const char* vmin = leptris_element_attribute_ns(
1984
+ root, "http://www.w3.org/2001/XMLSchema-versioning",
1985
+ "minVersion");
1986
+ const char* vmax = leptris_element_attribute_ns(
1987
+ root, "http://www.w3.org/2001/XMLSchema-versioning",
1988
+ "maxVersion");
1989
+ int is11 = (ver && strcmp(ver, "1.1") == 0) ||
1990
+ (vmin && strcmp(vmin, "1.1") == 0);
1991
+ if (vmax && strcmp(vmax, "1.0") == 0) is11 = 0;
1992
+ s->version_11 = is11;
1964
1993
  }
1965
1994
 
1966
1995
  const char* local = NULL;
@@ -2021,6 +2050,7 @@ static LeptrisXsdSchema xsd_compile_impl(const char* xsd_text,
2021
2050
 
2022
2051
  xsd_capture_root(s, root);
2023
2052
  xsd_resolve_extension_bases(s);
2053
+ xsd_resolve_pending_attr_refs(s);
2024
2054
 
2025
2055
  leptris_document_free(doc);
2026
2056
  return s;
@@ -2245,7 +2275,8 @@ static void xsd_capture_root(struct leptris_xsd_schema* s,
2245
2275
 
2246
2276
  if (strcmp(local, "include") == 0 ||
2247
2277
  strcmp(local, "import") == 0 ||
2248
- strcmp(local, "redefine") == 0) {
2278
+ strcmp(local, "redefine") == 0 ||
2279
+ strcmp(local, "override") == 0) {
2249
2280
  const char* loc = leptris_element_attribute(
2250
2281
  (LeptrisElement)n, "schemaLocation");
2251
2282
  if (loc && s->base_dir && s->include_depth < 16) {
@@ -2312,6 +2343,20 @@ static void xsd_capture_root(struct leptris_xsd_schema* s,
2312
2343
  if (sub_ns) free(sub_ns);
2313
2344
  s->target_ns = saved_ns;
2314
2345
  }
2346
+ /* leptris#1913 (XSD 1.1 §I.4): the override
2347
+ * element's OWN declaration children
2348
+ * replace same-named components of the base
2349
+ * just captured — capture them AFTER the
2350
+ * base so the lookup ladder (head-first)
2351
+ * sees the replacements. */
2352
+ if (subroot && same_ns &&
2353
+ strcmp(local, "override") == 0) {
2354
+ s->include_depth++;
2355
+ s->capture_force = 1;
2356
+ xsd_capture_root(s, (LeptrisElement)n);
2357
+ s->capture_force = 0;
2358
+ s->include_depth--;
2359
+ }
2315
2360
  leptris_document_free(sub);
2316
2361
  }
2317
2362
  free(text);
@@ -2446,7 +2491,8 @@ static void xsd_capture_root(struct leptris_xsd_schema* s,
2446
2491
  XsdAttrGroupDef* seen = s->attr_groups;
2447
2492
  for (; seen; seen = seen->next)
2448
2493
  if (strcmp(seen->name, nm) == 0) break;
2449
- if (!seen) xsd_capture_attr_group_def(s, (LeptrisElement)n, nm);
2494
+ if (!seen || s->capture_force)
2495
+ xsd_capture_attr_group_def(s, (LeptrisElement)n, nm);
2450
2496
  }
2451
2497
  } else if (strcmp(local, "group") == 0 && uri && !strcmp(uri, XSD_NS)) {
2452
2498
  const char* nm =
@@ -3109,6 +3155,7 @@ static XsdAttrDecl* xsd_copy_attr_rows(const XsdAttrDecl* src) {
3109
3155
  d->type = xsd_strdup(src->type);
3110
3156
  d->fixed = xsd_strdup(src->fixed);
3111
3157
  d->required = src->required;
3158
+ d->pending_ref = src->pending_ref;
3112
3159
  if (tail)
3113
3160
  tail->next = d;
3114
3161
  else
@@ -3118,6 +3165,51 @@ static XsdAttrDecl* xsd_copy_attr_rows(const XsdAttrDecl* src) {
3118
3165
  return head;
3119
3166
  }
3120
3167
 
3168
+ /* leptris-ruby#569: re-resolve the rows the #1880 attributeGroup
3169
+ * pre-pass captured before the import chase had registered the
3170
+ * referenced unit's top-level attributes. Idempotent; pending rows
3171
+ * that never resolve keep declaring their name (untyped) — the
3172
+ * compile-time ref check already rejects true danglers loudly. */
3173
+ #define XSD_PENDING_REF 1
3174
+ #define XSD_PENDING_USE 2
3175
+ static void xsd_resolve_pending_attr_refs(struct leptris_xsd_schema* s) {
3176
+ if (!s) return;
3177
+ int progressed = 1;
3178
+ while (progressed) {
3179
+ progressed = 0;
3180
+ for (XsdAttrGroupDef* g = s->attr_groups; g; g = g->next)
3181
+ for (XsdAttrDecl* a = g->attrs; a; a = a->next) {
3182
+ if (!(a->pending_ref & XSD_PENDING_REF) || !a->name)
3183
+ continue;
3184
+ const XsdAttrDecl* src = xsd_find_top_attr(s, a->name);
3185
+ if (!src) continue;
3186
+ free(a->type);
3187
+ free(a->fixed);
3188
+ a->type = xsd_strdup(src->type);
3189
+ a->fixed = xsd_strdup(src->fixed);
3190
+ if (!(a->pending_ref & XSD_PENDING_USE))
3191
+ a->required = src->required;
3192
+ a->pending_ref &= ~XSD_PENDING_REF;
3193
+ progressed = 1;
3194
+ }
3195
+ for (XsdTypeAttrs* t = s->type_attrs; t; t = t->next)
3196
+ for (XsdAttrDecl* a = t->attrs; a; a = a->next) {
3197
+ if (!(a->pending_ref & XSD_PENDING_REF) || !a->name)
3198
+ continue;
3199
+ const XsdAttrDecl* src = xsd_find_top_attr(s, a->name);
3200
+ if (!src) continue;
3201
+ free(a->type);
3202
+ free(a->fixed);
3203
+ a->type = xsd_strdup(src->type);
3204
+ a->fixed = xsd_strdup(src->fixed);
3205
+ if (!(a->pending_ref & XSD_PENDING_USE))
3206
+ a->required = src->required;
3207
+ a->pending_ref &= ~XSD_PENDING_REF;
3208
+ progressed = 1;
3209
+ }
3210
+ }
3211
+ }
3212
+
3121
3213
  /* Capture the attribute rows of a complexType or attributeGroup:
3122
3214
  * named rows, inline anonymous simpleTypes (synthesized slots),
3123
3215
  * refs to top-level attributes, and attributeGroup refs. */
@@ -3185,16 +3277,31 @@ static XsdAttrDecl* xsd_capture_attr_rows(struct leptris_xsd_schema* s,
3185
3277
  leptris_element_attribute(ae, "ref"));
3186
3278
  const XsdAttrDecl* src =
3187
3279
  ref ? xsd_find_top_attr(s, ref) : NULL;
3188
- if (!src) {
3280
+ if (!src && !ref) {
3189
3281
  free(d);
3190
3282
  continue;
3191
3283
  }
3192
- d->name = xsd_strdup(src->name);
3193
- d->type = xsd_strdup(src->type);
3194
- d->fixed = xsd_strdup(src->fixed);
3195
- d->required = use
3196
- ? (strcmp(use, "required") == 0)
3197
- : src->required;
3284
+ if (!src) {
3285
+ /* leptris-ruby#569: the #1880 pre-pass captures
3286
+ * attributeGroup defs BEFORE the import chase
3287
+ * registers the referenced unit's globals — an
3288
+ * unresolved ref used to be silently DROPPED
3289
+ * here, hole-punching the type's rows (a:blip
3290
+ * @r:embed "not declared (strict)") or leaving
3291
+ * the type attribute-less so the strict walk
3292
+ * never ran. Keep the row pending; the
3293
+ * post-capture fixup resolves it. */
3294
+ d->name = xsd_strdup(xsd_local_name(ref));
3295
+ d->pending_ref = use ? 3 : 1;
3296
+ d->required = (use && strcmp(use, "required") == 0);
3297
+ } else {
3298
+ d->name = xsd_strdup(src->name);
3299
+ d->type = xsd_strdup(src->type);
3300
+ d->fixed = xsd_strdup(src->fixed);
3301
+ d->required = use
3302
+ ? (strcmp(use, "required") == 0)
3303
+ : src->required;
3304
+ }
3198
3305
  }
3199
3306
  if (tail)
3200
3307
  tail->next = d;
@@ -3802,5 +3909,6 @@ LEPTRIS_API LeptrisXsdSchema leptris_xsd_compile_set(
3802
3909
  s->base_dir = saved;
3803
3910
  }
3804
3911
  xsd_resolve_extension_bases(s);
3912
+ xsd_resolve_pending_attr_refs(s);
3805
3913
  return s;
3806
3914
  }
@@ -197,6 +197,15 @@ typedef struct xsd_attr_decl {
197
197
  char* type; /* builtin ref or local simpleType name (NULL=anySimple) */
198
198
  char* fixed; /* #FIXED value: present values must string-equal it */
199
199
  int required;
200
+ /* leptris-ruby#569: the row came from <xs:attribute ref=.../>
201
+ * whose global declaration was not yet captured (the #1880
202
+ * attributeGroup pre-pass runs before the import chase). The
203
+ * row is kept — never silently dropped — and xsd_compile_impl
204
+ * re-resolves it once the full merged capture has run
205
+ * (xsd_resolve_pending_attr_refs). bit 0 = ref unresolved,
206
+ * bit 1 = the ref carried its own use= (it overrides the
207
+ * declaration's). */
208
+ int pending_ref;
200
209
  struct xsd_attr_decl* next;
201
210
  } XsdAttrDecl;
202
211
 
@@ -120,11 +120,28 @@ leptris_add_test(test_large_docs parser/test_large_documents.cpp)
120
120
  leptris_add_test(test_encoding parser/test_encoding.cpp)
121
121
  leptris_add_test(test_dom dom/test_dom.cpp)
122
122
  leptris_add_test(test_element_children dom/test_element_children.cpp)
123
+ leptris_add_test(test_entity_refs dom/test_entity_refs.cpp)
123
124
  leptris_add_test(test_namespace_cache dom/test_namespace_cache.cpp)
124
125
  leptris_add_test(test_map_lifecycle dom/test_map_lifecycle.cpp)
125
126
  leptris_add_test(test_simd_count parser/test_simd_count.cpp)
126
127
  leptris_add_test(test_ws_shape parser/test_whitespace_shape.cpp)
127
128
  leptris_add_test(test_descriptor abi/test_descriptor.cpp)
129
+ leptris_add_test(test_capabilities abi/test_capabilities.cpp)
130
+ # The capability descriptor's build-conditional bits follow the
131
+ # engine's PUBLIC macros, which do not flow through the object
132
+ # aggregation (same mirror as test_qt3 below).
133
+ if(LEPTRIS_ENABLE_DUCET)
134
+ target_compile_definitions(test_capabilities PRIVATE LEPTRIS_HAS_DUCET=1)
135
+ endif()
136
+ if(LEPTRIS_ENABLE_UTF8PROC)
137
+ target_compile_definitions(test_capabilities PRIVATE LEPTRIS_HAS_UTF8PROC=1)
138
+ endif()
139
+ if(LEPTRIS_ENABLE_ICONV)
140
+ target_compile_definitions(test_capabilities PRIVATE LEPTRIS_HAS_ICONV=1)
141
+ endif()
142
+ if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|AMD64|i[3-6]86)")
143
+ target_compile_definitions(test_capabilities PRIVATE LEPTRIS_HAS_AVX2_BUILD=1)
144
+ endif()
128
145
  leptris_add_test(test_document_children dom/test_document_children.cpp)
129
146
  leptris_add_test(test_vtable dom/test_vtable.cpp)
130
147
  leptris_add_test(test_node_surface_parity dom/test_node_surface_parity.cpp)
@@ -0,0 +1,112 @@
1
+ // leptris#1905: one call answering what this installed engine
2
+ // serves. The descriptor is a versioned bitset — new capabilities
3
+ // APPEND bits, never reorder or repack (a reorder bumps
4
+ // LEPTRIS_CAPS_DESCRIPTOR_VERSION).
5
+ #include <leptris.h>
6
+ #include <leptris/descriptor.h>
7
+ #include <leptris/dtd.h>
8
+ #include <leptris/html.h>
9
+ #include <leptris/sax/sax.h>
10
+ #include <leptris/xpath/xpath.h>
11
+ #include <leptris/xquery/xquery.h>
12
+
13
+ #include <gtest/gtest.h>
14
+
15
+ // Anchor law: each unconditional bit's face symbol is REFERENCED
16
+ // here — a descriptor bit without a real, linked face fails the
17
+ // BUILD of this test, not just the assertion.
18
+ namespace caps_anchors {
19
+ void* const kParse = (void*)&leptris_parse_string;
20
+ void* const kDom = (void*)&leptris_document_root;
21
+ void* const kXpath = (void*)&leptris_xpath_eval;
22
+ void* const kXquery = (void*)&leptris_xquery_eval;
23
+ void* const kDtd = (void*)&leptris_dtd_parse;
24
+ void* const kSax = (void*)&leptris_sax_parse;
25
+ void* const kHtml = (void*)&leptris_parse_html_string;
26
+ void* const kXinclude = (void*)&leptris_xinclude_process;
27
+ void* const kDiff = (void*)&leptris_diff;
28
+ void* const kDigest = (void*)&leptris_node_digest;
29
+ void* const kXsd = (void*)&leptris_xsd_compile;
30
+ void* const kXsdSet = (void*)&leptris_xsd_compile_set;
31
+ void* const kRelaxng = (void*)&leptris_rng_parse;
32
+ void* const kSchematron = (void*)&leptris_schematron_parse;
33
+ void* const kXslt = (void*)&leptris_xslt_parse;
34
+ void* const kDescriptor = (void*)&leptris_plan_result_build_packed;
35
+ void* const kNsSnapshot = (void*)&leptris_element_namespace_declarations_snapshot;
36
+ void* const kChildrenBatch = (void*)&leptris_element_children_batch;
37
+ void* const kNameCompare = (void*)&leptris_node_name_compare;
38
+ void* const kVersion = (void*)&leptris_version;
39
+ void* const kEntityRefs = (void*)&leptris_entity_ref_node_name;
40
+ } // namespace caps_anchors
41
+
42
+ TEST(LeptrisCapabilities, DescriptorVersionIsCurrent) {
43
+ LeptrisCapabilities c = leptris_capabilities();
44
+ EXPECT_EQ(c.descriptor_version, LEPTRIS_CAPS_DESCRIPTOR_VERSION);
45
+ }
46
+
47
+ TEST(LeptrisCapabilities, UnconditionalFacesAreSet) {
48
+ LeptrisCapabilities c = leptris_capabilities();
49
+ EXPECT_NE(c.caps & LEPTRIS_CAP_PARSE, 0ULL);
50
+ EXPECT_NE(c.caps & LEPTRIS_CAP_DOM, 0ULL);
51
+ EXPECT_NE(c.caps & LEPTRIS_CAP_XPATH, 0ULL);
52
+ EXPECT_NE(c.caps & LEPTRIS_CAP_XQUERY, 0ULL);
53
+ EXPECT_NE(c.caps & LEPTRIS_CAP_DTD, 0ULL);
54
+ EXPECT_NE(c.caps & LEPTRIS_CAP_SAX, 0ULL);
55
+ EXPECT_NE(c.caps & LEPTRIS_CAP_HTML, 0ULL);
56
+ EXPECT_NE(c.caps & LEPTRIS_CAP_XINCLUDE, 0ULL);
57
+ EXPECT_NE(c.caps & LEPTRIS_CAP_DIFF, 0ULL);
58
+ EXPECT_NE(c.caps & LEPTRIS_CAP_DIGEST, 0ULL);
59
+ EXPECT_NE(c.caps & LEPTRIS_CAP_XSD, 0ULL);
60
+ EXPECT_NE(c.caps & LEPTRIS_CAP_XSD_SET, 0ULL);
61
+ EXPECT_NE(c.caps & LEPTRIS_CAP_RELAXNG, 0ULL);
62
+ EXPECT_NE(c.caps & LEPTRIS_CAP_SCHEMATRON, 0ULL);
63
+ EXPECT_NE(c.caps & LEPTRIS_CAP_XSLT, 0ULL);
64
+ EXPECT_NE(c.caps & LEPTRIS_CAP_DESCRIPTOR, 0ULL);
65
+ EXPECT_NE(c.caps & LEPTRIS_CAP_NS_SNAPSHOT_BULK, 0ULL);
66
+ EXPECT_NE(c.caps & LEPTRIS_CAP_CHILDREN_BATCH, 0ULL);
67
+ EXPECT_NE(c.caps & LEPTRIS_CAP_NAME_COMPARE, 0ULL);
68
+ EXPECT_NE(c.caps & LEPTRIS_CAP_VERSION, 0ULL);
69
+ EXPECT_NE(c.caps & LEPTRIS_CAP_ENTITY_REF_NODES, 0ULL);
70
+ }
71
+
72
+ TEST(LeptrisCapabilities, BuildConditionalBitsMatchTheBuild) {
73
+ LeptrisCapabilities c = leptris_capabilities();
74
+ #if defined(LEPTRIS_HAS_DUCET)
75
+ EXPECT_NE(c.caps & LEPTRIS_CAP_COLLATION_DUCET, 0ULL);
76
+ #else
77
+ EXPECT_EQ(c.caps & LEPTRIS_CAP_COLLATION_DUCET, 0ULL);
78
+ #endif
79
+ #if defined(LEPTRIS_HAS_UTF8PROC)
80
+ EXPECT_NE(c.caps & LEPTRIS_CAP_UNICODE_UTF8PROC, 0ULL);
81
+ #else
82
+ EXPECT_EQ(c.caps & LEPTRIS_CAP_UNICODE_UTF8PROC, 0ULL);
83
+ #endif
84
+ #if defined(LEPTRIS_HAS_ICONV)
85
+ EXPECT_NE(c.caps & LEPTRIS_CAP_ENCODING_ICONV, 0ULL);
86
+ #else
87
+ EXPECT_EQ(c.caps & LEPTRIS_CAP_ENCODING_ICONV, 0ULL);
88
+ #endif
89
+ #if defined(LEPTRIS_HAS_AVX2_BUILD)
90
+ EXPECT_NE(c.caps & LEPTRIS_CAP_SIMD_AVX2, 0ULL);
91
+ #else
92
+ EXPECT_EQ(c.caps & LEPTRIS_CAP_SIMD_AVX2, 0ULL);
93
+ #endif
94
+ }
95
+
96
+ TEST(LeptrisCapabilities, NoUnknownBits) {
97
+ LeptrisCapabilities c = leptris_capabilities();
98
+ constexpr unsigned long long kKnown =
99
+ LEPTRIS_CAP_PARSE | LEPTRIS_CAP_DOM | LEPTRIS_CAP_XPATH |
100
+ LEPTRIS_CAP_XQUERY | LEPTRIS_CAP_DTD | LEPTRIS_CAP_SAX |
101
+ LEPTRIS_CAP_HTML | LEPTRIS_CAP_XINCLUDE | LEPTRIS_CAP_DIFF |
102
+ LEPTRIS_CAP_DIGEST | LEPTRIS_CAP_XSD | LEPTRIS_CAP_XSD_SET |
103
+ LEPTRIS_CAP_RELAXNG | LEPTRIS_CAP_SCHEMATRON | LEPTRIS_CAP_XSLT |
104
+ LEPTRIS_CAP_DESCRIPTOR | LEPTRIS_CAP_NS_SNAPSHOT_BULK |
105
+ LEPTRIS_CAP_CHILDREN_BATCH | LEPTRIS_CAP_NAME_COMPARE |
106
+ LEPTRIS_CAP_VERSION | LEPTRIS_CAP_COLLATION_DUCET |
107
+ LEPTRIS_CAP_UNICODE_UTF8PROC | LEPTRIS_CAP_ENCODING_ICONV |
108
+ LEPTRIS_CAP_SIMD_AVX2 | LEPTRIS_CAP_ENTITY_REF_NODES;
109
+ EXPECT_EQ(c.caps & ~kKnown, 0ULL)
110
+ << "an unknown bit is set — the descriptor grew without "
111
+ "bumping LEPTRIS_CAPS_DESCRIPTOR_VERSION";
112
+ }
@@ -0,0 +1,111 @@
1
+ // leptris#1904: LEPTRIS_PARSE_KEEP_ENTITY_REFS yields entity
2
+ // references as FIRST-CLASS nodes — segments split around the five
3
+ // built-ins and custom named references, numeric character
4
+ // references folded into text (they are character references, not
5
+ // entity references, per XML 1.0 §4.1). The DOM the binding
6
+ // consumes: text / entity-ref / text / ... with string-value,
7
+ // serialization, and XPath walking the expanded value.
8
+ #include <gtest/gtest.h>
9
+ #include <leptris.h>
10
+ #include <cstring>
11
+ #include <string>
12
+ #include <vector>
13
+
14
+ namespace {
15
+
16
+ struct ChildInfo {
17
+ int type;
18
+ std::string text;
19
+ std::string name;
20
+ };
21
+
22
+ std::vector<ChildInfo> children_of(LeptrisElement e) {
23
+ std::vector<ChildInfo> rows;
24
+ for (LeptrisNodeRef c = leptris_node_first_child(
25
+ leptris_element_as_node(e));
26
+ c; c = leptris_node_next_sibling(c)) {
27
+ ChildInfo row;
28
+ row.type = (int)leptris_node_get_type(c);
29
+ if (row.type == LEPTRIS_NODE_TYPE_TEXT)
30
+ row.text = leptris_text_node_get_content(c);
31
+ if (row.type == LEPTRIS_NODE_TYPE_ENTITY_REF)
32
+ row.name = leptris_entity_ref_node_name(c);
33
+ rows.push_back(row);
34
+ }
35
+ return rows;
36
+ }
37
+
38
+ } // namespace
39
+
40
+ TEST(EntityRefNodes, BuiltinsBecomeNodes) {
41
+ const char* xml = "<a>x&amp;y&lt;z&gt;w</a>";
42
+ LeptrisStatus st = LEPTRIS_OK;
43
+ LeptrisDocument doc = leptris_parse_string_flags(
44
+ xml, strlen(xml), LEPTRIS_PARSE_KEEP_ENTITY_REFS, &st);
45
+ ASSERT_NE(doc, (LeptrisDocument)0);
46
+ LeptrisElement a = leptris_document_root(doc);
47
+ std::vector<ChildInfo> kids = children_of(a);
48
+ ASSERT_EQ(kids.size(), 7u);
49
+ EXPECT_EQ(kids[0].type, (int)LEPTRIS_NODE_TYPE_TEXT);
50
+ EXPECT_EQ(kids[0].text, "x");
51
+ EXPECT_EQ(kids[1].type, (int)LEPTRIS_NODE_TYPE_ENTITY_REF);
52
+ EXPECT_EQ(kids[1].name, "amp");
53
+ EXPECT_EQ(kids[2].text, "y");
54
+ EXPECT_EQ(kids[3].name, "lt");
55
+ EXPECT_EQ(kids[4].text, "z");
56
+ EXPECT_EQ(kids[5].name, "gt");
57
+ EXPECT_EQ(kids[6].text, "w");
58
+ leptris_document_free(doc);
59
+ }
60
+
61
+ TEST(EntityRefNodes, NumericCharacterRefsStayText) {
62
+ /* XML 1.0 §4.1: character references are NOT entity references. */
63
+ const char* xml = "<a>&#65;&#x42;</a>";
64
+ LeptrisStatus st = LEPTRIS_OK;
65
+ LeptrisDocument doc = leptris_parse_string_flags(
66
+ xml, strlen(xml), LEPTRIS_PARSE_KEEP_ENTITY_REFS, &st);
67
+ ASSERT_NE(doc, (LeptrisDocument)0);
68
+ LeptrisElement a = leptris_document_root(doc);
69
+ std::vector<ChildInfo> kids = children_of(a);
70
+ ASSERT_EQ(kids.size(), 1u);
71
+ EXPECT_EQ(kids[0].type, (int)LEPTRIS_NODE_TYPE_TEXT);
72
+ EXPECT_EQ(kids[0].text, "AB");
73
+ leptris_document_free(doc);
74
+ }
75
+
76
+ TEST(EntityRefNodes, StringValueSerializationAndXPathAgree) {
77
+ const char* xml = "<a>x&amp;y&lt;z</a>";
78
+ LeptrisStatus st = LEPTRIS_OK;
79
+ LeptrisDocument doc = leptris_parse_string_flags(
80
+ xml, strlen(xml), LEPTRIS_PARSE_KEEP_ENTITY_REFS, &st);
81
+ ASSERT_NE(doc, (LeptrisDocument)0);
82
+ LeptrisElement a = leptris_document_root(doc);
83
+ EXPECT_STREQ(leptris_element_text(a), "x&y<z");
84
+ char* ser = leptris_document_serialize(doc, NULL);
85
+ ASSERT_NE(ser, nullptr);
86
+ EXPECT_STREQ(ser, "<a>x&amp;y&lt;z</a>");
87
+ leptris_free_string(ser);
88
+ LeptrisXPathResult r = leptris_xpath_eval(doc, NULL, "string(/a)");
89
+ ASSERT_NE(r, nullptr);
90
+ char* sv = leptris_xpath_result_string(r);
91
+ EXPECT_STREQ(sv, "x&y<z");
92
+ leptris_free_string(sv);
93
+ leptris_xpath_result_free(r);
94
+ leptris_document_free(doc);
95
+ }
96
+
97
+ TEST(EntityRefNodes, CustomNamedRefsAreNodes) {
98
+ const char* xml =
99
+ "<!DOCTYPE r [<!ENTITY foo \"x\">]><r>a&foo;b</r>";
100
+ LeptrisStatus st = LEPTRIS_OK;
101
+ LeptrisDocument doc = leptris_parse_string_flags(
102
+ xml, strlen(xml), LEPTRIS_PARSE_KEEP_ENTITY_REFS, &st);
103
+ ASSERT_NE(doc, (LeptrisDocument)0);
104
+ LeptrisElement r = leptris_document_root(doc);
105
+ std::vector<ChildInfo> kids = children_of(r);
106
+ ASSERT_EQ(kids.size(), 3u);
107
+ EXPECT_EQ(kids[1].type, (int)LEPTRIS_NODE_TYPE_ENTITY_REF);
108
+ EXPECT_EQ(kids[1].name, "foo");
109
+ EXPECT_STREQ(leptris_element_text(r), "axb");
110
+ leptris_document_free(doc);
111
+ }
@@ -7,6 +7,7 @@
7
7
  #include <gtest/gtest.h>
8
8
 
9
9
  #include <cstdio>
10
+ #include <fstream>
10
11
  #include <cstring>
11
12
  #include <string>
12
13
  #include <algorithm>
@@ -3680,3 +3681,325 @@ TEST(XsdContent, Issue1894ReproStaysUnderCapAndCorrect) {
3680
3681
  EXPECT_EQ(leptris_xsd_error_count(s), 0u);
3681
3682
  leptris_xsd_free(s);
3682
3683
  }
3684
+
3685
+
3686
+ /* leptris-ruby#569 family: cross-namespace references into an
3687
+ * IMPORTED unit. The importing schema must declare xmlns="urn:a"
3688
+ * as the DEFAULT namespace — unprefixed ref QNames resolve to
3689
+ * no-namespace otherwise (spec behavior, the #1901 repro lesson). */
3690
+ TEST(XsdCrossNs, AttributeRefIntoImportedUnitResolves) {
3691
+ const char* rel =
3692
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
3693
+ " targetNamespace=\"urn:r\" elementFormDefault=\"qualified\">"
3694
+ "<xs:simpleType name=\"ST_RelId\">"
3695
+ "<xs:restriction base=\"xs:string\"/></xs:simpleType>"
3696
+ "<xs:attribute name=\"embed\" type=\"ST_RelId\"/>"
3697
+ "</xs:schema>";
3698
+ const char* main =
3699
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
3700
+ " xmlns:r=\"urn:r\" xmlns=\"urn:a\" targetNamespace=\"urn:a\""
3701
+ " elementFormDefault=\"qualified\">"
3702
+ "<xs:import namespace=\"urn:r\" schemaLocation=\"blip_repro_rel.xsd\"/>"
3703
+ "<xs:attributeGroup name=\"AG_Blob\">"
3704
+ "<xs:attribute ref=\"r:embed\" use=\"optional\"/>"
3705
+ "</xs:attributeGroup>"
3706
+ "<xs:complexType name=\"CT_Blip\">"
3707
+ "<xs:sequence><xs:element name=\"e\" type=\"xs:string\""
3708
+ " minOccurs=\"0\"/></xs:sequence>"
3709
+ "<xs:attributeGroup ref=\"AG_Blob\"/>"
3710
+ "</xs:complexType>"
3711
+ "<xs:element name=\"blip\" type=\"CT_Blip\"/>"
3712
+ "</xs:schema>";
3713
+
3714
+ const char* dir = std::getenv("TMPDIR");
3715
+ std::string base = dir ? dir : "/tmp";
3716
+ std::string rel_path = base + "/blip_repro_rel.xsd";
3717
+ std::string main_path = base + "/blip_repro_main.xsd";
3718
+ {
3719
+ std::ofstream f(rel_path);
3720
+ f << rel;
3721
+ }
3722
+ {
3723
+ std::ofstream f(main_path);
3724
+ f << main;
3725
+ }
3726
+ const char* paths[2] = {rel_path.c_str(), main_path.c_str()};
3727
+ LeptrisStatus st = LEPTRIS_OK;
3728
+ LeptrisXsdSchema s =
3729
+ leptris_xsd_compile_set(paths, 2, &st);
3730
+ if (st != LEPTRIS_OK || s == (LeptrisXsdSchema)0) {
3731
+ const char* err = s ? leptris_xsd_error(s) : "(no handle)";
3732
+ GTEST_FAIL() << "compile_set failed st=" << (int)st
3733
+ << " err=" << (err ? err : "(null)");
3734
+ }
3735
+
3736
+ EXPECT_EQ(validate_compiled(s,
3737
+ "<a:blip xmlns:a=\"urn:a\" xmlns:r=\"urn:r\""
3738
+ " r:embed=\"rId2\"><e>x</e></a:blip>"),
3739
+ 1)
3740
+ << "cross-unit attribute ref must resolve: "
3741
+ << leptris_xsd_error(s);
3742
+ std::remove(rel_path.c_str());
3743
+ std::remove(main_path.c_str());
3744
+ leptris_xsd_free(s);
3745
+ }
3746
+
3747
+ /* Same shape through the single-document import chase. */
3748
+ TEST(XsdCrossNs, SingleDocImportChaseResolves) {
3749
+ const char* rel =
3750
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
3751
+ " targetNamespace=\"urn:r\" elementFormDefault=\"qualified\">"
3752
+ "<xs:simpleType name=\"ST_RelId\">"
3753
+ "<xs:restriction base=\"xs:string\"/></xs:simpleType>"
3754
+ "<xs:attribute name=\"embed\" type=\"ST_RelId\"/>"
3755
+ "</xs:schema>";
3756
+ const char* main =
3757
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
3758
+ " xmlns:r=\"urn:r\" xmlns=\"urn:a\" targetNamespace=\"urn:a\""
3759
+ " elementFormDefault=\"qualified\">"
3760
+ "<xs:import namespace=\"urn:r\""
3761
+ " schemaLocation=\"blip_repro_rel.xsd\"/>"
3762
+ "<xs:attributeGroup name=\"AG_Blob\">"
3763
+ "<xs:attribute ref=\"r:embed\" use=\"optional\"/>"
3764
+ "</xs:attributeGroup>"
3765
+ "<xs:complexType name=\"CT_Blip\">"
3766
+ "<xs:sequence><xs:element name=\"e\" type=\"xs:string\""
3767
+ " minOccurs=\"0\"/></xs:sequence>"
3768
+ "<xs:attributeGroup ref=\"AG_Blob\"/>"
3769
+ "</xs:complexType>"
3770
+ "<xs:element name=\"blip\" type=\"CT_Blip\"/>"
3771
+ "</xs:schema>";
3772
+
3773
+ const char* dir = std::getenv("TMPDIR");
3774
+ std::string base = dir ? dir : "/tmp";
3775
+ std::string rel_path = base + "/blip_repro_rel.xsd";
3776
+ std::string main_path = base + "/blip_repro_main.xsd";
3777
+ {
3778
+ std::ofstream f(rel_path);
3779
+ f << rel;
3780
+ }
3781
+ {
3782
+ std::ofstream f(main_path);
3783
+ f << main;
3784
+ }
3785
+ LeptrisStatus st = LEPTRIS_OK;
3786
+ LeptrisXsdSchema s =
3787
+ leptris_xsd_compile_file(main_path.c_str(), &st);
3788
+ if (st != LEPTRIS_OK || s == (LeptrisXsdSchema)0) {
3789
+ const char* err = s ? leptris_xsd_error(s) : "(no handle)";
3790
+ GTEST_FAIL() << "single-doc compile failed st=" << (int)st
3791
+ << " err=" << (err ? err : "(null)");
3792
+ }
3793
+
3794
+ EXPECT_EQ(validate_compiled(s,
3795
+ "<a:blip xmlns:a=\"urn:a\" xmlns:r=\"urn:r\""
3796
+ " r:embed=\"rId2\"><e>x</e></a:blip>"),
3797
+ 1)
3798
+ << "import-chase attribute ref must resolve: "
3799
+ << leptris_xsd_error(s);
3800
+ std::remove(rel_path.c_str());
3801
+ std::remove(main_path.c_str());
3802
+ leptris_xsd_free(s);
3803
+ }
3804
+
3805
+ /* The #569 regression itself: the #1880 attributeGroup pre-pass
3806
+ * captured AG_Blob and resolved its <xs:attribute ref="r:embed"/>
3807
+ * row BEFORE the import chase registered the referenced unit's
3808
+ * r:embed — the row used to be silently dropped, so whole-instance
3809
+ * validation then rejected every a:blip @r:embed ("not declared
3810
+ * (strict)") on the real DrawingML chain. The row must survive as
3811
+ * pending and resolve once the full capture has run. */
3812
+ TEST(XsdCrossNs, AttrGroupRefRowResolvedAfterImportChase) {
3813
+ const char* rel =
3814
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
3815
+ " targetNamespace=\"urn:r\" elementFormDefault=\"qualified\">"
3816
+ "<xs:attribute name=\"embed\" type=\"xs:string\"/>"
3817
+ "</xs:schema>";
3818
+ const char* main =
3819
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
3820
+ " xmlns:r=\"urn:r\" xmlns=\"urn:a\" targetNamespace=\"urn:a\""
3821
+ " elementFormDefault=\"qualified\">"
3822
+ "<xs:import namespace=\"urn:r\" schemaLocation=\"ag569_rel.xsd\"/>"
3823
+ "<xs:attributeGroup name=\"AG_Blob\">"
3824
+ "<xs:attribute ref=\"r:embed\"/>"
3825
+ "</xs:attributeGroup>"
3826
+ "<xs:complexType name=\"CT_Blip\">"
3827
+ "<xs:sequence><xs:element name=\"e\" type=\"xs:string\""
3828
+ " minOccurs=\"0\"/></xs:sequence>"
3829
+ "<xs:attributeGroup ref=\"AG_Blob\"/>"
3830
+ "</xs:complexType>"
3831
+ "<xs:element name=\"blip\" type=\"CT_Blip\"/>"
3832
+ "</xs:schema>";
3833
+
3834
+ const char* dir = std::getenv("TMPDIR");
3835
+ std::string base = dir ? dir : "/tmp";
3836
+ std::string rel_path = base + "/ag569_rel.xsd";
3837
+ std::string main_path = base + "/ag569_main.xsd";
3838
+ {
3839
+ std::ofstream f(rel_path);
3840
+ f << rel;
3841
+ }
3842
+ {
3843
+ std::ofstream f(main_path);
3844
+ f << main;
3845
+ }
3846
+ LeptrisStatus st = LEPTRIS_OK;
3847
+ LeptrisXsdSchema s =
3848
+ leptris_xsd_compile_file(main_path.c_str(), &st);
3849
+ ASSERT_NE(s, (LeptrisXsdSchema)0);
3850
+ const char* err = leptris_xsd_error(s);
3851
+ ASSERT_EQ(st, LEPTRIS_OK)
3852
+ << "compile failed: " << (err ? err : "(null)");
3853
+
3854
+ EXPECT_EQ(validate_compiled(s,
3855
+ "<a:blip xmlns:a=\"urn:a\" xmlns:r=\"urn:r\""
3856
+ " r:embed=\"rId2\"><e>x</e></a:blip>"),
3857
+ 1)
3858
+ << "pre-pass ref row must resolve after the import chase: "
3859
+ << leptris_xsd_error(s);
3860
+ std::remove(rel_path.c_str());
3861
+ std::remove(main_path.c_str());
3862
+ leptris_xsd_free(s);
3863
+ }
3864
+
3865
+ /* leptris-ruby#569: compiling the REAL wml.xsd (ISO transitional,
3866
+ * 790 element decls, import chain to the drawing units) must yield
3867
+ * a cleanly compiled schema — a missing import file poisons the
3868
+ * graph (the '{mce}Ignorable' class), and the merged capture must
3869
+ * carry every unit. The schema set is bundled at $BLIP_CHAIN_DIR
3870
+ * in dev; CI skips when the fixture is absent so the suite stays
3871
+ * hermetic. */
3872
+ TEST(XsdCrossNs, RealWmlChainCompilesDeclarations) {
3873
+ const char* dir = std::getenv("BLIP_CHAIN_DIR");
3874
+ if (!dir || *dir == '\0') {
3875
+ GTEST_SKIP() << "BLIP_CHAIN_DIR not set";
3876
+ }
3877
+ std::string wml = std::string(dir) + "/wml.xsd";
3878
+ std::ifstream f(wml);
3879
+ ASSERT_TRUE(f.good()) << wml;
3880
+ LeptrisStatus st = LEPTRIS_OK;
3881
+ LeptrisXsdSchema s = leptris_xsd_compile_file(wml.c_str(), &st);
3882
+ ASSERT_NE(s, (LeptrisXsdSchema)0);
3883
+ const char* err = leptris_xsd_error(s);
3884
+ EXPECT_EQ(st, LEPTRIS_OK)
3885
+ << "compile status " << (int)st
3886
+ << " decls=" << leptris_xsd_declaration_count(s)
3887
+ << " err=" << (err ? err : "(clean)");
3888
+ leptris_xsd_free(s);
3889
+ }
3890
+
3891
+ /* leptris#1911: vc:minVersion="1.1" marks the schema as XSD 1.1
3892
+ * (the W3C suite and moxml both use the versioning namespace; the
3893
+ * plain version attribute is the other legal spelling). The
3894
+ * alternative's test selects the type — validation must run the
3895
+ * SELECTED type's content model, in both directions. */
3896
+ TEST(Xsd11Gate, CtaSelectsAlternativeType) {
3897
+ const char xsd[] =
3898
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
3899
+ " vc:minVersion=\"1.1\""
3900
+ " xmlns:vc=\"http://www.w3.org/2001/XMLSchema-versioning\">"
3901
+ "<xs:element name=\"shape\" type=\"Shape\">"
3902
+ "<xs:alternative test=\"@kind='circle'\" type=\"Circle\"/>"
3903
+ "</xs:element>"
3904
+ "<xs:complexType name=\"Shape\" abstract=\"true\">"
3905
+ "<xs:attribute name=\"kind\" type=\"xs:string\"/>"
3906
+ "</xs:complexType>"
3907
+ "<xs:complexType name=\"Circle\">"
3908
+ "<xs:complexContent><xs:extension base=\"Shape\">"
3909
+ "<xs:sequence><xs:element name=\"r\" type=\"xs:integer\"/>"
3910
+ "</xs:sequence></xs:extension></xs:complexContent>"
3911
+ "</xs:complexType></xs:schema>";
3912
+ LeptrisStatus st = LEPTRIS_OK;
3913
+ LeptrisXsdSchema s = leptris_xsd_compile(xsd, strlen(xsd), &st);
3914
+ ASSERT_NE(s, (LeptrisXsdSchema)0);
3915
+ ASSERT_EQ(st, LEPTRIS_OK) << leptris_xsd_error(s);
3916
+ EXPECT_STREQ(leptris_xsd_version(s), "1.1")
3917
+ << "vc:minVersion must gate the 1.1 feature set";
3918
+ EXPECT_EQ(validate_compiled(s,
3919
+ "<shape kind=\"circle\"><r>4</r></shape>"),
3920
+ 1)
3921
+ << "the selected Circle type admits <r>: "
3922
+ << leptris_xsd_error(s);
3923
+ EXPECT_EQ(validate_compiled(s, "<shape kind=\"circle\"/>"), 0)
3924
+ << "the selected Circle type REQUIRES <r>";
3925
+ leptris_xsd_free(s);
3926
+ }
3927
+
3928
+ /* leptris#1910: an xs:assert in a vc:minVersion="1.1" schema must
3929
+ * be evaluated — a violating instance produces an assertion row. */
3930
+ TEST(Xsd11Gate, AssertIsEvaluated) {
3931
+ const char xsd[] =
3932
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
3933
+ " vc:minVersion=\"1.1\""
3934
+ " xmlns:vc=\"http://www.w3.org/2001/XMLSchema-versioning\">"
3935
+ "<xs:element name=\"size\">"
3936
+ "<xs:complexType><xs:sequence>"
3937
+ "<xs:element name=\"w\" type=\"xs:integer\"/>"
3938
+ "<xs:element name=\"h\" type=\"xs:integer\"/>"
3939
+ "</xs:sequence><xs:assert test=\"w le h\"/></xs:complexType>"
3940
+ "</xs:element></xs:schema>";
3941
+ LeptrisStatus st = LEPTRIS_OK;
3942
+ LeptrisXsdSchema s = leptris_xsd_compile(xsd, strlen(xsd), &st);
3943
+ ASSERT_NE(s, (LeptrisXsdSchema)0);
3944
+ ASSERT_EQ(st, LEPTRIS_OK) << leptris_xsd_error(s);
3945
+ EXPECT_EQ(validate_compiled(s, "<size><w>3</w><h>5</h></size>"), 1)
3946
+ << "satisfying assert must stay valid: "
3947
+ << leptris_xsd_error(s);
3948
+ EXPECT_EQ(validate_compiled(s, "<size><w>9</w><h>5</h></size>"), 0)
3949
+ << "violating assert must produce a finding";
3950
+ leptris_xsd_free(s);
3951
+ }
3952
+
3953
+ /* leptris#1913: xs:override (XSD 1.1 Structures §I.4) — the base
3954
+ * document's declarations load (xs:override is an include-family
3955
+ * chase), then the override body's same-named declarations REPLACE
3956
+ * them. Previously override was absent from the chase condition:
3957
+ * the base never loaded and the body's nested declarations were
3958
+ * never captured — an empty symbol space (decls=0). */
3959
+ TEST(Xsd11Gate, OverrideLoadsBaseAndReplacesComponents) {
3960
+ const char* base =
3961
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
3962
+ " targetNamespace=\"urn:b\" xmlns=\"urn:b\""
3963
+ " elementFormDefault=\"qualified\">"
3964
+ "<xs:element name=\"doc\" type=\"Doc\"/>"
3965
+ "<xs:complexType name=\"Doc\">"
3966
+ "<xs:sequence><xs:element name=\"a\" type=\"xs:string\"/>"
3967
+ "</xs:sequence></xs:complexType></xs:schema>";
3968
+ const char* ovr =
3969
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
3970
+ " targetNamespace=\"urn:b\" xmlns=\"urn:b\""
3971
+ " elementFormDefault=\"qualified\" vc:minVersion=\"1.1\""
3972
+ " xmlns:vc=\"http://www.w3.org/2001/XMLSchema-versioning\">"
3973
+ "<xs:override schemaLocation=\"ovr1913_base.xsd\">"
3974
+ "<xs:complexType name=\"Doc\">"
3975
+ "<xs:sequence><xs:element name=\"b\" type=\"xs:integer\"/>"
3976
+ "</xs:sequence></xs:complexType>"
3977
+ "</xs:override></xs:schema>";
3978
+ const char* dir = std::getenv("TMPDIR");
3979
+ std::string tmp = dir ? dir : "/tmp";
3980
+ std::string base_path = tmp + "/ovr1913_base.xsd";
3981
+ std::string ovr_path = tmp + "/ovr1913_ovr.xsd";
3982
+ {
3983
+ std::ofstream f(base_path);
3984
+ f << base;
3985
+ }
3986
+ {
3987
+ std::ofstream f(ovr_path);
3988
+ f << ovr;
3989
+ }
3990
+ LeptrisStatus st = LEPTRIS_OK;
3991
+ LeptrisXsdSchema s = leptris_xsd_compile_file(ovr_path.c_str(), &st);
3992
+ ASSERT_NE(s, (LeptrisXsdSchema)0);
3993
+ ASSERT_EQ(st, LEPTRIS_OK) << leptris_xsd_error(s);
3994
+ EXPECT_GT(leptris_xsd_declaration_count(s), 0u)
3995
+ << "override must not produce an empty symbol space";
3996
+ EXPECT_EQ(validate_compiled(s, "<doc xmlns=\"urn:b\"><b>1</b></doc>"),
3997
+ 1)
3998
+ << "the overridden Doc admits <b>: " << leptris_xsd_error(s);
3999
+ EXPECT_EQ(validate_compiled(s, "<doc xmlns=\"urn:b\"><a>x</a></doc>"),
4000
+ 0)
4001
+ << "the overridden Doc no longer admits <a>";
4002
+ std::remove(base_path.c_str());
4003
+ std::remove(ovr_path.c_str());
4004
+ leptris_xsd_free(s);
4005
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
3
3
  "name": "leptris",
4
- "version": "1.9.390",
4
+ "version": "1.9.394",
5
5
  "description": "High-performance XML parser and XPath 1.0 engine in C (libleptris)",
6
6
  "homepage": "https://github.com/leptris/leptris",
7
7
  "license": "MIT",
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leptris
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.390.3
4
+ version: 1.9.394.0
5
5
  platform: ppc64le-linux
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-29 00:00:00.000000000 Z
11
+ date: 2026-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -744,6 +744,7 @@ files:
744
744
  - vendor-src/libleptris/src/man/libleptris.5.adoc
745
745
  - vendor-src/libleptris/test/CMakeLists.txt
746
746
  - vendor-src/libleptris/test/README.md
747
+ - vendor-src/libleptris/test/abi/test_capabilities.cpp
747
748
  - vendor-src/libleptris/test/abi/test_descriptor.cpp
748
749
  - vendor-src/libleptris/test/abi/test_doctype_api.cpp
749
750
  - vendor-src/libleptris/test/abi/test_dom_deep_copy.cpp
@@ -782,6 +783,7 @@ files:
782
783
  - vendor-src/libleptris/test/dom/test_document_children.cpp
783
784
  - vendor-src/libleptris/test/dom/test_dom.cpp
784
785
  - vendor-src/libleptris/test/dom/test_element_children.cpp
786
+ - vendor-src/libleptris/test/dom/test_entity_refs.cpp
785
787
  - vendor-src/libleptris/test/dom/test_map_lifecycle.cpp
786
788
  - vendor-src/libleptris/test/dom/test_namespace_cache.cpp
787
789
  - vendor-src/libleptris/test/dom/test_node_surface_parity.cpp