fzy

terminal fuzzy finder picker

git clone https://9o.is/git/fzy.git

test_choices.c

(3957B)


      1 #define _GNU_SOURCE
      2 #include <stdlib.h>
      3 #include <string.h>
      4 
      5 #include "../config.h"
      6 #include "options.h"
      7 #include "choices.h"
      8 
      9 #include "greatest/greatest.h"
     10 
     11 #define ASSERT_SIZE_T_EQ(a,b) ASSERT_EQ_FMT((size_t)(a), (b), "%zu")
     12 
     13 static options_t default_options;
     14 static choices_t choices;
     15 
     16 static void setup(void *udata) {
     17     (void)udata;
     18 
     19     options_init(&default_options);
     20     choices_init(&choices, &default_options);
     21 }
     22 
     23 static void teardown(void *udata) {
     24     (void)udata;
     25     choices_destroy(&choices);
     26 }
     27 
     28 TEST test_choices_empty() {
     29 	ASSERT_SIZE_T_EQ(0, choices.size);
     30 	ASSERT_SIZE_T_EQ(0, choices.available);
     31 	ASSERT_SIZE_T_EQ(0, choices.selection);
     32 
     33 	choices_prev(&choices);
     34 	ASSERT_SIZE_T_EQ(0, choices.selection);
     35 
     36 	choices_next(&choices);
     37 	ASSERT_SIZE_T_EQ(0, choices.selection);
     38 
     39 	PASS();
     40 }
     41 
     42 TEST test_choices_1() {
     43 	choices_add(&choices, "tags");
     44 
     45 	choices_search(&choices, "");
     46 	ASSERT_SIZE_T_EQ(1, choices.available);
     47 	ASSERT_SIZE_T_EQ(0, choices.selection);
     48 
     49 	choices_search(&choices, "t");
     50 	ASSERT_SIZE_T_EQ(1, choices.available);
     51 	ASSERT_SIZE_T_EQ(0, choices.selection);
     52 
     53 	choices_prev(&choices);
     54 	ASSERT_SIZE_T_EQ(0, choices.selection);
     55 
     56 	choices_next(&choices);
     57 	ASSERT_SIZE_T_EQ(0, choices.selection);
     58 
     59 	ASSERT(!strcmp(choices_get(&choices, 0), "tags"));
     60 	ASSERT_EQ(NULL, choices_get(&choices, 1));
     61 
     62 	PASS();
     63 }
     64 
     65 TEST test_choices_2() {
     66 	choices_add(&choices, "tags");
     67 	choices_add(&choices, "test");
     68 
     69 	/* Empty search */
     70 	choices_search(&choices, "");
     71 	ASSERT_SIZE_T_EQ(0, choices.selection);
     72 	ASSERT_SIZE_T_EQ(2, choices.available);
     73 
     74 	choices_next(&choices);
     75 	ASSERT_SIZE_T_EQ(1, choices.selection);
     76 	choices_next(&choices);
     77 	ASSERT_SIZE_T_EQ(0, choices.selection);
     78 
     79 	choices_prev(&choices);
     80 	ASSERT_SIZE_T_EQ(1, choices.selection);
     81 	choices_prev(&choices);
     82 	ASSERT_SIZE_T_EQ(0, choices.selection);
     83 
     84 	/* Filtered search */
     85 	choices_search(&choices, "te");
     86 	ASSERT_SIZE_T_EQ(1, choices.available);
     87 	ASSERT_SIZE_T_EQ(0, choices.selection);
     88 	ASSERT_STR_EQ("test", choices_get(&choices, 0));
     89 
     90 	choices_next(&choices);
     91 	ASSERT_SIZE_T_EQ(0, choices.selection);
     92 
     93 	choices_prev(&choices);
     94 	ASSERT_SIZE_T_EQ(0, choices.selection);
     95 
     96 	/* No results */
     97 	choices_search(&choices, "foobar");
     98 	ASSERT_SIZE_T_EQ(0, choices.available);
     99 	ASSERT_SIZE_T_EQ(0, choices.selection);
    100 
    101 	/* Different order due to scoring */
    102 	choices_search(&choices, "ts");
    103 	ASSERT_SIZE_T_EQ(2, choices.available);
    104 	ASSERT_SIZE_T_EQ(0, choices.selection);
    105 	ASSERT_STR_EQ("test", choices_get(&choices, 0));
    106 	ASSERT_STR_EQ("tags", choices_get(&choices, 1));
    107 
    108 	PASS();
    109 }
    110 
    111 TEST test_choices_without_search() {
    112 	/* Before a search is run, it should return no results */
    113 
    114 	ASSERT_SIZE_T_EQ(0, choices.available);
    115 	ASSERT_SIZE_T_EQ(0, choices.selection);
    116 	ASSERT_SIZE_T_EQ(0, choices.size);
    117 	ASSERT_EQ(NULL, choices_get(&choices, 0));
    118 
    119 	choices_add(&choices, "test");
    120 
    121 	ASSERT_SIZE_T_EQ(0, choices.available);
    122 	ASSERT_SIZE_T_EQ(0, choices.selection);
    123 	ASSERT_SIZE_T_EQ(1, choices.size);
    124 	ASSERT_EQ(NULL, choices_get(&choices, 0));
    125 
    126 	PASS();
    127 }
    128 
    129 /* Regression test for segfault */
    130 TEST test_choices_unicode() {
    131 	choices_add(&choices, "Edmund Husserl - Méditations cartésiennes - Introduction a la phénoménologie.pdf");
    132 	choices_search(&choices, "e");
    133 
    134 	PASS();
    135 }
    136 
    137 TEST test_choices_large_input() {
    138 	const int N = 100000;
    139 	char *strings[100000];
    140 
    141 	for(int i = 0; i < N; i++) {
    142 		asprintf(&strings[i], "%i", i);
    143 		choices_add(&choices, strings[i]);
    144 	}
    145 
    146 	choices_search(&choices, "12");
    147 
    148 	/* Must match `seq 0 99999 | grep '.*1.*2.*' | wc -l` */
    149 	ASSERT_SIZE_T_EQ(8146, choices.available);
    150 
    151 	ASSERT_STR_EQ("12", choices_get(&choices, 0));
    152 
    153 	for(int i = 0; i < N; i++) {
    154 		free(strings[i]);
    155 	}
    156 
    157 	PASS();
    158 }
    159 
    160 SUITE(choices_suite) {
    161 	SET_SETUP(setup, NULL);
    162 	SET_TEARDOWN(teardown, NULL);
    163 
    164 	RUN_TEST(test_choices_empty);
    165 	RUN_TEST(test_choices_1);
    166 	RUN_TEST(test_choices_2);
    167 	RUN_TEST(test_choices_without_search);
    168 	RUN_TEST(test_choices_unicode);
    169 	RUN_TEST(test_choices_large_input);
    170 }