import { assert } from "chai" ; import { assertThrowsChain } from "../../helpers.spec" ; import { TwitchBadge } from "../badge" ; import { TwitchBadgesList } from "../badges" ; import { TwitchEmote } from "../emote" ; import { MissingTagError } from "./missing-tag-error" ; import { ParseError } from "./parse-error" ; import { tagParserFor , TagValueParser } from "./tag-values" ; describe ( "./message/parser/tag-values" , function ( ) { function checkRequire < V , A extends any [ ] > ( subject , ... converterArgs ) { describe ( "#requireData" , function ( ) { it ( "should throw MissingTagError on missing key" , function ( ) { assertThrowsChain ( ( ) => subject ( tagParserFor ( { } ) ) ( "key" , ... converterArgs ) , MissingTagError , 'Required tag value not present at key "key" (is undefined)' ) ; } ) ; it ( "should throw MissingTagError on null value" , function ( ) { assertThrowsChain ( ( ) => subject ( tagParserFor ( { key : null } ) ) ( "key" , ... converterArgs ) , MissingTagError , 'Required tag value not present at key "key" (is null)' ) ; } ) ; } ) ; } function checkGet < V , A extends any [ ] > ( subject , ... converterArgs ) { describe ( "#getData" , function ( ) { it ( "should return undefined on missing key" , function ( ) { assert . isUndefined ( subject ( tagParserFor ( { } ) ) ( "key" , ... converterArgs ) ) ; } ) ; it ( "should return undefined on null value" , function ( ) { assert . isUndefined ( subject ( tagParserFor ( { key : null } ) ) ( "key" , ... converterArgs ) ) ; } ) ; } ) ; } describe ( "#getString(), #requireString()" , function ( ) { checkGet ( ( p ) => p . getString ) ; checkRequire ( ( p ) => p . requireString ) ; it ( "should return the value if value exists (also on empty string)" , function ( ) { assert . strictEqual ( tagParserFor ( { key : "value" } ) . getString ( "key" ) , "value" ) ; assert . strictEqual ( tagParserFor ( { key : "value" } ) . requireString ( "key" ) , "value" ) ; assert . strictEqual ( tagParserFor ( { key : "" } ) . getString ( "key" ) , "" ) ; assert . strictEqual ( tagParserFor ( { key : "" } ) . requireString ( "key" ) , "" ) ; } ) ; } ) ; function checkThrowsUnparseableInt < V , A extends any [ ] > ( subject , ... converterArgs ) { it ( "should throw ParseError on empty string input" , function ( ) { assertThrowsChain ( ( ) => subject ( tagParserFor ( { key : "" } ) ) ( "key" , ... converterArgs ) , ParseError , 'Failed to parse integer from tag value ""' ) ; } ) ; it ( "should throw ParseError on invalid integer input" , function ( ) { assertThrowsChain ( ( ) => subject ( tagParserFor ( { key : "abc" } ) ) ( "key" , ... converterArgs ) , ParseError , 'Failed to parse integer from tag value "abc"' ) ; } ) ; } describe ( "#getInt(), #requireInt()" , function ( ) { checkGet ( ( p ) => p . getInt ) ; checkRequire ( ( p ) => p . requireInt ) ; checkThrowsUnparseableInt ( ( p ) => p . getInt ) ; checkThrowsUnparseableInt ( ( p ) => p . requireInt ) ; it ( "should return a number if value exists and was parseable" , function ( ) { assert . strictEqual ( 15 , tagParserFor ( { key : "15" } ) . getInt ( "key" ) ) ; assert . strictEqual ( 15 , tagParserFor ( { key : "15" } ) . requireInt ( "key" ) ) ; } ) ; } ) ; describe ( "#getBoolean(), #requireBoolean()" , function ( ) { checkGet ( ( p ) => p . getBoolean ) ; checkRequire ( ( p ) => p . requireBoolean ) ; checkThrowsUnparseableInt ( ( p ) => p . getInt ) ; checkThrowsUnparseableInt ( ( p ) => p . requireInt ) ; it ( "should return false if the parsed integer is 0" , function ( ) { assert . isFalse ( tagParserFor ( { key : "0" } ) . getBoolean ( "key" ) ) ; assert . isFalse ( tagParserFor ( { key : "0.0" } ) . getBoolean ( "key" ) ) ; } ) ; it ( "should return false if the parsed integer is non-0" , function ( ) { assert . isTrue ( tagParserFor ( { key : "1" } ) . getBoolean ( "key" ) ) ; assert . isTrue ( tagParserFor ( { key : "-1" } ) . getBoolean ( "key" ) ) ; assert . isTrue ( tagParserFor ( { key : "15" } ) . getBoolean ( "key" ) ) ; assert . isTrue ( tagParserFor ( { key : "-15" } ) . getBoolean ( "key" ) ) ; } ) ; } ) ; describe ( "#getColor(), #requireColor()" , function ( ) { checkGet ( ( p ) => p . getColor ) ; checkRequire ( ( p ) => p . requireColor ) ; it ( "should parse #RRGGBB color input correctly" , function ( ) { assert . deepStrictEqual ( tagParserFor ( { key : "#aabbcc" } ) . getColor ( "key" ) , { r : 0xaa , g : 0xbb , b : 0xcc , } ) ; assert . deepStrictEqual ( tagParserFor ( { key : "#AABBCC" } ) . getColor ( "key" ) , { r : 0xaa , g : 0xbb , b : 0xcc , } ) ; assert . deepStrictEqual ( tagParserFor ( { key : "#12D3FF" } ) . getColor ( "key" ) , { r : 0x12 , g : 0xd3 , b : 0xff , } ) ; } ) ; it ( "#getColor() should return undefined on empty string input" , function ( ) { assert . isUndefined ( tagParserFor ( { key : "" } ) . getColor ( "key" ) ) ; } ) ; it ( "#requireColor() should throw MissingDataError on empty string input" , function ( ) { assertThrowsChain ( ( ) => tagParserFor ( { key : "" } ) . requireColor ( "key" ) , MissingTagError , 'Required tag value not present at key "key" (is empty string)' ) ; } ) ; } ) ; describe ( "#getTimestamp(), #requireTimestamp()" , function ( ) { checkGet ( ( p ) => p . getTimestamp ) ; checkRequire ( ( p ) => p . requireTimestamp ) ; checkThrowsUnparseableInt ( ( p ) => p . getTimestamp ) ; checkThrowsUnparseableInt ( ( p ) => p . requireTimestamp ) ; it ( "should interpret given integer values as milliseconds since UTC epoch" , function ( ) { assert . strictEqual ( tagParserFor ( { key : "1234567" } ) . requireTimestamp ( "key" ) . getTime ( ) , 1234567 ) ; } ) ; } ) ; describe ( "#getBadges(), #requireBadges()" , function ( ) { checkGet ( ( p ) => p . getBadges ) ; checkRequire ( ( p ) => p . requireBadges ) ; it ( "should return an empty list on empty string input" , function ( ) { assert . deepStrictEqual ( tagParserFor ( { key : "" } ) . getBadges ( "key" ) , new TwitchBadgesList ( ) ) ; } ) ; it ( "should return single-element array on single badge" , function ( ) { assert . deepStrictEqual ( tagParserFor ( { key : "admin/1" } ) . getBadges ( "key" ) , new TwitchBadgesList ( new TwitchBadge ( "admin" , "1" ) ) ) ; } ) ; it ( "should accept two badges in the tag source" , function ( ) { assert . deepStrictEqual ( tagParserFor ( { key : "admin/1,subscriber/32" } ) . getBadges ( "key" ) , new TwitchBadgesList ( new TwitchBadge ( "admin" , "1" ) , new TwitchBadge ( "subscriber" , "32" ) ) ) ; } ) ; it ( "should accept three badges in the tag source" , function ( ) { assert . deepStrictEqual ( tagParserFor ( { key : "admin/1,subscriber/32,bits/1000" } ) . getBadges ( "key" ) , new TwitchBadgesList ( new TwitchBadge ( "admin" , "1" ) , new TwitchBadge ( "subscriber" , "32" ) , new TwitchBadge ( "bits" , "1000" ) ) ) ; } ) ; } ) ; describe ( "#getTagEmotes()" , function ( ) { checkGet ( ( p ) => p . getEmotes , "lul" ) ; checkRequire ( ( p ) => p . requireEmoteSets , "lul" ) ; it ( "should return an empty list on empty string input" , function ( ) { const actual = tagParserFor ( { key : "" } ) . getEmotes ( "key" , "test" ) ; assert . deepStrictEqual ( actual , [ ] ) ; } ) ; it ( "should return single-element array on single emote" , function ( ) { const actual = tagParserFor ( { key : "25:4-8" } ) . getEmotes ( "key" , "asd Kappa def" ) ; assert . deepStrictEqual ( actual , [ new TwitchEmote ( "25" , 4 , 9 , "Kappa" ) ] ) ; } ) ; it ( "should return 2-element array on 2 identical emotes" , function ( ) { const actual = tagParserFor ( { key : "25:4-8,14-18" } ) . getEmotes ( "key" , "asd Kappa def Kappa def" ) ; assert . deepStrictEqual ( actual , [ new TwitchEmote ( "25" , 4 , 9 , "Kappa" ) , new TwitchEmote ( "25" , 14 , 19 , "Kappa" ) , ] ) ; } ) ; it ( "should return 2-element array on 2 different emotes" , function ( ) { const actual = tagParserFor ( { key : "25:4-8/1902:14-18" } ) . getEmotes ( "key" , "asd Kappa def Keepo def" ) ; assert . deepStrictEqual ( actual , [ new TwitchEmote ( "25" , 4 , 9 , "Kappa" ) , new TwitchEmote ( "1902" , 14 , 19 , "Keepo" ) , ] ) ; } ) ; it ( "should return a correctly sorted 3-element array on interleaved emotes" , function ( ) { const actual = tagParserFor ( { key : "25:5-9,27-31/1902:16-20" } ) . getEmotes ( "key" , "test Kappa test Keepo test Kappa" ) ; assert . deepStrictEqual ( actual , [ new TwitchEmote ( "25" , 5 , 10 , "Kappa" ) , new TwitchEmote ( "1902" , 16 , 21 , "Keepo" ) , new TwitchEmote ( "25" , 27 , 32 , "Kappa" ) , ] ) ; } ) ; } ) ; describe ( "#getEmoteSets(), #requireEmoteSets()" , function ( ) { checkGet ( ( p ) => p . getEmoteSets ) ; checkRequire ( ( p ) => p . requireEmoteSets ) ; it ( "should return an empty list on empty string input" , function ( ) { const actual = tagParserFor ( { key : "" } ) . getEmoteSets ( "key" ) ; assert . deepStrictEqual ( actual , [ ] ) ; } ) ; it ( "should parse one emote set correctly" , function ( ) { const actual = tagParserFor ( { key : "0" } ) . getEmoteSets ( "key" ) ; assert . deepStrictEqual ( actual , [ "0" ] ) ; } ) ; it ( "should parse two emote set correctly" , function ( ) { const actual = tagParserFor ( { key : "0,3343" } ) . getEmoteSets ( "key" ) ; assert . deepStrictEqual ( actual , [ "0" , "3343" ] ) ; } ) ; it ( "should parse three emote set correctly" , function ( ) { const actual = tagParserFor ( { key : "0,7897,3343" } ) . getEmoteSets ( "key" ) ; assert . deepStrictEqual ( actual , [ "0" , "7897" , "3343" ] ) ; } ) ; } ) ; } ) ;