1+ #!/usr/bin/env python
2+ """
3+ Pytest plugin hooks for the pyld test-suite runner.
4+
5+ - Adds CLI options: --earl, --loader, --tests (paths), --number
6+ - Configures jsonld default loader based on --loader
7+ - Captures test outcomes and writes an EARL report when requested
8+ """
9+ from __future__ import annotations
10+
11+ import os
12+ import sys
13+ import pytest
14+
15+ # ensure local lib on path for jsonld
16+ sys .path .insert (0 , os .path .join (os .path .dirname (__file__ ), '..' , 'lib' ))
17+ from pyld import jsonld # type: ignore
18+ from helpers import EarlReport
19+
20+ EARL_REPORT = EarlReport ()
21+
22+
23+ def pytest_addoption (parser ):
24+ parser .addoption ('--earl' , action = 'store' , default = None ,
25+ help = 'Write EARL report to this filename' )
26+ parser .addoption ('--loader' , action = 'store' , default = 'requests' ,
27+ help = 'Document loader to use: requests or aiohttp [default: requests]' )
28+ parser .addoption ('--tests' , action = 'store' , default = '' ,
29+ help = 'Colon-separated list of test manifests or directories to run (overrides discovery)' )
30+ parser .addoption ('--number' , action = 'store' , default = None ,
31+ help = 'Limit tests to those containing the specified test identifier' )
32+
33+
34+ def pytest_configure (config ):
35+ # Set a default JSON-LD document loader early based on option
36+ loader = config .getoption ('--loader' )
37+ if loader == 'requests' :
38+ jsonld ._default_document_loader = jsonld .requests_document_loader ()
39+ elif loader == 'aiohttp' :
40+ jsonld ._default_document_loader = jsonld .aiohttp_document_loader ()
41+ # make EARL report instance available via config
42+ config .earl_report = EARL_REPORT
43+
44+
45+ def pytest_runtest_makereport (item , call ):
46+ """
47+ Capture finished test call outcome and add to the EARL report.
48+ The test item is expected to have a 'case' funcarg (our parametrized tests).
49+ """
50+ # Only interested in the 'call' phase outcome (not setup/teardown)
51+ if call .when != 'call' :
52+ return
53+
54+ # call.excinfo is None for a passing call; set success accordingly
55+ success = call .excinfo is None
56+
57+ # Extract test id from fixture 'case' if present
58+ case = item .funcargs .get ('case' ) if 'case' in item .funcargs else None
59+ if case :
60+ data = case .get ('test_data' , {})
61+ test_id = data .get ('id' , data .get ('@id' , data .get ('name' , data .get ('label' , item .name ))))
62+ else :
63+ test_id = item .name
64+
65+ # Only record pass/fail (skipped tests will not be recorded as pass)
66+ if success :
67+ EARL_REPORT .add_assertion (test_id , True )
68+ else :
69+ EARL_REPORT .add_assertion (test_id , False )
70+
71+
72+ def pytest_sessionfinish (session , exitstatus ):
73+ earl_path = session .config .getoption ('--earl' ) or os .environ .get ('PYLD_EARL' )
74+ if earl_path :
75+ # write the EARL report collected
76+ session .config .earl_report .write (earl_path )
77+ print (f'Wrote EARL report to: { earl_path } ' )
0 commit comments