Files
TransPyC/ViperBTests/ViperZipfileProject/App/main.vp
T

260 lines
8.4 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# main.vp — ViperZipfileProject:zipfile 模块读写测试
#
# 覆盖:
# 1) ZipFile("w") 写入 4 个成员(deflate 文本 / deflate 大文件 / stored 伪随机 / 空文件)
# 2) ZipFile("r") 读回: 成员数/名称/大小/compress_size 检查 + 逐成员内容比对
# (CRC32 校验由 zipfile.read 内部完成)
# 3) 损坏 stored 成员 payload 1 字节 → 再次 read 应返回 None 且错误码 ZIP_ERR_CRC
import t, c
from stdint import *
import stdio
import stdlib
import string
import zipfile
import w32.fileio as fio
import w32.win32file as wf
ZIP_PATH: str = "zip_roundtrip.zip"
BIG_LEN: t.CSizeT = 100000
RND_LEN: t.CSizeT = 5000
HELLO_TEXT: str = "Hello, Viper Zipfile!\n"
fail_count: t.CInt = 0
def chk(name: str, cond: t.CInt):
global fail_count
if cond:
stdio.printf("[PASS] %s\n", name)
else:
fail_count += 1
stdio.printf("[FAIL] %s\n", name)
def StrLen(s: bytes) -> t.CSizeT:
n: t.CSizeT = 0
while s is not None and c.Deref(s) != 0:
n += 1
s += 1
return n
def fill_pattern(buf: bytes, length: t.CSizeT, kind: t.CInt):
i: t.CSizeT = 0
while i < length:
if kind == 1:
# 'A'..'G' 循环 — 高度可压缩
buf[i] = 65 + (i % 7)
else:
# 伪随机 — 供 ZIP_STORED 成员
buf[i] = (i * 37 + 11) & 0xFF
i += 1
def WriteZip() -> t.CInt:
stdio.printf("\n--- 1) 写 zip(4 个成员) ---\n")
wf.DeleteFileA(ZIP_PATH)
w: zipfile.ZipFile | t.CPtr = zipfile.ZipFile(ZIP_PATH, "w", zipfile.ZIP_DEFLATED)
if w.ok == 0:
stdio.printf("open(w) failed: %s\n", zipfile.error())
return 1
hello: bytes = stdlib.malloc(64)
if not hello:
stdio.printf("malloc hello failed\n")
w.close()
return 1
string.strcpy(hello, HELLO_TEXT)
hello_len: t.CSizeT = StrLen(hello)
big: bytes = stdlib.malloc(BIG_LEN)
if not big:
stdio.printf("malloc big failed\n")
stdlib.free(hello)
w.close()
return 1
fill_pattern(big, BIG_LEN, 1)
rnd: bytes = stdlib.malloc(RND_LEN)
if not rnd:
stdio.printf("malloc rnd failed\n")
stdlib.free(hello)
stdlib.free(big)
w.close()
return 1
fill_pattern(rnd, RND_LEN, 0)
rc: t.CInt = w.write("hello.txt", hello, hello_len, zipfile.ZIP_DEFLATED)
chk("write hello.txt (deflate)", rc == zipfile.ZIP_ERR_OK)
rc = w.write("big.bin", big, BIG_LEN, zipfile.ZIP_DEFLATED)
chk("write big.bin (deflate, 100000B)", rc == zipfile.ZIP_ERR_OK)
rc = w.write("random.bin", rnd, RND_LEN, zipfile.ZIP_STORED)
chk("write random.bin (stored)", rc == zipfile.ZIP_ERR_OK)
rc = w.write("empty.txt", None, 0, zipfile.ZIP_DEFLATED)
chk("write empty.txt (deflate, 0B)", rc == zipfile.ZIP_ERR_OK)
rc = w.close()
chk("close(w)", rc == zipfile.ZIP_ERR_OK)
stdlib.free(hello)
stdlib.free(big)
stdlib.free(rnd)
return 0
def CheckReadBack(buf: bytes, expect: bytes, length: t.CSizeT) -> t.CInt:
# buf: zipfile.read 返回的解压缓冲;expect: 期望内容
if buf is None:
return 0
if length == 0:
return 1
return t.CInt(string.memcmp(buf, expect, length) == 0)
def ReadZip() -> t.CInt:
stdio.printf("\n--- 2) 读回校验 ---\n")
r: zipfile.ZipFile | t.CPtr = zipfile.ZipFile(ZIP_PATH, "r")
if r.ok == 0:
stdio.printf("open(r) failed: %s\n", zipfile.error())
return 1
chk("entry count == 4", r.info_count == 4)
i: t.CSizeT = 0
while i < r.info_count:
stdio.printf(" [%d] %s\n", t.CInt(i), r.namelist_at(i))
i += 1
# ---- hello.txt:deflate 文本 ----
info: zipfile.ZipInfo | t.CPtr = r.getinfo("hello.txt")
chk("getinfo(hello.txt)", info is not None)
hello_expect: bytes = stdlib.malloc(64)
string.strcpy(hello_expect, HELLO_TEXT)
exp_len: t.CSizeT = StrLen(hello_expect)
if info is not None:
chk("hello file_size == 22", info.file_size == exp_len)
chk("hello compress_size > 0", info.compress_size > 0)
olen: t.CSizeT = 0
data: bytes = r.read("hello.txt", c.Addr(olen))
chk("read(hello.txt)", data is not None)
chk("hello content match", CheckReadBack(data, hello_expect, olen) == 1)
stdlib.free(data)
stdlib.free(hello_expect)
# ---- big.bin:deflate 大文件 ----
info = r.getinfo("big.bin")
chk("getinfo(big.bin)", info is not None)
big_expect: bytes = stdlib.malloc(BIG_LEN)
fill_pattern(big_expect, BIG_LEN, 1)
if info is not None:
chk("big file_size == 100000", info.file_size == BIG_LEN)
chk("big compress_size < file_size", info.compress_size < info.file_size)
chk("big crc != 0", info.crc32 != 0)
olen = 0
data = r.read("big.bin", c.Addr(olen))
chk("read(big.bin)", data is not None)
chk("big content match", data is not None and olen == BIG_LEN
and CheckReadBack(data, big_expect, BIG_LEN) == 1)
stdlib.free(data)
stdlib.free(big_expect)
# ---- random.bin:stored ----
info = r.getinfo("random.bin")
chk("getinfo(random.bin)", info is not None)
rnd_expect: bytes = stdlib.malloc(RND_LEN)
fill_pattern(rnd_expect, RND_LEN, 0)
if info is not None:
chk("random file_size == 5000", info.file_size == RND_LEN)
chk("random stored: compress_size == file_size", info.compress_size == info.file_size)
olen = 0
data = r.read("random.bin", c.Addr(olen))
chk("read(random.bin)", data is not None)
chk("random content match", data is not None and olen == RND_LEN
and CheckReadBack(data, rnd_expect, RND_LEN) == 1)
stdlib.free(data)
stdlib.free(rnd_expect)
# ---- empty.txt:空成员 ----
info = r.getinfo("empty.txt")
chk("getinfo(empty.txt)", info is not None)
olen = 0
data = r.read("empty.txt", c.Addr(olen))
chk("read(empty.txt) ok", data is not None)
chk("empty length == 0", olen == 0)
stdlib.free(data)
# ---- 不存在成员 ----
olen = 0
data = r.read("no_such.txt", c.Addr(olen))
chk("read(missing) returns None", data is None)
chk("read(missing) code NOT_FOUND", zipfile.error_code() == zipfile.ZIP_ERR_NOT_FOUND)
rc: t.CInt = r.close()
chk("close(r)", rc == zipfile.ZIP_ERR_OK)
return 0
def CorruptStoredCheck() -> t.CInt:
stdio.printf("\n--- 3) 损坏 stored 成员后 CRC 校验 ---\n")
r: zipfile.ZipFile | t.CPtr = zipfile.ZipFile(ZIP_PATH, "r")
if r.ok == 0:
stdio.printf("open(r) failed: %s\n", zipfile.error())
return 1
info: zipfile.ZipInfo | t.CPtr = r.getinfo("random.bin")
chk("getinfo(random.bin)", info is not None)
if info is None or info.compress_size < 2:
stdio.printf("cannot locate stored member payload\n")
r.close()
return 1
# 本地头无 extra 时,数据起点 = header_offset + 30 + 名字长
start: t.CSizeT = t.CSizeT(info.header_offset) + 30 + info.name_len
flip_pos: t.CSizeT = start + info.compress_size - 1
stdio.printf(" flip byte at offset %lld (raw)\n", flip_pos)
f: fio.File | t.CPtr = fio.File(ZIP_PATH, fio.MODE.RP)
chk("open RP", f.closed == 0)
if f.closed == 0:
byte_buf: bytes = stdlib.malloc(1)
if not byte_buf:
r.close()
return 1
f.seek(LONG(flip_pos), fio.SEEK_SET)
rd: LONG = f.read(byte_buf, 1)
chk("read back byte", rd == 1)
f.seek(LONG(flip_pos), fio.SEEK_SET)
byte_buf[0] = (byte_buf[0] ^ 0xFF) & 0xFF
wr: LONG = f.write(byte_buf, 1)
chk("flip byte written", wr == 1)
f.close()
stdlib.free(byte_buf)
r.close()
z2: zipfile.ZipFile | t.CPtr = zipfile.ZipFile(ZIP_PATH, "r")
chk("reopen after corruption", z2.ok == 1)
olen: t.CSizeT = 0
data: bytes = z2.read("random.bin", c.Addr(olen))
chk("corrupted read returns None", data is None)
chk("error code == ZIP_ERR_CRC", zipfile.error_code() == zipfile.ZIP_ERR_CRC)
stdio.printf(" last error: %s\n", zipfile.error())
if data is not None:
stdlib.free(data)
z2.close()
return 0
@t.CExport
def main() -> int:
stdio.printf("ViperZipfileProject: zipfile 模块读写测试\n")
if WriteZip() != 0:
return 1
if ReadZip() != 0:
return 1
if CorruptStoredCheck() != 0:
return 1
wf.DeleteFileA(ZIP_PATH)
stdio.printf("\n失败数: %d\n", fail_count)
if fail_count == 0:
stdio.printf("全部通过\n")
return t.CInt(fail_count != 0)