#comparing two dynamic values for equality or otherwise checking to_json/decoder roundtrip works?

1 messages · Page 1 of 1 (latest)

gentle solar
#

I want to check if anything is lost when I go json -> decoder -> to_json, so far the only way I could think of is do json -> decoder -> to_json then check if roundtrip json decode dynamic is the same as original json decode dynamic. However in some cases it might be ok for items in the json to change order, but that makes comparing the old/roundtrip dynamic fail even if (I believe) they are otherwise the same. Is there a nicer way to confirm that nothing changed in the json besides order of items?

pub fn check_roundtrip(
  in: String,
  thing_dec: decode.Decoder(a),
  thing_to_json,
  from_test: String,
) {
  let assert Ok(as_dynamic) = json.parse(in, decode.dynamic)
    as { from_test <> " check_roundtrip decode dynamic" }
  let assert Ok(as_thing) = json.parse(in, thing_dec)
    as { from_test <> " check_roundtrip decode thing" }

  let assert Ok(as_dynamic_roundtrip) =
    as_thing
    |> thing_to_json
    |> json.to_string
    |> json.parse(decode.dynamic)
  assert as_dynamic == as_dynamic_roundtrip
    as { from_test <> " check_roundtrip decode + encode roundtrip" }
}
dim narwhal
#

Why wouldn't you use dynamic1 == dynamic2?

gentle solar
#

does that work if the order of fields are different? I was trying with as_dynamic == as_dynamic_roundtrip but getting error, idk if because different order or changed values of fields

dim narwhal
#

If you're doing roundtrip testing of encoding and decoding I would recommend asserting the typed value and not the dynamic one

dim narwhal
gentle solar
#

yeah I would just feel warm and fuzzy inside if I could check roundtrip like this

#

to make sure I don't lose anything

#

asserting typed values is probably enough

dim narwhal
#

How are you constructing the dynamic values where you don't know what they include?

gentle solar
#

In the json, key "extension" should be an array of exactly (for example) 6 values, but each value has a field that identifies what type it is and what fields it will have, so I might try to write actual types for specific extensions and decode into them rather than just 6 generic extensions. But that loses the order they're in, which I think is fine, just want to check it's only losing order if they were in the right order it'd be same json as original

dim narwhal
#

JSON objects are not ordered, so if this is JSON you likely shouldn't be testing ordering

#

If you depend on ordering then you can have unexpected behaviour due to different parsers handling it differently

gentle solar
#

right I want to check if everything in roundtrip json is same except reordering

dim narwhal
#

Then you would test with the typed values

#

You should aim to work with dynamic as little as possible

snow cliff
#

to stop skirting around the bush you shouldnt have a generic check_roundtrip function, just write tests for the data you have

gentle solar
#

Ik it feels like xy problem but roundtrip would help me catch a lot for my case, I'm not giving great context maybe I'll try again later with an example

snow cliff
#

write the roundtrip in the test if you need it

gentle solar
#

ok here is a good example (discord attached it), there are a lot of fields in the json and for some the decoder/to_json is tricky, extensions and decimals in particular. Parsing is a good start but I need to test the to_json as well. A roundtrip would also be nice to prove it works without having to check a lot of fields. And when changing a type like decimal or datetime, the test would still work without more effort and catch if the type roundtrips wrong. But idk how to do the roundtrip check, still not sure what to compare for equality.

#

because the order of extensions changes

south wind
#

so I think your test would be something like

let value =
  Resource(
    resource_type: "Patient", 
    id: "example", 
    profile: [
    "http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient|9.0.0",
  ])

let parsed =
  value
  |> resource_to_json
  |> json.to_string
  |> json.parse(thing_dec)

assert parsed == value
gentle solar
#

type -> json -> type is a good start but copying all the json file to types sounds kind of slow/error prone, and if you start with type you could pass a roundtrip test without actually complying with the spec. So I feel like starting with json would be nicer. If not possible it's fine though ty

dim narwhal
#

Would make maintenance a bit harder as you don’t get type system and refactorings when the data structure changes

gentle solar
#

that was kind of another reason why I thought it'd be nicer, because right now time is just string, at some point I will try parsing time into timestamp with implicit precision and was thinking the roundtrip starting from json would still work without having to be updated

#

for example

#

but yeah there need to be tests of the actual types too

#

I was thinking of this more for taking all the random messy json files available and checking they all work