package net.nightwhistler.pageturner.view.bookview;
import android.text.Spanned;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.widget.TextView;
import org.robolectric.RobolectricTestRunner;
import net.nightwhistler.pageturner.Configuration;
import net.nightwhistler.pageturner.dto.HighLight;
import net.nightwhistler.pageturner.view.HighlightManager;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.robolectric.annotation.Config;
import java.util.ArrayList;
import java.util.List;
import static net.nightwhistler.pageturner.view.bookview.LayoutTextUtil.getSpanned;
import static net.nightwhistler.pageturner.view.bookview.LayoutTextUtil.getStringOfLength;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.*;
@Config(emulateSdk = 18)
@RunWith(RobolectricTestRunner.class)
public class FixedPagesStrategyTest {
private StaticLayoutFactory mockFactory = mock(StaticLayoutFactory.class);
private BookView mockBookView;
private TextView mockTextView;
private FixedPagesStrategy strategy;
@Before
public void createMocks() {
this.mockFactory = mock(StaticLayoutFactory.class);
Configuration mockConfig = mock(Configuration.class);
this.mockBookView = mock(BookView.class);
this.mockTextView = mock(TextView.class);
HighlightManager mockManager = mock(HighlightManager.class);
when(mockManager.getHighLights(anyString())).thenReturn( new ArrayList<HighLight>() );
when(mockBookView.getInnerView()).thenReturn(mockTextView);
//Layout has lines of 10 characters, each 10px high
final int LINE_WIDTH = 10; //10 characters
final int LINE_HEIGHT = 10; //10 pixels per line
initMockLayout(LINE_WIDTH, LINE_HEIGHT);
this.strategy = new FixedPagesStrategy();
this.strategy.setLayoutFactory(mockFactory);
this.strategy.setBookView(mockBookView);
this.strategy.setConfig(mockConfig);
this.strategy.setHighlightManager(mockManager);
}
private void initMockLayout( final int lineWidth, final int lineHeight ) {
when(mockFactory.create( any(CharSequence.class), any(TextPaint.class),
anyInt(), anyInt())).thenAnswer(new Answer<StaticLayout>() {
@Override
public StaticLayout answer(InvocationOnMock invocation)
throws Throwable {
if ( invocation != null && invocation.getArguments()[0] != null ) {
return LayoutTextUtil.createMockLayout(invocation.getArguments()[0].toString(),
lineWidth, lineHeight);
} else {
return null;
}
}
});
}
@Test
/**
* Simple testcase: the window fits 5 lines exactly.
*/
public void testGetOffsets() {
//Text is 275 characters long, which is 5.5 pages.
//Every line should be exactly ABCDEFGHIJ
String text = LayoutTextUtil.getStringOfLength("ABCDEFGHIJ", 275);
/*
* The BookView is 50px high, meaning it will fit 5 lines,
* which means 50 characters.
*/
when(this.mockBookView.getMeasuredHeight()).thenReturn(50);
List<Integer> offsets = this.strategy.getPageOffsets(text, false);
assertEquals(6, offsets.size() );
assertEquals((int) 0, (int) offsets.get(0));
assertEquals((int) 50, (int) offsets.get(1));
}
@Test
/**
* Slightly more complicated test: the window fits
* 5 lines and a bit.
*
*/
public void testGetOffsetsBadFit() {
//Text is 275 characters long, which is 5.5 pages.
//Every line should be exactly ABCDEFGHIJ
String text = LayoutTextUtil.getStringOfLength("ABCDEFGHIJ", 275);
/*
* The BookView is 55px high, meaning it will fit 5 lines, but not 6.
*/
when(this.mockBookView.getMeasuredHeight()).thenReturn(55);
List<Integer> offsets = this.strategy.getPageOffsets(text, false);
//The end result should still be 6 pages
assertEquals(6, offsets.size() );
//Offsets are still 0, 50...
assertEquals((int) 0, (int) offsets.get(0));
assertEquals((int) 50, (int) offsets.get(1));
}
@Test
/**
* Special case, where the lines are higher than
* can be fit on the screen. This can happen with
* large images.
*/
public void testVeryLargeLines() {
//1 char wide, 105px high
initMockLayout(1, 105);
String text = "ABC";
/*
* The BookView is 100px high
*/
when(this.mockBookView.getMeasuredHeight()).thenReturn(100);
List<Integer> offsets = this.strategy.getPageOffsets(text, false);
//Each line should be a page
assertEquals(3, offsets.size() );
assertEquals((int) 0, (int) offsets.get(0));
assertEquals((int) 1, (int) offsets.get(1));
assertEquals((int) 2, (int) offsets.get(2));
}
@Test
public void testEmptyText() {
Spanned text = getSpanned("");
List<Integer> offsets = this.strategy.getPageOffsets(text, false);
//We should have an empty list
assertEquals(0, offsets.size() );
}
/**
* In this test the text is just 1 line long.
*
* Should yield 1 page.
*/
@Test
public void testOneLinePage() {
//5 chars wide, 105px high
initMockLayout(5, 105);
Spanned text = getSpanned("1234");
/*
* The BookView is 100px high
*/
when(this.mockBookView.getMeasuredHeight()).thenReturn(100);
List<Integer> offsets = this.strategy.getPageOffsets(text, false);
//We should have a single page
assertEquals(1, offsets.size() );
assertEquals((int) 0, (int) offsets.get(0));
}
@Test
public void testPageTurning() {
String page1 = getStringOfLength("ABCDEFGHIJ", 50);
String page2 = getStringOfLength("012345", 50);
String page3 = getStringOfLength("XYZABC", 25);
Spanned text = getSpanned( page1 + page2 + page3 );
assertEquals(125, text.length()); //Sanity check
/*
* The BookView is 50px high, meaning it will fit 5 lines.
*/
when(this.mockBookView.getMeasuredHeight()).thenReturn(50);
List<Integer> offsets = this.strategy.getPageOffsets(text, false);
assertEquals(3, offsets.size() );
this.strategy.loadText( text );
this.strategy.updatePosition();
assertEquals(0, this.strategy.getCurrentPage());
verify( mockTextView ).setText(page1);
this.strategy.pageDown();
verify( mockTextView ).setText(page2);
this.strategy.pageDown();
verify( mockTextView ).setText(page3);
this.strategy.pageUp();
verify( mockTextView, times(2) ).setText(page2);
}
}