package org.nextprot.api.isoform.mapper.service;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.io.Files;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.Mockito;
import org.nextprot.api.commons.bio.AminoAcidCode;
import org.nextprot.api.commons.constants.AnnotationCategory;
import org.nextprot.api.commons.exception.NextProtException;
import org.nextprot.api.core.service.OverviewService;
import org.nextprot.api.isoform.mapper.IsoformMappingBaseTest;
import org.nextprot.api.isoform.mapper.domain.SingleFeatureQuery;
import org.nextprot.api.isoform.mapper.domain.FeatureQueryException;
import org.nextprot.api.isoform.mapper.domain.FeatureQueryFailure;
import org.nextprot.api.isoform.mapper.domain.FeatureQueryResult;
import org.nextprot.api.isoform.mapper.domain.impl.FeatureQueryFailureImpl;
import org.nextprot.api.isoform.mapper.domain.impl.SingleFeatureQuerySuccessImpl;
import org.nextprot.api.isoform.mapper.domain.impl.exception.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.List;
import java.util.function.Function;
import static java.util.stream.Collectors.toList;
import static org.mockito.Mockito.when;
@ActiveProfiles({ "dev" })
public class IsoformMappingServiceTest extends IsoformMappingBaseTest {
@Autowired
public OverviewService overviewService;
@Autowired
private IsoformMappingService service;
@Test
public void shouldValidateVariantOnCanonicalIsoform() throws Exception {
FeatureQueryResult result = service.validateFeature(new SingleFeatureQuery("SCN11A-p.Leu1158Pro", AnnotationCategory.VARIANT.getApiTypeName(), "NX_Q9UI33"));
assertIsoformFeatureValid(result, "NX_Q9UI33-1", 1158, 1158, true);
}
@Test
public void shouldNotValidateIncompatibleProteinAndGeneName() throws Exception {
FeatureQueryResult result = service.validateFeature(new SingleFeatureQuery("SCN11A-p.Leu1158Pro", AnnotationCategory.VARIANT.getApiTypeName(), "NX_P01308"));
SingleFeatureQuery query = Mockito.mock(SingleFeatureQuery.class);
when(query.getAccession()).thenReturn("NX_P01308");
assertIsoformFeatureNotValid((FeatureQueryFailureImpl) result, new IncompatibleGeneAndProteinNameException(query, "SCN11A", Lists.newArrayList("INS")));
}
@Test
public void shouldNotValidateInvalidVariantName() throws Exception {
FeatureQueryResult result = service.validateFeature(new SingleFeatureQuery("SCN11A-z.Leu1158Pro", AnnotationCategory.VARIANT.getApiTypeName(), "NX_Q9UI33"));
SingleFeatureQuery query = Mockito.mock(SingleFeatureQuery.class);
when(query.getFeature()).thenReturn("SCN11A-z.Leu1158Pro");
Assert.assertFalse(result.isSuccess());
Assert.assertEquals("invalid feature format: SCN11A-z.Leu1158Pro", ((FeatureQueryFailureImpl)result).getError().getMessage());
Assert.assertEquals(1, ((FeatureQueryFailureImpl)result).getError().getCauses().size());
Assert.assertEquals("Cannot separate gene name from variation (missing '-p.')", ((FeatureQueryFailureImpl)result).getError().getCause(InvalidFeatureQueryFormatException.PARSE_ERROR_MESSAGE));
}
@Test
public void shouldNotValidateInvalidAminoAcidCode() throws Exception {
FeatureQueryResult result = service.validateFeature(new SingleFeatureQuery("SCN11A-p.Let1158Pro", AnnotationCategory.VARIANT.getApiTypeName(), "NX_Q9UI33"));
SingleFeatureQuery query = Mockito.mock(SingleFeatureQuery.class);
when(query.getFeature()).thenReturn("SCN11A-p.Let1158Pro");
Assert.assertFalse(result.isSuccess());
Assert.assertEquals("invalid feature format: SCN11A-p.Let1158Pro", ((FeatureQueryFailureImpl)result).getError().getMessage());
Assert.assertEquals(1, ((FeatureQueryFailureImpl)result).getError().getCauses().size());
Assert.assertEquals("Let: invalid AminoAcidCode", ((FeatureQueryFailureImpl)result).getError().getCause(InvalidFeatureQueryFormatException.PARSE_ERROR_MESSAGE));
}
@Test
public void shouldNotValidateIncorrectAAVariantIsoform() throws Exception {
FeatureQueryResult result = service.validateFeature(new SingleFeatureQuery("SCN11A-p.Met1158Pro", AnnotationCategory.VARIANT.getApiTypeName(), "NX_Q9UI33"));
SingleFeatureQuery query = Mockito.mock(SingleFeatureQuery.class);
when(query.getAccession()).thenReturn("NX_Q9UI33");
when(query.getFeature()).thenReturn("SCN11A-p.Met1158Pro");
assertIsoformFeatureNotValid((FeatureQueryFailure) result, new UnexpectedFeatureQueryAminoAcidException(query, 1158,
new AminoAcidCode[] { AminoAcidCode.LEUCINE }, new AminoAcidCode[] { AminoAcidCode.METHIONINE }));
}
@Test
public void shouldNotValidateInvalidPositionVariantIsoform() throws Exception {
FeatureQueryResult result = service.validateFeature(new SingleFeatureQuery("SCN11A-p.Leu1158999Pro", AnnotationCategory.VARIANT.getApiTypeName(), "NX_Q9UI33"));
SingleFeatureQuery query = Mockito.mock(SingleFeatureQuery.class);
when(query.getAccession()).thenReturn("NX_Q9UI33");
assertIsoformFeatureNotValid((FeatureQueryFailureImpl) result, new OutOfBoundSequencePositionException(query, 1158999));
}
@Test
public void shouldPropagateVariantToAllIsoforms() throws Exception {
FeatureQueryResult result = service.propagateFeature(new SingleFeatureQuery("SCN11A-p.Leu1158Pro", AnnotationCategory.VARIANT.getApiTypeName(), "NX_Q9UI33"));
assertIsoformFeatureValid(result, "NX_Q9UI33-1", 1158, 1158, true);
assertIsoformFeatureValid(result, "NX_Q9UI33-2", 1158, 1158, true);
assertIsoformFeatureValid(result, "NX_Q9UI33-3", 1120, 1120, true);
}
@Test
public void shouldPropagateVariantToAllValidIsoforms() throws Exception {
FeatureQueryResult result = service.propagateFeature(new SingleFeatureQuery("SCN11A-p.Lys1710Thr", AnnotationCategory.VARIANT.getApiTypeName(), "NX_Q9UI33"));
assertIsoformFeatureValid(result, "NX_Q9UI33-1", 1710, 1710, true);
assertIsoformFeatureValid(result, "NX_Q9UI33-2", null, null, false);
assertIsoformFeatureValid(result, "NX_Q9UI33-3", 1672, 1672, true);
}
@Test
public void shouldValidatePtmOnCanonicalIsoform() throws Exception {
FeatureQueryResult result = service.validateFeature(new SingleFeatureQuery("BRCA1-P-Ser988", AnnotationCategory.GENERIC_PTM.getApiTypeName(), "NX_P38398"));
assertIsoformFeatureValid(result, "NX_P38398-1", 988, 988, true);
}
@Test
public void shouldValidateInsertionVariantOnCanonicalIsoform() throws Exception {
FeatureQueryResult result = service.validateFeature(new SingleFeatureQuery("MLH1-p.Lys722_Ala723insTyrLys", AnnotationCategory.VARIANT.getApiTypeName(), "NX_P40692"));
assertIsoformFeatureValid(result, "NX_P40692-1", 722, 723, true);
}
@Test
public void shouldValidateDeletionVariantOnCanonicalIsoform() throws Exception {
FeatureQueryResult result = service.validateFeature(new SingleFeatureQuery("BRCA2-p.Gly2281_Asp2312del", AnnotationCategory.VARIANT.getApiTypeName(), "NX_P51587"));
assertIsoformFeatureValid(result, "NX_P51587-1", 2281, 2312, true);
}
//@Test
public void validateVDList1() throws Exception {
String filename = IsoformMappingServiceTest.class.getResource("vd.tsv").getFile();
validateList(filename, true, service);
}
//@Test
public void validateVDList2() throws Exception {
String filename = IsoformMappingServiceTest.class.getResource("variant-multiple-mutants.csv").getFile();
validateList(filename, false, service);
}
@Test(expected = NextProtException.class)
public void shouldThrowExceptionWithIsonumber() throws Exception {
service.validateFeature(new SingleFeatureQuery("SCN11A-p.Leu1158Pro", AnnotationCategory.VARIANT.getApiTypeName(), "NX_Q9UI33-2"));
}
@Test
public void shouldReturnError() throws Exception {
FeatureQueryResult result = service.validateFeature(new SingleFeatureQuery("SCN11A-p-iso4.Leu1158Pro", AnnotationCategory.VARIANT.getApiTypeName(), "NX_Q9UI33"));
Assert.assertTrue(!result.isSuccess());
}
@Test
public void shouldValidateWithNoAccession() throws Exception {
FeatureQueryResult result = service.validateFeature(new SingleFeatureQuery("SCN11A-p.Leu1158Pro", AnnotationCategory.VARIANT.getApiTypeName(), ""));
assertIsoformFeatureValid(result, "NX_Q9UI33-1", 1158, 1158, true);
}
@Test
public void shouldValidateWithNullAccession() throws Exception {
FeatureQueryResult result = service.validateFeature(new SingleFeatureQuery("SCN11A-p.Leu1158Pro", AnnotationCategory.VARIANT.getApiTypeName(), null));
assertIsoformFeatureValid(result, "NX_Q9UI33-1", 1158, 1158, true);
Assert.assertEquals("NX_Q9UI33", result.getQuery().getAccession());
}
@Test
public void shouldNotValidateWithGeneNoAccession() throws Exception {
FeatureQueryResult result = service.validateFeature(new SingleFeatureQuery("SCN14A-p.Leu1158Pro", AnnotationCategory.VARIANT.getApiTypeName(), ""));
SingleFeatureQuery query = Mockito.mock(SingleFeatureQuery.class);
when(query.getAccession()).thenReturn("");
assertIsoformFeatureNotValid((FeatureQueryFailureImpl) result, new EntryAccessionNotFoundForGeneException(query, "SCN14A"));
}
// no more multiple accessions for gene GCNT2
// TODO: find another gene with multiple accessions
@Ignore
@Test
public void shouldNotValidateWithMultipleAccessions() throws Exception {
FeatureQueryResult result = service.validateFeature(new SingleFeatureQuery("GCNT2-p.Leu1158Pro", AnnotationCategory.VARIANT.getApiTypeName(), ""));
SingleFeatureQuery query = Mockito.mock(SingleFeatureQuery.class);
when(query.getAccession()).thenReturn("");
assertIsoformFeatureNotValid((FeatureQueryFailureImpl) result, new MultipleEntryAccessionForGeneException(query, "GCNT2",
Sets.newHashSet("NX_Q06430", "NX_Q8N0V5", "NX_Q8NFS9")));
}
@Test
public void shouldValidateMutagenesisOnCanonicalIsoform() throws Exception {
FeatureQueryResult result = service.validateFeature(new SingleFeatureQuery("ACVR1-p.Gln207Asp", AnnotationCategory.MUTAGENESIS.getApiTypeName(), ""));
assertIsoformFeatureValid(result, "NX_Q04771-1", 207, 207, true);
}
@Test
public void shouldValidateExtensionVariantOnCanonicalIsoform() throws Exception {
// RAD50-p.*1313Tyrext*66 (CAVA-VD024428)
FeatureQueryResult result = service.validateFeature(new SingleFeatureQuery("RAD50-p.Ter1313Tyrext*66", AnnotationCategory.VARIANT.getApiTypeName(), ""));
assertIsoformFeatureValid(result, "NX_Q92878-1", 1313, 1313, true);
}
@Test
public void shouldValidateExtensionVariantOnCanonicalIsoformBadPos() throws Exception {
SingleFeatureQuery query = new SingleFeatureQuery("RAD50-p.Ter1314Tyrext*66", AnnotationCategory.VARIANT.getApiTypeName(), "");
FeatureQueryResult result = service.validateFeature(query);
assertIsoformFeatureNotValid((FeatureQueryFailureImpl) result, new OutOfBoundSequencePositionException(query, 1313));
}
@Test
public void shouldValidateExtensionVariantOnCanonicalIsoformBadPos1() throws Exception {
SingleFeatureQuery query = new SingleFeatureQuery("BCL2-p.Met1ext-5", AnnotationCategory.VARIANT.getApiTypeName(), "");
FeatureQueryResult result = service.validateFeature(query);
assertIsoformFeatureValid(result, "NX_P10415-1", 1, 1, true);
}
@Test
public void shouldMap2IsoformsContainingLastAA() throws Exception {
SingleFeatureQuery query = new SingleFeatureQuery("SDHD-p.*160Leuext*3", AnnotationCategory.VARIANT.getApiTypeName(), "");
FeatureQueryResult result = service.propagateFeature(query);
assertIsoformFeatureValid(result, "NX_O14521-1", 160, 160, true);
assertIsoformFeatureValid(result, "NX_O14521-2", 121, 121, true);
assertIsoformFeatureValid(result, "NX_O14521-3", null, null, false);
assertIsoformFeatureValid(result, "NX_O14521-4", null, null, false);
}
@Test
public void shouldMap2IsoformsContainingFirstAA() throws Exception {
SingleFeatureQuery query = new SingleFeatureQuery("BCL2-p.Met1ext-5", AnnotationCategory.VARIANT.getApiTypeName(), "");
FeatureQueryResult result = service.propagateFeature(query);
assertIsoformFeatureValid(result, "NX_P10415-1", 1, 1, true);
assertIsoformFeatureValid(result, "NX_P10415-2", 1, 1, true);
}
@Test
public void shouldNotMap1IsoformsContainingFirstAA() throws Exception {
SingleFeatureQuery query = new SingleFeatureQuery("TESPA1-p.Met1ext-5", AnnotationCategory.VARIANT.getApiTypeName(), "");
FeatureQueryResult result = service.propagateFeature(query);
assertIsoformFeatureValid(result, "NX_A2RU30-1", 1, 1, true);
assertIsoformFeatureValid(result, "NX_A2RU30-2", null, null, false);
assertIsoformFeatureValid(result, "NX_A2RU30-3", null, null, false);
}
private static void assertIsoformFeatureValid(FeatureQueryResult result, String featureIsoformName, Integer expectedFirstPos, Integer expectedLastPos, boolean mapped) {
Assert.assertTrue(result.isSuccess());
SingleFeatureQuerySuccessImpl successResult = (SingleFeatureQuerySuccessImpl) result;
Assert.assertNotNull(successResult.getIsoformFeatureResult(featureIsoformName));
Assert.assertEquals(mapped, successResult.getIsoformFeatureResult(featureIsoformName).isMapped());
Assert.assertEquals(expectedFirstPos, successResult.getIsoformFeatureResult(featureIsoformName).getBeginIsoformPosition());
Assert.assertEquals(expectedLastPos, successResult.getIsoformFeatureResult(featureIsoformName).getEndIsoformPosition());
}
private static void assertIsoformFeatureNotValid(FeatureQueryFailure result, FeatureQueryException expectedException) {
Assert.assertTrue(!result.isSuccess());
Assert.assertEquals(expectedException.getReason(), result.getError());
}
private static void validateList(String filename, boolean tabSep, IsoformMappingService service) throws Exception {
FileInputStream is = new FileInputStream(filename);
BufferedReader br = new BufferedReader(new InputStreamReader(is));
PrintWriter pw = new PrintWriter(Files.getNameWithoutExtension(filename)+"-results.tsv");
List<String[]> twoFirstFieldsList = br.lines()
.map((tabSep) ? to2FirstTabFields : to2FirstCommaFields)
.collect(toList());
pw.append("accession\tvariant\tvalid\terror message\n");
for (String[] twoFields : twoFirstFieldsList) {
String accession = twoFields[0];
String feature = twoFields[1];
FeatureQueryResult result =
service.validateFeature(new SingleFeatureQuery(feature, AnnotationCategory.VARIANT.getApiTypeName(), accession));
pw.append(accession).append("\t").append(feature).append("\t").append(String.valueOf(result.isSuccess()));
if (result.isSuccess()) {
pw.append("\t");
} else {
FeatureQueryFailureImpl error = (FeatureQueryFailureImpl) result;
pw.append("\t").append(error.getError().getMessage());
}
pw.append("\n");
}
pw.close();
}
private static Function<String, String[]> to2FirstTabFields = (line) -> {
String[] p = line.split("\t");
return new String[] { p[0], p[1] };
};
private static Function<String, String[]> to2FirstCommaFields = (line) -> {
String[] p = line.split(",");
return new String[] { p[0], p[1] };
};
}