2894 lines
90 KiB
TypeScript
2894 lines
90 KiB
TypeScript
import {CachedMetadata, MetadataCache, Pos, TFile, TFolder, Vault} from 'obsidian';
|
|
import {
|
|
DEFAULT_FOLDER_CTIME,
|
|
DEFAULT_FOLDER_MTIME,
|
|
determineFolderDatesIfNeeded,
|
|
determineSortingGroup,
|
|
EQUAL_OR_UNCOMPARABLE,
|
|
FolderItemForSorting,
|
|
getSorterFnFor,
|
|
matchGroupRegex,
|
|
ProcessingContext,
|
|
sorterByBookmarkOrder,
|
|
sorterByMetadataField,
|
|
SorterFn
|
|
} from './custom-sort';
|
|
import {CustomSortGroupType, CustomSortOrder, CustomSortSpec, RegExpSpec} from './custom-sort-types';
|
|
import {CompoundDashNumberNormalizerFn, CompoundDotRomanNumberNormalizerFn} from "./sorting-spec-processor";
|
|
import {findStarredFile_pathParam, Starred_PluginInstance} from "../utils/StarredPluginSignature";
|
|
import {
|
|
ObsidianIconFolder_PluginInstance,
|
|
ObsidianIconFolderPlugin_Data
|
|
} from "../utils/ObsidianIconFolderPluginSignature";
|
|
|
|
const mockTFile = (basename: string, ext: string, size?: number, ctime?: number, mtime?: number): TFile => {
|
|
return {
|
|
stat: {
|
|
ctime: ctime ?? 0,
|
|
mtime: mtime ?? 0,
|
|
size: size ?? 0
|
|
},
|
|
basename: basename,
|
|
extension: ext,
|
|
vault: {} as Vault, // To satisfy TS typechecking
|
|
path: `Some parent folder/${basename}.${ext}`,
|
|
name: `${basename}.${ext}`,
|
|
parent: {} as TFolder // To satisfy TS typechecking
|
|
}
|
|
}
|
|
|
|
const mockTFolder = (name: string, children?: Array<TFolder|TFile>, parent?: TFolder): TFolder => {
|
|
return {
|
|
isRoot(): boolean { return name === '/' },
|
|
vault: {} as Vault, // To satisfy TS typechecking
|
|
path: `${name}`,
|
|
name: name,
|
|
parent: parent ?? ({} as TFolder), // To satisfy TS typechecking
|
|
children: children ?? []
|
|
}
|
|
}
|
|
|
|
const MOCK_TIMESTAMP: number = 1656417542418
|
|
const TIMESTAMP_OLDEST: number = MOCK_TIMESTAMP
|
|
const TIMESTAMP_NEWEST: number = MOCK_TIMESTAMP + 1000
|
|
const TIMESTAMP_INBETWEEN: number = MOCK_TIMESTAMP + 500
|
|
|
|
const mockTFolderWithChildren = (name: string): TFolder => {
|
|
const child1: TFolder = mockTFolder('Section A')
|
|
const child2: TFolder = mockTFolder('Section B')
|
|
const child3: TFile = mockTFile('Child file 1 created as oldest, modified recently', 'md', 100, TIMESTAMP_OLDEST, TIMESTAMP_NEWEST)
|
|
const child4: TFile = mockTFile('Child file 2 created as newest, not modified at all', 'md', 100, TIMESTAMP_NEWEST, TIMESTAMP_NEWEST)
|
|
const child5: TFile = mockTFile('Child file 3 created inbetween, modified inbetween', 'md', 100, TIMESTAMP_INBETWEEN, TIMESTAMP_INBETWEEN)
|
|
|
|
return mockTFolder(name, [child1, child2, child3, child4, child5])
|
|
}
|
|
|
|
const MockedLoc: Pos = {
|
|
start: {col:0,offset:0,line:0},
|
|
end: {col:0,offset:0,line:0}
|
|
}
|
|
|
|
describe('determineSortingGroup', () => {
|
|
describe('CustomSortGroupType.ExactHeadAndTail', () => {
|
|
it('should correctly recognize head and tail', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactHeadAndTail,
|
|
exactPrefix: 'Ref',
|
|
exactSuffix: 'ces'
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result: FolderItemForSorting = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md'
|
|
});
|
|
})
|
|
it('should not allow overlap of head and tail', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 444, MOCK_TIMESTAMP + 555, MOCK_TIMESTAMP + 666);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactHeadAndTail,
|
|
exactPrefix: 'Referen',
|
|
exactSuffix: 'rences'
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result: FolderItemForSorting = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // This indicates the last+1 idx (no match)
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 555,
|
|
mtime: MOCK_TIMESTAMP + 666,
|
|
path: 'Some parent folder/References.md'
|
|
});
|
|
})
|
|
it('should not allow overlap of head and tail, when simple regexp in head', () => {
|
|
// given
|
|
const file: TFile = mockTFile('Part123:-icle', 'md', 444, MOCK_TIMESTAMP + 555, MOCK_TIMESTAMP + 666);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['Some parent folder'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactHeadAndTail,
|
|
regexPrefix: {
|
|
regex: /^Part\d\d\d:/i
|
|
},
|
|
exactSuffix: ':-icle'
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // This indicates the last+1 idx (no match)
|
|
isFolder: false,
|
|
sortString: "Part123:-icle.md",
|
|
ctime: MOCK_TIMESTAMP + 555,
|
|
mtime: MOCK_TIMESTAMP + 666,
|
|
path: 'Some parent folder/Part123:-icle.md'
|
|
});
|
|
})
|
|
it('should not allow overlap of head and tail, when advanced regexp in head', () => {
|
|
// given
|
|
const file: TFile = mockTFile('Part123:-icle', 'md', 444, MOCK_TIMESTAMP + 555, MOCK_TIMESTAMP + 666);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['Some parent folder'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactHeadAndTail,
|
|
regexPrefix: {
|
|
regex: /^Part *(\d+(?:-\d+)*):/i,
|
|
normalizerFn: CompoundDashNumberNormalizerFn
|
|
},
|
|
exactSuffix: ':-icle'
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // This indicates the last+1 idx
|
|
isFolder: false,
|
|
sortString: "Part123:-icle.md",
|
|
ctime: MOCK_TIMESTAMP + 555,
|
|
mtime: MOCK_TIMESTAMP + 666,
|
|
path: 'Some parent folder/Part123:-icle.md'
|
|
});
|
|
})
|
|
it('should match head and tail, when simple regexp in head', () => {
|
|
// given
|
|
const file: TFile = mockTFile('Part123:-icle', 'md', 444, MOCK_TIMESTAMP + 555, MOCK_TIMESTAMP + 666);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['Some parent folder'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactHeadAndTail,
|
|
regexPrefix: {
|
|
regex: /^Part\d\d\d:/i,
|
|
normalizerFn: CompoundDashNumberNormalizerFn
|
|
},
|
|
exactSuffix: '-icle'
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0, // Matched!
|
|
isFolder: false,
|
|
sortString: "Part123:-icle.md",
|
|
ctime: MOCK_TIMESTAMP + 555,
|
|
mtime: MOCK_TIMESTAMP + 666,
|
|
path: 'Some parent folder/Part123:-icle.md'
|
|
});
|
|
})
|
|
it('should match head and tail, when advanced regexp in head', () => {
|
|
// given
|
|
const file: TFile = mockTFile('Part123:-icle', 'md', 444, MOCK_TIMESTAMP + 555, MOCK_TIMESTAMP + 666);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['Some parent folder'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactHeadAndTail,
|
|
regexPrefix: {
|
|
regex: /^Part *(\d+(?:-\d+)*):/i,
|
|
normalizerFn: CompoundDashNumberNormalizerFn
|
|
},
|
|
exactSuffix: '-icle'
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0, // Matched!
|
|
isFolder: false,
|
|
sortString: "00000123////Part123:-icle.md",
|
|
ctime: MOCK_TIMESTAMP + 555,
|
|
mtime: MOCK_TIMESTAMP + 666,
|
|
path: 'Some parent folder/Part123:-icle.md'
|
|
});
|
|
})
|
|
it('should not allow overlap of head and tail, when regexp in tail', () => {
|
|
// given
|
|
const file: TFile = mockTFile('Part:123-icle', 'md', 444, MOCK_TIMESTAMP + 555, MOCK_TIMESTAMP + 666);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['Some parent folder'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactHeadAndTail,
|
|
exactPrefix: 'Part:',
|
|
regexSuffix: {
|
|
regex: /: *(\d+(?:-\d+)*)-icle$/i,
|
|
normalizerFn: CompoundDashNumberNormalizerFn
|
|
}
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // This indicates the last+1 idx
|
|
isFolder: false,
|
|
sortString: "Part:123-icle.md",
|
|
ctime: MOCK_TIMESTAMP + 555,
|
|
mtime: MOCK_TIMESTAMP + 666,
|
|
path: 'Some parent folder/Part:123-icle.md'
|
|
});
|
|
});
|
|
it('should match head and tail, when simple regexp in head and tail', () => {
|
|
// given
|
|
const file: TFile = mockTFile('Part:123-icle', 'md', 444, MOCK_TIMESTAMP + 555, MOCK_TIMESTAMP + 666);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['Some parent folder'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactHeadAndTail,
|
|
regexPrefix: {
|
|
regex: /^Part:\d/i
|
|
},
|
|
regexSuffix: {
|
|
regex: /\d-icle$/i
|
|
}
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0, // Matched!
|
|
isFolder: false,
|
|
sortString: "Part:123-icle.md",
|
|
ctime: MOCK_TIMESTAMP + 555,
|
|
mtime: MOCK_TIMESTAMP + 666,
|
|
path: 'Some parent folder/Part:123-icle.md'
|
|
});
|
|
});
|
|
it('should match head and tail, when simple regexp in head and tail, overrideTitle', () => {
|
|
// given
|
|
const file: TFile = mockTFile('Part:123-icle', 'md', 444, MOCK_TIMESTAMP + 555, MOCK_TIMESTAMP + 666);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['Some parent folder'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactHeadAndTail,
|
|
regexPrefix: {
|
|
regex: /^Part:\d/i
|
|
},
|
|
regexSuffix: {
|
|
regex: /\d-icle$/i
|
|
},
|
|
overrideTitle: true // Should be ignored when no advanced regexp
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0, // Matched!
|
|
isFolder: false,
|
|
sortString: "Part:123-icle.md",
|
|
ctime: MOCK_TIMESTAMP + 555,
|
|
mtime: MOCK_TIMESTAMP + 666,
|
|
path: 'Some parent folder/Part:123-icle.md'
|
|
});
|
|
});
|
|
it('should match head and tail, when simple regexp in head and and mixed in tail', () => {
|
|
// given
|
|
const file: TFile = mockTFile('Part:1 1-23.456-icle', 'md', 444, MOCK_TIMESTAMP + 555, MOCK_TIMESTAMP + 666);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['Some parent folder'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactHeadAndTail,
|
|
regexPrefix: {
|
|
regex: /^Part:\d/i
|
|
},
|
|
regexSuffix: {
|
|
regex: / *(\d+(?:-\d+)*).\d\d\d-icle$/i,
|
|
normalizerFn: CompoundDashNumberNormalizerFn
|
|
}
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0, // Matched!
|
|
isFolder: false,
|
|
sortString: "00000001|00000023////Part:1 1-23.456-icle.md",
|
|
ctime: MOCK_TIMESTAMP + 555,
|
|
mtime: MOCK_TIMESTAMP + 666,
|
|
path: 'Some parent folder/Part:1 1-23.456-icle.md'
|
|
});
|
|
});
|
|
it('should match head and tail, when simple regexp in head and and mixed in tail, with overrideTitle', () => {
|
|
// given
|
|
const file: TFile = mockTFile('Part:1 1-23.456-icle', 'md', 444, MOCK_TIMESTAMP + 555, MOCK_TIMESTAMP + 666);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['Some parent folder'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactHeadAndTail,
|
|
regexPrefix: {
|
|
regex: /^Part:\d/i
|
|
},
|
|
regexSuffix: {
|
|
regex: / *(\d+(?:-\d+)*).\d\d\d-icle$/i,
|
|
normalizerFn: CompoundDashNumberNormalizerFn
|
|
},
|
|
overrideTitle: true
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0, // Matched!
|
|
isFolder: false,
|
|
sortString: "00000001|00000023//",
|
|
ctime: MOCK_TIMESTAMP + 555,
|
|
mtime: MOCK_TIMESTAMP + 666,
|
|
path: 'Some parent folder/Part:1 1-23.456-icle.md'
|
|
});
|
|
});
|
|
it('should match head and tail, when advanced regexp in tail', () => {
|
|
// given
|
|
const file: TFile = mockTFile('Part:123-icle', 'md', 444, MOCK_TIMESTAMP + 555, MOCK_TIMESTAMP + 666);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['Some parent folder'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactHeadAndTail,
|
|
exactPrefix: 'Part',
|
|
regexSuffix: {
|
|
regex: /: *(\d+(?:-\d+)*)-icle$/i,
|
|
normalizerFn: CompoundDashNumberNormalizerFn
|
|
}
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0, // Matched!
|
|
isFolder: false,
|
|
sortString: "00000123////Part:123-icle.md",
|
|
ctime: MOCK_TIMESTAMP + 555,
|
|
mtime: MOCK_TIMESTAMP + 666,
|
|
path: 'Some parent folder/Part:123-icle.md'
|
|
});
|
|
});
|
|
it('should match head and tail, when advanced regexp in both, head and tail', () => {
|
|
// given
|
|
const file: TFile = mockTFile('Part 555-6 123-icle', 'md', 444, MOCK_TIMESTAMP + 555, MOCK_TIMESTAMP + 666);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['Some parent folder'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactHeadAndTail,
|
|
regexPrefix: {
|
|
regex: /^Part *(\d+(?:-\d+)*)/i,
|
|
normalizerFn: CompoundDashNumberNormalizerFn
|
|
},
|
|
regexSuffix: {
|
|
regex: / *(\d+(?:-\d+)*)-icle$/i,
|
|
normalizerFn: CompoundDashNumberNormalizerFn
|
|
}
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0, // Matched!
|
|
isFolder: false,
|
|
sortString: "00000555|00000006//00000123////Part 555-6 123-icle.md",
|
|
ctime: MOCK_TIMESTAMP + 555,
|
|
mtime: MOCK_TIMESTAMP + 666,
|
|
path: 'Some parent folder/Part 555-6 123-icle.md'
|
|
});
|
|
});
|
|
it('should match head and tail, when advanced regexp in both, head and tail, with overrideTitle', () => {
|
|
// given
|
|
const file: TFile = mockTFile('Part 555-6 123-icle', 'md', 444, MOCK_TIMESTAMP + 555, MOCK_TIMESTAMP + 666);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['Some parent folder'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactHeadAndTail,
|
|
regexPrefix: {
|
|
regex: /^Part *(\d+(?:-\d+)*)/i,
|
|
normalizerFn: CompoundDashNumberNormalizerFn
|
|
},
|
|
regexSuffix: {
|
|
regex: / *(\d+(?:-\d+)*)-icle$/i,
|
|
normalizerFn: CompoundDashNumberNormalizerFn
|
|
},
|
|
overrideTitle: true
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0, // Matched!
|
|
isFolder: false,
|
|
sortString: "00000555|00000006//00000123//",
|
|
ctime: MOCK_TIMESTAMP + 555,
|
|
mtime: MOCK_TIMESTAMP + 666,
|
|
path: 'Some parent folder/Part 555-6 123-icle.md'
|
|
});
|
|
});
|
|
})
|
|
describe('CustomSortGroupType.ExactPrefix', () => {
|
|
it('should correctly recognize exact prefix', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
exactPrefix: 'Ref'
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md'
|
|
});
|
|
})
|
|
it('should correctly recognize exact simple regex prefix', () => {
|
|
// given
|
|
const file: TFile = mockTFile('Ref2erences', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
regexPrefix: {
|
|
regex: /Ref[0-9]/i
|
|
}
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "Ref2erences.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/Ref2erences.md'
|
|
});
|
|
})
|
|
it('should correctly recognize exact prefix, regexL variant', () => {
|
|
// given
|
|
const file: TFile = mockTFile('Reference i.xxx.vi.mcm', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
regexPrefix: {
|
|
regex: /^Reference *([MDCLXVI]+(?:\.[MDCLXVI]+)*)/i,
|
|
normalizerFn: CompoundDotRomanNumberNormalizerFn
|
|
}
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: '00000001|00000030|00000006|00001900////Reference i.xxx.vi.mcm.md',
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/Reference i.xxx.vi.mcm.md'
|
|
});
|
|
})
|
|
it('should correctly process not matching prefix', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
exactPrefix: 'Pref'
|
|
}]
|
|
}
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // This indicates the last+1 idx
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md'
|
|
});
|
|
})
|
|
})
|
|
describe('CustomSortGroupType.ExactSuffix', () => {
|
|
it('should correctly recognize exact suffix', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactSuffix,
|
|
exactSuffix: 'ces'
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md'
|
|
});
|
|
})
|
|
it('should correctly recognize exact simple regex suffix', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References 12', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactSuffix,
|
|
regexSuffix: {
|
|
regex: /ces [0-9][0-9]$/i
|
|
}
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References 12.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References 12.md'
|
|
});
|
|
})
|
|
it('should correctly recognize exact suffix, regexL variant', () => {
|
|
// given
|
|
const file: TFile = mockTFile('Reference i.xxx.vi.mcm', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactSuffix,
|
|
regexSuffix: {
|
|
regex: / *([MDCLXVI]+(?:\.[MDCLXVI]+)*)$/i,
|
|
normalizerFn: CompoundDotRomanNumberNormalizerFn
|
|
}
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: '00000001|00000030|00000006|00001900////Reference i.xxx.vi.mcm.md',
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/Reference i.xxx.vi.mcm.md'
|
|
});
|
|
})
|
|
it('should correctly process not matching suffix', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactSuffix,
|
|
exactSuffix: 'ence'
|
|
}]
|
|
}
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // This indicates the last+1 idx
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md'
|
|
});
|
|
})
|
|
it('should correctly process not matching regex suffix', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactSuffix,
|
|
regexSuffix: {
|
|
regex: /ence$/i
|
|
}
|
|
}]
|
|
}
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // This indicates the last+1 idx
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md'
|
|
});
|
|
})
|
|
})
|
|
describe('CustomSortGroupType.ExactName', () => {
|
|
it('should correctly recognize exact name', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactName,
|
|
exactText: 'References'
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md'
|
|
});
|
|
})
|
|
it('should correctly recognize exact simple regex-based name', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References 12', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactName,
|
|
regexPrefix: {
|
|
regex: /^References [0-9][0-9]$/i
|
|
}
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References 12.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References 12.md'
|
|
});
|
|
})
|
|
it('should correctly recognize exact name, regexL variant', () => {
|
|
// given
|
|
const file: TFile = mockTFile('Reference i.xxx.vi.mcm', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactName,
|
|
regexPrefix: {
|
|
regex: /^Reference *([MDCLXVI]+(?:\.[MDCLXVI]+)*)$/i,
|
|
normalizerFn: CompoundDotRomanNumberNormalizerFn
|
|
}
|
|
}]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: '00000001|00000030|00000006|00001900////Reference i.xxx.vi.mcm.md',
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/Reference i.xxx.vi.mcm.md'
|
|
});
|
|
})
|
|
it('should correctly process not matching name', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactName,
|
|
exactText: 'ence'
|
|
}]
|
|
}
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // This indicates the last+1 idx
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md'
|
|
});
|
|
})
|
|
it('should correctly process not matching regex name', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactName,
|
|
regexPrefix: {
|
|
regex: /^Reference$/i
|
|
}
|
|
}]
|
|
}
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // This indicates the last+1 idx
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md'
|
|
});
|
|
})
|
|
it('should consume shadow group instead of group, if shadow is present', () => {
|
|
// given
|
|
const file: TFile = mockTFile('gs-123', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactName,
|
|
exactText: 'g-123'
|
|
}],
|
|
groupsShadow: [{
|
|
type: CustomSortGroupType.ExactName,
|
|
exactText: 'gs-123'
|
|
}]
|
|
}
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0, // This indicates match!
|
|
isFolder: false,
|
|
sortString: "gs-123.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/gs-123.md'
|
|
});
|
|
})
|
|
})
|
|
describe('CustomSortGroupType.byMetadataFieldAlphabetical', () => {
|
|
it('should ignore the file item if it has no direct metadata', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.HasMetadataField,
|
|
withMetadataFieldName: "metadataField1",
|
|
exactPrefix: 'Ref'
|
|
}]
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
"References": {
|
|
frontmatter: {
|
|
metadataField1InvalidField: "directMetadataOnFile",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // The lastIdx+1, group not determined
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md'
|
|
});
|
|
})
|
|
it('should ignore the folder item if it has no metadata on folder note', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.HasMetadataField,
|
|
withMetadataFieldName: "metadataField1",
|
|
exactPrefix: 'Ref'
|
|
}]
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
"References": {
|
|
frontmatter: {
|
|
metadataField1: undefined,
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // lastIdx + 1, group not determined
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md'
|
|
});
|
|
})
|
|
it('should correctly include the File item if has direct metadata (group not sorted by metadata', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.HasMetadataField,
|
|
withMetadataFieldName: "metadataField1",
|
|
exactPrefix: 'Ref'
|
|
}]
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'Some parent folder/References.md': {
|
|
frontmatter: {
|
|
"metadataField1": "directMetadataOnFile",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md'
|
|
} as FolderItemForSorting);
|
|
})
|
|
it('should correctly include the Folder item if it has folder note metadata (group not sorted by metadata', () => {
|
|
// given
|
|
const folder: TFolder = mockTFolder('References');
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.HasMetadataField,
|
|
withMetadataFieldName: "metadataField1",
|
|
exactPrefix: 'Ref'
|
|
}]
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'References/References.md': {
|
|
frontmatter: {
|
|
"metadataField1": "directMetadataOnFile",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(folder, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: true,
|
|
sortString: "References",
|
|
ctime: DEFAULT_FOLDER_CTIME,
|
|
mtime: DEFAULT_FOLDER_MTIME,
|
|
path: 'References',
|
|
folder: folder
|
|
} as FolderItemForSorting);
|
|
})
|
|
})
|
|
describe('CustomSortGroupType.StarredOnly', () => {
|
|
it('should not match not starred file', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.StarredOnly
|
|
}]
|
|
}
|
|
const starredPluginInstance: Partial<Starred_PluginInstance> = {
|
|
findStarredFile: jest.fn( function(filePath: findStarredFile_pathParam): TFile | null {
|
|
return null
|
|
})
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, {
|
|
starredPluginInstance: starredPluginInstance as Starred_PluginInstance
|
|
} as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // The lastIdx+1, group not determined
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md'
|
|
});
|
|
expect(starredPluginInstance.findStarredFile).toHaveBeenCalledTimes(1)
|
|
})
|
|
it('should match starred file', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.StarredOnly
|
|
}]
|
|
}
|
|
const starredPluginInstance: Partial<Starred_PluginInstance> = {
|
|
findStarredFile: jest.fn( function(filePath: findStarredFile_pathParam): TFile | null {
|
|
return filePath.path === 'Some parent folder/References.md' ? file : null
|
|
})
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, {
|
|
starredPluginInstance: starredPluginInstance as Starred_PluginInstance
|
|
} as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md'
|
|
});
|
|
expect(starredPluginInstance.findStarredFile).toHaveBeenCalledTimes(1)
|
|
})
|
|
it('should not match empty folder', () => {
|
|
// given
|
|
const folder: TFolder = mockTFolder('TestEmptyFolder');
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.StarredOnly
|
|
}]
|
|
}
|
|
const starredPluginInstance: Partial<Starred_PluginInstance> = {
|
|
findStarredFile: jest.fn( function(filePath: findStarredFile_pathParam): TFile | null {
|
|
return filePath.path === 'Some parent folder/References.md' ? {} as TFile : null
|
|
})
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(folder, sortSpec, {
|
|
starredPluginInstance: starredPluginInstance as Starred_PluginInstance
|
|
} as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // The lastIdx+1, group not determined
|
|
isFolder: true,
|
|
sortString: "TestEmptyFolder",
|
|
ctime: 0,
|
|
mtime: 0,
|
|
path: 'TestEmptyFolder',
|
|
folder: {
|
|
children: [],
|
|
isRoot: expect.any(Function),
|
|
name: "TestEmptyFolder",
|
|
parent: {},
|
|
path: "TestEmptyFolder",
|
|
vault: {}
|
|
}
|
|
});
|
|
expect(starredPluginInstance.findStarredFile).not.toHaveBeenCalled()
|
|
})
|
|
it('should not match folder w/o starred items', () => {
|
|
// given
|
|
const folder: TFolder = mockTFolderWithChildren('TestEmptyFolder');
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.StarredOnly
|
|
}]
|
|
}
|
|
const starredPluginInstance: Partial<Starred_PluginInstance> = {
|
|
findStarredFile: jest.fn( function(filePath: findStarredFile_pathParam): TFile | null {
|
|
return filePath.path === 'Some parent folder/References.md' ? {} as TFile : null
|
|
})
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(folder, sortSpec, {
|
|
starredPluginInstance: starredPluginInstance as Starred_PluginInstance
|
|
} as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // The lastIdx+1, group not determined
|
|
isFolder: true,
|
|
sortString: "TestEmptyFolder",
|
|
ctime: 0,
|
|
mtime: 0,
|
|
path: 'TestEmptyFolder',
|
|
folder: {
|
|
children: expect.any(Array),
|
|
isRoot: expect.any(Function),
|
|
name: "TestEmptyFolder",
|
|
parent: {},
|
|
path: "TestEmptyFolder",
|
|
vault: {}
|
|
}
|
|
});
|
|
expect(starredPluginInstance.findStarredFile).toHaveBeenCalledTimes(folder.children.filter(f => (f as any).isRoot === undefined).length)
|
|
})
|
|
it('should match folder with one starred item', () => {
|
|
// given
|
|
const folder: TFolder = mockTFolderWithChildren('TestEmptyFolder');
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.StarredOnly
|
|
}]
|
|
}
|
|
const starredPluginInstance: Partial<Starred_PluginInstance> = {
|
|
findStarredFile: jest.fn(function (filePath: findStarredFile_pathParam): TFile | null {
|
|
return filePath.path === 'Some parent folder/Child file 2 created as newest, not modified at all.md' ? {} as TFile : null
|
|
})
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(folder, sortSpec, {
|
|
starredPluginInstance: starredPluginInstance as Starred_PluginInstance
|
|
} as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: true,
|
|
sortString: "TestEmptyFolder",
|
|
ctime: 0,
|
|
mtime: 0,
|
|
path: 'TestEmptyFolder',
|
|
folder: {
|
|
children: expect.any(Array),
|
|
isRoot: expect.any(Function),
|
|
name: "TestEmptyFolder",
|
|
parent: {},
|
|
path: "TestEmptyFolder",
|
|
vault: {}
|
|
}
|
|
});
|
|
// assume optimized checking of starred items -> first match ends the check
|
|
expect(starredPluginInstance.findStarredFile).toHaveBeenCalledTimes(2)
|
|
})
|
|
})
|
|
describe('CustomSortGroupType.HasIcon', () => {
|
|
it('should not match file w/o icon', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.HasIcon
|
|
}]
|
|
}
|
|
const obsidianIconFolderPluginInstance: Partial<ObsidianIconFolder_PluginInstance> = {
|
|
getData: jest.fn( function(): ObsidianIconFolderPlugin_Data {
|
|
return {settings: {}} // The obsidian-folder-icon plugin keeps the settings there indeed ;-)
|
|
})
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, {
|
|
iconFolderPluginInstance: obsidianIconFolderPluginInstance as ObsidianIconFolder_PluginInstance
|
|
} as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // The lastIdx+1, group not determined
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md'
|
|
});
|
|
expect(obsidianIconFolderPluginInstance.getData).toHaveBeenCalledTimes(1)
|
|
})
|
|
it('should not match file with icon of different name', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.HasIcon,
|
|
iconName: 'IncorrectIconName'
|
|
}]
|
|
}
|
|
const obsidianIconFolderPluginInstance: Partial<ObsidianIconFolder_PluginInstance> = {
|
|
getData: jest.fn( function(): ObsidianIconFolderPlugin_Data {
|
|
return {
|
|
settings: {}, // The obsidian-folder-icon plugin keeps the settings there indeed ;-)
|
|
'Some parent folder/References.md': 'CorrectIconName'
|
|
}
|
|
})
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, {
|
|
iconFolderPluginInstance: obsidianIconFolderPluginInstance as ObsidianIconFolder_PluginInstance
|
|
} as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // The lastIdx+1, group not determined
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md'
|
|
});
|
|
expect(obsidianIconFolderPluginInstance.getData).toHaveBeenCalledTimes(1)
|
|
})
|
|
it('should match file with any icon', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.HasIcon
|
|
}]
|
|
}
|
|
const obsidianIconFolderPluginInstance: Partial<ObsidianIconFolder_PluginInstance> = {
|
|
getData: jest.fn( function(): ObsidianIconFolderPlugin_Data {
|
|
return {
|
|
settings: {}, // The obsidian-folder-icon plugin keeps the settings there indeed ;-)
|
|
'Some parent folder/References.md': 'Irrelevant icon name, only presence matters'
|
|
}
|
|
})
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, {
|
|
iconFolderPluginInstance: obsidianIconFolderPluginInstance as ObsidianIconFolder_PluginInstance
|
|
} as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md'
|
|
});
|
|
expect(obsidianIconFolderPluginInstance.getData).toHaveBeenCalledTimes(1)
|
|
})
|
|
it('should match file with icon of expected name', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.HasIcon,
|
|
iconName: 'CorrectIconName'
|
|
}]
|
|
}
|
|
const obsidianIconFolderPluginInstance: Partial<ObsidianIconFolder_PluginInstance> = {
|
|
getData: jest.fn( function(): ObsidianIconFolderPlugin_Data {
|
|
return {
|
|
settings: {}, // The obsidian-folder-icon plugin keeps the settings there indeed ;-)
|
|
'Some parent folder/References.md': 'CorrectIconName'
|
|
}
|
|
})
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, {
|
|
iconFolderPluginInstance: obsidianIconFolderPluginInstance as ObsidianIconFolder_PluginInstance
|
|
} as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md'
|
|
});
|
|
expect(obsidianIconFolderPluginInstance.getData).toHaveBeenCalledTimes(1)
|
|
})
|
|
it('should not match folder w/o icon', () => {
|
|
// given
|
|
const folder: TFolder = mockTFolder('TestEmptyFolder');
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.HasIcon
|
|
}]
|
|
}
|
|
const obsidianIconFolderPluginInstance: Partial<ObsidianIconFolder_PluginInstance> = {
|
|
getData: jest.fn( function(): ObsidianIconFolderPlugin_Data {
|
|
return {settings: {}} // The obsidian-folder-icon plugin keeps the settings there indeed ;-)
|
|
})
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(folder, sortSpec, {
|
|
iconFolderPluginInstance: obsidianIconFolderPluginInstance as ObsidianIconFolder_PluginInstance
|
|
} as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // The lastIdx+1, group not determined
|
|
isFolder: true,
|
|
sortString: "TestEmptyFolder",
|
|
ctime: 0,
|
|
mtime: 0,
|
|
path: 'TestEmptyFolder',
|
|
folder: {
|
|
children: [],
|
|
isRoot: expect.any(Function),
|
|
name: "TestEmptyFolder",
|
|
parent: {},
|
|
path: "TestEmptyFolder",
|
|
vault: {}
|
|
}
|
|
});
|
|
expect(obsidianIconFolderPluginInstance.getData).toHaveBeenCalledTimes(1)
|
|
})
|
|
it('should match folder with any icon (icon specified by string alone)', () => {
|
|
// given
|
|
const folder: TFolder = mockTFolderWithChildren('TestEmptyFolder');
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.HasIcon
|
|
}]
|
|
}
|
|
const obsidianIconFolderPluginInstance: Partial<ObsidianIconFolder_PluginInstance> = {
|
|
getData: jest.fn( function(): ObsidianIconFolderPlugin_Data {
|
|
return {
|
|
settings: {}, // The obsidian-folder-icon plugin keeps the settings there indeed ;-)
|
|
'TestEmptyFolder': 'Irrelevant icon name, only presence matters'
|
|
}
|
|
})
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(folder, sortSpec, {
|
|
iconFolderPluginInstance: obsidianIconFolderPluginInstance as ObsidianIconFolder_PluginInstance
|
|
} as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: true,
|
|
sortString: "TestEmptyFolder",
|
|
ctime: 0,
|
|
mtime: 0,
|
|
path: 'TestEmptyFolder',
|
|
folder: {
|
|
children: expect.any(Array),
|
|
isRoot: expect.any(Function),
|
|
name: "TestEmptyFolder",
|
|
parent: {},
|
|
path: "TestEmptyFolder",
|
|
vault: {}
|
|
}
|
|
});
|
|
expect(obsidianIconFolderPluginInstance.getData).toHaveBeenCalledTimes(1)
|
|
})
|
|
it('should match folder with any icon (icon specified together with inheritance)', () => {
|
|
// given
|
|
const folder: TFolder = mockTFolderWithChildren('TestEmptyFolder');
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.HasIcon
|
|
}]
|
|
}
|
|
const obsidianIconFolderPluginInstance: Partial<ObsidianIconFolder_PluginInstance> = {
|
|
getData: jest.fn( function(): ObsidianIconFolderPlugin_Data {
|
|
return {
|
|
settings: {}, // The obsidian-folder-icon plugin keeps the settings there indeed ;-)
|
|
'TestEmptyFolder': {
|
|
iconName: 'ConfiguredIcon',
|
|
inheritanceIcon: 'ConfiguredInheritanceIcon'
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(folder, sortSpec, {
|
|
iconFolderPluginInstance: obsidianIconFolderPluginInstance as ObsidianIconFolder_PluginInstance
|
|
} as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: true,
|
|
sortString: "TestEmptyFolder",
|
|
ctime: 0,
|
|
mtime: 0,
|
|
path: 'TestEmptyFolder',
|
|
folder: {
|
|
children: expect.any(Array),
|
|
isRoot: expect.any(Function),
|
|
name: "TestEmptyFolder",
|
|
parent: {},
|
|
path: "TestEmptyFolder",
|
|
vault: {}
|
|
}
|
|
});
|
|
expect(obsidianIconFolderPluginInstance.getData).toHaveBeenCalledTimes(1)
|
|
})
|
|
it('should match folder with specified icon (icon specified by string alone)', () => {
|
|
// given
|
|
const folder: TFolder = mockTFolderWithChildren('TestEmptyFolder');
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.HasIcon,
|
|
iconName: 'ConfiguredIcon-by-string'
|
|
}]
|
|
}
|
|
const obsidianIconFolderPluginInstance: Partial<ObsidianIconFolder_PluginInstance> = {
|
|
getData: jest.fn( function(): ObsidianIconFolderPlugin_Data {
|
|
return {
|
|
settings: {}, // The obsidian-folder-icon plugin keeps the settings there indeed ;-)
|
|
'TestEmptyFolder': 'ConfiguredIcon-by-string'
|
|
}
|
|
})
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(folder, sortSpec, {
|
|
iconFolderPluginInstance: obsidianIconFolderPluginInstance as ObsidianIconFolder_PluginInstance
|
|
} as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: true,
|
|
sortString: "TestEmptyFolder",
|
|
ctime: 0,
|
|
mtime: 0,
|
|
path: 'TestEmptyFolder',
|
|
folder: {
|
|
children: expect.any(Array),
|
|
isRoot: expect.any(Function),
|
|
name: "TestEmptyFolder",
|
|
parent: {},
|
|
path: "TestEmptyFolder",
|
|
vault: {}
|
|
}
|
|
});
|
|
expect(obsidianIconFolderPluginInstance.getData).toHaveBeenCalledTimes(1)
|
|
})
|
|
it('should match folder with specified icon (icon specified together with inheritance)', () => {
|
|
// given
|
|
const folder: TFolder = mockTFolderWithChildren('TestEmptyFolder');
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.HasIcon,
|
|
iconName: 'ConfiguredIcon'
|
|
}]
|
|
}
|
|
const obsidianIconFolderPluginInstance: Partial<ObsidianIconFolder_PluginInstance> = {
|
|
getData: jest.fn( function(): ObsidianIconFolderPlugin_Data {
|
|
return {
|
|
settings: {}, // The obsidian-folder-icon plugin keeps the settings there indeed ;-)
|
|
'TestEmptyFolder': {
|
|
iconName: 'ConfiguredIcon',
|
|
inheritanceIcon: 'ConfiguredInheritanceIcon'
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(folder, sortSpec, {
|
|
iconFolderPluginInstance: obsidianIconFolderPluginInstance as ObsidianIconFolder_PluginInstance
|
|
} as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: true,
|
|
sortString: "TestEmptyFolder",
|
|
ctime: 0,
|
|
mtime: 0,
|
|
path: 'TestEmptyFolder',
|
|
folder: {
|
|
children: expect.any(Array),
|
|
isRoot: expect.any(Function),
|
|
name: "TestEmptyFolder",
|
|
parent: {},
|
|
path: "TestEmptyFolder",
|
|
vault: {}
|
|
}
|
|
});
|
|
expect(obsidianIconFolderPluginInstance.getData).toHaveBeenCalledTimes(1)
|
|
})
|
|
it('should not match folder with different icon (icon specified by string alone)', () => {
|
|
// given
|
|
const folder: TFolder = mockTFolderWithChildren('TestEmptyFolder');
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.HasIcon,
|
|
iconName: 'ConfiguredIcon-by-string'
|
|
}]
|
|
}
|
|
const obsidianIconFolderPluginInstance: Partial<ObsidianIconFolder_PluginInstance> = {
|
|
getData: jest.fn( function(): ObsidianIconFolderPlugin_Data {
|
|
return {
|
|
settings: {}, // The obsidian-folder-icon plugin keeps the settings there indeed ;-)
|
|
'TestEmptyFolder': 'AnotherConfiguredIcon-by-string'
|
|
}
|
|
})
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(folder, sortSpec, {
|
|
iconFolderPluginInstance: obsidianIconFolderPluginInstance as ObsidianIconFolder_PluginInstance
|
|
} as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // lastIdx+1 - no match
|
|
isFolder: true,
|
|
sortString: "TestEmptyFolder",
|
|
ctime: 0,
|
|
mtime: 0,
|
|
path: 'TestEmptyFolder',
|
|
folder: {
|
|
children: expect.any(Array),
|
|
isRoot: expect.any(Function),
|
|
name: "TestEmptyFolder",
|
|
parent: {},
|
|
path: "TestEmptyFolder",
|
|
vault: {}
|
|
}
|
|
});
|
|
expect(obsidianIconFolderPluginInstance.getData).toHaveBeenCalledTimes(1)
|
|
})
|
|
it('should not match folder with different icon (icon specified together with inheritance)', () => {
|
|
// given
|
|
const folder: TFolder = mockTFolderWithChildren('TestEmptyFolder');
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.HasIcon,
|
|
iconName: 'ConfiguredIcon'
|
|
}]
|
|
}
|
|
const obsidianIconFolderPluginInstance: Partial<ObsidianIconFolder_PluginInstance> = {
|
|
getData: jest.fn( function(): ObsidianIconFolderPlugin_Data {
|
|
return {
|
|
settings: {}, // The obsidian-folder-icon plugin keeps the settings there indeed ;-)
|
|
'TestEmptyFolder': {
|
|
iconName: 'OtherConfiguredIcon',
|
|
inheritanceIcon: 'ConfiguredInheritanceIcon'
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(folder, sortSpec, {
|
|
iconFolderPluginInstance: obsidianIconFolderPluginInstance as ObsidianIconFolder_PluginInstance
|
|
} as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 1, // lastIdx+1 - no match
|
|
isFolder: true,
|
|
sortString: "TestEmptyFolder",
|
|
ctime: 0,
|
|
mtime: 0,
|
|
path: 'TestEmptyFolder',
|
|
folder: {
|
|
children: expect.any(Array),
|
|
isRoot: expect.any(Function),
|
|
name: "TestEmptyFolder",
|
|
parent: {},
|
|
path: "TestEmptyFolder",
|
|
vault: {}
|
|
}
|
|
});
|
|
expect(obsidianIconFolderPluginInstance.getData).toHaveBeenCalledTimes(1)
|
|
})
|
|
})
|
|
describe('when sort by metadata is involved', () => {
|
|
it('should correctly read direct metadata from File item (order by metadata set on group) alph', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
byMetadataField: 'metadata-field-for-sorting',
|
|
exactPrefix: 'Ref',
|
|
order: CustomSortOrder.byMetadataFieldAlphabetical
|
|
}]
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'Some parent folder/References.md': {
|
|
frontmatter: {
|
|
"metadata-field-for-sorting": "direct metadata on file",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md',
|
|
metadataFieldValue: 'direct metadata on file'
|
|
} as FolderItemForSorting);
|
|
})
|
|
it('should correctly read direct metadata from File item (order by metadata set on group) alph rev', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
byMetadataField: 'metadata-field-for-sorting',
|
|
exactPrefix: 'Ref',
|
|
order: CustomSortOrder.byMetadataFieldAlphabeticalReverse
|
|
}]
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'Some parent folder/References.md': {
|
|
frontmatter: {
|
|
"metadata-field-for-sorting": "direct metadata on file",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md',
|
|
metadataFieldValue: 'direct metadata on file'
|
|
} as FolderItemForSorting);
|
|
})
|
|
it('should correctly read direct metadata from File item (order by metadata set on group) true alph', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
byMetadataField: 'metadata-field-for-sorting',
|
|
exactPrefix: 'Ref',
|
|
order: CustomSortOrder.byMetadataFieldTrueAlphabetical
|
|
}]
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'Some parent folder/References.md': {
|
|
frontmatter: {
|
|
"metadata-field-for-sorting": "direct metadata on file",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md',
|
|
metadataFieldValue: 'direct metadata on file'
|
|
} as FolderItemForSorting);
|
|
})
|
|
it('should correctly read direct metadata from File item (order by metadata set on group) true alph rev', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
byMetadataField: 'metadata-field-for-sorting',
|
|
exactPrefix: 'Ref',
|
|
order: CustomSortOrder.byMetadataFieldTrueAlphabeticalReverse
|
|
}]
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'Some parent folder/References.md': {
|
|
frontmatter: {
|
|
"metadata-field-for-sorting": "direct metadata on file",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md',
|
|
metadataFieldValue: 'direct metadata on file'
|
|
} as FolderItemForSorting);
|
|
})
|
|
it('should correctly read direct metadata from folder note item (order by metadata set on group)', () => {
|
|
// given
|
|
const folder: TFolder = mockTFolder('References');
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
exactPrefix: 'Ref',
|
|
byMetadataField: 'metadata-field-for-sorting',
|
|
order: CustomSortOrder.byMetadataFieldAlphabeticalReverse
|
|
}]
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'References/References.md': {
|
|
frontmatter: {
|
|
'metadata-field-for-sorting': "metadata on folder note",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(folder, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: true,
|
|
sortString: "References",
|
|
ctime: DEFAULT_FOLDER_CTIME,
|
|
mtime: DEFAULT_FOLDER_MTIME,
|
|
path: 'References',
|
|
metadataFieldValue: 'metadata on folder note',
|
|
folder: folder
|
|
} as FolderItemForSorting);
|
|
})
|
|
it('should correctly read direct metadata from File item (order by metadata set on target folder)', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
exactPrefix: 'Ref',
|
|
order: CustomSortOrder.byMetadataFieldAlphabetical
|
|
}],
|
|
defaultOrder: CustomSortOrder.byMetadataFieldAlphabeticalReverse,
|
|
byMetadataField: 'metadata-field-for-sorting-specified-on-target-folder'
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'Some parent folder/References.md': {
|
|
frontmatter: {
|
|
"metadata-field-for-sorting-specified-on-target-folder": "direct metadata on file, not obvious",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md',
|
|
metadataFieldValueForDerived: 'direct metadata on file, not obvious'
|
|
} as FolderItemForSorting);
|
|
})
|
|
it('should correctly read direct metadata from File item (order by metadata set on group, no metadata name specified on group)', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.HasMetadataField,
|
|
order: CustomSortOrder.byMetadataFieldAlphabetical,
|
|
withMetadataFieldName: 'field-used-with-with-metadata-syntax'
|
|
}]
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'Some parent folder/References.md': {
|
|
frontmatter: {
|
|
'field-used-with-with-metadata-syntax': "direct metadata on file, tricky",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md',
|
|
metadataFieldValue: 'direct metadata on file, tricky'
|
|
} as FolderItemForSorting);
|
|
})
|
|
it('should correctly read direct metadata from File item (order by metadata set on group, no metadata name specified anywhere)', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
exactPrefix: 'Ref',
|
|
order: CustomSortOrder.byMetadataFieldAlphabetical
|
|
}]
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'Some parent folder/References.md': {
|
|
frontmatter: {
|
|
'sort-index-value': "direct metadata on file, under default name",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md',
|
|
metadataFieldValue: 'direct metadata on file, under default name'
|
|
} as FolderItemForSorting);
|
|
})
|
|
})
|
|
|
|
describe('when sort by metadata is involved (specified in secondary sort, for group of for target folder)', () => {
|
|
it('should correctly read direct metadata from File item (order by metadata set on group) alph', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
byMetadataFieldSecondary: 'metadata-field-for-sorting',
|
|
exactPrefix: 'Ref',
|
|
order: CustomSortOrder.alphabetical,
|
|
secondaryOrder: CustomSortOrder.byMetadataFieldAlphabetical
|
|
}]
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'Some parent folder/References.md': {
|
|
frontmatter: {
|
|
"metadata-field-for-sorting": "direct metadata on file",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md',
|
|
metadataFieldValueSecondary: 'direct metadata on file'
|
|
} as FolderItemForSorting);
|
|
})
|
|
it('should correctly read direct metadata from File item (order by metadata set on group) alph rev', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
byMetadataFieldSecondary: 'metadata-field-for-sorting',
|
|
exactPrefix: 'Ref',
|
|
order: CustomSortOrder.alphabeticalReverse,
|
|
secondaryOrder: CustomSortOrder.byMetadataFieldAlphabeticalReverse
|
|
}]
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'Some parent folder/References.md': {
|
|
frontmatter: {
|
|
"metadata-field-for-sorting": "direct metadata on file",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md',
|
|
metadataFieldValueSecondary: 'direct metadata on file'
|
|
} as FolderItemForSorting);
|
|
})
|
|
it('should correctly read direct metadata from File item (order by metadata set on group) true alph', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
byMetadataField: 'non-existing-mdata',
|
|
byMetadataFieldSecondary: 'metadata-field-for-sorting',
|
|
exactPrefix: 'Ref',
|
|
order: CustomSortOrder.byMetadataFieldTrueAlphabetical,
|
|
secondaryOrder: CustomSortOrder.byMetadataFieldTrueAlphabetical
|
|
}]
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'Some parent folder/References.md': {
|
|
frontmatter: {
|
|
"metadata-field-for-sorting": "direct metadata on file",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md',
|
|
metadataFieldValueSecondary: 'direct metadata on file'
|
|
} as FolderItemForSorting);
|
|
})
|
|
it('should correctly read direct metadata from File item (order by metadata set on group) true alph rev (dbl mdata)', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
byMetadataField: 'metadata-field-for-sorting',
|
|
byMetadataFieldSecondary: 'metadata-field-for-sorting secondary',
|
|
exactPrefix: 'Ref',
|
|
order: CustomSortOrder.byMetadataFieldTrueAlphabetical,
|
|
secondaryOrder: CustomSortOrder.byMetadataFieldTrueAlphabeticalReverse
|
|
}]
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'Some parent folder/References.md': {
|
|
frontmatter: {
|
|
"metadata-field-for-sorting": "direct metadata on file",
|
|
"metadata-field-for-sorting secondary": "direct another metadata on file",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md',
|
|
metadataFieldValue: 'direct metadata on file',
|
|
metadataFieldValueSecondary: 'direct another metadata on file'
|
|
} as FolderItemForSorting);
|
|
})
|
|
it('should correctly read direct metadata from folder note item (order by metadata set on group)', () => {
|
|
// given
|
|
const folder: TFolder = mockTFolder('References');
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
exactPrefix: 'Ref',
|
|
byMetadataFieldSecondary: 'metadata-field-for-sorting',
|
|
order: CustomSortOrder.standardObsidian,
|
|
secondaryOrder: CustomSortOrder.byMetadataFieldAlphabeticalReverse
|
|
}]
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'References/References.md': {
|
|
frontmatter: {
|
|
'metadata-field-for-sorting': "metadata on folder note",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(folder, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: true,
|
|
sortString: "References",
|
|
ctime: DEFAULT_FOLDER_CTIME,
|
|
mtime: DEFAULT_FOLDER_MTIME,
|
|
path: 'References',
|
|
metadataFieldValueSecondary: 'metadata on folder note',
|
|
folder: folder
|
|
} as FolderItemForSorting);
|
|
})
|
|
it('should correctly read direct metadata from File item (order by metadata set on target folder)', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
exactPrefix: 'Ref',
|
|
order: CustomSortOrder.trueAlphabetical,
|
|
secondaryOrder: CustomSortOrder.byMetadataFieldAlphabetical
|
|
}],
|
|
defaultOrder: CustomSortOrder.byCreatedTime,
|
|
defaultSecondaryOrder: CustomSortOrder.byMetadataFieldAlphabeticalReverse,
|
|
byMetadataFieldSecondary: 'metadata-field-for-sorting-specified-on-target-folder'
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'Some parent folder/References.md': {
|
|
frontmatter: {
|
|
"metadata-field-for-sorting-specified-on-target-folder": "direct metadata on file, not obvious",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md',
|
|
metadataFieldValueForDerivedSecondary: 'direct metadata on file, not obvious'
|
|
} as FolderItemForSorting);
|
|
})
|
|
it('should correctly read direct metadata from File item (order by metadata set on group, no metadata name specified on group)', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.HasMetadataField,
|
|
order: CustomSortOrder.standardObsidian,
|
|
secondaryOrder: CustomSortOrder.byMetadataFieldAlphabetical,
|
|
withMetadataFieldName: 'field-used-with-with-metadata-syntax'
|
|
}]
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'Some parent folder/References.md': {
|
|
frontmatter: {
|
|
'field-used-with-with-metadata-syntax': "direct metadata on file, tricky",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md',
|
|
metadataFieldValueSecondary: 'direct metadata on file, tricky',
|
|
} as FolderItemForSorting);
|
|
})
|
|
it('should correctly read direct metadata from File item (order by metadata set on group, no metadata name specified anywhere)', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
exactPrefix: 'Ref',
|
|
order: CustomSortOrder.byCreatedTimeReverse,
|
|
secondaryOrder: CustomSortOrder.byMetadataFieldAlphabetical
|
|
}]
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'Some parent folder/References.md': {
|
|
frontmatter: {
|
|
'sort-index-value': "direct metadata on file, under default name",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md',
|
|
metadataFieldValueSecondary: 'direct metadata on file, under default name',
|
|
} as FolderItemForSorting);
|
|
})
|
|
})
|
|
|
|
describe('when sort by metadata is involved, at every level', () => {
|
|
it('should correctly read direct metadata from File item (order by metadata set at each level)', () => {
|
|
// given
|
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
exactPrefix: 'Ref',
|
|
order: CustomSortOrder.byMetadataFieldAlphabetical,
|
|
byMetadataField: 'mdata-for-primary',
|
|
secondaryOrder: CustomSortOrder.byMetadataFieldAlphabeticalReverse,
|
|
byMetadataFieldSecondary: 'mdata-for-secondary'
|
|
}],
|
|
defaultOrder: CustomSortOrder.byMetadataFieldTrueAlphabetical,
|
|
byMetadataField: 'mdata-for-default-primary',
|
|
defaultSecondaryOrder: CustomSortOrder.byMetadataFieldTrueAlphabeticalReverse,
|
|
byMetadataFieldSecondary: 'mdata-for-default-secondary'
|
|
}
|
|
const ctx: Partial<ProcessingContext> = {
|
|
_mCache: {
|
|
getCache: function (path: string): CachedMetadata | undefined {
|
|
return {
|
|
'Some parent folder/References.md': {
|
|
frontmatter: {
|
|
'mdata-for-primary': "filemdata 1",
|
|
'mdata-for-secondary': "filemdata 2",
|
|
'mdata-for-default-primary': "filemdata 3",
|
|
'mdata-for-default-secondary': "filemdata 4",
|
|
position: MockedLoc
|
|
}
|
|
}
|
|
}[path]
|
|
}
|
|
} as MetadataCache
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 0,
|
|
isFolder: false,
|
|
sortString: "References.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/References.md',
|
|
metadataFieldValue: 'filemdata 1',
|
|
metadataFieldValueSecondary: 'filemdata 2',
|
|
metadataFieldValueForDerived: 'filemdata 3',
|
|
metadataFieldValueForDerivedSecondary: 'filemdata 4',
|
|
} as FolderItemForSorting);
|
|
})
|
|
})
|
|
|
|
it('should correctly apply priority group', () => {
|
|
// given
|
|
const file: TFile = mockTFile('Abcdef!', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
groups: [{
|
|
filesOnly: true,
|
|
order: CustomSortOrder.alphabetical,
|
|
type: CustomSortGroupType.MatchAll
|
|
}, {
|
|
foldersOnly: true,
|
|
order: CustomSortOrder.alphabetical,
|
|
type: CustomSortGroupType.MatchAll
|
|
}, {
|
|
exactSuffix: "def!",
|
|
priority: 2,
|
|
order: CustomSortOrder.alphabetical,
|
|
type: CustomSortGroupType.ExactSuffix
|
|
}, {
|
|
exactText: "Abcdef!",
|
|
order: CustomSortOrder.alphabetical,
|
|
priority: 3,
|
|
type: CustomSortGroupType.ExactName
|
|
}, {
|
|
order: CustomSortOrder.alphabetical,
|
|
type: CustomSortGroupType.Outsiders
|
|
}],
|
|
outsidersGroupIdx: 4,
|
|
targetFoldersPaths: ['/'],
|
|
priorityOrder: [3,2,0,1]
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 3,
|
|
isFolder: false,
|
|
sortString: "Abcdef!.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/Abcdef!.md'
|
|
});
|
|
})
|
|
it('should correctly recognize and apply combined group', () => {
|
|
// given
|
|
const file1: TFile = mockTFile('Hello :-) ha', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const file2: TFile = mockTFile('Hello World :-)', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
groups: [{
|
|
exactSuffix: "def!",
|
|
order: CustomSortOrder.alphabeticalReverse,
|
|
type: CustomSortGroupType.ExactSuffix
|
|
}, {
|
|
exactPrefix: "Hello :-)",
|
|
order: CustomSortOrder.alphabeticalReverse,
|
|
type: CustomSortGroupType.ExactPrefix,
|
|
combineWithIdx: 1
|
|
}, {
|
|
exactText: "Hello World :-)",
|
|
order: CustomSortOrder.alphabeticalReverse,
|
|
type: CustomSortGroupType.ExactName,
|
|
combineWithIdx: 1
|
|
}, {
|
|
filesOnly: true,
|
|
order: CustomSortOrder.alphabetical,
|
|
type: CustomSortGroupType.MatchAll
|
|
}, {
|
|
foldersOnly: true,
|
|
order: CustomSortOrder.alphabetical,
|
|
type: CustomSortGroupType.MatchAll
|
|
}, {
|
|
order: CustomSortOrder.alphabetical,
|
|
type: CustomSortGroupType.Outsiders
|
|
}],
|
|
outsidersGroupIdx: 5,
|
|
targetFoldersPaths: ['/']
|
|
}
|
|
|
|
// when
|
|
const result1 = determineSortingGroup(file1, sortSpec)
|
|
const result2 = determineSortingGroup(file2, sortSpec)
|
|
|
|
// then
|
|
expect(result1).toEqual({
|
|
groupIdx: 1, // Imposed by combined groups
|
|
isFolder: false,
|
|
sortString: "Hello :-) ha.md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/Hello :-) ha.md'
|
|
});
|
|
expect(result2).toEqual({
|
|
groupIdx: 1, // Imposed by combined groups
|
|
isFolder: false,
|
|
sortString: "Hello World :-).md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/Hello World :-).md'
|
|
});
|
|
})
|
|
it('should correctly recognize and apply combined group in connection with priorities', () => {
|
|
// given
|
|
const file: TFile = mockTFile('Hello :-)', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
|
const sortSpec: CustomSortSpec = {
|
|
groups: [{
|
|
filesOnly: true,
|
|
order: CustomSortOrder.alphabetical,
|
|
type: CustomSortGroupType.MatchAll
|
|
}, {
|
|
foldersOnly: true,
|
|
order: CustomSortOrder.alphabetical,
|
|
type: CustomSortGroupType.MatchAll
|
|
}, {
|
|
exactSuffix: "def!",
|
|
order: CustomSortOrder.alphabeticalReverse,
|
|
type: CustomSortGroupType.ExactSuffix,
|
|
combineWithIdx: 2
|
|
}, {
|
|
exactText: "Hello :-)",
|
|
order: CustomSortOrder.alphabeticalReverse,
|
|
type: CustomSortGroupType.ExactName,
|
|
priority: 1,
|
|
combineWithIdx: 2
|
|
}, {
|
|
order: CustomSortOrder.alphabetical,
|
|
type: CustomSortGroupType.Outsiders
|
|
}],
|
|
outsidersGroupIdx: 4,
|
|
priorityOrder: [3,0,1,2],
|
|
targetFoldersPaths: ['/']
|
|
}
|
|
|
|
// when
|
|
const result = determineSortingGroup(file, sortSpec)
|
|
|
|
// then
|
|
expect(result).toEqual({
|
|
groupIdx: 2, // Imposed by combined groups
|
|
isFolder: false,
|
|
sortString: "Hello :-).md",
|
|
ctime: MOCK_TIMESTAMP + 222,
|
|
mtime: MOCK_TIMESTAMP + 333,
|
|
path: 'Some parent folder/Hello :-).md'
|
|
});
|
|
})
|
|
})
|
|
|
|
describe('determineFolderDatesIfNeeded', () => {
|
|
it('should not be triggered if not needed - sorting method does not require it', () => {
|
|
// given
|
|
const folder: TFolder = mockTFolderWithChildren('Test folder 1')
|
|
const OUTSIDERS_GROUP_IDX = 0
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
groups: [{
|
|
type: CustomSortGroupType.Outsiders,
|
|
order: CustomSortOrder.alphabetical
|
|
}],
|
|
outsidersGroupIdx: OUTSIDERS_GROUP_IDX
|
|
}
|
|
|
|
// when
|
|
const result: FolderItemForSorting = determineSortingGroup(folder, sortSpec)
|
|
determineFolderDatesIfNeeded([result], sortSpec)
|
|
|
|
// then
|
|
expect(result.ctime).toEqual(DEFAULT_FOLDER_CTIME)
|
|
expect(result.mtime).toEqual(DEFAULT_FOLDER_CTIME)
|
|
})
|
|
it.each(
|
|
[
|
|
[CustomSortOrder.byCreatedTimeReverseAdvanced, undefined],
|
|
[CustomSortOrder.byCreatedTimeAdvanced, undefined],
|
|
[CustomSortOrder.byModifiedTimeAdvanced, undefined],
|
|
[CustomSortOrder.byModifiedTimeReverseAdvanced, undefined],
|
|
[CustomSortOrder.alphabetical, CustomSortOrder.byCreatedTimeReverseAdvanced],
|
|
[CustomSortOrder.alphabetical, CustomSortOrder.byCreatedTimeAdvanced],
|
|
[CustomSortOrder.alphabetical, CustomSortOrder.byModifiedTimeAdvanced],
|
|
[CustomSortOrder.alphabetical, CustomSortOrder.byModifiedTimeReverseAdvanced]
|
|
])('should correctly determine dates, if triggered by %s under default %s', (order: CustomSortOrder, folderOrder: CustomSortOrder | undefined) => {
|
|
// given
|
|
const folder: TFolder = mockTFolderWithChildren('Test folder 1')
|
|
const OUTSIDERS_GROUP_IDX = 0
|
|
const sortSpec: CustomSortSpec = {
|
|
targetFoldersPaths: ['/'],
|
|
defaultOrder: folderOrder,
|
|
groups: [{
|
|
type: CustomSortGroupType.Outsiders,
|
|
order: order
|
|
}],
|
|
outsidersGroupIdx: OUTSIDERS_GROUP_IDX
|
|
}
|
|
|
|
// when
|
|
const result: FolderItemForSorting = determineSortingGroup(folder, sortSpec)
|
|
determineFolderDatesIfNeeded([result], sortSpec)
|
|
|
|
// then
|
|
expect(result.ctime).toEqual(TIMESTAMP_OLDEST)
|
|
expect(result.mtime).toEqual(TIMESTAMP_NEWEST)
|
|
})
|
|
})
|
|
|
|
describe('matchGroupRegex', () => {
|
|
it( 'should correctly handle no match', () => {
|
|
// given
|
|
const regExpSpec: RegExpSpec = {
|
|
regex: /a(b)c/i
|
|
}
|
|
const name: string = 'Abbc'
|
|
|
|
// when
|
|
const [matched, matchedGroup, entireMatch] = matchGroupRegex(regExpSpec, name)
|
|
|
|
// then
|
|
expect(matched).toBe(false)
|
|
expect(matchedGroup).toBeUndefined()
|
|
expect(entireMatch).toBeUndefined()
|
|
})
|
|
it('should correctly handle no matching group match and normalizer absent', () => {
|
|
// given
|
|
const regExpSpec: RegExpSpec = {
|
|
regex: /ab+c/i
|
|
}
|
|
const name: string = 'Abbbc'
|
|
|
|
// when
|
|
const [matched, matchedGroup, entireMatch] = matchGroupRegex(regExpSpec, name)
|
|
|
|
// then
|
|
expect(matched).toBe(true)
|
|
expect(matchedGroup).toBeUndefined()
|
|
expect(entireMatch).toBe('Abbbc')
|
|
})
|
|
it('should correctly handle no matching group match and normalizer present', () => {
|
|
// given
|
|
const regExpSpec: RegExpSpec = {
|
|
regex: /ab+c/i,
|
|
normalizerFn: jest.fn()
|
|
}
|
|
const name: string = 'Abc'
|
|
|
|
// when
|
|
const [matched, matchedGroup, entireMatch] = matchGroupRegex(regExpSpec, name)
|
|
|
|
// then
|
|
expect(matched).toBe(true)
|
|
expect(matchedGroup).toBeUndefined()
|
|
expect(entireMatch).toBe('Abc')
|
|
expect(regExpSpec.normalizerFn).not.toHaveBeenCalled()
|
|
})
|
|
it('should correctly handle matching group match and normalizer absent', () => {
|
|
// given
|
|
const regExpSpec: RegExpSpec = {
|
|
regex: /a(b+)c/i
|
|
}
|
|
const name: string = 'Abbbc'
|
|
|
|
// when
|
|
const [matched, matchedGroup, entireMatch] = matchGroupRegex(regExpSpec, name)
|
|
|
|
// then
|
|
expect(matched).toBe(true)
|
|
expect(matchedGroup).toBe('bbb')
|
|
expect(entireMatch).toBe('Abbbc')
|
|
})
|
|
it('should correctly handle matching group match and normalizer present', () => {
|
|
// given
|
|
const regExpSpec: RegExpSpec = {
|
|
regex: /a(b+)c/i,
|
|
normalizerFn: jest.fn((s) => `>>${s}<<`)
|
|
}
|
|
const name: string = 'Abc'
|
|
|
|
// when
|
|
const [matched, matchedGroup, entireMatch] = matchGroupRegex(regExpSpec, name)
|
|
|
|
// then
|
|
expect(matched).toBe(true)
|
|
expect(matchedGroup).toBe('>>b<<')
|
|
expect(entireMatch).toBe('Abc')
|
|
expect(regExpSpec.normalizerFn).toHaveBeenCalledTimes(1)
|
|
})
|
|
})
|
|
|
|
const SORT_FIRST_GOES_EARLIER: number = -1
|
|
const SORT_FIRST_GOES_LATER: number = 1
|
|
const SORT_ITEMS_ARE_EQUAL: number = 0
|
|
|
|
describe('CustomSortOrder.byMetadataFieldAlphabetical', () => {
|
|
it('should correctly order alphabetically when metadata on both items is present', () => {
|
|
// given
|
|
const itemA: Partial<FolderItemForSorting> = {
|
|
metadataFieldValue: 'A'
|
|
}
|
|
const itemB: Partial<FolderItemForSorting> = {
|
|
metadataFieldValue: 'B'
|
|
}
|
|
const sorter: SorterFn = getSorterFnFor(CustomSortOrder.byMetadataFieldAlphabetical)
|
|
|
|
// when
|
|
const result1: number = sorter(itemA as FolderItemForSorting, itemB as FolderItemForSorting)
|
|
const result2: number = sorter(itemB as FolderItemForSorting, itemA as FolderItemForSorting)
|
|
|
|
// then
|
|
expect(result1).toBe(SORT_FIRST_GOES_EARLIER)
|
|
expect(result2).toBe(SORT_FIRST_GOES_LATER)
|
|
})
|
|
it('should correctly compare when metadata on both items is present and equal', () => {
|
|
// given
|
|
const itemA: Partial<FolderItemForSorting> = {
|
|
metadataFieldValue: 'Aaa',
|
|
sortString: 'n123'
|
|
}
|
|
const itemB: Partial<FolderItemForSorting> = {
|
|
metadataFieldValue: 'Aaa',
|
|
sortString: 'a123'
|
|
}
|
|
const sorter: SorterFn = getSorterFnFor(CustomSortOrder.byMetadataFieldAlphabetical)
|
|
|
|
// when
|
|
const result1: number = sorter(itemA as FolderItemForSorting, itemB as FolderItemForSorting)
|
|
const result2: number = sorter(itemB as FolderItemForSorting, itemA as FolderItemForSorting)
|
|
const result3: number = sorter(itemB as FolderItemForSorting, itemB as FolderItemForSorting)
|
|
|
|
// then
|
|
expect(result1).toBe(EQUAL_OR_UNCOMPARABLE)
|
|
expect(result2).toBe(EQUAL_OR_UNCOMPARABLE)
|
|
expect(result3).toBe(EQUAL_OR_UNCOMPARABLE)
|
|
})
|
|
it('should put the item with metadata earlier if the second one has no metadata ', () => {
|
|
// given
|
|
const itemA: Partial<FolderItemForSorting> = {
|
|
metadataFieldValue: 'n159',
|
|
sortString: 'n123'
|
|
}
|
|
const itemB: Partial<FolderItemForSorting> = {
|
|
sortString: 'n123'
|
|
}
|
|
const sorter: SorterFn = getSorterFnFor(CustomSortOrder.byMetadataFieldAlphabetical)
|
|
|
|
// when
|
|
const result1: number = sorter(itemA as FolderItemForSorting, itemB as FolderItemForSorting)
|
|
const result2: number = sorter(itemB as FolderItemForSorting, itemA as FolderItemForSorting)
|
|
|
|
// then
|
|
expect(result1).toBe(SORT_FIRST_GOES_EARLIER)
|
|
expect(result2).toBe(SORT_FIRST_GOES_LATER)
|
|
})
|
|
it('should refuse comparison if no metadata on both items', () => {
|
|
// given
|
|
const itemA: Partial<FolderItemForSorting> = {
|
|
sortString: 'ccc'
|
|
}
|
|
const itemB: Partial<FolderItemForSorting> = {
|
|
sortString: 'ccc '
|
|
}
|
|
const sorter: SorterFn = getSorterFnFor(CustomSortOrder.byMetadataFieldAlphabetical)
|
|
|
|
// when
|
|
const result1: number = sorter(itemA as FolderItemForSorting, itemB as FolderItemForSorting)
|
|
const result2: number = sorter(itemB as FolderItemForSorting, itemA as FolderItemForSorting)
|
|
const result3: number = sorter(itemB as FolderItemForSorting, itemB as FolderItemForSorting)
|
|
|
|
// then
|
|
expect(result1).toBe(EQUAL_OR_UNCOMPARABLE)
|
|
expect(result2).toBe(EQUAL_OR_UNCOMPARABLE)
|
|
expect(result3).toBe(EQUAL_OR_UNCOMPARABLE)
|
|
})
|
|
})
|
|
|
|
describe('CustomSortOrder.byMetadataFieldAlphabeticalReverse', () => {
|
|
it('should correctly order alphabetically reverse when metadata on both items is present', () => {
|
|
// given
|
|
const itemA: Partial<FolderItemForSorting> = {
|
|
metadataFieldValue: 'A'
|
|
}
|
|
const itemB: Partial<FolderItemForSorting> = {
|
|
metadataFieldValue: 'B'
|
|
}
|
|
const sorter: SorterFn = getSorterFnFor(CustomSortOrder.byMetadataFieldAlphabeticalReverse)
|
|
|
|
// when
|
|
const result1: number = sorter(itemA as FolderItemForSorting, itemB as FolderItemForSorting)
|
|
const result2: number = sorter(itemB as FolderItemForSorting, itemA as FolderItemForSorting)
|
|
|
|
// then
|
|
expect(result1).toBe(SORT_FIRST_GOES_LATER)
|
|
expect(result2).toBe(SORT_FIRST_GOES_EARLIER)
|
|
})
|
|
it('should correctly compare when metadata on both items is present and equal', () => {
|
|
// given
|
|
const itemA: Partial<FolderItemForSorting> = {
|
|
metadataFieldValue: 'Aaa',
|
|
sortString: 'n123'
|
|
}
|
|
const itemB: Partial<FolderItemForSorting> = {
|
|
metadataFieldValue: 'Aaa',
|
|
sortString: 'a123'
|
|
}
|
|
const sorter: SorterFn = getSorterFnFor(CustomSortOrder.byMetadataFieldAlphabeticalReverse)
|
|
|
|
// when
|
|
const result1: number = sorter(itemA as FolderItemForSorting, itemB as FolderItemForSorting)
|
|
const result2: number = sorter(itemB as FolderItemForSorting, itemA as FolderItemForSorting)
|
|
const result3: number = sorter(itemB as FolderItemForSorting, itemB as FolderItemForSorting)
|
|
|
|
// then
|
|
expect(result1).toBe(EQUAL_OR_UNCOMPARABLE)
|
|
expect(result2).toBe(EQUAL_OR_UNCOMPARABLE)
|
|
expect(result3).toBe(EQUAL_OR_UNCOMPARABLE)
|
|
})
|
|
it('should put the item with metadata later if the second one has no metadata (reverse order)', () => {
|
|
// given
|
|
const itemA: Partial<FolderItemForSorting> = {
|
|
metadataFieldValue: '15',
|
|
sortString: 'n123'
|
|
}
|
|
const itemB: Partial<FolderItemForSorting> = {
|
|
sortString: 'n123'
|
|
}
|
|
const sorter: SorterFn = getSorterFnFor(CustomSortOrder.byMetadataFieldAlphabeticalReverse)
|
|
|
|
// when
|
|
const result1: number = sorter(itemA as FolderItemForSorting, itemB as FolderItemForSorting)
|
|
const result2: number = sorter(itemB as FolderItemForSorting, itemA as FolderItemForSorting)
|
|
|
|
// then
|
|
expect(result1).toBe(SORT_FIRST_GOES_LATER)
|
|
expect(result2).toBe(SORT_FIRST_GOES_EARLIER)
|
|
})
|
|
it('should refrain from comparing if no metadata on both items', () => {
|
|
// given
|
|
const itemA: Partial<FolderItemForSorting> = {
|
|
sortString: 'ccc'
|
|
}
|
|
const itemB: Partial<FolderItemForSorting> = {
|
|
sortString: 'ccc '
|
|
}
|
|
const sorter: SorterFn = getSorterFnFor(CustomSortOrder.byMetadataFieldAlphabeticalReverse)
|
|
|
|
// when
|
|
const result1: number = sorter(itemA as FolderItemForSorting, itemB as FolderItemForSorting)
|
|
const result2: number = sorter(itemB as FolderItemForSorting, itemA as FolderItemForSorting)
|
|
const result3: number = sorter(itemB as FolderItemForSorting, itemB as FolderItemForSorting)
|
|
|
|
// then
|
|
expect(result1).toBe(EQUAL_OR_UNCOMPARABLE)
|
|
expect(result2).toBe(EQUAL_OR_UNCOMPARABLE)
|
|
expect(result3).toBe(EQUAL_OR_UNCOMPARABLE)
|
|
})
|
|
})
|
|
|
|
describe('sorterByMetadataField', () => {
|
|
it.each([
|
|
[true,'abc','def',-1, 'a', 'a'],
|
|
[true,'xyz','klm',1, 'b', 'b'],
|
|
[true,'mmm','mmm',EQUAL_OR_UNCOMPARABLE, 'c', 'c'],
|
|
[true,'mmm','mmm',EQUAL_OR_UNCOMPARABLE, 'd', 'e'],
|
|
[true,'mmm','mmm',EQUAL_OR_UNCOMPARABLE, 'e', 'd'],
|
|
[true,'abc',undefined,-1, 'a','a'],
|
|
[true,undefined,'klm',1, 'b','b'],
|
|
[true,undefined,undefined,EQUAL_OR_UNCOMPARABLE, 'a','a'],
|
|
[true,undefined,undefined,EQUAL_OR_UNCOMPARABLE, 'a','b'],
|
|
[true,undefined,undefined,EQUAL_OR_UNCOMPARABLE, 'd','c'],
|
|
[false,'abc','def',1, 'a', 'a'],
|
|
[false,'xyz','klm',-1, 'b', 'b'],
|
|
[false,'mmm','mmm',EQUAL_OR_UNCOMPARABLE, 'c', 'c'],
|
|
[false,'mmm','mmm',EQUAL_OR_UNCOMPARABLE, 'd', 'e'],
|
|
[false,'mmm','mmm',EQUAL_OR_UNCOMPARABLE, 'e', 'd'],
|
|
[false,'abc',undefined,1, 'a','a'],
|
|
[false,undefined,'klm',-1, 'b','b'],
|
|
[false,undefined,undefined,EQUAL_OR_UNCOMPARABLE, 'a','a'],
|
|
[false,undefined,undefined,EQUAL_OR_UNCOMPARABLE, 'a','b'],
|
|
[false,undefined,undefined,EQUAL_OR_UNCOMPARABLE, 'd','c'],
|
|
|
|
])('straight order %s, comparing %s and %s should return %s for sortStrings %s and %s',
|
|
(straight: boolean, metadataA: string|undefined, metadataB: string|undefined, order: number, sortStringA: string, sortStringB) => {
|
|
const sorterFn = sorterByMetadataField(!straight, false)
|
|
const itemA: Partial<FolderItemForSorting> = {metadataFieldValue: metadataA, sortString: sortStringA}
|
|
const itemB: Partial<FolderItemForSorting> = {metadataFieldValue: metadataB, sortString: sortStringB}
|
|
const result = sorterFn(itemA as FolderItemForSorting, itemB as FolderItemForSorting)
|
|
|
|
// then
|
|
expect(result).toBe(order)
|
|
})
|
|
})
|
|
|
|
describe('sorterByBookmarkOrder', () => {
|
|
it.each([
|
|
[true,10,20,-1, 'a', 'a'],
|
|
[true,20,10,1, 'b', 'b'],
|
|
[true,30,30,0, 'c', 'c'], // not possible in reality - each bookmark order is unique by definition - covered for clarity
|
|
[true,1,1,0, 'd', 'e'], // ----//----
|
|
[true,2,2,0, 'e', 'd'], // ----//----
|
|
[true,3,undefined,-1, 'a','a'],
|
|
[true,undefined,4,1, 'b','b'],
|
|
[true,undefined,undefined,0, 'a','a'],
|
|
[true,undefined,undefined,-1, 'a','b'],
|
|
[true,undefined,undefined,1, 'd','c'],
|
|
[false,10,20,1, 'a', 'a'],
|
|
[false,20,10,-1, 'b', 'b'],
|
|
[false,30,30,0, 'c', 'c'], // not possible in reality - each bookmark order is unique by definition - covered for clarity
|
|
[false,1,1,0, 'd', 'e'], // ------//-----
|
|
[false,2,2,0, 'e', 'd'], // ------//-----
|
|
[false,3,undefined,1, 'a','a'],
|
|
[false,undefined,4,-1, 'b','b'],
|
|
[false,undefined,undefined,0, 'a','a'],
|
|
[false,undefined,undefined,1, 'a','b'],
|
|
[false,undefined,undefined,-1, 'd','c'],
|
|
|
|
])('straight order %s, comparing %s and %s should return %s for sortStrings %s and %s',
|
|
(straight: boolean, bookmarkA: number|undefined, bookmarkB: number|undefined, order: number, sortStringA: string, sortStringB) => {
|
|
const sorterFn = sorterByBookmarkOrder(!straight, false)
|
|
const itemA: Partial<FolderItemForSorting> = {bookmarkedIdx: bookmarkA, sortString: sortStringA}
|
|
const itemB: Partial<FolderItemForSorting> = {bookmarkedIdx: bookmarkB, sortString: sortStringB}
|
|
const result = sorterFn(itemA as FolderItemForSorting, itemB as FolderItemForSorting)
|
|
const normalizedResult = result < 0 ? -1 : ((result > 0) ? 1 : result)
|
|
|
|
// then
|
|
expect(normalizedResult).toBe(order)
|
|
})
|
|
})
|