PythonSTB commited on
Commit
b52906b
·
verified ·
1 Parent(s): b843ec1

Upload cryptography/Test_Cryptography.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. cryptography/Test_Cryptography.py +512 -0
cryptography/Test_Cryptography.py ADDED
@@ -0,0 +1,512 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ On-device verification for the cross-compiled cryptography + cffi wheels.
3
+
4
+ Run after installing:
5
+ pip install pycparser-2.22-py2.py3-none-any.whl
6
+ pip install cffi-2.1.1-cp312-cp312-android_24_<ABI>.whl
7
+ pip install cryptography-50.0.0-cp312-abi3-android_24_<ABI>.whl
8
+
9
+ Usage:
10
+ python test_crypto_on_device.py [--quick]
11
+
12
+ Exit code 0 = everything required PASSed.
13
+ Sections marked [SKIP] are features the bundled OpenSSL 3.2.1 does not
14
+ provide (e.g. post-quantum ML-KEM/ML-DSA) and are informational only.
15
+
16
+ Generated by RIMI
17
+ """
18
+ import sys
19
+ import traceback
20
+
21
+ RESULTS = []
22
+
23
+
24
+ def test(name, fn):
25
+ try:
26
+ fn()
27
+ RESULTS.append((name, "PASS", None))
28
+ except NotImplementedError as exc:
29
+ RESULTS.append((name, "SKIP", str(exc)))
30
+ except Exception as exc:
31
+ RESULTS.append((name, "FAIL", "%s: %s" % (type(exc).__name__, exc)))
32
+ print(" ! %s -> %s: %s" % (name, type(exc).__name__, exc))
33
+
34
+
35
+ def section(title):
36
+ print("=" * 60)
37
+ print(title)
38
+ print("=" * 60)
39
+
40
+
41
+ # ---------------------------------------------------------------------------
42
+ # 1. cryptography import surface
43
+ # ---------------------------------------------------------------------------
44
+ def imports_core():
45
+ import cryptography
46
+ assert cryptography.__version__ == "50.0.0", cryptography.__version__
47
+ import cryptography.hazmat.bindings._rust # noqa: F401 (the .so extension)
48
+ import cryptography.exceptions # noqa: F401
49
+ import cryptography.utils # noqa: F401
50
+ import cryptography.fernet # noqa: F401
51
+ import cryptography.cobblestone # noqa: F401
52
+
53
+
54
+ def imports_bindings():
55
+ import cryptography.hazmat.backends.openssl.backend # noqa: F401
56
+ import cryptography.hazmat.bindings.openssl._conditional # noqa: F401
57
+ import cryptography.hazmat.bindings.openssl.binding # noqa: F401
58
+ import cryptography.hazmat.bindings._rust # noqa: F401
59
+
60
+
61
+ def imports_primitives():
62
+ import cryptography.hazmat.primitives.hashes # noqa: F401
63
+ import cryptography.hazmat.primitives.hmac # noqa: F401
64
+ import cryptography.hazmat.primitives.cmac # noqa: F401
65
+ import cryptography.hazmat.primitives.ciphers # noqa: F401
66
+ import cryptography.hazmat.primitives.ciphers.aead # noqa: F401
67
+ import cryptography.hazmat.primitives.padding # noqa: F401
68
+ import cryptography.hazmat.primitives.constant_time # noqa: F401
69
+ import cryptography.hazmat.primitives.keywrap # noqa: F401
70
+ import cryptography.hazmat.primitives.poly1305 # noqa: F401
71
+ import cryptography.hazmat.primitives.hpke # noqa: F401
72
+ import cryptography.hazmat.primitives.kdf.hkdf # noqa: F401
73
+ import cryptography.hazmat.primitives.kdf.pbkdf2 # noqa: F401
74
+ import cryptography.hazmat.primitives.kdf.scrypt # noqa: F401
75
+ import cryptography.hazmat.primitives.kdf.kbkdf # noqa: F401
76
+ import cryptography.hazmat.primitives.kdf.concatkdf # noqa: F401
77
+ import cryptography.hazmat.primitives.kdf.x963kdf # noqa: F401
78
+ import cryptography.hazmat.primitives.serialization # noqa: F401
79
+ import cryptography.hazmat.primitives.serialization.pkcs7 # noqa: F401
80
+ import cryptography.hazmat.primitives.serialization.pkcs12 # noqa: F401
81
+ import cryptography.hazmat.primitives.serialization.ssh # noqa: F401
82
+ import cryptography.hazmat.primitives.twofactor.hotp # noqa: F401
83
+ import cryptography.hazmat.primitives.twofactor.totp # noqa: F401
84
+
85
+
86
+ def imports_asymmetric():
87
+ import cryptography.hazmat.primitives.asymmetric.rsa # noqa: F401
88
+ import cryptography.hazmat.primitives.asymmetric.ec # noqa: F401
89
+ import cryptography.hazmat.primitives.asymmetric.dsa # noqa: F401
90
+ import cryptography.hazmat.primitives.asymmetric.dh # noqa: F401
91
+ import cryptography.hazmat.primitives.asymmetric.ed25519 # noqa: F401
92
+ import cryptography.hazmat.primitives.asymmetric.ed448 # noqa: F401
93
+ import cryptography.hazmat.primitives.asymmetric.x25519 # noqa: F401
94
+ import cryptography.hazmat.primitives.asymmetric.x448 # noqa: F401
95
+ import cryptography.hazmat.primitives.asymmetric.padding # noqa: F401
96
+ import cryptography.hazmat.primitives.asymmetric.utils # noqa: F401
97
+
98
+
99
+ def imports_x509():
100
+ import cryptography.x509 # noqa: F401
101
+ import cryptography.x509.base # noqa: F401
102
+ import cryptography.x509.extensions # noqa: F401
103
+ import cryptography.x509.general_name # noqa: F401
104
+ import cryptography.x509.name # noqa: F401
105
+ import cryptography.x509.ocsp # noqa: F401
106
+ import cryptography.x509.oid # noqa: F401
107
+ import cryptography.x509.verification # noqa: F401
108
+ import cryptography.x509.certificate_transparency # noqa: F401
109
+
110
+
111
+ # ---------------------------------------------------------------------------
112
+ # 2. hashes / hmac / cmac
113
+ # ---------------------------------------------------------------------------
114
+ def hashes():
115
+ from cryptography.hazmat.primitives import hashes
116
+ d = hashes.Hash(hashes.SHA256())
117
+ d.update(b"hello cryptography")
118
+ assert d.finalize().hex() == (
119
+ "a301dc0ba3af7e81df0d99b6b37c4ffca866cb2ee44058bb76158db3b59d02b9"
120
+ ), "SHA256 mismatch"
121
+
122
+
123
+ def sha512():
124
+ from cryptography.hazmat.primitives import hashes
125
+ d = hashes.Hash(hashes.SHA512())
126
+ d.update(b"abc")
127
+ h = d.finalize().hex()
128
+ assert h.startswith("ddaf35a193617aba"), "SHA512 mismatch"
129
+
130
+
131
+ def sha3_and_blake2():
132
+ from cryptography.hazmat.primitives import hashes
133
+ for cls in (hashes.SHA3_256, hashes.SHA3_512):
134
+ d = hashes.Hash(cls())
135
+ d.update(b"data")
136
+ assert len(d.finalize()) == d.algorithm.digest_size
137
+ d = hashes.Hash(hashes.BLAKE2b(digest_size=64))
138
+ d.update(b"data")
139
+ assert len(d.finalize()) == 64
140
+ d = hashes.Hash(hashes.SHA256())
141
+ d.update(b"x")
142
+ assert len(d.finalize()) == 32
143
+
144
+
145
+ def hmac_():
146
+ from cryptography.hazmat.primitives import hashes, hmac
147
+ h = hmac.HMAC(b"key", hashes.SHA256())
148
+ h.update(b"message")
149
+ assert len(h.finalize()) == 32
150
+
151
+
152
+ def cmac():
153
+ from cryptography.hazmat.primitives import cmac
154
+ from cryptography.hazmat.primitives.ciphers import algorithms
155
+ c = cmac.CMAC(algorithms.AES(b"0" * 16))
156
+ c.update(b"msg")
157
+ assert len(c.finalize()) == 16
158
+
159
+
160
+ # ---------------------------------------------------------------------------
161
+ # 3. symmetric ciphers
162
+ # ---------------------------------------------------------------------------
163
+ def aes_gcm():
164
+ from cryptography.hazmat.primitives.ciphers.aead import AESGCM
165
+ key = bytes(range(32))
166
+ nonce = b"123456789012"
167
+ ct = AESGCM(key).encrypt(nonce, b"secret message", b"aad")
168
+ pt = AESGCM(key).decrypt(nonce, ct, b"aad")
169
+ assert pt == b"secret message"
170
+
171
+
172
+ def aes_cbc():
173
+ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
174
+ cipher = Cipher(algorithms.AES(b"0" * 16), modes.CBC(b"0" * 16))
175
+ enc = cipher.encryptor()
176
+ ct = enc.update(b"0123456789abcdef") + enc.finalize()
177
+ cipher2 = Cipher(algorithms.AES(b"0" * 16), modes.CBC(b"0" * 16))
178
+ dec = cipher2.decryptor()
179
+ assert dec.update(ct) + dec.finalize() == b"0123456789abcdef"
180
+
181
+
182
+ def chacha20_poly1305():
183
+ from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305
184
+ key = bytes(range(32))
185
+ nonce = b"123456789012"
186
+ ct = ChaCha20Poly1305(key).encrypt(nonce, b"hello", None)
187
+ assert ChaCha20Poly1305(key).decrypt(nonce, ct, None) == b"hello"
188
+
189
+
190
+ def padding_():
191
+ from cryptography.hazmat.primitives import padding
192
+ p = padding.PKCS7(128).padder()
193
+ data = p.update(b"1234") + p.finalize()
194
+ u = padding.PKCS7(128).unpadder()
195
+ assert u.update(data) + u.finalize() == b"1234"
196
+
197
+
198
+ def keywrap_():
199
+ from cryptography.hazmat.primitives.keywrap import aes_key_wrap, aes_key_unwrap
200
+ kek = b"0" * 16
201
+ wrapped = aes_key_wrap(kek, b"1" * 24)
202
+ assert aes_key_unwrap(kek, wrapped) == b"1" * 24
203
+
204
+
205
+ # ---------------------------------------------------------------------------
206
+ # 4. asymmetric
207
+ # ---------------------------------------------------------------------------
208
+ def rsa_sign_verify():
209
+ from cryptography.hazmat.primitives import hashes, serialization
210
+ from cryptography.hazmat.primitives.asymmetric import padding, rsa
211
+ key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
212
+ sig = key.sign(b"data", padding.PKCS1v15(), hashes.SHA256())
213
+ key.public_key().verify(sig, b"data", padding.PKCS1v15(), hashes.SHA256())
214
+
215
+ pub_pem = key.public_key().public_bytes(
216
+ serialization.Encoding.PEM,
217
+ serialization.PublicFormat.SubjectPublicKeyInfo,
218
+ )
219
+ loaded = serialization.load_pem_public_key(pub_pem)
220
+ loaded.verify(sig, b"data", padding.PKCS1v15(), hashes.SHA256())
221
+
222
+ priv_pem = key.private_bytes(
223
+ serialization.Encoding.PEM,
224
+ serialization.PrivateFormat.PKCS8,
225
+ serialization.NoEncryption(),
226
+ )
227
+ assert serialization.load_pem_private_key(priv_pem, None) is not None
228
+
229
+
230
+ def rsa_oaep():
231
+ from cryptography.hazmat.primitives import hashes
232
+ from cryptography.hazmat.primitives.asymmetric import padding, rsa
233
+ key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
234
+ ct = key.public_key().encrypt(
235
+ b"top secret", padding.OAEP(mgf=padding.MGF1(hashes.SHA256()),
236
+ algorithm=hashes.SHA256(), label=None)
237
+ )
238
+ assert key.decrypt(ct, padding.OAEP(mgf=padding.MGF1(hashes.SHA256()),
239
+ algorithm=hashes.SHA256(),
240
+ label=None)) == b"top secret"
241
+
242
+
243
+ def ec_():
244
+ from cryptography.hazmat.primitives import hashes
245
+ from cryptography.hazmat.primitives.asymmetric import ec
246
+ key = ec.generate_private_key(ec.SECP256R1())
247
+ sig = key.sign(b"msg", ec.ECDSA(hashes.SHA256()))
248
+ key.public_key().verify(sig, b"msg", ec.ECDSA(hashes.SHA256()))
249
+
250
+
251
+ def ed25519_():
252
+ from cryptography.hazmat.primitives.asymmetric import ed25519
253
+ key = ed25519.Ed25519PrivateKey.generate()
254
+ sig = key.sign(b"msg")
255
+ key.public_key().verify(sig, b"msg")
256
+
257
+
258
+ def ed448_():
259
+ from cryptography.hazmat.primitives.asymmetric import ed448
260
+ key = ed448.Ed448PrivateKey.generate()
261
+ sig = key.sign(b"msg")
262
+ key.public_key().verify(sig, b"msg")
263
+
264
+
265
+ def x25519_():
266
+ from cryptography.hazmat.primitives.asymmetric import x25519
267
+ a = x25519.X25519PrivateKey.generate()
268
+ b = x25519.X25519PrivateKey.generate()
269
+ sa = a.exchange(b.public_key())
270
+ sb = b.exchange(a.public_key())
271
+ assert sa == sb
272
+
273
+
274
+ def x448_():
275
+ from cryptography.hazmat.primitives.asymmetric import x448
276
+ a = x448.X448PrivateKey.generate()
277
+ b = x448.X448PrivateKey.generate()
278
+ assert a.exchange(b.public_key()) == b.exchange(a.public_key())
279
+
280
+
281
+ def dh_():
282
+ from cryptography.hazmat.primitives.asymmetric import dh
283
+ params = dh.generate_parameters(generator=2, key_size=2048)
284
+ a = params.generate_private_key()
285
+ b = params.generate_private_key()
286
+ assert a.exchange(b.public_key()) == b.exchange(a.public_key())
287
+
288
+
289
+ def dsa_():
290
+ from cryptography.hazmat.primitives import hashes
291
+ from cryptography.hazmat.primitives.asymmetric import dsa
292
+ key = dsa.generate_private_key(key_size=2048)
293
+ sig = key.sign(b"m", hashes.SHA256())
294
+ key.public_key().verify(sig, b"m", hashes.SHA256())
295
+
296
+
297
+ # ---------------------------------------------------------------------------
298
+ # 5. KDF / password hashing
299
+ # ---------------------------------------------------------------------------
300
+ def hkdf_():
301
+ from cryptography.hazmat.primitives import hashes
302
+ from cryptography.hazmat.primitives.kdf.hkdf import HKDF
303
+ k = HKDF(algorithm=hashes.SHA256(), length=32, salt=None, info=b"i").derive(b"pw")
304
+ assert len(k) == 32
305
+
306
+
307
+ def pbkdf2_():
308
+ from cryptography.hazmat.primitives import hashes
309
+ from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
310
+ k = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=b"s", iterations=1000).derive(b"pw")
311
+ assert len(k) == 32
312
+
313
+
314
+ def scrypt_():
315
+ from cryptography.hazmat.primitives.kdf.scrypt import Scrypt
316
+ k = Scrypt(salt=b"salt", length=32, n=2**14, r=8, p=1).derive(b"pw")
317
+ assert len(k) == 32
318
+
319
+
320
+ # ---------------------------------------------------------------------------
321
+ # 6. x509
322
+ # ---------------------------------------------------------------------------
323
+ def x509_selfsigned():
324
+ import datetime
325
+ from cryptography import x509
326
+ from cryptography.hazmat.primitives import hashes, serialization
327
+ from cryptography.hazmat.primitives.asymmetric import ec
328
+ from cryptography.x509.oid import NameOID
329
+
330
+ key = ec.generate_private_key(ec.SECP256R1())
331
+ name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "test")])
332
+ now = datetime.datetime.now(datetime.timezone.utc)
333
+ cert = (
334
+ x509.CertificateBuilder()
335
+ .subject_name(name)
336
+ .issuer_name(name)
337
+ .public_key(key.public_key())
338
+ .serial_number(x509.random_serial_number())
339
+ .not_valid_before(now - datetime.timedelta(days=1))
340
+ .not_valid_after(now + datetime.timedelta(days=1))
341
+ .add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True)
342
+ .sign(key, hashes.SHA256())
343
+ )
344
+ pem = cert.public_bytes(serialization.Encoding.PEM)
345
+ loaded = x509.load_pem_x509_certificate(pem)
346
+ assert loaded.subject == name
347
+ loaded.public_key().verify(
348
+ cert.signature, cert.tbs_certificate_bytes,
349
+ ec.ECDSA(hashes.SHA256()),
350
+ )
351
+
352
+
353
+ # ---------------------------------------------------------------------------
354
+ # 7. fernet
355
+ # ---------------------------------------------------------------------------
356
+ def fernet_():
357
+ from cryptography.fernet import Fernet
358
+ f = Fernet(Fernet.generate_key())
359
+ t = f.encrypt(b"payload")
360
+ assert f.decrypt(t) == b"payload"
361
+
362
+
363
+ # ---------------------------------------------------------------------------
364
+ # 8. cffi
365
+ # ---------------------------------------------------------------------------
366
+ def cffi_import():
367
+ import _cffi_backend
368
+ import cffi
369
+ assert cffi.__version__ == "2.1.1", cffi.__version__
370
+ # backend version must match the cffi package version
371
+ assert getattr(_cffi_backend, "__version__", None) in (None, "2.1.1")
372
+
373
+
374
+ def _open_libc(ffi):
375
+ import ctypes.util
376
+ for name in ("libc.so", "libc.so.6", "c"):
377
+ try:
378
+ return ffi.dlopen(name)
379
+ except OSError:
380
+ continue
381
+ found = ctypes.util.find_library("c")
382
+ if found:
383
+ return ffi.dlopen(found)
384
+ raise NotImplementedError("no libc available on this platform")
385
+
386
+
387
+ def cffi_libc_call():
388
+ import cffi
389
+ ffi = cffi.FFI()
390
+ ffi.cdef("size_t strlen(const char *s);")
391
+ lib = _open_libc(ffi)
392
+ s = ffi.new("char[]", b"android-cffi")
393
+ n = lib.strlen(s)
394
+ assert n == 12, n
395
+
396
+
397
+ def cffi_abi_mode():
398
+ import cffi
399
+ ffi = cffi.FFI()
400
+ ffi.cdef("int abs(int x);")
401
+ lib = _open_libc(ffi)
402
+ assert lib.abs(-5) == 5
403
+
404
+
405
+ def cffi_struct():
406
+ import cffi
407
+ ffi = cffi.FFI()
408
+ ffi.cdef(
409
+ "typedef struct { int x; int y; } point_t; "
410
+ "point_t make_point(int x, int y);"
411
+ )
412
+ # use ABI mode call into a trivial function we link ourselves via ctypes-free
413
+ # path is not available, so just validate the type machinery and FFI().new()
414
+ p = ffi.new("point_t*")
415
+ p.x = 3
416
+ p.y = 4
417
+ assert p.x == 3 and p.y == 4
418
+
419
+
420
+ def cffi_callback():
421
+ import cffi
422
+ ffi = cffi.FFI()
423
+ ffi.cdef("typedef int (*cb_t)(int);")
424
+ calls = []
425
+ cb = ffi.callback("int(int)", lambda n: (calls.append(n), n + 1)[1])
426
+ assert cb(10) == 11
427
+ assert calls == [10]
428
+
429
+
430
+ # ---------------------------------------------------------------------------
431
+ def main():
432
+ quick = "--quick" in sys.argv
433
+
434
+ section("1. cryptography imports (full surface)")
435
+ test("import core (version + _rust.so + fernet)", imports_core)
436
+ test("import bindings/backends", imports_bindings)
437
+ test("import primitives", imports_primitives)
438
+ test("import asymmetric", imports_asymmetric)
439
+ test("import x509", imports_x509)
440
+
441
+ section("2. hashes / hmac / cmac")
442
+ test("SHA256", hashes)
443
+ test("SHA512", sha512)
444
+ test("SHA3 / BLAKE2", sha3_and_blake2)
445
+ test("HMAC", hmac_)
446
+ test("CMAC", cmac)
447
+
448
+ section("3. symmetric ciphers")
449
+ test("AES-GCM", aes_gcm)
450
+ test("AES-CBC", aes_cbc)
451
+ test("ChaCha20-Poly1305", chacha20_poly1305)
452
+ test("PKCS7 padding", padding_)
453
+ test("AES keywrap", keywrap_)
454
+
455
+ section("4. asymmetric")
456
+ test("RSA sign/verify + PEM roundtrip", rsa_sign_verify)
457
+ test("RSA-OAEP", rsa_oaep)
458
+ test("EC P-256", ec_)
459
+ test("Ed25519", ed25519_)
460
+ test("Ed448", ed448_)
461
+ test("X25519 key exchange", x25519_)
462
+ test("X448 key exchange", x448_)
463
+ test("DH", dh_)
464
+ test("DSA", dsa_)
465
+
466
+ section("5. KDF")
467
+ test("HKDF", hkdf_)
468
+ test("PBKDF2", pbkdf2_)
469
+ test("scrypt", scrypt_)
470
+
471
+ section("6. X.509")
472
+ test("self-signed cert build+parse+verify", x509_selfsigned)
473
+
474
+ section("7. Fernet")
475
+ test("Fernet encrypt/decrypt", fernet_)
476
+
477
+ section("8. cffi")
478
+ test("cffi import (backend version match)", cffi_import)
479
+ test("cffi dlopen libc + strlen", cffi_libc_call)
480
+ test("cffi ABI mode abs()", cffi_abi_mode)
481
+ test("cffi struct", cffi_struct)
482
+ test("cffi callback", cffi_callback)
483
+
484
+ print()
485
+ print("=" * 60)
486
+ print("SUMMARY")
487
+ print("=" * 60)
488
+ fails = 0
489
+ skips = 0
490
+ for name, status, why in RESULTS:
491
+ mark = " OK" if status == "PASS" else (" SKIP" if status == "SKIP" else "FAIL")
492
+ print("%s %s" % (mark, name))
493
+ if why:
494
+ print(" -> %s" % why)
495
+ if status == "FAIL":
496
+ fails += 1
497
+ elif status == "SKIP":
498
+ skips += 1
499
+ print()
500
+ passed = len(RESULTS) - fails - skips
501
+ print("passed=%d skipped=%d failed=%d" % (passed, skips, fails))
502
+ if fails:
503
+ print("RESULT: FAILED")
504
+ elif skips and not quick:
505
+ print("RESULT: PASSED (with informational skips)")
506
+ else:
507
+ print("RESULT: PASSED")
508
+ sys.exit(1 if fails else 0)
509
+
510
+
511
+ if __name__ == "__main__":
512
+ main()