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

35 statements  

« prev     ^ index     » next       coverage.py v7.16.1, created at 2026-09-23 03:53 +0000

1""" 

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

3 

4import SCons.Script.SConsOptions 

5import SCons.Node.FS 

6import SCons.Environment 

7import SCons.Script.Main 

8from google.protobuf import text_format 

9from apio.scons.apio_env import ApioEnv 

10from apio.common.proto.apio_scons_pb2 import ( 

11 SconsParams, 

12 TargetParams, 

13 ApioEnvParams, 

14) 

15 

16 

17TEST_PARAMS = """ 

18timestamp: "20123412052" 

19arch: ice40 

20fpga_info { 

21 fpga_id: "ice40hx4k-tq144-8k" 

22 part_num: "ICE40HX4K-TQ144" 

23 size: "8k" 

24 ice40_params { 

25 type: "hx8k" 

26 package: "tq144:4k" 

27 } 

28} 

29verbosity { 

30 all: false 

31 synth: false 

32 pnr: false 

33} 

34environment { 

35 platform_id: "darwin-arm64" 

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

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

38} 

39apio_env_params { 

40 env_name: "default" 

41 board_id: "alhambra-ii" 

42 top_module: "main" 

43} 

44""" 

45 

46 

47class SconsHacks: 

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

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

50 in future versions of SCons.""" 

51 

52 @staticmethod 

53 def reset_scons_state() -> None: 

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

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

56 normal operation where an scons process contains a single scons 

57 session but with pytest testing, where multiple independent tests 

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

59 before each test.""" 

60 

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

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

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

64 

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

66 values = SCons.Script.SConsOptions.SConsValues( 

67 parser.get_default_values() 

68 ) 

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

70 SCons.Script.Main.OptionsParser = parser 

71 

72 # -- Reset the scons target list variable. 

73 SCons.Node.FS.default_fs = None 

74 

75 # -- Clear the SCons targets 

76 SCons.Environment.CleanTargets = {} 

77 

78 

79def make_test_scons_params() -> SconsParams: 

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

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

82 

83 

84def make_test_apio_env( 

85 *, 

86 targets: list[str] | None = None, 

87 platform_id: str | None = None, 

88 is_windows: bool | None = None, 

89 # debug_level: int = 0, 

90 apio_env_params: ApioEnvParams | None = None, 

91 target_params: TargetParams | None = None, 

92) -> ApioEnv: 

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

94 with the current directory as the root dir. 

95 """ 

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 )