rebase-errors.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. #!/usr/bin/env python
  2. # Copyright (c) 2016 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. """Helper script to update the test error expectations based on actual results.
  6. This is useful for regenerating test expectations after making changes to the
  7. error format.
  8. To use this run the affected tests, and then pass the input to this script
  9. (either via stdin, or as the first argument). For instance:
  10. $ ./out/Release/net_unittests --gtest_filter="*VerifyCertificateChain*" | \
  11. net/data/verify_certificate_chain_unittest/rebase-errors.py
  12. The script works by scanning the stdout looking for gtest failures having a
  13. particular format. The C++ test side should have been instrumented to dump out
  14. the test file's path on mismatch.
  15. This script will then update the corresponding test/error file that contains the
  16. error expectation.
  17. """
  18. import os
  19. import sys
  20. import re
  21. # Regular expression to find the failed errors in test stdout.
  22. # * Group 1 of the match is file path (relative to //src) where the
  23. # expected errors were read from.
  24. # * Group 2 of the match is the actual error text
  25. failed_test_regex = re.compile(r"""
  26. Cert path errors don't match expectations \((.+?)\)
  27. EXPECTED:
  28. (?:.|\n)*?
  29. ACTUAL:
  30. ((?:.|\n)*?)
  31. ===> Use net/data/verify_certificate_chain_unittest/rebase-errors.py to rebaseline.
  32. """, re.MULTILINE)
  33. def read_file_to_string(path):
  34. """Reads a file entirely to a string"""
  35. with open(path, 'r') as f:
  36. return f.read()
  37. def write_string_to_file(data, path):
  38. """Writes a string to a file"""
  39. print "Writing file %s ..." % (path)
  40. with open(path, "w") as f:
  41. f.write(data)
  42. def get_src_root():
  43. """Returns the path to the enclosing //src directory. This assumes the
  44. current script is inside the source tree."""
  45. cur_dir = os.path.dirname(os.path.realpath(__file__))
  46. while True:
  47. parent_dir, dirname = os.path.split(cur_dir)
  48. # Check if it looks like the src/ root.
  49. if dirname == "src" and os.path.isdir(os.path.join(cur_dir, "net")):
  50. return cur_dir
  51. if not parent_dir or parent_dir == cur_dir:
  52. break
  53. cur_dir = parent_dir
  54. print "Couldn't find src dir"
  55. sys.exit(1)
  56. def get_abs_path(rel_path):
  57. """Converts |rel_path| (relative to src) to a full path"""
  58. return os.path.join(get_src_root(), rel_path)
  59. def fixup_errors_for_file(actual_errors, test_file_path):
  60. """Updates the errors in |test_file_path| to match |actual_errors|"""
  61. contents = read_file_to_string(test_file_path)
  62. header = "\nexpected_errors:\n"
  63. index = contents.find(header)
  64. if index < 0:
  65. print "Couldn't find expected_errors"
  66. sys.exit(1)
  67. # The rest of the file contains the errors (overwrite).
  68. contents = contents[0:index] + header + actual_errors
  69. write_string_to_file(contents, test_file_path)
  70. def main():
  71. if len(sys.argv) > 2:
  72. print 'Usage: %s [path-to-unittest-stdout]' % (sys.argv[0])
  73. sys.exit(1)
  74. # Read the input either from a file, or from stdin.
  75. test_stdout = None
  76. if len(sys.argv) == 2:
  77. test_stdout = read_file_to_string(sys.argv[1])
  78. else:
  79. print 'Reading input from stdin...'
  80. test_stdout = sys.stdin.read()
  81. for m in failed_test_regex.finditer(test_stdout):
  82. src_relative_errors_path = m.group(1)
  83. errors_path = get_abs_path(src_relative_errors_path)
  84. actual_errors = m.group(2)
  85. if errors_path.endswith(".test"):
  86. fixup_errors_for_file(actual_errors, errors_path)
  87. elif errors_path.endswith(".txt"):
  88. write_string_to_file(actual_errors, errors_path)
  89. else:
  90. print 'Unknown file extension'
  91. sys.exit(1)
  92. if __name__ == "__main__":
  93. main()