summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hawthorn <john.hawthorn@gmail.com>2014-07-12 15:07:22 -0700
committerJohn Hawthorn <john.hawthorn@gmail.com>2014-07-12 15:17:04 -0700
commitafeeb5bb458042c353573c2b2f464d35123e5aad (patch)
tree5e81c336692403148e8d77c915f066191d66ae2a
parente550feae6dd230ceff8ebaab91f7e41ea333d1c7 (diff)
Add tests and split matching into match.c
-rw-r--r--.gitignore1
-rw-r--r--Makefile17
-rw-r--r--fzy.c11
-rw-r--r--match.c12
-rw-r--r--test.rb41
-rw-r--r--testscore.c20
6 files changed, 87 insertions, 15 deletions
diff --git a/.gitignore b/.gitignore
index 5bae2fa..f54609d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
fzy
+testscore
*.o
diff --git a/Makefile b/Makefile
index 7944bcb..974332c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,15 @@
-LIBS=
CFLAGS+=-Wall -Wextra -g
-TARGET=fzy
-OBJECTS=fzy.o
-$(TARGET): $(OBJECTS)
- $(CC) $(CCFLAGS) -o $@ $^ $(LIBS)
+all: fzy testscore
+
+testscore: testscore.o match.o
+ $(CC) $(CCFLAGS) -o $@ $^
+
+test: testscore
+ ruby test.rb
+
+fzy: fzy.o match.o
+ $(CC) $(CCFLAGS) -o $@ $^
clean:
- $(RM) $(TARGET) *.o
+ $(RM) fzy testscore *.o
diff --git a/fzy.c b/fzy.c
index fc6dd3d..06a3717 100644
--- a/fzy.c
+++ b/fzy.c
@@ -7,15 +7,8 @@
#include <fcntl.h>
#include <ctype.h>
-double match(const char *needle, const char *haystack){
- while(*needle){
- if(!*haystack)
- return 0.0;
- while(tolower(*needle) == tolower(*haystack++))
- needle++;
- }
- return 1.0;
-}
+/* from match.c */
+double match(const char *needle, const char *haystack);
#define INITIAL_CAPACITY 1
int choices_capacity = 0;
diff --git a/match.c b/match.c
new file mode 100644
index 0000000..dc79660
--- /dev/null
+++ b/match.c
@@ -0,0 +1,12 @@
+#include <ctype.h>
+
+double match(const char *needle, const char *haystack){
+ while(*needle){
+ if(!*haystack)
+ return 0.0;
+ while(*haystack && tolower(*needle) == tolower(*haystack++)){
+ needle++;
+ }
+ }
+ return 1.0;
+}
diff --git a/test.rb b/test.rb
new file mode 100644
index 0000000..6b92faf
--- /dev/null
+++ b/test.rb
@@ -0,0 +1,41 @@
+require "minitest/autorun"
+
+# Largely borrowed from selecta
+describe "score" do
+ def score(candidate, query)
+ # FIXME: should escape this properly
+ `./testscore '#{query}' '#{candidate}'`.to_f
+ end
+
+ it "scores 1 when the query is empty" do
+ assert_equal 1, score("a", "")
+ end
+
+ it "scores 0 when the choice is empty" do
+ assert_equal 0, score("", "a")
+ end
+
+ it "scores 1 when exact match" do
+ assert_equal 1, score("a", "a")
+ end
+
+ it "scores 0 when the query is longer than the choice" do
+ assert_equal 0, score("short", "longer")
+ end
+
+ it "scores 0 when the query doesn't match at all" do
+ assert_equal 0, score("a", "b")
+ end
+
+ it "scores 0 when only a prefix of the query matches" do
+ assert_equal 0, score("ab", "ac")
+ end
+
+ it "scores greater than 0 when it matches" do
+ assert_operator 0, :<, score("a", "a")
+ assert_operator 0, :<, score("ab", "a")
+ assert_operator 0, :<, score("ba", "a")
+ assert_operator 0, :<, score("bab", "a")
+ assert_operator 0, :<, score("babababab", "aaaa")
+ end
+end
diff --git a/testscore.c b/testscore.c
new file mode 100644
index 0000000..6ce3aea
--- /dev/null
+++ b/testscore.c
@@ -0,0 +1,20 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+/* from match.c */
+double match(const char *needle, const char *haystack);
+
+void usage(const char *argv0){
+ fprintf(stderr, "USAGE: %s QUERY CANDIDATE\n", argv0);
+}
+
+int main(int argc, char *argv[]){
+ if(argc != 3){
+ usage(argv[0]);
+ }
+
+ double result = match(argv[1], argv[2]);
+ printf("%f\n", result);
+
+ return 0;
+}