@@ -624,6 +624,206 @@ describe('Infinites', () => {
624624 } )
625625 } )
626626
627+ describe ( 'Branding' , ( ) => {
628+ const segmentLegacyPersist : IPieceLifespan = {
629+ scope : 'segment' ,
630+ presence : 'forward-scope' ,
631+ inShadow : 'legacy-persist' ,
632+ }
633+ const rundownLegacyPersist : IPieceLifespan = {
634+ scope : 'rundown' ,
635+ presence : 'forward-scope' ,
636+ inShadow : 'legacy-persist' ,
637+ }
638+
639+ function limitTo ( piece : Piece , onlyValidForBranding : string [ ] ) : Piece {
640+ return { ...piece , onlyValidForBranding }
641+ }
642+
643+ describe ( 'the playing PartInstance' , ( ) => {
644+ /** Play the PieceInstances in part0 with the Branding selected, and return the ids of those continued into part1 */
645+ function getContinuedIds ( pieceInstances : PieceInstance [ ] , brandingId : string | null = null ) : string [ ] {
646+ const playing = createPlaying ( 'part0' , pieceInstances )
647+ const branded = { ...playing , partInstance : { ...playing . partInstance , brandingId } }
648+ return getContinuedPieceIds ( getParams ( 'part1' , [ ] , branded ) ) . sort ( )
649+ }
650+
651+ function createOnChange ( id : string , start : number | 'now' , onlyValidForBranding ?: string [ ] ) : PieceInstance {
652+ const piece = createPiece ( id , 'part0' , 0 , 'layer' , rundownPlayhead )
653+ return createPieceInstance ( onlyValidForBranding ? limitTo ( piece , onlyValidForBranding ) : piece , {
654+ piece : { enable : { start } } ,
655+ } )
656+ }
657+
658+ function createAdlibbedOnEnd ( id : string , start : number | 'now' ) : PieceInstance {
659+ return createPieceInstance ( createPiece ( id , 'part0' , 0 , 'layer' , rundownLegacyPersist ) , {
660+ dynamicallyConvertedToInfinite : 1 ,
661+ piece : { enable : { start } } ,
662+ } )
663+ }
664+
665+ test ( 'the onChange piece starting last is the one continued' , ( ) => {
666+ expect ( getContinuedIds ( [ createOnChange ( 'early' , 1000 ) , createOnChange ( 'late' , 2000 ) ] ) ) . toEqual ( [ 'late' ] )
667+ } )
668+
669+ test ( 'the onChange piece starting last is chosen regardless of the order they are considered in' , ( ) => {
670+ expect ( getContinuedIds ( [ createOnChange ( 'late' , 2000 ) , createOnChange ( 'early' , 1000 ) ] ) ) . toEqual ( [ 'late' ] )
671+ } )
672+
673+ test ( "an onChange piece starting 'now' starts later than any planned start" , ( ) => {
674+ expect ( getContinuedIds ( [ createOnChange ( 'planned' , 2000 ) , createOnChange ( 'now' , 'now' ) ] ) ) . toEqual ( [
675+ 'now' ,
676+ ] )
677+ } )
678+
679+ test ( 'the adlibbed onEnd piece starting last is the one continued' , ( ) => {
680+ expect (
681+ getContinuedIds ( [ createAdlibbedOnEnd ( 'early' , 1000 ) , createAdlibbedOnEnd ( 'late' , 2000 ) ] )
682+ ) . toEqual ( [ 'late' ] )
683+ } )
684+
685+ test ( "an adlibbed onEnd piece starting 'now' starts later than any planned start" , ( ) => {
686+ expect (
687+ getContinuedIds ( [ createAdlibbedOnEnd ( 'planned' , 2000 ) , createAdlibbedOnEnd ( 'now' , 'now' ) ] )
688+ ) . toEqual ( [ 'now' ] )
689+ } )
690+
691+ test ( 'a piece hidden by the Branding is not continued, as it is not playing' , ( ) => {
692+ // Without the Branding it would have stopped the other, as it starts later
693+ expect (
694+ getContinuedIds (
695+ [ createOnChange ( 'shown' , 1000 ) , createOnChange ( 'hidden' , 2000 , [ 'brandingB' ] ) ] ,
696+ 'brandingA'
697+ )
698+ ) . toEqual ( [ 'shown' ] )
699+ } )
700+
701+ test ( 'a piece used with the selected Branding is continued' , ( ) => {
702+ expect ( getContinuedIds ( [ createOnChange ( 'limited' , 1000 , [ 'brandingA' ] ) ] , 'brandingA' ) ) . toEqual ( [
703+ 'limited' ,
704+ ] )
705+ } )
706+
707+ test ( 'a piece limited to a Branding is stopped by a later unlimited one' , ( ) => {
708+ const limited = createOnChange ( 'limited' , 1000 , [ 'brandingA' ] )
709+ const later = createOnChange ( 'later' , 2000 )
710+
711+ expect ( getContinuedIds ( [ limited , later ] , 'brandingA' ) ) . toEqual ( [ 'later' ] )
712+ expect ( getContinuedIds ( [ later , limited ] , 'brandingA' ) ) . toEqual ( [ 'later' ] )
713+ } )
714+
715+ test ( 'a piece limited to a Branding does not stop an earlier unlimited one' , ( ) => {
716+ const early = createOnChange ( 'early' , 1000 )
717+ const limited = createOnChange ( 'limited' , 2000 , [ 'brandingA' ] )
718+
719+ expect ( getContinuedIds ( [ early , limited ] , 'brandingA' ) ) . toEqual ( [ 'early' , 'limited' ] )
720+ expect ( getContinuedIds ( [ limited , early ] , 'brandingA' ) ) . toEqual ( [ 'early' , 'limited' ] )
721+ } )
722+
723+ test ( 'a piece limited to a Branding is kept when an unlimited one starts at the same time' , ( ) => {
724+ const limited = createOnChange ( 'limited' , 1000 , [ 'brandingA' ] )
725+ const unlimited = createOnChange ( 'unlimited' , 1000 )
726+
727+ expect ( getContinuedIds ( [ limited , unlimited ] , 'brandingA' ) ) . toEqual ( [ 'limited' , 'unlimited' ] )
728+ expect ( getContinuedIds ( [ unlimited , limited ] , 'brandingA' ) ) . toEqual ( [ 'limited' , 'unlimited' ] )
729+ } )
730+ } )
731+
732+ describe ( 'planned pieces' , ( ) => {
733+ /** The ids of the planned Pieces continued into part2, the last Part in segment0 */
734+ function getKeptIds ( pieces : Piece [ ] ) : string [ ] {
735+ return getContinuedPieceIds ( getParams ( 'part2' , pieces ) ) . sort ( )
736+ }
737+
738+ function createInfinite ( id : string , partId : string , sourceLayerId = 'layer' ) : Piece {
739+ return createPiece ( id , partId , 0 , sourceLayerId , segmentLegacyPersist )
740+ }
741+
742+ test ( 'without Branding, only the last starting infinite on a layer is kept' , ( ) => {
743+ expect ( getKeptIds ( [ createInfinite ( 'early' , 'part0' ) , createInfinite ( 'late' , 'part1' ) ] ) ) . toEqual ( [
744+ 'late' ,
745+ ] )
746+ } )
747+
748+ test ( 'an infinite limited to a Branding does not stop the one before it' , ( ) => {
749+ expect (
750+ getKeptIds ( [
751+ createInfinite ( 'early' , 'part0' ) ,
752+ limitTo ( createInfinite ( 'late' , 'part1' ) , [ 'brandingA' ] ) ,
753+ ] )
754+ ) . toEqual ( [ 'early' , 'late' ] )
755+ } )
756+
757+ test ( 'infinites limited to different Brandings are all kept' , ( ) => {
758+ expect (
759+ getKeptIds ( [
760+ limitTo ( createInfinite ( 'early' , 'part0' ) , [ 'brandingB' ] ) ,
761+ limitTo ( createInfinite ( 'late' , 'part1' ) , [ 'brandingA' ] ) ,
762+ ] )
763+ ) . toEqual ( [ 'early' , 'late' ] )
764+ } )
765+
766+ test ( 'an infinite limited to a Branding is stopped by a later unlimited one' , ( ) => {
767+ expect (
768+ getKeptIds ( [
769+ limitTo ( createInfinite ( 'early' , 'part0' ) , [ 'brandingA' ] ) ,
770+ createInfinite ( 'late' , 'part1' ) ,
771+ ] )
772+ ) . toEqual ( [ 'late' ] )
773+ } )
774+
775+ test ( 'an infinite limited to a Branding is stopped by a later unlimited one, in either order' , ( ) => {
776+ expect (
777+ getKeptIds ( [
778+ createInfinite ( 'late' , 'part1' ) ,
779+ limitTo ( createInfinite ( 'early' , 'part0' ) , [ 'brandingA' ] ) ,
780+ ] )
781+ ) . toEqual ( [ 'late' ] )
782+ } )
783+
784+ test ( 'an infinite limited to a Branding is kept when it starts at the same time as an unlimited one' , ( ) => {
785+ // Neither is preferred, so this has to be left to be resolved during playout
786+ const limited = limitTo ( createInfinite ( 'limited' , 'part1' ) , [ 'brandingA' ] )
787+ const unlimited = createInfinite ( 'unlimited' , 'part1' )
788+
789+ expect ( getKeptIds ( [ limited , unlimited ] ) ) . toEqual ( [ 'limited' , 'unlimited' ] )
790+ expect ( getKeptIds ( [ unlimited , limited ] ) ) . toEqual ( [ 'limited' , 'unlimited' ] )
791+ } )
792+
793+ test ( 'a later unlimited infinite stops both the limited and the unlimited ones before it' , ( ) => {
794+ expect (
795+ getKeptIds ( [
796+ createInfinite ( 'early' , 'part0' ) ,
797+ limitTo ( createInfinite ( 'limited' , 'part0' ) , [ 'brandingA' ] ) ,
798+ createInfinite ( 'latest' , 'part1' ) ,
799+ ] )
800+ ) . toEqual ( [ 'latest' ] )
801+ } )
802+
803+ test ( 'an unlimited infinite is kept when everything after it is limited' , ( ) => {
804+ expect (
805+ getKeptIds ( [
806+ createInfinite ( 'early' , 'part0' ) ,
807+ limitTo ( createInfinite ( 'late' , 'part1' ) , [ 'brandingA' ] ) ,
808+ limitTo ( createInfinite ( 'latest' , 'part1' ) , [ 'brandingB' ] ) ,
809+ ] )
810+ ) . toEqual ( [ 'early' , 'late' , 'latest' ] )
811+ } )
812+
813+ test ( 'an override does not affect the selection, as it cannot move the Piece between layers' , ( ) => {
814+ const late : Piece = { ...createInfinite ( 'late' , 'part1' ) , branding : { brandingA : { name : 'branded' } } }
815+
816+ expect ( getKeptIds ( [ createInfinite ( 'early' , 'part0' ) , late ] ) ) . toEqual ( [ 'late' ] )
817+ } )
818+
819+ test ( 'infinites on separate layers never compete' , ( ) => {
820+ expect (
821+ getKeptIds ( [ createInfinite ( 'early' , 'part0' , 'layer0' ) , createInfinite ( 'late' , 'part1' , 'layer1' ) ] )
822+ ) . toEqual ( [ 'early' , 'late' ] )
823+ } )
824+ } )
825+ } )
826+
627827 describe ( 'queries' , ( ) => {
628828 const part = getPart ( 'part1' )
629829
0 commit comments