name = "uuid"
description = """
ETNA workload for the Rust `uuid` crate. Each variant re-introduces one
historical bug-fix into a fresh patched branch and pairs it with a
framework-neutral property, four PBT adapters, and a deterministic
witness test.
"""
language = "rust"
strategies = ["proptest", "quickcheck", "crabcheck", "hegel"]
crate = "uuid"
base_commit = "e6fa34189526f409a628f26a89284af314712a67"

[[tasks]]
mutations = ["to_fields_le_byte_swap_0a096d4_1"]

[tasks.source]
repo = "https://github.com/uuid-rs/uuid"
commits = ["0a096d4fb752c71ad8528f3e167e9afd58b4217e"]
commit_subjects = ["fix to_fields_le byte index"]
summary = "`Uuid::to_fields_le` read both halves of `d2` from byte 5 instead of bytes 4 and 5, so the accessor did not invert `from_fields_le` and the round-trip dropped half the bytes."

[tasks.injection]
kind = "patch"
files = ["src/lib.rs"]
locations = [{ file = "src/lib.rs" }]
patch = "patches/to_fields_le_byte_swap_0a096d4_1.patch"

[tasks.bug]
short_name = "to_fields_le_byte_swap"
invariant = "`Uuid::from_fields_le(d1, d2, d3, &d4).to_fields_le()` must round-trip to the original `(d1, d2, d3, &d4)`."
how_triggered = "In `Uuid::to_fields_le`, replaces `as_bytes()[4]` with `as_bytes()[5]` when assembling `d2`'s low byte, so both halves of `d2` are read from byte 5."

[[tasks.tasks]]
property = "FromToFieldsLeRoundtrip"
witnesses = [
  { test_fn = "witness_from_to_fields_le_roundtrip_case_byte_mismatch" },
]

[[tasks]]
mutations = ["v7_random_bytes_order_3af4733_1"]

[tasks.source]
repo = "https://github.com/uuid-rs/uuid"
commits = ["3af4733e60f956bd8673b419d3a9e83fcd0a0b8e"]
commit_subjects = ["fix: keep the order when filling random bytes"]
summary = "`encode_unix_timestamp_millis` swapped `counter_random_bytes[0]` and `[1]` when packing the version/random nibble pair of a v7 UUID, so the bytes ended up in the wrong byte positions relative to RFC 9562 §5.7."

[tasks.injection]
kind = "patch"
files = ["src/timestamp.rs"]
locations = [{ file = "src/timestamp.rs" }]
patch = "patches/v7_random_bytes_order_3af4733_1.patch"

[tasks.bug]
short_name = "v7_random_bytes_order"
invariant = "`Builder::from_unix_timestamp_millis(millis, &bytes)` must produce a UUID whose byte layout matches RFC 9562 §5.7 — in particular `ub[7] == bytes[1]` and `(ub[6] & 0x0F) == (bytes[0] & 0x0F)`."
how_triggered = "In `timestamp::encode_unix_timestamp_millis`, swaps `counter_random_bytes[0]` and `counter_random_bytes[1]` when assembling `counter_random_version`, so the two bytes land in the wrong nibble/byte of the v7 UUID."

[[tasks.tasks]]
property = "V7EncodeByteLayout"
witnesses = [
  { test_fn = "witness_v7_encode_byte_layout_case_byte_swap" },
]

[[tasks]]
mutations = ["version_max_guard_0ed83cf_1"]

[tasks.source]
repo = "https://github.com/uuid-rs/uuid"
commits = ["0ed83cf517a34e28f348811ffabf933b694bc901"]
commit_subjects = ["fix up a few bugs in timestamp related code"]
summary = "`Uuid::get_version`'s `0xf` arm was written without the accompanying `if self.is_max()` guard, so any UUID whose version nibble was `0xF` — even if the other bytes were not all-ones — was reported as `Version::Max` (the RFC 9562 all-ones sentinel)."

[tasks.injection]
kind = "patch"
files = ["src/lib.rs"]
locations = [{ file = "src/lib.rs" }]
patch = "patches/version_max_guard_0ed83cf_1.patch"

[tasks.bug]
short_name = "version_max_guard"
invariant = "`Uuid::get_version()` returns `Some(Version::Max)` **iff** the UUID is the all-ones sentinel. No other UUID with version nibble `0xF` may be reported as `Version::Max`."
how_triggered = "In `Uuid::get_version`, drops the `if self.is_max()` guard on the `0xf` match arm, so any UUID whose version nibble is `0xF` is classified as `Version::Max` regardless of the other bytes."

[[tasks.tasks]]
property = "VersionMaxRequiresAllOnes"
witnesses = [
  { test_fn = "witness_version_max_requires_all_ones_case_version_nibble_only" },
]
