IO.
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]];
somehow need to delete old database entries first
schema ¬ LoganBerry.Describe[db: database];
LoganBerry.Close[db: database];
Create a file given name by opening a stream, then closing it
filename ¬ PFS.PathFromRope[schema.logs.first.file];
newStream ¬ PFS.StreamOpen[fileName: filename, accessOptions: $create];
IO.PutChar[newStream, 377C];
IO.Close[newStream];
<<FS.Close[FS.Create[name: schema.logs.first.file]];>>
FOR i:
LIST
OF LoganBerry.IndexInfo ¬ schema.indices, i.rest
WHILE i#
NIL
DO
PFS.Delete[name: PFS.PathFromRope[i.first.file]];
ENDLOOP;
<<database ¬ LoganBerry.Open[dbName: dbFileName ! LoganBerry.Error => {
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];
log and indices should be empty at this point, but rebuild just to be sure
LoganBerry.BuildIndices[db: database];
MarkKeysUnused[1, dbSize];
now generate new entries
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 = {
[entry: LoganBerry.Entry] RETURNS [continue: BOOL]
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]];
Retrieve [start..end]
count ¬ 0;
entry ¬ LoganBerry.NextEntry[cursor: cursor];
UNTIL entry =
NIL
DO
count ¬ count + 1;
entry ¬ LoganBerry.NextEntry[cursor: cursor];
ENDLOOP;
Note: at this point it is hard to predict count since ordering is non-numerical
Retrieve (end..start]
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;
};