RoutineWatchEvaluatorTest.java revision 6ebde20b03db4c0d57f67acaac11832b610b966b
1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.tv.recommendation; 18 19import static org.junit.Assert.assertEquals; 20 21import android.support.test.filters.SmallTest; 22import android.test.MoreAsserts; 23 24import com.android.tv.data.Program; 25import com.android.tv.recommendation.RoutineWatchEvaluator.ProgramTime; 26 27import org.junit.Test; 28 29import java.util.Arrays; 30import java.util.Calendar; 31import java.util.List; 32import java.util.TreeSet; 33import java.util.concurrent.TimeUnit; 34 35@SmallTest 36public class RoutineWatchEvaluatorTest extends EvaluatorTestCase<RoutineWatchEvaluator> { 37 private static class ScoredItem implements Comparable<ScoredItem> { 38 private final String mBase; 39 private final String mText; 40 private final double mScore; 41 42 private ScoredItem(String base, String text) { 43 this.mBase = base; 44 this.mText = text; 45 this.mScore = RoutineWatchEvaluator.calculateTitleMatchScore(base, text); 46 } 47 48 @Override 49 public int compareTo(ScoredItem scoredItem) { 50 return Double.compare(mScore, scoredItem.mScore); 51 } 52 53 @Override 54 public String toString() { 55 return mBase + " scored with " + mText + " is " + mScore; 56 } 57 } 58 59 private static ScoredItem score(String t1, String t2) { 60 return new ScoredItem(t1, t2); 61 } 62 63 @Override 64 public RoutineWatchEvaluator createEvaluator() { 65 return new RoutineWatchEvaluator(); 66 } 67 68 @Test 69 public void testSplitTextToWords() { 70 assertSplitTextToWords(""); 71 assertSplitTextToWords("Google", "Google"); 72 assertSplitTextToWords("The Big Bang Theory", "The", "Big", "Bang", "Theory"); 73 assertSplitTextToWords("Hello, world!", "Hello", "world"); 74 assertSplitTextToWords("Adam's Rib", "Adam's", "Rib"); 75 assertSplitTextToWords("G.I. Joe", "G.I", "Joe"); 76 assertSplitTextToWords("A.I.", "A.I"); 77 } 78 79 @Test 80 public void testCalculateMaximumMatchedWordSequenceLength() { 81 assertMaximumMatchedWordSequenceLength(0, "", "Google"); 82 assertMaximumMatchedWordSequenceLength(2, "The Big Bang Theory", "Big Bang"); 83 assertMaximumMatchedWordSequenceLength(2, "The Big Bang Theory", "Theory Of Big Bang"); 84 assertMaximumMatchedWordSequenceLength(4, "The Big Bang Theory", "The Big Bang Theory"); 85 assertMaximumMatchedWordSequenceLength(1, "Modern Family", "Family Guy"); 86 assertMaximumMatchedWordSequenceLength(1, "The Simpsons", "The Walking Dead"); 87 assertMaximumMatchedWordSequenceLength(3, "Game Of Thrones 1", "Game Of Thrones 6"); 88 assertMaximumMatchedWordSequenceLength(0, "Dexter", "Friends"); 89 } 90 91 @Test 92 public void testCalculateTitleMatchScore_empty() { 93 assertEqualScores(0.0, RoutineWatchEvaluator.calculateTitleMatchScore("", "")); 94 assertEqualScores(0.0, RoutineWatchEvaluator.calculateTitleMatchScore("foo", "")); 95 assertEqualScores(0.0, RoutineWatchEvaluator.calculateTitleMatchScore("", "foo")); 96 } 97 98 @Test 99 public void testCalculateTitleMatchScore_spaces() { 100 assertEqualScores(0.0, RoutineWatchEvaluator.calculateTitleMatchScore(" ", " ")); 101 assertEqualScores(0.0, RoutineWatchEvaluator.calculateTitleMatchScore("foo", " ")); 102 assertEqualScores(0.0, RoutineWatchEvaluator.calculateTitleMatchScore(" ", "foo")); 103 } 104 105 106 @Test 107 public void testCalculateTitleMatchScore_null() { 108 assertEqualScores(0.0, RoutineWatchEvaluator.calculateTitleMatchScore(null, null)); 109 assertEqualScores(0.0, RoutineWatchEvaluator.calculateTitleMatchScore("foo", null)); 110 assertEqualScores(0.0, RoutineWatchEvaluator.calculateTitleMatchScore(null, "foo")); 111 } 112 113 @Test 114 public void testCalculateTitleMatchScore_longerMatchIsBetter() { 115 String base = "foo bar baz"; 116 assertInOrder( 117 score(base, ""), 118 score(base, "bar"), 119 score(base, "foo bar"), 120 score(base, "foo bar baz")); 121 } 122 123 @Test 124 public void testProgramTime_createFromProgram() { 125 Calendar time = Calendar.getInstance(); 126 int todayDayOfWeek = time.get(Calendar.DAY_OF_WEEK); 127 // Value of DayOfWeek is between 1 and 7 (inclusive). 128 int tomorrowDayOfWeek = (todayDayOfWeek % 7) + 1; 129 130 // Today 00:00 - 01:00. 131 ProgramTime programTimeToday0000_0100 = ProgramTime.createFromProgram( 132 createDummyProgram(todayAtHourMin(0, 0), TimeUnit.HOURS.toMillis(1))); 133 assertProgramTime(todayDayOfWeek, hourMinuteToSec(0, 0), hourMinuteToSec(1, 0), 134 programTimeToday0000_0100); 135 136 // Today 23:30 - 24:30. 137 ProgramTime programTimeToday2330_2430 = ProgramTime.createFromProgram( 138 createDummyProgram(todayAtHourMin(23, 30), TimeUnit.HOURS.toMillis(1))); 139 assertProgramTime(todayDayOfWeek, hourMinuteToSec(23, 30), hourMinuteToSec(24, 30), 140 programTimeToday2330_2430); 141 142 // Tomorrow 00:00 - 01:00. 143 ProgramTime programTimeTomorrow0000_0100 = ProgramTime.createFromProgram( 144 createDummyProgram(tomorrowAtHourMin(0, 0), TimeUnit.HOURS.toMillis(1))); 145 assertProgramTime(tomorrowDayOfWeek, hourMinuteToSec(0, 0), hourMinuteToSec(1, 0), 146 programTimeTomorrow0000_0100); 147 148 // Tomorrow 23:30 - 24:30. 149 ProgramTime programTimeTomorrow2330_2430 = ProgramTime.createFromProgram( 150 createDummyProgram(tomorrowAtHourMin(23, 30), TimeUnit.HOURS.toMillis(1))); 151 assertProgramTime(tomorrowDayOfWeek, hourMinuteToSec(23, 30), hourMinuteToSec(24, 30), 152 programTimeTomorrow2330_2430); 153 154 // Today 18:00 - Tomorrow 12:00. 155 ProgramTime programTimeToday1800_3600 = ProgramTime.createFromProgram( 156 createDummyProgram(todayAtHourMin(18, 0), TimeUnit.HOURS.toMillis(18))); 157 // Maximum duration of ProgramTime is 12 hours. 158 // So, this program looks like it ends at Tomorrow 06:00 (30:00). 159 assertProgramTime(todayDayOfWeek, hourMinuteToSec(18, 0), hourMinuteToSec(30, 0), 160 programTimeToday1800_3600); 161 } 162 163 @Test 164 public void testCalculateOverlappedIntervalScore() { 165 // Today 21:00 - 24:00. 166 ProgramTime programTimeToday2100_2400 = ProgramTime.createFromProgram( 167 createDummyProgram(todayAtHourMin(21, 0), TimeUnit.HOURS.toMillis(3))); 168 // Today 22:00 - 01:00. 169 ProgramTime programTimeToday2200_0100 = ProgramTime.createFromProgram( 170 createDummyProgram(todayAtHourMin(22, 0), TimeUnit.HOURS.toMillis(3))); 171 // Tomorrow 00:00 - 03:00. 172 ProgramTime programTimeTomorrow0000_0300 = ProgramTime.createFromProgram( 173 createDummyProgram(tomorrowAtHourMin(0, 0), TimeUnit.HOURS.toMillis(3))); 174 // Tomorrow 20:00 - Tomorrow 23:00. 175 ProgramTime programTimeTomorrow2000_2300 = ProgramTime.createFromProgram( 176 createDummyProgram(tomorrowAtHourMin(20, 0), TimeUnit.HOURS.toMillis(3))); 177 178 // Check intersection time and commutative law in all cases. 179 int oneHourInSec = hourMinuteToSec(1, 0); 180 assertOverlappedIntervalScore(2 * oneHourInSec, true, programTimeToday2100_2400, 181 programTimeToday2200_0100); 182 assertOverlappedIntervalScore(0, false, programTimeToday2100_2400, 183 programTimeTomorrow0000_0300); 184 assertOverlappedIntervalScore(2 * oneHourInSec, false, programTimeToday2100_2400, 185 programTimeTomorrow2000_2300); 186 assertOverlappedIntervalScore(oneHourInSec, true, programTimeToday2200_0100, 187 programTimeTomorrow0000_0300); 188 assertOverlappedIntervalScore(oneHourInSec, false, programTimeToday2200_0100, 189 programTimeTomorrow2000_2300); 190 assertOverlappedIntervalScore(0, false, programTimeTomorrow0000_0300, 191 programTimeTomorrow2000_2300); 192 } 193 194 @Test 195 public void testGetTimeOfDayInSec() { 196 // Time was set as 00:00:00. So, getTimeOfDay must returns 0 (= 0 * 60 * 60 + 0 * 60 + 0). 197 assertEquals("TimeOfDayInSec", hourMinuteToSec(0, 0), 198 RoutineWatchEvaluator.getTimeOfDayInSec(todayAtHourMin(0, 0))); 199 200 // Time was set as 23:59:59. So, getTimeOfDay must returns 23 * 60 + 60 + 59 * 60 + 59. 201 assertEquals("TimeOfDayInSec", hourMinuteSecondToSec(23, 59, 59), 202 RoutineWatchEvaluator.getTimeOfDayInSec(todayAtHourMinSec(23, 59, 59))); 203 } 204 205 private void assertSplitTextToWords(String text, String... words) { 206 List<String> wordList = RoutineWatchEvaluator.splitTextToWords(text); 207 MoreAsserts.assertContentsInOrder(wordList, words); 208 } 209 210 private void assertMaximumMatchedWordSequenceLength(int expectedLength, String text1, 211 String text2) { 212 List<String> wordList1 = RoutineWatchEvaluator.splitTextToWords(text1); 213 List<String> wordList2 = RoutineWatchEvaluator.splitTextToWords(text2); 214 assertEquals("MaximumMatchedWordSequenceLength", expectedLength, 215 RoutineWatchEvaluator.calculateMaximumMatchedWordSequenceLength( 216 wordList1, wordList2)); 217 assertEquals("MaximumMatchedWordSequenceLength", expectedLength, 218 RoutineWatchEvaluator.calculateMaximumMatchedWordSequenceLength( 219 wordList2, wordList1)); 220 } 221 222 private void assertProgramTime(int expectedWeekDay, int expectedStartTimeOfDayInSec, 223 int expectedEndTimeOfDayInSec, ProgramTime actualProgramTime) { 224 assertEquals("Weekday", expectedWeekDay, actualProgramTime.weekDay); 225 assertEquals("StartTimeOfDayInSec", expectedStartTimeOfDayInSec, 226 actualProgramTime.startTimeOfDayInSec); 227 assertEquals("EndTimeOfDayInSec", expectedEndTimeOfDayInSec, 228 actualProgramTime.endTimeOfDayInSec); 229 } 230 231 private void assertOverlappedIntervalScore(int expectedSeconds, boolean overlappedOnSameDay, 232 ProgramTime t1, ProgramTime t2) { 233 double score = expectedSeconds; 234 if (!overlappedOnSameDay) { 235 score *= RoutineWatchEvaluator.MULTIPLIER_FOR_UNMATCHED_DAY_OF_WEEK; 236 } 237 // Two tests for testing commutative law. 238 assertEqualScores("OverlappedIntervalScore", score, 239 RoutineWatchEvaluator.calculateOverlappedIntervalScore(t1, t2)); 240 assertEqualScores("OverlappedIntervalScore", score, 241 RoutineWatchEvaluator.calculateOverlappedIntervalScore(t2, t1)); 242 } 243 244 private int hourMinuteToSec(int hour, int minute) { 245 return hourMinuteSecondToSec(hour, minute, 0); 246 } 247 248 private int hourMinuteSecondToSec(int hour, int minute, int second) { 249 return hour * 60 * 60 + minute * 60 + second; 250 } 251 252 private Calendar todayAtHourMin(int hour, int minute) { 253 return todayAtHourMinSec(hour, minute, 0); 254 } 255 256 private Calendar todayAtHourMinSec(int hour, int minute, int second) { 257 Calendar time = Calendar.getInstance(); 258 time.set(Calendar.HOUR_OF_DAY, hour); 259 time.set(Calendar.MINUTE, minute); 260 time.set(Calendar.SECOND, second); 261 return time; 262 } 263 264 private Calendar tomorrowAtHourMin(int hour, int minute) { 265 Calendar time = todayAtHourMin(hour, minute); 266 time.add(Calendar.DATE, 1); 267 return time; 268 } 269 270 private Program createDummyProgram(Calendar startTime, long programDurationMs) { 271 long startTimeMs = startTime.getTimeInMillis(); 272 273 return new Program.Builder().setStartTimeUtcMillis(startTimeMs) 274 .setEndTimeUtcMillis(startTimeMs + programDurationMs).build(); 275 } 276 277 private static <T> void assertInOrder(T... items) { 278 TreeSet<T> copy = new TreeSet<>(Arrays.asList(items)); 279 MoreAsserts.assertContentsInOrder(copy, items); 280 } 281} 282