Java tutorial
/* $HeadURL$ * $Id$ * * Copyright (c) 2006-2010 by Public Library of Science * http://plos.org * http://ambraproject.org * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ambraproject.annotation.service; import org.ambraproject.BaseTest; import org.ambraproject.annotation.Context; import org.ambraproject.cache.Cache; import org.ambraproject.models.Annotation; import org.ambraproject.models.AnnotationCitation; import org.ambraproject.models.AnnotationType; import org.ambraproject.models.Article; import org.ambraproject.models.ArticleAuthor; import org.ambraproject.models.Flag; import org.ambraproject.models.FlagReasonCode; import org.ambraproject.models.Rating; import org.ambraproject.models.UserProfile; import org.ambraproject.views.AnnotationView; import org.apache.commons.lang.ArrayUtils; import org.springframework.beans.factory.annotation.Autowired; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEqualsNoOrder; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; /** * Test for methods of {@link AnnotationService}. The test just references methods of the interface so that different * implementations can be autowired in. The test creates it's own dummy data and so shouldn't be dependent on external * databases * * @author Alex Kudlick */ public class AnnotationServiceTest extends BaseTest { @Autowired protected AnnotationService annotationService; @Autowired protected Cache articleHtmlCache; //just used to check that articles get kicked out of the cache when notes are created @DataProvider(name = "articleAnnotations") public Object[][] getArticleAnnotations() { Article article = new Article("id:doi-for-annotationsTopLevel-test"); article.setJournal("test journal"); article.setTitle("test article title"); article.seteLocationId("1234"); article.setAuthors(Arrays.asList(new ArticleAuthor("article", "author", "1"), new ArticleAuthor("article", "author", "2"))); article.setDate(Calendar.getInstance().getTime()); article.setCollaborativeAuthors(Arrays.asList("Collab Author 1", "Collab Author 2", "Collab Author 3")); dummyDataStore.store(article); UserProfile creator = new UserProfile("user-1-annotationsTopLevel", "email@annotationsTopLevel.org", "user-1-annotationsTopLevel"); dummyDataStore.store(creator); //dates to be able to differentiate expected order of results Calendar lastYear = Calendar.getInstance(); lastYear.add(Calendar.YEAR, -1); Calendar lastMonth = Calendar.getInstance(); lastMonth.add(Calendar.MONTH, -1); Map<Long, List<Annotation>> replyMap = new HashMap<Long, List<Annotation>>(2); /**********ANNOTATIONS ON THE FIRST ARTICLE***********/ /******************RETURN ORDER SHOULD BE mCorrection, fCorrection****************************/ //fCorrection created is last month, mCorrection created is last year, but the replies to mCorrection were created now Annotation fCorrection = new Annotation(creator, AnnotationType.FORMAL_CORRECTION, article.getID()); fCorrection.setAnnotationUri("formal-correction-annotationsTopLevel-fc1"); fCorrection.setTitle("formal-correction-annotationsTopLevel-fc1"); fCorrection.setBody("formal-correction-annotationsTopLevel-body-fc1"); fCorrection.setAnnotationCitation(new AnnotationCitation(article)); fCorrection.setCreated(lastMonth.getTime()); dummyDataStore.store(fCorrection); Annotation mCorrection = new Annotation(creator, AnnotationType.MINOR_CORRECTION, article.getID()); mCorrection.setAnnotationUri("minor-correction-annotationsTopLevel-mc1"); mCorrection.setTitle("minor-correction-annotationsTopLevel-mc1"); mCorrection.setBody("minor-correction-annotationsTopLevel-body-mc1"); mCorrection.setAnnotationCitation(new AnnotationCitation(article)); mCorrection.setCreated(lastYear.getTime()); dummyDataStore.store(mCorrection); Annotation mCorrectionReply1 = new Annotation(creator, AnnotationType.REPLY, mCorrection.getArticleID()); mCorrectionReply1.setParentID(mCorrection.getID()); mCorrectionReply1.setAnnotationUri("reply1-to-minor-correction-uri"); mCorrectionReply1.setTitle("reply1-to-minor-correction-title"); mCorrectionReply1.setBody("reply1-to-minor-correction-body"); dummyDataStore.store(mCorrectionReply1); Annotation mCorrectionReply2 = new Annotation(creator, AnnotationType.REPLY, mCorrection.getArticleID()); mCorrectionReply2.setParentID(mCorrection.getID()); mCorrectionReply2.setAnnotationUri("reply2-to-minor-correction-uri"); mCorrectionReply2.setTitle("reply2-to-minor-correction-title"); mCorrectionReply2.setBody("reply2-to-minor-correction-body"); dummyDataStore.store(mCorrectionReply2); replyMap.put(mCorrection.getID(), Arrays.asList(mCorrectionReply1, mCorrectionReply2)); Article article1 = new Article("id:doi-for-annotationsTopLevel-test-1"); article1.setJournal("test journal"); article1.seteLocationId("1234"); article1.setTitle("test article1 title"); article1.setAuthors(Arrays.asList(new ArticleAuthor("article", "author", "1"), new ArticleAuthor("article", "author", "2"))); article1.setDate(Calendar.getInstance().getTime()); article1.setCollaborativeAuthors(Arrays.asList("Collab Author 1", "Collab Author 2", "Collab Author 3")); dummyDataStore.store(article1); /**********ANNOTATIONS ON THE SECOND ARTICLE***********/ /**********RETURN ORDER SHOULD BE fCorrection1, fCorrection2**/ //fCorrection1 and it's reply have created date last year, but the reply to reply date is now //fCorrection2 and it's reply have created date last month Annotation fCorrection1 = new Annotation(creator, AnnotationType.FORMAL_CORRECTION, article1.getID()); fCorrection1.setAnnotationUri("formal-correction-1-annotationsTopLevel-fc2"); fCorrection1.setTitle("formal-correction-1-annotationsTopLevel-fc2"); fCorrection1.setBody("formal-correction-1-annotationsTopLevel-body-fc2"); fCorrection1.setAnnotationCitation(new AnnotationCitation(article1)); fCorrection1.setCreated(lastMonth.getTime()); dummyDataStore.store(fCorrection1); Annotation fCorrection1Reply1 = new Annotation(creator, AnnotationType.REPLY, fCorrection1.getArticleID()); fCorrection1Reply1.setParentID(fCorrection1.getID()); fCorrection1Reply1.setAnnotationUri("reply1-to-formal-correction1-uri"); fCorrection1Reply1.setTitle("reply1-to-formal-correction1-title"); fCorrection1Reply1.setBody("reply1-to-formal-correction1-body"); fCorrection1Reply1.setCreated(lastMonth.getTime()); dummyDataStore.store(fCorrection1Reply1); Annotation fCorrection1ReplyToReply = new Annotation(creator, AnnotationType.REPLY, fCorrection1.getArticleID()); fCorrection1ReplyToReply.setParentID(fCorrection1Reply1.getID()); fCorrection1ReplyToReply.setAnnotationUri("reply-to-reply-to-formal-correction1-uri"); fCorrection1ReplyToReply.setTitle("reply-to-reply-to-formal-correction1-title"); fCorrection1ReplyToReply.setBody("reply-to-reply-to-formal-correction1-body"); dummyDataStore.store(fCorrection1ReplyToReply); replyMap.put(fCorrection1.getID(), Arrays.asList(fCorrection1Reply1)); replyMap.put(fCorrection1Reply1.getID(), Arrays.asList(fCorrection1ReplyToReply)); Annotation fCorrection2 = new Annotation(creator, AnnotationType.FORMAL_CORRECTION, article1.getID()); fCorrection2.setAnnotationUri("formal-correction-1-annotationsTopLevel-fc3"); fCorrection2.setTitle("formal-correction-1-annotationsTopLevel-fc3"); fCorrection2.setBody("formal-correction-1-annotationsTopLevel-body-fc3"); fCorrection2.setAnnotationCitation(new AnnotationCitation(article1)); fCorrection2.setCreated(lastYear.getTime()); dummyDataStore.store(fCorrection2); Annotation fCorrection2Reply1 = new Annotation(creator, AnnotationType.REPLY, fCorrection1.getArticleID()); fCorrection2Reply1.setParentID(fCorrection2.getID()); fCorrection2Reply1.setAnnotationUri("reply1-to-formal-correction2-uri"); fCorrection2Reply1.setTitle("reply1-to-formal-correction2-title"); fCorrection2Reply1.setBody("reply1-to-formal-correction2-body"); fCorrection2Reply1.setCreated(lastMonth.getTime()); dummyDataStore.store(fCorrection2Reply1); replyMap.put(fCorrection2.getID(), Arrays.asList(fCorrection2Reply1)); Article article2 = new Article("id:doi-for-annotationsTopLevel-test-2"); article2.setJournal("test journal"); article2.setTitle("test article2 title"); article2.seteLocationId("1234"); article2.setAuthors(Arrays.asList(new ArticleAuthor("article", "author", "1"), new ArticleAuthor("article", "author", "2"))); article2.setDate(Calendar.getInstance().getTime()); article2.setCollaborativeAuthors(Arrays.asList("Collab Author 1", "Collab Author 2", "Collab Author 3")); dummyDataStore.store(article2); UserProfile creator2 = new UserProfile("user-2-annotationsTopLevel", "email2@annotationsTopLevel.org", "user-2-annotationsTopLevel"); dummyDataStore.store(creator2); /**********ANNOTATIONS ON THE THIRD ARTICLE***********/ /**********RETURN ORDER SHOULD BE comment, retraction*******/ Annotation retraction = new Annotation(creator2, AnnotationType.RETRACTION, article2.getID()); retraction.setAnnotationUri("retraction-1-annotationsTopLevel-r1"); retraction.setTitle("retraction-1-annotationsTopLevel-r1"); retraction.setBody("retraction-1-annotationsTopLevel-body-r1"); retraction.setAnnotationCitation(new AnnotationCitation(article2)); retraction.setCreated(lastYear.getTime()); dummyDataStore.store(retraction); Annotation comment = new Annotation(creator2, AnnotationType.COMMENT, article2.getID()); comment.setAnnotationUri("comment-annotationsTopLevel-r1"); comment.setTitle("comment-annotationsTopLevel-r1"); comment.setBody("comment-annotationsTopLevel-body-r1"); comment.setCreated(lastMonth.getTime()); dummyDataStore.store(comment); AnnotationView fCorrectionView = new AnnotationView(fCorrection, article.getDoi(), article.getTitle(), replyMap); AnnotationView mCorrectionView = new AnnotationView(mCorrection, article.getDoi(), article.getTitle(), replyMap); AnnotationView fCorrection1View = new AnnotationView(fCorrection1, article1.getDoi(), article1.getTitle(), replyMap); AnnotationView fCorrection2View = new AnnotationView(fCorrection2, article1.getDoi(), article1.getTitle(), replyMap); AnnotationView retractionView = new AnnotationView(retraction, article2.getDoi(), article2.getTitle(), replyMap); AnnotationView commentView = new AnnotationView(comment, article2.getDoi(), article2.getTitle(), replyMap); //Pass in query parameters and expected results for each set of articles / citations return new Object[][] { { article, EnumSet.of(AnnotationType.FORMAL_CORRECTION, AnnotationType.MINOR_CORRECTION), AnnotationService.AnnotationOrder.MOST_RECENT_REPLY, new AnnotationView[] { mCorrectionView, //mCorrection has a more recent reply fCorrectionView }, replyMap }, { article, EnumSet.of(AnnotationType.FORMAL_CORRECTION, AnnotationType.MINOR_CORRECTION), AnnotationService.AnnotationOrder.OLDEST_TO_NEWEST, new AnnotationView[] { mCorrectionView, //mCorrection has created date last year, fCorrection last month fCorrectionView }, replyMap }, { article1, EnumSet.of(AnnotationType.FORMAL_CORRECTION), AnnotationService.AnnotationOrder.MOST_RECENT_REPLY, new AnnotationView[] { fCorrection1View, //fCorrection1 has a more recent reply to reply fCorrection2View }, replyMap }, { article1, EnumSet.of(AnnotationType.FORMAL_CORRECTION), AnnotationService.AnnotationOrder.OLDEST_TO_NEWEST, new AnnotationView[] { fCorrection2View, //fCorrection2 has created date last year fCorrection1View }, replyMap }, { article1, EnumSet.of(AnnotationType.FORMAL_CORRECTION, AnnotationType.MINOR_CORRECTION), AnnotationService.AnnotationOrder.MOST_RECENT_REPLY, new AnnotationView[] { fCorrection1View, //fCorrection1 has a more recent reply to reply fCorrection2View }, replyMap }, { article, EnumSet.of(AnnotationType.RETRACTION), AnnotationService.AnnotationOrder.MOST_RECENT_REPLY, new AnnotationView[] {}, replyMap }, { article2, EnumSet.of(AnnotationType.RETRACTION), AnnotationService.AnnotationOrder.MOST_RECENT_REPLY, new AnnotationView[] { retractionView }, replyMap }, { article2, EnumSet.of(AnnotationType.RETRACTION, AnnotationType.COMMENT), AnnotationService.AnnotationOrder.MOST_RECENT_REPLY, new AnnotationView[] { commentView, //comment has more recent created date retractionView }, replyMap }, { article2, EnumSet.of(AnnotationType.RETRACTION, AnnotationType.COMMENT), AnnotationService.AnnotationOrder.OLDEST_TO_NEWEST, new AnnotationView[] { retractionView, commentView //comment has more recent created date }, replyMap }, { article2, EnumSet.of(AnnotationType.FORMAL_CORRECTION, AnnotationType.MINOR_CORRECTION), AnnotationService.AnnotationOrder.MOST_RECENT_REPLY, new AnnotationView[] {}, replyMap } }; } @Test(dataProvider = "articleAnnotations") public void testListAnnotations(final Article article, final Set<AnnotationType> annotationTypes, final AnnotationService.AnnotationOrder order, final AnnotationView[] expectedViews, final Map<Long, List<Annotation>> fullReplyMap) { AnnotationView[] resultViews = annotationService.listAnnotations(article.getID(), annotationTypes, order); //Not just calling assertEquals here, so we can give a more informative message (the .toSting() on the arrays is huge) assertNotNull(resultViews, "returned null array of results"); assertEquals(resultViews.length, expectedViews.length, "returned incorrect number of results"); for (int i = 0; i < resultViews.length; i++) { assertEquals(resultViews[i].getCitation(), expectedViews[i].getCitation(), "Result " + (i + 1) + " had incorrect citation with order " + order); assertEquals(resultViews[i], expectedViews[i], "Result " + (i + 1) + " was incorrect with order " + order); recursivelyCheckReplies(resultViews[i], fullReplyMap); } } @Test(dataProvider = "articleAnnotations") public void testListAnnotationsNoReplies(final Article article, final Set<AnnotationType> annotationTypes, final AnnotationService.AnnotationOrder order, final AnnotationView[] expectedViews, final Map<Long, List<Annotation>> notUsed) { if (order != AnnotationService.AnnotationOrder.MOST_RECENT_REPLY) { AnnotationView[] resultViews = annotationService.listAnnotationsNoReplies(article.getID(), annotationTypes, order); //Not just calling assertEquals here, so we can give a more informative message (the .toSting() on the arrays is huge) assertNotNull(resultViews, "returned null array of results"); assertEquals(resultViews.length, expectedViews.length, "returned incorrect number of results"); for (int i = 0; i < resultViews.length; i++) { assertEquals(resultViews[i].getCitation(), expectedViews[i].getCitation(), "Result " + (i + 1) + " had incorrect citation with order " + order); assertEquals(resultViews[i], expectedViews[i], "Result " + (i + 1) + " was incorrect with order " + order); assertTrue(ArrayUtils.isEmpty(resultViews[i].getReplies()), "returned annotation with replies loaded up"); } } } @Test(expectedExceptions = { IllegalArgumentException.class }) public void testListAnnotationNoRepliesWithBadOrderArgument() { annotationService.listAnnotationsNoReplies(1231l, null, AnnotationService.AnnotationOrder.MOST_RECENT_REPLY); } @Test public void testCreateComment() throws Exception { Article article = new Article("id:doiForCreateCommentByService"); UserProfile user = new UserProfile("authIdForCreateCommentService", "email@createCommentService.org", "displayNAmeForCreateCommentService"); dummyDataStore.store(article); dummyDataStore.store(user); String body = "Test body"; String title = "test title"; String ciStatement = "ciStatement"; Context context = new Context(null, 0, null, 0, article.getDoi()); Long id = annotationService.createComment(user, article.getDoi(), title, body, ciStatement, context, false); assertNotNull(id, "Returned null annotation id"); Annotation storedAnnotation = dummyDataStore.get(Annotation.class, id); assertNotNull(storedAnnotation, "didn't store annotation to the db"); assertEquals(storedAnnotation.getArticleID(), article.getID(), "stored annotation had incorrect article id"); assertEquals(storedAnnotation.getBody(), body, "stored annotation had incorrect body"); assertEquals(storedAnnotation.getTitle(), title, "stored annotation had incorrect title"); assertEquals(storedAnnotation.getCompetingInterestBody(), ciStatement, "stored annotation had incorrect ci statement"); assertEquals(storedAnnotation.getType(), AnnotationType.COMMENT, "Stored annotation had incorrect type"); assertNull(storedAnnotation.getXpath(), "Stored annotation had an xpath associated with it"); assertNotNull(storedAnnotation.getAnnotationUri(), "Service didn't generate an annotation uri"); } @Test public void testCreateInlineNote() throws Exception { Article article = new Article("id:doiForCreateInlineNoteByService"); UserProfile user = new UserProfile("authIdForCreateInlineNoteByService", "email@createInlineNoteByService.org", "displayNAmeForCreateInlineNoteByService"); dummyDataStore.store(article); dummyDataStore.store(user); //put the article in the cache to see that it gets kicked out articleHtmlCache.put(article.getDoi(), new Cache.Item(article)); String body = "Test body"; String title = "test title"; String ciStatement = "ciStatement"; Context context = new Context("/article[1]/body[1]/sec[1]/p[3]", 107, "/article[1]/body[1]/sec[1]/p[3]", 640, article.getDoi()); String expectedXpath = article.getDoi() + "#xpointer(string-range%28%2Farticle%5B1%5D%2Fbody%5B1%5D%2Fsec%5B1%5D%2Fp%5B3%5D%2C+%27%27%2C+107%2C+533%29%5B1%5D)"; Long id = annotationService.createComment(user, article.getDoi(), title, body, ciStatement, context, false); assertNotNull(id, "Returned null annotation id"); Annotation storedAnnotation = dummyDataStore.get(Annotation.class, id); assertNotNull(storedAnnotation, "didn't store annotation to the db"); assertEquals(storedAnnotation.getArticleID(), article.getID(), "stored annotation had incorrect article id"); assertEquals(storedAnnotation.getBody(), body, "stored annotation had incorrect body"); assertEquals(storedAnnotation.getTitle(), title, "stored annotation had incorrect title"); assertEquals(storedAnnotation.getCompetingInterestBody(), ciStatement, "stored annotation had incorrect ci statement"); assertEquals(storedAnnotation.getType(), AnnotationType.NOTE, "Stored annotation had incorrect type"); assertEquals(storedAnnotation.getXpath(), expectedXpath, "stored annotation had incorrect xpath associated with it"); assertNotNull(storedAnnotation.getAnnotationUri(), "Service didn't generate an annotation uri"); assertNull(articleHtmlCache.get(article.getDoi()), "Article didn't get kicked out of cache"); } @Test(expectedExceptions = { IllegalArgumentException.class }) public void testCreateCommentWithNullBody() throws Exception { Article article = new Article("id:doiForCreateWithNullBody"); UserProfile user = new UserProfile("authIdForCreateWithNullBody", "email@CreateWithNullBody.org", "displayNAmeForCreateWithNullBody"); dummyDataStore.store(article); dummyDataStore.store(user); annotationService.createComment(user, article.getDoi(), "foo", null, "foo", null, false); } @Test(expectedExceptions = { IllegalArgumentException.class }) public void testCreateCommentWithNullUser() throws Exception { Article article = new Article("id:doiForCreateWithNullUser"); dummyDataStore.store(article); annotationService.createComment(null, article.getDoi(), "foo", "foo", "foo", null, false); } @Test(expectedExceptions = { IllegalArgumentException.class }) public void testCreateCommentWithBadDoi() throws Exception { Article article = new Article("id:doiForCreateWithBadDoi"); UserProfile user = new UserProfile("authIdForCreateWithBadDoi", "email@CreateWithBadDoi.org", "displayNAmeForCreateWithBadDoi"); dummyDataStore.store(user); annotationService.createComment(user, article.getDoi(), "foo", "foo", "foo", null, false); } @Test public void testCreateAndFlagAsCorrection() { Article article = new Article("id:doiForCreateAndFlagByService"); UserProfile user = new UserProfile("authIdForCreateAndFlagByService", "email@CreateAndFlagByService.org", "displayNAmeForCreateAndFlagByService"); dummyDataStore.store(article); dummyDataStore.store(user); String body = "Test body"; String title = "test title"; String ciStatement = "ciStatement"; Context context = new Context("/article[1]/body[1]/sec[1]/p[3]", 107, "/article[1]/body[1]/sec[1]/p[3]", 640, article.getDoi()); String expectedXpath = article.getDoi() + "#xpointer(string-range%28%2Farticle%5B1%5D%2Fbody%5B1%5D%2Fsec%5B1%5D%2Fp%5B3%5D%2C+%27%27%2C+107%2C+533%29%5B1%5D)"; Long id = annotationService.createComment(user, article.getDoi(), title, body, ciStatement, context, true); assertNotNull(id, "Returned null annotation id"); Annotation storedAnnotation = dummyDataStore.get(Annotation.class, id); assertNotNull(storedAnnotation, "didn't store annotation to the db"); assertEquals(storedAnnotation.getArticleID(), article.getID(), "stored annotation had incorrect article id"); assertEquals(storedAnnotation.getBody(), body, "stored annotation had incorrect body"); assertEquals(storedAnnotation.getTitle(), title, "stored annotation had incorrect title"); assertEquals(storedAnnotation.getCompetingInterestBody(), ciStatement, "stored annotation had incorrect ci statement"); assertEquals(storedAnnotation.getType(), AnnotationType.NOTE, "Stored annotation had incorrect type"); assertEquals(storedAnnotation.getXpath(), expectedXpath, "stored annotation had incorrect xpath associated with it"); assertNotNull(storedAnnotation.getAnnotationUri(), "Service didn't generate an annotation uri"); List<Flag> allFlags = dummyDataStore.getAll(Flag.class); assertTrue(allFlags.size() > 0, "didn't create a flag for comment"); boolean foundFlag = false; for (Flag flag : allFlags) { if (flag.getFlaggedAnnotation().getID().equals(id)) { foundFlag = true; assertEquals(flag.getReason(), FlagReasonCode.CORRECTION, "Flag had incorrect reason code"); } } assertTrue(foundFlag, "Didn't create a flag for annotation"); } @DataProvider(name = "storedAnnotation") public Object[][] getStoredAnnotation() { Article article = new Article("id:doi-for-annotationService-test"); article.setJournal("test journal"); article.seteLocationId("12340-37951"); article.setVolume("articl volume"); article.setTitle("article test title"); article.setIssue("article issue"); article.setDate(Calendar.getInstance().getTime()); article.setCollaborativeAuthors( Arrays.asList("The Skoll Foundation", "The Bill and Melinda Gates Foundation")); dummyDataStore.store(article); UserProfile creator = new UserProfile("authIdForAnnotationService", "email@annotationService.org", "displayNameForAnnotationService"); dummyDataStore.store(creator); Annotation annotation = new Annotation(creator, AnnotationType.COMMENT, article.getID()); annotation.setTitle("test title for annotation service test"); annotation.setBody("test body for annotation service test"); annotation.setXpath("test xpath"); annotation.setAnnotationUri("id:annotationWithReplies"); annotation.setAnnotationCitation(new AnnotationCitation(article)); annotation.getAnnotationCitation().setSummary("Citation summary"); annotation.getAnnotationCitation().setNote("Citation note"); dummyDataStore.store(annotation.getAnnotationCitation()); dummyDataStore.store(annotation); /* the reply tree structure is ... original / \ reply1 reply2 / \ reply3 reply4 \ reply5 */ Map<Long, List<Annotation>> replies = new HashMap<Long, List<Annotation>>(3); List<Annotation> repliesToOriginal = new ArrayList<Annotation>(3); List<Annotation> repliesToReply2 = new ArrayList<Annotation>(2); List<Annotation> repliesToReply4 = new ArrayList<Annotation>(1); replies.put(annotation.getID(), repliesToOriginal); //set created dates for replies so we can check ordering by date Calendar lastYear = Calendar.getInstance(); lastYear.add(Calendar.YEAR, -1); //Reply to the original annotation Annotation reply1 = new Annotation(creator, AnnotationType.REPLY, article.getID()); reply1.setParentID(annotation.getID()); reply1.setTitle("title for reply to original comment"); reply1.setBody("body for reply to original comment"); reply1.setAnnotationUri("id:reply1ForTestAnnotationView"); dummyDataStore.store(reply1); repliesToOriginal.add(reply1); //Reply to the original annotation. This should show up first since it has last year as created date Annotation reply2 = new Annotation(creator, AnnotationType.REPLY, article.getID()); reply2.setParentID(annotation.getID()); reply2.setTitle("title for 2nd reply to original comment"); reply2.setBody("body for 2nd reply to original comment"); reply2.setAnnotationUri("id:reply2ForTestAnnotationView"); reply2.setCreated(lastYear.getTime()); dummyDataStore.store(reply2); repliesToOriginal.add(reply2); replies.put(reply2.getID(), repliesToReply2); //reply to reply2 Annotation reply3 = new Annotation(creator, AnnotationType.REPLY, article.getID()); reply3.setParentID(reply2.getID()); reply3.setTitle("title for 1st reply to reply"); reply3.setBody("body for 1st reply to reply"); reply3.setAnnotationUri("id:reply3ForTestAnnotationView"); dummyDataStore.store(reply3); repliesToReply2.add(reply3); //reply to reply2. This should show up first since it has last year as created date Annotation reply4 = new Annotation(creator, AnnotationType.REPLY, article.getID()); reply4.setParentID(reply2.getID()); reply4.setTitle("title for 2nd reply to reply"); reply4.setBody("body for 2nd reply to reply"); reply4.setAnnotationUri("id:reply4ForTestAnnotationView"); reply4.setCreated(lastYear.getTime()); dummyDataStore.store(reply4); repliesToReply2.add(reply4); replies.put(reply4.getID(), repliesToReply4); //reply to reply4 Annotation reply5 = new Annotation(creator, AnnotationType.REPLY, article.getID()); reply5.setParentID(reply4.getID()); reply5.setTitle("title for 3rd level reply"); reply5.setBody("body for 3rd level reply"); reply5.setAnnotationUri("id:reply5ForTestAnnotationView"); dummyDataStore.store(reply5); repliesToReply4.add(reply5); return new Object[][] { { annotation, replies }, { reply1, replies }, { reply2, replies }, { reply3, replies }, { reply4, replies } }; } @Test(dataProvider = "storedAnnotation") public void testGetFullAnnotationView(Annotation annotation, Map<Long, List<Annotation>> fullReplyMap) { AnnotationView result = annotationService.getFullAnnotationView(annotation.getID()); assertNotNull(result, "Returned null annotation view"); String expectedDoi = dummyDataStore.get(Article.class, annotation.getArticleID()).getDoi(); String expectedTitle = dummyDataStore.get(Article.class, annotation.getArticleID()).getTitle(); assertEquals(result.getArticleDoi(), expectedDoi, "AnnotationView had incorrect article doi"); assertEquals(result.getArticleTitle(), expectedTitle, "AnnotationView had incorrect article title"); checkAnnotationProperties(result, annotation); recursivelyCheckReplies(result, fullReplyMap); //check ordering of replies for (int i = 0; i < result.getReplies().length - 1; i++) { assertTrue(result.getReplies()[i].getCreated().before(result.getReplies()[i + 1].getCreated()), "Replies were out of order for annotation " + annotation.getAnnotationUri() + " (should be earliest -> latest)"); } } private void recursivelyCheckReplies(AnnotationView annotationView, Map<Long, List<Annotation>> fullReplyMap) { List<Annotation> expectedReplies = fullReplyMap.get(annotationView.getID()); if (expectedReplies != null) { assertEquals(annotationView.getReplies().length, expectedReplies.size(), "Returned incorrect number of replies"); for (AnnotationView actual : annotationView.getReplies()) { boolean foundMatch = false; for (Annotation expected : expectedReplies) { if (actual.getID().equals(expected.getID())) { foundMatch = true; assertEquals(actual.getTitle(), expected.getTitle(), "Annotation view had incorrect title"); assertEquals(actual.getBody(), "<p>" + expected.getBody() + "</p>", "Annotation view had incorrect body"); assertEquals(actual.getCompetingInterestStatement(), expected.getCompetingInterestBody() == null ? "" : expected.getCompetingInterestBody(), "Annotation view had incorrect ci statement"); assertEquals(actual.getAnnotationUri(), expected.getAnnotationUri(), "Annotation view had incorrect annotation uri"); } } assertTrue(foundMatch, "Returned unexpected reply: " + actual); //recursively check the replies recursivelyCheckReplies(actual, fullReplyMap); } } else { assertTrue(ArrayUtils.isEmpty(annotationView.getReplies()), "Returned replies when none were expected: " + Arrays.deepToString(annotationView.getReplies())); } } @Test public void testAnnotationViewEscapesHtml() { UserProfile creator = new UserProfile("authIdForAnnotationViewEscapesHtml", "email@EscapesHtml.org", "displayNameForAnnotationViewEscapesHtml"); dummyDataStore.store(creator); Long articleId = Long .valueOf(dummyDataStore.store(new Article("id:doi-for-AnnotationViewEscapesViewHtml"))); String title = "hello <p /> world!"; String expectedTitle = "hello <p /> world!"; String body = "You & I"; String expectedBody = "<p>You & I</p>"; Annotation annotation = new Annotation(creator, AnnotationType.COMMENT, articleId); annotation.setTitle(title); annotation.setBody(body); dummyDataStore.store(annotation); AnnotationView result = annotationService.getFullAnnotationView(annotation.getID()); assertNotNull(result, "returned null annotation view"); assertEquals(result.getTitle(), expectedTitle, "AnnotationView didn't escape html in title"); assertEquals(result.getBody(), expectedBody, "AnnotationView didn't escape html in body"); } @Test public void testAnnotationViewCorrectionTitles() { UserProfile creator = new UserProfile("authIdForAnnotationViewCorrectionTitles", "email@CorrectionTitles.org", "displayNameForAnnotationViewCorrectionTitles"); dummyDataStore.store(creator); Article article = new Article(); article.setDoi("id:doi-for-annotationViewCorrectionsTitles"); article.setTitle("test article"); Long articleID = Long.valueOf(dummyDataStore.store(article)); String title = "Dummy Title"; Annotation formalCorrection = new Annotation(creator, AnnotationType.FORMAL_CORRECTION, articleID); formalCorrection.setTitle(title); dummyDataStore.store(formalCorrection); Annotation minorCorrection = new Annotation(creator, AnnotationType.MINOR_CORRECTION, articleID); minorCorrection.setTitle(title); dummyDataStore.store(minorCorrection); Annotation retraction = new Annotation(creator, AnnotationType.RETRACTION, articleID); retraction.setTitle(title); dummyDataStore.store(retraction); AnnotationView formalCorrectionView = annotationService.getFullAnnotationView(formalCorrection.getID()); assertNotNull(formalCorrectionView, "returned null annotation view"); assertEquals(formalCorrectionView.getTitle(), "Formal Correction: " + title, "Formal Correction didn't have correct title"); AnnotationView minorCorrectionView = annotationService.getFullAnnotationView(minorCorrection.getID()); assertNotNull(minorCorrectionView, "returned null annotation view"); assertEquals(minorCorrectionView.getTitle(), "Minor Correction: " + title, "Minor Correction didn't have correct title"); AnnotationView retractionView = annotationService.getFullAnnotationView(retraction.getID()); assertNotNull(retractionView, "returned null annotation view"); assertEquals(retractionView.getTitle(), "Retraction: " + title, "Retraction didn't have correct title"); } @Test(dataProvider = "storedAnnotation") public void testGetBasicAnnotationViewById(Annotation annotation, Map<Long, List<Annotation>> fullReplyMap) { AnnotationView result = annotationService.getBasicAnnotationView(annotation.getID()); assertNotNull(result, "Returned null annotation view"); String expectedDoi = dummyDataStore.get(Article.class, annotation.getArticleID()).getDoi(); String expectedTitle = dummyDataStore.get(Article.class, annotation.getArticleID()).getTitle(); assertEquals(result.getArticleDoi(), expectedDoi, "AnnotationView had incorrect article doi"); assertEquals(result.getArticleTitle(), expectedTitle, "AnnotationView had incorrect article title"); checkAnnotationProperties(result, annotation); assertTrue(ArrayUtils.isEmpty(result.getReplies()), "Returned annotation with replies"); } @Test(dataProvider = "storedAnnotation") public void testGetBasicAnnotationViewByURI(Annotation annotation, Map<Long, List<Annotation>> fullReplyMap) { AnnotationView result = annotationService.getBasicAnnotationViewByUri(annotation.getAnnotationUri()); assertNotNull(result, "Returned null annotation view"); String expectedDoi = dummyDataStore.get(Article.class, annotation.getArticleID()).getDoi(); String expectedTitle = dummyDataStore.get(Article.class, annotation.getArticleID()).getTitle(); assertEquals(result.getArticleDoi(), expectedDoi, "AnnotationView had incorrect article doi"); assertEquals(result.getArticleTitle(), expectedTitle, "AnnotationView had incorrect article title"); checkAnnotationProperties(result, annotation); assertTrue(ArrayUtils.isEmpty(result.getReplies()), "Returned annotation with replies"); } @Test public void testCreateFlag() throws Exception { UserProfile creator = new UserProfile("authIdForCreateFlag", "email@createFlag.org", "displayNameForCreateFlag"); dummyDataStore.store(creator); Annotation annotation = new Annotation(creator, AnnotationType.COMMENT, 123l); Long annotationId = Long.valueOf(dummyDataStore.store(annotation)); String comment = "This is spam"; Long flagId = annotationService.createFlag(creator, annotationId, FlagReasonCode.SPAM, comment); assertNotNull(flagId, "returned null flag id"); Flag storedFlag = dummyDataStore.get(Flag.class, flagId); assertNotNull(storedFlag, "didn't store flag to the database"); assertEquals(storedFlag.getReason(), FlagReasonCode.SPAM, "stored flag had incorrect reason code"); assertEquals(storedFlag.getComment(), comment, "stored flag had incorrect comment"); assertNotNull(storedFlag.getFlaggedAnnotation(), "stored flag had null annotation"); assertEquals(storedFlag.getFlaggedAnnotation().getID(), annotationId, "stored flag had incorrect annotation id"); } @Test public void testCreateReply() { UserProfile creator = new UserProfile("authIdForCreateReply", "email@createReply.org", "displayNameForCreateReply"); dummyDataStore.store(creator); Article article = new Article("id:doi-for-create-reply"); Long articleId = Long.valueOf(dummyDataStore.store(article)); Annotation annotation = new Annotation(creator, AnnotationType.COMMENT, articleId); Long annotationId = Long.valueOf(dummyDataStore.store(annotation)); String title = "test title for reply"; String body = "test body for reply"; Long replyId = annotationService.createReply(creator, annotationId, title, body, null); assertNotNull(replyId, "returned null reply id"); Annotation storedReply = dummyDataStore.get(Annotation.class, replyId); assertNotNull(storedReply, "didn't store reply to the database"); assertEquals(storedReply.getType(), AnnotationType.REPLY, "Stored reply had incorrect type"); assertEquals(storedReply.getParentID(), annotation.getID(), "Stored reply had incorrect parent id"); assertEquals(storedReply.getArticleID(), annotation.getArticleID(), "stored reply had incorrect article id"); assertNotNull(storedReply.getAnnotationUri(), "reply didn't get an annotation uri generated"); assertEquals(storedReply.getTitle(), title, "reply had incorrect title"); assertEquals(storedReply.getBody(), body, "reply had incorrect body"); } @Test public void testCountComments() { UserProfile user = new UserProfile("authIdForTestCountComments", "email@testCountComments.org", "displayNameTestCountComments"); dummyDataStore.store(user); Article article = new Article("id:doi-test-count-comments"); dummyDataStore.store(article); Long commentId = Long .valueOf(dummyDataStore.store(new Annotation(user, AnnotationType.COMMENT, article.getID()))); dummyDataStore.store(new Annotation(user, AnnotationType.FORMAL_CORRECTION, article.getID())); dummyDataStore.store(new Annotation(user, AnnotationType.MINOR_CORRECTION, article.getID())); dummyDataStore.store(new Annotation(user, AnnotationType.RETRACTION, article.getID())); dummyDataStore.store(new Annotation(user, AnnotationType.NOTE, article.getID())); dummyDataStore.store(new Rating(user, article.getID())); Annotation reply = new Annotation(user, AnnotationType.REPLY, article.getID()); reply.setParentID(commentId); dummyDataStore.store(reply); assertEquals( annotationService.countAnnotations(article.getID(), EnumSet.of(AnnotationType.NOTE, AnnotationType.COMMENT)), 2, "annotation service returned incorrect count of comments and notes"); assertEquals( annotationService.countAnnotations(article.getID(), EnumSet.of(AnnotationType.FORMAL_CORRECTION, AnnotationType.MINOR_CORRECTION, AnnotationType.RETRACTION)), 3, "annotation service returned incorrect count of corrections"); assertEquals(annotationService.countAnnotations(article.getID(), EnumSet.allOf(AnnotationType.class)), 7, "annotation service returned incorrect count of comments and notes"); } }