DIRECTORY BasicTime USING [GetClockPulses, GMT, Pulses, PulsesToMicroseconds], Commander USING [Register, CommandProc], CommanderOps USING [ParseToList], Convert USING [AppendChar, RopeFromInt, IntFromRope, Error], IO, LoganBerry, PFS USING [Delete, PATH, PathFromRope, StreamOpen], PrintEnglish USING [IntToEnglish], Random USING [RandomStream, Create, ChooseInt], Rope USING [ROPE, Equal]; LoganBerryTest: CEDAR PROGRAM IMPORTS BasicTime, Commander, CommanderOps, Convert, IO, LoganBerry, PFS, PrintEnglish, Random, Rope ~ BEGIN ROPE: TYPE ~ Rope.ROPE; defaultDbFileName: ROPE ¬ "LoganBerry.df"; dbFileName: ROPE ¬ defaultDbFileName; database: LoganBerry.OpenDB ¬ LoganBerry.nullDB; rs: Random.RandomStream¬ Random.Create[range: 10000, seed: -1]; TestCase: TYPE = {create, enumerate, generate, deleteA, deleteB, rewriteA, rewriteB, replace, readRandom, checkData, closeAndOpen, bidirectionalGenerate, binaryData, invalidOps, buildIndices, compactA, compactB, generateSecondary}; dbSize: CARDINAL ¬ 1000; -- size of test database, should be less than 10000 numReads: CARDINAL ¬ 100; numDeletes: CARDINAL ¬ 10; numReplaces: CARDINAL ¬ 10; savedEntries: LIST OF LoganBerry.Entry; RunTest: PROC [n: TestCase, out: IO.STREAM ¬ NIL] RETURNS [failed: BOOLEAN ¬ FALSE] ~ { ENABLE LoganBerry.Error => { IF out # NIL THEN out.PutF["Error from LoganBerry: %g - %g\n", IO.atom[ec], IO.rope[explanation]]; failed ¬ TRUE; CONTINUE; }; start, stop: BasicTime.Pulses; avalue: LoganBerry.AttributeValue; entry: LoganBerry.Entry; cursor: LoganBerry.Cursor; schema: LoganBerry.SchemaInfo; i: INT; count: CARDINAL; start ¬ BasicTime.GetClockPulses[]; SELECT n FROM $create => { -- build a LoganBerry test database in random order newStream: IO.STREAM; filename: PFS.PATH; IF out # NIL THEN out.PutF1["Creating new test database with %g entries.\n", IO.int[dbSize]]; schema ¬ LoganBerry.Describe[db: database]; LoganBerry.Close[db: database]; filename ¬ PFS.PathFromRope[schema.logs.first.file]; newStream ¬ PFS.StreamOpen[fileName: filename, accessOptions: $create]; IO.PutChar[newStream, 377C]; IO.Close[newStream]; FOR i: LIST OF LoganBerry.IndexInfo ¬ schema.indices, i.rest WHILE i#NIL DO PFS.Delete[name: PFS.PathFromRope[i.first.file]]; ENDLOOP; < { IO.PutF[out, "Error from LoganBerry: %g - %g\n", IO.atom[ec], IO.rope[explanation]]; RETRY -- this statement added to original code; bombed out otherwise } ];>> database ¬ LoganBerry.Open[dbName: dbFileName ! LoganBerry.Error => IF ec=$BadIndex THEN RETRY]; LoganBerry.BuildIndices[db: database]; MarkKeysUnused[1, dbSize]; THROUGH [1..dbSize] DO i ¬ GenerateUnusedKey[1, dbSize]; entry ¬ LIST[[$Integer, Convert.RopeFromInt[i]], [$Rope, PrintEnglish.IntToEnglish[i]]]; LoganBerry.WriteEntry[db: database, entry: entry]; ENDLOOP; }; $enumerate => { -- enumerate the database to get the number of entries AddOne: LoganBerry.EntryProc = { count ¬ count + 1; RETURN[TRUE]; }; IF out # NIL THEN out.PutRope["Enumerating entries.\n"]; count ¬ 0; LoganBerry.EnumerateEntries[db: database, key: $Integer, proc: AddOne]; IF count # dbSize AND out # NIL THEN out.PutRope["Warning: count # standard database size.\n"]; dbSize ¬ count; IF out # NIL THEN out.PutF1["Test database contains %g entries.\n", IO.card[dbSize]]; }; $generate => { -- generate the complete database and see if the number is correct IF out # NIL THEN out.PutRope["Generating entries.\n"]; count ¬ 0; cursor ¬ LoganBerry.GenerateEntries[db: database, key: $Integer]; entry ¬ LoganBerry.NextEntry[cursor: cursor]; UNTIL entry = NIL DO count ¬ count + 1; entry ¬ LoganBerry.NextEntry[cursor: cursor]; ENDLOOP; LoganBerry.EndGenerate[cursor: cursor]; IF count # dbSize THEN { IF out # NIL THEN out.PutRope["Error: count # database size.\n"]; failed ¬ TRUE; }; }; $generateSecondary => { -- generate the complete database using secondary index IF out # NIL THEN out.PutRope["Generating entries using secondary index.\n"]; count ¬ 0; cursor ¬ LoganBerry.GenerateEntries[db: database, key: $Rope]; entry ¬ LoganBerry.NextEntry[cursor: cursor]; UNTIL entry = NIL DO count ¬ count + 1; entry ¬ LoganBerry.NextEntry[cursor: cursor]; ENDLOOP; LoganBerry.EndGenerate[cursor: cursor]; IF count # dbSize THEN { IF out # NIL THEN out.PutRope["Error: count # database size.\n"]; failed ¬ TRUE; }; }; $deleteA => { -- delete some entries IF out # NIL THEN out.PutF1["Reading and deleting %g entries.\n", IO.card[numDeletes]]; MarkKeysUnused[1, dbSize]; savedEntries ¬ NIL; THROUGH [1..numDeletes] DO i ¬ GenerateUnusedKey[1, dbSize]; avalue ¬ Convert.RopeFromInt[i]; entry ¬ LoganBerry.ReadEntry[db: database, key: $Integer, value: avalue].entry; savedEntries ¬ CONS[entry, savedEntries]; LoganBerry.DeleteEntry[db: database, key: $Integer, value: avalue]; ENDLOOP; }; $deleteB => { -- verify that the deleted entries can not be read IF out # NIL THEN out.PutRope["Verifying deletes.\n"]; THROUGH [1..3] DO i ¬ GenerateUsedKey[1, dbSize]; avalue ¬ Convert.RopeFromInt[i]; IF LoganBerry.ReadEntry[db: database, key: $Integer, value: avalue].entry # NIL THEN { IF out # NIL THEN out.PutRope["Error: sucessfully read deleted entry.\n"]; failed ¬ TRUE; }; ENDLOOP; }; $rewriteA => { -- rewrite the deleted entries IF out # NIL THEN out.PutRope["Rewriting deleted entries.\n"]; WHILE savedEntries # NIL DO LoganBerry.WriteEntry[db: database, entry: savedEntries.first]; savedEntries ¬ savedEntries.rest; ENDLOOP; }; $rewriteB => { -- verify that the rewritten entries can be read IF out # NIL THEN out.PutRope["Verifying rewrites.\n"]; THROUGH [1..3] DO i ¬ GenerateUsedKey[1, dbSize]; avalue ¬ Convert.RopeFromInt[i]; IF LoganBerry.ReadEntry[db: database, key: $Integer, value: avalue].entry = NIL THEN { IF out # NIL THEN out.PutRope["Error: unable to read replaced entry.\n"]; failed ¬ TRUE; }; ENDLOOP; }; $readRandom => { -- read some random entries IF out # NIL THEN out.PutF1["Reading %g entries.\n", IO.card[numReads]]; THROUGH [1..numReads] DO i ¬ Random.ChooseInt[rs, 1, dbSize]; avalue ¬ Convert.RopeFromInt[i]; IF LoganBerry.ReadEntry[db: database, key: $Integer, value: avalue].entry = NIL THEN { IF out # NIL THEN out.PutF1["Error: unable to read entry #%g.\n", IO.rope[avalue]]; failed ¬ TRUE; }; ENDLOOP; }; $checkData => { -- check the consistency of the data IF out # NIL THEN out.PutRope["Checking data.\n"]; THROUGH [1..10] DO i ¬ Random.ChooseInt[rs, 1, dbSize]; avalue ¬ Convert.RopeFromInt[i]; entry ¬ LoganBerry.ReadEntry[db: database, key: $Integer, value: avalue].entry; avalue ¬ GetAttributeValue[entry, $Rope]; IF NOT Rope.Equal[avalue, PrintEnglish.IntToEnglish[i]] THEN { IF out # NIL THEN out.PutRope["Error: $Rope value # expected value.\n"]; failed ¬ TRUE; }; ENDLOOP; }; $replace => { -- replace some random entries (then restore to original values) replacement: LoganBerry.Entry; IF out # NIL THEN out.PutF1["Replacing (then restoring) %g entries.\n", IO.card[numReplaces]]; THROUGH [1..numReplaces] DO i ¬ Random.ChooseInt[rs, 1, dbSize]; avalue ¬ Convert.RopeFromInt[i]; entry ¬ LoganBerry.ReadEntry[db: database, key: $Integer, value: avalue].entry; replacement ¬ LIST[[$Integer, avalue], [$Rope, "replacement value"]]; LoganBerry.WriteEntry[db: database, entry: replacement, replace: TRUE]; replacement ¬ LoganBerry.ReadEntry[db: database, key: $Integer, value: avalue].entry; IF NOT Rope.Equal[GetAttributeValue[replacement, $Rope], "replacement value"] THEN { IF out # NIL THEN out.PutRope["Error: replacement $Rope value # expected value.\n"]; failed ¬ TRUE; }; LoganBerry.WriteEntry[db: database, entry: entry, replace: TRUE]; ENDLOOP; }; $closeAndOpen => { -- close and reopen the database caughtError: BOOLEAN ¬ FALSE; IF out # NIL THEN out.PutRope["Closing and reopening the database.\n"]; i ¬ Random.ChooseInt[rs, 1, dbSize]; avalue ¬ Convert.RopeFromInt[i]; LoganBerry.Close[db: database]; [] ¬ LoganBerry.ReadEntry[db: database, key: $Integer, value: avalue ! LoganBerry.Error => { caughtError ¬ TRUE; IF ec = $DBClosed THEN CONTINUE ELSE REJECT}; ]; IF caughtError THEN { IF out # NIL THEN out.PutRope["Error: database not reopened after close.\n"]; failed ¬ TRUE; }; database ¬ LoganBerry.Open[dbName: dbFileName]; IF LoganBerry.ReadEntry[db: database, key: $Integer, value: avalue].entry = NIL THEN { IF out # NIL THEN out.PutF1["Error: unable to read entry #%g.\n", IO.rope[avalue]]; failed ¬ TRUE; }; }; $bidirectionalGenerate => { -- generate a subrange of entries in both directions IF out # NIL THEN out.PutRope["Advanced test of generate.\n"]; i ¬ Random.ChooseInt[rs, 1, dbSize-10]; avalue ¬ Convert.RopeFromInt[i]; cursor ¬ LoganBerry.GenerateEntries[db: database, key: $Integer, start: avalue, end: Convert.RopeFromInt[i+9]]; count ¬ 0; entry ¬ LoganBerry.NextEntry[cursor: cursor]; UNTIL entry = NIL DO count ¬ count + 1; entry ¬ LoganBerry.NextEntry[cursor: cursor]; ENDLOOP; entry ¬ LoganBerry.NextEntry[cursor: cursor, dir: decreasing]; UNTIL entry = NIL DO count ¬ count - 1; entry ¬ LoganBerry.NextEntry[cursor: cursor, dir: decreasing]; ENDLOOP; IF count # 1 THEN { IF out # NIL THEN out.PutRope["Error: generated increasing/decreasing subrange of wrong size.\n"]; failed ¬ TRUE; }; LoganBerry.EndGenerate[cursor: cursor]; }; $compactA => { -- compact the database IF out # NIL THEN out.PutRope["Compacting log.\n"]; LoganBerry.CompactLogs[db: database]; }; $compactB => { -- verify that the compacted database has the correct number of entries IF out # NIL THEN out.PutRope["Counting number of entries.\n"]; count ¬ 0; cursor ¬ LoganBerry.GenerateEntries[db: database, key: $Integer]; entry ¬ LoganBerry.NextEntry[cursor: cursor]; UNTIL entry = NIL DO count ¬ count + 1; entry ¬ LoganBerry.NextEntry[cursor: cursor]; ENDLOOP; LoganBerry.EndGenerate[cursor: cursor]; IF count # dbSize THEN { IF out # NIL THEN out.PutF1["Error: count # database size. count = %g\n", IO.card[count]]; failed ¬ TRUE; }; }; $buildIndices => { -- rebuild the database indices IF out # NIL THEN out.PutRope["Rebuilding indices.\n"]; LoganBerry.BuildIndices[db: database]; }; $binaryData => { -- write and read strange values (then delete them) IF out # NIL THEN out.PutRope["Writing strange values and verifying them.\n"]; avalue ¬ "CR\r in value"; entry ¬ LIST[[$Integer, "0"], [$Rope, avalue]]; LoganBerry.WriteEntry[db: database, entry: entry, replace: TRUE]; entry ¬ LoganBerry.ReadEntry[db: database, key: $Integer, value: "0"].entry; IF NOT Rope.Equal[avalue, GetAttributeValue[entry, $Rope]] THEN { IF out # NIL THEN out.PutRope["Error: incorrectly read back value with CR.\n"]; failed ¬ TRUE; }; avalue ¬ "LF\l in value"; entry ¬ LIST[[$Integer, "0"], [$Rope, avalue]]; LoganBerry.WriteEntry[db: database, entry: entry, replace: TRUE]; entry ¬ LoganBerry.ReadEntry[db: database, key: $Integer, value: "0"].entry; IF NOT Rope.Equal[avalue, GetAttributeValue[entry, $Rope]] THEN { IF out # NIL THEN out.PutRope["Error: incorrectly read back value with LF.\n"]; failed ¬ TRUE; }; avalue ¬ "\"quoted\""; entry ¬ LIST[[$Integer, "0"], [$Rope, avalue]]; LoganBerry.WriteEntry[db: database, entry: entry, replace: TRUE]; entry ¬ LoganBerry.ReadEntry[db: database, key: $Integer, value: "0"].entry; IF NOT Rope.Equal[avalue, GetAttributeValue[entry, $Rope]] THEN { IF out # NIL THEN out.PutRope["Error: incorrectly read back quoted value.\n"]; failed ¬ TRUE; }; avalue ¬ "backslash-quote\\\" in value"; entry ¬ LIST[[$Integer, "0"], [$Rope, avalue]]; LoganBerry.WriteEntry[db: database, entry: entry, replace: TRUE]; entry ¬ LoganBerry.ReadEntry[db: database, key: $Integer, value: "0"].entry; IF NOT Rope.Equal[avalue, GetAttributeValue[entry, $Rope]] THEN { IF out # NIL THEN out.PutRope["Error: incorrectly read back value with backslash-quote.\n"]; failed ¬ TRUE; }; avalue ¬ "\""; entry ¬ LIST[[$Integer, "0"], [$Rope, avalue]]; LoganBerry.WriteEntry[db: database, entry: entry, replace: TRUE]; entry ¬ LoganBerry.ReadEntry[db: database, key: $Integer, value: "0"].entry; IF NOT Rope.Equal[avalue, GetAttributeValue[entry, $Rope]] THEN { IF out # NIL THEN out.PutRope["Error: incorrectly read back value = quote.\n"]; failed ¬ TRUE; }; avalue ¬ "\\"; entry ¬ LIST[[$Integer, "0"], [$Rope, avalue]]; LoganBerry.WriteEntry[db: database, entry: entry, replace: TRUE]; entry ¬ LoganBerry.ReadEntry[db: database, key: $Integer, value: "0"].entry; IF NOT Rope.Equal[avalue, GetAttributeValue[entry, $Rope]] THEN { IF out # NIL THEN out.PutRope["Error: incorrectly read back value = backslash.\n"]; failed ¬ TRUE; }; LoganBerry.DeleteEntry[db: database, key: $Integer, value: "0"]; }; $invalidOps => { -- try to raise errors caughtError: BOOLEAN ¬ FALSE; IF out # NIL THEN out.PutRope["Checking generated errors.\n"]; [] ¬ LoganBerry.Open[dbName: "Nonexistent.badname" ! LoganBerry.Error => {caughtError ¬ TRUE; IF ec = $CantOpenSchema THEN CONTINUE ELSE REJECT};]; IF NOT caughtError THEN { IF out # NIL THEN out.PutRope["Error: able to open nonexistent database.\n"]; failed ¬ TRUE; }; caughtError ¬ FALSE; [] ¬ LoganBerry.Describe[db: 1010101 ! LoganBerry.Error => {caughtError ¬ TRUE; IF ec = $BadDBHandle THEN CONTINUE ELSE REJECT};]; IF NOT caughtError THEN { IF out # NIL THEN out.PutRope["Error: able to operate on bad database.\n"]; failed ¬ TRUE; }; caughtError ¬ FALSE; [] ¬ LoganBerry.ReadEntry[db: database, key: $NonIndex, value: avalue ! LoganBerry.Error => {caughtError ¬ TRUE; IF ec = $NoIndex THEN CONTINUE ELSE REJECT};]; IF NOT caughtError THEN { IF out # NIL THEN out.PutRope["Error: able to read using nonexistent index.\n"]; failed ¬ TRUE; }; i ¬ Random.ChooseInt[rs, 1, dbSize]; avalue ¬ Convert.RopeFromInt[i]; entry ¬ LoganBerry.ReadEntry[db: database, key: $Integer, value: avalue].entry; caughtError ¬ FALSE; [] ¬ LoganBerry.WriteEntry[db: database, entry: entry ! LoganBerry.Error => {caughtError ¬ TRUE; IF ec = $ValueNotUnique THEN CONTINUE ELSE REJECT};]; IF NOT caughtError THEN { IF out # NIL THEN out.PutRope["Error: able to write duplicate entry.\n"]; failed ¬ TRUE; }; caughtError ¬ FALSE; [] ¬ LoganBerry.WriteEntry[db: database, entry: entry.rest ! LoganBerry.Error => {caughtError ¬ TRUE; IF ec = $NoPrimaryKey THEN CONTINUE ELSE REJECT};]; IF NOT caughtError THEN { IF out # NIL THEN out.PutRope["Error: able to write without primary key.\n"]; failed ¬ TRUE; }; }; ENDCASE => { IF out # NIL THEN out.PutRope["Error: No such test.\n"]; failed ¬ TRUE; }; stop ¬ BasicTime.GetClockPulses[]; IF out # NIL THEN out.PutF1["Running time: %g\n", IO.rope[ElapsedTime[start, stop]]]; }; ElapsedTime: PROC [start, stop: BasicTime.Pulses] RETURNS [ROPE] ~ { microseconds, seconds: LONG CARDINAL; digit: CARDINAL; any: BOOL ¬ FALSE; text: REF TEXT ¬ NEW[TEXT[8]]; microseconds ¬ BasicTime.PulsesToMicroseconds[stop - start]; seconds ¬ microseconds / 1000000; microseconds ¬ microseconds MOD 1000000; THROUGH [0..6) DO microseconds ¬ microseconds * 10; digit ¬ microseconds / 1000000; microseconds ¬ microseconds MOD 1000000; IF NOT any THEN { text ¬ Convert.AppendChar[to: text, from: '., quote: FALSE]; any ¬ TRUE; }; text ¬ Convert.AppendChar[to: text, from: digit + '0, quote: FALSE]; IF microseconds = 0 THEN EXIT; ENDLOOP; RETURN [IO.PutFR["%r%g\n", IO.card[seconds], IO.text[text]]]; }; usedKeys: PACKED ARRAY [1..10000] OF BOOLEAN; MarkKeysUnused: PROC [min, max: INT] RETURNS [] ~ { FOR i: INT IN [min..max] DO usedKeys[i] ¬ FALSE; ENDLOOP; }; GenerateUnusedKey: PROC [min, max: INT] RETURNS [INT] ~ { i: INT; i ¬ Random.ChooseInt[rs, min, max]; WHILE usedKeys[i] DO IF i < max THEN i ¬ i + 1 ELSE i ¬ min; ENDLOOP; usedKeys[i] ¬ TRUE; RETURN[i]; }; GenerateUsedKey: PROC [min, max: INT] RETURNS [INT] ~ { i: INT; i ¬ Random.ChooseInt[rs, min, max]; WHILE NOT usedKeys[i] DO IF i < max THEN i ¬ i + 1 ELSE i ¬ min; ENDLOOP; RETURN[i]; }; GetAttributeValue: PROC [entry: LoganBerry.Entry, type: LoganBerry.AttributeType] RETURNS [LoganBerry.AttributeValue] ~ { FOR e: LoganBerry.Entry ¬ entry, e.rest WHILE e # NIL DO IF e.first.type = type THEN RETURN[e.first.value]; ENDLOOP; RETURN[NIL]; }; TestLoganBerry: Commander.CommandProc = { needToBuildIndices: BOOLEAN ¬ FALSE; numErrors: INT ¬ 0; firstTest: TestCase ¬ enumerate; lastTest: TestCase ¬ invalidOps; start, stop: BasicTime.Pulses; args: LIST OF ROPE ¬ CommanderOps.ParseToList[cmd].list; dbFileName ¬ defaultDbFileName; WHILE args#NIL DO SELECT TRUE FROM Rope.Equal[args.first, "-s"] => { -- standard test case firstTest ¬ enumerate; lastTest ¬ invalidOps; }; Rope.Equal[args.first, "-f"] => { -- full testcase IO.PutRope[cmd.out, "Running ALL tests... \n\n"]; firstTest ¬ FIRST[TestCase]; lastTest ¬ LAST[TestCase]; }; Rope.Equal[args.first, "-r"] => { -- specified range of tests ENABLE Convert.Error => GOTO Usage; f, l: CARDINAL; -- ordinal value of desired tests IF args.rest = NIL OR args.rest.rest = NIL THEN GOTO Usage; f ¬ Convert.IntFromRope[args.rest.first]; l ¬ Convert.IntFromRope[args.rest.rest.first]; firstTest ¬ VAL[f]; lastTest ¬ VAL[l]; args ¬ args.rest.rest; }; Rope.Equal[args.first, "-t"] => { -- specific test ENABLE Convert.Error => GOTO Usage; t: CARDINAL; -- ordinal value of desired test IF args.rest = NIL THEN GOTO Usage; t ¬ Convert.IntFromRope[args.rest.first]; firstTest ¬ lastTest ¬ VAL[t]; args ¬ args.rest; }; Rope.Equal[args.first, "-d"] => { -- use named database IF args.rest = NIL THEN GOTO Usage; dbFileName ¬ args.rest.first; args ¬ args.rest; }; ENDCASE => { GOTO Usage; }; args ¬ args.rest; ENDLOOP; database ¬ LoganBerry.Open[dbName: dbFileName ! LoganBerry.Error => { IF ec=$BadIndex THEN {needToBuildIndices ¬ TRUE; RETRY} ELSE {IO.PutF[cmd.out, "Error from LoganBerry: %g - %g\n", IO.atom[ec], IO.rope[explanation]]; GOTO CantOpen}} ]; IF needToBuildIndices THEN { IO.PutRope[cmd.out, "Building indices..."]; LoganBerry.BuildIndices[db: database]; IO.PutRope[cmd.out, " done\n"]; }; start ¬ BasicTime.GetClockPulses[]; FOR t: TestCase IN [firstTest..lastTest] DO IF RunTest[t, cmd.out] THEN numErrors ¬ numErrors + 1; ENDLOOP; stop ¬ BasicTime.GetClockPulses[]; IO.PutF[cmd.out, "%g Errors; elapsed time = %g\n", IO.int[numErrors], IO.rope[ElapsedTime[start, stop]]]; LoganBerry.Close[db: database]; EXITS CantOpen => IO.PutRope[cmd.out, "Test case not run.\n"]; Usage => IO.PutRope[cmd.out, "Usage: TestLoganBerry {-s} {-f} {-r first last} {-t testcase} {-d database} Arguments: -s => standard test case [1..13] (default) -f => full test case [0..17] -r => range of test cases [first..last] -t => specific test case [testcase] -d => use named database (default=LoganBerry-Source.df) Valid testcases: 0 = $create => build a LoganBerry test database in random order 1 = $enumerate => enumerate the database to get the number of entries 2 = $generate => generate the complete database and see if the number is correct 3 = $deleteA => delete some entries 4 = $deleteB => verify that the deleted entries can not be read 5 = $rewriteA => rewrite the deleted entries 6 = $rewriteB => verify that the rewritten entries can be read 7 = $replace => replace some random entries (then restore to original values) 8 = $readRandom => read some random entries 9 = $checkData => check the consistency of the data 10 = $closeAndOpen => close and reopen the database 11 = $bidirectionalGenerate => generate a subrange of entries in both directions 12 = $binaryData => write and read strange values (then delete them) 13 = $invalidOps => try to raise errors 14 = $buildIndices => rebuild the database indices 15 = $compactA => compact the database 16 = $compactB => verify that the compacted database has the correct number of entries 17 = $generateSecondary => generate the complete database using secondary index "]; }; Commander.Register[key: "TestLoganBerry", proc: TestLoganBerry, doc: "Test the LoganBerry package." ]; END. l LoganBerryTest.mesa (Cedar10 version) Copyright Σ 1986, 1992 by Xerox Corporation. All rights reserved. Doug Terry, June 17, 1992 1:00 pm PDT Brian Oki, February 13, 1990 11:14:53 am PST A test program for LoganBerry. Simply type "TestLoganBerry" to a command tool. Willie-s, April 23, 1992 3:21 pm PDT The set of tests must be updated whenever a new test is added The following numbers pertain to specific tests Runs and times the given test. attr: LoganBerry.Attribute; atype: LoganBerry.AttributeType; somehow need to delete old database entries first Create a file given name by opening a stream, then closing it <> log and indices should be empty at this point, but rebuild just to be sure now generate new entries [entry: LoganBerry.Entry] RETURNS [continue: BOOL] Retrieve [start..end] Note: at this point it is hard to predict count since ordering is non-numerical Retrieve (end..start] Taken from InitialCommandsImpl.Time. [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] run all test cases except for create and compact (which take too long) Doug Terry, February 27, 1986 10:43:30 am PST changes to: DIRECTORY, LoganBerryTest, IMPORTS, ~, RunTest, Proc, Proc, Proc, TestLoganBerry, TestLoganQuery Doug Terry, February 27, 1986 7:21:25 pm PST changes to: DIRECTORY, LoganBerryTest, IMPORTS, ~, RunTest, ElapsedTime, Proc, Proc, TestLoganBerry, TestLoganQuery, END, RunTest, MarkKeysUnused, GenerateUnusedKey, GenerateUsedKey, TestCase, AddOne (local of RunTest) Doug Terry, February 27, 1986 8:45:56 pm PST changes to: TestCase, ~, RunTest, GetAttributeValue, Proc, DIRECTORY, IMPORTS, TestLoganQuery, ElapsedTime, MarkKeysUnused, TestLoganBerry Doug Terry, February 27, 1986 9:35:37 pm PST changes to: TestLoganBerry Brian Oki, June 12, 1989 (PCedar version) 8:49:06 am PDT changes for PCedar version: replaced FS with UFS, used streams instead of files. changed create seletion in RunTest; added RETRY statement to LoganBerry.Open signal Brian Oki, February 13, 1990 10:47:18 am PST (PCedar version) changes for PCedar version: replaced UFS with PFS Κz–(cedarcode) style•NewlineDelimiter ™code™%Kšœ Οeœ6™BK™%K™,K™KšœO™OK™$K™—šΟk ˜ Kšœ žœžœ ˜DKšœ žœ˜(Kšœ žœ˜!Kšœžœ/˜˜DKšœ˜Kšœ˜—KšœDžœžœžœ˜`K™JKšœ&˜&Kšœ˜K™šžœ ž˜K˜!KšœžœL˜XKšœ2˜2Kšžœ˜—K˜—šœ 6˜G–6 -- [entry: LoganBerry.Entry] RETURNS [continue: BOOL]š‘œ˜ Jšœžœ žœ™2K˜Kšžœžœ˜ K˜—Kšžœžœžœ(˜9K˜ KšœG˜GKšžœžœžœžœ<˜`K˜Kšžœžœžœ3žœ˜VK˜—šœ B˜RKšžœžœžœ'˜8K˜ K˜AK˜-šžœ žœž˜K˜K˜-Kšžœ˜—Kšœ'˜'šžœžœ˜Kšžœžœžœ0˜AKšœ žœ˜K˜—K˜—šœ 7˜PKšžœžœžœ=˜NK˜ K˜>K˜-šžœ žœž˜K˜K˜-Kšžœ˜—Kšœ'˜'šžœžœ˜Kšžœžœžœ0˜AKšœ žœ˜K˜—K˜—šœ ˜%Kšžœžœžœ1žœ˜XKšœ˜Kšœžœ˜šžœž˜K˜!K˜ K˜OKšœžœ˜)KšœC˜CKšžœ˜—K˜—šœ 2˜AKšžœžœžœ&˜7šžœž˜K˜K˜ šžœJžœžœ˜VKšžœžœžœ9˜JKšœ žœ˜K˜—Kšžœ˜—K˜—šœ ˜.Kšžœžœžœ.˜?šžœžœž˜Kšœ?˜?K˜!Kšžœ˜—K˜—šœ 0˜@Kšžœžœžœ'˜8šžœž˜K˜K˜ šžœJžœžœ˜VKšžœžœžœ8˜IKšœ žœ˜K˜—Kšžœ˜—K˜—šœ ˜-Kšžœžœžœ$žœ˜Išžœž˜K˜$K˜ šžœJžœžœ˜VKšžœžœžœ1žœ˜SKšœ žœ˜K˜—Kšžœ˜—K˜—šœ $˜5Kšžœžœžœ"˜3šžœ ž˜K˜$K˜ K˜OK˜)šžœžœ2žœ˜>Kšžœžœžœ7˜HKšœ žœ˜K˜—Kšžœ˜—K˜—šœ @˜OKšœ˜Kšžœžœžœ7žœ˜_šžœž˜K˜$K˜ K˜OKšœžœ3˜EKšœAžœ˜GK˜UšžœžœHžœ˜TKšžœžœžœC˜TKšœ žœ˜K˜—Kšœ;žœ˜AKšžœ˜—K˜—šœ  ˜4Kšœ žœžœ˜Kšžœžœžœ7˜HK˜$K˜ Kšœ˜˜Gšœ˜Kšœžœ˜Kš žœžœžœžœžœ˜-—Kšœ˜—šžœ žœ˜Kšžœžœžœ<˜MKšœ žœ˜K˜—K–/[conv: LoganBerry.Conv _ NIL, dbName: ROPE]˜/šžœJžœžœ˜VKšžœžœžœ1žœ˜SKšœ žœ˜K˜—K˜—šœ 4˜QKšžœžœžœ.˜?K˜'K˜ K˜oK™K˜ K˜-šžœ žœž˜K˜K˜-Kšžœ˜—K™OK™K˜>šžœ žœž˜K˜K˜>Kšžœ˜—šžœ žœ˜KšžœžœžœQ˜bKšœ žœ˜K˜—Kšœ'˜'K˜—šœ ˜'Kšžœžœžœ#˜4Kšœ%˜%K˜—šœ G˜WKšžœžœžœ/˜@K˜ K˜AK˜-šžœ žœž˜K˜K˜-Kšžœ˜—Kšœ'˜'šžœžœ˜Kšžœžœžœ:žœ˜[Kšœ žœ˜K˜—K˜—šœ ˜3Kšžœžœžœ'˜8Kšœ&˜&K˜—šœ 3˜EKšžœžœžœ>˜OK˜Kšœžœ#˜/Kšœ;žœ˜AK˜L–-[s1: ROPE, s2: ROPE, case: BOOL _ TRUE]šžœžœ5žœ˜AKšžœžœžœ>˜OKšœ žœ˜K˜—K˜Kšœžœ#˜/Kšœ;žœ˜AK˜L–-[s1: ROPE, s2: ROPE, case: BOOL _ TRUE]šžœžœ5žœ˜AKšžœžœžœ>˜OKšœ žœ˜K˜—K˜Kšœžœ#˜/Kšœ;žœ˜AK˜L–-[s1: ROPE, s2: ROPE, case: BOOL _ TRUE]šžœžœ5žœ˜AKšžœžœžœ=˜NKšœ žœ˜K˜—K˜(Kšœžœ#˜/Kšœ;žœ˜AK˜L–-[s1: ROPE, s2: ROPE, case: BOOL _ TRUE]šžœžœ5žœ˜AKšžœžœžœK˜\Kšœ žœ˜K˜—K˜Kšœžœ#˜/Kšœ;žœ˜AK˜L–-[s1: ROPE, s2: ROPE, case: BOOL _ TRUE]šžœžœ5žœ˜AKšžœžœžœ>˜OKšœ žœ˜K˜—K˜Kšœžœ#˜/Kšœ;žœ˜AK˜L–-[s1: ROPE, s2: ROPE, case: BOOL _ TRUE]šžœžœ5žœ˜AKšžœžœžœB˜SKšœ žœ˜K˜—Kšœ@˜@K˜—šœ ˜(Kšœ žœžœ˜Kšžœžœžœ.˜?˜5Kš œ#žœžœžœžœžœžœ˜^—šžœžœ žœ˜Kšžœžœžœ<˜MKšœ žœ˜K˜—Kšœžœ˜˜'Kš œ#žœžœžœžœžœžœ˜[—šžœžœ žœ˜Kšžœžœžœ:˜KKšœ žœ˜K˜—Kšœžœ˜˜HKš œ#žœžœžœžœžœžœ˜W—šžœžœ žœ˜Kšžœžœžœ?˜PKšœ žœ˜K˜—K˜$K˜ K˜OKšœžœ˜˜8Kš œ#žœžœžœžœžœžœ˜^—šžœžœ žœ˜Kšžœžœžœ8˜IKšœ žœ˜K˜—Kšœžœ˜˜=Kš œ#žœžœžœžœžœžœ˜\—šžœžœ žœ˜Kšžœžœžœ<˜MKšœ žœ˜K˜—K˜—šžœ˜ Kšžœžœžœ(˜9Kšœ žœ˜Kšœ˜——K˜"Kšžœžœžœ!žœ!˜UK˜K™—š‘ œžœ!žœžœ˜DKšœ$™$Kšœžœžœ˜%Kšœžœ˜Kšœžœžœ˜Kš œžœžœžœžœ˜K˜Kšžœžœ˜#Kšœžœ !˜2Kš žœ žœžœžœžœžœ˜;K˜*K˜/Kšœ žœ˜Kšœ žœ˜K˜Kšœ˜—šœ# ˜3Kšžœžœ˜#Kšœžœ  ˜.Kšžœ žœžœžœ˜#K˜*Kšœžœ˜K˜Kšœ˜—šœ# ˜8Kšžœ žœžœžœ˜#K˜K˜Kšœ˜—šžœ˜ Kšžœ˜ Kšœ˜——K˜Kšžœ˜—–/[conv: LoganBerry.Conv _ NIL, dbName: ROPE]˜EKšžœžœžœžœ˜7Kš žœžœ3žœ žœžœ˜q—šžœžœ˜Kšžœ)˜+Kšœ&˜&Kšžœ˜K˜—K˜#šžœ žœž˜+Kšžœžœ˜6Kšžœ˜—K˜"Kšžœ1žœžœ!˜iKšœ˜šž˜šœ ˜ Kšžœ*˜,—šœ ˜ Kšžœ^˜`K˜ Kšœ-˜-Kšœ˜Kšœ)˜)Kšœ%˜%K˜:Kšœ˜Kšœ 1˜BKšœ 3˜HKšœ ?˜SKšœ ˜&Kšœ /˜BKšœ ˜/Kšœ -˜AKšœ =˜PKšœ ˜.Kšœ !˜6Kšœ ˜5Kšœ! 1˜RKšœ 0˜FKšœ ˜)Kšœ ˜4Kšœ ˜(Kšœ D˜XKšœ 4˜QKšœ˜——K˜—J™J™Kšœg˜gK˜—Kšžœ˜™-Kšœ Οr`™l—™,Kšœ ’»œ™Ϊ—™,Kšœ ’~™Š—™,Kšœ ’™—™8KšΟiœ6™PKšœ*žœ$™S—™>Kš£œ™1—K™—…—M¨nŽ