77from glob import glob
88from pathlib import Path
99from typing import (
10- Any ,
1110 Callable ,
12- Dict ,
1311 Final ,
1412 Generator ,
15- List ,
1613 Optional ,
1714 Self ,
1815 Set ,
19- Type ,
2016)
2117
2218import git
23- import pytest
2419import requests_cache
2520from _pytest .config import Config
2621from _pytest .config .argparsing import Parser
3126from requests_cache import CachedSession
3227from requests_cache .backends .sqlite import SQLiteCache
3328
34- from ethereum_spec_tools .evm_tools .statetest import TestCase as StateTestCase
35- from ethereum_spec_tools .evm_tools .statetest import (
36- read_test_case as read_state_test_case ,
37- )
38-
39- from . import FORKS , TEST_FIXTURES
40- from .helpers .exceptional_test_patterns import (
41- exceptional_blockchain_test_patterns ,
42- exceptional_state_test_patterns ,
43- )
44- from .helpers .load_blockchain_tests import Load , run_blockchain_st_test
45- from .helpers .load_state_tests import run_state_test
29+ from . import TEST_FIXTURES
30+ from .helpers import ALL_FIXTURE_TYPES
4631
4732try :
4833 from xdist import get_xdist_worker_id
@@ -316,201 +301,12 @@ def pytest_collect_file(
316301 return None
317302
318303
319- class Fixture :
320- """Single fixture from a JSON file."""
321-
322- @classmethod
323- def is_format (cls , obj : object ) -> bool :
324- """Return true if the object can be parsed as the fixture type."""
325- raise NotImplementedError ("Not implemented." )
326-
327- @classmethod
328- def collect (
329- cls , file_path : str , key : str , obj : Dict [str , Any ]
330- ) -> Generator [Item , None , None ]:
331- """Collect tests from a single fixture dictionary."""
332- pass
333-
334-
335- class StateTest (Item ):
336- """Single state test case item."""
337-
338- test_case : StateTestCase
339- test_dict : Dict [str , Any ]
340-
341- def __init__ (
342- self ,
343- * args : Any ,
344- test_case : StateTestCase ,
345- test_dict : Dict [str , Any ],
346- ** kwargs : Any ,
347- ) -> None :
348- """Initialize a single test case item."""
349- super ().__init__ (* args , ** kwargs )
350- self .test_case = test_case
351- self .test_dict = test_dict
352- self .own_markers .append (pytest .mark .fork (self .test_case .fork_name ))
353- self .own_markers .append (pytest .mark .evm_tools )
354- self .own_markers .append (pytest .mark .json_state_tests )
355- eels_fork = FORKS [test_case .fork_name ]["eels_fork" ]
356- test_patterns = exceptional_state_test_patterns (
357- test_case .fork_name , eels_fork
358- )
359- if any (x .search (test_case .key ) for x in test_patterns .slow ):
360- self .own_markers .append (pytest .mark .slow )
361-
362- def runtest (self ) -> None :
363- """Execute the test logic for this specific static test."""
364- test_case_dict = {
365- "test_file" : self .test_case .path ,
366- "test_key" : self .test_case .key ,
367- "index" : self .test_case .index ,
368- "json_fork" : self .test_case .fork_name ,
369- "test_dict" : self .test_dict ,
370- }
371- run_state_test (test_case_dict )
372-
373-
374- class StateTestFixture (Fixture ):
375- """Single state test fixture from a JSON file."""
376-
377- @classmethod
378- def is_format (cls , obj : object ) -> bool :
379- """Return true if the object can be parsed as the fixture type."""
380- if "env" not in obj :
381- return False
382- if "pre" not in obj :
383- return False
384- if "transaction" not in obj :
385- return False
386- if "post" not in obj :
387- return False
388- return True
389-
390- @classmethod
391- def collect (
392- cls , parent : Collector , file_path : str , key : str , obj : Dict [str , Any ]
393- ) -> Generator [Item , None , None ]:
394- """Collect state tests from a single fixture dictionary."""
395- for test_case in read_state_test_case (
396- test_file_path = file_path , key = key , test = obj
397- ):
398- if test_case .fork_name not in FORKS :
399- continue
400- name = f"{ key } - { test_case .index } "
401- new_item = StateTest .from_parent (
402- parent ,
403- name = name ,
404- test_case = test_case ,
405- test_dict = obj ,
406- )
407- yield new_item
408-
409-
410- class BlockchainTest (Item ):
411- """Single state test case item."""
412-
413- test_file : str
414- test_key : str
415- fork_name : str
416- test_dict : Dict [str , Any ]
417-
418- def __init__ (
419- self ,
420- * args : Any ,
421- test_file : str ,
422- test_key : str ,
423- fork_name : str ,
424- test_dict : Dict [str , Any ],
425- ** kwargs : Any ,
426- ) -> None :
427- """Initialize a single test case item."""
428- super ().__init__ (* args , ** kwargs )
429- self .test_file = test_file
430- self .test_key = test_key
431- self .test_dict = test_dict
432- self .fork_name = fork_name
433- self .own_markers .append (pytest .mark .fork (fork_name ))
434- self .own_markers .append (pytest .mark .evm_tools )
435- self .own_markers .append (pytest .mark .json_blockchain_tests )
436- eels_fork = FORKS [fork_name ]["eels_fork" ]
437- test_patterns = exceptional_blockchain_test_patterns (
438- fork_name , eels_fork
439- )
440- _identifier = "(" + test_file + "|" + test_key + ")"
441- if any (
442- x .search (test_file ) for x in test_patterns .expected_fail
443- ) or any (x .search (_identifier ) for x in test_patterns .expected_fail ):
444- self .own_markers .append (pytest .mark .skip ("Expected to fail" ))
445- if any (x .search (_identifier ) for x in test_patterns .slow ):
446- self .own_markers .append (pytest .mark .slow )
447- if any (x .search (_identifier ) for x in test_patterns .big_memory ):
448- self .own_markers .append (pytest .mark .bigmem )
449-
450- def runtest (self ) -> None :
451- """Execute the test logic for this specific static test."""
452- test_case_dict = {
453- "test_file" : self .test_file ,
454- "test_key" : self .test_key ,
455- "test_dict" : self .test_dict ,
456- }
457- eels_fork = FORKS [self .fork_name ]["eels_fork" ]
458- load = Load (
459- self .fork_name ,
460- eels_fork ,
461- )
462- run_blockchain_st_test (test_case_dict , load = load )
463-
464-
465- class BlockchainTestFixture (Fixture ):
466- """Single blockchain test fixture from a JSON file."""
467-
468- @classmethod
469- def is_format (cls , obj : Dict ) -> bool :
470- """Return true if the object can be parsed as the fixture type."""
471- if "genesisBlockHeader" not in obj :
472- return False
473- if "blocks" not in obj :
474- return False
475- if "engineNewPayloads" in obj :
476- return False
477- if "preHash" in obj :
478- return False
479- if "network" not in obj :
480- return False
481- return True
482-
483- @classmethod
484- def collect (
485- cls , parent : Collector , file_path : str , key : str , obj : Dict [str , Any ]
486- ) -> Generator [Item , None , None ]:
487- """Collect blockchain tests from a single fixture dictionary."""
488- name = f"{ key } "
489- if "network" not in obj or obj ["network" ] not in FORKS :
490- return
491- new_item = BlockchainTest .from_parent (
492- parent ,
493- name = name ,
494- test_file = file_path ,
495- test_key = key ,
496- fork_name = obj ["network" ],
497- test_dict = obj ,
498- )
499- yield new_item
500-
501-
502- FixtureTypes : List [Type [Fixture ]] = [
503- StateTestFixture ,
504- BlockchainTestFixture ,
505- ]
506-
507-
508304class FixturesFile (File ):
509305 """Single JSON file containing fixtures."""
510306
511307 def collect (
512308 self : Self ,
513- ) -> Generator [StateTestFixture | BlockchainTestFixture , None , None ]:
309+ ) -> Generator [Item | Collector , None , None ]:
514310 """Collect test cases from a single JSON fixtures file."""
515311 with open (self .path , "r" ) as file :
516312 try :
@@ -519,15 +315,19 @@ def collect(
519315 return # Skip *.json files that are unreadable.
520316 if not isinstance (loaded_file , dict ):
521317 return
522- for key , fixture_dict in loaded_file .items ():
523- if not isinstance (fixture_dict , dict ):
318+ for key , test_dict in loaded_file .items ():
319+ if not isinstance (test_dict , dict ):
524320 continue
525- for fixture_type in FixtureTypes :
526- if not fixture_type .is_format (fixture_dict ):
321+ for fixture_type in ALL_FIXTURE_TYPES :
322+ if not fixture_type .is_format (test_dict ):
527323 continue
528- yield from fixture_type .collect (
324+ name = key
325+ if "::" in name :
326+ name = name .split ("::" )[1 ]
327+ yield fixture_type .from_parent ( # type: ignore
529328 parent = self ,
530- file_path = str (self .path ),
531- key = key ,
532- obj = fixture_dict ,
329+ name = name ,
330+ test_file = str (self .path ),
331+ test_key = key ,
332+ test_dict = test_dict ,
533333 )
0 commit comments