Skip to content

Commit

Permalink
Refine msgpack fixpoint test
Browse files Browse the repository at this point in the history
The parser mapping ByteVector to MsgpackItem can be seen as a not
injective morphism, that is, there are many ByteVectors that will map to
the same MsgpackItem. Because of this, we cannot possibly guarantee that
`serialize(parse(bs))` is fixpoint for an arbitrary `bs`. However,
currently implemented serializers *are* injective (if we exclude the
Timestamp format family as it can be represented with Extension types)
and so, we can guarantee `serialize(parse(bs)) == bs` if `bs` is a
member of a subset of ByteVector that is emitted by a serializer.

In other words, the following code will be true for any `bs` if
`serialize` is injective and we ignore the Timestamp type family:
```
 val first = serialize(parse(bs))
 val second = serialize(parse(first))
 first == second
```

This test makes sure that the above holds.
  • Loading branch information
jarmuszz committed Aug 18, 2024
1 parent 1ed1f73 commit ac14528
Showing 1 changed file with 41 additions and 18 deletions.
59 changes: 41 additions & 18 deletions msgpack/src/test/scala/fs2/data/msgpack/SerializerSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -169,26 +169,49 @@ object SerializerSpec extends SimpleIOSuite {
.compile
.foldMonoid
}
test("MessagePack item serializer should be fix point when optimizing for size") {

test("MessagePack item serializer should be fixpoint for a subset of ByteVector") {
/* The parser mapping ByteVector to MsgpackItem can be seen as a not injective morphism, that is, there
* are many ByteVectors that will map to the same MsgpackItem. Because of this, we cannot possibly guarantee that
* `serialize(parse(bs))` is fixpoint for an arbitrary `bs`. However, currently implemented serializers *are*
* injective (if we exclude the Timestamp format family as it can be represented with Extension types) and so, we
* can guarantee `serialize(parse(bs)) == bs` if `bs` is a member of a subset of ByteVector that is emitted by a
* serializer.
*
* In other words, the following code will be true for any `bs` if `serialize` is injective and we ignore the
* Timestamp type family:
* {{{
* val first = serialize(parse(bs))
* val second = serialize(parse(first))
* first == second
* }}}
*
* This test makes sure that the above holds.
*/

val cases = List(
hex"CB3FCB5A858793DD98",
hex"d6ffaabbccdd",
hex"81A77765622D61707083A7736572766C65749583AC736572766C65742D6E616D65A8636F666178434453AD736572766C65742D636C617373B86F72672E636F6661782E6364732E434453536572766C6574AA696E69742D706172616DDE002ABD636F6E666967476C6F73736172793A696E7374616C6C6174696F6E4174B05068696C6164656C706869612C205041B9636F6E666967476C6F73736172793A61646D696E456D61696CAD6B736D40706F626F782E636F6DB8636F6E666967476C6F73736172793A706F77657265644279A5436F666178BC636F6E666967476C6F73736172793A706F7765726564427949636F6EB12F696D616765732F636F6661782E676966B9636F6E666967476C6F73736172793A73746174696350617468AF2F636F6E74656E742F737461746963B674656D706C61746550726F636573736F72436C617373B96F72672E636F6661782E5779736977796754656D706C617465B374656D706C6174654C6F61646572436C617373BD6F72672E636F6661782E46696C657354656D706C6174654C6F61646572AC74656D706C61746550617468A974656D706C61746573B474656D706C6174654F7665727269646550617468A0B364656661756C744C69737454656D706C617465B06C69737454656D706C6174652E68746DB364656661756C7446696C6554656D706C617465B361727469636C6554656D706C6174652E68746DA67573654A5350C2AF6A73704C69737454656D706C617465B06C69737454656D706C6174652E6A7370AF6A737046696C6554656D706C617465B361727469636C6554656D706C6174652E6A7370B563616368655061636B61676554616773547261636BCCC8B563616368655061636B6167655461677353746F7265CCC8B763616368655061636B61676554616773526566726573683CB3636163686554656D706C61746573547261636B64B3636163686554656D706C6174657353746F726532B5636163686554656D706C61746573526566726573680FAF63616368655061676573547261636BCCC8AF6361636865506167657353746F726564B163616368655061676573526566726573680AB3636163686550616765734469727479526561640AB8736561726368456E67696E654C69737454656D706C617465B8666F72536561726368456E67696E65734C6973742E68746DB8736561726368456E67696E6546696C6554656D706C617465B4666F72536561726368456E67696E65732E68746DB4736561726368456E67696E65526F626F74734462B15745422D494E462F726F626F74732E6462AC7573654461746153746F7265C3AE6461746153746F7265436C617373B66F72672E636F6661782E53716C4461746153746F7265B07265646972656374696F6E436C617373B86F72672E636F6661782E53716C5265646972656374696F6EAD6461746153746F72654E616D65A5636F666178AF6461746153746F7265447269766572D92C636F6D2E6D6963726F736F66742E6A6462632E73716C7365727665722E53514C536572766572447269766572AC6461746153746F726555726CD93B6A6462633A6D6963726F736F66743A73716C7365727665723A2F2F4C4F43414C484F53543A313433333B44617461626173654E616D653D676F6F6EAD6461746153746F726555736572A27361B16461746153746F726550617373776F7264B26461746153746F7265546573745175657279B26461746153746F7265546573745175657279D922534554204E4F434F554E54204F4E3B73656C65637420746573743D2774657374273BB06461746153746F72654C6F6746696C65D9242F7573722F6C6F63616C2F746F6D6361742F6C6F67732F6461746173746F72652E6C6F67B26461746153746F7265496E6974436F6E6E730AB16461746153746F72654D6178436F6E6E7364B76461746153746F7265436F6E6E55736167654C696D697464B16461746153746F72654C6F674C6576656CA56465627567AC6D617855726C4C656E677468CD01F483AC736572766C65742D6E616D65AA636F666178456D61696CAD736572766C65742D636C617373BA6F72672E636F6661782E6364732E456D61696C536572766C6574AA696E69742D706172616D82A86D61696C486F7374A56D61696C31B06D61696C486F73744F76657272696465A56D61696C3282AC736572766C65742D6E616D65AA636F66617841646D696EAD736572766C65742D636C617373BA6F72672E636F6661782E6364732E41646D696E536572766C657482AC736572766C65742D6E616D65AB66696C65536572766C6574AD736572766C65742D636C617373B96F72672E636F6661782E6364732E46696C65536572766C657483AC736572766C65742D6E616D65AA636F666178546F6F6C73AD736572766C65742D636C617373BF6F72672E636F6661782E636D732E436F666178546F6F6C73536572766C6574AA696E69742D706172616D8DAC74656D706C61746550617468AF746F6F6C7374656D706C617465732FA36C6F6701AB6C6F674C6F636174696F6ED9252F7573722F6C6F63616C2F746F6D6361742F6C6F67732F436F666178546F6F6C732E6C6F67AA6C6F674D617853697A65A0A7646174614C6F6701AF646174614C6F674C6F636174696F6ED9222F7573722F6C6F63616C2F746F6D6361742F6C6F67732F646174614C6F672E6C6F67AE646174614C6F674D617853697A65A0AF72656D6F7665506167654361636865D9252F636F6E74656E742F61646D696E2F72656D6F76653F63616368653D70616765732669643DB372656D6F766554656D706C6174654361636865D9292F636F6E74656E742F61646D696E2F72656D6F76653F63616368653D74656D706C617465732669643DB266696C655472616E73666572466F6C646572D9342F7573722F6C6F63616C2F746F6D6361742F776562617070732F636F6E74656E742F66696C655472616E73666572466F6C646572AD6C6F6F6B496E436F6E7465787401AC61646D696E47726F7570494404AA62657461536572766572C3AF736572766C65742D6D617070696E6785A8636F666178434453A12FAA636F666178456D61696CB32F636F6661787574696C2F61656D61696C2F2AAA636F66617841646D696EA82F61646D696E2F2AAB66696C65536572766C6574A92F7374617469632F2AAA636F666178546F6F6C73A82F746F6F6C732F2AA67461676C696282AA7461676C69622D757269A9636F6661782E746C64AF7461676C69622D6C6F636174696F6EB72F5745422D494E462F746C64732F636F6661782E746C64"
hex"918FA46461746582A662756666657282A474797065A6427566666572A4646174619401234567A474797065CCFFA35F6964B8363663316233363661333137353434376163346335343165A5696E64657800A467756964D92438666665653537302D353938312D346630362D623635382D653435383163363064373539A86973416374697665C3A762616C616E6365CB40A946956A97C84CA361676516A8657965436F6C6F72A4626C7565A46E616D65AD4D6F72746F6E204C6974746C65A761646472657373D9313933372044656172626F726E20436F7572742C204861726C656967682C204D6173736163687573657474732C2033353936AA72656769737465726564BA323032332D30382D32395431303A34353A3335202D30323A3030A86C61746974756465CB4047551159C49774A96C6F6E676974756465CBC065F94A771C970FA47461677397A54C6F72656DA3657374A86465736572756E74A54C6F72656DA46E697369A76C61626F726973A86465736572756E74A7667269656E64739382A2696400A46E616D65B04865726E616E64657A204C6172736F6E82A2696401A46E616D65AF4D616E6E696E672053617267656E7482A2696402A46E616D65AF536176616E6E6168204E65776D616E"
)

Stream
.emits(cases)
.evalMap { hex =>
Stream
.chunk(Chunk.byteVector(hex))
.through(low.items[IO])
.through(low.toBinary[IO])
.compile
.toList
.map(x => expect.same(ByteVector(x), hex))
def round(data: ByteVector, compress: Boolean) =
Stream
.chunk(Chunk.byteVector(data))
.through(low.items[IO])
.through(low.bytes[IO](compress, false))
.fold(ByteVector.empty)(_ :+ _)

def process(compress: Boolean, serializerName: String) =
for {
data <- Stream.emits(cases)
pre <- round(data, compress)
processed <- round(pre, compress)
} yield {
if (processed == pre)
success
else
failure(s"${serializerName} should be fixpoint for: ${pre} but it emitted ${processed}")
}
.compile
.foldMonoid
}

}
(process(true, "ItemSerializer.compressed") ++ process(false, "ItemSerializer.none")).compile.foldMonoid
}
}

0 comments on commit ac14528

Please sign in to comment.