6824a10e57dc50ddc8a3c48246e24722a59acdea
[jalview.git] / test / jalview / ws2 / client / slivka / SlivkaWSDiscovererTest.java
1 package jalview.ws2.client.slivka;
2
3 import static org.hamcrest.MatcherAssert.assertThat;
4 import static org.hamcrest.Matchers.*;
5 import static org.mockito.Mockito.mock;
6 import static org.mockito.Mockito.when;
7
8 import java.io.IOException;
9 import java.net.MalformedURLException;
10 import java.net.URI;
11 import java.net.URL;
12 import java.util.ArrayList;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.function.Function;
17
18 import org.hamcrest.Matcher;
19 import org.testng.annotations.BeforeClass;
20 import org.testng.annotations.BeforeMethod;
21 import org.testng.annotations.DataProvider;
22 import org.testng.annotations.Test;
23
24 import jalview.bin.Cache;
25 import jalview.bin.Console;
26 import jalview.ws.params.ValueConstrainI.ValueType;
27 import jalview.ws.params.simple.BooleanOption;
28 import jalview.ws.params.simple.DoubleParameter;
29 import jalview.ws.params.simple.IntegerParameter;
30 import jalview.ws.params.simple.StringParameter;
31 import jalview.ws2.actions.alignment.AlignmentAction;
32 import jalview.ws2.actions.annotation.AnnotationAction;
33 import jalview.ws2.client.api.WebServiceDiscovererI;
34 import uk.ac.dundee.compbio.slivkaclient.Parameter;
35 import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
36 import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
37
38 public class SlivkaWSDiscovererTest
39 {
40   private static final String URLS_PROPERTY_NAME = "SLIVKAHOSTURLS";
41
42   SlivkaClient clientMock;
43
44   Function<URL, SlivkaClient> factoryMock;
45
46   @BeforeClass(alwaysRun = true)
47   public void setupProperties()
48   {
49     Cache.loadProperties("test/jalview/ws2/client/slivka/default.jvprops");
50     Console.initLogger();
51   }
52
53   @BeforeMethod
54   public void setupDiscoverer() throws IOException
55   {
56     clientMock = mock(SlivkaClient.class);
57   }
58
59   @Test(groups = { "Functional" })
60   public void getStatusForUrl_servicesReturned_statusIsOK() throws Exception
61   {
62     when(clientMock.getServices())
63         .thenReturn(List.of(mock(SlivkaService.class)));
64     var discoverer = new SlivkaWSDiscoverer(
65         url -> url.toString().equals("http://example.org") ? clientMock
66             : null);
67     assertThat(discoverer.getStatusForUrl(new URL("http://example.org")),
68         is(WebServiceDiscovererI.STATUS_OK));
69   }
70
71   @Test(groups = { "Functional" })
72   public void getStatusForUrl_noServicesReturned_statusIsNoServices()
73       throws Exception
74   {
75     when(clientMock.getServices()).thenReturn(List.of());
76     var discoverer = new SlivkaWSDiscoverer(
77         url -> url.toString().equals("http://example.org") ? clientMock
78             : null);
79     assertThat(discoverer.getStatusForUrl(new URL("http://example.org")),
80         is(WebServiceDiscovererI.STATUS_NO_SERVICES));
81   }
82
83   @Test(groups = { "Functional" })
84   public void getStatusForUrl_exceptionThrown_statusIsInvalid()
85       throws Exception
86   {
87     when(clientMock.getServices()).thenThrow(new IOException());
88     var discoverer = new SlivkaWSDiscoverer(
89         url -> url.toString().equals("http://example.org") ? clientMock
90             : null);
91     assertThat(discoverer.getStatusForUrl(new URL("http://example.org")),
92         is(WebServiceDiscovererI.STATUS_INVALID));
93   }
94
95   @Test(groups = { "Functional" })
96   public void testGetUrls_noPropEntry_defaultUrlReturned()
97       throws MalformedURLException
98   {
99     var discoverer = SlivkaWSDiscoverer.getInstance();
100     assertThat(discoverer.getUrls(),
101         contains(new URL("https://www.compbio.dundee.ac.uk/slivka/")));
102   }
103
104   @DataProvider
105   public Object[][] urlPropertyValues() throws MalformedURLException
106   {
107     return new Object[][] {
108         { "http://example.org/", List.of(new URL("http://example.org/")) },
109         { "https://example.org/slivka/",
110             List.of(new URL("https://example.org/slivka/")) },
111         { "https://www.compbio.dundee.ac.uk/,http://www.example.org/",
112             List.of(new URL("https://www.compbio.dundee.ac.uk/"),
113                 new URL("http://www.example.org/")) },
114         { "http://example.org/,", List.of(new URL("http://example.org/")) },
115         { ",http://example.org", List.of(new URL("http://example.org")) },
116         { "", List.of() },
117         { ",", List.of() },
118         { "example.org", List.of() },
119         { "example.org,http://example.org",
120             List.of(new URL("http://example.org")) } };
121   }
122
123   @Test(groups = { "Functional" }, dataProvider = "urlPropertyValues")
124   public void testGetUrls_urlsProperlyParsed(String propValue,
125       List<URL> expected)
126   {
127     Cache.setProperty(URLS_PROPERTY_NAME, propValue);
128     var discoverer = SlivkaWSDiscoverer.getInstance();
129     assertThat(discoverer.getUrls(), equalTo(expected));
130   }
131
132   @Test(groups = { "Functional" })
133   public void testSetUrls_emptyList_propertyReset()
134   {
135     Cache.setProperty(URLS_PROPERTY_NAME, "http://www.example.org");
136     var discoverer = SlivkaWSDiscoverer.getInstance();
137     discoverer.setUrls(List.of());
138     assertThat(Cache.getProperty(URLS_PROPERTY_NAME), is(nullValue()));
139   }
140
141   @Test(groups = { "Functional" })
142   public void testSetUrls_null_propertyReset()
143   {
144     Cache.setProperty(URLS_PROPERTY_NAME, "http://www.example.org");
145     var discoverer = SlivkaWSDiscoverer.getInstance();
146     discoverer.setUrls(null);
147     assertThat(Cache.getProperty(URLS_PROPERTY_NAME), is(nullValue()));
148   }
149
150   @DataProvider
151   public Object[][] urlsList() throws MalformedURLException
152   {
153     return new Object[][] {
154         { List.of(new URL("http://example.org")), "http://example.org" },
155         { List.of(new URL("http://example.org/")), "http://example.org/" },
156         { List.of(new URL("http://example.org/slivka/")),
157             "http://example.org/slivka/" },
158         { List.of(new URL("https://www.compbio.dundee.ac.uk/slivka/"),
159             new URL("http://example.org")),
160             "https://www.compbio.dundee.ac.uk/slivka/,http://example.org" }, };
161   }
162
163   @Test(groups = { "Functional" }, dataProvider = "urlsList")
164   public void testSetUrls_urlsPropertySet(List<URL> urls, String expected)
165       throws MalformedURLException
166   {
167     var discoverer = SlivkaWSDiscoverer.getInstance();
168     discoverer.setUrls(urls);
169     assertThat(Cache.getProperty(URLS_PROPERTY_NAME), equalTo(expected));
170   }
171
172   @Test(groups = { "Functional" })
173   public void testFetchServices_oneService_basicDataMatches()
174       throws IOException
175   {
176     var service = new SlivkaService(
177         URI.create("http://example.org/api/services/example"),
178         "example", "Example name", "Example service description",
179         "John Smith", "1.0", "MIT License",
180         List.of("operation::analysis::multiple sequence alignment"),
181         List.of(), List.of(), null);
182     when(clientMock.getServices()).thenReturn(List.of(service));
183     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
184     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
185     var webServices = discoverer
186         .fetchServices(new URL("http://example.org/"));
187     assertThat(webServices, hasSize(1));
188     var webService = webServices.get(0);
189     assertThat(webService.getUrl(),
190         equalTo(new URL("http://example.org/")));
191     assertThat(webService.getClientName(), equalTo("slivka"));
192     assertThat(webService.getName(), equalTo("Example name"));
193     assertThat(webService.getDescription(),
194         equalTo("Example service description"));
195   }
196
197   @DataProvider
198   public String[] validMultipleSequenceAlignmentClassifiers()
199   {
200     return new String[] {
201         "Operation :: Analysis :: Multiple sequence alignment",
202         "operation :: analysis :: multiple sequence alignment",
203         "Operation\t::\tAnalysis\t::\tMultiple sequence alignment",
204         "Operation::Analysis::Multiple sequence alignment",
205         "Operation :: Analysis :: Multiple Sequence Alignment",
206         "OPERATION :: ANALYSIS :: MULTIPLE SEQUENCE ALIGNMENT",
207         "Operation :: Analysis :: Sequence alignment :: Multiple sequence alignment",
208         "Operation :: Analysis :: Sequence analysis :: Sequence alignment :: Multiple sequence alignment",
209         "Operation :: Alignment :: Multiple sequence alignment",
210         "Operation :: Alignment :: Sequence alignment :: Multiple sequence alignment",
211         "Operation :: Comparison :: Multiple sequence alignment",
212         "Operation :: Comparison :: Sequence comparison :: Sequence alignment :: Multiple sequence alignment" };
213
214   }
215
216   @Test(
217     groups = { "Functional" },
218     dataProvider = "validMultipleSequenceAlignmentClassifiers")
219   public void testFetchServices_multipleSequenceAlignmentClassifier_serviceTypeIsMSA(
220       String classifier) throws IOException
221   {
222     var service = new SlivkaService(URI.create("http://example.org/"),
223         "example", "name", "description", "author", "1.0", "MIT",
224         List.of(classifier), List.of(), List.of(), null);
225     when(clientMock.getServices()).thenReturn(List.of(service));
226     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
227     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
228     var webServices = discoverer
229         .fetchServices(new URL("http://example.org/"));
230     assertThat(webServices, hasSize(1));
231     assertThat(webServices.get(0).getCategory(), equalTo("Alignment"));
232     assertThat(webServices.get(0).getActionClass(),
233         typeCompatibleWith(AlignmentAction.class));
234   }
235
236   @DataProvider
237   public SlivkaService[] multipleSequenceAlignmentService()
238   {
239     return new SlivkaService[] {
240         new SlivkaService(
241             URI.create("http://example.org/"), "example", "Examaple name",
242             "Example description", "John Smith", "1.0", "MIT",
243             List.of("Operation :: Analysis :: Multiple sequence alignment"),
244             List.of(), List.of(), null),
245         new SlivkaService(
246             URI.create("http://example.org/api/services/muscle"),
247             "muscle", "MUSCLE",
248             "MUltiple Sequence Comparison by Log- Expectation",
249             "Robert C. Edgar", "3.8.31", "Public domain",
250             List.of("Topic :: Computational biology :: Sequence analysis",
251                 "Operation :: Analysis :: Sequence analysis :: Sequence alignment :: Multiple sequence alignment"),
252             List.of(), List.of(), null),
253         new SlivkaService(
254             URI.create("http://example.org/api/services/tcoffee"),
255             "tcoffee", "TCoffee",
256             "Tree-based Consistency Objective Function for Alignment Evaluation",
257             "Cedric Notredame", "13.41.0", "GNU GPL",
258             List.of("Topic :: Computational biology :: Sequence analysis",
259                 "Operation :: Analysis :: Sequence analysis :: Sequence alignment :: Multiple sequence alignment"),
260             List.of(), List.of(), null) };
261   }
262
263   @Test(
264     groups = { "Functional" },
265     dataProvider = "multipleSequenceAlignmentService")
266   public void testFetchServices_multipleSequenceAlignmentService_actionTypeIsAlignment(
267       SlivkaService service) throws IOException
268   {
269     when(clientMock.getServices()).thenReturn(List.of(service));
270     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
271     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
272     var webServices = discoverer
273         .fetchServices(new URL("http://example.org/"));
274     assertThat(webServices.get(0).getCategory(), equalTo("Alignment"));
275     assertThat(webServices.get(0).getActionClass(),
276         typeCompatibleWith(AlignmentAction.class));
277   }
278
279   @Test(
280     groups = { "Functional" },
281     dataProvider = "multipleSequenceAlignmentService")
282   public void testFetchServices_multipleSequenceAlignmentService_serviceIsNonInteractive(
283       SlivkaService service) throws IOException
284   {
285     when(clientMock.getServices()).thenReturn(List.of(service));
286     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
287     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
288     var webServices = discoverer
289         .fetchServices(new URL("http://example.org/"));
290     assertThat(webServices.get(0).isInteractive(), is(false));
291   }
292
293   @DataProvider
294   public SlivkaService[] clustalFamilyService()
295   {
296     return new SlivkaService[] {
297         new SlivkaService(
298             URI.create("http://example.org/api/services/clustalo"),
299             "clustalo", "ClustalO",
300             "Clustal Omega is the latest addition to the Clustal family.",
301             "Fabian Sievers, et al.", "1.2.4", "GNU GPL ver. 2",
302             List.of("Topic :: Computational biology :: Sequence analysis",
303                 "Operation :: Analysis :: Sequence analysis :: Sequence alignment :: Multiple sequence alignment"),
304             List.of(), List.of(), null),
305         new SlivkaService(
306             URI.create("http://example.org/api/services/clustalw"),
307             "clustalw", "ClustalW",
308             "ClustalW is a general purpose multiple alignment program.",
309             "Larkin MA, et al.", "2.1", "GNU GPL ver. 3",
310             List.of("Topic :: Computation biology :: Sequence analysis",
311                 "Operation :: Analysis :: Multiple sequence alignment"),
312             List.of(), List.of(), null),
313         new SlivkaService(
314             URI.create("http://example.org/api/services/clustalw2"),
315             "clustalw2", "ClustalW2",
316             "ClustalW is a general purpose multiple alignment program.",
317             "Larkin MA, et al.", "2.1", "GNU GPL ver. 3",
318             List.of("Topic :: Computation biology :: Sequence analysis",
319                 "Operation :: Analysis :: Multiple sequence alignment"),
320             List.of(), List.of(), null), };
321   }
322
323   @Test(groups = { "Functional" }, dataProvider = "clustalFamilyService")
324   public void testFetchService_clustalFamilyService_containsTwoActions(
325       SlivkaService service) throws IOException
326   {
327     when(clientMock.getServices()).thenReturn(List.of(service));
328     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org"));
329     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
330     var webServices = discoverer
331         .fetchServices(new URL("http://example.org"));
332     var actions = webServices.get(0).getActions();
333     assertThat(actions, hasSize(2));
334     assertThat(actions.get(0), allOf(hasProperty("name", is("Alignment")),
335         hasProperty("subcategory", is("Align"))));
336     assertThat(actions.get(1),
337         allOf(hasProperty("name", is("Re-alignment")),
338             hasProperty("subcategory", is("Realign"))));
339   }
340
341   @DataProvider
342   public String[] validRNASecondaryStructurePredictionClassifiers()
343   {
344     return new String[] {
345         "Operation :: Analysis :: RNA secondary structure prediction",
346         "operation :: analysis :: rna secondary structure prediction",
347         "OPERATION :: ANALYSIS :: RNA SECONDARY STRUCTURE PREDICTION",
348         "Operation\t::\tAnalysis\t::\tRNA secondary structure prediction",
349         "Operation::Analysis::RNA secondary structure prediction",
350         "Operation :: Analysis :: Structure analysis :: RNA secondary structure prediction",
351         "Operation :: Analysis :: Structure analysis :: Nucleic acid structure analysis :: RNA secondary structure analysis :: RNA secondary structure prediction",
352         "Operation :: Analysis :: Structure analysis :: Nucleic acid structure analysis :: Nucleic acid structure prediction :: RNA secondary structure prediction",
353         "Operation :: Analysis :: Sequence analysis :: Nucleic acid sequence analysis :: Nucleic acid feature detection :: RNA secondary structure prediction",
354         "Operation :: Prediction and recognition :: RNA secondary structure prediction",
355         "Operation :: Prediction and recognition :: Nucleic acid feature detection :: RNA secondary structure prediction",
356         "Operation :: Prediction and recignition :: Nucleic acid structure prediction :: RNA secondary structure prediction", };
357   }
358
359   @DataProvider
360   public Iterator<Object> RNASecondaryStructurePredictionService()
361   {
362     var services = new ArrayList<>();
363     for (var classifier : validRNASecondaryStructurePredictionClassifiers())
364     {
365       services.add(new SlivkaService(URI.create("http://example.org/"),
366           "example", "name", "description", "author", "1.0", "MIT",
367           List.of(classifier), List.of(), List.of(), null));
368     }
369     return services.iterator();
370   }
371
372   @Test(
373     groups = { "Functional" },
374     dataProvider = "RNASecondaryStructurePredictionService")
375   public void testFetchServices_RNASecStrPredClassifier_serviceTypeIsRNASecStrPred(
376       SlivkaService service) throws IOException
377   {
378     when(clientMock.getServices()).thenReturn(List.of(service));
379     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
380     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
381     var webServices = discoverer
382         .fetchServices(new URL("http://example.org/"));
383     assertThat(webServices, hasSize(1));
384     assertThat(webServices.get(0).getCategory(),
385         equalTo("Secondary Structure Prediction"));
386     assertThat(webServices.get(0).getActionClass(),
387         typeCompatibleWith(AnnotationAction.class));
388   }
389
390   @DataProvider
391   public String[] validConservationAnalysisClassifiers()
392   {
393     return new String[] {
394         "Operation :: Analysis :: Sequence alignment analysis (conservation)",
395         "Operation::Analysis::Sequence alignment analysis (conservation)",
396         "Operation\t::\tAnalysis\t::\tSequence alignment analysis (conservation)",
397         "Operation :: Analysis :: Sequence analysis :: Sequence alignment analysis (conservation)",
398         "Operation :: Analysis :: Sequence analysis :: Sequence alignment analysis :: Sequence alignment analysis (conservation)", };
399   }
400
401   @DataProvider
402   public Iterator<Object> ConservationAnalysisService()
403   {
404     var services = new ArrayList<>();
405     for (var classifier : validConservationAnalysisClassifiers())
406     {
407       services.add(new SlivkaService(URI.create("http://example.org/"),
408           "example", "name", "description", "author", "1.0", "MIT",
409           List.of(classifier), List.of(), List.of(), null));
410     }
411     return services.iterator();
412   }
413
414   @Test(
415     groups = { "Functional" },
416     dataProvider = "validConservationAnalysisClassifiers")
417   public void testFetchServices_conservationAnalysisClassifier_serviceTypeIsConservation(
418       String classifier) throws IOException
419   {
420     var service = new SlivkaService(URI.create("http://example.org/"),
421         "example", "name", "description", "author", "1.0", "MIT",
422         List.of(classifier), List.of(), List.of(), null);
423     when(clientMock.getServices()).thenReturn(List.of(service));
424     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
425     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
426     var webServices = discoverer
427         .fetchServices(new URL("http://example.org/"));
428     assertThat(webServices, hasSize(1));
429     assertThat(webServices.get(0).getCategory(), equalTo("Conservation"));
430     assertThat(webServices.get(0).getActionClass(),
431         typeCompatibleWith(AnnotationAction.class));
432   }
433
434   @DataProvider
435   public Object[] validProteinSequenceAnalysisClassifiers()
436   {
437     return new Object[] {
438         "Operation :: Analysis :: Sequence analysis :: Protein sequence analysis", };
439   }
440
441   @Test(
442     groups = { "Functional" },
443     dataProvider = "validProteinSequenceAnalysisClassifiers")
444   public void testFetchServices_proteinSequenceAnalysisClassifier_serviceTypeIsProtSeqAnalysis(
445       String classifier) throws IOException
446   {
447     var service = new SlivkaService(URI.create("http://example.org/"),
448         "example", "name", "description", "author", "1.0", "MIT",
449         List.of(classifier), List.of(), List.of(), null);
450     when(clientMock.getServices()).thenReturn(List.of(service));
451     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
452     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
453     var webServices = discoverer
454         .fetchServices(new URL("http://example.org/"));
455     assertThat(webServices, hasSize(1));
456     assertThat(webServices.get(0).getCategory(),
457         equalTo("Protein Disorder"));
458     assertThat(webServices.get(0).getActionClass(),
459         typeCompatibleWith(AnnotationAction.class));
460   }
461
462   @DataProvider
463   public Object[] validProteinSecondaryStructurePredictionClassifiers()
464   {
465     return new Object[] {
466         "Operation ;: Analysis :: Protein secondary structure prediction",
467         "Operation :: Analysis :: Structure analysis :: Protein structure analysis :: Protein secondary structure analysis :: Protein secondary structure prediction",
468         "Operation :: Analysis :: Sequence analysis :: Protein sequence analysis :: Protein feature detection :: Protein secondary structure prediction",
469         "Operation :: Analysis :: Sequence analysis :: Protein sequence analysis :: Protein secondary structure prediction",
470         "Operation :: Prediction and recognition :: Protein secondary structure prediction",
471         "Operation :: Prediction and recognition :: Protein feature detection :: Protein secondary structure prediction", };
472   }
473
474   @Test(
475     enabled = false, // sec. str. pred. not implemented for slivka
476     groups = { "Functional" },
477     dataProvider = "validProteinSecondaryStructurePredictionClassifiers")
478   public void testFetchServices_proteinSecStrPredClassifier_serviceTypeIsProtSecStrPred(
479       String classifier) throws IOException
480   {
481     var service = new SlivkaService(URI.create("http://example.org/"),
482         "example", "name", "description", "author", "1.0", "MIT",
483         List.of(classifier), List.of(), List.of(), null);
484     when(clientMock.getServices()).thenReturn(List.of(service));
485     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
486     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
487     var webServices = discoverer
488         .fetchServices(new URL("http://example.org/"));
489     assertThat(webServices, hasSize(1));
490     assertThat(webServices.get(0).getCategory(),
491         equalTo("Protein Disorder"));
492     assertThat(webServices.get(0).getActionClass(),
493         typeCompatibleWith(AnnotationAction.class));
494   }
495
496   @DataProvider
497   public SlivkaService[] unrecognisedService()
498   {
499     return new SlivkaService[] {
500         new SlivkaService(URI.create("http://example.org/"), "example",
501             "Example name", "Example description", "John Smith",
502             "1.0.0", "Apache License, version 2.0",
503             List.of("This :: Classifier :: Does not exist"), List.of(),
504             List.of(), null) };
505   }
506
507   @Test(groups = { "Functional" }, dataProvider = "unrecognisedService")
508   public void testFetchServices_unrecognisedService_noServiceDiscovered(
509       SlivkaService service) throws IOException
510   {
511     when(clientMock.getServices()).thenReturn(List.of(service));
512     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org"));
513     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
514     var webServices = discoverer
515         .fetchServices(new URL("http://example.org"));
516     assertThat(webServices, hasSize(0));
517   }
518
519   @DataProvider
520   public Object[] serviceParameterAndMappedClass()
521   {
522     return new Object[][] {
523         {
524             new Parameter.IntegerParameter("param", "Parameter", "Description",
525                 true, false, null, Map.of(), null, null),
526             IntegerParameter.class
527         },
528         {
529             new Parameter.DecimalParameter("param", "Parameter",
530                 "Description", true, false, null, Map.of(), null, null,
531                 false, false),
532             DoubleParameter.class
533         },
534         {
535             new Parameter.TextParameter("param", "Parameter", "Description",
536                 true, false, null, Map.of(), 0, null),
537             StringParameter.class
538         },
539         {
540             new Parameter.FlagParameter("param", "Parameter", "Description",
541                 true, false, null, Map.of()),
542             BooleanOption.class
543         },
544         {
545             new Parameter.ChoiceParameter("param", "Parameter", "Description",
546                 true, false, null, Map.of(), List.of()),
547             StringParameter.class
548         },
549     };
550   }
551
552   @Test(
553     groups = { "Functional" },
554     dataProvider = "serviceParameterAndMappedClass")
555   public void testServiceParameter_slivkaParameterMappedToJalviewParameter(
556       Parameter slivkaParameter, Class<?> expectedClass)
557       throws IOException
558   {
559     var service = new SlivkaService(URI.create("http://example.org"),
560         "example", "name", "description", "author", "1.0",
561         "MIT License",
562         List.of("Operation :: Analysis :: Multiple sequence alignment"),
563         List.of(slivkaParameter), List.of(), null);
564     when(clientMock.getServices()).thenReturn(List.of(service));
565     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org"));
566     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
567     var webServices = discoverer
568         .fetchServices(new URL("http://example.org"));
569     var paramDatastore = webServices.get(0).getParamDatastore();
570     var arguments = paramDatastore.getServiceParameters();
571     assertThat(arguments.get(0), instanceOf(expectedClass));
572   }
573
574   @DataProvider
575   public Object[][] serviceParametersAndPropertyMatcher()
576   {
577     return new Object[][] {
578         {
579             new Parameter.IntegerParameter("param1", "Parameter 1",
580                 "Description of parameter 1", true, false, null, Map.of(),
581                 null, null),
582             allOf(
583                 hasProperty("name", equalTo("param1")),
584                 hasProperty("label", equalTo("Parameter 1")),
585                 hasProperty("description", equalTo("Description of parameter 1")),
586                 hasProperty("required", is(true)),
587                 hasProperty("value", nullValue()))
588         },
589         {
590             new Parameter.IntegerParameter("param2", null, null, true, false,
591                 null, Map.of(), null, null),
592             allOf(
593                 hasProperty("name", equalTo("param2")),
594                 hasProperty("label", equalTo("param2")),
595                 hasProperty("description", nullValue()),
596                 hasProperty("required", is(true)),
597                 hasProperty("value", nullValue()))
598         },
599         {
600             new Parameter.IntegerParameter("param3", "Parameter 3", "", false,
601                 false, 12, Map.of(), null, null),
602             allOf(
603                 hasProperty("name", equalTo("param3")),
604                 hasProperty("label", equalTo("Parameter 3")),
605                 hasProperty("description", equalTo("")),
606                 hasProperty("required", is(false)),
607                 hasProperty("value", equalTo("12")))
608         },
609     };
610   }
611
612   @Test(
613     groups = { "Functional" },
614     dataProvider = "serviceParametersAndPropertyMatcher")
615   public void testServiceParameters_testBasicParameterProperties(
616       Parameter parameter, Matcher<Object> matcher) throws IOException
617   {
618     var service = new SlivkaService(URI.create("http://example.org/"),
619         "example", "Example name", "Example description", "John Smith",
620         "1.0", "MIT",
621         List.of("Operation :: Analysis :: Multiple sequence alignment"),
622         List.of(parameter), List.of(), null);
623     when(clientMock.getServices()).thenReturn(List.of(service));
624     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
625     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
626     var webServices = discoverer
627         .fetchServices(new URL("http://example.org/"));
628     var paramDatastore = webServices.get(0).getParamDatastore();
629     var arguments = paramDatastore.getServiceParameters();
630     assertThat(arguments.get(0), matcher);
631   }
632
633   @DataProvider
634   public Object[][] integerParametersAndPropertyMatcher()
635   {
636     return new Object[][] {
637         {
638             new Parameter.IntegerParameter("param", null, null, true, false,
639                 null, Map.of(), null, null),
640             hasProperty("validValue", hasProperty("type", is(ValueType.Integer)))
641         },
642         {
643             new Parameter.IntegerParameter("param", null, null, true, false,
644                 null, Map.of(), null, null),
645             hasProperty("validValue", allOf(
646                 hasProperty("min", nullValue()),
647                 hasProperty("max", nullValue()))),
648         },
649         {
650             new Parameter.IntegerParameter("param", null, null, true, false,
651                 null, Map.of(), -12, 42),
652             hasProperty("validValue", allOf(
653                 hasProperty("min", is(-12)),
654                 hasProperty("max", is(42))))
655         },
656     };
657   }
658
659   @Test(
660     groups = { "Functional" },
661     dataProvider = "integerParametersAndPropertyMatcher")
662   public void testServiceParameters_testIntegerProperties(
663       Parameter parameter, Matcher<Object> matcher) throws IOException
664   {
665     var service = new SlivkaService(URI.create("http://example.org"),
666         "example", "Example name", "Example description", "John Smith",
667         "1.0", "MIT",
668         List.of("Operation :: Analysis :: Multiple Sequence Alignment"),
669         List.of(parameter), List.of(), null);
670     when(clientMock.getServices()).thenReturn(List.of(service));
671     when(clientMock.getUrl()).thenReturn(URI.create("http://example.org/"));
672     var discoverer = new SlivkaWSDiscoverer(url -> clientMock);
673     var webServices = discoverer
674         .fetchServices(new URL("http://example.org/"));
675     var paramDatastore = webServices.get(0).getParamDatastore();
676     var arguments = paramDatastore.getServiceParameters();
677     assertThat(arguments.get(0), matcher);
678   }
679 }