From de0627529956ddce273522af432d10bdd4329b6b Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Thu, 11 May 2023 01:03:37 -0700 Subject: [PATCH] fix up CRW parsing a bit.. add test cases and framework for smaller tests add a class to emulate a file, and only store the part of the file that was read/accessed... This reduces storing an 11MB file down to under 100KB... It also allows tests to run w/o the whole file... Put the original files in fixtures/original... fix up a couple of issues w/ parsing CRW files, and also allow the ability to skip parts of the CRW file... This allows skipping large parts, like the CCD data and the large thumbnail.. --- ui/fixtures/RAW_CANON_5D_ARGB.CR2 | Bin 0 -> 76348 bytes ui/fixtures/RAW_CANON_5D_ARGB.CR2.fmt | 1 + ui/fixtures/RAW_CANON_G2.CRW | Bin 0 -> 3350332 bytes ui/fixtures/RAW_CANON_G2.CRW.fmt | 1 + ui/medashare/metadata/crw.py | 481 ++++++++++++++++++++++++-- ui/medashare/tests.py | 3 + 6 files changed, 466 insertions(+), 20 deletions(-) create mode 100644 ui/fixtures/RAW_CANON_5D_ARGB.CR2 create mode 100644 ui/fixtures/RAW_CANON_5D_ARGB.CR2.fmt create mode 100644 ui/fixtures/RAW_CANON_G2.CRW create mode 100644 ui/fixtures/RAW_CANON_G2.CRW.fmt diff --git a/ui/fixtures/RAW_CANON_5D_ARGB.CR2 b/ui/fixtures/RAW_CANON_5D_ARGB.CR2 new file mode 100644 index 0000000000000000000000000000000000000000..b5f7c9b27c44a27ca8f6731424794c808334de58 GIT binary patch literal 76348 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 z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF 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 0: + pos1, cnt1 = sc[scidx - 1] + pos1end = pos1 + cnt1 + if pos <= pos1end: + # merge + sc[scidx - 1] = (pos1, max(pos1end - pos1, pos + cnt - pos1)) + return + + # possibly prefix to entry + posend = pos + cnt + if scidx < len(sc) and posend >= sc[scidx][0]: + pos1, cnt1 = sc[scidx] + sc[scidx] = (pos, max(pos1 + cnt1 - pos, posend - pos)) + return + + sc[scidx:scidx] = [ (pos, cnt) ] + + def _check(self, pos1, cnt1, pos2, cnt2): + # check if 2 is within 1 + pos1end = pos1 + cnt1 + pos2end = pos2 + cnt2 + if pos2 >= pos1 and pos2end <= pos1end: + return True + + return False + + def tolist(self): + '''Return a copy of the list. Can be used to recreate or + serialize. + + That is: + SparseCover(sc.tolist()) == sc + ''' + + return self._sc[:] + + def covered(self, pos, cnt): + '''Check to see if [pos, cnt) is covered. + ''' + + sc = self._sc + + if len(sc) == 0: + return False + + scidx = bisect.bisect_right(sc, (pos, float('inf'))) + + #print('f:', repr(sc), pos, cnt, scidx) + + if scidx - 1 >= 0 and self._check(*sc[scidx - 1], pos, cnt): + return True + + if scidx >= len(sc): + return False + + return False + +class _TestSparseCover(unittest.TestCase): + def test_sc_wronginput(self): + # wrong order + self.assertEqual(SparseCover([(10, 1), (1, 5)]).tolist(), [ (1, 5), (10, 1) ]) + + # over lapping, no extension + self.assertEqual(SparseCover([(10, 10), (11, 5)]).tolist(), [ (10, 10) ]) + + # extending + self.assertEqual(SparseCover([(10, 10), (11, 10)]).tolist(), [ (10, 11) ]) + + # prefix overlap + self.assertEqual(SparseCover([(10, 10), (5, 10)]).tolist(), [ (5, 15) ]) + + # prefix exact + self.assertEqual(SparseCover([(10, 10), (5, 5)]).tolist(), [ (5, 15) ]) + + def test_sc(self): + sc = SparseCover() + + self.assertFalse(sc.covered(5, 10)) + + sc.add(10, 50) + + self.assertFalse(sc.covered(5, 10)) + self.assertFalse(sc.covered(50, 50)) + + self.assertTrue(sc.covered(10, 50)) + self.assertTrue(sc.covered(20, 10)) + + sc.add(100, 50) + + self.assertFalse(sc.covered(5, 10)) + self.assertFalse(sc.covered(50, 50)) + self.assertFalse(sc.covered(50, 100)) + self.assertFalse(sc.covered(120, 100)) + self.assertFalse(sc.covered(150, 1)) + + self.assertTrue(sc.covered(20, 10)) + self.assertTrue(sc.covered(100, 50)) + self.assertTrue(sc.covered(100, 1)) + self.assertTrue(sc.covered(149, 1)) + + self.assertEqual(sc.tolist(), [ (10, 50), (100, 50) ]) + + sc = SparseCover(sc.tolist()) + + sc.add(140, 20) + + self.assertEqual(sc.tolist(), [ (10, 50), (100, 60) ]) + + sc.add(1, 5) + + self.assertFalse(sc.covered(50, 100)) + + self.assertTrue(sc.covered(3, 1)) + + self.assertEqual(sc.tolist(), [ (1, 5), (10, 50), (100, 60) ]) + +class _FileEmulator: + __real_open = open + __hash_factory = hashlib.sha512 + + def __init__(self, fname, origfile, emulmetafile): + self._closed = False + self._updateable = False + self._updated = False + self._basefp = None + self._emulmetafile = None + self._pos = 0 + self._sc = None + + orighash = None + + try: + origfp = self.__real_open(origfile, 'rb') + orighash = self._hexdgstfp(origfp) + except FileNotFoundError: + origfp = None + + + try: + with self.__real_open(emulmetafile) as fp: + emuldata = json.load(fp) + + if orighash is not None and emuldata['hash'] != orighash: + raise RuntimeError('hash of emulated date (%s) does not match original file (%s)' % (repr(str(emulmetafile)), repr(str(origfile)))) + + except FileNotFoundError: + if origfp is None: + raise RuntimeError('emulated metadata not present and original file not present: %s' % repr(str(origfile))) + # orig file exists time to emulate it. + + + origfp.seek(0, os.SEEK_END) + + emuldata = { + 'hash': orighash, + 'parts': [], + 'size': origfp.tell(), + } + + # need to make sure this gets written out + self._updated = True + + if origfp is not None: + try: + self._basefp = self.__real_open(fname, 'r+b') + except FileNotFoundError: + # if this fails, race lost, try again + self._basefp = self.__real_open(fname, 'x+b') + + self._updateable = True + else: + self._basefp = self.__real_open(fname, 'rb') + + + self._emulmetafile = emulmetafile + self._emuldata = emuldata + self._origfp = origfp + + self._sc = SparseCover(emuldata['parts']) + + @classmethod + def _hexdgstfp(cls, fp): + fp.seek(0) + + dgst = cls.__hash_factory() + d = None + while d != b'': + d = fp.read(64*1024) + dgst.update(d) + + return dgst.hexdigest() + + def __enter__(self): + return self + + @property + def closed(self): + return self._closed + + def close(self): + if self._closed: + return + + if self._origfp is not None: + self._origfp.close() + self._origfp = None + + if self._basefp is not None: + self._basefp.close() + self._basefp = None + + self._closed = True + + if self._updateable and self._updated: + self._emuldata['parts'] = self._sc.tolist() + with self.__real_open(self._emulmetafile, 'w') as fp: + json.dump(self._emuldata, fp) + print(file=fp) + + self._updated = False + self._updateable = False + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + + return False + + def __del__(self): + self.close() + + def tell(self): + return self._pos + + def seek(self, pos, whence=os.SEEK_SET): + if whence == os.SEEK_SET: + self._pos = pos + elif whence == os.SEEK_END: + self._pos = self._emuldata['size'] + pos + else: + raise ValueError('invalid whence: %s' % repr(str(whence))) + + def read(self, cnt): + #if cnt > 100*1000: + # import traceback + # traceback.print_stack() + + if self.closed: + raise ValueError('read of closed file') + + if not self._sc.covered(self._pos, cnt): + if not self._updateable: + raise RuntimeError('dota not present and not updateable') + + # read in the data + self._origfp.seek(self._pos) + data = self._origfp.read(cnt) + + # write it out + self._basefp.seek(self._pos) + self._basefp.write(data) + self._basefp.flush() + + self._sc.add(self._pos, cnt) + self._updated = True + + #print('d1:', len(data), repr(data[:50]), (self._pos, cnt), repr(self._basefp)) + + self._pos += cnt + + return data + + self._basefp.seek(self._pos) + data = self._basefp.read(cnt) + #print('d2:', len(data), repr(data[:50]), (self._pos, cnt), repr(self._basefp)) + + self._pos += cnt + + return data + +class FileMockTest: + ''' + Mixin w/ unittest.TestCase to mock open, and store subsets + of files. + + The original base files are taken from the attribute fmt_origpath. + The sparse file, and it's meta data will be stores in fmt_basepath. + + You can view that fmt_origpath is backing fmt_basepath in that any + missing files/data from fmt_basepath will be obtained from + fmt_origpath. + + Usage: + class MyTestCase(FileMockTest, TestCase): + fmt_origpath = pathlib.Path(xxx) + + def setUp(self): + super().setUp() + ... + + Required Attributes: + fmt_basepath - underlying path + fmt_origpa/h - path to original files + + Note: if one of the following methods are used, super MUST be + called: setUp, tearDown. + + For example, if the class has a setUp function: + class Example(FileMockTest, TestCase): + def setUp(self): + <... custom setup code ...> + + super().setUp() + ''' + + __real_open = open + __ext = '.fmt' + + def setUp(self): + super().setUp() + + try: + self.fmt_origpath = self.fmt_origpath.resolve() + self.fmt_basepath = self.fmt_basepath.resolve() + except AttributeError: + raise RuntimeError('attribute fmt_origpath not defined on class %s' % self.__class__.__name__) + + self.__openmockpatch = unittest.mock.patch(__name__ + '.open') + + self.__openmock = self.__openmockpatch.start() + + self.__openmock.side_effect = self.__genopen + + def __genopen(self, fname, *args, **kwargs): + fname = pathlib.Path(fname) + #print('genop:', repr(fname), repr(self.fmt_basepath), repr(args)) + + emulmetafile = pathlib.Path(str(fname) + self.__ext) + + # 1) not in fmt_basepath + # 2) exists in basepath, but not emulated + if not fname.is_relative_to(self.fmt_basepath.resolve()) or \ + fname.exists() and not emulmetafile.exists(): + return self.__real_open(fname, *args, **kwargs) + + # either base file is missing, or base file is emulated + + if not args or args[0] != 'rb': + raise ValueError('can only emulate a file for reading binary') + + fname = fname.resolve() + + # need to try to pull from original file + bpplen = len(self.fmt_basepath.parts) + assert fname.parts[:bpplen] == self.fmt_basepath.parts + origfile = pathlib.Path(*(self.fmt_origpath.parts + fname.parts[bpplen:])) + + return _FileEmulator(fname, origfile, emulmetafile) + + def tearDown(self): + try: + self.__openmockpatch.stop() + except Exception: + pass + + super().tearDown() + +class _TestFileMock(unittest.TestCase): + def xtest_foo(self): + class TC(FileMockTest, unittest.TestCase): + def test_openmocked(self): + self.assertIsNot(open, FileMockTest._real_open) + + def test_basicopen(self): + with open('foo', 'r') as fp: + fp.read(10) + + + loader = unittest.TestLoader() + try: + loader.loadTestsFromTestCase(TC).debug() + except Exception: + import traceback + traceback.print_exc() + raise + +class _TestCRW(FileMockTest, unittest.TestCase): + fmt_basepath = pathlib.Path('fixtures') + fmt_origpath = fmt_basepath / 'original' -class _TestCRW(unittest.TestCase): def setUp(self): self.fixtures = pathlib.Path('fixtures').resolve() + super().setUp() + def test_tagname(self): a = TagName('foo', (1, 2)) @@ -1278,11 +1715,15 @@ class _TestCRW(unittest.TestCase): def test_crw(self): with open(self.fixtures / 'RAW_CANON_G2.CRW', 'rb') as fp: - ci = idcrw(fp) + ci = idcrw(fp, [ 'CRW_CCDDATA', 'CRW_THMBBIG' ]) self.assertEqual(ci['CRW_INFO']['INFO_EXPOSEINFO']['CAMERA_MODELID'], (17825792, 2222501223)) self.assertEqual(ci.find('CAMERA_MODELID'), (17825792, 2222501223)) + self.assertEqual(ci.find('CAMERA_MAKEMODEL'), ('Canon', 'Canon PowerShot G2')) + self.assertEqual(ci.find('UNKN_ORIGFNAME'), 'CRW_0011.CRW') + self.assertEqual(ci.find('INFO_TARGETTYPE'), (0, 19680, 39964, 10801)) + #print(repr(ci)) #print(repr(list(ci.keys()))) #print(repr(list(ci['CRW_INFO'].keys()))) #print('unkn:', sorted(TagName._unkn)) diff --git a/ui/medashare/tests.py b/ui/medashare/tests.py index 5ab2915..7120e3f 100644 --- a/ui/medashare/tests.py +++ b/ui/medashare/tests.py @@ -7,3 +7,6 @@ from .tags import _TestTagCache from .mtree import Test from .server import _TestCases, _TestPostConfig from .magic import _TestMagic +from .metadata.crw import _TestCRW +from .metadata.crw import _TestFileMock +from .metadata.crw import _TestSparseCover