validate_test.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #!/usr/bin/env python3
  2. # Copyright 2023 The Chromium Authors. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. import os
  6. import sys
  7. import unittest
  8. import unittest.mock
  9. _THIS_DIR = os.path.abspath(os.path.dirname(__file__))
  10. # The repo's root directory.
  11. _ROOT_DIR = os.path.abspath(os.path.join(_THIS_DIR, "..", ".."))
  12. # Add the repo's root directory for clearer imports.
  13. sys.path.insert(0, _ROOT_DIR)
  14. import gclient_utils
  15. import metadata.validate
  16. import metadata.validation_result
  17. import metadata.fields.known
  18. # Common paths for tests.
  19. _SOURCE_FILE_DIR = os.path.join(_THIS_DIR, "data")
  20. _VALID_METADATA_FILEPATH = os.path.join(_THIS_DIR, "data",
  21. "README.chromium.test.multi-valid")
  22. _INVALID_METADATA_FILEPATH = os.path.join(_THIS_DIR, "data",
  23. "README.chromium.test.multi-invalid")
  24. class ValidateContentTest(unittest.TestCase):
  25. """Tests for the validate_content function."""
  26. def test_empty(self):
  27. # Validate empty content (should result in a validation error).
  28. results = metadata.validate.validate_content(
  29. content="",
  30. source_file_dir=_SOURCE_FILE_DIR,
  31. repo_root_dir=_THIS_DIR,
  32. )
  33. self.assertEqual(len(results), 1)
  34. self.assertTrue(results[0].is_fatal())
  35. def test_valid(self):
  36. # Validate valid file content (no errors or warnings).
  37. results = metadata.validate.validate_content(
  38. content=gclient_utils.FileRead(_VALID_METADATA_FILEPATH),
  39. source_file_dir=_SOURCE_FILE_DIR,
  40. repo_root_dir=_THIS_DIR,
  41. )
  42. self.assertEqual(len(results), 0)
  43. def test_invalid(self):
  44. # Validate invalid file content (both errors and warnings).
  45. results = metadata.validate.validate_content(
  46. content=gclient_utils.FileRead(_INVALID_METADATA_FILEPATH),
  47. source_file_dir=_SOURCE_FILE_DIR,
  48. repo_root_dir=_THIS_DIR,
  49. )
  50. self.assertEqual(len(results), 9)
  51. error_count = 0
  52. warning_count = 0
  53. for result in results:
  54. if result.is_fatal():
  55. error_count += 1
  56. else:
  57. warning_count += 1
  58. self.assertEqual(error_count, 7)
  59. self.assertEqual(warning_count, 2)
  60. class ValidateFileTest(unittest.TestCase):
  61. """Tests for the validate_file function."""
  62. def test_missing(self):
  63. # Validate a file that does not exist.
  64. results = metadata.validate.validate_file(
  65. filepath=os.path.join(_THIS_DIR, "data", "MISSING.chromium"),
  66. repo_root_dir=_THIS_DIR,
  67. )
  68. # There should be exactly 1 error returned.
  69. self.assertEqual(len(results), 1)
  70. self.assertTrue(results[0].is_fatal())
  71. def test_valid(self):
  72. # Validate a valid file (no errors or warnings).
  73. results = metadata.validate.validate_file(
  74. filepath=_VALID_METADATA_FILEPATH,
  75. repo_root_dir=_THIS_DIR,
  76. )
  77. self.assertEqual(len(results), 0)
  78. def test_invalid(self):
  79. # Validate an invalid file (both errors and warnings).
  80. results = metadata.validate.validate_file(
  81. filepath=_INVALID_METADATA_FILEPATH,
  82. repo_root_dir=_THIS_DIR,
  83. )
  84. self.assertEqual(len(results), 9)
  85. error_count = 0
  86. warning_count = 0
  87. for result in results:
  88. if result.is_fatal():
  89. error_count += 1
  90. else:
  91. warning_count += 1
  92. self.assertEqual(error_count, 7)
  93. self.assertEqual(warning_count, 2)
  94. class CheckFileTest(unittest.TestCase):
  95. """Tests for the check_file function."""
  96. def test_missing(self):
  97. # Check a file that does not exist.
  98. errors, warnings = metadata.validate.check_file(
  99. filepath=os.path.join(_THIS_DIR, "data", "MISSING.chromium"),
  100. repo_root_dir=_THIS_DIR,
  101. )
  102. # TODO(aredulla): update this test once validation errors can be
  103. # returned as errors. Bug: b/285453019.
  104. # self.assertEqual(len(errors), 1)
  105. # self.assertEqual(len(warnings), 0)
  106. self.assertEqual(len(errors), 0)
  107. self.assertEqual(len(warnings), 1)
  108. def test_valid(self):
  109. # Check file with valid content (no errors or warnings).
  110. errors, warnings = metadata.validate.check_file(
  111. filepath=_VALID_METADATA_FILEPATH,
  112. repo_root_dir=_THIS_DIR,
  113. )
  114. self.assertEqual(len(errors), 0)
  115. self.assertEqual(len(warnings), 0)
  116. def test_invalid(self):
  117. # Check file with invalid content (both errors and warnings).
  118. errors, warnings = metadata.validate.check_file(
  119. filepath=_INVALID_METADATA_FILEPATH,
  120. repo_root_dir=_THIS_DIR,
  121. )
  122. # TODO(aredulla): update this test once validation errors can be
  123. # returned as errors. Bug: b/285453019.
  124. # self.assertEqual(len(errors), 7)
  125. # self.assertEqual(len(warnings), 2)
  126. self.assertEqual(len(errors), 0)
  127. self.assertEqual(len(warnings), 9)
  128. class ValidationResultTest(unittest.TestCase):
  129. """Tests ValidationResult handles strings correctly."""
  130. def test_ordering(self):
  131. ve = metadata.validation_result.ValidationError(
  132. "abc",
  133. ["message1", "message2"],
  134. )
  135. vw = metadata.validation_result.ValidationError(
  136. "def",
  137. ["message3", "message4"],
  138. )
  139. # Check errors preceeds warnings.
  140. self.assertLess(ve, vw)
  141. self.assertGreater(vw, ve)
  142. self.assertEqual([ve, vw], list(sorted([vw, ve])))
  143. def test_message_generation(self):
  144. ve = metadata.validation_result.ValidationError(
  145. "abc",
  146. ["message1", "message2"],
  147. )
  148. self.assertEqual(
  149. ("Third party metadata issue: abc message1 message2 Check "
  150. "//third_party/README.chromium.template for details."),
  151. ve.get_message())
  152. self.assertEqual("abc message1 message2",
  153. ve.get_message(prescript='', postscript=''))
  154. def test_getters(self):
  155. ve = metadata.validation_result.ValidationError(
  156. "abc",
  157. ["message1", "message2"],
  158. )
  159. self.assertEqual("abc", ve.get_reason())
  160. self.assertEqual(["message1", "message2"], ve.get_additional())
  161. class ValidationWithLineNumbers(unittest.TestCase):
  162. def test_reports_line_number(self):
  163. """Checks validate reports line number if available."""
  164. filepath = os.path.join(_THIS_DIR, "data",
  165. "README.chromium.test.validation-line-number")
  166. content = gclient_utils.FileRead(filepath)
  167. unittest.mock.patch(
  168. 'metadata.fields.known.LICENSE_FILE.validate_on_disk',
  169. return_value=metadata.validation_result.ValidationError(
  170. "File doesn't exist."))
  171. results = metadata.validate.validate_content(content,
  172. "chromium/src/test_dir",
  173. "chromium/src")
  174. for r in results:
  175. if r.get_reason() == 'License File is invalid.':
  176. self.assertEqual(r.get_lines(), [10])
  177. elif r.get_reason(
  178. ) == "Required field 'License Android Compatible' is missing.":
  179. # We can't add a line number to errors caused by missing fields.
  180. self.assertEqual(r.get_lines(), [])
  181. elif r.get_reason() == "Versioning fields are insufficient.":
  182. # We can't add a line number to errors caused by missing fields.
  183. self.assertEqual(r.get_lines(), [])
  184. elif r.get_reason(
  185. ) == "License has a license not in the allowlist.":
  186. self.assertEqual(r.get_lines(), [9])
  187. elif r.get_reason() == "URL is invalid.":
  188. self.assertEqual(r.get_lines(), [2, 3, 4])
  189. elif r.get_reason() == "Shipped in Chromium is invalid":
  190. self.assertEqual(r.get_lines(), [13])
  191. if __name__ == "__main__":
  192. unittest.main()