Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions lib/opencdd/cddal/serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ def language_suffix(property_id)
def format_value(value)
s = value.to_s
return quote_string(s) if string_literal?(s)
return format_set(s) if set_like?(s)
s
end

Expand All @@ -194,15 +193,6 @@ def quote_string(s)
"\"#{escaped}\""
end

def set_like?(s)
s.start_with?("(") && s.end_with?(")")
end

def format_set(s)
elements = Opencdd::StructuredValues.unwrap_and_split(s)
"{ #{elements.join(', ')} }"
end

def symbol_name_for(entity)
code = entity.code&.to_s
return code if code && !code.empty?
Expand Down
6 changes: 5 additions & 1 deletion lib/opencdd/parcel/writer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,11 @@ def add_data_sheets(workbook, built_sheets, source_language, hidden_directives =
rows = emitter.emit(built.sheet, built.entities)
workbook.add_worksheet(name: built.sheet.name) do |ws|
rows.each do |row|
emitted = ws.add_row(row)
# All property values are strings per IEC 61360 wire format.
# Force string cell type so values like "001" survive round-trip
# (otherwise caxlsx auto-types numeric-looking strings and roo
# reads them back as integers, breaking semantically_equal?).
emitted = ws.add_row(row, types: :string)
emitted.hidden = true if row_hidden?(row, hidden_directives)
end
end
Expand Down
16 changes: 5 additions & 11 deletions spec/import_pipeline_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,11 @@ def write_parcel(database, parcel_id:, **opts)
end

describe "scenario 3: parcel → cddal → parcel (round-trip)" do
# Cross-format round-trips hit a known Parcel writer normalization:
# version/revision codes stored as strings ("001") are written as
# numeric cells (1) and read back as "1". +semantically_equal?+
# does exact property-hash comparison and reports this as a
# mismatch. The entity graph itself (IRDIs, types, counts) survives
# the detour cleanly — that is the invariant tested here.
#
# TODO: the value-normalization gap should be resolved either in
# the Parcel writer (preserve string values) or in
# +semantically_equal?+ (normalize numeric strings). Flagged, not
# fixed — see [[ask-before-semantic-changes]].
# Cross-format round-trips preserve the entity graph (IRDIs, types,
# counts) cleanly. A full +semantically_equal?+ assertion is blocked
# by a separate multilingual key normalization gap (MDC_P004_1 vs
# MDC_P004.en) — see spec/parcel_string_preservation_spec.rb for the
# narrower string-preservation test that verifies audit A3's fix.
let(:parcel_source) do
path = write_parcel(source_database, parcel_id: "OCDDSRC3")
Opencdd::Database.load_workbook(path)
Expand Down
36 changes: 36 additions & 0 deletions spec/parcel_string_preservation_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
require "spec_helper"
require "tmpdir"

RSpec.describe "Parcel writer string preservation (audit A3)" do
# Reproduces the original bug: numeric-looking strings like "001" were
# written as numeric cells and read back as 1, breaking semantically_equal?.
# Fix: Parcel::Writer#add_data_sheets forces `types: :string` per row.
let(:database) do
klass = Opencdd::Klass.new(
irdi: Opencdd::IRDI.parse("0112/2///62656_4#AAA001"),
properties: {
Opencdd::PropertyIds::MDC_P001_5 => "0112/2///62656_4#AAA001",
Opencdd::PropertyIds::MDC_P004_1 => "Sample class", # preferred_name.en
Opencdd::PropertyIds::MDC_P002_1 => "001", # version (the bug)
Opencdd::PropertyIds::MDC_P002_2 => "01", # revision
},
meta_class_irdi: Opencdd::IRDI.parse("0112/2///62656_1#MDC_C002"),
)
Opencdd::Database.new.add_entity(klass)
end

it "preserves leading-zero strings through xlsx round-trip" do
tmp = File.join(Dir.mktmpdir, "round-trip.xlsx")
Opencdd::Parcel::Writer.new(database).write(tmp, parcel_id: "TEST")

reloaded = Opencdd::Database.load_workbook(tmp)
sample = reloaded.entities.first

expect(sample.version).to eq("001")
expect(sample.revision).to eq("01")
end

# Note: a full semantically_equal? round-trip test is blocked by a separate
# multilingual key normalization gap (MDC_P004_1 vs MDC_P004.en). That's a
# different audit item; not in scope here.
end
Loading