1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 package org.mozilla.gecko.activitystream.homepanel.topstories;
6 
7 import junit.framework.Assert;
8 import org.json.JSONArray;
9 import org.json.JSONException;
10 import org.json.JSONObject;
11 import org.junit.Test;
12 import org.junit.runner.RunWith;
13 import org.mozilla.gecko.activitystream.homepanel.model.TopStory;
14 import org.mozilla.gecko.background.testhelpers.TestRunner;
15 
16 import java.util.List;
17 
18 @RunWith(TestRunner.class)
19 public class TestPocketStoriesLoader {
20     private static final String KEY_STATUS = "status";
21     private static final String KEY_LIST = "list";
22 
23     private static final String KEY_URL = "url";
24     private static final String KEY_DEDUPE_URL = "dedupe_url";
25     private static final String KEY_TITLE = "title";
26     private static final String KEY_IMAGE_SRC = "image_src";
27 
28     private static final String POCKET_URL = "POCKET_URL";
29     private static final String PAGE_URL = "PAGE_URL";
30     private static final String TITLE = "TITLE";
31     private static final String IMAGE_URL = "IMAGE_URL";
32 
makeBasicPocketResponse(JSONObject[] storyItems)33     private String makeBasicPocketResponse(JSONObject[] storyItems) {
34         final JSONObject basicResponse = new JSONObject();
35         try {
36             final JSONArray array = new JSONArray();
37             for (JSONObject item : storyItems) {
38                 array.put(item);
39             }
40 
41             basicResponse.put(KEY_STATUS, 1); // arbitrarily chosen
42             basicResponse.put(KEY_LIST, array);
43 
44         } catch (JSONException e) {
45             Assert.fail("Problem creating Pocket response JSON object");
46         }
47         return basicResponse.toString();
48     }
49 
makeBasicStoryItem()50     private JSONObject makeBasicStoryItem() {
51         final JSONObject storyItem = new JSONObject();
52         try {
53             storyItem.put(KEY_URL, POCKET_URL);
54             storyItem.put(KEY_DEDUPE_URL, PAGE_URL);
55             storyItem.put(KEY_TITLE, TITLE);
56             storyItem.put(KEY_IMAGE_SRC, IMAGE_URL);
57         } catch (JSONException e) {
58             Assert.fail("Problem creating Pocket story JSON object");
59         }
60         return storyItem;
61     }
62 
63     @Test
testJSONStringToTopStoriesWithBasicObject()64     public void testJSONStringToTopStoriesWithBasicObject() {
65         final String basicResponseString = makeBasicPocketResponse(new JSONObject[] { makeBasicStoryItem() });
66         final List<TopStory> stories = PocketStoriesLoader.jsonStringToTopStories(basicResponseString);
67         Assert.assertEquals(1, stories.size());
68 
69         final TopStory story = stories.get(0);
70         Assert.assertEquals(PAGE_URL, story.getUrl());
71         Assert.assertEquals(TITLE, story.getTitle());
72         Assert.assertEquals(IMAGE_URL, story.getImageUrl());
73     }
74 
75     @Test
testJSONStringToTopStoriesWithMissingTitle()76     public void testJSONStringToTopStoriesWithMissingTitle() {
77         final JSONObject storyItem = makeBasicStoryItem();
78         storyItem.remove(KEY_TITLE);
79         final String malformedResponseString = makeBasicPocketResponse(new JSONObject[] { storyItem });
80         final List<TopStory> stories = PocketStoriesLoader.jsonStringToTopStories(malformedResponseString);
81         Assert.assertEquals(0, stories.size()); // Should skip malformed item.
82     }
83 
84     @Test
testJSONStringToTopStoriesDropsMalformedTitle()85     public void testJSONStringToTopStoriesDropsMalformedTitle() throws Exception {
86         final JSONObject malformedStory = makeBasicStoryItem();
87         malformedStory.put(KEY_TITLE, "");
88         assertJSONStringToTopStoriesDropsMalformedStory(malformedStory);
89     }
90 
91     @Test
testJSONStringToTopStoriesDropsMalformedURL()92     public void testJSONStringToTopStoriesDropsMalformedURL() throws Exception {
93         final JSONObject malformedStory = makeBasicStoryItem();
94         malformedStory.put(KEY_DEDUPE_URL, "");
95         assertJSONStringToTopStoriesDropsMalformedStory(malformedStory);
96     }
97 
98     @Test
testJSONStringToTopStoriesDropsMalformedImageURL()99     public void testJSONStringToTopStoriesDropsMalformedImageURL() throws Exception {
100         final JSONObject malformedStory = makeBasicStoryItem();
101         malformedStory.put(KEY_IMAGE_SRC, "");
102         assertJSONStringToTopStoriesDropsMalformedStory(malformedStory);
103     }
104 
assertJSONStringToTopStoriesDropsMalformedStory(final JSONObject malformedStory)105     private void assertJSONStringToTopStoriesDropsMalformedStory(final JSONObject malformedStory) throws JSONException {
106         final JSONObject expectedStory = makeBasicStoryItem();
107         final String expectedStoryTitle = "expectedItem";
108         expectedStory.put(KEY_TITLE, expectedStoryTitle);
109 
110         final String jsonResponse = makeBasicPocketResponse(new JSONObject[] { expectedStory, malformedStory });
111         final List<TopStory> actualTopStories = PocketStoriesLoader.jsonStringToTopStories(jsonResponse);
112 
113         Assert.assertEquals("Expected one malformed item to be removed, leaving size 1", 1, actualTopStories.size());
114         Assert.assertEquals(expectedStoryTitle, actualTopStories.get(0).getTitle());
115     }
116 
117     // Pulled 8/28 Pocket response, with some trimming for content/brevity.
118     final String VALID_POCKET_RESPONSE = "{\"status\":1,\"list\":[" +
119             "{\"id\":2910,\"url\":\"https:\\/\\/pocket.co\\/pocket-shorted-url\"," +
120             "\"dedupe_url\":\"http:\\/\\/www.bbc.co.uk\\/actual-url\"," +
121             "\"title\":\"A Title Here\"," +
122             "\"excerpt\":\"Middle-aged people are being urged...\"," +
123             "\"domain\":\"bbc.co.uk\"," +
124             "\"image_src\":\"https:\\/\\/img.cloudfront.net\"," +
125             "\"published_timestamp\":\"1503550800\",\"sort_id\":0}," +
126 
127             "{\"id\":2909,\"url\":\"https:\\/\\/pocket.co\\/00000\"," +
128             "\"dedupe_url\":\"http:\\/\\/fortune.com\"," +
129             "\"title\":\"The Mattress Industry\",\"excerpt\":\"In any random commute...\"," +
130             "\"domain\":\"fortune.com\",\"image_src\":\"https:\\/\\/d33ypg4xwx0n86.cloudfront.net\"," +
131             "\"published_timestamp\":\"1503464400\",\"sort_id\":1}," +
132 
133             "{\"id\":2908,\"url\":\"https:\\/\\/pocket.co\\/00000\"," +
134             "\"dedupe_url\":\"https:\\/\\/medium.com\",\"title\":\"Mediocrity is a Virus.\"," +
135             "\"excerpt\":\"Little things become big things.\",\"domain\":\"medium.com\"," +
136             "\"image_src\":\"https:\\/\\/d33ypg4xwx0n86.cloudfront.net\",\"published_timestamp\":\"1503578016\",\"sort_id\":2}]}";
137 
138     @Test
testJSONStringToTopStoriesWithPocketServerResponse()139     public void testJSONStringToTopStoriesWithPocketServerResponse() {
140         final List<TopStory> stories = PocketStoriesLoader.jsonStringToTopStories(VALID_POCKET_RESPONSE);
141         Assert.assertEquals(3, stories.size());
142         final TopStory story = stories.get(0);
143 
144         Assert.assertEquals("http://www.bbc.co.uk/actual-url", story.getUrl());
145         Assert.assertEquals("A Title Here", story.getTitle());
146         Assert.assertEquals("https://img.cloudfront.net", story.getImageUrl());
147     }
148 }