| #!/usr/bin/env python | |
| # Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| # Self-test for skimage. | |
| import filecmp | |
| import os | |
| import subprocess | |
| import sys | |
| import tempfile | |
| class BinaryNotFoundException(Exception): | |
| def __str__ (self): | |
| return ("Could not find binary!\n" | |
| "Did you forget to build the tools project?\n" | |
| "Self tests failed") | |
| # Find a path to the binary to use. Iterates through a list of possible | |
| # locations the binary may be. | |
| def PickBinaryPath(base_dir): | |
| POSSIBLE_BINARY_PATHS = [ | |
| 'out/Debug/skimage', | |
| 'out/Release/skimage', | |
| 'xcodebuild/Debug/skimage', | |
| 'xcodebuild/Release/skimage', | |
| ] | |
| for binary in POSSIBLE_BINARY_PATHS: | |
| binary_full_path = os.path.join(base_dir, binary) | |
| if (os.path.exists(binary_full_path)): | |
| return binary_full_path | |
| raise BinaryNotFoundException | |
| # Quit early if two files have different content. | |
| def DieIfFilesMismatch(expected, actual): | |
| if not filecmp.cmp(expected, actual): | |
| raise Exception("Error: file mismatch! expected=%s , actual=%s" % ( | |
| expected, actual)) | |
| def test_invalid_file(file_dir, skimage_binary): | |
| """ Test the return value of skimage when an invalid file is decoded. | |
| If there is no expectation file, or the file expects a particular | |
| result, skimage should return nonzero indicating failure. | |
| If the file has no expectation, or ignore-failure is set to true, | |
| skimage should return zero indicating success. """ | |
| invalid_file = os.path.join(file_dir, "skimage", "input", "bad-images", | |
| "invalid.png") | |
| # No expectations file: | |
| args = [skimage_binary, "--readPath", invalid_file] | |
| result = subprocess.call(args) | |
| if 0 == result: | |
| raise Exception("'%s' should have reported failure!" % " ".join(args)) | |
| # Directory holding all expectations files | |
| expectations_dir = os.path.join(file_dir, "skimage", "input", "bad-images") | |
| # Expectations file expecting a valid decode: | |
| incorrect_expectations = os.path.join(expectations_dir, | |
| "incorrect-results.json") | |
| args = [skimage_binary, "--readPath", invalid_file, | |
| "--readExpectationsPath", incorrect_expectations] | |
| result = subprocess.call(args) | |
| if 0 == result: | |
| raise Exception("'%s' should have reported failure!" % " ".join(args)) | |
| # Empty expectations: | |
| empty_expectations = os.path.join(expectations_dir, "empty-results.json") | |
| output = subprocess.check_output([skimage_binary, "--readPath", invalid_file, | |
| "--readExpectationsPath", | |
| empty_expectations], | |
| stderr=subprocess.STDOUT) | |
| if not "Missing" in output: | |
| # Another test (in main()) tests to ensure that "Missing" does not appear | |
| # in the output. That test could be passed if the output changed so | |
| # "Missing" never appears. This ensures that an error is not missed if | |
| # that happens. | |
| raise Exception( | |
| "skimage output changed! This may cause other self tests to fail!") | |
| # Ignore failure: | |
| ignore_expectations = os.path.join(expectations_dir, "ignore-results.json") | |
| output = subprocess.check_output([skimage_binary, "--readPath", invalid_file, | |
| "--readExpectationsPath", | |
| ignore_expectations], | |
| stderr=subprocess.STDOUT) | |
| if not "failures" in output: | |
| # Another test (in main()) tests to ensure that "failures" does not | |
| # appear in the output. That test could be passed if the output changed | |
| # so "failures" never appears. This ensures that an error is not missed | |
| # if that happens. | |
| raise Exception( | |
| "skimage output changed! This may cause other self tests to fail!") | |
| def test_incorrect_expectations(file_dir, skimage_binary): | |
| """ Test that comparing to incorrect expectations fails, unless | |
| ignore-failures is set to true. """ | |
| valid_file = os.path.join(file_dir, "skimage", "input", | |
| "images-with-known-hashes", | |
| "1209453360120438698.png") | |
| expectations_dir = os.path.join(file_dir, "skimage", "input", | |
| "images-with-known-hashes") | |
| incorrect_results = os.path.join(expectations_dir, | |
| "incorrect-results.json") | |
| args = [skimage_binary, "--readPath", valid_file, "--readExpectationsPath", | |
| incorrect_results] | |
| result = subprocess.call(args) | |
| if 0 == result: | |
| raise Exception("'%s' should have reported failure!" % " ".join(args)) | |
| ignore_results = os.path.join(expectations_dir, "ignore-failures.json") | |
| subprocess.check_call([skimage_binary, "--readPath", valid_file, | |
| "--readExpectationsPath", ignore_results]) | |
| def main(): | |
| # Use the directory of this file as the out directory | |
| file_dir = os.path.abspath(os.path.dirname(__file__)) | |
| trunk_dir = os.path.normpath(os.path.join(file_dir, os.pardir, os.pardir)) | |
| # Find the binary | |
| skimage_binary = PickBinaryPath(trunk_dir) | |
| print "Running " + skimage_binary | |
| # Generate an expectations file from known images. | |
| images_dir = os.path.join(file_dir, "skimage", "input", | |
| "images-with-known-hashes") | |
| expectations_path = os.path.join(file_dir, "skimage", "output-actual", | |
| "create-expectations", "expectations.json") | |
| subprocess.check_call([skimage_binary, "--readPath", images_dir, | |
| "--createExpectationsPath", expectations_path]) | |
| # Make sure the expectations file was generated correctly. | |
| golden_expectations = os.path.join(file_dir, "skimage", "output-expected", | |
| "create-expectations", | |
| "expectations.json") | |
| DieIfFilesMismatch(expected=golden_expectations, actual=expectations_path) | |
| # Tell skimage to read back the expectations file it just wrote, and | |
| # confirm that the images in images_dir match it. | |
| output = subprocess.check_output([skimage_binary, "--readPath", images_dir, | |
| "--readExpectationsPath", | |
| expectations_path], | |
| stderr=subprocess.STDOUT) | |
| # Although skimage succeeded, it would have reported success if the file | |
| # was missing from the expectations file. Consider this a failure, since | |
| # the expectations file was created from this same image. (It will print | |
| # "Missing" in this case before listing the missing expectations). | |
| if "Missing" in output: | |
| raise Exception("Expectations file was missing expectations: %s" % output) | |
| # Again, skimage would succeed if there were known failures (and print | |
| # "failures"), but there should be no failures, since the file just | |
| # created did not include failures to ignore. | |
| if "failures" in output: | |
| raise Exception("Image failed: %s" % output) | |
| test_incorrect_expectations(file_dir=file_dir, | |
| skimage_binary=skimage_binary) | |
| # Generate an expectations file from an empty directory. | |
| empty_dir = tempfile.mkdtemp() | |
| expectations_path = os.path.join(file_dir, "skimage", "output-actual", | |
| "empty-dir", "expectations.json") | |
| subprocess.check_call([skimage_binary, "--readPath", empty_dir, | |
| "--createExpectationsPath", expectations_path]) | |
| golden_expectations = os.path.join(file_dir, "skimage", "output-expected", | |
| "empty-dir", "expectations.json") | |
| DieIfFilesMismatch(expected=golden_expectations, actual=expectations_path) | |
| os.rmdir(empty_dir) | |
| # Generate an expectations file from a nonexistent directory. | |
| expectations_path = os.path.join(file_dir, "skimage", "output-actual", | |
| "nonexistent-dir", "expectations.json") | |
| subprocess.check_call([skimage_binary, "--readPath", "/nonexistent/dir", | |
| "--createExpectationsPath", expectations_path]) | |
| golden_expectations = os.path.join(file_dir, "skimage", "output-expected", | |
| "nonexistent-dir", "expectations.json") | |
| DieIfFilesMismatch(expected=golden_expectations, actual=expectations_path) | |
| test_invalid_file(file_dir=file_dir, skimage_binary=skimage_binary) | |
| # Done with all tests. | |
| print "Self tests succeeded!" | |
| if __name__ == "__main__": | |
| main() |