| #!/usr/bin/env python3 |
| # Copyright 2020 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """ |
| Unit tests for platform_json.py |
| |
| """ |
| |
| import collections |
| import io |
| import json |
| import os |
| import sys |
| import tempfile |
| import unittest |
| |
| import platform_json |
| |
| MOCK_CONSOLIDATED_JSON_CONTENTS = \ |
| '''{ |
| "DEFAULTS": { |
| "platform": null, |
| "parent": null, |
| "field1": 5, |
| "field2": 5, |
| "field3": 5, |
| "field4": 5, |
| "fieldArray": [ |
| "elem5" |
| ] |
| }, |
| "my_platform": { |
| "platform": "my_platform", |
| "parent": "my_parent", |
| "field1": 1, |
| "fieldArray": [ |
| "elem1", |
| "elem2" |
| ], |
| "models": { |
| "my_model": { |
| "field1": 4 |
| }, |
| "my_model2": { |
| "field2": 4 |
| } |
| } |
| }, |
| "my_parent": { |
| "platform": "my_parent", |
| "parent": "my_grandparent", |
| "field1": 2, |
| "field2": 2 |
| }, |
| "my_grandparent": { |
| "platform": "my_grandparent", |
| "field1": 3, |
| "field2": 3, |
| "field3": 3 |
| } |
| }''' |
| |
| |
| def _run_main(argv): |
| """Run platform_json.main(argv), capturing and returning stdout.""" |
| original_stdout = sys.stdout |
| capture_io = io.StringIO() |
| sys.stdout = capture_io |
| try: |
| platform_json.main(argv) |
| return capture_io.getvalue() |
| finally: |
| capture_io.close() |
| sys.stdout = original_stdout |
| |
| |
| class AbstractMockConfigTestCase(object): |
| """Parent class to handle setup and teardown of mock configs.""" |
| |
| def setUp(self): # pylint:disable=invalid-name |
| """Write mock JSON to a temporary file""" |
| _, self.mock_filepath = tempfile.mkstemp() |
| with open(self.mock_filepath, 'w') as mock_file: |
| mock_file.write(MOCK_CONSOLIDATED_JSON_CONTENTS) |
| |
| def tearDown(self): # pylint:disable=invalid-name |
| """Destroy the mock JSON file""" |
| os.remove(self.mock_filepath) |
| |
| |
| class InheritanceTestCase(AbstractMockConfigTestCase, unittest.TestCase): |
| """Ensure that all levels of inheritance are handled correctly""" |
| |
| def runTest(self): # pylint:disable=invalid-name |
| """Load platform config and check that it looks correct""" |
| consolidated_json = platform_json.load_consolidated_json( |
| self.mock_filepath) |
| my_platform = platform_json.calculate_config('my_platform', |
| None, |
| consolidated_json) |
| self.assertEqual(my_platform['field1'], 1) # No inheritance |
| self.assertEqual(my_platform['field2'], 2) # Direct inheritance |
| self.assertEqual(my_platform['field3'], 3) # Recursive inheritance |
| self.assertEqual(my_platform['field4'], 5) # Inherit from DEFAULTS |
| my_model = platform_json.calculate_config('my_platform', |
| 'my_model', |
| consolidated_json) |
| self.assertEqual(my_model['field1'], 4) # Model override |
| self.assertEqual(my_model['field2'], 2) # Everything else is the same |
| self.assertEqual(my_model['field3'], 3) |
| self.assertEqual(my_model['field4'], 5) |
| |
| |
| class EndToEndPlatformTestCase(AbstractMockConfigTestCase, unittest.TestCase): |
| """End-to-end testing for specifying the platform name.""" |
| |
| def runTest(self): # pylint: disable=invalid-name |
| """Main test logic""" |
| # Basic platform specification |
| argv = ['my_platform', '-c', self.mock_filepath] |
| expected_json = collections.OrderedDict({ |
| 'platform': 'my_platform', |
| 'parent': 'my_parent', |
| 'field1': 1, |
| 'field2': 2, |
| 'field3': 3, |
| 'field4': 5, |
| 'fieldArray': [ |
| 'elem1', |
| 'elem2', |
| ], |
| }) |
| expected_output = json.dumps(expected_json, indent=4) + '\n' |
| self.assertEqual(_run_main(argv), expected_output) |
| |
| # Condensed output |
| argv.append('--condense-output') |
| expected_output = json.dumps(expected_json, indent=None) |
| self.assertEqual(_run_main(argv), expected_output) |
| |
| # Non-existent platform should raise an error |
| argv = ['fake_platform', '-c', self.mock_filepath] |
| with self.assertRaises(platform_json.PlatformNotFoundError): |
| _run_main(argv) |
| |
| |
| class EndToEndFieldTestCase(AbstractMockConfigTestCase, unittest.TestCase): |
| """End-to-end testing for specifying the field name.""" |
| |
| def runTest(self): # pylint: disable=invalid-name |
| """Main test logic""" |
| # Basic field specification |
| argv = ['my_platform', '-f', 'field1', '-c', self.mock_filepath] |
| self.assertEqual(_run_main(argv), '1\n') |
| |
| # Condensed output should yield no newline |
| argv.append('--condense-output') |
| self.assertEqual(_run_main(argv), '1') |
| |
| # Non-existent field should raise an error |
| argv = ['my_platform', '-f', 'fake_field', '-c', self.mock_filepath] |
| with self.assertRaises(platform_json.FieldNotFoundError): |
| _run_main(argv) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |