# This file is part of the Glowtables software # Copyright (C) 2023 Valentin Lorentz # # This program is free software: you can redistribute it and/or modify it under the # terms of the GNU Affero General Public License version 3, as published by the # Free Software Foundation. # # 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License along with # this program. If not, see . """Tests :mod:`glowtables.table`. Test cases use a graph containing a few CPUs, with names and clock frequencies. """ import textwrap from decimal import Decimal import pytest import rdflib from glowtables.sparql import SparqlBackend from glowtables.table import Language, LiteralField, Table CPU1_URI = rdflib.URIRef("http://example.org/grown-1700") CPU2_URI = rdflib.URIRef("http://example.org/grown-3600") CPU3_URI = rdflib.URIRef("http://example.org/secret-project") CG_URI = rdflib.URIRef("http://example.org/likestone-underdog") CPU = rdflib.URIRef("http://example.org/CPU") DISPLAY_NAME = rdflib.URIRef("http://example.org/display-name") FREQUENCY = rdflib.URIRef("http://example.org/clock-frequency") TYPE = rdflib.URIRef("http://example.org/type") @pytest.fixture() def rdflib_graph() -> rdflib.Graph: graph = rdflib.Graph() # A CPU with all the properties graph.add((CPU1_URI, DISPLAY_NAME, rdflib.Literal("Grown 1700"))) graph.add((CPU1_URI, TYPE, CPU)) graph.add((CPU1_URI, FREQUENCY, rdflib.Literal(3000))) # Another CPU, without a frequency graph.add((CPU2_URI, DISPLAY_NAME, rdflib.Literal("Grown 3600"))) graph.add((CPU2_URI, TYPE, CPU)) # Another CPU, without a name graph.add((CPU3_URI, TYPE, CPU)) graph.add((CPU3_URI, FREQUENCY, rdflib.Literal(9000))) # Add a graphics card; which should be excluded from CPU searches graph.add((CG_URI, DISPLAY_NAME, rdflib.Literal("LikeStone Underdog"))) graph.add((CG_URI, FREQUENCY, rdflib.Literal(1626))) graph.add((CG_URI, TYPE, rdflib.URIRef("http://example.org/graphics-card"))) return graph def test_single_literal(rdflib_sparql: SparqlBackend) -> None: name_field = LiteralField( "display_name", {Language("en"): "Name"}, str, rdflib.URIRef("http://example.org/display-name"), ) table = Table( id="test-table", fields=[name_field], constraints="?subject .", ) assert table.sparql() == textwrap.dedent( """ SELECT ?display_name WHERE { ?subject . ?subject ?display_name. } """ ) assert set(table.query(rdflib_sparql)) == { ("Grown 1700",), ("Grown 3600",), } def test_two_literals(rdflib_sparql: SparqlBackend) -> None: name_field = LiteralField( "display_name", {Language("en"): "Name"}, str, rdflib.URIRef("http://example.org/display-name"), ) frequency_field = LiteralField( "frequency", {Language("en"): "Clock frequency"}, Decimal, rdflib.URIRef("http://example.org/clock-frequency"), ) table = Table( id="test-table", fields=[name_field, frequency_field], constraints="?subject .", ) assert table.sparql() == textwrap.dedent( """ SELECT ?display_name ?frequency WHERE { ?subject . ?subject ?display_name. ?subject ?frequency. } """ ) assert set(table.query(rdflib_sparql)) == { ("Grown 1700", 3000), } def test_default_value(rdflib_sparql: SparqlBackend) -> None: name_field = LiteralField( "display_name", {Language("en"): "Name"}, str, rdflib.URIRef("http://example.org/display-name"), default="Anonymous CPU", ) frequency_field = LiteralField( "frequency", {Language("en"): "Clock frequency"}, Decimal, rdflib.URIRef("http://example.org/clock-frequency"), default=Decimal(0), ) table = Table( id="test-table", fields=[name_field, frequency_field], constraints="?subject .", ) assert table.sparql() == textwrap.dedent( """ SELECT ?display_name ?frequency WHERE { ?subject . OPTIONAL { ?subject ?display_name. }. OPTIONAL { ?subject ?frequency. }. } """ ) assert set(table.query(rdflib_sparql)) == { ("Grown 1700", 3000), ("Grown 3600", None), (None, 9000), } def test_field_id_subject() -> None: name_field = LiteralField( "subject", {Language("en"): "Name"}, str, rdflib.URIRef("http://example.org/display-name"), ) with pytest.raises(ValueError, match="both subject and a field id"): Table( id="test-table", fields=[name_field], constraints="", ) def test_field_id_clash() -> None: name_field = LiteralField( "name", {Language("en"): "Name"}, str, rdflib.URIRef("http://example.org/name"), ) display_name_field = LiteralField( "name", {Language("en"): "Display Name"}, str, rdflib.URIRef("http://example.org/display-name"), ) with pytest.raises(ValueError, match="has duplicate field ids: name"): Table( id="test-table", fields=[name_field, display_name_field], constraints="", )