1#!/usr/bin/python3 2# 3# This file and its contents are supplied under the terms of the 4# Common Development and Distribution License ("CDDL"), version 1.0. 5# You may only use this file in accordance with the terms of version 6# 1.0 of the CDDL. 7# 8# A full copy of the text of the CDDL should have accompanied this 9# source. A copy of the CDDL is also available via the Internet at 10# http://www.illumos.org/license/CDDL. 11# 12 13# 14# Copyright 2026 Gordon W. Ross 15# 16 17""" 18Unit tests for EnvConfig._parse() - the environment config file parser. 19 20Tests use canned string input via io.StringIO so no external files are needed. 21""" 22 23import io 24import unittest 25 26from symbol_test import EnvConfig, CompileEnv 27 28# --------------------------------------------------------------------------- 29# Canned input: a realistic slice of cxx-symbols-env.cfg. 30# Exercises: comment lines, blank lines, env with empty defs, env with defs, 31# env_group referencing multiple envs. 32# --------------------------------------------------------------------------- 33 34CANNED_CXX = """\ 35# 36# Compilation environments for C++ symbol visibility tests. 37# 38 39# Plain C++ standards - no extra defines. 40env | CXX98\t\t| c++98 | 41env | CXX11\t\t| c++11 | 42env | CXX17\t\t| c++17 | 43 44# _C99 variants add -D_STDC_C99. 45env | CXX98_C99\t\t| c++98 | -D_STDC_C99 46env | CXX11_C99\t\t| c++11 | -D_STDC_C99 47 48env_group | CXX98+\t| CXX17 CXX11 CXX98 49env_group | CXX_C99+\t| CXX11_C99 CXX98_C99 50env_group | ALL\t\t| CXX98+ 51""" 52 53# Expected envs: name -> (lang, defs) 54EXPECTED_ENVS = { 55 'CXX98': ('c++98', ''), 56 'CXX11': ('c++11', ''), 57 'CXX17': ('c++17', ''), 58 'CXX98_C99': ('c++98', '-D_STDC_C99'), 59 'CXX11_C99': ('c++11', '-D_STDC_C99'), 60} 61 62# Expected groups: name -> frozenset of member env names 63EXPECTED_GROUPS = { 64 'CXX98+': frozenset({'CXX17', 'CXX11', 'CXX98'}), 65 'CXX_C99+': frozenset({'CXX11_C99', 'CXX98_C99'}), 66 'ALL': frozenset({'CXX17', 'CXX11', 'CXX98'}), 67} 68 69 70class TestParseEnvCfg(unittest.TestCase): 71 72 def setUp(self): 73 self.cfg = EnvConfig('c++') 74 self.cfg._parse(io.StringIO(CANNED_CXX), filename='<test>') 75 76 def test_env_count(self): 77 self.assertEqual(len(self.cfg.envs), len(EXPECTED_ENVS)) 78 79 def test_env_names(self): 80 self.assertEqual(set(self.cfg.envs.keys()), set(EXPECTED_ENVS.keys())) 81 82 def test_env_lang_and_defs(self): 83 for name, (lang, defs) in EXPECTED_ENVS.items(): 84 with self.subTest(env=name): 85 env = self.cfg.envs[name] 86 self.assertEqual(env.lang, lang) 87 self.assertEqual(env.defs, defs) 88 89 def test_group_count(self): 90 self.assertEqual(len(self.cfg.groups), len(EXPECTED_GROUPS)) 91 92 def test_group_names(self): 93 self.assertEqual(set(self.cfg.groups.keys()), 94 set(EXPECTED_GROUPS.keys())) 95 96 def test_group_members(self): 97 for name, members in EXPECTED_GROUPS.items(): 98 with self.subTest(group=name): 99 self.assertEqual(self.cfg.groups[name], members) 100 101 def test_positive_coverage_sets(self): 102 self.assertEqual(set(self.cfg.envs), set(EXPECTED_ENVS)) 103 self.assertEqual(self.cfg.expand('ALL'), set(EXPECTED_GROUPS['ALL'])) 104 self.assertNotEqual(set(self.cfg.envs), self.cfg.expand('ALL')) 105 106 def test_resolve_expected_success(self): 107 test_set, need_set = self.cfg.resolve('-CXX98+ +CXX11') 108 self.assertEqual(test_set, set(EXPECTED_GROUPS['CXX98+'])) 109 self.assertEqual(need_set, {'CXX11'}) 110 111 def test_lang_mismatch_raises(self): 112 """--lang=c should be rejected when env lines use c++ standards.""" 113 cfg = EnvConfig('c') 114 with self.assertRaises(SystemExit): 115 cfg._parse(io.StringIO(CANNED_CXX), filename='<test>') 116 117 def test_group_undefined_member_raises(self): 118 """A group referencing an undefined env name should raise.""" 119 bad = "env | FOO | c++11 |\nenv_group | BAR | FOO NOSUCHENV\n" 120 cfg = EnvConfig('c++') 121 with self.assertRaises(SystemExit): 122 cfg._parse(io.StringIO(bad), filename='<test>') 123 124 125if __name__ == '__main__': 126 unittest.main() 127