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 17 package com.android.tv.recommendation; 18 19 import static androidx.test.InstrumentationRegistry.getContext; 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertTrue; 22 23 import com.android.tv.data.api.Channel; 24 import com.android.tv.recommendation.RecommendationUtils.ChannelRecordSortedMapHelper; 25 import com.android.tv.recommendation.Recommender.Evaluator; 26 import com.android.tv.testing.utils.Utils; 27 import java.util.ArrayList; 28 import java.util.List; 29 import org.junit.Before; 30 31 /** Base test case for Recommendation Evaluator Unit tests. */ 32 public abstract class EvaluatorTestCase<T extends Evaluator> { 33 private static final long INVALID_CHANNEL_ID = -1; 34 35 private static final double SCORE_DELTA = 0.01; 36 37 private ChannelRecordSortedMapHelper mChannelRecordSortedMap; 38 private RecommendationDataManager mDataManager; 39 40 public T mEvaluator; 41 42 @Before setUp()43 public void setUp() { 44 mChannelRecordSortedMap = new ChannelRecordSortedMapHelper(getContext()); 45 mDataManager = 46 RecommendationUtils.createMockRecommendationDataManager(mChannelRecordSortedMap); 47 Recommender mRecommender = new FakeRecommender(); 48 mEvaluator = createEvaluator(); 49 mEvaluator.setRecommender(mRecommender); 50 mChannelRecordSortedMap.setRecommender(mRecommender); 51 mChannelRecordSortedMap.resetRandom(Utils.createTestRandom()); 52 } 53 54 /** Each evaluator test has to create Evaluator in {@code mEvaluator}. */ createEvaluator()55 public abstract T createEvaluator(); 56 addChannels(int numberOfChannels)57 public void addChannels(int numberOfChannels) { 58 mChannelRecordSortedMap.addChannels(numberOfChannels); 59 } 60 addChannel()61 public Channel addChannel() { 62 return mChannelRecordSortedMap.addChannel(); 63 } 64 addRandomWatchLogs( long watchStartTimeMs, long watchEndTimeMs, long maxWatchDurationMs)65 public void addRandomWatchLogs( 66 long watchStartTimeMs, long watchEndTimeMs, long maxWatchDurationMs) { 67 assertTrue( 68 mChannelRecordSortedMap.addRandomWatchLogs( 69 watchStartTimeMs, watchEndTimeMs, maxWatchDurationMs)); 70 } 71 addWatchLog(long channelId, long watchStartTimeMs, long durationTimeMs)72 public void addWatchLog(long channelId, long watchStartTimeMs, long durationTimeMs) { 73 assertTrue( 74 mChannelRecordSortedMap.addWatchLog(channelId, watchStartTimeMs, durationTimeMs)); 75 } 76 getChannelIdListSorted()77 public List<Long> getChannelIdListSorted() { 78 return new ArrayList<>(mChannelRecordSortedMap.keySet()); 79 } 80 getLatestWatchEndTimeMs()81 public long getLatestWatchEndTimeMs() { 82 long latestWatchEndTimeMs = 0; 83 for (ChannelRecord channelRecord : mChannelRecordSortedMap.values()) { 84 latestWatchEndTimeMs = 85 Math.max(latestWatchEndTimeMs, channelRecord.getLastWatchEndTimeMs()); 86 } 87 return latestWatchEndTimeMs; 88 } 89 90 /** Check whether scores of each channels are valid. */ assertChannelScoresValid()91 protected void assertChannelScoresValid() { 92 assertEqualScores( 93 Evaluator.NOT_RECOMMENDED, mEvaluator.evaluateChannel(INVALID_CHANNEL_ID)); 94 assertEqualScores( 95 Evaluator.NOT_RECOMMENDED, 96 mEvaluator.evaluateChannel(mChannelRecordSortedMap.size())); 97 98 for (long channelId : mChannelRecordSortedMap.keySet()) { 99 double score = mEvaluator.evaluateChannel(channelId); 100 assertTrue( 101 "Channel " + channelId + " score of " + score + "is not valid", 102 score == Evaluator.NOT_RECOMMENDED || (0.0 <= score && score <= 1.0)); 103 } 104 } 105 106 /** Notify that loading channels and watch logs are finished. */ notifyChannelAndWatchLogLoaded()107 protected void notifyChannelAndWatchLogLoaded() { 108 mEvaluator.onChannelRecordListChanged(new ArrayList<>(mChannelRecordSortedMap.values())); 109 } 110 assertEqualScores(double expected, double actual)111 void assertEqualScores(double expected, double actual) { 112 assertEquals(expected, actual, SCORE_DELTA); 113 } 114 assertEqualScores(String message, double expected, double actual)115 void assertEqualScores(String message, double expected, double actual) { 116 assertEquals(message, expected, actual, SCORE_DELTA); 117 } 118 119 private class FakeRecommender extends Recommender { FakeRecommender()120 public FakeRecommender() { 121 super( 122 new Recommender.Listener() { 123 @Override 124 public void onRecommenderReady() {} 125 126 @Override 127 public void onRecommendationChanged() {} 128 }, 129 true, 130 mDataManager); 131 } 132 133 @Override getChannelRecord(long channelId)134 public ChannelRecord getChannelRecord(long channelId) { 135 return mChannelRecordSortedMap.get(channelId); 136 } 137 } 138 } 139