Class: Ea::Validation::XmiParity

Inherits:
Object
  • Object
show all
Defined in:
lib/ea/validation/xmi_parity.rb

Overview

Compares Ea::Transformers.qea_to_xmi output against EA's reference XMI export (examples/exports/*/model.xml).

Reports per-element-type counts (packagedElement, ownedAttribute, ownedEnd, memberEnd, generalization, connector, diagram, style, tags, documentation, xmi:Extension) so gaps surface clearly.

Used by the parity regression spec to track XMI export fidelity over time. Improvements to QeaToXmi should shrink the gaps.

Defined Under Namespace

Classes: Counts

Constant Summary collapse

ELEMENT_TYPES =
%w[
  packagedElement
  ownedAttribute
  ownedOperation
  ownedEnd
  memberEnd
  generalization
  connector
  diagram
  taggedValue
  xmi:Extension
  style
  tags
  documentation
].freeze

Class Method Summary collapse

Class Method Details

.compare(qea_path, reference_xmi_path) ⇒ Hash

Returns :reference, :delta each a Counts.

Parameters:

  • qea_path (String)

    path to the QEA file

  • reference_xmi_path (String)

    path to EA's reference XMI

Returns:

  • (Hash)

    :reference, :delta each a Counts



50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/ea/validation/xmi_parity.rb', line 50

def self.compare(qea_path, reference_xmi_path)
  database = Ea::Qea.load(qea_path)
  ours_xml = Ea::Transformers.qea_to_xmi(database)
  ref_xml = File.read(reference_xmi_path)

  {
    qea: qea_path,
    reference: reference_xmi_path,
    ours: count(ours_xml),
    reference_counts: count(ref_xml),
    delta: count(ours_xml).delta(count(ref_xml))
  }
end

.count(xml) ⇒ Counts

Parameters:

  • xml (String)

    XMI markup (any encoding)

Returns:



66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/ea/validation/xmi_parity.rb', line 66

def self.count(xml)
  # EA exports use windows-1252; force UTF-8 for safe regex.
  safe = xml.to_s.encode("UTF-8", invalid: :replace, undef: :replace,
                          replace: "?")
  by_type = ELEMENT_TYPES.each_with_object({}) do |tag, acc|
    # Match `<tag>` followed by space, `/`, or `>` (covers
    # `<tag/>`, `<tag foo=...>`, `<tag>`). Using %r{} to avoid
    # `/` regex-delimiter conflict with the `/` in the class.
    acc[tag] = safe.scan(%r{<#{tag}[\s/>]}).size
  end
  Counts.new(total: by_type.values.sum, by_type: by_type)
end