Repository: deepset-ai/haystack

Issue:
Separate Memory Retrievers and tests
In Haystack 2.0, we want each Component to be in a separate file (the same goes for tests).

Therefore, we should separate `MemoryBM25Retriever` and `MemoryEmbeddingRetriever`.



Discussion:

Resolving patch:
diff --git a/haystack/preview/components/retrievers/__init__.py b/haystack/preview/components/retrievers/__init__.py
--- a/haystack/preview/components/retrievers/__init__.py
+++ b/haystack/preview/components/retrievers/__init__.py
@@ -1,3 +1,4 @@
-from haystack.preview.components.retrievers.memory import MemoryBM25Retriever, MemoryEmbeddingRetriever
+from haystack.preview.components.retrievers.memory_bm25_retriever import MemoryBM25Retriever
+from haystack.preview.components.retrievers.memory_embedding_retriever import MemoryEmbeddingRetriever
 
 __all__ = ["MemoryBM25Retriever", "MemoryEmbeddingRetriever"]
diff --git a/haystack/preview/components/retrievers/memory_bm25_retriever.py b/haystack/preview/components/retrievers/memory_bm25_retriever.py
new file mode 100644
--- /dev/null
+++ b/haystack/preview/components/retrievers/memory_bm25_retriever.py
@@ -0,0 +1,98 @@
+from typing import Dict, List, Any, Optional
+
+from haystack.preview import component, Document, default_to_dict, default_from_dict, DeserializationError
+from haystack.preview.document_stores import MemoryDocumentStore, document_store
+
+
+@component
+class MemoryBM25Retriever:
+    """
+    A component for retrieving documents from a MemoryDocumentStore using the BM25 algorithm.
+
+    Needs to be connected to a MemoryDocumentStore to run.
+    """
+
+    def __init__(
+        self,
+        document_store: MemoryDocumentStore,
+        filters: Optional[Dict[str, Any]] = None,
+        top_k: int = 10,
+        scale_score: bool = True,
+    ):
+        """
+        Create a MemoryBM25Retriever component.
+
+        :param document_store: An instance of MemoryDocumentStore.
+        :param filters: A dictionary with filters to narrow down the search space. Default is None.
+        :param top_k: The maximum number of documents to retrieve. Default is 10.
+        :param scale_score: Whether to scale the BM25 score or not. Default is True.
+
+        :raises ValueError: If the specified top_k is not > 0.
+        """
+        if not isinstance(document_store, MemoryDocumentStore):
+            raise ValueError("document_store must be an instance of MemoryDocumentStore")
+
+        self.document_store = document_store
+
+        if top_k <= 0:
+            raise ValueError(f"top_k must be > 0, but got {top_k}")
+
+        self.filters = filters
+        self.top_k = top_k
+        self.scale_score = scale_score
+
+    def to_dict(self) -> Dict[str, Any]:
+        """
+        Serialize this component to a dictionary.
+        """
+        docstore = self.document_store.to_dict()
+        return default_to_dict(
+            self, document_store=docstore, filters=self.filters, top_k=self.top_k, scale_score=self.scale_score
+        )
+
+    @classmethod
+    def from_dict(cls, data: Dict[str, Any]) -> "MemoryBM25Retriever":
+        """
+        Deserialize this component from a dictionary.
+        """
+        init_params = data.get("init_parameters", {})
+        if "document_store" not in init_params:
+            raise DeserializationError("Missing 'document_store' in serialization data")
+        if "type" not in init_params["document_store"]:
+            raise DeserializationError("Missing 'type' in document store's serialization data")
+        if init_params["document_store"]["type"] not in document_store.registry:
+            raise DeserializationError(f"DocumentStore type '{init_params['document_store']['type']}' not found")
+
+        docstore_class = document_store.registry[init_params["document_store"]["type"]]
+        docstore = docstore_class.from_dict(init_params["document_store"])
+        data["init_parameters"]["document_store"] = docstore
+        return default_from_dict(cls, data)
+
+    @component.output_types(documents=List[Document])
+    def run(
+        self,
+        query: str,
+        filters: Optional[Dict[str, Any]] = None,
+        top_k: Optional[int] = None,
+        scale_score: Optional[bool] = None,
+    ):
+        """
+        Run the MemoryBM25Retriever on the given input data.
+
+        :param query: The query string for the retriever.
+        :param filters: A dictionary with filters to narrow down the search space.
+        :param top_k: The maximum number of documents to return.
+        :param scale_score: Whether to scale the BM25 scores or not.
+        :return: The retrieved documents.
+
+        :raises ValueError: If the specified DocumentStore is not found or is not a MemoryDocumentStore instance.
+        """
+        if filters is None:
+            filters = self.filters
+        if top_k is None:
+            top_k = self.top_k
+        if scale_score is None:
+            scale_score = self.scale_score
+
+        docs = self.document_store.bm25_retrieval(query=query, filters=filters, top_k=top_k, scale_score=scale_score)
+        return {"documents": docs}
diff --git a/haystack/preview/components/retrievers/memory.py b/haystack/preview/components/retrievers/memory_embedding_retriever.py
similarity index 55%
rename from haystack/preview/components/retrievers/memory.py
rename to haystack/preview/components/retrievers/memory_embedding_retriever.py
--- a/haystack/preview/components/retrievers/memory.py
+++ b/haystack/preview/components/retrievers/memory_embedding_retriever.py
@@ -4,100 +4,6 @@
 from haystack.preview.document_stores import MemoryDocumentStore, document_store
 
 
-@component
-class MemoryBM25Retriever:
-    """
-    A component for retrieving documents from a MemoryDocumentStore using the BM25 algorithm.
-
-    Needs to be connected to a MemoryDocumentStore to run.
-    """
-
-    def __init__(
-        self,
-        document_store: MemoryDocumentStore,
-        filters: Optional[Dict[str, Any]] = None,
-        top_k: int = 10,
-        scale_score: bool = True,
-    ):
-        """
-        Create a MemoryBM25Retriever component.
-
-        :param document_store: An instance of MemoryDocumentStore.
-        :param filters: A dictionary with filters to narrow down the search space. Default is None.
-        :param top_k: The maximum number of documents to retrieve. Default is 10.
-        :param scale_score: Whether to scale the BM25 score or not. Default is True.
-
-        :raises ValueError: If the specified top_k is not > 0.
-        """
-        if not isinstance(document_store, MemoryDocumentStore):
-            raise ValueError("document_store must be an instance of MemoryDocumentStore")
-
-        self.document_store = document_store
-
-        if top_k <= 0:
-            raise ValueError(f"top_k must be > 0, but got {top_k}")
-
-        self.filters = filters
-        self.top_k = top_k
-        self.scale_score = scale_score
-
-    def to_dict(self) -> Dict[str, Any]:
-        """
-        Serialize this component to a dictionary.
-        """
-        docstore = self.document_store.to_dict()
-        return default_to_dict(
-            self, document_store=docstore, filters=self.filters, top_k=self.top_k, scale_score=self.scale_score
-        )
-
-    @classmethod
-    def from_dict(cls, data: Dict[str, Any]) -> "MemoryBM25Retriever":
-        """
-        Deserialize this component from a dictionary.
-        """
-        init_params = data.get("init_parameters", {})
-        if "document_store" not in init_params:
-            raise DeserializationError("Missing 'document_store' in serialization data")
-        if "type" not in init_params["document_store"]:
-            raise DeserializationError("Missing 'type' in document store's serialization data")
-        if init_params["document_store"]["type"] not in document_store.registry:
-            raise DeserializationError(f"DocumentStore type '{init_params['document_store']['type']}' not found")
-
-        docstore_class = document_store.registry[init_params["document_store"]["type"]]
-        docstore = docstore_class.from_dict(init_params["document_store"])
-        data["init_parameters"]["document_store"] = docstore
-        return default_from_dict(cls, data)
-
-    @component.output_types(documents=List[Document])
-    def run(
-        self,
-        query: str,
-        filters: Optional[Dict[str, Any]] = None,
-        top_k: Optional[int] = None,
-        scale_score: Optional[bool] = None,
-    ):
-        """
-        Run the MemoryBM25Retriever on the given input data.
-
-        :param query: The query string for the retriever.
-        :param filters: A dictionary with filters to narrow down the search space.
-        :param top_k: The maximum number of documents to return.
-        :param scale_score: Whether to scale the BM25 scores or not.
-        :return: The retrieved documents.
-
-        :raises ValueError: If the specified DocumentStore is not found or is not a MemoryDocumentStore instance.
-        """
-        if filters is None:
-            filters = self.filters
-        if top_k is None:
-            top_k = self.top_k
-        if scale_score is None:
-            scale_score = self.scale_score
-
-        docs = self.document_store.bm25_retrieval(query=query, filters=filters, top_k=top_k, scale_score=scale_score)
-        return {"documents": docs}
-
-
 @component
 class MemoryEmbeddingRetriever:
     """
@@ -153,7 +59,7 @@ def to_dict(self) -> Dict[str, Any]:
         )
 
     @classmethod
-    def from_dict(cls, data: Dict[str, Any]) -> "MemoryBM25Retriever":
+    def from_dict(cls, data: Dict[str, Any]) -> "MemoryEmbeddingRetriever":
         """
         Deserialize this component from a dictionary.
         """


Test patch:
diff --git a/test/preview/components/retrievers/test_memory_bm25_retriever.py b/test/preview/components/retrievers/test_memory_bm25_retriever.py
new file mode 100644
--- /dev/null
+++ b/test/preview/components/retrievers/test_memory_bm25_retriever.py
@@ -0,0 +1,183 @@
+from typing import Dict, Any
+
+import pytest
+
+from haystack.preview import Pipeline, DeserializationError
+from haystack.preview.testing.factory import document_store_class
+from haystack.preview.components.retrievers.memory_bm25_retriever import MemoryBM25Retriever
+from haystack.preview.dataclasses import Document
+from haystack.preview.document_stores import MemoryDocumentStore
+
+
+@pytest.fixture()
+def mock_docs():
+    return [
+        Document(text="Javascript is a popular programming language"),
+        Document(text="Java is a popular programming language"),
+        Document(text="Python is a popular programming language"),
+        Document(text="Ruby is a popular programming language"),
+        Document(text="PHP is a popular programming language"),
+    ]
+
+
+class TestMemoryBM25Retriever:
+    @pytest.mark.unit
+    def test_init_default(self):
+        retriever = MemoryBM25Retriever(MemoryDocumentStore())
+        assert retriever.filters is None
+        assert retriever.top_k == 10
+        assert retriever.scale_score
+
+    @pytest.mark.unit
+    def test_init_with_parameters(self):
+        retriever = MemoryBM25Retriever(MemoryDocumentStore(), filters={"name": "test.txt"}, top_k=5, scale_score=False)
+        assert retriever.filters == {"name": "test.txt"}
+        assert retriever.top_k == 5
+        assert not retriever.scale_score
+
+    @pytest.mark.unit
+    def test_init_with_invalid_top_k_parameter(self):
+        with pytest.raises(ValueError, match="top_k must be > 0, but got -2"):
+            MemoryBM25Retriever(MemoryDocumentStore(), top_k=-2, scale_score=False)
+
+    @pytest.mark.unit
+    def test_to_dict(self):
+        MyFakeStore = document_store_class("MyFakeStore", bases=(MemoryDocumentStore,))
+        document_store = MyFakeStore()
+        document_store.to_dict = lambda: {"type": "MyFakeStore", "init_parameters": {}}
+        component = MemoryBM25Retriever(document_store=document_store)
+
+        data = component.to_dict()
+        assert data == {
+            "type": "MemoryBM25Retriever",
+            "init_parameters": {
+                "document_store": {"type": "MyFakeStore", "init_parameters": {}},
+                "filters": None,
+                "top_k": 10,
+                "scale_score": True,
+            },
+        }
+
+    @pytest.mark.unit
+    def test_to_dict_with_custom_init_parameters(self):
+        MyFakeStore = document_store_class("MyFakeStore", bases=(MemoryDocumentStore,))
+        document_store = MyFakeStore()
+        document_store.to_dict = lambda: {"type": "MyFakeStore", "init_parameters": {}}
+        component = MemoryBM25Retriever(
+            document_store=document_store, filters={"name": "test.txt"}, top_k=5, scale_score=False
+        )
+        data = component.to_dict()
+        assert data == {
+            "type": "MemoryBM25Retriever",
+            "init_parameters": {
+                "document_store": {"type": "MyFakeStore", "init_parameters": {}},
+                "filters": {"name": "test.txt"},
+                "top_k": 5,
+                "scale_score": False,
+            },
+        }
+
+    @pytest.mark.unit
+    def test_from_dict(self):
+        document_store_class("MyFakeStore", bases=(MemoryDocumentStore,))
+        data = {
+            "type": "MemoryBM25Retriever",
+            "init_parameters": {
+                "document_store": {"type": "MyFakeStore", "init_parameters": {}},
+                "filters": {"name": "test.txt"},
+                "top_k": 5,
+            },
+        }
+        component = MemoryBM25Retriever.from_dict(data)
+        assert isinstance(component.document_store, MemoryDocumentStore)
+        assert component.filters == {"name": "test.txt"}
+        assert component.top_k == 5
+        assert component.scale_score
+
+    @pytest.mark.unit
+    def test_from_dict_without_docstore(self):
+        data = {"type": "MemoryBM25Retriever", "init_parameters": {}}
+        with pytest.raises(DeserializationError, match="Missing 'document_store' in serialization data"):
+            MemoryBM25Retriever.from_dict(data)
+
+    @pytest.mark.unit
+    def test_from_dict_without_docstore_type(self):
+        data = {"type": "MemoryBM25Retriever", "init_parameters": {"document_store": {"init_parameters": {}}}}
+        with pytest.raises(DeserializationError, match="Missing 'type' in document store's serialization data"):
+            MemoryBM25Retriever.from_dict(data)
+
+    @pytest.mark.unit
+    def test_from_dict_nonexisting_docstore(self):
+        data = {
+            "type": "MemoryBM25Retriever",
+            "init_parameters": {"document_store": {"type": "NonexistingDocstore", "init_parameters": {}}},
+        }
+        with pytest.raises(DeserializationError, match="DocumentStore type 'NonexistingDocstore' not found"):
+            MemoryBM25Retriever.from_dict(data)
+
+    @pytest.mark.unit
+    def test_retriever_valid_run(self, mock_docs):
+        top_k = 5
+        ds = MemoryDocumentStore()
+        ds.write_documents(mock_docs)
+
+        retriever = MemoryBM25Retriever(ds, top_k=top_k)
+        result = retriever.run(query="PHP")
+
+        assert "documents" in result
+        assert len(result["documents"]) == top_k
+        assert result["documents"][0].text == "PHP is a popular programming language"
+
+    @pytest.mark.unit
+    def test_invalid_run_wrong_store_type(self):
+        SomeOtherDocumentStore = document_store_class("SomeOtherDocumentStore")
+        with pytest.raises(ValueError, match="document_store must be an instance of MemoryDocumentStore"):
+            MemoryBM25Retriever(SomeOtherDocumentStore())
+
+    @pytest.mark.integration
+    @pytest.mark.parametrize(
+        "query, query_result",
+        [
+            ("Javascript", "Javascript is a popular programming language"),
+            ("Java", "Java is a popular programming language"),
+        ],
+    )
+    def test_run_with_pipeline(self, mock_docs, query: str, query_result: str):
+        ds = MemoryDocumentStore()
+        ds.write_documents(mock_docs)
+        retriever = MemoryBM25Retriever(ds)
+
+        pipeline = Pipeline()
+        pipeline.add_component("retriever", retriever)
+        result: Dict[str, Any] = pipeline.run(data={"retriever": {"query": query}})
+
+        assert result
+        assert "retriever" in result
+        results_docs = result["retriever"]["documents"]
+        assert results_docs
+        assert results_docs[0].text == query_result
+
+    @pytest.mark.integration
+    @pytest.mark.parametrize(
+        "query, query_result, top_k",
+        [
+            ("Javascript", "Javascript is a popular programming language", 1),
+            ("Java", "Java is a popular programming language", 2),
+            ("Ruby", "Ruby is a popular programming language", 3),
+        ],
+    )
+    def test_run_with_pipeline_and_top_k(self, mock_docs, query: str, query_result: str, top_k: int):
+        ds = MemoryDocumentStore()
+        ds.write_documents(mock_docs)
+        retriever = MemoryBM25Retriever(ds)
+
+        pipeline = Pipeline()
+        pipeline.add_component("retriever", retriever)
+        result: Dict[str, Any] = pipeline.run(data={"retriever": {"query": query, "top_k": top_k}})
+
+        assert result
+        assert "retriever" in result
+        results_docs = result["retriever"]["documents"]
+        assert results_docs
+        assert len(results_docs) == top_k
+        assert results_docs[0].text == query_result
diff --git a/test/preview/components/retrievers/test_memory_embedding_retriever.py b/test/preview/components/retrievers/test_memory_embedding_retriever.py
new file mode 100644
--- /dev/null
+++ b/test/preview/components/retrievers/test_memory_embedding_retriever.py
@@ -0,0 +1,162 @@
+from typing import Dict, Any
+
+import pytest
+
+from haystack.preview import Pipeline, DeserializationError
+from haystack.preview.testing.factory import document_store_class
+from haystack.preview.components.retrievers.memory_embedding_retriever import MemoryEmbeddingRetriever
+from haystack.preview.dataclasses import Document
+from haystack.preview.document_stores import MemoryDocumentStore
+
+
+class TestMemoryEmbeddingRetriever:
+    @pytest.mark.unit
+    def test_init_default(self):
+        retriever = MemoryEmbeddingRetriever(MemoryDocumentStore())
+        assert retriever.filters is None
+        assert retriever.top_k == 10
+        assert retriever.scale_score
+
+    @pytest.mark.unit
+    def test_init_with_parameters(self):
+        retriever = MemoryEmbeddingRetriever(
+            MemoryDocumentStore(), filters={"name": "test.txt"}, top_k=5, scale_score=False
+        )
+        assert retriever.filters == {"name": "test.txt"}
+        assert retriever.top_k == 5
+        assert not retriever.scale_score
+
+    @pytest.mark.unit
+    def test_init_with_invalid_top_k_parameter(self):
+        with pytest.raises(ValueError, match="top_k must be > 0, but got -2"):
+            MemoryEmbeddingRetriever(MemoryDocumentStore(), top_k=-2, scale_score=False)
+
+    @pytest.mark.unit
+    def test_to_dict(self):
+        MyFakeStore = document_store_class("MyFakeStore", bases=(MemoryDocumentStore,))
+        document_store = MyFakeStore()
+        document_store.to_dict = lambda: {"type": "MyFakeStore", "init_parameters": {}}
+        component = MemoryEmbeddingRetriever(document_store=document_store)
+
+        data = component.to_dict()
+        assert data == {
+            "type": "MemoryEmbeddingRetriever",
+            "init_parameters": {
+                "document_store": {"type": "MyFakeStore", "init_parameters": {}},
+                "filters": None,
+                "top_k": 10,
+                "scale_score": True,
+                "return_embedding": False,
+            },
+        }
+
+    @pytest.mark.unit
+    def test_to_dict_with_custom_init_parameters(self):
+        MyFakeStore = document_store_class("MyFakeStore", bases=(MemoryDocumentStore,))
+        document_store = MyFakeStore()
+        document_store.to_dict = lambda: {"type": "MyFakeStore", "init_parameters": {}}
+        component = MemoryEmbeddingRetriever(
+            document_store=document_store,
+            filters={"name": "test.txt"},
+            top_k=5,
+            scale_score=False,
+            return_embedding=True,
+        )
+        data = component.to_dict()
+        assert data == {
+            "type": "MemoryEmbeddingRetriever",
+            "init_parameters": {
+                "document_store": {"type": "MyFakeStore", "init_parameters": {}},
+                "filters": {"name": "test.txt"},
+                "top_k": 5,
+                "scale_score": False,
+                "return_embedding": True,
+            },
+        }
+
+    @pytest.mark.unit
+    def test_from_dict(self):
+        document_store_class("MyFakeStore", bases=(MemoryDocumentStore,))
+        data = {
+            "type": "MemoryEmbeddingRetriever",
+            "init_parameters": {
+                "document_store": {"type": "MyFakeStore", "init_parameters": {}},
+                "filters": {"name": "test.txt"},
+                "top_k": 5,
+            },
+        }
+        component = MemoryEmbeddingRetriever.from_dict(data)
+        assert isinstance(component.document_store, MemoryDocumentStore)
+        assert component.filters == {"name": "test.txt"}
+        assert component.top_k == 5
+        assert component.scale_score
+
+    @pytest.mark.unit
+    def test_from_dict_without_docstore(self):
+        data = {"type": "MemoryEmbeddingRetriever", "init_parameters": {}}
+        with pytest.raises(DeserializationError, match="Missing 'document_store' in serialization data"):
+            MemoryEmbeddingRetriever.from_dict(data)
+
+    @pytest.mark.unit
+    def test_from_dict_without_docstore_type(self):
+        data = {"type": "MemoryEmbeddingRetriever", "init_parameters": {"document_store": {"init_parameters": {}}}}
+        with pytest.raises(DeserializationError, match="Missing 'type' in document store's serialization data"):
+            MemoryEmbeddingRetriever.from_dict(data)
+
+    @pytest.mark.unit
+    def test_from_dict_nonexisting_docstore(self):
+        data = {
+            "type": "MemoryEmbeddingRetriever",
+            "init_parameters": {"document_store": {"type": "NonexistingDocstore", "init_parameters": {}}},
+        }
+        with pytest.raises(DeserializationError, match="DocumentStore type 'NonexistingDocstore' not found"):
+            MemoryEmbeddingRetriever.from_dict(data)
+
+    @pytest.mark.unit
+    def test_valid_run(self):
+        top_k = 3
+        ds = MemoryDocumentStore(embedding_similarity_function="cosine")
+        docs = [
+            Document(text="my document", embedding=[0.1, 0.2, 0.3, 0.4]),
+            Document(text="another document", embedding=[1.0, 1.0, 1.0, 1.0]),
+            Document(text="third document", embedding=[0.5, 0.7, 0.5, 0.7]),
+        ]
+        ds.write_documents(docs)
+
+        retriever = MemoryEmbeddingRetriever(ds, top_k=top_k)
+        result = retriever.run(query_embedding=[0.1, 0.1, 0.1, 0.1], return_embedding=True)
+
+        assert "documents" in result
+        assert len(result["documents"]) == top_k
+        assert result["documents"][0].embedding == [1.0, 1.0, 1.0, 1.0]
+
+    @pytest.mark.unit
+    def test_invalid_run_wrong_store_type(self):
+        SomeOtherDocumentStore = document_store_class("SomeOtherDocumentStore")
+        with pytest.raises(ValueError, match="document_store must be an instance of MemoryDocumentStore"):
+            MemoryEmbeddingRetriever(SomeOtherDocumentStore())
+
+    @pytest.mark.integration
+    def test_run_with_pipeline(self):
+        ds = MemoryDocumentStore(embedding_similarity_function="cosine")
+        top_k = 2
+        docs = [
+            Document(text="my document", embedding=[0.1, 0.2, 0.3, 0.4]),
+            Document(text="another document", embedding=[1.0, 1.0, 1.0, 1.0]),
+            Document(text="third document", embedding=[0.5, 0.7, 0.5, 0.7]),
+        ]
+        ds.write_documents(docs)
+        retriever = MemoryEmbeddingRetriever(ds, top_k=top_k)
+
+        pipeline = Pipeline()
+        pipeline.add_component("retriever", retriever)
+        result: Dict[str, Any] = pipeline.run(
+            data={"retriever": {"query_embedding": [0.1, 0.1, 0.1, 0.1], "return_embedding": True}}
+        )
+
+        assert result
+        assert "retriever" in result
+        results_docs = result["retriever"]["documents"]
+        assert results_docs
+        assert len(results_docs) == top_k
+        assert results_docs[0].embedding == [1.0, 1.0, 1.0, 1.0]
diff --git a/test/preview/components/retrievers/test_memory_retriever.py b/test/preview/components/retrievers/test_memory_retriever.py
deleted file mode 100644
--- a/test/preview/components/retrievers/test_memory_retriever.py
+++ /dev/null
@@ -1,277 +0,0 @@
-from typing import Dict, Any
-
-import pytest
-
-from haystack.preview import Pipeline, DeserializationError
-from haystack.preview.testing.factory import document_store_class
-from haystack.preview.components.retrievers.memory import MemoryBM25Retriever, MemoryEmbeddingRetriever
-from haystack.preview.dataclasses import Document
-from haystack.preview.document_stores import MemoryDocumentStore
-
-
-@pytest.fixture()
-def mock_docs():
-    return [
-        Document(text="Javascript is a popular programming language"),
-        Document(text="Java is a popular programming language"),
-        Document(text="Python is a popular programming language"),
-        Document(text="Ruby is a popular programming language"),
-        Document(text="PHP is a popular programming language"),
-    ]
-
-
-class TestMemoryRetrievers:
-    @pytest.mark.parametrize("retriever_cls", [MemoryBM25Retriever, MemoryEmbeddingRetriever])
-    @pytest.mark.unit
-    def test_init_default(self, retriever_cls):
-        retriever = retriever_cls(MemoryDocumentStore())
-        assert retriever.filters is None
-        assert retriever.top_k == 10
-        assert retriever.scale_score
-
-    @pytest.mark.parametrize("retriever_cls", [MemoryBM25Retriever, MemoryEmbeddingRetriever])
-    @pytest.mark.unit
-    def test_init_with_parameters(self, retriever_cls):
-        retriever = retriever_cls(MemoryDocumentStore(), filters={"name": "test.txt"}, top_k=5, scale_score=False)
-        assert retriever.filters == {"name": "test.txt"}
-        assert retriever.top_k == 5
-        assert not retriever.scale_score
-
-    @pytest.mark.parametrize("retriever_cls", [MemoryBM25Retriever, MemoryEmbeddingRetriever])
-    @pytest.mark.unit
-    def test_init_with_invalid_top_k_parameter(self, retriever_cls):
-        with pytest.raises(ValueError, match="top_k must be > 0, but got -2"):
-            retriever_cls(MemoryDocumentStore(), top_k=-2, scale_score=False)
-
-    @pytest.mark.unit
-    def test_bm25_retriever_to_dict(self):
-        MyFakeStore = document_store_class("MyFakeStore", bases=(MemoryDocumentStore,))
-        document_store = MyFakeStore()
-        document_store.to_dict = lambda: {"type": "MyFakeStore", "init_parameters": {}}
-        component = MemoryBM25Retriever(document_store=document_store)
-
-        data = component.to_dict()
-        assert data == {
-            "type": "MemoryBM25Retriever",
-            "init_parameters": {
-                "document_store": {"type": "MyFakeStore", "init_parameters": {}},
-                "filters": None,
-                "top_k": 10,
-                "scale_score": True,
-            },
-        }
-
-    @pytest.mark.unit
-    def test_embedding_retriever_to_dict(self):
-        MyFakeStore = document_store_class("MyFakeStore", bases=(MemoryDocumentStore,))
-        document_store = MyFakeStore()
-        document_store.to_dict = lambda: {"type": "MyFakeStore", "init_parameters": {}}
-        component = MemoryEmbeddingRetriever(document_store=document_store)
-
-        data = component.to_dict()
-        assert data == {
-            "type": "MemoryEmbeddingRetriever",
-            "init_parameters": {
-                "document_store": {"type": "MyFakeStore", "init_parameters": {}},
-                "filters": None,
-                "top_k": 10,
-                "scale_score": True,
-                "return_embedding": False,
-            },
-        }
-
-    @pytest.mark.unit
-    def test_bm25_retriever_to_dict_with_custom_init_parameters(self):
-        MyFakeStore = document_store_class("MyFakeStore", bases=(MemoryDocumentStore,))
-        document_store = MyFakeStore()
-        document_store.to_dict = lambda: {"type": "MyFakeStore", "init_parameters": {}}
-        component = MemoryBM25Retriever(
-            document_store=document_store, filters={"name": "test.txt"}, top_k=5, scale_score=False
-        )
-        data = component.to_dict()
-        assert data == {
-            "type": "MemoryBM25Retriever",
-            "init_parameters": {
-                "document_store": {"type": "MyFakeStore", "init_parameters": {}},
-                "filters": {"name": "test.txt"},
-                "top_k": 5,
-                "scale_score": False,
-            },
-        }
-
-    @pytest.mark.unit
-    def test_embedding_retriever_to_dict_with_custom_init_parameters(self):
-        MyFakeStore = document_store_class("MyFakeStore", bases=(MemoryDocumentStore,))
-        document_store = MyFakeStore()
-        document_store.to_dict = lambda: {"type": "MyFakeStore", "init_parameters": {}}
-        component = MemoryEmbeddingRetriever(
-            document_store=document_store,
-            filters={"name": "test.txt"},
-            top_k=5,
-            scale_score=False,
-            return_embedding=True,
-        )
-        data = component.to_dict()
-        assert data == {
-            "type": "MemoryEmbeddingRetriever",
-            "init_parameters": {
-                "document_store": {"type": "MyFakeStore", "init_parameters": {}},
-                "filters": {"name": "test.txt"},
-                "top_k": 5,
-                "scale_score": False,
-                "return_embedding": True,
-            },
-        }
-
-    @pytest.mark.parametrize("retriever_cls", [MemoryBM25Retriever, MemoryEmbeddingRetriever])
-    @pytest.mark.unit
-    def test_from_dict(self, retriever_cls):
-        document_store_class("MyFakeStore", bases=(MemoryDocumentStore,))
-        data = {
-            "type": retriever_cls.__name__,
-            "init_parameters": {
-                "document_store": {"type": "MyFakeStore", "init_parameters": {}},
-                "filters": {"name": "test.txt"},
-                "top_k": 5,
-            },
-        }
-        component = retriever_cls.from_dict(data)
-        assert isinstance(component.document_store, MemoryDocumentStore)
-        assert component.filters == {"name": "test.txt"}
-        assert component.top_k == 5
-        assert component.scale_score
-
-    @pytest.mark.parametrize("retriever_cls", [MemoryBM25Retriever, MemoryEmbeddingRetriever])
-    @pytest.mark.unit
-    def test_from_dict_without_docstore(self, retriever_cls):
-        data = {"type": retriever_cls.__name__, "init_parameters": {}}
-        with pytest.raises(DeserializationError, match="Missing 'document_store' in serialization data"):
-            retriever_cls.from_dict(data)
-
-    @pytest.mark.parametrize("retriever_cls", [MemoryBM25Retriever, MemoryEmbeddingRetriever])
-    @pytest.mark.unit
-    def test_from_dict_without_docstore_type(self, retriever_cls):
-        data = {"type": retriever_cls.__name__, "init_parameters": {"document_store": {"init_parameters": {}}}}
-        with pytest.raises(DeserializationError, match="Missing 'type' in document store's serialization data"):
-            retriever_cls.from_dict(data)
-
-    @pytest.mark.parametrize("retriever_cls", [MemoryBM25Retriever, MemoryEmbeddingRetriever])
-    @pytest.mark.unit
-    def test_from_dict_nonexisting_docstore(self, retriever_cls):
-        data = {
-            "type": retriever_cls.__name__,
-            "init_parameters": {"document_store": {"type": "NonexistingDocstore", "init_parameters": {}}},
-        }
-        with pytest.raises(DeserializationError, match="DocumentStore type 'NonexistingDocstore' not found"):
-            retriever_cls.from_dict(data)
-
-    @pytest.mark.unit
-    def test_bm25_retriever_valid_run(self, mock_docs):
-        top_k = 5
-        ds = MemoryDocumentStore()
-        ds.write_documents(mock_docs)
-
-        retriever = MemoryBM25Retriever(ds, top_k=top_k)
-        result = retriever.run(query="PHP")
-
-        assert "documents" in result
-        assert len(result["documents"]) == top_k
-        assert result["documents"][0].text == "PHP is a popular programming language"
-
-    @pytest.mark.unit
-    def test_embedding_retriever_valid_run(self):
-        top_k = 3
-        ds = MemoryDocumentStore(embedding_similarity_function="cosine")
-        docs = [
-            Document(text="my document", embedding=[0.1, 0.2, 0.3, 0.4]),
-            Document(text="another document", embedding=[1.0, 1.0, 1.0, 1.0]),
-            Document(text="third document", embedding=[0.5, 0.7, 0.5, 0.7]),
-        ]
-        ds.write_documents(docs)
-
-        retriever = MemoryEmbeddingRetriever(ds, top_k=top_k)
-        result = retriever.run(query_embedding=[0.1, 0.1, 0.1, 0.1], return_embedding=True)
-
-        assert "documents" in result
-        assert len(result["documents"]) == top_k
-        assert result["documents"][0].embedding == [1.0, 1.0, 1.0, 1.0]
-
-    @pytest.mark.parametrize("retriever_cls", [MemoryBM25Retriever, MemoryEmbeddingRetriever])
-    @pytest.mark.unit
-    def test_invalid_run_wrong_store_type(self, retriever_cls):
-        SomeOtherDocumentStore = document_store_class("SomeOtherDocumentStore")
-        with pytest.raises(ValueError, match="document_store must be an instance of MemoryDocumentStore"):
-            retriever_cls(SomeOtherDocumentStore())
-
-    @pytest.mark.integration
-    @pytest.mark.parametrize(
-        "query, query_result",
-        [
-            ("Javascript", "Javascript is a popular programming language"),
-            ("Java", "Java is a popular programming language"),
-        ],
-    )
-    def test_run_bm25_retriever_with_pipeline(self, mock_docs, query: str, query_result: str):
-        ds = MemoryDocumentStore()
-        ds.write_documents(mock_docs)
-        retriever = MemoryBM25Retriever(ds)
-
-        pipeline = Pipeline()
-        pipeline.add_component("retriever", retriever)
-        result: Dict[str, Any] = pipeline.run(data={"retriever": {"query": query}})
-
-        assert result
-        assert "retriever" in result
-        results_docs = result["retriever"]["documents"]
-        assert results_docs
-        assert results_docs[0].text == query_result
-
-    @pytest.mark.integration
-    def test_run_embedding_retriever_with_pipeline(self):
-        ds = MemoryDocumentStore(embedding_similarity_function="cosine")
-        top_k = 2
-        docs = [
-            Document(text="my document", embedding=[0.1, 0.2, 0.3, 0.4]),
-            Document(text="another document", embedding=[1.0, 1.0, 1.0, 1.0]),
-            Document(text="third document", embedding=[0.5, 0.7, 0.5, 0.7]),
-        ]
-        ds.write_documents(docs)
-        retriever = MemoryEmbeddingRetriever(ds, top_k=top_k)
-
-        pipeline = Pipeline()
-        pipeline.add_component("retriever", retriever)
-        result: Dict[str, Any] = pipeline.run(
-            data={"retriever": {"query_embedding": [0.1, 0.1, 0.1, 0.1], "return_embedding": True}}
-        )
-
-        assert result
-        assert "retriever" in result
-        results_docs = result["retriever"]["documents"]
-        assert results_docs
-        assert len(results_docs) == top_k
-        assert results_docs[0].embedding == [1.0, 1.0, 1.0, 1.0]
-
-    @pytest.mark.integration
-    @pytest.mark.parametrize(
-        "query, query_result, top_k",
-        [
-            ("Javascript", "Javascript is a popular programming language", 1),
-            ("Java", "Java is a popular programming language", 2),
-            ("Ruby", "Ruby is a popular programming language", 3),
-        ],
-    )
-    def test_run_bm25_retriever_with_pipeline_and_top_k(self, mock_docs, query: str, query_result: str, top_k: int):
-        ds = MemoryDocumentStore()
-        ds.write_documents(mock_docs)
-        retriever = MemoryBM25Retriever(ds)
-
-        pipeline = Pipeline()
-        pipeline.add_component("retriever", retriever)
-        result: Dict[str, Any] = pipeline.run(data={"retriever": {"query": query, "top_k": top_k}})
-
-        assert result
-        assert "retriever" in result
-        results_docs = result["retriever"]["documents"]
-        assert results_docs
-        assert len(results_docs) == top_k
-        assert results_docs[0].text == query_result