Ruby tests were a nice way to start, and it was nice to borrow some from
selecta. However, it's going to be much easier to write tests in the
same language as the implementation.
| ... | ... |
@@ -1,12 +1,12 @@ |
| 1 | 1 |
CFLAGS+=-Wall -Wextra -g -std=c99 |
| 2 | 2 |
|
| 3 |
-all: fzy testscore |
|
| 3 |
+all: fzy fzytest |
|
| 4 | 4 |
|
| 5 |
-testscore: testscore.o match.o |
|
| 5 |
+fzytest: fzytest.o match.o |
|
| 6 | 6 |
$(CC) $(CCFLAGS) -o $@ $^ |
| 7 | 7 |
|
| 8 |
-test: testscore |
|
| 9 |
- ruby test.rb |
|
| 8 |
+test: fzytest |
|
| 9 |
+ -./fzytest |
|
| 10 | 10 |
|
| 11 | 11 |
fzy: fzy.o match.o |
| 12 | 12 |
$(CC) $(CCFLAGS) -o $@ $^ |
| ... | ... |
@@ -15,4 +15,6 @@ fzy: fzy.o match.o |
| 15 | 15 |
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< |
| 16 | 16 |
|
| 17 | 17 |
clean: |
| 18 |
- $(RM) fzy testscore *.o |
|
| 18 |
+ $(RM) fzy fzytest *.o |
|
| 19 |
+ |
|
| 20 |
+.PHONY: test all clean |
| 19 | 21 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,42 @@ |
| 1 |
+#include <stdio.h> |
|
| 2 |
+#include "fzy.h" |
|
| 3 |
+ |
|
| 4 |
+const char *testname; |
|
| 5 |
+int testsrun = 0, testspassed = 0; |
|
| 6 |
+ |
|
| 7 |
+#define TEST(name) int test_##name(){ testname = #name; testsrun++; do
|
|
| 8 |
+#define ENDTEST while(0); testspassed++; return 0;} |
|
| 9 |
+#define assert(x) if(!(x)){fprintf(stderr, "test \"%s\" failed\n assert(%s) was false\n at %s:%i\n\n", testname, #x, __FILE__ ,__LINE__);return -1;}
|
|
| 10 |
+ |
|
| 11 |
+TEST(match){
|
|
| 12 |
+ assert(has_match("a", "a"));
|
|
| 13 |
+ assert(has_match("a", "ab"));
|
|
| 14 |
+ assert(has_match("a", "ba"));
|
|
| 15 |
+ assert(has_match("abc", "a|b|c"));
|
|
| 16 |
+ |
|
| 17 |
+ /* non-match */ |
|
| 18 |
+ assert(!has_match("a", ""));
|
|
| 19 |
+ assert(!has_match("a", "b"));
|
|
| 20 |
+ |
|
| 21 |
+ /* match when query is empty */ |
|
| 22 |
+ assert(has_match("", ""));
|
|
| 23 |
+ assert(has_match("", "a"));
|
|
| 24 |
+}ENDTEST |
|
| 25 |
+ |
|
| 26 |
+TEST(scoring){
|
|
| 27 |
+ assert(match("amo", "app/models/foo") < match("amo", "app/models/order"));
|
|
| 28 |
+}ENDTEST |
|
| 29 |
+ |
|
| 30 |
+void summary(){
|
|
| 31 |
+ printf("%i tests run: %i passed %i failed\n", testsrun, testspassed, testsrun - testspassed);
|
|
| 32 |
+} |
|
| 33 |
+ |
|
| 34 |
+int main(int argc, char *argv[]){
|
|
| 35 |
+ test_match(); |
|
| 36 |
+ test_scoring(); |
|
| 37 |
+ |
|
| 38 |
+ summary(); |
|
| 39 |
+ |
|
| 40 |
+ /* exit 0 if all tests pass */ |
|
| 41 |
+ return testsrun != testspassed; |
|
| 42 |
+} |
| 0 | 43 |
deleted file mode 100644 |
| ... | ... |
@@ -1,54 +0,0 @@ |
| 1 |
-require "minitest/autorun" |
|
| 2 |
- |
|
| 3 |
-# Largely borrowed from selecta |
|
| 4 |
-describe "score" do |
|
| 5 |
- def score(candidate, query) |
|
| 6 |
- # FIXME: should escape this properly |
|
| 7 |
- ret = `./testscore '#{query}' '#{candidate}'`
|
|
| 8 |
- ret.to_f unless ret.empty? |
|
| 9 |
- end |
|
| 10 |
- |
|
| 11 |
- def assert_unmatched(candidate, query) |
|
| 12 |
- assert_equal nil, score(candidate, query) |
|
| 13 |
- end |
|
| 14 |
- |
|
| 15 |
- def assert_matched(candidate, query) |
|
| 16 |
- assert_operator 0, :<=, score(candidate, query) |
|
| 17 |
- end |
|
| 18 |
- |
|
| 19 |
- it "scores 1 when the query is empty" do |
|
| 20 |
- assert_equal 1, score("a", "")
|
|
| 21 |
- end |
|
| 22 |
- |
|
| 23 |
- it "scores 0 when the choice is empty" do |
|
| 24 |
- assert_unmatched "", "a" |
|
| 25 |
- end |
|
| 26 |
- |
|
| 27 |
- it "scores 1 when exact match" do |
|
| 28 |
- assert_equal 1, score("a", "a")
|
|
| 29 |
- end |
|
| 30 |
- |
|
| 31 |
- it "scores 0 when the query is longer than the choice" do |
|
| 32 |
- assert_unmatched "short", "longer" |
|
| 33 |
- end |
|
| 34 |
- |
|
| 35 |
- it "scores 0 when the query doesn't match at all" do |
|
| 36 |
- assert_unmatched "a", "b" |
|
| 37 |
- end |
|
| 38 |
- |
|
| 39 |
- it "scores 0 when only a prefix of the query matches" do |
|
| 40 |
- assert_unmatched "ab", "ac" |
|
| 41 |
- end |
|
| 42 |
- |
|
| 43 |
- it "scores greater than 0 when it matches" do |
|
| 44 |
- assert_matched "a", "a" |
|
| 45 |
- assert_matched "ab", "a" |
|
| 46 |
- assert_matched "ba", "a" |
|
| 47 |
- assert_matched "bab", "a" |
|
| 48 |
- assert_matched "bababababab", "aaaaa" |
|
| 49 |
- end |
|
| 50 |
- |
|
| 51 |
- it "prefers start of words" do |
|
| 52 |
- assert_operator score("app/models/foo", "amo"), :<, score("app/models/order", "amo")
|
|
| 53 |
- end |
|
| 54 |
-end |
| 55 | 0 |
deleted file mode 100644 |
| ... | ... |
@@ -1,22 +0,0 @@ |
| 1 |
-#include <stdlib.h> |
|
| 2 |
-#include <stdio.h> |
|
| 3 |
- |
|
| 4 |
-#include "fzy.h" |
|
| 5 |
-double match(const char *needle, const char *haystack); |
|
| 6 |
- |
|
| 7 |
-void usage(const char *argv0){
|
|
| 8 |
- fprintf(stderr, "USAGE: %s QUERY CANDIDATE\n", argv0); |
|
| 9 |
-} |
|
| 10 |
- |
|
| 11 |
-int main(int argc, char *argv[]){
|
|
| 12 |
- if(argc != 3){
|
|
| 13 |
- usage(argv[0]); |
|
| 14 |
- } |
|
| 15 |
- |
|
| 16 |
- if(has_match(argv[1], argv[2])){
|
|
| 17 |
- double result = match(argv[1], argv[2]); |
|
| 18 |
- printf("%f\n", result);
|
|
| 19 |
- } |
|
| 20 |
- |
|
| 21 |
- return 0; |
|
| 22 |
-} |