Update Lucene from 3.0.3 to the current version 8.2.0
Signed-off-by: Andrew DeMaria <lostonamountain@gmail.com>
This commit is contained in:
+137
-137
@@ -1,138 +1,138 @@
|
||||
package org.airsonic.player.service.search;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.airsonic.player.TestCaseUtils;
|
||||
import org.airsonic.player.dao.DaoHelper;
|
||||
import org.airsonic.player.dao.MusicFolderDao;
|
||||
import org.airsonic.player.service.MediaScannerService;
|
||||
import org.airsonic.player.service.SettingsService;
|
||||
import org.airsonic.player.util.HomeRule;
|
||||
import org.airsonic.player.util.MusicFolderTestData;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.rules.SpringClassRule;
|
||||
import org.springframework.test.context.junit4.rules.SpringMethodRule;
|
||||
|
||||
@ContextConfiguration(locations = {
|
||||
"/applicationContext-service.xml",
|
||||
"/applicationContext-cache.xml",
|
||||
"/applicationContext-testdb.xml"})
|
||||
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
|
||||
@Component
|
||||
/**
|
||||
* Abstract class for scanning MusicFolder.
|
||||
*/
|
||||
public abstract class AbstractAirsonicHomeTest implements AirsonicHomeTest {
|
||||
|
||||
@ClassRule
|
||||
public static final SpringClassRule classRule = new SpringClassRule() {
|
||||
HomeRule homeRule = new HomeRule();
|
||||
|
||||
@Override
|
||||
public Statement apply(Statement base, Description description) {
|
||||
Statement spring = super.apply(base, description);
|
||||
return homeRule.apply(spring, description);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Currently, Maven is executing test classes in series,
|
||||
* so this class can hold the state.
|
||||
* When executing in parallel, subclasses should override this.
|
||||
*/
|
||||
private static AtomicBoolean dataBasePopulated = new AtomicBoolean();
|
||||
|
||||
// Above.
|
||||
private static AtomicBoolean dataBaseReady = new AtomicBoolean();
|
||||
|
||||
protected final static Function<String, String> resolveBaseMediaPath = (childPath) -> {
|
||||
return MusicFolderTestData.resolveBaseMediaPath().concat(childPath);
|
||||
};
|
||||
|
||||
@Autowired
|
||||
protected DaoHelper daoHelper;
|
||||
|
||||
@Autowired
|
||||
protected MediaScannerService mediaScannerService;
|
||||
|
||||
@Autowired
|
||||
protected MusicFolderDao musicFolderDao;
|
||||
|
||||
@Autowired
|
||||
protected SettingsService settingsService;
|
||||
|
||||
@Rule
|
||||
public final SpringMethodRule springMethodRule = new SpringMethodRule();
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
@Override
|
||||
public AtomicBoolean dataBasePopulated() {
|
||||
return dataBasePopulated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AtomicBoolean dataBaseReady() {
|
||||
return dataBaseReady;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void populateDatabaseOnlyOnce() {
|
||||
if (!dataBasePopulated().get()) {
|
||||
dataBasePopulated().set(true);
|
||||
getMusicFolders().forEach(musicFolderDao::createMusicFolder);
|
||||
settingsService.clearMusicFolderCache();
|
||||
try {
|
||||
// Await time to avoid scan failure.
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
TestCaseUtils.execScan(mediaScannerService);
|
||||
System.out.println("--- Report of records count per table ---");
|
||||
Map<String, Integer> records = TestCaseUtils.recordsInAllTables(daoHelper);
|
||||
records.keySet().stream().filter(s ->
|
||||
s.equals("MEDIA_FILE")
|
||||
| s.equals("ARTIST")
|
||||
| s.equals("MUSIC_FOLDER")
|
||||
| s.equals("ALBUM"))
|
||||
.forEach(tableName ->
|
||||
System.out.println("\t" + tableName + " : " + records.get(tableName).toString()));
|
||||
System.out.println("--- *********************** ---");
|
||||
try {
|
||||
// Await for Lucene to finish writing(asynchronous).
|
||||
for (int i = 0; i < 5; i++) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
dataBaseReady().set(true);
|
||||
} else {
|
||||
while (!dataBaseReady().get()) {
|
||||
try {
|
||||
// The subsequent test method waits while reading DB data.
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
package org.airsonic.player.service.search;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.airsonic.player.TestCaseUtils;
|
||||
import org.airsonic.player.dao.DaoHelper;
|
||||
import org.airsonic.player.dao.MusicFolderDao;
|
||||
import org.airsonic.player.service.MediaScannerService;
|
||||
import org.airsonic.player.service.SettingsService;
|
||||
import org.airsonic.player.util.HomeRule;
|
||||
import org.airsonic.player.util.MusicFolderTestData;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.rules.SpringClassRule;
|
||||
import org.springframework.test.context.junit4.rules.SpringMethodRule;
|
||||
|
||||
@ContextConfiguration(locations = {
|
||||
"/applicationContext-service.xml",
|
||||
"/applicationContext-cache.xml",
|
||||
"/applicationContext-testdb.xml"})
|
||||
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
|
||||
@Component
|
||||
/**
|
||||
* Abstract class for scanning MusicFolder.
|
||||
*/
|
||||
public abstract class AbstractAirsonicHomeTest implements AirsonicHomeTest {
|
||||
|
||||
@ClassRule
|
||||
public static final SpringClassRule classRule = new SpringClassRule() {
|
||||
HomeRule homeRule = new HomeRule();
|
||||
|
||||
@Override
|
||||
public Statement apply(Statement base, Description description) {
|
||||
Statement spring = super.apply(base, description);
|
||||
return homeRule.apply(spring, description);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Currently, Maven is executing test classes in series,
|
||||
* so this class can hold the state.
|
||||
* When executing in parallel, subclasses should override this.
|
||||
*/
|
||||
private static AtomicBoolean dataBasePopulated = new AtomicBoolean();
|
||||
|
||||
// Above.
|
||||
private static AtomicBoolean dataBaseReady = new AtomicBoolean();
|
||||
|
||||
protected final static Function<String, String> resolveBaseMediaPath = (childPath) -> {
|
||||
return MusicFolderTestData.resolveBaseMediaPath().concat(childPath);
|
||||
};
|
||||
|
||||
@Autowired
|
||||
protected DaoHelper daoHelper;
|
||||
|
||||
@Autowired
|
||||
protected MediaScannerService mediaScannerService;
|
||||
|
||||
@Autowired
|
||||
protected MusicFolderDao musicFolderDao;
|
||||
|
||||
@Autowired
|
||||
protected SettingsService settingsService;
|
||||
|
||||
@Rule
|
||||
public final SpringMethodRule springMethodRule = new SpringMethodRule();
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
@Override
|
||||
public AtomicBoolean dataBasePopulated() {
|
||||
return dataBasePopulated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AtomicBoolean dataBaseReady() {
|
||||
return dataBaseReady;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void populateDatabaseOnlyOnce() {
|
||||
if (!dataBasePopulated().get()) {
|
||||
dataBasePopulated().set(true);
|
||||
getMusicFolders().forEach(musicFolderDao::createMusicFolder);
|
||||
settingsService.clearMusicFolderCache();
|
||||
try {
|
||||
// Await time to avoid scan failure.
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
TestCaseUtils.execScan(mediaScannerService);
|
||||
System.out.println("--- Report of records count per table ---");
|
||||
Map<String, Integer> records = TestCaseUtils.recordsInAllTables(daoHelper);
|
||||
records.keySet().stream().filter(s ->
|
||||
s.equals("MEDIA_FILE")
|
||||
| s.equals("ARTIST")
|
||||
| s.equals("MUSIC_FOLDER")
|
||||
| s.equals("ALBUM"))
|
||||
.forEach(tableName ->
|
||||
System.out.println("\t" + tableName + " : " + records.get(tableName).toString()));
|
||||
System.out.println("--- *********************** ---");
|
||||
try {
|
||||
// Await for Lucene to finish writing(asynchronous).
|
||||
for (int i = 0; i < 5; i++) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
dataBaseReady().set(true);
|
||||
} else {
|
||||
while (!dataBaseReady().get()) {
|
||||
try {
|
||||
// The subsequent test method waits while reading DB data.
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+45
-45
@@ -1,45 +1,45 @@
|
||||
package org.airsonic.player.service.search;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.airsonic.player.domain.MusicFolder;
|
||||
import org.airsonic.player.util.MusicFolderTestData;
|
||||
|
||||
/**
|
||||
* Test case interface for scanning MusicFolder.
|
||||
*/
|
||||
public interface AirsonicHomeTest {
|
||||
|
||||
/**
|
||||
* MusicFolder used by test class.
|
||||
*
|
||||
* @return MusicFolder used by test class
|
||||
*/
|
||||
default List<MusicFolder> getMusicFolders() {
|
||||
return MusicFolderTestData.getTestMusicFolders();
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether the data input has been completed.
|
||||
*
|
||||
* @return Static AtomicBoolean indicating whether the data injection has been
|
||||
* completed
|
||||
*/
|
||||
abstract AtomicBoolean dataBasePopulated();
|
||||
|
||||
/**
|
||||
* Whether the data input has been completed.
|
||||
*
|
||||
* @return Static AtomicBoolean indicating whether the data injection has been
|
||||
* completed
|
||||
*/
|
||||
abstract AtomicBoolean dataBaseReady();
|
||||
|
||||
/**
|
||||
* Populate the database only once.
|
||||
* It is called in the @Before granted method.
|
||||
*/
|
||||
void populateDatabaseOnlyOnce();
|
||||
|
||||
}
|
||||
package org.airsonic.player.service.search;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.airsonic.player.domain.MusicFolder;
|
||||
import org.airsonic.player.util.MusicFolderTestData;
|
||||
|
||||
/**
|
||||
* Test case interface for scanning MusicFolder.
|
||||
*/
|
||||
public interface AirsonicHomeTest {
|
||||
|
||||
/**
|
||||
* MusicFolder used by test class.
|
||||
*
|
||||
* @return MusicFolder used by test class
|
||||
*/
|
||||
default List<MusicFolder> getMusicFolders() {
|
||||
return MusicFolderTestData.getTestMusicFolders();
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether the data input has been completed.
|
||||
*
|
||||
* @return Static AtomicBoolean indicating whether the data injection has been
|
||||
* completed
|
||||
*/
|
||||
abstract AtomicBoolean dataBasePopulated();
|
||||
|
||||
/**
|
||||
* Whether the data input has been completed.
|
||||
*
|
||||
* @return Static AtomicBoolean indicating whether the data injection has been
|
||||
* completed
|
||||
*/
|
||||
abstract AtomicBoolean dataBaseReady();
|
||||
|
||||
/**
|
||||
* Populate the database only once.
|
||||
* It is called in the @Before granted method.
|
||||
*/
|
||||
void populateDatabaseOnlyOnce();
|
||||
|
||||
}
|
||||
|
||||
+73
-31
@@ -11,7 +11,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.lucene.analysis.TokenStream;
|
||||
import org.apache.lucene.analysis.tokenattributes.TermAttribute;
|
||||
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -85,9 +85,12 @@ public class AnalyzerFactoryTestCase {
|
||||
public void testPunctuation1() {
|
||||
|
||||
String query = "B︴C";
|
||||
String expected1 = "b";
|
||||
String expected2 = "c";
|
||||
String expected = "b︴c";
|
||||
|
||||
/*
|
||||
* XXX 3.x -> 8.x :
|
||||
* The definition of punctuation has changed.
|
||||
*/
|
||||
Arrays.stream(IndexType.values()).flatMap(i -> Arrays.stream(i.getFields())).forEach(n -> {
|
||||
List<String> terms = toTermString(n, query);
|
||||
switch (n) {
|
||||
@@ -100,9 +103,8 @@ public class AnalyzerFactoryTestCase {
|
||||
case FieldNames.FOLDER:
|
||||
case FieldNames.GENRE:
|
||||
case FieldNames.MEDIA_TYPE:
|
||||
assertEquals("tokenized : " + n, 2, terms.size());
|
||||
assertEquals("tokenized : " + n, expected1, terms.get(0));
|
||||
assertEquals("tokenized : " + n, expected2, terms.get(1));
|
||||
assertEquals("tokenized : " + n, 1, terms.size());
|
||||
assertEquals("tokenized : " + n, expected, terms.get(0));
|
||||
break;
|
||||
|
||||
/*
|
||||
@@ -112,9 +114,8 @@ public class AnalyzerFactoryTestCase {
|
||||
case FieldNames.ARTIST:
|
||||
case FieldNames.ALBUM:
|
||||
case FieldNames.TITLE:
|
||||
assertEquals("tokenized : " + n, 2, terms.size());
|
||||
assertEquals("tokenized : " + n, expected1, terms.get(0));
|
||||
assertEquals("tokenized : " + n, expected2, terms.get(1));
|
||||
assertEquals("tokenized : " + n, 1, terms.size());
|
||||
assertEquals("tokenized : " + n, expected, terms.get(0));
|
||||
break;
|
||||
/*
|
||||
* ID, FOLDER_ID, YEAR
|
||||
@@ -256,12 +257,17 @@ public class AnalyzerFactoryTestCase {
|
||||
*/
|
||||
String queryFullWidth = "THIS IS FULL-WIDTH SENTENCES.";
|
||||
terms = toTermString(queryFullWidth);
|
||||
assertEquals(5, terms.size());
|
||||
assertEquals("this", terms.get(0));// removal target is ignored
|
||||
assertEquals("is", terms.get(1));
|
||||
assertEquals("full", terms.get(2));
|
||||
assertEquals("width", terms.get(3));
|
||||
assertEquals("sentences", terms.get(4));
|
||||
/*
|
||||
* XXX 3.x -> 8.x :
|
||||
*
|
||||
* This is not a change due to the library but an intentional change.
|
||||
* The filter order has been changed properly
|
||||
* as it is probably not a deliberate specification.
|
||||
*/
|
||||
assertEquals(3, terms.size());
|
||||
assertEquals("full", terms.get(0));
|
||||
assertEquals("width", terms.get(1));
|
||||
assertEquals("sentences", terms.get(2));
|
||||
|
||||
}
|
||||
|
||||
@@ -428,6 +434,11 @@ public class AnalyzerFactoryTestCase {
|
||||
query = "_ID3_ARTIST_ Céline Frisch: Café Zimmermann";
|
||||
terms = toTermString(query);
|
||||
assertEquals(5, terms.size());
|
||||
|
||||
/*
|
||||
* XXX 3.x -> 8.x : _id3_artist_ in UAX#29.
|
||||
* Since the effect is large, trim with Filter.
|
||||
*/
|
||||
assertEquals("id3_artist", terms.get(0));
|
||||
assertEquals("celine", terms.get(1));
|
||||
assertEquals("frisch", terms.get(2));
|
||||
@@ -438,6 +449,11 @@ public class AnalyzerFactoryTestCase {
|
||||
query = "_ID3_ARTIST_ Sarah Walker/Nash Ensemble";
|
||||
terms = toTermString(query);
|
||||
assertEquals(5, terms.size());
|
||||
|
||||
/*
|
||||
* XXX 3.x -> 8.x : _id3_artist_ in UAX#29.
|
||||
* Since the effect is large, trim with Filter.
|
||||
*/
|
||||
assertEquals("id3_artist", terms.get(0));
|
||||
assertEquals("sarah", terms.get(1));
|
||||
assertEquals("walker", terms.get(2));
|
||||
@@ -464,14 +480,18 @@ public class AnalyzerFactoryTestCase {
|
||||
assertEquals(asList("abc", "def"), toTermString("~ABC~DEF~"));
|
||||
assertEquals(asList("abc", "def"), toTermString("*ABC*DEF*"));
|
||||
assertEquals(asList("abc", "def"), toTermString("?ABC?DEF?"));
|
||||
assertEquals(asList("abc", "def"), toTermString(":ABC:DEF:"));
|
||||
assertEquals(asList("abc:def"), toTermString(":ABC:DEF:")); // XXX 3.x -> 8.x : abc def -> abc:def
|
||||
assertEquals(asList("abc", "def"), toTermString("-ABC-DEF-"));
|
||||
assertEquals(asList("abc", "def"), toTermString("/ABC/DEF/"));
|
||||
assertEquals(asList("abc", "def"), toTermString("_ABC_DEF_"));
|
||||
/*
|
||||
* XXX 3.x -> 8.x : _abc_def_ in UAX#29.
|
||||
* Since the effect is large, trim with Filter.
|
||||
*/
|
||||
assertEquals(asList("abc_def"), toTermString("_ABC_DEF_")); // XXX 3.x -> 8.x : abc def -> abc_def
|
||||
assertEquals(asList("abc", "def"), toTermString(",ABC,DEF,"));
|
||||
assertEquals(asList("abc.def"), toTermString(".ABC.DEF."));
|
||||
assertEquals(asList("abc&def"), toTermString("&ABC&DEF&"));
|
||||
assertEquals(asList("abc@def"), toTermString("@ABC@DEF@"));
|
||||
assertEquals(asList("abc", "def"), toTermString("&ABC&DEF&")); // XXX 3.x -> 8.x : abc&def -> abc def
|
||||
assertEquals(asList("abc", "def"), toTermString("@ABC@DEF@")); // XXX 3.x -> 8.x : abc@def -> abc def
|
||||
assertEquals(asList("abc'def"), toTermString("'ABC'DEF'"));
|
||||
|
||||
// trim and delimiter and number
|
||||
@@ -491,11 +511,15 @@ public class AnalyzerFactoryTestCase {
|
||||
assertEquals(asList("abc1", "def"), toTermString("*ABC1*DEF*"));
|
||||
assertEquals(asList("abc1", "def"), toTermString("?ABC1?DEF?"));
|
||||
assertEquals(asList("abc1", "def"), toTermString(":ABC1:DEF:"));
|
||||
assertEquals(asList("abc1,def"), toTermString(",ABC1,DEF,"));
|
||||
assertEquals(asList("abc1-def"), toTermString("-ABC1-DEF-"));
|
||||
assertEquals(asList("abc1/def"), toTermString("/ABC1/DEF/"));
|
||||
assertEquals(asList("abc1", "def"), toTermString(",ABC1,DEF,")); // XXX 3.x -> 8.x : abc1,def -> abc1 def
|
||||
assertEquals(asList("abc1", "def"), toTermString("-ABC1-DEF-")); // XXX 3.x -> 8.x : abc1-def -> abc1 def
|
||||
assertEquals(asList("abc1", "def"), toTermString("/ABC1/DEF/")); // XXX 3.x -> 8.x : abc1/def -> abc1 def
|
||||
/*
|
||||
* XXX 3.x -> 8.x : _abc1_def_ in UAX#29.
|
||||
* Since the effect is large, trim with Filter.
|
||||
*/
|
||||
assertEquals(asList("abc1_def"), toTermString("_ABC1_DEF_"));
|
||||
assertEquals(asList("abc1.def"), toTermString(".ABC1.DEF."));
|
||||
assertEquals(asList("abc1", "def"), toTermString(".ABC1.DEF.")); // XXX 3.x -> 8.x : abc1.def -> abc1 def
|
||||
assertEquals(asList("abc1", "def"), toTermString("&ABC1&DEF&"));
|
||||
assertEquals(asList("abc1", "def"), toTermString("@ABC1@DEF@"));
|
||||
assertEquals(asList("abc1", "def"), toTermString("'ABC1'DEF'"));
|
||||
@@ -517,14 +541,17 @@ public class AnalyzerFactoryTestCase {
|
||||
assertEquals("airsonic", terms.get(0));
|
||||
assertEquals("analysis", terms.get(1));
|
||||
|
||||
/*
|
||||
* XXX 3.x -> 8.x :
|
||||
* we ve -> we've
|
||||
*/
|
||||
query = "We’ve been here before.";
|
||||
terms = toTermString(query);
|
||||
assertEquals(5, terms.size());
|
||||
assertEquals("we", terms.get(0));
|
||||
assertEquals("ve", terms.get(1));
|
||||
assertEquals("been", terms.get(2));
|
||||
assertEquals("here", terms.get(3));
|
||||
assertEquals("before", terms.get(4));
|
||||
assertEquals(4, terms.size());
|
||||
assertEquals("we've", terms.get(0));
|
||||
assertEquals("been", terms.get(1));
|
||||
assertEquals("here", terms.get(2));
|
||||
assertEquals("before", terms.get(3));
|
||||
|
||||
query = "LʼHomme";
|
||||
terms = toTermString(query);
|
||||
@@ -591,6 +618,21 @@ public class AnalyzerFactoryTestCase {
|
||||
assertEquals("glasses", terms.get(5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenre() {
|
||||
|
||||
/*
|
||||
* Confirming no conversion to singular.
|
||||
*/
|
||||
|
||||
String query = "{}";
|
||||
List<String> terms = toQueryTermString(FieldNames.GENRE, query);
|
||||
assertEquals(1, terms.size());
|
||||
assertEquals("{ }", terms.get(0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
private List<String> toTermString(String str) {
|
||||
return toTermString(null, str);
|
||||
}
|
||||
@@ -602,7 +644,7 @@ public class AnalyzerFactoryTestCase {
|
||||
new StringReader(str));
|
||||
stream.reset();
|
||||
while (stream.incrementToken()) {
|
||||
result.add(stream.getAttribute(TermAttribute.class).toString()
|
||||
result.add(stream.getAttribute(CharTermAttribute.class).toString()
|
||||
.replaceAll("^term\\=", ""));
|
||||
}
|
||||
stream.close();
|
||||
@@ -627,7 +669,7 @@ public class AnalyzerFactoryTestCase {
|
||||
new StringReader(str));
|
||||
stream.reset();
|
||||
while (stream.incrementToken()) {
|
||||
result.add(stream.getAttribute(TermAttribute.class).toString()
|
||||
result.add(stream.getAttribute(CharTermAttribute.class).toString()
|
||||
.replaceAll("^term\\=", ""));
|
||||
}
|
||||
stream.close();
|
||||
|
||||
+67
-43
@@ -8,9 +8,7 @@ import org.airsonic.player.domain.RandomSearchCriteria;
|
||||
import org.airsonic.player.domain.SearchCriteria;
|
||||
import org.airsonic.player.util.HomeRule;
|
||||
import org.apache.commons.lang.builder.ToStringBuilder;
|
||||
import org.apache.lucene.queryParser.ParseException;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.util.NumericUtils;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@@ -77,8 +75,34 @@ public class QueryFactoryTestCase {
|
||||
private static final List<MusicFolder> SINGLE_FOLDERS = Arrays.asList(MUSIC_FOLDER1);
|
||||
private static final List<MusicFolder> MULTI_FOLDERS = Arrays.asList(MUSIC_FOLDER1, MUSIC_FOLDER2);
|
||||
|
||||
|
||||
/*
|
||||
* XXX 3.x -> 8.x :
|
||||
* It does not change the basic functional requirements for the query.
|
||||
* However, some minor improvements are included.
|
||||
*
|
||||
* - Use 'Or' instead of 'SpanOr'.
|
||||
* This is suitable for 8.x document definition and query grammar.
|
||||
* A more rigorous comparison.
|
||||
*
|
||||
* - Removed comparison of input value and path from condition of search.
|
||||
* It causes a false search that the user can not imagine.
|
||||
* Originally unnecessary.
|
||||
*
|
||||
* - mediaType and genre changed to raw string key comparison.
|
||||
* Currently, these are "key" strings, both in the requirements and in the implementation.
|
||||
* The legacy "normalize" is dirty code that compensates for the incomplete analytics implementation
|
||||
* and is not necessary as long as proper key comparison can be done.
|
||||
*
|
||||
* => Treating these strictly as keys enables DB reference.
|
||||
* For example, can support multi-genre by creating a new genre field that implements another Tokenizer.
|
||||
*
|
||||
* - The method for comparing ranges of numbers has changed.
|
||||
* This is suitable for 8.x.
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testSearchArtist() throws ParseException, IOException {
|
||||
public void testSearchArtist() throws IOException {
|
||||
SearchCriteria criteria = new SearchCriteria();
|
||||
criteria.setOffset(10);
|
||||
criteria.setCount(Integer.MAX_VALUE);
|
||||
@@ -86,16 +110,16 @@ public class QueryFactoryTestCase {
|
||||
|
||||
Query query = queryFactory.search(criteria, SINGLE_FOLDERS, IndexType.ARTIST);
|
||||
assertEquals("SearchArtist",
|
||||
"+((artist:abc* folder:abc*) (artist:def* folder:def*)) +spanOr([folder:" + PATH1 + "])",
|
||||
"+((artist:abc*) (artist:def*)) +(folder:" + PATH1 + ")",
|
||||
query.toString());
|
||||
|
||||
query = queryFactory.search(criteria, MULTI_FOLDERS, IndexType.ARTIST);
|
||||
assertEquals("SearchArtist", "+((artist:abc* folder:abc*) (artist:def* folder:def*)) +spanOr([folder:" + PATH1
|
||||
+ ", folder:" + PATH2 + "])", query.toString());
|
||||
assertEquals("SearchArtist", "+((artist:abc*) (artist:def*)) +(folder:" + PATH1
|
||||
+ " folder:" + PATH2 + ")", query.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchAlbum() throws ParseException, IOException {
|
||||
public void testSearchAlbum() throws IOException {
|
||||
SearchCriteria criteria = new SearchCriteria();
|
||||
criteria.setOffset(10);
|
||||
criteria.setCount(Integer.MAX_VALUE);
|
||||
@@ -103,19 +127,19 @@ public class QueryFactoryTestCase {
|
||||
|
||||
Query query = queryFactory.search(criteria, SINGLE_FOLDERS, IndexType.ALBUM);
|
||||
assertEquals("SearchAlbum",
|
||||
"+((album:abc* artist:abc* folder:abc*) (album:def* artist:def* folder:def*)) +spanOr([folder:" + PATH1
|
||||
+ "])",
|
||||
"+((album:abc* artist:abc*) (album:def* artist:def*)) +(folder:" + PATH1
|
||||
+ ")",
|
||||
query.toString());
|
||||
|
||||
query = queryFactory.search(criteria, MULTI_FOLDERS, IndexType.ALBUM);
|
||||
assertEquals("SearchAlbum",
|
||||
"+((album:abc* artist:abc* folder:abc*) (album:def* artist:def* folder:def*)) +spanOr([folder:" + PATH1
|
||||
+ ", folder:" + PATH2 + "])",
|
||||
"+((album:abc* artist:abc*) (album:def* artist:def*)) +(folder:" + PATH1
|
||||
+ " folder:" + PATH2 + ")",
|
||||
query.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchSong() throws ParseException, IOException {
|
||||
public void testSearchSong() throws IOException {
|
||||
SearchCriteria criteria = new SearchCriteria();
|
||||
criteria.setOffset(10);
|
||||
criteria.setCount(Integer.MAX_VALUE);
|
||||
@@ -123,34 +147,34 @@ public class QueryFactoryTestCase {
|
||||
|
||||
Query query = queryFactory.search(criteria, SINGLE_FOLDERS, IndexType.SONG);
|
||||
assertEquals("SearchSong",
|
||||
"+((title:abc* artist:abc*) (title:def* artist:def*)) +spanOr([folder:" + PATH1 + "])",
|
||||
"+((title:abc* artist:abc*) (title:def* artist:def*)) +(folder:" + PATH1 + ")",
|
||||
query.toString());
|
||||
|
||||
query = queryFactory.search(criteria, MULTI_FOLDERS, IndexType.SONG);
|
||||
assertEquals("SearchSong", "+((title:abc* artist:abc*) (title:def* artist:def*)) +spanOr([folder:" + PATH1
|
||||
+ ", folder:" + PATH2 + "])", query.toString());
|
||||
assertEquals("SearchSong", "+((title:abc* artist:abc*) (title:def* artist:def*)) +(folder:" + PATH1
|
||||
+ " folder:" + PATH2 + ")", query.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchArtistId3() throws ParseException, IOException {
|
||||
public void testSearchArtistId3() throws IOException {
|
||||
SearchCriteria criteria = new SearchCriteria();
|
||||
criteria.setOffset(10);
|
||||
criteria.setCount(Integer.MAX_VALUE);
|
||||
criteria.setQuery(QUERY_ENG_ONLY);
|
||||
|
||||
Query query = queryFactory.search(criteria, SINGLE_FOLDERS, IndexType.ARTIST_ID3);
|
||||
assertEquals("SearchSong", "+((artist:abc*) (artist:def*)) +spanOr([folderId:"
|
||||
+ NumericUtils.intToPrefixCoded(FID1) + "])", query.toString());
|
||||
assertEquals("SearchSong", "+((artist:abc*) (artist:def*)) +(folderId:"
|
||||
+ FID1 + ")", query.toString());
|
||||
|
||||
query = queryFactory.search(criteria, MULTI_FOLDERS, IndexType.ARTIST_ID3);
|
||||
assertEquals("SearchSong",
|
||||
"+((artist:abc*) (artist:def*)) +spanOr([folderId:" + NumericUtils.intToPrefixCoded(FID1)
|
||||
+ ", folderId:" + NumericUtils.intToPrefixCoded(FID2) + "])",
|
||||
"+((artist:abc*) (artist:def*)) +(folderId:" + FID1
|
||||
+ " folderId:" + FID2 + ")",
|
||||
query.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchAlbumId3() throws ParseException, IOException {
|
||||
public void testSearchAlbumId3() throws IOException {
|
||||
SearchCriteria criteria = new SearchCriteria();
|
||||
criteria.setOffset(10);
|
||||
criteria.setCount(Integer.MAX_VALUE);
|
||||
@@ -158,74 +182,74 @@ public class QueryFactoryTestCase {
|
||||
|
||||
Query query = queryFactory.search(criteria, SINGLE_FOLDERS, IndexType.ALBUM_ID3);
|
||||
assertEquals(
|
||||
"SearchAlbumId3", "+((album:abc* artist:abc* folderId:abc*) (album:def* artist:def* folderId:def*)) "
|
||||
+ "+spanOr([folderId:" + NumericUtils.intToPrefixCoded(FID1) + "])",
|
||||
"SearchAlbumId3", "+((album:abc* artist:abc*) (album:def* artist:def*)) "
|
||||
+ "+(folderId:" + FID1 + ")",
|
||||
query.toString());
|
||||
|
||||
query = queryFactory.search(criteria, MULTI_FOLDERS, IndexType.ALBUM_ID3);
|
||||
assertEquals("SearchAlbumId3",
|
||||
"+((album:abc* artist:abc* folderId:abc*) (album:def* artist:def* folderId:def*)) +spanOr([folderId:"
|
||||
+ NumericUtils.intToPrefixCoded(FID1) + ", folderId:"
|
||||
+ NumericUtils.intToPrefixCoded(FID2) + "])",
|
||||
"+((album:abc* artist:abc*) (album:def* artist:def*)) +(folderId:"
|
||||
+ FID1 + " folderId:"
|
||||
+ FID2 + ")",
|
||||
query.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchByNameArtist() throws ParseException {
|
||||
public void testSearchByNameArtist() throws IOException {
|
||||
Query query = queryFactory.searchByName(FieldNames.ARTIST, QUERY_ENG_ONLY);
|
||||
assertEquals("SearchByNameArtist", "artist:abc artist:def*", query.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchByNameAlbum() throws ParseException {
|
||||
public void testSearchByNameAlbum() throws IOException {
|
||||
Query query = queryFactory.searchByName(FieldNames.ALBUM, QUERY_ENG_ONLY);
|
||||
assertEquals("SearchByNameAlbum", "album:abc album:def*", query.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchByNameTitle() throws ParseException {
|
||||
public void testSearchByNameTitle() throws IOException {
|
||||
Query query = queryFactory.searchByName(FieldNames.TITLE, QUERY_ENG_ONLY);
|
||||
assertEquals("SearchByNameTitle", "title:abc title:def*", query.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRandomSongs() {
|
||||
public void testGetRandomSongs() throws IOException {
|
||||
RandomSearchCriteria criteria = new RandomSearchCriteria(50, "Classic Rock",
|
||||
Integer.valueOf(1900), Integer.valueOf(2000), SINGLE_FOLDERS);
|
||||
|
||||
Query query = queryFactory.getRandomSongs(criteria);
|
||||
assertEquals(ToStringBuilder.reflectionToString(criteria),
|
||||
"+mediaType:music +genre:classicrock +year:[1900 TO 2000] +spanOr([folder:" + PATH1 + "])",
|
||||
"+mediaType:MUSIC +genre:Classic Rock +year:[1900 TO 2000] +(folder:" + PATH1 + ")",
|
||||
query.toString());
|
||||
|
||||
criteria = new RandomSearchCriteria(50, "Classic Rock", Integer.valueOf(1900),
|
||||
Integer.valueOf(2000), MULTI_FOLDERS);
|
||||
query = queryFactory.getRandomSongs(criteria);
|
||||
assertEquals(ToStringBuilder.reflectionToString(criteria),
|
||||
"+mediaType:music +genre:classicrock +year:[1900 TO 2000] +spanOr([folder:" + PATH1 + ", folder:" + PATH2
|
||||
+ "])",
|
||||
"+mediaType:MUSIC +genre:Classic Rock +year:[1900 TO 2000] +(folder:" + PATH1 + " folder:" + PATH2
|
||||
+ ")",
|
||||
query.toString());
|
||||
|
||||
criteria = new RandomSearchCriteria(50, "Classic Rock", null, null, MULTI_FOLDERS);
|
||||
query = queryFactory.getRandomSongs(criteria);
|
||||
assertEquals(ToStringBuilder.reflectionToString(criteria),
|
||||
"+mediaType:music +genre:classicrock +spanOr([folder:" + PATH1 + ", folder:" + PATH2 + "])",
|
||||
"+mediaType:MUSIC +genre:Classic Rock +(folder:" + PATH1 + " folder:" + PATH2 + ")",
|
||||
query.toString());
|
||||
|
||||
criteria = new RandomSearchCriteria(50, "Classic Rock", Integer.valueOf(1900), null,
|
||||
MULTI_FOLDERS);
|
||||
query = queryFactory.getRandomSongs(criteria);
|
||||
assertEquals(ToStringBuilder.reflectionToString(criteria),
|
||||
"+mediaType:music +genre:classicrock +year:[1900 TO *] +spanOr([folder:" + PATH1 + ", folder:" + PATH2
|
||||
+ "])",
|
||||
"+mediaType:MUSIC +genre:Classic Rock +year:[1900 TO 2147483647] +(folder:" + PATH1 + " folder:" + PATH2
|
||||
+ ")",
|
||||
query.toString());
|
||||
|
||||
criteria = new RandomSearchCriteria(50, "Classic Rock", null, Integer.valueOf(2000),
|
||||
MULTI_FOLDERS);
|
||||
query = queryFactory.getRandomSongs(criteria);
|
||||
assertEquals(ToStringBuilder.reflectionToString(criteria),
|
||||
"+mediaType:music +genre:classicrock +year:[* TO 2000] +spanOr([folder:" + PATH1 + ", folder:" + PATH2
|
||||
+ "])",
|
||||
"+mediaType:MUSIC +genre:Classic Rock +year:[-2147483648 TO 2000] +(folder:" + PATH1 + " folder:" + PATH2
|
||||
+ ")",
|
||||
query.toString());
|
||||
}
|
||||
|
||||
@@ -233,23 +257,23 @@ public class QueryFactoryTestCase {
|
||||
public void testGetRandomAlbums() {
|
||||
Query query = queryFactory.getRandomAlbums(SINGLE_FOLDERS);
|
||||
assertEquals(ToStringBuilder.reflectionToString(SINGLE_FOLDERS),
|
||||
"spanOr([folder:" + PATH1 + "])", query.toString());
|
||||
"(folder:" + PATH1 + ")", query.toString());
|
||||
|
||||
query = queryFactory.getRandomAlbums(MULTI_FOLDERS);
|
||||
assertEquals(ToStringBuilder.reflectionToString(MULTI_FOLDERS),
|
||||
"spanOr([folder:" + PATH1 + ", folder:" + PATH2 + "])", query.toString());
|
||||
"(folder:" + PATH1 + " folder:" + PATH2 + ")", query.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRandomAlbumsId3() {
|
||||
Query query = queryFactory.getRandomAlbumsId3(SINGLE_FOLDERS);
|
||||
assertEquals(ToStringBuilder.reflectionToString(SINGLE_FOLDERS),
|
||||
"spanOr([folderId:" + NumericUtils.intToPrefixCoded(FID1) + "])", query.toString());
|
||||
"(folderId:" + FID1 + ")", query.toString());
|
||||
|
||||
query = queryFactory.getRandomAlbumsId3(MULTI_FOLDERS);
|
||||
assertEquals(ToStringBuilder.reflectionToString(MULTI_FOLDERS),
|
||||
"spanOr([folderId:" + NumericUtils.intToPrefixCoded(FID1) + ", folderId:"
|
||||
+ NumericUtils.intToPrefixCoded(FID2) + "])",
|
||||
"(folderId:" + FID1 + " folderId:"
|
||||
+ FID2 + ")",
|
||||
query.toString());
|
||||
}
|
||||
|
||||
|
||||
+136
-58
@@ -52,103 +52,182 @@ public class SearchServiceSpecialGenreTestCase extends AbstractAirsonicHomeTest
|
||||
*
|
||||
* Legacy can not search all these genres.
|
||||
* (Strictly speaking, the genre field is not created at index creation.)
|
||||
*
|
||||
* // XXX 3.x -> 8.x : Do the process more strictly.
|
||||
*
|
||||
* - Values that can be cross-referenced with DB are stored in the index.
|
||||
* - Search is also possible with user's readable value (file tag value).
|
||||
* - However, there is an exception in parentheses.
|
||||
*/
|
||||
@Test
|
||||
public void testQueryEscapeRequires() {
|
||||
|
||||
List<MusicFolder> folders = getMusicFolders();
|
||||
|
||||
Function<String, RandomSearchCriteria> simpleStringCriteria = s ->
|
||||
new RandomSearchCriteria(Integer.MAX_VALUE, // count
|
||||
s, // genre,
|
||||
null, // fromYear
|
||||
null, // toYear
|
||||
folders // musicFolders
|
||||
);
|
||||
new RandomSearchCriteria(Integer.MAX_VALUE, // count
|
||||
s, // genre,
|
||||
null, // fromYear
|
||||
null, // toYear
|
||||
getMusicFolders() // musicFolders
|
||||
);
|
||||
|
||||
List<MediaFile> songs = searchService.getRandomSongs(simpleStringCriteria.apply("+"));
|
||||
Assert.assertEquals(0, songs.size());
|
||||
Assert.assertEquals(1, songs.size());// XXX 3.x -> 8.x : Searchable
|
||||
Assert.assertEquals("+", songs.get(0).getGenre());
|
||||
Assert.assertEquals("Query Escape Requires 1", songs.get(0).getTitle());
|
||||
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply("-"));
|
||||
Assert.assertEquals(0, songs.size());
|
||||
Assert.assertEquals(1, songs.size());// XXX 3.x -> 8.x : Searchable
|
||||
Assert.assertEquals("-", songs.get(0).getGenre());
|
||||
Assert.assertEquals("Query Escape Requires 2", songs.get(0).getTitle());
|
||||
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply("&&"));
|
||||
Assert.assertEquals(0, songs.size());
|
||||
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply("+"));
|
||||
Assert.assertEquals(0, songs.size());
|
||||
Assert.assertEquals(1, songs.size());// XXX 3.x -> 8.x : Searchable
|
||||
Assert.assertEquals("&&", songs.get(0).getGenre());
|
||||
Assert.assertEquals("Query Escape Requires 3", songs.get(0).getTitle());
|
||||
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply("||"));
|
||||
Assert.assertEquals(0, songs.size());
|
||||
Assert.assertEquals(1, songs.size());// XXX 3.x -> 8.x : Searchable
|
||||
Assert.assertEquals("||", songs.get(0).getGenre());
|
||||
Assert.assertEquals("Query Escape Requires 4", songs.get(0).getTitle());
|
||||
|
||||
/*
|
||||
* // XXX 3.x -> 8.x : Brackets ()
|
||||
*
|
||||
* Lucene can handle these.
|
||||
* However, brackets are specially parsed before the index creation process.
|
||||
*
|
||||
* This string is never stored in the index.
|
||||
* This is the only exception.
|
||||
*/
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply(" ("));// space & bracket
|
||||
Assert.assertEquals(0, songs.size());
|
||||
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply(")"));
|
||||
Assert.assertEquals(0, songs.size());
|
||||
|
||||
/*
|
||||
* // XXX 3.x -> 8.x : Brackets {}[]
|
||||
*
|
||||
* Lucene can handle these.
|
||||
* However, brackets are specially parsed before the index creation process.
|
||||
*
|
||||
* This can be done with a filter that performs the reverse process
|
||||
* on the input values when searching.
|
||||
* As a result, the values stored in the file can be retrieved by search.
|
||||
*
|
||||
* @see AnalyzerFactory
|
||||
*
|
||||
* >>>>>
|
||||
*/
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply("{}"));
|
||||
Assert.assertEquals(0, songs.size());
|
||||
Assert.assertEquals(1, songs.size());// XXX 3.x -> 8.x : Searchable
|
||||
/*
|
||||
* This is the result of the tag parser and domain value.
|
||||
* It is different from the tag value in file.
|
||||
*/
|
||||
Assert.assertEquals("{ }", songs.get(0).getGenre());
|
||||
Assert.assertEquals("Query Escape Requires 7", songs.get(0).getTitle());
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply("{ }"));
|
||||
Assert.assertEquals(1, songs.size());// XXX 3.x -> 8.x : Searchable
|
||||
Assert.assertEquals("Query Escape Requires 7", songs.get(0).getTitle());
|
||||
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply("[]"));
|
||||
Assert.assertEquals(0, songs.size());
|
||||
Assert.assertEquals(1, songs.size());// XXX 3.x -> 8.x : Searchable
|
||||
/*
|
||||
* This is the result of the tag parser and domain value.
|
||||
* It is different from the tag value in file.
|
||||
*/
|
||||
Assert.assertEquals("[ ]", songs.get(0).getGenre());
|
||||
Assert.assertEquals("Query Escape Requires 8", songs.get(0).getTitle());
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply("[ ]"));
|
||||
Assert.assertEquals(1, songs.size());// XXX 3.x -> 8.x : Searchable
|
||||
Assert.assertEquals("Query Escape Requires 8", songs.get(0).getTitle());
|
||||
// <<<<<
|
||||
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply("^"));
|
||||
Assert.assertEquals(0, songs.size());
|
||||
Assert.assertEquals(1, songs.size());// XXX 3.x -> 8.x : Searchable
|
||||
Assert.assertEquals("^", songs.get(0).getGenre());
|
||||
Assert.assertEquals("Query Escape Requires 9", songs.get(0).getTitle());
|
||||
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply("\""));
|
||||
Assert.assertEquals(0, songs.size());
|
||||
Assert.assertEquals(1, songs.size());// XXX 3.x -> 8.x : Searchable
|
||||
Assert.assertEquals("\"", songs.get(0).getGenre());
|
||||
Assert.assertEquals("Query Escape Requires 10", songs.get(0).getTitle());
|
||||
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply("~"));
|
||||
Assert.assertEquals(0, songs.size());
|
||||
Assert.assertEquals(1, songs.size());// XXX 3.x -> 8.x : Searchable
|
||||
Assert.assertEquals("~", songs.get(0).getGenre());
|
||||
Assert.assertEquals("Query Escape Requires 11", songs.get(0).getTitle());
|
||||
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply("*"));
|
||||
Assert.assertEquals(0, songs.size());
|
||||
Assert.assertEquals(1, songs.size());// XXX 3.x -> 8.x : Searchable
|
||||
Assert.assertEquals("*", songs.get(0).getGenre());
|
||||
Assert.assertEquals("Query Escape Requires 12", songs.get(0).getTitle());
|
||||
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply("?"));
|
||||
Assert.assertEquals(0, songs.size());
|
||||
Assert.assertEquals(1, songs.size());// XXX 3.x -> 8.x : Searchable
|
||||
Assert.assertEquals("?", songs.get(0).getGenre());
|
||||
Assert.assertEquals("Query Escape Requires 13", songs.get(0).getTitle());
|
||||
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply(":"));
|
||||
Assert.assertEquals(0, songs.size());
|
||||
Assert.assertEquals(1, songs.size());// XXX 3.x -> 8.x : Searchable
|
||||
Assert.assertEquals(":", songs.get(0).getGenre());
|
||||
Assert.assertEquals("Query Escape Requires 14", songs.get(0).getTitle());
|
||||
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply("\\"));
|
||||
Assert.assertEquals(0, songs.size());
|
||||
Assert.assertEquals(1, songs.size());// XXX 3.x -> 8.x : Searchable
|
||||
Assert.assertEquals("\\", songs.get(0).getGenre());
|
||||
Assert.assertEquals("Query Escape Requires 15", songs.get(0).getTitle());
|
||||
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply("/"));
|
||||
Assert.assertEquals(0, songs.size());
|
||||
Assert.assertEquals(1, songs.size());// XXX 3.x -> 8.x : Searchable
|
||||
Assert.assertEquals("/", songs.get(0).getGenre());
|
||||
Assert.assertEquals("Query Escape Requires 16", songs.get(0).getTitle());
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Jaudiotagger applies special treatment to bracket (FILE17).
|
||||
*
|
||||
* XXX 3.x -> 8.x : Specification of genre search became more natural.
|
||||
*/
|
||||
@Test
|
||||
public void testBrackets() {
|
||||
|
||||
List<MusicFolder> folders = getMusicFolders();
|
||||
|
||||
RandomSearchCriteria criteria = new RandomSearchCriteria(Integer.MAX_VALUE, // count
|
||||
"-(GENRE)-", // genre,
|
||||
Function<String, RandomSearchCriteria> simpleStringCriteria = s ->
|
||||
new RandomSearchCriteria(Integer.MAX_VALUE, // count
|
||||
s, // genre,
|
||||
null, // fromYear
|
||||
null, // toYear
|
||||
folders // musicFolders
|
||||
getMusicFolders() // musicFolders
|
||||
);
|
||||
|
||||
List<MediaFile> songs = searchService.getRandomSongs(criteria);
|
||||
Assert.assertEquals(0, songs.size());
|
||||
// -(GENRE)- is registered as genre of FILE17.
|
||||
|
||||
criteria = new RandomSearchCriteria(Integer.MAX_VALUE, // count
|
||||
" genre", // genre,
|
||||
null, // fromYear
|
||||
null, // toYear
|
||||
folders // musicFolders
|
||||
);
|
||||
|
||||
songs = searchService.getRandomSongs(criteria);
|
||||
/*
|
||||
* Search by genre string registered in file.
|
||||
*
|
||||
* The value stored in the index is different from legacy.
|
||||
* Domain value is kept as it is.
|
||||
*/
|
||||
List<MediaFile> songs = searchService.getRandomSongs(simpleStringCriteria.apply("-(GENRE)-"));
|
||||
Assert.assertEquals(1, songs.size());
|
||||
Assert.assertEquals("Consistency with Tag Parser 1", songs.get(0).getTitle());
|
||||
Assert.assertEquals("-GENRE -", songs.get(0).getGenre());
|
||||
Assert.assertEquals("Consistency with Tag Parser 1", songs.get(0).getTitle());
|
||||
|
||||
/*
|
||||
* Search by Domain value.
|
||||
*/
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply("-GENRE -"));
|
||||
Assert.assertEquals(1, songs.size());
|
||||
Assert.assertEquals("-GENRE -", songs.get(0).getGenre());
|
||||
Assert.assertEquals("Consistency with Tag Parser 1", songs.get(0).getTitle());
|
||||
|
||||
/*
|
||||
* Legacy genre search
|
||||
*/
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply(" genre"));
|
||||
// Strong unique parsing rules have been removed.
|
||||
Assert.assertEquals(0, songs.size());
|
||||
|
||||
}
|
||||
|
||||
@@ -188,29 +267,28 @@ public class SearchServiceSpecialGenreTestCase extends AbstractAirsonicHomeTest
|
||||
@Test
|
||||
public void testOthers() {
|
||||
|
||||
List<MusicFolder> folders = getMusicFolders();
|
||||
|
||||
RandomSearchCriteria criteria = new RandomSearchCriteria(Integer.MAX_VALUE, // count
|
||||
"{'“『【【】】[︴○◎@ $〒→+]FULL-WIDTHCæsar's", // genre,
|
||||
Function<String, RandomSearchCriteria> simpleStringCriteria = s ->
|
||||
new RandomSearchCriteria(Integer.MAX_VALUE, // count
|
||||
s, // genre,
|
||||
null, // fromYear
|
||||
null, // toYear
|
||||
folders // musicFolders
|
||||
getMusicFolders() // musicFolders
|
||||
);
|
||||
|
||||
List<MediaFile> songs = searchService.getRandomSongs(criteria);
|
||||
Assert.assertEquals(0, songs.size());
|
||||
|
||||
criteria = new RandomSearchCriteria(Integer.MAX_VALUE, // count
|
||||
"widthcaesar", // genre,
|
||||
null, // fromYear
|
||||
null, // toYear
|
||||
folders // musicFolders
|
||||
);
|
||||
|
||||
songs = searchService.getRandomSongs(criteria);
|
||||
// XXX 3.x -> 8.x : Do the process more strictly.
|
||||
List<MediaFile> songs = searchService
|
||||
.getRandomSongs(simpleStringCriteria.apply("{'“『【【】】[︴○◎@ $〒→+]FULL-WIDTHCæsar's"));
|
||||
Assert.assertEquals(1, songs.size());
|
||||
Assert.assertEquals(1, songs.size());
|
||||
Assert.assertEquals("Other special strings 1", songs.get(0).getTitle());
|
||||
Assert.assertEquals("{'“『【【】】[︴○◎@ $〒→+]FULL-WIDTHCæsar's", songs.get(0).getGenre());
|
||||
|
||||
/*
|
||||
* Legacy kept "widthcaesar" using their own rules.
|
||||
* The previous rule has been discarded.
|
||||
*/
|
||||
songs = searchService.getRandomSongs(simpleStringCriteria.apply("widthcaesar"));
|
||||
Assert.assertEquals(0, songs.size());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+14
-2
@@ -56,11 +56,23 @@ public class SearchServiceStartWithStopwardsTestCase extends AbstractAirsonicHom
|
||||
|
||||
criteria.setQuery("will");
|
||||
SearchResult result = searchService.search(criteria, folders, IndexType.ARTIST_ID3);
|
||||
Assert.assertEquals("Williams hit by \"will\" ", 1, result.getTotalHits());
|
||||
// XXX 3.x -> 8.x : The filter is properly applied to the input(Stopward)
|
||||
Assert.assertEquals("Williams hit by \"will\" ", 0, result.getTotalHits());
|
||||
|
||||
criteria.setQuery("the");
|
||||
result = searchService.search(criteria, folders, IndexType.SONG);
|
||||
Assert.assertEquals("Theater hit by \"the\" ", 1, result.getTotalHits());
|
||||
// XXX 3.x -> 8.x : The filter is properly applied to the input(Stopward)
|
||||
Assert.assertEquals("Theater hit by \"the\" ", 0, result.getTotalHits());
|
||||
|
||||
criteria.setQuery("willi");
|
||||
result = searchService.search(criteria, folders, IndexType.ARTIST_ID3);
|
||||
// XXX 3.x -> 8.x : Normal forward matching
|
||||
Assert.assertEquals("Williams hit by \"Williams\" ", 1, result.getTotalHits());
|
||||
|
||||
criteria.setQuery("thea");
|
||||
result = searchService.search(criteria, folders, IndexType.SONG);
|
||||
// XXX 3.x -> 8.x : Normal forward matching
|
||||
Assert.assertEquals("Theater hit by \"thea\" ", 1, result.getTotalHits());
|
||||
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -164,7 +164,12 @@ public class SearchServiceTestCase extends AbstractAirsonicHomeTest {
|
||||
artistId3Result.getItems().size());
|
||||
ParamSearchResult<Artist> artistResult = searchService.searchByName(query, 0,
|
||||
Integer.MAX_VALUE, allMusicFolders, Artist.class);
|
||||
Assert.assertEquals("(21) Specify '" + query + "' as the name, and get an artist.", 0,
|
||||
|
||||
/*
|
||||
* // XXX 3.x -> 8.x :
|
||||
* Hit 'Nash*' as the slash becomes a delimiter.
|
||||
*/
|
||||
Assert.assertEquals("(21) Specify '" + query + "' as the name, and get an artist.", 1,
|
||||
artistResult.getItems().size());
|
||||
|
||||
// *** testGetRandomSongs() ***
|
||||
|
||||
Reference in New Issue
Block a user