-- Test2Impl.mesa
-- written by Bill Paxton, April 1981
-- last edit by Bill Paxton, 29-Jun-81 15:59:27

-- This module provides random testing for editing Text nodes

DIRECTORY
EditTest,
TextEdit,
RopeEdit,
TextNode,
RunReader,
RopeReader,
Rope,
RopeInline;

Test2Impl: PROGRAM
	IMPORTS EditTest, TextEdit, RopeEdit,
		RunReader, RopeReader, Rope
	EXPORTS EditTest =
BEGIN
OPEN
	rI:Rope,
	EditTest,
	editI:TextEdit,
	ropeI:RopeEdit,
	nodeI:TextNode,
	runrdrI:RunReader,
	roperdrI:RopeReader;
	
-- ***** Text Edit operations

ReplaceByChar: PUBLIC PROC = {
	dest: Node ← PickNode[];
	destStart, destEnd, destLen, oldSize, oldPos, newPos, resultStart, resultLen: Offset;
	newRope, oldRope: Rope;
	newRuns, oldRuns: Runs;
	inherit: BOOLEAN ← RandomBoolean[];
	looks: Looks;
	IF ~inherit THEN looks ← PickLooks[];
	[destStart,destEnd] ← PickTwo[dest];
	oldSize ← editI.Size[dest];
	oldRope ← editI.GetRope[dest];
	oldRuns ← editI.GetRuns[dest];
	BeforeUndo[dest];
	[resultStart,resultLen] ← editI.ReplaceByChar[dest,'#,
		destStart,destLen←destEnd-destStart,inherit,looks,event];
	newRope ← editI.GetRope[dest];
	newRuns ← editI.GetRuns[dest];
	IF resultStart # destStart OR resultLen # 1 THEN ERROR;
	CheckSize[dest,oldSize+1-destLen];
	CheckRopes[newRope,0,oldRope,0,destStart];
	IF editI.FetchChar[dest,destStart] # '# THEN ERROR;
	oldPos ← destStart+destLen; newPos ← destStart+1;
	CheckRopes[newRope,newPos,oldRope,oldPos,oldSize-oldPos];
	CheckRuns[newRuns,0,oldRuns,0,destStart];
	IF ~inherit AND editI.FetchLooks[dest,destStart] # looks THEN ERROR;
	CheckRuns[newRuns,newPos,oldRuns,oldPos,oldSize-oldPos];
	TestUndo[];
	AdjustLength[dest] };

InsertChar: PUBLIC PROC = {
	dest: Node ← PickNode[];
	destLoc: Offset ← PickOne[dest];
	oldSize, loc, oldPos, newPos, resultStart, resultLen: Offset;
	newRope, oldRope: Rope;
	newRuns, oldRuns: Runs;
	inherit: BOOLEAN ← RandomBoolean[];
	looks: Looks;
	num: NAT ← ChooseNAT[1,20]; -- number of chars to insert
	IF ~inherit THEN looks ← PickLooks[];
	oldSize ← editI.Size[dest];
	oldRope ← editI.GetRope[dest];
	oldRuns ← editI.GetRuns[dest];
	loc ← destLoc;
	FOR i:NAT IN [0..num) DO
		[resultStart,resultLen] ← editI.InsertChar[dest,'z-i,loc,inherit,looks];
		IF resultStart # loc OR resultLen # 1 THEN ERROR;
		loc ← loc+1;
		ENDLOOP;
	newRope ← editI.GetRope[dest];
	newRuns ← editI.GetRuns[dest];
	CheckSize[dest,oldSize+num];
	CheckRopes[newRope,0,oldRope,0,destLoc];
	loc ← destLoc;
	FOR i:NAT IN [0..num) DO
		IF editI.FetchChar[dest,loc] # 'z-i THEN ERROR;
		IF ~inherit AND editI.FetchLooks[dest,loc] # looks THEN ERROR;
		loc ← loc+1;
		ENDLOOP;
	oldPos ← destLoc; newPos ← destLoc+num;
	CheckRopes[newRope,newPos,oldRope,oldPos,oldSize-oldPos];
	CheckRuns[newRuns,0,oldRuns,0,destLoc];
	CheckRuns[newRuns,newPos,oldRuns,oldPos,oldSize-oldPos];
	AdjustLength[dest] };

AppendChar: PUBLIC PROC = {
	dest: Node ← PickNode[];
	inherit: BOOLEAN ← RandomBoolean[];
	looks: Looks;
	loc, oldSize, resultStart, resultLen: Offset;
	newRope, oldRope: Rope;
	newRuns, oldRuns: Runs;
	num: NAT ← ChooseNAT[1,20]; -- number of chars to append
	IF ~inherit THEN looks ← PickLooks[];
	oldSize ← editI.Size[dest];
	oldRope ← editI.GetRope[dest];
	oldRuns ← editI.GetRuns[dest];
	FOR i:NAT IN [0..num) DO
		loc: Offset ← editI.Size[dest];
		[resultStart,resultLen] ← editI.AppendChar[dest,'Z-i,inherit,looks];
		IF resultStart # loc OR resultLen # 1 THEN ERROR;
		ENDLOOP;
	newRope ← editI.GetRope[dest];
	newRuns ← editI.GetRuns[dest];
	CheckSize[dest,oldSize+num];
	CheckRopes[newRope,0,oldRope,0,oldSize];
	loc ← oldSize;
	FOR i:NAT IN [0..num) DO
		IF editI.FetchChar[dest,loc] # 'Z-i THEN ERROR;
		IF ~inherit AND editI.FetchLooks[dest,loc] # looks THEN ERROR;
		loc ← loc+1;
		ENDLOOP;
	CheckRuns[newRuns,0,oldRuns,0,oldSize];
	AdjustLength[dest] };

string: REF READONLY TEXT ← "1234567890123456789012345678901234567890";
stringRope: Rope ← rI.FromString[string];

ReplaceByString: PUBLIC PROC = {
	dest: Node ← PickNode[];
	destStart, destEnd, destLen, oldSize, oldPos, newPos, resultStart, resultLen: Offset;
	newRope, oldRope: Rope;
	newRuns, oldRuns: Runs;
	inherit: BOOLEAN ← RandomBoolean[];
	looks: Looks;
	strStart, strEnd, strLen: NAT;
	oldSize ← editI.Size[dest];
	oldRope ← editI.GetRope[dest];
	oldRuns ← editI.GetRuns[dest];
	IF ~inherit THEN looks ← PickLooks[];
	[destStart,destEnd] ← PickTwo[dest];
	[strStart,strEnd] ← ChooseTwoNATs[0,string.length];
	BeforeUndo[dest];
	[resultStart,resultLen] ← editI.ReplaceByString[dest,string,strStart,
		strLen←strEnd-strStart,destStart,destLen←destEnd-destStart,inherit,looks,event];
	newRope ← editI.GetRope[dest];
	newRuns ← editI.GetRuns[dest];
	IF resultStart # destStart OR resultLen # strLen THEN ERROR;
	CheckSize[dest,oldSize+strLen-destLen];
	CheckRopes[newRope,0,oldRope,0,destStart];
	CheckRopes[newRope,destStart,stringRope,strStart,strLen];
	oldPos ← destStart+destLen; newPos ← destStart+strLen;
	CheckRopes[newRope,newPos,oldRope,oldPos,oldSize-oldPos];
	CheckRuns[newRuns,0,oldRuns,0,destStart];
	IF ~inherit AND strLen>0 AND
		editI.FetchLooks[dest,destStart] # looks THEN ERROR;
	CheckRuns[newRuns,newPos,oldRuns,oldPos,oldSize-oldPos];
	TestUndo[];
	AdjustLength[dest] };

InsertString: PUBLIC PROC = {
	dest: Node ← PickNode[];
	InsertStringInNode[dest];
	AdjustLength[dest] };

InsertStringInNode: PUBLIC PROC [dest: Node] = {
	oldSize, resultStart, resultLen: Offset;
	destLoc: Offset ← PickOne[dest];
	inherit: BOOLEAN ← RandomBoolean[];
	newRope, oldRope: Rope;
	newRuns, oldRuns: Runs;
	looks: Looks;
	strStart, strEnd, strLen: NAT;
	IF ~inherit THEN looks ← PickLooks[];
	[strStart,strEnd] ← ChooseTwoNATs[0,string.length];
	oldSize ← editI.Size[dest];
	oldRope ← editI.GetRope[dest];
	oldRuns ← editI.GetRuns[dest];
	[resultStart,resultLen] ← editI.InsertString[dest,string,strStart,strLen←strEnd-strStart,
		destLoc,inherit,looks];
	newRope ← editI.GetRope[dest];
	newRuns ← editI.GetRuns[dest];
	IF resultStart # destLoc OR resultLen # strLen THEN ERROR;
	CheckSize[dest,oldSize+strLen];
	CheckRopes[newRope,0,oldRope,0,destLoc];
	CheckRopes[newRope,destLoc,stringRope,strStart,strLen];
	CheckRopes[newRope,destLoc+strLen,oldRope,destLoc,oldSize-destLoc];
	CheckRuns[newRuns,0,oldRuns,0,destLoc];
	IF ~inherit AND strLen>0 AND
		editI.FetchLooks[dest,destLoc] # looks THEN ERROR;
	CheckRuns[newRuns,destLoc+strLen,oldRuns,destLoc,oldSize-destLoc] };

AppendString: PUBLIC PROC = {
	dest: Node ← PickNode[];
	inherit: BOOLEAN ← RandomBoolean[];
	looks: Looks;
	oldSize, resultStart, resultLen: Offset;
	newRope, oldRope: Rope;
	newRuns, oldRuns: Runs;
	strStart, strEnd, strLen: NAT;
	IF ~inherit THEN looks ← PickLooks[];
	[strStart,strEnd] ← ChooseTwoNATs[0,string.length];
	oldSize ← editI.Size[dest];
	oldRope ← editI.GetRope[dest];
	oldRuns ← editI.GetRuns[dest];
	[resultStart,resultLen] ← editI.AppendString[dest,string,strStart,strLen←strEnd-strStart,
		inherit,looks];
	newRope ← editI.GetRope[dest];
	newRuns ← editI.GetRuns[dest];
	IF resultStart # oldSize OR resultLen # strLen THEN ERROR;
	CheckSize[dest,oldSize+strLen];
	CheckRopes[newRope,0,oldRope,0,oldSize];
	CheckRopes[newRope,oldSize,stringRope,strStart,strLen];
	CheckRuns[newRuns,0,oldRuns,0,oldSize];
	IF ~inherit AND strLen>0 AND
		editI.FetchLooks[dest,oldSize] # looks THEN ERROR;
	AdjustLength[dest] };

ReplaceByRope: PUBLIC PROC = {
	dest: Node ← PickNode[];
	rope: Rope ← PickRope[];
	newRope, oldRope: Rope;
	newRuns, oldRuns: Runs;
	destStart, destEnd, destLen, oldSize, oldPos, newPos, ropeLen, resultStart, resultLen: Offset;
	inherit: BOOLEAN ← RandomBoolean[];
	looks: Looks;
	[destStart,destEnd] ← PickTwo[dest];
	IF ~inherit THEN looks ← PickLooks[];
	oldSize ← editI.Size[dest];
	oldRope ← editI.GetRope[dest];
	oldRuns ← editI.GetRuns[dest];
	ropeLen ← ropeI.Size[rope];
	BeforeUndo[dest];
	[resultStart,resultLen] ← editI.ReplaceByRope[dest,rope,
		destStart,destLen←destEnd-destStart,inherit,looks,event];
	newRope ← editI.GetRope[dest];
	newRuns ← editI.GetRuns[dest];
	IF resultStart # destStart OR resultLen # ropeLen THEN ERROR;
	CheckSize[dest,oldSize+ropeLen-destLen];
	CheckRopes[newRope,0,oldRope,0,destStart];
	CheckRopes[newRope,destStart,rope,0,ropeLen];
	oldPos ← destStart+destLen; newPos ← destStart+ropeLen;
	CheckRopes[newRope,newPos,oldRope,oldPos,oldSize-oldPos];
	CheckRuns[newRuns,0,oldRuns,0,destStart];
	IF ~inherit AND ropeLen>0 AND
		editI.FetchLooks[dest,destStart] # looks THEN ERROR;
	CheckRuns[newRuns,newPos,oldRuns,oldPos,oldSize-oldPos];
	TestUndo[];
	AdjustLength[dest] };

InsertRope: PUBLIC PROC = {
	dest: Node ← PickNode[];
	destLoc: Offset ← PickOne[dest];
	oldSize, ropeLen, resultStart, resultLen: Offset;
	rope: Rope ← PickRope[];
	newRope, oldRope: Rope;
	newRuns, oldRuns: Runs;
	inherit: BOOLEAN ← RandomBoolean[];
	looks: Looks;
	IF ~inherit THEN looks ← PickLooks[];
	oldSize ← editI.Size[dest];
	oldRope ← editI.GetRope[dest];
	oldRuns ← editI.GetRuns[dest];
	ropeLen ← ropeI.Size[rope];
	[resultStart,resultLen] ← editI.InsertRope[dest,rope,destLoc,inherit,looks];
	newRope ← editI.GetRope[dest];
	newRuns ← editI.GetRuns[dest];
	IF resultStart # destLoc OR resultLen # ropeLen THEN ERROR;
	CheckSize[dest,oldSize+ropeLen];
	CheckRopes[newRope,0,oldRope,0,destLoc];
	CheckRopes[newRope,destLoc,rope,0,ropeLen];
	CheckRopes[newRope,destLoc+ropeLen,oldRope,destLoc,oldSize-destLoc];
	CheckRuns[newRuns,0,oldRuns,0,destLoc];
	IF ~inherit AND ropeLen>0 AND
		editI.FetchLooks[dest,destLoc] # looks THEN ERROR;
	CheckRuns[newRuns,destLoc+ropeLen,oldRuns,destLoc,oldSize-destLoc];
	AdjustLength[dest] };

AppendRope: PUBLIC PROC = {
	dest: Node ← PickNode[];
	rope: Rope ← PickRope[];
	oldSize, ropeLen, resultStart, resultLen: Offset;
	newRope, oldRope: Rope;
	newRuns, oldRuns: Runs;
	inherit: BOOLEAN ← RandomBoolean[];
	looks: Looks;
	IF ~inherit THEN looks ← PickLooks[];
	oldSize ← editI.Size[dest];
	oldRope ← editI.GetRope[dest];
	oldRuns ← editI.GetRuns[dest];
	ropeLen ← ropeI.Size[rope];
	[resultStart,resultLen] ← editI.AppendRope[dest,rope,inherit,looks];
	newRope ← editI.GetRope[dest];
	newRuns ← editI.GetRuns[dest];
	IF resultStart # oldSize OR resultLen # ropeLen THEN ERROR;
	CheckSize[dest,oldSize+ropeLen];
	CheckRopes[newRope,0,oldRope,0,oldSize];
	CheckRopes[newRope,oldSize,rope,0,ropeLen];
	CheckRuns[newRuns,0,oldRuns,0,oldSize];
	IF ~inherit AND ropeLen>0 AND
		editI.FetchLooks[dest,oldSize] # looks THEN ERROR;
	AdjustLength[dest] };

END.