310 lines
10 KiB
Python
310 lines
10 KiB
Python
"""Tests for the webrequest module."""
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
import requests
|
|
|
|
from src.bibapi.webrequest import (
|
|
ALLOWED_IPS,
|
|
BibTextTransformer,
|
|
TransformerType,
|
|
WebRequest,
|
|
cover,
|
|
get_content,
|
|
)
|
|
|
|
|
|
class TestTransformerType:
|
|
"""Tests for TransformerType enum."""
|
|
|
|
def test_transformer_type_values(self):
|
|
"""Test TransformerType enum values."""
|
|
assert TransformerType.ARRAY.value == "ARRAY"
|
|
assert TransformerType.COinS.value == "COinS"
|
|
assert TransformerType.BibTeX.value == "BibTeX"
|
|
assert TransformerType.RIS.value == "RIS"
|
|
assert TransformerType.RDS.value == "RDS"
|
|
|
|
|
|
class TestWebRequest:
|
|
"""Tests for WebRequest class."""
|
|
|
|
def test_webrequest_init_not_allowed_ip(self):
|
|
"""Test WebRequest raises PermissionError for non-allowed IP."""
|
|
with patch("requests.get") as mock_get:
|
|
mock_response = MagicMock()
|
|
mock_response.text = "192.168.1.1" # Not in ALLOWED_IPS
|
|
mock_get.return_value = mock_response
|
|
|
|
with pytest.raises(PermissionError, match="not allowed"):
|
|
WebRequest()
|
|
|
|
def test_webrequest_init_allowed_ip(self):
|
|
"""Test WebRequest initializes successfully with allowed IP."""
|
|
with patch("requests.get") as mock_get:
|
|
mock_response = MagicMock()
|
|
mock_response.text = ALLOWED_IPS[0] # Use first allowed IP
|
|
mock_get.return_value = mock_response
|
|
|
|
wr = WebRequest()
|
|
assert wr.public_ip == ALLOWED_IPS[0]
|
|
assert wr.timeout == 5
|
|
assert wr.use_any is False
|
|
|
|
def test_webrequest_no_connection(self):
|
|
"""Test WebRequest raises ConnectionError when no internet."""
|
|
with patch("requests.get") as mock_get:
|
|
mock_get.side_effect = requests.exceptions.RequestException("No connection")
|
|
|
|
with pytest.raises(ConnectionError, match="No internet connection"):
|
|
WebRequest()
|
|
|
|
def test_webrequest_use_any_book(self):
|
|
"""Test use_any_book property."""
|
|
with patch("requests.get") as mock_get:
|
|
mock_response = MagicMock()
|
|
mock_response.text = ALLOWED_IPS[0]
|
|
mock_get.return_value = mock_response
|
|
|
|
wr = WebRequest()
|
|
result = wr.use_any_book
|
|
assert result.use_any is True
|
|
|
|
def test_webrequest_set_apparat(self):
|
|
"""Test set_apparat method."""
|
|
with patch("requests.get") as mock_get:
|
|
mock_response = MagicMock()
|
|
mock_response.text = ALLOWED_IPS[0]
|
|
mock_get.return_value = mock_response
|
|
|
|
wr = WebRequest()
|
|
result = wr.set_apparat(5)
|
|
assert result.apparat == "05" # Padded with 0
|
|
|
|
result = wr.set_apparat(15)
|
|
assert result.apparat == 15 # Not padded
|
|
|
|
def test_webrequest_get_ppn(self):
|
|
"""Test get_ppn method."""
|
|
with patch("requests.get") as mock_get:
|
|
mock_response = MagicMock()
|
|
mock_response.text = ALLOWED_IPS[0]
|
|
mock_get.return_value = mock_response
|
|
|
|
wr = WebRequest()
|
|
|
|
# Normal signature
|
|
result = wr.get_ppn("ABC 123")
|
|
assert result.ppn == "ABC 123"
|
|
assert result.signature == "ABC 123"
|
|
|
|
# Signature with +
|
|
result = wr.get_ppn("ABC+123")
|
|
assert result.ppn == "ABC%2B123"
|
|
|
|
# DOI
|
|
result = wr.get_ppn("https://doi.org/10.1234/test")
|
|
assert result.ppn == "test"
|
|
|
|
def test_webrequest_search_book(self):
|
|
"""Test search_book method."""
|
|
with patch("requests.get") as mock_get:
|
|
# First call for IP check
|
|
ip_response = MagicMock()
|
|
ip_response.text = ALLOWED_IPS[0]
|
|
|
|
# Second call for actual search
|
|
search_response = MagicMock()
|
|
search_response.text = "<html>results</html>"
|
|
|
|
mock_get.side_effect = [ip_response, search_response]
|
|
|
|
wr = WebRequest()
|
|
result = wr.search_book("test search")
|
|
assert result == "<html>results</html>"
|
|
|
|
def test_webrequest_search_ppn(self):
|
|
"""Test search_ppn method."""
|
|
with patch("requests.get") as mock_get:
|
|
ip_response = MagicMock()
|
|
ip_response.text = ALLOWED_IPS[0]
|
|
|
|
ppn_response = MagicMock()
|
|
ppn_response.text = "<html>ppn result</html>"
|
|
|
|
mock_get.side_effect = [ip_response, ppn_response]
|
|
|
|
wr = WebRequest()
|
|
result = wr.search_ppn("123456")
|
|
assert result == "<html>ppn result</html>"
|
|
|
|
def test_webrequest_search(self):
|
|
"""Test search method."""
|
|
with patch("requests.get") as mock_get:
|
|
ip_response = MagicMock()
|
|
ip_response.text = ALLOWED_IPS[0]
|
|
|
|
search_response = MagicMock()
|
|
search_response.text = "<html>detail page</html>"
|
|
|
|
mock_get.side_effect = [ip_response, search_response]
|
|
|
|
wr = WebRequest()
|
|
result = wr.search("https://example.com/book")
|
|
assert result == "<html>detail page</html>"
|
|
|
|
def test_webrequest_search_error(self):
|
|
"""Test search method handles errors."""
|
|
with patch("requests.get") as mock_get:
|
|
ip_response = MagicMock()
|
|
ip_response.text = ALLOWED_IPS[0]
|
|
|
|
mock_get.side_effect = [ip_response, requests.exceptions.RequestException()]
|
|
|
|
wr = WebRequest()
|
|
result = wr.search("https://example.com/book")
|
|
assert result is None
|
|
|
|
def test_webrequest_get_book_links(self):
|
|
"""Test get_book_links method."""
|
|
html = """<html>
|
|
<a class="title getFull" href="/opac/book/123">Book 1</a>
|
|
<a class="title getFull" href="/opac/book/456">Book 2</a>
|
|
</html>"""
|
|
|
|
with patch("requests.get") as mock_get:
|
|
ip_response = MagicMock()
|
|
ip_response.text = ALLOWED_IPS[0]
|
|
|
|
search_response = MagicMock()
|
|
search_response.text = html
|
|
|
|
mock_get.side_effect = [ip_response, search_response]
|
|
|
|
wr = WebRequest()
|
|
wr.ppn = "test"
|
|
links = wr.get_book_links("test")
|
|
|
|
assert len(links) == 2
|
|
assert "https://rds.ibs-bw.de/opac/book/123" in links[0]
|
|
|
|
|
|
class TestBibTextTransformer:
|
|
"""Tests for BibTextTransformer class."""
|
|
|
|
def test_bibtexttransformer_init_valid_mode(self):
|
|
"""Test BibTextTransformer initialization with valid mode."""
|
|
bt = BibTextTransformer(TransformerType.ARRAY)
|
|
assert bt.mode == "ARRAY"
|
|
|
|
def test_bibtexttransformer_init_default_mode(self):
|
|
"""Test BibTextTransformer uses ARRAY as default mode."""
|
|
bt = BibTextTransformer()
|
|
assert bt.mode == "ARRAY"
|
|
|
|
def test_bibtexttransformer_invalid_mode(self):
|
|
"""Test BibTextTransformer raises error for invalid mode."""
|
|
|
|
# Create a fake invalid mode
|
|
class FakeMode:
|
|
value = "INVALID"
|
|
|
|
with pytest.raises(ValueError, match="not valid"):
|
|
BibTextTransformer(FakeMode())
|
|
|
|
def test_bibtexttransformer_use_signature(self):
|
|
"""Test use_signature method."""
|
|
bt = BibTextTransformer()
|
|
result = bt.use_signature("ABC 123")
|
|
assert result.signature == "ABC 123"
|
|
|
|
def test_bibtexttransformer_get_data_none(self):
|
|
"""Test get_data with None input."""
|
|
bt = BibTextTransformer()
|
|
result = bt.get_data(None)
|
|
assert result.data is None
|
|
|
|
def test_bibtexttransformer_get_data_ris(self):
|
|
"""Test get_data with RIS format."""
|
|
bt = BibTextTransformer(TransformerType.RIS)
|
|
data = ["Some data", "TY - BOOK\nTI - Test"]
|
|
result = bt.get_data(data)
|
|
assert "TY -" in result.data
|
|
|
|
def test_bibtexttransformer_get_data_array(self):
|
|
"""Test get_data with ARRAY format."""
|
|
bt = BibTextTransformer(TransformerType.ARRAY)
|
|
data = ["Some data", "[kid] => 123456"]
|
|
result = bt.get_data(data)
|
|
assert "[kid]" in result.data
|
|
|
|
def test_bibtexttransformer_get_data_coins(self):
|
|
"""Test get_data with COinS format."""
|
|
bt = BibTextTransformer(TransformerType.COinS)
|
|
data = ["Some data", "ctx_ver=Z39.88"]
|
|
result = bt.get_data(data)
|
|
assert "ctx_ver" in result.data
|
|
|
|
def test_bibtexttransformer_get_data_bibtex(self):
|
|
"""Test get_data with BibTeX format."""
|
|
bt = BibTextTransformer(TransformerType.BibTeX)
|
|
data = ["Some data", "@book{test2023,"]
|
|
result = bt.get_data(data)
|
|
assert "@book" in result.data
|
|
|
|
def test_bibtexttransformer_get_data_rds(self):
|
|
"""Test get_data with RDS format."""
|
|
bt = BibTextTransformer(TransformerType.RDS)
|
|
data = ["Some data", "RDS ---------------------------------- test"]
|
|
result = bt.get_data(data)
|
|
assert "RDS" in result.data
|
|
|
|
def test_bibtexttransformer_return_data_none(self):
|
|
"""Test return_data when data is None."""
|
|
bt = BibTextTransformer()
|
|
bt.get_data(None)
|
|
result = bt.return_data()
|
|
assert result is None
|
|
|
|
|
|
class TestCoverFunction:
|
|
"""Tests for the cover function."""
|
|
|
|
def test_cover_returns_content(self):
|
|
"""Test cover function returns image content."""
|
|
with patch("requests.get") as mock_get:
|
|
mock_response = MagicMock()
|
|
mock_response.content = b"fake_image_content"
|
|
mock_get.return_value = mock_response
|
|
|
|
result = cover("9783123456789")
|
|
assert result == b"fake_image_content"
|
|
|
|
def test_cover_url_format(self):
|
|
"""Test cover function calls correct URL."""
|
|
with patch("requests.get") as mock_get:
|
|
mock_response = MagicMock()
|
|
mock_response.content = b""
|
|
mock_get.return_value = mock_response
|
|
|
|
cover("9783123456789")
|
|
|
|
called_url = mock_get.call_args[0][0]
|
|
assert "9783123456789" in called_url
|
|
assert "buchhandel.de/cover" in called_url
|
|
|
|
|
|
class TestGetContentFunction:
|
|
"""Tests for the get_content function."""
|
|
|
|
def test_get_content(self):
|
|
"""Test get_content extracts text from div."""
|
|
from bs4 import BeautifulSoup
|
|
|
|
html = '<html><div class="test-class"> Content Here </div></html>'
|
|
soup = BeautifulSoup(html, "html.parser")
|
|
|
|
result = get_content(soup, "test-class")
|
|
assert result == "Content Here"
|