diff --git a/src/cfgnet/plugins/concept/cargo_plugin.py b/src/cfgnet/plugins/concept/cargo_plugin.py
new file mode 100644
index 0000000..654a2f7
--- /dev/null
+++ b/src/cfgnet/plugins/concept/cargo_plugin.py
@@ -0,0 +1,56 @@
+# This file is part of the CfgNet module.
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see .
+from cfgnet.plugins.file_type.toml_plugin import TomlPlugin
+from cfgnet.config_types.config_types import ConfigType
+
+
+class CargoPlugin(TomlPlugin):
+ def __init__(self):
+ super().__init__("cargo")
+ self.excluded_keys = [
+ "description",
+ "authors",
+ "maintainers",
+ "readme",
+ "keywords",
+ "classifiers",
+ ]
+
+ def is_responsible(self, abs_file_path: str) -> bool:
+ if abs_file_path.endswith("Cargo.toml"):
+ return True
+ return False
+
+ @staticmethod
+ def get_config_type(option_name: str) -> ConfigType:
+ """
+ Find config type based on option name.
+
+ :param option_name: name of option
+ :return: config type
+ """
+ if option_name in (
+ "homepage",
+ "repository",
+ "documentation",
+ "urls",
+ "url",
+ ):
+ return ConfigType.URL
+ if option_name in ("include", "exclude"):
+ return ConfigType.PATH
+ if option_name in ("version", "dependencies", "dev-dependencies"):
+ return ConfigType.VERSION_NUMBER
+ return ConfigType.UNKNOWN
diff --git a/src/cfgnet/plugins/file_type/toml_plugin.py b/src/cfgnet/plugins/file_type/toml_plugin.py
index c9878a7..3df1832 100644
--- a/src/cfgnet/plugins/file_type/toml_plugin.py
+++ b/src/cfgnet/plugins/file_type/toml_plugin.py
@@ -87,31 +87,10 @@ def _iter_data(self, data, line_number_dict, parent):
if isinstance(value, dict):
self._iter_data(value, line_number_dict, option)
elif isinstance(value, list):
- index = 0
- for entry in value:
- if isinstance(entry, dict):
- virtual_option = OptionNode(
- option.name + "_" + str(index), lineno
- )
- option.add_child(virtual_option)
- self._iter_data(
- entry, line_number_dict, virtual_option
- )
- index += 1
- else:
- name = (
- f"{option.name}:{entry}"
- if option.config_type
- == ConfigType.VERSION_NUMBER
- else entry
- )
- option.add_child(ValueNode(name))
+ value_node = ValueNode(name=str(value))
+ option.add_child(value_node)
else:
- name = (
- f"{option.name}:{value}"
- if option.config_type == ConfigType.VERSION_NUMBER
- else value
- )
+ name = value
option.add_child(ValueNode(name))
# pylint: disable=unused-argument
diff --git a/src/cfgnet/plugins/plugin_manager.py b/src/cfgnet/plugins/plugin_manager.py
index 0896c8a..bef4f9d 100644
--- a/src/cfgnet/plugins/plugin_manager.py
+++ b/src/cfgnet/plugins/plugin_manager.py
@@ -52,6 +52,7 @@
from cfgnet.plugins.concept.angular_plugin import AngularPlugin
from cfgnet.plugins.concept.mapreduce_plugin import MapReducePlugin
from cfgnet.plugins.concept.circleci_plugin import CircleCiPlugin
+from cfgnet.plugins.concept.cargo_plugin import CargoPlugin
class PluginManager:
@@ -85,6 +86,7 @@ class PluginManager:
AngularPlugin(),
MapReducePlugin(),
CircleCiPlugin(),
+ CargoPlugin(),
]
file_type_plugins: List[Plugin] = [
diff --git a/tests/cfgnet/plugins/concept/test_cargo_plugin.py b/tests/cfgnet/plugins/concept/test_cargo_plugin.py
new file mode 100644
index 0000000..45efb12
--- /dev/null
+++ b/tests/cfgnet/plugins/concept/test_cargo_plugin.py
@@ -0,0 +1,85 @@
+# This file is part of the CfgNet module.
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see .
+import os
+import pytest
+
+from cfgnet.plugins.concept.cargo_plugin import CargoPlugin
+from cfgnet.config_types.config_types import ConfigType
+from tests.utility.id_creator import make_id
+
+
+@pytest.fixture(name="get_plugin")
+def get_plugin_():
+ plugin = CargoPlugin()
+ return plugin
+
+
+def test_is_responsible(get_plugin):
+ plugin = get_plugin
+
+ assert plugin.is_responsible("tests/files/Cargo.toml")
+ assert not plugin.is_responsible("tests/files/test.toml")
+
+
+def test_parse_pyproject_file(get_plugin):
+ plugin = get_plugin
+ file = os.path.abspath("tests/files/Cargo.toml")
+
+ artifact = plugin.parse_file(file, "Cargo.toml")
+ nodes = artifact.get_nodes()
+ ids = {node.id for node in nodes}
+
+ assert artifact is not None
+ assert len(nodes) == 13
+
+ assert make_id("Cargo.toml", "file", "Cargo.toml") in ids
+ assert make_id("Cargo.toml", "package", "name", "example") in ids
+ assert make_id("Cargo.toml", "package", "version", "0.1.0") in ids
+ assert make_id("Cargo.toml", "package", "edition", "2021") in ids
+ assert make_id("Cargo.toml", "package", "license", "MIT") in ids
+ assert make_id("Cargo.toml", "package", "homepage", "https://example.com") in ids
+ assert make_id("Cargo.toml", "package", "workspace", "path/to/workspace/root") in ids
+ assert make_id("Cargo.toml", "dependencies", "serde", "1.0") in ids
+ assert make_id("Cargo.toml", "dependencies", "rand", "0.8") in ids
+ assert make_id("Cargo.toml", "dev-dependencies", "tokio", "version", "1") in ids
+ assert make_id("Cargo.toml", "dev-dependencies", "tokio", "features", "['full']") in ids
+ assert make_id("Cargo.toml", "features", "default", "['serde']") in ids
+ assert make_id("Cargo.toml", "profile", "release", "opt-level", "3") in ids
+
+
+def test_config_types(get_plugin):
+ plugin = get_plugin
+ file = os.path.abspath("tests/files/Cargo.toml")
+
+ artifact = plugin.parse_file(file, "Cargo.toml")
+ nodes = artifact.get_nodes()
+
+ name_node = next(filter(lambda x: x.id == make_id("Cargo.toml", "package", "name", "example"), nodes))
+ path_node = next(filter(lambda x: x.id == make_id("Cargo.toml", "package", "workspace", "path/to/workspace/root"), nodes))
+ number_node = next(filter(lambda x: x.id == make_id("Cargo.toml", "package", "edition", "2021"), nodes))
+ dep_node = next(filter(lambda x: x.id == make_id("Cargo.toml", "dependencies", "serde", "1.0"), nodes))
+ url_node = next(filter(lambda x: x.id == make_id("Cargo.toml", "package", "homepage", "https://example.com"), nodes))
+ version_node = next(filter(lambda x: x.id == make_id("Cargo.toml", "package", "version", "0.1.0"), nodes))
+ license_node = next(filter(lambda x: x.id == make_id("Cargo.toml", "package", "license", "MIT"), nodes))
+ number_node2 = next(filter(lambda x: x.id == make_id("Cargo.toml", "profile", "release", "opt-level", "3"), nodes))
+
+ assert path_node.config_type == ConfigType.PATH
+ assert url_node.config_type == ConfigType.URL
+ assert license_node.config_type == ConfigType.LICENSE
+ assert dep_node.config_type == ConfigType.VERSION_NUMBER
+ assert number_node.config_type == ConfigType.NUMBER
+ assert version_node.config_type == ConfigType.VERSION_NUMBER
+ assert name_node.config_type == ConfigType.NAME
+ assert number_node2.config_type == ConfigType.NUMBER
diff --git a/tests/cfgnet/plugins/concept/test_pyproject_plugin.py b/tests/cfgnet/plugins/concept/test_pyproject_plugin.py
index 75eddd7..aeaf280 100644
--- a/tests/cfgnet/plugins/concept/test_pyproject_plugin.py
+++ b/tests/cfgnet/plugins/concept/test_pyproject_plugin.py
@@ -47,88 +47,19 @@ def test_parse_pyproject_file(get_plugin):
ids = {node.id for node in nodes}
assert artifact is not None
- assert len(nodes) == 12
+ assert len(nodes) == 11
assert make_id("pyproject.toml", "file", "pyproject.toml") in ids
assert make_id("pyproject.toml", "tool", "poetry", "name", "CfgNet") in ids
- assert (
- make_id("pyproject.toml", "tool", "poetry", "version", "version:1.0.0")
- in ids
- )
- assert (
- make_id("pyproject.toml", "tool", "poetry", "include", "test.py")
- in ids
- )
- assert (
- make_id("pyproject.toml", "tool", "poetry", "exclude", "hello.py")
- in ids
- )
- assert (
- make_id("pyproject.toml", "tool", "poetry", "license", "GPL-3.0+")
- in ids
- )
- assert (
- make_id(
- "pyproject.toml",
- "tool",
- "poetry",
- "homepage",
- "https://github.com",
- )
- in ids
- )
- assert (
- make_id(
- "pyproject.toml",
- "tool",
- "poetry",
- "packages",
- "packages_0",
- "include",
- "cfgnet",
- )
- in ids
- )
- assert (
- make_id(
- "pyproject.toml",
- "tool",
- "poetry",
- "packages",
- "packages_0",
- "from",
- "src",
- )
- in ids
- )
- assert (
- make_id(
- "pyproject.toml",
- "tool",
- "poetry",
- "dependencies",
- "python",
- "python:^3.8",
- )
- in ids
- )
- assert (
- make_id(
- "pyproject.toml",
- "tool",
- "poetry",
- "dev-dependencies",
- "cov",
- "cov:5.1",
- )
- in ids
- )
- assert (
- make_id(
- "pyproject.toml", "tool", "poetry", "scripts", "cfgnet", "main"
- )
- in ids
- )
+ assert make_id("pyproject.toml", "tool", "poetry", "version", "1.0.0") in ids
+ assert make_id("pyproject.toml", "tool", "poetry", "include", "['test.py']") in ids
+ assert make_id("pyproject.toml", "tool", "poetry", "exclude", "['hello.py']") in ids
+ assert make_id("pyproject.toml", "tool", "poetry", "license", "GPL-3.0+") in ids
+ assert make_id("pyproject.toml", "tool", "poetry", "homepage", "https://github.com") in ids
+ assert make_id("pyproject.toml", "tool", "poetry", "packages", "[{'include': 'cfgnet', 'from': 'src'}]") in ids
+ assert make_id("pyproject.toml", "tool", "poetry", "dependencies", "python", "^3.8") in ids
+ assert make_id("pyproject.toml", "tool", "poetry", "dev-dependencies", "cov", "5.1") in ids
+ assert make_id("pyproject.toml", "tool", "poetry", "scripts", "cfgnet", "main") in ids
def test_config_types(get_plugin):
diff --git a/tests/cfgnet/plugins/file_type/test_toml_plugin.py b/tests/cfgnet/plugins/file_type/test_toml_plugin.py
index a6bd50a..436753b 100644
--- a/tests/cfgnet/plugins/file_type/test_toml_plugin.py
+++ b/tests/cfgnet/plugins/file_type/test_toml_plugin.py
@@ -46,35 +46,12 @@ def test_parse_toml_file(get_plugin):
ids = {node.id for node in nodes}
assert artifact is not None
- assert len(nodes) == 8
+ assert len(nodes) == 7
assert make_id("test.toml", "file", "test.toml") in ids
assert make_id("test.toml", "tool", "poetry", "name", "cfgnet") in ids
assert make_id("test.toml", "tool", "poetry", "version", "v1.1.0") in ids
- assert make_id("test.toml", "tool", "poetry", "keywords", "config") in ids
+ assert make_id("test.toml", "tool", "poetry", "keywords", "['config']") in ids
assert make_id("test.toml", "dependencies", "python", "^3.6") in ids
assert make_id("test.toml", "dependencies", "gitpython", "^3.0") in ids
- assert (
- make_id(
- "test.toml",
- "tool",
- "poetry",
- "packages",
- "packages_0",
- "include",
- "cfgnet",
- )
- in ids
- )
- assert (
- make_id(
- "test.toml",
- "tool",
- "poetry",
- "packages",
- "packages_0",
- "from",
- "src",
- )
- in ids
- )
+ assert make_id("test.toml", "tool", "poetry", "packages", "[{'include': 'cfgnet', 'from': 'src'}]") in ids
diff --git a/tests/cfgnet/plugins/test_plugin_manager.py b/tests/cfgnet/plugins/test_plugin_manager.py
index d82734c..b4683cd 100644
--- a/tests/cfgnet/plugins/test_plugin_manager.py
+++ b/tests/cfgnet/plugins/test_plugin_manager.py
@@ -19,42 +19,22 @@
def test_get_all_plugins():
all_plugins = PluginManager.get_plugins()
- assert len(all_plugins) == 27
+ assert len(all_plugins) == 28
def test_get_responsible_plugin():
plugins = PluginManager.get_plugins()
- docker_plugin = PluginManager.get_responsible_plugin(
- plugins, "path/to/Dockerfile"
- )
- maven_plugin = PluginManager.get_responsible_plugin(
- plugins, "path/to/pom.xml"
- )
- nodejs_plugin = PluginManager.get_responsible_plugin(
- plugins, "path/to/package.json"
- )
- docker_compose_plugin = PluginManager.get_responsible_plugin(
- plugins, "path/to/docker-compose.yml"
- )
- travis_plugin = PluginManager.get_responsible_plugin(
- plugins, "path/to/.travis.yml"
- )
- cypress_plugin = PluginManager.get_responsible_plugin(
- plugins, "path/to/cypress.json"
- )
- tsconfig_plugin = PluginManager.get_responsible_plugin(
- plugins, "path/to/tsconfig.json"
- )
- poetry_plugin = PluginManager.get_responsible_plugin(
- plugins, "path/to/pyproject.toml"
- )
- spring_plugin = PluginManager.get_responsible_plugin(
- plugins, "path/to/application.properties"
- )
- apache_webserver_plugin = PluginManager.get_responsible_plugin(
- plugins, "path/to/httpd.conf"
- )
+ docker_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/Dockerfile")
+ maven_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/pom.xml")
+ nodejs_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/package.json")
+ docker_compose_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/docker-compose.yml")
+ travis_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/.travis.yml")
+ cypress_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/cypress.json")
+ tsconfig_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/tsconfig.json")
+ poetry_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/pyproject.toml")
+ spring_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/application.properties")
+ apache_webserver_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/httpd.conf")
mysql_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/my.cnf")
ansible_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/ansible.cfg")
ansible_playbook_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/playbooks/test.yaml")
@@ -72,6 +52,7 @@ def test_get_responsible_plugin():
angular_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/angular.json")
mapreduce_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/mapred-site.xml")
circleci_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/.circleci/config.yml")
+ cargo_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/Cargo.toml")
assert docker_plugin.concept_name == "docker"
assert maven_plugin.concept_name == "maven"
@@ -100,3 +81,4 @@ def test_get_responsible_plugin():
assert angular_plugin.concept_name == "angular"
assert mapreduce_plugin.concept_name == "mapreduce"
assert circleci_plugin.concept_name == "circleci"
+ assert cargo_plugin.concept_name == "cargo"
diff --git a/tests/files/Cargo.toml b/tests/files/Cargo.toml
new file mode 100644
index 0000000..8948786
--- /dev/null
+++ b/tests/files/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name = "example"
+version = "0.1.0"
+authors = ["Your Name "]
+edition = "2021"
+homepage = "https://example.com"
+workspace = "path/to/workspace/root"
+
+# Optional description and license fields
+description = "A simple Rust project example"
+license = "MIT"
+
+[dependencies]
+serde = "1.0"
+rand = "0.8"
+
+# Optional section for dev dependencies, only used during development
+[dev-dependencies]
+tokio = { version = "1", features = ["full"] }
+
+[features]
+default = ["serde"]
+
+# Optional section for custom configurations
+[profile.release]
+opt-level = 3
\ No newline at end of file