package de.westnordost.streetcomplete.data.osmnotes;
import junit.framework.TestCase;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import de.westnordost.osmapi.common.Handler;
import de.westnordost.osmapi.common.errors.OsmConflictException;
import de.westnordost.osmapi.map.MapDataDao;
import de.westnordost.osmapi.map.data.BoundingBox;
import de.westnordost.osmapi.map.data.Element;
import de.westnordost.osmapi.map.data.LatLon;
import de.westnordost.osmapi.map.data.OsmLatLon;
import de.westnordost.osmapi.map.data.Way;
import de.westnordost.osmapi.notes.Note;
import de.westnordost.osmapi.notes.NoteComment;
import de.westnordost.osmapi.notes.NotesDao;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
public class CreateNoteUploadTest extends TestCase
{
private MapDataDao mapDataDao;
private CreateNoteDao createNoteDb;
private NotesDao notesDao;
private OsmNoteQuestDao osmNoteQuestDb;
private NoteDao noteDb;
@Override public void setUp()
{
mapDataDao = mock(MapDataDao.class);
createNoteDb = mock(CreateNoteDao.class);
notesDao = mock(NotesDao.class);
osmNoteQuestDb = mock(OsmNoteQuestDao.class);
noteDb = mock(NoteDao.class);
}
private CreateNoteUpload makeCreateNoteUpload()
{
return new CreateNoteUpload(createNoteDb, notesDao, noteDb, osmNoteQuestDb, mapDataDao);
}
public void testCancel() throws InterruptedException
{
when(createNoteDb.getAll(any(BoundingBox.class))).thenAnswer(
new Answer<List<CreateNote>>()
{
@Override public List<CreateNote> answer(InvocationOnMock invocation) throws Throwable
{
Thread.sleep(1000); // take your time...
ArrayList<CreateNote> result = new ArrayList<>();
result.add(null);
return result;
}
});
final CreateNoteUpload u = makeCreateNoteUpload();
final AtomicBoolean cancel = new AtomicBoolean(false);
Thread t = new Thread(new Runnable()
{
@Override public void run()
{
u.upload(cancel);
}
});
t.start();
cancel.set(true);
// cancelling the thread works if we come out here without exceptions. If the note upload
// would actually try to start anything, there would be a nullpointer exception since we
// feeded it only with nulls to work with
t.join();
}
public void testUploadNoteForDeletedElementWillCancel()
{
/* the mock for MapDataDao returns null for getNode, getWay, getRelation... by defaiƶt */
CreateNote createNote = createACreateNote();
createNote.elementType = Element.Type.WAY;
createNote.elementId = 5L;
assertNull(makeCreateNoteUpload().uploadCreateNote(createNote));
verifyNoteNotInsertedIntoDb(createNote.id);
}
public void testCreateNoteOnExistingNoteWillCommentOnExistingNote()
{
CreateNote createNote = createACreateNote();
createNote.elementType = Element.Type.WAY;
createNote.elementId = 5L;
Note note = createNote(createNote);
setUpThereIsANoteFor(createNote, note);
when(notesDao.comment(anyLong(), anyString())).thenReturn(note);
assertNotNull(makeCreateNoteUpload().uploadCreateNote(createNote));
verify(notesDao).comment(note.id, createNote.text);
verifyNoteInsertedIntoDb(createNote.id, note);
}
public void testCreateNoteOnExistingClosedNoteWillCancel()
{
CreateNote createNote = createACreateNote();
createNote.elementType = Element.Type.WAY;
createNote.elementId = 5L;
Note note = createNote(createNote);
note.status = Note.Status.CLOSED;
setUpThereIsANoteFor(createNote, note);
assertNull(makeCreateNoteUpload().uploadCreateNote(createNote));
verify(notesDao).getAll(any(BoundingBox.class), any(Handler.class), anyInt(), anyInt());
verifyNoMoreInteractions(notesDao);
verifyNoteNotInsertedIntoDb(createNote.id);
}
public void testCreateNoteOnExistingNoteWillCancelWhenConflictException()
{
CreateNote createNote = createACreateNote();
createNote.elementType = Element.Type.WAY;
createNote.elementId = 5L;
Note note = createNote(createNote);
setUpThereIsANoteFor(createNote, note);
when(notesDao.comment(anyLong(), anyString())).thenThrow(OsmConflictException.class);
assertNull(makeCreateNoteUpload().uploadCreateNote(createNote));
verify(notesDao).comment(note.id, createNote.text);
verifyNoteNotInsertedIntoDb(createNote.id);
}
public void testCreateNoteWithNoAssociatedElement()
{
CreateNote createNote = createACreateNote();
Note note = createNote(null);
when(notesDao.create(any(LatLon.class), anyString())).thenReturn(note);
assertNotNull(makeCreateNoteUpload().uploadCreateNote(createNote));
verify(notesDao).create(createNote.position, createNote.text);
verifyNoteInsertedIntoDb(createNote.id, note);
}
public void testCreateNoteWithAssociatedElementAndNoNoteYet()
{
CreateNote createNote = createACreateNote();
createNote.elementType = Element.Type.WAY;
createNote.elementId = 5L;
when(mapDataDao.getWay(createNote.elementId)).thenReturn(mock(Way.class));
Note note = createNote(createNote);
when(notesDao.create(any(LatLon.class), anyString())).thenReturn(note);
assertNotNull(makeCreateNoteUpload().uploadCreateNote(createNote));
verify(notesDao).create(createNote.position, createNote.text +
CreateNoteUpload.getAssociatedElementString(createNote));
verifyNoteInsertedIntoDb(createNote.id, note);
}
private void verifyNoteNotInsertedIntoDb(long createNoteId)
{
verifyNoMoreInteractions(noteDb, osmNoteQuestDb);
verify(createNoteDb).delete(createNoteId);
}
private void verifyNoteInsertedIntoDb(long createNoteId, Note note)
{
verify(noteDb).put(note);
verify(osmNoteQuestDb).add(any(OsmNoteQuest.class));
verify(createNoteDb).delete(createNoteId);
}
private void setUpThereIsANoteFor(CreateNote createNote, final Note note)
{
when(mapDataDao.getWay(createNote.elementId)).thenReturn(mock(Way.class));
doAnswer(new Answer<Void>()
{
@Override public Void answer(InvocationOnMock invocation) throws Throwable
{
Handler<Note> handler = (Handler<Note>) invocation.getArguments()[1];
handler.handle(note);
return null;
}
}).when(notesDao).getAll(any(BoundingBox.class), any(Handler.class), anyInt(), anyInt());
}
private Note createNote(CreateNote fitsTo)
{
Note note = new Note();
note.id = 2;
note.status = Note.Status.OPEN;
note.dateCreated = new Date();
note.position = new OsmLatLon(1,2);
NoteComment comment = new NoteComment();
comment.text = "bla bla";
if(fitsTo != null)
{
comment.text += CreateNoteUpload.getAssociatedElementString(fitsTo);
}
comment.action = NoteComment.Action.OPENED;
comment.date = new Date();
note.comments.add(0, comment);
return note;
}
private CreateNote createACreateNote()
{
CreateNote n = new CreateNote();
n.id = 1;
n.text = "jo ho";
n.position = new OsmLatLon(1.0,2.0);
return n;
}
}