diff options
Diffstat (limited to 'test')
35 files changed, 1335 insertions, 1137 deletions
diff --git a/test/lib/composite.js b/test/lib/composite.js new file mode 100644 index 00000000..359d364d --- /dev/null +++ b/test/lib/composite.js @@ -0,0 +1,33 @@ +import {compositeFrom} from '#composite'; + +export function quickCheckCompositeOutputs(t, dependencies) { + return (step, outputDict) => { + t.same( + Object.keys(step.toDescription().outputs), + Object.keys(outputDict)); + + const composite = compositeFrom({ + compose: false, + steps: [ + step, + + { + dependencies: Object.keys(outputDict), + + // Access all dependencies by their expected keys - + // the composition runner actually provides a proxy + // and is checking that *we* access the dependencies + // we've specified. + compute: dependencies => + Object.fromEntries( + Object.keys(outputDict) + .map(key => [key, dependencies[key]])), + }, + ], + }); + + t.same( + composite.expose.compute(dependencies), + outputDict); + }; +} diff --git a/test/lib/content-function.js b/test/lib/content-function.js index 7bc62139..a46d18c9 100644 --- a/test/lib/content-function.js +++ b/test/lib/content-function.js @@ -17,8 +17,23 @@ import mock from './generic-mock.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); +function cleanURLSpec(reference) { + const prepared = structuredClone(reference); + + for (const spec of Object.values(prepared)) { + if (spec.prefix) { + // Strip out STATIC_VERSION. This updates fairly regularly and we + // don't want it to affect snapshot tests. + spec.prefix = spec.prefix + .replace(/static-\d+[a-z]\d+/i, 'static'); + } + } + + return prepared; +} + export function testContentFunctions(t, message, fn) { - const urls = generateURLs(urlSpec); + const urls = generateURLs(cleanURLSpec(urlSpec)); t.test(message, async t => { let loadedContentDependencies; @@ -52,7 +67,6 @@ export function testContentFunctions(t, message, fn) { to, urls, - cachebust: 413, pagePath: ['home'], appendIndexHTML: false, getColors: c => getColors(c, {chroma}), diff --git a/test/lib/index.js b/test/lib/index.js index 5fb5bf78..4c9ee23f 100644 --- a/test/lib/index.js +++ b/test/lib/index.js @@ -1,5 +1,6 @@ Error.stackTraceLimit = Infinity; +export * from './composite.js'; export * from './content-function.js'; export * from './generic-mock.js'; export * from './wiki-data.js'; diff --git a/test/lib/wiki-data.js b/test/lib/wiki-data.js index d2d860ce..7c3d2147 100644 --- a/test/lib/wiki-data.js +++ b/test/lib/wiki-data.js @@ -1,6 +1,8 @@ import CacheableObject from '#cacheable-object'; import find from '#find'; import {withEntries} from '#sugar'; +import Thing from '#thing'; +import thingConstructors from '#things'; import {linkWikiDataArrays} from '#yaml'; export function linkAndBindWikiData(wikiData, { @@ -12,23 +14,6 @@ export function linkAndBindWikiData(wikiData, { ? withEntries(wikiData, entries => entries .map(([key, value]) => [key, value.slice()])) : wikiData)); - - // If albumData is present, automatically set albums' ownTrackData values - // by resolving track sections' references against the full array. This is - // just a nicety for working with albums throughout tests. - if (inferAlbumsOwnTrackData && wikiData.albumData && wikiData.trackData) { - for (const album of wikiData.albumData) { - const trackSections = - CacheableObject.getUpdateValue(album, 'trackSections'); - - const trackRefs = - trackSections.flatMap(section => section.tracks); - - album.ownTrackData = - trackRefs.map(ref => - find.track(ref, wikiData.trackData, {mode: 'error'})); - } - } } customLinkWikiDataArrays(wikiData); @@ -70,3 +55,99 @@ export function linkAndBindWikiData(wikiData, { .bind(null, wikiData, {XXX_decacheWikiData: true}), }; } + +export function stubWikiData() { + return { + albumData: [], + artistData: [], + artTagData: [], + flashData: [], + flashActData: [], + flashSideData: [], + groupData: [], + groupCategoryData: [], + newsData: [], + staticPageData: [], + trackData: [], + trackSectionData: [], + }; +} + +export function stubThing(wikiData, constructor, properties = {}) { + const thing = Reflect.construct(constructor, []); + Object.assign(thing, properties); + + const wikiDataSpec = { + Album: 'albumData', + Artist: 'artistData', + ArtTag: 'artTagData', + Flash: 'flashData', + FlashAct: 'flashActData', + FlashSide: 'flashSideData', + Group: 'groupData', + GroupCategory: 'groupCategoryData', + NewsEntry: 'newsData', + StaticPage: 'staticPageData', + Track: 'trackData', + TrackSection: 'trackSectionData', + }; + + const wikiDataMap = + new Map( + Object.entries(wikiDataSpec) + .map(([thingKey, wikiDataKey]) => [ + thingConstructors[thingKey], + wikiData[wikiDataKey], + ])); + + const wikiDataArray = + wikiDataMap.get(constructor); + + wikiDataArray.push(thing); + + return thing; +} + +export function stubTrackAndAlbum(wikiData, trackDirectory = null, albumDirectory = null) { + const {Track, TrackSection, Album} = thingConstructors; + + const track = + stubThing(wikiData, Track, {directory: trackDirectory}); + + const section = + stubThing(wikiData, TrackSection, {tracks: [track]}); + + const album = + stubThing(wikiData, Album, {directory: albumDirectory, trackSections: [section]}); + + return {track, album, section}; +} + +export function stubArtistAndContribs(wikiData, artistName = `Test Artist`) { + const {Artist} = thingConstructors; + + const artist = + stubThing(wikiData, Artist, {name: artistName}); + + const contribs = + [{artist: artistName, annotation: null}]; + + const badContribs = + [{artist: `Figment of Your Imagination`, annotation: null}]; + + return {artist, contribs, badContribs}; +} + +export function stubFlashAndAct(wikiData, flashDirectory = null) { + const {Flash, FlashAct} = thingConstructors; + + const flash = + stubThing(wikiData, Flash, {directory: flashDirectory}); + + const flashAct = + stubThing(wikiData, FlashAct, { + flashes: [Thing.getReference(flash)], + }); + + return {flash, flashAct}; +} diff --git a/test/snapshot/generateAdditionalFilesList.js b/test/snapshot/generateAdditionalFilesList.js deleted file mode 100644 index 3ea1c37e..00000000 --- a/test/snapshot/generateAdditionalFilesList.js +++ /dev/null @@ -1,64 +0,0 @@ -import t from 'tap'; -import {testContentFunctions} from '#test-lib'; - -testContentFunctions(t, 'generateAdditionalFilesList (snapshot)', async (t, evaluate) => { - await evaluate.load(); - - evaluate.snapshot('no additional files', { - name: 'generateAdditionalFilesList', - args: [[]], - }); - - evaluate.snapshot('basic behavior', { - name: 'generateAdditionalFilesList', - args: [ - [ - { - title: 'SBURB Wallpaper', - files: [ - 'sburbwp_1280x1024.jpg', - 'sburbwp_1440x900.jpg', - 'sburbwp_1920x1080.jpg', - ], - }, - { - title: 'Fake Section', - description: 'Ooo, what happens if there are NO file links provided?', - files: [ - 'oops.mp3', - 'Internet Explorer.gif', - 'daisy.mp3', - ], - }, - { - title: 'Alternate Covers', - description: 'This is just an example description.', - files: [ - 'Homestuck_Vol4_alt1.jpg', - 'Homestuck_Vol4_alt2.jpg', - 'Homestuck_Vol4_alt3.jpg', - ], - }, - ], - ], - slots: { - fileLinks: { - 'sburbwp_1280x1024.jpg': 'link to 1280x1024', - 'sburbwp_1440x900.jpg': 'link to 1440x900', - 'sburbwp_1920x1080.jpg': null, - 'Homestuck_Vol4_alt1.jpg': 'link to alt1', - 'Homestuck_Vol4_alt2.jpg': null, - 'Homestuck_Vol4_alt3.jpg': 'link to alt3', - }, - fileSizes: { - 'sburbwp_1280x1024.jpg': 2500, - 'sburbwp_1440x900.jpg': null, - 'sburbwp_1920x1080.jpg': null, - 'Internet Explorer.gif': 1, - 'Homestuck_Vol4_alt1.jpg': 1234567, - 'Homestuck_Vol4_alt2.jpg': 1234567, - 'Homestuck_Vol4_alt3.jpg': 1234567, - } - }, - }); -}); diff --git a/test/snapshot/generateAdditionalFilesShortcut.js b/test/snapshot/generateAdditionalFilesShortcut.js deleted file mode 100644 index 9825efa1..00000000 --- a/test/snapshot/generateAdditionalFilesShortcut.js +++ /dev/null @@ -1,36 +0,0 @@ -import t from 'tap'; -import {testContentFunctions} from '#test-lib'; - -testContentFunctions(t, 'generateAdditionalFilesShortcut (snapshot)', async (t, evaluate) => { - await evaluate.load(); - - evaluate.snapshot('no additional files', { - name: 'generateAdditionalFilesShortcut', - args: [[]], - }); - - evaluate.snapshot('basic behavior', { - name: 'generateAdditionalFilesShortcut', - args: [ - [ - { - title: 'SBURB Wallpaper', - files: [ - 'sburbwp_1280x1024.jpg', - 'sburbwp_1440x900.jpg', - 'sburbwp_1920x1080.jpg', - ], - }, - { - title: 'Alternate Covers', - description: 'This is just an example description.', - files: [ - 'Homestuck_Vol4_alt1.jpg', - 'Homestuck_Vol4_alt2.jpg', - 'Homestuck_Vol4_alt3.jpg', - ], - }, - ], - ], - }); -}); diff --git a/test/snapshot/generateAlbumCoverArtwork.js b/test/snapshot/generateAlbumCoverArtwork.js deleted file mode 100644 index 9244c034..00000000 --- a/test/snapshot/generateAlbumCoverArtwork.js +++ /dev/null @@ -1,36 +0,0 @@ -import t from 'tap'; - -import contentFunction from '#content-function'; -import {testContentFunctions} from '#test-lib'; - -testContentFunctions(t, 'generateAlbumCoverArtwork (snapshot)', async (t, evaluate) => { - await evaluate.load({ - mock: { - image: evaluate.stubContentFunction('image'), - }, - }); - - const album = { - directory: 'bee-forus-seatbelt-safebee', - coverArtFileExtension: 'png', - color: '#f28514', - artTags: [ - {name: 'Damara', directory: 'damara', isContentWarning: false}, - {name: 'Cronus', directory: 'cronus', isContentWarning: false}, - {name: 'Bees', directory: 'bees', isContentWarning: false}, - {name: 'creepy crawlies', isContentWarning: true}, - ], - }; - - evaluate.snapshot('display: primary', { - name: 'generateAlbumCoverArtwork', - args: [album], - slots: {mode: 'primary'}, - }); - - evaluate.snapshot('display: thumbnail', { - name: 'generateAlbumCoverArtwork', - args: [album], - slots: {mode: 'thumbnail'}, - }); -}); diff --git a/test/snapshot/generateAlbumReleaseInfo.js b/test/snapshot/generateAlbumReleaseInfo.js index 3dea1196..f41e502d 100644 --- a/test/snapshot/generateAlbumReleaseInfo.js +++ b/test/snapshot/generateAlbumReleaseInfo.js @@ -8,22 +8,22 @@ testContentFunctions(t, 'generateAlbumReleaseInfo (snapshot)', async (t, evaluat name: 'generateAlbumReleaseInfo', args: [{ artistContribs: [ - {who: {name: 'Toby Fox', directory: 'toby-fox', urls: null}, what: 'music probably'}, - {who: {name: 'Tensei', directory: 'tensei', urls: ['https://tenseimusic.bandcamp.com/']}, what: 'hot jams'}, + {artist: {name: 'Toby Fox', directory: 'toby-fox', urls: []}, annotation: 'music probably'}, + {artist: {name: 'Tensei', directory: 'tensei', urls: ['https://tenseimusic.bandcamp.com/']}, annotation: 'hot jams'}, ], coverArtistContribs: [ - {who: {name: 'Hanni Brosh', directory: 'hb', urls: null}, what: null}, + {artist: {name: 'Hanni Brosh', directory: 'hb', urls: []}, annotation: null}, ], wallpaperArtistContribs: [ - {who: {name: 'Hanni Brosh', directory: 'hb', urls: null}, what: null}, - {who: {name: 'Niklink', directory: 'niklink', urls: null}, what: 'edits'}, + {artist: {name: 'Hanni Brosh', directory: 'hb', urls: []}, annotation: null}, + {artist: {name: 'Niklink', directory: 'niklink', urls: []}, annotation: 'edits'}, ], bannerArtistContribs: [ - {who: {name: 'Hanni Brosh', directory: 'hb', urls: null}, what: null}, - {who: {name: 'Niklink', directory: 'niklink', urls: null}, what: 'edits'}, + {artist: {name: 'Hanni Brosh', directory: 'hb', urls: []}, annotation: null}, + {artist: {name: 'Niklink', directory: 'niklink', urls: []}, annotation: 'edits'}, ], name: 'AlterniaBound', diff --git a/test/snapshot/generateAlbumSecondaryNav.js b/test/snapshot/generateAlbumSecondaryNav.js index 709b062e..2495bc4a 100644 --- a/test/snapshot/generateAlbumSecondaryNav.js +++ b/test/snapshot/generateAlbumSecondaryNav.js @@ -4,25 +4,60 @@ import {testContentFunctions} from '#test-lib'; testContentFunctions(t, 'generateAlbumSecondaryNav (snapshot)', async (t, evaluate) => { await evaluate.load(); - let album, group1, group2; + let album, anotherAlbum, group1, group2; - group1 = {name: 'VCG', directory: 'vcg', color: '#abcdef'}; - group2 = {name: 'Bepis', directory: 'bepis', color: '#123456'}; + group1 = { + name: 'VCG', + directory: 'vcg', + color: '#abcdef', + serieses: [], + }; + + group2 = { + name: 'Bepis', + directory: 'bepis', + color: '#123456', + serieses: [], + }; album = { + name: 'Album', + directory: 'album', date: new Date('2010-04-13'), groups: [group1, group2], }; + anotherAlbum = { + name: 'Last', + directory: 'last', + date: new Date('2010-06-12'), + }; + group1.albums = [ - {name: 'First', directory: 'first', date: new Date('2010-04-10')}, + { + name: 'First', + directory: 'first', + date: new Date('2010-04-10'), + }, album, - {name: 'Last', directory: 'last', date: new Date('2010-06-12')}, + anotherAlbum, + ]; + + group1.serieses = [ + { + name: 'Series', + albums: [album, anotherAlbum], + group: group1, + }, ]; group2.albums = [ album, - {name: 'Second', directory: 'second', date: new Date('2011-04-13')}, + { + name: 'Second', + directory: 'second', + date: new Date('2011-04-13'), + }, ]; evaluate.snapshot('basic behavior, mode: album', { diff --git a/test/snapshot/generateAlbumSidebarGroupBox.js b/test/snapshot/generateAlbumSidebarGroupBox.js index 87850510..f920bd96 100644 --- a/test/snapshot/generateAlbumSidebarGroupBox.js +++ b/test/snapshot/generateAlbumSidebarGroupBox.js @@ -11,6 +11,8 @@ testContentFunctions(t, 'generateAlbumSidebarGroupBox (snapshot)', async (t, eva let album, group; album = { + name: 'Middle', + directory: 'middle', date: new Date('2010-04-13'), }; diff --git a/test/snapshot/generateAlbumTrackList.js b/test/snapshot/generateAlbumTrackList.js index 181cc1d2..e09f1c4a 100644 --- a/test/snapshot/generateAlbumTrackList.js +++ b/test/snapshot/generateAlbumTrackList.js @@ -6,16 +6,20 @@ testContentFunctions(t, 'generateAlbumTrackList (snapshot)', async (t, evaluate) mock: { generateAlbumTrackListMissingDuration: evaluate.stubContentFunction('generateAlbumTrackListMissingDuration'), + + image: + evaluate.stubContentFunction('image'), }, }); const contribs1 = [ - {who: {name: 'Apricot', directory: 'apricot', urls: null}}, + {artist: {name: 'Apricot', directory: 'apricot', urls: []}}, ]; const contribs2 = [ - {who: {name: 'Apricot', directory: 'apricot', urls: null}}, - {who: {name: 'Peach', directory: 'peach', urls: ['https://peach.bandcamp.com/']}}, + {artist: {name: 'Apricot', directory: 'apricot', urls: []}}, + {artist: {name: 'Peach', directory: 'peach', urls: ['https://peach.bandcamp.com/']}}, + {artist: {name: 'Cerise', directory: 'cerise', urls: []}}, ]; const color1 = '#fb07ff'; @@ -45,6 +49,16 @@ testContentFunctions(t, 'generateAlbumTrackList (snapshot)', async (t, evaluate) tracks, }; + const albumWithTrackSectionDescriptions = { + color: color1, + artistContribs: contribs1, + trackSections: [ + {name: 'First section', tracks: tracks.slice(0, 3), description: `Why yes!`}, + {name: 'Second section', tracks: tracks.slice(3), description: `How *contentful,* this is.`}, + ], + tracks, + }; + const albumWithNoDuration = { color: color1, artistContribs: contribs1, @@ -62,6 +76,11 @@ testContentFunctions(t, 'generateAlbumTrackList (snapshot)', async (t, evaluate) args: [albumWithoutTrackSections], }); + evaluate.snapshot(`basic behavior, with descriptions`, { + name: 'generateAlbumTrackList', + args: [albumWithTrackSectionDescriptions], + }); + evaluate.snapshot(`collapseDurationScope: never`, { name: 'generateAlbumTrackList', slots: {collapseDurationScope: 'never'}, diff --git a/test/snapshot/generateCoverArtwork.js b/test/snapshot/generateCoverArtwork.js deleted file mode 100644 index e35dd8d0..00000000 --- a/test/snapshot/generateCoverArtwork.js +++ /dev/null @@ -1,31 +0,0 @@ -import t from 'tap'; -import {testContentFunctions} from '#test-lib'; - -testContentFunctions(t, 'generateCoverArtwork (snapshot)', async (t, evaluate) => { - await evaluate.load({ - mock: { - image: evaluate.stubContentFunction('image', {mock: true}), - }, - }); - - const artTags = [ - {name: 'Damara', directory: 'damara', isContentWarning: false}, - {name: 'Cronus', directory: 'cronus', isContentWarning: false}, - {name: 'Bees', directory: 'bees', isContentWarning: false}, - {name: 'creepy crawlies', isContentWarning: true}, - ]; - - const path = ['media.albumCover', 'bee-forus-seatbelt-safebee', 'png']; - - evaluate.snapshot('display: primary', { - name: 'generateCoverArtwork', - args: [artTags], - slots: {path, mode: 'primary'}, - }); - - evaluate.snapshot('display: thumbnail', { - name: 'generateCoverArtwork', - args: [artTags], - slots: {path, mode: 'thumbnail'}, - }); -}); diff --git a/test/snapshot/generatePreviousNextLinks.js b/test/snapshot/generatePreviousNextLinks.js deleted file mode 100644 index 0d952f59..00000000 --- a/test/snapshot/generatePreviousNextLinks.js +++ /dev/null @@ -1,35 +0,0 @@ -import t from 'tap'; -import * as html from '#html'; -import {testContentFunctions} from '#test-lib'; - -testContentFunctions(t, 'generatePreviousNextLinks (snapshot)', async (t, evaluate) => { - await evaluate.load(); - - const quickSnapshot = (message, slots) => - evaluate.snapshot(message, { - name: 'generatePreviousNextLinks', - slots, - postprocess: template => template.content.join('\n'), - }); - - quickSnapshot('basic behavior', { - previousLink: evaluate.stubTemplate('previous'), - nextLink: evaluate.stubTemplate('next'), - }); - - quickSnapshot('previous missing', { - nextLink: evaluate.stubTemplate('next'), - }); - - quickSnapshot('next missing', { - previousLink: evaluate.stubTemplate('previous'), - }); - - quickSnapshot('neither link present', {}); - - quickSnapshot('disable id', { - previousLink: evaluate.stubTemplate('previous'), - nextLink: evaluate.stubTemplate('next'), - id: false, - }); -}); diff --git a/test/snapshot/generateTrackAdditionalNamesBox.js b/test/snapshot/generateTrackAdditionalNamesBox.js deleted file mode 100644 index 9c1e3598..00000000 --- a/test/snapshot/generateTrackAdditionalNamesBox.js +++ /dev/null @@ -1,107 +0,0 @@ -import t from 'tap'; - -import contentFunction from '#content-function'; -import {testContentFunctions} from '#test-lib'; - -testContentFunctions(t, 'generateTrackAdditionalNamesBox (snapshot)', async (t, evaluate) => { - await evaluate.load({ - mock: { - generateAdditionalNamesBox: - evaluate.stubContentFunction('generateAdditionalNamesBox'), - }, - }); - - const stubTrack = { - additionalNames: [], - sharedAdditionalNames: [], - inferredAdditionalNames: [], - }; - - const quickSnapshot = (message, trackProperties) => - evaluate.snapshot(message, { - name: 'generateTrackAdditionalNamesBox', - args: [{...stubTrack, ...trackProperties}], - }); - - quickSnapshot(`no additional names`, {}); - - quickSnapshot(`own additional names only`, { - additionalNames: [ - {name: `Foo Bar`, annotation: `the Alps`}, - ], - }); - - quickSnapshot(`shared additional names only`, { - sharedAdditionalNames: [ - {name: `Bar Foo`, annotation: `the Rockies`}, - ], - }); - - quickSnapshot(`inferred additional names only`, { - inferredAdditionalNames: [ - {name: `Baz Baz`, from: [{directory: `the-pyrenees`}]}, - ], - }); - - quickSnapshot(`multiple own`, { - additionalNames: [ - {name: `Apple Time!`}, - {name: `Pterodactyl Time!`}, - {name: `Banana Time!`}, - ], - }); - - quickSnapshot(`own and shared, some overlap`, { - additionalNames: [ - {name: `weed dreams..`, annotation: `own annotation`}, - {name: `夜間のMOON汗`, annotation: `own annotation`}, - ], - sharedAdditionalNames: [ - {name: `weed dreams..`, annotation: `shared annotation`}, - {name: `GAMINGブラザー96`, annotation: `shared annotation`}, - ], - }); - - quickSnapshot(`shared and inferred, some overlap`, { - sharedAdditionalNames: [ - {name: `Coruscate`, annotation: `shared annotation`}, - {name: `Arbroath`, annotation: `shared annotation`}, - ], - inferredAdditionalNames: [ - {name: `Arbroath`, from: [{directory: `inferred-from`}]}, - {name: `Prana Ferox`, from: [{directory: `inferred-from`}]}, - ], - }); - - quickSnapshot(`own and inferred, some overlap`, { - additionalNames: [ - {name: `Ke$halo Strike Back`, annotation: `own annotation`}, - {name: `Ironic Mania`, annotation: `own annotation`}, - ], - inferredAdditionalNames: [ - {name: `Ironic Mania`, from: [{directory: `inferred-from`}]}, - {name: `ANARCHY::MEGASTRIFE`, from: [{directory: `inferred-from`}]}, - ], - }); - - quickSnapshot(`own and shared and inferred, various overlap`, { - additionalNames: [ - {name: `Own!`, annotation: `own annotation`}, - {name: `Own! Shared!`, annotation: `own annotation`}, - {name: `Own! Inferred!`, annotation: `own annotation`}, - {name: `Own! Shared! Inferred!`, annotation: `own annotation`}, - ], - sharedAdditionalNames: [ - {name: `Shared!`, annotation: `shared annotation`}, - {name: `Own! Shared!`, annotation: `shared annotation`}, - {name: `Shared! Inferred!`, annotation: `shared annotation`}, - {name: `Own! Shared! Inferred!`, annotation: `shared annotation`}, - ], - inferredAdditionalNames: [ - {name: `Inferred!`, from: [{directory: `inferred-from`}]}, - {name: `Own! Inferred!`, from: [{directory: `inferred-from`}]}, - {name: `Shared! Inferred!`, from: [{directory: `inferred-from`}]}, - {name: `Own! Shared! Inferred!`, from: [{directory: `inferred-from`}]}, - ], - }); -}); diff --git a/test/snapshot/generateTrackCoverArtwork.js b/test/snapshot/generateTrackCoverArtwork.js deleted file mode 100644 index 1e651eb1..00000000 --- a/test/snapshot/generateTrackCoverArtwork.js +++ /dev/null @@ -1,61 +0,0 @@ -import t from 'tap'; -import {testContentFunctions} from '#test-lib'; - -testContentFunctions(t, 'generateTrackCoverArtwork (snapshot)', async (t, evaluate) => { - await evaluate.load({ - mock: { - image: evaluate.stubContentFunction('image'), - }, - }); - - const album = { - directory: 'bee-forus-seatbelt-safebee', - coverArtFileExtension: 'png', - artTags: [ - {name: 'Damara', directory: 'damara', isContentWarning: false}, - {name: 'Cronus', directory: 'cronus', isContentWarning: false}, - {name: 'Bees', directory: 'bees', isContentWarning: false}, - {name: 'creepy crawlies', isContentWarning: true}, - ], - }; - - const track1 = { - directory: 'beesmp3', - hasUniqueCoverArt: true, - coverArtFileExtension: 'jpg', - color: '#f28514', - artTags: [{name: 'Bees', directory: 'bees', isContentWarning: false}], - album, - }; - - const track2 = { - directory: 'fake-bonus-track', - hasUniqueCoverArt: false, - color: '#abcdef', - album, - }; - - evaluate.snapshot('display: primary - unique art', { - name: 'generateTrackCoverArtwork', - args: [track1], - slots: {mode: 'primary'}, - }); - - evaluate.snapshot('display: thumbnail - unique art', { - name: 'generateTrackCoverArtwork', - args: [track1], - slots: {mode: 'thumbnail'}, - }); - - evaluate.snapshot('display: primary - no unique art', { - name: 'generateTrackCoverArtwork', - args: [track2], - slots: {mode: 'primary'}, - }); - - evaluate.snapshot('display: thumbnail - no unique art', { - name: 'generateTrackCoverArtwork', - args: [track2], - slots: {mode: 'thumbnail'}, - }); -}); diff --git a/test/snapshot/generateTrackReleaseInfo.js b/test/snapshot/generateTrackReleaseInfo.js index c72344b9..931377c8 100644 --- a/test/snapshot/generateTrackReleaseInfo.js +++ b/test/snapshot/generateTrackReleaseInfo.js @@ -4,8 +4,8 @@ import {testContentFunctions} from '#test-lib'; testContentFunctions(t, 'generateTrackReleaseInfo (snapshot)', async (t, evaluate) => { await evaluate.load(); - const artistContribs = [{who: {name: 'Toby Fox', directory: 'toby-fox', urls: null}, what: null}]; - const coverArtistContribs = [{who: {name: 'Alpaca', directory: 'alpaca', urls: null}, what: '🔥'}]; + const artistContribs = [{artist: {name: 'Toby Fox', directory: 'toby-fox', urls: []}, annotation: null}]; + const coverArtistContribs = [{artist: {name: 'Alpaca', directory: 'alpaca', urls: []}, annotation: '🔥'}]; evaluate.snapshot('basic behavior', { name: 'generateTrackReleaseInfo', diff --git a/test/snapshot/image.js b/test/snapshot/image.js index 447e7fa7..1985211f 100644 --- a/test/snapshot/image.js +++ b/test/snapshot/image.js @@ -38,11 +38,10 @@ testContentFunctions(t, 'image (snapshot)', async (t, evaluate) => { }, }); - quickSnapshot('width & height', { + quickSnapshot('dimensions', { slots: { src: 'foobar', - width: 600, - height: 400, + dimensions: [600, 400], }, }); @@ -53,6 +52,14 @@ testContentFunctions(t, 'image (snapshot)', async (t, evaluate) => { }, }); + quickSnapshot('dimensions with square', { + slots: { + src: 'foobar', + dimensions: [600, 400], + square: true, + }, + }); + quickSnapshot('lazy with square', { slots: { src: 'foobar', diff --git a/test/snapshot/linkContribution.js b/test/snapshot/linkContribution.js index ebd3be58..47ef1503 100644 --- a/test/snapshot/linkContribution.js +++ b/test/snapshot/linkContribution.js @@ -9,80 +9,49 @@ testContentFunctions(t, 'linkContribution (snapshot)', async (t, evaluate) => { name: 'linkContribution', multiple: [ {args: [ - {who: { + {artist: { name: 'Clark Powell', directory: 'clark-powell', urls: ['https://soundcloud.com/plazmataz'], - }, what: null}, + }, annotation: null}, ]}, {args: [ - {who: { + {artist: { name: 'Grounder & Scratch', directory: 'the-big-baddies', urls: [], - }, what: 'Snooping'}, + }, annotation: 'Snooping'}, ]}, {args: [ - {who: { + {artist: { name: 'Toby Fox', directory: 'toby-fox', urls: ['https://tobyfox.bandcamp.com/', 'https://toby.fox/'], - }, what: 'Arrangement'}, + }, annotation: 'Arrangement'}, ]}, ], slots, }); - quickSnapshot('showContribution & showIcons (inline)', { - showContribution: true, - showIcons: true, - iconMode: 'inline', + quickSnapshot('showAnnotation & showExternalLinks', { + showAnnotation: true, + showExternalLinks: true, }); - quickSnapshot('showContribution & showIcons (tooltip)', { - showContribution: true, - showIcons: true, - iconMode: 'tooltip', + quickSnapshot('only showAnnotation', { + showAnnotation: true, }); - quickSnapshot('only showContribution', { - showContribution: true, - }); - - quickSnapshot('only showIcons (inline)', { - showIcons: true, - iconMode: 'inline', - }); - - quickSnapshot('only showIcons (tooltip)', { - showContribution: true, - showIcons: true, - iconMode: 'tooltip', + quickSnapshot('only showExternalLinks', { + showExternalLinks: true, }); quickSnapshot('no accents', {}); - evaluate.snapshot('loads of links (inline)', { - name: 'linkContribution', - args: [ - {who: {name: 'Lorem Ipsum Lover', directory: 'lorem-ipsum-lover', urls: [ - 'https://loremipsum.io', - 'https://loremipsum.io/generator/', - 'https://loremipsum.io/#meaning', - 'https://loremipsum.io/#usage-and-examples', - 'https://loremipsum.io/#controversy', - 'https://loremipsum.io/#when-to-use-lorem-ipsum', - 'https://loremipsum.io/#lorem-ipsum-all-the-things', - 'https://loremipsum.io/#original-source', - ]}, what: null}, - ], - slots: {showIcons: true}, - }); - - evaluate.snapshot('loads of links (tooltip)', { + evaluate.snapshot('loads of links', { name: 'linkContribution', args: [ - {who: {name: 'Lorem Ipsum Lover', directory: 'lorem-ipsum-lover', urls: [ + {artist: {name: 'Lorem Ipsum Lover', directory: 'lorem-ipsum-lover', urls: [ 'https://loremipsum.io', 'https://loremipsum.io/generator/', 'https://loremipsum.io/#meaning', @@ -91,14 +60,14 @@ testContentFunctions(t, 'linkContribution (snapshot)', async (t, evaluate) => { 'https://loremipsum.io/#when-to-use-lorem-ipsum', 'https://loremipsum.io/#lorem-ipsum-all-the-things', 'https://loremipsum.io/#original-source', - ]}, what: null}, + ]}, annotation: null}, ], - slots: {showIcons: true, iconMode: 'tooltip'}, + slots: {showExternalLinks: true}, }); quickSnapshot('no preventWrapping', { - showContribution: true, - showIcons: true, + showAnnotation: true, + showExternalLinks: true, preventWrapping: false, }); }); diff --git a/test/snapshot/linkExternal.js b/test/snapshot/linkExternal.js index f4138630..90c98f4b 100644 --- a/test/snapshot/linkExternal.js +++ b/test/snapshot/linkExternal.js @@ -20,35 +20,174 @@ testContentFunctions(t, 'linkExternal (snapshot)', async (t, evaluate) => { }); const quickSnapshotAllStyles = (context, urls) => { - for (const style of ['platform', 'normal', 'compact']) { + for (const style of ['platform', 'handle']) { const message = `context: ${context}, style: ${style}`; quickSnapshot(message, urls, {context, style}); } }; + // Try to comprehensively test every regular expression + // (in `match` and extractions like `handle` or `details`). + + // Try to *also* represent a reasonable variety of what kinds + // of URLs appear throughout the wiki. (This should serve to + // identify areas which #external-links is expected to + // accommodate, regardless whether or not there is special + // attention given in the actual descriptors.) + + // For normal custom-domain matches (e.g. Mastodon), + // it's OK to just test one custom domain in the list. + + // Generally match the sorting order in externalLinkSpec, + // so corresponding and missing test cases are easy to locate. + quickSnapshotAllStyles('generic', [ + // platform: appleMusic + 'https://music.apple.com/us/artist/system-of-a-down/462715', + + // platform: artstation + 'https://www.artstation.com/eevaningtea', + 'https://witnesstheabsurd.artstation.com/', + + // platform: bandcamp + 'https://music.solatrus.com/', 'https://homestuck.bandcamp.com/', - 'https://soundcloud.com/plazmataz', - 'https://aeritus.tumblr.com/', - 'https://twitter.com/awkwarddoesart', + + // platform: bluesky + 'https://bsky.app/profile/jacobtheloofah.bsky.social', + + // platform: carrd + 'https://aliceflare.carrd.co', + 'https://bigchaslappa.carrd.co/', + + // platform: cohost + 'https://cohost.org/cosmoptera', + + // platform: deconreconstruction.music + 'https://music.deconreconstruction.com/albums/catch-322', + 'https://music.deconreconstruction.com/albums/catch-322?track=arcjecs-theme', + + // platform: deconreconstruction + 'https://www.deconreconstruction.com/', + + // platform: deviantart + 'https://culdhira.deviantart.com', 'https://www.deviantart.com/chesswanderlust-sama', - 'https://en.wikipedia.org/wiki/Haydn_Quartet_(vocal_ensemble)', - 'https://www.poetryfoundation.org/poets/christina-rossetti', - 'https://www.instagram.com/levc_egm/', - 'https://www.patreon.com/CecilyRenns', - 'https://open.spotify.com/artist/63SNNpNOicDzG3LY82G4q3', - 'https://buzinkai.newgrounds.com/', + 'https://www.deviantart.com/shilloshilloh/art/Homestuck-Jake-English-268874606', - // Just one custom domain of each platform is OK here - 'https://music.solatrus.com/', - 'https://types.pl/', + // platform: facebook + 'https://www.facebook.com/DoomedCloud/', + 'https://www.facebook.com/pages/WoodenToaster/280642235307371', + 'https://www.facebook.com/Svixy/posts/400018786702633', + + // platform: fandom.mspaintadventures + 'https://mspaintadventures.fandom.com/wiki/Draconian_Dignitary', + 'https://mspaintadventures.fandom.com/wiki/', + 'https://mspaintadventures.fandom.com/', + // platform: fandom 'https://community.fandom.com/', 'https://community.fandom.com/wiki/', 'https://community.fandom.com/wiki/Community_Central', - 'https://mspaintadventures.fandom.com/', - 'https://mspaintadventures.fandom.com/wiki/', - 'https://mspaintadventures.fandom.com/wiki/Draconian_Dignitary', + + // platform: gamebanana + 'https://gamebanana.com/members/2028092', + 'https://gamebanana.com/mods/459476', + + // platform: homestuck + 'https://homestuck.com/', + + // platform: hsmusic.archive + 'https://hsmusic.wiki/media/misc/archive/Firefly%20Cloud%20Remix.mp3', + + // platform: hsmusic + 'https://hsmusic.wiki/feedback/', + + // platform: internetArchive + 'https://archive.org/details/a-life-well-lived', + 'https://archive.org/details/VastError_Volume1/11+Renaissance.mp3', + + // platform: instagram + 'https://instagram.com/bass.and.noises', + 'https://www.instagram.com/levc_egm/', + + // platform: itch + 'https://tuyoki.itch.io/', + 'https://itch.io/profile/bravelittletoreador', + + // platform: ko-fi + 'https://ko-fi.com/gnaach', + + // platform: linktree + 'https://linktr.ee/bbpanzu', + + // platform: mastodon + 'https://types.pl/', + + // platform: mspfa + 'https://canwc.mspfa.com/', + 'https://mspfa.com/?s=12003&p=1045', + 'https://mspfa.com/user/?u=103334508819793669241', + + // platform: neocities + 'https://wodaro.neocities.org', + 'https://neomints.neocities.org/', + + // platform: newgrounds + 'https://buzinkai.newgrounds.com/', + 'https://www.newgrounds.com/audio/listen/1256058', + + // platform: patreon + 'https://www.patreon.com/CecilyRenns', + + // platform: poetryFoundation + 'https://www.poetryfoundation.org/poets/christina-rossetti', + 'https://www.poetryfoundation.org/poems/45000/remember-56d224509b7ae', + + // platform: soundcloud + 'https://soundcloud.com/plazmataz', + 'https://soundcloud.com/worthikids/1-i-accidentally-broke-my', + + // platform: spotify + 'https://open.spotify.com/artist/63SNNpNOicDzG3LY82G4q3', + 'https://open.spotify.com/album/0iHvPD8rM3hQa0qeVtPQ3t', + 'https://open.spotify.com/track/6YEGQH32aAXb9vQQbBrPlw', + + // platform: tiktok + 'https://www.tiktok.com/@richaadeb', + + // platform: toyhouse + 'https://toyhou.se/ghastaboo', + + // platform: tumblr + 'https://aeritus.tumblr.com/', + 'https://vol5anthology.tumblr.com/post/159528808107/hey-everyone-its-413-and-that-means-we-have', + 'https://www.tumblr.com/electricwestern', + 'https://www.tumblr.com/spellmynamewithabang/142767566733/happy-413-this-is-the-first-time-anyones-heard', + + // platform: twitch + 'https://www.twitch.tv/ajhebard', + 'https://www.twitch.tv/vargskelethor/', + + // platform: twitter + 'https://twitter.com/awkwarddoesart', + 'https://twitter.com/purenonsens/', + 'https://twitter.com/circlejourney/status/1202265927183548416', + + // platform: waybackMachine + 'https://web.archive.org/web/20120405160556/https://homestuck.bandcamp.com/album/colours-and-mayhem-universe-a', + 'https://web.archive.org/web/20160807111207/http://griffinspacejam.com:80/', + + // platform: wikipedia + 'https://en.wikipedia.org/wiki/Haydn_Quartet_(vocal_ensemble)', + + // platform: youtube + 'https://youtube.com/@bani-chan8949', + 'https://www.youtube.com/@Razzie16', + 'https://www.youtube.com/channel/UCQXfvlKkpbOqEz4BepHqK7g', + 'https://www.youtube.com/watch?v=6ekVnZm29kw', + 'https://youtu.be/WBkC038wSio', + 'https://www.youtube.com/playlist?list=PLy5UGIMKOXpONMExgI7lVYFwQa54QFp_H', ]); quickSnapshotAllStyles('album', [ diff --git a/test/snapshot/linkThing.js b/test/snapshot/linkThing.js index 502db6d7..9b5cff33 100644 --- a/test/snapshot/linkThing.js +++ b/test/snapshot/linkThing.js @@ -20,7 +20,7 @@ testContentFunctions(t, 'linkThing (snapshot)', async (t, evaluate) => { }); quickSnapshot('preferShortName', { - args: ['localized.tag', { + args: ['localized.artTagGallery', { directory: 'five-oceanfalls', name: 'Five (Oceanfalls)', nameShort: 'Five', diff --git a/test/snapshot/transformContent.js b/test/snapshot/transformContent.js index 87e337e4..63391681 100644 --- a/test/snapshot/transformContent.js +++ b/test/snapshot/transformContent.js @@ -156,6 +156,16 @@ testContentFunctions(t, 'transformContent (snapshot)', async (t, evaluate) => { `[[date:13 April 2004]], and don't ye forget it`, {mode: 'lyrics'}); + quickSnapshot( + 'emails', + `Email cute dogs to qznebula@protonmail.com please.\n` + + `Just kidding... [unless?](mailto:qznebula@protonmail.com)`); + + quickSnapshot( + `absorb punctuation`, + `Don't you think this is an [interesting pull request](https://github.com/hsmusic/hsmusic-wiki/pull/567), Steve?\n` + + `Aren't you [interested](https://github.com/hsmusic/hsmusic-wiki/pull/567)... in [checking it out](https://github.com/hsmusic/hsmusic-wiki/pull/567)?!!`); + // TODO: Snapshots for mode: inline // TODO: Snapshots for mode: single-link }); diff --git a/test/unit/content/dependencies/generateAlbumTrackList.js b/test/unit/content/dependencies/generateAlbumTrackList.js index 7b3ecd33..988f8505 100644 --- a/test/unit/content/dependencies/generateAlbumTrackList.js +++ b/test/unit/content/dependencies/generateAlbumTrackList.js @@ -10,6 +10,9 @@ testContentFunctions(t, 'generateAlbumTrackList (unit)', async (t, evaluate) => generate: (name, {html}) => html.tag('li', `Item: ${name}`), }, + + image: + evaluate.stubContentFunction('image'), }, }); diff --git a/test/unit/content/dependencies/linkContribution.js b/test/unit/content/dependencies/linkContribution.js index 94908901..3ffd71d2 100644 --- a/test/unit/content/dependencies/linkContribution.js +++ b/test/unit/content/dependencies/linkContribution.js @@ -2,46 +2,48 @@ import t from 'tap'; import {testContentFunctions} from '#test-lib'; t.test('generateContributionLinks (unit)', async t => { - const who1 = { + const artist1 = { name: 'Clark Powell', directory: 'clark-powell', urls: ['https://soundcloud.com/plazmataz'], }; - const who2 = { + const artist2 = { name: 'Grounder & Scratch', directory: 'the-big-baddies', urls: [], }; - const who3 = { + const artist3 = { name: 'Toby Fox', directory: 'toby-fox', urls: ['https://tobyfox.bandcamp.com/', 'https://toby.fox/'], }; - const what1 = null; - const what2 = 'Snooping'; - const what3 = 'Arrangement'; + const annotation1 = null; + const annotation2 = 'Snooping'; + const annotation3 = 'Arrangement'; await testContentFunctions(t, 'generateContributionLinks (unit 1)', async (t, evaluate) => { const slots = { - showContribution: true, - showIcons: true, + showAnnotation: true, + showExternalLinks: true, }; await evaluate.load({ mock: evaluate.mock(mock => ({ linkArtist: { - relations: mock.function('linkArtist.relations', () => ({})) - .args([undefined, who1]).next() - .args([undefined, who2]).next() - .args([undefined, who3]), - - data: mock.function('linkArtist.data', () => ({})) - .args([who1]).next() - .args([who2]).next() - .args([who3]), + relations: mock + .function('linkArtist.relations', () => ({})) + .args([undefined, artist1]).next() + .args([undefined, artist2]).next() + .args([undefined, artist3]), + + data: mock + .function('linkArtist.data', () => ({})) + .args([artist1]).next() + .args([artist2]).next() + .args([artist3]), // This can be tweaked to return a specific (mocked) template // for each artist if we need to test for slots in the future. @@ -49,13 +51,18 @@ t.test('generateContributionLinks (unit)', async t => { .repeat(3), }, - linkExternalAsIcon: { - data: mock.function('linkExternalAsIcon.data', () => ({})) - .args([who1.urls[0]]).next() - .args([who3.urls[0]]).next() - .args([who3.urls[1]]), - - generate: mock.function('linkExternalAsIcon.generate', () => 'icon') + generateExternalIcon: { + data: mock + .function('generateExternalIcon.data', () => ({})) + .args([artist1.urls[0]]).next() + .args([artist3.urls[0]]).next() + .args([artist3.urls[1]]), + + generate: mock + .function('generateExternalIcon.generate', () => ({ + toString: () => 'icon', + setSlot: () => {}, + })) .repeat(3), } })), @@ -64,9 +71,9 @@ t.test('generateContributionLinks (unit)', async t => { evaluate({ name: 'linkContribution', multiple: [ - {args: [{who: who1, what: what1}]}, - {args: [{who: who2, what: what2}]}, - {args: [{who: who3, what: what3}]}, + {args: [{artist: artist1, annotation: annotation1}]}, + {args: [{artist: artist2, annotation: annotation2}]}, + {args: [{artist: artist3, annotation: annotation3}]}, ], slots, }); @@ -74,24 +81,27 @@ t.test('generateContributionLinks (unit)', async t => { await testContentFunctions(t, 'generateContributionLinks (unit 2)', async (t, evaluate) => { const slots = { - showContribution: false, - showIcons: false, + showAnnotation: false, + showExternalLinks: false, }; await evaluate.load({ mock: evaluate.mock(mock => ({ linkArtist: { - relations: mock.function('linkArtist.relations', () => ({})) - .args([undefined, who1]).next() - .args([undefined, who2]).next() - .args([undefined, who3]), - - data: mock.function('linkArtist.data', () => ({})) - .args([who1]).next() - .args([who2]).next() - .args([who3]), - - generate: mock.function(() => 'artist link') + relations: mock + .function('linkArtist.relations', () => ({})) + .args([undefined, artist1]).next() + .args([undefined, artist2]).next() + .args([undefined, artist3]), + + data: mock + .function('linkArtist.data', () => ({})) + .args([artist1]).next() + .args([artist2]).next() + .args([artist3]), + + generate: mock + .function(() => 'artist link') .repeat(3), }, @@ -99,11 +109,16 @@ t.test('generateContributionLinks (unit)', async t => { // tree is the same since whether or not the external icon links are // shown is dependent on a slot, which is undefined and arbitrary at // relations/data time (it might change on a whim at generate time). - linkExternalAsIcon: { - data: mock.function('linkExternalAsIcon.data', () => ({})) + generateExternalIcon: { + data: mock + .function('generateExternalIcon.data', () => ({})) .repeat(3), - generate: mock.function('linkExternalAsIcon.generate', () => 'icon') + generate: mock + .function('generateExternalIcon.generate', () => ({ + toString: () => 'icon', + setSlot: () => {}, + })) .repeat(3), }, })), @@ -112,9 +127,9 @@ t.test('generateContributionLinks (unit)', async t => { evaluate({ name: 'linkContribution', multiple: [ - {args: [{who: who1, what: what1}]}, - {args: [{who: who2, what: what2}]}, - {args: [{who: who3, what: what3}]}, + {args: [{artist: artist1, annotation: annotation1}]}, + {args: [{artist: artist2, annotation: annotation2}]}, + {args: [{artist: artist3, annotation: annotation3}]}, ], slots, }); diff --git a/test/unit/data/cacheable-object.js b/test/unit/data/cacheable-object.js index 8c31a5bc..4b927248 100644 --- a/test/unit/data/cacheable-object.js +++ b/test/unit/data/cacheable-object.js @@ -4,7 +4,7 @@ import CacheableObject from '#cacheable-object'; function newCacheableObject(PD) { return new (class extends CacheableObject { - static propertyDescriptors = PD; + static [CacheableObject.propertyDescriptors] = PD; }); } diff --git a/test/unit/data/composite/control-flow/withResultOfAvailabilityCheck.js b/test/unit/data/composite/control-flow/withResultOfAvailabilityCheck.js index 2bcabb4f..9d588e4c 100644 --- a/test/unit/data/composite/control-flow/withResultOfAvailabilityCheck.js +++ b/test/unit/data/composite/control-flow/withResultOfAvailabilityCheck.js @@ -177,10 +177,11 @@ t.test(`withResultOfAvailabilityCheck: validate dynamic inputs`, t => { mode: 'banana', }), {message: `Error computing composition`, cause: - {message: `Error computing composition withResultOfAvailabilityCheck`, cause: - {message: `Errors in input values provided to withResultOfAvailabilityCheck`, errors: [ - {message: `mode: Expected one of null empty falsy index, got banana`}, - ]}}}); + {message: `Error in step 1 of 2, withResultOfAvailabilityCheck`, cause: + {message: `Error computing composition withResultOfAvailabilityCheck`, cause: + {message: `Errors in input values provided to withResultOfAvailabilityCheck`, errors: [ + {message: `mode: Expected one of null empty falsy index, got banana`}, + ]}}}}); t.throws( () => composite.expose.compute({ @@ -188,8 +189,9 @@ t.test(`withResultOfAvailabilityCheck: validate dynamic inputs`, t => { mode: null, }), {message: `Error computing composition`, cause: - {message: `Error computing composition withResultOfAvailabilityCheck`, cause: - {message: `Errors in input values provided to withResultOfAvailabilityCheck`, errors: [ - {message: `mode: Expected a value, got null`}, - ]}}}); + {message: `Error in step 1 of 2, withResultOfAvailabilityCheck`, cause: + {message: `Error computing composition withResultOfAvailabilityCheck`, cause: + {message: `Errors in input values provided to withResultOfAvailabilityCheck`, errors: [ + {message: `mode: Expected a value, got null`}, + ]}}}}); }); diff --git a/test/unit/data/composite/data/withPropertiesFromObject.js b/test/unit/data/composite/data/withPropertiesFromObject.js index 750dc8c4..b81d51a5 100644 --- a/test/unit/data/composite/data/withPropertiesFromObject.js +++ b/test/unit/data/composite/data/withPropertiesFromObject.js @@ -1,4 +1,5 @@ import t from 'tap'; +import {quickCheckCompositeOutputs} from '#test-lib'; import {compositeFrom, input} from '#composite'; import {exposeDependency} from '#composite/control-flow'; @@ -62,6 +63,8 @@ t.test(`withPropertiesFromObject: output shapes & values`, t => { ['foo', 'baz', 'missing3'], }; + const qcco = quickCheckCompositeOutputs(t, dependencies); + const mapLevel1 = [ [input.value('prefix_value'), [ ['object_dependency', [ @@ -153,28 +156,10 @@ t.test(`withPropertiesFromObject: output shapes & values`, t => { properties: propertiesInput, }); - quickCheckOutputs(step, outputDict); + qcco(step, outputDict); } } } - - function quickCheckOutputs(step, outputDict) { - t.same( - Object.keys(step.toDescription().outputs), - Object.keys(outputDict)); - - const composite = compositeFrom({ - compose: false, - steps: [step, { - dependencies: Object.keys(outputDict), - compute: dependencies => dependencies, - }], - }); - - t.same( - composite.expose.compute(dependencies), - outputDict); - } }); t.test(`withPropertiesFromObject: validate static inputs`, t => { @@ -226,11 +211,12 @@ t.test(`withPropertiesFromObject: validate dynamic inputs`, t => { properties: 'onceMore', }), {message: `Error computing composition`, cause: - {message: `Error computing composition withPropertiesFromObject`, cause: - {message: `Errors in input values provided to withPropertiesFromObject`, errors: [ - {message: `object: Expected an object, got string`}, - {message: `properties: Expected an array, got string`}, - ]}}}); + {message: `Error in step 1 of 2, withPropertiesFromObject`, cause: + {message: `Error computing composition withPropertiesFromObject`, cause: + {message: `Errors in input values provided to withPropertiesFromObject`, errors: [ + {message: `object: Expected an object, got string`}, + {message: `properties: Expected an array, got string`}, + ]}}}}); t.throws( () => composite.expose.compute({ @@ -238,17 +224,18 @@ t.test(`withPropertiesFromObject: validate dynamic inputs`, t => { properties: ['abc', 'def', 123], }), {message: `Error computing composition`, cause: - {message: `Error computing composition withPropertiesFromObject`, cause: - {message: `Errors in input values provided to withPropertiesFromObject`, errors: [ - {message: `object: Expected an object, got array`}, - {message: `properties: Errors validating array items`, errors: [ - { - [Symbol.for('hsmusic.annotateError.indexInSourceArray')]: 2, - message: `Error at zero-index 2: 123`, - cause: { - message: `Expected a string, got number`, + {message: `Error in step 1 of 2, withPropertiesFromObject`, cause: + {message: `Error computing composition withPropertiesFromObject`, cause: + {message: `Errors in input values provided to withPropertiesFromObject`, errors: [ + {message: `object: Expected an object, got array`}, + {message: `properties: Errors validating array items`, errors: [ + { + [Symbol.for('hsmusic.annotateError.indexInSourceArray')]: 2, + message: `Error at zero-index 2: 123`, + cause: { + message: `Expected a string, got number`, + }, }, - }, - ]}, - ]}}}); + ]}, + ]}}}}); }); diff --git a/test/unit/data/composite/data/withPropertyFromObject.js b/test/unit/data/composite/data/withPropertyFromObject.js index 6a772c36..912c924c 100644 --- a/test/unit/data/composite/data/withPropertyFromObject.js +++ b/test/unit/data/composite/data/withPropertyFromObject.js @@ -1,5 +1,7 @@ import t from 'tap'; +import {quickCheckCompositeOutputs} from '#test-lib'; +import CacheableObject from '#cacheable-object'; import {compositeFrom, input} from '#composite'; import {exposeDependency} from '#composite/control-flow'; import {withPropertyFromObject} from '#composite/data'; @@ -42,6 +44,89 @@ t.test(`withPropertyFromObject: basic behavior`, t => { }), null); }); +t.test(`withPropertyFromObject: "internal" input`, t => { + t.plan(7); + + const composite = compositeFrom({ + compose: false, + + steps: [ + withPropertyFromObject({ + object: 'object', + property: 'property', + internal: 'internal', + }), + + exposeDependency({dependency: '#value'}), + ], + }); + + const thing = new (class extends CacheableObject { + static [CacheableObject.propertyDescriptors] = { + foo: { + flags: {update: true, expose: false}, + }, + + bar: { + flags: {update: true, expose: true}, + }, + + baz: { + flags: {update: true, expose: true}, + expose: { + transform: baz => baz * 2, + }, + }, + }; + }); + + thing.foo = 100; + thing.bar = 200; + thing.baz = 300; + + t.match(composite, { + expose: { + dependencies: ['object', 'property', 'internal'], + }, + }); + + t.equal(composite.expose.compute({ + object: thing, + property: 'foo', + internal: true, + }), 100); + + t.equal(composite.expose.compute({ + object: thing, + property: 'bar', + internal: true, + }), 200); + + t.equal(composite.expose.compute({ + object: thing, + property: 'baz', + internal: true, + }), 300); + + t.equal(composite.expose.compute({ + object: thing, + property: 'baz', + internal: false, + }), 600); + + t.equal(composite.expose.compute({ + object: thing, + property: 'bimbam', + internal: false, + }), null); + + t.equal(composite.expose.compute({ + object: null, + property: 'bambim', + internal: false, + }), null); +}); + t.test(`withPropertyFromObject: output shapes & values`, t => { t.plan(2 * 3 ** 2); @@ -56,6 +141,8 @@ t.test(`withPropertyFromObject: output shapes & values`, t => { 'baz', }; + const qcco = quickCheckCompositeOutputs(t, dependencies); + const mapLevel1 = [ ['object_dependency', [ ['property_dependency', { @@ -98,25 +185,7 @@ t.test(`withPropertyFromObject: output shapes & values`, t => { property: propertyInput, }); - quickCheckOutputs(step, outputDict); + qcco(step, outputDict); } } - - function quickCheckOutputs(step, outputDict) { - t.same( - Object.keys(step.toDescription().outputs), - Object.keys(outputDict)); - - const composite = compositeFrom({ - compose: false, - steps: [step, { - dependencies: Object.keys(outputDict), - compute: dependencies => dependencies, - }], - }); - - t.same( - composite.expose.compute(dependencies), - outputDict); - } }); diff --git a/test/unit/data/composite/data/withUniqueItemsOnly.js b/test/unit/data/composite/data/withUniqueItemsOnly.js index 965b14b5..50b16f43 100644 --- a/test/unit/data/composite/data/withUniqueItemsOnly.js +++ b/test/unit/data/composite/data/withUniqueItemsOnly.js @@ -1,4 +1,5 @@ import t from 'tap'; +import {quickCheckCompositeOutputs} from '#test-lib'; import {compositeFrom, input} from '#composite'; import {exposeDependency} from '#composite/control-flow'; @@ -44,6 +45,8 @@ t.test(`withUniqueItemsOnly: output shapes & values`, t => { [8, 8, 7, 6, 6, 5, 'bar', true, true, 5], }; + const qcco = quickCheckCompositeOutputs(t, dependencies); + const mapLevel1 = [ ['list_dependency', { '#list_dependency': [1, 2, 3, 4, 'foo', false], @@ -61,24 +64,6 @@ t.test(`withUniqueItemsOnly: output shapes & values`, t => { list: listInput, }); - quickCheckOutputs(step, outputDict); - } - - function quickCheckOutputs(step, outputDict) { - t.same( - Object.keys(step.toDescription().outputs), - Object.keys(outputDict)); - - const composite = compositeFrom({ - compose: false, - steps: [step, { - dependencies: Object.keys(outputDict), - compute: dependencies => dependencies, - }], - }); - - t.same( - composite.expose.compute(dependencies), - outputDict); + qcco(step, outputDict); } }); diff --git a/test/unit/data/composite/things/track/withAlbum.js b/test/unit/data/composite/things/track/withAlbum.js index 30f8cc5d..6f50776b 100644 --- a/test/unit/data/composite/things/track/withAlbum.js +++ b/test/unit/data/composite/things/track/withAlbum.js @@ -1,5 +1,9 @@ import t from 'tap'; +import '#import-heck'; + +import Thing from '#thing'; + import {compositeFrom, input} from '#composite'; import {exposeConstant, exposeDependency} from '#composite/control-flow'; import {withAlbum} from '#composite/things/track'; @@ -21,9 +25,21 @@ t.test(`withAlbum: basic behavior`, t => { }, }); - const fakeTrack1 = {directory: 'foo'}; - const fakeTrack2 = {directory: 'bar'}; - const fakeAlbum = {directory: 'baz', tracks: [fakeTrack1]}; + const fakeTrack1 = { + [Thing.isThing]: true, + directory: 'foo', + }; + + const fakeTrack2 = { + [Thing.isThing]: true, + directory: 'bar', + }; + + const fakeAlbum = { + [Thing.isThing]: true, + directory: 'baz', + tracks: [fakeTrack1], + }; t.equal( composite.expose.compute({ @@ -40,7 +56,7 @@ t.test(`withAlbum: basic behavior`, t => { null); }); -t.test(`withAlbum: early exit conditions (notFoundMode: null)`, t => { +t.test(`withAlbum: early exit conditions`, t => { t.plan(4); const composite = compositeFrom({ @@ -53,9 +69,21 @@ t.test(`withAlbum: early exit conditions (notFoundMode: null)`, t => { ], }); - const fakeTrack1 = {directory: 'foo'}; - const fakeTrack2 = {directory: 'bar'}; - const fakeAlbum = {directory: 'baz', tracks: [fakeTrack1]}; + const fakeTrack1 = { + [Thing.isThing]: true, + directory: 'foo', + }; + + const fakeTrack2 = { + [Thing.isThing]: true, + directory: 'bar', + }; + + const fakeAlbum = { + [Thing.isThing]: true, + directory: 'baz', + tracks: [fakeTrack1], + }; t.equal( composite.expose.compute({ @@ -89,56 +117,3 @@ t.test(`withAlbum: early exit conditions (notFoundMode: null)`, t => { null, `early exits if albumData is null`); }); - -t.test(`withAlbum: early exit conditions (notFoundMode: exit)`, t => { - t.plan(4); - - const composite = compositeFrom({ - compose: false, - steps: [ - withAlbum({ - notFoundMode: input.value('exit'), - }), - - exposeConstant({ - value: input.value('bimbam'), - }), - ], - }); - - const fakeTrack1 = {directory: 'foo'}; - const fakeTrack2 = {directory: 'bar'}; - const fakeAlbum = {directory: 'baz', tracks: [fakeTrack1]}; - - t.equal( - composite.expose.compute({ - albumData: [fakeAlbum], - this: fakeTrack1, - }), - 'bimbam', - `does not early exit if albumData is present and contains the track`); - - t.equal( - composite.expose.compute({ - albumData: [fakeAlbum], - this: fakeTrack2, - }), - null, - `early exits if albumData is present and does not contain the track`); - - t.equal( - composite.expose.compute({ - albumData: [], - this: fakeTrack1, - }), - null, - `early exits if albumData is empty array`); - - t.equal( - composite.expose.compute({ - albumData: null, - this: fakeTrack1, - }), - null, - `early exits if albumData is null`); -}); diff --git a/test/unit/data/composite/wiki-data/withParsedCommentaryEntries.js b/test/unit/data/composite/wiki-data/withParsedCommentaryEntries.js index babe4fae..411fd11d 100644 --- a/test/unit/data/composite/wiki-data/withParsedCommentaryEntries.js +++ b/test/unit/data/composite/wiki-data/withParsedCommentaryEntries.js @@ -28,12 +28,13 @@ function stubArtist(artistName = `Test Artist`) { } t.test(`withParsedCommentaryEntries: basic behavior`, t => { - t.plan(3); + t.plan(7); const artist1 = stubArtist(`Mobius Trip`); const artist2 = stubArtist(`Hadron Kaleido`); + const artist3 = stubArtist('Homestuck'); - const artistData = [artist1, artist2]; + const artistData = [artist1, artist2, artist3]; t.match(composite, { expose: { @@ -53,6 +54,10 @@ t.test(`withParsedCommentaryEntries: basic behavior`, t => { artistDisplayText: null, annotation: null, date: null, + accessDate: null, + accessKind: null, + secondDate: null, + dateKind: null, body: `Some commentary.\nVery cool.`, }, ]); @@ -76,6 +81,10 @@ t.test(`withParsedCommentaryEntries: basic behavior`, t => { annotation: `music, art`, date: new Date('12 January 2015'), body: `First commentary entry.\nVery cool.`, + secondDate: null, + dateKind: null, + accessDate: null, + accessKind: null, }, { artists: [artist2], @@ -83,6 +92,10 @@ t.test(`withParsedCommentaryEntries: basic behavior`, t => { annotation: `moral support`, date: new Date('4 April 2022'), body: `Second commentary entry. Yes. So cool.`, + secondDate: null, + dateKind: null, + accessDate: null, + accessKind: null, }, { artists: [], @@ -90,6 +103,10 @@ t.test(`withParsedCommentaryEntries: basic behavior`, t => { annotation: `pingas`, date: new Date('25 August 2023'), body: `Oh no.. Oh dear...`, + secondDate: null, + dateKind: null, + accessDate: null, + accessKind: null, }, { artists: [artist1, artist2], @@ -97,6 +114,260 @@ t.test(`withParsedCommentaryEntries: basic behavior`, t => { annotation: null, date: null, body: `And back around we go.`, + secondDate: null, + dateKind: null, + accessDate: null, + accessKind: null, + }, + ]); + + t.same(composite.expose.compute({ + artistData, + from: + `<i>Homestuck:</i> ([Bandcamp credits blurb](https://web.archive.org/web/20201024170202/https://homestuck.bandcamp.com/track/sburban-countdown-3) on "Homestuck Vol. 1-4 (with Midnight Crew: Drawing Dead)", 10/25/2019)\n` + + `\n` + + `Written by [[artist:michael-guy-bowman|Michael Guy Bowman]]<br>\n` + + `Arrangement by [[artist:mark-j-hadley|Mark Hadley]]\n` + + `\n` + + `<i>Homestuck:</i> ([fake](https://web.archive.org/web/20201024170202/https://homestuck.bandcamp.com/fake), 7/20/2019 captured 4/13/2024)\n` + + `This isn't real!\n` + + `\n` + + `<i>Homestuck:</i> ([fake](https://homestuck.com/fake), 10/25/2011 accessed 10/27/2011)\n` + + `This isn't real either!\n` + + `\n` + + `<i>Homestuck:</i> ([fake](https://web.archive.org/web/20201024170202/https://homestuck.bandcamp.com/fake), 7/20/2019 accessed 4/13/2024)\n` + + `Not this one, neither!\n` + }), [ + { + artists: [artist3], + artistDisplayText: null, + annotation: `[Bandcamp credits blurb](https://web.archive.org/web/20201024170202/https://homestuck.bandcamp.com/track/sburban-countdown-3) on "Homestuck Vol. 1-4 (with Midnight Crew: Drawing Dead)"`, + date: new Date('10/25/2019'), + body: + `Written by [[artist:michael-guy-bowman|Michael Guy Bowman]]<br>\n` + + `Arrangement by [[artist:mark-j-hadley|Mark Hadley]]`, + secondDate: null, + dateKind: null, + accessDate: new Date('10/24/2020'), + accessKind: 'captured', + }, + { + artists: [artist3], + artistDisplayText: null, + annotation: `[fake](https://web.archive.org/web/20201024170202/https://homestuck.bandcamp.com/fake)`, + date: new Date('7/20/2019'), + body: `This isn't real!`, + secondDate: null, + dateKind: null, + accessDate: new Date('4/13/2024'), + accessKind: 'captured', + }, + { + artists: [artist3], + artistDisplayText: null, + annotation: `[fake](https://homestuck.com/fake)`, + date: new Date('10/25/2011'), + body: `This isn't real either!`, + secondDate: null, + dateKind: null, + accessDate: new Date('10/27/2011'), + accessKind: 'accessed', + }, + { + artists: [artist3], + artistDisplayText: null, + annotation: `[fake](https://web.archive.org/web/20201024170202/https://homestuck.bandcamp.com/fake)`, + date: new Date('7/20/2019'), + body: `Not this one, neither!`, + secondDate: null, + dateKind: null, + accessDate: new Date('4/13/2024'), + accessKind: 'accessed', + }, + ]); + + t.same(composite.expose.compute({ + artistData, + from: + `<i>Homestuck:</i> ([MSPA sound credits](https://web.archive.org/web/20120805031705/http://www.mspaintadventures.com:80/soundcredits.html), sometime 6/21/2012 - 8/5/2012)\n` + + `\n` + + `[[flash:246|Page 2146]] - <b>"Sburban Countdown"</b><br>\n` + + `Available on Bandcamp in [[album:homestuck-vol-1-4|Homestuck Vol. 1-4]]<br>\n` + + `Written by [[artist:michael-guy-bowman|Michael Guy Bowman]]<br>\n` + + `Arrangement by [[artist:mark-j-hadley|Mark Hadley]]\n` + + `\n` + + `<i>Homestuck:</i> ([fake](https://web.archive.org/web/20201024170202/https://homestuck.bandcamp.com/fake), 7/20/2019 - 7/20/2022 captured 4/13/2024)\n` + + `It's goin' once.\n` + + `\n` + + `<i>Homestuck:</i> (10/25/2011 - 10/28/2011 accessed 10/27/2011)\n` + + `It's goin' twice.\n` + + `\n` + + `<i>Homestuck:</i> ([fake](https://web.archive.org/web/20201024170202/https://homestuck.bandcamp.com/fake), 7/20/2019 - 7/20/2022 accessed 4/13/2024)\n` + + `It's goin' thrice!\n` + }), [ + { + artists: [artist3], + artistDisplayText: null, + annotation: `[MSPA sound credits](https://web.archive.org/web/20120805031705/http://www.mspaintadventures.com:80/soundcredits.html)`, + body: + `[[flash:246|Page 2146]] - <b>"Sburban Countdown"</b><br>\n` + + `Available on Bandcamp in [[album:homestuck-vol-1-4|Homestuck Vol. 1-4]]<br>\n` + + `Written by [[artist:michael-guy-bowman|Michael Guy Bowman]]<br>\n` + + `Arrangement by [[artist:mark-j-hadley|Mark Hadley]]`, + date: new Date('6/21/2012'), + secondDate: new Date('8/5/2012'), + dateKind: 'sometime', + accessDate: new Date('8/5/2012'), + accessKind: 'captured', + }, + { + artists: [artist3], + artistDisplayText: null, + annotation: `[fake](https://web.archive.org/web/20201024170202/https://homestuck.bandcamp.com/fake)`, + body: `It's goin' once.`, + date: new Date('7/20/2019'), + secondDate: new Date('7/20/2022'), + dateKind: null, + accessDate: new Date('4/13/2024'), + accessKind: 'captured', + }, + { + artists: [artist3], + artistDisplayText: null, + annotation: '', // TODO: This should be null, but the regex isn't structured for that, at the moment. + body: `It's goin' twice.`, + date: new Date('10/25/2011'), + secondDate: new Date('10/28/2011'), + dateKind: null, + accessDate: new Date('10/27/2011'), + accessKind: 'accessed', + + }, + { + artists: [artist3], + artistDisplayText: null, + annotation: `[fake](https://web.archive.org/web/20201024170202/https://homestuck.bandcamp.com/fake)`, + body: `It's goin' thrice!`, + date: new Date('7/20/2019'), + secondDate: new Date('7/20/2022'), + dateKind: null, + accessDate: new Date('4/13/2024'), + accessKind: 'accessed', + }, + ]); + + t.same(composite.expose.compute({ + artistData, + from: + `<i>Homestuck:</i> ([MSPA sound credits](https://web.archive.org/web/20120805031705/http://www.mspaintadventures.com:80/soundcredits.html), sometime 6/21/2012 - 8/5/2012)\n` + + `\n` + + `[[flash:246|Page 2146]] - <b>"Sburban Countdown"</b><br>\n` + + `Available on Bandcamp in [[album:homestuck-vol-1-4|Homestuck Vol. 1-4]]<br>\n` + + `Written by [[artist:michael-guy-bowman|Michael Guy Bowman]]<br>\n` + + `Arrangement by [[artist:mark-j-hadley|Mark Hadley]]\n` + + `\n` + + `<i>Homestuck:</i> ([fake](https://web.archive.org/web/20201024170202/https://homestuck.bandcamp.com/fake), 7/20/2019 - 7/20/2022 captured 4/13/2024)\n` + + `It's goin' once.\n` + + `\n` + + `<i>Homestuck:</i> (10/25/2011 - 10/28/2011 accessed 10/27/2011)\n` + + `It's goin' twice.\n` + + `\n` + + `<i>Homestuck:</i> ([fake](https://web.archive.org/web/20201024170202/https://homestuck.bandcamp.com/fake), 7/20/2019 - 7/20/2022 accessed 4/13/2024)\n` + + `It's goin' thrice!\n` + }), [ + { + artists: [artist3], + artistDisplayText: null, + annotation: `[MSPA sound credits](https://web.archive.org/web/20120805031705/http://www.mspaintadventures.com:80/soundcredits.html)`, + body: + `[[flash:246|Page 2146]] - <b>"Sburban Countdown"</b><br>\n` + + `Available on Bandcamp in [[album:homestuck-vol-1-4|Homestuck Vol. 1-4]]<br>\n` + + `Written by [[artist:michael-guy-bowman|Michael Guy Bowman]]<br>\n` + + `Arrangement by [[artist:mark-j-hadley|Mark Hadley]]`, + date: new Date('6/21/2012'), + secondDate: new Date('8/5/2012'), + dateKind: 'sometime', + accessDate: new Date('8/5/2012'), + accessKind: 'captured', + }, + { + artists: [artist3], + artistDisplayText: null, + annotation: `[fake](https://web.archive.org/web/20201024170202/https://homestuck.bandcamp.com/fake)`, + body: `It's goin' once.`, + date: new Date('7/20/2019'), + secondDate: new Date('7/20/2022'), + dateKind: null, + accessDate: new Date('4/13/2024'), + accessKind: 'captured', + }, + { + artists: [artist3], + artistDisplayText: null, + annotation: '', // TODO: This should be null, but the regex isn't structured for that, at the moment. + body: `It's goin' twice.`, + date: new Date('10/25/2011'), + secondDate: new Date('10/28/2011'), + dateKind: null, + accessDate: new Date('10/27/2011'), + accessKind: 'accessed', + + }, + { + artists: [artist3], + artistDisplayText: null, + annotation: `[fake](https://web.archive.org/web/20201024170202/https://homestuck.bandcamp.com/fake)`, + body: `It's goin' thrice!`, + date: new Date('7/20/2019'), + secondDate: new Date('7/20/2022'), + dateKind: null, + accessDate: new Date('4/13/2024'), + accessKind: 'accessed', + }, + ]); + + t.same(composite.expose.compute({ + artistData, + from: + `<i>Homestuck:</i> ([Homestuck sound credits](https://web.archive.org/web/20180717171235/https://www.homestuck.com/credits/sound), excerpt, around 4/3/2018)\n` + + `blablabla\n` + + `<i>Homestuck:</i> ([fake](https://web.archive.org/web/20201024170202/https://homestuck.bandcamp.com/fake), around 7/20/2019 - 7/20/2022 captured 4/13/2024)\n` + + `Snoopin', snoopin', snoo,\n` + + `<i>Homestuck:</i> ([fake](https://web.archive.org/web/20201024170202/https://homestuck.bandcamp.com/fake), throughout 7/20/2019 - 7/20/2022 accessed 4/13/2024)\n` + + `~ pingas ~\n` + }), [ + { + artists: [artist3], + artistDisplayText: null, + annotation: `[Homestuck sound credits](https://web.archive.org/web/20180717171235/https://www.homestuck.com/credits/sound), excerpt`, + body: `blablabla`, + date: new Date('4/3/2018'), + secondDate: null, + dateKind: 'around', + accessDate: new Date('7/17/2018'), + accessKind: 'captured', + }, + { + artists: [artist3], + artistDisplayText: null, + annotation: `[fake](https://web.archive.org/web/20201024170202/https://homestuck.bandcamp.com/fake)`, + body: `Snoopin', snoopin', snoo,`, + date: new Date('7/20/2019'), + secondDate: new Date('7/20/2022'), + dateKind: 'around', + accessDate: new Date('4/13/2024'), + accessKind: 'captured', + }, + { + artists: [artist3], + artistDisplayText: null, + annotation: `[fake](https://web.archive.org/web/20201024170202/https://homestuck.bandcamp.com/fake)`, + body: `~ pingas ~`, + date: new Date('7/20/2019'), + secondDate: new Date('7/20/2022'), + dateKind: 'throughout', + accessDate: new Date('4/13/2024'), + accessKind: 'accessed', }, ]); }); diff --git a/test/unit/data/things/album.js b/test/unit/data/things/album.js index 46ea83b0..a64488f7 100644 --- a/test/unit/data/things/album.js +++ b/test/unit/data/things/album.js @@ -1,52 +1,27 @@ import t from 'tap'; -import {linkAndBindWikiData} from '#test-lib'; import thingConstructors from '#things'; -const { - Album, - ArtTag, - Artist, - Track, -} = thingConstructors; - -function stubArtTag(tagName = `Test Art Tag`) { - const tag = new ArtTag(); - tag.name = tagName; - - return tag; -} - -function stubArtistAndContribs() { - const artist = new Artist(); - artist.name = `Test Artist`; - - const contribs = [{who: `Test Artist`, what: null}]; - const badContribs = [{who: `Figment of Your Imagination`, what: null}]; - - return {artist, contribs, badContribs}; -} - -function stubTrack(directory = 'foo') { - const track = new Track(); - track.directory = directory; - - return track; -} +import { + linkAndBindWikiData, + stubArtistAndContribs, + stubThing, + stubWikiData, +} from '#test-lib'; t.test(`Album.artTags`, t => { + const {Album, ArtTag} = thingConstructors; + t.plan(3); - const {artist, contribs} = stubArtistAndContribs(); - const album = new Album(); - const tag1 = stubArtTag(`Tag 1`); - const tag2 = stubArtTag(`Tag 2`); + const wikiData = stubWikiData(); + + const {contribs} = stubArtistAndContribs(wikiData); + const album = stubThing(wikiData, Album); + const tag1 = stubThing(wikiData, ArtTag, {name: `Tag 1`}); + const tag2 = stubThing(wikiData, ArtTag, {name: `Tag 2`}); - const {XXX_decacheWikiData} = linkAndBindWikiData({ - albumData: [album], - artistData: [artist], - artTagData: [tag1, tag2], - }); + linkAndBindWikiData(wikiData); t.same(album.artTags, [], `artTags #1: defaults to empty array`); @@ -63,15 +38,16 @@ t.test(`Album.artTags`, t => { }); t.test(`Album.bannerDimensions`, t => { + const {Album} = thingConstructors; + t.plan(4); - const album = new Album(); - const {artist, contribs, badContribs} = stubArtistAndContribs(); + const wikiData = stubWikiData(); - linkAndBindWikiData({ - albumData: [album], - artistData: [artist], - }); + const album = stubThing(wikiData, Album); + const {contribs, badContribs} = stubArtistAndContribs(wikiData); + + linkAndBindWikiData(wikiData); t.equal(album.bannerDimensions, null, `Album.bannerDimensions #1: defaults to null`); @@ -93,15 +69,16 @@ t.test(`Album.bannerDimensions`, t => { }); t.test(`Album.bannerFileExtension`, t => { + const {Album} = thingConstructors; + t.plan(5); - const album = new Album(); - const {artist, contribs, badContribs} = stubArtistAndContribs(); + const wikiData = stubWikiData(); + + const album = stubThing(wikiData, Album); + const {contribs, badContribs} = stubArtistAndContribs(wikiData); - linkAndBindWikiData({ - albumData: [album], - artistData: [artist], - }); + linkAndBindWikiData(wikiData); t.equal(album.bannerFileExtension, null, `Album.bannerFileExtension #1: defaults to null`); @@ -128,15 +105,16 @@ t.test(`Album.bannerFileExtension`, t => { }); t.test(`Album.bannerStyle`, t => { + const {Album} = thingConstructors; + t.plan(4); - const album = new Album(); - const {artist, contribs, badContribs} = stubArtistAndContribs(); + const wikiData = stubWikiData(); + + const album = stubThing(wikiData, Album); + const {contribs, badContribs} = stubArtistAndContribs(wikiData); - linkAndBindWikiData({ - albumData: [album], - artistData: [artist], - }); + linkAndBindWikiData(wikiData); t.equal(album.bannerStyle, null, `Album.bannerStyle #1: defaults to null`); @@ -158,15 +136,16 @@ t.test(`Album.bannerStyle`, t => { }); t.test(`Album.coverArtDate`, t => { + const {Album} = thingConstructors; + t.plan(6); - const album = new Album(); - const {artist, contribs, badContribs} = stubArtistAndContribs(); + const wikiData = stubWikiData(); - linkAndBindWikiData({ - albumData: [album], - artistData: [artist], - }); + const album = stubThing(wikiData, Album); + const {contribs, badContribs} = stubArtistAndContribs(wikiData); + + linkAndBindWikiData(wikiData); t.equal(album.coverArtDate, null, `Album.coverArtDate #1: defaults to null`); @@ -198,15 +177,16 @@ t.test(`Album.coverArtDate`, t => { }); t.test(`Album.coverArtFileExtension`, t => { + const {Album} = thingConstructors; + t.plan(5); - const album = new Album(); - const {artist, contribs, badContribs} = stubArtistAndContribs(); + const wikiData = stubWikiData(); + + const album = stubThing(wikiData, Album); + const {contribs, badContribs} = stubArtistAndContribs(wikiData); - linkAndBindWikiData({ - albumData: [album], - artistData: [artist], - }); + linkAndBindWikiData(wikiData); t.equal(album.coverArtFileExtension, null, `Album.coverArtFileExtension #1: is null if coverArtistContribs empty (1/2)`); @@ -234,81 +214,105 @@ t.test(`Album.coverArtFileExtension`, t => { }); t.test(`Album.tracks`, t => { - t.plan(5); + const {Album, Track, TrackSection} = thingConstructors; + + t.plan(4); - const album = new Album(); - const track1 = stubTrack('track1'); - const track2 = stubTrack('track2'); - const track3 = stubTrack('track3'); + let wikiData = stubWikiData(); + + const album = stubThing(wikiData, Album); + album.directory = 'foo'; + + const track1 = stubThing(wikiData, Track, {directory: 'track1'}); + const track2 = stubThing(wikiData, Track, {directory: 'track2'}); + const track3 = stubThing(wikiData, Track, {directory: 'track3'}); const tracks = [track1, track2, track3]; - album.ownTrackData = tracks; + const section1 = stubThing(wikiData, TrackSection, {unqualifiedDirectory: 'section1'}); + const section2 = stubThing(wikiData, TrackSection, {unqualifiedDirectory: 'section2'}); + const section3 = stubThing(wikiData, TrackSection, {unqualifiedDirectory: 'section3'}); + const section4 = stubThing(wikiData, TrackSection, {unqualifiedDirectory: 'section4'}); + const section5 = stubThing(wikiData, TrackSection, {unqualifiedDirectory: 'section5'}); + const section6 = stubThing(wikiData, TrackSection, {unqualifiedDirectory: 'section6'}); + const sections = [section1, section2, section3, section4, section5, section6]; + + wikiData = null; for (const track of tracks) { track.albumData = [album]; } + for (const section of sections) { + section.albumData = [album]; + } + t.same(album.tracks, [], `Album.tracks #1: defaults to empty array`); - album.trackSections = [ - {tracks: ['track:track1', 'track:track2', 'track:track3']}, - ]; + section1.tracks = [track1, track2, track3]; + + album.trackSections = [section1]; t.same(album.tracks, [track1, track2, track3], `Album.tracks #2: pulls tracks from one track section`); - album.trackSections = [ - {tracks: ['track:track1']}, - {tracks: ['track:track2', 'track:track3']}, - ]; + section1.tracks = [track1]; + section2.tracks = [track2, track3]; + + album.trackSections = [section1, section2]; t.same(album.tracks, [track1, track2, track3], `Album.tracks #3: pulls tracks from multiple track sections`); - album.trackSections = [ - {tracks: ['track:track1', 'track:does-not-exist']}, - {tracks: ['track:this-one-neither', 'track:track2']}, - {tracks: ['track:effectively-empty-section']}, - {tracks: ['track:track3']}, - ]; - - t.same(album.tracks, [track1, track2, track3], - `Album.tracks #4: filters out references without matches`); + section1.tracks = [track1]; + section2.tracks = []; + section3.tracks = [track2]; + section4.tracks = []; + section5.tracks = []; + section6.tracks = [track3]; - album.trackSections = [ - {tracks: ['track:track1']}, - {}, - {tracks: ['track:track2']}, - {}, - {}, - {tracks: ['track:track3']}, - ]; + album.trackSections = [section1, section2, section3, section4, section5, section6]; t.same(album.tracks, [track1, track2, track3], - `Album.tracks #5: skips missing tracks property`); + `Album.tracks #4: skips empty track sections`); }); t.test(`Album.trackSections`, t => { + const {Album, Track, TrackSection} = thingConstructors; + t.plan(7); - const album = new Album(); - const track1 = stubTrack('track1'); - const track2 = stubTrack('track2'); - const track3 = stubTrack('track3'); - const track4 = stubTrack('track4'); + let wikiData = stubWikiData(); + + const album = stubThing(wikiData, Album); + + const track1 = stubThing(wikiData, Track, {directory: 'track1'}); + const track2 = stubThing(wikiData, Track, {directory: 'track2'}); + const track3 = stubThing(wikiData, Track, {directory: 'track3'}); + const track4 = stubThing(wikiData, Track, {directory: 'track4'}); const tracks = [track1, track2, track3, track4]; - album.ownTrackData = tracks; + const section1 = stubThing(wikiData, TrackSection, {unqualifiedDirectory: 'section1'}); + const section2 = stubThing(wikiData, TrackSection, {unqualifiedDirectory: 'section2'}); + const section3 = stubThing(wikiData, TrackSection, {unqualifiedDirectory: 'section3'}); + const section4 = stubThing(wikiData, TrackSection, {unqualifiedDirectory: 'section4'}); + const section5 = stubThing(wikiData, TrackSection, {unqualifiedDirectory: 'section5'}); + const sections = [section1, section2, section3, section4, section5]; + + wikiData = null; for (const track of tracks) { track.albumData = [album]; } - album.trackSections = [ - {tracks: ['track:track1', 'track:track2']}, - {tracks: ['track:track3', 'track:track4']}, - ]; + for (const section of sections) { + section.albumData = [album]; + } + + section1.tracks = [track1, track2]; + section2.tracks = [track3, track4]; + + album.trackSections = [section1, section2]; t.match(album.trackSections, [ {tracks: [track1, track2]}, @@ -320,11 +324,14 @@ t.test(`Album.trackSections`, t => { {tracks: [track3, track4], startIndex: 2}, ], `Album.trackSections #2: exposes startIndex`); - album.trackSections = [ - {name: 'First section', tracks: ['track:track1']}, - {name: 'Second section', tracks: ['track:track2']}, - {tracks: ['track:track3']}, - ]; + section1.tracks = [track1]; + section2.tracks = [track2]; + section3.tracks = [track3]; + + section1.name = 'First section'; + section2.name = 'Second section'; + + album.trackSections = [section1, section2, section3]; t.match(album.trackSections, [ {name: 'First section', tracks: [track1]}, @@ -334,11 +341,11 @@ t.test(`Album.trackSections`, t => { album.color = '#123456'; - album.trackSections = [ - {tracks: ['track:track1'], color: null}, - {tracks: ['track:track2'], color: '#abcdef'}, - {tracks: ['track:track3'], color: null}, - ]; + section2.color = '#abcdef'; + + // XXX_decacheWikiData + album.trackSections = []; + album.trackSections = [section1, section2, section3]; t.match(album.trackSections, [ {tracks: [track1], color: '#123456'}, @@ -346,11 +353,11 @@ t.test(`Album.trackSections`, t => { {tracks: [track3], color: '#123456'}, ], `Album.trackSections #4: exposes color, inherited from album`); - album.trackSections = [ - {tracks: ['track:track1'], dateOriginallyReleased: null}, - {tracks: ['track:track2'], dateOriginallyReleased: new Date('2009-04-11')}, - {tracks: ['track:track3'], dateOriginallyReleased: null}, - ]; + section2.dateOriginallyReleased = new Date('2009-04-11'); + + // XXX_decacheWikiData + album.trackSections = []; + album.trackSections = [section1, section2, section3]; t.match(album.trackSections, [ {tracks: [track1], dateOriginallyReleased: null}, @@ -358,11 +365,12 @@ t.test(`Album.trackSections`, t => { {tracks: [track3], dateOriginallyReleased: null}, ], `Album.trackSections #5: exposes dateOriginallyReleased, if present`); - album.trackSections = [ - {tracks: ['track:track1'], isDefaultTrackSection: true}, - {tracks: ['track:track2'], isDefaultTrackSection: false}, - {tracks: ['track:track3'], isDefaultTrackSection: null}, - ]; + section1.isDefaultTrackSection = true; + section2.isDefaultTrackSection = false; + + // XXX_decacheWikiData + album.trackSections = []; + album.trackSections = [section1, section2, section3]; t.match(album.trackSections, [ {tracks: [track1], isDefaultTrackSection: true}, @@ -370,31 +378,40 @@ t.test(`Album.trackSections`, t => { {tracks: [track3], isDefaultTrackSection: false}, ], `Album.trackSections #6: exposes isDefaultTrackSection, defaults to false`); - album.trackSections = [ - {tracks: ['track:track1', 'track:track2', 'track:snooping'], color: '#112233'}, - {tracks: ['track:track3', 'track:as-usual'], color: '#334455'}, - {tracks: [], color: '#bbbbba'}, - {tracks: ['track:icy', 'track:chilly', 'track:frigid'], color: '#556677'}, - {tracks: ['track:track4'], color: '#778899'}, - ]; + section1.tracks = [track1, track2]; + section2.tracks = [track3]; + section3.tracks = []; + section4.tracks = []; + section5.tracks = [track4]; + + section1.color = '#112233'; + section2.color = '#334455'; + section3.color = '#bbbbba'; + section4.color = '#556677'; + section5.color = '#778899'; + + album.trackSections = [section1, section2, section3, section4, section5]; t.match(album.trackSections, [ {tracks: [track1, track2], color: '#112233'}, {tracks: [track3], color: '#334455'}, + {tracks: [], color: '#bbbbba'}, + {tracks: [], color: '#556677'}, {tracks: [track4], color: '#778899'}, - ], `Album.trackSections #7: filters out references without matches & empty sections`); + ], `Album.trackSections #7: keeps empty sections`); }); t.test(`Album.wallpaperFileExtension`, t => { + const {Album} = thingConstructors; + t.plan(5); - const album = new Album(); - const {artist, contribs, badContribs} = stubArtistAndContribs(); + const wikiData = stubWikiData(); - linkAndBindWikiData({ - albumData: [album], - artistData: [artist], - }); + const album = stubThing(wikiData, Album); + const {contribs, badContribs} = stubArtistAndContribs(wikiData); + + linkAndBindWikiData(wikiData); t.equal(album.wallpaperFileExtension, null, `Album.wallpaperFileExtension #1: defaults to null`); @@ -421,15 +438,16 @@ t.test(`Album.wallpaperFileExtension`, t => { }); t.test(`Album.wallpaperStyle`, t => { + const {Album} = thingConstructors; + t.plan(4); - const album = new Album(); - const {artist, contribs, badContribs} = stubArtistAndContribs(); + const wikiData = stubWikiData(); + + const album = stubThing(wikiData, Album); + const {contribs, badContribs} = stubArtistAndContribs(wikiData); - linkAndBindWikiData({ - albumData: [album], - artistData: [artist], - }); + linkAndBindWikiData(wikiData); t.equal(album.wallpaperStyle, null, `Album.wallpaperStyle #1: defaults to null`); diff --git a/test/unit/data/things/art-tag.js b/test/unit/data/things/art-tag.js index 561c93ef..015acd0e 100644 --- a/test/unit/data/things/art-tag.js +++ b/test/unit/data/things/art-tag.js @@ -1,55 +1,10 @@ import t from 'tap'; -import {linkAndBindWikiData} from '#test-lib'; import thingConstructors from '#things'; -const { - Album, - Artist, - ArtTag, - Track, -} = thingConstructors; - -function stubAlbum(tracks, directory = 'bar') { - const album = new Album(); - album.directory = directory; - - const trackRefs = tracks.map(t => Thing.getReference(t)); - album.trackSections = [{tracks: trackRefs}]; - - return album; -} - -function stubTrack(directory = 'foo') { - const track = new Track(); - track.directory = directory; - - return track; -} - -function stubTrackAndAlbum(trackDirectory = 'foo', albumDirectory = 'bar') { - const track = stubTrack(trackDirectory); - const album = stubAlbum([track], albumDirectory); - - return {track, album}; -} - -function stubArtist(artistName = `Test Artist`) { - const artist = new Artist(); - artist.name = artistName; - - return artist; -} - -function stubArtistAndContribs(artistName = `Test Artist`) { - const artist = stubArtist(artistName); - const contribs = [{who: artistName, what: null}]; - const badContribs = [{who: `Figment of Your Imagination`, what: null}]; - - return {artist, contribs, badContribs}; -} - t.test(`ArtTag.nameShort`, t => { + const {ArtTag} = thingConstructors; + t.plan(3); const artTag = new ArtTag(); diff --git a/test/unit/data/things/flash.js b/test/unit/data/things/flash.js index 62059604..de39e80d 100644 --- a/test/unit/data/things/flash.js +++ b/test/unit/data/things/flash.js @@ -1,39 +1,24 @@ import t from 'tap'; -import {linkAndBindWikiData} from '#test-lib'; import thingConstructors from '#things'; -const { - Flash, - FlashAct, - Thing, -} = thingConstructors; - -function stubFlash(directory = 'foo') { - const flash = new Flash(); - flash.directory = directory; - - return flash; -} - -function stubFlashAct(flashes, directory = 'bar') { - const flashAct = new FlashAct(); - flashAct.directory = directory; - flashAct.flashes = flashes.map(flash => Thing.getReference(flash)); - - return flashAct; -} +import { + linkAndBindWikiData, + stubThing, + stubWikiData, +} from '#test-lib'; t.test(`Flash.color`, t => { + const {Flash, FlashAct} = thingConstructors; + t.plan(4); - const flash = stubFlash(); - const flashAct = stubFlashAct([flash]); + const wikiData = stubWikiData(); + + const flash = stubThing(wikiData, Flash, {directory: 'my-flash'}); + const flashAct = stubThing(wikiData, FlashAct, {flashes: ['flash:my-flash']}); - const {XXX_decacheWikiData} = linkAndBindWikiData({ - flashData: [flash], - flashActData: [flashAct], - }); + const {XXX_decacheWikiData} = linkAndBindWikiData(wikiData); t.equal(flash.color, null, `color #1: defaults to null`); diff --git a/test/unit/data/things/track.js b/test/unit/data/things/track.js index b1c1611e..403dc064 100644 --- a/test/unit/data/things/track.js +++ b/test/unit/data/things/track.js @@ -1,75 +1,20 @@ import t from 'tap'; -import {linkAndBindWikiData} from '#test-lib'; +import {bindFind} from '#find'; import thingConstructors from '#things'; -const { - Album, - ArtTag, - Artist, - Flash, - FlashAct, - Thing, - Track, -} = thingConstructors; - -function stubAlbum(tracks, directory = 'bar') { - const album = new Album(); - album.directory = directory; - - const trackRefs = tracks.map(t => Thing.getReference(t)); - album.trackSections = [{tracks: trackRefs}]; - - return album; -} - -function stubTrack(directory = 'foo') { - const track = new Track(); - track.directory = directory; - - return track; -} - -function stubTrackAndAlbum(trackDirectory = 'foo', albumDirectory = 'bar') { - const track = stubTrack(trackDirectory); - const album = stubAlbum([track], albumDirectory); - - return {track, album}; -} - -function stubArtist(artistName = `Test Artist`) { - const artist = new Artist(); - artist.name = artistName; - - return artist; -} - -function stubArtistAndContribs(artistName = `Test Artist`) { - const artist = stubArtist(artistName); - const contribs = [{who: artistName, what: null}]; - const badContribs = [{who: `Figment of Your Imagination`, what: null}]; - - return {artist, contribs, badContribs}; -} - -function stubArtTag(tagName = `Test Art Tag`) { - const tag = new ArtTag(); - tag.name = tagName; - - return tag; -} - -function stubFlashAndAct(directory = 'zam') { - const flash = new Flash(); - flash.directory = directory; - - const flashAct = new FlashAct(); - flashAct.flashes = [Thing.getReference(flash)]; - - return {flash, flashAct}; -} +import { + linkAndBindWikiData, + stubArtistAndContribs, + stubFlashAndAct, + stubThing, + stubTrackAndAlbum, + stubWikiData, +} from '#test-lib'; t.test(`Track.album`, t => { + const {Album, Track, TrackSection} = thingConstructors; + t.plan(6); // Note: These asserts use manual albumData/trackData relationships @@ -77,20 +22,28 @@ t.test(`Track.album`, t => { // be relevant for this case. Other properties use the same underlying // get-album behavior as Track.album so aren't tested as aggressively. - const track1 = stubTrack('track1'); - const track2 = stubTrack('track2'); - const album1 = new Album(); - const album2 = new Album(); + let wikiData = stubWikiData(); + + const track1 = stubThing(wikiData, Track, {directory: 'track1'}); + const track2 = stubThing(wikiData, Track, {directory: 'track2'}); + const album1 = stubThing(wikiData, Album); + const album2 = stubThing(wikiData, Album); + const section1 = stubThing(wikiData, TrackSection, {unqualifiedDirectory: 'section1'}); + const section2 = stubThing(wikiData, TrackSection, {unqualifiedDirectory: 'section2'}); + + wikiData = null; t.equal(track1.album, null, `album #1: defaults to null`); track1.albumData = [album1, album2]; track2.albumData = [album1, album2]; - album1.ownTrackData = [track1, track2]; - album2.ownTrackData = [track1, track2]; - album1.trackSections = [{tracks: ['track:track1']}]; - album2.trackSections = [{tracks: ['track:track2']}]; + section1.tracks = [track1]; + section2.tracks = [track2]; + section1.albumData = [album1]; + section2.albumData = [album2]; + album1.trackSections = [section1]; + album2.trackSections = [section2]; t.equal(track1.album, album1, `album #2: is album when album's trackSections matches track`); @@ -105,37 +58,100 @@ t.test(`Track.album`, t => { t.equal(track1.album, null, `album #4: is null when track missing albumData`); - album1.ownTrackData = []; - track1.albumData = [album1, album2]; + section1.tracks = []; + + // XXX_decacheWikiData + album1.trackSections = []; + album1.trackSections = [section1]; + track1.albumData = []; + track1.albumData = [album2, album1]; t.equal(track1.album, null, - `album #5: is null when album missing ownTrackData`); + `album #5: is null when album track section missing tracks`); - album1.ownTrackData = [track1, track2]; - album1.trackSections = [{tracks: ['track:track2']}]; + section1.tracks = [track2]; // XXX_decacheWikiData + album1.trackSections = []; + album1.trackSections = [section1]; track1.albumData = []; - track1.albumData = [album1, album2]; + track1.albumData = [album2, album1]; t.equal(track1.album, null, - `album #6: is null when album's trackSections don't match track`); + `album #6: is null when album track section doesn't match track`); +}); + +t.test(`Track.alwaysReferenceByDirectory`, t => { + t.plan(7); + + const wikiData = stubWikiData(); + + const {track: originalTrack} = + stubTrackAndAlbum(wikiData, 'original-track', 'original-album'); + + const {track: rereleaseTrack, album: rereleaseAlbum} = + stubTrackAndAlbum(wikiData, 'rerelease-track', 'rerelease-album'); + + originalTrack.name = 'Cowabunga'; + rereleaseTrack.name = 'Cowabunga'; + + originalTrack.dataSourceAlbum = 'album:original-album'; + rereleaseTrack.dataSourceAlbum = 'album:rerelease-album'; + + rereleaseTrack.originalReleaseTrack = 'track:original-track'; + + const {XXX_decacheWikiData} = linkAndBindWikiData(wikiData); + + t.equal(originalTrack.alwaysReferenceByDirectory, false, + `alwaysReferenceByDirectory #1: defaults to false`); + + t.equal(rereleaseTrack.alwaysReferenceByDirectory, true, + `alwaysReferenceByDirectory #2: is true if rerelease name matches original`); + + rereleaseTrack.name = 'Foo Dog!'; + + t.equal(rereleaseTrack.alwaysReferenceByDirectory, false, + `alwaysReferenceByDirectory #3: is false if rerelease name doesn't match original`); + + rereleaseTrack.name = `COWabunga`; + + t.equal(rereleaseTrack.alwaysReferenceByDirectory, false, + `alwaysReferenceByDirectory #4: is false if rerelease name doesn't match original exactly`); + + rereleaseAlbum.alwaysReferenceTracksByDirectory = true; + XXX_decacheWikiData(); + + t.equal(rereleaseTrack.alwaysReferenceByDirectory, true, + `alwaysReferenceByDirectory #5: is true if album's alwaysReferenceTracksByDirectory is true`); + + rereleaseTrack.alwaysReferenceByDirectory = false; + + t.equal(rereleaseTrack.alwaysReferenceByDirectory, false, + `alwaysReferenceByDirectory #6: doesn't inherit from album if set to false`); + + rereleaseTrack.name = 'Cowabunga'; + + t.equal(rereleaseTrack.alwaysReferenceByDirectory, false, + `alwaysReferenceByDirectory #7: doesn't compare original release name if set to false`); }); t.test(`Track.artTags`, t => { + const {ArtTag} = thingConstructors; + t.plan(6); - const {track, album} = stubTrackAndAlbum(); - const {artist, contribs} = stubArtistAndContribs(); - const tag1 = stubArtTag(`Tag 1`); - const tag2 = stubArtTag(`Tag 2`); + const wikiData = stubWikiData(); - const {XXX_decacheWikiData} = linkAndBindWikiData({ - albumData: [album], - artistData: [artist], - artTagData: [tag1, tag2], - trackData: [track], - }); + const {track, album} = stubTrackAndAlbum(wikiData); + const {contribs} = stubArtistAndContribs(wikiData); + + const tag1 = + stubThing(wikiData, ArtTag, {name: `Tag 1`}); + + const tag2 = + stubThing(wikiData, ArtTag, {name: `Tag 2`}); + + const {XXX_decacheWikiData} = linkAndBindWikiData(wikiData); t.same(track.artTags, [], `artTags #1: defaults to empty array`); @@ -173,114 +189,106 @@ t.test(`Track.artTags`, t => { }); t.test(`Track.artistContribs`, t => { + const {Album, Artist, Track, TrackSection} = thingConstructors; + t.plan(4); - const {track, album} = stubTrackAndAlbum(); - const artist1 = stubArtist(`Artist 1`); - const artist2 = stubArtist(`Artist 2`); + const wikiData = stubWikiData(); + + const track = + stubThing(wikiData, Track); - const {XXX_decacheWikiData} = linkAndBindWikiData({ - albumData: [album], - artistData: [artist1, artist2], - trackData: [track], - }); + const section = + stubThing(wikiData, TrackSection, {tracks: [track]}); + + const album = + stubThing(wikiData, Album, {trackSections: [section]}); + + const artist1 = + stubThing(wikiData, Artist, {name: `Artist 1`}); + + const artist2 = + stubThing(wikiData, Artist, {name: `Artist 2`}); + + const {XXX_decacheWikiData} = linkAndBindWikiData(wikiData); t.same(track.artistContribs, [], `artistContribs #1: defaults to empty array`); album.artistContribs = [ - {who: `Artist 1`, what: `composition`}, - {who: `Artist 2`, what: null}, + {artist: `Artist 1`, annotation: `composition`}, + {artist: `Artist 2`, annotation: null}, ]; XXX_decacheWikiData(); - t.same(track.artistContribs, - [{who: artist1, what: `composition`}, {who: artist2, what: null}], + t.match(track.artistContribs, + [{artist: artist1, annotation: `composition`}, {artist: artist2, annotation: null}], `artistContribs #2: inherits album artistContribs`); track.artistContribs = [ - {who: `Artist 1`, what: `arrangement`}, + {artist: `Artist 1`, annotation: `arrangement`}, ]; - t.same(track.artistContribs, [{who: artist1, what: `arrangement`}], + t.match(track.artistContribs, [{artist: artist1, annotation: `arrangement`}], `artistContribs #3: resolves from own value`); track.artistContribs = [ - {who: `Artist 1`, what: `snooping`}, - {who: `Artist 413`, what: `as`}, - {who: `Artist 2`, what: `usual`}, + {artist: `Artist 1`, annotation: `snooping`}, + {artist: `Artist 413`, annotation: `as`}, + {artist: `Artist 2`, annotation: `usual`}, ]; - t.same(track.artistContribs, - [{who: artist1, what: `snooping`}, {who: artist2, what: `usual`}], + t.match(track.artistContribs, + [{artist: artist1, annotation: `snooping`}, {artist: artist2, annotation: `usual`}], `artistContribs #4: filters out names without matches`); }); t.test(`Track.color`, t => { - t.plan(5); + t.plan(4); + + const wikiData = stubWikiData(); - const {track, album} = stubTrackAndAlbum(); + const {track, album, section} = stubTrackAndAlbum(wikiData); - const {XXX_decacheWikiData} = linkAndBindWikiData({ - albumData: [album], - trackData: [track], - }); + const {XXX_decacheWikiData} = linkAndBindWikiData(wikiData); t.equal(track.color, null, `color #1: defaults to null`); album.color = '#abcdef'; - album.trackSections = [{ - color: '#beeeef', - tracks: [Thing.getReference(track)], - }]; + section.color = '#beeeef'; + + album.trackSections = [section]; + XXX_decacheWikiData(); t.equal(track.color, '#beeeef', `color #2: inherits from track section before album`); - // Replace the album with a completely fake one. This isn't realistic, since - // in correct data, Album.tracks depends on Albums.trackSections and so the - // track's album will always have a corresponding track section. But if that - // connection breaks for some future reason (with the album still present), - // Track.color should still inherit directly from the album. - track.albumData = [ - { - constructor: {[Thing.referenceType]: 'album'}, - color: '#abcdef', - tracks: [track], - trackSections: [ - {color: '#baaaad', tracks: []}, - ], - }, - ]; - - t.equal(track.color, '#abcdef', - `color #3: inherits from album without matching track section`); - track.color = '#123456'; t.equal(track.color, '#123456', - `color #4: is own value`); + `color #3: is own value`); t.throws(() => { track.color = '#aeiouw'; }, {cause: TypeError}, - `color #5: must be set to valid color`); + `color #4: must be set to valid color`); }); t.test(`Track.commentatorArtists`, t => { + const {Artist, Track} = thingConstructors; + t.plan(8); - const track = new Track(); - const artist1 = stubArtist(`SnooPING`); - const artist2 = stubArtist(`ASUsual`); - const artist3 = stubArtist(`Icy`); + const wikiData = stubWikiData(); - linkAndBindWikiData({ - trackData: [track], - artistData: [artist1, artist2, artist3], - }); + const track = stubThing(wikiData, Track); + const artist1 = stubThing(wikiData, Artist, {name: `SnooPING`}); + const artist2 = stubThing(wikiData, Artist, {name: `ASUsual`}); + const artist3 = stubThing(wikiData, Artist, {name: `Icy`}); + + linkAndBindWikiData(wikiData); // Keep track of the last commentary string in a separate value, since // the track.commentary property exposes as a completely different format @@ -303,7 +311,7 @@ t.test(`Track.commentatorArtists`, t => { `Track.commentatorArtists #2: works with two commentators`); track.commentary = commentary += - `<i>Icy|<b>Icy What You Did There</b>:</i>\n` + + `<i>Icy|<b>Icy annotation You Did There</b>:</i>\n` + `Incredible.\n`; t.same(track.commentatorArtists, [artist1, artist2, artist3], @@ -346,47 +354,47 @@ t.test(`Track.commentatorArtists`, t => { }); t.test(`Track.coverArtistContribs`, t => { + const {Artist} = thingConstructors; + t.plan(5); - const {track, album} = stubTrackAndAlbum(); - const artist1 = stubArtist(`Artist 1`); - const artist2 = stubArtist(`Artist 2`); + const wikiData = stubWikiData(); - const {XXX_decacheWikiData} = linkAndBindWikiData({ - albumData: [album], - artistData: [artist1, artist2], - trackData: [track], - }); + const {track, album} = stubTrackAndAlbum(wikiData); + const artist1 = stubThing(wikiData, Artist, {name: `Artist 1`}); + const artist2 = stubThing(wikiData, Artist, {name: `Artist 2`}); + + const {XXX_decacheWikiData} = linkAndBindWikiData(wikiData); t.same(track.coverArtistContribs, [], `coverArtistContribs #1: defaults to empty array`); album.trackCoverArtistContribs = [ - {who: `Artist 1`, what: `lines`}, - {who: `Artist 2`, what: null}, + {artist: `Artist 1`, annotation: `lines`}, + {artist: `Artist 2`, annotation: null}, ]; XXX_decacheWikiData(); - t.same(track.coverArtistContribs, - [{who: artist1, what: `lines`}, {who: artist2, what: null}], + t.match(track.coverArtistContribs, + [{artist: artist1, annotation: `lines`}, {artist: artist2, annotation: null}], `coverArtistContribs #2: inherits album trackCoverArtistContribs`); track.coverArtistContribs = [ - {who: `Artist 1`, what: `collage`}, + {artist: `Artist 1`, annotation: `collage`}, ]; - t.same(track.coverArtistContribs, [{who: artist1, what: `collage`}], + t.match(track.coverArtistContribs, [{artist: artist1, annotation: `collage`}], `coverArtistContribs #3: resolves from own value`); track.coverArtistContribs = [ - {who: `Artist 1`, what: `snooping`}, - {who: `Artist 413`, what: `as`}, - {who: `Artist 2`, what: `usual`}, + {artist: `Artist 1`, annotation: `snooping`}, + {artist: `Artist 413`, annotation: `as`}, + {artist: `Artist 2`, annotation: `usual`}, ]; - t.same(track.coverArtistContribs, - [{who: artist1, what: `snooping`}, {who: artist2, what: `usual`}], + t.match(track.coverArtistContribs, + [{artist: artist1, annotation: `snooping`}, {artist: artist2, annotation: `usual`}], `coverArtistContribs #4: filters out names without matches`); track.disableUniqueCoverArt = true; @@ -398,14 +406,12 @@ t.test(`Track.coverArtistContribs`, t => { t.test(`Track.coverArtDate`, t => { t.plan(8); - const {track, album} = stubTrackAndAlbum(); - const {artist, contribs, badContribs} = stubArtistAndContribs(); + const wikiData = stubWikiData(); + + const {track, album} = stubTrackAndAlbum(wikiData); + const {contribs, badContribs} = stubArtistAndContribs(wikiData); - const {XXX_decacheWikiData} = linkAndBindWikiData({ - albumData: [album], - artistData: [artist], - trackData: [track], - }); + const {XXX_decacheWikiData} = linkAndBindWikiData(wikiData); track.coverArtistContribs = contribs; @@ -458,14 +464,12 @@ t.test(`Track.coverArtDate`, t => { t.test(`Track.coverArtFileExtension`, t => { t.plan(8); - const {track, album} = stubTrackAndAlbum(); - const {artist, contribs} = stubArtistAndContribs(); + const wikiData = stubWikiData(); + + const {track, album} = stubTrackAndAlbum(wikiData); + const {contribs} = stubArtistAndContribs(wikiData); - const {XXX_decacheWikiData} = linkAndBindWikiData({ - albumData: [album], - artistData: [artist], - trackData: [track], - }); + const {XXX_decacheWikiData} = linkAndBindWikiData(wikiData); t.equal(track.coverArtFileExtension, null, `coverArtFileExtension #1: defaults to null`); @@ -518,12 +522,11 @@ t.test(`Track.coverArtFileExtension`, t => { t.test(`Track.date`, t => { t.plan(3); - const {track, album} = stubTrackAndAlbum(); + const wikiData = stubWikiData(); - const {XXX_decacheWikiData} = linkAndBindWikiData({ - albumData: [album], - trackData: [track], - }); + const {track, album} = stubTrackAndAlbum(wikiData); + + const {XXX_decacheWikiData} = linkAndBindWikiData(wikiData); t.equal(track.date, null, `date #1: defaults to null`); @@ -543,17 +546,13 @@ t.test(`Track.date`, t => { t.test(`Track.featuredInFlashes`, t => { t.plan(2); - const {track, album} = stubTrackAndAlbum('track1'); + const wikiData = stubWikiData(); - const {flash: flash1, flashAct: flashAct1} = stubFlashAndAct('flash1'); - const {flash: flash2, flashAct: flashAct2} = stubFlashAndAct('flash2'); + const {track} = stubTrackAndAlbum(wikiData, 'track1'); + const {flash: flash1} = stubFlashAndAct(wikiData, 'flash1'); + const {flash: flash2} = stubFlashAndAct(wikiData, 'flash2'); - const {XXX_decacheWikiData} = linkAndBindWikiData({ - albumData: [album], - trackData: [track], - flashData: [flash1, flash2], - flashActData: [flashAct1, flashAct2], - }); + const {XXX_decacheWikiData} = linkAndBindWikiData(wikiData); t.same(track.featuredInFlashes, [], `featuredInFlashes #1: defaults to empty array`); @@ -569,14 +568,12 @@ t.test(`Track.featuredInFlashes`, t => { t.test(`Track.hasUniqueCoverArt`, t => { t.plan(7); - const {track, album} = stubTrackAndAlbum(); - const {artist, contribs, badContribs} = stubArtistAndContribs(); + const wikiData = stubWikiData(); + + const {track, album} = stubTrackAndAlbum(wikiData); + const {contribs, badContribs} = stubArtistAndContribs(wikiData); - const {XXX_decacheWikiData} = linkAndBindWikiData({ - albumData: [album], - artistData: [artist], - trackData: [track], - }); + const {XXX_decacheWikiData} = linkAndBindWikiData(wikiData); t.equal(track.hasUniqueCoverArt, false, `hasUniqueCoverArt #1: defaults to false`); @@ -621,13 +618,12 @@ t.test(`Track.hasUniqueCoverArt`, t => { t.test(`Track.originalReleaseTrack`, t => { t.plan(3); - const {track: track1, album: album1} = stubTrackAndAlbum('track1'); - const {track: track2, album: album2} = stubTrackAndAlbum('track2'); + const wikiData = stubWikiData(); - const {wikiData, linkWikiDataArrays, XXX_decacheWikiData} = linkAndBindWikiData({ - albumData: [album1, album2], - trackData: [track1, track2], - }); + const {track: track1} = stubTrackAndAlbum(wikiData, 'track1'); + const {track: track2} = stubTrackAndAlbum(wikiData, 'track2'); + + linkAndBindWikiData(wikiData); t.equal(track2.originalReleaseTrack, null, `originalReleaseTrack #1: defaults to null`); @@ -646,15 +642,14 @@ t.test(`Track.originalReleaseTrack`, t => { t.test(`Track.otherReleases`, t => { t.plan(6); - const {track: track1, album: album1} = stubTrackAndAlbum('track1'); - const {track: track2, album: album2} = stubTrackAndAlbum('track2'); - const {track: track3, album: album3} = stubTrackAndAlbum('track3'); - const {track: track4, album: album4} = stubTrackAndAlbum('track4'); + const wikiData = stubWikiData(); + + const {track: track1} = stubTrackAndAlbum(wikiData, 'track1'); + const {track: track2} = stubTrackAndAlbum(wikiData, 'track2'); + const {track: track3} = stubTrackAndAlbum(wikiData, 'track3'); + const {track: track4} = stubTrackAndAlbum(wikiData, 'track4'); - const {wikiData, linkWikiDataArrays, XXX_decacheWikiData} = linkAndBindWikiData({ - albumData: [album1, album2, album3, album4], - trackData: [track1, track2, track3, track4], - }); + const {linkWikiDataArrays, XXX_decacheWikiData} = linkAndBindWikiData(wikiData); t.same(track1.otherReleases, [], `otherReleases #1: defaults to empty array`); @@ -668,13 +663,13 @@ t.test(`Track.otherReleases`, t => { `otherReleases #2: otherReleases of original release are its rereleases`); wikiData.trackData = [track1, track3, track2, track4]; - linkWikiDataArrays(); + linkWikiDataArrays({bindFind}); t.same(track1.otherReleases, [track3, track2, track4], `otherReleases #3: otherReleases matches trackData order`); wikiData.trackData = [track3, track2, track1, track4]; - linkWikiDataArrays(); + linkWikiDataArrays({bindFind}); t.same(track2.otherReleases, [track1, track3, track4], `otherReleases #4: otherReleases of rerelease are original track then other rereleases (1/3)`); @@ -689,15 +684,14 @@ t.test(`Track.otherReleases`, t => { t.test(`Track.referencedByTracks`, t => { t.plan(4); - const {track: track1, album: album1} = stubTrackAndAlbum('track1'); - const {track: track2, album: album2} = stubTrackAndAlbum('track2'); - const {track: track3, album: album3} = stubTrackAndAlbum('track3'); - const {track: track4, album: album4} = stubTrackAndAlbum('track4'); + const wikiData = stubWikiData(); - const {XXX_decacheWikiData} = linkAndBindWikiData({ - albumData: [album1, album2, album3, album4], - trackData: [track1, track2, track3, track4], - }); + const {track: track1} = stubTrackAndAlbum(wikiData, 'track1'); + const {track: track2} = stubTrackAndAlbum(wikiData, 'track2'); + const {track: track3} = stubTrackAndAlbum(wikiData, 'track3'); + const {track: track4} = stubTrackAndAlbum(wikiData, 'track4'); + + const {XXX_decacheWikiData} = linkAndBindWikiData(wikiData); t.same(track1.referencedByTracks, [], `referencedByTracks #1: defaults to empty array`); @@ -725,15 +719,14 @@ t.test(`Track.referencedByTracks`, t => { t.test(`Track.sampledByTracks`, t => { t.plan(4); - const {track: track1, album: album1} = stubTrackAndAlbum('track1'); - const {track: track2, album: album2} = stubTrackAndAlbum('track2'); - const {track: track3, album: album3} = stubTrackAndAlbum('track3'); - const {track: track4, album: album4} = stubTrackAndAlbum('track4'); + const wikiData = stubWikiData(); + + const {track: track1} = stubTrackAndAlbum(wikiData, 'track1'); + const {track: track2} = stubTrackAndAlbum(wikiData, 'track2'); + const {track: track3} = stubTrackAndAlbum(wikiData, 'track3'); + const {track: track4} = stubTrackAndAlbum(wikiData, 'track4'); - const {XXX_decacheWikiData} = linkAndBindWikiData({ - albumData: [album1, album2, album3, album4], - trackData: [track1, track2, track3, track4], - }); + const {XXX_decacheWikiData} = linkAndBindWikiData(wikiData); t.same(track1.sampledByTracks, [], `sampledByTracks #1: defaults to empty array`); diff --git a/test/unit/data/things/validators.js b/test/unit/data/validators.js index 11134a90..3a217d6f 100644 --- a/test/unit/data/things/validators.js +++ b/test/unit/data/validators.js @@ -1,5 +1,5 @@ import t from 'tap'; -import {showAggregate} from '#sugar'; +import {showAggregate} from '#aggregate'; import { // Basic types @@ -280,17 +280,17 @@ t.test('isContentString', t => { t.test('isContribution', t => { t.plan(4); - t.ok(isContribution({who: 'artist:toby-fox', what: 'Music'})); - t.ok(isContribution({who: 'Toby Fox'})); - t.throws(() => isContribution(({who: 'group:umspaf', what: 'Organizing'})), - {errors: /who/}); - t.throws(() => isContribution(({who: 'artist:toby-fox', what: 123})), - {errors: /what/}); + t.ok(isContribution({artist: 'artist:toby-fox', annotation: 'Music'})); + t.ok(isContribution({artist: 'Toby Fox'})); + t.throws(() => isContribution(({artist: 'group:umspaf', annotation: 'Organizing'})), + {errors: /artist/}); + t.throws(() => isContribution(({artist: 'artist:toby-fox', annotation: 123})), + {errors: /annotation/}); }); t.test('isContributionList', t => { t.plan(4); - t.ok(isContributionList([{who: 'Beavis'}, {who: 'Butthead', what: 'Wrangling'}])); + t.ok(isContributionList([{artist: 'Beavis'}, {artist: 'Butthead', annotation: 'Wrangling'}])); t.ok(isContributionList([])); t.throws(() => isContributionList(2)); t.throws(() => isContributionList(['Charlie', 'Woodstock'])); |