Coverage for tests / unit_tests / scons / testing.py: 100%

37 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-03-25 02:31 +0000

1""" 

2Helpers for apio's scons testing.""" 

3 

4from typing import Optional, List 

5import SCons.Script.SConsOptions 

6import SCons.Node.FS 

7import SCons.Environment 

8import SCons.Script.Main 

9from google.protobuf import text_format 

10from apio.scons.apio_env import ApioEnv 

11from apio.common.proto.apio_pb2 import SconsParams, TargetParams, ApioEnvParams 

12 

13 

14TEST_PARAMS = """ 

15timestamp: "20123412052" 

16arch: ICE40 

17fpga_info { 

18 fpga_id: "ice40hx4k-tq144-8k" 

19 part_num: "ICE40HX4K-TQ144" 

20 size: "8k" 

21 ice40_params { 

22 type: "hx8k" 

23 package: "tq144:4k" 

24 } 

25} 

26verbosity { 

27 all: false 

28 synth: false 

29 pnr: false 

30} 

31environment { 

32 platform_id: "darwin-arm64" 

33 debug_level: 1 

34 yosys_path: "/Users/user/.apio/packages/oss-cad-suite/share/yosys" 

35 trellis_path: "/Users/user/.apio/packages/oss-cad-suite/share/trellis" 

36} 

37apio_env_params { 

38 env_name: "default" 

39 board_id: "alhambra-ii" 

40 top_module: "main" 

41} 

42""" 

43 

44 

45class SconsHacks: 

46 """A collection of static methods that encapsulate scons access outside of 

47 the official scons API. Hopefully this will not be too difficult to adapt 

48 in future versions of SCons.""" 

49 

50 @staticmethod 

51 def reset_scons_state() -> None: 

52 """Reset the relevant SCons global variables. Unfortunately scons 

53 uses a few global variables to hold its state. This works well in 

54 normal operation where an scons process contains a single scons 

55 session but with pytest testing, where multiple independent tests 

56 are running in the same process, we need to reset though variables 

57 before each test.""" 

58 

59 # -- The Cons.Script.Main.OptionsParser variables contains the command 

60 # -- line options of scons. We reset them here and tests can access 

61 # -- them using SetOption() and GetOption(). 

62 

63 parser = SCons.Script.SConsOptions.Parser("my_fake_version") 

64 values = SCons.Script.SConsOptions.SConsValues( 

65 parser.get_default_values() 

66 ) 

67 parser.parse_args(args=[], values=values) 

68 SCons.Script.Main.OptionsParser = parser 

69 

70 # -- Reset the scons target list variable. 

71 SCons.Node.FS.default_fs = None 

72 

73 # -- Clear the SCons targets 

74 SCons.Environment.CleanTargets = {} 

75 

76 

77def make_test_scons_params() -> SconsParams: 

78 """Create a fake scons params for testing.""" 

79 return text_format.Parse(TEST_PARAMS, SconsParams()) 

80 

81 

82def make_test_apio_env( 

83 *, 

84 targets: Optional[List[str]] = None, 

85 platform_id: str = None, 

86 is_windows: bool = None, 

87 debug_level: int = 0, 

88 apio_env_params: ApioEnvParams = None, 

89 target_params: TargetParams = None, 

90) -> ApioEnv: 

91 """Creates a fresh apio env for testing. The env is created 

92 with the current directory as the root dir. 

93 """ 

94 

95 # pylint: disable=too-many-arguments 

96 

97 # -- Specify both or nether. 

98 assert (platform_id is None) == (is_windows is None) 

99 

100 # -- Bring scons to a starting state. 

101 SconsHacks.reset_scons_state() 

102 

103 # -- Create default params. 

104 scons_params = make_test_scons_params() 

105 

106 # -- Set debug level 

107 scons_params.environment.debug_level = debug_level 

108 

109 # -- Apply user overrides. 

110 if platform_id is not None: 

111 scons_params.environment.platform_id = platform_id 

112 if is_windows is not None: 

113 scons_params.environment.is_windows = is_windows 

114 if apio_env_params is not None: 

115 scons_params.apio_env_params.MergeFrom(apio_env_params) 

116 if target_params is not None: 

117 scons_params.target.MergeFrom(target_params) 

118 

119 # -- Determine scons target. 

120 if targets is not None: 

121 command_line_targets = targets 

122 else: 

123 command_line_targets = ["build"] 

124 

125 # -- Create and return the apio env. 

126 return ApioEnv( 

127 command_line_targets=command_line_targets, scons_params=scons_params 

128 )