Coverage for tests / test_provenance.py: 100%

74 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2026-07-17 16:43 +0000

1#!/usr/bin/env python3 

2 

3# SPDX-FileCopyrightText: 2025-2026 Arcangelo Massari <arcangelo.massari@unibo.it> 

4# 

5# SPDX-License-Identifier: ISC 

6 

7""" 

8Tests for the provenance generator script. 

9""" 

10 

11import os 

12import sys 

13import tempfile 

14import shutil 

15import pytest 

16from rdflib import Dataset, URIRef, Namespace 

17from rdflib.namespace import RDF 

18 

19# Add the src directory to the path so we can import the module 

20sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 

21from changes_metadata_manager.generate_provenance import generate_provenance_snapshots 

22 

23 

24@pytest.fixture 

25def test_environment(): 

26 """Set up test data and environment.""" 

27 test_dir = tempfile.mkdtemp(dir="./tests/") 

28 test_ttl = os.path.join(test_dir, "test_data.ttl") 

29 test_output = tempfile.mktemp(suffix=".nq") 

30 

31 # Create test data file 

32 with open(test_ttl, "w") as f: 

33 f.write(""" 

34@prefix ex: <http://example.org/> . 

35@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . 

36@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . 

37@prefix crm: <http://www.cidoc-crm.org/cidoc-crm/> . 

38 

39ex:item1 a crm:E22_Human-Made_Object ; 

40 rdfs:label "Test Manuscript" . 

41 

42ex:item2 a crm:E21_Person ; 

43 rdfs:label "John Doe" . 

44 """) 

45 

46 yield {"test_dir": test_dir, "test_ttl": test_ttl, "test_output": test_output} 

47 

48 # Clean up 

49 if os.path.exists(test_dir): 

50 shutil.rmtree(test_dir) 

51 if os.path.exists(test_output): 

52 os.remove(test_output) 

53 

54 

55def test_provenance_generation(test_environment): 

56 """Test that provenance snapshots are generated correctly.""" 

57 # Get test environment variables 

58 test_dir = test_environment["test_dir"] 

59 test_output = test_environment["test_output"] 

60 

61 # Generate provenance snapshots 

62 agent_orcid = "https://orcid.org/0000-0002-8420-0696" 

63 primary_source = "https://example.org/primary-source" 

64 generate_provenance_snapshots( 

65 test_dir, 

66 test_output, 

67 output_format="trig", 

68 agent_orcid=agent_orcid, 

69 primary_source=primary_source, 

70 ) 

71 

72 # Check that the output file was created 

73 assert os.path.exists(test_output), "Output file was not created" 

74 

75 # Load the output file 

76 dataset = Dataset() 

77 dataset.parse(test_output, format="trig") 

78 

79 # Define namespaces 

80 PROV = Namespace("http://www.w3.org/ns/prov#") 

81 

82 # Check that we have the expected named graphs 

83 expected_graphs = [ 

84 URIRef("http://example.org/item1/prov/"), 

85 URIRef("http://example.org/item2/prov/"), 

86 ] 

87 actual_graphs = [g.identifier for g in dataset.graphs()] 

88 

89 for graph in expected_graphs: 

90 assert graph in actual_graphs, f"Expected graph {graph} not found" 

91 

92 # Check that snapshots are typed as prov:Entity 

93 item1_prov_graph = dataset.graph(URIRef("http://example.org/item1/prov/")) 

94 item2_prov_graph = dataset.graph(URIRef("http://example.org/item2/prov/")) 

95 

96 item1_snapshot = URIRef("http://example.org/item1/prov/se/1") 

97 item2_snapshot = URIRef("http://example.org/item2/prov/se/1") 

98 

99 assert (item1_snapshot, RDF.type, PROV.Entity) in item1_prov_graph, ( 

100 "item1 snapshot is not typed as prov:Entity" 

101 ) 

102 assert (item2_snapshot, RDF.type, PROV.Entity) in item2_prov_graph, ( 

103 "item2 snapshot is not typed as prov:Entity" 

104 ) 

105 

106 # Check for specializationOf relationship 

107 assert ( 

108 item1_snapshot, 

109 PROV.specializationOf, 

110 URIRef("http://example.org/item1"), 

111 ) in item1_prov_graph 

112 assert ( 

113 item2_snapshot, 

114 PROV.specializationOf, 

115 URIRef("http://example.org/item2"), 

116 ) in item2_prov_graph 

117 

118 # Check for primary source relationship 

119 assert ( 

120 item1_snapshot, 

121 PROV.hadPrimarySource, 

122 URIRef(primary_source), 

123 ) in item1_prov_graph, "item1 snapshot missing primary source" 

124 assert ( 

125 item2_snapshot, 

126 PROV.hadPrimarySource, 

127 URIRef(primary_source), 

128 ) in item2_prov_graph, "item2 snapshot missing primary source" 

129 

130 

131def test_input_format_parameter(test_environment): 

132 """Test that the input_format parameter works correctly.""" 

133 # Get test environment variables 

134 test_dir = test_environment["test_dir"] 

135 test_output = test_environment["test_output"] 

136 

137 # Create a file with an unknown extension but containing Turtle content 

138 test_unknown = os.path.join(test_dir, "unknown_format.xyz") 

139 with open(test_unknown, "w") as f: 

140 f.write(""" 

141@prefix ex: <http://example.org/> . 

142@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . 

143@prefix crm: <http://www.cidoc-crm.org/cidoc-crm/> . 

144 

145ex:item3 a crm:E22_Human-Made_Object ; 

146 rdfs:label "Test Object with Unknown Format" . 

147 """) 

148 

149 # Generate provenance snapshots, specifying the format explicitly 

150 agent_orcid = "https://orcid.org/0000-0002-8420-0696" 

151 primary_source = "https://example.org/primary-source" 

152 generate_provenance_snapshots( 

153 test_dir, 

154 test_output, 

155 input_format="turtle", 

156 output_format="trig", 

157 agent_orcid=agent_orcid, 

158 primary_source=primary_source, 

159 ) 

160 

161 # Check that the output file was created 

162 assert os.path.exists(test_output), "Output file was not created" 

163 

164 # Load the output file 

165 dataset = Dataset() 

166 dataset.parse(test_output, format="trig") 

167 

168 # Define namespaces 

169 PROV = Namespace("http://www.w3.org/ns/prov#") 

170 

171 # Check that we have the expected named graph for item3 

172 item3_graph = URIRef("http://example.org/item3/prov/") 

173 actual_graphs = [g.identifier for g in dataset.graphs()] 

174 assert item3_graph in actual_graphs, f"Expected graph {item3_graph} not found" 

175 

176 # Check that snapshot is typed as prov:Entity 

177 item3_prov_graph = dataset.graph(item3_graph) 

178 item3_snapshot = URIRef("http://example.org/item3/prov/se/1") 

179 assert (item3_snapshot, RDF.type, PROV.Entity) in item3_prov_graph, ( 

180 "item3 snapshot is not typed as prov:Entity" 

181 ) 

182 

183 

184def test_empty_directory(test_environment): 

185 """Test that the script handles empty directories correctly.""" 

186 # Create an empty directory 

187 empty_dir = tempfile.mkdtemp(dir="./tests/") 

188 test_output = test_environment["test_output"] 

189 

190 try: 

191 # Generate provenance snapshots for the empty directory 

192 agent_orcid = "https://orcid.org/0000-0002-8420-0696" 

193 primary_source = "https://example.org/primary-source" 

194 generate_provenance_snapshots( 

195 empty_dir, 

196 test_output, 

197 agent_orcid=agent_orcid, 

198 primary_source=primary_source, 

199 ) 

200 

201 # Check that the output file was not created 

202 assert not os.path.exists(test_output), ( 

203 "Output file should not be created for empty directory" 

204 ) 

205 finally: 

206 # Clean up 

207 if os.path.exists(empty_dir): 

208 shutil.rmtree(empty_dir) 

209 

210 

211if __name__ == "__main__": 

212 pytest.main()