Пример #1
0
def proc_batch(files):
    """Runs each task in the pipeline on batches of files.

    These tasks read and write to the files directly. They are given a list of
    all files at once to avoid spawning too many subprocesses.

    Keyword arguments:
    files -- list of file names

    Returns true if all tasks succeeded.
    """
    all_success = True

    for subtask in task_pipeline:
        work = []
        for name in files:
            config_file = Config(os.path.dirname(name), ".styleguide")
            if subtask.should_process_file(config_file, name):
                work.append(name)

        if work:
            if verbose1 or verbose2:
                print("Running", type(subtask).__name__)
                if verbose2:
                    for name in work:
                        print("  on", name)

            all_success &= subtask.run_batch(config_file, work)

    return all_success
Пример #2
0
    def run(self, output_type):
        """Runs the task on each input list element, then compares the resulting
        output against the corresponding output list element.

        output_type == FILE: output list contains file contents
        output_type == STDOUT: output list contains stdout contents

        Keyword Arguments:
        output_type -- the type of output stored in the output list
        """
        assert len(self.inputs) == len(self.outputs)

        config_file = Config(os.path.abspath(os.getcwd()), ".styleguide")

        for i in range(len(self.inputs)):
            if self.task.should_process_file(config_file, self.inputs[i][0]):
                print("Running test {}...".format(i))

                if output_type == OutputType.FILE:
                    output, success = self.task.run_pipeline(
                        config_file, self.inputs[i][0], self.inputs[i][1])
                elif output_type == OutputType.STDOUT:
                    saved_stdout = sys.stdout
                    sys.stdout = io.StringIO()
                    _output, success = self.task.run_pipeline(
                        config_file, self.inputs[i][0], self.inputs[i][1])
                    sys.stdout.seek(0)
                    output = sys.stdout.read()
                    sys.stdout = saved_stdout

                assert output == self.outputs[i][0]
                assert success == self.outputs[i][2]
Пример #3
0
def proc_batch(files):
    """Runs each task in the pipeline on batches of files.

    These tasks read and write to the files directly. They are given a list of
    all files at once to avoid spawning too many subprocesses.

    Keyword arguments:
    files -- list of file names

    Returns true if all tasks succeeded.
    """
    all_success = True

    for subtask in task_pipeline:
        work = []
        for name in files:
            config_file = Config(os.path.dirname(name), ".styleguide")
            if subtask.should_process_file(config_file, name):
                work.append(name)

        if work:
            # Conservative estimate for max argument length. 32767 is from the
            # Win32 docs for CreateProcessA(), but the limit appears to be lower
            # than that in practice.
            MAX_WIN32_ARGS_LEN = 32767 * 7 / 8

            for subwork in chunks(work, MAX_WIN32_ARGS_LEN):
                if verbose1 or verbose2:
                    print("Running", type(subtask).__name__)
                    if verbose2:
                        for name in subwork:
                            print("  on", name)
                all_success &= subtask.run_batch(config_file, subwork)

    return all_success
Пример #4
0
    def run_pipeline(self, config_file, name, lines):
        linesep = super().get_linesep(lines)

        license_template = Config.read_file(
            os.path.dirname(os.path.abspath(name)), ".styleguide-license")

        # Get year when file was most recently modified in Git history
        #
        # Committer date is used instead of author date (the one shown by "git
        # log" because the year the file was last modified in the history should
        # be used. Author dates can be older than this or even out of order in
        # the log.
        cmd = ["git", "log", "-n", "1", "--format=%ci", "--", name]
        last_year = subprocess.run(cmd,
                                   stdout=subprocess.PIPE).stdout.decode()[:4]

        # Check if file has uncomitted changes in the working directory
        cmd = ["git", "diff-index", "--quiet", "HEAD", "--", name]
        has_uncommitted_changes = subprocess.run(cmd).returncode

        # If file hasn't been committed yet or has changes in the working
        # directory, use current calendar year as end of copyright year range
        if last_year == "" or has_uncommitted_changes:
            last_year = str(date.today().year)

        success, first_year, appendix = self.__try_regex(
            lines, last_year, license_template)
        if not success:
            success, first_year, appendix = self.__try_string_search(
                lines, last_year, license_template)

        output = ""

        # Determine copyright range and trailing padding
        if first_year != last_year:
            year_range = first_year + "-" + last_year
        else:
            year_range = first_year

        for line in license_template:
            # Insert copyright year range
            line = line.replace("{year}", year_range)

            # Insert padding which expands to the 80th column. If there is more
            # than one padding token, the line may contain fewer than 80
            # characters due to rounding during the padding width calculation.
            PADDING_TOKEN = "{padding}"
            padding_count = line.count(PADDING_TOKEN)
            if padding_count:
                padding = 80 - len(line) + len(PADDING_TOKEN) * padding_count
                padding_width = int(padding / padding_count)
                line = line.replace(PADDING_TOKEN, " " * padding_width)

            output += line + linesep

        # Copy rest of original file into new one
        output += appendix

        return output, True
Пример #5
0
def test_usingdeclaration():
    task = UsingDeclaration()

    inputs = []
    outputs = []

    # Before class block
    inputs.append(("./Test.h",
        "using std::chrono;" + os.linesep + \
        "class Test {" + os.linesep + \
        "}" + os.linesep))
    outputs.append(("./Test.h: 1: 'using std::chrono;' in global namespace\n",
                    False, False))

    # Inside enum block
    inputs.append(("./Test.h",
        "enum Test {" + os.linesep + \
        "  using std::chrono;" + os.linesep + \
        "}" + os.linesep))
    outputs.append(("", False, True))

    # After { block
    inputs.append(("./Test.h",
        "{" + os.linesep + \
        "}" + os.linesep + \
        "using std::chrono;" + os.linesep))
    outputs.append(("./Test.h: 3: 'using std::chrono;' in global namespace\n",
                    False, False))

    # Before class block with NOLINT
    inputs.append(("./Test.h",
        "using std::chrono;  // NOLINT" + os.linesep + \
        "class Test {" + os.linesep + \
        "}" + os.linesep))
    outputs.append(("", False, True))

    assert len(inputs) == len(outputs)

    config_file = Config(os.path.abspath(os.getcwd()), ".styleguide")
    saved_stdout = sys.stdout
    for i in range(len(inputs)):
        new_stdout = io.StringIO()
        sys.stdout = new_stdout
        unused_output, file_changed, success = task.run_pipeline(
            config_file, inputs[i][0], inputs[i][1])
        sys.stdout = saved_stdout
        new_stdout.seek(0)
        output = new_stdout.read()
        assert output == outputs[i][0]
        assert file_changed == outputs[i][1]
        assert success == outputs[i][2]
Пример #6
0
def test_config():
    config_file = Config(os.path.abspath(os.getcwd()), ".styleguide")
    assert config_file.is_modifiable_file("." + os.sep + "wpiformat" + os.sep +
                                          "javaguidelink.png")
    assert config_file.is_generated_file("." + os.sep + "wpiformat" + os.sep +
                                         "wpiformat" + os.sep + "cpplint.py")

    assert not config_file.is_generated_file("." + os.sep + "wpiformat" +
                                             os.sep + "diff_cpplint.py")
    assert not config_file.is_generated_file("." + os.sep + "wpiformat" +
                                             os.sep + "update_cpplint.py")
    assert not config_file.is_modifiable_file("." + os.sep + "wpiformat" +
                                              os.sep + "license.txt")
Пример #7
0
def test_whitespace():
    task = Whitespace()

    inputs = []
    outputs = []

    file_appendix = \
        "#pragma once" + os.linesep + \
        os.linesep + \
        "#include <iostream>" + os.linesep + \
        os.linesep + \
        "int main() {" + os.linesep + \
        "  std::cout << \"Hello World!\";" + os.linesep + \
        "}" + os.linesep

    # Empty file
    inputs.append(("./Test.h", ""))
    outputs.append(("", False, True))

    # No trailing whitespace
    inputs.append(("./Test.h", file_appendix))
    outputs.append((file_appendix, False, True))

    # Two spaces trailing
    inputs.append(
        ("./Test.h",
         "#pragma once" + os.linesep + os.linesep + "#include <iostream>" +
         os.linesep + os.linesep + "int main() {  " + os.linesep +
         "  std::cout << \"Hello World!\";  " + os.linesep + "}" + os.linesep))
    outputs.append((file_appendix, True, True))

    # Two tabs trailing
    inputs.append((
        "./Test.h",
        "#pragma once" + os.linesep + os.linesep + "#include <iostream>" +
        os.linesep + os.linesep + "int main() {\t\t" + os.linesep +
        "  std::cout << \"Hello World!\";\t\t" + os.linesep + "}" + os.linesep))
    outputs.append((file_appendix, True, True))

    assert len(inputs) == len(outputs)

    config_file = Config(os.path.abspath(os.getcwd()), ".styleguide")
    for i in range(len(inputs)):
        output, file_changed, success = task.run_pipeline(
            config_file, inputs[i][0], inputs[i][1])
        assert output == outputs[i][0]
        assert file_changed == outputs[i][1]
        assert success == outputs[i][2]
Пример #8
0
def proc_pipeline(name):
    """Runs the contents of each files through the task pipeline.

    If the contents were modified at any point, the result is written back out
    to the file.

    Keyword arguments:
    name -- file name string
    """
    config_file = Config(os.path.dirname(name), ".styleguide")
    if verbose1 or verbose2:
        with print_lock:
            print("Processing", name)
            if verbose2:
                for subtask in task_pipeline:
                    if subtask.should_process_file(config_file, name):
                        print("  with " + type(subtask).__name__)

    lines = ""
    with open(name, "r") as file:
        try:
            lines = file.read()
        except UnicodeDecodeError:
            print("Error: " + name + " contains characters not in UTF-8. "
                  "Should this be considered a generated file?")
            return False

    file_changed = False

    # The success flag is aggregated across multiple file processing results
    all_success = True

    for subtask in task_pipeline:
        if subtask.should_process_file(config_file, name):
            lines, changed, success = subtask.run_pipeline(
                config_file, name, lines)
            file_changed |= changed
            all_success &= success

    if file_changed:
        with open(name, "wb") as file:
            file.write(lines.encode())

        # After file is written, reset file_changed flag
        file_changed = False

    return all_success
Пример #9
0
def test_newline():
    task = Newline()

    inputs = []
    outputs = []

    file_appendix = \
        "#pragma once" + os.linesep + \
        os.linesep + \
        "#include <iostream>" + os.linesep + \
        os.linesep + \
        "int main() {" + os.linesep + \
        "  std::cout << \"Hello World!\";" + os.linesep + \
        "}"

    # Empty file
    inputs.append(("./Test.h", ""))
    outputs.append(("\n", True, True))

    # No newline
    inputs.append(("./Test.h", file_appendix))
    outputs.append((file_appendix + os.linesep, True, True))

    # One newline
    inputs.append((inputs[1][0], inputs[1][1] + os.linesep))
    outputs.append((outputs[1][0], False, True))

    # Two newlines
    inputs.append((inputs[1][0], inputs[1][1] + os.linesep + os.linesep))
    outputs.append((outputs[1][0], True, True))

    # .bat file with no "./" prefix
    inputs.append(("test.bat", inputs[1][1].replace(os.linesep, "\r\n")))
    outputs.append((outputs[1][0].replace(os.linesep, "\r\n"), True, True))

    assert len(inputs) == len(outputs)

    config_file = Config(os.path.abspath(os.getcwd()), ".styleguide")
    for i in range(len(inputs)):
        output, file_changed, success = task.run_pipeline(
            config_file, inputs[i][0], inputs[i][1])
        assert output == outputs[i][0]
        assert file_changed == outputs[i][1]
        assert success == outputs[i][2]
Пример #10
0
    def run_pipeline(self, config_file, name, lines):
        linesep = Task.get_linesep(lines)

        license_template = Config.read_file(
            os.path.dirname(os.path.abspath(name)), ".styleguide-license")

        success, year, appendix = self.__try_regex(lines, license_template)
        if not success:
            success, year, appendix = self.__try_string_search(
                lines, license_template)

        output = ""

        # Determine copyright range and trailing padding
        if year != self.__current_year:
            year = year + "-" + self.__current_year

        for line in license_template:
            # Insert copyright year range
            line = line.replace("{year}", year)

            # Insert padding which expands to the 80th column. If there is more
            # than one padding token, the line may contain fewer than 80
            # characters due to rounding during the padding width calculation.
            PADDING_TOKEN = "{padding}"
            padding_count = line.count(PADDING_TOKEN)
            if padding_count:
                padding = 80 - len(line) + len(PADDING_TOKEN) * padding_count
                padding_width = int(padding / padding_count)
                line = line.replace(PADDING_TOKEN, " " * padding_width)

            output += line + linesep

        # Copy rest of original file into new one
        output += appendix

        return (output, lines != output, True)
def test_usingnamespacestd():
    task = UsingNamespaceStd()

    inputs = []
    outputs = []

    warning_str = "avoid \"using namespace std;\" in production software. While it is used in introductory C++, it pollutes the global namespace with standard library symbols.\n"

    # Hello World
    inputs.append(("./Main.cpp",
        "using namespace std;" + os.linesep + \
        os.linesep + \
        "int main() {" + os.linesep + \
        "  cout << \"Hello World!\"" + os.linesep + \
        "}" + os.linesep))
    outputs.append(("Warning: ./Main.cpp: 1: " + warning_str, False, True))

    # Inside braces and not first line
    inputs.append(("./Main.cpp",
        "int main() {" + os.linesep + \
        "  using namespace std;" + os.linesep + \
        "  cout << \"Hello World!\"" + os.linesep + \
        "}" + os.linesep))
    outputs.append(("Warning: ./Main.cpp: 2: " + warning_str, False, True))

    # std::chrono
    inputs.append(("./Main.cpp",
        "#include <thread>" + os.linesep + \
        os.linesep + \
        "int main() {" + os.linesep + \
        "  using namespace std::chrono;" + os.linesep + \
        os.linesep + \
        "  std::this_thread::sleep_for(10ms);" + os.linesep + \
        "}" + os.linesep))
    outputs.append(("Warning: ./Main.cpp: 4: " + warning_str, False, True))

    # Ignore std::literals
    inputs.append(
        ("./Main.cpp", "using namespace std::literals;" + os.linesep))
    outputs.append(("", False, True))

    # Ignore std::chrono_literals
    inputs.append(
        ("./Main.cpp", "using namespace std::chrono_literals;" + os.linesep))
    outputs.append(("", False, True))

    # Ignore std::placeholders
    inputs.append(
        ("./Main.cpp", "using namespace std::placeholders;" + os.linesep))
    outputs.append(("", False, True))

    assert len(inputs) == len(outputs)

    config_file = Config(os.path.abspath(os.getcwd()), ".styleguide")
    saved_stdout = sys.stdout
    for i in range(len(inputs)):
        new_stdout = io.StringIO()
        sys.stdout = new_stdout
        unused_output, file_changed, success = task.run_pipeline(
            config_file, inputs[i][0], inputs[i][1])
        sys.stdout = saved_stdout
        new_stdout.seek(0)
        output = new_stdout.read()
        print("Running test {}...".format(i))
        print("output=", output)
        print("outputs[i][0]=", outputs[i][0])
        assert output == outputs[i][0]
        assert file_changed == outputs[i][1]
        assert success == outputs[i][2]
Пример #12
0
def test_includeorder():
    task = IncludeOrder()

    inputs = []
    outputs = []

    # cpp source including related header with wrong include braces and C++ sys
    # before C sys headers
    inputs.append(("./Utility.cpp",
        "#include <Utility.h>" + os.linesep + \
        os.linesep + \
        "#include <sstream>" + os.linesep + \
        os.linesep + \
        "#include <cxxabi.h>" + os.linesep + \
        "#include <execinfo.h>" + os.linesep + \
        os.linesep + \
        "#include \"HAL/HAL.h\"" + os.linesep + \
        "#include \"Task.h\"" + os.linesep + \
        "#include \"nivision.h\"" + os.linesep))
    outputs.append((
        "#include \"Utility.h\"" + os.linesep + \
        os.linesep + \
        "#include <cxxabi.h>" + os.linesep + \
        "#include <execinfo.h>" + os.linesep + \
        os.linesep + \
        "#include <sstream>" + os.linesep + \
        os.linesep + \
        "#include \"HAL/HAL.h\"" + os.linesep + \
        "#include \"Task.h\"" + os.linesep + \
        "#include \"nivision.h\"" + os.linesep, True, True))

    # Ensure quotes around C and C++ std header includes are replaced with
    # angle brackets and they are properly sorted into two groups
    inputs.append(("./Test.h",
        "#include \"stdio.h\"" + os.linesep + \
        "#include \"iostream\"" + os.linesep + \
        "#include \"memory\"" + os.linesep + \
        "#include \"signal.h\"" + os.linesep))
    outputs.append((
        "#include <signal.h>" + os.linesep + \
        "#include <stdio.h>" + os.linesep + \
        os.linesep + \
        "#include <iostream>" + os.linesep + \
        "#include <memory>" + os.linesep, True, True))

    # Ensure NOLINT headers take precedence over overrides and have newline
    # inserted
    inputs.append(("./Test.h",
        "#include \"ctre/PDP.h\"  // NOLINT" + os.linesep + \
        "#include <atomic>" + os.linesep + \
        "#include <condition_variable>" + os.linesep + \
        "#include <thread>" + os.linesep))
    outputs.append((
        "#include \"ctre/PDP.h\"  // NOLINT" + os.linesep + \
        os.linesep + \
        "#include <atomic>" + os.linesep + \
        "#include <condition_variable>" + os.linesep + \
        "#include <thread>" + os.linesep, True, True))

    # Check sorting for at least one header from each group except related
    # header. Test.inc isn't considered related in headers.
    inputs.append(("./Test.h",
        "#include \"MyHeader.h\"" + os.linesep + \
        "#include <stdio.h>" + os.linesep + \
        "#include \"Test.inc\"" + os.linesep + \
        "#include <sys/time.h>" + os.linesep + \
        "#include <fstream>" + os.linesep + \
        "#include <boost/algorithm/string/replace.hpp>" + os.linesep))
    outputs.append((
        "#include <stdio.h>" + os.linesep + \
        "#include <sys/time.h>" + os.linesep + \
        os.linesep + \
        "#include <fstream>" + os.linesep + \
        os.linesep + \
        "#include <boost/algorithm/string/replace.hpp>" + os.linesep + \
        os.linesep + \
        "#include \"MyHeader.h\"" + os.linesep + \
        "#include \"Test.inc\"" + os.linesep, True, True))

    # Verify "other header" isn't identified as C system include
    inputs.append(("./Test.h",
        "#include <OtherHeader.h>" + os.linesep + \
        "#include <sys/time.h>" + os.linesep))
    outputs.append((
        "#include <sys/time.h>" + os.linesep + \
        os.linesep + \
        "#include <OtherHeader.h>" + os.linesep, True, True))

    # Verify newline is added between last header and code after it
    inputs.append(("./Test.cpp",
        "#include \"MyFile.h\"" + os.linesep + \
        os.linesep + \
        "#include <iostream>" + os.linesep + \
        "namespace std {" + os.linesep + \
        "}" + os.linesep))
    outputs.append((
        "#include <iostream>" + os.linesep + \
        os.linesep + \
        "#include \"MyFile.h\"" + os.linesep + \
        os.linesep + \
        "namespace std {" + os.linesep + \
        "}" + os.linesep, True, True))

    # Verify newlines are removed between last header and code after it
    inputs.append(("./Test.cpp",
        "#include \"MyFile.h\"" + os.linesep + \
        os.linesep + \
        "#include <iostream>" + os.linesep + \
        os.linesep + \
        os.linesep + \
        os.linesep + \
        "namespace std {" + os.linesep + \
        "}" + os.linesep))
    outputs.append((outputs[len(outputs) - 1][0], True, True))

    # Ensure headers stay grouped together between license header and other code
    inputs.append(("./Test.cpp",
        "// Copyright (c) Company Name 2016." + os.linesep + \
        "#include <iostream>" + os.linesep + \
        "#include \"Test.h\"" + os.linesep + \
        "namespace std {" + os.linesep + \
        "}" + os.linesep))
    outputs.append((
        "// Copyright (c) Company Name 2016." + os.linesep + \
        "#include \"Test.h\"" + os.linesep + \
        os.linesep + \
        "#include <iostream>" + os.linesep + \
        os.linesep + \
        "namespace std {" + os.linesep + \
        "}" + os.linesep, True, True))

    # Verify headers are sorted across #ifdef
    inputs.append(("./Error.h",
        "#pragma once" + os.linesep + \
        os.linesep + \
        "#include <stdint.h>" + os.linesep + \
        os.linesep + \
        "#include <string>" + os.linesep + \
        os.linesep + \
        "#ifdef _WIN32" + os.linesep + \
        "#include <Windows.h>" + os.linesep + \
        "// This is a comment" + os.linesep + \
        "#undef GetMessage" + os.linesep + \
        "#endif" + os.linesep + \
        os.linesep + \
        "#include <string>" + os.linesep + \
        os.linesep + \
        "#include \"Base.h\"" + os.linesep + \
        "#include \"llvm/StringRef.h\"" + os.linesep))
    outputs.append((
        "#pragma once" + os.linesep + \
        os.linesep + \
        "#include <stdint.h>" + os.linesep + \
        os.linesep + \
        "#include <string>" + os.linesep + \
        os.linesep + \
        "#ifdef _WIN32" + os.linesep + \
        "#include <Windows.h>" + os.linesep + \
        "// This is a comment" + os.linesep + \
        "#undef GetMessage" + os.linesep + \
        "#endif" + os.linesep + \
        os.linesep + \
        "#include \"Base.h\"" + os.linesep + \
        "#include \"llvm/StringRef.h\"" + os.linesep, True, True))

    # Verify "#ifdef _WIN32" acts as barrier for out-of-order includes
    inputs.append(("./Error.h",
        "#pragma once" + os.linesep + \
        os.linesep + \
        "#include <stdint.h>" + os.linesep + \
        os.linesep + \
        "#include <string>" + os.linesep + \
        os.linesep + \
        "#ifdef _WIN32" + os.linesep + \
        "#include <string>" + os.linesep + \
        os.linesep + \
        "#include <Windows.h>" + os.linesep + \
        "#endif" + os.linesep + \
        os.linesep + \
        "#include <string>" + os.linesep + \
        os.linesep + \
        "#include \"Base.h\"" + os.linesep + \
        "#include \"llvm/StringRef.h\"" + os.linesep))
    outputs.append((inputs[len(inputs) - 1][1], False, True))

    # Verify "#ifdef __linux__" is sorted in correct category below other
    # headers
    inputs.append(("./Error.h",
        "#pragma once" + os.linesep + \
        os.linesep + \
        "#include <stdlib.h>" + os.linesep + \
        os.linesep + \
        "#include <string>" + os.linesep + \
        os.linesep + \
        "#ifdef __linux__" + os.linesep + \
        "#include <stdio.h>" + os.linesep + \
        "#endif" + os.linesep + \
        os.linesep + \
        "#include \"Base.h\"" + os.linesep + \
        "#include \"llvm/StringRef.h\"" + os.linesep))
    outputs.append((
        "#pragma once" + os.linesep + \
        os.linesep + \
        "#include <stdlib.h>" + os.linesep + \
        os.linesep + \
        "#ifdef __linux__" + os.linesep + \
        "#include <stdio.h>" + os.linesep + \
        "#endif" + os.linesep + \
        os.linesep + \
        "#include <string>" + os.linesep + \
        os.linesep + \
        "#include \"Base.h\"" + os.linesep + \
        "#include \"llvm/StringRef.h\"" + os.linesep, True, True))

    # Verify "#ifdef __linux__" is included in output if no headers are in same
    # category
    inputs.append(("./Error.h",
        "#pragma once" + os.linesep + \
        os.linesep + \
        "#ifdef __linux__" + os.linesep + \
        "#include <stdio.h>" + os.linesep + \
        "#endif" + os.linesep + \
        os.linesep + \
        "#include <string>" + os.linesep + \
        os.linesep + \
        "#include \"Base.h\"" + os.linesep + \
        "#include \"llvm/StringRef.h\"" + os.linesep))
    outputs.append((inputs[len(inputs) - 1][1], False, True))

    # Verify #ifdef blocks in a row are handled properly
    inputs.append(("./Log.cpp",
        "#include \"Log.h\"" + os.linesep + \
        os.linesep + \
        "#include <cstdio>" + os.linesep + \
        os.linesep + \
        "#ifdef _WIN32" + os.linesep + \
        "#include <cstdlib>" + os.linesep + \
        "#else" + os.linesep + \
        "#include <cstring>" + os.linesep + \
        "#endif" + os.linesep + \
        os.linesep + \
        "#ifdef __APPLE__" + os.linesep + \
        "#include <libgen.h>" + os.linesep + \
        "#endif" + os.linesep + \
        os.linesep + \
        "#ifdef __ANDROID__" + os.linesep + \
        "#include <libgen.h>" + os.linesep + \
        "#endif" + os.linesep + \
        os.linesep + \
        "using namespace cs;" + os.linesep))
    outputs.append((
        "#include \"Log.h\"" + os.linesep + \
        os.linesep + \
        "#ifdef __APPLE__" + os.linesep + \
        "#include <libgen.h>" + os.linesep + \
        "#endif" + os.linesep + \
        os.linesep + \
        "#ifdef __ANDROID__" + os.linesep + \
        "#include <libgen.h>" + os.linesep + \
        "#endif" + os.linesep + \
        os.linesep + \
        "#include <cstdio>" + os.linesep + \
        os.linesep + \
        "#ifdef _WIN32" + os.linesep + \
        "#include <cstdlib>" + os.linesep + \
        "#else" + os.linesep + \
        "#include <cstring>" + os.linesep + \
        "#endif" + os.linesep + \
        os.linesep + \
        "using namespace cs;" + os.linesep, True, True))

    # Verify comments aren't mangled
    inputs.append(("./cscore.h",
        "/* C API */" + os.linesep + \
        "#include \"cscore_c.h\"" + os.linesep + \
        os.linesep + \
        "#ifdef __cplusplus" + os.linesep + \
        "/* C++ API */" + os.linesep + \
        "#include \"cscore_cpp.h\"" + os.linesep + \
        "#include \"cscore_oo.h\"" + os.linesep + \
        "#endif /* __cplusplus */" + os.linesep))
    outputs.append((inputs[len(inputs) - 1][1], False, True))

    # Check recursive #ifdef
    inputs.append(("./Test.h",
        "#include <algorithm>" + os.linesep + \
        os.linesep + \
        "#ifdef __linux__" + os.linesep + \
        "#include <sys/socket.h>" + os.linesep + \
        "#include <sys/syscall.h>" + os.linesep + \
        "#ifdef __GNUC__ > 4" + os.linesep + \
        "#include <algorithm>" + os.linesep + \
        "#endif" + os.linesep + \
        "#endif" + os.linesep))
    outputs.append((
        "#include <algorithm>" + os.linesep + \
        os.linesep + \
        "#ifdef __linux__" + os.linesep + \
        "#include <sys/socket.h>" + os.linesep + \
        "#include <sys/syscall.h>" + os.linesep + \
        os.linesep + \
        "#ifdef __GNUC__ > 4" + os.linesep + \
        "#include <algorithm>" + os.linesep + \
        "#endif" + os.linesep + \
        "#endif" + os.linesep, True, True))

    # Verify extra newline from #endif is removed
    inputs.append(("./Test.h",
        "#include \"HAL/HAL.h\"" + os.linesep + \
        "#include \"NotifyListener.h\"" + os.linesep + \
        os.linesep + \
        "#ifdef __cplusplus" + os.linesep + \
        "extern \"C\" {" + os.linesep + \
        "#endif" + os.linesep + \
        os.linesep + \
        "void HALSIM_ResetSPIAccelerometerData(int32_t index);" + \
        os.linesep))
    outputs.append((inputs[len(inputs) - 1][1], False, True))

    # Large test
    inputs.append(("./UsbCameraImpl.cpp",
        "#include <algorithm>" + os.linesep + \
        os.linesep + \
        "#include \"Handle.h\"" + os.linesep + \
        "#include \"Log.h\"" + os.linesep + \
        "#include \"Notifier.h\"" + os.linesep + \
        "#include \"UsbUtil.h\"" + os.linesep + \
        "#include \"c_util.h\"" + os.linesep + \
        "#include \"cscore_cpp.h\"" + os.linesep + \
        os.linesep + \
        "#ifdef __linux__" + os.linesep + \
        "#include <dirent.h>" + os.linesep + \
        "#include <fcntl.h>" + os.linesep + \
        "#include <libgen.h>" + os.linesep + \
        "#include <linux/kernel.h>" + os.linesep + \
        "#include <linux/types.h>" + os.linesep + \
        "#include <linux/videodev2.h>" + os.linesep + \
        "#include <sys/eventfd.h>" + os.linesep + \
        "#include <sys/inotify.h>" + os.linesep + \
        "#include <sys/ioctl.h>" + os.linesep + \
        "#include <sys/select.h>" + os.linesep + \
        "#include <sys/stat.h>" + os.linesep + \
        "#include <sys/time.h>" + os.linesep + \
        "#include <sys/types.h>" + os.linesep + \
        "#include <unistd.h>" + os.linesep + \
        os.linesep + \
        "#elif defined(_WIN32)" + os.linesep + \
        os.linesep + \
        "#endif" + os.linesep + \
        os.linesep + \
        "using namespace cs;" + os.linesep))
    outputs.append((
        "#ifdef __linux__" + os.linesep + \
        "#include <dirent.h>" + os.linesep + \
        "#include <fcntl.h>" + os.linesep + \
        "#include <libgen.h>" + os.linesep + \
        "#include <linux/kernel.h>" + os.linesep + \
        "#include <linux/types.h>" + os.linesep + \
        "#include <linux/videodev2.h>" + os.linesep + \
        "#include <sys/eventfd.h>" + os.linesep + \
        "#include <sys/inotify.h>" + os.linesep + \
        "#include <sys/ioctl.h>" + os.linesep + \
        "#include <sys/select.h>" + os.linesep + \
        "#include <sys/stat.h>" + os.linesep + \
        "#include <sys/time.h>" + os.linesep + \
        "#include <sys/types.h>" + os.linesep + \
        "#include <unistd.h>" + os.linesep + \
        "#elif defined(_WIN32)" + os.linesep + \
        "#endif" + os.linesep + \
        os.linesep + \
        "#include <algorithm>" + os.linesep + \
        os.linesep + \
        "#include \"Handle.h\"" + os.linesep + \
        "#include \"Log.h\"" + os.linesep + \
        "#include \"Notifier.h\"" + os.linesep + \
        "#include \"UsbUtil.h\"" + os.linesep + \
        "#include \"c_util.h\"" + os.linesep + \
        "#include \"cscore_cpp.h\"" + os.linesep + \
        os.linesep + \
        "using namespace cs;" + os.linesep, True, True))

    # Verify relevant headers are found and sorted correctly
    inputs.append(("./PDP.cpp",
        "#include <memory>" + os.linesep + \
        os.linesep + \
        "#include \"HAL/PDP.h\"" + os.linesep + \
        os.linesep + \
        "#include \"ctre/PDP.h\"" + os.linesep + \
        os.linesep + \
        "using namespace hal;" + os.linesep))
    outputs.append((
        "#include \"HAL/PDP.h\"" + os.linesep + \
        os.linesep + \
        "#include <memory>" + os.linesep + \
        os.linesep + \
        "#include \"ctre/PDP.h\"" + os.linesep + \
        os.linesep + \
        "using namespace hal;" + os.linesep, True, True))

    # Check for idempotence
    inputs.append(("./PDP.cpp", outputs[len(outputs) - 1][0]))
    outputs.append((inputs[len(inputs) - 1][1], False, True))

    # Verify subgroups are sorted
    inputs.append(("./PDP.cpp",
        "#include \"support/jni_util.h\"" + os.linesep + \
        "#include \"llvm/SmallString.h\"" + os.linesep + \
        "#include \"llvm/raw_ostream.h\"" + os.linesep))
    outputs.append((
        "#include \"llvm/SmallString.h\"" + os.linesep + \
        "#include \"llvm/raw_ostream.h\"" + os.linesep + \
        "#include \"support/jni_util.h\"" + os.linesep, True, True))

    # Verify duplicate headers are removed
    inputs.append(("./PDP.cpp",
        "#include <memory>" + os.linesep + \
        "#include \"ctre/PDP.h\"" + os.linesep + \
        os.linesep + \
        "#include \"HAL/PDP.h\"" + os.linesep + \
        os.linesep + \
        "#include \"ctre/PDP.h\"" + os.linesep + \
        "#include <memory>" + os.linesep + \
        os.linesep + \
        "using namespace hal;" + os.linesep))
    outputs.append((
        "#include \"HAL/PDP.h\"" + os.linesep + \
        os.linesep + \
        "#include <memory>" + os.linesep + \
        os.linesep + \
        "#include \"ctre/PDP.h\"" + os.linesep + \
        os.linesep + \
        "using namespace hal;" + os.linesep, True, True))

    # Verify source file inclusion is disallowed
    inputs.append(("./Test.h",
        "#include <memory>" + os.linesep + \
        os.linesep + \
        "#include \"Stuff.cpp\"" + os.linesep, False, False))
    outputs.append((inputs[len(inputs) - 1][1], False, False))

    assert len(inputs) == len(outputs)

    config_file = Config(os.path.abspath(os.getcwd()), ".styleguide")
    for i in range(len(inputs)):
        output, file_changed, success = task.run_pipeline(
            config_file, inputs[i][0], inputs[i][1])
        assert output == outputs[i][0]
        assert file_changed == outputs[i][1]
        assert success == outputs[i][2]
Пример #13
0
    def run_pipeline(self, config_file, name, lines):
        linesep = Task.get_linesep(lines)

        license_template = Config.read_file(
            os.path.dirname(os.path.abspath(name)), ".styleguide-license")

        # Strip newlines at top of file
        stripped_lines = lines.lstrip().split(linesep)

        # If a comment at the beginning of the file is considered a license, it
        # is replaced with an updated license. Otherwise, a license header is
        # inserted before it.
        first_comment_is_license = False
        license_end = 0

        # Regex for tokenizing on comment boundaries
        token_regex = re.compile("^/\*|\*/|^//")

        in_multiline_comment = False
        for line in stripped_lines:
            # If part of comment contains "Copyright (c)", comment is license.
            if "Copyright (c)" in line:
                first_comment_is_license = True

            line_has_comment = False
            for match in token_regex.finditer(line):
                # If any comment token was matched, the line has a comment
                line_has_comment = True

                token = match.group()

                if token == "/*":
                    in_multiline_comment = True
                elif token == "*/":
                    in_multiline_comment = False
            if not in_multiline_comment and not line_has_comment:
                break
            else:
                license_end += 1

        # If comment at beginning of file is non-empty license, update it
        if first_comment_is_license and license_end > 0:
            file_parts = \
                [linesep.join(stripped_lines[0:license_end]),
                 linesep + linesep.join(stripped_lines[license_end:]).lstrip()]
        else:
            file_parts = ["", linesep + lines.lstrip()]

        # Default year when none is found is current one
        year = self.__current_year

        year_regex = re.compile("Copyright \(c\).*\s(20..)")
        modify_copyright = False
        for line in file_parts[0].split(linesep):
            match = year_regex.search(line)
            # If license contains copyright pattern, extract the first year
            if match:
                year = match.group(1)
                modify_copyright = True
                break

        output = ""

        # Determine copyright range and trailing padding
        if modify_copyright and year != self.__current_year:
            year = year + "-" + self.__current_year

        for line in license_template:
            # Insert copyright year range
            line = line.replace("{year}", year)

            # Insert padding which expands to the 80th column. If there is more
            # than one padding token, the line may contain fewer than 80
            # characters due to rounding during the padding width calculation.
            PADDING_TOKEN = "{padding}"
            padding_count = line.count(PADDING_TOKEN)
            if padding_count:
                padding = 80 - len(line) + len(PADDING_TOKEN) * padding_count
                padding_width = int(padding / padding_count)
                line = line.replace(PADDING_TOKEN, " " * padding_width)

            output += line + linesep

        # Copy rest of original file into new one
        if len(file_parts) > 1:
            output += file_parts[1]

        return (output, lines != output, True)
Пример #14
0
def test_includeguard():
    task = IncludeGuard()

    inputs = []
    outputs = []

    # Fix incorrect include guard
    inputs.append(("./Test.h",
        "#ifndef WRONG_H" + os.linesep + \
        "#define WRONG_C" + os.linesep + \
        os.linesep + \
        "#endif" + os.linesep))
    outputs.append((
        "#ifndef STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep + \
        "#define STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep + \
        os.linesep + \
        "#endif  // STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep, True, True))

    # Ensure nested preprocessor statements are handled properly for incorrect
    # include guard
    inputs.append(("./Test.h",
        "#ifndef WRONG_H" + os.linesep + \
        "#define WRONG_C" + os.linesep + \
        os.linesep + \
        "#if SOMETHING" + os.linesep + \
        "// do something" + os.linesep + \
        "#endif" + os.linesep + \
        "#endif" + os.linesep))
    outputs.append((
        "#ifndef STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep + \
        "#define STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep + \
        os.linesep + \
        "#if SOMETHING" + os.linesep + \
        "// do something" + os.linesep + \
        "#endif" + os.linesep + \
        "#endif  // STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep, True, True))

    # Don't touch correct include guard
    inputs.append(("./Test.h",
        "#ifndef STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep + \
        "#define STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep + \
        os.linesep + \
        "#endif  // STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep))
    outputs.append((inputs[len(inputs) - 1][1], False, True))

    # Fail on missing include guard
    inputs.append(("./Test.h", "// Empty file" + os.linesep))
    outputs.append((inputs[len(inputs) - 1][1], False, False))

    # Verify pragma once counts as include guard
    inputs.append(("./Test.h", "#pragma once" + os.linesep))
    outputs.append((inputs[len(inputs) - 1][1], False, True))

    assert len(inputs) == len(outputs)

    config_file = Config(os.path.abspath(os.getcwd()), ".styleguide")
    for i in range(len(inputs)):
        output, file_changed, success = task.run_pipeline(
            config_file, inputs[i][0], inputs[i][1])
        assert output == outputs[i][0]
        assert file_changed == outputs[i][1]
        assert success == outputs[i][2]
Пример #15
0
def main():
    # Parse command-line arguments
    parser = argparse.ArgumentParser(
        description=
        "Runs all formatting tasks on the code base. This should be invoked from a directory within the project."
    )
    parser.add_argument(
        "-v",
        dest="verbose1",
        action="store_true",
        help="verbosity level 1 (prints names of processed files)")
    parser.add_argument(
        "-vv",
        dest="verbose2",
        action="store_true",
        help=
        "verbosity level 2 (prints names of processed files and tasks run on them)"
    )
    parser.add_argument(
        "-j",
        dest="jobs",
        type=int,
        default=mp.cpu_count(),
        help="number of jobs to run (default is number of cores)")
    parser.add_argument(
        "-y",
        dest="year",
        type=int,
        default=date.today().year,
        help=
        "year to use when updating license headers (default is current year)")
    parser.add_argument(
        "-clang",
        dest="clang_version",
        type=str,
        default="",
        help=
        "version suffix for clang-format (invokes \"clang-format-CLANG_VERSION\" or \"clang-format\" if no suffix provided)"
    )
    parser.add_argument(
        "-f",
        dest="file",
        type=str,
        default="",
        nargs="+",
        help=
        "file or directory names (can be path relative to python invocation directory or absolute path)"
    )
    args = parser.parse_args()

    # All discovered files are relative to Git repo root directory, so find the
    # root.
    root_path = Task.get_repo_root()
    if root_path == "":
        print("Error: not invoked within a Git repository", file=sys.stderr)
        sys.exit(1)

    # If no files explicitly specified
    if not args.file:
        # Delete temporary files from previous incomplete run
        files = [
            os.path.join(dp, f)
            for dp, dn, fn in os.walk(root_path)
            for f in fn
            if f.endswith(".tmp")
        ]
        for f in files:
            os.remove(f)

        # Recursively create list of files in given directory
        files = [
            os.path.join(dp, f) for dp, dn, fn in os.walk(root_path) for f in fn
        ]

        if not files:
            print("Error: no files found to format", file=sys.stderr)
            sys.exit(1)
    else:
        files = []
        for name in args.file:
            # If a directory was specified, recursively expand it
            if os.path.isdir(name):
                files.extend([
                    os.path.join(dp, f)
                    for dp, dn, fn in os.walk(name)
                    for f in fn
                ])
            else:
                files.append(name)

    # Convert relative paths of files to absolute paths
    files = [os.path.abspath(name) for name in files]

    # Don't run tasks on Git metadata
    files = [name for name in files if os.sep + ".git" + os.sep not in name]

    # Don't check for changes in or run tasks on ignored files
    files = filter_ignored_files(files)

    # Create list of all changed files
    changed_file_list = []

    output_list = subprocess.run(
        ["git", "diff", "--name-only", "master"],
        stdout=subprocess.PIPE).stdout.split()
    for line in output_list:
        changed_file_list.append(root_path + os.sep +
                                 line.strip().decode("ascii"))

    # Don't run tasks on modifiable or generated files
    work = []
    for name in files:
        config_file = Config(os.path.dirname(name), ".styleguide")

        if config_file.is_modifiable_file(name):
            continue
        if config_file.is_generated_file(name):
            # Emit warning if a generated file was editted
            if name in changed_file_list:
                print("Warning: generated file '" + name + "' modified")
            continue

        work.append(name)
    files = work

    # If there are no files left, do nothing
    if len(files) == 0:
        sys.exit(0)

    # Prepare file batches for batch tasks
    chunksize = math.ceil(len(files) / args.jobs)
    file_batches = [
        files[i:i + chunksize] for i in range(0, len(files), chunksize)
    ]

    # IncludeOrder is run after Stdlib so any C std headers changed to C++ or
    # vice versa are sorted properly. ClangFormat is run after the other tasks
    # so it can clean up their formatting.
    task_pipeline = [
        BraceComment(),
        CIdentList(),
        IncludeGuard(),
        LicenseUpdate(str(args.year)),
        JavaClass(),
        Newline(),
        Stdlib(),
        IncludeOrder(),
        UsingDeclaration(),
        UsingNamespaceStd(),
        Whitespace()
    ]
    run_pipeline(task_pipeline, args, files)

    task_pipeline = [ClangFormat(args.clang_version)]
    run_batch(task_pipeline, args, file_batches)

    # These tasks fix clang-format formatting
    task_pipeline = [Jni()]
    run_pipeline(task_pipeline, args, files)

    # Lint is run last since previous tasks can affect its output.
    task_pipeline = [PyFormat(), Lint()]
    run_batch(task_pipeline, args, file_batches)
Пример #16
0
def test_stdlib():
    task = Stdlib()

    inputs = []
    outputs = []

    inputs.append(("./Main.cpp",
        "#include <cstdint>" + os.linesep + \
        "#include <stdlib.h>" + os.linesep + \
        os.linesep + \
        "int main() {" + os.linesep + \
        "  auto mem = static_cast<std::uint8_t*>(malloc(5));" + os.linesep + \
        "  std::int32_t i = 4;" + os.linesep + \
        "  int32_t a = -2;" + os.linesep + \
        "  std::uint_fast16_t j = 5;" + os.linesep + \
        "  std::uint_fast16_t* k = &j;" + os.linesep + \
        "  std::uint_fast16_t** l = &k;" + os.linesep + \
        "  std::uint_fast16_t ** m = l;" + os.linesep + \
        "  free(mem);" + os.linesep + \
        "}" + os.linesep))
    outputs.append((
        "#include <stdint.h>" + os.linesep + \
        "#include <cstdlib>" + os.linesep + \
        os.linesep + \
        "int main() {" + os.linesep + \
        "  auto mem = static_cast<uint8_t*>(std::malloc(5));" + os.linesep + \
        "  int32_t i = 4;" + os.linesep + \
        "  int32_t a = -2;" + os.linesep + \
        "  uint_fast16_t j = 5;" + os.linesep + \
        "  uint_fast16_t* k = &j;" + os.linesep + \
        "  uint_fast16_t** l = &k;" + os.linesep + \
        "  uint_fast16_t ** m = l;" + os.linesep + \
        "  std::free(mem);" + os.linesep + \
        "}" + os.linesep, True, True))

    # FILE should be recognized as type here
    inputs.append(("./Class.cpp", "static FILE* Class::file = nullptr;"))
    outputs.append(("static std::FILE* Class::file = nullptr;", True, True))

    # FILE should not be recognized as type here
    inputs.append(("./Class.cpp",
        "static int Class::error1 = ERR_FILE;" + os.linesep + \
        "#define FILE_LOG(level)" + os.linesep + \
        "if (level > FILELog::ReportingLevel())" + os.linesep))
    outputs.append((
        "static int Class::error1 = ERR_FILE;" + os.linesep + \
        "#define FILE_LOG(level)" + os.linesep + \
        "if (level > FILELog::ReportingLevel())" + os.linesep, False, True))

    # Remove "std::" from beginning of line
    inputs.append(("./Class.cpp",
                   "/**" + os.linesep + \
                   " *" + os.linesep + \
                   " */" + os.linesep + \
                   "std::size_t SizeUleb128(uint64_t val) {" + os.linesep + \
                   "  uint32_t result = 0;" + os.linesep))
    outputs.append(("/**" + os.linesep + \
                    " *" + os.linesep + \
                    " */" + os.linesep + \
                    "size_t SizeUleb128(uint64_t val) {" + os.linesep + \
                    "  uint32_t result = 0;" + os.linesep, True, True))

    # Remove "std::" from beginning of file
    inputs.append(("./Class.cpp",
                   "std::size_t SizeUleb128(uint64_t val) {" + os.linesep + \
                   "  uint32_t result = 0;" + os.linesep))
    outputs.append(("size_t SizeUleb128(uint64_t val) {" + os.linesep + \
                    "  uint32_t result = 0;" + os.linesep, True, True))

    # Don't prepend "std::" to function name if it's a function definition
    # "time()" in other contexts is a C standard library function.
    inputs.append(
        ("./Test.cpp",
         "uint64_t time() const { return m_val.last_change; }" + os.linesep))
    outputs.append((inputs[len(inputs) - 1][1], False, True))

    # Test detection of type within static_cast<>
    inputs.append(("./Test.cpp", "static_cast<std::uint64_t>(x);" + os.linesep))
    outputs.append(("static_cast<uint64_t>(x);" + os.linesep, True, True))

    # Types followed by semicolon should match
    inputs.append(("./Main.cpp", "typedef integer std::uint8_t;"))
    outputs.append(("typedef integer uint8_t;", True, True))

    assert len(inputs) == len(outputs)

    config_file = Config(os.path.abspath(os.getcwd()), ".styleguide")
    for i in range(len(inputs)):
        output, file_changed, success = task.run_pipeline(
            config_file, inputs[i][0], inputs[i][1])
        assert output == outputs[i][0]
        assert file_changed == outputs[i][1]
        assert success == outputs[i][2]
Пример #17
0
def test_licenseupdate():
    year = str(date.today().year)

    task = LicenseUpdate(year)

    inputs = []
    outputs = []

    file_appendix = \
        "#pragma once" + os.linesep + \
        os.linesep + \
        "#include <iostream>" + os.linesep + \
        os.linesep + \
        "int main() {" + os.linesep + \
        "  std::cout << \"Hello World!\";" + os.linesep + \
        "}"

    # pragma once at top of file
    inputs.append(("./Test.h", file_appendix))
    outputs.append((
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */"
        .format(year) + os.linesep + os.linesep + file_appendix, True, True))

    # pragma once at top of file preceded by newline
    temp = (inputs[len(inputs) - 1][0],
            os.linesep + inputs[len(inputs) - 1][1])
    inputs.append(temp)
    outputs.append(outputs[len(outputs) - 1])

    # File containing up-to-date license preceded by newline
    inputs.append((
        "./Test.h", os.linesep +
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */"
        .format(year) + os.linesep + os.linesep + file_appendix))
    outputs.append((inputs[len(inputs) - 1][1].lstrip(), True, True))

    # File containing up-to-date range license
    inputs.append((
        "./Test.h",
        "/*                                Company Name                                */"
        + os.linesep +
        "// Copyright (c) 2011-{} Company Name. All Rights Reserved.".format(
            year) + os.linesep + os.linesep + file_appendix))
    outputs.append((
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) 2011-{} Company Name. All Rights Reserved.                 */"
        .format(year) + os.linesep + os.linesep + file_appendix, True, True))

    # File containing up-to-date license with one year
    inputs.append((
        "./Test.h",
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */"
        .format(year) + os.linesep + os.linesep + file_appendix))
    outputs.append((inputs[len(inputs) - 1][1], False, True))

    # File with three newlines between license and include guard
    inputs.append((
        "./Test.h",
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */"
        .format(year) + os.linesep + os.linesep + os.linesep + file_appendix))
    outputs.append((outputs[len(outputs) - 1][0], True, True))

    # File with only one newline between license and include guard
    inputs.append((
        "./Test.h",
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */"
        .format(year) + os.linesep + file_appendix))
    outputs.append((outputs[len(outputs) - 1][0], True, True))

    # File with multiline comment spanning multiple lines of license header
    inputs.append((
        "./Test.h", "/*" + os.linesep +
        " * Autogenerated file! Do not manually edit this file. This version is regenerated"
        + os.linesep +
        " * any time the publish task is run, or when this file is deleted." +
        os.linesep + " */" + os.linesep + os.linesep +
        "const char* WPILibVersion = \"\";"))
    outputs.append((
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */"
        .format(year) + os.linesep + os.linesep + inputs[len(inputs) - 1][1],
        True, True))

    # File containing license year range in different postion than template
    # (If the year isn't extracted, the range will be replaced with one year and
    # the test will fail.)
    inputs.append((
        "./Test.h",
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) Company Name 2011-{}. All Rights Reserved.                 */"
        .format(year) + os.linesep + os.linesep + file_appendix))
    outputs.append((
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) 2011-{} Company Name. All Rights Reserved.                 */"
        .format(year) + os.linesep + os.linesep + file_appendix, True, True))

    # File excluded from license update isn't modified
    inputs.append(("./Excluded.h",
                   "/* Copyright (c) Company Name 2011-{}. */".format(year) +
                   os.linesep + os.linesep + file_appendix))
    outputs.append(("/* Copyright (c) Company Name 2011-{}. */".format(year) +
                    os.linesep + os.linesep + file_appendix, False, True))

    assert len(inputs) == len(outputs)

    config_file = Config(os.path.abspath(os.getcwd()), ".styleguide")
    for i in range(len(inputs)):
        # Ensure files excluded from license update won't be processed
        if inputs[i][0] == "./Excluded.h":
            assert not task.should_process_file(config_file, inputs[i][0])
        else:
            assert task.should_process_file(config_file, inputs[i][0])

        if task.should_process_file(config_file, inputs[i][0]):
            output, file_changed, success = task.run_pipeline(
                config_file, inputs[i][0], inputs[i][1])
            assert output == outputs[i][0]
            assert file_changed == outputs[i][1]
            assert success == outputs[i][2]
Пример #18
0
def test_bracecomment():
    task = BraceComment()

    inputs = []
    outputs = []

    # Empty anonymous namespace
    inputs.append(("./Test.h",
        "namespace {" + os.linesep + \
        "}// comment" + os.linesep))
    outputs.append((
        "namespace {" + os.linesep + \
        "}  // namespace" + os.linesep, True, True))

    # Anonymous namespace containing comment
    inputs.append(("./Test.h",
        "namespace {" + os.linesep + \
        "  // comment" + os.linesep + \
        "}// comment" + os.linesep))
    outputs.append((
        "namespace {" + os.linesep + \
        "  // comment" + os.linesep + \
        "}  // namespace" + os.linesep, True, True))

    # namespace
    inputs.append(("./Test.h",
        "namespace hal {" + os.linesep + \
        "  // comment" + os.linesep + \
        "}// comment" + os.linesep))
    outputs.append((
        "namespace hal {" + os.linesep + \
        "  // comment" + os.linesep + \
        "}  // namespace hal" + os.linesep, True, True))

    # namespace with leftover input
    inputs.append(("./Test.h",
        "// comment before namespace" + os.linesep + \
        "namespace hal {" + os.linesep + \
        "  // comment" + os.linesep + \
        "}// comment" + os.linesep + \
        "// comment after namespace" + os.linesep))
    outputs.append((
        "// comment before namespace" + os.linesep + \
        "namespace hal {" + os.linesep + \
        "  // comment" + os.linesep + \
        "}  // namespace hal" + os.linesep + \
        "// comment after namespace" + os.linesep, True, True))

    # Braces within namespace
    inputs.append(("./Test.h",
        "namespace {" + os.linesep + \
        os.linesep + \
        "struct AnalogGyro {" + os.linesep + \
        "  HAL_AnalogInputHandle handle;" + os.linesep + \
        "  double voltsPerDegreePerSecond;" + os.linesep + \
        "  double offset;" + os.linesep + \
        "  int32_t center;" + os.linesep + \
        "}" + os.linesep + \
        os.linesep + \
        "}" + os.linesep))
    outputs.append((
        "namespace {" + os.linesep + \
        os.linesep + \
        "struct AnalogGyro {" + os.linesep + \
        "  HAL_AnalogInputHandle handle;" + os.linesep + \
        "  double voltsPerDegreePerSecond;" + os.linesep + \
        "  double offset;" + os.linesep + \
        "  int32_t center;" + os.linesep + \
        "}" + os.linesep + \
        os.linesep + \
        "}  // namespace" + os.linesep, True, True))

    # extern "C"
    inputs.append(("./Test.h",
        "extern \"C\" {" + os.linesep + \
        "    // nothing" + os.linesep + \
        "}// comment" + os.linesep))
    outputs.append((
        "extern \"C\" {" + os.linesep + \
        "    // nothing" + os.linesep + \
        "}  // extern \"C\"" + os.linesep, True, True))

    # Nested brackets should be handled properly
    inputs.append(("./Test.cpp",
        "extern \"C\" {" + os.linesep + \
        "void func() {" + os.linesep + \
        "  if (1) {" + os.linesep + \
        "  } else if (1) {" + os.linesep + \
        "  } else {" + os.linesep + \
        "  }" + os.linesep + \
        "}" + os.linesep + \
        "}  // extern \"C\"" + os.linesep))
    outputs.append((inputs[len(inputs) - 1][1], False, True))

    # Nested brackets on same line
    inputs.append(("./Test.cpp",
        "namespace wpi {" + os.linesep + \
        "{{}}" + os.linesep + \
        "}  // namespace java" + os.linesep))
    outputs.append((
        "namespace wpi {" + os.linesep + \
        "{{}}" + os.linesep + \
        "}  // namespace wpi" + os.linesep, True, True))

    # Handle single-line statements correctly
    inputs.append(
        ("./Test.cpp", "namespace hal { Type typeName; }" + os.linesep))
    outputs.append(
        ("namespace hal { Type typeName; }  // namespace hal" + os.linesep,
         True, True))

    # Two incorrect comments
    inputs.append(("./Test.h",
        "namespace {" + os.linesep + \
        "    // nothing" + os.linesep + \
        "}// comment" + os.linesep + \
        "namespace Name {" + os.linesep + \
        "    // nothing" + os.linesep + \
        "}" + os.linesep))
    outputs.append((
        "namespace {" + os.linesep + \
        "    // nothing" + os.linesep + \
        "}  // namespace" + os.linesep + \
        "namespace Name {" + os.linesep + \
        "    // nothing" + os.linesep + \
        "}  // namespace Name" + os.linesep, True, True))

    # Don't touch correct comment
    inputs.append(("./Test.h",
        "namespace {" + os.linesep + \
        "    // nothing" + os.linesep + \
        "}  // namespace" + os.linesep))
    outputs.append((inputs[len(inputs) - 1][1], False, True))

    assert len(inputs) == len(outputs)

    config_file = Config(os.path.abspath(os.getcwd()), ".styleguide")
    for i in range(len(inputs)):
        output, file_changed, success = task.run_pipeline(
            config_file, inputs[i][0], inputs[i][1])
        assert output == outputs[i][0]
        assert file_changed == outputs[i][1]
        assert success == outputs[i][2]
Пример #19
0
def test_licenseupdate():
    year = str(date.today().year)

    task = LicenseUpdate(year)
    test = TaskTest(task)

    file_appendix = \
        "#pragma once" + os.linesep + \
        os.linesep + \
        "#include <iostream>" + os.linesep + \
        os.linesep + \
        "int main() {" + os.linesep + \
        "  std::cout << \"Hello World!\";" + os.linesep + \
        "}"

    # pragma once at top of file
    test.add_input("./Test.h", file_appendix)
    test.add_output(
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */".
        format(year) + os.linesep + os.linesep + file_appendix, True, True)

    # pragma once at top of file preceded by newline
    test.add_input("./Test.h", os.linesep + file_appendix)
    test.add_output(
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */".
        format(year) + os.linesep + os.linesep + file_appendix, True, True)

    # File containing up-to-date license preceded by newline
    test.add_input(
        "./Test.h", os.linesep +
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */".
        format(year) + os.linesep + os.linesep + file_appendix)
    test.add_output(
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */".
        format(year) + os.linesep + os.linesep + file_appendix, True, True)

    # File containing up-to-date range license
    test.add_input(
        "./Test.h",
        "/*                                Company Name                                */"
        + os.linesep +
        "// Copyright (c) 2011-{} Company Name. All Rights Reserved.".format(
            year) + os.linesep + os.linesep + file_appendix)
    test.add_output(
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) 2011-{} Company Name. All Rights Reserved.                 */".
        format(year) + os.linesep + os.linesep + file_appendix, True, True)

    # File containing up-to-date license with one year
    test.add_input(
        "./Test.h",
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */".
        format(year) + os.linesep + os.linesep + file_appendix)
    test.add_latest_input_as_output(True)

    # File with three newlines between license and include guard
    test.add_input(
        "./Test.h",
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */".
        format(year) + os.linesep + os.linesep + os.linesep + file_appendix)
    test.add_output(
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */".
        format(year) + os.linesep + os.linesep + file_appendix, True, True)

    # File with only one newline between license and include guard
    test.add_input(
        "./Test.h",
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */".
        format(year) + os.linesep + file_appendix)
    test.add_output(
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */".
        format(year) + os.linesep + os.linesep + file_appendix, True, True)

    # File with multiline comment spanning multiple lines of license header
    test.add_input(
        "./Test.h", "/*" + os.linesep +
        " * Autogenerated file! Do not manually edit this file. This version is regenerated"
        + os.linesep +
        " * any time the publish task is run, or when this file is deleted." +
        os.linesep + " */" + os.linesep + os.linesep +
        "const char* WPILibVersion = \"\";")
    test.add_output(
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */".
        format(year) + os.linesep + os.linesep + "/*" + os.linesep +
        " * Autogenerated file! Do not manually edit this file. This version is regenerated"
        + os.linesep +
        " * any time the publish task is run, or when this file is deleted." +
        os.linesep + " */" + os.linesep + os.linesep +
        "const char* WPILibVersion = \"\";", True, True)

    # File containing license year range in different postion than template
    # (If the year isn't extracted, the range will be replaced with one year and
    # the test will fail.)
    test.add_input(
        "./Test.h",
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) Company Name 2011-{}. All Rights Reserved.                 */".
        format(year) + os.linesep + os.linesep + file_appendix)
    test.add_output(
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) 2011-{} Company Name. All Rights Reserved.                 */".
        format(year) + os.linesep + os.linesep + file_appendix, True, True)

    # Ensure "/*" after "*/" on same line is detected
    test.add_input("./Test.h",
        "/*----------------------------------------------------------------------------*/" + os.linesep + \
        "/* Copyright (c) 2011 FIRST. All Rights Reserved.                             */" + os.linesep + \
        "/* Open Source Software - may be modified and shared by FRC teams. The code   */" + os.linesep + \
        "/* must be accompanied by the FIRST BSD license file in the root directory of */" + os.linesep + \
        "/* the project.                                                               */" + os.linesep + \
        "/*----------------------------------------------------------------------------*//*" + os.linesep + \
        os.linesep + \
        "blah" + os.linesep + \
        os.linesep + \
        "*/" + os.linesep)
    test.add_output(
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) 2011-{} Company Name. All Rights Reserved.                 */".
        format(year) + os.linesep + os.linesep, True, True)

    # File excluded from license update isn't modified
    test.add_input(
        "./Excluded.h", "/* Copyright (c) Company Name 2011-{}. */".format(year)
        + os.linesep + os.linesep + file_appendix)
    test.add_output(
        "/* Copyright (c) Company Name 2011-{}. */".format(year) + os.linesep +
        os.linesep + file_appendix, False, True)

    # Ensure license regex matches
    test.add_input("./Test.h",
        "/* Company Name */" + os.linesep + \
        "/* Copyright (c) 1992-2015 Company Name. All Rights Reserved. */" + os.linesep + \
        os.linesep + file_appendix)
    test.add_output(
        "/*                                Company Name                                */" + os.linesep + \
        "/* Copyright (c) 1992-2018 Company Name. All Rights Reserved.                 */" + os.linesep + \
        os.linesep + file_appendix, True, True)

    # Ensure excluded files won't be processed
    config_file = Config(os.path.abspath(os.getcwd()), ".styleguide")
    assert not task.should_process_file(config_file, "./Excluded.h")

    test.run(OutputType.FILE)
Пример #20
0
def test_licenseupdate():
    year = str(date.today().year)

    task = LicenseUpdate()
    test = TaskTest(task)

    file_appendix = \
        "#pragma once" + os.linesep + \
        os.linesep + \
        "#include <iostream>" + os.linesep + \
        os.linesep + \
        "int main() {" + os.linesep + \
        "  std::cout << \"Hello World!\";" + os.linesep + \
        "}"

    # pragma once at top of file
    test.add_input("./Test.h", file_appendix)
    test.add_output(
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */"
        .format(year) + os.linesep + os.linesep + file_appendix, True, True)

    # pragma once at top of file preceded by newline
    test.add_input("./Test.h", os.linesep + file_appendix)
    test.add_output(
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */"
        .format(year) + os.linesep + os.linesep + file_appendix, True, True)

    # File containing up-to-date license preceded by newline
    test.add_input(
        "./Test.h", os.linesep +
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */"
        .format(year) + os.linesep + os.linesep + file_appendix)
    test.add_output(
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */"
        .format(year) + os.linesep + os.linesep + file_appendix, True, True)

    # File containing up-to-date range license
    test.add_input(
        "./Test.h",
        "/*                                Company Name                                */"
        + os.linesep +
        "// Copyright (c) 2011-{} Company Name. All Rights Reserved.".format(
            year) + os.linesep + os.linesep + file_appendix)
    test.add_output(
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) 2011-{} Company Name. All Rights Reserved.                 */"
        .format(year) + os.linesep + os.linesep + file_appendix, True, True)

    # File containing up-to-date license with one year
    test.add_input(
        "./Test.h",
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */"
        .format(year) + os.linesep + os.linesep + file_appendix)
    test.add_latest_input_as_output(True)

    # File with three newlines between license and include guard
    test.add_input(
        "./Test.h",
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */"
        .format(year) + os.linesep + os.linesep + os.linesep + file_appendix)
    test.add_output(
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */"
        .format(year) + os.linesep + os.linesep + file_appendix, True, True)

    # File with only one newline between license and include guard
    test.add_input(
        "./Test.h",
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */"
        .format(year) + os.linesep + file_appendix)
    test.add_output(
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */"
        .format(year) + os.linesep + os.linesep + file_appendix, True, True)

    # File with multiline comment spanning multiple lines of license header
    test.add_input(
        "./Test.h", "/*" + os.linesep +
        " * Autogenerated file! Do not manually edit this file. This version is regenerated"
        + os.linesep +
        " * any time the publish task is run, or when this file is deleted." +
        os.linesep + " */" + os.linesep + os.linesep +
        "const char* WPILibVersion = \"\";")
    test.add_output(
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) {} Company Name. All Rights Reserved.                      */"
        .format(year) + os.linesep + os.linesep + "/*" + os.linesep +
        " * Autogenerated file! Do not manually edit this file. This version is regenerated"
        + os.linesep +
        " * any time the publish task is run, or when this file is deleted." +
        os.linesep + " */" + os.linesep + os.linesep +
        "const char* WPILibVersion = \"\";", True, True)

    # File containing license year range in different postion than template
    # (If the year isn't extracted, the range will be replaced with one year and
    # the test will fail.)
    test.add_input(
        "./Test.h",
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) Company Name 2011-{}. All Rights Reserved.                 */"
        .format(year) + os.linesep + os.linesep + file_appendix)
    test.add_output(
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) 2011-{} Company Name. All Rights Reserved.                 */"
        .format(year) + os.linesep + os.linesep + file_appendix, True, True)

    # Ensure "/*" after "*/" on same line is detected
    test.add_input("./Test.h",
        "/*----------------------------------------------------------------------------*/" + os.linesep + \
        "/* Copyright (c) 2011 FIRST. All Rights Reserved.                             */" + os.linesep + \
        "/* Open Source Software - may be modified and shared by FRC teams. The code   */" + os.linesep + \
        "/* must be accompanied by the FIRST BSD license file in the root directory of */" + os.linesep + \
        "/* the project.                                                               */" + os.linesep + \
        "/*----------------------------------------------------------------------------*//*" + os.linesep + \
        os.linesep + \
        "blah" + os.linesep + \
        os.linesep + \
        "*/" + os.linesep)
    test.add_output(
        "/*                                Company Name                                */"
        + os.linesep +
        "/* Copyright (c) 2011-{} Company Name. All Rights Reserved.                 */"
        .format(year) + os.linesep + os.linesep, True, True)

    # File excluded from license update isn't modified
    test.add_input(
        "./Excluded.h",
        "/* Copyright (c) Company Name 2011-{}. */".format(year) + os.linesep +
        os.linesep + file_appendix)
    test.add_output(
        "/* Copyright (c) Company Name 2011-{}. */".format(year) + os.linesep +
        os.linesep + file_appendix, False, True)

    # Ensure license regex matches
    test.add_input("./Test.h",
        "/* Company Name */" + os.linesep + \
        "/* Copyright (c) 1992-2015 Company Name. All Rights Reserved. */" + os.linesep + \
        os.linesep + file_appendix)
    test.add_output(
        "/*                                Company Name                                */" + os.linesep + \
        "/* Copyright (c) 1992-" + year + " Company Name. All Rights Reserved.                 */" + os.linesep + \
        os.linesep + file_appendix, True, True)

    # Ensure excluded files won't be processed
    config_file = Config(os.path.abspath(os.getcwd()), ".styleguide")
    assert not task.should_process_file(config_file, "./Excluded.h")

    # Create git repo to test license years for commits
    with OpenTemporaryDirectory():
        subprocess.run(["git", "init", "-q"])

        # Add base files
        with open(".styleguide-license", "w") as file:
            file.write("// Copyright (c) {year}")
        with open(".styleguide", "w") as file:
            file.write("cppSrcFileInclude {\n" + r"\.cpp$")
        subprocess.run(["git", "add", ".styleguide-license"])
        subprocess.run(["git", "add", ".styleguide"])
        subprocess.run(["git", "commit", "-q", "-m", "\"Initial commit\""])

        # Add file with commit date of last year and range through this year
        with open("last-year.cpp", "w") as file:
            file.write(f"// Copyright (c) 2017-{year}")
        subprocess.run(["git", "add", "last-year.cpp"])
        subprocess.run(["git", "commit", "-q", "-m", "\"Last year\""])
        last_iso_year = f"{int(year) - 1}-01-01T00:00:00"
        subprocess.Popen([
            "git", "commit", "-q", "--amend", "--no-edit",
            f"--date={last_iso_year}"
        ],
                         env={
                             **os.environ, "GIT_COMMITTER_DATE": last_iso_year
                         }).wait()

        # Add file with commit date of this year and range through this year
        with open("this-year.cpp", "w") as file:
            file.write(f"// Copyright (c) 2017-{year}")
        subprocess.run(["git", "add", "this-year.cpp"])
        subprocess.run(["git", "commit", "-q", "-m", "\"This year\""])

        # Add file with commit date of next year and range through this year
        with open("next-year.cpp", "w") as file:
            file.write(f"// Copyright (c) 2017-{year}")
        subprocess.run(["git", "add", "next-year.cpp"])
        subprocess.run(["git", "commit", "-q", "-m", "\"Next year\""])
        next_iso_year = f"{int(year) + 1}-01-01T00:00:00"
        subprocess.Popen([
            "git", "commit", "-q", "--amend", "--no-edit",
            f"--date={next_iso_year}"
        ],
                         env={
                             **os.environ, "GIT_COMMITTER_DATE": next_iso_year
                         }).wait()

        # Create uncommitted file with no year
        Path("no-year.cpp").touch()

        # Run wpiformat on last-year.cpp
        with open("last-year.cpp", "r") as input:
            lines = input.read()
        output, changed, success = task.run_pipeline(config_file,
                                                     "last-year.cpp", lines)
        assert output == f"// Copyright (c) 2017-{int(year) - 1}\n\n"

        # Run wpiformat on this-year.cpp
        with open("last-year.cpp", "r") as input:
            lines = input.read()
        output, changed, success = task.run_pipeline(config_file,
                                                     "this-year.cpp", lines)
        assert output == f"// Copyright (c) 2017-{year}\n\n"

        # Run wpiformat on next-year.cpp
        with open("next-year.cpp", "r") as input:
            lines = input.read()
        output, changed, success = task.run_pipeline(config_file,
                                                     "next-year.cpp", lines)
        assert output == f"// Copyright (c) 2017-{int(year) + 1}\n\n"

        # Run wpiformat on no-year.cpp
        # Should have current calendar year
        with open("no-year.cpp", "r") as input:
            lines = input.read()
        output, changed, success = task.run_pipeline(config_file, "no-year.cpp",
                                                     lines)
        assert output == f"// Copyright (c) {year}\n\n"

    test.run(OutputType.FILE)