| # Copyright 2019 The ChromiumOS Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Unittests for gnlint.""" |
| |
| import logging |
| from pathlib import Path |
| |
| from chromite.lib import cros_test_lib |
| from chromite.lint import linters |
| |
| |
| # Stub error location dict. |
| # Used by test data to verify the right node is included in an error. |
| STUB_ERROR_LOCATION = { |
| "begin_column": 4, |
| "begin_line": 5, |
| "end_column": 6, |
| "end_line": 7, |
| } |
| |
| |
| class LintTestCase(cros_test_lib.TestCase): |
| """Helper for running linters.""" |
| |
| def _CheckLinter( |
| self, functor, inputs, gn_path=None, is_bad_input=True |
| ) -> None: |
| """Make sure |functor| rejects or accepts every input in |inputs|. |
| |
| When is_bad_input is true, the expected error location in the input |
| should be filled with STUB_ERROR_LOCATION and the other nodes should |
| not have it as the location of the node. |
| """ |
| # First run a sanity check. |
| ret = functor(self.STUB_DATA, gn_path) |
| self.assertEqual(ret, []) |
| |
| # Then run through all the bad inputs. |
| for x in inputs: |
| ret = functor(x, gn_path) |
| if is_bad_input: |
| self.assertNotEqual(ret, []) |
| for e in ret: |
| self.assertEqual(e.location, STUB_ERROR_LOCATION) |
| else: |
| self.assertEqual(ret, []) |
| |
| |
| class UtilityTests(cros_test_lib.MockTestCase): |
| """Tests for utility funcs.""" |
| |
| def testMainErrors(self) -> None: |
| """Make sure outputting results doesn't crash.""" |
| self.PatchObject( |
| linters.gnlint, |
| "CheckGnData", |
| return_value=[ |
| linters.gnlint.LintResult( |
| "LintFunc", Path("foo.gn"), None, "msg!", logging.ERROR |
| ), |
| ], |
| ) |
| linters.gnlint.Data("", Path("foo.gn")) |
| |
| |
| class FilesystemUtilityTests(cros_test_lib.TestCase): |
| """Tests for utility funcs that access the filesystem.""" |
| |
| def testCheckGnData(self) -> None: |
| """Check CheckGnData tails down correctly.""" |
| content = "# gn file\n" |
| ret = linters.gnlint.CheckGnData(content, Path("asdf.gn")) |
| self.assertEqual(ret, []) |
| |
| def testGnFileOption(self) -> None: |
| """Check CheckGnData processes file options correctly.""" |
| static_library_with_visibility_flag = ( |
| 'static_library("a") {\n' |
| ' cflags = [ "-fvisibility=default" ]\n' |
| "}\n" |
| ) |
| gn_options = "#gnlint: disable=GnLintVisibilityFlags\n" |
| ret = linters.gnlint.CheckGnData( |
| static_library_with_visibility_flag, Path("asdf.gn") |
| ) |
| self.assertEqual(len(ret), 1) |
| ret = linters.gnlint.CheckGnData( |
| gn_options + static_library_with_visibility_flag, Path("asdf.gn") |
| ) |
| self.assertEqual(ret, []) |
| |
| |
| def CreateTestData(flag_name, operator, value): |
| """Creates dictionary for testing simple assignment in a static_library. |
| |
| The assigned literal is set to be the error location when an error is |
| expected for the input. |
| """ |
| # static_library("my_static_library") { |
| # <flag_name> <operator> [ <value> ] |
| # } |
| # |
| # for example, when flag_name='cflags', operator='+=', value='"-lfoo"', |
| # the result stands for a gn file like this: |
| # static_library("my_static_library") { |
| # cflags += [ "-lfoo" ] |
| # } |
| if not isinstance(value, list): |
| value = [value] |
| value_list = [] |
| for item in value: |
| value_list.append( |
| { |
| "location": STUB_ERROR_LOCATION, |
| "type": "LITERAL", |
| "value": item, |
| } |
| ) |
| return { |
| "child": [ |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "LITERAL", |
| "value": '"my_static_library"', |
| } |
| ], |
| "type": "LIST", |
| }, |
| { |
| "child": [ |
| { |
| "child": [ |
| {"type": "IDENTIFIER", "value": flag_name}, |
| {"child": value_list, "type": "LIST"}, |
| ], |
| "type": "BINARY", |
| "value": operator, |
| } |
| ], |
| "type": "BLOCK", |
| }, |
| ], |
| "type": "FUNCTION", |
| "value": "static_library", |
| } |
| ], |
| "type": "BLOCK", |
| } |
| |
| |
| def CreateInstallPathTestData(target, value): |
| """creates data for testing simple assignment for install_path. |
| |
| the assigned literal is set to be the error location when an error is |
| expected for the input. |
| """ |
| # <target>("test") { |
| # install_path = <value> |
| # } |
| # variable = "/some/path" |
| # <target>("unquoted") { |
| # install_path = variable |
| # } |
| return { |
| "child": [ |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "LITERAL", |
| "value": '"test"', |
| } |
| ], |
| }, |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "IDENTIFIER", |
| "value": "install_path", |
| }, |
| {"type": "LITERAL", "value": value}, |
| ], |
| "type": "BINARY", |
| "value": "=", |
| "location": STUB_ERROR_LOCATION, |
| } |
| ], |
| "type": "BLOCK", |
| }, |
| ], |
| "type": "FUNCTION", |
| "value": target, |
| }, |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "IDENTIFIER", |
| "value": "variable", |
| }, |
| {"type": "LITERAL", "value": '"/some/path"'}, |
| ], |
| "type": "BINARY", |
| "value": "=", |
| }, |
| ], |
| }, |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "LITERAL", |
| "value": '"unquoted"', |
| } |
| ], |
| }, |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "IDENTIFIER", |
| "value": "install_path", |
| }, |
| {"type": "IDENTIFIER", "value": "variable"}, |
| ], |
| "type": "LITERAL", |
| "value": "=", |
| } |
| ], |
| "type": "BLOCK", |
| }, |
| ], |
| "type": "FUNCTION", |
| "value": target, |
| }, |
| ], |
| "type": "BLOCK", |
| } |
| |
| |
| def CreateDepsTestData(value): |
| """creates data for testing simple assignment for deps. |
| |
| the assigned list is set to be the error location when an error is |
| expected for the input. |
| """ |
| # static_library("test") { |
| # deps = [ <value> ] |
| # } |
| if not isinstance(value, list): |
| value = [value] |
| value_list = [] |
| for item in value: |
| value_list.append( |
| { |
| "location": STUB_ERROR_LOCATION, |
| "type": "LITERAL", |
| "value": item, |
| } |
| ) |
| return { |
| "child": [ |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "LITERAL", |
| "value": '"test"', |
| } |
| ], |
| }, |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "IDENTIFIER", |
| "value": "deps", |
| }, |
| {"child": value_list, "type": "LIST"}, |
| ], |
| "type": "BINARY", |
| "value": "=", |
| } |
| ], |
| "type": "BLOCK", |
| }, |
| ], |
| "type": "FUNCTION", |
| "value": "static_library", |
| } |
| ], |
| "type": "BLOCK", |
| } |
| |
| |
| class GnLintTests(LintTestCase): |
| """Tests of various gn linters.""" |
| |
| STUB_DATA = {"type": "BLOCK"} |
| |
| def testGnLintLibFlags(self) -> None: |
| """Verify GnLintLibFlags catches bad inputs.""" |
| |
| self._CheckLinter( |
| linters.gnlint.GnLintLibFlags, |
| [ |
| CreateTestData("ldflags", "=", '"-lfoo"'), |
| CreateTestData("ldflags", "+=", '"-lfoo"'), |
| CreateTestData("ldflags", "-=", '"-lfoo"'), |
| ], |
| ) |
| |
| def testGnLintVisibilityFlags(self) -> None: |
| """Verify GnLintVisibilityFlags catches bad inputs.""" |
| self._CheckLinter( |
| linters.gnlint.GnLintVisibilityFlags, |
| [ |
| CreateTestData("cflags", "=", '"-fvisibility"'), |
| CreateTestData("cflags", "+=", '"-fvisibility"'), |
| CreateTestData("cflags", "-=", '"-fvisibility=default"'), |
| CreateTestData("cflags_c", "-=", '"-fvisibility=hidden"'), |
| CreateTestData("cflags_cc", "-=", '"-fvisibility=internal"'), |
| ], |
| ) |
| |
| def testGnLintDefineFlags(self) -> None: |
| """Verify GnLintDefineFlags catches bad inputs.""" |
| self._CheckLinter( |
| linters.gnlint.GnLintDefineFlags, |
| [ |
| CreateTestData("cflags", "=", '"-D_FLAG"'), |
| CreateTestData("cflags", "+=", '"-D_FLAG"'), |
| CreateTestData("cflags", "-=", '"-D_FLAG=1"'), |
| CreateTestData("cflags_c", "=", '"-D_FLAG=0"'), |
| CreateTestData("cflags_cc", "=", '"-D_FLAG="something""'), |
| ], |
| ) |
| |
| def testGnLintCommonTesting(self) -> None: |
| """Verify GnLintCommonTesting catches bad inputs.""" |
| self._CheckLinter( |
| linters.gnlint.GnLintCommonTesting, |
| [ |
| CreateTestData("libs", "=", '"gmock"'), |
| CreateTestData("libs", "=", '"gtest"'), |
| CreateTestData("libs", "=", ['"gmock"', '"gtest"']), |
| ], |
| ) |
| |
| def testGnLintDefines(self) -> None: |
| """Verify GnLintDefines catches bad inputs.""" |
| self._CheckLinter( |
| linters.gnlint.GnLintDefines, |
| [ |
| CreateTestData("defines", "=", '"-DDEBUG_FLAG"'), |
| CreateTestData("defines", "=", '"DEBUG-FLAG"'), |
| CreateTestData("defines", "=", '"-DTEST_VALUE=1"'), |
| CreateTestData("defines", "=", '"TEST-VALUE=1"'), |
| CreateTestData("defines", "=", '"USE_FLAG"'), |
| ], |
| ) |
| |
| def testGnLintStaticSharedLibMixing(self) -> None: |
| """Verify GnLintStaticSharedLibMixing catches bad inputs.""" |
| # static_library("static_pie") { |
| # configs += [ "//common-mk:pie" ] |
| # } |
| # shared_library("shared") { |
| # deps = [ ":static_pie" ] |
| # } |
| self._CheckLinter( |
| linters.gnlint.GnLintStaticSharedLibMixing, |
| # pylint: disable=line-too-long |
| [ |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "LITERAL", |
| "value": '"static_pie"', |
| } |
| ], |
| "type": "LIST", |
| }, |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "IDENTIFIER", |
| "value": "configs", |
| }, |
| { |
| "child": [ |
| { |
| "type": "LITERAL", |
| "value": ( |
| '"//common-' |
| 'mk:pie"' |
| ), |
| } |
| ], |
| "type": "LIST", |
| }, |
| ], |
| "type": "BINARY", |
| "value": "+=", |
| } |
| ], |
| "type": "BLOCK", |
| }, |
| ], |
| "location": STUB_ERROR_LOCATION, |
| "type": "FUNCTION", |
| "value": "static_library", |
| }, |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "LITERAL", |
| "value": '"shared"', |
| } |
| ], |
| "type": "LIST", |
| }, |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "IDENTIFIER", |
| "value": "deps", |
| }, |
| { |
| "child": [ |
| { |
| "type": "LITERAL", |
| "value": ( |
| '":static_pie"' |
| ), |
| } |
| ], |
| "type": "LIST", |
| }, |
| ], |
| "type": "BINARY", |
| "value": "=", |
| } |
| ], |
| "type": "BLOCK", |
| }, |
| ], |
| "type": "FUNCTION", |
| "value": "shared_library", |
| }, |
| ], |
| "type": "BLOCK", |
| } |
| ], |
| ) |
| |
| # Negative test case which makes linked library PIC. Should be accepted. |
| # static_library("static_pic") { |
| # configs += [ "//common-mk:pic" ] |
| # configs -= [ "//common-mk:pie" ] |
| # } |
| # shared_library("shared") { |
| # deps = [ ":static_pic" ] |
| # } |
| self._CheckLinter( |
| linters.gnlint.GnLintStaticSharedLibMixing, |
| [ |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "LITERAL", |
| "value": '"static_pic"', |
| } |
| ], |
| "type": "LIST", |
| }, |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "IDENTIFIER", |
| "value": "configs", |
| }, |
| { |
| "child": [ |
| { |
| "type": "LITERAL", |
| "value": ( |
| '"//common-' |
| 'mk:pic"' |
| ), |
| } |
| ], |
| "type": "LIST", |
| }, |
| ], |
| "type": "BINARY", |
| "value": "+=", |
| }, |
| { |
| "child": [ |
| { |
| "type": "IDENTIFIER", |
| "value": "configs", |
| }, |
| { |
| "child": [ |
| { |
| "type": "LITERAL", |
| "value": ( |
| '"//common-' |
| 'mk:pie"' |
| ), |
| } |
| ], |
| "type": "LIST", |
| }, |
| ], |
| "type": "BINARY", |
| "value": "-=", |
| }, |
| ], |
| "type": "BLOCK", |
| }, |
| ], |
| "type": "FUNCTION", |
| "value": "static_library", |
| }, |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "LITERAL", |
| "value": '"shared"', |
| } |
| ], |
| "type": "LIST", |
| }, |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "IDENTIFIER", |
| "value": "deps", |
| }, |
| { |
| "child": [ |
| { |
| "type": "LITERAL", |
| "value": ( |
| '":static_pic"' |
| ), |
| } |
| ], |
| "type": "LIST", |
| }, |
| ], |
| "type": "BINARY", |
| "value": "=", |
| } |
| ], |
| "type": "BLOCK", |
| }, |
| ], |
| "type": "FUNCTION", |
| "value": "shared_library", |
| }, |
| ], |
| "type": "BLOCK", |
| } |
| ], |
| is_bad_input=False, |
| ) |
| |
| def testGnLintSourceFileNames(self) -> None: |
| """Verify GnLintSourceFileNames catches bad inputs.""" |
| self._CheckLinter( |
| linters.gnlint.GnLintSourceFileNames, |
| [ |
| CreateTestData("sources", "=", '"foo_unittest.c"'), |
| CreateTestData("sources", "=", '"foo_unittest.cc"'), |
| CreateTestData("sources", "=", '"foo_unittest.h"'), |
| ], |
| ) |
| |
| def testGnLintPkgConfigs(self) -> None: |
| """Verify GnLintPkgConfigs catches bad inputs.""" |
| self._CheckLinter( |
| linters.gnlint.GnLintPkgConfigs, |
| [ |
| CreateTestData("libs", "=", '"z"'), |
| CreateTestData("libs", "=", '"ssl"'), |
| ], |
| ) |
| |
| def testGnLintOrderingWithinTarget(self) -> None: |
| """Verify GnLintOrderingWithinTarget catches bad inputs.""" |
| # static_library("my_static_library") { |
| # configs = [ "foo" ] |
| # sources = [ "bar" ] |
| # } |
| self._CheckLinter( |
| linters.gnlint.GnLintOrderingWithinTarget, |
| [ |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "LITERAL", |
| "value": '"my_static_library"', |
| } |
| ], |
| "type": "LIST", |
| }, |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "IDENTIFIER", |
| "value": "configs", |
| }, |
| { |
| "child": ["foo"], |
| "type": "LIST", |
| }, |
| ], |
| "type": "BINARY", |
| "value": "=", |
| }, |
| { |
| "child": [ |
| { |
| "type": "IDENTIFIER", |
| "value": "sources", |
| }, |
| { |
| "child": ["bar"], |
| "type": "LIST", |
| }, |
| ], |
| "location": STUB_ERROR_LOCATION, |
| "type": "BINARY", |
| "value": "=", |
| }, |
| ], |
| "type": "BLOCK", |
| }, |
| ], |
| "type": "FUNCTION", |
| "value": "static_library", |
| } |
| ], |
| "type": "BLOCK", |
| } |
| ], |
| ) |
| |
| # static_library("my_static_library") { |
| # sources = [ "foo" ] |
| # configs = [ "bar" ] |
| # } |
| self._CheckLinter( |
| linters.gnlint.GnLintOrderingWithinTarget, |
| [ |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "LITERAL", |
| "value": '"my_static_library"', |
| } |
| ], |
| "type": "LIST", |
| }, |
| { |
| "child": [ |
| { |
| "child": [ |
| { |
| "type": "IDENTIFIER", |
| "value": "sources", |
| }, |
| { |
| "child": ["foo"], |
| "type": "LIST", |
| }, |
| ], |
| "type": "BINARY", |
| "value": "=", |
| }, |
| { |
| "child": [ |
| { |
| "type": "IDENTIFIER", |
| "value": "configs", |
| }, |
| { |
| "child": ["bar"], |
| "type": "LIST", |
| }, |
| ], |
| "type": "BINARY", |
| "value": "=", |
| }, |
| ], |
| "type": "BLOCK", |
| }, |
| ], |
| "type": "FUNCTION", |
| "value": "static_library", |
| } |
| ], |
| "type": "BLOCK", |
| } |
| ], |
| is_bad_input=False, |
| ) |
| |
| def testInternalMisquotingUsage(self) -> None: |
| """Verify we raise an internal exception if we're mistreating quotes.""" |
| with self.assertRaises(linters.gnlint.InternalLinterError): |
| linters.gnlint.GnLintInstallPathAlias( |
| CreateInstallPathTestData("executable", "unquoted") |
| ) |
| |
| def testGnLintInstallPathAlias(self) -> None: |
| """Verify GnLintInstallPathAlias catches full path instead of alias.""" |
| self._CheckLinter( |
| linters.gnlint.GnLintInstallPathAlias, |
| [ |
| # executable |
| CreateInstallPathTestData("executable", '"bin"'), |
| CreateInstallPathTestData("executable", '"sbin"'), |
| # shared_liabary |
| CreateInstallPathTestData("shared_library", '"lib"'), |
| # shared_library |
| CreateInstallPathTestData("static_library", '"lib"'), |
| # install_config |
| CreateInstallPathTestData("install_config", '"dbus_system_d"'), |
| CreateInstallPathTestData( |
| "install_config", '"dbus_system_services"' |
| ), |
| CreateInstallPathTestData("install_config", '"miniail_conf"'), |
| CreateInstallPathTestData("install_config", '"seccomp_policy"'), |
| CreateInstallPathTestData("install_config", '"tmpfilesd"'), |
| CreateInstallPathTestData( |
| "install_config", '"tmpfiled_ondemand"' |
| ), |
| CreateInstallPathTestData("install_config", '"upstart"'), |
| # absolute path |
| CreateInstallPathTestData("install_config", '"/test/path"'), |
| ], |
| is_bad_input=False, |
| ) |
| self._CheckLinter( |
| linters.gnlint.GnLintInstallPathAlias, |
| [ |
| # executable |
| CreateInstallPathTestData("executable", '"/bin"'), |
| CreateInstallPathTestData("executable", '"/usr/bin"'), |
| CreateInstallPathTestData("executable", '"/sbin"'), |
| CreateInstallPathTestData("executable", '"/usr/sbin"'), |
| # shared_liabary |
| CreateInstallPathTestData("shared_library", '"/usr/lib"'), |
| CreateInstallPathTestData("shared_library", '"/usr/lib64"'), |
| # shared_library |
| CreateInstallPathTestData("static_library", '"/usr/local/lib"'), |
| # install_config |
| CreateInstallPathTestData( |
| "install_config", '"/etc/dbus-1/system.d"' |
| ), |
| CreateInstallPathTestData( |
| "install_config", '"/usr/share/dbus-1/system-services"' |
| ), |
| CreateInstallPathTestData( |
| "install_config", '"/usr/share/minijail"' |
| ), |
| CreateInstallPathTestData( |
| "install_config", '"/usr/share/policy"' |
| ), |
| CreateInstallPathTestData( |
| "install_config", '"/usr/lib/tmpfiles.d"' |
| ), |
| CreateInstallPathTestData( |
| "install_config", '"/usr/lib/tmpfiles.d/on-demand"' |
| ), |
| CreateInstallPathTestData("install_config", '"/etc/init"'), |
| CreateInstallPathTestData("install_config", '"/etc/init/"'), |
| ], |
| ) |
| |
| def testGnLintDepsOtherProjectDirectly(self) -> None: |
| """Verify GnLintDepsOtherProjectDirectly catches bad inputs. |
| |
| Disallow dependency from other project directly. |
| """ |
| self._CheckLinter( |
| linters.gnlint.GnLintDepsOtherProjectDirectly, |
| [ |
| CreateDepsTestData(['"test1"', '"test2"']), |
| CreateDepsTestData(['"//common-mk"', '"test"']), |
| CreateDepsTestData(['"test"', '"//test_project"']), |
| ], |
| gn_path=Path("platform2/test_project/BUILD.gn"), |
| is_bad_input=False, |
| ) |
| self._CheckLinter( |
| linters.gnlint.GnLintDepsOtherProjectDirectly, |
| [ |
| CreateDepsTestData(['"//platform_camera"', '"test"']), |
| ], |
| gn_path=Path("platform/camera/BUILD.gn"), |
| is_bad_input=False, |
| ) |
| self._CheckLinter( |
| linters.gnlint.GnLintDepsOtherProjectDirectly, |
| [ |
| CreateDepsTestData(['"//test2_project"', '"test"']), |
| CreateDepsTestData(['"//test_project"', '"//test2_project"']), |
| ], |
| gn_path=Path("platform2/test_project/BUILD.gn"), |
| ) |
| self._CheckLinter( |
| linters.gnlint.GnLintDepsOtherProjectDirectly, |
| [ |
| CreateDepsTestData(['"//platform_camera"', '"test"']), |
| ], |
| gn_path=Path("platform2/camera/BUILD.gn"), |
| ) |
| |
| def testGnLintNoIfDefinedUseVars(self) -> None: |
| """Verify GnLintNoIfDefinedUseVars catches bad inputs.""" |
| self._CheckLinter( |
| linters.gnlint.GnLintNoIfDefinedUseVars, |
| [ |
| { |
| "child": [ |
| { |
| "begin_token": "(", |
| "child": [ |
| { |
| "accessor_kind": "member", |
| "child": [ |
| { |
| "location": STUB_ERROR_LOCATION, |
| "type": "IDENTIFIER", |
| "value": "kernel_5_15", |
| } |
| ], |
| "location": STUB_ERROR_LOCATION, |
| "type": "ACCESSOR", |
| "value": "use", |
| } |
| ], |
| "end": { |
| "location": STUB_ERROR_LOCATION, |
| "type": "END", |
| "value": ")", |
| }, |
| "location": STUB_ERROR_LOCATION, |
| "type": "LIST", |
| } |
| ], |
| "location": STUB_ERROR_LOCATION, |
| "type": "FUNCTION", |
| "value": "defined", |
| }, |
| ], |
| ) |
| |
| def testGnLintDepsRelativePath(self) -> None: |
| """Verify GnLintDepsRelativePath catches bad inputs. |
| |
| Disallow relative path to depend on other project. |
| """ |
| self._CheckLinter( |
| linters.gnlint.GnLintDepsRelativePath, |
| [ |
| CreateDepsTestData(['"//common-mk"', '"test"']), |
| ], |
| is_bad_input=False, |
| ) |
| self._CheckLinter( |
| linters.gnlint.GnLintDepsRelativePath, |
| [ |
| CreateDepsTestData( |
| ['"//common-mk"', '"test"', '"../other_project/targets"'] |
| ), |
| ], |
| ) |