Index: test/tools/llvm-cov/multithreaded-report.test =================================================================== --- test/tools/llvm-cov/multithreaded-report.test +++ test/tools/llvm-cov/multithreaded-report.test @@ -1,8 +1,5 @@ # Test "report" command with and without multiple threads. -# Temporarily disable the test on Windows as it doesn't support "diff -r". -REQUIRES: shell - RUN: llvm-cov report -num-threads=1 \ RUN: -path-equivalence=/tmp,%S/Inputs \ RUN: -instr-profile %S/Inputs/multithreaded_report/main.profdata \ Index: utils/lit/lit/TestRunner.py =================================================================== --- utils/lit/lit/TestRunner.py +++ utils/lit/lit/TestRunner.py @@ -346,14 +346,15 @@ """executeBuiltinDiff - Compare files line by line.""" args = expand_glob_expressions(cmd.args, cmd_shenv.cwd)[1:] try: - opts, args = getopt.gnu_getopt(args, "wbu", ["strip-trailing-cr"]) + opts, args = getopt.gnu_getopt(args, "wbur", ["strip-trailing-cr"]) except getopt.GetoptError as err: raise InternalShellError(cmd, "Unsupported: 'diff': %s" % str(err)) - filelines, filepaths = ([] for i in range(2)) + filelines, filepaths, dirs_data = ([] for i in range(3)) ignore_all_space = False ignore_space_change = False unified_diff = False + recursive_diff = False strip_trailing_cr = False for o, a in opts: if o == "-w": @@ -362,6 +363,8 @@ ignore_space_change = True elif o == "-u": unified_diff = True + elif o == "-r": + recursive_diff = True elif o == "--strip-trailing-cr": strip_trailing_cr = True else: @@ -370,6 +373,18 @@ if len(args) != 2: raise InternalShellError(cmd, "Error: missing or extra operand") + def recursivelyReadDir(path): + dir_data = {} + for dir, subdirList, fileList in os.walk(path): + if not fileList: + # Add empty dirs for comparison as well. + dir_data[os.path.relpath(dir, path)] = None + continue + for file in fileList: + with open(os.path.join(dir, file), 'r') as f: + dir_data[os.path.relpath(file, path)] = f.readlines() + return dir_data + stderr = StringIO() stdout = StringIO() exitCode = 0 @@ -378,27 +393,54 @@ if not os.path.isabs(file): file = os.path.realpath(os.path.join(cmd_shenv.cwd, file)) filepaths.append(file) - with open(file, 'r') as f: - filelines.append(f.readlines()) + if recursive_diff: + dirs_data.append(recursivelyReadDir(file)) + else: + with open(file, 'r') as f: + filelines.append(f.readlines()) - def compose2(f, g): - return lambda x: f(g(x)) + def compateTwoFiles(filelines, filepaths): + exitCode = 0 + def compose2(f, g): + return lambda x: f(g(x)) + + f = lambda x: x + if strip_trailing_cr: + f = compose2(lambda line: line.rstrip('\r'), f) + if ignore_all_space or ignore_space_change: + ignoreSpace = lambda line, separator: separator.join(line.split()) + ignoreAllSpaceOrSpaceChange = functools.partial(ignoreSpace, separator='' if ignore_all_space else ' ') + f = compose2(ignoreAllSpaceOrSpaceChange, f) + + for idx, lines in enumerate(filelines): + filelines[idx]= [f(line) for line in lines] + + func = difflib.unified_diff if unified_diff else difflib.context_diff + for diff in func(filelines[0], filelines[1], filepaths[0], filepaths[1]): + stdout.write(diff) + exitCode = 1 + return exitCode + + if not recursive_diff: + exitCode |= compateTwoFiles(filelines, filepaths) + else: + # Check names of files and directories first. + filenames_in_dirs = [set(data.keys()) for data in dirs_data] + if filenames_in_dirs[0] != filenames_in_dirs[1]: + exitCode = 1 + for filename in filenames_in_dirs[0] - filenames_in_dirs[1]: + stdout.write("Only in %s: %s" % (filepaths[0], filename)) + for filename in filenames_in_dirs[1] - filenames_in_dirs[0]: + stdout.write("Only in %s: %s" % (filepaths[1], filename)) + # Check contents of the files. + for filename, contents in dirs_data[0].iteritems(): + if not filename in dirs_data[1] or contents is None: + continue + exitCode |= compateTwoFiles( + [contents, dirs_data[1][filename]], + [os.path.join(filepaths[0], filename), + os.path.join(filepaths[1], filename)]) - f = lambda x: x - if strip_trailing_cr: - f = compose2(lambda line: line.rstrip('\r'), f) - if ignore_all_space or ignore_space_change: - ignoreSpace = lambda line, separator: separator.join(line.split()) - ignoreAllSpaceOrSpaceChange = functools.partial(ignoreSpace, separator='' if ignore_all_space else ' ') - f = compose2(ignoreAllSpaceOrSpaceChange, f) - - for idx, lines in enumerate(filelines): - filelines[idx]= [f(line) for line in lines] - - func = difflib.unified_diff if unified_diff else difflib.context_diff - for diff in func(filelines[0], filelines[1], filepaths[0], filepaths[1]): - stdout.write(diff) - exitCode = 1 except IOError as err: stderr.write("Error: 'diff' command failed, %s\n" % str(err)) exitCode = 1 Index: utils/lit/tests/Inputs/shtest-shell/diff-r.txt =================================================================== --- /dev/null +++ utils/lit/tests/Inputs/shtest-shell/diff-r.txt @@ -0,0 +1,63 @@ +# Check recursive diff ("diff -r"). + +# Create two directories for further comparison. +# RUN: rm -rf %t/dir1 %t/dir2 +# RUN: mkdir -p %t/dir1 %t/dir2 + +# Create same files in both of the dirs. +# RUN: echo "hello" > %t/dir1/f1 +# RUN: echo "hello" > %t/dir2/f1 + +# Create same subdirectories with same contents. +# RUN: mkdir -p %t/dir1/subdir %t/dir2/subdir +# RUN: echo "12345" > %t/dir1/subdir/f01 +# RUN: echo "12345" > %t/dir2/subdir/f01 +# RUN: echo -e "xxx\nzzz\nyyy" > %t/dir1/subdir/f02 +# RUN: echo -e "xxx\nzzz\nyyy" > %t/dir2/subdir/f02 + +# Create empty subdirectories with same names. +# RUN: mkdir -p %t/dir1/empty_subdir %t/dir2/empty_subdir +# RUN: diff -r %t/dir1 %t/dir2 + +# Add two empty files with different names, "diff -r" should fail. +# RUN: touch %t/dir1/dir1unique +# RUN: touch %t/dir2/dir2unique +# RUN: not diff -r %t/dir1 %t/dir2 > %t.output +# RUN: grep "Only in %t/dir1: dir1unique" %t.output +# RUN: grep "Only in %t/dir2: dir2unique" %t.output +# RUN: rm %t/dir1/dir1unique %t/dir2/dir2unique + +# Same filenames but different content, "diff -r" should fail. +# RUN: echo "00000" > %t/dir2/subdir/f01 +# RUN: not diff -r %t/dir1 %t/dir2 > %t.output +# RUN: grep "diff -r %t/dir1/subdir/f01 %t/dir2/subdir/f01" %t.output +# RUN: grep "< 12345" %t.output +# RUN: grep "> 00000" %t.output +# RUN: echo "12345" > %t/dir2/subdir/f01 + +# An extra file in one of the directories, "dirr -r" should fail. +# RUN: touch %t/dir2/extrafile +# RUN: not diff -r %t/dir1 %t/dir2 > %t.output +# RUN: grep "Only in %t/dir2: extrafile" %t.output + +# Non-empty extra file, "diff -r" should fail. +# RUN: echo "content" > %t/dir2/extrafile +# RUN: not diff -r %t/dir1 %t/dir2 > %t.output +# RUN: grep "Only in %t/dir2: extrafile" %t.output +# RUN: rm %t/dir2/extrafile + +# Empty extra directory, "diff -r" should fail. +# RUN: mkdir -p %t/dir1/extra_subdir +# RUN: not diff -r %t/dir1 %t/dir2 > %t.output +# RUN: grep "Only in %t/dir1: extra_subdir" %t.output + +# Non-empty extra directory, diff -r should fail. +# RUN: mkdir -p %t/dir1/extra_subdir/dir +# RUN: echo "1337" > %t/dir1/extra_subdir/dir/file +# RUN: not diff -r %t/dir1 %t/dir2 > %t.output +# RUN: grep "Only in %t/dir1: extra_subdir" %t.output + +# Sanity check for the test directory. +# RUN: rm -rf %t/dir1/extra_subdir +# RUN: diff -r %t/dir1 %t/dir2 +# RUN: rm -rf %t/dir1 %t/dir2 %t.output Index: utils/lit/tests/shtest-shell.py =================================================================== --- utils/lit/tests/shtest-shell.py +++ utils/lit/tests/shtest-shell.py @@ -71,6 +71,8 @@ # CHECK: error: command failed with exit status: 127 # CHECK: *** +# CHECK: PASS: shtest-shell :: diff-r.txt + # CHECK: FAIL: shtest-shell :: error-0.txt # CHECK: *** TEST 'shtest-shell :: error-0.txt' FAILED *** # CHECK: $ "not-a-real-command"