@@ -388,3 +388,244 @@ describe('Distance expression', () => {
388388 } ) ;
389389 } ) ;
390390} ) ;
391+
392+ describe ( 'index-of expression' , ( ) => {
393+ test ( 'requires a needle' , ( ) => {
394+ const response = createExpression ( [ 'index-of' ] ) ;
395+ expect ( response . result ) . toBe ( 'error' ) ;
396+ } ) ;
397+ test ( 'requires a haystack' , ( ) => {
398+ const response = createExpression ( [ 'index-of' , 'a' ] ) ;
399+ expect ( response . result ) . toBe ( 'error' ) ;
400+ } ) ;
401+ test ( 'rejects a fourth argument' , ( ) => {
402+ const response = createExpression ( [ 'index-of' , 'a' , 'abc' , 1 , 8 ] ) ;
403+ expect ( response . result ) . toBe ( 'error' ) ;
404+ } ) ;
405+ test ( 'requires a primitive as the needle' , ( ) => {
406+ const response = createExpression ( [ 'index-of' , [ 'literal' , [ 'a' ] ] , [ 'a' , 'b' , 'c' ] ] ) ;
407+ expect ( response . result ) . toBe ( 'error' ) ;
408+ } ) ;
409+ test ( 'requires a string or array as the haystack' , ( ) => {
410+ const response = createExpression ( [ 'index-of' , 't' , true ] ) ;
411+ expect ( response . result ) . toBe ( 'error' ) ;
412+ } ) ;
413+ test ( 'finds an empty substring in an empty string' , ( ) => {
414+ const response = createExpression ( [ 'index-of' , '' , '' ] ) ;
415+ expect ( response . result ) . toBe ( 'success' ) ;
416+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 0 ) ;
417+ } ) ;
418+ test ( 'finds an empty substring in a non-empty string' , ( ) => {
419+ const response = createExpression ( [ 'index-of' , '' , 'abc' ] ) ;
420+ expect ( response . result ) . toBe ( 'success' ) ;
421+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 0 ) ;
422+ } ) ;
423+ test ( 'cannot find a non-empty substring in an empty string' , ( ) => {
424+ const response = createExpression ( [ 'index-of' , 'abc' , '' ] ) ;
425+ expect ( response . result ) . toBe ( 'success' ) ;
426+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( - 1 ) ;
427+ } ) ;
428+ test ( 'finds a non-empty substring in a non-empty string' , ( ) => {
429+ const response = createExpression ( [ 'index-of' , 'b' , 'abc' ] ) ;
430+ expect ( response . result ) . toBe ( 'success' ) ;
431+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 1 ) ;
432+ } ) ;
433+ test ( 'only finds the first occurrence in a string' , ( ) => {
434+ const response = createExpression ( [ 'index-of' , 'b' , 'abbc' ] ) ;
435+ expect ( response . result ) . toBe ( 'success' ) ;
436+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 1 ) ;
437+ } ) ;
438+ test ( 'starts looking for the substring at a positive start index' , ( ) => {
439+ const response = createExpression ( [ 'index-of' , 'a' , 'abc' , 1 ] ) ;
440+ expect ( response . result ) . toBe ( 'success' ) ;
441+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( - 1 ) ;
442+ } ) ;
443+ test ( 'starts looking for the substring at a negative start index' , ( ) => {
444+ const response = createExpression ( [ 'index-of' , 'c' , 'abc' , - 1 ] ) ;
445+ expect ( response . result ) . toBe ( 'success' ) ;
446+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 2 ) ;
447+ } ) ;
448+ test ( 'counts a non-ASCII character as a single character' , ( ) => {
449+ const response = createExpression ( [ 'index-of' , '镇' , '市镇' ] ) ;
450+ expect ( response . result ) . toBe ( 'success' ) ;
451+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 1 ) ;
452+ } ) ;
453+ test ( 'counts a surrogate pair as a single character' , ( ) => {
454+ const response = createExpression ( [ 'index-of' , '市镇' , '丐𦨭市镇' ] ) ;
455+ expect ( response . result ) . toBe ( 'success' ) ;
456+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 2 ) ;
457+ } ) ;
458+ test ( 'cannot find an element in an empty array' , ( ) => {
459+ const response = createExpression ( [ 'index-of' , 1 , [ 'literal' , [ ] ] ] ) ;
460+ expect ( response . result ) . toBe ( 'success' ) ;
461+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( - 1 ) ;
462+ } ) ;
463+ test ( 'finds an element in a non-empty array' , ( ) => {
464+ const response = createExpression ( [ 'index-of' , 2 , [ 'literal' , [ 1 , 2 , 3 ] ] ] ) ;
465+ expect ( response . result ) . toBe ( 'success' ) ;
466+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 1 ) ;
467+ } ) ;
468+ test ( 'only finds the first occurrence in an array' , ( ) => {
469+ const response = createExpression ( [ 'index-of' , 2 , [ 'literal' , [ 1 , 2 , 2 , 3 ] ] ] ) ;
470+ expect ( response . result ) . toBe ( 'success' ) ;
471+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 1 ) ;
472+ } ) ;
473+ test ( 'starts looking for the element at a positive start index' , ( ) => {
474+ const response = createExpression ( [ 'index-of' , 1 , [ 'literal' , [ 1 , 2 , 3 ] ] , 1 ] ) ;
475+ expect ( response . result ) . toBe ( 'success' ) ;
476+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( - 1 ) ;
477+ } ) ;
478+ test ( 'starts looking for the element at a negative start index' , ( ) => {
479+ const response = createExpression ( [ 'index-of' , 3 , [ 'literal' , [ 1 , 2 , 3 ] ] , - 1 ] ) ;
480+ expect ( response . result ) . toBe ( 'success' ) ;
481+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 2 ) ;
482+ } ) ;
483+ } ) ;
484+
485+ describe ( 'length expression' , ( ) => {
486+ test ( 'requires an argument' , ( ) => {
487+ const response = createExpression ( [ 'length' ] ) ;
488+ expect ( response . result ) . toBe ( 'error' ) ;
489+ } ) ;
490+ test ( 'requires a string or array as the argument' , ( ) => {
491+ const response = createExpression ( [ 'length' , true ] ) ;
492+ expect ( response . result ) . toBe ( 'error' ) ;
493+ } ) ;
494+ test ( 'rejects a second argument' , ( ) => {
495+ const response = createExpression ( [ 'length' , 'abc' , 'def' ] ) ;
496+ expect ( response . result ) . toBe ( 'error' ) ;
497+ } ) ;
498+ test ( 'measures an empty string' , ( ) => {
499+ const response = createExpression ( [ 'length' , '' ] ) ;
500+ expect ( response . result ) . toBe ( 'success' ) ;
501+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 0 ) ;
502+ } ) ;
503+ test ( 'measures a non-empty string' , ( ) => {
504+ const response = createExpression ( [ 'length' , 'abc' ] ) ;
505+ expect ( response . result ) . toBe ( 'success' ) ;
506+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 3 ) ;
507+ } ) ;
508+ test ( 'counts a non-ASCII character as a single character' , ( ) => {
509+ const response = createExpression ( [ 'length' , '市镇' ] ) ;
510+ expect ( response . result ) . toBe ( 'success' ) ;
511+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 2 ) ;
512+ } ) ;
513+ test ( 'counts a surrogate pair as a single character' , ( ) => {
514+ const response = createExpression ( [ 'length' , '丐𦨭市镇' ] ) ;
515+ expect ( response . result ) . toBe ( 'success' ) ;
516+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 4 ) ;
517+ } ) ;
518+ test ( 'measures an empty array' , ( ) => {
519+ const response = createExpression ( [ 'length' , [ 'literal' , [ ] ] ] ) ;
520+ expect ( response . result ) . toBe ( 'success' ) ;
521+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 0 ) ;
522+ } ) ;
523+ test ( 'measures a non-empty array' , ( ) => {
524+ const response = createExpression ( [ 'length' , [ 'literal' , [ 1 , 2 , 3 ] ] ] ) ;
525+ expect ( response . result ) . toBe ( 'success' ) ;
526+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 3 ) ;
527+ } ) ;
528+ } ) ;
529+
530+ describe ( 'slice expression' , ( ) => {
531+ test ( 'requires an input argument' , ( ) => {
532+ const response = createExpression ( [ 'slice' ] ) ;
533+ expect ( response . result ) . toBe ( 'error' ) ;
534+ } ) ;
535+ test ( 'requires a start index argument' , ( ) => {
536+ const response = createExpression ( [ 'slice' , 'abc' ] ) ;
537+ expect ( response . result ) . toBe ( 'error' ) ;
538+ } ) ;
539+ test ( 'rejects a fourth argument' , ( ) => {
540+ const response = createExpression ( [ 'slice' , 'abc' , 0 , 1 , 8 ] ) ;
541+ expect ( response . result ) . toBe ( 'error' ) ;
542+ } ) ;
543+ test ( 'requires a string or array as the input argument' , ( ) => {
544+ const response = createExpression ( [ 'slice' , true , 0 ] ) ;
545+ expect ( response . result ) . toBe ( 'error' ) ;
546+ } ) ;
547+ test ( 'requires a number as the start index argument' , ( ) => {
548+ const response = createExpression ( [ 'slice' , 'abc' , true ] ) ;
549+ expect ( response . result ) . toBe ( 'error' ) ;
550+ } ) ;
551+ test ( 'slices an empty string' , ( ) => {
552+ const response = createExpression ( [ 'slice' , '' , 0 ] ) ;
553+ expect ( response . result ) . toBe ( 'success' ) ;
554+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( '' ) ;
555+ } ) ;
556+ test ( 'slices a string starting at the beginning' , ( ) => {
557+ const response = createExpression ( [ 'slice' , 'abc' , 0 ] ) ;
558+ expect ( response . result ) . toBe ( 'success' ) ;
559+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 'abc' ) ;
560+ } ) ;
561+ test ( 'slices a string starting at the middle' , ( ) => {
562+ const response = createExpression ( [ 'slice' , 'abc' , 1 ] ) ;
563+ expect ( response . result ) . toBe ( 'success' ) ;
564+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 'bc' ) ;
565+ } ) ;
566+ test ( 'slices a string starting at the end' , ( ) => {
567+ const response = createExpression ( [ 'slice' , 'abc' , 3 ] ) ;
568+ expect ( response . result ) . toBe ( 'success' ) ;
569+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( '' ) ;
570+ } ) ;
571+ test ( 'slices a string backwards from the end' , ( ) => {
572+ const response = createExpression ( [ 'slice' , 'abc' , - 2 ] ) ;
573+ expect ( response . result ) . toBe ( 'success' ) ;
574+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( 'bc' ) ;
575+ } ) ;
576+ test ( 'slices a string by a zero-length range' , ( ) => {
577+ const response = createExpression ( [ 'slice' , 'abc' , 1 , 1 ] ) ;
578+ expect ( response . result ) . toBe ( 'success' ) ;
579+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( '' ) ;
580+ } ) ;
581+ test ( 'slices a string by a negative-length range' , ( ) => {
582+ const response = createExpression ( [ 'slice' , 'abc' , 2 , 1 ] ) ;
583+ expect ( response . result ) . toBe ( 'success' ) ;
584+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( '' ) ;
585+ } ) ;
586+ test ( 'avoids splitting a non-ASCII character' , ( ) => {
587+ const response = createExpression ( [ 'slice' , '市镇' , 1 ] ) ;
588+ expect ( response . result ) . toBe ( 'success' ) ;
589+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( '镇' ) ;
590+ } ) ;
591+ test ( 'avoids splitting a surrogate pair' , ( ) => {
592+ const response = createExpression ( [ 'slice' , '丐𦨭市镇' , 2 ] ) ;
593+ expect ( response . result ) . toBe ( 'success' ) ;
594+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toBe ( '市镇' ) ;
595+ } ) ;
596+ test ( 'slices an empty array' , ( ) => {
597+ const response = createExpression ( [ 'slice' , [ 'literal' , [ ] ] , 0 ] ) ;
598+ expect ( response . result ) . toBe ( 'success' ) ;
599+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toEqual ( [ ] ) ;
600+ } ) ;
601+ test ( 'slices an array starting at the beginning' , ( ) => {
602+ const response = createExpression ( [ 'slice' , [ 'literal' , [ 1 , 2 , 3 ] ] , 0 ] ) ;
603+ expect ( response . result ) . toBe ( 'success' ) ;
604+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toEqual ( [ 1 , 2 , 3 ] ) ;
605+ } ) ;
606+ test ( 'slices an array starting at the middle' , ( ) => {
607+ const response = createExpression ( [ 'slice' , [ 'literal' , [ 1 , 2 , 3 ] ] , 1 ] ) ;
608+ expect ( response . result ) . toBe ( 'success' ) ;
609+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toEqual ( [ 2 , 3 ] ) ;
610+ } ) ;
611+ test ( 'slices an array starting at the end' , ( ) => {
612+ const response = createExpression ( [ 'slice' , [ 'literal' , [ 1 , 2 , 3 ] ] , 3 ] ) ;
613+ expect ( response . result ) . toBe ( 'success' ) ;
614+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toEqual ( [ ] ) ;
615+ } ) ;
616+ test ( 'slices an array backwards from the end' , ( ) => {
617+ const response = createExpression ( [ 'slice' , [ 'literal' , [ 1 , 2 , 3 ] ] , - 2 ] ) ;
618+ expect ( response . result ) . toBe ( 'success' ) ;
619+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toEqual ( [ 2 , 3 ] ) ;
620+ } ) ;
621+ test ( 'slices an array by a zero-length range' , ( ) => {
622+ const response = createExpression ( [ 'slice' , [ 'literal' , [ 1 , 2 , 3 ] ] , 1 , 1 ] ) ;
623+ expect ( response . result ) . toBe ( 'success' ) ;
624+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toEqual ( [ ] ) ;
625+ } ) ;
626+ test ( 'slices an array by a negative-length range' , ( ) => {
627+ const response = createExpression ( [ 'slice' , [ 'literal' , [ 1 , 2 , 3 ] ] , 2 , 1 ] ) ;
628+ expect ( response . result ) . toBe ( 'success' ) ;
629+ expect ( ( response . value as StyleExpression ) ?. evaluate ( { zoom : 20 } ) ) . toEqual ( [ ] ) ;
630+ } ) ;
631+ } ) ;
0 commit comments