diff --git a/build.xml b/build.xml index e93bf33f..37f4370a 100644 --- a/build.xml +++ b/build.xml @@ -60,15 +60,9 @@ - diff --git a/source/net/sourceforge/filebot/ListChangeSynchronizer.java b/source/net/sourceforge/filebot/ListChangeSynchronizer.java new file mode 100644 index 00000000..9f7f6b56 --- /dev/null +++ b/source/net/sourceforge/filebot/ListChangeSynchronizer.java @@ -0,0 +1,51 @@ + +package net.sourceforge.filebot; + + +import java.util.List; + +import ca.odell.glazedlists.EventList; +import ca.odell.glazedlists.event.ListEvent; +import ca.odell.glazedlists.event.ListEventListener; + + +//TODO: testcase, class doc +public class ListChangeSynchronizer implements ListEventListener { + + private final List target; + + + public ListChangeSynchronizer(EventList source, List target) { + this.target = target; + source.addListEventListener(this); + } + + + public void listChanged(ListEvent listChanges) { + EventList source = listChanges.getSourceList(); + + // update target list + while (listChanges.next()) { + int index = listChanges.getIndex(); + int type = listChanges.getType(); + + switch (type) { + case ListEvent.INSERT: + target.add(index, source.get(index)); + break; + case ListEvent.UPDATE: + target.set(index, source.get(index)); + break; + case ListEvent.DELETE: + target.remove(index); + break; + } + } + } + + + public static ListChangeSynchronizer syncEventListToList(EventList source, List target) { + return new ListChangeSynchronizer(source, target); + } + +} diff --git a/source/net/sourceforge/filebot/ui/AbstractSearchPanel.java b/source/net/sourceforge/filebot/ui/AbstractSearchPanel.java index 3d020100..14a549b0 100644 --- a/source/net/sourceforge/filebot/ui/AbstractSearchPanel.java +++ b/source/net/sourceforge/filebot/ui/AbstractSearchPanel.java @@ -34,6 +34,7 @@ import net.sourceforge.tuned.ProgressIterator; import net.sourceforge.tuned.ui.SelectButtonTextField; import net.sourceforge.tuned.ui.SwingWorkerPropertyChangeAdapter; import net.sourceforge.tuned.ui.TunedUtil; +import ca.odell.glazedlists.BasicEventList; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.swing.AutoCompleteSupport; @@ -46,14 +47,13 @@ public abstract class AbstractSearchPanel extends Fi private final SelectButtonTextField searchField; - private final EventList searchHistory; + private final EventList searchHistory = new BasicEventList(); - public AbstractSearchPanel(String title, Icon icon, EventList searchHistory) { + @SuppressWarnings("unchecked") + public AbstractSearchPanel(String title, Icon icon) { super(title, icon); - this.searchHistory = searchHistory; - setLayout(new BorderLayout(10, 5)); searchField = new SelectButtonTextField(); @@ -84,6 +84,15 @@ public abstract class AbstractSearchPanel extends Fi add(searchBox, BorderLayout.NORTH); add(centerPanel, BorderLayout.CENTER); + /* + * TODO: fetchHistory + // no need to care about thread-safety, history-lists are only accessed from the EDT + CompositeList completionList = new CompositeList(); + + completionList.addMemberList((EventList) searchHistory); + completionList.addMemberList(fetchHistory); + */ + AutoCompleteSupport.install(searchField.getEditor(), searchHistory); TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), searchAction); @@ -102,7 +111,7 @@ public abstract class AbstractSearchPanel extends Fi protected abstract URI getLink(S client, SearchResult searchResult); - public List getSearchHistory() { + public EventList getSearchHistory() { return searchHistory; } diff --git a/source/net/sourceforge/filebot/ui/panel/rename/MatchAction.java b/source/net/sourceforge/filebot/ui/panel/rename/MatchAction.java index d735a208..15156cf3 100644 --- a/source/net/sourceforge/filebot/ui/panel/rename/MatchAction.java +++ b/source/net/sourceforge/filebot/ui/panel/rename/MatchAction.java @@ -19,20 +19,18 @@ import javax.swing.SwingWorker; import net.sourceforge.filebot.resources.ResourceManager; import net.sourceforge.filebot.ui.panel.rename.entry.ListEntry; -import net.sourceforge.filebot.ui.panel.rename.match.Match; -import net.sourceforge.filebot.ui.panel.rename.match.Matcher; -import net.sourceforge.filebot.ui.panel.rename.similarity.LengthEqualsMetric; -import net.sourceforge.filebot.ui.panel.rename.similarity.MultiSimilarityMetric; -import net.sourceforge.filebot.ui.panel.rename.similarity.SimilarityMetric; -import net.sourceforge.filebot.ui.panel.rename.similarity.StringEqualsMetric; -import net.sourceforge.filebot.ui.panel.rename.similarity.StringSimilarityMetric; +import net.sourceforge.filebot.ui.panel.rename.matcher.Match; +import net.sourceforge.filebot.ui.panel.rename.matcher.Matcher; +import net.sourceforge.filebot.ui.panel.rename.metric.CompositeSimilarityMetric; +import net.sourceforge.filebot.ui.panel.rename.metric.NumericSimilarityMetric; +import net.sourceforge.filebot.ui.panel.rename.metric.SimilarityMetric; import net.sourceforge.tuned.ui.ProgressDialog; import net.sourceforge.tuned.ui.SwingWorkerProgressMonitor; class MatchAction extends AbstractAction { - private MultiSimilarityMetric metrics; + private CompositeSimilarityMetric metrics; private final RenameList namesList; private final RenameList filesList; @@ -50,7 +48,7 @@ class MatchAction extends AbstractAction { this.filesList = filesList; // length similarity will only effect torrent <-> file matches - metrics = new MultiSimilarityMetric(new StringSimilarityMetric(), new StringEqualsMetric(), new LengthEqualsMetric()); + metrics = new CompositeSimilarityMetric(new NumericSimilarityMetric()); setMatchName2File(true); } @@ -69,7 +67,7 @@ class MatchAction extends AbstractAction { } - public MultiSimilarityMetric getMetrics() { + public CompositeSimilarityMetric getMetrics() { return metrics; } @@ -92,7 +90,7 @@ class MatchAction extends AbstractAction { ProgressDialog progressDialog = monitor.getProgressDialog(); progressDialog.setTitle("Matching ..."); - progressDialog.setHeader("Matching ..."); + progressDialog.setHeader(progressDialog.getTitle()); progressDialog.setIcon((Icon) getValue(SMALL_ICON)); backgroundMatcher.execute(); diff --git a/source/net/sourceforge/filebot/ui/panel/rename/SimilarityPanel.java b/source/net/sourceforge/filebot/ui/panel/rename/SimilarityPanel.java index 31f1f574..ebcd5b55 100644 --- a/source/net/sourceforge/filebot/ui/panel/rename/SimilarityPanel.java +++ b/source/net/sourceforge/filebot/ui/panel/rename/SimilarityPanel.java @@ -19,8 +19,8 @@ import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import net.sourceforge.filebot.ui.panel.rename.entry.ListEntry; -import net.sourceforge.filebot.ui.panel.rename.similarity.MultiSimilarityMetric; -import net.sourceforge.filebot.ui.panel.rename.similarity.SimilarityMetric; +import net.sourceforge.filebot.ui.panel.rename.metric.CompositeSimilarityMetric; +import net.sourceforge.filebot.ui.panel.rename.metric.SimilarityMetric; import net.sourceforge.tuned.ui.notification.SeparatorBorder; @@ -70,7 +70,7 @@ class SimilarityPanel extends Box { } - public void setMetrics(MultiSimilarityMetric metrics) { + public void setMetrics(CompositeSimilarityMetric metrics) { grid.removeAll(); updaterList.clear(); diff --git a/source/net/sourceforge/filebot/ui/panel/rename/metric/AbstractNameSimilarityMetric.java b/source/net/sourceforge/filebot/ui/panel/rename/metric/AbstractNameSimilarityMetric.java new file mode 100644 index 00000000..f731ae34 --- /dev/null +++ b/source/net/sourceforge/filebot/ui/panel/rename/metric/AbstractNameSimilarityMetric.java @@ -0,0 +1,38 @@ + +package net.sourceforge.filebot.ui.panel.rename.metric; + + +import net.sourceforge.filebot.ui.panel.rename.entry.ListEntry; + + +public abstract class AbstractNameSimilarityMetric implements SimilarityMetric { + + @Override + public float getSimilarity(ListEntry a, ListEntry b) { + return getSimilarity(normalize(a.getName()), normalize(b.getName())); + } + + + protected String normalize(String name) { + name = stripChecksum(name); + name = normalizeSeparators(name); + name = name.trim(); + name = name.toLowerCase(); + + return name; + } + + + protected String normalizeSeparators(String name) { + return name.replaceAll("[\\._ ]+", " "); + } + + + protected String stripChecksum(String name) { + return name.replaceAll("\\[\\p{XDigit}{8}\\]", ""); + } + + + public abstract float getSimilarity(String a, String b); + +} diff --git a/source/net/sourceforge/filebot/ui/panel/rename/metric/CompositeSimilarityMetric.java b/source/net/sourceforge/filebot/ui/panel/rename/metric/CompositeSimilarityMetric.java new file mode 100644 index 00000000..fe5a61a9 --- /dev/null +++ b/source/net/sourceforge/filebot/ui/panel/rename/metric/CompositeSimilarityMetric.java @@ -0,0 +1,51 @@ + +package net.sourceforge.filebot.ui.panel.rename.metric; + + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import net.sourceforge.filebot.ui.panel.rename.entry.ListEntry; + + +public class CompositeSimilarityMetric implements SimilarityMetric, Iterable { + + private List similarityMetrics; + + + public CompositeSimilarityMetric(SimilarityMetric... metrics) { + similarityMetrics = Arrays.asList(metrics); + } + + + @Override + public float getSimilarity(ListEntry a, ListEntry b) { + float similarity = 0; + + for (SimilarityMetric metric : similarityMetrics) { + similarity += metric.getSimilarity(a, b) / similarityMetrics.size(); + } + + return similarity; + } + + + @Override + public String getDescription() { + return null; + } + + + @Override + public String getName() { + return "Average"; + } + + + @Override + public Iterator iterator() { + return similarityMetrics.iterator(); + } + +} diff --git a/source/net/sourceforge/filebot/ui/panel/rename/metric/LengthEqualsMetric.java b/source/net/sourceforge/filebot/ui/panel/rename/metric/LengthEqualsMetric.java new file mode 100644 index 00000000..a3f24a6c --- /dev/null +++ b/source/net/sourceforge/filebot/ui/panel/rename/metric/LengthEqualsMetric.java @@ -0,0 +1,36 @@ + +package net.sourceforge.filebot.ui.panel.rename.metric; + + +import net.sourceforge.filebot.ui.panel.rename.entry.AbstractFileEntry; +import net.sourceforge.filebot.ui.panel.rename.entry.ListEntry; + + +public class LengthEqualsMetric implements SimilarityMetric { + + @Override + public float getSimilarity(ListEntry a, ListEntry b) { + if ((a instanceof AbstractFileEntry) && (b instanceof AbstractFileEntry)) { + long lengthA = ((AbstractFileEntry) a).getLength(); + long lengthB = ((AbstractFileEntry) b).getLength(); + + if (lengthA == lengthB) + return 1; + } + + return 0; + } + + + @Override + public String getDescription() { + return "Check whether file size is equal or not"; + } + + + @Override + public String getName() { + return "Length"; + } + +} diff --git a/source/net/sourceforge/filebot/ui/panel/rename/metric/NumericSimilarityMetric.java b/source/net/sourceforge/filebot/ui/panel/rename/metric/NumericSimilarityMetric.java new file mode 100644 index 00000000..bf2d0926 --- /dev/null +++ b/source/net/sourceforge/filebot/ui/panel/rename/metric/NumericSimilarityMetric.java @@ -0,0 +1,100 @@ + +package net.sourceforge.filebot.ui.panel.rename.metric; + + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Scanner; +import java.util.Set; + +import uk.ac.shef.wit.simmetrics.similaritymetrics.AbstractStringMetric; +import uk.ac.shef.wit.simmetrics.similaritymetrics.EuclideanDistance; +import uk.ac.shef.wit.simmetrics.tokenisers.InterfaceTokeniser; +import uk.ac.shef.wit.simmetrics.wordhandlers.DummyStopTermHandler; +import uk.ac.shef.wit.simmetrics.wordhandlers.InterfaceTermHandler; + + +public class NumericSimilarityMetric extends AbstractNameSimilarityMetric { + + private final AbstractStringMetric metric; + + + public NumericSimilarityMetric() { + // I have absolutely no clue as to why, but I get a good matching behavior + // when using my NumberTokensier with EuclideanDistance + metric = new EuclideanDistance(new NumberTokeniser()); + } + + + @Override + public float getSimilarity(String a, String b) { + return metric.getSimilarity(a, b); + } + + + @Override + public String getDescription() { + return "Similarity of number patterns"; + } + + + @Override + public String getName() { + return "Numbers"; + } + + + private static class NumberTokeniser implements InterfaceTokeniser { + + private final String delimiter = "(\\D)+"; + + + @Override + public ArrayList tokenizeToArrayList(String input) { + ArrayList tokens = new ArrayList(); + + Scanner scanner = new Scanner(input); + scanner.useDelimiter(delimiter); + + while (scanner.hasNextInt()) { + tokens.add(Integer.toString(scanner.nextInt())); + } + + return tokens; + } + + + @Override + public Set tokenizeToSet(String input) { + return new HashSet(tokenizeToArrayList(input)); + } + + + @Override + public String getShortDescriptionString() { + return getClass().getSimpleName(); + } + + + @Override + public String getDelimiters() { + return delimiter; + } + + private InterfaceTermHandler stopWordHandler = new DummyStopTermHandler(); + + + @Override + public InterfaceTermHandler getStopWordHandler() { + return stopWordHandler; + } + + + @Override + public void setStopWordHandler(InterfaceTermHandler stopWordHandler) { + this.stopWordHandler = stopWordHandler; + } + + } + +} diff --git a/source/net/sourceforge/filebot/ui/panel/rename/metric/SimilarityMetric.java b/source/net/sourceforge/filebot/ui/panel/rename/metric/SimilarityMetric.java new file mode 100644 index 00000000..45b07bf8 --- /dev/null +++ b/source/net/sourceforge/filebot/ui/panel/rename/metric/SimilarityMetric.java @@ -0,0 +1,17 @@ + +package net.sourceforge.filebot.ui.panel.rename.metric; + + +import net.sourceforge.filebot.ui.panel.rename.entry.ListEntry; + + +public interface SimilarityMetric { + + public float getSimilarity(ListEntry a, ListEntry b); + + + public String getDescription(); + + + public String getName(); +} diff --git a/source/net/sourceforge/filebot/ui/panel/rename/metric/StringSimilarityMetric.java b/source/net/sourceforge/filebot/ui/panel/rename/metric/StringSimilarityMetric.java new file mode 100644 index 00000000..896022d4 --- /dev/null +++ b/source/net/sourceforge/filebot/ui/panel/rename/metric/StringSimilarityMetric.java @@ -0,0 +1,41 @@ + +package net.sourceforge.filebot.ui.panel.rename.metric; + + +import uk.ac.shef.wit.simmetrics.similaritymetrics.AbstractStringMetric; +import uk.ac.shef.wit.simmetrics.similaritymetrics.MongeElkan; +import uk.ac.shef.wit.simmetrics.tokenisers.TokeniserQGram3Extended; + + +public class StringSimilarityMetric extends AbstractNameSimilarityMetric { + + private final AbstractStringMetric metric; + + + public StringSimilarityMetric() { + // I have absolutely no clue as to why, but I get a good matching behavior + // when using MongeElkan with a QGram3Extended (far from perfect though) + metric = new MongeElkan(new TokeniserQGram3Extended()); + + //TODO QGram3Extended VS Whitespace (-> normalized values) + } + + + @Override + public float getSimilarity(String a, String b) { + return metric.getSimilarity(a, b); + } + + + @Override + public String getDescription() { + return "Similarity of names"; + } + + + @Override + public String getName() { + return metric.getShortDescriptionString(); + } + +} diff --git a/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePanel.java b/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePanel.java index eb4eaa1a..4b2968da 100644 --- a/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePanel.java +++ b/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePanel.java @@ -5,6 +5,7 @@ package net.sourceforge.filebot.ui.panel.subtitle; import java.net.URI; import java.util.List; +import net.sourceforge.filebot.ListChangeSynchronizer; import net.sourceforge.filebot.Settings; import net.sourceforge.filebot.resources.ResourceManager; import net.sourceforge.filebot.ui.AbstractSearchPanel; @@ -12,30 +13,28 @@ import net.sourceforge.filebot.ui.SelectDialog; import net.sourceforge.filebot.web.SearchResult; import net.sourceforge.filebot.web.SubtitleClient; import net.sourceforge.filebot.web.SubtitleDescriptor; -import net.sourceforge.tuned.BasicCachingList; import net.sourceforge.tuned.FunctionIterator; import net.sourceforge.tuned.ProgressIterator; import net.sourceforge.tuned.FunctionIterator.Function; import net.sourceforge.tuned.ui.SimpleIconProvider; -import ca.odell.glazedlists.EventList; -import ca.odell.glazedlists.GlazedLists; public class SubtitlePanel extends AbstractSearchPanel { public SubtitlePanel() { - super("Subtitle", ResourceManager.getIcon("panel.subtitle"), globalSearchHistory()); + super("Subtitle", ResourceManager.getIcon("panel.subtitle")); getHistoryPanel().setColumnHeader1("Show / Movie"); getHistoryPanel().setColumnHeader2("Number of Subtitles"); getSearchField().getSelectButton().setModel(SubtitleClient.getAvailableSubtitleClients()); getSearchField().getSelectButton().setIconProvider(SimpleIconProvider.forClass(SubtitleClient.class)); - } - - - private static EventList globalSearchHistory() { - return GlazedLists.eventList(new BasicCachingList(Settings.getSettings().asStringList(Settings.SUBTITLE_HISTORY))); + + List persistentSearchHistory = Settings.getSettings().asStringList(Settings.SUBTITLE_HISTORY); + + getSearchHistory().addAll(persistentSearchHistory); + + ListChangeSynchronizer.syncEventListToList(getSearchHistory(), persistentSearchHistory); } diff --git a/source/net/sourceforge/filebot/web/TVRageClient.java b/source/net/sourceforge/filebot/web/TVRageClient.java index ba6bdea0..d14df243 100644 --- a/source/net/sourceforge/filebot/web/TVRageClient.java +++ b/source/net/sourceforge/filebot/web/TVRageClient.java @@ -49,7 +49,7 @@ public class TVRageClient extends EpisodeListClient { List searchResults = new ArrayList(nodes.size()); for (Node node : nodes) { - String showid = XPathUtil.selectString("showid", node); + int showid = XPathUtil.selectInteger("showid", node); String name = XPathUtil.selectString("name", node); String link = XPathUtil.selectString("link", node); @@ -65,7 +65,7 @@ public class TVRageClient extends EpisodeListClient { @Override public ProgressIterator getEpisodeList(SearchResult searchResult, int season) throws IOException, SAXException, ParserConfigurationException { - String showId = ((TVRageSearchResult) searchResult).getShowId(); + int showId = ((TVRageSearchResult) searchResult).getShowId(); String episodeListUri = String.format("http://" + host + "/feeds/episode_list.php?sid=" + showId); Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(episodeListUri); @@ -110,18 +110,18 @@ public class TVRageClient extends EpisodeListClient { public static class TVRageSearchResult extends SearchResult { - private final String showId; + private final int showId; private final String link; - public TVRageSearchResult(String name, String showId, String link) { + public TVRageSearchResult(String name, int showId, String link) { super(name); this.showId = showId; this.link = link; } - public String getShowId() { + public int getShowId() { return showId; } diff --git a/source/net/sourceforge/tuned/PreferencesList.java b/source/net/sourceforge/tuned/PreferencesList.java index c57cc7dc..746705e3 100644 --- a/source/net/sourceforge/tuned/PreferencesList.java +++ b/source/net/sourceforge/tuned/PreferencesList.java @@ -39,28 +39,36 @@ public class PreferencesList extends AbstractList { @Override public boolean add(T e) { - prefs.put(key(size()), e); + setImpl(size(), e); return true; } + //TODO: assert invalid index + @Override + public void add(int index, T element) { + copy(index, index + 1, size() - index); + + setImpl(index, element); + } + + + private T setImpl(int index, T element) { + return prefs.put(key(index), element); + } + + + /** + * @return always null + */ @Override public T remove(int index) { - int lastIndex = size() - 1; - List shiftList = new ArrayList(subList(index, lastIndex + 1)); - - T value = shiftList.remove(0); - + copy(index + 1, index, lastIndex - index); prefs.remove(key(lastIndex)); - for (T element : shiftList) { - set(index, element); - index++; - } - - return value; + return null; } @@ -69,7 +77,19 @@ public class PreferencesList extends AbstractList { if (index < 0 || index >= size()) throw new IndexOutOfBoundsException(); - return prefs.put(key(index), element); + return setImpl(index, element); + } + + + private void copy(int startIndex, int newStartIndex, int count) { + if (count == 0 || startIndex == newStartIndex) + return; + + List copy = new ArrayList(subList(startIndex, startIndex + count)); + + for (int i = newStartIndex, n = 0; n < count; i++, n++) { + setImpl(i, copy.get(n)); + } } diff --git a/test/AllTests.java b/test/AllTests.java index bd0de2bc..858d2af2 100644 --- a/test/AllTests.java +++ b/test/AllTests.java @@ -1,6 +1,7 @@ - import junit.framework.JUnit4TestAdapter; import junit.framework.Test; +import net.sourceforge.filebot.FileBotTestSuite; +import net.sourceforge.tuned.TunedTestSuite; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -8,7 +9,7 @@ import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) -@SuiteClasses( { net.sourceforge.tuned.TestSuite.class, net.sourceforge.filebot.TestSuite.class }) +@SuiteClasses( { FileBotTestSuite.class, TunedTestSuite.class }) public class AllTests { public static Test suite() { diff --git a/test/net/sourceforge/filebot/FileBotTestSuite.java b/test/net/sourceforge/filebot/FileBotTestSuite.java new file mode 100644 index 00000000..5aae87fc --- /dev/null +++ b/test/net/sourceforge/filebot/FileBotTestSuite.java @@ -0,0 +1,23 @@ + +package net.sourceforge.filebot; + + +import junit.framework.JUnit4TestAdapter; +import junit.framework.Test; +import net.sourceforge.filebot.ui.panel.rename.MatcherTestSuite; +import net.sourceforge.filebot.web.WebTestSuite; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + + +@RunWith(Suite.class) +@SuiteClasses( { MatcherTestSuite.class, WebTestSuite.class }) +public class FileBotTestSuite { + + public static Test suite() { + return new JUnit4TestAdapter(FileBotTestSuite.class); + } + +} diff --git a/test/net/sourceforge/filebot/ui/panel/rename/MatcherTestSuite.java b/test/net/sourceforge/filebot/ui/panel/rename/MatcherTestSuite.java new file mode 100644 index 00000000..bf123307 --- /dev/null +++ b/test/net/sourceforge/filebot/ui/panel/rename/MatcherTestSuite.java @@ -0,0 +1,23 @@ + +package net.sourceforge.filebot.ui.panel.rename; + + +import junit.framework.JUnit4TestAdapter; +import junit.framework.Test; +import net.sourceforge.filebot.ui.panel.rename.metric.AbstractNameSimilarityMetricTest; +import net.sourceforge.filebot.ui.panel.rename.metric.NumericSimilarityMetricTest; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + + +@RunWith(Suite.class) +@SuiteClasses( { AbstractNameSimilarityMetricTest.class, NumericSimilarityMetricTest.class }) +public class MatcherTestSuite { + + public static Test suite() { + return new JUnit4TestAdapter(MatcherTestSuite.class); + } + +} diff --git a/test/net/sourceforge/filebot/ui/panel/rename/metric/AbstractNameSimilarityMetricTest.java b/test/net/sourceforge/filebot/ui/panel/rename/metric/AbstractNameSimilarityMetricTest.java new file mode 100644 index 00000000..669d5894 --- /dev/null +++ b/test/net/sourceforge/filebot/ui/panel/rename/metric/AbstractNameSimilarityMetricTest.java @@ -0,0 +1,83 @@ + +package net.sourceforge.filebot.ui.panel.rename.metric; + + +import static org.junit.Assert.assertEquals; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; + +import net.sourceforge.tuned.TestUtil; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + + +@RunWith(Parameterized.class) +public class AbstractNameSimilarityMetricTest { + + private static final BasicNameSimilarityMetric metric = new BasicNameSimilarityMetric(); + + + @Parameters + public static Collection createParameters() { + Map matches = new LinkedHashMap(); + + // normalize separators + matches.put("test s01e01 first", "test.S01E01.First"); + matches.put("test s01e02 second", "test_S01E02_Second"); + matches.put("test s01e03 third", "__test__S01E03__Third__"); + matches.put("test s01e04 four", "test s01e04 four"); + + // strip checksum + matches.put("test", "test [EF62DF13]"); + + // lower-case + matches.put("the a-team", "The A-Team"); + + return TestUtil.asParameters(matches.entrySet().toArray()); + } + + private Entry entry; + + + public AbstractNameSimilarityMetricTest(Entry entry) { + this.entry = entry; + } + + + @Test + public void normalize() { + String normalizedName = entry.getKey(); + String unnormalizedName = entry.getValue(); + + assertEquals(normalizedName, metric.normalize(unnormalizedName)); + } + + + private static class BasicNameSimilarityMetric extends AbstractNameSimilarityMetric { + + @Override + public float getSimilarity(String a, String b) { + return a.equals(b) ? 1 : 0; + } + + + @Override + public String getDescription() { + return "Equals"; + } + + + @Override + public String getName() { + return "Equals"; + } + + } + +} diff --git a/test/net/sourceforge/filebot/ui/panel/rename/metric/NumericSimilarityMetricTest.java b/test/net/sourceforge/filebot/ui/panel/rename/metric/NumericSimilarityMetricTest.java new file mode 100644 index 00000000..0f2b17ed --- /dev/null +++ b/test/net/sourceforge/filebot/ui/panel/rename/metric/NumericSimilarityMetricTest.java @@ -0,0 +1,96 @@ + +package net.sourceforge.filebot.ui.panel.rename.metric; + + +import static org.junit.Assert.assertEquals; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; + +import net.sourceforge.tuned.TestUtil; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + + +@RunWith(Parameterized.class) +public class NumericSimilarityMetricTest { + + private static NumericSimilarityMetric metric = new NumericSimilarityMetric(); + + private static Map matches = createMatches(); + + + public static Map createMatches() { + Map matches = new LinkedHashMap(); + + // lots of naming variations + matches.put("Test - 1x01", "test.S01E01.Pilot.HDTV.XviD-FQM"); + matches.put("Test - 1x02", "test.S01E02.HDTV.XviD-DIMENSION"); + matches.put("Test - 1x03", "test.S01E03.Third.time.is.the.charm.DSR.XviD-2SD"); + matches.put("Test - 1x04", "test.S01E04.Four.Square.HDTV-FQM.eng"); + matches.put("Test - 1x05", "test.season.1.episode.05.DSR.eng"); + matches.put("Test - 1x06", "test.1x06.dsr.V1"); + matches.put("Test - 1x07", "test.s01e07.dsr.tempt.12.V0"); + matches.put("Test - 1x08", "test.s01e08.dsr.tempt.16.V0"); + matches.put("Test - 1x09", "Test - 1x09"); + matches.put("Test - 1x10", "test.s01e10.dsr.xvid-2sd.VO"); + matches.put("Test - 1x11", "Test - 01x11 - The Question"); + matches.put("Test - 1x12", "test.1x12.iht.VO"); + matches.put("Test - 1x13", "Test.S01E13.DSR.XviD-0TV"); + matches.put("Test - 1x14", "Test.S01E14.DSR.XviD-2SD"); + matches.put("Test - 1x15", "Test.S01E15.DSR.XviD-0TV"); + matches.put("Test - 1x16", "test.1x16.0tv.VO"); + matches.put("Test - 1x17", "Test.S01E17.42.is.the.answer.DSR.XviD-0TV"); + matches.put("Test - 1x18", "Test.S01E18.DSR.XviD-0TV"); + + // lots of numbers + matches.put("The 4400 - 1x01", "the.4400.s1e01.pilot.720p"); + matches.put("The 4400 - 4x04", "the.4400.s4e04.eden.720p"); + + return matches; + } + + + @Parameters + public static Collection createParameters() { + return TestUtil.asParameters(matches.keySet().toArray()); + } + + private String normalizedName; + + + public NumericSimilarityMetricTest(String normalizedName) { + this.normalizedName = normalizedName; + } + + + @Test + public void getBestMatch() { + String match = getBestMatch(normalizedName, matches.values()); + + assertEquals(matches.get(normalizedName), match); + } + + + public String getBestMatch(String value, Collection testdata) { + float maxSimilarity = -1; + String mostSimilar = null; + + for (String comparisonValue : testdata) { + float similarity = metric.getSimilarity(value, comparisonValue); + + // System.out.println(String.format("%s vs %s = %f", value, comparisonValue, similarity)); + + if (similarity > maxSimilarity) { + maxSimilarity = similarity; + mostSimilar = comparisonValue; + } + } + + return mostSimilar; + } +} diff --git a/test/net/sourceforge/filebot/web/TVRageClientTest.java b/test/net/sourceforge/filebot/web/TVRageClientTest.java index 941cf9fe..1dfa9355 100644 --- a/test/net/sourceforge/filebot/web/TVRageClientTest.java +++ b/test/net/sourceforge/filebot/web/TVRageClientTest.java @@ -15,7 +15,7 @@ import org.junit.Test; public class TVRageClientTest { private TVRageClient tvrage = new TVRageClient(); - private TVRageSearchResult testResult = new TVRageSearchResult("Buffy the Vampire Slayer", "2930", "http://www.tvrage.com/Buffy_The_Vampire_Slayer"); + private TVRageSearchResult testResult = new TVRageSearchResult("Buffy the Vampire Slayer", 2930, "http://www.tvrage.com/Buffy_The_Vampire_Slayer"); @Test diff --git a/test/net/sourceforge/filebot/TestSuite.java b/test/net/sourceforge/filebot/web/WebTestSuite.java similarity index 60% rename from test/net/sourceforge/filebot/TestSuite.java rename to test/net/sourceforge/filebot/web/WebTestSuite.java index f19cb0b6..a051f77f 100644 --- a/test/net/sourceforge/filebot/TestSuite.java +++ b/test/net/sourceforge/filebot/web/WebTestSuite.java @@ -1,5 +1,5 @@ -package net.sourceforge.filebot; +package net.sourceforge.filebot.web; import junit.framework.JUnit4TestAdapter; @@ -11,11 +11,11 @@ import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) -@SuiteClasses( {}) -public class TestSuite { +@SuiteClasses( { TVRageClientTest.class }) +public class WebTestSuite { public static Test suite() { - return new JUnit4TestAdapter(TestSuite.class); + return new JUnit4TestAdapter(WebTestSuite.class); } } diff --git a/test/net/sourceforge/tuned/PreferencesListTest.java b/test/net/sourceforge/tuned/PreferencesListTest.java index 8661fc50..98a1b7ee 100644 --- a/test/net/sourceforge/tuned/PreferencesListTest.java +++ b/test/net/sourceforge/tuned/PreferencesListTest.java @@ -5,6 +5,7 @@ package net.sourceforge.tuned; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import java.util.ArrayList; import java.util.List; import java.util.prefs.Preferences; @@ -23,7 +24,7 @@ public class PreferencesListTest { @BeforeClass public static void setUpBeforeClass() throws Exception { - root = Preferences.userRoot().node("filebot-test/PreferencesList"); + root = Preferences.userRoot().node("junit-test"); strings = root.node("strings"); strings.put("0", "Rei"); @@ -59,7 +60,7 @@ public class PreferencesListTest { @Test - public void testAdd() { + public void add() { List list = PreferencesList.map(numbers, Integer.class); list.add(3); @@ -70,16 +71,25 @@ public class PreferencesListTest { @Test public void remove() { - temp.put("0", "Gladiator 1"); - temp.put("1", "Gladiator 2"); - temp.put("2", "Gladiator 3"); - temp.put("3", "Gladiator 4"); - List list = PreferencesList.map(temp, String.class); + ArrayList compareValues = new ArrayList(); + + compareValues.add("Gladiator 1"); + compareValues.add("Gladiator 2"); + compareValues.add("Gladiator 3"); + compareValues.add("Gladiator 4"); + compareValues.add("Gladiator 5"); + + List prefs = PreferencesList.map(temp, String.class); + prefs.addAll(compareValues); + + for (int index : new int[] { 4, 0, 1 }) { + prefs.remove(index); + compareValues.remove(index); + + assertArrayEquals(compareValues.toArray(), prefs.toArray()); + } - assertEquals("Gladiator 2", list.remove(1)); - assertEquals("Gladiator 4", list.remove(2)); - assertEquals("Gladiator 1", list.remove(0)); } diff --git a/test/net/sourceforge/tuned/PreferencesMapTest.java b/test/net/sourceforge/tuned/PreferencesMapTest.java index d3459bf1..70a73ea8 100644 --- a/test/net/sourceforge/tuned/PreferencesMapTest.java +++ b/test/net/sourceforge/tuned/PreferencesMapTest.java @@ -31,7 +31,7 @@ public class PreferencesMapTest { @BeforeClass public static void setUpBeforeClass() throws Exception { - root = Preferences.userRoot().node("filebot-test/PreferencesMap"); + root = Preferences.userRoot().node("junit-test"); strings = root.node("strings"); strings.put("1", "Firefly"); diff --git a/test/net/sourceforge/tuned/TestUtil.java b/test/net/sourceforge/tuned/TestUtil.java index 5efc070e..69bb6397 100644 --- a/test/net/sourceforge/tuned/TestUtil.java +++ b/test/net/sourceforge/tuned/TestUtil.java @@ -11,16 +11,14 @@ import java.util.List; public class TestUtil { - public static List> rotations(Collection source) { - List> rotations = new ArrayList>(); + public static List asParameters(Object... parameterSet) { + List list = new ArrayList(); - for (int i = 0; i < source.size(); i++) { - List copy = new ArrayList(source); - Collections.rotate(copy, i); - rotations.add(copy); + for (Object parameter : parameterSet) { + list.add(new Object[] { parameter }); } - return rotations; + return list; } @@ -35,13 +33,16 @@ public class TestUtil { } - public static List asParameters(Object... parameterSet) { - List list = new ArrayList(); + public static List> rotations(Collection source) { + List> rotations = new ArrayList>(); - for (Object parameter : parameterSet) { - list.add(new Object[] { parameter }); + for (int i = 0; i < source.size(); i++) { + List copy = new ArrayList(source); + Collections.rotate(copy, i); + rotations.add(copy); } - return list; + return rotations; } + } diff --git a/test/net/sourceforge/tuned/TestSuite.java b/test/net/sourceforge/tuned/TunedTestSuite.java similarity index 81% rename from test/net/sourceforge/tuned/TestSuite.java rename to test/net/sourceforge/tuned/TunedTestSuite.java index eb950fe4..f9596dbe 100644 --- a/test/net/sourceforge/tuned/TestSuite.java +++ b/test/net/sourceforge/tuned/TunedTestSuite.java @@ -12,10 +12,10 @@ import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) @SuiteClasses( { FunctionIteratorTest.class, PreferencesMapTest.class, PreferencesListTest.class }) -public class TestSuite { +public class TunedTestSuite { public static Test suite() { - return new JUnit4TestAdapter(TestSuite.class); + return new JUnit4TestAdapter(TunedTestSuite.class); } }