From 1030698083707e91d8cf86c71ec44a24f8704f30 Mon Sep 17 00:00:00 2001 From: Remo Senekowitsch Date: Mon, 18 Sep 2023 22:16:17 +0200 Subject: [PATCH] Sync variable-length-quantity with problem-specifications (#1731) Notably, this removes any tests about overflow as well as the overflow variant from the error enum in the stub. Overflow handling is a valuable thing to learn and practice, but there are other exercises which do that. So it seems unnecesary to expand the case only on the Rust track and maintain our own additional tests. This is a backwards compatible change, submissions which choose to handle overflow should still work fine. --- .../.docs/instructions.md | 6 +- .../.meta/test_template.tera | 33 +++ .../variable-length-quantity/.meta/tests.toml | 91 +++++- .../variable-length-quantity/src/lib.rs | 1 - .../tests/variable-length-quantity.rs | 276 ++++++++++++------ 5 files changed, 315 insertions(+), 92 deletions(-) create mode 100644 exercises/practice/variable-length-quantity/.meta/test_template.tera diff --git a/exercises/practice/variable-length-quantity/.docs/instructions.md b/exercises/practice/variable-length-quantity/.docs/instructions.md index eadce28d0..501254826 100644 --- a/exercises/practice/variable-length-quantity/.docs/instructions.md +++ b/exercises/practice/variable-length-quantity/.docs/instructions.md @@ -2,10 +2,10 @@ Implement variable length quantity encoding and decoding. -The goal of this exercise is to implement [VLQ](https://en.wikipedia.org/wiki/Variable-length_quantity) encoding/decoding. +The goal of this exercise is to implement [VLQ][vlq] encoding/decoding. In short, the goal of this encoding is to encode integer values in a way that would save bytes. -Only the first 7 bits of each byte is significant (right-justified; sort of like an ASCII byte). +Only the first 7 bits of each byte are significant (right-justified; sort of like an ASCII byte). So, if you have a 32-bit value, you have to unpack it into a series of 7-bit bytes. Of course, you will have a variable number of bytes depending upon your integer. To indicate which is the last byte of the series, you leave bit #7 clear. @@ -30,3 +30,5 @@ Here are examples of integers as 32-bit values, and the variable length quantiti 08000000 C0 80 80 00 0FFFFFFF FF FF FF 7F ``` + +[vlq]: https://en.wikipedia.org/wiki/Variable-length_quantity diff --git a/exercises/practice/variable-length-quantity/.meta/test_template.tera b/exercises/practice/variable-length-quantity/.meta/test_template.tera new file mode 100644 index 000000000..f36d9b504 --- /dev/null +++ b/exercises/practice/variable-length-quantity/.meta/test_template.tera @@ -0,0 +1,33 @@ +use variable_length_quantity as vlq; +{% for test in cases %} +#[test] +{% if loop.index != 1 -%} +#[ignore] +{% endif -%} +fn {{ test.description | slugify | replace(from="-", to="_") }}() { +{%- if test.property == "encode" %} + let input = &{{ test.input.integers | json_encode() }}; + let output = vlq::{{ fn_names[0] }}(input); + let expected = vec![ + {%- for byte in test.expected -%} + 0x{{ byte | to_hex }}, + {%- endfor -%} + ]; +{%- elif test.property == "decode" %} + let input = &[ + {%- for byte in test.input.integers -%} + 0x{{ byte | to_hex }}, + {%- endfor -%} + ]; + let output = vlq::{{ fn_names[1] }}(input); + let expected = {% if test.expected is object -%} + Err(vlq::Error::IncompleteNumber) + {%- else -%} + Ok(vec!{{ test.expected | json_encode() }}) + {%- endif %}; +{%- else %} + panic!("unknown property: {{ test.property }}"); +{%- endif %} + assert_eq!(output, expected); +} +{% endfor -%} diff --git a/exercises/practice/variable-length-quantity/.meta/tests.toml b/exercises/practice/variable-length-quantity/.meta/tests.toml index be690e975..c9af549fc 100644 --- a/exercises/practice/variable-length-quantity/.meta/tests.toml +++ b/exercises/practice/variable-length-quantity/.meta/tests.toml @@ -1,3 +1,88 @@ -# This is an auto-generated file. Regular comments will be removed when this -# file is regenerated. Regenerating will not touch any manually added keys, -# so comments can be added in a "comment" key. +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[35c9db2e-f781-4c52-b73b-8e76427defd0] +description = "Encode a series of integers, producing a series of bytes. -> zero" + +[be44d299-a151-4604-a10e-d4b867f41540] +description = "Encode a series of integers, producing a series of bytes. -> arbitrary single byte" + +[ea399615-d274-4af6-bbef-a1c23c9e1346] +description = "Encode a series of integers, producing a series of bytes. -> largest single byte" + +[77b07086-bd3f-4882-8476-8dcafee79b1c] +description = "Encode a series of integers, producing a series of bytes. -> smallest double byte" + +[63955a49-2690-4e22-a556-0040648d6b2d] +description = "Encode a series of integers, producing a series of bytes. -> arbitrary double byte" + +[29da7031-0067-43d3-83a7-4f14b29ed97a] +description = "Encode a series of integers, producing a series of bytes. -> largest double byte" + +[3345d2e3-79a9-4999-869e-d4856e3a8e01] +description = "Encode a series of integers, producing a series of bytes. -> smallest triple byte" + +[5df0bc2d-2a57-4300-a653-a75ee4bd0bee] +description = "Encode a series of integers, producing a series of bytes. -> arbitrary triple byte" + +[f51d8539-312d-4db1-945c-250222c6aa22] +description = "Encode a series of integers, producing a series of bytes. -> largest triple byte" + +[da78228b-544f-47b7-8bfe-d16b35bbe570] +description = "Encode a series of integers, producing a series of bytes. -> smallest quadruple byte" + +[11ed3469-a933-46f1-996f-2231e05d7bb6] +description = "Encode a series of integers, producing a series of bytes. -> arbitrary quadruple byte" + +[d5f3f3c3-e0f1-4e7f-aad0-18a44f223d1c] +description = "Encode a series of integers, producing a series of bytes. -> largest quadruple byte" + +[91a18b33-24e7-4bfb-bbca-eca78ff4fc47] +description = "Encode a series of integers, producing a series of bytes. -> smallest quintuple byte" + +[5f34ff12-2952-4669-95fe-2d11b693d331] +description = "Encode a series of integers, producing a series of bytes. -> arbitrary quintuple byte" + +[7489694b-88c3-4078-9864-6fe802411009] +description = "Encode a series of integers, producing a series of bytes. -> maximum 32-bit integer input" + +[f9b91821-cada-4a73-9421-3c81d6ff3661] +description = "Encode a series of integers, producing a series of bytes. -> two single-byte values" + +[68694449-25d2-4974-ba75-fa7bb36db212] +description = "Encode a series of integers, producing a series of bytes. -> two multi-byte values" + +[51a06b5c-de1b-4487-9a50-9db1b8930d85] +description = "Encode a series of integers, producing a series of bytes. -> many multi-byte values" + +[baa73993-4514-4915-bac0-f7f585e0e59a] +description = "Decode a series of bytes, producing a series of integers. -> one byte" + +[72e94369-29f9-46f2-8c95-6c5b7a595aee] +description = "Decode a series of bytes, producing a series of integers. -> two bytes" + +[df5a44c4-56f7-464e-a997-1db5f63ce691] +description = "Decode a series of bytes, producing a series of integers. -> three bytes" + +[1bb58684-f2dc-450a-8406-1f3452aa1947] +description = "Decode a series of bytes, producing a series of integers. -> four bytes" + +[cecd5233-49f1-4dd1-a41a-9840a40f09cd] +description = "Decode a series of bytes, producing a series of integers. -> maximum 32-bit integer" + +[e7d74ba3-8b8e-4bcb-858d-d08302e15695] +description = "Decode a series of bytes, producing a series of integers. -> incomplete sequence causes error" + +[aa378291-9043-4724-bc53-aca1b4a3fcb6] +description = "Decode a series of bytes, producing a series of integers. -> incomplete sequence causes error, even if value is zero" + +[a91e6f5a-c64a-48e3-8a75-ce1a81e0ebee] +description = "Decode a series of bytes, producing a series of integers. -> multiple values" diff --git a/exercises/practice/variable-length-quantity/src/lib.rs b/exercises/practice/variable-length-quantity/src/lib.rs index 76097b80d..15f55c68c 100644 --- a/exercises/practice/variable-length-quantity/src/lib.rs +++ b/exercises/practice/variable-length-quantity/src/lib.rs @@ -1,7 +1,6 @@ #[derive(Debug, PartialEq, Eq)] pub enum Error { IncompleteNumber, - Overflow, } /// Convert a list of numbers to a stream of bytes encoded with variable length encoding. diff --git a/exercises/practice/variable-length-quantity/tests/variable-length-quantity.rs b/exercises/practice/variable-length-quantity/tests/variable-length-quantity.rs index b2e3e7e29..68079b12c 100644 --- a/exercises/practice/variable-length-quantity/tests/variable-length-quantity.rs +++ b/exercises/practice/variable-length-quantity/tests/variable-length-quantity.rs @@ -1,134 +1,238 @@ use variable_length_quantity as vlq; #[test] -fn to_single_byte() { - assert_eq!(&[0x00], vlq::to_bytes(&[0x00]).as_slice()); - assert_eq!(&[0x40], vlq::to_bytes(&[0x40]).as_slice()); - assert_eq!(&[0x7f], vlq::to_bytes(&[0x7f]).as_slice()); +fn zero() { + let input = &[0]; + let output = vlq::to_bytes(input); + let expected = vec![0x0]; + assert_eq!(output, expected); } #[test] #[ignore] -fn to_double_byte() { - assert_eq!(&[0x81, 0x00], vlq::to_bytes(&[0x80]).as_slice()); - assert_eq!(&[0xc0, 0x00], vlq::to_bytes(&[0x2000]).as_slice()); - assert_eq!(&[0xff, 0x7f], vlq::to_bytes(&[0x3fff]).as_slice()); +fn arbitrary_single_byte() { + let input = &[64]; + let output = vlq::to_bytes(input); + let expected = vec![0x40]; + assert_eq!(output, expected); } #[test] #[ignore] -fn to_triple_byte() { - assert_eq!(&[0x81, 0x80, 0x00], vlq::to_bytes(&[0x4000]).as_slice()); - assert_eq!(&[0xc0, 0x80, 0x00], vlq::to_bytes(&[0x10_0000]).as_slice()); - assert_eq!(&[0xff, 0xff, 0x7f], vlq::to_bytes(&[0x1f_ffff]).as_slice()); +fn largest_single_byte() { + let input = &[127]; + let output = vlq::to_bytes(input); + let expected = vec![0x7f]; + assert_eq!(output, expected); } #[test] #[ignore] -fn to_quadruple_byte() { - assert_eq!( - &[0x81, 0x80, 0x80, 0x00], - vlq::to_bytes(&[0x20_0000]).as_slice() - ); - assert_eq!( - &[0xc0, 0x80, 0x80, 0x00], - vlq::to_bytes(&[0x0800_0000]).as_slice() - ); - assert_eq!( - &[0xff, 0xff, 0xff, 0x7f], - vlq::to_bytes(&[0x0fff_ffff]).as_slice() - ); +fn smallest_double_byte() { + let input = &[128]; + let output = vlq::to_bytes(input); + let expected = vec![0x81, 0x0]; + assert_eq!(output, expected); } #[test] #[ignore] -fn to_quintuple_byte() { - assert_eq!( - &[0x81, 0x80, 0x80, 0x80, 0x00], - vlq::to_bytes(&[0x1000_0000]).as_slice() - ); - assert_eq!( - &[0x8f, 0xf8, 0x80, 0x80, 0x00], - vlq::to_bytes(&[0xff00_0000]).as_slice() - ); - assert_eq!( - &[0x8f, 0xff, 0xff, 0xff, 0x7f], - vlq::to_bytes(&[0xffff_ffff]).as_slice() - ); +fn arbitrary_double_byte() { + let input = &[8192]; + let output = vlq::to_bytes(input); + let expected = vec![0xc0, 0x0]; + assert_eq!(output, expected); } #[test] #[ignore] -fn from_bytes() { - assert_eq!(Ok(vec![0x7f]), vlq::from_bytes(&[0x7f])); - assert_eq!(Ok(vec![0x2000]), vlq::from_bytes(&[0xc0, 0x00])); - assert_eq!(Ok(vec![0x1f_ffff]), vlq::from_bytes(&[0xff, 0xff, 0x7f])); - assert_eq!( - Ok(vec![0x20_0000]), - vlq::from_bytes(&[0x81, 0x80, 0x80, 0x00]) - ); - assert_eq!( - Ok(vec![0xffff_ffff]), - vlq::from_bytes(&[0x8f, 0xff, 0xff, 0xff, 0x7f]) - ); +fn largest_double_byte() { + let input = &[16383]; + let output = vlq::to_bytes(input); + let expected = vec![0xff, 0x7f]; + assert_eq!(output, expected); } #[test] #[ignore] -fn to_bytes_multiple_values() { - assert_eq!(&[0x40, 0x7f], vlq::to_bytes(&[0x40, 0x7f]).as_slice()); - assert_eq!( - &[0x81, 0x80, 0x00, 0xc8, 0xe8, 0x56], - vlq::to_bytes(&[0x4000, 0x12_3456]).as_slice() - ); - assert_eq!( - &[ - 0xc0, 0x00, 0xc8, 0xe8, 0x56, 0xff, 0xff, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0x81, 0x80, - 0x00, - ], - vlq::to_bytes(&[0x2000, 0x12_3456, 0x0fff_ffff, 0x00, 0x3fff, 0x4000]).as_slice() - ); +fn smallest_triple_byte() { + let input = &[16384]; + let output = vlq::to_bytes(input); + let expected = vec![0x81, 0x80, 0x0]; + assert_eq!(output, expected); } #[test] #[ignore] -fn from_bytes_multiple_values() { - assert_eq!( - Ok(vec![0x2000, 0x12_3456, 0x0fff_ffff, 0x00, 0x3fff, 0x4000]), - vlq::from_bytes(&[ - 0xc0, 0x00, 0xc8, 0xe8, 0x56, 0xff, 0xff, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0x81, 0x80, - 0x00, - ]) - ); +fn arbitrary_triple_byte() { + let input = &[1048576]; + let output = vlq::to_bytes(input); + let expected = vec![0xc0, 0x80, 0x0]; + assert_eq!(output, expected); } #[test] #[ignore] -fn incomplete_byte_sequence() { - assert_eq!(Err(vlq::Error::IncompleteNumber), vlq::from_bytes(&[0xff])); +fn largest_triple_byte() { + let input = &[2097151]; + let output = vlq::to_bytes(input); + let expected = vec![0xff, 0xff, 0x7f]; + assert_eq!(output, expected); } #[test] #[ignore] -fn zero_incomplete_byte_sequence() { - assert_eq!(Err(vlq::Error::IncompleteNumber), vlq::from_bytes(&[0x80])); +fn smallest_quadruple_byte() { + let input = &[2097152]; + let output = vlq::to_bytes(input); + let expected = vec![0x81, 0x80, 0x80, 0x0]; + assert_eq!(output, expected); } #[test] #[ignore] -fn overflow_u32() { - assert_eq!( - Err(vlq::Error::Overflow), - vlq::from_bytes(&[0xff, 0xff, 0xff, 0xff, 0x7f]) - ); +fn arbitrary_quadruple_byte() { + let input = &[134217728]; + let output = vlq::to_bytes(input); + let expected = vec![0xc0, 0x80, 0x80, 0x0]; + assert_eq!(output, expected); } #[test] #[ignore] -fn chained_execution_is_identity() { - let test = &[0xf2, 0xf6, 0x96, 0x9c, 0x3b, 0x39, 0x2e, 0x30, 0xb3, 0x24]; - assert_eq!( - Ok(Vec::from(&test[..])), - vlq::from_bytes(&vlq::to_bytes(test)) - ); +fn largest_quadruple_byte() { + let input = &[268435455]; + let output = vlq::to_bytes(input); + let expected = vec![0xff, 0xff, 0xff, 0x7f]; + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn smallest_quintuple_byte() { + let input = &[268435456]; + let output = vlq::to_bytes(input); + let expected = vec![0x81, 0x80, 0x80, 0x80, 0x0]; + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn arbitrary_quintuple_byte() { + let input = &[4278190080]; + let output = vlq::to_bytes(input); + let expected = vec![0x8f, 0xf8, 0x80, 0x80, 0x0]; + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn maximum_32_bit_integer_input() { + let input = &[4294967295]; + let output = vlq::to_bytes(input); + let expected = vec![0x8f, 0xff, 0xff, 0xff, 0x7f]; + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn two_single_byte_values() { + let input = &[64, 127]; + let output = vlq::to_bytes(input); + let expected = vec![0x40, 0x7f]; + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn two_multi_byte_values() { + let input = &[16384, 1193046]; + let output = vlq::to_bytes(input); + let expected = vec![0x81, 0x80, 0x0, 0xc8, 0xe8, 0x56]; + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn many_multi_byte_values() { + let input = &[8192, 1193046, 268435455, 0, 16383, 16384]; + let output = vlq::to_bytes(input); + let expected = vec![ + 0xc0, 0x0, 0xc8, 0xe8, 0x56, 0xff, 0xff, 0xff, 0x7f, 0x0, 0xff, 0x7f, 0x81, 0x80, 0x0, + ]; + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn one_byte() { + let input = &[0x7f]; + let output = vlq::from_bytes(input); + let expected = Ok(vec![127]); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn two_bytes() { + let input = &[0xc0, 0x0]; + let output = vlq::from_bytes(input); + let expected = Ok(vec![8192]); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn three_bytes() { + let input = &[0xff, 0xff, 0x7f]; + let output = vlq::from_bytes(input); + let expected = Ok(vec![2097151]); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn four_bytes() { + let input = &[0x81, 0x80, 0x80, 0x0]; + let output = vlq::from_bytes(input); + let expected = Ok(vec![2097152]); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn maximum_32_bit_integer() { + let input = &[0x8f, 0xff, 0xff, 0xff, 0x7f]; + let output = vlq::from_bytes(input); + let expected = Ok(vec![4294967295]); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn incomplete_sequence_causes_error() { + let input = &[0xff]; + let output = vlq::from_bytes(input); + let expected = Err(vlq::Error::IncompleteNumber); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn incomplete_sequence_causes_error_even_if_value_is_zero() { + let input = &[0x80]; + let output = vlq::from_bytes(input); + let expected = Err(vlq::Error::IncompleteNumber); + assert_eq!(output, expected); +} + +#[test] +#[ignore] +fn multiple_values() { + let input = &[ + 0xc0, 0x0, 0xc8, 0xe8, 0x56, 0xff, 0xff, 0xff, 0x7f, 0x0, 0xff, 0x7f, 0x81, 0x80, 0x0, + ]; + let output = vlq::from_bytes(input); + let expected = Ok(vec![8192, 1193046, 268435455, 0, 16383, 16384]); + assert_eq!(output, expected); }