blob: 3f1190060eb5304bfc71051fd71e50a191db6bf5 [file] [log] [blame]
# Copyright 2023 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Tests for the pw_build.gn_config module."""
import unittest
from typing import Iterable
from pw_build.gn_config import (
consolidate_configs,
GnConfig,
GN_CONFIG_FLAGS,
)
from pw_build.gn_utils import GnLabel, MalformedGnError
class TestGnConfig(unittest.TestCase):
"""Tests for gn_config.GnConfig.
Attributes:
config: A common config for testing.
"""
def compare(self, actual: Iterable[str], *expected: str):
"""Sorts lists and compares them."""
self.assertEqual(sorted(expected), sorted(list(actual)))
def setUp(self):
self.config = GnConfig()
def test_bool_empty(self):
"""Identifies an empty config correctly."""
self.assertFalse(self.config)
def test_bool_nonempty(self):
"""Identifies a non-empty config correctly."""
self.config.add('defines', 'KEY=VAL')
self.assertTrue(self.config)
def test_has_none(self):
"""Indicates a config does not have a flag when it has no values."""
self.assertFalse(self.config.has('cflags'))
def test_has_single(self):
"""Indicates a config has a flag when it has one value."""
self.config.add('cflags', '-frobinator')
self.assertTrue(self.config.has('cflags'))
def test_has_multiple(self):
"""Indicates a config has a flag when it has multiple values."""
self.config.add('cflags', '-frobinator')
self.config.add('cflags', '-fizzbuzzer')
self.assertTrue(self.config.has('cflags'))
def test_has_two_flags(self):
"""Indicates a config has a flag when it has multiple flags."""
self.config.add('cflags', '-frobinator')
self.config.add('cflags_c', '-foobarbaz')
self.assertTrue(self.config.has('cflags'))
def test_add_and_get(self):
"""Tests ability to add valid flags to a config."""
for flag in GN_CONFIG_FLAGS:
self.config.add(flag, f'{flag}_value1')
self.config.add(flag, f'{flag}_value2', f'{flag}_value3')
for flag in GN_CONFIG_FLAGS:
self.compare(
self.config.get(flag),
f'{flag}_value1',
f'{flag}_value2',
f'{flag}_value3',
)
def test_add_and_get_invalid(self):
"""Tests ability to add only valid flags to a config."""
with self.assertRaises(MalformedGnError):
self.config.add('invalid', 'value')
def test_take_missing(self):
"""Tests ability to return an empty list when taking a missing flag."""
self.compare(self.config.take('cflags'))
self.assertFalse(self.config.has('defines'))
self.assertFalse(self.config.has('cflags'))
def test_take(self):
"""Tests ability to remove and return values from a config."""
self.config.add('defines', 'KEY1=VAL1', 'KEY2=VAL2')
self.config.add('cflags', '-frobinator', '-fizzbuzzer')
self.assertTrue(self.config.has('defines'))
self.assertTrue(self.config.has('cflags'))
self.compare(self.config.take('cflags'), '-frobinator', '-fizzbuzzer')
self.assertTrue(self.config.has('defines'))
self.assertFalse(self.config.has('cflags'))
def test_deduplicate_no_label(self):
"""Tests raising an error from deduplicating a labelless config."""
cfg1 = GnConfig()
cfg1.add('defines', 'KEY1=VAL1')
with self.assertRaises(ValueError):
list(self.config.deduplicate(cfg1))
def test_deduplicate_empty(self):
"""Tests deduplicating an empty config."""
cfg2 = GnConfig()
cfg2.label = ':cfg2'
self.assertFalse(list(self.config.deduplicate(cfg2)))
def test_deduplicate_not_subset(self):
"""Tests deduplicating a config whose values are not a subset."""
self.config.add('defines', 'KEY1=VAL1', 'KEY2=VAL2')
self.config.add('cflags', '-frobinator', '-fizzbuzzer', '-foobarbaz')
cfg3 = GnConfig()
cfg3.label = ':cfg3'
cfg3.add('defines', 'KEY1=VAL1', 'KEY3=VAL3')
self.assertFalse(list(self.config.deduplicate(cfg3)))
def test_deduplicate(self):
"""Tests deduplicating multiple overlapping configs."""
self.config.add('defines', 'KEY1=VAL1', 'KEY2=VAL2')
self.config.add('cflags', '-frobinator', '-fizzbuzzer', '-foobarbaz')
cfg4 = GnConfig()
cfg4.label = ':cfg4'
cfg4.add('defines', 'KEY1=VAL1')
cfg4.add('cflags', '-frobinator')
cfg5 = GnConfig()
cfg5.label = ':cfg5'
cfg5.add('defines', 'KEY1=VAL1')
cfg5.add('cflags', '-foobarbaz')
cfg6 = GnConfig()
cfg6.label = ':skipped'
cfg6.add('cflags', '-foobarbaz')
cfgs = [
str(cfg.label) for cfg in self.config.deduplicate(cfg4, cfg5, cfg6)
]
self.assertEqual(cfgs, [':cfg4', ':cfg5'])
self.compare(self.config.get('defines'), 'KEY2=VAL2')
self.compare(self.config.get('cflags'), '-fizzbuzzer')
def test_extract_public(self):
"""Tests ability to removes and return `public_config` values."""
self.config.add('public_defines', 'KEY1=VAL1', 'KEY2=VAL2')
self.config.add('defines', 'KEY3=VAL3', 'KEY4=VAL4')
self.config.add('include_dirs', 'foo', 'bar', 'baz')
self.config.add('cflags', '-frobinator', '-fizzbuzzer')
config = self.config.extract_public()
self.assertFalse(self.config.has('public_defines'))
self.assertFalse(self.config.has('include_dirs'), 'KEY2=VAL2')
self.compare(self.config.get('defines'), 'KEY3=VAL3', 'KEY4=VAL4')
self.compare(self.config.get('cflags'), '-frobinator', '-fizzbuzzer')
self.assertFalse(config.has('public_defines'))
self.compare(config.get('defines'), 'KEY1=VAL1', 'KEY2=VAL2')
self.compare(config.get('include_dirs'), 'foo', 'bar', 'baz')
self.assertFalse(config.has('cflags'))
def test_consolidate_configs(self):
"""Tests ability to merges configs into the smallest exact cover."""
cfg1 = GnConfig()
cfg1.add('cflags', 'one', 'a', 'b')
cfg1.add('defines', 'k=1')
cfg1.add('include_dirs', 'foo', 'bar')
cfg2 = GnConfig()
cfg2.add('cflags', 'one', 'a', 'b', 'c')
cfg2.add('defines', 'k=1')
cfg2.add('include_dirs', 'foo', 'baz')
cfg3 = GnConfig()
cfg3.add('cflags', 'one', 'two', 'a', 'b')
cfg3.add('defines', 'k=1')
cfg3.add('include_dirs', 'foo', 'bar')
cfg4 = GnConfig()
cfg4.add('cflags', 'one', 'b', 'c')
cfg4.add('defines', 'k=0')
cfg4.add('include_dirs', 'foo', 'baz')
label = GnLabel('//foo/bar')
common = list(consolidate_configs(label, cfg1, cfg2, cfg3, cfg4))
self.assertEqual(len(common), 3)
self.assertEqual(str(common[0].label), '//foo/bar:bar_public_config1')
self.assertEqual(str(common[1].label), '//foo/bar:bar_config1')
self.assertEqual(str(common[2].label), '//foo/bar:bar_config2')
self.compare(common[0].get('include_dirs'), 'foo')
self.compare(common[1].get('cflags'), 'one', 'b')
self.compare(common[2].get('cflags'), 'a')
self.compare(common[2].get('defines'), 'k=1')
if __name__ == '__main__':
unittest.main()