@@ -27,6 +27,7 @@ import { withAnalyticsMock } from '../fixtures/mocks/analytics';
2727import { getProfileWithNiceTracks } from '../fixtures/profiles/tracks' ;
2828import { blankStore , storeWithProfile } from '../fixtures/stores' ;
2929import { assertSetContainsOnly } from '../fixtures/custom-assertions' ;
30+ import { formatTree } from '../fixtures/utils' ;
3031
3132import * as App from '../../actions/app' ;
3233import * as ProfileView from '../../actions/profile-view' ;
@@ -750,6 +751,175 @@ describe('actions/ProfileView', function () {
750751 } ) ;
751752 } ) ;
752753 } ) ;
754+
755+ function setup ( ) {
756+ // Create a profile which has more than 32 stacks, so that, if any parts of the implementation
757+ // use a BitSet to keep track of something that's per-stack (such as whether a stack matches
758+ // the search filter), the BitSet needs at least two 32-bit slots.
759+ const { profile } = getProfileFromTextSamples ( `
760+ A[lib:K][file:S] A[lib:K][file:S] A[lib:K][file:S] D[lib:nNn][file:uV] C[lib:m][file:t]
761+ B[lib:L][file:t] B[lib:L][file:t] E[lib:O][file:Pq]
762+ A[lib:K][file:S] C[lib:m][file:t]
763+ B[lib:L][file:t] D[lib:n][file:uV]
764+ B[lib:L][file:t]
765+ B[lib:L][file:t]
766+ B[lib:L][file:t]
767+ B[lib:L][file:t]
768+ B[lib:L][file:t]
769+ B[lib:L][file:t]
770+ B[lib:L][file:t]
771+ B[lib:L][file:t]
772+ B[lib:L][file:t]
773+ B[lib:L][file:t]
774+ B[lib:L][file:t]
775+ B[lib:L][file:t]
776+ B[lib:L][file:t]
777+ B[lib:L][file:t]
778+ B[lib:L][file:t]
779+ B[lib:L][file:t]
780+ B[lib:L][file:t]
781+ B[lib:L][file:t]
782+ B[lib:L][file:t]
783+ B[lib:L][file:t]
784+ B[lib:L][file:t]
785+ B[lib:L][file:t]
786+ B[lib:L][file:t]
787+ B[lib:L][file:t]
788+ B[lib:L][file:t]
789+ B[lib:L][file:t]
790+ B[lib:L][file:t]
791+ B[lib:L][file:t]
792+ B[lib:L][file:t]
793+ B[lib:L][file:t]
794+ ` ) ;
795+
796+ const { dispatch, getState } = storeWithProfile ( profile ) ;
797+ return { dispatch, getState, profile } ;
798+ }
799+
800+ it ( 'starts as an unfiltered call tree' , function ( ) {
801+ const { getState } = setup ( ) ;
802+ const originalCallTree = selectedThreadSelectors . getCallTree ( getState ( ) ) ;
803+ expect ( formatTree ( originalCallTree ) ) . toEqual ( [
804+ '- A (total: 3, self: —)' ,
805+ ' - B (total: 2, self: —)' ,
806+ ' - A (total: 1, self: —)' ,
807+ ' - B (total: 1, self: —)' ,
808+ ' - B (total: 1, self: —)' ,
809+ ' - B (total: 1, self: —)' ,
810+ ' - B (total: 1, self: —)' ,
811+ ' - B (total: 1, self: —)' ,
812+ ' - B (total: 1, self: —)' ,
813+ ' - B (total: 1, self: —)' ,
814+ ' - B (total: 1, self: —)' ,
815+ ' - B (total: 1, self: —)' ,
816+ ' - B (total: 1, self: —)' ,
817+ ' - B (total: 1, self: —)' ,
818+ ' - B (total: 1, self: —)' ,
819+ ' - B (total: 1, self: —)' ,
820+ ' - B (total: 1, self: —)' ,
821+ ' - B (total: 1, self: —)' ,
822+ ' - B (total: 1, self: —)' ,
823+ ' - B (total: 1, self: —)' ,
824+ ' - B (total: 1, self: —)' ,
825+ ' - B (total: 1, self: —)' ,
826+ ' - B (total: 1, self: —)' ,
827+ ' - B (total: 1, self: —)' ,
828+ ' - B (total: 1, self: —)' ,
829+ ' - B (total: 1, self: —)' ,
830+ ' - B (total: 1, self: —)' ,
831+ ' - B (total: 1, self: —)' ,
832+ ' - B (total: 1, self: —)' ,
833+ ' - B (total: 1, self: —)' ,
834+ ' - B (total: 1, self: —)' ,
835+ ' - B (total: 1, self: —)' ,
836+ ' - B (total: 1, self: —)' ,
837+ ' - B (total: 1, self: 1)' ,
838+ ' - C (total: 1, self: —)' ,
839+ ' - D (total: 1, self: 1)' ,
840+ ' - E (total: 1, self: 1)' ,
841+ '- D (total: 1, self: 1)' ,
842+ '- C (total: 1, self: 1)' ,
843+ ] ) ;
844+ } ) ;
845+
846+ it ( 'filters out all samples if there is no match' , function ( ) {
847+ const { dispatch, getState } = setup ( ) ;
848+ dispatch ( ProfileView . changeCallTreeSearchString ( 'F' ) ) ;
849+ const callTree = selectedThreadSelectors . getCallTree ( getState ( ) ) ;
850+ expect ( formatTree ( callTree ) ) . toEqual ( [ ] ) ;
851+ } ) ;
852+
853+ it ( 'filters based on function names' , function ( ) {
854+ const { dispatch, getState } = setup ( ) ;
855+ dispatch ( ProfileView . changeCallTreeSearchString ( 'c' ) ) ;
856+ const callTree = selectedThreadSelectors . getCallTree ( getState ( ) ) ;
857+ // Keep all stacks which include function C
858+ expect ( formatTree ( callTree ) ) . toEqual ( [
859+ '- A (total: 1, self: —)' ,
860+ ' - B (total: 1, self: —)' ,
861+ ' - C (total: 1, self: —)' ,
862+ ' - D (total: 1, self: 1)' ,
863+ '- C (total: 1, self: 1)' ,
864+ ] ) ;
865+
866+ // Also test with uppercase 'C'
867+ dispatch ( ProfileView . changeCallTreeSearchString ( 'C' ) ) ;
868+ const callTree2 = selectedThreadSelectors . getCallTree ( getState ( ) ) ;
869+ // Keep all stacks which include function C
870+ expect ( formatTree ( callTree2 ) ) . toEqual ( [
871+ '- A (total: 1, self: —)' ,
872+ ' - B (total: 1, self: —)' ,
873+ ' - C (total: 1, self: —)' ,
874+ ' - D (total: 1, self: 1)' ,
875+ '- C (total: 1, self: 1)' ,
876+ ] ) ;
877+ } ) ;
878+
879+ it ( 'filters based on filenames' , function ( ) {
880+ const { dispatch, getState } = setup ( ) ;
881+ dispatch ( ProfileView . changeCallTreeSearchString ( 'u' ) ) ;
882+ const callTree_u = selectedThreadSelectors . getCallTree ( getState ( ) ) ;
883+ // Keep all stacks which include function D, which has filename uV
884+ expect ( formatTree ( callTree_u ) ) . toEqual ( [
885+ '- A (total: 1, self: —)' ,
886+ ' - B (total: 1, self: —)' ,
887+ ' - C (total: 1, self: —)' ,
888+ ' - D (total: 1, self: 1)' ,
889+ '- D (total: 1, self: 1)' ,
890+ ] ) ;
891+ dispatch ( ProfileView . changeCallTreeSearchString ( 'pQ' ) ) ;
892+ const callTree_pQ = selectedThreadSelectors . getCallTree ( getState ( ) ) ;
893+ // Keep all stacks which include function E, which has filename Pq
894+ expect ( formatTree ( callTree_pQ ) ) . toEqual ( [
895+ '- A (total: 1, self: —)' ,
896+ ' - E (total: 1, self: 1)' ,
897+ ] ) ;
898+ } ) ;
899+
900+ it ( 'filters based on library names' , function ( ) {
901+ const { dispatch, getState } = setup ( ) ;
902+ dispatch ( ProfileView . changeCallTreeSearchString ( 'M' ) ) ;
903+ const callTree_M = selectedThreadSelectors . getCallTree ( getState ( ) ) ;
904+ // Keep all stacks which include function C, which has lib name m
905+ expect ( formatTree ( callTree_M ) ) . toEqual ( [
906+ '- A (total: 1, self: —)' ,
907+ ' - B (total: 1, self: —)' ,
908+ ' - C (total: 1, self: —)' ,
909+ ' - D (total: 1, self: 1)' ,
910+ '- C (total: 1, self: 1)' ,
911+ ] ) ;
912+ dispatch ( ProfileView . changeCallTreeSearchString ( 'NN' ) ) ;
913+ const callTree_NN = selectedThreadSelectors . getCallTree ( getState ( ) ) ;
914+ // Keep all stacks which include function D, which has filename nNn
915+ expect ( formatTree ( callTree_NN ) ) . toEqual ( [
916+ '- A (total: 1, self: —)' ,
917+ ' - B (total: 1, self: —)' ,
918+ ' - C (total: 1, self: —)' ,
919+ ' - D (total: 1, self: 1)' ,
920+ '- D (total: 1, self: 1)' ,
921+ ] ) ;
922+ } ) ;
753923 } ) ;
754924
755925 /**
0 commit comments