import {LocationManager} from '../../../../../src/backend/model/database/LocationManager'; import {SearchManager} from '../../../../../src/backend/model/database/sql/SearchManager'; import {SearchResultDTO} from '../../../../../src/common/entities/SearchResultDTO'; import {Utils} from '../../../../../src/common/Utils'; import {SQLTestHelper} from '../../../SQLTestHelper'; import { ANDSearchQuery, DateSearch, DistanceSearch, OrientationSearch, ORSearchQuery, RatingSearch, ResolutionSearch, SearchQueryDTO, SearchQueryTypes, SomeOfSearchQuery, TextSearch, TextSearchQueryMatchTypes } from '../../../../../src/common/entities/SearchQueryDTO'; import {IndexingManager} from '../../../../../src/backend/model/database/sql/IndexingManager'; import {DirectoryDTO} from '../../../../../src/common/entities/DirectoryDTO'; import {TestHelper} from './TestHelper'; import {ObjectManagers} from '../../../../../src/backend/model/ObjectManagers'; import {GalleryManager} from '../../../../../src/backend/model/database/sql/GalleryManager'; import {Connection} from 'typeorm'; import {DirectoryEntity} from '../../../../../src/backend/model/database/sql/enitites/DirectoryEntity'; import {GPSMetadata, PhotoDTO, PhotoMetadata} from '../../../../../src/common/entities/PhotoDTO'; import {VideoDTO} from '../../../../../src/common/entities/VideoDTO'; import {MediaDTO} from '../../../../../src/common/entities/MediaDTO'; import {AutoCompleteItem} from '../../../../../src/common/entities/AutoCompleteItem'; import {Config} from '../../../../../src/common/config/private/Config'; const deepEqualInAnyOrder = require('deep-equal-in-any-order'); const chai = require('chai'); chai.use(deepEqualInAnyOrder); const {expect} = chai; // to help WebStorm to handle the test cases declare let describe: any; declare const after: any; declare const before: any; const tmpDescribe = describe; describe = SQLTestHelper.describe; // fake it os IDE plays nicely (recognize the test) class IndexingManagerTest extends IndexingManager { public async saveToDB(scannedDirectory: DirectoryDTO): Promise { return super.saveToDB(scannedDirectory); } } class GalleryManagerTest extends GalleryManager { public async selectParentDir(connection: Connection, directoryName: string, directoryParent: string): Promise { return super.selectParentDir(connection, directoryName, directoryParent); } public async fillParentDir(connection: Connection, dir: DirectoryEntity): Promise { return super.fillParentDir(connection, dir); } } describe('SearchManager', (sqlHelper: SQLTestHelper) => { describe = tmpDescribe; let dir: DirectoryDTO; /** * dir * |- v * |- p * |- p2 * |-> subDir * |- p_faceLess * |-> subDir2 * |- p4 */ let v: VideoDTO; let p: PhotoDTO; let p2: PhotoDTO; let p_faceLess: PhotoDTO; let p4: PhotoDTO; const setUpTestGallery = async (): Promise => { const directory: DirectoryDTO = TestHelper.getDirectoryEntry(); const subDir = TestHelper.getDirectoryEntry(directory, 'The Phantom Menace'); const subDir2 = TestHelper.getDirectoryEntry(directory, 'Return of the Jedi'); TestHelper.getPhotoEntry1(directory); TestHelper.getPhotoEntry2(directory); TestHelper.getPhotoEntry4(subDir2); const pFaceLess = TestHelper.getPhotoEntry3(subDir); delete pFaceLess.metadata.faces; TestHelper.getVideoEntry1(directory); dir = await SQLTestHelper.persistTestDir(directory); p = dir.media[0]; p2 = dir.media[1]; v = dir.media[2]; p4 = dir.directories[1].media[0]; p_faceLess = dir.directories[0].media[0]; }; const setUpSqlDB = async () => { await sqlHelper.initDB(); await setUpTestGallery(); }; before(async () => { await setUpSqlDB(); }); after(async () => { await sqlHelper.clearDB(); }); it('should get autocomplete', async () => { const sm = new SearchManager(); const cmp = (a: AutoCompleteItem, b: AutoCompleteItem) => { if (a.text === b.text) { return a.type - b.type; } return a.text.localeCompare(b.text); }; expect((await sm.autocomplete('tat', SearchQueryTypes.any_text))).to.deep.equalInAnyOrder([ new AutoCompleteItem('Tatooine', SearchQueryTypes.position)]); expect((await sm.autocomplete('star', SearchQueryTypes.any_text))).to.deep.equalInAnyOrder([ new AutoCompleteItem('star wars', SearchQueryTypes.keyword), new AutoCompleteItem('death star', SearchQueryTypes.keyword)]); expect((await sm.autocomplete('wars', SearchQueryTypes.any_text))).to.deep.equalInAnyOrder([ new AutoCompleteItem('star wars', SearchQueryTypes.keyword), new AutoCompleteItem('wars dir', SearchQueryTypes.directory)]); expect((await sm.autocomplete('arch', SearchQueryTypes.any_text))).eql([ new AutoCompleteItem('Research City', SearchQueryTypes.position)]); Config.Client.Search.AutoComplete.maxItemsPerCategory = 99999; expect((await sm.autocomplete('wa', SearchQueryTypes.any_text))).to.deep.equalInAnyOrder([ new AutoCompleteItem('star wars', SearchQueryTypes.keyword), new AutoCompleteItem('Anakin Skywalker', SearchQueryTypes.person), new AutoCompleteItem('Luke Skywalker', SearchQueryTypes.person), new AutoCompleteItem('wars dir', SearchQueryTypes.directory)]); Config.Client.Search.AutoComplete.maxItemsPerCategory = 1; expect((await sm.autocomplete('a', SearchQueryTypes.any_text))).to.deep.equalInAnyOrder([ new AutoCompleteItem('Ajan Kloss', SearchQueryTypes.position), new AutoCompleteItem('Amber stone', SearchQueryTypes.caption), new AutoCompleteItem('star wars', SearchQueryTypes.keyword), new AutoCompleteItem('Anakin Skywalker', SearchQueryTypes.person), new AutoCompleteItem('Castilon', SearchQueryTypes.position), new AutoCompleteItem('Devaron', SearchQueryTypes.position), new AutoCompleteItem('The Phantom Menace', SearchQueryTypes.directory)]); Config.Client.Search.AutoComplete.maxItemsPerCategory = 5; expect((await sm.autocomplete('sw', SearchQueryTypes.any_text))).to.deep.equalInAnyOrder([ new AutoCompleteItem('sw1.jpg', SearchQueryTypes.file_name), new AutoCompleteItem('sw2.jpg', SearchQueryTypes.file_name), new AutoCompleteItem('sw3.jpg', SearchQueryTypes.file_name), new AutoCompleteItem('sw4.jpg', SearchQueryTypes.file_name), new AutoCompleteItem(v.name, SearchQueryTypes.file_name)]); expect((await sm.autocomplete(v.name, SearchQueryTypes.any_text))).to.deep.equalInAnyOrder( [new AutoCompleteItem(v.name, SearchQueryTypes.file_name)]); }); const searchifyMedia = (m: MediaDTO): MediaDTO => { const tmpM = m.directory.media; const tmpD = m.directory.directories; const tmpMT = m.directory.metaFile; delete m.directory.directories; delete m.directory.media; delete m.directory.metaFile; const ret = Utils.clone(m); if ((ret.metadata as PhotoMetadata).faces && !(ret.metadata as PhotoMetadata).faces.length) { delete (ret.metadata as PhotoMetadata).faces; } m.directory.directories = tmpD; m.directory.media = tmpM; m.directory.metaFile = tmpMT; return ret; }; const removeDir = (result: SearchResultDTO) => { result.media = result.media.map(m => searchifyMedia(m)); return Utils.clone(result); }; describe('advanced search', async () => { it('should AND', async () => { const sm = new SearchManager(); let query: SearchQueryDTO = { type: SearchQueryTypes.AND, list: [{text: p.metadata.faces[0].name, type: SearchQueryTypes.person}, {text: p2.metadata.caption, type: SearchQueryTypes.caption}] }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [], metaFile: [], resultOverflow: false })); query = { type: SearchQueryTypes.AND, list: [{text: p.metadata.faces[0].name, type: SearchQueryTypes.person}, {text: p.metadata.caption, type: SearchQueryTypes.caption}] }; expect(await sm.search(query)).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p], metaFile: [], resultOverflow: false })); // make sure that this shows both photos. We need this the the rest of the tests query = {text: 'a', type: SearchQueryTypes.person}; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2, p4], metaFile: [], resultOverflow: false })); query = { type: SearchQueryTypes.AND, list: [{ type: SearchQueryTypes.AND, list: [{text: 'a', type: SearchQueryTypes.person}, {text: p.metadata.keywords[0], type: SearchQueryTypes.keyword}] }, {text: p.metadata.caption, type: SearchQueryTypes.caption} ] }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p], metaFile: [], resultOverflow: false })); }); it('should OR', async () => { const sm = new SearchManager(); let query: SearchQueryDTO = { type: SearchQueryTypes.OR, list: [{text: 'Not a person', type: SearchQueryTypes.person}, {text: 'Not a caption', type: SearchQueryTypes.caption}] }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [], metaFile: [], resultOverflow: false })); query = { type: SearchQueryTypes.OR, list: [{text: p.metadata.faces[0].name, type: SearchQueryTypes.person}, {text: p2.metadata.caption, type: SearchQueryTypes.caption}] }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2], metaFile: [], resultOverflow: false })); query = { type: SearchQueryTypes.OR, list: [{text: p.metadata.faces[0].name, type: SearchQueryTypes.person}, {text: p.metadata.caption, type: SearchQueryTypes.caption}] }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p], metaFile: [], resultOverflow: false })); // make sure that this shows both photos. We need this the the rest of the tests query = {text: 'a', type: SearchQueryTypes.person}; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2, p4], metaFile: [], resultOverflow: false })); query = { type: SearchQueryTypes.OR, list: [{ type: SearchQueryTypes.OR, list: [{text: 'a', type: SearchQueryTypes.person}, {text: p.metadata.keywords[0], type: SearchQueryTypes.keyword}] }, {text: p.metadata.caption, type: SearchQueryTypes.caption} ] }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2, p4], metaFile: [], resultOverflow: false })); query = { type: SearchQueryTypes.OR, list: [{ type: SearchQueryTypes.OR, list: [{text: p.metadata.keywords[0], type: SearchQueryTypes.keyword}, {text: p2.metadata.keywords[0], type: SearchQueryTypes.keyword}] }, {text: p_faceLess.metadata.caption, type: SearchQueryTypes.caption} ] }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2, p_faceLess], metaFile: [], resultOverflow: false })); }); it('should minimum of', async () => { const sm = new SearchManager(); let query: SomeOfSearchQuery = { type: SearchQueryTypes.SOME_OF, list: [{text: 'jpg', type: SearchQueryTypes.file_name}, {text: 'mp4', type: SearchQueryTypes.file_name}] }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2, p_faceLess, p4, v], metaFile: [], resultOverflow: false })); query = { type: SearchQueryTypes.SOME_OF, list: [{text: 'R2', type: SearchQueryTypes.person}, {text: 'Anakin', type: SearchQueryTypes.person}, {text: 'Luke', type: SearchQueryTypes.person}] }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2, p4], metaFile: [], resultOverflow: false })); query.min = 2; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2, p4], metaFile: [], resultOverflow: false })); query.min = 3; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [], metaFile: [], resultOverflow: false })); query = { type: SearchQueryTypes.SOME_OF, min: 3, list: [{text: 'sw', type: SearchQueryTypes.file_name}, {text: 'R2', type: SearchQueryTypes.person}, {text: 'Kamino', type: SearchQueryTypes.position}, {text: 'Han', type: SearchQueryTypes.person}] }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2], metaFile: [], resultOverflow: false })); }); describe('should search text', async () => { it('as any', async () => { const sm = new SearchManager(); let query = {text: 'sw', type: SearchQueryTypes.any_text}; expect(Utils.clone(await sm.search({text: 'sw', type: SearchQueryTypes.any_text}))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2, p_faceLess, v, p4], metaFile: [], resultOverflow: false })); query = {text: 'sw', negate: true, type: SearchQueryTypes.any_text}; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [], metaFile: [], resultOverflow: false })); query = {text: 'Boba', type: SearchQueryTypes.any_text}; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p], metaFile: [], resultOverflow: false })); query = {text: 'Boba', negate: true, type: SearchQueryTypes.any_text}; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p2, p_faceLess, p4], metaFile: [], resultOverflow: false })); query = {text: 'Boba', negate: true, type: SearchQueryTypes.any_text}; // all should have faces const sRet = await sm.search(query); for (let i = 0; i < sRet.media.length; ++i) { if (sRet.media[i].id === p_faceLess.id) { continue; } expect((sRet.media[i]).metadata.faces).to.be.not.an('undefined'); expect((sRet.media[i]).metadata.faces).to.be.lengthOf.above(1); } query = { text: 'Boba', type: SearchQueryTypes.any_text, matchType: TextSearchQueryMatchTypes.exact_match }; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [], metaFile: [], resultOverflow: false })); query = { text: 'Boba Fett', type: SearchQueryTypes.any_text, matchType: TextSearchQueryMatchTypes.exact_match }; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p], metaFile: [], resultOverflow: false })); }); it('as position', async () => { const sm = new SearchManager(); const query = {text: 'Tatooine', type: SearchQueryTypes.position}; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p], metaFile: [], resultOverflow: false })); }); it('as keyword', async () => { const sm = new SearchManager(); let query = { text: 'kie', type: SearchQueryTypes.keyword }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p2, p_faceLess], metaFile: [], resultOverflow: false })); query = { text: 'wa', type: SearchQueryTypes.keyword }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2, p_faceLess, p4], metaFile: [], resultOverflow: false })); query = { text: 'han', type: SearchQueryTypes.keyword }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [], metaFile: [], resultOverflow: false })); query = { text: 'star wars', matchType: TextSearchQueryMatchTypes.exact_match, type: SearchQueryTypes.keyword }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2, p_faceLess, p4], metaFile: [], resultOverflow: false })); query = { text: 'wookiees', matchType: TextSearchQueryMatchTypes.exact_match, type: SearchQueryTypes.keyword }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p_faceLess], metaFile: [], resultOverflow: false })); }); it('as caption', async () => { const sm = new SearchManager(); const query = { text: 'han', type: SearchQueryTypes.caption }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p], metaFile: [], resultOverflow: false })); }); it('as file_name', async () => { const sm = new SearchManager(); let query = { text: 'sw', type: SearchQueryTypes.file_name }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2, p_faceLess, v, p4], metaFile: [], resultOverflow: false })); query = { text: 'sw4', type: SearchQueryTypes.file_name }; expect(Utils.clone(await sm.search({ text: 'sw4', type: SearchQueryTypes.file_name }))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p4], metaFile: [], resultOverflow: false })); }); it('as directory', async () => { const sm = new SearchManager(); let query = { text: 'of the J', type: SearchQueryTypes.directory }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p4], metaFile: [], resultOverflow: false })); query = { text: 'wars dir', type: SearchQueryTypes.directory }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2, v, p_faceLess, p4], metaFile: [], resultOverflow: false })); query = { text: '/wars dir', matchType: TextSearchQueryMatchTypes.exact_match, type: SearchQueryTypes.directory }; expect(Utils.clone(await sm.search({ text: '/wars dir', matchType: TextSearchQueryMatchTypes.exact_match, type: SearchQueryTypes.directory }))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2, v], metaFile: [], resultOverflow: false })); query = { text: '/wars dir/Return of the Jedi', matchType: TextSearchQueryMatchTypes.exact_match, type: SearchQueryTypes.directory }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p4], metaFile: [], resultOverflow: false })); query = { text: '/wars dir/Return of the Jedi', matchType: TextSearchQueryMatchTypes.exact_match, type: SearchQueryTypes.directory }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p4], metaFile: [], resultOverflow: false })); }); it('as person', async () => { const sm = new SearchManager(); let query = { text: 'Boba', type: SearchQueryTypes.person }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p], metaFile: [], resultOverflow: false })); query = { text: 'Boba', type: SearchQueryTypes.person, matchType: TextSearchQueryMatchTypes.exact_match }; expect(Utils.clone(await sm.search(query))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [], metaFile: [], resultOverflow: false })); query = { text: 'Boba Fett', type: SearchQueryTypes.person, matchType: TextSearchQueryMatchTypes.exact_match }; expect(Utils.clone(await sm.search({ text: 'Boba Fett', type: SearchQueryTypes.person, matchType: TextSearchQueryMatchTypes.exact_match }))).to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p], metaFile: [], resultOverflow: false })); }); }); it('should search date', async () => { const sm = new SearchManager(); let query = {before: 0, after: 0, type: SearchQueryTypes.date}; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [], metaFile: [], resultOverflow: false })); query = { before: p.metadata.creationDate, after: p.metadata.creationDate, type: SearchQueryTypes.date }; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p], metaFile: [], resultOverflow: false })); query = { before: p.metadata.creationDate, after: p.metadata.creationDate, negate: true, type: SearchQueryTypes.date }; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p2, p_faceLess, p4, v], metaFile: [], resultOverflow: false })); query = { before: p.metadata.creationDate + 1000000000, after: 0, type: SearchQueryTypes.date }; expect(Utils.clone(await sm.search({ before: p.metadata.creationDate + 1000000000, after: 0, type: SearchQueryTypes.date }))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2, p_faceLess, v, p4], metaFile: [], resultOverflow: false })); }); it('should search rating', async () => { const sm = new SearchManager(); let query = {min: 0, max: 0, type: SearchQueryTypes.rating}; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [], metaFile: [], resultOverflow: false })); query = {min: 0, max: 5, type: SearchQueryTypes.rating}; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2, p_faceLess], metaFile: [], resultOverflow: false })); query = {min: 0, max: 5, negate: true, type: SearchQueryTypes.rating}; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [], metaFile: [], resultOverflow: false })); query = {min: 2, max: 2, type: SearchQueryTypes.rating}; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p2], metaFile: [], resultOverflow: false })); query = {min: 2, max: 2, negate: true, type: SearchQueryTypes.rating}; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p_faceLess], metaFile: [], resultOverflow: false })); }); it('should search resolution', async () => { const sm = new SearchManager(); let query = {min: 0, max: 0, type: SearchQueryTypes.resolution}; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [], metaFile: [], resultOverflow: false })); query = {max: 1, type: SearchQueryTypes.resolution}; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, v], metaFile: [], resultOverflow: false })); query = {min: 2, max: 3, type: SearchQueryTypes.resolution}; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p2, p_faceLess], metaFile: [], resultOverflow: false })); query = {min: 2, max: 3, negate: true, type: SearchQueryTypes.resolution}; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, v, p4], metaFile: [], resultOverflow: false })); query = {min: 3, type: SearchQueryTypes.resolution}; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p4], metaFile: [], resultOverflow: false })); }); it('should search orientation', async () => { const sm = new SearchManager(); let query = { landscape: false, type: SearchQueryTypes.orientation }; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2, p4, v], metaFile: [], resultOverflow: false })); query = { landscape: true, type: SearchQueryTypes.orientation }; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p_faceLess, v], metaFile: [], resultOverflow: false })); }); it('should search distance', async () => { ObjectManagers.getInstance().LocationManager = new LocationManager(); const sm = new SearchManager(); ObjectManagers.getInstance().LocationManager.getGPSData = async (): Promise => { return { longitude: 10, latitude: 10, altitude: 0 }; }; let query = { from: {text: 'Tatooine'}, distance: 1, type: SearchQueryTypes.distance }; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p], metaFile: [], resultOverflow: false })); query = { from: {GPSData: {latitude: 0, longitude: 0}}, distance: 112 * 10, // number of km per degree = ~111km type: SearchQueryTypes.distance }; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p2], metaFile: [], resultOverflow: false })); query = { from: {GPSData: {latitude: 0, longitude: 0}}, distance: 112 * 10, // number of km per degree = ~111km negate: true, type: SearchQueryTypes.distance }; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p_faceLess, p4], metaFile: [], resultOverflow: false })); query = { from: {GPSData: {latitude: 10, longitude: 10}}, distance: 1, type: SearchQueryTypes.distance }; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p], metaFile: [], resultOverflow: false })); query = { from: {GPSData: {latitude: 10, longitude: 10}}, distance: 112 * 5, // number of km per degree = ~111km type: SearchQueryTypes.distance }; expect(Utils.clone(await sm.search(query))) .to.deep.equalInAnyOrder(removeDir({ searchQuery: query, directories: [], media: [p, p_faceLess, p4], metaFile: [], resultOverflow: false })); }); }); it('should get random photo', async () => { const sm = new SearchManager(); let query = { text: 'xyz', type: SearchQueryTypes.keyword }; expect(await sm.getRandomPhoto(query)).to.not.exist; query = { text: 'wookiees', matchType: TextSearchQueryMatchTypes.exact_match, type: SearchQueryTypes.keyword }; expect(Utils.clone(await sm.getRandomPhoto(query))).to.deep.equalInAnyOrder(searchifyMedia(p_faceLess)); }); });