From a98413cde3ffb619ea0aba54d0d44fa2b0756e02 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 25 Jun 2026 23:58:45 -0500 Subject: [PATCH 1/9] Remove frame class type enum --- src/id3v2/frames/attachmentFrame.ts | 5 +- src/id3v2/frames/commentsFrame.ts | 5 +- src/id3v2/frames/eventTimeCodeFrame.ts | 5 +- src/id3v2/frames/frame.ts | 104 +----------------- src/id3v2/frames/frameFactory.ts | 2 +- src/id3v2/frames/genreFrame.ts | 5 +- src/id3v2/frames/musicCdIdentifierFrame.ts | 5 +- src/id3v2/frames/playCountFrame.ts | 5 +- src/id3v2/frames/popularimeterFrame.ts | 5 +- src/id3v2/frames/privateFrame.ts | 5 +- src/id3v2/frames/relativeVolumeFrame.ts | 5 +- src/id3v2/frames/synchronizedLyricsFrame.ts | 5 +- src/id3v2/frames/termsOfUseFrame.ts | 5 +- src/id3v2/frames/textInformationFrame.ts | 5 +- src/id3v2/frames/uniqueFileIdentifierFrame.ts | 5 +- src/id3v2/frames/unknownFrame.ts | 5 +- src/id3v2/frames/unsynchronizedLyricsFrame.ts | 5 +- src/id3v2/frames/urlLinkFrame.ts | 4 +- src/id3v2/frames/userTextInformationFrame.ts | 4 +- src/id3v2/frames/userUrlLinkFrame.ts | 4 - 20 files changed, 19 insertions(+), 174 deletions(-) diff --git a/src/id3v2/frames/attachmentFrame.ts b/src/id3v2/frames/attachmentFrame.ts index 49f77e2..df3287d 100644 --- a/src/id3v2/frames/attachmentFrame.ts +++ b/src/id3v2/frames/attachmentFrame.ts @@ -1,8 +1,8 @@ +import Frame from "./frame"; import Id3v2Settings from "../id3v2Settings"; import {ByteVector, StringType} from "../../byteVector"; import {CorruptFileError} from "../../errors"; import {IFileAbstraction} from "../../fileAbstraction"; -import {Frame, FrameClassType} from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; import {IPicture, Picture, PictureLazy, PictureType} from "../../picture"; @@ -118,9 +118,6 @@ export default class AttachmentFrame extends Frame implements IPicture { // #region Properties - /** @inheritDoc */ - public get frameClassType(): FrameClassType { return FrameClassType.AttachmentFrame; } - /** * Gets the image data stored in the current instance. */ diff --git a/src/id3v2/frames/commentsFrame.ts b/src/id3v2/frames/commentsFrame.ts index f5e5d1e..6a0fdf6 100644 --- a/src/id3v2/frames/commentsFrame.ts +++ b/src/id3v2/frames/commentsFrame.ts @@ -1,7 +1,7 @@ +import Frame from "./frame"; import Id3v2Settings from "../id3v2Settings"; import {ByteVector, StringType} from "../../byteVector"; import {CorruptFileError} from "../../errors"; -import {Frame, FrameClassType} from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; import {Guards} from "../../utils"; @@ -91,9 +91,6 @@ export default class CommentsFrame extends Frame { // #region Public Properties - /** @inheritDoc */ - public get frameClassType(): FrameClassType { return FrameClassType.CommentsFrame; } - /** * Gets the description stored in the current instance, or empty string if not set. */ diff --git a/src/id3v2/frames/eventTimeCodeFrame.ts b/src/id3v2/frames/eventTimeCodeFrame.ts index 31d8d68..e1c7c15 100644 --- a/src/id3v2/frames/eventTimeCodeFrame.ts +++ b/src/id3v2/frames/eventTimeCodeFrame.ts @@ -1,5 +1,5 @@ +import Frame from "./frame"; import {ByteVector} from "../../byteVector"; -import {Frame, FrameClassType} from "./frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; import {Guards} from "../../utils"; @@ -166,9 +166,6 @@ export class EventTimeCodeFrame extends Frame { // #region Properties - /** @inheritDoc */ - public get frameClassType(): FrameClassType { return FrameClassType.EventTimeCodeFrame; } - /** * Gets the event this frame contains. Each {@link EventTimeCode} represents a single event at a * certain point in time. diff --git a/src/id3v2/frames/frame.ts b/src/id3v2/frames/frame.ts index dc734d3..b4056ff 100644 --- a/src/id3v2/frames/frame.ts +++ b/src/id3v2/frames/frame.ts @@ -5,107 +5,11 @@ import {Id3v2FrameFlags, Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifier} from "../frameIdentifiers"; import {Guards, NumberUtils} from "../../utils"; -/** - * Enumeration of types of frames. - */ -// @TODO: We can probably get rid of this since instance of works quite well. -export enum FrameClassType { - /** - * Indicates the frame is an attachment frame. - */ - AttachmentFrame, - - /** - * Indicates the frame is a comments frame. - */ - CommentsFrame, - - /** - * Indicates the frame is an event time code frame. - */ - EventTimeCodeFrame, - - /** - * Indicates the frame is a genre frame. - */ - GenreFrame, - - /** - * Indicates the frame is a music CD identifier frame. - */ - MusicCdIdentifierFrame, - - /** - * Indicates the frame is a play count frame. - */ - PlayCountFrame, - - /** - * Indicates the frame is a popularimeter frame. - */ - PopularimeterFrame, - - /** - * Indicates the frame is a private frame. - */ - PrivateFrame, - - /** - * Indicates the frame is relative volume frame. - */ - RelativeVolumeFrame, - - /** - * Indicates the frame is a synchronized lyrics frame. - */ - SynchronizedLyricsFrame, - - /** - * Indicates the frame is a terms of use frame. - */ - TermsOfUseFrame, - - /** - * Indicates the frame is a text information frame. - */ - TextInformationFrame, - - /** - * Indicates the frame is an unique file identifier frame. - */ - UniqueFileIdentifierFrame, - - /** - * Indicates the frame is an unknown frame. - */ - UnknownFrame, - - /** - * Indicates the frame is an attachment frame. - */ - UnsynchronizedLyricsFrame, - - /** - * Indicates the frame is a URL link frame. - */ - UrlLinkFrame, - - /** - * Indicates the frame is a user text information frame. - */ - UserTextInformationFrame, - - /** - * Indicates the frame is a user URL link frame. - */ - UserUrlLinkFrame, -} - /** * Abstract class that represents an ID3v2 frame. Frames are the unit for storing information in * an ID3v2 tag. There are various types of frames that store differently structured information. */ -export abstract class Frame { +export default abstract class Frame { private _header: Id3v2FrameHeader; @@ -150,12 +54,6 @@ export abstract class Frame { // @TODO: This shouldn't be necessary, but removing it breaks more things than I want to fix right now. public set flags(value: Id3v2FrameFlags) { this._header.flags = value; } - /** - * Gets a flag indicating which type of frame the current instance is. - */ - // @TODO: This can be removed as instanceof is pretty good now. - public abstract get frameClassType(): FrameClassType; - /** * Gets the frame ID for the current instance. * @returns Object representing of the identifier of the frame diff --git a/src/id3v2/frames/frameFactory.ts b/src/id3v2/frames/frameFactory.ts index c678b26..03be210 100644 --- a/src/id3v2/frames/frameFactory.ts +++ b/src/id3v2/frames/frameFactory.ts @@ -1,5 +1,6 @@ import AttachmentFrame from "./attachmentFrame"; import CommentsFrame from "./commentsFrame"; +import Frame from "./frame"; import GenreFrame from "./genreFrame"; import MusicCdIdentifierFrame from "./musicCdIdentifierFrame"; import PlayCountFrame from "./playCountFrame"; @@ -18,7 +19,6 @@ import {ByteVector} from "../../byteVector"; import {CorruptFileError, NotImplementedError} from "../../errors"; import {EventTimeCodeFrame} from "./eventTimeCodeFrame"; import {File} from "../../file"; -import {Frame} from "./frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifier, FrameIdentifiers} from "../frameIdentifiers"; import {RelativeVolumeFrame} from "./relativeVolumeFrame"; diff --git a/src/id3v2/frames/genreFrame.ts b/src/id3v2/frames/genreFrame.ts index ccea823..4666246 100644 --- a/src/id3v2/frames/genreFrame.ts +++ b/src/id3v2/frames/genreFrame.ts @@ -1,7 +1,7 @@ +import Frame from "./frame"; import Genres from "../../genres"; import Id3v2Settings from "../id3v2Settings"; import {ByteVector, StringType} from "../../byteVector"; -import {Frame, FrameClassType} from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; import {Guards, StringUtils} from "../../utils"; @@ -135,9 +135,6 @@ export default class GenreFrame extends Frame { // #region Properties - /** @inheritDoc */ - public get frameClassType(): FrameClassType { return FrameClassType.GenreFrame; } - /** * Gets the genres contained in the current instance. * Note: Modifying the contents of the returned value will not modify the contents of the diff --git a/src/id3v2/frames/musicCdIdentifierFrame.ts b/src/id3v2/frames/musicCdIdentifierFrame.ts index f8faf10..a8f458d 100644 --- a/src/id3v2/frames/musicCdIdentifierFrame.ts +++ b/src/id3v2/frames/musicCdIdentifierFrame.ts @@ -1,5 +1,5 @@ +import Frame from "./frame"; import {ByteVector} from "../../byteVector"; -import {Frame, FrameClassType} from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; import {Guards} from "../../utils"; @@ -47,9 +47,6 @@ export default class MusicCdIdentifierFrame extends Frame { return frame; } - /** @inheritDoc */ - public get frameClassType(): FrameClassType { return FrameClassType.MusicCdIdentifierFrame; } - /** * Gets the identifier data stored in the current instance */ diff --git a/src/id3v2/frames/playCountFrame.ts b/src/id3v2/frames/playCountFrame.ts index ff6e34b..082edcc 100644 --- a/src/id3v2/frames/playCountFrame.ts +++ b/src/id3v2/frames/playCountFrame.ts @@ -1,5 +1,5 @@ +import Frame from "./frame"; import {ByteVector} from "../../byteVector"; -import {Frame, FrameClassType} from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; import {Guards} from "../../utils"; @@ -54,9 +54,6 @@ export default class PlayCountFrame extends Frame { // #region Public Properties - /** @inheritDoc */ - public get frameClassType(): FrameClassType { return FrameClassType.PlayCountFrame; } - /** * Gets the play count of the current instance. */ diff --git a/src/id3v2/frames/popularimeterFrame.ts b/src/id3v2/frames/popularimeterFrame.ts index d37b450..90e00a5 100644 --- a/src/id3v2/frames/popularimeterFrame.ts +++ b/src/id3v2/frames/popularimeterFrame.ts @@ -1,6 +1,6 @@ +import Frame from "./frame"; import {ByteVector, StringType} from "../../byteVector"; import {CorruptFileError, NotSupportedError} from "../../errors"; -import {Frame, FrameClassType} from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; import {Guards} from "../../utils"; @@ -82,9 +82,6 @@ export default class PopularimeterFrame extends Frame { // #region Properties - /** @inheritDoc */ - public get frameClassType(): FrameClassType { return FrameClassType.PopularimeterFrame; } - /** * Gets the play count of the current instance */ diff --git a/src/id3v2/frames/privateFrame.ts b/src/id3v2/frames/privateFrame.ts index 2d1e357..2cd1a25 100644 --- a/src/id3v2/frames/privateFrame.ts +++ b/src/id3v2/frames/privateFrame.ts @@ -1,6 +1,6 @@ +import Frame from "./frame"; import {ByteVector, StringType} from "../../byteVector"; import {CorruptFileError, NotImplementedError} from "../../errors"; -import {Frame, FrameClassType} from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; import {Guards} from "../../utils"; @@ -63,9 +63,6 @@ export default class PrivateFrame extends Frame { // #region Public Properties - /** @inheritDoc */ - public get frameClassType(): FrameClassType { return FrameClassType.PrivateFrame; } - /** * Gets the owner of the current instance. * There should only be one frame with a given owner per tag. diff --git a/src/id3v2/frames/relativeVolumeFrame.ts b/src/id3v2/frames/relativeVolumeFrame.ts index ddb4523..241609a 100644 --- a/src/id3v2/frames/relativeVolumeFrame.ts +++ b/src/id3v2/frames/relativeVolumeFrame.ts @@ -1,5 +1,5 @@ +import Frame from "./frame"; import {ByteVector, StringType} from "../../byteVector"; -import {Frame, FrameClassType} from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; import {Guards, NumberUtils} from "../../utils"; @@ -267,9 +267,6 @@ export class RelativeVolumeFrame extends Frame { // #region Properties - /** @inheritDoc */ - public get frameClassType(): FrameClassType { return FrameClassType.RelativeVolumeFrame; } - /** * Gets the channels in the current instance that have a value */ diff --git a/src/id3v2/frames/synchronizedLyricsFrame.ts b/src/id3v2/frames/synchronizedLyricsFrame.ts index 4a7c715..a8c863e 100644 --- a/src/id3v2/frames/synchronizedLyricsFrame.ts +++ b/src/id3v2/frames/synchronizedLyricsFrame.ts @@ -1,7 +1,7 @@ +import Frame from "./frame"; import Id3v2Settings from "../id3v2Settings"; import {ByteVector, StringType} from "../../byteVector"; import {CorruptFileError} from "../../errors"; -import {Frame, FrameClassType} from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; import {Guards} from "../../utils"; @@ -195,9 +195,6 @@ export class SynchronizedLyricsFrame extends Frame { // #region Properties - /** @inheritDoc */ - public get frameClassType(): FrameClassType { return FrameClassType.SynchronizedLyricsFrame; } - /** * Gets the description of the current instance. */ diff --git a/src/id3v2/frames/termsOfUseFrame.ts b/src/id3v2/frames/termsOfUseFrame.ts index 2e0f140..7b18af9 100644 --- a/src/id3v2/frames/termsOfUseFrame.ts +++ b/src/id3v2/frames/termsOfUseFrame.ts @@ -1,7 +1,7 @@ +import Frame from "./frame"; import Id3v2Settings from "../id3v2Settings"; import {ByteVector, StringType} from "../../byteVector"; import {CorruptFileError} from "../../errors"; -import {Frame, FrameClassType} from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; import {Guards} from "../../utils"; @@ -65,9 +65,6 @@ export default class TermsOfUseFrame extends Frame { // #region Properties - /** @inheritDoc */ - public get frameClassType(): FrameClassType { return FrameClassType.TermsOfUseFrame; } - /** * Gets the ISO-639-2 language code stored in the current instance. */ diff --git a/src/id3v2/frames/textInformationFrame.ts b/src/id3v2/frames/textInformationFrame.ts index 17d5b7d..f9d127a 100644 --- a/src/id3v2/frames/textInformationFrame.ts +++ b/src/id3v2/frames/textInformationFrame.ts @@ -1,6 +1,6 @@ +import Frame from "./frame"; import Id3v2Settings from "../id3v2Settings"; import {ByteVector, StringType} from "../../byteVector"; -import {Frame, FrameClassType} from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifier, FrameIdentifiers} from "../frameIdentifiers"; import {Guards} from "../../utils"; @@ -231,9 +231,6 @@ export default class TextInformationFrame extends Frame { // #region Properties - /** @inheritDoc */ - public get frameClassType(): FrameClassType { return FrameClassType.TextInformationFrame; } - /** * Gets the text contained in the current instance. * Note: Modifying the contents of the returned value will not modify the contents of the diff --git a/src/id3v2/frames/uniqueFileIdentifierFrame.ts b/src/id3v2/frames/uniqueFileIdentifierFrame.ts index 8b9880b..9e072f9 100644 --- a/src/id3v2/frames/uniqueFileIdentifierFrame.ts +++ b/src/id3v2/frames/uniqueFileIdentifierFrame.ts @@ -1,6 +1,6 @@ +import Frame from "./frame"; import {ByteVector, StringType} from "../../byteVector"; import {CorruptFileError} from "../../errors"; -import {Frame, FrameClassType} from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; import {Guards} from "../../utils"; @@ -71,9 +71,6 @@ export default class UniqueFileIdentifierFrame extends Frame { // #region Properties - /** @inheritDoc */ - public get frameClassType(): FrameClassType { return FrameClassType.UniqueFileIdentifierFrame; } - /** * Gets the owner of this unique ID. */ diff --git a/src/id3v2/frames/unknownFrame.ts b/src/id3v2/frames/unknownFrame.ts index 7c98f9a..939d796 100644 --- a/src/id3v2/frames/unknownFrame.ts +++ b/src/id3v2/frames/unknownFrame.ts @@ -1,5 +1,5 @@ +import Frame from "./frame"; import {ByteVector} from "../../byteVector"; -import {Frame, FrameClassType} from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifier} from "../frameIdentifiers"; import {Guards} from "../../utils"; @@ -41,9 +41,6 @@ export default class UnknownFrame extends Frame { return frame; } - /** @inheritDoc */ - public get frameClassType(): FrameClassType { return FrameClassType.UnknownFrame; } - /** * Gets and sets the field data in the current instance */ diff --git a/src/id3v2/frames/unsynchronizedLyricsFrame.ts b/src/id3v2/frames/unsynchronizedLyricsFrame.ts index 1407873..715afcb 100644 --- a/src/id3v2/frames/unsynchronizedLyricsFrame.ts +++ b/src/id3v2/frames/unsynchronizedLyricsFrame.ts @@ -1,7 +1,7 @@ +import Frame from "./frame"; import Id3v2Settings from "../id3v2Settings"; import {ByteVector, StringType} from "../../byteVector"; import {CorruptFileError} from "../../errors"; -import {Frame, FrameClassType} from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; import {Guards} from "../../utils"; @@ -90,9 +90,6 @@ export default class UnsynchronizedLyricsFrame extends Frame { // #region Properties - /** @inheritDoc */ - public get frameClassType(): FrameClassType { return FrameClassType.UnsynchronizedLyricsFrame; } - /** * Gets the description of the contents of the current instance. */ diff --git a/src/id3v2/frames/urlLinkFrame.ts b/src/id3v2/frames/urlLinkFrame.ts index 7878d25..26d8b0a 100644 --- a/src/id3v2/frames/urlLinkFrame.ts +++ b/src/id3v2/frames/urlLinkFrame.ts @@ -1,5 +1,5 @@ +import Frame from "./frame"; import {ByteVector, StringType} from "../../byteVector"; -import {Frame, FrameClassType} from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifier} from "../frameIdentifiers"; import {Guards} from "../../utils"; @@ -78,8 +78,6 @@ export default class UrlLinkFrame extends Frame { // #region Properties - public get frameClassType(): FrameClassType { return FrameClassType.UrlLinkFrame; } - /** * Gets the text contained in the current instance. */ diff --git a/src/id3v2/frames/userTextInformationFrame.ts b/src/id3v2/frames/userTextInformationFrame.ts index 2903c70..1188b57 100644 --- a/src/id3v2/frames/userTextInformationFrame.ts +++ b/src/id3v2/frames/userTextInformationFrame.ts @@ -1,7 +1,7 @@ import TextInformationFrame from "./textInformationFrame"; import Id3v2Settings from "../id3v2Settings"; import {ByteVector, StringType} from "../../byteVector"; -import {Frame, FrameClassType} from "./frame"; +import Frame from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; import {Guards, StringComparison} from "../../utils"; @@ -77,8 +77,6 @@ export default class UserTextInformationFrame extends TextInformationFrame { // #region Properties - public get frameClassType(): FrameClassType { return FrameClassType.UserTextInformationFrame; } - /** * Gets the description stored in the current instance. */ diff --git a/src/id3v2/frames/userUrlLinkFrame.ts b/src/id3v2/frames/userUrlLinkFrame.ts index abe9b1b..95e9c4a 100644 --- a/src/id3v2/frames/userUrlLinkFrame.ts +++ b/src/id3v2/frames/userUrlLinkFrame.ts @@ -1,7 +1,6 @@ import Id3v2Settings from "../id3v2Settings"; import UrlLinkFrame from "./urlLinkFrame"; import {ByteVector, StringType} from "../../byteVector"; -import {FrameClassType} from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; import {Guards} from "../../utils"; @@ -90,9 +89,6 @@ export default class UserUrlLinkFrame extends UrlLinkFrame { // #region Properties - /** @inheritDoc */ - public get frameClassType(): FrameClassType { return FrameClassType.UserUrlLinkFrame; } - /** * Gets the description stored in the current instance. */ From 12549d470b3fa1ab4f3f67771bfd6cfc8cabc41c Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Fri, 26 Jun 2026 13:19:07 -0500 Subject: [PATCH 2/9] Reimplement filtering --- src/id3v2/frames/attachmentFrame.ts | 23 +--- src/id3v2/frames/commentsFrame.ts | 39 +------ src/id3v2/frames/eventTimeCodeFrame.ts | 7 +- src/id3v2/frames/genreFrame.ts | 12 +- src/id3v2/frames/musicCdIdentifierFrame.ts | 7 +- src/id3v2/frames/playCountFrame.ts | 7 +- src/id3v2/frames/popularimeterFrame.ts | 12 +- src/id3v2/frames/privateFrame.ts | 14 +-- src/id3v2/frames/relativeVolumeFrame.ts | 12 +- src/id3v2/frames/synchronizedLyricsFrame.ts | 25 +--- src/id3v2/frames/termsOfUseFrame.ts | 12 +- src/id3v2/frames/textInformationFrame.ts | 21 +--- src/id3v2/frames/uniqueFileIdentifierFrame.ts | 12 +- src/id3v2/frames/unknownFrame.ts | 7 +- src/id3v2/frames/unsynchronizedLyricsFrame.ts | 46 +------- src/id3v2/frames/urlLinkFrame.ts | 17 +-- src/id3v2/frames/userTextInformationFrame.ts | 20 +--- src/id3v2/frames/userUrlLinkFrame.ts | 8 +- src/id3v2/id3v2Tag.ts | 108 ++++-------------- src/utils.ts | 15 ++- 20 files changed, 113 insertions(+), 311 deletions(-) diff --git a/src/id3v2/frames/attachmentFrame.ts b/src/id3v2/frames/attachmentFrame.ts index df3287d..3bb0e51 100644 --- a/src/id3v2/frames/attachmentFrame.ts +++ b/src/id3v2/frames/attachmentFrame.ts @@ -6,7 +6,7 @@ import {IFileAbstraction} from "../../fileAbstraction"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; import {IPicture, Picture, PictureLazy, PictureType} from "../../picture"; -import {Guards} from "../../utils"; +import {ArrayUtils, Guards} from "../../utils"; export default class AttachmentFrame extends Frame implements IPicture { // NOTE: It probably doesn't look necessary to implement IPicture, but it makes converting a @@ -247,26 +247,9 @@ export default class AttachmentFrame extends Frame implements IPicture { return frame; } - /** - * Get a specified attachment frame from the specified tag, optionally creating it if it does - * not exist. - * @param frames List of attachment frames to search - * @param description Description to match - * @param type Picture type to match - * @returns Matching frame or `undefined` if a match wasn't found and `create` is `false` - */ - public static find( - frames: AttachmentFrame[], - description?: string, - type: PictureType = PictureType.Other - ): AttachmentFrame { + public static filterFrames(frames: Frame[]): AttachmentFrame[] { Guards.truthy(frames, "frames"); - return frames.find((f) => { - if (description && f.description !== description) { return false; } - // noinspection RedundantIfStatementJS - if (type !== PictureType.Other && f.type !== type) { return false; } - return true; - }); + return ArrayUtils.ofType(frames, AttachmentFrame); } /** diff --git a/src/id3v2/frames/commentsFrame.ts b/src/id3v2/frames/commentsFrame.ts index 6a0fdf6..a5267f4 100644 --- a/src/id3v2/frames/commentsFrame.ts +++ b/src/id3v2/frames/commentsFrame.ts @@ -4,7 +4,7 @@ import {ByteVector, StringType} from "../../byteVector"; import {CorruptFileError} from "../../errors"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; -import {Guards} from "../../utils"; +import {ArrayUtils, Guards} from "../../utils"; /** * Class that extends {@link Frame}, implementing support for ID3v2 Comments (COMM) frames. @@ -140,42 +140,9 @@ export default class CommentsFrame extends Frame { // #endregion - /** - * Gets a comment frame that matched the provided parameters from the list of frames - * @param frames Frames to search for best matching frame - * @param description Description of the comments frame to match - * @param language Optional, ISO-639-2 language code to match - * @returns Object containing the matching frame or `undefined` if a match was not found - */ - public static find(frames: CommentsFrame[], description: string, language?: string): CommentsFrame { - Guards.truthy(frames, "frames"); - - return frames.find((f) => { - if (f.description !== description) { return false; } - // noinspection RedundantIfStatementJS - if (language && f.language !== language) { return false; } - return true; - }); - } - - /** - * Gets all comment frames that match the provided parameters from the list of frames - * @param frames Frames to search - * @param description Description of the comments frame to match - * @param language Optional, ISO-639-2 language code to match - * @returns - * Array of comments frames that match the provided parameters or an - * empty array if none were found - */ - public static findAll(frames: CommentsFrame[], description: string, language?: string): CommentsFrame[] { + public static filterFrames(frames: Frame[]): CommentsFrame[] { Guards.truthy(frames, "frames"); - - return frames.filter((f) => { - if (f.description !== description) { return false; } - // noinspection RedundantIfStatementJS - if (language && f.language !== language) { return false; } - return true; - }); + return ArrayUtils.ofType(frames, CommentsFrame); } /** diff --git a/src/id3v2/frames/eventTimeCodeFrame.ts b/src/id3v2/frames/eventTimeCodeFrame.ts index e1c7c15..f893de9 100644 --- a/src/id3v2/frames/eventTimeCodeFrame.ts +++ b/src/id3v2/frames/eventTimeCodeFrame.ts @@ -2,7 +2,7 @@ import Frame from "./frame"; import {ByteVector} from "../../byteVector"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; -import {Guards} from "../../utils"; +import {ArrayUtils, Guards} from "../../utils"; import {EventType, TimestampFormat} from "../utilTypes"; import {CorruptFileError} from "../../errors"; @@ -189,6 +189,11 @@ export class EventTimeCodeFrame extends Frame { // #region Methods + public filterFrames(frames: Frame[]): EventTimeCodeFrame[] { + Guards.truthy(frames, "frames"); + return ArrayUtils.ofType(frames, EventTimeCodeFrame); + } + /** @inheritDoc */ public clone(): Frame { const frame = new EventTimeCodeFrame(this.header); diff --git a/src/id3v2/frames/genreFrame.ts b/src/id3v2/frames/genreFrame.ts index 4666246..a4bf607 100644 --- a/src/id3v2/frames/genreFrame.ts +++ b/src/id3v2/frames/genreFrame.ts @@ -4,7 +4,7 @@ import Id3v2Settings from "../id3v2Settings"; import {ByteVector, StringType} from "../../byteVector"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; -import {Guards, StringUtils} from "../../utils"; +import {ArrayUtils, Guards, StringUtils} from "../../utils"; import {CorruptFileError} from "../../errors"; /** @@ -160,15 +160,9 @@ export default class GenreFrame extends Frame { // #region Public Methods - /** - * Gets a {@link GenreFrame} object from a specified list of genre frames. - * @param frames List of frames to search - * @returns Matching frame if it exists in `tag`, `undefined` if a matching frame was not found - */ - public static findGenreFrame(frames: GenreFrame[]): GenreFrame { + public static filterFrames(frames: Frame[]): GenreFrame[] { Guards.truthy(frames, "frames"); - - return frames.find((f) => f.frameId === FrameIdentifiers.TCON); + return ArrayUtils.ofType(frames, GenreFrame); } /** @inheritDoc */ diff --git a/src/id3v2/frames/musicCdIdentifierFrame.ts b/src/id3v2/frames/musicCdIdentifierFrame.ts index a8f458d..cf10e0e 100644 --- a/src/id3v2/frames/musicCdIdentifierFrame.ts +++ b/src/id3v2/frames/musicCdIdentifierFrame.ts @@ -2,7 +2,7 @@ import Frame from "./frame"; import {ByteVector} from "../../byteVector"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; -import {Guards} from "../../utils"; +import {ArrayUtils, Guards} from "../../utils"; /** * Class extends {@link Frame}, implementing support for ID3v2 Music CD Identifier (MCDI) frames. @@ -57,6 +57,11 @@ export default class MusicCdIdentifierFrame extends Frame { */ public set data(value: ByteVector) { this._data = value; } + public static filterFrames(frames: Frame[]): MusicCdIdentifierFrame[] { + Guards.truthy(frames, "frames"); + return ArrayUtils.ofType(frames, MusicCdIdentifierFrame); + } + /** @inheritDoc */ public clone(): MusicCdIdentifierFrame { const frame = new MusicCdIdentifierFrame(new Id3v2FrameHeader(FrameIdentifiers.MCDI)); diff --git a/src/id3v2/frames/playCountFrame.ts b/src/id3v2/frames/playCountFrame.ts index 082edcc..c9ee1c0 100644 --- a/src/id3v2/frames/playCountFrame.ts +++ b/src/id3v2/frames/playCountFrame.ts @@ -2,7 +2,7 @@ import Frame from "./frame"; import {ByteVector} from "../../byteVector"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; -import {Guards} from "../../utils"; +import {ArrayUtils, Guards} from "../../utils"; import {CorruptFileError, NotSupportedError} from "../../errors"; /** @@ -69,6 +69,11 @@ export default class PlayCountFrame extends Frame { // #endregion + public static filterFrames(frames: Frame[]): PlayCountFrame[] { + Guards.truthy(frames, "frames"); + return ArrayUtils.ofType(frames, PlayCountFrame); + } + /** @inheritDoc */ public clone(): Frame { const frame = new PlayCountFrame(new Id3v2FrameHeader(FrameIdentifiers.PCNT)); diff --git a/src/id3v2/frames/popularimeterFrame.ts b/src/id3v2/frames/popularimeterFrame.ts index 90e00a5..21aae72 100644 --- a/src/id3v2/frames/popularimeterFrame.ts +++ b/src/id3v2/frames/popularimeterFrame.ts @@ -3,7 +3,7 @@ import {ByteVector, StringType} from "../../byteVector"; import {CorruptFileError, NotSupportedError} from "../../errors"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; -import {Guards} from "../../utils"; +import {ArrayUtils, Guards} from "../../utils"; /** * This class extends {@link Frame} implementing support for ID3v2 popularimeter (POPM) frames. @@ -120,15 +120,9 @@ export default class PopularimeterFrame extends Frame { // #endregion - /** - * Gets a popularimeter frame from a specified tag that matches the given parameters - * @param frames List of frames to search - * @param user User email to use to match the frame in the `tag` - * @returns Frame containing the matching user or `undefined` if a match was not found - */ - public static find(frames: PopularimeterFrame[], user: string): PopularimeterFrame { + public static filterFrames(frames: Frame[]): PopularimeterFrame[] { Guards.truthy(frames, "frames"); - return frames.find((f) => f.user === user); + return ArrayUtils.ofType(frames, PopularimeterFrame); } /** @inheritDoc */ diff --git a/src/id3v2/frames/privateFrame.ts b/src/id3v2/frames/privateFrame.ts index 2cd1a25..5a0b951 100644 --- a/src/id3v2/frames/privateFrame.ts +++ b/src/id3v2/frames/privateFrame.ts @@ -3,7 +3,7 @@ import {ByteVector, StringType} from "../../byteVector"; import {CorruptFileError, NotImplementedError} from "../../errors"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; -import {Guards} from "../../utils"; +import {ArrayUtils, Guards} from "../../utils"; /** * This class extends {@link Frame} implementing support for ID3v2 private (PRIV) frames. @@ -81,17 +81,9 @@ export default class PrivateFrame extends Frame { // #endregion - /** - * Get a specified private frame from the list of private frames that matches the provided - * parameters. - * @param frames List of frames to search - * @param owner Owner to match when searching - * @returns Matching frame or `undefined` if a match was not found - */ - public static find(frames: PrivateFrame[], owner: string): PrivateFrame { + public static filterFrames(frames: Frame[]): PrivateFrame[] { Guards.truthy(frames, "frames"); - - return frames.find((f) => f._owner === owner); + return ArrayUtils.ofType(frames, PrivateFrame); } /** @inheritDoc */ diff --git a/src/id3v2/frames/relativeVolumeFrame.ts b/src/id3v2/frames/relativeVolumeFrame.ts index 241609a..608a8fe 100644 --- a/src/id3v2/frames/relativeVolumeFrame.ts +++ b/src/id3v2/frames/relativeVolumeFrame.ts @@ -2,7 +2,7 @@ import Frame from "./frame"; import {ByteVector, StringType} from "../../byteVector"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; -import {Guards, NumberUtils} from "../../utils"; +import {ArrayUtils, Guards, NumberUtils} from "../../utils"; import {CorruptFileError} from "../../errors"; /** @@ -291,15 +291,9 @@ export class RelativeVolumeFrame extends Frame { return frame; } - /** - * Gets a specified volume adjustment frame from the list of relative volume frames - * @param frames List of frames to search - * @param identification Identification to match - * @returns Frame containing the matching user or `undefined` if a match was not found - */ - public static find(frames: RelativeVolumeFrame[], identification: string): RelativeVolumeFrame { + public static filterFrames(frames: Frame[]): RelativeVolumeFrame[] { Guards.truthy(frames, "frame"); - return frames.find((f) => f.identification === identification); + return ArrayUtils.ofType(frames, RelativeVolumeFrame); } /** diff --git a/src/id3v2/frames/synchronizedLyricsFrame.ts b/src/id3v2/frames/synchronizedLyricsFrame.ts index a8c863e..7689f63 100644 --- a/src/id3v2/frames/synchronizedLyricsFrame.ts +++ b/src/id3v2/frames/synchronizedLyricsFrame.ts @@ -4,7 +4,7 @@ import {ByteVector, StringType} from "../../byteVector"; import {CorruptFileError} from "../../errors"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; -import {Guards} from "../../utils"; +import {ArrayUtils, Guards} from "../../utils"; import {SynchronizedTextType, TimestampFormat} from "../utilTypes"; /** @@ -267,28 +267,9 @@ export class SynchronizedLyricsFrame extends Frame { // #region Public Methods - /** - * Gets a specified lyrics frame from a list of synchronized lyrics frames - * @param frames List of frames to search - * @param description Description to match - * @param textType Text type to match - * @param language Optionally, ISO-639-2 language code to match - * @returns Frame containing the matching user, `undefined` if a match was not found - */ - public static find( - frames: SynchronizedLyricsFrame[], - description: string, - textType: SynchronizedTextType, - language?: string - ): SynchronizedLyricsFrame { + public static filterFrames(frames: Frame[]): SynchronizedLyricsFrame[] { Guards.truthy(frames, "frames"); - return frames.find((f) => { - if (f.description !== description) { return false; } - if (language && f.language !== language) { return false; } - // noinspection RedundantIfStatementJS - if (f.textType !== textType) { return false; } - return true; - }); + return ArrayUtils.ofType(frames, SynchronizedLyricsFrame); } /** diff --git a/src/id3v2/frames/termsOfUseFrame.ts b/src/id3v2/frames/termsOfUseFrame.ts index 7b18af9..71cc527 100644 --- a/src/id3v2/frames/termsOfUseFrame.ts +++ b/src/id3v2/frames/termsOfUseFrame.ts @@ -4,7 +4,7 @@ import {ByteVector, StringType} from "../../byteVector"; import {CorruptFileError} from "../../errors"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; -import {Guards} from "../../utils"; +import {ArrayUtils, Guards} from "../../utils"; export default class TermsOfUseFrame extends Frame { private _language: string; @@ -104,15 +104,9 @@ export default class TermsOfUseFrame extends Frame { // #region Public Methods - /** - * Gets a specified terms of use frame from the list of frames - * @param frames List of frames to search - * @param language Optionally, the ISO-639-2 language code to match - * @returns A matching frame if found or `undefined` if a matching frame was not found - */ - public static find(frames: TermsOfUseFrame[], language?: string): TermsOfUseFrame { + public static filterFrames(frames: Frame[]): TermsOfUseFrame[] { Guards.truthy(frames, "frames"); - return frames.find((f) => !language || f.language === language); + return ArrayUtils.ofType(frames, TermsOfUseFrame); } /** diff --git a/src/id3v2/frames/textInformationFrame.ts b/src/id3v2/frames/textInformationFrame.ts index f9d127a..e8a43cd 100644 --- a/src/id3v2/frames/textInformationFrame.ts +++ b/src/id3v2/frames/textInformationFrame.ts @@ -3,7 +3,7 @@ import Id3v2Settings from "../id3v2Settings"; import {ByteVector, StringType} from "../../byteVector"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifier, FrameIdentifiers} from "../frameIdentifiers"; -import {Guards} from "../../utils"; +import {ArrayUtils, Guards} from "../../utils"; import {CorruptFileError} from "../../errors"; /** @@ -264,21 +264,12 @@ export default class TextInformationFrame extends Frame { // #region Public Methods - /** - * Gets a {@link TextInformationFrame} object of a specified type from a specified type from a - * list of text information frames. - * @param frames List of frames to search - * @param ident Frame identifier to search for - * @returns Matching frame if it exists in `tag`, `undefined` if a matching frame was not found - */ - public static findTextInformationFrame( - frames: TextInformationFrame[], - ident: FrameIdentifier - ): TextInformationFrame { + public static filterFrames(frames: Frame[], identifier: FrameIdentifier): TextInformationFrame[] { Guards.truthy(frames, "frames"); - Guards.truthy(ident, "ident"); - - return frames.find((f) => f.frameId === ident); + const textFrames = ArrayUtils.ofType(frames, TextInformationFrame); + return !!identifier + ? textFrames.filter(f => f.frameId === identifier) + : textFrames; } /** @inheritDoc */ diff --git a/src/id3v2/frames/uniqueFileIdentifierFrame.ts b/src/id3v2/frames/uniqueFileIdentifierFrame.ts index 9e072f9..1cd833c 100644 --- a/src/id3v2/frames/uniqueFileIdentifierFrame.ts +++ b/src/id3v2/frames/uniqueFileIdentifierFrame.ts @@ -3,7 +3,7 @@ import {ByteVector, StringType} from "../../byteVector"; import {CorruptFileError} from "../../errors"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; -import {Guards} from "../../utils"; +import {ArrayUtils, Guards} from "../../utils"; /** * Implements support for ID3v2 Unique File Identifier (UFID) frames. @@ -95,15 +95,9 @@ export default class UniqueFileIdentifierFrame extends Frame { // #region Methods - /** - * Gets a unique file identifier frame from a list of frames - * @param frames List of frames to search - * @param owner Owner to match - * @returns Frame containing the matching user, `undefined` if a match was not found - */ - public static find(frames: UniqueFileIdentifierFrame[], owner: string): UniqueFileIdentifierFrame { + public static filterFrames(frames: Frame[]): UniqueFileIdentifierFrame[] { Guards.truthy(frames, "frames"); - return frames.find((f) => f.owner === owner); + return ArrayUtils.ofType(frames, UniqueFileIdentifierFrame); } /** @inheritDoc */ diff --git a/src/id3v2/frames/unknownFrame.ts b/src/id3v2/frames/unknownFrame.ts index 939d796..af89323 100644 --- a/src/id3v2/frames/unknownFrame.ts +++ b/src/id3v2/frames/unknownFrame.ts @@ -2,7 +2,7 @@ import Frame from "./frame"; import {ByteVector} from "../../byteVector"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifier} from "../frameIdentifiers"; -import {Guards} from "../../utils"; +import {ArrayUtils, Guards} from "../../utils"; /** * Fallback type when no other frame class works for a given frame. @@ -46,6 +46,11 @@ export default class UnknownFrame extends Frame { */ public data: ByteVector; + public static FilterFrames(frames: Frame[]): UnknownFrame[] { + Guards.truthy(frames, "frames"); + return ArrayUtils.ofType(frames, UnknownFrame); + } + /** @inheritDoc */ public clone(): Frame { return UnknownFrame.fromData(this.header.frameId, this.data); diff --git a/src/id3v2/frames/unsynchronizedLyricsFrame.ts b/src/id3v2/frames/unsynchronizedLyricsFrame.ts index 715afcb..eededbc 100644 --- a/src/id3v2/frames/unsynchronizedLyricsFrame.ts +++ b/src/id3v2/frames/unsynchronizedLyricsFrame.ts @@ -4,7 +4,8 @@ import {ByteVector, StringType} from "../../byteVector"; import {CorruptFileError} from "../../errors"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; -import {Guards} from "../../utils"; +import {ArrayUtils, Guards} from "../../utils"; +import UnknownFrame from "./unknownFrame"; /** * Extends {@link Frame} implementing support for ID3v2 unsynchronized lyrics (USLT) frames. @@ -132,48 +133,9 @@ export default class UnsynchronizedLyricsFrame extends Frame { // #region Public Methods - /** - * Gets the first unsynchronized lyrics frame from a list of frames that matches the provided - * parameters. - * @param frames List of frames to search - * @param description Description to match - * @param language Optionally, ISO-639-2 language code to match - * @returns Frame that matches provided parameters, `undefined` if a match was not found - */ - public static find( - frames: UnsynchronizedLyricsFrame[], - description: string, - language: string - ): UnsynchronizedLyricsFrame { - Guards.truthy(frames, "frames"); - return frames.find((f) => { - if (f.description !== description) { return false; } - // noinspection RedundantIfStatementJS - if (language && f.language !== language) { return false; } - return true; - }); - } - - /** - * Gets all unsynchronized lyrics frames that match the provided parameters from a list of - * frames - * @param frames List of frames to search - * @param description Description to match - * @param language Optionally, ISO-639-2 language code to match - * @returns List of frames matching provided parameters, empty array if no matches were found - */ - public static findAll( - frames: UnsynchronizedLyricsFrame[], - description: string, - language: string - ): UnsynchronizedLyricsFrame[] { + public static filterFrames(frames: Frame[]): UnsynchronizedLyricsFrame[] { Guards.truthy(frames, "frames"); - return frames.filter((f) => { - if (f.description !== description) { return false; } - // noinspection RedundantIfStatementJS - if (language && f.language !== language) { return false; } - return true; - }); + return ArrayUtils.ofType(frames, UnsynchronizedLyricsFrame); } /** diff --git a/src/id3v2/frames/urlLinkFrame.ts b/src/id3v2/frames/urlLinkFrame.ts index 26d8b0a..b6a352d 100644 --- a/src/id3v2/frames/urlLinkFrame.ts +++ b/src/id3v2/frames/urlLinkFrame.ts @@ -2,7 +2,7 @@ import Frame from "./frame"; import {ByteVector, StringType} from "../../byteVector"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifier} from "../frameIdentifiers"; -import {Guards} from "../../utils"; +import {ArrayUtils, Guards} from "../../utils"; /** * Provides ID3v2 URL Link frame implementation (section 4.3.1) covering `W000` to `WZZZ`, @@ -91,17 +91,12 @@ export default class UrlLinkFrame extends Frame { // #region Methods - /** - * Gets the first frame that matches the provided type - * @param frames Object to search in - * @param ident Frame identifier to search for - * @returns Frame containing the matching frameId, `undefined` if a match was not found - */ - public static findUrlLinkFrame(frames: UrlLinkFrame[], ident: FrameIdentifier): UrlLinkFrame { + public static filterFrames(frames: Frame[], identifier: FrameIdentifier): UrlLinkFrame[] { Guards.truthy(frames, "frames"); - Guards.truthy(ident, "ident"); - - return frames.find((f) => f.frameId === ident); + const urlFrames = ArrayUtils.ofType(frames, UrlLinkFrame); + return !!identifier + ? urlFrames.filter(f => f.frameId === identifier) + : urlFrames; } /** @inheritDoc */ diff --git a/src/id3v2/frames/userTextInformationFrame.ts b/src/id3v2/frames/userTextInformationFrame.ts index 1188b57..cbbd9c0 100644 --- a/src/id3v2/frames/userTextInformationFrame.ts +++ b/src/id3v2/frames/userTextInformationFrame.ts @@ -4,7 +4,7 @@ import {ByteVector, StringType} from "../../byteVector"; import Frame from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; -import {Guards, StringComparison} from "../../utils"; +import {ArrayUtils, Guards, StringComparison} from "../../utils"; import {CorruptFileError} from "../../errors"; export default class UserTextInformationFrame extends TextInformationFrame { @@ -104,23 +104,9 @@ export default class UserTextInformationFrame extends TextInformationFrame { // #region Public Methods - /** - * Gets a user text information frame from a specified tag - * @param frames Object to search in - * @param description Description to use to match the frame in the `tag` - * @param caseSensitive Whether or not to search for the frame case-sensitively. - * @returns Frame containing the matching user, `undefined` if a match was not found - */ - public static findUserTextInformationFrame( - frames: UserTextInformationFrame[], - description: string, - caseSensitive: boolean = true - ): UserTextInformationFrame { + public static filterFrames(frames: Frame[]): UserTextInformationFrame[] { Guards.truthy(frames, "frames"); - Guards.truthy(description, "description"); - - const comparison = caseSensitive ? StringComparison.caseSensitive : StringComparison.caseInsensitive; - return frames.find((f) => comparison(f.description, description)); + return ArrayUtils.ofType(frames, UserTextInformationFrame); } /** @inheritDoc */ diff --git a/src/id3v2/frames/userUrlLinkFrame.ts b/src/id3v2/frames/userUrlLinkFrame.ts index 95e9c4a..99dee7a 100644 --- a/src/id3v2/frames/userUrlLinkFrame.ts +++ b/src/id3v2/frames/userUrlLinkFrame.ts @@ -3,7 +3,8 @@ import UrlLinkFrame from "./urlLinkFrame"; import {ByteVector, StringType} from "../../byteVector"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; -import {Guards} from "../../utils"; +import {ArrayUtils, Guards} from "../../utils"; +import Frame from "./frame"; /** * Provides support for ID3v2 User URL Link frames (WXXX). @@ -114,6 +115,11 @@ export default class UserUrlLinkFrame extends UrlLinkFrame { // #region Methods + public static filterFrames(frames: Frame[]): UserUrlLinkFrame[] { + Guards.truthy(frames, "frames"); + return ArrayUtils.ofType(frames, UserUrlLinkFrame); + } + /** * Gets a frame from a list of frames. * @param frames List of frames to search diff --git a/src/id3v2/id3v2Tag.ts b/src/id3v2/id3v2Tag.ts index 4635f50..2dc7566 100644 --- a/src/id3v2/id3v2Tag.ts +++ b/src/id3v2/id3v2Tag.ts @@ -1,5 +1,6 @@ import AttachmentFrame from "./frames/attachmentFrame"; import CommentsFrame from "./frames/commentsFrame"; +import Frame from "./frames/frame"; import GenreFrame from "./frames/genreFrame"; import Id3v2ExtendedHeader from "./id3v2ExtendedHeader"; import Id3v2TagFooter from "./id3v2TagFooter"; @@ -13,7 +14,6 @@ import UserTextInformationFrame from "./frames/userTextInformationFrame"; import {ByteVector, StringType} from "../byteVector"; import {CorruptFileError, NotImplementedError, NotSupportedError} from "../errors"; import {File, ReadStyle} from "../file"; -import {Frame, FrameClassType} from "./frames/frame"; import {Id3v2FrameFactory} from "./frames/frameFactory"; import {FrameIdentifier, FrameIdentifiers} from "./frameIdentifiers"; import {Id3v2FrameFlags} from "./frames/frameHeader"; @@ -196,18 +196,9 @@ export default class Id3v2Tag extends Tag { // Migrate any incompatible frames that have direct migrations if (value === 4 && (originalVersion === 2 || originalVersion === 3)) { // * TYER, etc -> TDRC - const tyerFrames = this.getFramesByIdentifier( - FrameClassType.TextInformationFrame, - FrameIdentifiers.TYER - ); - const tdatFrames = this.getFramesByIdentifier( - FrameClassType.TextInformationFrame, - FrameIdentifiers.TDAT - ); - const timeFrames = this.getFramesByIdentifier( - FrameClassType.TextInformationFrame, - FrameIdentifiers.TIME - ); + const tyerFrames = TextInformationFrame.filterFrames(this._frameList, FrameIdentifiers.TYER); + const tdatFrames = TextInformationFrame.filterFrames(this._frameList, FrameIdentifiers.TDAT); + const timeFrames = TextInformationFrame.filterFrames(this._frameList, FrameIdentifiers.TIME); if (tyerFrames.length > 0) { this.removeFrames(FrameIdentifiers.TYER); this.removeFrames(FrameIdentifiers.TDAT); @@ -227,10 +218,7 @@ export default class Id3v2Tag extends Tag { } } else if (originalVersion === 4 && (value === 2 || value === 3)) { // * TDRC -> TYER, etc - const tdrcFrames = this.getFramesByIdentifier( - FrameClassType.TextInformationFrame, - FrameIdentifiers.TDRC - ); + const tdrcFrames = TextInformationFrame.filterFrames(this._frameList, FrameIdentifiers.TDRC); if (tdrcFrames.length > 0) { const tdrcText = tdrcFrames[0].text[0]; this.removeFrames(FrameIdentifiers.TDRC); @@ -467,7 +455,7 @@ export default class Id3v2Tag extends Tag { * @remarks Stored in the `COMM` frame */ get comment(): string { - const frames = this.getFramesByClassType(FrameClassType.CommentsFrame); + const frames = CommentsFrame.filterFrames(this._frameList); const f = CommentsFrame.findPreferred(frames, "", Id3v2Tag.language); return f ? f.toString() : undefined; } @@ -476,9 +464,9 @@ export default class Id3v2Tag extends Tag { * @remarks Stored in the `COMM` frame */ set comment(value: string) { - const commentFrames = this.getFramesByClassType(FrameClassType.CommentsFrame); + const commentFrames = CommentsFrame.filterFrames(this._frameList); - // Delete the "" comment frames that are in this language + // Delete the "" comment frames that are in this language @TODO: That's not what this does if (!value) { this.removeFrames(FrameIdentifiers.COMM); return; @@ -555,20 +543,14 @@ export default class Id3v2Tag extends Tag { } // Case 1: We have a TDRC frame (v2.4), preferentially replace contents with year - const tdrcFrames = this.getFramesByIdentifier( - FrameClassType.TextInformationFrame, - FrameIdentifiers.TDRC - ); + const tdrcFrames = TextInformationFrame.filterFrames(this._frameList, FrameIdentifiers.TDRC); if (tdrcFrames.length > 0) { this.setNumberFrame(FrameIdentifiers.TDRC, value, 0); return; } // Case 2: We have a TYER/TYE frame (v2.3/v2.2) - const tyerFrames = this.getFramesByIdentifier( - FrameClassType.TextInformationFrame, - FrameIdentifiers.TYER - ); + const tyerFrames = TextInformationFrame.filterFrames(this._frameList, FrameIdentifiers.TYER) if (tyerFrames.length > 0) { this.setNumberFrame(FrameIdentifiers.TYER, value, 0); return; @@ -632,7 +614,7 @@ export default class Id3v2Tag extends Tag { * @remarks Stored in the `USLT` frame */ get lyrics(): string { - const frames = this.getFramesByClassType(FrameClassType.UnsynchronizedLyricsFrame); + const frames = UnsynchronizedLyricsFrame.filterFrames(this._frameList); const frame = UnsynchronizedLyricsFrame.findPreferred(frames, "", Id3v2Tag.language); return frame ? frame.toString() : undefined; } @@ -641,7 +623,7 @@ export default class Id3v2Tag extends Tag { * @remarks Stored in the `USLT` frame */ set lyrics(value: string) { - const frames = this.getFramesByClassType(FrameClassType.UnsynchronizedLyricsFrame); + const frames = UnsynchronizedLyricsFrame.filterFrames(this._frameList); // Delete all unsynchronized lyrics frames in this language // @TODO: Verify that deleting only this language is the correct behavior @@ -993,7 +975,7 @@ export default class Id3v2Tag extends Tag { * @remarks Stored in the `APIC` frame */ get pictures(): IPicture[] { - return this.getFramesByClassType(FrameClassType.AttachmentFrame).slice(0); + return AttachmentFrame.filterFrames(this._frameList).slice(0); } /** * @inheritDoc @@ -1069,38 +1051,6 @@ export default class Id3v2Tag extends Tag { } } - /** - * Gets all frames with a specific frame class type. - * NOTE: This diverges from the .NET implementation due to the inability to do type checking - * like in .NET (ie `x is y`). Instead, type guards are added to each frame class which provides - * the same functionality. - * @param type Class type of the frame to find - * @returns TFrame[] Array of frames with the specified class type - */ - public getFramesByClassType(type: FrameClassType): TFrame[] { - // TODO: Can we access static properties from TFrame? if so, can we use that to get the frame class type? - Guards.notNullOrUndefined(type, "type"); - - return this._frameList.filter((f) => f && f.frameClassType === type); - } - - /** - * Gets a list of frames with the specified identifier contained in the current instance. - * NOTE: This implementation deviates a bit from the original .NET implementation due to the - * inability to do `x is y` comparison by types in typescript without type guards. - * `type` is the type guard for differentiating frame types. If all frames are needed - * use {@link frames}. - * @param type Type of frame to return - * @param ident Identifier of the frame - * @returns TFrame[] Array of frames with the desired frame identifier - */ - public getFramesByIdentifier(type: FrameClassType, ident: FrameIdentifier): TFrame[] { - Guards.notNullOrUndefined(type, "type"); - Guards.truthy(ident, "ident"); - - return this._frameList.filter((f) => f && f.frameClassType === type && f.frameId === ident); - } - /** * Gets the text value from a specified text information frame (or URL frame if that was * specified). @@ -1112,14 +1062,11 @@ export default class Id3v2Tag extends Tag { let frame: Frame; if (ident.isUrlFrame) { - const frames = this.getFramesByClassType(FrameClassType.UrlLinkFrame); - frame = UrlLinkFrame.findUrlLinkFrame(frames, ident); + frame = UrlLinkFrame.filterFrames(this._frameList, ident)[0]; } else if (ident === FrameIdentifiers.TCON) { - const frames = this.getFramesByClassType(FrameClassType.GenreFrame); - frame = GenreFrame.findGenreFrame(frames); + frame = GenreFrame.filterFrames(this._frameList)[0]; } else { - const frames = this.getFramesByClassType(FrameClassType.TextInformationFrame); - frame = TextInformationFrame.findTextInformationFrame(frames, ident); + frame = TextInformationFrame.filterFrames(this._frameList, ident)[0]; } const result = frame ? frame.toString() : undefined; @@ -1346,15 +1293,13 @@ export default class Id3v2Tag extends Tag { let frame: TextInformationFrame|GenreFrame; if (ident === FrameIdentifiers.TCON) { - const frames = this.getFramesByClassType(FrameClassType.GenreFrame); - frame = GenreFrame.findGenreFrame(frames); + frame = GenreFrame.filterFrames(this._frameList)[0]; if (!frame) { frame = GenreFrame.fromEncoding(); this.addFrame(frame); } } else { - const frames = this.getFramesByClassType(FrameClassType.TextInformationFrame); - frame = TextInformationFrame.findTextInformationFrame(frames, ident); + frame = TextInformationFrame.filterFrames(this._frameList, ident)[0]; if (!frame) { frame = TextInformationFrame.fromIdentifier(ident); this.addFrame(frame); @@ -1387,8 +1332,7 @@ export default class Id3v2Tag extends Tag { return; } - const frames = this.getFramesByClassType(FrameClassType.UrlLinkFrame); - let urlFrame = UrlLinkFrame.findUrlLinkFrame(frames, ident); + let urlFrame = UrlLinkFrame.filterFrames(this._frameList, ident)[0]; if (!urlFrame) { urlFrame = UrlLinkFrame.fromIdentity(ident); this.addFrame(urlFrame); @@ -1549,13 +1493,11 @@ export default class Id3v2Tag extends Tag { private getTextAsArray(ident: FrameIdentifier): string[] { if (ident === FrameIdentifiers.TCON) { - const frames = this.getFramesByClassType(FrameClassType.GenreFrame); - const frame = GenreFrame.findGenreFrame(frames); + const frame = GenreFrame.filterFrames(this._frameList)[0]; return frame ? frame.text : []; } - const frames = this.getFramesByClassType(FrameClassType.TextInformationFrame); - const frame = TextInformationFrame.findTextInformationFrame(frames, ident); + const frame = TextInformationFrame.filterFrames(this._frameList, ident)[0]; return frame ? frame.text : []; } @@ -1580,7 +1522,7 @@ export default class Id3v2Tag extends Tag { private getUfidText(owner: string): string { // Get the UFID frame, frame will be undefined if nonexistent - const frames = this.getFramesByClassType(FrameClassType.UniqueFileIdentifierFrame); + const frames = UniqueFileIdentifierFrame.filterFrames(this._frameList); const frame = UniqueFileIdentifierFrame.find(frames, owner); // If the frame existed, frame.identifier is a byte vector, get a string @@ -1590,7 +1532,7 @@ export default class Id3v2Tag extends Tag { private getUserTextAsString(description: string, caseSensitive: boolean = true): string { // Gets the TXXX frame, frame will be undefined if nonexistent - const frames = this.getFramesByClassType(FrameClassType.UserTextInformationFrame); + const frames = UserTextInformationFrame.filterFrames(this._frameList); const frame = UserTextInformationFrame.findUserTextInformationFrame(frames, description, caseSensitive); // TXXX frames support multi-value strings, join them up and return only the text from the @@ -1601,7 +1543,7 @@ export default class Id3v2Tag extends Tag { private setUfidText(owner: string, text: string): void { // Get the UFID frame, create if necessary - const frames = this.getFramesByClassType(FrameClassType.UniqueFileIdentifierFrame); + const frames = UniqueFileIdentifierFrame.filterFrames(this._frameList); let frame = UniqueFileIdentifierFrame.find(frames, owner); // If we have a real string, convert to byte vector and apply to frame @@ -1617,7 +1559,7 @@ export default class Id3v2Tag extends Tag { private setUserTextAsString(description: string, text: string, caseSensitive: boolean = true): void { // Get the TXXX frame, create a new one if needed - const frames = this.getFramesByClassType(FrameClassType.UserTextInformationFrame); + const frames = UserTextInformationFrame.filterFrames(this._frameList); let frame = UserTextInformationFrame.findUserTextInformationFrame(frames, description, caseSensitive); if (!text) { diff --git a/src/utils.ts b/src/utils.ts index 21ecdb1..b301422 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -171,7 +171,18 @@ export class FileUtils { } } +// eslint-disable-next-line @typescript-eslint/ban-types +export type TypeReference = Function & { prototype: T }; + export class ArrayUtils { + public static isFalsyOrEmpty(array: unknown[]): boolean { + return !array || array.length === 0; + } + + public static ofType(array: unknown[], type: TypeReference): T[] { + return array.filter((e): e is T => e instanceof type); + } + public static remove(array: T[], callbackFn: (e: T, i: number) => boolean): void { let i = array.length; while (i--) { @@ -181,10 +192,6 @@ export class ArrayUtils { } } - public static isFalsyOrEmpty(array: unknown[]): boolean { - return !array || array.length === 0; - } - public static safePush(array: T[], element: T): void { if (element) { array.push(element); From 7bca5f24322921a1a4d60fe741bec2e978e678c0 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 30 Jun 2026 11:50:12 -0500 Subject: [PATCH 3/9] Change ID3v2 tag to use the new filter methods. --- src/id3v2/id3v2Tag.ts | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/id3v2/id3v2Tag.ts b/src/id3v2/id3v2Tag.ts index 2dc7566..227040e 100644 --- a/src/id3v2/id3v2Tag.ts +++ b/src/id3v2/id3v2Tag.ts @@ -623,8 +623,6 @@ export default class Id3v2Tag extends Tag { * @remarks Stored in the `USLT` frame */ set lyrics(value: string) { - const frames = UnsynchronizedLyricsFrame.filterFrames(this._frameList); - // Delete all unsynchronized lyrics frames in this language // @TODO: Verify that deleting only this language is the correct behavior if (!value) { @@ -633,7 +631,8 @@ export default class Id3v2Tag extends Tag { } // Find or create the appropriate unsynchronized lyrics frame - let frame = UnsynchronizedLyricsFrame.find(frames, "", Id3v2Tag.language); + const frames = UnsynchronizedLyricsFrame.filterFrames(this._frameList); + let frame = frames.find(f => f.language === Id3v2Tag.language); if (!frame) { frame = UnsynchronizedLyricsFrame.fromData("", Id3v2Tag.language); this.addFrame(frame); @@ -1523,7 +1522,7 @@ export default class Id3v2Tag extends Tag { private getUfidText(owner: string): string { // Get the UFID frame, frame will be undefined if nonexistent const frames = UniqueFileIdentifierFrame.filterFrames(this._frameList); - const frame = UniqueFileIdentifierFrame.find(frames, owner); + const frame = frames.find(f => f.owner === owner); // If the frame existed, frame.identifier is a byte vector, get a string const result = frame ? frame.identifier.toString(StringType.Latin1) : undefined; @@ -1531,12 +1530,9 @@ export default class Id3v2Tag extends Tag { } private getUserTextAsString(description: string, caseSensitive: boolean = true): string { - // Gets the TXXX frame, frame will be undefined if nonexistent - const frames = UserTextInformationFrame.filterFrames(this._frameList); - const frame = UserTextInformationFrame.findUserTextInformationFrame(frames, description, caseSensitive); - // TXXX frames support multi-value strings, join them up and return only the text from the // frame + const frame = this.getUserTextFrame(description, caseSensitive); const result = frame ? frame.text.join(";") : undefined; // TODO: Consider escaping ';' before joining? return result || undefined; } @@ -1544,7 +1540,7 @@ export default class Id3v2Tag extends Tag { private setUfidText(owner: string, text: string): void { // Get the UFID frame, create if necessary const frames = UniqueFileIdentifierFrame.filterFrames(this._frameList); - let frame = UniqueFileIdentifierFrame.find(frames, owner); + let frame = frames.find(f => f.owner === owner); // If we have a real string, convert to byte vector and apply to frame if (!text && frame) { @@ -1558,10 +1554,7 @@ export default class Id3v2Tag extends Tag { } private setUserTextAsString(description: string, text: string, caseSensitive: boolean = true): void { - // Get the TXXX frame, create a new one if needed - const frames = UserTextInformationFrame.filterFrames(this._frameList); - let frame = UserTextInformationFrame.findUserTextInformationFrame(frames, description, caseSensitive); - + let frame = this.getUserTextFrame(description, caseSensitive); if (!text) { // Remove the frame if it exists, otherwise do nothing if (frame) { @@ -1576,5 +1569,15 @@ export default class Id3v2Tag extends Tag { } } + private getUserTextFrame(description: string, caseSensitive: boolean): UserTextInformationFrame { + // Gets the TXXX frame, frame will be undefined if nonexistent + const frames = UserTextInformationFrame.filterFrames(this._frameList); + return frames.find(f => { + return caseSensitive + ? f.description === description + : f.description.toUpperCase() === description.toUpperCase(); + }); + } + // #endregion } From 1bff6b559425f84624e9f7f640438c0e3440bce6 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 30 Jun 2026 11:52:14 -0500 Subject: [PATCH 4/9] Fixup Index --- src/index.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/index.ts b/src/index.ts index 871b81f..8d0a71d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -93,10 +93,7 @@ export { EventTimeCode as Id3v2EventTimeCode, EventTimeCodeFrame as Id3v2EventTimeCodeFrame } from "./id3v2/frames/eventTimeCodeFrame"; -export { - Frame as Id3v2Frame, - FrameClassType as Id3v2FrameClassType -} from "./id3v2/frames/frame"; +export {default as Id3v2Frame} from "./id3v2/frames/frame"; export { FrameCreator as Id3v2FrameCreator, Id3v2FrameFactory From 1d60b6f0a0c4fe2b4a3c115294c48380f2bc9575 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 30 Jun 2026 23:01:51 -0500 Subject: [PATCH 5/9] Fix Tests --- src/id3v2/frames/eventTimeCodeFrame.ts | 2 +- src/id3v2/frames/textInformationFrame.ts | 2 +- src/id3v2/frames/unknownFrame.ts | 2 +- src/id3v2/frames/unsynchronizedLyricsFrame.ts | 1 - src/id3v2/frames/urlLinkFrame.ts | 6 +- src/id3v2/id3v2Tag.ts | 2 +- test-unit/id3v2/attachmentsFrameTests.ts | 229 ++++++------- test-unit/id3v2/commentsFrameTests.ts | 181 ++++------ test-unit/id3v2/eventTimeCodeFrameTests.ts | 122 +++++-- test-unit/id3v2/frameConstructorTests.ts | 2 +- test-unit/id3v2/frameFactoryTests.ts | 100 +++--- test-unit/id3v2/frameTests.ts | 6 +- test-unit/id3v2/genreFrameTests.ts | 85 ++++- test-unit/id3v2/id3v2TagTests.ts | 265 +++++---------- .../id3v2/musicCdIdentifierFrameTests.ts | 90 ++++- test-unit/id3v2/playCountFrameTests.ts | 112 ++++++- test-unit/id3v2/popularimeterFrameTests.ts | 131 +++++--- test-unit/id3v2/privateFrameTests.ts | 115 ++++--- test-unit/id3v2/relativeVolumeFrameTests.ts | 150 +++++++-- .../id3v2/synchronizedLyricsFrameTests.ts | 282 +++++----------- test-unit/id3v2/termsOfUseFrameTests.ts | 130 ++++---- test-unit/id3v2/textInformationFrameTests.ts | 248 +++++++------- .../id3v2/uniqueFileIdentifierFrameTests.ts | 134 +++++--- test-unit/id3v2/unknownFrameTests.ts | 123 +++++-- .../id3v2/unsynchronizedLyricsFrameTests.ts | 312 ++++-------------- test-unit/id3v2/urlLinkFrameTests.ts | 199 ++++++++--- .../id3v2/userTextInformationFrameTests.ts | 171 ++++------ test-unit/id3v2/userUrlLinkFrameTests.ts | 118 ++++--- 28 files changed, 1711 insertions(+), 1609 deletions(-) diff --git a/src/id3v2/frames/eventTimeCodeFrame.ts b/src/id3v2/frames/eventTimeCodeFrame.ts index f893de9..c729279 100644 --- a/src/id3v2/frames/eventTimeCodeFrame.ts +++ b/src/id3v2/frames/eventTimeCodeFrame.ts @@ -189,7 +189,7 @@ export class EventTimeCodeFrame extends Frame { // #region Methods - public filterFrames(frames: Frame[]): EventTimeCodeFrame[] { + public static filterFrames(frames: Frame[]): EventTimeCodeFrame[] { Guards.truthy(frames, "frames"); return ArrayUtils.ofType(frames, EventTimeCodeFrame); } diff --git a/src/id3v2/frames/textInformationFrame.ts b/src/id3v2/frames/textInformationFrame.ts index e8a43cd..b54ca18 100644 --- a/src/id3v2/frames/textInformationFrame.ts +++ b/src/id3v2/frames/textInformationFrame.ts @@ -264,7 +264,7 @@ export default class TextInformationFrame extends Frame { // #region Public Methods - public static filterFrames(frames: Frame[], identifier: FrameIdentifier): TextInformationFrame[] { + public static filterFrames(frames: Frame[], identifier?: FrameIdentifier): TextInformationFrame[] { Guards.truthy(frames, "frames"); const textFrames = ArrayUtils.ofType(frames, TextInformationFrame); return !!identifier diff --git a/src/id3v2/frames/unknownFrame.ts b/src/id3v2/frames/unknownFrame.ts index af89323..19f197d 100644 --- a/src/id3v2/frames/unknownFrame.ts +++ b/src/id3v2/frames/unknownFrame.ts @@ -46,7 +46,7 @@ export default class UnknownFrame extends Frame { */ public data: ByteVector; - public static FilterFrames(frames: Frame[]): UnknownFrame[] { + public static filterFrames(frames: Frame[]): UnknownFrame[] { Guards.truthy(frames, "frames"); return ArrayUtils.ofType(frames, UnknownFrame); } diff --git a/src/id3v2/frames/unsynchronizedLyricsFrame.ts b/src/id3v2/frames/unsynchronizedLyricsFrame.ts index eededbc..d8a3836 100644 --- a/src/id3v2/frames/unsynchronizedLyricsFrame.ts +++ b/src/id3v2/frames/unsynchronizedLyricsFrame.ts @@ -5,7 +5,6 @@ import {CorruptFileError} from "../../errors"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; import {ArrayUtils, Guards} from "../../utils"; -import UnknownFrame from "./unknownFrame"; /** * Extends {@link Frame} implementing support for ID3v2 unsynchronized lyrics (USLT) frames. diff --git a/src/id3v2/frames/urlLinkFrame.ts b/src/id3v2/frames/urlLinkFrame.ts index b6a352d..57f7d67 100644 --- a/src/id3v2/frames/urlLinkFrame.ts +++ b/src/id3v2/frames/urlLinkFrame.ts @@ -69,7 +69,7 @@ export default class UrlLinkFrame extends Frame { * Constructs and initializes an empty frame with the provided frame identity * @param ident Identity of the frame to construct */ - public static fromIdentity(ident: FrameIdentifier): UrlLinkFrame { + public static fromIdentifier(ident: FrameIdentifier): UrlLinkFrame { Guards.truthy(ident, "ident"); return new UrlLinkFrame(new Id3v2FrameHeader(ident)); } @@ -91,7 +91,7 @@ export default class UrlLinkFrame extends Frame { // #region Methods - public static filterFrames(frames: Frame[], identifier: FrameIdentifier): UrlLinkFrame[] { + public static filterFrames(frames: Frame[], identifier?: FrameIdentifier): UrlLinkFrame[] { Guards.truthy(frames, "frames"); const urlFrames = ArrayUtils.ofType(frames, UrlLinkFrame); return !!identifier @@ -101,7 +101,7 @@ export default class UrlLinkFrame extends Frame { /** @inheritDoc */ public clone(): UrlLinkFrame { - const frame = UrlLinkFrame.fromIdentity(this.frameId); + const frame = UrlLinkFrame.fromIdentifier(this.frameId); frame._text = this._text; return frame; } diff --git a/src/id3v2/id3v2Tag.ts b/src/id3v2/id3v2Tag.ts index 227040e..712a27f 100644 --- a/src/id3v2/id3v2Tag.ts +++ b/src/id3v2/id3v2Tag.ts @@ -1333,7 +1333,7 @@ export default class Id3v2Tag extends Tag { let urlFrame = UrlLinkFrame.filterFrames(this._frameList, ident)[0]; if (!urlFrame) { - urlFrame = UrlLinkFrame.fromIdentity(ident); + urlFrame = UrlLinkFrame.fromIdentifier(ident); this.addFrame(urlFrame); } diff --git a/test-unit/id3v2/attachmentsFrameTests.ts b/test-unit/id3v2/attachmentsFrameTests.ts index 9027d77..9d023f4 100644 --- a/test-unit/id3v2/attachmentsFrameTests.ts +++ b/test-unit/id3v2/attachmentsFrameTests.ts @@ -3,14 +3,15 @@ import {params, suite, test} from "@testdeck/mocha"; import {assert} from "chai"; import AttachmentFrame from "../../src/id3v2/frames/attachmentFrame"; +import Frame from "../../src/id3v2/frames/frame"; import FrameConstructorTests from "./frameConstructorTests"; import Id3v2Settings from "../../src/id3v2/id3v2Settings"; import PropertyTests from "../utilities/propertyTests"; +import UnknownFrame from "../../src/id3v2/frames/unknownFrame"; import {ByteVector, StringType} from "../../src/byteVector"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifier, FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; -import {IPicture, PictureType} from "../../src/picture"; +import {IPicture, Picture, PictureType} from "../../src/picture"; import {Testers} from "../utilities/testers"; const getTestFrame = () => getCustomTestFrame( @@ -38,6 +39,30 @@ const getCustomTestFrame = ( return AttachmentFrame.fromPicture(mockPicture.object); } +const verifyFrame = ( + frame: AttachmentFrame, + frameIdentifier: FrameIdentifier, + data: ByteVector, + description: string, + filename: string, + mimeType: string, + encoding: StringType, + pictureType: PictureType +): void => { + assert.isOk(frame); + assert.instanceOf(frame, AttachmentFrame); + + Testers.bvEqual(frame.data, data); + assert.strictEqual(frame.description, description); + assert.strictEqual(frame.filename, filename); + assert.strictEqual(frame.mimeType, mimeType); + assert.strictEqual(frame.textEncoding, encoding); + assert.strictEqual(frame.type, pictureType); + + // NOTE: This happens last because the frame identifier can be changed after parsing. + assert.strictEqual(frame.frameId, frameIdentifier); +} + @suite class Id3v2_AttachmentFrame_ConstructorTests extends FrameConstructorTests { get fromFieldBytes(): (h: Id3v2FrameHeader, d: ByteVector, v: number) => Frame { return AttachmentFrame.fromFieldBytes; @@ -64,7 +89,7 @@ const getCustomTestFrame = ( const frame = AttachmentFrame.fromPicture(mockPicture.object); // Assert - Id3v2_AttachmentFrame_ConstructorTests.verifyFrame( + verifyFrame( frame, FrameIdentifiers.APIC, data, @@ -91,7 +116,7 @@ const getCustomTestFrame = ( const frame = AttachmentFrame.fromPicture(mockPicture.object); // Assert - Id3v2_AttachmentFrame_ConstructorTests.verifyFrame( + verifyFrame( frame, FrameIdentifiers.GEOB, data, @@ -128,7 +153,7 @@ const getCustomTestFrame = ( const frame = AttachmentFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_AttachmentFrame_ConstructorTests.verifyFrame( + verifyFrame( frame, FrameIdentifiers.APIC, testData, @@ -160,7 +185,7 @@ const getCustomTestFrame = ( const frame = AttachmentFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_AttachmentFrame_ConstructorTests.verifyFrame( + verifyFrame( frame, FrameIdentifiers.APIC, testData, @@ -191,7 +216,7 @@ const getCustomTestFrame = ( const frame = AttachmentFrame.fromFieldBytes(header, fieldBytes, 2); // Assert - Id3v2_AttachmentFrame_ConstructorTests.verifyFrame( + verifyFrame( frame, FrameIdentifiers.APIC, testData, @@ -225,7 +250,7 @@ const getCustomTestFrame = ( const frame = AttachmentFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_AttachmentFrame_ConstructorTests.verifyFrame( + verifyFrame( frame, FrameIdentifiers.GEOB, testData, @@ -259,7 +284,7 @@ const getCustomTestFrame = ( const frame = AttachmentFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_AttachmentFrame_ConstructorTests.verifyFrame( + verifyFrame( frame, FrameIdentifiers.GEOB, testData, @@ -270,29 +295,6 @@ const getCustomTestFrame = ( PictureType.NotAPicture ); } - - private static verifyFrame( - frame: AttachmentFrame, - ft: FrameIdentifier, - d: ByteVector, - desc: string, - fn: string, - mt: string, - te: StringType, - t: PictureType - ) { - assert.isOk(frame); - assert.equal(frame.frameClassType, FrameClassType.AttachmentFrame); - - Testers.bvEqual(frame.data, d); - assert.strictEqual(frame.description, desc); - assert.strictEqual(frame.filename, fn); - assert.strictEqual(frame.mimeType, mt); - assert.strictEqual(frame.textEncoding, te); - assert.strictEqual(frame.type, t); - - assert.strictEqual(frame.frameId, ft); - } } @suite class Id3v2_AttachmentFrame_PropertyTests { @@ -422,16 +424,16 @@ const getCustomTestFrame = ( const output = frame.clone(); // Assert - assert.isOk(output); - assert.equal(output.frameClassType, FrameClassType.AttachmentFrame); - - Testers.bvEqual(output.data, frame.data); - assert.strictEqual(output.description, frame.description); - assert.strictEqual(output.filename, frame.filename); - assert.strictEqual(output.mimeType, frame.mimeType); - assert.strictEqual(output.textEncoding, frame.textEncoding); - assert.strictEqual(output.type, frame.type); - assert.strictEqual(frame.frameId, frame.frameId); + verifyFrame( + output, + frame.frameId, + frame.data, + frame.description, + frame.filename, + frame.mimeType, + frame.textEncoding, + frame.type + ); } @test @@ -454,16 +456,16 @@ const getCustomTestFrame = ( const output = frame.clone(); // Assert - assert.isOk(output); - assert.equal(output.frameClassType, FrameClassType.AttachmentFrame); - - Testers.bvEqual(output.data, frame.data); - assert.strictEqual(output.description, frame.description); - assert.strictEqual(output.filename, frame.filename); - assert.strictEqual(output.mimeType, frame.mimeType); - assert.strictEqual(output.textEncoding, frame.textEncoding); - assert.strictEqual(output.type, frame.type); - assert.strictEqual(frame.frameId, frame.frameId); + verifyFrame( + output, + frame.frameId, + frame.data, + frame.description, + frame.filename, + frame.mimeType, + frame.textEncoding, + frame.type + ); } @test @@ -477,124 +479,107 @@ const getCustomTestFrame = ( const output = frame.clone(); // Assert - assert.isOk(output); - assert.equal(output.frameClassType, FrameClassType.AttachmentFrame); - - Testers.bvEqual(output.data, frame.data); - assert.strictEqual(output.description, frame.description); - assert.strictEqual(output.filename, frame.filename); - assert.strictEqual(output.mimeType, frame.mimeType); - assert.strictEqual(output.textEncoding, frame.textEncoding); - assert.strictEqual(output.type, frame.type); - assert.strictEqual(frame.frameId, frame.frameId); + verifyFrame( + output, + frame.frameId, + frame.data, + frame.description, + frame.filename, + frame.mimeType, + frame.textEncoding, + frame.type + ); } @test - public find_falsyFrames() { - // Act / Assert - assert.throws(() => { AttachmentFrame.find(undefined); }); - assert.throws(() => { AttachmentFrame.find(null); }); + public filterFrames_falsyFrames() { + Testers.testTruthy((v: Frame[]) => AttachmentFrame.filterFrames(v)); } @test - public find_noFrames() { + public filterFrames_noFrames() { // Arrange - const frames: AttachmentFrame[] = []; + const frames: Frame[] = []; // Act - const output = AttachmentFrame.find(frames); + const output = AttachmentFrame.filterFrames(frames); // Assert - assert.isUndefined(output); + assert.isArray(output); + assert.isEmpty(output); } @test - public find_noMatchByDescription() { + public filterFrames_noMatch() { // Arrange - const frame1 = getTestFrame(); - frame1.description = "fux"; - frame1.type = PictureType.Artist; - const frame2 = getTestFrame(); - frame2.description = "bux"; - frame2.type = PictureType.Artist; - + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(234)); const frames = [frame1, frame2]; // Act - const output = AttachmentFrame.find(frames, "qux", PictureType.Artist); + const result = AttachmentFrame.filterFrames(frames); // Assert - assert.isUndefined(output); + assert.isArray(result); + assert.isEmpty(result); } @test - public find_noMatchByType() { - const frame1 = getTestFrame(); - frame1.description = "qux"; - frame1.type = PictureType.FrontCover; - const frame2 = getTestFrame(); - frame2.description = "qux"; - frame2.type = PictureType.BackCover; + public filterFrames_singleMatch() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + + const pic2 = Picture.fromData(ByteVector.fromUint(8888)); + const frame2 = AttachmentFrame.fromPicture(pic2); const frames = [frame1, frame2]; // Act - const output = AttachmentFrame.find(frames, "qux", PictureType.Artist); + const result = AttachmentFrame.filterFrames(frames); // Assert - assert.isUndefined(output); + assert.isArray(result); + assert.deepEqual(result, [frame2]); } @test - public find_matchWithoutDescription() { - const frame1 = getTestFrame(); - frame1.type = PictureType.FrontCover; - const frame2 = getTestFrame(); - frame2.type = PictureType.BackCover; - - const frames = [frame1, frame2]; - - // Act - const output = AttachmentFrame.find(frames, undefined, PictureType.BackCover); + public filterFrames_multipleMatches() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); - // Assert - assert.strictEqual(output, frame2); - } + const pic2 = Picture.fromData(ByteVector.fromUint(8888)); + const frame2 = AttachmentFrame.fromPicture(pic2); - @test - public find_matchWithoutType() { - const frame1 = getTestFrame(); - frame1.description = "bux"; - frame1.type = PictureType.FrontCover; - const frame2 = getTestFrame(); - frame2.description = "qux"; - frame2.type = PictureType.BackCover; + const pic3 = Picture.fromData(ByteVector.fromUint(9999)); + const frame3 = AttachmentFrame.fromPicture(pic3); - const frames = [frame1, frame2]; + const frames = [frame1, frame2, frame3]; // Act - const output = AttachmentFrame.find(frames, "qux"); + const result = AttachmentFrame.filterFrames(frames); // Assert - assert.strictEqual(output, frame2); + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); } @test - public find_matchWithoutEither() { - const frame1 = getTestFrame(); - frame1.description = "bux"; - frame1.type = PictureType.FrontCover; - const frame2 = getTestFrame(); - frame2.description = "qux"; - frame2.type = PictureType.BackCover; + public filterFrames_allMatches() { + // Arrange + const pic1 = Picture.fromData(ByteVector.fromUint(8888)); + const frame1 = AttachmentFrame.fromPicture(pic1); + + const pic2 = Picture.fromData(ByteVector.fromUint(9999)); + const frame2 = AttachmentFrame.fromPicture(pic2); const frames = [frame1, frame2]; // Act - const output = AttachmentFrame.find(frames); + const result = AttachmentFrame.filterFrames(frames); // Assert - assert.strictEqual(output, frame1); + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); } @test diff --git a/test-unit/id3v2/commentsFrameTests.ts b/test-unit/id3v2/commentsFrameTests.ts index a9883f7..a59f03f 100644 --- a/test-unit/id3v2/commentsFrameTests.ts +++ b/test-unit/id3v2/commentsFrameTests.ts @@ -2,11 +2,12 @@ import {params, suite, test} from "@testdeck/mocha"; import {assert} from "chai"; import CommentsFrame from "../../src/id3v2/frames/commentsFrame"; +import Frame from "../../src/id3v2/frames/frame"; import FrameConstructorTests from "./frameConstructorTests"; import Id3v2Settings from "../../src/id3v2/id3v2Settings"; import PropertyTests from "../utilities/propertyTests"; +import UnknownFrame from "../../src/id3v2/frames/unknownFrame"; import {ByteVector, StringType} from "../../src/byteVector"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {Testers} from "../utilities/testers"; @@ -24,6 +25,23 @@ const getTestFrame = (): CommentsFrame => { return CommentsFrame.fromFieldBytes(header, fieldBytes, 4); } +const verifyFrame = ( + frame: CommentsFrame, + expectedDesc: string, + expectedLang: string, + expectedEncoding: StringType, + expectedText: string +) => { + assert.isOk(frame); + assert.instanceOf(frame, CommentsFrame); + assert.strictEqual(frame.frameId, FrameIdentifiers.COMM); + + assert.strictEqual(frame.description, expectedDesc); + assert.strictEqual(frame.language, expectedLang); + assert.strictEqual(frame.textEncoding, expectedEncoding); + assert.strictEqual(frame.text, expectedText); +} + @suite class Id3v2_CommentsFrame_ConstructorTests extends FrameConstructorTests { public get fromFieldBytes(): (h: Id3v2FrameHeader, fb: ByteVector, v: number) => Frame { return CommentsFrame.fromFieldBytes; @@ -38,13 +56,7 @@ const getTestFrame = (): CommentsFrame => { const frame = CommentsFrame.fromDescription(description); // Assert - Id3v2_CommentsFrame_ConstructorTests.validateFrame( - frame, - description, - "XXX", - Id3v2Settings.defaultEncoding, - "" - ); + verifyFrame(frame, description, "XXX", Id3v2Settings.defaultEncoding, ""); } @test @@ -57,13 +69,7 @@ const getTestFrame = (): CommentsFrame => { const frame = CommentsFrame.fromDescription(description, language); // Assert - Id3v2_CommentsFrame_ConstructorTests.validateFrame( - frame, - description, - language, - Id3v2Settings.defaultEncoding, - "" - ); + verifyFrame(frame, description, language, Id3v2Settings.defaultEncoding, ""); } @test @@ -77,7 +83,7 @@ const getTestFrame = (): CommentsFrame => { const frame = CommentsFrame.fromDescription(description, language, encoding); // Assert - Id3v2_CommentsFrame_ConstructorTests.validateFrame(frame, description, language, encoding, ""); + verifyFrame(frame, description, language, encoding, ""); } @params(2, "v2") @@ -108,7 +114,7 @@ const getTestFrame = (): CommentsFrame => { const frame = CommentsFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_CommentsFrame_ConstructorTests.validateFrame(frame, "", "eng", StringType.Latin1, ""); + verifyFrame(frame, "", "eng", StringType.Latin1, ""); } @params(2, "v2") @@ -128,7 +134,7 @@ const getTestFrame = (): CommentsFrame => { const frame = CommentsFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_CommentsFrame_ConstructorTests.validateFrame(frame, "", "eng", StringType.Latin1, "fux"); + verifyFrame(frame, "", "eng", StringType.Latin1, "fux"); } @params(2, "v2") @@ -149,7 +155,7 @@ const getTestFrame = (): CommentsFrame => { const frame = CommentsFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_CommentsFrame_ConstructorTests.validateFrame(frame, "", "eng", StringType.Latin1, "fux"); + verifyFrame(frame, "", "eng", StringType.Latin1, "fux"); } @params(2, "v2") @@ -170,7 +176,7 @@ const getTestFrame = (): CommentsFrame => { const frame = CommentsFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_CommentsFrame_ConstructorTests.validateFrame(frame, "fux", "eng", StringType.Latin1, "bux"); + verifyFrame(frame, "fux", "eng", StringType.Latin1, "bux"); } @params(StringType.Latin1, "single_byte_encoding") @@ -190,24 +196,7 @@ const getTestFrame = (): CommentsFrame => { const frame = CommentsFrame.fromFieldBytes(header, fieldBytes, 4); // Assert - Id3v2_CommentsFrame_ConstructorTests.validateFrame(frame, "fux", "eng", encoding, "bux"); - } - - private static validateFrame( - frame: CommentsFrame, - expectedDesc: string, - expectedLang: string, - expectedEncoding: StringType, - expectedText: string - ) { - assert.isOk(frame); - assert.equal(frame.frameClassType, FrameClassType.CommentsFrame); - assert.strictEqual(frame.frameId, FrameIdentifiers.COMM); - - assert.strictEqual(frame.description, expectedDesc); - assert.strictEqual(frame.language, expectedLang); - assert.strictEqual(frame.textEncoding, expectedEncoding); - assert.strictEqual(frame.text, expectedText); + verifyFrame(frame, "fux", "eng", encoding, "bux"); } } @@ -261,119 +250,84 @@ const getTestFrame = (): CommentsFrame => { @suite class Id3v2_CommentsFrame_MethodTests { @test - public find_falsyFrames() { + public filterFrames_falsyFrames() { // Act/Assert - Testers.testTruthy((v: CommentsFrame[]) => { CommentsFrame.find(v, "fux"); }); + Testers.testTruthy((v: CommentsFrame[]) => { CommentsFrame.filterFrames(v); }); } @test - public find_frameDoesNotExist() { + public filterFrames_noFrames() { // Arrange - const frames = [ - CommentsFrame.fromDescription("fux", "jpn"), // nothing matches - CommentsFrame.fromDescription("bux", "jpn"), // desc matches, not language - CommentsFrame.fromDescription("qux", "eng") // language matches, not desc - ]; + const frames: Frame[] = []; // Act - const output = CommentsFrame.find(frames, "bux", "eng"); + const output = CommentsFrame.filterFrames(frames); // Assert - assert.isUndefined(output); + assert.isArray(output); + assert.isEmpty(output); } @test - public find_frameExistsWithoutLanguage() { + public filterFrames_noMatch() { // Arrange - const frames = [ - CommentsFrame.fromDescription("fux", "jpn"), // nothing matches - CommentsFrame.fromDescription("bux", "jpn"), // desc matches, not language - CommentsFrame.fromDescription("qux", "jpn") // desc does not match - ]; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(234)); + const frames = [frame1, frame2]; // Act - const output = CommentsFrame.find(frames, "bux"); + const result = CommentsFrame.filterFrames(frames); // Assert - assert.isOk(output); - assert.strictEqual(output, frames[1]); + assert.isArray(result); + assert.isEmpty(result); } @test - public find_frameExistsWithLanguage() { + public filterFrames_singleMatch() { // Arrange - const frames = [ - CommentsFrame.fromDescription("fux", "jpn"), // nothing matches - CommentsFrame.fromDescription("bux", "jpn"), // desc matches, not language - CommentsFrame.fromDescription("qux", "eng"), // language matches, not desc - CommentsFrame.fromDescription("bux", "eng") // everything matches - ]; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = CommentsFrame.fromDescription("foo"); + const frames = [frame1, frame2]; // Act - const output = CommentsFrame.find(frames, "bux", "eng"); + const result = CommentsFrame.filterFrames(frames); // Assert - assert.isOk(output); - assert.strictEqual(output, frames[3]); + assert.isArray(result); + assert.deepEqual(result, [frame2]); } @test - public findAll_falsyFrames() { - // Act/Assert - Testers.testTruthy((v: CommentsFrame[]) => { CommentsFrame.findAll(v, "fux"); }); - } - - @test - public findAll_frameDoesNotExist() { + public filterFrames_multipleMatches() { // Arrange - const frames = [ - CommentsFrame.fromDescription("fux", "jpn"), - CommentsFrame.fromDescription("bux", "jpn"), - CommentsFrame.fromDescription("qux", "eng") - ]; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = CommentsFrame.fromDescription("foo"); + const frame3 = CommentsFrame.fromDescription("bar"); - // Act - const output = CommentsFrame.findAll(frames, "fux", "eng"); - - // Assert - assert.isArray(output); - assert.isEmpty(output); - } - - @test - public findAll_frameExistsWithoutLanguage() { - // Arrange - const frames = [ - CommentsFrame.fromDescription("fux", "jpn"), - CommentsFrame.fromDescription("bux", "jpn"), - CommentsFrame.fromDescription("bux", "eng"), - CommentsFrame.fromDescription("qux", "eng") - ]; + const frames = [frame1, frame2, frame3]; // Act - const output = CommentsFrame.findAll(frames, "bux"); + const result = CommentsFrame.filterFrames(frames); // Assert - assert.isArray(output); - assert.sameMembers(output, [frames[1], frames[2]]); + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); } @test - public findAll_frameExistsWithLanguage() { + public filterFrames_allMatches() { // Arrange - const frames = [ - CommentsFrame.fromDescription("fux", "jpn"), - CommentsFrame.fromDescription("bux", "jpn"), - CommentsFrame.fromDescription("bux", "eng"), - CommentsFrame.fromDescription("qux", "eng") - ]; + const frame1 = CommentsFrame.fromDescription("foo"); + const frame2 = CommentsFrame.fromDescription("bar"); + const frames = [frame1, frame2]; // Act - const output = CommentsFrame.findAll(frames, "bux", "eng"); + const result = CommentsFrame.filterFrames(frames); // Assert - assert.isArray(output); - assert.sameMembers(output, [frames[2]]); + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); } @test @@ -464,14 +418,7 @@ const getTestFrame = (): CommentsFrame => { const output = frame.clone(); // Assert - assert.isOk(output); - assert.equal(output.frameClassType, FrameClassType.CommentsFrame); - assert.strictEqual(output.frameId, FrameIdentifiers.COMM); - - assert.strictEqual(output.description, frame.description); - assert.strictEqual(output.language, frame.language); - assert.strictEqual(output.textEncoding, frame.textEncoding); - assert.strictEqual(output.text, frame.text); + verifyFrame(output, frame.description, frame.language, frame.textEncoding, frame.text); } @params([2, StringType.Latin1], "v2_single_byte") diff --git a/test-unit/id3v2/eventTimeCodeFrameTests.ts b/test-unit/id3v2/eventTimeCodeFrameTests.ts index 1568aae..7e93515 100644 --- a/test-unit/id3v2/eventTimeCodeFrameTests.ts +++ b/test-unit/id3v2/eventTimeCodeFrameTests.ts @@ -1,16 +1,27 @@ import {params, suite, test} from "@testdeck/mocha"; import {assert} from "chai"; +import Frame from "../../src/id3v2/frames/frame"; import FrameConstructorTests from "./frameConstructorTests"; import PropertyTests from "../utilities/propertyTests"; +import UnknownFrame from "../../src/id3v2/frames/unknownFrame"; import {ByteVector} from "../../src/byteVector"; import {EventTimeCode, EventTimeCodeFrame} from "../../src/id3v2/frames/eventTimeCodeFrame"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Testers} from "../utilities/testers"; import {EventType, TimestampFormat} from "../../src/id3v2/utilTypes"; +const assertFrame = (frame: EventTimeCodeFrame, e: EventTimeCode[], t: TimestampFormat) => { + assert.isOk(frame); + assert.instanceOf(frame, EventTimeCodeFrame); + assert.strictEqual(frame.frameId, FrameIdentifiers.ETCO); + assert.isTrue((frame.flags | Id3v2FrameFlags.FileAlterPreservation) > 0); + + assert.deepStrictEqual(frame.events, e); + assert.strictEqual(frame.timestampFormat, t); +} + @suite class Id3v2_EventTimeCodeTests { @test public constructor_invalidTime() { @@ -98,7 +109,7 @@ import {EventType, TimestampFormat} from "../../src/id3v2/utilTypes"; const output = EventTimeCodeFrame.fromEmpty(); // Assert - Id3v2_EventTimeCodeFrame_ConstructorTests.assertFrame(output, [], TimestampFormat.Unknown); + assertFrame(output, [], TimestampFormat.Unknown); } @test @@ -107,7 +118,7 @@ import {EventType, TimestampFormat} from "../../src/id3v2/utilTypes"; const output = EventTimeCodeFrame.fromTimestampFormat(TimestampFormat.AbsoluteMilliseconds); // Assert - Id3v2_EventTimeCodeFrame_ConstructorTests.assertFrame(output, [], TimestampFormat.AbsoluteMilliseconds); + assertFrame(output, [], TimestampFormat.AbsoluteMilliseconds); } @params(2, "v2") @@ -134,7 +145,7 @@ import {EventType, TimestampFormat} from "../../src/id3v2/utilTypes"; const frame = EventTimeCodeFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_EventTimeCodeFrame_ConstructorTests.assertFrame(frame, [], TimestampFormat.AbsoluteMilliseconds); + assertFrame(frame, [], TimestampFormat.AbsoluteMilliseconds); } @params(2, "v2") @@ -155,11 +166,7 @@ import {EventType, TimestampFormat} from "../../src/id3v2/utilTypes"; const frame = EventTimeCodeFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_EventTimeCodeFrame_ConstructorTests.assertFrame( - frame, - [event1, event2], - TimestampFormat.AbsoluteMilliseconds - ); + assertFrame(frame, [event1, event2], TimestampFormat.AbsoluteMilliseconds); } @params(2, "v2") @@ -179,16 +186,6 @@ import {EventType, TimestampFormat} from "../../src/id3v2/utilTypes"; // Act / Assert assert.throws(() => EventTimeCodeFrame.fromFieldBytes(header, fieldBytes, version)); } - - private static assertFrame(frame: EventTimeCodeFrame, e: EventTimeCode[], t: TimestampFormat) { - assert.isOk(frame); - assert.strictEqual(frame.frameClassType, FrameClassType.EventTimeCodeFrame); - assert.strictEqual(frame.frameId, FrameIdentifiers.ETCO); - assert.isTrue((frame.flags | Id3v2FrameFlags.FileAlterPreservation) > 0); - - assert.deepStrictEqual(frame.events, e); - assert.strictEqual(frame.timestampFormat, t); - } } @suite class Id3v2_EventTimeCodeFrame_PropertyTests { @@ -233,13 +230,88 @@ import {EventType, TimestampFormat} from "../../src/id3v2/utilTypes"; const output = frame.clone(); // Assert - assert.isOk(output); - assert.strictEqual(output.frameClassType, FrameClassType.EventTimeCodeFrame); - assert.strictEqual(output.frameId, FrameIdentifiers.ETCO); - assert.isTrue((output.flags | Id3v2FrameFlags.FileAlterPreservation) > 0); + assertFrame(output, frame.events, frame.timestampFormat); + } + + @test + public filterFrames_falsyFrames() { + // Act/Assert + Testers.testTruthy((v: Frame[]) => { EventTimeCodeFrame.filterFrames(v); }); + } + + @test + public filterFrames_noFrames() { + // Arrange + const frames: Frame[] = []; + + // Act + const output = EventTimeCodeFrame.filterFrames(frames); + + // Assert + assert.isArray(output); + assert.isEmpty(output); + } + + @test + public filterFrames_noMatch() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(234)); + const frames = [frame1, frame2]; + + // Act + const result = EventTimeCodeFrame.filterFrames(frames); - assert.deepStrictEqual(output.events, frame.events); - assert.strictEqual(output.timestampFormat, frame.timestampFormat); + // Assert + assert.isArray(result); + assert.isEmpty(result); + } + + @test + public filterFrames_singleMatch() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = EventTimeCodeFrame.fromEmpty(); + const frames = [frame1, frame2]; + + // Act + const result = EventTimeCodeFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame2]); + } + + @test + public filterFrames_multipleMatches() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = EventTimeCodeFrame.fromEmpty(); + const frame3 = EventTimeCodeFrame.fromEmpty(); + + const frames = [frame1, frame2, frame3]; + + // Act + const result = EventTimeCodeFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); + } + + @test + public filterFrames_allMatches() { + // Arrange + const frame1 = EventTimeCodeFrame.fromEmpty(); + const frame2 = EventTimeCodeFrame.fromEmpty(); + const frames = [frame1, frame2]; + + // Act + const result = EventTimeCodeFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); } @params(2, "v2") diff --git a/test-unit/id3v2/frameConstructorTests.ts b/test-unit/id3v2/frameConstructorTests.ts index d306d47..600e201 100644 --- a/test-unit/id3v2/frameConstructorTests.ts +++ b/test-unit/id3v2/frameConstructorTests.ts @@ -1,7 +1,7 @@ import {test} from "@testdeck/mocha"; +import Frame from "../../src/id3v2/frames/frame"; import {ByteVector} from "../../src/byteVector"; -import {Frame} from "../../src/id3v2/frames/frame"; import {Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Testers} from "../utilities/testers"; diff --git a/test-unit/id3v2/frameFactoryTests.ts b/test-unit/id3v2/frameFactoryTests.ts index 5a55f4a..e409e51 100644 --- a/test-unit/id3v2/frameFactoryTests.ts +++ b/test-unit/id3v2/frameFactoryTests.ts @@ -1,7 +1,10 @@ import {params, suite, test} from "@testdeck/mocha"; import {assert} from "chai"; +import AttachmentFrame from "../../src/id3v2/frames/attachmentFrame"; import CommentsFrame from "../../src/id3v2/frames/commentsFrame"; +import Frame from "../../src/id3v2/frames/frame"; +import MusicCdIdentifierFrame from "../../src/id3v2/frames/musicCdIdentifierFrame"; import PlayCountFrame from "../../src/id3v2/frames/playCountFrame"; import PopularimeterFrame from "../../src/id3v2/frames/popularimeterFrame"; import PrivateFrame from "../../src/id3v2/frames/privateFrame"; @@ -17,7 +20,6 @@ import UserUrlLinkFrame from "../../src/id3v2/frames/userUrlLinkFrame"; import {ByteVector, StringType} from "../../src/byteVector"; import {EventTimeCodeFrame} from "../../src/id3v2/frames/eventTimeCodeFrame"; import {File} from "../../src/file"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {FrameCreator, Id3v2FrameFactory} from "../../src/id3v2/frames/frameFactory"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifier, FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; @@ -113,6 +115,9 @@ import {NumberUtils} from "../../src/utils"; // Act const result = Id3v2FrameFactory.createFrameFromFile(file, 0, version, false); + + // Assert + assert.isUndefined(result); } @test @@ -127,7 +132,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.AttachmentFrame, 4); + FrameFactoryTests.validateOutput(output, AttachmentFrame, 4); } @test @@ -140,7 +145,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.CommentsFrame, 4); + FrameFactoryTests.validateOutput(output, CommentsFrame, 4); } @test @@ -153,7 +158,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.EventTimeCodeFrame, 4); + FrameFactoryTests.validateOutput(output, EventTimeCodeFrame, 4); } @test @@ -168,7 +173,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.AttachmentFrame, 4); + FrameFactoryTests.validateOutput(output, AttachmentFrame, 4); } @test @@ -183,7 +188,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.MusicCdIdentifierFrame, 4); + FrameFactoryTests.validateOutput(output, MusicCdIdentifierFrame, 4); } @test @@ -196,7 +201,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.PlayCountFrame, 4); + FrameFactoryTests.validateOutput(output, PlayCountFrame, 4); } @test @@ -209,7 +214,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.PopularimeterFrame, 4); + FrameFactoryTests.validateOutput(output, PopularimeterFrame, 4); } @test @@ -222,7 +227,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.PrivateFrame, 4); + FrameFactoryTests.validateOutput(output, PrivateFrame, 4); } @test @@ -235,7 +240,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.RelativeVolumeFrame, 4); + FrameFactoryTests.validateOutput(output, RelativeVolumeFrame, 4); } @test @@ -248,7 +253,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.SynchronizedLyricsFrame, 4); + FrameFactoryTests.validateOutput(output, SynchronizedLyricsFrame, 4); } @test @@ -262,7 +267,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.TextInformationFrame, 4); + FrameFactoryTests.validateOutput(output, TextInformationFrame, 4); } @test @@ -275,7 +280,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.UserTextInformationFrame, 4); + FrameFactoryTests.validateOutput(output, UserTextInformationFrame, 4); } @test @@ -288,7 +293,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.UniqueFileIdentifierFrame, 4); + FrameFactoryTests.validateOutput(output, UniqueFileIdentifierFrame, 4); } @test @@ -304,7 +309,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 2, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.UniqueFileIdentifierFrame, 4); + FrameFactoryTests.validateOutput(output, UniqueFileIdentifierFrame, 4); } @test @@ -319,13 +324,13 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.UnknownFrame, 4); + FrameFactoryTests.validateOutput(output, UnknownFrame, 4); } @test public createFrameFromFile_urlFrame() { // Arrange - const frame = UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM); + const frame = UrlLinkFrame.fromIdentifier(FrameIdentifiers.WCOM); frame.text = "foo"; const data = frame.render(4); const file = TestFile.getFile(data); @@ -334,7 +339,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.UrlLinkFrame, 4); + FrameFactoryTests.validateOutput(output, UrlLinkFrame, 4); } public createFrameFromFile_user() { @@ -346,7 +351,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.TermsOfUseFrame, 4); + FrameFactoryTests.validateOutput(output, TermsOfUseFrame, 4); } @test @@ -359,7 +364,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.UnsynchronizedLyricsFrame, 4); + FrameFactoryTests.validateOutput(output, UnsynchronizedLyricsFrame, 4); } @test @@ -372,7 +377,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.UserUrlLinkFrame, 4); + FrameFactoryTests.validateOutput(output, UserUrlLinkFrame, 4); } @test @@ -393,7 +398,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 3, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.UnknownFrame, data.length); + FrameFactoryTests.validateOutput(output, UnknownFrame, data.length); mockCreator.verify( (c) => c(It.isValue(fieldBytes), It.isValue(0), It.isAny(), It.isValue(3)), Times.atLeastOnce() @@ -461,7 +466,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromFile(file, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.UnknownFrame, data.length); + FrameFactoryTests.validateOutput(output, UnknownFrame, data.length); assert.notStrictEqual(output.frame, frame); assert.strictEqual(output.totalSize, data.length); @@ -642,7 +647,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.AttachmentFrame, 4); + FrameFactoryTests.validateOutput(output, AttachmentFrame, 4); } @test @@ -654,7 +659,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.CommentsFrame, 4); + FrameFactoryTests.validateOutput(output, CommentsFrame, 4); } @test @@ -666,7 +671,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.EventTimeCodeFrame, 4); + FrameFactoryTests.validateOutput(output, EventTimeCodeFrame, 4); } @test @@ -681,7 +686,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.AttachmentFrame, 4); + FrameFactoryTests.validateOutput(output, AttachmentFrame, 4); } @test @@ -696,7 +701,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.MusicCdIdentifierFrame, 4); + FrameFactoryTests.validateOutput(output, MusicCdIdentifierFrame, 4); } @test @@ -708,7 +713,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.PlayCountFrame, 4); + FrameFactoryTests.validateOutput(output, PlayCountFrame, 4); } @test @@ -720,7 +725,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.PopularimeterFrame, 4); + FrameFactoryTests.validateOutput(output, PopularimeterFrame, 4); } @test @@ -732,7 +737,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.PrivateFrame, 4); + FrameFactoryTests.validateOutput(output, PrivateFrame, 4); } @test @@ -744,7 +749,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.RelativeVolumeFrame, 4); + FrameFactoryTests.validateOutput(output, RelativeVolumeFrame, 4); } @test @@ -756,7 +761,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.SynchronizedLyricsFrame, 4); + FrameFactoryTests.validateOutput(output, SynchronizedLyricsFrame, 4); } @test @@ -770,7 +775,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.TextInformationFrame, 4); + FrameFactoryTests.validateOutput(output, TextInformationFrame, 4); } @test @@ -782,7 +787,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.UserTextInformationFrame, 4); + FrameFactoryTests.validateOutput(output, UserTextInformationFrame, 4); } @test @@ -794,7 +799,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.UniqueFileIdentifierFrame, 4); + FrameFactoryTests.validateOutput(output, UniqueFileIdentifierFrame, 4); } @test @@ -809,7 +814,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.UnknownFrame, 4); + FrameFactoryTests.validateOutput(output, UnknownFrame, 4); } @test @@ -827,13 +832,13 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 10, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.UnknownFrame, 4); + FrameFactoryTests.validateOutput(output, UnknownFrame, 4); } @test public createFrameFromTagBytes_urlFrame() { // Arrange - const frame = UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM); + const frame = UrlLinkFrame.fromIdentifier(FrameIdentifiers.WCOM); frame.text = "foo"; const data = frame.render(4); @@ -841,7 +846,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.UrlLinkFrame, 4); + FrameFactoryTests.validateOutput(output, UrlLinkFrame, 4); } @test @@ -853,7 +858,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.TermsOfUseFrame, 4); + FrameFactoryTests.validateOutput(output, TermsOfUseFrame, 4); } @test @@ -865,7 +870,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.UnsynchronizedLyricsFrame, 4); + FrameFactoryTests.validateOutput(output, UnsynchronizedLyricsFrame, 4); } @test @@ -877,7 +882,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.UserUrlLinkFrame, 4); + FrameFactoryTests.validateOutput(output, UserUrlLinkFrame, 4); } @test @@ -897,7 +902,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 3, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.UnknownFrame, data.length); + FrameFactoryTests.validateOutput(output, UnknownFrame, data.length); mockCreator.verify( (c) => c(It.isValue(fieldBytes), It.isValue(0), It.isAny(), It.isValue(3)), Times.atLeastOnce() @@ -963,7 +968,7 @@ import {NumberUtils} from "../../src/utils"; const output = Id3v2FrameFactory.createFrameFromTagBytes(data, 0, 4, false); // Assert - FrameFactoryTests.validateOutput(output, FrameClassType.UnknownFrame, data.length); + FrameFactoryTests.validateOutput(output, UnknownFrame, data.length); assert.notStrictEqual(output.frame, frame); assert.strictEqual(output.totalSize, data.length); @@ -1075,14 +1080,15 @@ import {NumberUtils} from "../../src/utils"; private static validateOutput( output: {frame: Frame; totalSize: number}, - classType: FrameClassType, + // eslint-disable-next-line @typescript-eslint/ban-types + classType: Function, id3v2Version: number ) { assert.ok(output); const frame = output.frame; assert.ok(frame); - assert.strictEqual(frame.frameClassType, classType); + assert.instanceOf(frame, classType); const expectedSize = frame.size + Id3v2FrameHeader.getBaseSize(id3v2Version) assert.strictEqual(output.totalSize, expectedSize); diff --git a/test-unit/id3v2/frameTests.ts b/test-unit/id3v2/frameTests.ts index fef0cd1..2c25808 100644 --- a/test-unit/id3v2/frameTests.ts +++ b/test-unit/id3v2/frameTests.ts @@ -1,9 +1,9 @@ import {suite, test} from "@testdeck/mocha"; import {assert} from "chai"; +import Frame from "../../src/id3v2/frames/frame"; import PropertyTests from "../utilities/propertyTests"; import {ByteVector} from "../../src/byteVector"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Testers} from "../utilities/testers"; @@ -19,10 +19,6 @@ class TestFrame extends Frame { super(header); } - get frameClassType(): FrameClassType { - return undefined; - } - public clone(): Frame { return undefined; } diff --git a/test-unit/id3v2/genreFrameTests.ts b/test-unit/id3v2/genreFrameTests.ts index ba849f4..072c437 100644 --- a/test-unit/id3v2/genreFrameTests.ts +++ b/test-unit/id3v2/genreFrameTests.ts @@ -1,14 +1,15 @@ import {suite, test} from "@testdeck/mocha"; import {assert} from "chai"; -import Id3v2Settings from "../../src/id3v2/id3v2Settings"; +import Frame from "../../src/id3v2/frames/frame"; +import FrameConstructorTests from "./frameConstructorTests"; import GenreFrame from "../../src/id3v2/frames/genreFrame"; +import Id3v2Settings from "../../src/id3v2/id3v2Settings"; +import UnknownFrame from "../../src/id3v2/frames/unknownFrame"; import {ByteVector, StringType} from "../../src/byteVector"; -import {FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Testers} from "../utilities/testers"; -import FrameConstructorTests from "./frameConstructorTests"; @suite class Id3v2_GenreFrameTests extends FrameConstructorTests { @@ -24,8 +25,9 @@ class Id3v2_GenreFrameTests extends FrameConstructorTests { // Assert assert.isOk(frame); - assert.strictEqual(frame.frameClassType, FrameClassType.GenreFrame); + assert.instanceOf(frame, GenreFrame); assert.strictEqual(frame.frameId, FrameIdentifiers.TCON); + assert.deepStrictEqual(frame.text, []); assert.strictEqual(frame.textEncoding, StringType.UTF16BE); } @@ -462,38 +464,93 @@ class Id3v2_GenreFrameTests extends FrameConstructorTests { // Assert assert.isOk(output); + assert.instanceOf(frame, GenreFrame); assert.notStrictEqual(output, frame); - assert.strictEqual(output.frameClassType, FrameClassType.GenreFrame); + assert.strictEqual(output.frameId, FrameIdentifiers.TCON); assert.deepStrictEqual(output.text, ["foo", "bar"]); assert.strictEqual(output.textEncoding, StringType.UTF16BE); } @test - public find_falsyFrames() { + public filterFrames_falsyFrames() { // Act/Assert - Testers.testTruthy((v: GenreFrame[]) => { GenreFrame.findGenreFrame(v); }); + Testers.testTruthy((v: Frame[]) => { GenreFrame.filterFrames(v); }); } @test - public find_frameExists() { + public filterFrames_noFrames() { // Arrange - const frame = GenreFrame.fromEncoding(); + const frames: Frame[] = []; + + // Act + const output = GenreFrame.filterFrames(frames); + + // Assert + assert.isArray(output); + assert.isEmpty(output); + } + + @test + public filterFrames_noMatch() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(234)); + const frames = [frame1, frame2]; + + // Act + const result = GenreFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.isEmpty(result); + } + + @test + public filterFrames_singleMatch() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = GenreFrame.fromEncoding(StringType.UTF16); + const frames = [frame1, frame2]; // Act - const output = GenreFrame.findGenreFrame([frame]); + const result = GenreFrame.filterFrames(frames); // Assert - assert.strictEqual(output, frame); + assert.isArray(result); + assert.deepEqual(result, [frame2]); } @test - public find_frameDoesNotExist() { + public filterFrames_multipleMatches() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = GenreFrame.fromEncoding(StringType.UTF16); + const frame3 = GenreFrame.fromEncoding(StringType.UTF16BE); + + const frames = [frame1, frame2, frame3]; + + // Act + const result = GenreFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); + } + + @test + public filterFrames_allMatches() { + // Arrange + const frame1 = GenreFrame.fromEncoding(StringType.Hex); + const frame2 = GenreFrame.fromEncoding(StringType.Latin1); + const frames = [frame1, frame2]; + // Act - const output = GenreFrame.findGenreFrame([]); + const result = GenreFrame.filterFrames(frames); // Assert - assert.isUndefined(output); + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); } @test diff --git a/test-unit/id3v2/id3v2TagTests.ts b/test-unit/id3v2/id3v2TagTests.ts index c269d3b..8c6ed29 100644 --- a/test-unit/id3v2/id3v2TagTests.ts +++ b/test-unit/id3v2/id3v2TagTests.ts @@ -8,6 +8,7 @@ import Id3v2Settings from "../../src/id3v2/id3v2Settings"; import Id3v2Tag from "../../src/id3v2/id3v2Tag"; import Id3v2TagFooter from "../../src/id3v2/id3v2TagFooter"; import PlayCountFrame from "../../src/id3v2/frames/playCountFrame"; +import PrivateFrame from "../../src/id3v2/frames/privateFrame"; import PropertyTests from "../utilities/propertyTests"; import SyncData from "../../src/id3v2/syncData"; import TestFile from "../utilities/testFile"; @@ -19,14 +20,13 @@ import UrlLinkFrame from "../../src/id3v2/frames/urlLinkFrame"; import UserTextInformationFrame from "../../src/id3v2/frames/userTextInformationFrame"; import {ByteVector, StringType} from "../../src/byteVector"; import {File, ReadStyle} from "../../src/file"; -import {FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifier, FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Id3v2TagHeader, Id3v2TagHeaderFlags} from "../../src/id3v2/id3v2TagHeader"; import {IPicture} from "../../src/picture"; import {TagTypes} from "../../src/tag"; import {Testers} from "../utilities/testers"; -import PrivateFrame from "../../src/id3v2/frames/privateFrame"; +import AttachmentFrame from "../../src/id3v2/frames/attachmentFrame"; const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: number): ByteVector => { return ByteVector.concatenate( @@ -106,22 +106,20 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: let frame2Found = false; let emptyFrameFound = false; for (const f of tag.frames) { - switch (f.frameClassType) { - case FrameClassType.PlayCountFrame: - assert.isFalse(frame1Found); - frame1Found = true; - break; - case FrameClassType.UniqueFileIdentifierFrame: - assert.isFalse(frame2Found); - frame2Found = true; - break; - case FrameClassType.UnknownFrame: - emptyFrameFound = true; - break; - default: - assert.fail(f.frameClassType, undefined, "Unexpected frame found"); + if (f instanceof PlayCountFrame) { + assert.isFalse(frame1Found); + frame1Found = true; + } else if (f instanceof UniqueFileIdentifierFrame) { + assert.isFalse(frame2Found); + frame2Found = true; + } else if (f instanceof UnknownFrame) { + assert.isFalse(emptyFrameFound); + emptyFrameFound = true; + } else { + assert.fail(f, undefined, "Unexpected frame found"); } } + assert.isTrue(frame1Found); assert.isTrue(frame2Found); assert.isFalse(emptyFrameFound); @@ -149,7 +147,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: // - Right frames assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.PlayCountFrame); + assert.instanceOf(tag.frames[0], PlayCountFrame); } @test @@ -171,7 +169,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: // - Right frames assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.PlayCountFrame); + assert.instanceOf(tag.frames[0], PlayCountFrame); } @test @@ -242,22 +240,20 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: let frame2Found = false; let emptyFrameFound = false; for (const f of tag.frames) { - switch (f.frameClassType) { - case FrameClassType.PlayCountFrame: - assert.isFalse(frame1Found); - frame1Found = true; - break; - case FrameClassType.UniqueFileIdentifierFrame: - assert.isFalse(frame2Found); - frame2Found = true; - break; - case FrameClassType.UnknownFrame: - emptyFrameFound = true; - break; - default: - assert.fail(f.frameClassType, undefined, "Unexpected frame found"); + if (f instanceof PlayCountFrame) { + assert.isFalse(frame1Found); + frame1Found = true; + } else if (f instanceof UniqueFileIdentifierFrame) { + assert.isFalse(frame2Found); + frame2Found = true; + } else if (f instanceof UnknownFrame) { + assert.isFalse(emptyFrameFound); + emptyFrameFound = true; + } else { + assert.fail(f, undefined, "Unexpected frame found"); } } + assert.isTrue(frame1Found); assert.isTrue(frame2Found); assert.isFalse(emptyFrameFound); @@ -290,7 +286,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyRoundTrip(set, get, true); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TCMP); assert.deepStrictEqual(( tag.frames[0]).text, ["1"]); @@ -368,7 +364,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyRoundTrip(set, get, "foo"); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.UserTextInformationFrame); + assert.instanceOf(tag.frames[0], UserTextInformationFrame); assert.strictEqual(( tag.frames[0]).description, "Description"); assert.deepStrictEqual(( tag.frames[0]).text, ["foo"]); @@ -580,7 +576,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: // Assert assert.strictEqual(tag.comment, "foo"); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.CommentsFrame); + assert.instanceOf(tag.frames[0], CommentsFrame); assert.strictEqual(( tag.frames[0]).text, "foo"); assert.strictEqual(( tag.frames[0]).language, "eng"); assert.strictEqual(( tag.frames[0]).description, ""); @@ -626,7 +622,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: // Assert assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.GenreFrame); + assert.instanceOf(tag.frames[0], GenreFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TCON); assert.deepStrictEqual(( tag.frames[0]).text, ["Classical", "foo"]); } @@ -644,7 +640,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: // Assert assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.GenreFrame); + assert.instanceOf(tag.frames[0], GenreFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TCON); assert.deepStrictEqual(( tag.frames[0]).text, ["Classical", "foo"]); } @@ -662,7 +658,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: // Assert assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.GenreFrame); + assert.instanceOf(tag.frames[0], GenreFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TCON); assert.deepStrictEqual(( tag.frames[0]).text, ["Classical", "foo"]); } finally { @@ -802,13 +798,13 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyRoundTrip(set, get, 2); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TRCK); assert.deepStrictEqual(( tag.frames[0]).text, ["02"]); PropertyTests.propertyRoundTrip(set, get, 123); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TRCK); assert.deepStrictEqual(( tag.frames[0]).text, ["123"]); @@ -829,19 +825,19 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyRoundTrip(set, get, 2); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TRCK); assert.deepStrictEqual(( tag.frames[0]).text, ["02/123"]); PropertyTests.propertyRoundTrip(set, get, 123); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TRCK); assert.deepStrictEqual(( tag.frames[0]).text, ["123/123"]); PropertyTests.propertyRoundTrip(set, get, 0); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TRCK); assert.deepStrictEqual(( tag.frames[0]).text, ["00/123"]); } @@ -872,13 +868,13 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyRoundTrip(set, get, 2); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TRCK); assert.deepStrictEqual(( tag.frames[0]).text, ["0/2"]); PropertyTests.propertyRoundTrip(set, get, 123); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TRCK); assert.deepStrictEqual(( tag.frames[0]).text, ["0/123"]); @@ -899,19 +895,19 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyRoundTrip(set, get, 2); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TRCK); assert.deepStrictEqual(( tag.frames[0]).text, ["12/2"]); PropertyTests.propertyRoundTrip(set, get, 123); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TRCK); assert.deepStrictEqual(( tag.frames[0]).text, ["12/123"]); PropertyTests.propertyRoundTrip(set, get, 0); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TRCK); assert.deepStrictEqual(( tag.frames[0]).text, ["12"]); } @@ -942,13 +938,13 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyRoundTrip(set, get, 2); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TPOS); assert.deepStrictEqual(( tag.frames[0]).text, ["2"]); PropertyTests.propertyRoundTrip(set, get, 123); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TPOS); assert.deepStrictEqual(( tag.frames[0]).text, ["123"]); @@ -969,19 +965,19 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyRoundTrip(set, get, 2); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TPOS); assert.deepStrictEqual(( tag.frames[0]).text, ["2/123"]); PropertyTests.propertyRoundTrip(set, get, 123); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TPOS); assert.deepStrictEqual(( tag.frames[0]).text, ["123/123"]); PropertyTests.propertyRoundTrip(set, get, 0); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TPOS); assert.deepStrictEqual(( tag.frames[0]).text, ["0/123"]); } @@ -1012,7 +1008,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyRoundTrip(set, get, 2); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TPOS); assert.deepStrictEqual(( tag.frames[0]).text, ["0/2"]); @@ -1033,13 +1029,13 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyRoundTrip(set, get, 2); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TPOS); assert.deepStrictEqual(( tag.frames[0]).text, ["12/2"]); PropertyTests.propertyRoundTrip(set, get, 0); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TPOS); assert.deepStrictEqual(( tag.frames[0]).text, ["12"]); } @@ -1060,7 +1056,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyRoundTrip(set, get, "lyrics"); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.UnsynchronizedLyricsFrame); + assert.instanceOf(tag.frames[0], UnsynchronizedLyricsFrame); assert.strictEqual(( tag.frames[0]).description, ""); assert.deepStrictEqual(( tag.frames[0]).text, "lyrics"); assert.strictEqual(( tag.frames[0]).textEncoding, Id3v2Settings.defaultEncoding); @@ -1093,7 +1089,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyRoundTrip(set, get, 128); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TBPM); assert.deepStrictEqual(( tag.frames[0]).text, ["128"]); @@ -1134,7 +1130,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyRoundTrip(set, get, new Date("2020-04-25 12:34:56")); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.TDTG); assert.deepStrictEqual(( tag.frames[0]).text, ["2020-04-25T12:34:56"]); @@ -1193,7 +1189,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyRoundTrip(set, get, "abcd-ef12-3456-7890"); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.UniqueFileIdentifierFrame); + assert.instanceOf(tag.frames[0], UniqueFileIdentifierFrame); assert.strictEqual(tag.frames[0].frameId, FrameIdentifiers.UFID); assert.deepStrictEqual(( tag.frames[0]).owner, "http://musicbrainz.org"); const expectedBytes = ByteVector.fromString("abcd-ef12-3456-7890", StringType.UTF8); @@ -1270,7 +1266,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyNormalized(setProp, getProp, 1.23456, 1.23); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.UserTextInformationFrame); + assert.instanceOf(tag.frames[0], UserTextInformationFrame); assert.strictEqual(( tag.frames[0]).description, "REPLAYGAIN_TRACK_GAIN"); assert.deepStrictEqual(( tag.frames[0]).text, ["1.23 dB"]); @@ -1296,7 +1292,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyNormalized(setProp, getProp, 1.23456789, 1.234568); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.UserTextInformationFrame); + assert.instanceOf(tag.frames[0], UserTextInformationFrame); assert.strictEqual(( tag.frames[0]).description, "REPLAYGAIN_TRACK_PEAK"); assert.deepStrictEqual(( tag.frames[0]).text, ["1.234568"]); @@ -1319,7 +1315,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyNormalized(setProp, getProp, 1.23456, 1.23); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.UserTextInformationFrame); + assert.instanceOf(tag.frames[0], UserTextInformationFrame); assert.strictEqual(( tag.frames[0]).description, "REPLAYGAIN_ALBUM_GAIN"); assert.deepStrictEqual(( tag.frames[0]).text, ["1.23 dB"]); @@ -1345,7 +1341,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyNormalized(setProp, getProp, 1.23456789, 1.234568); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.UserTextInformationFrame); + assert.instanceOf(tag.frames[0], UserTextInformationFrame); assert.strictEqual(( tag.frames[0]).description, "REPLAYGAIN_ALBUM_PEAK"); assert.deepStrictEqual(( tag.frames[0]).text, ["1.234568"]); @@ -1409,8 +1405,8 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: tag.pictures = pictures; assert.strictEqual(tag.frames.length, 2); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.AttachmentFrame); - assert.strictEqual(tag.frames[1].frameClassType, FrameClassType.AttachmentFrame); + assert.instanceOf(tag.frames[0], AttachmentFrame); + assert.instanceOf(tag.frames[1], AttachmentFrame); tag.pictures = undefined; assert.deepStrictEqual(tag.pictures, []); @@ -1443,7 +1439,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyRoundTrip(setProp, getProp, ["foo", "bar", "baz"]); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, fId); assert.deepStrictEqual(( tag.frames[0]).text, ["foo", "bar", "baz"]); @@ -1466,7 +1462,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyRoundTrip(setProp, getProp, "foo"); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.TextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(tag.frames[0].frameId, fId); assert.deepStrictEqual(( tag.frames[0]).text, ["foo"]); @@ -1489,7 +1485,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyRoundTrip(setProp, getProp, "foo"); assert.strictEqual(tag.frames.length, 1); - assert.strictEqual(tag.frames[0].frameClassType, FrameClassType.UserTextInformationFrame); + assert.instanceOf(tag.frames[0], TextInformationFrame); assert.strictEqual(( tag.frames[0]).description, desc); assert.deepStrictEqual(( tag.frames[0]).text, ["foo"]); @@ -1551,10 +1547,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: assert.notOwnInclude(dest.frames, sFrame2); assert.ownInclude(dest.frames, dFrame1); - const dPcnt = dest.getFramesByIdentifier( - FrameClassType.PlayCountFrame, - FrameIdentifiers.PCNT - )[0]; + const dPcnt = PlayCountFrame.filterFrames(dest.frames)[0]; assert.strictEqual(dPcnt.playCount, sFrame1.playCount); } @@ -1583,120 +1576,12 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: assert.notOwnInclude(dest.frames, sFrame1); assert.notOwnInclude(dest.frames, sFrame2); - const dTcom = dest.getFramesByIdentifier( - FrameClassType.TextInformationFrame, - FrameIdentifiers.TCOM - )[0]; + const dTcom = TextInformationFrame.filterFrames(dest.frames, FrameIdentifiers.TCOM)[0]; assert.deepStrictEqual(dTcom.text, ["foo", "bar"]); - const dPcnt = dest.getFramesByIdentifier( - FrameClassType.PlayCountFrame, - FrameIdentifiers.PCNT - )[0]; + const dPcnt = PlayCountFrame.filterFrames(dest.frames)[0]; assert.strictEqual(dPcnt.playCount, sFrame1.playCount); } - - @test - public getFramesByClassType_invalidClassType() { - // Arrange - const tag = Id3v2Tag.fromEmpty(); - - // Act / Assert - assert.throws(() => { tag.getFramesByClassType(undefined); }); - assert.throws(() => { tag.getFramesByClassType(null); }); - } - - @test - public getFramesByClassType_hasMatches() { - // Arrange - const tag = Id3v2Tag.fromEmpty(); - const frame1 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOM); - const frame2 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCON); - const frame3 = PlayCountFrame.fromEmpty(); - tag.frames.push(frame1, frame2, frame3); - - // Act - const result = tag.getFramesByClassType(FrameClassType.TextInformationFrame); - - // Assert - assert.isArray(result); - assert.strictEqual(result.length, 2); - assert.sameMembers(result, [frame1, frame2]); - } - - @test - public getFramesByClassType_noMatches() { - // Arrange - const tag = Id3v2Tag.fromEmpty(); - tag.frames.push(PlayCountFrame.fromEmpty()); - - // Act - const result = tag.getFramesByClassType(FrameClassType.TextInformationFrame); - - // Assert - assert.isArray(result); - assert.isEmpty(result); - } - - @test - public getFramesByIdentifier_invalidClassType() { - // Arrange - const tag = Id3v2Tag.fromEmpty(); - - // Act / Assert - assert.throws(() => { tag.getFramesByIdentifier(undefined, FrameIdentifiers.TCOM); }); - assert.throws(() => { tag.getFramesByIdentifier(null, FrameIdentifiers.TCOM); }); - } - - @test - public getFramesByIdentifier_invalidIdentifier() { - // Arrange - const tag = Id3v2Tag.fromEmpty(); - const classType = FrameClassType.TextInformationFrame; - - // Act / Assert - assert.throws(() => { tag.getFramesByIdentifier(classType, undefined); }); - assert.throws(() => { tag.getFramesByIdentifier(classType, null); }); - } - - @test - public getFramesByIdentifier_hasMatches() { - // Arrange - const tag = Id3v2Tag.fromEmpty(); - const frame1 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOM); - const frame2 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOM); - const frame3 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCON); - tag.frames.push(frame1, frame2, frame3); - - // Act - const result = tag.getFramesByIdentifier( - FrameClassType.TextInformationFrame, - FrameIdentifiers.TCOM - ); - - // Assert - assert.isArray(result); - assert.strictEqual(result.length, 2); - assert.sameMembers(result, [frame1, frame2]); - } - - @test - public getFramesByIdentifier_noMatches() { - // Arrange - const tag = Id3v2Tag.fromEmpty(); - tag.frames.push(TextInformationFrame.fromIdentifier(FrameIdentifiers.TCON)); - - // Act - const result = tag.getFramesByIdentifier( - FrameClassType.TextInformationFrame, - FrameIdentifiers.TCOM - ); - - // Assert - assert.isArray(result); - assert.isEmpty(result); - } - @test public getTextAsString_invalidIdentity() { // Arrange @@ -1712,9 +1597,9 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: // Arrange const tag = Id3v2Tag.fromEmpty(); const frame1 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOM); - const frame2 = UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM); + const frame2 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.WCOM); frame2.text = "foo"; - const frame3 = UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM); + const frame3 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.WCOM); frame3.text = "bar"; tag.frames.push(frame1, frame2, frame3); @@ -1729,7 +1614,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: public getTextAsString_textFrame() { // Arrange const tag = Id3v2Tag.fromEmpty(); - const frame1 = UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM); + const frame1 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.WCOM); const frame2 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOM); frame2.text = ["foo"]; const frame3 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOM); @@ -1747,7 +1632,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: public getTextAsString_noMatches() { // Arrange const tag = Id3v2Tag.fromEmpty(); - const frame1 = UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM); + const frame1 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.WCOM); tag.frames.push(frame1); // Act @@ -2210,9 +2095,9 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: @params(undefined, "undefined") public setUrlFrame_falsyValue_removesFrame(text: string) { // Arrange - const frame1 = UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM); + const frame1 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.WCOM); frame1.text = "foo"; - const frame2 = UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM); + const frame2 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.WCOM); frame2.text = "bar"; const tag = Id3v2Tag.fromEmpty(); @@ -2243,7 +2128,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: public setUrlFrame_withMatchingFrames_updatesFrame() { // Arrange const tag = Id3v2Tag.fromEmpty(); - const frame = UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM); + const frame = UrlLinkFrame.fromIdentifier(FrameIdentifiers.WCOM); frame.text = "fux"; // Act diff --git a/test-unit/id3v2/musicCdIdentifierFrameTests.ts b/test-unit/id3v2/musicCdIdentifierFrameTests.ts index 17f615c..4f0b36e 100644 --- a/test-unit/id3v2/musicCdIdentifierFrameTests.ts +++ b/test-unit/id3v2/musicCdIdentifierFrameTests.ts @@ -1,11 +1,12 @@ import {params, suite, test} from "@testdeck/mocha"; import {assert} from "chai"; +import Frame from "../../src/id3v2/frames/frame"; import FrameConstructorTests from "./frameConstructorTests"; import MusicCdIdentifierFrame from "../../src/id3v2/frames/musicCdIdentifierFrame"; import PropertyTests from "../utilities/propertyTests"; +import UnknownFrame from "../../src/id3v2/frames/unknownFrame"; import {ByteVector, StringType} from "../../src/byteVector"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Testers} from "../utilities/testers"; @@ -65,11 +66,88 @@ import {Testers} from "../utilities/testers"; const result = frame.clone(); // Assert - assert.ok(result); - assert.strictEqual(result.frameClassType, FrameClassType.MusicCdIdentifierFrame); - assert.strictEqual(result.frameId, FrameIdentifiers.MCDI); + Id3v2_MusicCdIdentifierFrameTests.assertFrame(result, frame.data); + } + + @test + public filterFrames_falsyFrames() { + // Act/Assert + Testers.testTruthy((v: MusicCdIdentifierFrame[]) => { MusicCdIdentifierFrame.filterFrames(v); }); + } + + @test + public filterFrames_noFrames() { + // Arrange + const frames: Frame[] = []; + + // Act + const output = MusicCdIdentifierFrame.filterFrames(frames); + + // Assert + assert.isArray(output); + assert.isEmpty(output); + } + + @test + public filterFrames_noMatch() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(234)); + const frames = [frame1, frame2]; + + // Act + const result = MusicCdIdentifierFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.isEmpty(result); + } + + @test + public filterFrames_singleMatch() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = MusicCdIdentifierFrame.fromData(ByteVector.empty()); + const frames = [frame1, frame2]; + + // Act + const result = MusicCdIdentifierFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame2]); + } + + @test + public filterFrames_multipleMatches() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = MusicCdIdentifierFrame.fromData(ByteVector.empty()); + const frame3 = MusicCdIdentifierFrame.fromData(ByteVector.empty()); + + const frames = [frame1, frame2, frame3]; - Testers.bvEqual(result.data, fieldBytes); + // Act + const result = MusicCdIdentifierFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); + } + + @test + public filterFrames_allMatches() { + // Arrange + const frame1 = MusicCdIdentifierFrame.fromData(ByteVector.empty()); + const frame2 = MusicCdIdentifierFrame.fromData(ByteVector.empty()); + const frames = [frame1, frame2]; + + // Act + const result = MusicCdIdentifierFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); } @params(2, "v2") @@ -93,7 +171,7 @@ import {Testers} from "../utilities/testers"; private static assertFrame(frame: MusicCdIdentifierFrame, d: ByteVector) { assert.isOk(frame); - assert.strictEqual(frame.frameClassType, FrameClassType.MusicCdIdentifierFrame); + assert.instanceOf(frame, MusicCdIdentifierFrame); assert.strictEqual(frame.frameId, FrameIdentifiers.MCDI); Testers.bvEqual(frame.data, d); diff --git a/test-unit/id3v2/playCountFrameTests.ts b/test-unit/id3v2/playCountFrameTests.ts index 0c1937e..40824a9 100644 --- a/test-unit/id3v2/playCountFrameTests.ts +++ b/test-unit/id3v2/playCountFrameTests.ts @@ -1,15 +1,24 @@ import {params, suite, test} from "@testdeck/mocha"; import {assert} from "chai"; +import Frame from "../../src/id3v2/frames/frame"; import FrameConstructorTests from "./frameConstructorTests"; import PlayCountFrame from "../../src/id3v2/frames/playCountFrame"; import PropertyTests from "../utilities/propertyTests"; +import UnknownFrame from "../../src/id3v2/frames/unknownFrame"; import {ByteVector} from "../../src/byteVector"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Testers} from "../utilities/testers"; +const assertFrame = (frame: PlayCountFrame, p: bigint) => { + assert.isOk(frame); + assert.instanceOf(frame, PlayCountFrame); + assert.strictEqual(frame.frameId, FrameIdentifiers.PCNT); + + assert.strictEqual(frame.playCount, p); +} + @suite class Id3v2_PlayCountFrame_ConstructorTests extends FrameConstructorTests { public get fromFieldBytes(): (h: Id3v2FrameHeader, d: ByteVector, v: number) => Frame { return PlayCountFrame.fromFieldBytes; @@ -21,7 +30,7 @@ import {Testers} from "../utilities/testers"; const frame = PlayCountFrame.fromEmpty(); // Assert - this.assertFrame(frame, BigInt(0)); + assertFrame(frame, BigInt(0)); } @params(2, "v2") @@ -60,7 +69,7 @@ import {Testers} from "../utilities/testers"; const frame = PlayCountFrame.fromFieldBytes(header, fieldBytes, version); // Assert - this.assertFrame(frame, BigInt(1234)); + assertFrame(frame, BigInt(1234)); } @params(2, "v2") @@ -75,7 +84,7 @@ import {Testers} from "../utilities/testers"; const frame = PlayCountFrame.fromFieldBytes(header, fieldBytes, version); // Assert - this.assertFrame(frame, BigInt("1108152157446")); + assertFrame(frame, BigInt("1108152157446")); } @params(2, "v2") @@ -90,15 +99,7 @@ import {Testers} from "../utilities/testers"; const frame = PlayCountFrame.fromFieldBytes(header, fieldBytes, version); // Assert - this.assertFrame(frame, BigInt("72623859790382856")); - } - - private assertFrame(frame: PlayCountFrame, p: bigint) { - assert.isOk(frame); - assert.strictEqual(frame.frameClassType, FrameClassType.PlayCountFrame); - assert.strictEqual(frame.frameId, FrameIdentifiers.PCNT); - - assert.strictEqual(frame.playCount, p); + assertFrame(frame, BigInt("72623859790382856")); } } @@ -129,11 +130,88 @@ import {Testers} from "../utilities/testers"; const output = frame.clone(); // Assert - assert.isOk(output); - assert.strictEqual(output.frameClassType, FrameClassType.PlayCountFrame); - assert.strictEqual(output.frameId, FrameIdentifiers.PCNT); + assertFrame(output, frame.playCount); + } + + @test + public filterFrames_falsyFrames() { + // Act/Assert + Testers.testTruthy((v: PlayCountFrame[]) => { PlayCountFrame.filterFrames(v); }); + } + + @test + public filterFrames_noFrames() { + // Arrange + const frames: Frame[] = []; + + // Act + const output = PlayCountFrame.filterFrames(frames); + + // Assert + assert.isArray(output); + assert.isEmpty(output); + } + + @test + public filterFrames_noMatch() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(234)); + const frames = [frame1, frame2]; + + // Act + const result = PlayCountFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.isEmpty(result); + } + + @test + public filterFrames_singleMatch() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = PlayCountFrame.fromEmpty(); + const frames = [frame1, frame2]; + + // Act + const result = PlayCountFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame2]); + } + + @test + public filterFrames_multipleMatches() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = PlayCountFrame.fromEmpty(); + const frame3 = PlayCountFrame.fromEmpty(); - assert.strictEqual(output.playCount, frame.playCount); + const frames = [frame1, frame2, frame3]; + + // Act + const result = PlayCountFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); + } + + @test + public filterFrames_allMatches() { + // Arrange + const frame1 = PlayCountFrame.fromEmpty(); + const frame2 = PlayCountFrame.fromEmpty(); + const frames = [frame1, frame2]; + + // Act + const result = PlayCountFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); } @params(2, "v2") diff --git a/test-unit/id3v2/popularimeterFrameTests.ts b/test-unit/id3v2/popularimeterFrameTests.ts index 5aea5f7..509abde 100644 --- a/test-unit/id3v2/popularimeterFrameTests.ts +++ b/test-unit/id3v2/popularimeterFrameTests.ts @@ -1,15 +1,26 @@ import {params, suite, test} from "@testdeck/mocha"; import {assert} from "chai"; +import Frame from "../../src/id3v2/frames/frame"; import FrameConstructorTests from "./frameConstructorTests"; import PopularimeterFrame from "../../src/id3v2/frames/popularimeterFrame"; import PropertyTests from "../utilities/propertyTests"; +import UnknownFrame from "../../src/id3v2/frames/unknownFrame"; import {ByteVector, StringType} from "../../src/byteVector"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Testers} from "../utilities/testers"; +const assertFrame = (frame: PopularimeterFrame, u: string, p: bigint, r: number) => { + assert.isOk(frame); + assert.instanceOf(frame, PopularimeterFrame); + assert.strictEqual(frame.frameId, FrameIdentifiers.POPM); + + assert.strictEqual(frame.playCount, p); + assert.strictEqual(frame.rating, r); + assert.strictEqual(frame.user, u); +} + @suite class Id3v2_PopularimeterFrame_ConstructorTests extends FrameConstructorTests { public get fromFieldBytes(): (h: Id3v2FrameHeader, d: ByteVector, v: number) => Frame { return PopularimeterFrame.fromFieldBytes; @@ -21,7 +32,7 @@ import {Testers} from "../utilities/testers"; const frame = PopularimeterFrame.fromUser("fux"); // Assert - this.assertFrame(frame, "fux", undefined, 0); + assertFrame(frame, "fux", undefined, 0); } @params(2, "v2") @@ -84,7 +95,7 @@ import {Testers} from "../utilities/testers"; const frame = PopularimeterFrame.fromFieldBytes(header, fieldBytes, 4); // Assert - this.assertFrame(frame, "foo@example.com", undefined, 0xAB); + assertFrame(frame, "foo@example.com", undefined, 0xAB); } @params(2, "v2") @@ -103,7 +114,7 @@ import {Testers} from "../utilities/testers"; const frame = PopularimeterFrame.fromFieldBytes(header, fieldBytes, version); // Assert - this.assertFrame(frame, "foo@example.com", BigInt(1234), 0xAB); + assertFrame(frame, "foo@example.com", BigInt(1234), 0xAB); } @params(2, "v2") @@ -122,7 +133,7 @@ import {Testers} from "../utilities/testers"; const frame = PopularimeterFrame.fromFieldBytes(header, fieldBytes, version); // Assert - this.assertFrame(frame, "foo@example.com", BigInt("1108152157446"), 0xAB); + assertFrame(frame, "foo@example.com", BigInt("1108152157446"), 0xAB); } @params(2, "v2") @@ -141,23 +152,7 @@ import {Testers} from "../utilities/testers"; const frame = PopularimeterFrame.fromFieldBytes(header, fieldBytes, version); // Assert - this.assertFrame(frame, "foo@example.com", BigInt("72623859790382856"), 0xAB); - } - - private assertFrame(frame: PopularimeterFrame, u: string, p: bigint, r: number) { - assert.isOk(frame); - assert.strictEqual(frame.frameClassType, FrameClassType.PopularimeterFrame); - assert.strictEqual(frame.frameId, FrameIdentifiers.POPM); - - if (p === undefined) { - assert.isUndefined(frame.playCount); - } else { - assert.isOk(frame.playCount); - assert.strictEqual(p, frame.playCount); - } - - assert.strictEqual(frame.rating, r); - assert.strictEqual(frame.user, u); + assertFrame(frame, "foo@example.com", BigInt("72623859790382856"), 0xAB); } } @@ -206,70 +201,98 @@ import {Testers} from "../utilities/testers"; @suite class Id3v2_PopularimeterFrame_MethodTests { @test - public find_falsyFrames() { - // Act / Assert - Testers.testTruthy((v: PopularimeterFrame[]) => { PopularimeterFrame.find(v, "fux"); }); + public clone() { + // Arrange + const frame = PopularimeterFrame.fromUser("fux"); + frame.playCount = BigInt(1234); + frame.rating = 5; + + // Act + const output = frame.clone(); + + // Assert + assertFrame(output, frame.user, frame.playCount, frame.rating); } @test - public find_noFrames() { + public filterFrames_falsyFrames() { + // Act/Assert + Testers.testTruthy((v: PopularimeterFrame[]) => { PopularimeterFrame.filterFrames(v); }); + } + + @test + public filterFrames_noFrames() { + // Arrange + const frames: Frame[] = []; + // Act - const output = PopularimeterFrame.find([], "fux"); + const output = PopularimeterFrame.filterFrames(frames); // Assert - assert.isUndefined(output); + assert.isArray(output); + assert.isEmpty(output); } @test - public find_noMatches() { + public filterFrames_noMatch() { // Arrange - const frames = [ - PopularimeterFrame.fromUser("fux") - ]; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(234)); + const frames = [frame1, frame2]; // Act - const output = PopularimeterFrame.find(frames, "bux"); + const result = PopularimeterFrame.filterFrames(frames); // Assert - assert.isUndefined(output); + assert.isArray(result); + assert.isEmpty(result); } @test - public find_matches() { + public filterFrames_singleMatch() { // Arrange - const frames = [ - PopularimeterFrame.fromUser("fux"), - PopularimeterFrame.fromUser("bux") - ]; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = PopularimeterFrame.fromUser("foo"); + const frames = [frame1, frame2]; // Act - const output = PopularimeterFrame.find(frames, "bux"); + const result = PopularimeterFrame.filterFrames(frames); // Assert - assert.isOk(output); - assert.strictEqual(output, frames[1]); + assert.isArray(result); + assert.deepEqual(result, [frame2]); } @test - public clone() { + public filterFrames_multipleMatches() { // Arrange - const frame = PopularimeterFrame.fromUser("fux"); - frame.playCount = BigInt(1234); - frame.rating = 5; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = PopularimeterFrame.fromUser("foo"); + const frame3 = PopularimeterFrame.fromUser("bar"); + + const frames = [frame1, frame2, frame3]; // Act - const output = frame.clone(); + const result = PopularimeterFrame.filterFrames(frames); // Assert - assert.isOk(output); - assert.strictEqual(output.frameClassType, FrameClassType.PopularimeterFrame); - assert.strictEqual(output.frameId, FrameIdentifiers.POPM); + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); + } - assert.isOk(output.playCount); - assert.strictEqual(frame.playCount, output.playCount); + @test + public filterFrames_allMatches() { + // Arrange + const frame1 = PopularimeterFrame.fromUser("foo"); + const frame2 = PopularimeterFrame.fromUser("bar"); + const frames = [frame1, frame2]; + + // Act + const result = PopularimeterFrame.filterFrames(frames); - assert.strictEqual(output.rating, frame.rating); - assert.strictEqual(output.user, frame.user); + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); } @params(2, "v2") diff --git a/test-unit/id3v2/privateFrameTests.ts b/test-unit/id3v2/privateFrameTests.ts index 804aae7..0521bea 100644 --- a/test-unit/id3v2/privateFrameTests.ts +++ b/test-unit/id3v2/privateFrameTests.ts @@ -1,15 +1,25 @@ import {params, suite, test} from "@testdeck/mocha"; import {assert} from "chai"; +import Frame from "../../src/id3v2/frames/frame"; import FrameConstructorTests from "./frameConstructorTests"; import PropertyTests from "../utilities/propertyTests"; import PrivateFrame from "../../src/id3v2/frames/privateFrame"; +import UnknownFrame from "../../src/id3v2/frames/unknownFrame"; import {ByteVector, StringType} from "../../src/byteVector"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Testers} from "../utilities/testers"; +const assertFrame = (frame: PrivateFrame, o: string, d: ByteVector) => { + assert.isOk(frame); + assert.instanceOf(frame, PrivateFrame); + assert.strictEqual(frame.frameId, FrameIdentifiers.PRIV); + + assert.strictEqual(frame.owner, o); + Testers.bvEqual(frame.privateData, d); +} + @suite class Id3v2_PrivateFrame_ConstructorTests extends FrameConstructorTests { public get fromFieldBytes(): (h: Id3v2FrameHeader, d: ByteVector, v: number) => Frame { return PrivateFrame.fromFieldBytes; @@ -21,7 +31,7 @@ import {Testers} from "../utilities/testers"; const frame = PrivateFrame.fromOwner("foo"); // Assert - Id3v2_PrivateFrame_ConstructorTests.assertFrame(frame, "foo", ByteVector.empty()); + assertFrame(frame, "foo", ByteVector.empty()); } @test @@ -49,7 +59,7 @@ import {Testers} from "../utilities/testers"; const frame = PrivateFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_PrivateFrame_ConstructorTests.assertFrame(frame, "fux", ByteVector.empty()); + assertFrame(frame, "fux", ByteVector.empty()); } @params(2, "v2") @@ -68,7 +78,7 @@ import {Testers} from "../utilities/testers"; const frame = PrivateFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_PrivateFrame_ConstructorTests.assertFrame(frame, "", dataBytes); + assertFrame(frame, "", dataBytes); } @params(2, "v2") @@ -88,16 +98,7 @@ import {Testers} from "../utilities/testers"; const frame = PrivateFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_PrivateFrame_ConstructorTests.assertFrame(frame, "foo", dataBytes); - } - - private static assertFrame(frame: PrivateFrame, o: string, d: ByteVector) { - assert.isOk(frame); - assert.strictEqual(frame.frameClassType, FrameClassType.PrivateFrame); - assert.strictEqual(frame.frameId, FrameIdentifiers.PRIV); - - assert.strictEqual(frame.owner, o); - Testers.bvEqual(frame.privateData, d); + assertFrame(frame, "foo", dataBytes); } } @@ -118,66 +119,98 @@ import {Testers} from "../utilities/testers"; @suite class Id3v2_PrivateFrame_MethodTests { @test - public find_noFrames() { + public clone() { // Arrange - const frames: PrivateFrame[] = []; + const frame = PrivateFrame.fromOwner("fux"); // Act - const output = PrivateFrame.find(frames, "fux"); + const output = frame.clone(); // Assert - assert.isUndefined(output); + assertFrame(output, frame.owner, frame.privateData); + } + + @test + public filterFrames_falsyFrames() { + // Act/Assert + Testers.testTruthy((v: PrivateFrame[]) => { PrivateFrame.filterFrames(v); }); } @test - public find_noMatch() { + public filterFrames_noFrames() { // Arrange - const frames = [ - PrivateFrame.fromOwner("fux") - ]; + const frames: Frame[] = []; // Act - const output = PrivateFrame.find(frames, "bux"); + const output = PrivateFrame.filterFrames(frames); // Assert - assert.isUndefined(output); + assert.isArray(output); + assert.isEmpty(output); } @test - public find_match() { + public filterFrames_noMatch() { // Arrange - const frames = [ - PrivateFrame.fromOwner("fux"), - PrivateFrame.fromOwner("bux") - ]; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(234)); + const frames = [frame1, frame2]; // Act - const output = PrivateFrame.find(frames, "bux"); + const result = PrivateFrame.filterFrames(frames); // Assert - assert.strictEqual(output, frames[1]); + assert.isArray(result); + assert.isEmpty(result); } @test - public clone() { + public filterFrames_singleMatch() { // Arrange - const frame = PrivateFrame.fromOwner("fux"); + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = PrivateFrame.fromOwner("foo"); + const frames = [frame1, frame2]; // Act - const output = frame.clone(); + const result = PrivateFrame.filterFrames(frames); // Assert - assert.isOk(output); - assert.notEqual(frame, output); + assert.isArray(result); + assert.deepEqual(result, [frame2]); + } + + @test + public filterFrames_multipleMatches() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = PrivateFrame.fromOwner("foo"); + const frame3 = PrivateFrame.fromOwner("bar"); + + const frames = [frame1, frame2, frame3]; - assert.strictEqual(output.frameClassType, FrameClassType.PrivateFrame); - assert.strictEqual(output.frameId, FrameIdentifiers.PRIV); + // Act + const result = PrivateFrame.filterFrames(frames); - assert.strictEqual(output.owner, frame.owner); - assert.notEqual(output.privateData, frame.privateData); - Testers.bvEqual(output.privateData, frame.privateData); + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); } + @test + public filterFrames_allMatches() { + // Arrange + const frame1 = PrivateFrame.fromOwner("foo"); + const frame2 = PrivateFrame.fromOwner("bar"); + const frames = [frame1, frame2]; + + // Act + const result = PrivateFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); + } + @test public render_v2_throws() { // Arrange diff --git a/test-unit/id3v2/relativeVolumeFrameTests.ts b/test-unit/id3v2/relativeVolumeFrameTests.ts index 756e8a5..0e08fa1 100644 --- a/test-unit/id3v2/relativeVolumeFrameTests.ts +++ b/test-unit/id3v2/relativeVolumeFrameTests.ts @@ -1,15 +1,25 @@ import {params, suite, test} from "@testdeck/mocha"; import {assert} from "chai"; -import ConstructorTests from "./frameConstructorTests"; +import Frame from "../../src/id3v2/frames/frame"; +import FrameConstructorTests from "./frameConstructorTests"; import PropertyTests from "../utilities/propertyTests"; +import UnknownFrame from "../../src/id3v2/frames/unknownFrame"; import {ChannelData, ChannelType, RelativeVolumeFrame} from "../../src/id3v2/frames/relativeVolumeFrame"; import {ByteVector, StringType} from "../../src/byteVector"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Testers} from "../utilities/testers"; +const assertFrame = (frame: RelativeVolumeFrame, c: ChannelData[], i: string) => { + assert.isOk(frame); + assert.instanceOf(frame, RelativeVolumeFrame); + assert.strictEqual(frame.frameId, FrameIdentifiers.RVA2); + + assert.deepStrictEqual(frame.channels, c); + assert.strictEqual(frame.identification, i); +} + @suite class Id3v2_RelativeVolumeChannelData { @test public peakBits_setInvalidValues() { @@ -272,7 +282,7 @@ import {Testers} from "../utilities/testers"; } } -@suite class Id3v2_RelativeVolumeFrame_ConstructorTests extends ConstructorTests { +@suite class Id3v2_RelativeVolumeFrame_ConstructorTests extends FrameConstructorTests { public get fromFieldBytes(): (h: Id3v2FrameHeader, b: ByteVector, v: number) => Frame { return RelativeVolumeFrame.fromFieldBytes; } @@ -283,7 +293,7 @@ import {Testers} from "../utilities/testers"; const frame = RelativeVolumeFrame.fromIdentification("foo"); // Assert - Id3v2_RelativeVolumeFrame_ConstructorTests.assertFrame(frame, [], "foo"); + assertFrame(frame, [], "foo"); } @params(2, "v2") @@ -310,7 +320,7 @@ import {Testers} from "../utilities/testers"; const frame = RelativeVolumeFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_RelativeVolumeFrame_ConstructorTests.assertFrame(frame, [], "foobarbaz"); + assertFrame(frame, [], "foobarbaz"); } @params(2, "v2") @@ -335,7 +345,7 @@ import {Testers} from "../utilities/testers"; channelData.peakBits = 32; channelData.peakVolume = BigInt(16909060); channelData.volumeAdjustment = 123/512; - Id3v2_RelativeVolumeFrame_ConstructorTests.assertFrame(frame, [channelData], "foobarbaz"); + assertFrame(frame, [channelData], "foobarbaz"); } @params(2, "v2") @@ -371,7 +381,7 @@ import {Testers} from "../utilities/testers"; cd2.peakBits = 32; cd2.peakVolume = BigInt(33752069); cd2.volumeAdjustment = 234 / 512; - Id3v2_RelativeVolumeFrame_ConstructorTests.assertFrame(frame, [cd2, cd1], "foobarbaz"); + assertFrame(frame, [cd2, cd1], "foobarbaz"); } @params(2, "v2") @@ -400,7 +410,7 @@ import {Testers} from "../utilities/testers"; cd1.peakBits = 32; cd1.peakVolume = BigInt(16909060); cd1.volumeAdjustment = 123 / 512; - Id3v2_RelativeVolumeFrame_ConstructorTests.assertFrame(frame, [cd1], "foobarbaz"); + assertFrame(frame, [cd1], "foobarbaz"); } @params(2, "v2") @@ -431,56 +441,124 @@ import {Testers} from "../utilities/testers"; cd1.peakBits = 32; cd1.peakVolume = BigInt(16909060); cd1.volumeAdjustment = 123 / 512; - Id3v2_RelativeVolumeFrame_ConstructorTests.assertFrame(frame, [cd1], "foobarbaz"); + assertFrame(frame, [cd1], "foobarbaz"); } +} - private static assertFrame(frame: RelativeVolumeFrame, c: ChannelData[], i: string) { - assert.isOk(frame); - assert.strictEqual(frame.frameClassType, FrameClassType.RelativeVolumeFrame); - assert.strictEqual(frame.frameId, FrameIdentifiers.RVA2); +@suite class Id3v2_RelativeVolumeFrame_MethodTests { + @test + public clone() { + // Arrange + const frame = RelativeVolumeFrame.fromIdentification("foobarbaz"); + frame.setPeakBits(ChannelType.Subwoofer, 32); + frame.setPeakVolume(ChannelType.Subwoofer, BigInt(12345)); + frame.setVolumeAdjustment(ChannelType.Subwoofer, -1.23); + frame.setPeakBits(ChannelType.BackCenter, 48); + frame.setPeakVolume(ChannelType.BackCenter, BigInt(23456)); + frame.setVolumeAdjustment(ChannelType.BackCenter, 1.23); + + // Act + const clone = frame.clone(); - assert.deepStrictEqual(frame.channels, c); - assert.strictEqual(frame.identification, i); + // Assert + assert.isOk(clone); + assert.instanceOf(clone, RelativeVolumeFrame); + assert.notStrictEqual(clone, frame); + assert.strictEqual(clone.identification, frame.identification); + assert.deepStrictEqual(clone.channels, frame.channels); + assert.strictEqual(clone.getPeakBits(ChannelType.Subwoofer), frame.getPeakBits(ChannelType.Subwoofer)); + assert.strictEqual(clone.getPeakVolume(ChannelType.Subwoofer), frame.getPeakVolume(ChannelType.Subwoofer)); + assert.strictEqual( + clone.getVolumeAdjustment(ChannelType.Subwoofer), + frame.getVolumeAdjustment(ChannelType.Subwoofer) + ); + assert.strictEqual(clone.getPeakBits(ChannelType.BackCenter), frame.getPeakBits(ChannelType.BackCenter)); + assert.strictEqual(clone.getPeakVolume(ChannelType.BackCenter), frame.getPeakVolume(ChannelType.BackCenter)); + assert.strictEqual( + clone.getVolumeAdjustment(ChannelType.BackCenter), + frame.getVolumeAdjustment(ChannelType.BackCenter) + ); } -} -@suite class Id3v2_RelativeVolumeFrameMethodTests { @test - public find_falsyFrames() { - // Act / Assert - Testers.testTruthy((v: RelativeVolumeFrame[]) => { RelativeVolumeFrame.find(v, "foo"); }); + public filterFrames_falsyFrames() { + // Act/Assert + Testers.testTruthy((v: RelativeVolumeFrame[]) => { RelativeVolumeFrame.filterFrames(v); }); } @test - public find_noMatches() { + public filterFrames_noFrames() { // Arrange - const frames = [ - RelativeVolumeFrame.fromIdentification("fux"), - RelativeVolumeFrame.fromIdentification("bux") - ]; + const frames: Frame[] = []; + + // Act + const output = RelativeVolumeFrame.filterFrames(frames); + + // Assert + assert.isArray(output); + assert.isEmpty(output); + } + + @test + public filterFrames_noMatch() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(234)); + const frames = [frame1, frame2]; + + // Act + const result = RelativeVolumeFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.isEmpty(result); + } + + @test + public filterFrames_singleMatch() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = RelativeVolumeFrame.fromIdentification("foo"); + const frames = [frame1, frame2]; + + // Act + const result = RelativeVolumeFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame2]); + } + + @test + public filterFrames_multipleMatches() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = RelativeVolumeFrame.fromIdentification("foo"); + const frame3 = RelativeVolumeFrame.fromIdentification("bar"); + + const frames = [frame1, frame2, frame3]; // Act - const result = RelativeVolumeFrame.find(frames, "qux"); + const result = RelativeVolumeFrame.filterFrames(frames); // Assert - assert.isUndefined(result); + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); } @test - public find_multipleMatches() { + public filterFrames_allMatches() { // Arrange - const frames = [ - RelativeVolumeFrame.fromIdentification("fux"), - RelativeVolumeFrame.fromIdentification("bux"), - RelativeVolumeFrame.fromIdentification("qux"), - RelativeVolumeFrame.fromIdentification("qux") - ]; + const frame1 = RelativeVolumeFrame.fromIdentification("foo"); + const frame2 = RelativeVolumeFrame.fromIdentification("bar"); + const frames = [frame1, frame2]; // Act - const result = RelativeVolumeFrame.find(frames, "qux"); + const result = RelativeVolumeFrame.filterFrames(frames); // Assert - assert.strictEqual(result, frames[2]); + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); } @test diff --git a/test-unit/id3v2/synchronizedLyricsFrameTests.ts b/test-unit/id3v2/synchronizedLyricsFrameTests.ts index 30c0d93..e719003 100644 --- a/test-unit/id3v2/synchronizedLyricsFrameTests.ts +++ b/test-unit/id3v2/synchronizedLyricsFrameTests.ts @@ -1,17 +1,41 @@ import {params, suite, test} from "@testdeck/mocha"; import {assert} from "chai"; +import Frame from "../../src/id3v2/frames/frame"; import FrameConstructorTests from "./frameConstructorTests"; import Id3v2Settings from "../../src/id3v2/id3v2Settings"; import PropertyTests from "../utilities/propertyTests"; +import UnknownFrame from "../../src/id3v2/frames/unknownFrame"; import {ByteVector, StringType} from "../../src/byteVector"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {SynchronizedLyricsFrame, SynchronizedText} from "../../src/id3v2/frames/synchronizedLyricsFrame"; import {Testers} from "../utilities/testers"; import {SynchronizedTextType, TimestampFormat} from "../../src/id3v2/utilTypes"; +const assertFrame = ( + frame: SynchronizedLyricsFrame, + description: string, + format: TimestampFormat, + language: string, + text: SynchronizedText[], + textEncoding: StringType, + textType: SynchronizedTextType +) => { + assert.isOk(frame); + assert.instanceOf(frame, SynchronizedLyricsFrame); + assert.strictEqual(frame.frameId, FrameIdentifiers.SYLT); + + assert.strictEqual(frame.description, description); + assert.strictEqual(frame.format, format); + assert.strictEqual(frame.language, language); + assert.strictEqual(frame.textEncoding, textEncoding); + assert.strictEqual(frame.textType, textType); + + assert.isArray(frame.text); + assert.deepStrictEqual(frame.text, text); +} + @suite class Id3v2_SynchronizedTextTests { @test public synchronizedText_construct() { @@ -57,15 +81,7 @@ import {SynchronizedTextType, TimestampFormat} from "../../src/id3v2/utilTypes"; const frame = SynchronizedLyricsFrame.fromInfo(description, language, textType); // Assert - Id3v2_SynchronizedLyricsFrame_ConstructorTests.assertFrame( - frame, - description, - TimestampFormat.Unknown, - language, - [], - Id3v2Settings.defaultEncoding, - textType - ); + assertFrame(frame, description, TimestampFormat.Unknown, language, [], Id3v2Settings.defaultEncoding, textType); } @test @@ -80,15 +96,7 @@ import {SynchronizedTextType, TimestampFormat} from "../../src/id3v2/utilTypes"; const frame = SynchronizedLyricsFrame.fromInfo(description, language, textType, encoding); // Assert - Id3v2_SynchronizedLyricsFrame_ConstructorTests.assertFrame( - frame, - description, - TimestampFormat.Unknown, - language, - [], - encoding, - textType - ); + assertFrame(frame, description, TimestampFormat.Unknown, language, [], encoding, textType); } @params(2, "v2") @@ -184,7 +192,7 @@ import {SynchronizedTextType, TimestampFormat} from "../../src/id3v2/utilTypes"; const frame = SynchronizedLyricsFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_SynchronizedLyricsFrame_ConstructorTests.assertFrame( + assertFrame( frame, "bux", TimestampFormat.AbsoluteMilliseconds, @@ -217,7 +225,7 @@ import {SynchronizedTextType, TimestampFormat} from "../../src/id3v2/utilTypes"; const frame = SynchronizedLyricsFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_SynchronizedLyricsFrame_ConstructorTests.assertFrame( + assertFrame( frame, "bux", TimestampFormat.AbsoluteMilliseconds, @@ -252,7 +260,7 @@ import {SynchronizedTextType, TimestampFormat} from "../../src/id3v2/utilTypes"; const frame = SynchronizedLyricsFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_SynchronizedLyricsFrame_ConstructorTests.assertFrame( + assertFrame( frame, "bux", TimestampFormat.AbsoluteMilliseconds, @@ -286,7 +294,7 @@ import {SynchronizedTextType, TimestampFormat} from "../../src/id3v2/utilTypes"; const frame = SynchronizedLyricsFrame.fromFieldBytes(header, fieldBytes, 4); // Assert - Id3v2_SynchronizedLyricsFrame_ConstructorTests.assertFrame( + assertFrame( frame, "baz", TimestampFormat.AbsoluteMpegFrames, @@ -296,29 +304,6 @@ import {SynchronizedTextType, TimestampFormat} from "../../src/id3v2/utilTypes"; SynchronizedTextType.Events ); } - - private static assertFrame( - frame: SynchronizedLyricsFrame, - d: string, - f: TimestampFormat, - l: string, - t: SynchronizedText[], - te: StringType, - tt: SynchronizedTextType - ) { - assert.isOk(frame); - assert.strictEqual(frame.frameClassType, FrameClassType.SynchronizedLyricsFrame); - assert.strictEqual(frame.frameId, FrameIdentifiers.SYLT); - - assert.strictEqual(frame.description, d); - assert.strictEqual(frame.format, f); - assert.strictEqual(frame.language, l); - assert.strictEqual(frame.textEncoding, te); - assert.strictEqual(frame.textType, tt); - - assert.isArray(frame.text); - assert.deepStrictEqual(frame.text, t); - } } @suite class Id3v2_SynchronizedLyricsFrame_PropertyTests { @@ -403,212 +388,103 @@ import {SynchronizedTextType, TimestampFormat} from "../../src/id3v2/utilTypes"; @suite class Id3v2_SynchronizedLyricsFrame_MethodTests { @test - public find_falsyFrames() { - // Act / Assert - Testers.testTruthy((v: SynchronizedLyricsFrame[]) => { - SynchronizedLyricsFrame.find(v, "fux", SynchronizedTextType.Chord); - }); - } - - @test - public find_emptyFrames() { - // Act - const output = SynchronizedLyricsFrame.find([], "fux", SynchronizedTextType.Chord); - - // Assert - assert.isUndefined(output); - } - - @test - public find_noMatchWithoutLanguage() { - // Arrange - const frames = [ - SynchronizedLyricsFrame.fromInfo("foo", "bar", SynchronizedTextType.Trivia), // desc does not match - SynchronizedLyricsFrame.fromInfo("fux", "bux", SynchronizedTextType.Trivia) // type does not match - ]; - - // Act - const output = SynchronizedLyricsFrame.find(frames, "fux", SynchronizedTextType.Chord); - - // Assert - assert.isUndefined(output); - } - - @test - public find_noMatchWithLanguage() { - // Arrange - const frames = [ - SynchronizedLyricsFrame.fromInfo("foo", "bar", SynchronizedTextType.Trivia), // desc does not match - SynchronizedLyricsFrame.fromInfo("fux", "bar", SynchronizedTextType.Trivia), // lang goes not match - SynchronizedLyricsFrame.fromInfo("fux", "bux", SynchronizedTextType.Trivia) // type does not match - ]; - - // Act - const output = SynchronizedLyricsFrame.find(frames, "fux", SynchronizedTextType.Chord, "bux"); - - // Assert - assert.isUndefined(output); - } - - @test - public find_matchExists() { + public clone() { // Arrange - const frames = [ - SynchronizedLyricsFrame.fromInfo("foo", "bar", SynchronizedTextType.Trivia), // desc does not match - SynchronizedLyricsFrame.fromInfo("fux", "bar", SynchronizedTextType.Trivia), // lang goes not match - SynchronizedLyricsFrame.fromInfo("fux", "bux", SynchronizedTextType.Trivia), // type does not match - SynchronizedLyricsFrame.fromInfo("fux", "bux", SynchronizedTextType.Chord) // Is match - ]; + const frame = SynchronizedLyricsFrame.fromInfo("fux", "bux", SynchronizedTextType.Chord); // Act - const output = SynchronizedLyricsFrame.find(frames, "fux", SynchronizedTextType.Chord, "bux"); + const output = frame.clone(); // Assert - assert.isOk(output); - assert.strictEqual(output, frames[3]); + assertFrame(output, + frame.description, + frame.format, + frame.language, + frame.text, + frame.textEncoding, + frame.textType + ); } @test - public findPreferred_falsyFrames() { - // Act / Assert - assert.throws(() => { - SynchronizedLyricsFrame.findPreferred(undefined, "fux", "bux", SynchronizedTextType.Chord); - }); - assert.throws(() => { - SynchronizedLyricsFrame.findPreferred(null, "fux", "bux", SynchronizedTextType.Chord); - }); + public filterFrames_falsyFrames() { + // Act/Assert + Testers.testTruthy((v: SynchronizedLyricsFrame[]) => { SynchronizedLyricsFrame.filterFrames(v); }); } @test - public findPreferred_noFrames() { - // Act - const output = SynchronizedLyricsFrame.findPreferred([], "fux", "bux", SynchronizedTextType.Chord); - - // Assert - assert.isUndefined(output); - } - - @test - public findPreferred_perfectMatch() { + public filterFrames_noFrames() { // Arrange - const frames = [ - SynchronizedLyricsFrame.fromInfo("foo", "bar", SynchronizedTextType.Trivia), // desc does not match - SynchronizedLyricsFrame.fromInfo("fux", "bar", SynchronizedTextType.Trivia), // lang goes not match - SynchronizedLyricsFrame.fromInfo("fux", "bux", SynchronizedTextType.Trivia), // type does not match - SynchronizedLyricsFrame.fromInfo("fux", "bux", SynchronizedTextType.Chord) // perfect match - ]; + const frames: Frame[] = []; // Act - const output = SynchronizedLyricsFrame.findPreferred(frames, "fux", "bux", SynchronizedTextType.Chord); + const output = SynchronizedLyricsFrame.filterFrames(frames); // Assert - assert.isOk(output); - assert.strictEqual(output, frames[3]); + assert.isArray(output); + assert.isEmpty(output); } @test - public findPreferred_descLangMatch() { + public filterFrames_noMatch() { // Arrange - const frames = [ - SynchronizedLyricsFrame.fromInfo("foo", "bar", SynchronizedTextType.Trivia), // desc does not match - SynchronizedLyricsFrame.fromInfo("fux", "bar", SynchronizedTextType.Trivia), // lang goes not match - SynchronizedLyricsFrame.fromInfo("fux", "bux", SynchronizedTextType.Trivia), // type does not match - ]; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(234)); + const frames = [frame1, frame2]; // Act - const output = SynchronizedLyricsFrame.findPreferred(frames, "fux", "bux", SynchronizedTextType.Chord); + const result = SynchronizedLyricsFrame.filterFrames(frames); // Assert - assert.isOk(output); - assert.strictEqual(output, frames[2]); + assert.isArray(result); + assert.isEmpty(result); } @test - public findPreferred_langMatch() { + public filterFrames_singleMatch() { // Arrange - const frames = [ - SynchronizedLyricsFrame.fromInfo("foo", "bar", SynchronizedTextType.Trivia), // nothing matches - SynchronizedLyricsFrame.fromInfo("foo", "bux", SynchronizedTextType.Trivia), // lang matches - ]; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = SynchronizedLyricsFrame.fromInfo("foo", "bar", SynchronizedTextType.Other); + const frames = [frame1, frame2]; // Act - const output = SynchronizedLyricsFrame.findPreferred(frames, "fux", "bux", SynchronizedTextType.Chord); + const result = SynchronizedLyricsFrame.filterFrames(frames); // Assert - assert.isOk(output); - assert.strictEqual(output, frames[1]); + assert.isArray(result); + assert.deepEqual(result, [frame2]); } @test - public findPreferred_descMatch() { + public filterFrames_multipleMatches() { // Arrange - const frames = [ - SynchronizedLyricsFrame.fromInfo("foo", "bar", SynchronizedTextType.Trivia), // nothing matches - SynchronizedLyricsFrame.fromInfo("fux", "bar", SynchronizedTextType.Trivia), // desc matches - ]; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = SynchronizedLyricsFrame.fromInfo("foo", "bar", SynchronizedTextType.Other); + const frame3 = SynchronizedLyricsFrame.fromInfo("foo", "bar", SynchronizedTextType.Other); - // Act - const output = SynchronizedLyricsFrame.findPreferred(frames, "fux", "bux", SynchronizedTextType.Chord); - - // Assert - assert.isOk(output); - assert.strictEqual(output, frames[1]); - } - - @test - public findPreferred_typeMatch() { - // Arrange - const frames = [ - SynchronizedLyricsFrame.fromInfo("foo", "bar", SynchronizedTextType.Trivia), // nothing matches - SynchronizedLyricsFrame.fromInfo("foo", "bar", SynchronizedTextType.Chord), // type matches - ]; - - // Act - const output = SynchronizedLyricsFrame.findPreferred(frames, "fux", "bux", SynchronizedTextType.Chord); - - // Assert - assert.isOk(output); - assert.strictEqual(output, frames[1]); - } - - @test - public findPreferred_nothingMatches() { - // Arrange - const frames = [ - SynchronizedLyricsFrame.fromInfo("foo", "bar", SynchronizedTextType.Trivia), // nothing matches - SynchronizedLyricsFrame.fromInfo("foo", "bar", SynchronizedTextType.Trivia), // nothing matches - ]; + const frames = [frame1, frame2, frame3]; // Act - const output = SynchronizedLyricsFrame.findPreferred(frames, "fux", "bux", SynchronizedTextType.Chord); + const result = SynchronizedLyricsFrame.filterFrames(frames); // Assert - assert.isOk(output); - assert.strictEqual(output, frames[0]); + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); } @test - public clone() { + public filterFrames_allMatches() { // Arrange - const frame = SynchronizedLyricsFrame.fromInfo("fux", "bux", SynchronizedTextType.Chord); + const frame1 = SynchronizedLyricsFrame.fromInfo("foo", "bar", SynchronizedTextType.Other); + const frame2 = SynchronizedLyricsFrame.fromInfo("foo", "bar", SynchronizedTextType.Other); + const frames = [frame1, frame2]; // Act - const output = frame.clone(); + const result = SynchronizedLyricsFrame.filterFrames(frames); // Assert - assert.isOk(output); - assert.notStrictEqual(output, frame); - assert.strictEqual(output.frameClassType, FrameClassType.SynchronizedLyricsFrame); - assert.strictEqual(frame.frameId, FrameIdentifiers.SYLT); - - assert.strictEqual(output.description, frame.description); - assert.strictEqual(output.format, frame.format); - assert.strictEqual(output.language, frame.language); - assert.strictEqual(output.textEncoding, frame.textEncoding); - assert.strictEqual(output.textType, frame.textType); - - assert.isArray(output.text); - assert.deepStrictEqual(output.text, frame.text); + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); } @params(2, "v2") diff --git a/test-unit/id3v2/termsOfUseFrameTests.ts b/test-unit/id3v2/termsOfUseFrameTests.ts index 5c5fa8b..b27493b 100644 --- a/test-unit/id3v2/termsOfUseFrameTests.ts +++ b/test-unit/id3v2/termsOfUseFrameTests.ts @@ -1,16 +1,27 @@ import {params, suite, test} from "@testdeck/mocha"; import {assert} from "chai"; +import Frame from "../../src/id3v2/frames/frame"; import FrameConstructorTests from "./frameConstructorTests"; import Id3v2Settings from "../../src/id3v2/id3v2Settings"; import PropertyTests from "../utilities/propertyTests"; import TermsOfUseFrame from "../../src/id3v2/frames/termsOfUseFrame"; +import UnknownFrame from "../../src/id3v2/frames/unknownFrame"; import {ByteVector, StringType} from "../../src/byteVector"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Testers} from "../utilities/testers"; +const assertFrame = (frame: TermsOfUseFrame, language: string, text: string, textEncoding: StringType) => { + assert.isOk(frame); + assert.instanceOf(frame, TermsOfUseFrame); + assert.strictEqual(frame.frameId, FrameIdentifiers.USER); + + assert.strictEqual(frame.language, language); + assert.strictEqual(frame.text, text); + assert.strictEqual(frame.textEncoding, textEncoding); +} + @suite class Id3v2_TermsOfUseFrame_ConstructorTests extends FrameConstructorTests { public get fromFieldBytes(): (h: Id3v2FrameHeader, d: ByteVector, v: number) => Frame { return TermsOfUseFrame.fromFieldBytes; @@ -22,7 +33,7 @@ import {Testers} from "../utilities/testers"; const output = TermsOfUseFrame.fromFields("fux"); // Assert - Id3v2_TermsOfUseFrame_ConstructorTests.assertFrame(output, "fux", "", Id3v2Settings.defaultEncoding); + assertFrame(output, "fux", "", Id3v2Settings.defaultEncoding); } @test @@ -31,7 +42,7 @@ import {Testers} from "../utilities/testers"; const output = TermsOfUseFrame.fromFields("fux", StringType.UTF16BE); // Assert - Id3v2_TermsOfUseFrame_ConstructorTests.assertFrame(output, "fux", "", StringType.UTF16BE); + assertFrame(output, "fux", "", StringType.UTF16BE); } @params(2, "v2") @@ -61,7 +72,7 @@ import {Testers} from "../utilities/testers"; const frame = TermsOfUseFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_TermsOfUseFrame_ConstructorTests.assertFrame(frame, "eng", "", StringType.Latin1); + assertFrame(frame, "eng", "", StringType.Latin1); } @params(2, "v2") @@ -80,7 +91,7 @@ import {Testers} from "../utilities/testers"; const frame = TermsOfUseFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_TermsOfUseFrame_ConstructorTests.assertFrame(frame, "eng", "foobarbaz", StringType.Latin1); + assertFrame(frame, "eng", "foobarbaz", StringType.Latin1); } @params(StringType.Latin1, "single_byte") @@ -98,17 +109,7 @@ import {Testers} from "../utilities/testers"; const frame = TermsOfUseFrame.fromFieldBytes(header, fieldBytes, 4); // Assert - Id3v2_TermsOfUseFrame_ConstructorTests.assertFrame(frame, "eng", "foobarbaz", encoding); - } - - private static assertFrame(frame: TermsOfUseFrame, language: string, text: string, textEncoding: StringType) { - assert.isOk(frame); - assert.strictEqual(frame.frameClassType, FrameClassType.TermsOfUseFrame); - assert.strictEqual(frame.frameId, FrameIdentifiers.USER); - - assert.strictEqual(frame.language, language); - assert.strictEqual(frame.text, text); - assert.strictEqual(frame.textEncoding, textEncoding); + assertFrame(frame, "eng", "foobarbaz", encoding); } } @@ -153,97 +154,84 @@ import {Testers} from "../utilities/testers"; @suite class Id3v2_TermsOfUseFrame_MethodTests { @test - public find_falsyFrames() { + public filterFrames_falsyFrames() { // Act/Assert - assert.throws(() => { TermsOfUseFrame.find(undefined); }); - } - - @test - public find_noFrames() { - // Act - const output = TermsOfUseFrame.find([]); - - // Assert - assert.isUndefined(output); + Testers.testTruthy((v: TermsOfUseFrame[]) => { TermsOfUseFrame.filterFrames(v); }); } @test - public find_matchWithFrames_returnsFirst() { + public filterFrames_noFrames() { // Arrange - const frames = [ - TermsOfUseFrame.fromFields("eng"), - TermsOfUseFrame.fromFields("jpn") - ]; + const frames: Frame[] = []; // Act - const output = TermsOfUseFrame.find(frames); + const output = TermsOfUseFrame.filterFrames(frames); // Assert - assert.isOk(output); - assert.strictEqual(output, frames[0]); + assert.isArray(output); + assert.isEmpty(output); } @test - public find_matchWithFramesWithLanguage() { + public filterFrames_noMatch() { // Arrange - const frames = [ - TermsOfUseFrame.fromFields("eng"), - TermsOfUseFrame.fromFields("jpn") - ]; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(234)); + const frames = [frame1, frame2]; // Act - const output = TermsOfUseFrame.find(frames, "jpn"); + const result = TermsOfUseFrame.filterFrames(frames); // Assert - assert.isOk(output); - assert.strictEqual(output, frames[1]); + assert.isArray(result); + assert.isEmpty(result); } @test - public findPreferred_falsyFrames() { - // Act/Assert - assert.throws(() => TermsOfUseFrame.findPreferred(undefined, "eng")); - } + public filterFrames_singleMatch() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = TermsOfUseFrame.fromFields("foo"); + const frames = [frame1, frame2]; - @test - public findPreferred_noFrames() { // Act - const output = TermsOfUseFrame.findPreferred([], "eng"); + const result = TermsOfUseFrame.filterFrames(frames); // Assert - assert.isUndefined(output); + assert.isArray(result); + assert.deepEqual(result, [frame2]); } @test - public findPreferred_nonExactMatch() { + public filterFrames_multipleMatches() { // Arrange - const frames = [ - TermsOfUseFrame.fromFields("eng"), - TermsOfUseFrame.fromFields("jpn") - ]; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = TermsOfUseFrame.fromFields("foo"); + const frame3 = TermsOfUseFrame.fromFields("bar"); + + const frames = [frame1, frame2, frame3]; // Act - const output = TermsOfUseFrame.findPreferred(frames, "foo"); + const result = TermsOfUseFrame.filterFrames(frames); // Assert - assert.isOk(output); - assert.strictEqual(output, frames[0]); + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); } @test - public findPreferred_exactMatch() { + public filterFrames_allMatches() { // Arrange - const frames = [ - TermsOfUseFrame.fromFields("eng"), - TermsOfUseFrame.fromFields("jpn") - ]; + const frame1 = TermsOfUseFrame.fromFields("foo"); + const frame2 = TermsOfUseFrame.fromFields("bar"); + const frames = [frame1, frame2]; // Act - const output = TermsOfUseFrame.findPreferred(frames, "jpn"); + const result = TermsOfUseFrame.filterFrames(frames); // Assert - assert.isOk(output); - assert.strictEqual(output, frames[1]); + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); } @test @@ -256,13 +244,7 @@ import {Testers} from "../utilities/testers"; const output = frame.clone(); // Assert - assert.isOk(output); - assert.strictEqual(output.frameClassType, frame.frameClassType); - assert.strictEqual(output.frameId, frame.frameId); - - assert.strictEqual(output.language, frame.language); - assert.strictEqual(output.text, frame.text); - assert.strictEqual(output.textEncoding, frame.textEncoding); + assertFrame(output, frame.language, frame.text, frame.textEncoding); } @test diff --git a/test-unit/id3v2/textInformationFrameTests.ts b/test-unit/id3v2/textInformationFrameTests.ts index 4722450..915f171 100644 --- a/test-unit/id3v2/textInformationFrameTests.ts +++ b/test-unit/id3v2/textInformationFrameTests.ts @@ -1,16 +1,27 @@ import {params, suite, test} from "@testdeck/mocha"; import {assert} from "chai"; +import Frame from "../../src/id3v2/frames/frame"; import FrameConstructorTests from "./frameConstructorTests"; import Id3v2Settings from "../../src/id3v2/id3v2Settings"; import PropertyTests from "../utilities/propertyTests"; import TextInformationFrame from "../../src/id3v2/frames/textInformationFrame"; +import UnknownFrame from "../../src/id3v2/frames/unknownFrame"; import {ByteVector, StringType} from "../../src/byteVector"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifier, FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Testers} from "../utilities/testers"; +const assertFrame = (frame: TextInformationFrame, frameId: FrameIdentifier, text: string[], encoding: StringType) => { + assert.isOk(frame); + assert.instanceOf(frame, TextInformationFrame); + assert.strictEqual(frame.frameId, frameId); + + assert.isOk(frame.text); + assert.deepStrictEqual(frame.text, text); + assert.strictEqual(frame.textEncoding, encoding); +} + const getTestFrame = (): TextInformationFrame => { const frame = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOP, StringType.Latin1); frame.text = ["foo", "bar"]; @@ -35,14 +46,7 @@ const getTestFrame = (): TextInformationFrame => { const frame = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOP); // Assert - assert.isOk(frame); - assert.strictEqual(frame.frameClassType, FrameClassType.TextInformationFrame); - assert.strictEqual(frame.frameId, FrameIdentifiers.TCOP); - - assert.isOk(frame.text); - assert.isArray(frame.text); - assert.isEmpty(frame.text); - assert.strictEqual(frame.textEncoding, Id3v2Settings.defaultEncoding); + assertFrame(frame, FrameIdentifiers.TCOP, [], Id3v2Settings.defaultEncoding); } @test @@ -51,7 +55,7 @@ const getTestFrame = (): TextInformationFrame => { const frame = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOP, StringType.Latin1); // Assert - Id3v2_TextInformationFrame_ConstructorTests.assertFrame(frame, FrameIdentifiers.TCOP, []); + assertFrame(frame, FrameIdentifiers.TCOP, [], StringType.Latin1); } @params(2, "v2") @@ -78,10 +82,7 @@ const getTestFrame = (): TextInformationFrame => { const frame = TextInformationFrame.fromFieldBytes(header, fieldBytes, version); // Assert - assert.isOk(frame); - assert.strictEqual(frame.frameId, FrameIdentifiers.TCOP); - assert.deepEqual(frame.text, []); - assert.strictEqual(frame.textEncoding, StringType.UTF16BE); + assertFrame(frame, FrameIdentifiers.TCOP, [], StringType.UTF16BE); } @params(2, "v2") @@ -99,10 +100,7 @@ const getTestFrame = (): TextInformationFrame => { const frame = TextInformationFrame.fromFieldBytes(header, fieldBytes, version); // Assert - assert.isOk(frame); - assert.strictEqual(frame.frameId, FrameIdentifiers.TCOP); - assert.deepEqual(frame.text, []); - assert.strictEqual(frame.textEncoding, StringType.UTF16BE); + assertFrame(frame, FrameIdentifiers.TCOP, [], StringType.UTF16BE); } @params(2, "v2") @@ -119,7 +117,7 @@ const getTestFrame = (): TextInformationFrame => { const frame = TextInformationFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_TextInformationFrame_ConstructorTests.assertFrame(frame, FrameIdentifiers.TALB, ["fux/bux"]); + assertFrame(frame, FrameIdentifiers.TALB, ["fux/bux"], StringType.Latin1); } @params(2, "v2") @@ -136,7 +134,7 @@ const getTestFrame = (): TextInformationFrame => { const frame = TextInformationFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_TextInformationFrame_ConstructorTests.assertFrame(frame, FrameIdentifiers.TCOM, ["fux", "bux"]); + assertFrame(frame, FrameIdentifiers.TCOM, ["fux", "bux"], StringType.Latin1); } @params(2, "v2") @@ -155,7 +153,7 @@ const getTestFrame = (): TextInformationFrame => { const frame = TextInformationFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_TextInformationFrame_ConstructorTests.assertFrame(frame, FrameIdentifiers.TCOM, ["foo"]); + assertFrame(frame, FrameIdentifiers.TCOM, ["foo"], StringType.Latin1); } @params(StringType.Latin1, "single_byte") @@ -174,179 +172,205 @@ const getTestFrame = (): TextInformationFrame => { const frame = TextInformationFrame.fromFieldBytes(header, fieldBytes, 4); // Assert - Id3v2_TextInformationFrame_ConstructorTests.assertFrame(frame,FrameIdentifiers.TCOP, ["fux", "bux"],encoding); - } - - private static assertFrame( - frame: TextInformationFrame, - frameId: FrameIdentifier, - text: string[], - encoding: StringType = StringType.Latin1 - ): void { - assert.isOk(frame); - assert.strictEqual(frame.frameClassType, FrameClassType.TextInformationFrame); - assert.strictEqual(frame.frameId, frameId); - - assert.isOk(frame.text); - assert.deepStrictEqual(frame.text, text); - assert.strictEqual(frame.textEncoding, encoding); + assertFrame(frame,FrameIdentifiers.TCOP, ["fux", "bux"], encoding); } } @suite class Id3v2_TextInformationFrame_PropertyTests { - @test - public getText() { + @params(undefined, "undefined") + @params(null, "null") + @params([], "empty_array") + @params(["bar"], "truthy") + public text_values(value: string[]) { // Arrange - const frame = getTestFrame(); + const frame = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOP); // Act - const text = frame.text; - text.push("new item"); + frame.text = value; - // Assert - new item not added to frame - assert.notEqual(frame.text, text); - assert.strictEqual(2, frame.text.length); + // Assert + assert.deepStrictEqual(frame.text, value ?? []); } @test - public setText() { + public encoding() { // Arrange const frame = getTestFrame(); + const get = () => frame.textEncoding; + const set = (v: StringType) => { frame.textEncoding = v; }; // Act / Assert - PropertyTests.propertyRoundTrip((v) => { frame.text = v; }, () => frame.text, ["bux", "fux"]); + PropertyTests.propertyRoundTrip(set, get, StringType.UTF16BE); } +} - @params(undefined, "undefined") - @params(null, "null") - @params([], "empty_array") - @params(["bar"], "truthy") - public setText_values(value: string[]) { +@suite class Id3v2_TextInformationFrame_MethodTests { + @test + public clone_returnsCopy() { // Arrange - const frame = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOP); + const frame = getTestFrame(); // Act - frame.text = value; + const output = frame.clone(); // Assert - assert.deepStrictEqual(frame.text, value ?? []); + assertFrame(output, frame.frameId, frame.text, frame.textEncoding); } @test - public setEncoding_notRead() { + public filterFrames_falsyFrames() { + // Act/Assert + Testers.testTruthy((v: TextInformationFrame[]) => { TextInformationFrame.filterFrames(v); }); + } + + @test + public filterFrames_noIdentifier_noFrames() { // Arrange - const frame = getTestFrame(); + const frames: Frame[] = []; - // Act / Assert - PropertyTests.propertyRoundTrip( - (v) => { frame.textEncoding = v; }, - () => frame.textEncoding, - StringType.UTF16BE - ); + // Act + const output = TextInformationFrame.filterFrames(frames); + + // Assert + assert.isArray(output); + assert.isEmpty(output); } @test - public setEncoding_read() { + public filterFrames_noIdentifier_noMatch() { // Arrange - const frame = getTestFrame(); - const _ = frame.text; // Force a read + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(234)); + const frames = [frame1, frame2]; - // Act / Assert - PropertyTests.propertyRoundTrip( - (v) => { frame.textEncoding = v; }, - () => frame.textEncoding, - StringType.UTF16BE - ); + // Act + const result = TextInformationFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.isEmpty(result); } -} -@suite class Id3v2_TextInformationFrame_MethodTests { @test - public clone_returnsCopy() { + public filterFrames_noIdentifier_singleMatch() { // Arrange - const frame = getTestFrame(); + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOP); + const frames = [frame1, frame2]; // Act - const output = frame.clone(); + const result = TextInformationFrame.filterFrames(frames); // Assert - assert.ok(output); - assert.strictEqual(output.frameClassType, FrameClassType.TextInformationFrame); - assert.strictEqual(frame.frameId, FrameIdentifiers.TCOP); - - assert.deepStrictEqual(frame.text, output.text); - assert.strictEqual(frame.textEncoding, output.textEncoding); + assert.isArray(result); + assert.deepEqual(result, [frame2]); } @test - public find_falsyFrames() { + public filterFrames_noIdentifier_multipleMatches() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOP); + const frame3 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOP); + + const frames = [frame1, frame2, frame3]; + // Act - Testers.testTruthy((v: TextInformationFrame[]) => { - TextInformationFrame.findTextInformationFrame(v, FrameIdentifiers.TCOP); - }); + const result = TextInformationFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); } @test - public find_invalidIdentity() { + public filterFrames_noIdentifier_allMatches() { + // Arrange + const frame1 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOP); + const frame2 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOP); + const frames = [frame1, frame2]; + // Act - Testers.testTruthy((v: FrameIdentifier) => { TextInformationFrame.findTextInformationFrame([], v); }); + const result = TextInformationFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); } @test - public find_emptyFrames_returnsUndefined() { + public filterFrames_withIdentifier_noFrames() { // Arrange - const frames: TextInformationFrame[] = []; + const frames: Frame[] = []; // Act - const output = TextInformationFrame.findTextInformationFrame(frames, FrameIdentifiers.TCOM); + const output = TextInformationFrame.filterFrames(frames); // Assert - assert.isUndefined(output); + assert.isArray(output); + assert.isEmpty(output); } @test - public find_frameExists() { + public filterFrames_withIdentifier_noMatch() { // Arrange - const frames = [ - TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOP), - TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOM) - ]; + const frame1 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOM); + const frame2 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOM); + const frames = [frame1, frame2]; // Act - const output = TextInformationFrame.findTextInformationFrame(frames, FrameIdentifiers.TCOM); + const result = TextInformationFrame.filterFrames(frames, FrameIdentifiers.TCOP); // Assert - assert.isOk(output); - assert.equal(output, frames[1]); + assert.isArray(result); + assert.isEmpty(result); } @test - public find_frameExists_returnsFirstMatch() { + public filterFrames_withIdentifier_singleMatch() { // Arrange const frame1 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOM); - const frame2 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOM); + const frame2 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOP); const frames = [frame1, frame2]; // Act - const output = TextInformationFrame.findTextInformationFrame(frames, FrameIdentifiers.TCOM); + const result = TextInformationFrame.filterFrames(frames, FrameIdentifiers.TCOP); // Assert - assert.strictEqual(output, frame1); + assert.isArray(result); + assert.deepEqual(result, [frame2]); } @test - public find_frameDoesNotExist() { + public filterFrames_withIdentifier_multipleMatches() { // Arrange - const frames = [ - TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOP), - TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOM) - ]; + const frame1 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOM); + const frame2 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOP); + const frame3 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOP); + + const frames = [frame1, frame2, frame3]; + + // Act + const result = TextInformationFrame.filterFrames(frames, FrameIdentifiers.TCOP); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); + } + + @test + public filterFrames_withIdentifier_allMatches() { + // Arrange + const frame1 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOP); + const frame2 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOP); + const frames = [frame1, frame2]; // Act - const output = TextInformationFrame.findTextInformationFrame(frames, FrameIdentifiers.TALB); + const result = TextInformationFrame.filterFrames(frames, FrameIdentifiers.TCOP); // Assert - assert.isUndefined(output); + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); } @params(2, "v2") diff --git a/test-unit/id3v2/uniqueFileIdentifierFrameTests.ts b/test-unit/id3v2/uniqueFileIdentifierFrameTests.ts index 5c885ea..88f6c0e 100644 --- a/test-unit/id3v2/uniqueFileIdentifierFrameTests.ts +++ b/test-unit/id3v2/uniqueFileIdentifierFrameTests.ts @@ -1,11 +1,12 @@ import {params, suite, test} from "@testdeck/mocha"; import {assert} from "chai"; +import Frame from "../../src/id3v2/frames/frame"; import FrameConstructorTests from "./frameConstructorTests"; import PropertyTests from "../utilities/propertyTests"; import UniqueFileIdentifierFrame from "../../src/id3v2/frames/uniqueFileIdentifierFrame"; +import UnknownFrame from "../../src/id3v2/frames/unknownFrame"; import {ByteVector, StringType} from "../../src/byteVector"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Testers} from "../utilities/testers"; @@ -14,6 +15,19 @@ import {Testers} from "../utilities/testers"; const testIdentifier = ByteVector.fromString("foobarbaz", StringType.UTF8); const testOwner = "https://github.com/benrr101/node-taglib-sharp"; +const assertFrame = (frame: UniqueFileIdentifierFrame, o: string, i: ByteVector) => { + assert.isOk(frame); + assert.instanceOf(frame, UniqueFileIdentifierFrame); + assert.strictEqual(frame.frameId, FrameIdentifiers.UFID); + + assert.strictEqual(frame.owner, o); + if (i !== undefined) { + Testers.bvEqual(frame.identifier, i); + } else { + assert.isUndefined(frame.identifier); + } +} + @suite class Id3v2_UniqueFileIdentifierFrame_ConstructorTests extends FrameConstructorTests { public get fromFieldBytes(): (h: Id3v2FrameHeader, d: ByteVector, v: number) => Frame { return UniqueFileIdentifierFrame.fromFieldBytes; @@ -47,7 +61,7 @@ const testOwner = "https://github.com/benrr101/node-taglib-sharp"; const frame = UniqueFileIdentifierFrame.fromData(owner, identifier); // Assert - Id3v2_UniqueFileIdentifierFrame_ConstructorTests.assertFrame(frame, owner, identifier); + assertFrame(frame, owner, identifier); } @params(2, "v2") @@ -91,7 +105,7 @@ const testOwner = "https://github.com/benrr101/node-taglib-sharp"; // Assert const expectedData = ByteVector.concatenate(testIdentifier, 0x00, testIdentifier); - Id3v2_UniqueFileIdentifierFrame_ConstructorTests.assertFrame(frame, testOwner, expectedData); + assertFrame(frame, testOwner, expectedData); } @params(2, "v2") @@ -111,21 +125,7 @@ const testOwner = "https://github.com/benrr101/node-taglib-sharp"; const frame = UniqueFileIdentifierFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_UniqueFileIdentifierFrame_ConstructorTests.assertFrame(frame, testOwner, testIdentifier); - } - - private static assertFrame(frame: UniqueFileIdentifierFrame, o: string, i: ByteVector) { - assert.isOk(frame); - assert.strictEqual(frame.frameClassType, FrameClassType.UniqueFileIdentifierFrame); - assert.strictEqual(frame.frameId, FrameIdentifiers.UFID); - - assert.strictEqual(frame.owner, o); - - if (i !== undefined) { - Testers.bvEqual(frame.identifier, i); - } else { - assert.isUndefined(frame.identifier); - } + assertFrame(frame, testOwner, testIdentifier); } } @@ -152,70 +152,110 @@ const testOwner = "https://github.com/benrr101/node-taglib-sharp"; @suite class Id3v2_UniqueFileIdentifierFrame_MethodTests { @test - public find_falsyFrames_throws() { - // Act/Assert - Testers.testTruthy((v: UniqueFileIdentifierFrame[]) => { UniqueFileIdentifierFrame.find(v, "fux"); }); + public clone_noIdentifier() { + // Arrange + const frame = UniqueFileIdentifierFrame.fromData("fux", undefined); + + // Act + const clone = frame.clone(); + + // Assert + assertFrame(clone, frame.owner, frame.identifier); } @test - public find_validParams_returnsFirstMatch() { + public clone_withIdentifier() { // Arrange - const frame1 = UniqueFileIdentifierFrame.fromData("fux", ByteVector.fromSize(1)); - const frame2 = UniqueFileIdentifierFrame.fromData("fux", ByteVector.fromSize(1)); + const frame = UniqueFileIdentifierFrame.fromData("fux", ByteVector.fromString("qux", StringType.UTF8)); // Act - const result = UniqueFileIdentifierFrame.find([frame1, frame2], "fux"); + const clone = frame.clone(); // Assert - assert.strictEqual(result, frame1); + assertFrame(clone, frame.owner, frame.identifier); + } + + @test + public filterFrames_falsyFrames() { + // Act/Assert + Testers.testTruthy((v: UniqueFileIdentifierFrame[]) => { UniqueFileIdentifierFrame.filterFrames(v); }); } @test - public find_noMatches_returnsUndefined() { + public filterFrames_noFrames() { // Arrange - const frame1 = UniqueFileIdentifierFrame.fromData("fux", ByteVector.fromSize(1)); + const frames: Frame[] = []; // Act - const result = UniqueFileIdentifierFrame.find([frame1], "qux"); + const output = UniqueFileIdentifierFrame.filterFrames(frames); // Assert - assert.isUndefined(result); + assert.isArray(output); + assert.isEmpty(output); } @test - public clone_noIdentifier() { + public filterFrames_noMatch() { // Arrange - const frame = UniqueFileIdentifierFrame.fromData("fux", undefined); + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(234)); + const frames = [frame1, frame2]; // Act - const clone = frame.clone(); + const result = UniqueFileIdentifierFrame.filterFrames(frames); // Assert - assert.isOk(clone); - assert.strictEqual(clone.frameClassType, FrameClassType.UniqueFileIdentifierFrame); - assert.strictEqual(clone.frameId, FrameIdentifiers.UFID); - - assert.strictEqual(clone.identifier, frame.identifier); - assert.strictEqual(clone.owner, frame.owner); + assert.isArray(result); + assert.isEmpty(result); } @test - public clone_withIdentifier() { + public filterFrames_singleMatch() { // Arrange - const frame = UniqueFileIdentifierFrame.fromData("fux", ByteVector.fromString("qux", StringType.UTF8)); + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UniqueFileIdentifierFrame.fromData("foo", ByteVector.empty()); + const frames = [frame1, frame2]; // Act - const clone = frame.clone(); + const result = UniqueFileIdentifierFrame.filterFrames(frames); // Assert - assert.isOk(clone); - assert.strictEqual(clone.frameClassType, FrameClassType.UniqueFileIdentifierFrame); - assert.strictEqual(clone.frameId, FrameIdentifiers.UFID); + assert.isArray(result); + assert.deepEqual(result, [frame2]); + } + + @test + public filterFrames_multipleMatches() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UniqueFileIdentifierFrame.fromData("foo", ByteVector.empty()); + const frame3 = UniqueFileIdentifierFrame.fromData("foo", ByteVector.empty()); - Testers.bvEqual(clone.identifier, frame.identifier); - assert.strictEqual(clone.owner, frame.owner); + const frames = [frame1, frame2, frame3]; + + // Act + const result = UniqueFileIdentifierFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); } + @test + public filterFrames_allMatches() { + // Arrange + const frame1 = UniqueFileIdentifierFrame.fromData("foo", ByteVector.empty()); + const frame2 = UniqueFileIdentifierFrame.fromData("foo", ByteVector.empty()); + const frames = [frame1, frame2]; + + // Act + const result = UniqueFileIdentifierFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); + } + @params(2, "v2") @params(3, "v3") @params(4, "v4") diff --git a/test-unit/id3v2/unknownFrameTests.ts b/test-unit/id3v2/unknownFrameTests.ts index 2b1b7b6..7ecb504 100644 --- a/test-unit/id3v2/unknownFrameTests.ts +++ b/test-unit/id3v2/unknownFrameTests.ts @@ -1,14 +1,27 @@ import {params, suite, test} from "@testdeck/mocha"; import {assert} from "chai"; +import CommentsFrame from "../../src/id3v2/frames/commentsFrame"; +import Frame from "../../src/id3v2/frames/frame"; import FrameConstructorTests from "./frameConstructorTests"; import UnknownFrame from "../../src/id3v2/frames/unknownFrame"; import {ByteVector, StringType} from "../../src/byteVector"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifier, FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Testers} from "../utilities/testers"; +const assertFrame = (frame: UnknownFrame, fi: FrameIdentifier, d: ByteVector) => { + assert.ok(frame); + assert.instanceOf(frame, UnknownFrame); + assert.strictEqual(frame.frameId, fi); + + if (d !== undefined) { + Testers.bvEqual(frame.data, d); + } else { + assert.isUndefined(frame.data); + } +} + @suite class Id3v2_UnknownFrame_ConstructorTests extends FrameConstructorTests { public get fromFieldBytes(): (h: Id3v2FrameHeader, d: ByteVector, v: number) => Frame { return UnknownFrame.fromFieldBytes; @@ -30,7 +43,7 @@ import {Testers} from "../utilities/testers"; const frame = UnknownFrame.fromData(frameType, value); // Assert - Id3v2_UnknownFrame_ConstructorTests.assertFrame(frame, FrameIdentifiers.WXXX, undefined); + assertFrame(frame, FrameIdentifiers.WXXX, undefined); } @test @@ -43,7 +56,7 @@ import {Testers} from "../utilities/testers"; const frame = UnknownFrame.fromData(frameType, data); // Assert - Id3v2_UnknownFrame_ConstructorTests.assertFrame(frame, FrameIdentifiers.WXXX, data); + assertFrame(frame, FrameIdentifiers.WXXX, data); } @params(2, "v2") @@ -58,23 +71,7 @@ import {Testers} from "../utilities/testers"; const frame = UnknownFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_UnknownFrame_ConstructorTests.assertFrame( - frame, - FrameIdentifiers.WXXX, - ByteVector.fromString("foo bar baz", StringType.UTF8) - ); - } - - private static assertFrame(frame: UnknownFrame, fi: FrameIdentifier, d: ByteVector) { - assert.ok(frame); - assert.strictEqual(frame.frameClassType, FrameClassType.UnknownFrame); - assert.strictEqual(frame.frameId, fi); - - if (d !== undefined) { - Testers.bvEqual(frame.data, d); - } else { - assert.isUndefined(frame.data); - } + assertFrame(frame, FrameIdentifiers.WXXX, ByteVector.fromString("foo bar baz", StringType.UTF8)); } } @@ -92,12 +89,90 @@ import {Testers} from "../utilities/testers"; const result = frame.clone(); // Assert - assert.ok(result); - assert.strictEqual(result.frameClassType, FrameClassType.UnknownFrame); - assert.strictEqual(result.frameId, FrameIdentifiers.WXXX); - Testers.bvEqual(result.data, fieldBytes); + assertFrame(result, result.frameId, result.data); + } + + @test + public filterFrames_falsyFrames() { + // Act/Assert + Testers.testTruthy((v: UnknownFrame[]) => { UnknownFrame.filterFrames(v); }); + } + + @test + public filterFrames_noFrames() { + // Arrange + const frames: Frame[] = []; + + // Act + const output = UnknownFrame.filterFrames(frames); + + // Assert + assert.isArray(output); + assert.isEmpty(output); + } + + @test + public filterFrames_noMatch() { + // Arrange + const frame1 = CommentsFrame.fromDescription("foo"); + const frame2 = CommentsFrame.fromDescription("foo"); + const frames = [frame1, frame2]; + + // Act + const result = UnknownFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.isEmpty(result); + } + + @test + public filterFrames_singleMatch() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = CommentsFrame.fromDescription("foo"); + const frames = [frame1, frame2]; + + // Act + const result = UnknownFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame1]); + } + + @test + public filterFrames_multipleMatches() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame3 = CommentsFrame.fromDescription("foo"); + + const frames = [frame1, frame2, frame3]; + + // Act + const result = UnknownFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); } + @test + public filterFrames_allMatches() { + // Arrange + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frames = [frame1, frame2]; + + // Act + const result = UnknownFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); + } + @params(2, "v2") @params(3, "v3") @params(4, "v4") diff --git a/test-unit/id3v2/unsynchronizedLyricsFrameTests.ts b/test-unit/id3v2/unsynchronizedLyricsFrameTests.ts index 9b31ba7..d239c07 100644 --- a/test-unit/id3v2/unsynchronizedLyricsFrameTests.ts +++ b/test-unit/id3v2/unsynchronizedLyricsFrameTests.ts @@ -1,11 +1,12 @@ import {params, suite, test} from "@testdeck/mocha"; import {assert} from "chai"; +import Frame from "../../src/id3v2/frames/frame"; import FrameConstructorTests from "./frameConstructorTests"; import PropertyTests from "../utilities/propertyTests"; +import UnknownFrame from "../../src/id3v2/frames/unknownFrame"; import UnsynchronizedLyricsFrame from "../../src/id3v2/frames/unsynchronizedLyricsFrame"; import {ByteVector, StringType} from "../../src/byteVector"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Testers} from "../utilities/testers"; @@ -22,6 +23,17 @@ const getTestUnsynchronizedLyricsFrame = (): UnsynchronizedLyricsFrame => { return UnsynchronizedLyricsFrame.fromFieldBytes(header, fieldBytes, 4); }; +const assertFrame = (frame: UnsynchronizedLyricsFrame, d: string, l: string, t: string, te: StringType) => { + assert.isOk(frame); + assert.instanceOf(frame, UnsynchronizedLyricsFrame); + assert.strictEqual(frame.frameId, FrameIdentifiers.USLT); + + assert.strictEqual(frame.description, d); + assert.strictEqual(frame.language, l); + assert.strictEqual(frame.text, t); + assert.strictEqual(frame.textEncoding, te); +} + @suite class Id3v2_UnsynchronizedLyricsFrame_ConstructorTests extends FrameConstructorTests { public get fromFieldBytes(): (h: Id3v2FrameHeader, d: ByteVector, v: number) => Frame { return UnsynchronizedLyricsFrame.fromFieldBytes; @@ -39,7 +51,7 @@ const getTestUnsynchronizedLyricsFrame = (): UnsynchronizedLyricsFrame => { const frame = UnsynchronizedLyricsFrame.fromData(description, language, encoding); // Assert - Id3v2_UnsynchronizedLyricsFrame_ConstructorTests.assertFrame(frame, description, language, "", encoding); + assertFrame(frame, description, language, "", encoding); } @params(2, "v2") @@ -69,7 +81,7 @@ const getTestUnsynchronizedLyricsFrame = (): UnsynchronizedLyricsFrame => { const frame = UnsynchronizedLyricsFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_UnsynchronizedLyricsFrame_ConstructorTests.assertFrame(frame, "", "eng", "", StringType.Latin1); + assertFrame(frame, "", "eng", "", StringType.Latin1); } @params(2, "v2") @@ -88,7 +100,7 @@ const getTestUnsynchronizedLyricsFrame = (): UnsynchronizedLyricsFrame => { const frame = UnsynchronizedLyricsFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_UnsynchronizedLyricsFrame_ConstructorTests.assertFrame(frame, "", "eng", "foobarbaz", StringType.Latin1); + assertFrame(frame, "", "eng", "foobarbaz", StringType.Latin1); } @params(2, "v2") @@ -108,7 +120,7 @@ const getTestUnsynchronizedLyricsFrame = (): UnsynchronizedLyricsFrame => { const frame = UnsynchronizedLyricsFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_UnsynchronizedLyricsFrame_ConstructorTests.assertFrame(frame, "", "eng", "foobarbaz", StringType.Latin1); + assertFrame(frame, "", "eng", "foobarbaz", StringType.Latin1); } @params(2, "v2") @@ -129,7 +141,7 @@ const getTestUnsynchronizedLyricsFrame = (): UnsynchronizedLyricsFrame => { const frame = UnsynchronizedLyricsFrame.fromFieldBytes(header, fieldBytes, version); // Assert - Id3v2_UnsynchronizedLyricsFrame_ConstructorTests.assertFrame(frame, "foo", "eng", "bar", StringType.Latin1); + assertFrame(frame, "foo", "eng", "bar", StringType.Latin1); } @params(StringType.Latin1, "single_byte_encoding") @@ -149,18 +161,7 @@ const getTestUnsynchronizedLyricsFrame = (): UnsynchronizedLyricsFrame => { const frame = UnsynchronizedLyricsFrame.fromFieldBytes(header, fieldBytes, 4); // Assert - Id3v2_UnsynchronizedLyricsFrame_ConstructorTests.assertFrame(frame, "foo", "eng", "bar", encoding); - } - - private static assertFrame(frame: UnsynchronizedLyricsFrame, d: string, l: string, t: string, te: StringType) { - assert.isOk(frame); - assert.strictEqual(frame.frameClassType, FrameClassType.UnsynchronizedLyricsFrame); - assert.strictEqual(frame.frameId, FrameIdentifiers.USLT); - - assert.strictEqual(frame.description, d); - assert.strictEqual(frame.language, l); - assert.strictEqual(frame.text, t); - assert.strictEqual(frame.textEncoding, te); + assertFrame(frame, "foo", "eng", "bar", encoding); } } @@ -222,295 +223,98 @@ const getTestUnsynchronizedLyricsFrame = (): UnsynchronizedLyricsFrame => { @suite class Id3v2_UnsynchronizedLyricsFrame_MethodTests { @test - public find_falsyFrames_throws() { - // Act/Assert - Testers.testTruthy((v: UnsynchronizedLyricsFrame[]) => { UnsynchronizedLyricsFrame.find(v, "foo", "bar"); }); - } - - @test - public find_emptyFrames_returnsUndefined() { - // Arrange - const frames: UnsynchronizedLyricsFrame[] = []; - - // Act - const result = UnsynchronizedLyricsFrame.find(frames, "foo", "bar"); - - // Assert - assert.isUndefined(result); - } - - @test - public find_noMatchByDescription_returnsUndefined() { - // Arrange - Description is foo - const frames = [getTestUnsynchronizedLyricsFrame(), getTestUnsynchronizedLyricsFrame()]; - - // Act - const result = UnsynchronizedLyricsFrame.find(frames, "fux", "eng"); - - // Assert - assert.isUndefined(result); - } - - @test - public find_noMatchByLanguage_returnsUndefined() { - // Arrange - Language is eng - const frames = [getTestUnsynchronizedLyricsFrame(), getTestUnsynchronizedLyricsFrame()]; - - // Act - const result = UnsynchronizedLyricsFrame.find(frames, "foo", "fux"); - - // Assert - assert.isUndefined(result); - } - - @test - public find_matchWithLanguage_returnsFirstMatch() { - // Arrange - const frames = [ - getTestUnsynchronizedLyricsFrame(), - getTestUnsynchronizedLyricsFrame(), - getTestUnsynchronizedLyricsFrame(), - getTestUnsynchronizedLyricsFrame() - ]; - frames[2].language = "jpn"; - frames[3].description = "fux"; - - // Act - const result = UnsynchronizedLyricsFrame.find(frames, "foo", "eng"); - - // Assert - assert.ok(result); - assert.strictEqual(result, frames[0]); - } - - @test - public find_matchWithoutLanguage_returnsFirstMatch() { + public clone() { // Arrange - const frames = [ - getTestUnsynchronizedLyricsFrame(), - getTestUnsynchronizedLyricsFrame(), - getTestUnsynchronizedLyricsFrame(), - getTestUnsynchronizedLyricsFrame() - ]; - frames[2].language = "jpn"; - frames[3].description = "fux"; + const frame = getTestUnsynchronizedLyricsFrame(); // Act - const result = UnsynchronizedLyricsFrame.find(frames, "foo", undefined); + const result = frame.clone(); // Assert - assert.ok(result); - assert.strictEqual(result, frames[0]); + assertFrame(result, frame.description, frame.language, frame.text, frame.textEncoding); } @test - public findAll_falsyFrames_throws() { + public filterFrames_falsyFrames() { // Act/Assert - assert.throws(() => { UnsynchronizedLyricsFrame.findAll(null, "foo", "bar"); }); - assert.throws(() => { UnsynchronizedLyricsFrame.findAll(undefined, "foo", "bar"); }); + Testers.testTruthy((v: UnsynchronizedLyricsFrame[]) => { UnsynchronizedLyricsFrame.filterFrames(v); }); } @test - public findAll_emptyFrames_returnsUndefined() { + public filterFrames_noFrames() { // Arrange - const frames: UnsynchronizedLyricsFrame[] = []; - - // Act - const result = UnsynchronizedLyricsFrame.findAll(frames, "foo", "bar"); - - // Assert - assert.isOk(result); - assert.isArray(result); - assert.isEmpty(result); - } - - @test - public findAll_noMatchByDescription_returnsUndefined() { - // Arrange - Description is foo - const frames = [getTestUnsynchronizedLyricsFrame(), getTestUnsynchronizedLyricsFrame()]; - - // Act - const result = UnsynchronizedLyricsFrame.findAll(frames, "fux", "eng"); - - // Assert - assert.isOk(result); - assert.isArray(result); - assert.isEmpty(result); - } - - @test - public findAll_noMatchByLanguage_returnsUndefined() { - // Arrange - Language is eng - const frames = [getTestUnsynchronizedLyricsFrame(), getTestUnsynchronizedLyricsFrame()]; + const frames: Frame[] = []; // Act - const result = UnsynchronizedLyricsFrame.findAll(frames, "foo", "fux"); + const output = UnsynchronizedLyricsFrame.filterFrames(frames); // Assert - assert.isOk(result); - assert.isArray(result); - assert.isEmpty(result); + assert.isArray(output); + assert.isEmpty(output); } @test - public findAll_matchWithLanguage_returnsFirstMatch() { + public filterFrames_noMatch() { // Arrange - const frames = [ - getTestUnsynchronizedLyricsFrame(), - getTestUnsynchronizedLyricsFrame(), - getTestUnsynchronizedLyricsFrame(), - getTestUnsynchronizedLyricsFrame() - ]; - frames[2].language = "jpn"; - frames[3].description = "fux"; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(234)); + const frames = [frame1, frame2]; // Act - const result = UnsynchronizedLyricsFrame.findAll(frames, "foo", "eng"); + const result = UnsynchronizedLyricsFrame.filterFrames(frames); // Assert - assert.ok(result); assert.isArray(result); - assert.sameMembers(result, frames.slice(0, 2)); + assert.isEmpty(result); } @test - public findAll_matchWithoutLanguage_returnsFirstMatch() { + public filterFrames_singleMatch() { // Arrange - const frames = [ - getTestUnsynchronizedLyricsFrame(), - getTestUnsynchronizedLyricsFrame(), - getTestUnsynchronizedLyricsFrame(), - getTestUnsynchronizedLyricsFrame() - ]; - frames[2].language = "jpn"; - frames[3].description = "fux"; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnsynchronizedLyricsFrame.fromData("foo"); + const frames = [frame1, frame2]; // Act - const result = UnsynchronizedLyricsFrame.findAll(frames, "foo", undefined); + const result = UnsynchronizedLyricsFrame.filterFrames(frames); // Assert - assert.ok(result); assert.isArray(result); - assert.sameMembers(result, frames.slice(0, 3)); - } - - @test - public findPreferred_falsyFrames_throws() { - // Act/Assert - Testers.testTruthy((v: UnsynchronizedLyricsFrame[]) => { - UnsynchronizedLyricsFrame.findPreferred(v, "foo", "bar"); - }); - } - - @test - public findPreferred_noFrames_returnsUndefined() { - // Arrange - const frames: UnsynchronizedLyricsFrame[] = []; - - // Act - const result = UnsynchronizedLyricsFrame.findPreferred(frames, "fux", "qux"); - - // Assert - assert.isUndefined(result); - } - - @test - public findPreferred_perfectMatch_() { - // Arrange - const frames: UnsynchronizedLyricsFrame[] = [ - getTestUnsynchronizedLyricsFrame(), // Wrong description, wrong language - getTestUnsynchronizedLyricsFrame(), // Correct description, wrong language - getTestUnsynchronizedLyricsFrame(), // Wrong description, correct language - getTestUnsynchronizedLyricsFrame() // Correct description, correct language - ]; - frames[0].language = "jpn"; - frames[0].description = "fux"; - frames[1].language = "jpn"; - frames[2].description = "fux"; - - // Act - const result = UnsynchronizedLyricsFrame.findPreferred(frames, "foo", "eng"); - - // Assert - assert.ok(result); - assert.strictEqual(result, frames[3]); + assert.deepEqual(result, [frame2]); } @test - public findPreferred_matchByLanguage() { + public filterFrames_multipleMatches() { // Arrange - const frames: UnsynchronizedLyricsFrame[] = [ - getTestUnsynchronizedLyricsFrame(), // Wrong description, wrong language - getTestUnsynchronizedLyricsFrame(), // Correct description, wrong language - getTestUnsynchronizedLyricsFrame(), // Wrong description, correct language - ]; - frames[0].language = "jpn"; - frames[0].description = "fux"; - frames[1].language = "jpn"; - frames[2].description = "fux"; - - // Act - const result = UnsynchronizedLyricsFrame.findPreferred(frames, "foo", "eng"); + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnsynchronizedLyricsFrame.fromData("foo"); + const frame3 = UnsynchronizedLyricsFrame.fromData("bar"); - // Assert - assert.ok(result); - assert.strictEqual(result, frames[2]); - } - - @test - public findPreferred_matchByDescription() { - // Arrange - const frames: UnsynchronizedLyricsFrame[] = [ - getTestUnsynchronizedLyricsFrame(), // Wrong description, wrong language - getTestUnsynchronizedLyricsFrame(), // Correct description, wrong language - ]; - frames[0].language = "jpn"; - frames[0].description = "fux"; - frames[1].language = "jpn"; + const frames = [frame1, frame2, frame3]; // Act - const result = UnsynchronizedLyricsFrame.findPreferred(frames, "foo", "eng"); + const result = UnsynchronizedLyricsFrame.filterFrames(frames); // Assert - assert.ok(result); - assert.strictEqual(result, frames[1]); - } - - @test - public findPreferred_matchFirst() { - // Arrange - const frames: UnsynchronizedLyricsFrame[] = [ - getTestUnsynchronizedLyricsFrame(), // Wrong description, wrong language - getTestUnsynchronizedLyricsFrame(), // Wrong description, wrong language - ]; - - // Act - const result = UnsynchronizedLyricsFrame.findPreferred(frames, "fux", "jpn"); - - // Assert - assert.ok(result); - assert.strictEqual(result, frames[0]); + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); } @test - public clone() { + public filterFrames_allMatches() { // Arrange - const frame = getTestUnsynchronizedLyricsFrame(); + const frame1 = UnsynchronizedLyricsFrame.fromData("foo"); + const frame2 = UnsynchronizedLyricsFrame.fromData("bar"); + const frames = [frame1, frame2]; // Act - const result = frame.clone(); + const result = UnsynchronizedLyricsFrame.filterFrames(frames); // Assert - assert.ok(result); - assert.strictEqual(result.frameClassType, FrameClassType.UnsynchronizedLyricsFrame); - assert.strictEqual(result.frameId, FrameIdentifiers.USLT); - - assert.strictEqual(result.description, frame.description); - assert.strictEqual(result.language, frame.language); - assert.strictEqual(result.text, frame.text); - assert.strictEqual(result.textEncoding, frame.textEncoding); + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); } - + @params([2, StringType.Latin1], "v2_single_byte") @params([2, StringType.UTF16BE], "v2_multibyte") @params([3, StringType.Latin1], "v3_single_byte") diff --git a/test-unit/id3v2/urlLinkFrameTests.ts b/test-unit/id3v2/urlLinkFrameTests.ts index a15fa1b..ba5ba1f 100644 --- a/test-unit/id3v2/urlLinkFrameTests.ts +++ b/test-unit/id3v2/urlLinkFrameTests.ts @@ -1,14 +1,22 @@ import {params, suite, test} from "@testdeck/mocha"; import {assert} from "chai"; +import Frame from "../../src/id3v2/frames/frame"; import FrameConstructorTests from "./frameConstructorTests"; +import UnknownFrame from "../../src/id3v2/frames/unknownFrame"; import UrlLinkFrame from "../../src/id3v2/frames/urlLinkFrame"; import {ByteVector, StringType} from "../../src/byteVector"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifier, FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Testers} from "../utilities/testers"; +const assertFrame = (frame: UrlLinkFrame, identifier: FrameIdentifier, text: string|undefined) => { + assert.ok(frame); + assert.instanceOf(frame, UrlLinkFrame); + assert.strictEqual(frame.frameId, identifier); + assert.strictEqual(frame.text, text); +} + @suite class Id3v2_UrlLinkFrame_ConstructorTests extends FrameConstructorTests { public get fromFieldBytes(): (h: Id3v2FrameHeader, d: ByteVector, v: number) => Frame { return UrlLinkFrame.fromFieldBytes; @@ -17,19 +25,16 @@ import {Testers} from "../utilities/testers"; @test public fromIdentity_falsyIdentity() { // Act/Assert - Testers.testTruthy((v: FrameIdentifier) => { UrlLinkFrame.fromIdentity(v); }); + Testers.testTruthy((v: FrameIdentifier) => { UrlLinkFrame.fromIdentifier(v); }); } @test public fromIdentity_validIdentity() { // Act - const output = UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM); + const output = UrlLinkFrame.fromIdentifier(FrameIdentifiers.WCOM); // Assert - assert.ok(output); - assert.strictEqual(output.frameClassType, FrameClassType.UrlLinkFrame); - assert.strictEqual(output.frameId, FrameIdentifiers.WCOM); - assert.strictEqual(output.text, undefined); + assertFrame(output, FrameIdentifiers.WCOM, undefined); } @params(2, "v2") @@ -44,10 +49,7 @@ import {Testers} from "../utilities/testers"; const output = UrlLinkFrame.fromFieldBytes(header, fieldBytes, version); // Assert - assert.ok(output); - assert.strictEqual(output.frameClassType, FrameClassType.UrlLinkFrame); - assert.strictEqual(output.frameId, FrameIdentifiers.WCOM); - assert.strictEqual(output.text, "foo"); + assertFrame(output, FrameIdentifiers.WCOM, "foo"); } @params(2, "v2") @@ -65,7 +67,7 @@ import {Testers} from "../utilities/testers"; const output = UrlLinkFrame.fromFieldBytes(header, fieldBytes, version); // Assert - this.assertFrame(output, "foo"); + assertFrame(output, FrameIdentifiers.WCOM, "foo"); } @params(2, "v2") @@ -85,14 +87,7 @@ import {Testers} from "../utilities/testers"; const output = UrlLinkFrame.fromFieldBytes(header, fieldBytes, version); // Assert - this.assertFrame(output, "foo"); - } - - private assertFrame(frame: UrlLinkFrame, text: string) { - assert.ok(frame); - assert.strictEqual(frame.frameClassType, FrameClassType.UrlLinkFrame); - assert.strictEqual(frame.frameId, FrameIdentifiers.WCOM); - assert.strictEqual(frame.text, text); + assertFrame(output, FrameIdentifiers.WCOM, "foo"); } } @@ -103,7 +98,7 @@ import {Testers} from "../utilities/testers"; @params("bar", "truthy") public setText_falsyValues(value: string) { // Arrange - const frame = UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM); + const frame = UrlLinkFrame.fromIdentifier(FrameIdentifiers.WCOM); // Act frame.text = value; @@ -115,80 +110,178 @@ import {Testers} from "../utilities/testers"; @suite class Id3v2_UrlLinkFrame_MethodTests { @test - public findUrlLinkFrame_falsyFrames_throws(): void { + public clone_returnsCloneUsingRawData() { + // Arrange + const frame = UrlLinkFrame.fromIdentifier(FrameIdentifiers.WCOM); + frame.text = "foo"; + + // Act + const result = frame.clone(); + + // Assert + assertFrame(result, frame.frameId, frame.text); + } + + @test + public filterFrames_falsyFrames() { // Act/Assert - Testers.testTruthy((v: UrlLinkFrame[]) => { UrlLinkFrame.findUrlLinkFrame(v, FrameIdentifiers.WCOM); }); + Testers.testTruthy((v: UrlLinkFrame[]) => { UrlLinkFrame.filterFrames(v); }); } @test - public findUrlLinkFrame_falsyIdentity_throws(): void { + public filterFrames_noIdentifier_noFrames() { // Arrange - const frames = [UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM)]; + const frames: Frame[] = []; - // Act/Assert - Testers.testTruthy((v: FrameIdentifier) => { UrlLinkFrame.findUrlLinkFrame(frames, v); }); + // Act + const output = UrlLinkFrame.filterFrames(frames); + + // Assert + assert.isArray(output); + assert.isEmpty(output); } @test - public findUrlLinkFrame_emptyFrames_returnsUndefined() { + public filterFrames_noIdentifier_noMatch() { // Arrange - const frames: UrlLinkFrame[] = []; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(234)); + const frames = [frame1, frame2]; // Act - const result = UrlLinkFrame.findUrlLinkFrame(frames, FrameIdentifiers.WCOM); + const result = UrlLinkFrame.filterFrames(frames); // Assert - assert.isUndefined(result); + assert.isArray(result); + assert.isEmpty(result); } @test - public findUrlLinkFrame_noMatch_returnsUndefined() { + public filterFrames_noIdentifier_singleMatch() { // Arrange - const frames = [ - UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM), - UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOP) - ]; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.TCOP); + const frames = [frame1, frame2]; // Act - const result = UrlLinkFrame.findUrlLinkFrame(frames, FrameIdentifiers.WPAY); + const result = UrlLinkFrame.filterFrames(frames); // Assert - assert.isUndefined(result); + assert.isArray(result); + assert.deepEqual(result, [frame2]); } @test - public findUrlLinkFrame_match_returnsFirstMatch() { + public filterFrames_noIdentifier_multipleMatches() { // Arrange - const frame1 = UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM); - const frame2 = UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM); + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.TCOP); + const frame3 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.TCOP); + + const frames = [frame1, frame2, frame3]; + + // Act + const result = UrlLinkFrame.filterFrames(frames); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); + } + + @test + public filterFrames_noIdentifier_allMatches() { + // Arrange + const frame1 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.TCOP); + const frame2 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.TCOP); const frames = [frame1, frame2]; // Act - const result = UrlLinkFrame.findUrlLinkFrame(frames, FrameIdentifiers.WCOM); + const result = UrlLinkFrame.filterFrames(frames); // Assert - assert.equal(result, frame1); + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); } @test - public clone_returnsCloneUsingRawData() { + public filterFrames_withIdentifier_noFrames() { // Arrange - const frame = UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM); - frame.text = "foo"; + const frames: Frame[] = []; // Act - const result = frame.clone(); + const output = UrlLinkFrame.filterFrames(frames); // Assert - assert.isOk(result); - assert.strictEqual(result.frameId, frame.frameId); - assert.strictEqual(result.text, frame.text); + assert.isArray(output); + assert.isEmpty(output); + } + + @test + public filterFrames_withIdentifier_noMatch() { + // Arrange + const frame1 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.TCOM); + const frame2 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.TCOM); + const frames = [frame1, frame2]; + + // Act + const result = UrlLinkFrame.filterFrames(frames, FrameIdentifiers.TCOP); + + // Assert + assert.isArray(result); + assert.isEmpty(result); + } + + @test + public filterFrames_withIdentifier_singleMatch() { + // Arrange + const frame1 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.TCOM); + const frame2 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.TCOP); + const frames = [frame1, frame2]; + + // Act + const result = UrlLinkFrame.filterFrames(frames, FrameIdentifiers.TCOP); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame2]); + } + + @test + public filterFrames_withIdentifier_multipleMatches() { + // Arrange + const frame1 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.TCOM); + const frame2 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.TCOP); + const frame3 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.TCOP); + + const frames = [frame1, frame2, frame3]; + + // Act + const result = UrlLinkFrame.filterFrames(frames, FrameIdentifiers.TCOP); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); + } + + @test + public filterFrames_withIdentifier_allMatches() { + // Arrange + const frame1 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.TCOP); + const frame2 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.TCOP); + const frames = [frame1, frame2]; + + // Act + const result = UrlLinkFrame.filterFrames(frames, FrameIdentifiers.TCOP); + + // Assert + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); } @test public render_withoutText() { // Arrange - const frame = UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM); + const frame = UrlLinkFrame.fromIdentifier(FrameIdentifiers.WCOM); // Act const result = frame.render(4); @@ -201,7 +294,7 @@ import {Testers} from "../utilities/testers"; @test public render_withText() { // Arrange - const frame = UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM); + const frame = UrlLinkFrame.fromIdentifier(FrameIdentifiers.WCOM); frame.text = "foo"; // Act @@ -223,7 +316,7 @@ import {Testers} from "../utilities/testers"; @params("foo", "foo") public toString_returnsText(text: string) { // Arrange - const frame = UrlLinkFrame.fromIdentity(FrameIdentifiers.WCOM); + const frame = UrlLinkFrame.fromIdentifier(FrameIdentifiers.WCOM); frame.text = text; // Act diff --git a/test-unit/id3v2/userTextInformationFrameTests.ts b/test-unit/id3v2/userTextInformationFrameTests.ts index 80e3abc..fb601bf 100644 --- a/test-unit/id3v2/userTextInformationFrameTests.ts +++ b/test-unit/id3v2/userTextInformationFrameTests.ts @@ -1,15 +1,32 @@ import {params, suite, test} from "@testdeck/mocha"; import {assert} from "chai"; +import Frame from "../../src/id3v2/frames/frame"; import FrameConstructorTests from "./frameConstructorTests"; import Id3v2Settings from "../../src/id3v2/id3v2Settings"; +import UnknownFrame from "../../src/id3v2/frames/unknownFrame"; import UserTextInformationFrame from "../../src/id3v2/frames/userTextInformationFrame"; import {ByteVector, StringType} from "../../src/byteVector"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Testers} from "../utilities/testers"; +const assertFrame = ( + frame: UserTextInformationFrame, + description: string, + text: string[], + encoding: StringType +) => { + assert.isOk(frame); + assert.instanceOf(frame, UserTextInformationFrame); + assert.strictEqual(frame.frameId, FrameIdentifiers.TXXX); + + assert.isOk(frame.text); + assert.strictEqual(frame.description, description); + assert.deepStrictEqual(frame.text, text); + assert.strictEqual(frame.textEncoding, encoding); +} + const getTestFrame = (): UserTextInformationFrame => { const frame = UserTextInformationFrame.fromDescription("foo", StringType.Latin1); frame.text = ["bar"]; @@ -30,7 +47,7 @@ const getTestFrame = (): UserTextInformationFrame => { const frame = UserTextInformationFrame.fromDescription(description); // Assert - Id3v2_UserInformationFrame_ConstructorTests.assertFrame(frame, description, [], Id3v2Settings.defaultEncoding); + assertFrame(frame, description, [], Id3v2Settings.defaultEncoding); } @params(undefined, "undefined") @@ -42,7 +59,7 @@ const getTestFrame = (): UserTextInformationFrame => { const frame = UserTextInformationFrame.fromDescription(description, StringType.UTF16BE); // Assert - Id3v2_UserInformationFrame_ConstructorTests.assertFrame(frame, description, [], StringType.UTF16BE); + assertFrame(frame, description, [], StringType.UTF16BE); } @params(2, "v2") @@ -69,11 +86,7 @@ const getTestFrame = (): UserTextInformationFrame => { const frame = UserTextInformationFrame.fromFieldBytes(header, fieldBytes, version); // Assert - assert.isOk(frame); - assert.strictEqual(frame.description, ""); - assert.strictEqual(frame.frameId, FrameIdentifiers.TXXX); - assert.deepEqual(frame.text, []); - assert.strictEqual(frame.textEncoding, StringType.UTF16LE); + assertFrame(frame, "", [], StringType.UTF16LE); } @params(2, "v2") @@ -91,13 +104,7 @@ const getTestFrame = (): UserTextInformationFrame => { const output = UserTextInformationFrame.fromFieldBytes(header, fieldBytes, version); // Assert - assert.isOk(output); - assert.equal(output.frameClassType, FrameClassType.UserTextInformationFrame); - assert.strictEqual(output.frameId, FrameIdentifiers.TXXX); - - assert.strictEqual(output.description, ""); - assert.deepEqual(output.text, ["foo"]) - assert.strictEqual(output.textEncoding, StringType.UTF16BE); + assertFrame(output, "", ["foo"], StringType.UTF16BE); } @params(2, "v2") @@ -119,13 +126,7 @@ const getTestFrame = (): UserTextInformationFrame => { const output = UserTextInformationFrame.fromFieldBytes(header, fieldBytes, version); // Assert - assert.isOk(output); - assert.equal(output.frameClassType, FrameClassType.UserTextInformationFrame); - assert.strictEqual(output.frameId, FrameIdentifiers.TXXX); - - assert.strictEqual(output.description, "foo"); - assert.deepEqual(output.text, ["bar", "baz"]) - assert.strictEqual(output.textEncoding, StringType.UTF16BE); + assertFrame(output, "foo", ["bar", "baz"], StringType.UTF16BE); } @params(2, "v2") @@ -145,7 +146,7 @@ const getTestFrame = (): UserTextInformationFrame => { const frame = UserTextInformationFrame.fromFieldBytes(header, fieldData, version); // Assert - Id3v2_UserInformationFrame_ConstructorTests.assertFrame(frame, "foo", ["bar"], StringType.Latin1); + assertFrame(frame, "foo", ["bar"], StringType.Latin1); } @params(StringType.Latin1, "latin1") @@ -164,29 +165,7 @@ const getTestFrame = (): UserTextInformationFrame => { const output = UserTextInformationFrame.fromFieldBytes(header, fieldBytes, 4); // Assert - assert.isOk(output); - assert.equal(output.frameClassType, FrameClassType.UserTextInformationFrame); - assert.strictEqual(output.frameId, FrameIdentifiers.TXXX); - - assert.strictEqual(output.description, "foo"); - assert.deepEqual(output.text, ["bar"]) - assert.strictEqual(output.textEncoding, encoding); - } - - private static assertFrame( - frame: UserTextInformationFrame, - description: string, - text: string[], - encoding: StringType - ) { - assert.isOk(frame); - assert.strictEqual(frame.frameClassType, FrameClassType.UserTextInformationFrame); - assert.strictEqual(frame.frameId, FrameIdentifiers.TXXX); - - assert.isOk(frame.text); - assert.strictEqual(frame.description, description); - assert.deepStrictEqual(frame.text, text); - assert.strictEqual(frame.textEncoding, encoding); + assertFrame(output, "foo", ["bar"], encoding); } } @@ -279,108 +258,84 @@ const getTestFrame = (): UserTextInformationFrame => { @suite class Id3v2_UserTextInformationFrame_MethodTests { @test - public findUserTextInformationFrame_falsyFrames() { - // Act/Assert - Testers.testTruthy((v: UserTextInformationFrame[]) => { - UserTextInformationFrame.findUserTextInformationFrame(v, "foo"); - }); - } - - @test - public findUserTextInformationFrame_falsyDescription() { - // Arrange - const frames = [UserTextInformationFrame.fromDescription("foo")]; - + public filterFrames_falsyFrames() { // Act/Assert - Testers.testTruthy((v: string) => { UserTextInformationFrame.findUserTextInformationFrame(frames, v); }); + Testers.testTruthy((v: UserTextInformationFrame[]) => { UserTextInformationFrame.filterFrames(v); }); } @test - public findUserTextInformationFrame_emptyFrames_returnsUndefined() { + public filterFrames_noFrames() { // Arrange - const frames: UserTextInformationFrame[] = []; + const frames: Frame[] = []; // Act - const output = UserTextInformationFrame.findUserTextInformationFrame(frames, "foo"); + const output = UserTextInformationFrame.filterFrames(frames); // Assert - assert.isUndefined(output); + assert.isArray(output); + assert.isEmpty(output); } @test - public findUserTextInformationFrame_frameWithCaseSensitiveDescriptionDoesNotExist() { + public filterFrames_noMatch() { // Arrange - const frames = [ - UserTextInformationFrame.fromDescription("fUX"), - UserTextInformationFrame.fromDescription("bUX") - ]; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(234)); + const frames = [frame1, frame2]; // Act - const output = UserTextInformationFrame.findUserTextInformationFrame(frames, "fux"); + const result = UserTextInformationFrame.filterFrames(frames); // Assert - assert.isUndefined(output); + assert.isArray(result); + assert.isEmpty(result); } @test - public findUserTextInformationFrame_frameWithCaseInsensitiveDescriptionDoesNotExist() { + public filterFrames_singleMatch() { // Arrange - const frames = [ - UserTextInformationFrame.fromDescription("fUX"), - UserTextInformationFrame.fromDescription("bUX") - ]; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UserTextInformationFrame.fromDescription("foo"); + const frames = [frame1, frame2]; // Act - const output = UserTextInformationFrame.findUserTextInformationFrame(frames, "qux", false); + const result = UserTextInformationFrame.filterFrames(frames); // Assert - assert.isUndefined(output); + assert.isArray(result); + assert.deepEqual(result, [frame2]); } @test - public findUserTextInformationFrame_frameWithCaseSensitiveDescriptionExists() { + public filterFrames_multipleMatches() { // Arrange - const frames = [ - UserTextInformationFrame.fromDescription("Fux"), - UserTextInformationFrame.fromDescription("bUX") - ]; - - // Act - const output = UserTextInformationFrame.findUserTextInformationFrame(frames, "Fux"); - - // Assert - assert.isOk(output); - assert.strictEqual(output, frames[0]); - } + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UserTextInformationFrame.fromDescription("foo"); + const frame3 = UserTextInformationFrame.fromDescription("bar"); - @test - public findUserTextInformationFrame_frameWithCaseInsensitiveDescriptionExists() { - // Arrange - const frames = [ - UserTextInformationFrame.fromDescription("fUX"), - UserTextInformationFrame.fromDescription("bUX") - ]; + const frames = [frame1, frame2, frame3]; // Act - const output = UserTextInformationFrame.findUserTextInformationFrame(frames, "fux", false); + const result = UserTextInformationFrame.filterFrames(frames); // Assert - assert.isOk(output); - assert.strictEqual(output, frames[0]); + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); } @test - public findUserTextInformationFrame_match_returnsFirstMatch() { + public filterFrames_allMatches() { // Arrange const frame1 = UserTextInformationFrame.fromDescription("foo"); - const frame2 = UserTextInformationFrame.fromDescription("foo"); + const frame2 = UserTextInformationFrame.fromDescription("bar"); const frames = [frame1, frame2]; // Act - const output = UserTextInformationFrame.findUserTextInformationFrame(frames, "foo"); + const result = UserTextInformationFrame.filterFrames(frames); // Assert - assert.strictEqual(output, frame1); + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); } @test @@ -392,13 +347,7 @@ const getTestFrame = (): UserTextInformationFrame => { const output = frame.clone(); // Assert - assert.ok(output); - assert.strictEqual(output.frameClassType, FrameClassType.UserTextInformationFrame); - assert.strictEqual(frame.frameId, FrameIdentifiers.TXXX); - - assert.strictEqual(frame.description, output.description); - assert.deepStrictEqual(frame.text, output.text); - assert.strictEqual(frame.textEncoding, output.textEncoding); + assertFrame(output, frame.description, frame.text, frame.textEncoding); } @test diff --git a/test-unit/id3v2/userUrlLinkFrameTests.ts b/test-unit/id3v2/userUrlLinkFrameTests.ts index 4607c04..9b077da 100644 --- a/test-unit/id3v2/userUrlLinkFrameTests.ts +++ b/test-unit/id3v2/userUrlLinkFrameTests.ts @@ -1,15 +1,26 @@ import {params, suite, test} from "@testdeck/mocha"; import {assert} from "chai"; +import Frame from "../../src/id3v2/frames/frame"; import FrameConstructorTests from "./frameConstructorTests"; import Id3v2Settings from "../../src/id3v2/id3v2Settings"; +import UnknownFrame from "../../src/id3v2/frames/unknownFrame"; import UserUrlLinkFrame from "../../src/id3v2/frames/userUrlLinkFrame"; import {ByteVector, StringType} from "../../src/byteVector"; -import {Frame, FrameClassType} from "../../src/id3v2/frames/frame"; import {Id3v2FrameFlags, Id3v2FrameHeader} from "../../src/id3v2/frames/frameHeader"; import {FrameIdentifiers} from "../../src/id3v2/frameIdentifiers"; import {Testers} from "../utilities/testers"; +const assertFrame = (frame: UserUrlLinkFrame, description: string, text: string, encoding: StringType) => { + assert.ok(frame); + assert.instanceOf(frame, UserUrlLinkFrame); + assert.strictEqual(frame.frameId, FrameIdentifiers.WXXX); + + assert.strictEqual(frame.description, description); + assert.strictEqual(frame.text, text); + assert.equal(frame.textEncoding, encoding); +} + @suite class Id3v2_UserUrlLinkFrame_ConstructorTests extends FrameConstructorTests { public get fromFieldBytes(): (h: Id3v2FrameHeader, d: ByteVector, v: number) => Frame { return UserUrlLinkFrame.fromFieldBytes; @@ -55,7 +66,7 @@ import {Testers} from "../utilities/testers"; const output = UserUrlLinkFrame.fromFieldBytes(header, fieldBytes, version); // Assert - this.assertFrame(output, "foo", "bar", StringType.Latin1); + assertFrame(output, "foo", "bar", StringType.Latin1); } @params(2, "v2") @@ -73,7 +84,7 @@ import {Testers} from "../utilities/testers"; const output = UserUrlLinkFrame.fromFieldBytes(header, fieldBytes, version); // Assert - this.assertFrame(output, "", "foo", StringType.UTF16BE); + assertFrame(output, "", "foo", StringType.UTF16BE); } @params(2, "v2") @@ -96,7 +107,7 @@ import {Testers} from "../utilities/testers"; const output = UserUrlLinkFrame.fromFieldBytes(header, fieldBytes, version); // Assert - this.assertFrame(output, "foo", "bar", StringType.UTF16BE); + assertFrame(output, "foo", "bar", StringType.UTF16BE); } @params(2, "v2") @@ -116,7 +127,7 @@ import {Testers} from "../utilities/testers"; const output = UserUrlLinkFrame.fromFieldBytes(header, fieldBytes, version); // Assert - this.assertFrame(output, "foo", "bar", StringType.Latin1); + assertFrame(output, "foo", "bar", StringType.Latin1); } @params(StringType.Latin1, "single_byte") @@ -135,17 +146,7 @@ import {Testers} from "../utilities/testers"; const output = UserUrlLinkFrame.fromFieldBytes(header, fieldBytes, 4); // Assert - this.assertFrame(output, "foo", "bar", encoding); - } - - private assertFrame(frame: UserUrlLinkFrame, description: string, text: string, encoding: StringType) { - assert.ok(frame); - assert.equal(frame.frameClassType, FrameClassType.UserUrlLinkFrame); - assert.strictEqual(frame.frameId, FrameIdentifiers.WXXX); - - assert.strictEqual(frame.description, description); - assert.strictEqual(frame.text, text); - assert.equal(frame.textEncoding, encoding); + assertFrame(output, "foo", "bar", encoding); } } @@ -197,76 +198,97 @@ import {Testers} from "../utilities/testers"; @suite class Id3v2_UserUrlLink_MethodTests { @test - public findUserUrlLinkFrame_falsyFrames_throws(): void { + public clone_returnsClone() { + // Arrange + const frame = UserUrlLinkFrame.fromFields("foo", "fux"); + frame.textEncoding = StringType.UTF16BE; + + // Act + const result = frame.clone(); + + // Assert + assertFrame(result, frame.description, frame.text, frame.textEncoding); + } + + @test + public filterFrames_falsyFrames() { // Act/Assert - Testers.testTruthy((v: UserUrlLinkFrame[]) => { UserUrlLinkFrame.findUserUrlLinkFrame(v, "foo"); }); + Testers.testTruthy((v: UserUrlLinkFrame[]) => { UserUrlLinkFrame.filterFrames(v); }); } @test - public findUserUrlLinkFrame_falsyIdentity_throws(): void { + public filterFrames_noFrames() { // Arrange - const frames = [UserUrlLinkFrame.fromFields("foo", "bar")]; + const frames: Frame[] = []; - // Act/Assert - Testers.testTruthy((v: string) => { UserUrlLinkFrame.findUserUrlLinkFrame(frames, v); }); + // Act + const output = UserUrlLinkFrame.filterFrames(frames); + + // Assert + assert.isArray(output); + assert.isEmpty(output); } @test - public findUserUrlLinkFrame_emptyFrames_returnsUndefined() { + public filterFrames_noMatch() { // Arrange - const frames: UserUrlLinkFrame[] = []; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(234)); + const frames = [frame1, frame2]; // Act - const result = UserUrlLinkFrame.findUserUrlLinkFrame(frames, "foo"); + const result = UserUrlLinkFrame.filterFrames(frames); // Assert - assert.isUndefined(result); + assert.isArray(result); + assert.isEmpty(result); } @test - public findUserUrlLinkFrame_noMatch_returnsUndefined() { + public filterFrames_singleMatch() { // Arrange - const frames = [ - UserUrlLinkFrame.fromFields("foo", "fux"), - UserUrlLinkFrame.fromFields("bar", "bux") - ]; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UserUrlLinkFrame.fromFields("foo", "bar"); + const frames = [frame1, frame2]; // Act - const result = UserUrlLinkFrame.findUserUrlLinkFrame(frames, "baz"); + const result = UserUrlLinkFrame.filterFrames(frames); // Assert - assert.isUndefined(result); + assert.isArray(result); + assert.deepEqual(result, [frame2]); } @test - public findUserUrlLinkFrame_match_returnsFirstMatch() { + public filterFrames_multipleMatches() { // Arrange - const frame1 = UserUrlLinkFrame.fromFields("foo", "bar"); - const frame2 = UserUrlLinkFrame.fromFields("foo", "bux"); - const frames = [frame1, frame2]; + const frame1 = UnknownFrame.fromData(FrameIdentifiers.RVRB, ByteVector.fromUint(123)); + const frame2 = UserUrlLinkFrame.fromFields("foo", "bar"); + const frame3 = UserUrlLinkFrame.fromFields("foo", "bar"); + + const frames = [frame1, frame2, frame3]; // Act - const result = UserUrlLinkFrame.findUserUrlLinkFrame(frames, "foo"); + const result = UserUrlLinkFrame.filterFrames(frames); // Assert - assert.equal(result, frame1); + assert.isArray(result); + assert.deepEqual(result, [frame2, frame3]); } @test - public clone_returnsClone() { + public filterFrames_allMatches() { // Arrange - const frame = UserUrlLinkFrame.fromFields("foo", "fux"); - frame.textEncoding = StringType.UTF16BE; + const frame1 = UserUrlLinkFrame.fromFields("foo", "bar"); + const frame2 = UserUrlLinkFrame.fromFields("foo", "bar"); + const frames = [frame1, frame2]; // Act - const result = frame.clone(); + const result = UserUrlLinkFrame.filterFrames(frames); // Assert - assert.isOk(result); - assert.strictEqual(result.frameId, frame.frameId); - assert.strictEqual(result.description, frame.description); - assert.strictEqual(result.text, frame.text); - assert.strictEqual(result.textEncoding, frame.textEncoding); + assert.isArray(result); + assert.deepEqual(result, [frame1, frame2]); } @test From f15cef723c10d39de60acd19c65d55f91150be07 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Wed, 1 Jul 2026 13:55:02 -0500 Subject: [PATCH 6/9] Remove remaining findPreferred methods --- src/id3v2/frames/commentsFrame.ts | 55 ------------- src/id3v2/frames/synchronizedLyricsFrame.ts | 52 ------------- src/id3v2/frames/termsOfUseFrame.ts | 23 ------ src/id3v2/frames/unsynchronizedLyricsFrame.ts | 41 ---------- src/id3v2/frames/userUrlLinkFrame.ts | 13 ---- src/id3v2/id3v2Tag.ts | 41 +++++++--- test-unit/id3v2/commentsFrameTests.ts | 78 ------------------- test-unit/id3v2/id3v2TagTests.ts | 56 +++++++++++++ 8 files changed, 86 insertions(+), 273 deletions(-) diff --git a/src/id3v2/frames/commentsFrame.ts b/src/id3v2/frames/commentsFrame.ts index a5267f4..bbb11a4 100644 --- a/src/id3v2/frames/commentsFrame.ts +++ b/src/id3v2/frames/commentsFrame.ts @@ -9,8 +9,6 @@ import {ArrayUtils, Guards} from "../../utils"; /** * Class that extends {@link Frame}, implementing support for ID3v2 Comments (COMM) frames. * A {@link CommentsFrame} should be used for storing user-readable comments on the media file. - * When reading comments from a file, {@link CommentsFrame.findPreferred} should be used as it - * gracefully falls back to comments that you, as a developer, may not be expecting. */ export default class CommentsFrame extends Frame { private _description: string; @@ -145,59 +143,6 @@ export default class CommentsFrame extends Frame { return ArrayUtils.ofType(frames, CommentsFrame); } - /** - * Gets a specified comments frame from the specified tag, trying to match the description and - * language but accepting an incomplete match. - * The method tries matching with the following order of precedence: - * * The first frame with a matching description and language - * * The first frame with a matching language - * * The first frame with a matching description - * * The first frame - * @param frames Frames to search for best matching frame - * @param description Description to match - * @param language ISO-639-2 language code to match - */ - public static findPreferred(frames: CommentsFrame[], description: string, language?: string): CommentsFrame { - Guards.truthy(frames, "frames"); - - // Original .NET comments: - // This is weird, so bear with me. The best thing we can have is something straightforward - // and in our own language. If it has a description, then it is probably used for something - // other than an actual comment. If that doesn't work, we'd still rather have something in - // our own language than something in another. After that, all we have left are things in - // other languages, so we'd rather have one with actual content, so we try to get one with - // no description first. - - const skipITunes = !description || !description.startsWith("iTun"); - - let bestValue = -1; - let bestFrame: CommentsFrame; - - for (const frame of frames) { - if (skipITunes && frame.description.startsWith("iTun")) { - continue; - } - - const sameName = frame.description === description; - const sameLang = frame.language === language; - - if (sameName && sameLang) { - return frame; - } - - const value = sameLang ? 2 : sameName ? 1 : 0; - - if (value <= bestValue) { - continue; - } - - bestValue = value; - bestFrame = frame; - } - - return bestFrame; - } - /** @inheritDoc */ public clone(): Frame { const frame = CommentsFrame.fromDescription(this._description, this._language, this._textEncoding); diff --git a/src/id3v2/frames/synchronizedLyricsFrame.ts b/src/id3v2/frames/synchronizedLyricsFrame.ts index 7689f63..8d2e5cf 100644 --- a/src/id3v2/frames/synchronizedLyricsFrame.ts +++ b/src/id3v2/frames/synchronizedLyricsFrame.ts @@ -272,58 +272,6 @@ export class SynchronizedLyricsFrame extends Frame { return ArrayUtils.ofType(frames, SynchronizedLyricsFrame); } - /** - * Gets a synchronized lyrics frame from the specified list, trying to match the description and - * language but accepting an incomplete match. - * This method tries matching with the following order of precedence: - * * The first frame with a matching description, language, and type. - * * The first frame with a matching description and language. - * * The first frame with a matching language. - * * The first frame with a matching description. - * * The first frame with a matching type. - * * The first frame. - * @param frames List of frames to search for the best match - * @param description Description to match - * @param language ISO-639-2 language code to match - * @param textType Text type to match - * @returns The matching frame or `undefined` if a match was not found - */ - public static findPreferred( - frames: SynchronizedLyricsFrame[], - description: string, - language: string, - textType: SynchronizedTextType - ): SynchronizedLyricsFrame { - Guards.truthy(frames, "frames"); - - let bestValue = -1; - let bestFrame: SynchronizedLyricsFrame; - - for (const slFrame of frames) { - let value = 0; - if (slFrame.language === language) { - value += 4; - } - if (slFrame.description === description) { - value += 2; - } - if (slFrame.textType === textType) { - value += 1; - } - if (value === 7) { - return slFrame; - } - - if (value <= bestValue) { - continue; - } - bestValue = value; - bestFrame = slFrame; - } - - return bestFrame; - } - /** @inheritDoc */ public clone(): Frame { const frame = SynchronizedLyricsFrame.fromInfo( diff --git a/src/id3v2/frames/termsOfUseFrame.ts b/src/id3v2/frames/termsOfUseFrame.ts index 71cc527..c802204 100644 --- a/src/id3v2/frames/termsOfUseFrame.ts +++ b/src/id3v2/frames/termsOfUseFrame.ts @@ -109,29 +109,6 @@ export default class TermsOfUseFrame extends Frame { return ArrayUtils.ofType(frames, TermsOfUseFrame); } - /** - * Gets a specified terms of use frame from the list of frames, trying to match the language but - * accepting one with a different language if a match was not found. - * @param frames List of frames to search - * @param language ISO-639-2 language code to match - * @returns Frame containing the matching frame or `undefined` if a match was not found - */ - public static findPreferred(frames: TermsOfUseFrame[], language: string): TermsOfUseFrame { - Guards.truthy(frames, "frames"); - - let bestFrame: TermsOfUseFrame; - for (const f of frames) { - if (f.language === language) { - return f; - } - if (!bestFrame) { - bestFrame = f; - } - } - - return bestFrame; - } - /** @inheritDoc */ public clone(): Frame { const frame = TermsOfUseFrame.fromFields(this._language, this.textEncoding); diff --git a/src/id3v2/frames/unsynchronizedLyricsFrame.ts b/src/id3v2/frames/unsynchronizedLyricsFrame.ts index d8a3836..628cce7 100644 --- a/src/id3v2/frames/unsynchronizedLyricsFrame.ts +++ b/src/id3v2/frames/unsynchronizedLyricsFrame.ts @@ -137,47 +137,6 @@ export default class UnsynchronizedLyricsFrame extends Frame { return ArrayUtils.ofType(frames, UnsynchronizedLyricsFrame); } - /** - * Gets a specified unsynchronized frame from the list of frames, trying to match the - * description and language but, failing a perfect match, accepting an incomplete match. - * The method tries matching with the following order of precedence: - * * First frame with a matching description and language - * * First frame with a matching language - * * First frame with a matching description - * * First frame - * @param frames List of frames to search - * @param description Description to match - * @param language ISO-639-2 language code to match - */ - public static findPreferred( - frames: UnsynchronizedLyricsFrame[], - description: string, - language: string - ): UnsynchronizedLyricsFrame { - Guards.truthy(frames, "frames"); - - let bestValue = -1; - let bestFrame; - for (const f of frames) { - const sameName = f.description === description; - const sameLang = f.language === language; - - if (sameName && sameLang) { - return f; - } - - const value = sameLang - ? 2 - : sameName ? 1 : 0; - if (value > bestValue) { - bestValue = value; - bestFrame = f; - } - } - - return bestFrame; - } - /** @inheritDoc */ public clone(): Frame { const frame = UnsynchronizedLyricsFrame.fromData(this._description, this._language, this.textEncoding); diff --git a/src/id3v2/frames/userUrlLinkFrame.ts b/src/id3v2/frames/userUrlLinkFrame.ts index 99dee7a..52eb94d 100644 --- a/src/id3v2/frames/userUrlLinkFrame.ts +++ b/src/id3v2/frames/userUrlLinkFrame.ts @@ -120,19 +120,6 @@ export default class UserUrlLinkFrame extends UrlLinkFrame { return ArrayUtils.ofType(frames, UserUrlLinkFrame); } - /** - * Gets a frame from a list of frames. - * @param frames List of frames to search - * @param description Description of the frame to match - * @returns Frame containing the matching user, `undefined` if a match was not found - */ - public static findUserUrlLinkFrame(frames: UserUrlLinkFrame[], description: string): UserUrlLinkFrame { - Guards.truthy(frames, "frames"); - Guards.truthy(description, "description"); - - return frames.find((f) => f.description === description); - } - /** @inheritDoc */ public clone(): UserUrlLinkFrame { const frame = UserUrlLinkFrame.fromFields(this._description, this._text); diff --git a/src/id3v2/id3v2Tag.ts b/src/id3v2/id3v2Tag.ts index 712a27f..3d173c9 100644 --- a/src/id3v2/id3v2Tag.ts +++ b/src/id3v2/id3v2Tag.ts @@ -454,18 +454,14 @@ export default class Id3v2Tag extends Tag { * @inheritDoc * @remarks Stored in the `COMM` frame */ - get comment(): string { - const frames = CommentsFrame.filterFrames(this._frameList); - const f = CommentsFrame.findPreferred(frames, "", Id3v2Tag.language); - return f ? f.toString() : undefined; + get comment(): string|undefined { + return this.getCommentFramePreferred("", Id3v2Tag.language)?.toString(); } /** * @inheritDoc * @remarks Stored in the `COMM` frame */ set comment(value: string) { - const commentFrames = CommentsFrame.filterFrames(this._frameList); - // Delete the "" comment frames that are in this language @TODO: That's not what this does if (!value) { this.removeFrames(FrameIdentifiers.COMM); @@ -473,7 +469,7 @@ export default class Id3v2Tag extends Tag { } // Create or update the preferred comments frame - let frame = CommentsFrame.findPreferred(commentFrames, "", Id3v2Tag.language); + let frame = this.getCommentFramePreferred("", Id3v2Tag.language); if (!frame) { frame = CommentsFrame.fromDescription("", Id3v2Tag.language); this.addFrame(frame); @@ -615,16 +611,23 @@ export default class Id3v2Tag extends Tag { */ get lyrics(): string { const frames = UnsynchronizedLyricsFrame.filterFrames(this._frameList); - const frame = UnsynchronizedLyricsFrame.findPreferred(frames, "", Id3v2Tag.language); - return frame ? frame.toString() : undefined; + + // Find the best match for the language + return frames.length < 2 + ? frames[0]?.toString() + : frames.map(f => { + const langMatchScore = f.language === Id3v2Tag.language ? 2 : 0; + const nameMatchScore = f.description === "" ? 1 : 0; + const score = langMatchScore + nameMatchScore; + return {score: score, frame: f}; + }).sort((a, b) => b.score - a.score)[0].frame.toString(); } /** * @inheritDoc * @remarks Stored in the `USLT` frame */ set lyrics(value: string) { - // Delete all unsynchronized lyrics frames in this language - // @TODO: Verify that deleting only this language is the correct behavior + // Delete all unsynchronized lyrics frames in this language @TODO: That's not what this does. if (!value) { this.removeFrames(FrameIdentifiers.USLT); return; @@ -1490,6 +1493,22 @@ export default class Id3v2Tag extends Tag { this.readFromStart(file, position, style); } + private getCommentFramePreferred(description: string, language: string): CommentsFrame|undefined { + const frames = CommentsFrame.filterFrames(this._frameList); + if (frames.length < 2) { + return frames[0]; + } + + // The logic here is to map each frame to a score based on how many fields match. Then + // sort with the best match at the top, and return that frame. + return frames.map(f => { + const langMatchScore = f.language === language ? 2 : 0; + const nameMatchScore = f.description === description ? 1 : 0; + const score = langMatchScore + nameMatchScore; + return {score: score, frame: f}; + }).sort((a, b) => b.score - a.score)[0].frame; + } + private getTextAsArray(ident: FrameIdentifier): string[] { if (ident === FrameIdentifiers.TCON) { const frame = GenreFrame.filterFrames(this._frameList)[0]; diff --git a/test-unit/id3v2/commentsFrameTests.ts b/test-unit/id3v2/commentsFrameTests.ts index a59f03f..620dccb 100644 --- a/test-unit/id3v2/commentsFrameTests.ts +++ b/test-unit/id3v2/commentsFrameTests.ts @@ -330,84 +330,6 @@ const verifyFrame = ( assert.deepEqual(result, [frame1, frame2]); } - @test - public findPreferred_noFrames_returnsUndefined() { - // Arrange - const frames: CommentsFrame[] = []; - - // Act - const output = CommentsFrame.findPreferred(frames, "fux", "eng"); - - // Assert - assert.isUndefined(output); - } - - @test - public findPreferred_firstFrameMatch() { - // Arrange - const frames = [ - CommentsFrame.fromDescription("fux", "eng") - ]; - - // Act - const output = CommentsFrame.findPreferred(frames, "bux", "jpn"); - - // Assert - assert.isOk(output); - assert.strictEqual(output, frames[0]); - } - - @test - public findPreferred_languageMatch() { - // Arrange - const frames = [ - CommentsFrame.fromDescription("fux", "eng"), - CommentsFrame.fromDescription("bux", "eng"), - CommentsFrame.fromDescription("fux", "jpn"), - ]; - - // Act - const output = CommentsFrame.findPreferred(frames, "bux", "jpn"); - - // Assert - assert.isOk(output); - assert.strictEqual(output, frames[2]); - } - - @test - public findPreferred_descriptionMatch() { - // Arrange - const frames = [ - CommentsFrame.fromDescription("fux", "eng"), - CommentsFrame.fromDescription("bux", "eng"), - ]; - - // Act - const output = CommentsFrame.findPreferred(frames, "bux", "jpn"); - - // Assert - assert.isOk(output); - assert.strictEqual(output, frames[1]); - } - - @test - public findPreferred_perfectMatch() { - // Arrange - const frames = [ - CommentsFrame.fromDescription("fux", "eng"), - CommentsFrame.fromDescription("fux", "jpn"), - CommentsFrame.fromDescription("bux", "eng"), - CommentsFrame.fromDescription("bux", "jpn"), - ]; - - // Act - const output = CommentsFrame.findPreferred(frames, "bux", "jpn"); - - // Assert - assert.isOk(output); - assert.strictEqual(output, frames[3]); - } - @test public clone() { // Arrange diff --git a/test-unit/id3v2/id3v2TagTests.ts b/test-unit/id3v2/id3v2TagTests.ts index 8c6ed29..a1b6321 100644 --- a/test-unit/id3v2/id3v2TagTests.ts +++ b/test-unit/id3v2/id3v2TagTests.ts @@ -1068,6 +1068,43 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: } } + @test + public lyrics_multipleFrames() { + // Arrange + const frame1 = UnsynchronizedLyricsFrame.fromData("foo", "jpn"); // 0 Score + const frame2 = UnsynchronizedLyricsFrame.fromData("", "jpn"); // 1 Score + const frame3 = UnsynchronizedLyricsFrame.fromData("foo", "eng"); // 2 Score + const frame4 = UnsynchronizedLyricsFrame.fromData("", "eng"); // 3 Score + frame4.text = "foobarbaz"; + + const tag = Id3v2Tag.fromEmpty(); + tag.frames.push(frame1, frame2, frame3, frame4); + + const initialLanguage = Id3v2Tag.language; + try { + Id3v2Tag.language = "eng"; + + // ------------------- + // Act 1 + const result1 = tag.lyrics; + + // Assert 1 + assert.strictEqual(result1, frame4.text); + + // ------------------- + // Act 2 + tag.lyrics = undefined; + const result2 = tag.lyrics; + + // Assert 2 + assert.isUndefined(result2); + assert.isArray(tag.frames); + assert.isEmpty(tag.frames); + } finally { + Id3v2Tag.language = initialLanguage; + } + } + @test public grouping() { this.testTextFrameProperty( @@ -1628,6 +1665,25 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: assert.strictEqual(result, "foo"); } + @test + public getTextAsString_genreFrame() { + // Arrange + const frame1 = UrlLinkFrame.fromIdentifier(FrameIdentifiers.WCOM); + const frame2 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOM); + const frame3 = TextInformationFrame.fromIdentifier(FrameIdentifiers.TCOM); + const frame4 = GenreFrame.fromEncoding(StringType.Latin1); + frame4.text = ["foo"] + + const tag = Id3v2Tag.fromEmpty(); + tag.frames.push(frame1, frame2, frame3, frame4); + + // Act + const result = tag.getTextAsString(FrameIdentifiers.TCON); + + // Assert + assert.strictEqual(result, "foo"); + } + @test public getTextAsString_noMatches() { // Arrange From fcdec03bd94828728c91fea02a716dae82229d50 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Wed, 1 Jul 2026 14:30:13 -0500 Subject: [PATCH 7/9] :robot: comments --- src/id3v2/frames/userUrlLinkFrame.ts | 2 +- src/id3v2/id3v2Tag.ts | 40 ++++++++++++------- test-unit/id3v2/genreFrameTests.ts | 2 +- test-unit/id3v2/privateFrameTests.ts | 2 +- .../id3v2/uniqueFileIdentifierFrameTests.ts | 2 +- test-unit/id3v2/unknownFrameTests.ts | 2 +- .../id3v2/unsynchronizedLyricsFrameTests.ts | 2 +- 7 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/id3v2/frames/userUrlLinkFrame.ts b/src/id3v2/frames/userUrlLinkFrame.ts index 52eb94d..004bda5 100644 --- a/src/id3v2/frames/userUrlLinkFrame.ts +++ b/src/id3v2/frames/userUrlLinkFrame.ts @@ -1,10 +1,10 @@ +import Frame from "./frame"; import Id3v2Settings from "../id3v2Settings"; import UrlLinkFrame from "./urlLinkFrame"; import {ByteVector, StringType} from "../../byteVector"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; import {ArrayUtils, Guards} from "../../utils"; -import Frame from "./frame"; /** * Provides support for ID3v2 User URL Link frames (WXXX). diff --git a/src/id3v2/id3v2Tag.ts b/src/id3v2/id3v2Tag.ts index 3d173c9..15781b0 100644 --- a/src/id3v2/id3v2Tag.ts +++ b/src/id3v2/id3v2Tag.ts @@ -546,7 +546,7 @@ export default class Id3v2Tag extends Tag { } // Case 2: We have a TYER/TYE frame (v2.3/v2.2) - const tyerFrames = TextInformationFrame.filterFrames(this._frameList, FrameIdentifiers.TYER) + const tyerFrames = TextInformationFrame.filterFrames(this._frameList, FrameIdentifiers.TYER); if (tyerFrames.length > 0) { this.setNumberFrame(FrameIdentifiers.TYER, value, 0); return; @@ -610,17 +610,7 @@ export default class Id3v2Tag extends Tag { * @remarks Stored in the `USLT` frame */ get lyrics(): string { - const frames = UnsynchronizedLyricsFrame.filterFrames(this._frameList); - - // Find the best match for the language - return frames.length < 2 - ? frames[0]?.toString() - : frames.map(f => { - const langMatchScore = f.language === Id3v2Tag.language ? 2 : 0; - const nameMatchScore = f.description === "" ? 1 : 0; - const score = langMatchScore + nameMatchScore; - return {score: score, frame: f}; - }).sort((a, b) => b.score - a.score)[0].frame.toString(); + return this.getLyricsFramePreferred("", Id3v2Tag.language)?.toString(); } /** * @inheritDoc @@ -634,8 +624,7 @@ export default class Id3v2Tag extends Tag { } // Find or create the appropriate unsynchronized lyrics frame - const frames = UnsynchronizedLyricsFrame.filterFrames(this._frameList); - let frame = frames.find(f => f.language === Id3v2Tag.language); + let frame = this.getLyricsFramePreferred("", Id3v2Tag.language); if (!frame) { frame = UnsynchronizedLyricsFrame.fromData("", Id3v2Tag.language); this.addFrame(frame); @@ -1494,7 +1483,13 @@ export default class Id3v2Tag extends Tag { } private getCommentFramePreferred(description: string, language: string): CommentsFrame|undefined { - const frames = CommentsFrame.filterFrames(this._frameList); + let frames = CommentsFrame.filterFrames(this._frameList); + + // Skip iTunes comments frames if we're not looking for them + if (!description || !description.startsWith("iTun")) { + frames = frames.filter(f => !f.description.startsWith("iTun")); + } + if (frames.length < 2) { return frames[0]; } @@ -1509,6 +1504,21 @@ export default class Id3v2Tag extends Tag { }).sort((a, b) => b.score - a.score)[0].frame; } + private getLyricsFramePreferred(description: string, language: string): UnsynchronizedLyricsFrame { + const frames = UnsynchronizedLyricsFrame.filterFrames(this._frameList); + if (frames.length < 2) { + return frames[0]; + } + + // Find the best match for the language + return frames.map(f => { + const langMatchScore = f.language === language ? 2 : 0; + const nameMatchScore = f.description === description ? 1 : 0; + const score = langMatchScore + nameMatchScore; + return {score: score, frame: f}; + }).sort((a, b) => b.score - a.score)[0].frame; + } + private getTextAsArray(ident: FrameIdentifier): string[] { if (ident === FrameIdentifiers.TCON) { const frame = GenreFrame.filterFrames(this._frameList)[0]; diff --git a/test-unit/id3v2/genreFrameTests.ts b/test-unit/id3v2/genreFrameTests.ts index 072c437..707cbbf 100644 --- a/test-unit/id3v2/genreFrameTests.ts +++ b/test-unit/id3v2/genreFrameTests.ts @@ -464,7 +464,7 @@ class Id3v2_GenreFrameTests extends FrameConstructorTests { // Assert assert.isOk(output); - assert.instanceOf(frame, GenreFrame); + assert.instanceOf(output, GenreFrame); assert.notStrictEqual(output, frame); assert.strictEqual(output.frameId, FrameIdentifiers.TCON); diff --git a/test-unit/id3v2/privateFrameTests.ts b/test-unit/id3v2/privateFrameTests.ts index 0521bea..53d52c6 100644 --- a/test-unit/id3v2/privateFrameTests.ts +++ b/test-unit/id3v2/privateFrameTests.ts @@ -210,7 +210,7 @@ const assertFrame = (frame: PrivateFrame, o: string, d: ByteVector) => { assert.isArray(result); assert.deepEqual(result, [frame1, frame2]); } - + @test public render_v2_throws() { // Arrange diff --git a/test-unit/id3v2/uniqueFileIdentifierFrameTests.ts b/test-unit/id3v2/uniqueFileIdentifierFrameTests.ts index 88f6c0e..3d7ec9b 100644 --- a/test-unit/id3v2/uniqueFileIdentifierFrameTests.ts +++ b/test-unit/id3v2/uniqueFileIdentifierFrameTests.ts @@ -255,7 +255,7 @@ const assertFrame = (frame: UniqueFileIdentifierFrame, o: string, i: ByteVector) assert.isArray(result); assert.deepEqual(result, [frame1, frame2]); } - + @params(2, "v2") @params(3, "v3") @params(4, "v4") diff --git a/test-unit/id3v2/unknownFrameTests.ts b/test-unit/id3v2/unknownFrameTests.ts index 7ecb504..bdaba01 100644 --- a/test-unit/id3v2/unknownFrameTests.ts +++ b/test-unit/id3v2/unknownFrameTests.ts @@ -172,7 +172,7 @@ const assertFrame = (frame: UnknownFrame, fi: FrameIdentifier, d: ByteVector) => assert.isArray(result); assert.deepEqual(result, [frame1, frame2]); } - + @params(2, "v2") @params(3, "v3") @params(4, "v4") diff --git a/test-unit/id3v2/unsynchronizedLyricsFrameTests.ts b/test-unit/id3v2/unsynchronizedLyricsFrameTests.ts index d239c07..761ae69 100644 --- a/test-unit/id3v2/unsynchronizedLyricsFrameTests.ts +++ b/test-unit/id3v2/unsynchronizedLyricsFrameTests.ts @@ -314,7 +314,7 @@ const assertFrame = (frame: UnsynchronizedLyricsFrame, d: string, l: string, t: assert.isArray(result); assert.deepEqual(result, [frame1, frame2]); } - + @params([2, StringType.Latin1], "v2_single_byte") @params([2, StringType.UTF16BE], "v2_multibyte") @params([3, StringType.Latin1], "v3_single_byte") From 83828cdf1c7badc246d183ee6c51669a088959bd Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Wed, 1 Jul 2026 21:59:05 -0500 Subject: [PATCH 8/9] :robot: comments 2 --- src/id3v2/id3v2Tag.ts | 2 +- test-unit/id3v2/unknownFrameTests.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/id3v2/id3v2Tag.ts b/src/id3v2/id3v2Tag.ts index 15781b0..2a14e96 100644 --- a/src/id3v2/id3v2Tag.ts +++ b/src/id3v2/id3v2Tag.ts @@ -1504,7 +1504,7 @@ export default class Id3v2Tag extends Tag { }).sort((a, b) => b.score - a.score)[0].frame; } - private getLyricsFramePreferred(description: string, language: string): UnsynchronizedLyricsFrame { + private getLyricsFramePreferred(description: string, language: string): UnsynchronizedLyricsFrame|undefined { const frames = UnsynchronizedLyricsFrame.filterFrames(this._frameList); if (frames.length < 2) { return frames[0]; diff --git a/test-unit/id3v2/unknownFrameTests.ts b/test-unit/id3v2/unknownFrameTests.ts index bdaba01..5f98b4f 100644 --- a/test-unit/id3v2/unknownFrameTests.ts +++ b/test-unit/id3v2/unknownFrameTests.ts @@ -89,7 +89,7 @@ const assertFrame = (frame: UnknownFrame, fi: FrameIdentifier, d: ByteVector) => const result = frame.clone(); // Assert - assertFrame(result, result.frameId, result.data); + assertFrame(result, frame.frameId, frame.data); } @test From 15b4cfe3b18a50fda56363f7d6544f7301f64d7b Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Wed, 1 Jul 2026 22:08:54 -0500 Subject: [PATCH 9/9] :robot: comments 3 --- src/id3v2/frames/userTextInformationFrame.ts | 4 ++-- test-unit/id3v2/id3v2TagTests.ts | 2 +- test-unit/id3v2/urlLinkFrameTests.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/id3v2/frames/userTextInformationFrame.ts b/src/id3v2/frames/userTextInformationFrame.ts index cbbd9c0..f69d275 100644 --- a/src/id3v2/frames/userTextInformationFrame.ts +++ b/src/id3v2/frames/userTextInformationFrame.ts @@ -1,10 +1,10 @@ +import Frame from "./frame"; import TextInformationFrame from "./textInformationFrame"; import Id3v2Settings from "../id3v2Settings"; import {ByteVector, StringType} from "../../byteVector"; -import Frame from "./frame"; import {Id3v2FrameHeader} from "./frameHeader"; import {FrameIdentifiers} from "../frameIdentifiers"; -import {ArrayUtils, Guards, StringComparison} from "../../utils"; +import {ArrayUtils, Guards} from "../../utils"; import {CorruptFileError} from "../../errors"; export default class UserTextInformationFrame extends TextInformationFrame { diff --git a/test-unit/id3v2/id3v2TagTests.ts b/test-unit/id3v2/id3v2TagTests.ts index a1b6321..036bd11 100644 --- a/test-unit/id3v2/id3v2TagTests.ts +++ b/test-unit/id3v2/id3v2TagTests.ts @@ -1522,7 +1522,7 @@ const getTestTagHeader = (version: number, flags: Id3v2TagHeaderFlags, tagSize: PropertyTests.propertyRoundTrip(setProp, getProp, "foo"); assert.strictEqual(tag.frames.length, 1); - assert.instanceOf(tag.frames[0], TextInformationFrame); + assert.instanceOf(tag.frames[0], UserTextInformationFrame); assert.strictEqual(( tag.frames[0]).description, desc); assert.deepStrictEqual(( tag.frames[0]).text, ["foo"]); diff --git a/test-unit/id3v2/urlLinkFrameTests.ts b/test-unit/id3v2/urlLinkFrameTests.ts index ba5ba1f..0d49f1b 100644 --- a/test-unit/id3v2/urlLinkFrameTests.ts +++ b/test-unit/id3v2/urlLinkFrameTests.ts @@ -23,13 +23,13 @@ const assertFrame = (frame: UrlLinkFrame, identifier: FrameIdentifier, text: str } @test - public fromIdentity_falsyIdentity() { + public fromIdentifier_falsyIdentity() { // Act/Assert Testers.testTruthy((v: FrameIdentifier) => { UrlLinkFrame.fromIdentifier(v); }); } @test - public fromIdentity_validIdentity() { + public fromIdentifier_validIdentity() { // Act const output = UrlLinkFrame.fromIdentifier(FrameIdentifiers.WCOM);