Repository: MarketSquare/robotframework-robocop (python)

Issue:
[Bug] Providing `--argumentfile` is unuseful when default `.robocop` file exist
### What happened?

If default .robocop file exist, the another config file witch is set as  `--argumentfile` from command line, is ignored. So I can't execute robocop with other configurations if default .robocop file exist in main directory.

### Operating System

Linux

### Robocop version

2.5.0, 2.6.0

Pull request:
Refactor Config class to override default configuration file
Fixes #751

Now if user run:

```
robocop --verbose
```
it will use configuration from both cli and default configuration file (if it exists). This works like before.

When user run:

```
robocop --argumentfile path/to/file.txt
```
It will only use configuration from the cli and configuration file passed using ``--argumentfile`` (default configuration file will not be loaded).

Patch:
diff --git a/docs/releasenotes/2.7.0.rst b/docs/releasenotes/2.7.0.rst
new file mode 100644
index 0000000..d97789a
--- /dev/null
+++ b/docs/releasenotes/2.7.0.rst
@@ -0,0 +1,29 @@
+Robocop 2.7.0
+================
+
+You can install the latest available version by running::
+
+    pip install --upgrade robotframework-robocop
+
+or to install exactly this version::
+
+    pip install robotframework-robocop==2.7.0
+
+
+File configuration changes
+---------------------------
+
+We addressed several smaller issues and incoherence with Robocop file configuration.
+
+Overriding default configuration file
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When you're using Robocop from the command line it reads both the cli arguments and default
+configuration file (found in the disk). The default configuration file (either ``.robocop`` or ``pyproject.toml`` file)
+is used as a base that can be overridden by the cli arguments. The problem with the previous implementation was
+that when user specified path to argument file in the cli::
+
+    robocop --argumentfile myconfig.txt
+
+Robocop would read both default configuration file and configuration file from ``--argumentfile``. Now it will read
+default configuration file only if ``-A / --argumentfile`` options are not used.
diff --git a/docs/user_guide.rst b/docs/user_guide.rst
index 57804a9..3ecab1c 100644
--- a/docs/user_guide.rst
+++ b/docs/user_guide.rst
@@ -22,27 +22,33 @@ source code. More in :ref:`including-rules`.
 
 Loading configuration from file
 -------------------------------
-.. dropdown:: How to load configuratiom from file
+.. dropdown:: How to load configuration from the file
 
-    You can load arguments for Robocop from file with ``--argumentfile / -A`` option and path to argument file::
+    Robocop supports two formats of the configuration file: argument files and toml files. If argument file is not
+    provided using CLI, Robocop will try to find default configuration file using the following algorithm:
 
-        robocop --argumentfile argument_file.txt
-        robocop -A path/to/file.txt
+    - if the directory contains ``.robocop`` file, load it
+    - otherwise, if the directory contains ``pyproject.toml`` file, load it
+    - otherwise, go to parent directory. Stop search if ``.git`` or top disk directory is found
 
-    If no arguments are provided to Robocop it will try to find ``.robocop`` file and load it from there.
-    It will start looking from current directory and go up until it founds it or '.git' file is found. ``.robocop`` file
-    supports the same syntax as given from CLI::
+    .. dropdown:: ``.robocop`` argument file
 
-        --include rulename
-        # inline comment
-        --reports all
+        Argument file supports the same syntax as given from the CLI::
 
-    If there is no ``.robocop`` file present it will try to load ``pyproject.toml`` file (if there is toml module installed).
-    Robocop use [tool.robocop] section. Options have the same names as CLI arguments.
+            --include rulename
+            # inline comment
+            --reports all
 
-    .. dropdown:: Example pyproject.toml configuration file
+        You can load arguments for Robocop from file with ``--argumentfile / -A`` option and path to the argument file::
 
-        ::
+            robocop --argumentfile argument_file.txt
+            robocop -A path/to/file.txt
+
+    .. dropdown:: ``pyproject.toml`` configuration file
+
+        Robocop use [tool.robocop] section. Options have the same names as the CLI arguments.
+
+        Example pyproject.toml configuration file::
 
             [tool.robocop]
             paths = [
diff --git a/robocop/config.py b/robocop/config.py
index c8eacb0..56a3055 100644
--- a/robocop/config.py
+++ b/robocop/config.py
@@ -86,7 +86,6 @@ class Config:
     def __init__(self, root=None, from_cli: bool = False):
         self.from_cli = from_cli
         self.exec_dir = os.path.abspath(".")
-        self.root = Path(root) if root is not None else root
         self.include = set()
         self.exclude = set()
         self.ignore = set()
@@ -108,8 +107,8 @@ class Config:
         self.recursive = True
         self.verbose = False
         self.config_from = ""
-        self.parser = self._create_parser()
-        self.parse_opts(from_cli=from_cli)
+        self.root = find_project_root(root, ["."])
+        self.parse()
 
     def remove_severity(self):
         self.include = {self.replace_severity_values(rule) for rule in self.include}
@@ -184,6 +183,7 @@ class Config:
             "--no-recursive",
             dest="recursive",
             action="store_false",
+            default=self.recursive,
             help="Use this flag to stop scanning directories recursively.",
         )
         optional.add_argument(
@@ -303,32 +303,42 @@ class Config:
             help="Display Robocop version.",
         )
         optional.add_argument(
-            "-vv", "--verbose", action="store_true", help="Display extra information during execution."
+            "-vv",
+            "--verbose",
+            action="store_true",
+            default=self.verbose,
+            help="Display extra information during execution.",
         )
         optional.add_argument(
             "--directives",
             action="version",
-            version="1. Serve the public trust\n2. Protect the innocent\n3. Uphold the law\n4. [ACCESS " "DENIED]",
+            version="1. Serve the public trust\n2. Protect the innocent\n3. Uphold the law\n4. [ACCESS DENIED]",
             help=argparse.SUPPRESS,
         )
 
         return parser
 
-    def parse_opts(self, args=None, from_cli: bool = True):
-        if self.root is None:
-            self.root = find_project_root(self.paths)
-        self.load_default_config_file()
+    def parse(self):
+        if not self.from_cli:
+            self.load_default_config_file()
+            return
+        args = sys.argv[1:]
+        if not self.argument_file_in_cli(args):
+            self.load_default_config_file()
+        self.parse_args(args)
 
-        if from_cli:
-            args = self.parse_args(args)
-        else:
-            args = None
+    def argument_file_in_cli(self, args):
+        argument_options = {"-A", "--argumentfile"}
+        for arg in args:
+            if arg in argument_options:
+                return True
+        return False
 
+    def reload(self, rules):
         self.remove_severity()
         self.translate_patterns()
         self.print_config_source()
-
-        return args
+        self.validate_rule_names(rules)
 
     def print_config_source(self):
         # We can only print after reading all configs, since self.verbose is unknown before we read it from config
@@ -349,7 +359,7 @@ class Config:
         robocop_path = find_file_in_project_root(".robocop", self.root)
         if not robocop_path.is_file():
             return False
-        args = self.load_args_from_file(robocop_path)
+        args = self.load_argument_file(robocop_path)
         self.parse_args(args)
         return True
 
@@ -368,24 +378,17 @@ class Config:
             self.config_from = pyproject_path
 
     def parse_args_to_config(self, args):
-        if args is None:
-            return None
-
-        args = self.parser.parse_args(args)
+        parser = self._create_parser()
+        args = parser.parse_args(args)
         for key, value in dict(**vars(args)).items():
             if key in self.__dict__:
                 self.__dict__[key] = value
 
-        return args
-
     def parse_args(self, args):
         args = self.preparse(args)
-        if args:
-            args = self.parse_args_to_config(args)
-        return args
+        self.parse_args_to_config(args)
 
     def preparse(self, args):
-        args = sys.argv[1:] if args is None else args
         parsed_args = []
         args = (arg for arg in args)
         for arg in args:
@@ -394,12 +397,12 @@ class Config:
                     argfile = next(args)
                 except StopIteration:
                     raise ArgumentFileNotFoundError("") from None
-                parsed_args += self.load_args_from_file(argfile)
+                parsed_args += self.load_argument_file(argfile)
             else:
                 parsed_args.append(arg)
         return parsed_args
 
-    def load_args_from_file(self, argfile):
+    def load_argument_file(self, argfile):
         try:
             with FileReader(argfile) as arg_f:
                 args = []
@@ -428,7 +431,11 @@ class Config:
 
     def validate_rule_names(self, rules):
         # add rule name in form of old_name: new_name
-        deprecated = {"uneven-indent": "bad-indent", "could-be-forced-tags": "could-be-test-tags", "tag-already-set-in-force-tags": "tag-already-set-in-test-tags"}
+        deprecated = {
+            "uneven-indent": "bad-indent",
+            "could-be-forced-tags": "could-be-test-tags",
+            "tag-already-set-in-force-tags": "tag-already-set-in-test-tags",
+        }
         for rule in chain(self.include, self.exclude):
             if rule in deprecated:  # update warning description to specific case
                 print(
diff --git a/robocop/files.py b/robocop/files.py
index 5e0177a..853a9ef 100644
--- a/robocop/files.py
+++ b/robocop/files.py
@@ -8,13 +8,15 @@ from robocop.exceptions import FileError
 DEFAULT_EXCLUDES = r"(\.direnv|\.eggs|\.git|\.hg|\.nox|\.tox|\.venv|venv|\.svn)"
 
 
-def find_project_root(srcs):
-    """Return a directory containing .git, .robocop or pyproject.toml.
-    That directory will be a common parent of all files and directories
-    passed in `srcs`.
-    If no directory in the tree contains a marker that would specify it's the
-    project root, the root of the file system is returned.
+def find_project_root(root, srcs):
     """
+    Find project root.
+    If not provided in ``root`` argument, the first parent directory containing either .git, .robocop or pyproject.toml
+    file in any of  ``srcs`` paths will be root category.
+    If not found, returns the root of the file system.
+    """
+    if root is not None:
+        return Path(root)
     if not srcs:
         return Path("/").resolve()
 
diff --git a/robocop/run.py b/robocop/run.py
index 87f41a6..408ad88 100644
--- a/robocop/run.py
+++ b/robocop/run.py
@@ -62,7 +62,7 @@ class Robocop:
     def reload_config(self):
         """Reload checkers and reports based on current config"""
         self.load_checkers()
-        self.config.validate_rule_names(self.rules)
+        self.config.reload(self.rules)
         self.load_reports()
         self.configure_checkers_or_reports()
         self.check_for_disabled_rules()


Test patch:
diff --git a/tests/atest/utils/__init__.py b/tests/atest/utils/__init__.py
index 8577c40..8b9fbc1 100644
--- a/tests/atest/utils/__init__.py
+++ b/tests/atest/utils/__init__.py
@@ -70,7 +70,7 @@ def configure_robocop_with_rule(args, runner, rule, path, src_files: Optional[Li
             *paths,
         ]
     )
-    config.parse_opts(arguments)
+    config.parse_args(arguments)
     runner.config = config
     return runner
 
diff --git a/tests/e2e/test_e2e.py b/tests/e2e/test_e2e.py
index c6cd237..bf3bec4 100644
--- a/tests/e2e/test_e2e.py
+++ b/tests/e2e/test_e2e.py
@@ -1,6 +1,5 @@
 """ General E2E tests to catch any general issue in Robocop """
 
-import importlib
 import sys
 from pathlib import Path
 from unittest import mock
@@ -41,8 +40,8 @@ INVALID_TEST_DATA = Path(__file__).parent.parent / "test_data_invalid"
 
 
 def should_run_with_config(robocop_instance, cfg):
-    config = Config()
-    config.parse_opts(cfg.split())
+    with mock.patch.object(sys, "argv", ["robocop", *cfg.split()]):
+        config = Config(from_cli=True)
     robocop_instance.config = config
     with pytest.raises(SystemExit):
         robocop_instance.run()
@@ -50,12 +49,10 @@ def should_run_with_config(robocop_instance, cfg):
 
 
 def configure_robocop(robocop_instance, args):
-    config = Config()
-    config.parse_opts(args.split())
+    with mock.patch.object(sys, "argv", ["robocop", *args.split()]):
+        config = Config(from_cli=True)
     robocop_instance.config = config
-    robocop_instance.load_checkers()
-    robocop_instance.load_reports()
-    robocop_instance.configure_checkers_or_reports()
+    robocop_instance.reload_config()
 
 
 class TestE2E:
@@ -85,7 +82,7 @@ class TestE2E:
 
     def test_run_non_existing_file(self, robocop_instance):
         config = Config()
-        config.parse_opts(["some_path"])
+        config.paths = ["some_path"]
         robocop_instance.config = config
         with pytest.raises(FileError) as err:
             robocop_instance.run()
@@ -138,7 +135,7 @@ class TestE2E:
     def test_include_exclude_invalid_rule(self, robocop_instance, rules, expected):
         for method in ("--include", "--exclude"):
             config = Config()
-            config.parse_opts([method, rules, "."])
+            config.parse_args([method, rules, "."])
             robocop_instance.config = config
             with pytest.raises(ConfigGeneralError) as err:
                 robocop_instance.reload_config()
@@ -167,25 +164,25 @@ class TestE2E:
 
     def test_use_argument_file(self, robocop_instance, test_data_dir):
         config = Config()
-        config.parse_opts(["-A", str(test_data_dir / "argument_file" / "args.txt")])
+        config.parse_args(["-A", str(test_data_dir / "argument_file" / "args.txt")])
 
     def test_use_not_existing_argument_file(self, test_data_dir):
         config = Config()
         with pytest.raises(ArgumentFileNotFoundError) as err:
-            config.parse_opts(["--argumentfile", "some_file", str(test_data_dir)])
+            config.parse_args(["--argumentfile", "some_file", str(test_data_dir)])
         assert 'Argument file "some_file" does not exist' in str(err)
 
     def test_argument_file_without_path(self):
         config = Config()
         with pytest.raises(ArgumentFileNotFoundError) as err:
-            config.parse_opts(["--argumentfile"])
+            config.parse_args(["--argumentfile"])
         assert 'Argument file "" does not exist' in str(err)
 
     def test_use_nested_argument_file(self, test_data_dir):
         config = Config()
         nested_args_path = str(test_data_dir / "argument_file" / "args_nested.txt")
         with pytest.raises(NestedArgumentFileError) as err:
-            config.parse_opts(["-A", nested_args_path, str(test_data_dir)])
+            config.parse_args(["-A", nested_args_path, str(test_data_dir)])
         assert "Nested argument file in " in str(err)
 
     @pytest.mark.parametrize("threshold", ["i", "I", "e", "error", "W", "WARNING"])
diff --git a/tests/utest/test_argument_validation.py b/tests/utest/test_argument_validation.py
index 85eca6e..8905e07 100644
--- a/tests/utest/test_argument_validation.py
+++ b/tests/utest/test_argument_validation.py
@@ -14,10 +14,12 @@ def config():
 
 class TestArgumentValidation:
     def test_prog_name(self, config):
-        assert config.parser.prog == "robocop"
+        parser = config._create_parser()
+        assert parser.prog == "robocop"
 
     def test_parser_default_help_disabled(self, config):
-        assert not config.parser.add_help
+        parser = config._create_parser()
+        assert not parser.add_help
 
     def test_default_args(self, config):
         assert config.filetypes == {".resource", ".robot", ".tsv"}
@@ -31,101 +33,101 @@ class TestArgumentValidation:
         assert not config.list_reports
 
     def test_default_args_after_parse(self, config):
-        args = config.parse_opts([""])
-        assert args.filetypes == {".resource", ".robot", ".tsv"}
-        assert args.include == set()
-        assert args.exclude == set()
-        assert args.reports == ["return_status"]
-        assert args.configure == []
-        assert args.format == "{source}:{line}:{col} [{severity}] {rule_id} {desc} ({name})"
-        assert args.paths == [""]
-        assert args.output is None
+        config.parse_args([""])
+        assert config.filetypes == {".resource", ".robot", ".tsv"}
+        assert config.include == set()
+        assert config.exclude == set()
+        assert config.reports == ["return_status"]
+        assert config.configure == []
+        assert config.format == "{source}:{line}:{col} [{severity}] {rule_id} {desc} ({name})"
+        assert config.paths == [""]
+        assert config.output is None
 
     def test_filetypes_duplicate_defaults(self, config):
-        args = config.parse_opts(["--filetypes", "robot,resource", ""])
-        assert args.filetypes == {".resource", ".robot", ".tsv"}
+        config.parse_args(["--filetypes", "robot,resource", ""])
+        assert config.filetypes == {".resource", ".robot", ".tsv"}
 
     def test_filetypes_duplicate_dot_prefixed_defaults(self, config):
-        args = config.parse_opts(["--filetypes", ".robot,.resource", ""])
-        assert args.filetypes == {".resource", ".robot", ".tsv"}
+        config.parse_args(["--filetypes", ".robot,.resource", ""])
+        assert config.filetypes == {".resource", ".robot", ".tsv"}
 
     def test_include_one_rule(self, config):
         rule_name = "missing-doc-keyword"
-        args = config.parse_opts(["--include", rule_name, ""])
-        assert args.include == {rule_name}
+        config.parse_args(["--include", rule_name, ""])
+        assert config.include == {rule_name}
 
     def test_include_two_same_rules_comma_separated(self, config):
         rule_name = "missing-doc-keyword"
-        args = config.parse_opts(["--include", ",".join([rule_name, rule_name]), ""])
-        assert args.include == {rule_name}
+        config.parse_args(["--include", ",".join([rule_name, rule_name]), ""])
+        assert config.include == {rule_name}
 
     def test_include_two_same_rules_provided_separately(self, config):
         rule_name = "missing-doc-keyword"
-        args = config.parse_opts(["--include", rule_name, "--include", rule_name, ""])
-        assert args.include == {rule_name}
+        config.parse_args(["--include", rule_name, "--include", rule_name, ""])
+        assert config.include == {rule_name}
 
     def test_include_two_different_rules_comma_separated(self, config):
         rule_name1 = "missing-doc-keyword"
         rule_name2 = "not-allowed-char-in-name"
         rules_names = ",".join([rule_name1, rule_name2])
-        args = config.parse_opts(["--include", rules_names, ""])
-        assert args.include == {rule_name1, rule_name2}
+        config.parse_args(["--include", rules_names, ""])
+        assert config.include == {rule_name1, rule_name2}
 
     def test_include_two_different_rules_provided_separately(self, config):
         rule_name1 = "missing-doc-keyword"
         rule_name2 = "not-allowed-char-in-name"
-        args = config.parse_opts(["--include", rule_name1, "--include", rule_name2, ""])
-        assert args.include == {rule_name1, rule_name2}
+        config.parse_args(["--include", rule_name1, "--include", rule_name2, ""])
+        assert config.include == {rule_name1, rule_name2}
 
     def test_exclude_one_rule(self, config):
         rule_name = "missing-doc-keyword"
-        args = config.parse_opts(["--exclude", rule_name, ""])
-        assert args.exclude == {rule_name}
+        config.parse_args(["--exclude", rule_name, ""])
+        assert config.exclude == {rule_name}
 
     def test_exclude_two_same_rules_comma_separated(self, config):
         rule_name = "missing-doc-keyword"
-        args = config.parse_opts(["--exclude", ",".join([rule_name, rule_name]), ""])
-        assert args.exclude == {rule_name}
+        config.parse_args(["--exclude", ",".join([rule_name, rule_name]), ""])
+        assert config.exclude == {rule_name}
 
     def test_exclude_two_same_rules_provided_separately(self, config):
         rule_name = "missing-doc-keyword"
-        args = config.parse_opts(["--exclude", rule_name, "--exclude", rule_name, ""])
-        assert args.exclude == {rule_name}
+        config.parse_args(["--exclude", rule_name, "--exclude", rule_name, ""])
+        assert config.exclude == {rule_name}
 
     def test_exclude_two_different_rules_comma_separated(self, config):
         rule_name1 = "missing-doc-keyword"
         rule_name2 = "not-allowed-char-in-name"
         rules_names = ",".join([rule_name1, rule_name2])
-        args = config.parse_opts(["--exclude", rules_names, ""])
-        assert args.exclude == {rule_name1, rule_name2}
+        config.parse_args(["--exclude", rules_names, ""])
+        assert config.exclude == {rule_name1, rule_name2}
 
     def test_exclude_two_different_rules_provided_separately(self, config):
         rule_name1 = "missing-doc-keyword"
         rule_name2 = "not-allowed-char-in-name"
-        args = config.parse_opts(["--exclude", rule_name1, "--exclude", rule_name2, ""])
-        assert args.exclude == {rule_name1, rule_name2}
+        config.parse_args(["--exclude", rule_name1, "--exclude", rule_name2, ""])
+        assert config.exclude == {rule_name1, rule_name2}
 
     def test_format_overwrite_default(self, config):
         default_format = "{source}:{line}:{col} [{severity}] {rule_id} {desc}"
-        args = config.parse_opts(["--format", default_format, ""])
-        assert args.format == default_format
+        config.parse_args(["--format", default_format, ""])
+        assert config.format == default_format
 
     def test_format_empty(self, config):
         empty_format = ""
-        args = config.parse_opts(["--format", empty_format, ""])
-        assert args.format == ""
+        config.parse_args(["--format", empty_format, ""])
+        assert config.format == ""
 
     def test_format_new_value(self, config):
         new_format = "{source}: {rule_id} {desc}"
-        args = config.parse_opts(["--format", new_format, ""])
-        assert args.format == new_format
+        config.parse_args(["--format", new_format, ""])
+        assert config.format == new_format
 
     def test_output_new_value(self, config):
         output_file = "results"
-        args = config.parse_opts(["--output", output_file, ""])
-        assert isinstance(args.output, io.TextIOWrapper)
-        assert args.output.name == output_file
-        assert args.output.mode == "w"
+        config.parse_args(["--output", output_file, ""])
+        assert isinstance(config.output, io.TextIOWrapper)
+        assert config.output.name == output_file
+        assert config.output.mode == "w"
         assert pathlib.Path(output_file).exists()
         # parser will not close the file itself
         if not config.output.closed:
@@ -136,33 +138,33 @@ class TestArgumentValidation:
     @pytest.mark.parametrize("cmd", ["-h", "--help"])
     def test_help_message(self, config, cmd, capsys):
         with pytest.raises(SystemExit):
-            config.parse_opts([cmd])
+            config.parse_args([cmd])
         out, _ = capsys.readouterr()
         assert "usage:" in out
 
     @pytest.mark.parametrize("cmd", ["-v", "--version"])
     def test_version_number(self, config, cmd, capsys):
         with pytest.raises(SystemExit):
-            config.parse_opts(["-v"])
+            config.parse_args(["-v"])
         out, _ = capsys.readouterr()
         assert __version__ in out
 
     def test_paths_new_value(self, config):
-        args = config.parse_opts(["tests.robot"])
-        assert args.paths == ["tests.robot"]
+        config.parse_args(["tests.robot"])
+        assert config.paths == ["tests.robot"]
 
     def test_paths_two_values(self, config):
-        args = config.parse_opts(["tests.robot", "test2.robot"])
-        assert args.paths == ["tests.robot", "test2.robot"]
+        config.parse_args(["tests.robot", "test2.robot"])
+        assert config.paths == ["tests.robot", "test2.robot"]
 
     def test_list_reports(self, config):
-        args = config.parse_opts(["--list-reports"])
-        assert args.list_reports
+        config.parse_args(["--list-reports"])
+        assert config.list_reports
 
     def test_single_language(self, config):
-        args = config.parse_opts(["--lang", "fi"])
-        assert ["fi"] == args.language
+        config.parse_args(["--lang", "fi"])
+        assert ["fi"] == config.language
 
     def test_two_languages(self, config):
-        args = config.parse_opts(["--lang", "fi,pl"])
-        assert ["fi", "pl"] == args.language
+        config.parse_args(["--lang", "fi,pl"])
+        assert ["fi", "pl"] == config.language
diff --git a/tests/utest/test_default_config.py b/tests/utest/test_default_config.py
index 6a3d600..939981c 100644
--- a/tests/utest/test_default_config.py
+++ b/tests/utest/test_default_config.py
@@ -61,6 +61,7 @@ class TestDefaultConfig:
         src = path_to_test_data / "default_config"
         with working_directory(src), patch.object(sys, "argv", ["prog", "--verbose"]):
             config = Config(from_cli=True)
+        config.print_config_source()
         out, _ = capsys.readouterr()
         assert out == f"Loaded configuration from {config.config_from}\n"
 
@@ -155,6 +156,7 @@ class TestDefaultConfig:
         src = path_to_test_data / "only_pyproject"
         with working_directory(src), patch.object(sys, "argv", ["prog", "--verbose"]):
             config = Config(from_cli=True)
+        config.print_config_source()
         out, _ = capsys.readouterr()
         assert out == f"Loaded configuration from {config.config_from}\n"
 
@@ -177,7 +179,8 @@ class TestDefaultConfig:
     def test_load_empty_config(self, path_to_test_data, capsys, config_dir):
         src = path_to_test_data / config_dir
         with working_directory(src), patch.object(sys, "argv", ["prog", "--verbose"]):
-            Config(from_cli=True)
+            config = Config(from_cli=True)
+        config.print_config_source()
         out, _ = capsys.readouterr()
         assert out == "No config file found or configuration is empty. Using default configuration\n"
 
@@ -194,7 +197,7 @@ class TestDefaultConfig:
         pyproject.toml resolves relative path to config directory.
         For example if root/pyproject.toml contains test.py, it will become root/test.py
         """
-        src = path_to_test_data / f"relative_path_in_config_pyproject"
+        src = path_to_test_data / "relative_path_in_config_pyproject"
         work_dir = src / "nested"
         with working_directory(work_dir), patch.object(sys, "argv", ["robocop"]):
             config = Config(from_cli=True)
@@ -209,9 +212,23 @@ class TestDefaultConfig:
         and you're running robocop from root/nested,
         it will become root/nested/test.py
         """
-        src = path_to_test_data / f"relative_path_in_config_robocop"
+        src = path_to_test_data / "relative_path_in_config_robocop"
         work_dir = src / "nested"
         with working_directory(work_dir), patch.object(sys, "argv", ["robocop"]):
             config = Config(from_cli=True)
             ext_rule_path = config.ext_rules.pop()
             assert Path(ext_rule_path).absolute() == work_dir / "test.py"
+
+    def test_override_default_config(self, path_to_test_data):
+        """
+        Default config should not be loaded if "--argumentfile" option is used.
+        """
+        default_config = path_to_test_data / "only_pyproject"
+        other_config = path_to_test_data / "default_config_and_pyproject" / ".robocop"
+        for option_name in ("-A", "--argumentfile"):
+            with working_directory(default_config), patch.object(
+                sys, "argv", ["robocop", option_name, str(other_config)]
+            ):
+                config = Config(from_cli=True)
+            assert str(config.config_from) == str(other_config)
+            assert config.include == {"0810"}
diff --git a/tests/utest/test_thresholds.py b/tests/utest/test_thresholds.py
index 06f25fa..49bcf32 100644
--- a/tests/utest/test_thresholds.py
+++ b/tests/utest/test_thresholds.py
@@ -49,7 +49,8 @@ class TestRuleSeverityThreshold:
     def test_invalid_threshold_config(self):
         thresholds = SeverityThreshold("line_length")
         exp_error = (
-            "Invalid severity value 'error'. " "It should be list of `severity=param_value` pairs, separated by `:`."
+            "Invalid configuration for Robocop:\n"
+            "Invalid severity value 'error'. It should be list of `severity=param_value` pairs, separated by `:`."
         )
         with pytest.raises(robocop.exceptions.InvalidArgumentError, match=exp_error):
             thresholds.value = "error"