406 lines
15 KiB
Plaintext
406 lines
15 KiB
Plaintext
# 2012 July 12
|
|
#
|
|
# The author disclaims copyright to this source code. In place of
|
|
# a legal notice, here is a blessing:
|
|
#
|
|
# May you do good and not evil.
|
|
# May you find forgiveness for yourself and forgive others.
|
|
# May you share freely, never taking more than you give.
|
|
#
|
|
#***********************************************************************
|
|
#
|
|
|
|
set testdir [file dirname $argv0]
|
|
source $testdir/tester.tcl
|
|
set testprefix spellfix
|
|
|
|
ifcapable !vtab { finish_test ; return }
|
|
|
|
load_static_extension db spellfix nextchar
|
|
|
|
set vocab {
|
|
rabbi rabbit rabbits rabble rabid rabies raccoon raccoons race raced racer
|
|
racers races racetrack racial racially racing rack racked racket racketeer
|
|
racketeering racketeers rackets racking racks radar radars radial radially
|
|
radian radiance radiant radiantly radiate radiated radiates radiating radiation
|
|
radiations radiator radiators radical radically radicals radices radii radio
|
|
radioactive radioastronomy radioed radiography radioing radiology radios radish
|
|
radishes radium radius radix radon raft rafter rafters rafts rag rage raged
|
|
rages ragged raggedly raggedness raging rags ragweed raid raided raider raiders
|
|
raiding raids rail railed railer railers railing railroad railroaded railroader
|
|
railroaders railroading railroads rails railway railways raiment rain rainbow
|
|
raincoat raincoats raindrop raindrops rained rainfall rainier rainiest raining
|
|
rains rainstorm rainy raise raised raiser raisers raises raisin raising rake
|
|
raked rakes raking rallied rallies rally rallying ram ramble rambler rambles
|
|
rambling ramblings ramification ramifications ramp rampage rampant rampart
|
|
ramps ramrod rams ran ranch ranched rancher ranchers ranches ranching rancid
|
|
random randomization randomize randomized randomizes randomly randomness randy
|
|
rang range ranged rangeland ranger rangers ranges ranging rangy rank ranked
|
|
ranker rankers rankest ranking rankings rankle rankly rankness ranks ransack
|
|
ransacked ransacking ransacks ransom ransomer ransoming ransoms rant ranted
|
|
ranter ranters ranting rants rap rapacious rape raped raper rapes rapid
|
|
rapidity rapidly rapids rapier raping rapport rapprochement raps rapt raptly
|
|
rapture raptures rapturous rare rarely rareness rarer rarest rarity rascal
|
|
rascally rascals rash rasher rashly rashness rasp raspberry rasped rasping
|
|
rasps raster rat rate rated rater raters rates rather ratification ratified
|
|
ratifies ratify ratifying rating ratings ratio ration rational rationale
|
|
rationales rationalities rationality rationalization rationalizations
|
|
rationalize rationalized rationalizes rationalizing rationally rationals
|
|
rationing rations ratios rats rattle rattled rattler rattlers rattles
|
|
rattlesnake rattlesnakes rattling raucous ravage ravaged ravager ravagers
|
|
ravages ravaging rave raved raven ravening ravenous ravenously ravens raves
|
|
ravine ravines raving ravings raw rawer rawest rawly rawness ray rays raze
|
|
razor razors re reabbreviate reabbreviated reabbreviates reabbreviating reach
|
|
reachability reachable reachably reached reacher reaches reaching reacquired
|
|
react reacted reacting reaction reactionaries reactionary reactions reactivate
|
|
reactivated reactivates reactivating reactivation reactive reactively
|
|
reactivity reactor reactors reacts read readability readable reader readers
|
|
readied readier readies readiest readily readiness reading readings readjusted
|
|
readout readouts reads ready readying real realest realign realigned realigning
|
|
realigns realism realist realistic realistically realists realities reality
|
|
}
|
|
|
|
do_test 1.1 {
|
|
execsql { CREATE VIRTUAL TABLE t1 USING spellfix1 }
|
|
foreach word $vocab {
|
|
execsql { INSERT INTO t1(word) VALUES($word) }
|
|
}
|
|
} {}
|
|
|
|
foreach {tn word res} {
|
|
1 raxpi* {rasping 5 rasped 5 ragweed 5 raspberry 6 rasp 4}
|
|
2 ril* {rail 4 railed 4 railer 4 railers 4 railing 4}
|
|
3 rilis* {realism 6 realist 6 realistic 6 realistically 6 realists 6}
|
|
4 reail* {real 3 realest 3 realign 3 realigned 3 realigning 3}
|
|
5 ras* {rascal 3 rascally 3 rascals 3 rash 3 rasher 3}
|
|
6 realistss* {realists 8 realigns 8 realistic 9 realistically 9 realest 7}
|
|
7 realistss {realists 8 realist 7 realigns 8 realistic 9 realest 7}
|
|
8 rllation* {realities 9 reality 7 rallied 7 railed 4}
|
|
9 renstom* {rainstorm 8 ransom 6 ransomer 6 ransoming 6 ransoms 6}
|
|
} {
|
|
do_execsql_test 1.2.$tn {
|
|
SELECT word, matchlen FROM t1 WHERE word MATCH $word
|
|
ORDER BY score, word LIMIT 5
|
|
} $res
|
|
}
|
|
|
|
# Tests of the next_char function.
|
|
#
|
|
do_test 1.10 {
|
|
db eval {
|
|
CREATE TABLE vocab(w TEXT PRIMARY KEY);
|
|
INSERT INTO vocab SELECT word FROM t1;
|
|
}
|
|
} {}
|
|
do_execsql_test 1.11 {
|
|
SELECT next_char('re','vocab','w');
|
|
} {a}
|
|
do_execsql_test 1.11sub {
|
|
SELECT next_char('re','(SELECT w AS x FROM vocab)','x');
|
|
} {a}
|
|
do_execsql_test 1.12 {
|
|
SELECT next_char('r','vocab','w');
|
|
} {ae}
|
|
do_execsql_test 1.13 {
|
|
SELECT next_char('','vocab','w');
|
|
} {r}
|
|
do_test 1.14 {
|
|
catchsql {SELECT next_char('','xyzzy','a')}
|
|
} {1 {no such table: xyzzy}}
|
|
|
|
do_execsql_test 1.20 {
|
|
CREATE TABLE vocab2(w TEXT);
|
|
CREATE INDEX vocab2w ON vocab2(w COLLATE nocase);
|
|
INSERT INTO vocab2 VALUES('abc'), ('ABD'), ('aBe'), ('AbF');
|
|
SELECT next_char('ab', 'vocab2', 'w', null, 'nocase');
|
|
} {cDeF}
|
|
do_execsql_test 1.21 {
|
|
SELECT next_char('ab','vocab2','w',null,null);
|
|
} {c}
|
|
do_execsql_test 1.22 {
|
|
SELECT next_char('AB','vocab2','w',null,'NOCASE');
|
|
} {cDeF}
|
|
do_execsql_test 1.23 {
|
|
SELECT next_char('ab','vocab2','w',null,'binary');
|
|
} {c}
|
|
|
|
do_execsql_test 1.30 {
|
|
SELECT rowid FROM t1 WHERE word='rabbit';
|
|
} {2}
|
|
do_execsql_test 1.31 {
|
|
UPDATE t1 SET rowid=2000 WHERE word='rabbit';
|
|
SELECT rowid FROM t1 WHERE word='rabbit';
|
|
} {2000}
|
|
do_execsql_test 1.32 {
|
|
INSERT INTO t1(rowid, word) VALUES(3000,'melody');
|
|
SELECT rowid, word, matchlen FROM t1 WHERE word MATCH 'melotti'
|
|
ORDER BY score LIMIT 3;
|
|
} {3000 melody 6}
|
|
do_test 1.33 {
|
|
catchsql {INSERT INTO t1(rowid, word) VALUES(3000,'garden');}
|
|
} {1 {constraint failed}}
|
|
|
|
do_execsql_test 2.1 {
|
|
CREATE VIRTUAL TABLE t2 USING spellfix1;
|
|
INSERT INTO t2 (word, soundslike) VALUES('school', 'skuul');
|
|
INSERT INTO t2 (word, soundslike) VALUES('psalm', 'sarm');
|
|
SELECT word, matchlen FROM t2 WHERE word MATCH 'sar*' LIMIT 5;
|
|
} {psalm 4}
|
|
|
|
do_execsql_test 2.2 {
|
|
SELECT word, matchlen FROM t2 WHERE word MATCH 'skol*' LIMIT 5;
|
|
} {school 6}
|
|
|
|
set vocab {
|
|
kangaroo kanji kappa karate keel keeled keeling keels keen keener keenest
|
|
keenly keenness keep keeper keepers keeping keeps ken kennel kennels kept
|
|
kerchief kerchiefs kern kernel kernels kerosene ketchup kettle
|
|
kettles key keyboard keyboards keyed keyhole keying keynote keypad keypads keys
|
|
keystroke keystrokes keyword keywords kick kicked kicker kickers kicking
|
|
kickoff kicks kid kidded kiddie kidding kidnap kidnapper kidnappers kidnapping
|
|
kidnappings kidnaps kidney kidneys kids kill killed killer killers killing
|
|
killingly killings killjoy kills kilobit kilobits kiloblock kilobyte kilobytes
|
|
kilogram kilograms kilohertz kilohm kilojoule kilometer kilometers kiloton
|
|
kilovolt kilowatt kiloword kimono kin kind kinder kindergarten kindest
|
|
kindhearted kindle kindled kindles kindling kindly kindness kindred kinds
|
|
kinetic king kingdom kingdoms kingly kingpin kings kink kinky kinship kinsman
|
|
kiosk kiss kissed kisser kissers kisses kissing kit kitchen kitchenette
|
|
kitchens kite kited kites kiting kits kitten kittenish kittens kitty klaxon
|
|
kludge kludges klystron knack knapsack knapsacks knave knaves knead kneads knee
|
|
kneecap kneed kneeing kneel kneeled kneeling kneels knees knell knells knelt
|
|
knew knife knifed knifes knifing knight knighted knighthood knighting knightly
|
|
knights knit knits knives knob knobs knock knockdown knocked knocker knockers
|
|
knocking knockout knocks knoll knolls knot knots knotted knotting know knowable
|
|
knower knowhow knowing knowingly knowledge knowledgeable known knows knuckle
|
|
knuckled knuckles koala kosher kudo
|
|
}
|
|
|
|
do_execsql_test 3.1 {
|
|
CREATE TABLE costs(iLang, cFrom, cTo, iCost);
|
|
INSERT INTO costs VALUES(0, 'a', 'e', 1);
|
|
INSERT INTO costs VALUES(0, 'e', 'i', 1);
|
|
INSERT INTO costs VALUES(0, 'i', 'o', 1);
|
|
INSERT INTO costs VALUES(0, 'o', 'u', 1);
|
|
INSERT INTO costs VALUES(0, 'u', 'a', 1);
|
|
CREATE VIRTUAL TABLE t3 USING spellfix1(edit_cost_table=costs);
|
|
}
|
|
|
|
do_test 3.2 {
|
|
foreach w $vocab {
|
|
execsql { INSERT INTO t3(word) VALUES($w) }
|
|
}
|
|
} {}
|
|
|
|
foreach {tn word res} {
|
|
1 kos* {kosher 3 kiosk 4 kudo 2 kiss 3 kissed 3}
|
|
2 kellj* {killjoy 5 kill 4 killed 4 killer 4 killers 4}
|
|
3 kellj {kill 4 kills 5 killjoy 7 keel 4 killed 6}
|
|
} {
|
|
do_execsql_test 3.2.$tn {
|
|
SELECT word, matchlen FROM t3 WHERE word MATCH $word
|
|
ORDER BY score, word LIMIT 5
|
|
} $res
|
|
}
|
|
|
|
do_execsql_test 4.0 {
|
|
INSERT INTO t3(command) VALUES('edit_cost_table=NULL');
|
|
}
|
|
foreach {tn word res} {
|
|
1 kosher {kosher 0 kisser 51 kissers 76 kissed 126 kisses 126}
|
|
2 kellj {keels 60 killjoy 68 kills 80 keel 120 kill 125}
|
|
3 kashar {kosher 80 kisser 91 kissers 116 kissed 166 kisses 166}
|
|
} {
|
|
do_execsql_test 4.1.$tn {
|
|
SELECT word, distance FROM t3 WHERE word MATCH $word
|
|
ORDER BY score, word LIMIT 5
|
|
} $res
|
|
}
|
|
do_execsql_test 5.0 {
|
|
CREATE TABLE costs2(iLang, cFrom, cTo, iCost);
|
|
INSERT INTO costs2 VALUES(0, 'a', 'o', 1);
|
|
INSERT INTO costs2 VALUES(0, 'e', 'o', 4);
|
|
INSERT INTO costs2 VALUES(0, 'i', 'o', 8);
|
|
INSERT INTO costs2 VALUES(0, 'u', 'o', 16);
|
|
INSERT INTO t3(command) VALUES('edit_cost_table="costs2"');
|
|
}
|
|
|
|
foreach {tn word res} {
|
|
1 kasher {kosher 1}
|
|
2 kesher {kosher 4}
|
|
3 kisher {kosher 8}
|
|
4 kosher {kosher 0}
|
|
5 kusher {kosher 16}
|
|
} {
|
|
do_execsql_test 5.1.$tn {
|
|
SELECT word, distance FROM t3 WHERE word MATCH $word
|
|
ORDER BY score, word LIMIT 1
|
|
} $res
|
|
}
|
|
|
|
#-------------------------------------------------------------------------
|
|
# Try some queries by rowid.
|
|
#
|
|
do_execsql_test 6.1.1 {
|
|
SELECT word FROM t3 WHERE rowid = 10;
|
|
} {keener}
|
|
do_execsql_test 6.1.2 {
|
|
SELECT word, distance FROM t3 WHERE rowid = 10;
|
|
} {keener {}}
|
|
do_execsql_test 6.1.3 {
|
|
SELECT word, distance FROM t3 WHERE rowid = 10 AND word MATCH 'kiiner';
|
|
} {keener 300}
|
|
|
|
ifcapable trace {
|
|
proc trace_callback {sql} {
|
|
if {[string range $sql 0 2] == "-- "} {
|
|
lappend ::trace [string range $sql 3 end]
|
|
}
|
|
}
|
|
|
|
proc do_tracesql_test {tn sql {res {}}} {
|
|
set ::trace [list]
|
|
uplevel [list do_test $tn [subst -nocommands {
|
|
set vals [execsql {$sql}]
|
|
concat [set vals] [set ::trace]
|
|
}] [list {*}$res]]
|
|
}
|
|
|
|
db trace trace_callback
|
|
do_tracesql_test 6.2.1 {
|
|
SELECT word FROM t3 WHERE rowid = 10;
|
|
} {keener
|
|
{SELECT word, rank, NULL, langid, id FROM "main"."t3_vocab" WHERE rowid=?}
|
|
}
|
|
do_tracesql_test 6.2.2 {
|
|
SELECT word, distance FROM t3 WHERE rowid = 10;
|
|
} {keener {}
|
|
{SELECT word, rank, NULL, langid, id FROM "main"."t3_vocab" WHERE rowid=?}
|
|
}
|
|
do_tracesql_test 6.2.3 {
|
|
SELECT word, distance FROM t3 WHERE rowid = 10 AND word MATCH 'kiiner';
|
|
} {keener 300
|
|
{SELECT id, word, rank, coalesce(k1,word) FROM "main"."t3_vocab" WHERE langid=0 AND k2>=?1 AND k2<?2}
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------------------------
|
|
# Test that the spellfix1 table supports conflict handling (OR REPLACE
|
|
# and so on).
|
|
#
|
|
do_execsql_test 7.1 {
|
|
CREATE VIRTUAL TABLE t4 USING spellfix1;
|
|
PRAGMA table_info = t4;
|
|
} {
|
|
0 word {} 0 {} 0
|
|
1 rank {} 0 {} 0
|
|
2 distance {} 0 {} 0
|
|
3 langid {} 0 {} 0
|
|
4 score {} 0 {} 0
|
|
5 matchlen {} 0 {} 0
|
|
}
|
|
|
|
do_execsql_test 7.2.1 {
|
|
INSERT INTO t4(rowid, word) VALUES(1, 'Archilles');
|
|
INSERT INTO t4(rowid, word) VALUES(2, 'Pluto');
|
|
INSERT INTO t4(rowid, word) VALUES(3, 'Atrides');
|
|
INSERT OR REPLACE INTO t4(rowid, word) VALUES(2, 'Apollo');
|
|
SELECT rowid, word FROM t4;
|
|
} {
|
|
1 Archilles 2 Apollo 3 Atrides
|
|
}
|
|
do_catchsql_test 7.2.2 {
|
|
INSERT OR ABORT INTO t4(rowid, word) VALUES(1, 'Leto');
|
|
} {1 {constraint failed}}
|
|
do_catchsql_test 7.2.3 {
|
|
INSERT OR ROLLBACK INTO t4(rowid, word) VALUES(3, 'Zeus');
|
|
} {1 {constraint failed}}
|
|
do_catchsql_test 7.2.4 {
|
|
INSERT OR FAIL INTO t4(rowid, word) VALUES(3, 'Zeus');
|
|
} {1 {constraint failed}}
|
|
do_execsql_test 7.2.5 {
|
|
INSERT OR IGNORE INTO t4(rowid, word) VALUES(3, 'Zeus');
|
|
SELECT rowid, word FROM t4;
|
|
} {
|
|
1 Archilles 2 Apollo 3 Atrides
|
|
}
|
|
|
|
do_execsql_test 7.3.1 {
|
|
UPDATE OR REPLACE t4 SET rowid=3 WHERE rowid=1;
|
|
SELECT rowid, word FROM t4;
|
|
} {2 Apollo 3 Archilles}
|
|
do_catchsql_test 7.3.2 {
|
|
UPDATE OR ABORT t4 SET rowid=3 WHERE rowid=2;
|
|
} {1 {constraint failed}}
|
|
do_catchsql_test 7.3.3 {
|
|
UPDATE OR ROLLBACK t4 SET rowid=3 WHERE rowid=2;
|
|
} {1 {constraint failed}}
|
|
do_catchsql_test 7.3.4 {
|
|
UPDATE OR FAIL t4 SET rowid=3 WHERE rowid=2;
|
|
} {1 {constraint failed}}
|
|
do_execsql_test 7.3.5 {
|
|
UPDATE OR IGNORE t4 SET rowid=3 WHERE rowid=2;
|
|
SELECT rowid, word FROM t4;
|
|
} {2 Apollo 3 Archilles}
|
|
|
|
do_execsql_test 7.4.1 {
|
|
DELETE FROM t4;
|
|
INSERT INTO t4(rowid, word) VALUES(10, 'Agamemnon');
|
|
INSERT INTO t4(rowid, word) VALUES(20, 'Patroclus');
|
|
INSERT INTO t4(rowid, word) VALUES(30, 'Chryses');
|
|
|
|
CREATE TABLE t5(i, w);
|
|
INSERT INTO t5 VALUES(5, 'Poseidon');
|
|
INSERT INTO t5 VALUES(20, 'Chronos');
|
|
INSERT INTO t5 VALUES(30, 'Hera');
|
|
}
|
|
|
|
db_save_and_close
|
|
foreach {tn conflict err bRollback res} {
|
|
0 "" {1 {constraint failed}} 0
|
|
{10 Agamemnon 20 Patroclus 30 Chryses}
|
|
1 "OR REPLACE" {0 {}} 0
|
|
{5 Poseidon 10 Agamemnon 20 Chronos 30 Hera}
|
|
2 "OR ABORT" {1 {constraint failed}} 0
|
|
{10 Agamemnon 20 Patroclus 30 Chryses}
|
|
3 "OR ROLLBACK" {1 {constraint failed}} 1
|
|
{10 Agamemnon 20 Patroclus 30 Chryses}
|
|
5 "OR IGNORE" {0 {}} 0
|
|
{5 Poseidon 10 Agamemnon 20 Patroclus 30 Chryses}
|
|
} {
|
|
db_restore_and_reopen
|
|
load_static_extension db spellfix nextchar
|
|
|
|
execsql BEGIN
|
|
set sql "INSERT $conflict INTO t4(rowid, word) SELECT i, w FROM t5"
|
|
do_catchsql_test 7.4.2.$tn.1 $sql $err
|
|
do_execsql_test 7.4.2.$tn.2 { SELECT rowid, word FROM t4 } $res
|
|
|
|
do_test 7.4.2.$tn.3 { sqlite3_get_autocommit db } $bRollback
|
|
catchsql ROLLBACK
|
|
}
|
|
|
|
foreach {tn conflict err bRollback res} {
|
|
0 "" {1 {constraint failed}} 0
|
|
{10 Agamemnon 20 Patroclus 30 Chryses}
|
|
1 "OR REPLACE" {0 {}} 0
|
|
{15 Agamemnon 45 Chryses}
|
|
2 "OR ABORT" {1 {constraint failed}} 0
|
|
{10 Agamemnon 20 Patroclus 30 Chryses}
|
|
3 "OR ROLLBACK" {1 {constraint failed}} 1
|
|
{10 Agamemnon 20 Patroclus 30 Chryses}
|
|
5 "OR IGNORE" {0 {}} 0
|
|
{15 Agamemnon 20 Patroclus 45 Chryses}
|
|
} {
|
|
db_restore_and_reopen
|
|
load_static_extension db spellfix nextchar
|
|
|
|
execsql BEGIN
|
|
set sql "UPDATE $conflict t4 SET rowid=rowid + (rowid/2)"
|
|
do_catchsql_test 7.5.2.$tn.1 $sql $err
|
|
do_execsql_test 7.5.2.$tn.2 { SELECT rowid, word FROM t4 } $res
|
|
do_test 7.5.2.$tn.3 { sqlite3_get_autocommit db } $bRollback
|
|
catchsql ROLLBACK
|
|
}
|
|
|
|
finish_test
|