locate(@NonNull String content) {
45 | List paragraphs = splitIntoParagraphs(content);
46 | return byNumber ? locateByNumber(paragraphs) : locateByContent(paragraphs);
47 | }
48 |
49 | @NonNull
50 | private List locateByNumber(@NonNull List paragraphs) {
51 | List ranges = new ArrayList<>(1);
52 | if (paragraphs.size() >= paragraphNumber) {
53 | P paragraph = paragraphs.get(paragraphNumber - 1);
54 | ranges.add(TargetRange.from(paragraph.getStart(), paragraph.getEnd()));
55 | }
56 | return ranges;
57 | }
58 |
59 | @NonNull
60 | private List locateByContent(@NonNull List paragraphs) {
61 | List ranges = new ArrayList<>();
62 | if (excerpt.isEmpty()) {
63 | return ranges;
64 | }
65 |
66 | for (P paragraph : paragraphs) {
67 | if (paragraph.getContent().contains(excerpt)) {
68 | ranges.add(TargetRange.from(paragraph.getStart(), paragraph.getEnd()));
69 | }
70 | }
71 | return ranges;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/library/src/main/java/com/bunk3r/spanez/locators/Range.java:
--------------------------------------------------------------------------------
1 | package com.bunk3r.spanez.locators;
2 |
3 | import android.support.annotation.IntRange;
4 | import android.support.annotation.NonNull;
5 |
6 | import com.bunk3r.spanez.api.Locator;
7 | import com.bunk3r.spanez.models.TargetRange;
8 |
9 | import java.util.ArrayList;
10 | import java.util.Collections;
11 | import java.util.List;
12 |
13 | /**
14 | * Part of SpanEZ
15 | * Created by joragu on 1/12/2017.
16 | */
17 |
18 | @SuppressWarnings("WeakerAccess")
19 | public final class Range implements Locator {
20 | private final TargetRange targetRange;
21 | private final List ranges = new ArrayList<>(1);
22 | private final List empty = Collections.emptyList();
23 |
24 | public static Range from(@IntRange(from = 0) int start, @IntRange(from = 0) int end) {
25 | if (end < start) {
26 | throw new IllegalArgumentException("The end of the targetRange shouldn't be before the start");
27 | }
28 |
29 | return new Range(start, end);
30 | }
31 |
32 | private Range(int start, int end) {
33 | targetRange = TargetRange.from(start, end);
34 | ranges.add(targetRange);
35 | }
36 |
37 | @NonNull
38 | @Override
39 | public List locate(@NonNull String content) {
40 | final int contentLength = content.length();
41 | return (targetRange.getStart() < contentLength && targetRange.getEnd() < contentLength)
42 | ? ranges
43 | : empty;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/library/src/main/java/com/bunk3r/spanez/locators/Word.java:
--------------------------------------------------------------------------------
1 | package com.bunk3r.spanez.locators;
2 |
3 | import android.support.annotation.NonNull;
4 |
5 | import com.bunk3r.spanez.api.Locator;
6 | import com.bunk3r.spanez.models.TargetRange;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | /**
12 | * Part of SpanEZ
13 | * Created by joragu on 1/12/2017.
14 | */
15 |
16 | @SuppressWarnings("WeakerAccess")
17 | public final class Word implements Locator {
18 | private static final int NOT_FOUND = -1;
19 |
20 | private final String snippet;
21 | private final boolean findAllOccurrences;
22 |
23 | public static Word findFirst(@NonNull String word) {
24 | return new Word(word, false);
25 | }
26 |
27 | public static Word findAll(@NonNull String word) {
28 | return new Word(word, true);
29 | }
30 |
31 | private Word(@NonNull String snippet, boolean findAllOccurrences) {
32 | this.snippet = snippet;
33 | this.findAllOccurrences = findAllOccurrences;
34 | }
35 |
36 | @NonNull
37 | @Override
38 | public List locate(@NonNull String content) {
39 | List ranges = new ArrayList<>();
40 | if (snippet.isEmpty()) {
41 | return ranges;
42 | }
43 |
44 | int startingIndex = 0;
45 | int wordLength = snippet.length() - 1;
46 |
47 | do {
48 | int wordIndex = content.indexOf(snippet, startingIndex);
49 | if (wordIndex != NOT_FOUND) {
50 | ranges.add(TargetRange.from(wordIndex, wordIndex + wordLength));
51 | } else {
52 | break;
53 | }
54 | startingIndex = wordIndex + 1;
55 | } while (findAllOccurrences);
56 |
57 | return ranges;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/library/src/main/java/com/bunk3r/spanez/models/P.java:
--------------------------------------------------------------------------------
1 | package com.bunk3r.spanez.models;
2 |
3 | /**
4 | * Part of SpanEZ
5 | * Created by Jorge Aguilar on 1/21/2017.
6 | *
7 | * This defines the content of a Paragraph
8 | */
9 | public class P {
10 | private final String content;
11 | private final int startIndex;
12 | private final int endIndex;
13 |
14 | P(String fullContent, int startIndex, int endIndex) {
15 | this.content = fullContent.substring(startIndex, endIndex);
16 | this.startIndex = startIndex;
17 | this.endIndex = fullContent.length() != endIndex ? endIndex : endIndex - 1;
18 | }
19 |
20 | public String getContent() {
21 | return content;
22 | }
23 |
24 | public int getStart() {
25 | return startIndex;
26 | }
27 |
28 | public int getEnd() {
29 | return endIndex;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/library/src/main/java/com/bunk3r/spanez/models/ParagraphLocator.java:
--------------------------------------------------------------------------------
1 | package com.bunk3r.spanez.models;
2 |
3 | import android.support.annotation.NonNull;
4 |
5 | import com.bunk3r.spanez.api.Locator;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | /**
11 | * Part of SpanEZ
12 | * Created by joragu on 1/12/2017.
13 | *
14 | * This is just to specify that this locator should return a paragraph
15 | */
16 | @SuppressWarnings("WeakerAccess")
17 | public abstract class ParagraphLocator implements Locator {
18 | private static final int NOT_FOUND = -1;
19 |
20 | /**
21 | * Splits the content by new line character (\n), any empty paragraph is ignored
22 | *
23 | * @param content the full content to split into paragraphs
24 | * @return a list of {@code P} that contains all the paragraphs
25 | */
26 | @NonNull
27 | protected List
splitIntoParagraphs(@NonNull String content) {
28 | List
paragraphs = new ArrayList<>();
29 | int startPosition = 0;
30 | int newLinePosition;
31 |
32 | do {
33 | newLinePosition = content.indexOf('\n', startPosition);
34 | int paragraphEnd = newLinePosition != NOT_FOUND ? newLinePosition : content.length();
35 | if (paragraphEnd - startPosition > 0) {
36 | P paragraph = new P(content, startPosition, paragraphEnd);
37 | paragraphs.add(paragraph);
38 | }
39 | startPosition = newLinePosition + 1;
40 | } while (newLinePosition != NOT_FOUND);
41 |
42 | return paragraphs;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/library/src/main/java/com/bunk3r/spanez/models/TargetRange.java:
--------------------------------------------------------------------------------
1 | package com.bunk3r.spanez.models;
2 |
3 | import android.support.annotation.IntRange;
4 |
5 | /**
6 | * Part of SpanEZ
7 | * Created by joragu on 1/12/2017.
8 | */
9 | public final class TargetRange {
10 | @IntRange(from = 0)
11 | private final int start;
12 |
13 | @IntRange(from = 0)
14 | private final int end;
15 |
16 | public static TargetRange from(@IntRange(from = 0) int start, @IntRange(from = 0) int end) {
17 | if (end < start) {
18 | throw new IllegalArgumentException("The end of the range shouldn't be before the start");
19 | }
20 |
21 | return new TargetRange(start, end);
22 | }
23 |
24 | private TargetRange(@IntRange(from = 0) int start, @IntRange(from = 0) int end) {
25 | this.start = start;
26 | this.end = end;
27 | }
28 |
29 | @IntRange(from = 0)
30 | public int getStart() {
31 | return start;
32 | }
33 |
34 | @IntRange(from = 0)
35 | public int getEnd() {
36 | return end;
37 | }
38 |
39 | @Override
40 | public String toString() {
41 | return "TargetRange{" + "start=" + start + ", end=" + end + '}';
42 | }
43 |
44 | @Override
45 | public boolean equals(Object o) {
46 | if (this == o) {
47 | return true;
48 | }
49 |
50 | if (!(o instanceof TargetRange)) {
51 | return false;
52 | }
53 |
54 | TargetRange that = (TargetRange) o;
55 | return start == that.start && end == that.end;
56 |
57 | }
58 |
59 | @Override
60 | public int hashCode() {
61 | int result = 31;
62 | result *= start;
63 | result += end;
64 | return result;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/library/src/main/java/com/bunk3r/spanez/spans/ClickableSpanEZ.java:
--------------------------------------------------------------------------------
1 | package com.bunk3r.spanez.spans;
2 |
3 | import android.support.annotation.NonNull;
4 | import android.text.style.ClickableSpan;
5 | import android.view.View;
6 |
7 | import com.bunk3r.spanez.callbacks.OnSpanClickListener;
8 |
9 | /**
10 | * Part of SpanEZ
11 | * Created by joragu on 1/1/2017.
12 | */
13 |
14 | public final class ClickableSpanEZ extends ClickableSpan {
15 | private final OnSpanClickListener spanClickListener;
16 | private final String text;
17 |
18 | @NonNull
19 | public static ClickableSpan from(@NonNull OnSpanClickListener onSpanClickListener, @NonNull String content) {
20 | return new ClickableSpanEZ(onSpanClickListener, content);
21 | }
22 |
23 | private ClickableSpanEZ(@NonNull OnSpanClickListener onSpanClickListener, @NonNull String content) {
24 | super();
25 | spanClickListener = onSpanClickListener;
26 | text = content;
27 | }
28 |
29 | @Override
30 | public void onClick(View widget) {
31 | spanClickListener.onSpanClick(text);
32 | }
33 | }
--------------------------------------------------------------------------------
/library/src/test/java/com/bunk3r/spanez/SpanEZTest.java:
--------------------------------------------------------------------------------
1 | package com.bunk3r.spanez;
2 |
3 | import android.text.method.LinkMovementMethod;
4 | import android.text.style.AbsoluteSizeSpan;
5 | import android.text.style.AlignmentSpan;
6 | import android.text.style.ClickableSpan;
7 | import android.text.style.LocaleSpan;
8 | import android.text.style.RelativeSizeSpan;
9 | import android.text.style.ScaleXSpan;
10 | import android.text.style.StrikethroughSpan;
11 | import android.text.style.StyleSpan;
12 | import android.text.style.SubscriptSpan;
13 | import android.text.style.SuperscriptSpan;
14 | import android.text.style.TextAppearanceSpan;
15 | import android.text.style.TypefaceSpan;
16 | import android.text.style.URLSpan;
17 | import android.text.style.UnderlineSpan;
18 | import android.widget.TextView;
19 |
20 | import com.bunk3r.spanez.api.EZ;
21 | import com.bunk3r.spanez.api.StyleEZ;
22 | import com.bunk3r.spanez.callbacks.OnSpanClickListener;
23 | import com.bunk3r.spanez.locators.Paragraph;
24 | import com.bunk3r.spanez.locators.Range;
25 | import com.bunk3r.spanez.models.TargetRange;
26 |
27 | import org.junit.Before;
28 | import org.junit.Test;
29 | import org.junit.runner.RunWith;
30 | import org.mockito.ArgumentCaptor;
31 | import org.mockito.Mock;
32 | import org.mockito.junit.MockitoJUnitRunner;
33 |
34 | import java.util.Locale;
35 |
36 | import static org.mockito.ArgumentMatchers.anyString;
37 | import static org.mockito.ArgumentMatchers.isA;
38 | import static org.mockito.Mockito.only;
39 | import static org.mockito.Mockito.spy;
40 | import static org.mockito.Mockito.times;
41 | import static org.mockito.Mockito.verify;
42 |
43 | /**
44 | * Part of SpanEZ
45 | * Created by Jorge Aguilar on 1/21/2017.
46 | */
47 | @RunWith(MockitoJUnitRunner.class)
48 | public class SpanEZTest {
49 | private static final int INTEGER_ARG = 1;
50 | @Mock
51 | private TextView mockTextView;
52 |
53 | @Mock
54 | private OnSpanClickListener spanClickListener;
55 |
56 | private Paragraph paragraph;
57 | private Range range;
58 | private StyleEZ spanBuilder;
59 |
60 | @Before
61 | public void setUp() throws Exception {
62 | spanBuilder = SpanEZ.withTextView(mockTextView)
63 | .withContent("This is a dummy content");
64 | spanBuilder = spy(spanBuilder);
65 |
66 | int start = 1;
67 | int end = 5;
68 | range = Range.from(start, end);
69 | paragraph = Paragraph.number(1);
70 | }
71 |
72 | @Test
73 | public void bold_should_add_only_one_span() {
74 | spanBuilder.style(range, EZ.BOLD)
75 | .apply();
76 |
77 | verify((SpanEZ) spanBuilder, times(1))
78 | .addSpan(isA(TargetRange.class), isA(StyleSpan.class));
79 | }
80 |
81 | @Test
82 | public void italic_should_add_only_one_span() {
83 | spanBuilder.style(range, EZ.ITALIC)
84 | .apply();
85 |
86 | verify((SpanEZ) spanBuilder, times(1))
87 | .addSpan(isA(TargetRange.class), isA(StyleSpan.class));
88 | }
89 |
90 | @Test
91 | public void underline_should_add_only_one_span() {
92 | spanBuilder.style(range, EZ.UNDERLINE)
93 | .apply();
94 |
95 | verify((SpanEZ) spanBuilder, times(1))
96 | .addSpan(isA(TargetRange.class), isA(UnderlineSpan.class));
97 | }
98 |
99 | @Test
100 | public void strikethrough_should_add_only_one_span() {
101 | spanBuilder.style(range, EZ.STRIKETHROUGH)
102 | .apply();
103 |
104 | verify((SpanEZ) spanBuilder, times(1))
105 | .addSpan(isA(TargetRange.class), isA(StrikethroughSpan.class));
106 | }
107 |
108 | @Test
109 | public void subscript_should_add_only_one_span() {
110 | spanBuilder.style(range, EZ.SUBSCRIPT)
111 | .apply();
112 |
113 | verify((SpanEZ) spanBuilder, times(1))
114 | .addSpan(isA(TargetRange.class), isA(SubscriptSpan.class));
115 | }
116 |
117 | @Test
118 | public void superscript_should_add_only_one_span() {
119 | spanBuilder.style(range, EZ.SUPERSCRIPT)
120 | .apply();
121 |
122 | verify((SpanEZ) spanBuilder, times(1))
123 | .addSpan(isA(TargetRange.class), isA(SuperscriptSpan.class));
124 | }
125 |
126 | @Test
127 | public void link_should_add_only_one_span() {
128 | spanBuilder.link(range, "")
129 | .apply();
130 |
131 | verify((SpanEZ) spanBuilder, times(1))
132 | .addSpan(isA(TargetRange.class), isA(URLSpan.class));
133 | }
134 |
135 | @Test
136 | public void font_should_add_only_one_span() {
137 | spanBuilder.font(range, EZ.MONOSPACE)
138 | .apply();
139 |
140 | verify((SpanEZ) spanBuilder, times(1))
141 | .addSpan(isA(TargetRange.class), isA(TypefaceSpan.class));
142 | }
143 |
144 | @SuppressWarnings("ResourceType")
145 | @Test
146 | public void appearance_should_add_only_one_span() {
147 | spanBuilder.appearance(range, INTEGER_ARG)
148 | .apply();
149 |
150 | verify((SpanEZ) spanBuilder, times(1))
151 | .addSpan(isA(TargetRange.class), isA(TextAppearanceSpan.class));
152 | }
153 |
154 | @Test
155 | public void locale_should_add_only_one_span() {
156 | spanBuilder.locale(range, Locale.US)
157 | .apply();
158 |
159 | verify((SpanEZ) spanBuilder, times(1))
160 | .addSpan(isA(TargetRange.class), isA(LocaleSpan.class));
161 | }
162 |
163 | @Test
164 | public void scale_x_should_add_only_one_span() {
165 | spanBuilder.scaleX(range, INTEGER_ARG)
166 | .apply();
167 |
168 | verify((SpanEZ) spanBuilder, times(1))
169 | .addSpan(isA(TargetRange.class), isA(ScaleXSpan.class));
170 | }
171 |
172 | @Test
173 | public void relative_size_should_add_only_one_span() {
174 | spanBuilder.relativeSize(range, INTEGER_ARG)
175 | .apply();
176 |
177 | verify((SpanEZ) spanBuilder, times(1))
178 | .addSpan(isA(TargetRange.class), isA(RelativeSizeSpan.class));
179 | }
180 |
181 | @Test
182 | public void absolute_size_should_add_only_one_span() {
183 | spanBuilder.absoluteSize(range, INTEGER_ARG)
184 | .apply();
185 |
186 | verify((SpanEZ) spanBuilder, times(1))
187 | .addSpan(isA(TargetRange.class), isA(AbsoluteSizeSpan.class));
188 | }
189 |
190 | @Test
191 | public void absolute_size_pixel_independent_should_add_only_one_span() {
192 | spanBuilder.absoluteSizeDP(range, INTEGER_ARG)
193 | .apply();
194 |
195 | verify((SpanEZ) spanBuilder, times(1))
196 | .addSpan(isA(TargetRange.class), isA(AbsoluteSizeSpan.class));
197 | }
198 |
199 | @Test
200 | public void click_should_add_only_one_span() {
201 | spanBuilder.clickable(range, spanClickListener)
202 | .apply();
203 |
204 | verify(mockTextView, times(1))
205 | .setMovementMethod(isA(LinkMovementMethod.class));
206 |
207 | verify((SpanEZ) spanBuilder, times(1))
208 | .addSpan(isA(TargetRange.class), isA(ClickableSpan.class));
209 | }
210 |
211 | @Test
212 | public void clicking_on_a_click_span_triggers_callback() {
213 | spanBuilder.clickable(range, spanClickListener)
214 | .apply();
215 |
216 | ArgumentCaptor captor = ArgumentCaptor.forClass(ClickableSpan.class);
217 | verify((SpanEZ) spanBuilder, times(1))
218 | .addSpan(isA(TargetRange.class), captor.capture());
219 |
220 | captor.getValue().onClick(mockTextView);
221 |
222 | verify(spanClickListener, only())
223 | .onSpanClick(anyString());
224 | }
225 |
226 | @Test
227 | public void align_start_should_add_only_one_span() {
228 | spanBuilder.alignStart(paragraph)
229 | .apply();
230 |
231 | verify((SpanEZ) spanBuilder, times(1))
232 | .addSpan(isA(TargetRange.class), isA(AlignmentSpan.class));
233 | }
234 |
235 | @Test
236 | public void align_center_should_add_only_one_span() {
237 | spanBuilder.alignCenter(paragraph)
238 | .apply();
239 |
240 | verify((SpanEZ) spanBuilder, times(1))
241 | .addSpan(isA(TargetRange.class), isA(AlignmentSpan.class));
242 | }
243 |
244 | @Test
245 | public void align_end_should_add_only_one_span() {
246 | spanBuilder.alignEnd(paragraph)
247 | .apply();
248 |
249 | verify((SpanEZ) spanBuilder, times(1))
250 | .addSpan(isA(TargetRange.class), isA(AlignmentSpan.class));
251 | }
252 | }
--------------------------------------------------------------------------------
/library/src/test/java/com/bunk3r/spanez/locators/ParagraphTest.java:
--------------------------------------------------------------------------------
1 | package com.bunk3r.spanez.locators;
2 |
3 | import com.bunk3r.spanez.models.TargetRange;
4 |
5 | import org.junit.Test;
6 |
7 | import java.util.List;
8 |
9 | import static org.assertj.core.api.Java6Assertions.assertThat;
10 |
11 | /**
12 | * Part of SpanEZ
13 | * Created by joragu on 1/13/2017.
14 | */
15 | public class ParagraphTest {
16 | private static final int FIRST_PARAGRAPH = 1;
17 | private static final int MIDDLE_PARAGRAPH = 2;
18 | private static final int LAST_PARAGRAPH = 3;
19 | private static final int NOT_EXISTENT_PARAGRAPH = 4;
20 |
21 | private static final String EMPTY_EXCERPT = "";
22 | private static final String PARAGRAPH_EXCERPT = "paragraph";
23 | private static final String NOT_EXISTENT_EXCERPT = "random";
24 | private static final String FIRST_PARAGRAPH_CONTENT = "First paragraph";
25 | private static final String SECOND_PARAGRAPH_CONTENT = "Second paragraph";
26 | private static final String THIRD_PARAGRAPH_CONTENT = "Third paragraph";
27 | private static final String EMPTY_CONTENT = "";
28 | private static final String NEW_LINES_CONTENT = "\n\n\n\n";
29 | private static final String SINGLE_PARAGRAPH_CONTENT = NEW_LINES_CONTENT + FIRST_PARAGRAPH_CONTENT + NEW_LINES_CONTENT;
30 | private static final String MULTIPLE_PARAGRAPHS_CONTENT = FIRST_PARAGRAPH_CONTENT + "\n" + SECOND_PARAGRAPH_CONTENT + "\n" + THIRD_PARAGRAPH_CONTENT;
31 |
32 | private static final TargetRange FIRST_PARAGRAPH_RANGE = TargetRange.from(0, 15);
33 | private static final TargetRange SECOND_PARAGRAPH_RANGE = TargetRange.from(16, 32);
34 | private static final TargetRange THIRD_PARAGRAPH_RANGE = TargetRange.from(33, 47);
35 |
36 | @Test
37 | public void find_by_number_when_content_is_empty() {
38 | Paragraph paragraph = Paragraph.number(FIRST_PARAGRAPH);
39 | List results = paragraph.locate(EMPTY_CONTENT);
40 | assertThat(results).isEmpty();
41 | }
42 |
43 | @Test
44 | public void find_by_number_when_content_is_new_lines() {
45 | Paragraph paragraph = Paragraph.number(FIRST_PARAGRAPH);
46 | List results = paragraph.locate(NEW_LINES_CONTENT);
47 | assertThat(results).isEmpty();
48 | }
49 |
50 | @Test
51 | public void find_by_number_when_empty_paragraphs_exist() {
52 | Paragraph paragraph = Paragraph.number(FIRST_PARAGRAPH);
53 | List results = paragraph.locate(SINGLE_PARAGRAPH_CONTENT);
54 |
55 | int startIndex = 4;
56 | int endIndex = startIndex + FIRST_PARAGRAPH_CONTENT.length();
57 | TargetRange expectedResult = TargetRange.from(startIndex, endIndex);
58 | assertThat(results).hasSize(1)
59 | .containsOnly(expectedResult);
60 | }
61 |
62 | @Test
63 | public void find_by_number_when_paragraph_does_exist_at_start() {
64 | Paragraph paragraph = Paragraph.number(FIRST_PARAGRAPH);
65 | List results = paragraph.locate(MULTIPLE_PARAGRAPHS_CONTENT);
66 |
67 | assertThat(results).hasSize(1)
68 | .containsOnly(FIRST_PARAGRAPH_RANGE);
69 | }
70 |
71 | @Test
72 | public void find_by_number_when_paragraph_does_exist_at_center() {
73 | Paragraph paragraph = Paragraph.number(MIDDLE_PARAGRAPH);
74 | List results = paragraph.locate(MULTIPLE_PARAGRAPHS_CONTENT);
75 |
76 | assertThat(results).hasSize(1)
77 | .containsOnly(SECOND_PARAGRAPH_RANGE);
78 | }
79 |
80 | @Test
81 | public void find_by_number_when_paragraph_does_exist_at_end() {
82 | Paragraph paragraph = Paragraph.number(LAST_PARAGRAPH);
83 | List results = paragraph.locate(MULTIPLE_PARAGRAPHS_CONTENT);
84 |
85 | assertThat(results).hasSize(1)
86 | .containsOnly(THIRD_PARAGRAPH_RANGE);
87 | }
88 |
89 | @Test
90 | public void find_by_number_when_paragraph_does_not_exist() {
91 | Paragraph paragraph = Paragraph.number(NOT_EXISTENT_PARAGRAPH);
92 | List results = paragraph.locate(MULTIPLE_PARAGRAPHS_CONTENT);
93 | assertThat(results).isEmpty();
94 | }
95 |
96 | @Test
97 | public void find_by_content_when_content_is_empty() {
98 | Paragraph paragraph = Paragraph.containing(PARAGRAPH_EXCERPT);
99 | List results = paragraph.locate(EMPTY_CONTENT);
100 | assertThat(results).isEmpty();
101 | }
102 |
103 | @Test
104 | public void find_by_content_when_content_is_new_lines() {
105 | Paragraph paragraph = Paragraph.containing(PARAGRAPH_EXCERPT);
106 | List results = paragraph.locate(NEW_LINES_CONTENT);
107 | assertThat(results).isEmpty();
108 | }
109 |
110 | @Test
111 | public void find_by_content_when_excerpt_is_empty() {
112 | Paragraph paragraph = Paragraph.containing(EMPTY_EXCERPT);
113 | List results = paragraph.locate(MULTIPLE_PARAGRAPHS_CONTENT);
114 | assertThat(results).isEmpty();
115 | }
116 |
117 | @Test
118 | public void find_by_content_when_empty_paragraphs_exist() {
119 | Paragraph paragraph = Paragraph.containing(PARAGRAPH_EXCERPT);
120 | List results = paragraph.locate(SINGLE_PARAGRAPH_CONTENT);
121 |
122 | int startIndex = 4;
123 | int endIndex = startIndex + FIRST_PARAGRAPH_CONTENT.length();
124 | TargetRange expectedResult = TargetRange.from(startIndex, endIndex);
125 | assertThat(results).hasSize(1)
126 | .containsOnly(expectedResult);
127 | }
128 |
129 | @Test
130 | public void find_by_content_when_excerpt_not_present_in_content() {
131 | Paragraph paragraph = Paragraph.containing(NOT_EXISTENT_EXCERPT);
132 | List results = paragraph.locate(MULTIPLE_PARAGRAPHS_CONTENT);
133 | assertThat(results).isEmpty();
134 | }
135 |
136 | @Test
137 | public void find_by_content_when_paragraph_does_exist_at_start() {
138 | Paragraph paragraph = Paragraph.containing(FIRST_PARAGRAPH_CONTENT);
139 | List results = paragraph.locate(MULTIPLE_PARAGRAPHS_CONTENT);
140 |
141 | assertThat(results).hasSize(1)
142 | .containsOnly(FIRST_PARAGRAPH_RANGE);
143 | }
144 |
145 | @Test
146 | public void find_by_content_when_paragraph_does_exist_at_center() {
147 | Paragraph paragraph = Paragraph.containing(SECOND_PARAGRAPH_CONTENT);
148 | List results = paragraph.locate(MULTIPLE_PARAGRAPHS_CONTENT);
149 |
150 | assertThat(results).hasSize(1)
151 | .containsOnly(SECOND_PARAGRAPH_RANGE);
152 | }
153 |
154 | @Test
155 | public void find_by_content_when_paragraph_does_exist_at_end() {
156 | Paragraph paragraph = Paragraph.containing(THIRD_PARAGRAPH_CONTENT);
157 | List results = paragraph.locate(MULTIPLE_PARAGRAPHS_CONTENT);
158 |
159 | assertThat(results).hasSize(1)
160 | .containsOnly(THIRD_PARAGRAPH_RANGE);
161 | }
162 |
163 | @Test
164 | public void find_by_content_when_multiple_paragraphs_exist() {
165 | Paragraph paragraph = Paragraph.containing(PARAGRAPH_EXCERPT);
166 | List results = paragraph.locate(MULTIPLE_PARAGRAPHS_CONTENT);
167 |
168 | assertThat(results).hasSize(3)
169 | .containsOnly(FIRST_PARAGRAPH_RANGE,
170 | SECOND_PARAGRAPH_RANGE,
171 | THIRD_PARAGRAPH_RANGE);
172 | }
173 | }
--------------------------------------------------------------------------------
/library/src/test/java/com/bunk3r/spanez/locators/RangeTest.java:
--------------------------------------------------------------------------------
1 | package com.bunk3r.spanez.locators;
2 |
3 | import com.bunk3r.spanez.models.TargetRange;
4 |
5 | import org.junit.Test;
6 |
7 | import java.util.List;
8 |
9 | import static org.assertj.core.api.Java6Assertions.assertThat;
10 |
11 | /**
12 | * Part of SpanEZ
13 | * Created by joragu on 1/13/2017.
14 | */
15 | public class RangeTest {
16 | private static final String CONTENT = "This is a text where the range fits";
17 | private static final int RANGE_START = 0;
18 | private static final int RANGE_END = 10;
19 | private static final int RANGE_OUTSIDE_CONTENT = 100;
20 |
21 | @Test
22 | public void valid_range() {
23 | Range range = Range.from(RANGE_START, RANGE_END);
24 | assertThat(range).isNotNull();
25 | }
26 |
27 | @Test(expected = IllegalArgumentException.class)
28 | public void exception_thrown_when_range_is_invalid() {
29 | Range.from(RANGE_END, RANGE_START);
30 | }
31 |
32 | @Test
33 | public void range_should_not_change() {
34 | Range range = Range.from(RANGE_START, RANGE_END);
35 | List results = range.locate(CONTENT);
36 |
37 | TargetRange expectedResult = TargetRange.from(RANGE_START, RANGE_END);
38 | assertThat(results).hasSize(1)
39 | .containsOnly(expectedResult);
40 | }
41 |
42 | @Test
43 | public void do_not_a_range_if_end_range_outside_content() {
44 | Range range = Range.from(RANGE_START, RANGE_OUTSIDE_CONTENT);
45 | List results = range.locate(CONTENT);
46 | assertThat(results).isEmpty();
47 | }
48 |
49 | @Test
50 | public void do_not_a_range_if_start_range_outside_content() {
51 | Range range = Range.from(RANGE_OUTSIDE_CONTENT, RANGE_OUTSIDE_CONTENT);
52 | List results = range.locate(CONTENT);
53 | assertThat(results).isEmpty();
54 | }
55 | }
--------------------------------------------------------------------------------
/library/src/test/java/com/bunk3r/spanez/locators/WordTest.java:
--------------------------------------------------------------------------------
1 | package com.bunk3r.spanez.locators;
2 |
3 | import com.bunk3r.spanez.models.TargetRange;
4 |
5 | import org.junit.Test;
6 |
7 | import java.util.List;
8 |
9 | import static org.assertj.core.api.Java6Assertions.assertThat;
10 |
11 | /**
12 | * Part of SpanEZ
13 | * Created by joragu on 1/13/2017.
14 | */
15 | public class WordTest {
16 | private static final String EMPTY_WORD = "";
17 | private static final String FIRST_WORD = "start";
18 | private static final String MIDDLE_WORD = "middle";
19 | private static final String LAST_WORD = "end";
20 | private static final String WORD_NOT_IN_CONTENT = "blah blah";
21 | private static final String UNIQUE_CONTENT = FIRST_WORD + MIDDLE_WORD + LAST_WORD;
22 | private static final String REPEATED_CONTENT = FIRST_WORD + MIDDLE_WORD + MIDDLE_WORD + MIDDLE_WORD + LAST_WORD;
23 |
24 | private static final TargetRange FIRST_WORD_RANGE = TargetRange.from(0, 4);
25 | private static final TargetRange MIDDLE_WORD_RANGE = TargetRange.from(5, 10);
26 | private static final TargetRange LAST_WORD_RANGE = TargetRange.from(11, 13);
27 | private static final TargetRange REPEATED_MIDDLE_WORD_RANGE_1 = TargetRange.from(5, 10);
28 | private static final TargetRange REPEATED_MIDDLE_WORD_RANGE_2 = TargetRange.from(11, 16);
29 | private static final TargetRange REPEATED_MIDDLE_WORD_RANGE_3 = TargetRange.from(17, 22);
30 |
31 | @Test
32 | public void find_first_occurrence_when_only_one_exist_at_start() {
33 | Word wordLocator = Word.findFirst(FIRST_WORD);
34 | List results = wordLocator.locate(UNIQUE_CONTENT);
35 |
36 | assertThat(results).hasSize(1)
37 | .containsOnly(FIRST_WORD_RANGE);
38 | }
39 |
40 | @Test
41 | public void find_first_occurrence_when_only_one_exist_at_center() {
42 | Word wordLocator = Word.findFirst(MIDDLE_WORD);
43 | List results = wordLocator.locate(UNIQUE_CONTENT);
44 |
45 | assertThat(results).hasSize(1)
46 | .containsOnly(MIDDLE_WORD_RANGE);
47 | }
48 |
49 | @Test
50 | public void find_first_occurrence_when_only_one_exist_at_end() {
51 | Word wordLocator = Word.findFirst(LAST_WORD);
52 | List results = wordLocator.locate(UNIQUE_CONTENT);
53 |
54 | assertThat(results).hasSize(1)
55 | .containsOnly(LAST_WORD_RANGE);
56 | }
57 |
58 | @Test
59 | public void find_first_occurrence_when_multiple_exist() {
60 | Word wordLocator = Word.findFirst(MIDDLE_WORD);
61 | List results = wordLocator.locate(REPEATED_CONTENT);
62 |
63 | assertThat(results).hasSize(1)
64 | .containsOnly(REPEATED_MIDDLE_WORD_RANGE_1);
65 | }
66 |
67 | @Test
68 | public void find_first_when_it_does_not_exist_in_content() {
69 | Word wordLocator = Word.findFirst(WORD_NOT_IN_CONTENT);
70 | List results = wordLocator.locate(UNIQUE_CONTENT);
71 | assertThat(results).isEmpty();
72 | }
73 |
74 | @Test
75 | public void find_first_when_word_is_empty() {
76 | Word wordLocator = Word.findFirst(EMPTY_WORD);
77 | List results = wordLocator.locate(UNIQUE_CONTENT);
78 | assertThat(results).isEmpty();
79 | }
80 |
81 | @Test
82 | public void find_all_occurrence_when_only_one_exist_at_start() {
83 | Word wordLocator = Word.findAll(FIRST_WORD);
84 | List results = wordLocator.locate(UNIQUE_CONTENT);
85 |
86 | assertThat(results).hasSize(1)
87 | .containsOnly(FIRST_WORD_RANGE);
88 | }
89 |
90 | @Test
91 | public void find_all_occurrence_when_only_one_exist_at_end() {
92 | Word wordLocator = Word.findAll(LAST_WORD);
93 | List results = wordLocator.locate(UNIQUE_CONTENT);
94 |
95 | assertThat(results).hasSize(1)
96 | .containsOnly(LAST_WORD_RANGE);
97 | }
98 |
99 | @Test
100 | public void find_all_occurrence_when_multiple_exist() {
101 | Word wordLocator = Word.findAll(MIDDLE_WORD);
102 | List results = wordLocator.locate(REPEATED_CONTENT);
103 |
104 | assertThat(results).hasSize(3)
105 | .containsOnly(REPEATED_MIDDLE_WORD_RANGE_1,
106 | REPEATED_MIDDLE_WORD_RANGE_2,
107 | REPEATED_MIDDLE_WORD_RANGE_3);
108 | }
109 |
110 | @Test
111 | public void find_all_when_it_does_not_exist_in_content() {
112 | Word wordLocator = Word.findAll(WORD_NOT_IN_CONTENT);
113 | List results = wordLocator.locate(UNIQUE_CONTENT);
114 | assertThat(results).isEmpty();
115 | }
116 |
117 | @Test
118 | public void find_all_when_word_is_empty() {
119 | Word wordLocator = Word.findAll(EMPTY_WORD);
120 | List results = wordLocator.locate(UNIQUE_CONTENT);
121 | assertThat(results).isEmpty();
122 | }
123 | }
--------------------------------------------------------------------------------
/library/src/test/java/com/bunk3r/spanez/models/TargetRangeTest.java:
--------------------------------------------------------------------------------
1 | package com.bunk3r.spanez.models;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.assertj.core.api.Java6Assertions.assertThat;
6 |
7 | /**
8 | * Part of SpanEZ
9 | * Created by joragu on 1/13/2017.
10 | */
11 | public class TargetRangeTest {
12 | private static final int RANGE_ZERO = 0;
13 | private static final int RANGE_ONE = 1;
14 | private static final int RANGE_FIVE = 5;
15 | private static final int RANGE_TEN = 10;
16 |
17 | @Test
18 | public void valid_range() {
19 | TargetRange targetRange = TargetRange.from(RANGE_ZERO, RANGE_TEN);
20 | assertThat(targetRange).isNotNull();
21 | }
22 |
23 | @Test(expected = IllegalArgumentException.class)
24 | public void exception_thrown_when_range_is_invalid() {
25 | TargetRange.from(RANGE_TEN, RANGE_ZERO);
26 | }
27 |
28 | @Test
29 | public void hashcode_must_match() {
30 | TargetRange targetRange = TargetRange.from(RANGE_ONE, RANGE_FIVE);
31 | final int hashCode = targetRange.hashCode();
32 |
33 | int expectedResult = 36;
34 | assertThat(hashCode).isEqualTo(expectedResult);
35 | }
36 |
37 | @Test
38 | public void hashcode_must_not_match() {
39 | TargetRange targetRange = TargetRange.from(RANGE_ONE, RANGE_FIVE);
40 | final int hashCode = targetRange.hashCode();
41 |
42 | TargetRange otherRange = TargetRange.from(RANGE_ZERO, RANGE_TEN);
43 | assertThat(hashCode).isNotEqualTo(otherRange.hashCode());
44 | }
45 |
46 | @Test
47 | public void target_range_must_be_equal() {
48 | TargetRange targetRange = TargetRange.from(RANGE_ZERO, RANGE_TEN);
49 |
50 | TargetRange expectedResult = TargetRange.from(RANGE_ZERO, RANGE_TEN);
51 | assertThat(targetRange).isEqualTo(expectedResult);
52 | }
53 |
54 |
55 | @Test
56 | public void target_range_compare_same_instance() {
57 | TargetRange targetRange = TargetRange.from(RANGE_ZERO, RANGE_TEN);
58 |
59 | assertThat(targetRange).isEqualTo(targetRange);
60 | }
61 |
62 | @Test
63 | public void target_range_must_not_be_equal() {
64 | TargetRange targetRange = TargetRange.from(RANGE_ZERO, RANGE_TEN);
65 |
66 | TargetRange expectedResult = TargetRange.from(RANGE_ONE, RANGE_FIVE);
67 | assertThat(targetRange).isNotEqualTo(expectedResult);
68 | }
69 |
70 | @Test
71 | public void target_range_start_must_not_be_equal() {
72 | TargetRange targetRange = TargetRange.from(RANGE_ZERO, RANGE_TEN);
73 |
74 | TargetRange expectedResult = TargetRange.from(RANGE_ONE, RANGE_TEN);
75 | assertThat(targetRange).isNotEqualTo(expectedResult);
76 | }
77 |
78 | @Test
79 | public void target_range_must_not_be_equal_they_are_different_types() {
80 | TargetRange targetRange = TargetRange.from(RANGE_ZERO, RANGE_TEN);
81 | assertThat(targetRange).isNotEqualTo("a different object type");
82 | }
83 |
84 | @Test
85 | public void target_range_end_must_not_be_equal() {
86 | TargetRange targetRange = TargetRange.from(RANGE_ZERO, RANGE_TEN);
87 |
88 | TargetRange expectedResult = TargetRange.from(RANGE_ZERO, RANGE_FIVE);
89 | assertThat(targetRange).isNotEqualTo(expectedResult);
90 | }
91 |
92 | @Test
93 | public void getters_are_just_for_read_only() {
94 | TargetRange targetRange = TargetRange.from(RANGE_ZERO, RANGE_TEN);
95 |
96 | assertThat(targetRange.getStart()).isEqualTo(RANGE_ZERO);
97 | assertThat(targetRange.getEnd()).isEqualTo(RANGE_TEN);
98 | }
99 |
100 | @Test
101 | public void validating_target_range_to_string() {
102 | TargetRange targetRange = TargetRange.from(RANGE_ZERO, RANGE_TEN);
103 |
104 | assertThat(targetRange).hasToString("TargetRange{" + "start=" + RANGE_ZERO + ", end=" + RANGE_TEN + '}');
105 | }
106 | }
--------------------------------------------------------------------------------
/library/src/test/java/com/bunk3r/spanez/spans/ClickableSpanEZTest.java:
--------------------------------------------------------------------------------
1 | package com.bunk3r.spanez.spans;
2 |
3 | import android.text.style.ClickableSpan;
4 |
5 | import com.bunk3r.spanez.callbacks.OnSpanClickListener;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 | import org.mockito.Mock;
10 | import org.mockito.junit.MockitoJUnitRunner;
11 |
12 | import static org.mockito.Mockito.times;
13 | import static org.mockito.Mockito.verify;
14 |
15 | /**
16 | * Part of SpanEZ
17 | * Created by joragu on 1/17/2017.
18 | */
19 | @RunWith(MockitoJUnitRunner.class)
20 | public class ClickableSpanEZTest {
21 | private static final String FAKE_CONTENT = "Dummy Content";
22 |
23 | @Mock
24 | private OnSpanClickListener mockListener;
25 |
26 | @Test
27 | public void clicking_the_span_trigger_the_callback() {
28 | ClickableSpan clickableSpanEZ = ClickableSpanEZ.from(mockListener, FAKE_CONTENT);
29 |
30 | clickableSpanEZ.onClick(null);
31 | verify(mockListener, times(1)).onSpanClick(FAKE_CONTENT);
32 | }
33 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':library'
2 |
--------------------------------------------------------------------------------
/sonar-project.properties:
--------------------------------------------------------------------------------
1 | # suppress inspection "UnusedProperty" for whole file
2 |
3 | # Branches in which sonarQube will be run
4 | sonar.branch=master
5 |
6 | # must be unique in a given SonarQube instance
7 | sonar.projectKey=com.bunk3r:spanez
8 | # this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1.
9 | sonar.projectName=SpanEz
10 | sonar.projectVersion=2.0.1
11 |
12 | # Encoding of the source code. Default is default system encoding
13 | sonar.language=java
14 | sonar.sourceEncoding=UTF-8
15 |
16 | # Modules to be included in the report
17 | sonar.modules=library
18 |
19 | # Java compatibility version
20 | sonar.java.source=1.7
21 |
22 | # path to source and binaries for the code
23 | sonar.sources=src/main/java
24 | sonar.java.binaries=build/intermediates/classes/release
25 |
26 | # path to source and binaries for the tests
27 | sonar.tests=src/test/java
28 | sonar.java.test.binaries=build/intermediates/classes/test/release
29 |
30 | # path to the jacoco coverage report
31 | sonar.jacoco.reportPaths=build/jacoco/testReleaseUnitTest.exec
--------------------------------------------------------------------------------